Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[api-minor] Refactor fetching of built-in CMaps to utilize a factory on the display side instead, to allow users of the API to provide a custom CMap loading factory (e.g. for use with Node.js) #8064

Merged
merged 2 commits into from
Feb 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 38 additions & 68 deletions src/core/cmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ var error = sharedUtil.error;
var isInt = sharedUtil.isInt;
var isString = sharedUtil.isString;
var MissingDataException = sharedUtil.MissingDataException;
var CMapCompressionType = sharedUtil.CMapCompressionType;
var isEOF = corePrimitives.isEOF;
var isName = corePrimitives.isName;
var isCmd = corePrimitives.isCmd;
var isStream = corePrimitives.isStream;
var StringStream = coreStream.StringStream;
var Stream = coreStream.Stream;
var Lexer = coreParser.Lexer;

var BUILT_IN_CMAPS = [
Expand Down Expand Up @@ -423,25 +424,6 @@ var IdentityCMap = (function IdentityCMapClosure() {
})();

var BinaryCMapReader = (function BinaryCMapReaderClosure() {
function fetchBinaryData(url) {
return new Promise(function (resolve, reject) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onreadystatechange = function () {
if (request.readyState === XMLHttpRequest.DONE) {
if (!request.response || request.status !== 200 &&
request.status !== 0) {
reject(new Error('Unable to get binary cMap at: ' + url));
} else {
resolve(new Uint8Array(request.response));
}
}
};
request.send(null);
});
}

function hexToInt(a, size) {
var n = 0;
for (var i = 0; i <= size; i++) {
Expand Down Expand Up @@ -561,8 +543,8 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
}
};

function processBinaryCMap(url, cMap, extend) {
return fetchBinaryData(url).then(function (data) {
function processBinaryCMap(data, cMap, extend) {
return new Promise(function (resolve, reject) {
var stream = new BinaryCMapStream(data);
var header = stream.readByte();
cMap.vertical = !!(header & 1);
Expand Down Expand Up @@ -709,22 +691,23 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
}
break;
default:
error('Unknown type: ' + type);
break;
reject(new Error('processBinaryCMap: Unknown type: ' + type));
return;
}
}

if (useCMap) {
return extend(useCMap);
resolve(extend(useCMap));
return;
}
return cMap;
resolve(cMap);
});
}

function BinaryCMapReader() {}

BinaryCMapReader.prototype = {
read: processBinaryCMap
process: processBinaryCMap,
};

return BinaryCMapReader;
Expand Down Expand Up @@ -879,7 +862,7 @@ var CMapFactory = (function CMapFactoryClosure() {
}
}

function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) {
var previous;
var embededUseCMap;
objLoop: while (true) {
Expand Down Expand Up @@ -935,14 +918,13 @@ var CMapFactory = (function CMapFactoryClosure() {
useCMap = embededUseCMap;
}
if (useCMap) {
return extendCMap(cMap, builtInCMapParams, useCMap);
return extendCMap(cMap, fetchBuiltInCMap, useCMap);
}
return Promise.resolve(cMap);
}

function extendCMap(cMap, builtInCMapParams, useCMap) {
return createBuiltInCMap(useCMap, builtInCMapParams).then(
function(newCMap) {
function extendCMap(cMap, fetchBuiltInCMap, useCMap) {
return createBuiltInCMap(useCMap, fetchBuiltInCMap).then(function(newCMap) {
cMap.useCMap = newCMap;
// If there aren't any code space ranges defined clone all the parent ones
// into this cMap.
Expand All @@ -965,15 +947,7 @@ var CMapFactory = (function CMapFactoryClosure() {
});
}

function parseBinaryCMap(name, builtInCMapParams) {
var url = builtInCMapParams.url + name + '.bcmap';
var cMap = new CMap(true);
return new BinaryCMapReader().read(url, cMap, function (useCMap) {
return extendCMap(cMap, builtInCMapParams, useCMap);
});
}

function createBuiltInCMap(name, builtInCMapParams) {
function createBuiltInCMap(name, fetchBuiltInCMap) {
if (name === 'Identity-H') {
return Promise.resolve(new IdentityCMap(false, 2));
} else if (name === 'Identity-V') {
Expand All @@ -982,45 +956,41 @@ var CMapFactory = (function CMapFactoryClosure() {
if (BUILT_IN_CMAPS.indexOf(name) === -1) {
return Promise.reject(new Error('Unknown cMap name: ' + name));
}
assert(builtInCMapParams, 'built-in cMap parameters are not provided');
assert(fetchBuiltInCMap, 'Built-in CMap parameters are not provided.');

if (builtInCMapParams.packed) {
return parseBinaryCMap(name, builtInCMapParams);
}
return fetchBuiltInCMap(name).then(function (data) {
var cMapData = data.cMapData, compressionType = data.compressionType;
var cMap = new CMap(true);

return new Promise(function (resolve, reject) {
var url = builtInCMapParams.url + name;
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState === XMLHttpRequest.DONE) {
if (request.status === 200 || request.status === 0) {
var cMap = new CMap(true);
var lexer = new Lexer(new StringStream(request.responseText));
parseCMap(cMap, lexer, builtInCMapParams, null).then(
function (parsedCMap) {
resolve(parsedCMap);
});
} else {
reject(new Error('Unable to get cMap at: ' + url));
}
}
};
request.open('GET', url, true);
request.send(null);
if (compressionType === CMapCompressionType.BINARY) {
return new BinaryCMapReader().process(cMapData, cMap,
function (useCMap) {
return extendCMap(cMap, fetchBuiltInCMap, useCMap);
});
}
assert(compressionType === CMapCompressionType.NONE,
'TODO: Only BINARY/NONE CMap compression is currently supported.');
// Uncompressed CMap.
var lexer = new Lexer(new Stream(cMapData));
return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
});
}

return {
create: function (encoding, builtInCMapParams, useCMap) {
create: function (params) {
var encoding = params.encoding;
var fetchBuiltInCMap = params.fetchBuiltInCMap;
var useCMap = params.useCMap;

if (isName(encoding)) {
return createBuiltInCMap(encoding.name, builtInCMapParams);
return createBuiltInCMap(encoding.name, fetchBuiltInCMap);
} else if (isStream(encoding)) {
var cMap = new CMap();
var lexer = new Lexer(encoding);
return parseCMap(cMap, lexer, builtInCMapParams, useCMap).then(
return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(
function (parsedCMap) {
if (parsedCMap.isIdentityCMap) {
return createBuiltInCMap(parsedCMap.name, builtInCMapParams);
return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap);
}
return parsedCMap;
});
Expand Down
11 changes: 8 additions & 3 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ var Page = (function PageClosure() {
var DEFAULT_USER_UNIT = 1.0;
var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];

function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache,
builtInCMapCache) {
this.pdfManager = pdfManager;
this.pageIndex = pageIndex;
this.pageDict = pageDict;
this.xref = xref;
this.ref = ref;
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.evaluatorOptions = pdfManager.evaluatorOptions;
this.resourcesPromise = null;

Expand Down Expand Up @@ -248,6 +250,7 @@ var Page = (function PageClosure() {
handler, this.pageIndex,
this.idFactory,
this.fontCache,
this.builtInCMapCache,
this.evaluatorOptions);

var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
Expand Down Expand Up @@ -315,6 +318,7 @@ var Page = (function PageClosure() {
handler, self.pageIndex,
self.idFactory,
self.fontCache,
self.builtInCMapCache,
self.evaluatorOptions);

return partialEvaluator.getTextContent(contentStream,
Expand Down Expand Up @@ -551,9 +555,10 @@ var PDFDocument = (function PDFDocumentClosure() {
this.xref.parse(recoveryMode);
var self = this;
var pageFactory = {
createPage: function (pageIndex, dict, ref, fontCache) {
createPage: function (pageIndex, dict, ref, fontCache,
builtInCMapCache) {
return new Page(self.pdfManager, self.xref, pageIndex, dict, ref,
fontCache);
fontCache, builtInCMapCache);
}
};
this.catalog = new Catalog(this.pdfManager, this.xref, pageFactory);
Expand Down
51 changes: 39 additions & 12 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES;
var ImageKind = sharedUtil.ImageKind;
var OPS = sharedUtil.OPS;
var TextRenderingMode = sharedUtil.TextRenderingMode;
var CMapCompressionType = sharedUtil.CMapCompressionType;
var Util = sharedUtil.Util;
var assert = sharedUtil.assert;
var createPromiseCapability = sharedUtil.createPromiseCapability;
Expand Down Expand Up @@ -112,7 +113,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
forceDataSchema: false,
maxImageSize: -1,
disableFontFace: false,
cMapOptions: { url: null, packed: false },
disableNativeImageDecoder: false,
};

Expand Down Expand Up @@ -170,14 +170,31 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};

function PartialEvaluator(pdfManager, xref, handler, pageIndex,
idFactory, fontCache, options) {
idFactory, fontCache, builtInCMapCache, options) {
this.pdfManager = pdfManager;
this.xref = xref;
this.handler = handler;
this.pageIndex = pageIndex;
this.idFactory = idFactory;
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.options = options || DefaultPartialEvaluatorOptions;

this.fetchBuiltInCMap = function (name) {
var cachedCMap = builtInCMapCache[name];
if (cachedCMap) {
return Promise.resolve(cachedCMap);
}
return handler.sendWithPromise('FetchBuiltInCMap', {
name: name,
}).then(function (data) {
if (data.compressionType !== CMapCompressionType.NONE) {
// Given the size of uncompressed CMaps, only cache compressed ones.
builtInCMapCache[name] = data;
}
return data;
});
};
}

// Trying to minimize Date.now() usage and check every 100 time
Expand Down Expand Up @@ -1879,9 +1896,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var ucs2CMapName = Name.get(registry + '-' + ordering + '-UCS2');
// d) Obtain the CMap with the name constructed in step (c) (available
// from the ASN Web site; see the Bibliography).
return CMapFactory.create(ucs2CMapName, this.options.cMapOptions,
null).then(
function (ucs2CMap) {
return CMapFactory.create({
encoding: ucs2CMapName,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (ucs2CMap) {
var cMap = properties.cMap;
toUnicode = [];
cMap.forEach(function(charcode, cid) {
Expand All @@ -1907,16 +1926,22 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
var cmapObj = toUnicode;
if (isName(cmapObj)) {
return CMapFactory.create(cmapObj, this.options.cMapOptions, null).then(
function (cmap) {
return CMapFactory.create({
encoding: cmapObj,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (cmap) {
if (cmap instanceof IdentityCMap) {
return new IdentityToUnicodeMap(0, 0xFFFF);
}
return new ToUnicodeMap(cmap.getMap());
});
} else if (isStream(cmapObj)) {
return CMapFactory.create(cmapObj, this.options.cMapOptions, null).then(
function (cmap) {
return CMapFactory.create({
encoding: cmapObj,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (cmap) {
if (cmap instanceof IdentityCMap) {
return new IdentityToUnicodeMap(0, 0xFFFF);
}
Expand Down Expand Up @@ -2222,7 +2247,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var descriptor = preEvaluatedFont.descriptor;
var type = preEvaluatedFont.type;
var maxCharIndex = (composite ? 0xFFFF : 0xFF);
var cMapOptions = this.options.cMapOptions;
var properties;

if (!descriptor) {
Expand Down Expand Up @@ -2352,8 +2376,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (isName(cidEncoding)) {
properties.cidEncoding = cidEncoding.name;
}
cMapPromise = CMapFactory.create(cidEncoding, cMapOptions, null).then(
function (cMap) {
cMapPromise = CMapFactory.create({
encoding: cidEncoding,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (cMap) {
properties.cMap = cMap;
properties.vertical = properties.cMap.vertical;
});
Expand Down
8 changes: 5 additions & 3 deletions src/core/obj.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ var Catalog = (function CatalogClosure() {
this.xref = xref;
this.catDict = xref.getCatalogObj();
this.fontCache = new RefSetCache();
assert(isDict(this.catDict),
'catalog object is not a dictionary');
this.builtInCMapCache = Object.create(null);
assert(isDict(this.catDict), 'catalog object is not a dictionary');

// TODO refactor to move getPage() to the PDFDocument.
this.pageFactory = pageFactory;
Expand Down Expand Up @@ -428,6 +428,7 @@ var Catalog = (function CatalogClosure() {
delete font.translated;
}
this.fontCache.clear();
this.builtInCMapCache = Object.create(null);
}.bind(this));
},

Expand All @@ -438,7 +439,8 @@ var Catalog = (function CatalogClosure() {
var dict = a[0];
var ref = a[1];
return this.pageFactory.createPage(pageIndex, dict, ref,
this.fontCache);
this.fontCache,
this.builtInCMapCache);
}.bind(this)
);
}
Expand Down
5 changes: 0 additions & 5 deletions src/core/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -729,15 +729,10 @@ var WorkerMessageHandler = {

ensureNotTerminated();

var cMapOptions = {
url: data.cMapUrl === undefined ? null : data.cMapUrl,
packed: data.cMapPacked === true
};
var evaluatorOptions = {
forceDataSchema: data.disableCreateObjectURL,
maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize,
disableFontFace: data.disableFontFace,
cMapOptions: cMapOptions,
disableNativeImageDecoder: data.disableNativeImageDecoder,
};

Expand Down
Loading