1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-28 23:28:16 +02:00

[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)

Currently the built-in CMap files are loaded in `src/core/cmap.js` using `XMLHttpRequest` directly. For some environments that might be a problem, hence this patch refactors that to instead use a factory to load built-in CMaps on the main thread and message the data to the worker thread.

This is inspired by other recent work, e.g. the addition of the `CanvasFactory`, and to a large extent on the IRC discussion starting at http://logs.glob.uno/?c=mozilla%23pdfjs&s=12+Oct+2016&e=12+Oct+2016#c53010.
This commit is contained in:
Jonas Jenwald 2017-02-12 15:54:41 +01:00
parent b509a3f83c
commit 769c1450b7
10 changed files with 211 additions and 111 deletions

View file

@ -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 = [
@ -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++) {
@ -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);
@ -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;
@ -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) {
@ -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.
@ -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') {
@ -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;
});

View file

@ -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;
@ -112,7 +113,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
forceDataSchema: false,
maxImageSize: -1,
disableFontFace: false,
cMapOptions: { url: null, packed: false },
disableNativeImageDecoder: false,
};
@ -178,6 +178,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
this.idFactory = idFactory;
this.fontCache = fontCache;
this.options = options || DefaultPartialEvaluatorOptions;
this.fetchBuiltInCMap = function (name) {
return handler.sendWithPromise('FetchBuiltInCMap', {
name: name,
});
};
}
// Trying to minimize Date.now() usage and check every 100 time
@ -1879,9 +1885,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) {
@ -1907,16 +1915,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);
}
@ -2222,7 +2236,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) {
@ -2352,8 +2365,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;
});

View file

@ -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,
};