Add a cache to avoid to load several times a local font

On my computer, it takes few tenths of a second to load a local font.
Since a font can be used several times in a document, the cache will
improve performances.
This commit is contained in:
Calixte Denizet 2023-05-10 15:31:07 +02:00
parent 2d2f7b315e
commit cfb908c999
6 changed files with 38 additions and 2 deletions

View File

@ -81,6 +81,7 @@ class Catalog {
this.pageKidsCountCache = new RefSetCache();
this.pageIndexCache = new RefSetCache();
this.nonBlendModesSet = new RefSet();
this.systemFontCache = new Map();
}
get version() {
@ -1062,6 +1063,7 @@ class Catalog {
this.fontCache.clear();
this.builtInCMapCache.clear();
this.standardFontDataCache.clear();
this.systemFontCache.clear();
}
async getPageDict(pageIndex) {

View File

@ -74,6 +74,7 @@ class Page {
builtInCMapCache,
standardFontDataCache,
globalImageCache,
systemFontCache,
nonBlendModesSet,
xfaFactory,
}) {
@ -86,6 +87,7 @@ class Page {
this.builtInCMapCache = builtInCMapCache;
this.standardFontDataCache = standardFontDataCache;
this.globalImageCache = globalImageCache;
this.systemFontCache = systemFontCache;
this.nonBlendModesSet = nonBlendModesSet;
this.evaluatorOptions = pdfManager.evaluatorOptions;
this.resourcesPromise = null;
@ -270,6 +272,7 @@ class Page {
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});
@ -321,6 +324,7 @@ class Page {
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});
@ -390,6 +394,7 @@ class Page {
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});
@ -533,6 +538,7 @@ class Page {
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});
@ -602,6 +608,7 @@ class Page {
builtInCMapCache: this.builtInCMapCache,
standardFontDataCache: this.standardFontDataCache,
globalImageCache: this.globalImageCache,
systemFontCache: this.systemFontCache,
options: this.evaluatorOptions,
});
@ -1476,6 +1483,7 @@ class PDFDocument {
builtInCMapCache: catalog.builtInCMapCache,
standardFontDataCache: catalog.standardFontDataCache,
globalImageCache: catalog.globalImageCache,
systemFontCache: catalog.systemFontCache,
nonBlendModesSet: catalog.nonBlendModesSet,
xfaFactory,
});
@ -1574,6 +1582,7 @@ class PDFDocument {
builtInCMapCache: catalog.builtInCMapCache,
standardFontDataCache: catalog.standardFontDataCache,
globalImageCache: catalog.globalImageCache,
systemFontCache: catalog.systemFontCache,
nonBlendModesSet: catalog.nonBlendModesSet,
xfaFactory: null,
})

View File

@ -215,6 +215,7 @@ class PartialEvaluator {
builtInCMapCache,
standardFontDataCache,
globalImageCache,
systemFontCache,
options = null,
}) {
this.xref = xref;
@ -225,6 +226,7 @@ class PartialEvaluator {
this.builtInCMapCache = builtInCMapCache;
this.standardFontDataCache = standardFontDataCache;
this.globalImageCache = globalImageCache;
this.systemFontCache = systemFontCache;
this.options = options || DefaultPartialEvaluatorOptions;
this.parsingType3Font = false;
@ -4197,6 +4199,7 @@ class PartialEvaluator {
properties.isInternalFont = !!file;
if (!properties.isInternalFont && this.options.useSystemFonts) {
properties.systemFontInfo = getFontSubstitution(
this.systemFontCache,
this.idFactory,
this.options.standardFontDataUrl,
baseFontName,
@ -4309,6 +4312,7 @@ class PartialEvaluator {
isInternalFont = !!fontFile;
if (!isInternalFont && this.options.useSystemFonts) {
systemFontInfo = getFontSubstitution(
this.systemFontCache,
this.idFactory,
this.options.standardFontDataUrl,
fontName.name,

View File

@ -374,6 +374,7 @@ function makeLocal(prepend, local) {
* }
* or use the FontFace API.
*
* @param {Map} systemFontCache The cache of local fonts.
* @param {Object} idFactory The ids factory.
* @param {String} localFontPath Path to the fonts directory.
* @param {String} baseFontName The font name to be substituted.
@ -382,6 +383,7 @@ function makeLocal(prepend, local) {
* @returns an Object with the CSS, the loaded name, the src and the style.
*/
function getFontSubstitution(
systemFontCache,
idFactory,
localFontPath,
baseFontName,
@ -393,6 +395,12 @@ function getFontSubstitution(
// just replace them by a dash.
baseFontName = normalizeFontName(baseFontName);
const key = baseFontName;
let substitutionInfo = systemFontCache.get(key);
if (substitutionInfo) {
return substitutionInfo;
}
// First, check if we've a substitution for the base font.
let substitution = substitutionMap.get(baseFontName);
if (!substitution) {
@ -416,6 +424,7 @@ function getFontSubstitution(
const loadedName = `${idFactory.getDocId()}_sf_${idFactory.createFontId()}`;
if (!substitution) {
if (!validateFontName(baseFontName)) {
systemFontCache.set(key, null);
// If the baseFontName is not valid we don't want to use it.
return null;
}
@ -427,12 +436,14 @@ function getFontSubstitution(
(bold && BOLD) ||
(italic && ITALIC) ||
NORMAL;
return {
substitutionInfo = {
css: `${loadedName},sans-serif`,
loadedName,
src: `local(${baseFontName})`,
style,
};
systemFontCache.set(key, substitutionInfo);
return substitutionInfo;
}
while (substitution.alias) {
@ -467,12 +478,14 @@ function getFontSubstitution(
src = `local(${baseFontName}),${src}`;
}
return {
substitutionInfo = {
css: `${loadedName},${ultimate}`,
loadedName,
src,
style,
};
systemFontCache.set(key, substitutionInfo);
return substitutionInfo;
}
export { getFontSubstitution };

View File

@ -25,6 +25,8 @@ import {
import { isNodeJS } from "../shared/is_node.js";
class FontLoader {
#systemFonts = new Set();
constructor({
ownerDocument = globalThis.document,
styleElement = null, // For testing only.
@ -69,6 +71,7 @@ class FontLoader {
this._document.fonts.delete(nativeFontFace);
}
this.nativeFontFaces.clear();
this.#systemFonts.clear();
if (this.styleElement) {
// Note: ChildNode.remove doesn't throw if the parentNode is undefined.
@ -78,6 +81,9 @@ class FontLoader {
}
async loadSystemFont(info) {
if (!info || this.#systemFonts.has(info.loadedName)) {
return;
}
assert(
!this.disableFontFace,
"loadSystemFont shouldn't be called when `disableFontFace` is set."
@ -89,6 +95,7 @@ class FontLoader {
this.addNativeFontFace(fontFace);
try {
await fontFace.load();
this.#systemFonts.add(loadedName);
} catch {
warn(
`Cannot load system font: ${loadedName} for style ${style.style} and weight ${style.weight}.`

View File

@ -130,6 +130,7 @@ describe("annotation", function () {
fontCache: new RefSetCache(),
builtInCMapCache,
standardFontDataCache: new Map(),
systemFontCache: new Map(),
});
});