Skip to content

Commit 37c0a18

Browse files
committed
Cache the "raw" standard font data in the worker-thread (PR 12726 follow-up)
*This implementation is basically a copy of the pre-existing `builtInCMapCache` implementation.* For some, badly generated, PDF documents it's possible that we'll end up having to fetch the *same* standard font data over and over (which is obviously inefficient). While not common, it's certainly possible that a PDF document uses *custom* font names where the actual font then references one of the standard fonts; see e.g. issue 11399 for one such example. Note that I did suggest adding worker-thread caching of standard font data in PR 12726, however it wasn't deemed necessary at the time. Now that we have a real-world example that benefit from caching, I think that we should simply implement this now.
1 parent 6d88d8c commit 37c0a18

File tree

4 files changed

+47
-18
lines changed

4 files changed

+47
-18
lines changed

src/core/catalog.js

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Catalog {
7171

7272
this.fontCache = new RefSetCache();
7373
this.builtInCMapCache = new Map();
74+
this.standardFontDataCache = new Map();
7475
this.globalImageCache = new GlobalImageCache();
7576
this.pageKidsCountCache = new RefSetCache();
7677
this.pageIndexCache = new RefSetCache();
@@ -1020,6 +1021,7 @@ class Catalog {
10201021
}
10211022
this.fontCache.clear();
10221023
this.builtInCMapCache.clear();
1024+
this.standardFontDataCache.clear();
10231025
});
10241026
}
10251027

