Merge pull request #8064 from Snuffleupagus/fetchBuiltInCMap

[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)
This commit is contained in:
Yury Delendik 2017-02-17 15:30:31 -06:00 committed by GitHub
commit cfaa621a05
13 changed files with 240 additions and 120 deletions

View File

@ -36,11 +36,12 @@ var error = sharedUtil.error;
var isInt = sharedUtil.isInt; var isInt = sharedUtil.isInt;
var isString = sharedUtil.isString; var isString = sharedUtil.isString;
var MissingDataException = sharedUtil.MissingDataException; var MissingDataException = sharedUtil.MissingDataException;
var CMapCompressionType = sharedUtil.CMapCompressionType;
var isEOF = corePrimitives.isEOF; var isEOF = corePrimitives.isEOF;
var isName = corePrimitives.isName; var isName = corePrimitives.isName;
var isCmd = corePrimitives.isCmd; var isCmd = corePrimitives.isCmd;
var isStream = corePrimitives.isStream; var isStream = corePrimitives.isStream;
var StringStream = coreStream.StringStream; var Stream = coreStream.Stream;
var Lexer = coreParser.Lexer; var Lexer = coreParser.Lexer;
var BUILT_IN_CMAPS = [ var BUILT_IN_CMAPS = [
@ -423,25 +424,6 @@ var IdentityCMap = (function IdentityCMapClosure() {
})(); })();
var BinaryCMapReader = (function BinaryCMapReaderClosure() { 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) { function hexToInt(a, size) {
var n = 0; var n = 0;
for (var i = 0; i <= size; i++) { for (var i = 0; i <= size; i++) {
@ -561,8 +543,8 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
} }
}; };
function processBinaryCMap(url, cMap, extend) { function processBinaryCMap(data, cMap, extend) {
return fetchBinaryData(url).then(function (data) { return new Promise(function (resolve, reject) {
var stream = new BinaryCMapStream(data); var stream = new BinaryCMapStream(data);
var header = stream.readByte(); var header = stream.readByte();
cMap.vertical = !!(header & 1); cMap.vertical = !!(header & 1);
@ -709,22 +691,23 @@ var BinaryCMapReader = (function BinaryCMapReaderClosure() {
} }
break; break;
default: default:
error('Unknown type: ' + type); reject(new Error('processBinaryCMap: Unknown type: ' + type));
break; return;
} }
} }
if (useCMap) { if (useCMap) {
return extend(useCMap); resolve(extend(useCMap));
return;
} }
return cMap; resolve(cMap);
}); });
} }
function BinaryCMapReader() {} function BinaryCMapReader() {}
BinaryCMapReader.prototype = { BinaryCMapReader.prototype = {
read: processBinaryCMap process: processBinaryCMap,
}; };
return BinaryCMapReader; 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 previous;
var embededUseCMap; var embededUseCMap;
objLoop: while (true) { objLoop: while (true) {
@ -935,14 +918,13 @@ var CMapFactory = (function CMapFactoryClosure() {
useCMap = embededUseCMap; useCMap = embededUseCMap;
} }
if (useCMap) { if (useCMap) {
return extendCMap(cMap, builtInCMapParams, useCMap); return extendCMap(cMap, fetchBuiltInCMap, useCMap);
} }
return Promise.resolve(cMap); return Promise.resolve(cMap);
} }
function extendCMap(cMap, builtInCMapParams, useCMap) { function extendCMap(cMap, fetchBuiltInCMap, useCMap) {
return createBuiltInCMap(useCMap, builtInCMapParams).then( return createBuiltInCMap(useCMap, fetchBuiltInCMap).then(function(newCMap) {
function(newCMap) {
cMap.useCMap = newCMap; cMap.useCMap = newCMap;
// If there aren't any code space ranges defined clone all the parent ones // If there aren't any code space ranges defined clone all the parent ones
// into this cMap. // into this cMap.
@ -965,15 +947,7 @@ var CMapFactory = (function CMapFactoryClosure() {
}); });
} }
function parseBinaryCMap(name, builtInCMapParams) { function createBuiltInCMap(name, fetchBuiltInCMap) {
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) {
if (name === 'Identity-H') { if (name === 'Identity-H') {
return Promise.resolve(new IdentityCMap(false, 2)); return Promise.resolve(new IdentityCMap(false, 2));
} else if (name === 'Identity-V') { } else if (name === 'Identity-V') {
@ -982,45 +956,41 @@ var CMapFactory = (function CMapFactoryClosure() {
if (BUILT_IN_CMAPS.indexOf(name) === -1) { if (BUILT_IN_CMAPS.indexOf(name) === -1) {
return Promise.reject(new Error('Unknown cMap name: ' + name)); 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 fetchBuiltInCMap(name).then(function (data) {
return parseBinaryCMap(name, builtInCMapParams); var cMapData = data.cMapData, compressionType = data.compressionType;
}
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 cMap = new CMap(true);
var lexer = new Lexer(new StringStream(request.responseText));
parseCMap(cMap, lexer, builtInCMapParams, null).then( if (compressionType === CMapCompressionType.BINARY) {
function (parsedCMap) { return new BinaryCMapReader().process(cMapData, cMap,
resolve(parsedCMap); function (useCMap) {
return extendCMap(cMap, fetchBuiltInCMap, useCMap);
}); });
} else {
reject(new Error('Unable to get cMap at: ' + url));
} }
} assert(compressionType === CMapCompressionType.NONE,
}; 'TODO: Only BINARY/NONE CMap compression is currently supported.');
request.open('GET', url, true); // Uncompressed CMap.
request.send(null); var lexer = new Lexer(new Stream(cMapData));
return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
}); });
} }
return { return {
create: function (encoding, builtInCMapParams, useCMap) { create: function (params) {
var encoding = params.encoding;
var fetchBuiltInCMap = params.fetchBuiltInCMap;
var useCMap = params.useCMap;
if (isName(encoding)) { if (isName(encoding)) {
return createBuiltInCMap(encoding.name, builtInCMapParams); return createBuiltInCMap(encoding.name, fetchBuiltInCMap);
} else if (isStream(encoding)) { } else if (isStream(encoding)) {
var cMap = new CMap(); var cMap = new CMap();
var lexer = new Lexer(encoding); var lexer = new Lexer(encoding);
return parseCMap(cMap, lexer, builtInCMapParams, useCMap).then( return parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap).then(
function (parsedCMap) { function (parsedCMap) {
if (parsedCMap.isIdentityCMap) { if (parsedCMap.isIdentityCMap) {
return createBuiltInCMap(parsedCMap.name, builtInCMapParams); return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap);
} }
return parsedCMap; return parsedCMap;
}); });

View File

@ -71,13 +71,15 @@ var Page = (function PageClosure() {
var DEFAULT_USER_UNIT = 1.0; var DEFAULT_USER_UNIT = 1.0;
var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792]; 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.pdfManager = pdfManager;
this.pageIndex = pageIndex; this.pageIndex = pageIndex;
this.pageDict = pageDict; this.pageDict = pageDict;
this.xref = xref; this.xref = xref;
this.ref = ref; this.ref = ref;
this.fontCache = fontCache; this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.evaluatorOptions = pdfManager.evaluatorOptions; this.evaluatorOptions = pdfManager.evaluatorOptions;
this.resourcesPromise = null; this.resourcesPromise = null;
@ -248,6 +250,7 @@ var Page = (function PageClosure() {
handler, this.pageIndex, handler, this.pageIndex,
this.idFactory, this.idFactory,
this.fontCache, this.fontCache,
this.builtInCMapCache,
this.evaluatorOptions); this.evaluatorOptions);
var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]); var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
@ -315,6 +318,7 @@ var Page = (function PageClosure() {
handler, self.pageIndex, handler, self.pageIndex,
self.idFactory, self.idFactory,
self.fontCache, self.fontCache,
self.builtInCMapCache,
self.evaluatorOptions); self.evaluatorOptions);
return partialEvaluator.getTextContent(contentStream, return partialEvaluator.getTextContent(contentStream,
@ -551,9 +555,10 @@ var PDFDocument = (function PDFDocumentClosure() {
this.xref.parse(recoveryMode); this.xref.parse(recoveryMode);
var self = this; var self = this;
var pageFactory = { 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, return new Page(self.pdfManager, self.xref, pageIndex, dict, ref,
fontCache); fontCache, builtInCMapCache);
} }
}; };
this.catalog = new Catalog(this.pdfManager, this.xref, pageFactory); this.catalog = new Catalog(this.pdfManager, this.xref, pageFactory);

View File

@ -53,6 +53,7 @@ var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES;
var ImageKind = sharedUtil.ImageKind; var ImageKind = sharedUtil.ImageKind;
var OPS = sharedUtil.OPS; var OPS = sharedUtil.OPS;
var TextRenderingMode = sharedUtil.TextRenderingMode; var TextRenderingMode = sharedUtil.TextRenderingMode;
var CMapCompressionType = sharedUtil.CMapCompressionType;
var Util = sharedUtil.Util; var Util = sharedUtil.Util;
var assert = sharedUtil.assert; var assert = sharedUtil.assert;
var createPromiseCapability = sharedUtil.createPromiseCapability; var createPromiseCapability = sharedUtil.createPromiseCapability;
@ -112,7 +113,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
forceDataSchema: false, forceDataSchema: false,
maxImageSize: -1, maxImageSize: -1,
disableFontFace: false, disableFontFace: false,
cMapOptions: { url: null, packed: false },
disableNativeImageDecoder: false, disableNativeImageDecoder: false,
}; };
@ -170,14 +170,31 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}; };
function PartialEvaluator(pdfManager, xref, handler, pageIndex, function PartialEvaluator(pdfManager, xref, handler, pageIndex,
idFactory, fontCache, options) { idFactory, fontCache, builtInCMapCache, options) {
this.pdfManager = pdfManager; this.pdfManager = pdfManager;
this.xref = xref; this.xref = xref;
this.handler = handler; this.handler = handler;
this.pageIndex = pageIndex; this.pageIndex = pageIndex;
this.idFactory = idFactory; this.idFactory = idFactory;
this.fontCache = fontCache; this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.options = options || DefaultPartialEvaluatorOptions; 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 // Trying to minimize Date.now() usage and check every 100 time
@ -1879,9 +1896,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var ucs2CMapName = Name.get(registry + '-' + ordering + '-UCS2'); var ucs2CMapName = Name.get(registry + '-' + ordering + '-UCS2');
// d) Obtain the CMap with the name constructed in step (c) (available // d) Obtain the CMap with the name constructed in step (c) (available
// from the ASN Web site; see the Bibliography). // from the ASN Web site; see the Bibliography).
return CMapFactory.create(ucs2CMapName, this.options.cMapOptions, return CMapFactory.create({
null).then( encoding: ucs2CMapName,
function (ucs2CMap) { fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (ucs2CMap) {
var cMap = properties.cMap; var cMap = properties.cMap;
toUnicode = []; toUnicode = [];
cMap.forEach(function(charcode, cid) { cMap.forEach(function(charcode, cid) {
@ -1907,16 +1926,22 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) { readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
var cmapObj = toUnicode; var cmapObj = toUnicode;
if (isName(cmapObj)) { if (isName(cmapObj)) {
return CMapFactory.create(cmapObj, this.options.cMapOptions, null).then( return CMapFactory.create({
function (cmap) { encoding: cmapObj,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (cmap) {
if (cmap instanceof IdentityCMap) { if (cmap instanceof IdentityCMap) {
return new IdentityToUnicodeMap(0, 0xFFFF); return new IdentityToUnicodeMap(0, 0xFFFF);
} }
return new ToUnicodeMap(cmap.getMap()); return new ToUnicodeMap(cmap.getMap());
}); });
} else if (isStream(cmapObj)) { } else if (isStream(cmapObj)) {
return CMapFactory.create(cmapObj, this.options.cMapOptions, null).then( return CMapFactory.create({
function (cmap) { encoding: cmapObj,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (cmap) {
if (cmap instanceof IdentityCMap) { if (cmap instanceof IdentityCMap) {
return new IdentityToUnicodeMap(0, 0xFFFF); return new IdentityToUnicodeMap(0, 0xFFFF);
} }
@ -2222,7 +2247,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var descriptor = preEvaluatedFont.descriptor; var descriptor = preEvaluatedFont.descriptor;
var type = preEvaluatedFont.type; var type = preEvaluatedFont.type;
var maxCharIndex = (composite ? 0xFFFF : 0xFF); var maxCharIndex = (composite ? 0xFFFF : 0xFF);
var cMapOptions = this.options.cMapOptions;
var properties; var properties;
if (!descriptor) { if (!descriptor) {
@ -2352,8 +2376,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (isName(cidEncoding)) { if (isName(cidEncoding)) {
properties.cidEncoding = cidEncoding.name; properties.cidEncoding = cidEncoding.name;
} }
cMapPromise = CMapFactory.create(cidEncoding, cMapOptions, null).then( cMapPromise = CMapFactory.create({
function (cMap) { encoding: cidEncoding,
fetchBuiltInCMap: this.fetchBuiltInCMap,
useCMap: null,
}).then(function (cMap) {
properties.cMap = cMap; properties.cMap = cMap;
properties.vertical = properties.cMap.vertical; properties.vertical = properties.cMap.vertical;
}); });

View File

@ -71,8 +71,8 @@ var Catalog = (function CatalogClosure() {
this.xref = xref; this.xref = xref;
this.catDict = xref.getCatalogObj(); this.catDict = xref.getCatalogObj();
this.fontCache = new RefSetCache(); this.fontCache = new RefSetCache();
assert(isDict(this.catDict), this.builtInCMapCache = Object.create(null);
'catalog object is not a dictionary'); assert(isDict(this.catDict), 'catalog object is not a dictionary');
// TODO refactor to move getPage() to the PDFDocument. // TODO refactor to move getPage() to the PDFDocument.
this.pageFactory = pageFactory; this.pageFactory = pageFactory;
@ -428,6 +428,7 @@ var Catalog = (function CatalogClosure() {
delete font.translated; delete font.translated;
} }
this.fontCache.clear(); this.fontCache.clear();
this.builtInCMapCache = Object.create(null);
}.bind(this)); }.bind(this));
}, },
@ -438,7 +439,8 @@ var Catalog = (function CatalogClosure() {
var dict = a[0]; var dict = a[0];
var ref = a[1]; var ref = a[1];
return this.pageFactory.createPage(pageIndex, dict, ref, return this.pageFactory.createPage(pageIndex, dict, ref,
this.fontCache); this.fontCache,
this.builtInCMapCache);
}.bind(this) }.bind(this)
); );
} }

View File

@ -729,15 +729,10 @@ var WorkerMessageHandler = {
ensureNotTerminated(); ensureNotTerminated();
var cMapOptions = {
url: data.cMapUrl === undefined ? null : data.cMapUrl,
packed: data.cMapPacked === true
};
var evaluatorOptions = { var evaluatorOptions = {
forceDataSchema: data.disableCreateObjectURL, forceDataSchema: data.disableCreateObjectURL,
maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize, maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize,
disableFontFace: data.disableFontFace, disableFontFace: data.disableFontFace,
cMapOptions: cMapOptions,
disableNativeImageDecoder: data.disableNativeImageDecoder, disableNativeImageDecoder: data.disableNativeImageDecoder,
}; };

View File

@ -62,6 +62,7 @@ var CanvasGraphics = displayCanvas.CanvasGraphics;
var Metadata = displayMetadata.Metadata; var Metadata = displayMetadata.Metadata;
var getDefaultSetting = displayDOMUtils.getDefaultSetting; var getDefaultSetting = displayDOMUtils.getDefaultSetting;
var DOMCanvasFactory = displayDOMUtils.DOMCanvasFactory; var DOMCanvasFactory = displayDOMUtils.DOMCanvasFactory;
var DOMCMapReaderFactory = displayDOMUtils.DOMCMapReaderFactory;
var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536 var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
@ -142,6 +143,10 @@ if (typeof PDFJSDev !== 'undefined' &&
* of certain (simple) JPEG images in the browser. This is useful for * of certain (simple) JPEG images in the browser. This is useful for
* environments without DOM image support, such as e.g. Node.js. * environments without DOM image support, such as e.g. Node.js.
* The default value is `false`. * The default value is `false`.
* @property {Object} CMapReaderFactory - (optional) The factory that will be
* used when reading built-in CMap files. Providing a custom factory is useful
* for environments without `XMLHttpRequest` support, such as e.g. Node.js.
* The default value is {DOMCMapReaderFactory}.
*/ */
/** /**
@ -256,6 +261,7 @@ function getDocument(src, pdfDataRangeTransport,
params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
params.disableNativeImageDecoder = params.disableNativeImageDecoder === true; params.disableNativeImageDecoder = params.disableNativeImageDecoder === true;
var CMapReaderFactory = params.CMapReaderFactory || DOMCMapReaderFactory;
if (!worker) { if (!worker) {
// Worker was not provided -- creating and owning our own. // Worker was not provided -- creating and owning our own.
@ -273,7 +279,8 @@ function getDocument(src, pdfDataRangeTransport,
throw new Error('Loading aborted'); throw new Error('Loading aborted');
} }
var messageHandler = new MessageHandler(docId, workerId, worker.port); var messageHandler = new MessageHandler(docId, workerId, worker.port);
var transport = new WorkerTransport(messageHandler, task, rangeTransport); var transport = new WorkerTransport(messageHandler, task, rangeTransport,
CMapReaderFactory);
task._transport = transport; task._transport = transport;
messageHandler.send('Ready', null); messageHandler.send('Ready', null);
}); });
@ -309,8 +316,6 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
source: source, source: source,
disableRange: getDefaultSetting('disableRange'), disableRange: getDefaultSetting('disableRange'),
maxImageSize: getDefaultSetting('maxImageSize'), maxImageSize: getDefaultSetting('maxImageSize'),
cMapUrl: getDefaultSetting('cMapUrl'),
cMapPacked: getDefaultSetting('cMapPacked'),
disableFontFace: getDefaultSetting('disableFontFace'), disableFontFace: getDefaultSetting('disableFontFace'),
disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'), disableCreateObjectURL: getDefaultSetting('disableCreateObjectURL'),
postMessageTransfers: getDefaultSetting('postMessageTransfers') && postMessageTransfers: getDefaultSetting('postMessageTransfers') &&
@ -1429,12 +1434,17 @@ var PDFWorker = (function PDFWorkerClosure() {
* @ignore * @ignore
*/ */
var WorkerTransport = (function WorkerTransportClosure() { var WorkerTransport = (function WorkerTransportClosure() {
function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport) { function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport,
CMapReaderFactory) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
this.loadingTask = loadingTask; this.loadingTask = loadingTask;
this.pdfDataRangeTransport = pdfDataRangeTransport; this.pdfDataRangeTransport = pdfDataRangeTransport;
this.commonObjs = new PDFObjects(); this.commonObjs = new PDFObjects();
this.fontLoader = new FontLoader(loadingTask.docId); this.fontLoader = new FontLoader(loadingTask.docId);
this.CMapReaderFactory = new CMapReaderFactory({
baseUrl: getDefaultSetting('cMapUrl'),
isCompressed: getDefaultSetting('cMapPacked'),
});
this.destroyed = false; this.destroyed = false;
this.destroyCapability = null; this.destroyCapability = null;
@ -1794,6 +1804,15 @@ var WorkerTransport = (function WorkerTransportClosure() {
img.src = imageUrl; img.src = imageUrl;
}); });
}, this); }, this);
messageHandler.on('FetchBuiltInCMap', function (data) {
if (this.destroyed) {
return Promise.reject(new Error('Worker was destroyed'));
}
return this.CMapReaderFactory.fetch({
name: data.name,
});
}, this);
}, },
getData: function WorkerTransport_getData() { getData: function WorkerTransport_getData() {

View File

@ -31,6 +31,8 @@ var removeNullCharacters = sharedUtil.removeNullCharacters;
var warn = sharedUtil.warn; var warn = sharedUtil.warn;
var deprecated = sharedUtil.deprecated; var deprecated = sharedUtil.deprecated;
var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl;
var stringToBytes = sharedUtil.stringToBytes;
var CMapCompressionType = sharedUtil.CMapCompressionType;
var DEFAULT_LINK_REL = 'noopener noreferrer nofollow'; var DEFAULT_LINK_REL = 'noopener noreferrer nofollow';
@ -66,6 +68,57 @@ DOMCanvasFactory.prototype = {
} }
}; };
var DOMCMapReaderFactory = (function DOMCMapReaderFactoryClosure() {
function DOMCMapReaderFactory(params) {
this.baseUrl = params.baseUrl || null;
this.isCompressed = params.isCompressed || false;
}
DOMCMapReaderFactory.prototype = {
fetch: function(params) {
if (!params.name) {
return Promise.reject(new Error('CMap name must be specified.'));
}
return new Promise(function (resolve, reject) {
var url = this.baseUrl + params.name;
var request = new XMLHttpRequest();
if (this.isCompressed) {
url += '.bcmap';
request.responseType = 'arraybuffer';
}
request.onreadystatechange = function () {
if (request.readyState === XMLHttpRequest.DONE &&
(request.status === 200 || request.status === 0)) {
var data;
if (this.isCompressed && request.response) {
data = new Uint8Array(request.response);
} else if (!this.isCompressed && request.responseText) {
data = stringToBytes(request.responseText);
}
if (data) {
resolve({
cMapData: data,
compressionType: this.isCompressed ?
CMapCompressionType.BINARY : CMapCompressionType.NONE,
});
return;
}
reject(new Error('Unable to load ' +
(this.isCompressed ? 'binary' : '') +
' CMap at: ' + url));
}
}.bind(this);
request.open('GET', url, true);
request.send(null);
}.bind(this));
},
};
return DOMCMapReaderFactory;
})();
/** /**
* Optimised CSS custom property getter/setter. * Optimised CSS custom property getter/setter.
* @class * @class
@ -284,4 +337,5 @@ exports.hasCanvasTypedArrays = hasCanvasTypedArrays;
exports.getDefaultSetting = getDefaultSetting; exports.getDefaultSetting = getDefaultSetting;
exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL; exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL;
exports.DOMCanvasFactory = DOMCanvasFactory; exports.DOMCanvasFactory = DOMCanvasFactory;
exports.DOMCMapReaderFactory = DOMCMapReaderFactory;
})); }));

View File

@ -156,6 +156,12 @@ var VERBOSITY_LEVELS = {
infos: 5 infos: 5
}; };
var CMapCompressionType = {
NONE: 0,
BINARY: 1,
STREAM: 2,
};
// All the possible operations for an operator list. // All the possible operations for an operator list.
var OPS = { var OPS = {
// Intentionally start from 1 so it is easy to spot bad operators that will be // Intentionally start from 1 so it is easy to spot bad operators that will be
@ -2411,6 +2417,7 @@ exports.AnnotationFlag = AnnotationFlag;
exports.AnnotationType = AnnotationType; exports.AnnotationType = AnnotationType;
exports.FontType = FontType; exports.FontType = FontType;
exports.ImageKind = ImageKind; exports.ImageKind = ImageKind;
exports.CMapCompressionType = CMapCompressionType;
exports.InvalidPDFException = InvalidPDFException; exports.InvalidPDFException = InvalidPDFException;
exports.MessageHandler = MessageHandler; exports.MessageHandler = MessageHandler;
exports.MissingDataException = MissingDataException; exports.MissingDataException = MissingDataException;

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,9 @@ describe('font_post', function() {
}); });
it('has invalid selection attributes presence', function(done) { it('has invalid selection attributes presence', function(done) {
CMapFactory.create(new Name('Identity-H')).then(function (cMap) { CMapFactory.create({
encoding: Name.get('Identity-H'),
}).then(function (cMap) {
var font = new Font("font", new Stream(font1282), { var font = new Font("font", new Stream(font1282), {
loadedName: 'font', loadedName: 'font',
type: 'CIDFontType2', type: 'CIDFontType2',

File diff suppressed because one or more lines are too long

View File

@ -17,34 +17,58 @@
(function (root, factory) { (function (root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define('pdfjs-test/unit/cmap_spec', ['exports', 'pdfjs/core/cmap', define('pdfjs-test/unit/cmap_spec', ['exports', 'pdfjs/core/cmap',
'pdfjs/core/primitives', 'pdfjs/core/stream'], factory); 'pdfjs/core/primitives', 'pdfjs/core/stream', 'pdfjs/display/dom_utils'],
factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('../../src/core/cmap.js'), factory(exports, require('../../src/core/cmap.js'),
require('../../src/core/primitives.js'), require('../../src/core/primitives.js'),
require('../../src/core/stream.js')); require('../../src/core/stream.js'),
require('../../src/display/dom_utils.js'));
} else { } else {
factory((root.pdfjsTestUnitCMapSpec = {}), root.pdfjsCoreCMap, factory((root.pdfjsTestUnitCMapSpec = {}), root.pdfjsCoreCMap,
root.pdfjsCorePrimitives, root.pdfjsCoreStream); root.pdfjsCorePrimitives, root.pdfjsCoreStream,
root.pdfjsDisplayDOMUtils);
} }
}(this, function (exports, coreCMap, corePrimitives, coreStream) { }(this, function (exports, coreCMap, corePrimitives, coreStream,
displayDOMUtils) {
var CMapFactory = coreCMap.CMapFactory; var CMapFactory = coreCMap.CMapFactory;
var CMap = coreCMap.CMap; var CMap = coreCMap.CMap;
var IdentityCMap = coreCMap.IdentityCMap; var IdentityCMap = coreCMap.IdentityCMap;
var Name = corePrimitives.Name; var Name = corePrimitives.Name;
var StringStream = coreStream.StringStream; var StringStream = coreStream.StringStream;
var DOMCMapReaderFactory = displayDOMUtils.DOMCMapReaderFactory;
var cMapUrl = '../../external/bcmaps/'; var cMapUrl = '../../external/bcmaps/';
var cMapPacked = true; var cMapPacked = true;
describe('cmap', function() { describe('cmap', function() {
var fetchBuiltInCMap;
beforeAll(function (done) {
var CMapReaderFactory = new DOMCMapReaderFactory({
baseUrl: cMapUrl,
isCompressed: cMapPacked,
});
fetchBuiltInCMap = function (name) {
return CMapReaderFactory.fetch({
name: name,
});
};
done();
});
afterAll(function () {
fetchBuiltInCMap = null;
});
it('parses beginbfchar', function(done) { it('parses beginbfchar', function(done) {
var str = '2 beginbfchar\n' + var str = '2 beginbfchar\n' +
'<03> <00>\n' + '<03> <00>\n' +
'<04> <01>\n' + '<04> <01>\n' +
'endbfchar\n'; 'endbfchar\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.lookup(0x03)).toEqual(String.fromCharCode(0x00)); expect(cmap.lookup(0x03)).toEqual(String.fromCharCode(0x00));
expect(cmap.lookup(0x04)).toEqual(String.fromCharCode(0x01)); expect(cmap.lookup(0x04)).toEqual(String.fromCharCode(0x01));
@ -59,7 +83,7 @@ describe('cmap', function() {
'<06> <0B> 0\n' + '<06> <0B> 0\n' +
'endbfrange\n'; 'endbfrange\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.lookup(0x05)).toBeUndefined(); expect(cmap.lookup(0x05)).toBeUndefined();
expect(cmap.lookup(0x06)).toEqual(String.fromCharCode(0x00)); expect(cmap.lookup(0x06)).toEqual(String.fromCharCode(0x00));
@ -75,7 +99,7 @@ describe('cmap', function() {
'<0D> <12> [ 0 1 2 3 4 5 ]\n' + '<0D> <12> [ 0 1 2 3 4 5 ]\n' +
'endbfrange\n'; 'endbfrange\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.lookup(0x0C)).toBeUndefined(); expect(cmap.lookup(0x0C)).toBeUndefined();
expect(cmap.lookup(0x0D)).toEqual(0x00); expect(cmap.lookup(0x0D)).toEqual(0x00);
@ -91,7 +115,7 @@ describe('cmap', function() {
'<14> 0\n' + '<14> 0\n' +
'endcidchar\n'; 'endcidchar\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.lookup(0x14)).toEqual(0x00); expect(cmap.lookup(0x14)).toEqual(0x00);
expect(cmap.lookup(0x15)).toBeUndefined(); expect(cmap.lookup(0x15)).toBeUndefined();
@ -105,7 +129,7 @@ describe('cmap', function() {
'<0016> <001B> 0\n' + '<0016> <001B> 0\n' +
'endcidrange\n'; 'endcidrange\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.lookup(0x15)).toBeUndefined(); expect(cmap.lookup(0x15)).toBeUndefined();
expect(cmap.lookup(0x16)).toEqual(0x00); expect(cmap.lookup(0x16)).toEqual(0x00);
@ -122,7 +146,7 @@ describe('cmap', function() {
'<00000003> <00000004>\n' + '<00000003> <00000004>\n' +
'endcodespacerange\n'; 'endcodespacerange\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
var c = {}; var c = {};
cmap.readCharCode(String.fromCharCode(1), 0, c); cmap.readCharCode(String.fromCharCode(1), 0, c);
@ -141,7 +165,7 @@ describe('cmap', function() {
'<8EA1A1A1> <8EA1FEFE>\n' + '<8EA1A1A1> <8EA1FEFE>\n' +
'endcodespacerange\n'; 'endcodespacerange\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
var c = {}; var c = {};
cmap.readCharCode(String.fromCharCode(0x8E, 0xA1, 0xA1, 0xA1), 0, c); cmap.readCharCode(String.fromCharCode(0x8E, 0xA1, 0xA1, 0xA1), 0, c);
@ -155,8 +179,11 @@ describe('cmap', function() {
it('read usecmap', function(done) { it('read usecmap', function(done) {
var str = '/Adobe-Japan1-1 usecmap\n'; var str = '/Adobe-Japan1-1 usecmap\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream, var cmapPromise = CMapFactory.create({
{ url: cMapUrl, packed: cMapPacked }, null); encoding: stream,
fetchBuiltInCMap: fetchBuiltInCMap,
useCMap: null,
});
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap instanceof CMap).toEqual(true); expect(cmap instanceof CMap).toEqual(true);
expect(cmap.useCMap).not.toBeNull(); expect(cmap.useCMap).not.toBeNull();
@ -171,7 +198,7 @@ describe('cmap', function() {
it('parses cmapname', function(done) { it('parses cmapname', function(done) {
var str = '/CMapName /Identity-H def\n'; var str = '/CMapName /Identity-H def\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.name).toEqual('Identity-H'); expect(cmap.name).toEqual('Identity-H');
done(); done();
@ -182,7 +209,7 @@ describe('cmap', function() {
it('parses wmode', function(done) { it('parses wmode', function(done) {
var str = '/WMode 1 def\n'; var str = '/WMode 1 def\n';
var stream = new StringStream(str); var stream = new StringStream(str);
var cmapPromise = CMapFactory.create(stream); var cmapPromise = CMapFactory.create({ encoding: stream, });
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap.vertical).toEqual(true); expect(cmap.vertical).toEqual(true);
done(); done();
@ -191,8 +218,11 @@ describe('cmap', function() {
}); });
}); });
it('loads built in cmap', function(done) { it('loads built in cmap', function(done) {
var cmapPromise = CMapFactory.create(Name.get('Adobe-Japan1-1'), var cmapPromise = CMapFactory.create({
{ url: cMapUrl, packed: cMapPacked }, null); encoding: Name.get('Adobe-Japan1-1'),
fetchBuiltInCMap: fetchBuiltInCMap,
useCMap: null,
});
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap instanceof CMap).toEqual(true); expect(cmap instanceof CMap).toEqual(true);
expect(cmap.useCMap).toBeNull(); expect(cmap.useCMap).toBeNull();
@ -205,8 +235,11 @@ describe('cmap', function() {
}); });
}); });
it('loads built in identity cmap', function(done) { it('loads built in identity cmap', function(done) {
var cmapPromise = CMapFactory.create(Name.get('Identity-H'), var cmapPromise = CMapFactory.create({
{ url: cMapUrl, packed: cMapPacked }, null); encoding: Name.get('Identity-H'),
fetchBuiltInCMap: fetchBuiltInCMap,
useCMap: null,
});
cmapPromise.then(function (cmap) { cmapPromise.then(function (cmap) {
expect(cmap instanceof IdentityCMap).toEqual(true); expect(cmap instanceof IdentityCMap).toEqual(true);
expect(cmap.vertical).toEqual(false); expect(cmap.vertical).toEqual(false);

View File

@ -34,11 +34,13 @@ describe('document', function () {
var page1 = new Page(/* pdfManager = */ { }, /* xref = */ null, var page1 = new Page(/* pdfManager = */ { }, /* xref = */ null,
/* pageIndex = */ 0, /* pageIndex = */ 0,
/* pageDict = */ null, /* ref = */ null, /* pageDict = */ null, /* ref = */ null,
/* fontCache = */ null); /* fontCache = */ null,
/* builtInCMapCache = */ null);
var page2 = new Page(/* pdfManager = */ { }, /* xref = */ null, var page2 = new Page(/* pdfManager = */ { }, /* xref = */ null,
/* pageIndex = */ 1, /* pageIndex = */ 1,
/* pageDict = */ null, /* ref = */ null, /* pageDict = */ null, /* ref = */ null,
/* fontCache = */ null); /* fontCache = */ null,
/* builtInCMapCache = */ null);
var idFactory1 = page1.idFactory, idFactory2 = page2.idFactory; var idFactory1 = page1.idFactory, idFactory2 = page2.idFactory;