Re-factor the LocalTilingPatternCache to cache by Ref rather than Name (PR 12458 follow-up, issue 13780)

This way there cannot be any *incorrect* cache hits, since Refs are guaranteed to be unique.
Please note that the reason for caching by Ref rather than doing something along the lines of the `localShadingPatternCache` (which uses a `Map` directly), is that TilingPatterns are streams and those cannot be cached on the `XRef`-instance (this way we avoid unnecessary parsing).
This commit is contained in:
Jonas Jenwald 2021-08-18 12:49:01 +02:00
parent 8ee5acd85d
commit 5f25fea0fe
2 changed files with 16 additions and 26 deletions

View File

@ -795,7 +795,6 @@ class PartialEvaluator {
patternDict,
operatorList,
task,
cacheKey,
localTilingPatternCache
) {
// Create an IR of the pattern code.
@ -825,8 +824,8 @@ class PartialEvaluator {
operatorList.addDependencies(tilingOpList.dependencies);
operatorList.addOp(fn, tilingPatternIR);
if (cacheKey) {
localTilingPatternCache.set(cacheKey, patternDict.objId, {
if (patternDict.objId) {
localTilingPatternCache.set(/* name = */ null, patternDict.objId, {
operatorListIR,
dict: patternDict,
});
@ -1356,9 +1355,11 @@ class PartialEvaluator {
const patternName = args.pop();
// SCN/scn applies patterns along with normal colors
if (patternName instanceof Name) {
const name = patternName.name;
const rawPattern = patterns.getRaw(patternName.name);
const localTilingPattern = localTilingPatternCache.getByName(name);
const localTilingPattern =
rawPattern instanceof Ref &&
localTilingPatternCache.getByRef(rawPattern);
if (localTilingPattern) {
try {
const color = cs.base ? cs.base.getRgb(args, 0) : null;
@ -1373,11 +1374,8 @@ class PartialEvaluator {
// Handle any errors during normal TilingPattern parsing.
}
}
// TODO: Attempt to lookup cached TilingPatterns by reference as well,
// if and only if there are PDF documents where doing so would
// significantly improve performance.
const pattern = patterns.get(name);
const pattern = this.xref.fetchIfRef(rawPattern);
if (pattern) {
const dict = isStream(pattern) ? pattern.dict : pattern;
const typeNum = dict.get("PatternType");
@ -1392,7 +1390,6 @@ class PartialEvaluator {
dict,
operatorList,
task,
/* cacheKey = */ name,
localTilingPatternCache
);
} else if (typeNum === PatternType.SHADING) {

View File

@ -135,25 +135,18 @@ class LocalGStateCache extends BaseLocalCache {
}
class LocalTilingPatternCache extends BaseLocalCache {
set(name, ref = null, data) {
if (typeof name !== "string") {
throw new Error(
'LocalTilingPatternCache.set - expected "name" argument.'
);
constructor(options) {
super({ onlyRefs: true });
}
set(name = null, ref, data) {
if (!ref) {
throw new Error('LocalTilingPatternCache.set - expected "ref" argument.');
}
if (ref) {
if (this._imageCache.has(ref)) {
return;
}
this._nameRefMap.set(name, ref);
this._imageCache.put(ref, data);
if (this._imageCache.has(ref)) {
return;
}
// name
if (this._imageMap.has(name)) {
return;
}
this._imageMap.set(name, data);
this._imageCache.put(ref, data);
}
}