diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 1b1dc1b73..243c225ba 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -96,8 +96,9 @@ const DefaultPartialEvaluatorOptions = Object.freeze({ ignoreErrors: false, isEvalSupported: true, fontExtraProperties: false, - standardFontDataUrl: null, useSystemFonts: true, + cMapUrl: null, + standardFontDataUrl: null, }); const PatternType = { @@ -360,23 +361,25 @@ class PartialEvaluator { if (cachedData) { return cachedData; } - const readableStream = this.handler.sendWithStream("FetchBuiltInCMap", { - name, - }); - const reader = readableStream.getReader(); + let data; - const data = await new Promise(function (resolve, reject) { - function pump() { - reader.read().then(function ({ value, done }) { - if (done) { - return; - } - resolve(value); - pump(); - }, reject); + if (this.options.cMapUrl !== null) { + // Only compressed CMaps are (currently) supported here. + const url = `${this.options.cMapUrl}${name}.bcmap`; + const response = await fetch(url); + if (!response.ok) { + throw new Error( + `fetchBuiltInCMap: failed to fetch file "${url}" with "${response.statusText}".` + ); } - pump(); - }); + data = { + cMapData: new Uint8Array(await response.arrayBuffer()), + compressionType: CMapCompressionType.BINARY, + }; + } else { + // Get the data on the main-thread instead. + data = await this.handler.sendWithPromise("FetchBuiltInCMap", { name }); + } if (data.compressionType !== CMapCompressionType.NONE) { // Given the size of uncompressed CMaps, only cache compressed ones. diff --git a/src/core/worker.js b/src/core/worker.js index a69b76743..2ce3ef206 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -412,6 +412,7 @@ class WorkerMessageHandler { isEvalSupported: data.isEvalSupported, fontExtraProperties: data.fontExtraProperties, useSystemFonts: data.useSystemFonts, + cMapUrl: data.cMapUrl, standardFontDataUrl: data.standardFontDataUrl, }; diff --git a/src/display/api.js b/src/display/api.js index c319802ad..056e343cc 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -152,19 +152,19 @@ function setPDFNetworkStreamFactory(pdfNetworkStreamFactory) { * reading built-in CMap files. Providing a custom factory is useful for * environments without Fetch API or `XMLHttpRequest` support, such as * Node.js. The default value is {DOMCMapReaderFactory}. - * @property {boolean} [useSystemFonts] - When true, fonts that aren't embedded - * in the PDF will fallback to a system font. Defaults to true for web - * environments and false for node. + * @property {boolean} [useSystemFonts] - When `true`, fonts that aren't + * embedded in the PDF document will fallback to a system font. + * The default value is `true` in web environments and `false` in Node.js. * @property {string} [standardFontDataUrl] - The URL where the standard font * files are located. Include the trailing slash. - * @property {boolean} [useWorkerFetch] - Enable using fetch in the worker for - * resources. This currently only used for fetching the font data from the - * worker thread. When `true`, StandardFontDataFactory will be ignored. The - * default value is `true` in web environment and `false` for Node. * @property {Object} [StandardFontDataFactory] - The factory that will be used * when reading the standard font files. Providing a custom factory is useful * for environments without Fetch API or `XMLHttpRequest` support, such as * Node.js. The default value is {DOMStandardFontDataFactory}. + * @property {boolean} [useWorkerFetch] - Enable using the Fetch API in the + * worker-thread when reading CMap and standard font files. When `true`, + * the `CMapReaderFactory` and `StandardFontDataFactory` options are ignored. + * The default value is `true` in web wenvironments and `false` in Node.js. * @property {boolean} [stopAtErrors] - Reject certain promises, e.g. * `getOperatorList`, `getTextContent`, and `RenderTask`, when the associated * PDF data cannot be successfully parsed, instead of attempting to recover @@ -333,6 +333,7 @@ function getDocument(src) { } if (typeof params.useWorkerFetch !== "boolean") { params.useWorkerFetch = + params.CMapReaderFactory === DOMCMapReaderFactory && params.StandardFontDataFactory === DOMStandardFontDataFactory; } if (typeof params.isEvalSupported !== "boolean") { @@ -487,6 +488,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { fontExtraProperties: source.fontExtraProperties, enableXfa: source.enableXfa, useSystemFonts: source.useSystemFonts, + cMapUrl: source.useWorkerFetch ? source.cMapUrl : null, standardFontDataUrl: source.useWorkerFetch ? source.standardFontDataUrl : null, @@ -2680,36 +2682,19 @@ class WorkerTransport { this._onUnsupportedFeature.bind(this) ); + messageHandler.on("FetchBuiltInCMap", data => { + if (this.destroyed) { + return Promise.reject(new Error("Worker was destroyed")); + } + return this.CMapReaderFactory.fetch(data); + }); + messageHandler.on("FetchStandardFontData", data => { if (this.destroyed) { return Promise.reject(new Error("Worker was destroyed")); } return this.StandardFontDataFactory.fetch(data); }); - - messageHandler.on("FetchBuiltInCMap", (data, sink) => { - if (this.destroyed) { - sink.error(new Error("Worker was destroyed")); - return; - } - let fetched = false; - - sink.onPull = () => { - if (fetched) { - sink.close(); - return; - } - fetched = true; - - this.CMapReaderFactory.fetch(data) - .then(function (builtInCMap) { - sink.enqueue(builtInCMap, 1, [builtInCMap.cMapData.buffer]); - }) - .catch(function (reason) { - sink.error(reason); - }); - }; - }); } _onUnsupportedFeature({ featureId }) { diff --git a/test/driver.js b/test/driver.js index 70eacaab9..f4c7bde42 100644 --- a/test/driver.js +++ b/test/driver.js @@ -19,7 +19,7 @@ const WAITING_TIME = 100; // ms const PDF_TO_CSS_UNITS = 96.0 / 72.0; -const CMAP_URL = "../external/bcmaps/"; +const CMAP_URL = "/build/generic/web/cmaps/"; const CMAP_PACKED = true; const STANDARD_FONT_DATA_URL = "/build/generic/web/standard_fonts/"; const IMAGE_RESOURCES_PATH = "/web/images/"; diff --git a/test/test_manifest.json b/test/test_manifest.json index b84fbd7ac..4eb7c0cbf 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -4046,6 +4046,15 @@ "lastPage": 1, "type": "eq" }, + { "id": "mao-main_thread_fetch", + "file": "pdfs/mao.pdf", + "md5": "797093d67c4d4d4231ac6e1fb66bf6c3", + "rounds": 1, + "link": true, + "lastPage": 1, + "type": "eq", + "useWorkerFetch": false + }, { "id": "mao-text", "file": "pdfs/mao.pdf", "md5": "797093d67c4d4d4231ac6e1fb66bf6c3",