src/core/document.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class Page {
7979
globalIdFactory,
8080
fontCache,
8181
builtInCMapCache,
82+
standardFontDataCache,
8283
globalImageCache,
8384
nonBlendModesSet,
8485
xfaFactory,
@@ -90,6 +91,7 @@ class Page {
9091
this.ref = ref;
9192
this.fontCache = fontCache;
9293
this.builtInCMapCache = builtInCMapCache;
94+
this.standardFontDataCache = standardFontDataCache;
9395
this.globalImageCache = globalImageCache;
9496
this.nonBlendModesSet = nonBlendModesSet;
9597
this.evaluatorOptions = pdfManager.evaluatorOptions;
@@ -255,6 +257,7 @@ class Page {
255257
idFactory: this._localIdFactory,
256258
fontCache: this.fontCache,
257259
builtInCMapCache: this.builtInCMapCache,
260+
standardFontDataCache: this.standardFontDataCache,
258261
globalImageCache: this.globalImageCache,
259262
options: this.evaluatorOptions,
260263
});
@@ -321,6 +324,7 @@ class Page {
321324
idFactory: this._localIdFactory,
322325
fontCache: this.fontCache,
323326
builtInCMapCache: this.builtInCMapCache,
327+
standardFontDataCache: this.standardFontDataCache,
324328
globalImageCache: this.globalImageCache,
325329
options: this.evaluatorOptions,
326330
});
@@ -425,6 +429,7 @@ class Page {
425429
idFactory: this._localIdFactory,
426430
fontCache: this.fontCache,
427431
builtInCMapCache: this.builtInCMapCache,
432+
standardFontDataCache: this.standardFontDataCache,
428433
globalImageCache: this.globalImageCache,
429434
options: this.evaluatorOptions,
430435
});
@@ -878,7 +883,7 @@ class PDFDocument {
878883

879884
const options = Object.assign(
880885
Object.create(null),
881-
this.pdfManager.evaluatorOptions
886+
this.pdfManager.evaluatorOptions,
882887
);
883888
options.useSystemFonts = false;
884889

@@ -889,6 +894,7 @@ class PDFDocument {
889894
idFactory: this._globalIdFactory,
890895
fontCache: this.catalog.fontCache,
891896
builtInCMapCache: this.catalog.builtInCMapCache,
897+
standardFontDataCache: this.catalog.standardFontDataCache,
892898
options,
893899
});
894900
const operatorList = new OperatorList();
@@ -1148,6 +1154,7 @@ class PDFDocument {
11481154
globalIdFactory: this._globalIdFactory,
11491155
fontCache: catalog.fontCache,
11501156
builtInCMapCache: catalog.builtInCMapCache,
1157+
standardFontDataCache: catalog.standardFontDataCache,
11511158
globalImageCache: catalog.globalImageCache,
11521159
nonBlendModesSet: catalog.nonBlendModesSet,
11531160
xfaFactory: this.xfaFactory,
@@ -1170,6 +1177,7 @@ class PDFDocument {
11701177
globalIdFactory: this._globalIdFactory,
11711178
fontCache: catalog.fontCache,
11721179
builtInCMapCache: catalog.builtInCMapCache,
1180+
standardFontDataCache: catalog.standardFontDataCache,
11731181
globalImageCache: catalog.globalImageCache,
11741182
nonBlendModesSet: catalog.nonBlendModesSet,
11751183
xfaFactory: null,

src/core/evaluator.js

+35-17
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class PartialEvaluator {
207207
idFactory,
208208
fontCache,
209209
builtInCMapCache,
210+
standardFontDataCache,
210211
globalImageCache,
211212
options = null,
212213
}) {
@@ -216,6 +217,7 @@ class PartialEvaluator {
216217
this.idFactory = idFactory;
217218
this.fontCache = fontCache;
218219
this.builtInCMapCache = builtInCMapCache;
220+
this.standardFontDataCache = standardFontDataCache;
219221
this.globalImageCache = globalImageCache;
220222
this.options = options || DefaultPartialEvaluatorOptions;
221223
this.parsingType3Font = false;
@@ -390,40 +392,56 @@ class PartialEvaluator {
390392
}
391393

392394
async fetchStandardFontData(name) {
395+
const cachedData = this.standardFontDataCache.get(name);
396+
if (cachedData) {
397+
return new Stream(cachedData);
398+
}
399+
393400
// The symbol fonts are not consistent across platforms, always load the
394-
// font data for them.
401+
// standard font data for them.
395402
if (
396403
this.options.useSystemFonts &&
397404
name !== "Symbol" &&
398405
name !== "ZapfDingbats"
399406
) {
400407
return null;
401408
}
402-
const standardFontNameToFileName = getFontNameToFileMap();
403-
const filename = standardFontNameToFileName[name];
409+
410+
const standardFontNameToFileName = getFontNameToFileMap(),
411+
filename = standardFontNameToFileName[name];
412+
let data;
413+
404414
if (this.options.standardFontDataUrl !== null) {
405415
const url = `${this.options.standardFontDataUrl}${filename}`;
406416
const response = await fetch(url);
407417
if (!response.ok) {
408418
warn(
409-
`fetchStandardFontData failed to fetch file "${url}" with "${response.statusText}".`
419+
`fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".`
420+
);
421+
} else {
422+
data = await response.arrayBuffer();
423+
}
424+
} else {
425+
// Get the data on the main-thread instead.
426+
try {
427+
data = await this.handler.sendWithPromise("FetchStandardFontData", {
428+
filename,
429+
});
430+
} catch (e) {
431+
warn(
432+
`fetchStandardFontData: failed to fetch file "${filename}" with "${e}".`
410433
);
411-
return null;
412434
}
413-
return new Stream(await response.arrayBuffer());
414435
}
415-
// Get the data on the main thread instead.
416-
try {
417-
const data = await this.handler.sendWithPromise("FetchStandardFontData", {
418-
filename,
419-
});
420-
return new Stream(data);
421-
} catch (e) {
422-
warn(
423-
`fetchStandardFontData failed to fetch file "${filename}" with "${e}".`
424-
);
436+
437+
if (!data) {
438+
return null;
425439
}
426-
return null;
440+
// Cache the "raw" standard font data, to avoid fetching it repeateadly
441+
// (see e.g. issue 11399).
442+
this.standardFontDataCache.set(name, data);
443+
444+
return new Stream(data);
427445
}
428446

429447
async buildFormXObject(

test/unit/annotation_spec.js

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ describe("annotation", function () {
125125
idFactory: createIdFactory(/* pageIndex = */ 0),
126126
fontCache: new RefSetCache(),
127127
builtInCMapCache,
128+
standardFontDataCache: new Map(),
128129
});
129130
});
130131

0 commit comments

Comments
 (0)