Inline all the possible type checks in PartialEvaluator.hasBlendModes to avoid unnecessary function calls

For badly generated PDF documents, with issue 6961 being one example, there's well over one hundred thousand function calls being made in total for just the *two* pages.
This commit is contained in:
Jonas Jenwald 2019-10-12 11:24:37 +02:00
parent dcf49ac753
commit af71f9b40a

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,32 @@ 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);
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 +230,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) {