From 8ba83e73fa88175a46b842fe0f1f0f8bec9b9ba8 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 11 Feb 2026 22:37:49 +0100 Subject: [PATCH 1/2] Start using `Response.prototype.bytes()` in the code-base In all cases where we currently use `Response.prototype.arrayBuffer()` the result is immediately wrapped in a `Uint8Array`, which can be avoided by instead using the newer `Response.prototype.bytes()` method; see https://developer.mozilla.org/en-US/docs/Web/API/Response/bytes --- src/core/core_utils.js | 2 +- src/display/cmap_reader_factory.js | 6 ++---- src/display/display_utils.js | 7 ++++++- src/display/standard_fontdata_factory.js | 3 +-- src/display/wasm_factory.js | 3 +-- src/shared/util.js | 12 ++++++++++++ test/unit/test_utils.js | 3 +-- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/core/core_utils.js b/src/core/core_utils.js index f3218ac614053..5980a51f2a7b9 100644 --- a/src/core/core_utils.js +++ b/src/core/core_utils.js @@ -129,7 +129,7 @@ async function fetchBinaryData(url) { `Failed to fetch file "${url}" with "${response.statusText}".` ); } - return new Uint8Array(await response.arrayBuffer()); + return response.bytes(); } /** diff --git a/src/display/cmap_reader_factory.js b/src/display/cmap_reader_factory.js index 5246fbb23dfa3..748bf8812f3fb 100644 --- a/src/display/cmap_reader_factory.js +++ b/src/display/cmap_reader_factory.js @@ -64,11 +64,9 @@ class DOMCMapReaderFactory extends BaseCMapReaderFactory { async _fetch(url) { const data = await fetchData( url, - /* type = */ this.isCompressed ? "arraybuffer" : "text" + /* type = */ this.isCompressed ? "bytes" : "text" ); - return data instanceof ArrayBuffer - ? new Uint8Array(data) - : stringToBytes(data); + return data instanceof Uint8Array ? data : stringToBytes(data); } } diff --git a/src/display/display_utils.js b/src/display/display_utils.js index 16181b3e5e51b..c8f66a97d8916 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -48,6 +48,8 @@ async function fetchData(url, type = "text") { return response.arrayBuffer(); case "blob": return response.blob(); + case "bytes": + return response.bytes(); case "json": return response.json(); } @@ -58,7 +60,7 @@ async function fetchData(url, type = "text") { return new Promise((resolve, reject) => { const request = new XMLHttpRequest(); request.open("GET", url, /* async = */ true); - request.responseType = type; + request.responseType = type === "bytes" ? "arraybuffer" : type; request.onreadystatechange = () => { if (request.readyState !== XMLHttpRequest.DONE) { @@ -66,6 +68,9 @@ async function fetchData(url, type = "text") { } if (request.status === 200 || request.status === 0) { switch (type) { + case "bytes": + resolve(new Uint8Array(request.response)); + return; case "arraybuffer": case "blob": case "json": diff --git a/src/display/standard_fontdata_factory.js b/src/display/standard_fontdata_factory.js index bfd8af3c0cf68..15cdfdd230ab5 100644 --- a/src/display/standard_fontdata_factory.js +++ b/src/display/standard_fontdata_factory.js @@ -57,8 +57,7 @@ class DOMStandardFontDataFactory extends BaseStandardFontDataFactory { * @ignore */ async _fetch(url) { - const data = await fetchData(url, /* type = */ "arraybuffer"); - return new Uint8Array(data); + return fetchData(url, /* type = */ "bytes"); } } diff --git a/src/display/wasm_factory.js b/src/display/wasm_factory.js index 297e8e0e34e02..cc889e101d5ac 100644 --- a/src/display/wasm_factory.js +++ b/src/display/wasm_factory.js @@ -55,8 +55,7 @@ class DOMWasmFactory extends BaseWasmFactory { * @ignore */ async _fetch(url) { - const data = await fetchData(url, /* type = */ "arraybuffer"); - return new Uint8Array(data); + return fetchData(url, /* type = */ "bytes"); } } diff --git a/src/shared/util.js b/src/shared/util.js index ccbc2f56a6e84..039efa7d63eda 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -1248,6 +1248,18 @@ if ( }; } +// See https://developer.mozilla.org/en-US/docs/Web/API/Response/bytes#browser_compatibility +if ( + typeof PDFJSDev !== "undefined" && + !PDFJSDev.test("SKIP_BABEL") && + typeof Response.prototype.bytes !== "function" +) { + Response.prototype.bytes = async function () { + return new Uint8Array(await this.arrayBuffer()); + }; +} + +// TODO: Remove this once Safari 17.4 is the lowest supported version. if ( typeof PDFJSDev !== "undefined" && !PDFJSDev.test("SKIP_BABEL") && diff --git a/test/unit/test_utils.js b/test/unit/test_utils.js index 15b5fce06f50a..5d59c8f21c555 100644 --- a/test/unit/test_utils.js +++ b/test/unit/test_utils.js @@ -41,8 +41,7 @@ class DefaultFileReaderFactory { if (isNodeJS) { return fetchDataNode(params.path); } - const data = await fetchDataDOM(params.path, /* type = */ "arraybuffer"); - return new Uint8Array(data); + return fetchDataDOM(params.path, /* type = */ "bytes"); } } From 722f1ffbc6fc1e61382a89b78205f7aaf1fc8ce1 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 12 Feb 2026 11:23:28 +0100 Subject: [PATCH 2/2] Remove `type === "arraybuffer"` support from the `fetchData` helper function After the previous patch there's no longer any call-site using that type. --- src/display/display_utils.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/display/display_utils.js b/src/display/display_utils.js index c8f66a97d8916..072366315a822 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -44,8 +44,6 @@ async function fetchData(url, type = "text") { throw new Error(response.statusText); } switch (type) { - case "arraybuffer": - return response.arrayBuffer(); case "blob": return response.blob(); case "bytes": @@ -71,7 +69,6 @@ async function fetchData(url, type = "text") { case "bytes": resolve(new Uint8Array(request.response)); return; - case "arraybuffer": case "blob": case "json": resolve(request.response);