Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/core/cff_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,12 @@ class CFFParser {
this.emptyPrivateDictionary(parentDict);
return;
}
// The Private DICT extends past the end of the font data, which means
// the embedded font is truncated; abort so the caller can substitute a
// system font instead of rendering blank glyphs (issue 7625).
if (offset + size > this.bytes.length) {
throw new FormatError("CFF Private DICT extends past end of font");
}

const privateDictEnd = offset + size;
const dictData = this.bytes.subarray(offset, privateDictEnd);
Expand Down
30 changes: 29 additions & 1 deletion src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -4728,7 +4728,35 @@ class PartialEvaluator {
const newProperties = await this.extractDataStructures(dict, properties);
this.extractWidths(dict, descriptor, newProperties);

return new Font(fontName.name, fontFile, newProperties, this.options);
const font = new Font(fontName.name, fontFile, newProperties, this.options);
// The embedded font may have been too corrupt to parse, in which case
// we ended up in the fallback path without a substitution selected.
// Try the substitution map now so text renders in a font close to what
// the document asked for (issue 7625).
if (
font.missingFile &&
!font.systemFontInfo &&
!isType3Font &&
this.options.useSystemFonts
) {
const standardFontName = getStandardFontName(fontName.name);
const substitution = getFontSubstitution(
this.systemFontCache,
this.idFactory,
this.options.standardFontDataUrl,
fontName.name,
standardFontName,
type
);
if (substitution) {
if (substitution.guessFallback) {
substitution.guessFallback = false;
substitution.css += `,${font.fallbackName}`;
}
font.systemFontInfo = substitution;
}
}
return font;
}

static buildFontPaths(font, glyphs, handler, evaluatorOptions) {
Expand Down
15 changes: 15 additions & 0 deletions src/core/type1_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,24 @@ class Type1Parser {
},
};
let token, length, data, lenIV;
// Some fonts (e.g. those embedded in issue18548.pdf) define a second
// `/Subrs` and `/CharStrings` block that the PostScript runtime selects
// conditionally (e.g. high-resolution variants). Testing with other
// viewers shows that none of them actually use these conditional blocks,
// so we can "safely" ignore them.
let subrsParsed = false;
let charStringsParsed = false;
while ((token = this.getToken()) !== null) {
if (token !== "/") {
continue;
}
token = this.getToken();
switch (token) {
case "CharStrings":
if (charStringsParsed) {
break;
}
charStringsParsed = true;
// The number immediately following CharStrings must be greater or
// equal to the number of CharStrings.
this.getToken();
Expand Down Expand Up @@ -610,6 +621,10 @@ class Type1Parser {
}
break;
case "Subrs":
if (subrsParsed) {
break;
}
subrsParsed = true;
this.readInt(); // num
this.getToken(); // read in 'array'
while (this.getToken() === "dup") {
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -922,3 +922,4 @@
!knockout_groups_test.pdf
!issue18032.pdf
!Embedded_font.pdf
!issue18548_reduced.pdf
Binary file added test/pdfs/issue18548_reduced.pdf
Binary file not shown.
1 change: 1 addition & 0 deletions test/pdfs/issue7625.pdf.link
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/mozilla/pdf.js/files/467169/Er.aestetik.en.loftestang.for.laering.pdf
17 changes: 17 additions & 0 deletions test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14303,5 +14303,22 @@
"md5": "b68dd5a3e6833d1af94e295fe1d60285",
"rounds": 1,
"type": "eq"
},
{
"id": "issue18548_reduced",
"file": "pdfs/issue18548_reduced.pdf",
"md5": "39d15f7f810bd89a4e5858df9c75ca4e",
"rounds": 1,
"type": "eq"
},
{
"id": "issue7625",
"file": "pdfs/issue7625.pdf",
"md5": "77ca0a41da767dca31ca45219e2ae202",
"link": true,
"rounds": 1,
"firstPage": 1,
"lastPage": 1,
"type": "eq"
}
]
Loading