Use the CFF program directly for CID fonts wrapped in OpenType FontFile3

When a CIDFontType0 descendant has its program in a FontFile3 stream with
/Subtype /OpenType, the OTF wrapper sometimes lacks a usable cmap and the
CID→GID mapping only exists inside the embedded CFF itself. In that case
the OpenType-table path produces wrong glyphs, so route the font through
CFFFont and let it consume the inner CFF directly.

The file has been found in https://issues.chromium.org/issues/471404119.
This commit is contained in:
calixteman 2025-12-29 14:54:54 +01:00
parent 3450e95179
commit 91f2facce3
No known key found for this signature in database
GPG Key ID: 0C5442631EE0691F
5 changed files with 42 additions and 15 deletions

View File

@ -4664,9 +4664,22 @@ class PartialEvaluator {
throw new FormatError("invalid font name"); throw new FormatError("invalid font name");
} }
let fontFile, subtype, length1, length2, length3; let fontFile, fontFileN, subtype, length1, length2, length3;
try { try {
fontFile = descriptor.get("FontFile", "FontFile2", "FontFile3"); fontFile = descriptor.get("FontFile");
if (fontFile) {
fontFileN = 1;
} else {
fontFile = descriptor.get("FontFile2");
if (fontFile) {
fontFileN = 2;
} else {
fontFile = descriptor.get("FontFile3");
if (fontFile) {
fontFileN = 3;
}
}
}
if (fontFile) { if (fontFile) {
if (!(fontFile instanceof BaseStream)) { if (!(fontFile instanceof BaseStream)) {
@ -4776,6 +4789,7 @@ class PartialEvaluator {
name: fontName.name, name: fontName.name,
subtype, subtype,
file: fontFile, file: fontFile,
fontFileN,
length1, length1,
length2, length2,
length3, length3,

View File

@ -2670,10 +2670,23 @@ class Font {
} }
const isTrueType = !tables["CFF "]; const isTrueType = !tables["CFF "];
let parsedCff = null;
if (!isTrueType) { if (!isTrueType) {
try {
parsedCff = new CFFParser(
new Stream(tables["CFF "].data),
properties,
SEAC_ANALYSIS_ENABLED
).parse();
} catch {
warn("Failed to parse font " + properties.loadedName);
}
// OpenType font (skip composite fonts with non-default glyph mapping). // OpenType font (skip composite fonts with non-default glyph mapping).
if ( if (
(header.version === "OTTO" && !properties.composite) || (header.version === "OTTO" &&
(!properties.composite ||
(properties.fontFileN === 3 && parsedCff?.isCIDFont))) ||
!tables.head || !tables.head ||
!tables.hhea || !tables.hhea ||
!tables.maxp || !tables.maxp ||
@ -2713,19 +2726,11 @@ class Font {
} }
let numGlyphsFromCFF; let numGlyphsFromCFF;
if (!isTrueType) { if (parsedCff) {
try { try {
// Trying to repair CFF file parsedCff.duplicateFirstGlyph();
const parser = new CFFParser( tables["CFF "].data = new CFFCompiler(parsedCff).compile();
new Stream(tables["CFF "].data), numGlyphsFromCFF = parsedCff.charStringCount;
properties,
SEAC_ANALYSIS_ENABLED
);
const cff = parser.parse();
cff.duplicateFirstGlyph();
const compiler = new CFFCompiler(cff);
tables["CFF "].data = compiler.compile();
numGlyphsFromCFF = cff.charStringCount;
} catch { } catch {
warn("Failed to compile font " + properties.loadedName); warn("Failed to compile font " + properties.loadedName);
} }

View File

@ -921,3 +921,4 @@
!operator_list_cycle.pdf !operator_list_cycle.pdf
!knockout_groups_test.pdf !knockout_groups_test.pdf
!issue18032.pdf !issue18032.pdf
!Embedded_font.pdf

BIN
test/pdfs/Embedded_font.pdf Normal file

Binary file not shown.

View File

@ -14260,5 +14260,12 @@
"rounds": 1, "rounds": 1,
"type": "eq", "type": "eq",
"about": "Non-isolated knockout group with a nested non-isolated subgroup over existing text." "about": "Non-isolated knockout group with a nested non-isolated subgroup over existing text."
},
{
"id": "Embedded_font.pdf",
"file": "pdfs/Embedded_font.pdf",
"md5": "b68dd5a3e6833d1af94e295fe1d60285",
"rounds": 1,
"type": "eq"
} }
] ]