Skip to content

Commit 50c573d

Browse files
Merge pull request #19563 from Snuffleupagus/loadType3Data-once
Invoke `TranslatedFont.prototype.loadType3Data` only *once* per font
2 parents 56a683b + bdfa968 commit 50c573d

File tree

2 files changed

+48
-59
lines changed

2 files changed

+48
-59
lines changed

src/core/catalog.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,9 +1177,7 @@ class Catalog {
11771177
this.pageDictCache.clear();
11781178
this.nonBlendModesSet.clear();
11791179

1180-
const translatedFonts = await Promise.all(this.fontCache);
1181-
1182-
for (const { dict } of translatedFonts) {
1180+
for (const { dict } of await Promise.all(this.fontCache)) {
11831181
delete dict.cacheKey;
11841182
}
11851183
this.fontCache.clear();

src/core/evaluator.js

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,27 +1046,19 @@ class PartialEvaluator {
10461046
) {
10471047
const fontName = fontArgs?.[0] instanceof Name ? fontArgs[0].name : null;
10481048

1049-
let translated = await this.loadFont(
1049+
const translated = await this.loadFont(
10501050
fontName,
10511051
fontRef,
10521052
resources,
1053+
task,
10531054
fallbackFontDict,
10541055
cssFontInfo
10551056
);
10561057

10571058
if (translated.font.isType3Font) {
1058-
try {
1059-
await translated.loadType3Data(this, resources, task);
1060-
// Add the dependencies to the parent operatorList so they are
1061-
// resolved before Type3 operatorLists are executed synchronously.
1062-
operatorList.addDependencies(translated.type3Dependencies);
1063-
} catch (reason) {
1064-
translated = new TranslatedFont({
1065-
loadedName: "g_font_error",
1066-
font: new ErrorFont(`Type3 font load error: ${reason}`),
1067-
dict: translated.font,
1068-
});
1069-
}
1059+
// Add the dependencies to the parent operatorList so they are
1060+
// resolved before Type3 operatorLists are executed synchronously.
1061+
operatorList.addDependencies(translated.type3Dependencies);
10701062
}
10711063

10721064
state.font = translated.font;
@@ -1228,6 +1220,7 @@ class PartialEvaluator {
12281220
fontName,
12291221
font,
12301222
resources,
1223+
task,
12311224
fallbackFontDict = null,
12321225
cssFontInfo = null
12331226
) {
@@ -1356,14 +1349,21 @@ class PartialEvaluator {
13561349
font.loadedName = `${this.idFactory.getDocId()}_${fontID}`;
13571350

13581351
this.translateFont(preEvaluatedFont)
1359-
.then(translatedFont => {
1360-
resolve(
1361-
new TranslatedFont({
1362-
loadedName: font.loadedName,
1363-
font: translatedFont,
1364-
dict: font,
1365-
})
1366-
);
1352+
.then(async translatedFont => {
1353+
const translated = new TranslatedFont({
1354+
loadedName: font.loadedName,
1355+
font: translatedFont,
1356+
dict: font,
1357+
});
1358+
1359+
if (translatedFont.isType3Font) {
1360+
try {
1361+
await translated.loadType3Data(this, resources, task);
1362+
} catch (reason) {
1363+
throw new Error(`Type3 font load error: ${reason}`);
1364+
}
1365+
}
1366+
resolve(translated);
13671367
})
13681368
.catch(reason => {
13691369
// TODO reject?
@@ -1372,9 +1372,7 @@ class PartialEvaluator {
13721372
resolve(
13731373
new TranslatedFont({
13741374
loadedName: font.loadedName,
1375-
font: new ErrorFont(
1376-
reason instanceof Error ? reason.message : reason
1377-
),
1375+
font: new ErrorFont(reason?.message),
13781376
dict: font,
13791377
})
13801378
);
@@ -2616,16 +2614,12 @@ class PartialEvaluator {
26162614
}
26172615

26182616
async function handleSetFont(fontName, fontRef) {
2619-
const translated = await self.loadFont(fontName, fontRef, resources);
2620-
2621-
if (translated.font.isType3Font) {
2622-
try {
2623-
await translated.loadType3Data(self, resources, task);
2624-
} catch {
2625-
// Ignore Type3-parsing errors, since we only use `loadType3Data`
2626-
// here to ensure that we'll always obtain a useful /FontBBox.
2627-
}
2628-
}
2617+
const translated = await self.loadFont(
2618+
fontName,
2619+
fontRef,
2620+
resources,
2621+
task
2622+
);
26292623

26302624
textState.loadedName = translated.loadedName;
26312625
textState.font = translated.font;
@@ -4602,20 +4596,22 @@ class PartialEvaluator {
46024596
}
46034597

46044598
class TranslatedFont {
4599+
#sent = false;
4600+
4601+
#type3Loaded = null;
4602+
46054603
constructor({ loadedName, font, dict }) {
46064604
this.loadedName = loadedName;
46074605
this.font = font;
46084606
this.dict = dict;
4609-
this.type3Loaded = null;
46104607
this.type3Dependencies = font.isType3Font ? new Set() : null;
4611-
this.sent = false;
46124608
}
46134609

46144610
send(handler) {
4615-
if (this.sent) {
4611+
if (this.#sent) {
46164612
return;
46174613
}
4618-
this.sent = true;
4614+
this.#sent = true;
46194615

46204616
handler.send("commonobj", [
46214617
this.loadedName,
@@ -4645,12 +4641,12 @@ class TranslatedFont {
46454641
}
46464642

46474643
loadType3Data(evaluator, resources, task) {
4648-
if (this.type3Loaded) {
4649-
return this.type3Loaded;
4650-
}
4651-
if (!this.font.isType3Font) {
4652-
throw new Error("Must be a Type3 font.");
4644+
if (this.#type3Loaded) {
4645+
return this.#type3Loaded;
46534646
}
4647+
const { font, type3Dependencies } = this;
4648+
assert(font.isType3Font, "Must be a Type3 font.");
4649+
46544650
// When parsing Type3 glyphs, always ignore them if there are errors.
46554651
// Compared to the parsing of e.g. an entire page, it doesn't really
46564652
// make sense to only be able to render a Type3 glyph partially.
@@ -4662,14 +4658,12 @@ class TranslatedFont {
46624658
}
46634659
type3Evaluator.type3FontRefs = type3FontRefs;
46644660

4665-
const translatedFont = this.font,
4666-
type3Dependencies = this.type3Dependencies;
46674661
let loadCharProcsPromise = Promise.resolve();
46684662
const charProcs = this.dict.get("CharProcs");
46694663
const fontResources = this.dict.get("Resources") || resources;
46704664
const charProcOperatorList = Object.create(null);
46714665

4672-
const fontBBox = Util.normalizeRect(translatedFont.bbox || [0, 0, 0, 0]),
4666+
const fontBBox = Util.normalizeRect(font.bbox || [0, 0, 0, 0]),
46734667
width = fontBBox[2] - fontBBox[0],
46744668
height = fontBBox[3] - fontBBox[1];
46754669
const fontBBoxSize = Math.hypot(width, height);
@@ -4693,7 +4687,7 @@ class TranslatedFont {
46934687
// colour-related parameters) in the graphics state;
46944688
// any use of such operators shall be ignored."
46954689
if (operatorList.fnArray[0] === OPS.setCharWidthAndBounds) {
4696-
this._removeType3ColorOperators(operatorList, fontBBoxSize);
4690+
this.#removeType3ColorOperators(operatorList, fontBBoxSize);
46974691
}
46984692
charProcOperatorList[key] = operatorList.getIR();
46994693

@@ -4708,20 +4702,17 @@ class TranslatedFont {
47084702
});
47094703
});
47104704
}
4711-
this.type3Loaded = loadCharProcsPromise.then(() => {
4712-
translatedFont.charProcOperatorList = charProcOperatorList;
4705+
this.#type3Loaded = loadCharProcsPromise.then(() => {
4706+
font.charProcOperatorList = charProcOperatorList;
47134707
if (this._bbox) {
4714-
translatedFont.isCharBBox = true;
4715-
translatedFont.bbox = this._bbox;
4708+
font.isCharBBox = true;
4709+
font.bbox = this._bbox;
47164710
}
47174711
});
4718-
return this.type3Loaded;
4712+
return this.#type3Loaded;
47194713
}
47204714

4721-
/**
4722-
* @private
4723-
*/
4724-
_removeType3ColorOperators(operatorList, fontBBoxSize = NaN) {
4715+
#removeType3ColorOperators(operatorList, fontBBoxSize = NaN) {
47254716
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
47264717
assert(
47274718
operatorList.fnArray[0] === OPS.setCharWidthAndBounds,

0 commit comments

Comments
 (0)