move common handler code to a shared file
This commit is contained in:
parent
aaa7a20874
commit
12d033cabe
@ -129,11 +129,10 @@ class Page {
|
||||
};
|
||||
}
|
||||
|
||||
#createPartialEvaluator(handler, rendererHandler) {
|
||||
#createPartialEvaluator(handler) {
|
||||
return new PartialEvaluator({
|
||||
xref: this.xref,
|
||||
handler,
|
||||
rendererHandler,
|
||||
pageIndex: this.pageIndex,
|
||||
idFactory: this._localIdFactory,
|
||||
fontCache: this.fontCache,
|
||||
@ -450,10 +449,7 @@ class Page {
|
||||
const contentStreamPromise = this.getContentStream();
|
||||
const resourcesPromise = this.loadResources(RESOURCES_KEYS_OPERATOR_LIST);
|
||||
|
||||
const partialEvaluator = this.#createPartialEvaluator(
|
||||
handler,
|
||||
rendererHandler
|
||||
);
|
||||
const partialEvaluator = this.#createPartialEvaluator(handler);
|
||||
|
||||
const newAnnotsByPage = !this.xfaFactory
|
||||
? getNewAnnotationsMap(annotationStorage)
|
||||
@ -1336,7 +1332,7 @@ class PDFDocument {
|
||||
this.xfaFactory.setImages(xfaImages);
|
||||
}
|
||||
|
||||
async #loadXfaFonts(handler, task, rendererHandler) {
|
||||
async #loadXfaFonts(handler, task) {
|
||||
const acroForm = await this.pdfManager.ensureCatalog("acroForm");
|
||||
if (!acroForm) {
|
||||
return;
|
||||
@ -1362,7 +1358,6 @@ class PDFDocument {
|
||||
const partialEvaluator = new PartialEvaluator({
|
||||
xref: this.xref,
|
||||
handler,
|
||||
rendererHandler,
|
||||
pageIndex: -1,
|
||||
idFactory: this._globalIdFactory,
|
||||
fontCache,
|
||||
@ -1475,9 +1470,9 @@ class PDFDocument {
|
||||
this.xfaFactory.appendFonts(pdfFonts, reallyMissingFonts);
|
||||
}
|
||||
|
||||
loadXfaResources(handler, task, rendererHandler) {
|
||||
loadXfaResources(handler, task) {
|
||||
return Promise.all([
|
||||
this.#loadXfaFonts(handler, task, rendererHandler).catch(() => {
|
||||
this.#loadXfaFonts(handler, task).catch(() => {
|
||||
// Ignore errors, to allow the document to load.
|
||||
}),
|
||||
this.#loadXfaImages(),
|
||||
|
||||
@ -222,7 +222,6 @@ class PartialEvaluator {
|
||||
constructor({
|
||||
xref,
|
||||
handler,
|
||||
rendererHandler,
|
||||
pageIndex,
|
||||
idFactory,
|
||||
fontCache,
|
||||
@ -235,7 +234,6 @@ class PartialEvaluator {
|
||||
}) {
|
||||
this.xref = xref;
|
||||
this.handler = handler;
|
||||
this.rendererHandler = rendererHandler;
|
||||
this.pageIndex = pageIndex;
|
||||
this.idFactory = idFactory;
|
||||
this.fontCache = fontCache;
|
||||
@ -555,19 +553,13 @@ class PartialEvaluator {
|
||||
const transfers = imgData ? [imgData.bitmap || imgData.data.buffer] : null;
|
||||
|
||||
if (this.parsingType3Font || cacheGlobally) {
|
||||
this.handler.send("commonobj", [objId, "Image", imgData], transfers);
|
||||
return this.rendererHandler.send(
|
||||
return this.handler.send(
|
||||
"commonobj",
|
||||
[objId, "Image", imgData],
|
||||
transfers
|
||||
);
|
||||
}
|
||||
this.handler.send(
|
||||
"obj",
|
||||
[objId, this.pageIndex, "Image", imgData],
|
||||
transfers
|
||||
);
|
||||
return this.rendererHandler.send(
|
||||
return this.handler.send(
|
||||
"obj",
|
||||
[objId, this.pageIndex, "Image", imgData],
|
||||
transfers
|
||||
@ -795,10 +787,11 @@ class PartialEvaluator {
|
||||
// globally, check if the image is still cached locally on the main-thread
|
||||
// to avoid having to re-parse the image (since that can be slow).
|
||||
if (w * h > 250000 || hasMask) {
|
||||
const localLength = await this.rendererHandler.sendWithPromise(
|
||||
"commonobj",
|
||||
[objId, "CopyLocalImage", { imageRef }]
|
||||
);
|
||||
const localLength = await this.sendWithPromise("commonobj", [
|
||||
objId,
|
||||
"CopyLocalImage",
|
||||
{ imageRef },
|
||||
]);
|
||||
|
||||
if (localLength) {
|
||||
this.globalImageCache.setData(imageRef, globalCacheData);
|
||||
@ -1028,7 +1021,6 @@ class PartialEvaluator {
|
||||
|
||||
state.font = translated.font;
|
||||
translated.send(this.handler);
|
||||
translated.send(this.rendererHandler);
|
||||
return translated.loadedName;
|
||||
}
|
||||
|
||||
@ -1048,7 +1040,7 @@ class PartialEvaluator {
|
||||
PartialEvaluator.buildFontPaths(
|
||||
font,
|
||||
glyphs,
|
||||
this.rendererHandler,
|
||||
this.handler,
|
||||
this.options
|
||||
);
|
||||
}
|
||||
@ -1526,15 +1518,8 @@ class PartialEvaluator {
|
||||
|
||||
if (this.parsingType3Font) {
|
||||
this.handler.send("commonobj", [id, "Pattern", patternIR]);
|
||||
this.rendererHandler.send("commonobj", [id, "Pattern", patternIR]);
|
||||
} else {
|
||||
this.handler.send("obj", [id, this.pageIndex, "Pattern", patternIR]);
|
||||
this.rendererHandler.send("obj", [
|
||||
id,
|
||||
this.pageIndex,
|
||||
"Pattern",
|
||||
patternIR,
|
||||
]);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -873,6 +873,10 @@ class WorkerMessageHandler {
|
||||
.then(page => pdfManager.ensure(page, "getStructTree"));
|
||||
});
|
||||
|
||||
handler.on("FontFallback", function (data) {
|
||||
return pdfManager.fontFallback(data.id, handler);
|
||||
});
|
||||
|
||||
rendererHandler.on("FontFallback", function (data) {
|
||||
return pdfManager.fontFallback(data.id, rendererHandler);
|
||||
});
|
||||
|
||||
@ -45,7 +45,6 @@ import {
|
||||
RenderingCancelledException,
|
||||
StatTimer,
|
||||
} from "./display_utils.js";
|
||||
import { FontFaceObject, FontLoader } from "./font_loader.js";
|
||||
import {
|
||||
getDataProp,
|
||||
getFactoryUrlProp,
|
||||
@ -68,7 +67,7 @@ import { DOMCMapReaderFactory } from "display-cmap_reader_factory";
|
||||
import { DOMFilterFactory } from "./filter_factory.js";
|
||||
import { DOMStandardFontDataFactory } from "display-standard_fontdata_factory";
|
||||
import { DOMWasmFactory } from "display-wasm_factory";
|
||||
import { FontInfo } from "../shared/obj-bin-transform.js";
|
||||
import { FontLoader } from "./font_loader.js";
|
||||
import { GlobalWorkerOptions } from "./worker_options.js";
|
||||
import { Metadata } from "./metadata.js";
|
||||
import { OptionalContentConfig } from "./optional_content_config.js";
|
||||
@ -76,6 +75,7 @@ import { PDFDataTransportStream } from "./transport_stream.js";
|
||||
import { PDFFetchStream } from "display-fetch_stream";
|
||||
import { PDFNetworkStream } from "display-network";
|
||||
import { PDFNodeStream } from "display-node_stream";
|
||||
import { setupHandler } from "../shared/handle_objs.js";
|
||||
import { TextLayer } from "./text_layer.js";
|
||||
import { XfaText } from "./xfa_text.js";
|
||||
|
||||
@ -2828,105 +2828,13 @@ class WorkerTransport {
|
||||
page._startRenderPage(data.transparency, data.cacheKey);
|
||||
});
|
||||
|
||||
messageHandler.on("commonobj", ([id, type, exportedData]) => {
|
||||
if (this.destroyed) {
|
||||
return null; // Ignore any pending requests if the worker was terminated.
|
||||
}
|
||||
|
||||
if (this.commonObjs.has(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "Font":
|
||||
if ("error" in exportedData) {
|
||||
const exportedError = exportedData.error;
|
||||
warn(`Error during font loading: ${exportedError}`);
|
||||
this.commonObjs.resolve(id, exportedError);
|
||||
break;
|
||||
}
|
||||
|
||||
const fontData = new FontInfo(exportedData);
|
||||
const inspectFont =
|
||||
this._params.pdfBug && globalThis.FontInspector?.enabled
|
||||
? (font, url) => globalThis.FontInspector.fontAdded(font, url)
|
||||
: null;
|
||||
const font = new FontFaceObject(
|
||||
fontData,
|
||||
inspectFont,
|
||||
exportedData.extra,
|
||||
exportedData.charProcOperatorList
|
||||
);
|
||||
|
||||
this.fontLoader
|
||||
.bind(font)
|
||||
.catch(() => messageHandler.sendWithPromise("FontFallback", { id }))
|
||||
.finally(() => {
|
||||
if (!font.fontExtraProperties && font.data) {
|
||||
// Immediately release the `font.data` property once the font
|
||||
// has been attached to the DOM, since it's no longer needed,
|
||||
// rather than waiting for a `PDFDocumentProxy.cleanup` call.
|
||||
// Since `font.data` could be very large, e.g. in some cases
|
||||
// multiple megabytes, this will help reduce memory usage.
|
||||
font.clearData();
|
||||
}
|
||||
this.commonObjs.resolve(id, font);
|
||||
});
|
||||
break;
|
||||
case "CopyLocalImage":
|
||||
const { imageRef } = exportedData;
|
||||
assert(imageRef, "The imageRef must be defined.");
|
||||
|
||||
for (const pageProxy of this.#pageCache.values()) {
|
||||
for (const [, data] of pageProxy.objs) {
|
||||
if (data?.ref !== imageRef) {
|
||||
continue;
|
||||
}
|
||||
if (!data.dataLen) {
|
||||
return null;
|
||||
}
|
||||
this.commonObjs.resolve(id, structuredClone(data));
|
||||
return data.dataLen;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "FontPath":
|
||||
case "Image":
|
||||
case "Pattern":
|
||||
this.commonObjs.resolve(id, exportedData);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Got unknown common object type ${type}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
messageHandler.on("obj", ([id, pageIndex, type, imageData]) => {
|
||||
if (this.destroyed) {
|
||||
// Ignore any pending requests if the worker was terminated.
|
||||
return;
|
||||
}
|
||||
|
||||
const pageProxy = this.#pageCache.get(pageIndex);
|
||||
if (pageProxy.objs.has(id)) {
|
||||
return;
|
||||
}
|
||||
// Don't store data *after* cleanup has successfully run, see bug 1854145.
|
||||
if (pageProxy._intentStates.size === 0) {
|
||||
imageData?.bitmap?.close(); // Release any `ImageBitmap` data.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "Image":
|
||||
case "Pattern":
|
||||
pageProxy.objs.resolve(id, imageData);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Got unknown object type ${type}`);
|
||||
}
|
||||
});
|
||||
setupHandler(
|
||||
messageHandler,
|
||||
this.destroyed,
|
||||
this.commonObjs,
|
||||
this.#pageCache,
|
||||
this.fontLoader
|
||||
);
|
||||
|
||||
messageHandler.on("DocProgress", data => {
|
||||
if (this.destroyed) {
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { assert, warn } from "../shared/util.js";
|
||||
import { FontFaceObject, FontLoader } from "./font_loader.js";
|
||||
import { assert } from "../shared/util.js";
|
||||
import { CanvasGraphics } from "./canvas.js";
|
||||
import { DOMFilterFactory } from "./filter_factory.js";
|
||||
import { FontLoader } from "./font_loader.js";
|
||||
import { MessageHandler } from "../shared/message_handler.js";
|
||||
import { OffscreenCanvasFactory } from "./canvas_factory.js";
|
||||
import { PDFObjects } from "./display_utils.js";
|
||||
import { setupHandler } from "../shared/handle_objs.js";
|
||||
|
||||
class RendererMessageHandler {
|
||||
static #commonObjs = new PDFObjects();
|
||||
@ -56,19 +57,13 @@ class RendererMessageHandler {
|
||||
});
|
||||
this.#filterFactory = new DOMFilterFactory({});
|
||||
|
||||
workerHandler.on("commonobj", ([id, type, data]) => {
|
||||
if (terminated) {
|
||||
throw new Error("Renderer worker has been terminated.");
|
||||
}
|
||||
this.handleCommonObj(id, type, data, workerHandler);
|
||||
});
|
||||
|
||||
workerHandler.on("obj", ([id, pageIndex, type, data]) => {
|
||||
if (terminated) {
|
||||
throw new Error("Renderer worker has been terminated.");
|
||||
}
|
||||
this.handleObj(pageIndex, id, type, data);
|
||||
});
|
||||
setupHandler(
|
||||
workerHandler,
|
||||
terminated,
|
||||
this.#commonObjs,
|
||||
this.#objsMap,
|
||||
this.#fontLoader
|
||||
);
|
||||
});
|
||||
|
||||
mainHandler.on(
|
||||
@ -168,90 +163,6 @@ class RendererMessageHandler {
|
||||
mainHandler = null;
|
||||
});
|
||||
}
|
||||
|
||||
static handleCommonObj(id, type, exportedData, handler) {
|
||||
if (this.#commonObjs.has(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "Font":
|
||||
if ("error" in exportedData) {
|
||||
const exportedError = exportedData.error;
|
||||
warn(`Error during font loading: ${exportedError}`);
|
||||
this.#commonObjs.resolve(id, exportedError);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Make FontInspector work again.
|
||||
const inspectFont = null;
|
||||
// this._params.pdfBug && globalThis.FontInspector?.enabled
|
||||
// ? (font, url) => globalThis.FontInspector.fontAdded(font, url)
|
||||
// : null;
|
||||
const font = new FontFaceObject(exportedData, inspectFont);
|
||||
|
||||
this.#fontLoader
|
||||
.bind(font)
|
||||
.catch(() => handler.sendWithPromise("FontFallback", { id }))
|
||||
.finally(() => {
|
||||
if (!font.fontExtraProperties && font.data) {
|
||||
// Immediately release the `font.data` property once the font
|
||||
// has been attached to the DOM, since it's no longer needed,
|
||||
// rather than waiting for a `PDFDocumentProxy.cleanup` call.
|
||||
// Since `font.data` could be very large, e.g. in some cases
|
||||
// multiple megabytes, this will help reduce memory usage.
|
||||
font.data = null;
|
||||
}
|
||||
this.#commonObjs.resolve(id, font);
|
||||
});
|
||||
break;
|
||||
case "CopyLocalImage":
|
||||
const { imageRef } = exportedData;
|
||||
assert(imageRef, "The imageRef must be defined.");
|
||||
|
||||
for (const objs of this.#objsMap.values()) {
|
||||
for (const [, data] of objs) {
|
||||
if (data?.ref !== imageRef) {
|
||||
continue;
|
||||
}
|
||||
if (!data.dataLen) {
|
||||
return null;
|
||||
}
|
||||
this.#commonObjs.resolve(id, structuredClone(data));
|
||||
return data.dataLen;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "FontPath":
|
||||
case "Image":
|
||||
case "Pattern":
|
||||
this.#commonObjs.resolve(id, exportedData);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Got unknown common object type ${type}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static handleObj(pageIndex, id, type, exportedData) {
|
||||
const objs = this.pageObjs(pageIndex);
|
||||
|
||||
if (objs.has(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "Image":
|
||||
case "Pattern":
|
||||
objs.resolve(id, exportedData);
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Got unknown object type ${type} id ${id} for page ${pageIndex} data ${JSON.stringify(exportedData)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { RendererMessageHandler };
|
||||
|
||||
108
src/shared/handle_objs.js
Normal file
108
src/shared/handle_objs.js
Normal file
@ -0,0 +1,108 @@
|
||||
import { assert, warn } from "../shared/util.js";
|
||||
import { FontFaceObject } from "../display/font_loader.js";
|
||||
import { FontInfo } from "../shared/obj-bin-transform.js";
|
||||
|
||||
function setupHandler(handler, destroyed, commonObjs, pages, fontLoader) {
|
||||
handler.on("commonobj", ([id, type, exportedData]) => {
|
||||
if (destroyed) {
|
||||
return null; // Ignore any pending requests if the worker was terminated.
|
||||
}
|
||||
|
||||
if (commonObjs.has(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "Font":
|
||||
if ("error" in exportedData) {
|
||||
const exportedError = exportedData.error;
|
||||
warn(`Error during font loading: ${exportedError}`);
|
||||
commonObjs.resolve(id, exportedError);
|
||||
break;
|
||||
}
|
||||
|
||||
const fontData = new FontInfo(exportedData);
|
||||
const inspectFont = // TODO: Fix this
|
||||
// this._params.pdfBug && globalThis.FontInspector?.enabled
|
||||
// ? (font, url) => globalThis.FontInspector.fontAdded(font, url)
|
||||
// : null;
|
||||
null;
|
||||
const font = new FontFaceObject(
|
||||
fontData,
|
||||
inspectFont,
|
||||
exportedData.extra,
|
||||
exportedData.charProcOperatorList
|
||||
);
|
||||
|
||||
fontLoader
|
||||
.bind(font)
|
||||
.catch(() => handler.sendWithPromise("FontFallback", { id }))
|
||||
.finally(() => {
|
||||
if (!font.fontExtraProperties && font.data) {
|
||||
// Immediately release the `font.data` property once the font
|
||||
// has been attached to the DOM, since it's no longer needed,
|
||||
// rather than waiting for a `PDFDocumentProxy.cleanup` call.
|
||||
// Since `font.data` could be very large, e.g. in some cases
|
||||
// multiple megabytes, this will help reduce memory usage.
|
||||
font.clearData();
|
||||
}
|
||||
commonObjs.resolve(id, font);
|
||||
});
|
||||
break;
|
||||
case "CopyLocalImage":
|
||||
const { imageRef } = exportedData;
|
||||
assert(imageRef, "The imageRef must be defined.");
|
||||
|
||||
for (const page of pages.values()) {
|
||||
for (const [, data] of page.objs) {
|
||||
if (data?.ref !== imageRef) {
|
||||
continue;
|
||||
}
|
||||
if (!data.dataLen) {
|
||||
return null;
|
||||
}
|
||||
commonObjs.resolve(id, structuredClone(data));
|
||||
return data.dataLen;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "FontPath":
|
||||
case "Image":
|
||||
case "Pattern":
|
||||
commonObjs.resolve(id, exportedData);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Got unknown common object type ${type}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
handler.on("obj", ([id, pageIndex, type, imageData]) => {
|
||||
if (destroyed) {
|
||||
// Ignore any pending requests if the worker was terminated.
|
||||
return;
|
||||
}
|
||||
|
||||
const page = pages.get(pageIndex);
|
||||
if (page.objs.has(id)) {
|
||||
return;
|
||||
}
|
||||
// Don't store data *after* cleanup has successfully run, see bug 1854145.
|
||||
if (page._intentStates.size === 0) {
|
||||
imageData?.bitmap?.close(); // Release any `ImageBitmap` data.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "Image":
|
||||
case "Pattern":
|
||||
page.objs.resolve(id, imageData);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Got unknown object type ${type}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export { setupHandler };
|
||||
Loading…
x
Reference in New Issue
Block a user