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