Merge pull request #19548 from Snuffleupagus/Font-exportData-disableFontFace-fontExtraProperties

Send `disableFontFace` and `fontExtraProperties` as part of the exported font-data
This commit is contained in:
Jonas Jenwald 2025-02-26 11:25:29 +01:00 committed by GitHub
commit da17c7b82f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 132 additions and 115 deletions

View File

@ -1169,17 +1169,6 @@ class Catalog {
return shadow(this, "jsActions", actions); return shadow(this, "jsActions", actions);
} }
async fontFallback(id, handler) {
const translatedFonts = await Promise.all(this.fontCache);
for (const translatedFont of translatedFonts) {
if (translatedFont.loadedName === id) {
translatedFont.fallback(handler);
return;
}
}
}
async cleanup(manuallyTriggered = false) { async cleanup(manuallyTriggered = false) {
clearGlobalCaches(); clearGlobalCaches();
this.globalImageCache.clear(/* onlyData = */ manuallyTriggered); this.globalImageCache.clear(/* onlyData = */ manuallyTriggered);

View File

@ -1745,8 +1745,15 @@ class PDFDocument {
} }
} }
fontFallback(id, handler) { async fontFallback(id, handler) {
return this.catalog.fontFallback(id, handler); const { catalog, pdfManager } = this;
for (const translatedFont of await Promise.all(catalog.fontCache)) {
if (translatedFont.loadedName === id) {
translatedFont.fallback(handler, pdfManager.evaluatorOptions);
return;
}
}
} }
async cleanup(manuallyTriggered = false) { async cleanup(manuallyTriggered = false) {

View File

@ -1065,7 +1065,6 @@ class PartialEvaluator {
loadedName: "g_font_error", loadedName: "g_font_error",
font: new ErrorFont(`Type3 font load error: ${reason}`), font: new ErrorFont(`Type3 font load error: ${reason}`),
dict: translated.font, dict: translated.font,
evaluatorOptions: this.options,
}); });
} }
} }
@ -1086,8 +1085,7 @@ class PartialEvaluator {
if ( if (
isAddToPathSet || isAddToPathSet ||
state.fillColorSpace.name === "Pattern" || state.fillColorSpace.name === "Pattern" ||
font.disableFontFace || font.disableFontFace
this.options.disableFontFace
) { ) {
PartialEvaluator.buildFontPaths( PartialEvaluator.buildFontPaths(
font, font,
@ -1238,7 +1236,6 @@ class PartialEvaluator {
loadedName: "g_font_error", loadedName: "g_font_error",
font: new ErrorFont(`Font "${fontName}" is not available.`), font: new ErrorFont(`Font "${fontName}" is not available.`),
dict: font, dict: font,
evaluatorOptions: this.options,
}); });
let fontRef; let fontRef;
@ -1365,7 +1362,6 @@ class PartialEvaluator {
loadedName: font.loadedName, loadedName: font.loadedName,
font: translatedFont, font: translatedFont,
dict: font, dict: font,
evaluatorOptions: this.options,
}) })
); );
}) })
@ -1380,7 +1376,6 @@ class PartialEvaluator {
reason instanceof Error ? reason.message : reason reason instanceof Error ? reason.message : reason
), ),
dict: font, dict: font,
evaluatorOptions: this.options,
}) })
); );
}); });
@ -4367,7 +4362,7 @@ class PartialEvaluator {
newProperties newProperties
); );
} }
return new Font(baseFontName, file, newProperties); return new Font(baseFontName, file, newProperties, this.options);
} }
} }
@ -4559,7 +4554,7 @@ class PartialEvaluator {
const newProperties = await this.extractDataStructures(dict, properties); const newProperties = await this.extractDataStructures(dict, properties);
this.extractWidths(dict, descriptor, newProperties); this.extractWidths(dict, descriptor, newProperties);
return new Font(fontName.name, fontFile, newProperties); return new Font(fontName.name, fontFile, newProperties, this.options);
} }
static buildFontPaths(font, glyphs, handler, evaluatorOptions) { static buildFontPaths(font, glyphs, handler, evaluatorOptions) {
@ -4607,11 +4602,10 @@ class PartialEvaluator {
} }
class TranslatedFont { class TranslatedFont {
constructor({ loadedName, font, dict, evaluatorOptions }) { constructor({ loadedName, font, dict }) {
this.loadedName = loadedName; this.loadedName = loadedName;
this.font = font; this.font = font;
this.dict = dict; this.dict = dict;
this._evaluatorOptions = evaluatorOptions || DefaultPartialEvaluatorOptions;
this.type3Loaded = null; this.type3Loaded = null;
this.type3Dependencies = font.isType3Font ? new Set() : null; this.type3Dependencies = font.isType3Font ? new Set() : null;
this.sent = false; this.sent = false;
@ -4626,11 +4620,11 @@ class TranslatedFont {
handler.send("commonobj", [ handler.send("commonobj", [
this.loadedName, this.loadedName,
"Font", "Font",
this.font.exportData(this._evaluatorOptions.fontExtraProperties), this.font.exportData(),
]); ]);
} }
fallback(handler) { fallback(handler, evaluatorOptions) {
if (!this.font.data) { if (!this.font.data) {
return; return;
} }
@ -4646,7 +4640,7 @@ class TranslatedFont {
this.font, this.font,
/* glyphs = */ this.font.glyphCacheValues, /* glyphs = */ this.font.glyphCacheValues,
handler, handler,
this._evaluatorOptions evaluatorOptions
); );
} }

View File

@ -88,7 +88,9 @@ const EXPORT_DATA_PROPERTIES = [
"defaultVMetrics", "defaultVMetrics",
"defaultWidth", "defaultWidth",
"descent", "descent",
"disableFontFace",
"fallbackName", "fallbackName",
"fontExtraProperties",
"fontMatrix", "fontMatrix",
"isInvalidPDFjsFont", "isInvalidPDFjsFont",
"isType3Font", "isType3Font",
@ -970,11 +972,12 @@ function createNameTable(name, proto) {
* decoding logics whatever type it is (assuming the font type is supported). * decoding logics whatever type it is (assuming the font type is supported).
*/ */
class Font { class Font {
constructor(name, file, properties) { constructor(name, file, properties, evaluatorOptions) {
this.name = name; this.name = name;
this.psName = null; this.psName = null;
this.mimetype = null; this.mimetype = null;
this.disableFontFace = false; this.disableFontFace = evaluatorOptions.disableFontFace;
this.fontExtraProperties = evaluatorOptions.fontExtraProperties;
this.loadedName = properties.loadedName; this.loadedName = properties.loadedName;
this.isType3Font = properties.isType3Font; this.isType3Font = properties.isType3Font;
@ -1141,18 +1144,17 @@ class Font {
return shadow(this, "renderer", renderer); return shadow(this, "renderer", renderer);
} }
exportData(extraProperties = false) { exportData() {
const exportDataProperties = extraProperties const exportDataProps = this.fontExtraProperties
? [...EXPORT_DATA_PROPERTIES, ...EXPORT_DATA_EXTRA_PROPERTIES] ? [...EXPORT_DATA_PROPERTIES, ...EXPORT_DATA_EXTRA_PROPERTIES]
: EXPORT_DATA_PROPERTIES; : EXPORT_DATA_PROPERTIES;
const data = Object.create(null); const data = Object.create(null);
let property, value; for (const prop of exportDataProps) {
for (property of exportDataProperties) { const value = this[prop];
value = this[property];
// Ignore properties that haven't been explicitly set. // Ignore properties that haven't been explicitly set.
if (value !== undefined) { if (value !== undefined) {
data[property] = value; data[prop] = value;
} }
} }
return data; return data;
@ -3602,7 +3604,7 @@ class ErrorFont {
return [chars]; return [chars];
} }
exportData(extraProperties = false) { exportData() {
return { error: this.error }; return { error: this.error };
} }
} }

View File

@ -422,8 +422,6 @@ function getDocument(src = {}) {
}, },
}; };
const transportParams = { const transportParams = {
disableFontFace,
fontExtraProperties,
ownerDocument, ownerDocument,
pdfBug, pdfBug,
styleElement, styleElement,
@ -2787,8 +2785,6 @@ class WorkerTransport {
switch (type) { switch (type) {
case "Font": case "Font":
const { disableFontFace, fontExtraProperties, pdfBug } = this._params;
if ("error" in exportedData) { if ("error" in exportedData) {
const exportedError = exportedData.error; const exportedError = exportedData.error;
warn(`Error during font loading: ${exportedError}`); warn(`Error during font loading: ${exportedError}`);
@ -2797,20 +2793,16 @@ class WorkerTransport {
} }
const inspectFont = const inspectFont =
pdfBug && globalThis.FontInspector?.enabled this._params.pdfBug && globalThis.FontInspector?.enabled
? (font, url) => globalThis.FontInspector.fontAdded(font, url) ? (font, url) => globalThis.FontInspector.fontAdded(font, url)
: null; : null;
const font = new FontFaceObject(exportedData, { const font = new FontFaceObject(exportedData, inspectFont);
disableFontFace,
fontExtraProperties,
inspectFont,
});
this.fontLoader this.fontLoader
.bind(font) .bind(font)
.catch(() => messageHandler.sendWithPromise("FontFallback", { id })) .catch(() => messageHandler.sendWithPromise("FontFallback", { id }))
.finally(() => { .finally(() => {
if (!fontExtraProperties && font.data) { if (!font.fontExtraProperties && font.data) {
// Immediately release the `font.data` property once the font // Immediately release the `font.data` property once the font
// has been attached to the DOM, since it's no longer needed, // has been attached to the DOM, since it's no longer needed,
// rather than waiting for a `PDFDocumentProxy.cleanup` call. // rather than waiting for a `PDFDocumentProxy.cleanup` call.

View File

@ -355,17 +355,20 @@ class FontLoader {
} }
class FontFaceObject { class FontFaceObject {
constructor( constructor(translatedData, inspectFont = null) {
translatedData,
{ disableFontFace = false, fontExtraProperties = false, inspectFont = null }
) {
this.compiledGlyphs = Object.create(null); this.compiledGlyphs = Object.create(null);
// importing translated data // importing translated data
for (const i in translatedData) { for (const i in translatedData) {
this[i] = translatedData[i]; this[i] = translatedData[i];
} }
this.disableFontFace = disableFontFace === true; if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
this.fontExtraProperties = fontExtraProperties === true; if (typeof this.disableFontFace !== "boolean") {
unreachable("disableFontFace must be available.");
}
if (typeof this.fontExtraProperties !== "boolean") {
unreachable("fontExtraProperties must be available.");
}
}
this._inspectFont = inspectFont; this._inspectFont = inspectFont;
} }

View File

@ -16,17 +16,22 @@ describe("font_fpgm", function () {
const cMap = await CMapFactory.create({ const cMap = await CMapFactory.create({
encoding: Name.get("Identity-H"), encoding: Name.get("Identity-H"),
}); });
const font = new Font("font", new Stream(font2324), { const font = new Font(
loadedName: "font", "font",
type: "CIDFontType2", new Stream(font2324),
differences: [], {
defaultEncoding: [], loadedName: "font",
cMap, type: "CIDFontType2",
toUnicode: new ToUnicodeMap([]), differences: [],
xHeight: 0, defaultEncoding: [],
capHeight: 0, cMap,
italicAngle: 0, toUnicode: new ToUnicodeMap([]),
}); xHeight: 0,
capHeight: 0,
italicAngle: 0,
},
{}
);
const output = await ttx(font.data); const output = await ttx(font.data);
verifyTtxOutput(output); verifyTtxOutput(output);

View File

@ -17,16 +17,21 @@ describe("font_post", function () {
describe("OS/2 table removal on bad post table values", function () { describe("OS/2 table removal on bad post table values", function () {
it("has invalid version number", async function () { it("has invalid version number", async function () {
const font = new Font("font", new Stream(font2154), { const font = new Font(
loadedName: "font", "font",
type: "TrueType", new Stream(font2154),
differences: [], {
defaultEncoding: [], loadedName: "font",
toUnicode: new ToUnicodeMap([]), type: "TrueType",
xHeight: 0, differences: [],
capHeight: 0, defaultEncoding: [],
italicAngle: 0, toUnicode: new ToUnicodeMap([]),
}); xHeight: 0,
capHeight: 0,
italicAngle: 0,
},
{}
);
const output = await ttx(font.data); const output = await ttx(font.data);
verifyTtxOutput(output); verifyTtxOutput(output);
@ -39,17 +44,22 @@ describe("font_post", function () {
const cMap = await CMapFactory.create({ const cMap = await CMapFactory.create({
encoding: Name.get("Identity-H"), encoding: Name.get("Identity-H"),
}); });
const font = new Font("font", new Stream(font1282), { const font = new Font(
loadedName: "font", "font",
type: "CIDFontType2", new Stream(font1282),
differences: [], {
defaultEncoding: [], loadedName: "font",
cMap, type: "CIDFontType2",
toUnicode: new ToUnicodeMap([]), differences: [],
xHeight: 0, defaultEncoding: [],
capHeight: 0, cMap,
italicAngle: 0, toUnicode: new ToUnicodeMap([]),
}); xHeight: 0,
capHeight: 0,
italicAngle: 0,
},
{}
);
const output = await ttx(font.data); const output = await ttx(font.data);
verifyTtxOutput(output); verifyTtxOutput(output);

View File

@ -24,17 +24,22 @@ describe("font_post", function () {
const cMap = await CMapFactory.create({ const cMap = await CMapFactory.create({
encoding: Name.get("Identity-H"), encoding: Name.get("Identity-H"),
}); });
const font = new Font("font", new Stream(font2109), { const font = new Font(
loadedName: "font", "font",
type: "CIDFontType2", new Stream(font2109),
differences: [], {
defaultEncoding: [], loadedName: "font",
cMap, type: "CIDFontType2",
toUnicode: new ToUnicodeMap([]), differences: [],
xHeight: 0, defaultEncoding: [],
capHeight: 0, cMap,
italicAngle: 0, toUnicode: new ToUnicodeMap([]),
}); xHeight: 0,
capHeight: 0,
italicAngle: 0,
},
{}
);
const output = await ttx(font.data); const output = await ttx(font.data);
verifyTtxOutput(output); verifyTtxOutput(output);
@ -42,16 +47,21 @@ describe("font_post", function () {
}); });
it("has invalid glyph name indexes", async function () { it("has invalid glyph name indexes", async function () {
const font = new Font("font", new Stream(font2189), { const font = new Font(
loadedName: "font", "font",
type: "TrueType", new Stream(font2189),
differences: [], {
defaultEncoding: [], loadedName: "font",
toUnicode: new ToUnicodeMap([]), type: "TrueType",
xHeight: 0, differences: [],
capHeight: 0, defaultEncoding: [],
italicAngle: 0, toUnicode: new ToUnicodeMap([]),
}); xHeight: 0,
capHeight: 0,
italicAngle: 0,
},
{}
);
const output = await ttx(font.data); const output = await ttx(font.data);
verifyTtxOutput(output); verifyTtxOutput(output);
@ -59,16 +69,21 @@ describe("font_post", function () {
}); });
it("has right amount of glyphs specified", async function () { it("has right amount of glyphs specified", async function () {
const font = new Font("font", new Stream(font2374), { const font = new Font(
loadedName: "font", "font",
type: "TrueType", new Stream(font2374),
differences: [], {
defaultEncoding: [], loadedName: "font",
toUnicode: new ToUnicodeMap([]), type: "TrueType",
xHeight: 0, differences: [],
capHeight: 0, defaultEncoding: [],
italicAngle: 0, toUnicode: new ToUnicodeMap([]),
}); xHeight: 0,
capHeight: 0,
italicAngle: 0,
},
{}
);
const output = await ttx(font.data); const output = await ttx(font.data);
verifyTtxOutput(output); verifyTtxOutput(output);