From df696063b95ef45ec9cfca077787f91c04ea8c4e Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 20 Oct 2024 17:54:04 +0200 Subject: [PATCH 1/2] Change the `BaseCMapReaderFactory` fetch-helper to return a `Uint8Array` This moves more functionality into the base-class, rather than having to duplicate that in the extending classes. For consistency, also updates the `BaseStandardFontDataFactory` and introduces more `async`/`await` in various relevant code. --- src/display/base_factory.js | 32 +++++++++++++++++++------------- src/display/display_utils.js | 22 +++++++++------------- src/display/node_utils.js | 13 +++++++------ 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/display/base_factory.js b/src/display/base_factory.js index e6773daa90553..2cf132129eaef 100644 --- a/src/display/base_factory.js +++ b/src/display/base_factory.js @@ -127,22 +127,27 @@ class BaseCMapReaderFactory { throw new Error("CMap name must be specified."); } const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : ""); - const compressionType = this.isCompressed - ? CMapCompressionType.BINARY - : CMapCompressionType.NONE; - return this._fetchData(url, compressionType).catch(reason => { - throw new Error( - `Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}` - ); - }); + return this._fetch(url) + .then(cMapData => ({ + cMapData, + compressionType: this.isCompressed + ? CMapCompressionType.BINARY + : CMapCompressionType.NONE, + })) + .catch(reason => { + throw new Error( + `Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}` + ); + }); } /** * @ignore + * @returns {Promise} */ - _fetchData(url, compressionType) { - unreachable("Abstract method `_fetchData` called."); + async _fetch(url) { + unreachable("Abstract method `_fetch` called."); } } @@ -168,16 +173,17 @@ class BaseStandardFontDataFactory { } const url = `${this.baseUrl}${filename}`; - return this._fetchData(url).catch(reason => { + return this._fetch(url).catch(reason => { throw new Error(`Unable to load font data at: ${url}`); }); } /** * @ignore + * @returns {Promise} */ - _fetchData(url) { - unreachable("Abstract method `_fetchData` called."); + async _fetch(url) { + unreachable("Abstract method `_fetch` called."); } } diff --git a/src/display/display_utils.js b/src/display/display_utils.js index 93189f4c9de85..60b4587ebacf1 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -564,17 +564,14 @@ class DOMCMapReaderFactory extends BaseCMapReaderFactory { /** * @ignore */ - _fetchData(url, compressionType) { - return fetchData( + async _fetch(url) { + const data = await fetchData( url, /* type = */ this.isCompressed ? "arraybuffer" : "text" - ).then(data => ({ - cMapData: - data instanceof ArrayBuffer - ? new Uint8Array(data) - : stringToBytes(data), - compressionType, - })); + ); + return data instanceof ArrayBuffer + ? new Uint8Array(data) + : stringToBytes(data); } } @@ -582,10 +579,9 @@ class DOMStandardFontDataFactory extends BaseStandardFontDataFactory { /** * @ignore */ - _fetchData(url) { - return fetchData(url, /* type = */ "arraybuffer").then( - data => new Uint8Array(data) - ); + async _fetch(url) { + const data = await fetchData(url, /* type = */ "arraybuffer"); + return new Uint8Array(data); } } diff --git a/src/display/node_utils.js b/src/display/node_utils.js index 6c7c48cb87355..0dcffdb2c878a 100644 --- a/src/display/node_utils.js +++ b/src/display/node_utils.js @@ -113,10 +113,11 @@ class NodePackages { } } -const fetchData = function (url) { +async function fetchData(url) { const fs = NodePackages.get("fs"); - return fs.promises.readFile(url).then(data => new Uint8Array(data)); -}; + const data = await fs.promises.readFile(url); + return new Uint8Array(data); +} class NodeFilterFactory extends BaseFilterFactory {} @@ -134,8 +135,8 @@ class NodeCMapReaderFactory extends BaseCMapReaderFactory { /** * @ignore */ - _fetchData(url, compressionType) { - return fetchData(url).then(data => ({ cMapData: data, compressionType })); + async _fetch(url) { + return fetchData(url); } } @@ -143,7 +144,7 @@ class NodeStandardFontDataFactory extends BaseStandardFontDataFactory { /** * @ignore */ - _fetchData(url) { + async _fetch(url) { return fetchData(url); } } From 6c3336f04f7d751883ef56fc974339bdae9853ff Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Mon, 21 Oct 2024 11:58:06 +0200 Subject: [PATCH 2/2] Re-factor the `DefaultFileReaderFactory` unit-test helper We can re-use the existing helpers from `src/display/` rather than re-implementing the functionality here. --- src/display/node_utils.js | 1 + test/unit/test_utils.js | 21 ++++++--------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/display/node_utils.js b/src/display/node_utils.js index 0dcffdb2c878a..c0b1e6e2ce529 100644 --- a/src/display/node_utils.js +++ b/src/display/node_utils.js @@ -150,6 +150,7 @@ class NodeStandardFontDataFactory extends BaseStandardFontDataFactory { } export { + fetchData, NodeCanvasFactory, NodeCMapReaderFactory, NodeFilterFactory, diff --git a/test/unit/test_utils.js b/test/unit/test_utils.js index 507fc15649f48..473b292e83935 100644 --- a/test/unit/test_utils.js +++ b/test/unit/test_utils.js @@ -16,6 +16,8 @@ import { assert, isNodeJS } from "../../src/shared/util.js"; import { NullStream, StringStream } from "../../src/core/stream.js"; import { Page, PDFDocument } from "../../src/core/document.js"; +import { fetchData as fetchDataDOM } from "../../src/display/display_utils.js"; +import { fetchData as fetchDataNode } from "../../src/display/node_utils.js"; import { Ref } from "../../src/core/primitives.js"; let fs, http; @@ -33,27 +35,16 @@ const STANDARD_FONT_DATA_URL = isNodeJS ? "./external/standard_fonts/" : "../../external/standard_fonts/"; -class DOMFileReaderFactory { +class DefaultFileReaderFactory { static async fetch(params) { - const response = await fetch(params.path); - if (!response.ok) { - throw new Error(response.statusText); + if (isNodeJS) { + return fetchDataNode(params.path); } - return new Uint8Array(await response.arrayBuffer()); - } -} - -class NodeFileReaderFactory { - static async fetch(params) { - const data = await fs.promises.readFile(params.path); + const data = await fetchDataDOM(params.path, /* type = */ "arraybuffer"); return new Uint8Array(data); } } -const DefaultFileReaderFactory = isNodeJS - ? NodeFileReaderFactory - : DOMFileReaderFactory; - function buildGetDocumentParams(filename, options) { const params = Object.create(null); params.url = isNodeJS