From 7d963ddc7c52d76350caa8c8178071d9bd9dcd22 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 14 Mar 2026 09:19:44 +0100 Subject: [PATCH] Move the `compileFontInfo` call into the `Font.prototype.exportData` method (PR 20197 follow-up) After the changes in PR 20197 the code in the `TranslatedFont.prototype.send` method is not all that readable[1] given how it handles e.g. the `charProcOperatorList` data used with Type3 fonts. Since this is the only spot where `Font.prototype.exportData` is used, it seems much simpler to move the `compileFontInfo` call there and *directly* return the intended data rather than messing with it after the fact. Finally, while it doesn't really matter, the patch flips the order of the `charProcOperatorList` and `extra` properties throughout the code-base since the former is used with Type3 fonts while the latter (effectively) requires that debugging is enabled. --- [1] I had to re-read it twice, also looking at all the involved methods, in order to convince myself that it's actually correct. --- src/core/evaluator.js | 16 ++++-------- src/core/fonts.js | 31 ++++++++++++------------ src/core/obj_bin_transform_core.js | 3 --- src/display/api.js | 4 +-- src/display/font_loader.js | 9 ++++--- src/display/obj_bin_transform_display.js | 10 ++++---- test/unit/obj_bin_transform_spec.js | 4 +-- 7 files changed, 35 insertions(+), 42 deletions(-) diff --git a/src/core/evaluator.js b/src/core/evaluator.js index eddde0788..d4c7c139f 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -32,7 +32,6 @@ import { import { CMapFactory, IdentityCMap } from "./cmap.js"; import { Cmd, Dict, EOF, isName, Name, Ref, RefSet } from "./primitives.js"; import { - compileFontInfo, compileFontPathInfo, compilePatternInfo, } from "./obj_bin_transform_core.js"; @@ -4804,16 +4803,11 @@ class TranslatedFont { return; } this.#sent = true; - const fontData = this.font.exportData(); - const transfer = []; - if (fontData.data) { - if (fontData.data.charProcOperatorList) { - fontData.charProcOperatorList = fontData.data.charProcOperatorList; - } - fontData.data = compileFontInfo(fontData.data); - transfer.push(fontData.data); - } - handler.send("commonobj", [this.loadedName, "Font", fontData], transfer); + + const fontData = this.font.exportData(), + transfers = fontData.buffer ? [fontData.buffer] : null; + + handler.send("commonobj", [this.loadedName, "Font", fontData], transfers); // future path: switch to a SharedArrayBuffer // const sab = new SharedArrayBuffer(data.byteLength); // const view = new Uint8Array(sab); diff --git a/src/core/fonts.js b/src/core/fonts.js index 901a350f5..3e37fdd42 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -57,6 +57,7 @@ import { } from "./standard_fonts.js"; import { IdentityToUnicodeMap, ToUnicodeMap } from "./to_unicode_map.js"; import { CFFFont } from "./cff_font.js"; +import { compileFontInfo } from "./obj_bin_transform_core.js"; import { FontRendererFactory } from "./font_renderer.js"; import { getFontBasicMetrics } from "./metrics.js"; import { GlyfTable } from "./glyf.js"; @@ -80,7 +81,7 @@ const EXPORT_DATA_PROPERTIES = [ "bbox", "black", "bold", - "charProcOperatorList", + // "charProcOperatorList" is handled separately, since it's not compiled. "cssFontInfo", "data", "defaultVMetrics", @@ -973,6 +974,8 @@ class Font { #glyphCache = new Map(); + charProcOperatorList; + constructor(name, file, properties, evaluatorOptions) { this.name = name; this.psName = null; @@ -1147,28 +1150,26 @@ class Font { return shadow(this, "renderer", renderer); } - exportData() { + #getExportData(props) { const data = Object.create(null); - for (const prop of EXPORT_DATA_PROPERTIES) { + for (const prop of props) { const value = this[prop]; // Ignore properties that haven't been explicitly set. if (value !== undefined) { data[prop] = value; } } + return data; + } - if (!this.fontExtraProperties) { - return { data }; - } - - const extra = Object.create(null); - for (const prop of EXPORT_DATA_EXTRA_PROPERTIES) { - const value = this[prop]; - if (value !== undefined) { - extra[prop] = value; - } - } - return { data, extra }; + exportData() { + return { + buffer: compileFontInfo(this.#getExportData(EXPORT_DATA_PROPERTIES)), + charProcOperatorList: this.charProcOperatorList, + extra: this.fontExtraProperties + ? this.#getExportData(EXPORT_DATA_EXTRA_PROPERTIES) + : undefined, + }; } fallbackToSystemFont(properties) { diff --git a/src/core/obj_bin_transform_core.js b/src/core/obj_bin_transform_core.js index b9cbd75ac..3870f0610 100644 --- a/src/core/obj_bin_transform_core.js +++ b/src/core/obj_bin_transform_core.js @@ -169,7 +169,6 @@ function compileFontInfo(font) { view.setUint8(offset++, 0); offset += 2 * 4; // TODO: optimize this padding away } - assert( offset === FONT_INFO.OFFSET_FONT_MATRIX, "compileFontInfo: BBox properties offset mismatch" @@ -185,7 +184,6 @@ function compileFontInfo(font) { view.setUint8(offset++, 0); offset += 8 * 6; // TODO: optimize this padding away } - assert( offset === FONT_INFO.OFFSET_DEFAULT_VMETRICS, "compileFontInfo: FontMatrix properties offset mismatch" @@ -201,7 +199,6 @@ function compileFontInfo(font) { view.setUint8(offset++, 0); offset += 3 * 2; // TODO: optimize this padding away } - assert( offset === FONT_INFO.OFFSET_STRINGS, "compileFontInfo: DefaultVMetrics properties offset mismatch" diff --git a/src/display/api.js b/src/display/api.js index 136ac1fe9..dc4679bb0 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -2890,8 +2890,8 @@ class WorkerTransport { const font = new FontFaceObject( fontData, inspectFont, - exportedData.extra, - exportedData.charProcOperatorList + exportedData.charProcOperatorList, + exportedData.extra ); this.fontLoader diff --git a/src/display/font_loader.js b/src/display/font_loader.js index fbfb2bc82..c2f5a8044 100644 --- a/src/display/font_loader.js +++ b/src/display/font_loader.js @@ -359,7 +359,7 @@ class FontFaceObject { #fontData; - constructor(translatedData, inspectFont = null, extra, charProcOperatorList) { + constructor(translatedData, inspectFont = null, charProcOperatorList, extra) { if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { assert( typeof translatedData.disableFontFace === "boolean", @@ -372,12 +372,13 @@ class FontFaceObject { } this.#fontData = translatedData; this._inspectFont = inspectFont; - if (extra) { - Object.assign(this, extra); - } + if (charProcOperatorList) { this.charProcOperatorList = charProcOperatorList; } + if (extra) { + Object.assign(this, extra); + } } createNativeFontFace() { diff --git a/src/display/obj_bin_transform_display.js b/src/display/obj_bin_transform_display.js index 6f801ff56..1297a88ad 100644 --- a/src/display/obj_bin_transform_display.js +++ b/src/display/obj_bin_transform_display.js @@ -30,7 +30,7 @@ class CssFontInfo { constructor(buffer) { this.#buffer = buffer; - this.#view = new DataView(this.#buffer); + this.#view = new DataView(buffer); } #readString(index) { @@ -67,7 +67,7 @@ class SystemFontInfo { constructor(buffer) { this.#buffer = buffer; - this.#view = new DataView(this.#buffer); + this.#view = new DataView(buffer); } get guessFallback() { @@ -125,9 +125,9 @@ class FontInfo { #view; - constructor({ data, extra }) { - this.#buffer = data; - this.#view = new DataView(this.#buffer); + constructor({ buffer, extra }) { + this.#buffer = buffer; + this.#view = new DataView(buffer); if (extra) { Object.assign(this, extra); } diff --git a/test/unit/obj_bin_transform_spec.js b/test/unit/obj_bin_transform_spec.js index 9f8277798..8f3b11077 100644 --- a/test/unit/obj_bin_transform_spec.js +++ b/test/unit/obj_bin_transform_spec.js @@ -133,7 +133,7 @@ describe("obj_bin_transform", function () { sizeEstimate += 4 + fontInfo.data.length; const buffer = compileFontInfo(fontInfo); expect(buffer.byteLength).toEqual(sizeEstimate); - const deserialized = new FontInfo({ data: buffer }); + const deserialized = new FontInfo({ buffer }); expect(deserialized.black).toEqual(true); expect(deserialized.bold).toEqual(true); expect(deserialized.disableFontFace).toEqual(true); @@ -168,7 +168,7 @@ describe("obj_bin_transform", function () { cssFontInfo, systemFontInfo, }); - const deserialized = new FontInfo({ data: buffer }); + const deserialized = new FontInfo({ buffer }); expect(deserialized.cssFontInfo.fontWeight).toEqual("not a number"); expect(deserialized.systemFontInfo.src).toEqual("source"); });