From bfcbf2d78d835133f958eb22303a3f6a16c1542c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 12 Oct 2019 11:44:07 +0200 Subject: [PATCH] Cache processed 'ExtGState's in `PartialEvaluator.hasBlendModes` to avoid unnecessary parsing/lookups This simply extends the already existing caching of processed resources to avoid duplicated parsing of 'ExtGState's, which should help with badly generated PDF documents. This patch was tested using the PDF file from issue 6961, i.e. https://github.com/mozilla/pdf.js/files/121712/test.pdf, with the following manifest file: ``` [ { "id": "issue6961", "file": "../web/pdfs/issue6961.pdf", "md5": "", "rounds": 200, "type": "eq" } ] ``` which gave the following *overall* results when comparing this patch against the `master` branch: ``` -- Grouped By browser, stat -- browser | stat | Count | Baseline(ms) | Current(ms) | +/- | % | Result(P<.05) ------- | ------------ | ----- | ------------ | ----------- | --- | ----- | ------------- Firefox | Overall | 400 | 1063 | 1051 | -12 | -1.17 | faster Firefox | Page Request | 400 | 552 | 543 | -9 | -1.69 | faster Firefox | Rendering | 400 | 511 | 508 | -3 | -0.61 | ``` and the following *page-specific* results: ``` -- Grouped By page, stat -- page | stat | Count | Baseline(ms) | Current(ms) | +/- | % | Result(P<.05) ---- | ------------ | ----- | ------------ | ----------- | --- | ----- | ------------- 0 | Overall | 200 | 1122 | 1110 | -12 | -1.03 | 0 | Page Request | 200 | 552 | 544 | -8 | -1.48 | faster 0 | Rendering | 200 | 570 | 566 | -4 | -0.62 | 1 | Overall | 200 | 1005 | 992 | -13 | -1.33 | faster 1 | Page Request | 200 | 552 | 542 | -11 | -1.91 | faster 1 | Rendering | 200 | 452 | 450 | -3 | -0.61 | ``` --- src/core/evaluator.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 52c1e2c7f..91d7b610d 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -199,7 +199,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { for (let i = 0, ii = graphicStatesKeys.length; i < ii; i++) { const key = graphicStatesKeys[i]; - var graphicState = graphicStates.get(key); + let graphicState = graphicStates.getRaw(key); + if (graphicState instanceof Ref) { + if (processed[graphicState.toString()]) { + continue; // The ExtGState has already been processed. + } + graphicState = xref.fetch(graphicState); + } + if (!(graphicState instanceof Dict)) { + continue; + } + if (graphicState.objId) { + processed[graphicState.objId] = true; + } var bm = graphicState.get('BM'); if ((bm instanceof Name) && bm.name !== 'Normal') { return true;