Merge pull request #12583 from Snuffleupagus/nonBlendModesSet

Add global caching, for /Resources without blend modes, and use it to reduce repeated fetching/parsing in `PartialEvaluator.hasBlendModes`
This commit is contained in:
Tim van der Meij 2020-11-05 23:53:39 +01:00 committed by GitHub
commit 99ac2d1036
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 5 deletions

View File

@ -76,6 +76,7 @@ class Page {
fontCache,
builtInCMapCache,
globalImageCache,
nonBlendModesSet,
}) {
this.pdfManager = pdfManager;
this.pageIndex = pageIndex;
@ -85,6 +86,7 @@ class Page {
this.fontCache = fontCache;
this.builtInCMapCache = builtInCMapCache;
this.globalImageCache = globalImageCache;
this.nonBlendModesSet = nonBlendModesSet;
this.evaluatorOptions = pdfManager.evaluatorOptions;
this.resourcesPromise = null;
@ -312,7 +314,10 @@ class Page {
const opList = new OperatorList(intent, sink);
handler.send("StartRenderPage", {
transparency: partialEvaluator.hasBlendModes(this.resources),
transparency: partialEvaluator.hasBlendModes(
this.resources,
this.nonBlendModesSet
),
pageIndex: this.pageIndex,
intent,
});
@ -917,6 +922,7 @@ class PDFDocument {
fontCache: catalog.fontCache,
builtInCMapCache: catalog.builtInCMapCache,
globalImageCache: catalog.globalImageCache,
nonBlendModesSet: catalog.nonBlendModesSet,
});
}));
}

View File

@ -239,12 +239,15 @@ class PartialEvaluator {
return newEvaluator;
}
hasBlendModes(resources) {
hasBlendModes(resources, nonBlendModesSet) {
if (!(resources instanceof Dict)) {
return false;
}
if (resources.objId && nonBlendModesSet.has(resources.objId)) {
return false;
}
const processed = new RefSet();
const processed = new RefSet(nonBlendModesSet);
if (resources.objId) {
processed.put(resources.objId);
}
@ -344,6 +347,13 @@ class PartialEvaluator {
}
}
}
// When no blend modes exist, there's no need re-fetch/re-parse any of the
// processed `Ref`s again for subsequent pages. This helps reduce redundant
// `XRef.fetch` calls for some documents (e.g. issue6961.pdf).
processed.forEach(ref => {
nonBlendModesSet.put(ref);
});
return false;
}

View File

@ -76,6 +76,7 @@ class Catalog {
this.builtInCMapCache = new Map();
this.globalImageCache = new GlobalImageCache();
this.pageKidsCountCache = new RefSetCache();
this.nonBlendModesSet = new RefSet();
}
get version() {
@ -937,6 +938,7 @@ class Catalog {
clearPrimitiveCaches();
this.globalImageCache.clear(/* onlyData = */ manuallyTriggered);
this.pageKidsCountCache.clear();
this.nonBlendModesSet.clear();
const promises = [];
this.fontCache.forEach(function (promise) {

View File

@ -277,8 +277,16 @@ var Ref = (function RefClosure() {
// The reference is identified by number and generation.
// This structure stores only one instance of the reference.
class RefSet {
constructor() {
this._set = new Set();
constructor(parent = null) {
if (
(typeof PDFJSDev === "undefined" ||
PDFJSDev.test("!PRODUCTION || TESTING")) &&
parent &&
!(parent instanceof RefSet)
) {
unreachable('RefSet: Invalid "parent" value.');
}
this._set = new Set(parent && parent._set);
}
has(ref) {
@ -292,6 +300,16 @@ class RefSet {
remove(ref) {
this._set.delete(ref.toString());
}
forEach(callback) {
for (const ref of this._set.values()) {
callback(ref);
}
}
clear() {
this._set.clear();
}
}
class RefSetCache {