Merge pull request #11930 from Snuffleupagus/LocalImageCache

Improve the *local* image caching in `PartialEvaluator.getOperatorList`
This commit is contained in:
Tim van der Meij 2020-05-28 00:12:37 +02:00 committed by GitHub
commit fe5689705d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 22 deletions

View File

@ -79,6 +79,7 @@ import { DecodeStream } from "./stream.js";
import { getGlyphsUnicode } from "./glyphlist.js";
import { getMetrics } from "./metrics.js";
import { isPDFFunction } from "./function.js";
import { LocalImageCache } from "./image_utils.js";
import { MurmurHash3_64 } from "./murmurhash3.js";
import { OperatorList } from "./operator_list.js";
import { PDFImage } from "./image.js";
@ -444,7 +445,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
isInline = false,
operatorList,
cacheKey,
imageCache,
localImageCache,
}) {
var dict = image.dict;
const imageRef = dict.objId;
@ -491,10 +492,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
operatorList.addOp(OPS.paintImageMaskXObject, args);
if (cacheKey) {
imageCache[cacheKey] = {
localImageCache.set(cacheKey, imageRef, {
fn: OPS.paintImageMaskXObject,
args,
};
});
}
return undefined;
}
@ -598,10 +599,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
operatorList.addOp(OPS.paintImageXObject, args);
if (cacheKey) {
imageCache[cacheKey] = {
localImageCache.set(cacheKey, imageRef, {
fn: OPS.paintImageXObject,
args,
};
});
if (imageRef) {
this.globalImageCache.addPageIndex(imageRef, this.pageIndex);
@ -1201,7 +1202,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var self = this;
var xref = this.xref;
let parsingText = false;
var imageCache = Object.create(null);
const localImageCache = new LocalImageCache();
var xobjs = resources.get("XObject") || Dict.empty;
var patterns = resources.get("Pattern") || Dict.empty;
@ -1248,10 +1249,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case OPS.paintXObject:
// eagerly compile XForm objects
var name = args[0].name;
if (name && imageCache[name] !== undefined) {
operatorList.addOp(imageCache[name].fn, imageCache[name].args);
args = null;
continue;
if (name) {
const localImage = localImageCache.getByName(name);
if (localImage) {
operatorList.addOp(localImage.fn, localImage.args);
args = null;
continue;
}
}
next(
@ -1264,11 +1268,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
let xobj = xobjs.getRaw(name);
if (xobj instanceof Ref) {
const localImage = localImageCache.getByRef(xobj);
if (localImage) {
operatorList.addOp(localImage.fn, localImage.args);
resolveXObject();
return;
}
const globalImage = self.globalImageCache.getData(
xobj,
self.pageIndex
);
if (globalImage) {
operatorList.addDependency(globalImage.objId);
operatorList.addOp(globalImage.fn, globalImage.args);
@ -1276,6 +1287,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
resolveXObject();
return;
}
xobj = xref.fetch(xobj);
}
@ -1316,7 +1328,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
image: xobj,
operatorList,
cacheKey: name,
imageCache,
localImageCache,
})
.then(resolveXObject, rejectXObject);
return;
@ -1375,9 +1387,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case OPS.endInlineImage:
var cacheKey = args[0].cacheKey;
if (cacheKey) {
var cacheEntry = imageCache[cacheKey];
if (cacheEntry !== undefined) {
operatorList.addOp(cacheEntry.fn, cacheEntry.args);
const localImage = localImageCache.getByName(cacheKey);
if (localImage) {
operatorList.addOp(localImage.fn, localImage.args);
args = null;
continue;
}
@ -1389,7 +1401,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
isInline: true,
operatorList,
cacheKey,
imageCache,
localImageCache,
})
);
return;
@ -1712,7 +1724,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
var xobjs = null;
var skipEmptyXObjs = Object.create(null);
const emptyXObjectCache = new LocalImageCache();
var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
@ -2188,7 +2200,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var name = args[0].name;
if (name && skipEmptyXObjs[name] !== undefined) {
if (name && emptyXObjectCache.getByName(name)) {
break;
}
@ -2200,7 +2212,16 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
);
}
const xobj = xobjs.get(name);
let xobj = xobjs.getRaw(name);
if (xobj instanceof Ref) {
if (emptyXObjectCache.getByRef(xobj)) {
resolveXObject();
return;
}
xobj = xref.fetch(xobj);
}
if (!xobj) {
resolveXObject();
return;
@ -2215,7 +2236,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
if (type.name !== "Form") {
skipEmptyXObjs[name] = true;
emptyXObjectCache.set(name, xobj.dict.objId, true);
resolveXObject();
return;
}
@ -2266,7 +2288,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
})
.then(function () {
if (!sinkWrapper.enqueueInvoked) {
skipEmptyXObjs[name] = true;
emptyXObjectCache.set(name, xobj.dict.objId, true);
}
resolveXObject();
}, rejectXObject);

View File

@ -17,6 +17,45 @@
import { assert, info, shadow } from "../shared/util.js";
import { RefSetCache } from "./primitives.js";
class LocalImageCache {
constructor() {
this._nameRefMap = new Map();
this._imageMap = new Map();
this._imageCache = new RefSetCache();
}
getByName(name) {
const ref = this._nameRefMap.get(name);
if (ref) {
return this.getByRef(ref);
}
return this._imageMap.get(name) || null;
}
getByRef(ref) {
return this._imageCache.get(ref) || null;
}
set(name, ref = null, data) {
if (!name) {
throw new Error('LocalImageCache.set - expected "name" argument.');
}
if (ref) {
if (this._imageCache.has(ref)) {
return;
}
this._nameRefMap.set(name, ref);
this._imageCache.put(ref, data);
return;
}
// name
if (this._imageMap.has(name)) {
return;
}
this._imageMap.set(name, data);
}
}
class GlobalImageCache {
static get NUM_PAGES_THRESHOLD() {
return shadow(this, "NUM_PAGES_THRESHOLD", 2);
@ -111,4 +150,4 @@ class GlobalImageCache {
}
}
export { GlobalImageCache };
export { LocalImageCache, GlobalImageCache };