Skip to content

Commit

Permalink
Cache the "raw" standard font data in the worker-thread (PR 12726 fol…
Browse files Browse the repository at this point in the history
…low-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.
  • Loading branch information
Snuffleupagus committed Jun 8, 2021
1 parent d639a27 commit d5bd3f6
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 17 deletions.
2 changes: 2 additions & 0 deletions src/core/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class Catalog {

this.fontCache = new RefSetCache();
this.builtInCMapCache = new Map();
this.standardFontDataCache = new Map();
this.globalImageCache = new GlobalImageCache();
this.pageKidsCountCache = new RefSetCache();
this.pageIndexCache = new RefSetCache();
Expand Down Expand Up @@ -1020,6 +1021,7 @@ class Catalog {
}
this.fontCache.clear();
this.builtInCMapCache.clear();
this.standardFontDataCache.clear();
});
}

Expand Down
8 changes: 8 additions & 0 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class Page {
globalIdFactory,
fontCache,
builtInCMapCache,
standardFontDataCache,
globalImageCache,
nonBlendModesSet,
xfaFactory,
Expand All @@ -90,6 +91,7 @@ class Page {
this.ref = ref;
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.standardFontDataCache = standardFontDataCache;
this.globalImageCache = globalImageCache;
this.nonBlendModesSet = nonBlendModesSet;
this.evaluatorOptions = pdfManager.evaluatorOptions;
Expand Down Expand Up @@ -255,6 +257,7 @@ class Page {
idFactory: this._localIdFactory,
fontCache: this.fontCache,
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
options: this.evaluatorOptions,
});
Expand Down Expand Up @@ -321,6 +324,7 @@ class Page {
idFactory: this._localIdFactory,
fontCache: this.fontCache,
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
options: this.evaluatorOptions,
});
Expand Down Expand Up @@ -425,6 +429,7 @@ class Page {
idFactory: this._localIdFactory,
fontCache: this.fontCache,
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
options: this.evaluatorOptions,
});
Expand Down Expand Up @@ -883,6 +888,7 @@ class PDFDocument {
idFactory: this._globalIdFactory,
fontCache: this.catalog.fontCache,
builtInCMapCache: this.catalog.builtInCMapCache,
standardFontDataCache: this.catalog.standardFontDataCache,
});
const operatorList = new OperatorList();
const initialState = {
Expand Down Expand Up @@ -1141,6 +1147,7 @@ class PDFDocument {
globalIdFactory: this._globalIdFactory,
fontCache: catalog.fontCache,
builtInCMapCache: catalog.builtInCMapCache,
standardFontDataCache: catalog.standardFontDataCache,
globalImageCache: catalog.globalImageCache,
nonBlendModesSet: catalog.nonBlendModesSet,
xfaFactory: this.xfaFactory,
Expand All @@ -1163,6 +1170,7 @@ class PDFDocument {
globalIdFactory: this._globalIdFactory,
fontCache: catalog.fontCache,
builtInCMapCache: catalog.builtInCMapCache,
standardFontDataCache: catalog.standardFontDataCache,
globalImageCache: catalog.globalImageCache,
nonBlendModesSet: catalog.nonBlendModesSet,
xfaFactory: null,
Expand Down
52 changes: 35 additions & 17 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ class PartialEvaluator {
idFactory,
fontCache,
builtInCMapCache,
standardFontDataCache,
globalImageCache,
options = null,
}) {
Expand All @@ -214,6 +215,7 @@ class PartialEvaluator {
this.idFactory = idFactory;
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.standardFontDataCache = standardFontDataCache;
this.globalImageCache = globalImageCache;
this.options = options || DefaultPartialEvaluatorOptions;
this.parsingType3Font = false;
Expand Down Expand Up @@ -386,40 +388,56 @@ class PartialEvaluator {
}

async fetchStandardFontData(name) {
const cachedData = this.standardFontDataCache.get(name);
if (cachedData) {
return new Stream(cachedData);
}

// The symbol fonts are not consistent across platforms, always load the
// font data for them.
// standard font data for them.
if (
this.options.useSystemFonts &&
name !== "Symbol" &&
name !== "ZapfDingbats"
) {
return null;
}
const standardFontNameToFileName = getStdFontNameToFileMap();
const filename = standardFontNameToFileName[name];

const standardFontNameToFileName = getStdFontNameToFileMap(),
filename = standardFontNameToFileName[name];
let data;

if (this.options.standardFontDataUrl !== null) {
const url = `${this.options.standardFontDataUrl}${filename}.pfb`;
const response = await fetch(url);
if (!response.ok) {
warn(
`fetchStandardFontData failed to fetch file "${url}" with "${response.statusText}".`
`fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".`
);
} else {
data = await response.arrayBuffer();
}
} else {
// Get the data on the main-thread instead.
try {
data = await this.handler.sendWithPromise("FetchStandardFontData", {
filename,
});
} catch (e) {
warn(
`fetchStandardFontData: failed to fetch file "${filename}" with "${e}".`
);
return null;
}
return new Stream(await response.arrayBuffer());
}
// Get the data on the main thread instead.
try {
const data = await this.handler.sendWithPromise("FetchStandardFontData", {
filename,
});
return new Stream(data);
} catch (e) {
warn(
`fetchStandardFontData failed to fetch file "${filename}" with "${e}".`
);

if (!data) {
return null;
}
return null;
// Cache the "raw" standard font data, to avoid fetching it repeateadly
// (see e.g. issue 11399).
this.standardFontDataCache.set(name, data);

return new Stream(data);
}

async buildFormXObject(
Expand Down
1 change: 1 addition & 0 deletions test/unit/annotation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ describe("annotation", function () {
idFactory: createIdFactory(/* pageIndex = */ 0),
fontCache: new RefSetCache(),
builtInCMapCache,
standardFontDataCache: new Map(),
});
});

Expand Down

0 comments on commit d5bd3f6

Please sign in to comment.