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.
This commit is contained in:
Jonas Jenwald 2026-03-14 09:19:44 +01:00
parent d38cddf2b6
commit 7d963ddc7c
7 changed files with 35 additions and 42 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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"

View File

@ -2890,8 +2890,8 @@ class WorkerTransport {
const font = new FontFaceObject(
fontData,
inspectFont,
exportedData.extra,
exportedData.charProcOperatorList
exportedData.charProcOperatorList,
exportedData.extra
);
this.fontLoader

View File

@ -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() {

View File

@ -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);
}

View File

@ -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");
});