Skip to content

Commit b2ad652

Browse files
committed
fixup! Fix filters, annotation canvases
1 parent ccf05b9 commit b2ad652

4 files changed

Lines changed: 178 additions & 180 deletions

File tree

src/core/evaluator.js

Lines changed: 143 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -283,24 +283,20 @@ class PartialEvaluator {
283283
return newEvaluator;
284284
}
285285

286-
hasBlendModes(resources, nonBlendModesSet) {
287-
if (!(resources instanceof Dict)) {
288-
return false;
289-
}
290-
if (resources.objId && nonBlendModesSet.has(resources.objId)) {
291-
return false;
292-
}
293-
294-
const processed = new RefSet(nonBlendModesSet);
295-
if (resources.objId) {
296-
processed.put(resources.objId);
286+
_traverseExtGState(
287+
resources,
288+
processed,
289+
{
290+
checkGraphicState,
291+
onExtGStateFetchError = null,
292+
onXObjectFetchError = null,
293+
onResourceNode = null,
297294
}
298-
295+
) {
299296
const nodes = [resources],
300297
xref = this.xref;
301298
while (nodes.length) {
302299
const node = nodes.shift();
303-
// First check the current resources for blend modes.
304300
const graphicStates = node.get("ExtGState");
305301
if (graphicStates instanceof Dict) {
306302
for (let graphicState of graphicStates.getRawValues()) {
@@ -311,10 +307,11 @@ class PartialEvaluator {
311307
try {
312308
graphicState = xref.fetch(graphicState);
313309
} catch (ex) {
310+
if (onExtGStateFetchError?.(ex)) {
311+
return true;
312+
}
314313
// Avoid parsing a corrupt ExtGState more than once.
315314
processed.put(graphicState);
316-
317-
info(`hasBlendModes - ignoring ExtGState: "${ex}".`);
318315
continue;
319316
}
320317
}
@@ -324,66 +321,100 @@ class PartialEvaluator {
324321
if (graphicState.objId) {
325322
processed.put(graphicState.objId);
326323
}
324+
if (checkGraphicState(graphicState)) {
325+
return true;
326+
}
327+
}
328+
}
327329

328-
const bm = graphicState.get("BM");
329-
if (bm instanceof Name) {
330-
if (bm.name !== "Normal") {
331-
return true;
330+
const xObjects = node.get("XObject");
331+
if (xObjects instanceof Dict) {
332+
for (let xObject of xObjects.getRawValues()) {
333+
if (xObject instanceof Ref) {
334+
if (processed.has(xObject)) {
335+
// The XObject has already been processed, and by avoiding a
336+
// redundant `xref.fetch` we can *significantly* reduce the load
337+
// time for badly generated PDF files (fixes issue6961.pdf).
338+
continue;
332339
}
333-
continue;
334-
}
335-
if (bm !== undefined && Array.isArray(bm)) {
336-
for (const element of bm) {
337-
if (element instanceof Name && element.name !== "Normal") {
340+
try {
341+
xObject = xref.fetch(xObject);
342+
} catch (ex) {
343+
if (onXObjectFetchError?.(ex)) {
338344
return true;
339345
}
346+
// Avoid parsing a corrupt XObject more than once.
347+
processed.put(xObject);
348+
continue;
340349
}
341350
}
342-
}
343-
}
344-
// Descend into the XObjects to look for more resources and blend modes.
345-
const xObjects = node.get("XObject");
346-
if (!(xObjects instanceof Dict)) {
347-
continue;
348-
}
349-
for (let xObject of xObjects.getRawValues()) {
350-
if (xObject instanceof Ref) {
351-
if (processed.has(xObject)) {
352-
// The XObject has already been processed, and by avoiding a
353-
// redundant `xref.fetch` we can *significantly* reduce the load
354-
// time for badly generated PDF files (fixes issue6961.pdf).
351+
if (!(xObject instanceof BaseStream)) {
355352
continue;
356353
}
357-
try {
358-
xObject = xref.fetch(xObject);
359-
} catch (ex) {
360-
// Avoid parsing a corrupt XObject more than once.
361-
processed.put(xObject);
362-
363-
info(`hasBlendModes - ignoring XObject: "${ex}".`);
354+
if (xObject.dict.objId) {
355+
processed.put(xObject.dict.objId);
356+
}
357+
const xResources = xObject.dict.get("Resources");
358+
if (!(xResources instanceof Dict)) {
359+
continue;
360+
}
361+
// Checking objId to detect an infinite loop.
362+
if (xResources.objId && processed.has(xResources.objId)) {
364363
continue;
365364
}
366-
}
367-
if (!(xObject instanceof BaseStream)) {
368-
continue;
369-
}
370-
if (xObject.dict.objId) {
371-
processed.put(xObject.dict.objId);
372-
}
373-
const xResources = xObject.dict.get("Resources");
374-
if (!(xResources instanceof Dict)) {
375-
continue;
376-
}
377-
// Checking objId to detect an infinite loop.
378-
if (xResources.objId && processed.has(xResources.objId)) {
379-
continue;
380-
}
381365

382-
nodes.push(xResources);
383-
if (xResources.objId) {
384-
processed.put(xResources.objId);
366+
nodes.push(xResources);
367+
if (xResources.objId) {
368+
processed.put(xResources.objId);
369+
}
385370
}
386371
}
372+
if (onResourceNode?.(node, nodes)) {
373+
return true;
374+
}
375+
}
376+
return false;
377+
}
378+
379+
hasBlendModes(resources, nonBlendModesSet) {
380+
if (!(resources instanceof Dict)) {
381+
return false;
382+
}
383+
if (resources.objId && nonBlendModesSet.has(resources.objId)) {
384+
return false;
385+
}
386+
387+
const processed = new RefSet(nonBlendModesSet);
388+
if (resources.objId) {
389+
processed.put(resources.objId);
390+
}
391+
if (
392+
this._traverseExtGState(resources, processed, {
393+
checkGraphicState(graphicState) {
394+
const bm = graphicState.get("BM");
395+
if (bm instanceof Name) {
396+
return bm.name !== "Normal";
397+
}
398+
if (bm !== undefined && Array.isArray(bm)) {
399+
for (const element of bm) {
400+
if (element instanceof Name && element.name !== "Normal") {
401+
return true;
402+
}
403+
}
404+
}
405+
return false;
406+
},
407+
onExtGStateFetchError(ex) {
408+
info(`hasBlendModes - ignoring ExtGState: "${ex}".`);
409+
return false;
410+
},
411+
onXObjectFetchError(ex) {
412+
info(`hasBlendModes - ignoring XObject: "${ex}".`);
413+
return false;
414+
},
415+
})
416+
) {
417+
return true;
387418
}
388419

389420
// When no blend modes exist, there's no need re-fetch/re-parse any of the
@@ -449,126 +480,77 @@ class PartialEvaluator {
449480
if (resources.objId) {
450481
processed.put(resources.objId);
451482
}
452-
453-
const nodes = [resources],
454-
xref = this.xref;
455-
while (nodes.length) {
456-
const node = nodes.shift();
457-
const graphicStates = node.get("ExtGState");
458-
if (graphicStates instanceof Dict) {
459-
for (let graphicState of graphicStates.getRawValues()) {
460-
if (graphicState instanceof Ref) {
461-
if (processed.has(graphicState)) {
483+
const xref = this.xref;
484+
return this._traverseExtGState(resources, processed, {
485+
checkGraphicState: graphicState => {
486+
try {
487+
return this._hasCanvasFiltersInGState(graphicState);
488+
} catch (ex) {
489+
info(`hasCanvasFilters - failed to inspect filter data: "${ex}".`);
490+
return true;
491+
}
492+
},
493+
onExtGStateFetchError(ex) {
494+
info(`hasCanvasFilters - failed to fetch ExtGState: "${ex}".`);
495+
return true;
496+
},
497+
onXObjectFetchError(ex) {
498+
info(`hasCanvasFilters - failed to fetch XObject: "${ex}".`);
499+
return true;
500+
},
501+
onResourceNode(node, nodes) {
502+
const patterns = node.get("Pattern");
503+
if (!(patterns instanceof Dict)) {
504+
return false;
505+
}
506+
for (let pattern of patterns.getRawValues()) {
507+
if (pattern instanceof Ref) {
508+
if (processed.has(pattern)) {
462509
continue;
463510
}
464511
try {
465-
graphicState = xref.fetch(graphicState);
512+
pattern = xref.fetch(pattern);
466513
} catch (ex) {
467-
info(`hasCanvasFilters - failed to fetch ExtGState: "${ex}".`);
514+
info(`hasCanvasFilters - failed to fetch Pattern: "${ex}".`);
468515
return true;
469516
}
470517
}
471-
if (!(graphicState instanceof Dict)) {
472-
continue;
473-
}
474-
if (graphicState.objId) {
475-
processed.put(graphicState.objId);
476-
}
477-
try {
478-
if (this._hasCanvasFiltersInGState(graphicState)) {
479-
return true;
518+
if (pattern instanceof BaseStream) {
519+
if (pattern.dict.objId) {
520+
processed.put(pattern.dict.objId);
480521
}
481-
} catch (ex) {
482-
info(`hasCanvasFilters - failed to inspect filter data: "${ex}".`);
483-
return true;
484-
}
485-
}
486-
}
487-
488-
const xObjects = node.get("XObject");
489-
if (xObjects instanceof Dict) {
490-
for (let xObject of xObjects.getRawValues()) {
491-
if (xObject instanceof Ref) {
492-
if (processed.has(xObject)) {
522+
const patternResources = pattern.dict.get("Resources");
523+
if (!(patternResources instanceof Dict)) {
493524
continue;
494525
}
495-
try {
496-
xObject = xref.fetch(xObject);
497-
} catch (ex) {
498-
info(`hasCanvasFilters - failed to fetch XObject: "${ex}".`);
499-
return true;
526+
if (
527+
patternResources.objId &&
528+
processed.has(patternResources.objId)
529+
) {
530+
continue;
500531
}
501-
}
502-
if (!(xObject instanceof BaseStream)) {
503-
continue;
504-
}
505-
if (xObject.dict.objId) {
506-
processed.put(xObject.dict.objId);
507-
}
508-
const xResources = xObject.dict.get("Resources");
509-
if (!(xResources instanceof Dict)) {
510-
continue;
511-
}
512-
if (xResources.objId && processed.has(xResources.objId)) {
513-
continue;
514-
}
515-
516-
nodes.push(xResources);
517-
if (xResources.objId) {
518-
processed.put(xResources.objId);
519-
}
520-
}
521-
}
522532

523-
const patterns = node.get("Pattern");
524-
if (!(patterns instanceof Dict)) {
525-
continue;
526-
}
527-
for (let pattern of patterns.getRawValues()) {
528-
if (pattern instanceof Ref) {
529-
if (processed.has(pattern)) {
533+
nodes.push(patternResources);
534+
if (patternResources.objId) {
535+
processed.put(patternResources.objId);
536+
}
530537
continue;
531538
}
532-
try {
533-
pattern = xref.fetch(pattern);
534-
} catch (ex) {
535-
info(`hasCanvasFilters - failed to fetch Pattern: "${ex}".`);
536-
return true;
537-
}
538-
}
539-
if (pattern instanceof BaseStream) {
540-
if (pattern.dict.objId) {
541-
processed.put(pattern.dict.objId);
542-
}
543-
const patternResources = pattern.dict.get("Resources");
544-
if (!(patternResources instanceof Dict)) {
539+
if (!(pattern instanceof Dict)) {
545540
continue;
546541
}
547-
if (patternResources.objId && processed.has(patternResources.objId)) {
542+
if (pattern.objId && processed.has(pattern.objId)) {
548543
continue;
549544
}
550545

551-
nodes.push(patternResources);
552-
if (patternResources.objId) {
553-
processed.put(patternResources.objId);
546+
nodes.push(pattern);
547+
if (pattern.objId) {
548+
processed.put(pattern.objId);
554549
}
555-
continue;
556550
}
557-
if (!(pattern instanceof Dict)) {
558-
continue;
559-
}
560-
if (pattern.objId && processed.has(pattern.objId)) {
561-
continue;
562-
}
563-
564-
nodes.push(pattern);
565-
if (pattern.objId) {
566-
processed.put(pattern.objId);
567-
}
568-
}
569-
}
570-
571-
return false;
551+
return false;
552+
},
553+
});
572554
}
573555

574556
async fetchBuiltInCMap(name) {

0 commit comments

Comments
 (0)