Merge pull request #12034 from Snuffleupagus/Function-local-cache-3
Add local caching of `Function`s, by reference, in the `PDFFunctionFactory` (issue 2541)
This commit is contained in:
commit
29548ad498
@ -535,7 +535,7 @@ class ColorSpace {
|
||||
const name = xref.fetchIfRef(cs[1]);
|
||||
numComps = Array.isArray(name) ? name.length : 1;
|
||||
alt = this.parseToIR(cs[2], xref, resources, pdfFunctionFactory);
|
||||
const tintFn = pdfFunctionFactory.create(xref.fetchIfRef(cs[3]));
|
||||
const tintFn = pdfFunctionFactory.create(cs[3]);
|
||||
return ["AlternateCS", numComps, alt, tintFn];
|
||||
case "Lab":
|
||||
params = xref.fetchIfRef(cs[1]);
|
||||
|
@ -53,7 +53,6 @@ import { calculateMD5 } from "./crypto.js";
|
||||
import { Linearization } from "./parser.js";
|
||||
import { OperatorList } from "./operator_list.js";
|
||||
import { PartialEvaluator } from "./evaluator.js";
|
||||
import { PDFFunctionFactory } from "./function.js";
|
||||
|
||||
const DEFAULT_USER_UNIT = 1.0;
|
||||
const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
|
||||
@ -75,7 +74,6 @@ class Page {
|
||||
fontCache,
|
||||
builtInCMapCache,
|
||||
globalImageCache,
|
||||
pdfFunctionFactory,
|
||||
}) {
|
||||
this.pdfManager = pdfManager;
|
||||
this.pageIndex = pageIndex;
|
||||
@ -85,7 +83,6 @@ class Page {
|
||||
this.fontCache = fontCache;
|
||||
this.builtInCMapCache = builtInCMapCache;
|
||||
this.globalImageCache = globalImageCache;
|
||||
this.pdfFunctionFactory = pdfFunctionFactory;
|
||||
this.evaluatorOptions = pdfManager.evaluatorOptions;
|
||||
this.resourcesPromise = null;
|
||||
|
||||
@ -265,7 +262,6 @@ class Page {
|
||||
builtInCMapCache: this.builtInCMapCache,
|
||||
globalImageCache: this.globalImageCache,
|
||||
options: this.evaluatorOptions,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
});
|
||||
|
||||
const dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
|
||||
@ -359,7 +355,6 @@ class Page {
|
||||
builtInCMapCache: this.builtInCMapCache,
|
||||
globalImageCache: this.globalImageCache,
|
||||
options: this.evaluatorOptions,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
});
|
||||
|
||||
return partialEvaluator.getTextContent({
|
||||
@ -508,11 +503,6 @@ class PDFDocument {
|
||||
this.pdfManager = pdfManager;
|
||||
this.stream = stream;
|
||||
this.xref = new XRef(stream, pdfManager);
|
||||
|
||||
this.pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref: this.xref,
|
||||
isEvalSupported: pdfManager.evaluatorOptions.isEvalSupported,
|
||||
});
|
||||
this._pagePromises = [];
|
||||
}
|
||||
|
||||
@ -821,7 +811,6 @@ class PDFDocument {
|
||||
fontCache: catalog.fontCache,
|
||||
builtInCMapCache: catalog.builtInCMapCache,
|
||||
globalImageCache: catalog.globalImageCache,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
isNum,
|
||||
isString,
|
||||
OPS,
|
||||
shadow,
|
||||
stringToPDFString,
|
||||
TextRenderingMode,
|
||||
UNSUPPORTED_FEATURES,
|
||||
@ -72,6 +73,7 @@ import {
|
||||
getSymbolsFonts,
|
||||
} from "./standard_fonts.js";
|
||||
import { getTilingPatternIR, Pattern } from "./pattern.js";
|
||||
import { isPDFFunction, PDFFunctionFactory } from "./function.js";
|
||||
import { Lexer, Parser } from "./parser.js";
|
||||
import { LocalColorSpaceCache, LocalImageCache } from "./image_utils.js";
|
||||
import { bidi } from "./bidi.js";
|
||||
@ -79,7 +81,6 @@ import { ColorSpace } from "./colorspace.js";
|
||||
import { DecodeStream } from "./stream.js";
|
||||
import { getGlyphsUnicode } from "./glyphlist.js";
|
||||
import { getMetrics } from "./metrics.js";
|
||||
import { isPDFFunction } from "./function.js";
|
||||
import { MurmurHash3_64 } from "./murmurhash3.js";
|
||||
import { OperatorList } from "./operator_list.js";
|
||||
import { PDFImage } from "./image.js";
|
||||
@ -103,7 +104,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
builtInCMapCache,
|
||||
globalImageCache,
|
||||
options = null,
|
||||
pdfFunctionFactory,
|
||||
}) {
|
||||
this.xref = xref;
|
||||
this.handler = handler;
|
||||
@ -113,7 +113,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
this.builtInCMapCache = builtInCMapCache;
|
||||
this.globalImageCache = globalImageCache;
|
||||
this.options = options || DefaultPartialEvaluatorOptions;
|
||||
this.pdfFunctionFactory = pdfFunctionFactory;
|
||||
this.parsingType3Font = false;
|
||||
|
||||
this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this);
|
||||
@ -207,6 +206,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
SHADING_PATTERN = 2;
|
||||
|
||||
PartialEvaluator.prototype = {
|
||||
/**
|
||||
* Since Functions are only cached (locally) by reference, we can share one
|
||||
* `PDFFunctionFactory` instance within this `PartialEvaluator` instance.
|
||||
*/
|
||||
get _pdfFunctionFactory() {
|
||||
const pdfFunctionFactory = new PDFFunctionFactory({
|
||||
xref: this.xref,
|
||||
isEvalSupported: this.options.isEvalSupported,
|
||||
});
|
||||
return shadow(this, "_pdfFunctionFactory", pdfFunctionFactory);
|
||||
},
|
||||
|
||||
clone(newOptions = DefaultPartialEvaluatorOptions) {
|
||||
var newEvaluator = Object.create(this);
|
||||
newEvaluator.options = newOptions;
|
||||
@ -552,7 +563,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
res: resources,
|
||||
image,
|
||||
isInline,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
pdfFunctionFactory: this._pdfFunctionFactory,
|
||||
localColorSpaceCache,
|
||||
});
|
||||
// We force the use of RGBA_32BPP images here, because we can't handle
|
||||
@ -589,7 +600,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
res: resources,
|
||||
image,
|
||||
isInline,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
pdfFunctionFactory: this._pdfFunctionFactory,
|
||||
localColorSpaceCache,
|
||||
})
|
||||
.then(imageObj => {
|
||||
@ -651,7 +662,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
// we will build a map of integer values in range 0..255 to be fast.
|
||||
var transferObj = smask.get("TR");
|
||||
if (isPDFFunction(transferObj)) {
|
||||
const transferFn = this.pdfFunctionFactory.create(transferObj);
|
||||
const transferFn = this._pdfFunctionFactory.create(transferObj);
|
||||
var transferMap = new Uint8Array(256);
|
||||
var tmp = new Float32Array(1);
|
||||
for (var i = 0; i < 256; i++) {
|
||||
@ -1145,7 +1156,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
cs,
|
||||
xref: this.xref,
|
||||
resources,
|
||||
pdfFunctionFactory: this.pdfFunctionFactory,
|
||||
pdfFunctionFactory: this._pdfFunctionFactory,
|
||||
localColorSpaceCache,
|
||||
}).catch(reason => {
|
||||
if (reason instanceof AbortException) {
|
||||
@ -1202,7 +1213,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
this.xref,
|
||||
resources,
|
||||
this.handler,
|
||||
this.pdfFunctionFactory,
|
||||
this._pdfFunctionFactory,
|
||||
localColorSpaceCache
|
||||
);
|
||||
operatorList.addOp(fn, pattern.getIR());
|
||||
@ -1641,7 +1652,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
xref,
|
||||
resources,
|
||||
self.handler,
|
||||
self.pdfFunctionFactory,
|
||||
self._pdfFunctionFactory,
|
||||
localColorSpaceCache
|
||||
);
|
||||
var patternIR = shadingFill.getIR();
|
||||
|
@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Dict, isDict, isStream, Ref } from "./primitives.js";
|
||||
import {
|
||||
FormatError,
|
||||
info,
|
||||
@ -20,29 +21,94 @@ import {
|
||||
IsEvalSupportedCached,
|
||||
unreachable,
|
||||
} from "../shared/util.js";
|
||||
import { isDict, isStream } from "./primitives.js";
|
||||
import { PostScriptLexer, PostScriptParser } from "./ps_parser.js";
|
||||
import { LocalFunctionCache } from "./image_utils.js";
|
||||
|
||||
class PDFFunctionFactory {
|
||||
constructor({ xref, isEvalSupported = true }) {
|
||||
this.xref = xref;
|
||||
this.isEvalSupported = isEvalSupported !== false;
|
||||
this._localFunctionCache = null; // Initialized lazily.
|
||||
}
|
||||
|
||||
create(fn) {
|
||||
return PDFFunction.parse({
|
||||
const cachedFunction = this.getCached(fn);
|
||||
if (cachedFunction) {
|
||||
return cachedFunction;
|
||||
}
|
||||
const parsedFunction = PDFFunction.parse({
|
||||
xref: this.xref,
|
||||
isEvalSupported: this.isEvalSupported,
|
||||
fn,
|
||||
fn: fn instanceof Ref ? this.xref.fetch(fn) : fn,
|
||||
});
|
||||
|
||||
// Attempt to cache the parsed Function, by reference.
|
||||
this._cache(fn, parsedFunction);
|
||||
|
||||
return parsedFunction;
|
||||
}
|
||||
|
||||
createFromArray(fnObj) {
|
||||
return PDFFunction.parseArray({
|
||||
const cachedFunction = this.getCached(fnObj);
|
||||
if (cachedFunction) {
|
||||
return cachedFunction;
|
||||
}
|
||||
const parsedFunction = PDFFunction.parseArray({
|
||||
xref: this.xref,
|
||||
isEvalSupported: this.isEvalSupported,
|
||||
fnObj,
|
||||
fnObj: fnObj instanceof Ref ? this.xref.fetch(fnObj) : fnObj,
|
||||
});
|
||||
|
||||
// Attempt to cache the parsed Function, by reference.
|
||||
this._cache(fnObj, parsedFunction);
|
||||
|
||||
return parsedFunction;
|
||||
}
|
||||
|
||||
getCached(cacheKey) {
|
||||
let fnRef;
|
||||
if (cacheKey instanceof Ref) {
|
||||
fnRef = cacheKey;
|
||||
} else if (cacheKey instanceof Dict) {
|
||||
fnRef = cacheKey.objId;
|
||||
} else if (isStream(cacheKey)) {
|
||||
fnRef = cacheKey.dict && cacheKey.dict.objId;
|
||||
}
|
||||
if (fnRef) {
|
||||
if (!this._localFunctionCache) {
|
||||
this._localFunctionCache = new LocalFunctionCache();
|
||||
}
|
||||
const localFunction = this._localFunctionCache.getByRef(fnRef);
|
||||
if (localFunction) {
|
||||
return localFunction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_cache(cacheKey, parsedFunction) {
|
||||
if (!parsedFunction) {
|
||||
throw new Error(
|
||||
'PDFFunctionFactory._cache - expected "parsedFunction" argument.'
|
||||
);
|
||||
}
|
||||
let fnRef;
|
||||
if (cacheKey instanceof Ref) {
|
||||
fnRef = cacheKey;
|
||||
} else if (cacheKey instanceof Dict) {
|
||||
fnRef = cacheKey.objId;
|
||||
} else if (isStream(cacheKey)) {
|
||||
fnRef = cacheKey.dict && cacheKey.dict.objId;
|
||||
}
|
||||
if (fnRef) {
|
||||
if (!this._localFunctionCache) {
|
||||
this._localFunctionCache = new LocalFunctionCache();
|
||||
}
|
||||
this._localFunctionCache.set(/* name = */ null, fnRef, parsedFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,22 @@ class LocalColorSpaceCache extends BaseLocalCache {
|
||||
}
|
||||
}
|
||||
|
||||
class LocalFunctionCache extends BaseLocalCache {
|
||||
getByName(name) {
|
||||
unreachable("Should not call `getByName` method.");
|
||||
}
|
||||
|
||||
set(name = null, ref, data) {
|
||||
if (!ref) {
|
||||
throw new Error('LocalFunctionCache.set - expected "ref" argument.');
|
||||
}
|
||||
if (this._imageCache.has(ref)) {
|
||||
return;
|
||||
}
|
||||
this._imageCache.put(ref, data);
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalImageCache {
|
||||
static get NUM_PAGES_THRESHOLD() {
|
||||
return shadow(this, "NUM_PAGES_THRESHOLD", 2);
|
||||
@ -184,4 +200,9 @@ class GlobalImageCache {
|
||||
}
|
||||
}
|
||||
|
||||
export { LocalImageCache, LocalColorSpaceCache, GlobalImageCache };
|
||||
export {
|
||||
LocalImageCache,
|
||||
LocalColorSpaceCache,
|
||||
LocalFunctionCache,
|
||||
GlobalImageCache,
|
||||
};
|
||||
|
@ -178,7 +178,7 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
this.extendStart = extendStart;
|
||||
this.extendEnd = extendEnd;
|
||||
|
||||
var fnObj = dict.get("Function");
|
||||
var fnObj = dict.getRaw("Function");
|
||||
var fn = pdfFunctionFactory.createFromArray(fnObj);
|
||||
|
||||
// 10 samples seems good enough for now, but probably won't work
|
||||
@ -878,7 +878,7 @@ Shadings.Mesh = (function MeshClosure() {
|
||||
? cs.getRgb(dict.get("Background"), 0)
|
||||
: null;
|
||||
|
||||
var fnObj = dict.get("Function");
|
||||
var fnObj = dict.getRaw("Function");
|
||||
var fn = fnObj ? pdfFunctionFactory.createFromArray(fnObj) : null;
|
||||
|
||||
this.coords = [];
|
||||
|
Loading…
Reference in New Issue
Block a user