Merge pull request #11232 from Snuffleupagus/hasBlendModes-improvements

Cache processed 'ExtGState's in `PartialEvaluator.hasBlendModes` to avoid unnecessary parsing/lookups
This commit is contained in:
Tim van der Meij 2019-10-12 14:09:53 +02:00 committed by GitHub
commit c701ae3f4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -21,7 +21,7 @@ import {
} from '../shared/util'; } from '../shared/util';
import { CMapFactory, IdentityCMap } from './cmap'; import { CMapFactory, IdentityCMap } from './cmap';
import { import {
Cmd, Dict, EOF, isDict, isName, isRef, isStream, Name Cmd, Dict, EOF, isDict, isName, isRef, isStream, Name, Ref
} from './primitives'; } from './primitives';
import { import {
ErrorFont, Font, FontFlags, getFontType, IdentityToUnicodeMap, ToUnicodeMap ErrorFont, Font, FontFlags, getFontType, IdentityToUnicodeMap, ToUnicodeMap
@ -180,7 +180,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}, },
hasBlendModes: function PartialEvaluator_hasBlendModes(resources) { hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
if (!isDict(resources)) { if (!(resources instanceof Dict)) {
return false; return false;
} }
@ -191,33 +191,44 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var nodes = [resources], xref = this.xref; var nodes = [resources], xref = this.xref;
while (nodes.length) { while (nodes.length) {
var key, i, ii;
var node = nodes.shift(); var node = nodes.shift();
// First check the current resources for blend modes. // First check the current resources for blend modes.
var graphicStates = node.get('ExtGState'); var graphicStates = node.get('ExtGState');
if (isDict(graphicStates)) { if (graphicStates instanceof Dict) {
var graphicStatesKeys = graphicStates.getKeys(); var graphicStatesKeys = graphicStates.getKeys();
for (i = 0, ii = graphicStatesKeys.length; i < ii; i++) { for (let i = 0, ii = graphicStatesKeys.length; i < ii; i++) {
key = graphicStatesKeys[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'); var bm = graphicState.get('BM');
if (isName(bm) && bm.name !== 'Normal') { if ((bm instanceof Name) && bm.name !== 'Normal') {
return true; return true;
} }
} }
} }
// Descend into the XObjects to look for more resources and blend modes. // Descend into the XObjects to look for more resources and blend modes.
var xObjects = node.get('XObject'); var xObjects = node.get('XObject');
if (!isDict(xObjects)) { if (!(xObjects instanceof Dict)) {
continue; continue;
} }
var xObjectsKeys = xObjects.getKeys(); var xObjectsKeys = xObjects.getKeys();
for (i = 0, ii = xObjectsKeys.length; i < ii; i++) { for (let i = 0, ii = xObjectsKeys.length; i < ii; i++) {
key = xObjectsKeys[i]; const key = xObjectsKeys[i];
var xObject = xObjects.getRaw(key); var xObject = xObjects.getRaw(key);
if (isRef(xObject)) { if (xObject instanceof Ref) {
if (processed[xObject.toString()]) { if (processed[xObject.toString()]) {
// The XObject has already been processed, and by avoiding a // The XObject has already been processed, and by avoiding a
// redundant `xref.fetch` we can *significantly* reduce the load // redundant `xref.fetch` we can *significantly* reduce the load
@ -231,14 +242,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
if (xObject.dict.objId) { if (xObject.dict.objId) {
if (processed[xObject.dict.objId]) { if (processed[xObject.dict.objId]) {
// stream has objId and is processed already continue; // Stream has objId and was processed already.
continue;
} }
processed[xObject.dict.objId] = true; processed[xObject.dict.objId] = true;
} }
var xResources = xObject.dict.get('Resources'); var xResources = xObject.dict.get('Resources');
// Checking objId to detect an infinite loop. // Checking objId to detect an infinite loop.
if (isDict(xResources) && if ((xResources instanceof Dict) &&
(!xResources.objId || !processed[xResources.objId])) { (!xResources.objId || !processed[xResources.objId])) {
nodes.push(xResources); nodes.push(xResources);
if (xResources.objId) { if (xResources.objId) {