Re-factor how the GenericL10n class fetches localization-data

- Re-factor the existing `fetchData` helper function such that it can fetch more types of data, and it now supports "arraybuffer", "json", and "text".
   This only needed minor adjustments in the `DOMCMapReaderFactory` and `DOMStandardFontDataFactory` classes.[1]

 - Expose the `fetchData` helper function in the API, such that the viewer is able to access it.

 - Use the `fetchData` helper function in the `GenericL10n` class, since this should allow fetching of localization-data even if the default viewer is run in an environment without support for the Fetch API.

---
[1] While testing this I also noticed a minor inconsistency when handling standard font-data on the worker-thread.
This commit is contained in:
Jonas Jenwald 2023-11-14 12:54:21 +01:00
parent 44cde3ccca
commit 709d89420e
6 changed files with 45 additions and 20 deletions

View File

@ -425,7 +425,7 @@ class PartialEvaluator {
`fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".` `fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".`
); );
} else { } else {
data = await response.arrayBuffer(); data = new Uint8Array(await response.arrayBuffer());
} }
} else { } else {
// Get the data on the main-thread instead. // Get the data on the main-thread instead.

View File

@ -387,7 +387,7 @@ class DOMCanvasFactory extends BaseCanvasFactory {
} }
} }
async function fetchData(url, asTypedArray = false) { async function fetchData(url, type = "text") {
if ( if (
(typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) || (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) ||
isValidFetchUrl(url, document.baseURI) isValidFetchUrl(url, document.baseURI)
@ -396,29 +396,35 @@ async function fetchData(url, asTypedArray = false) {
if (!response.ok) { if (!response.ok) {
throw new Error(response.statusText); throw new Error(response.statusText);
} }
return asTypedArray switch (type) {
? new Uint8Array(await response.arrayBuffer()) case "arraybuffer":
: stringToBytes(await response.text()); return response.arrayBuffer();
case "json":
return response.json();
}
return response.text();
} }
// The Fetch API is not supported. // The Fetch API is not supported.
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = new XMLHttpRequest(); const request = new XMLHttpRequest();
request.open("GET", url, /* asTypedArray = */ true); request.open("GET", url, /* async = */ true);
request.responseType = type;
if (asTypedArray) {
request.responseType = "arraybuffer";
}
request.onreadystatechange = () => { request.onreadystatechange = () => {
if (request.readyState !== XMLHttpRequest.DONE) { if (request.readyState !== XMLHttpRequest.DONE) {
return; return;
} }
if (request.status === 200 || request.status === 0) { if (request.status === 200 || request.status === 0) {
let data; let data;
if (asTypedArray && request.response) { switch (type) {
data = new Uint8Array(request.response); case "arraybuffer":
} else if (!asTypedArray && request.responseText) { case "json":
data = stringToBytes(request.responseText); data = request.response;
break;
default:
data = request.responseText;
break;
} }
if (data) { if (data) {
resolve(data); resolve(data);
@ -437,8 +443,17 @@ class DOMCMapReaderFactory extends BaseCMapReaderFactory {
* @ignore * @ignore
*/ */
_fetchData(url, compressionType) { _fetchData(url, compressionType) {
return fetchData(url, /* asTypedArray = */ this.isCompressed).then(data => { return fetchData(
return { cMapData: data, compressionType }; url,
/* type = */ this.isCompressed ? "arraybuffer" : "text"
).then(data => {
return {
cMapData:
data instanceof ArrayBuffer
? new Uint8Array(data)
: stringToBytes(data),
compressionType,
};
}); });
} }
} }
@ -448,7 +463,9 @@ class DOMStandardFontDataFactory extends BaseStandardFontDataFactory {
* @ignore * @ignore
*/ */
_fetchData(url) { _fetchData(url) {
return fetchData(url, /* asTypedArray = */ true); return fetchData(url, /* type = */ "arraybuffer").then(data => {
return new Uint8Array(data);
});
} }
} }
@ -993,6 +1010,7 @@ export {
DOMFilterFactory, DOMFilterFactory,
DOMStandardFontDataFactory, DOMStandardFontDataFactory,
DOMSVGFactory, DOMSVGFactory,
fetchData,
getColorValues, getColorValues,
getCurrentTransform, getCurrentTransform,
getCurrentTransformInverse, getCurrentTransformInverse,

View File

@ -54,6 +54,7 @@ import {
} from "./display/api.js"; } from "./display/api.js";
import { import {
DOMSVGFactory, DOMSVGFactory,
fetchData,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,
getXfaPageViewport, getXfaPageViewport,
@ -92,6 +93,7 @@ export {
createValidAbsoluteUrl, createValidAbsoluteUrl,
DOMSVGFactory, DOMSVGFactory,
FeatureTest, FeatureTest,
fetchData,
getDocument, getDocument,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,

View File

@ -44,6 +44,7 @@ import {
} from "../../src/display/api.js"; } from "../../src/display/api.js";
import { import {
DOMSVGFactory, DOMSVGFactory,
fetchData,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,
getXfaPageViewport, getXfaPageViewport,
@ -78,6 +79,7 @@ const expectedAPI = Object.freeze({
createValidAbsoluteUrl, createValidAbsoluteUrl,
DOMSVGFactory, DOMSVGFactory,
FeatureTest, FeatureTest,
fetchData,
getDocument, getDocument,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,

View File

@ -17,6 +17,7 @@
import { FluentBundle, FluentResource } from "fluent-bundle"; import { FluentBundle, FluentResource } from "fluent-bundle";
import { DOMLocalization } from "fluent-dom"; import { DOMLocalization } from "fluent-dom";
import { fetchData } from "pdfjs-lib";
import { L10n } from "./l10n.js"; import { L10n } from "./l10n.js";
/** /**
@ -71,8 +72,8 @@ class GenericL10n extends L10n {
return null; return null;
} }
const url = new URL(path, baseURL); const url = new URL(path, baseURL);
const data = await fetch(url); const text = await fetchData(url, /* type = */ "text");
const text = await data.text();
const resource = new FluentResource(text); const resource = new FluentResource(text);
const bundle = new FluentBundle(lang); const bundle = new FluentBundle(lang);
const errors = bundle.addResource(resource); const errors = bundle.addResource(resource);
@ -84,8 +85,8 @@ class GenericL10n extends L10n {
static async #getPaths() { static async #getPaths() {
const { href } = document.querySelector(`link[type="application/l10n"]`); const { href } = document.querySelector(`link[type="application/l10n"]`);
const data = await fetch(href); const paths = await fetchData(href, /* type = */ "json");
const paths = await data.json();
return { baseURL: href.replace(/[^/]*$/, "") || "./", paths }; return { baseURL: href.replace(/[^/]*$/, "") || "./", paths };
} }
} }

View File

@ -35,6 +35,7 @@ const {
createValidAbsoluteUrl, createValidAbsoluteUrl,
DOMSVGFactory, DOMSVGFactory,
FeatureTest, FeatureTest,
fetchData,
getDocument, getDocument,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,
@ -80,6 +81,7 @@ export {
createValidAbsoluteUrl, createValidAbsoluteUrl,
DOMSVGFactory, DOMSVGFactory,
FeatureTest, FeatureTest,
fetchData,
getDocument, getDocument,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,