diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 9b3f31167..efbbcf969 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -982,7 +982,8 @@ class PartialEvaluator { patternDict, operatorList, task, - localTilingPatternCache + localTilingPatternCache, + seenRefs ) { // Create an IR of the pattern code. const tilingOpList = new CheckedOperatorList(); @@ -998,6 +999,7 @@ class PartialEvaluator { task, resources: patternResources, operatorList: tilingOpList, + prevRefs: seenRefs, }) .then(function () { const operatorListIR = tilingOpList.getIR(); @@ -1041,7 +1043,8 @@ class PartialEvaluator { task, state, fallbackFontDict = null, - cssFontInfo = null + cssFontInfo = null, + seenRefs = null ) { const fontName = fontArgs?.[0] instanceof Name ? fontArgs[0].name : null; @@ -1051,7 +1054,8 @@ class PartialEvaluator { resources, task, fallbackFontDict, - cssFontInfo + cssFontInfo, + seenRefs ); if (translated.font.isType3Font) { @@ -1152,7 +1156,10 @@ class PartialEvaluator { value[0], operatorList, task, - stateManager.state + stateManager.state, + /* fallbackFontDict = */ null, + /* cssFontInfo = */ null, + seenRefs ).then(function (loadedName) { operatorList.addDependency(loadedName); gStateObj.push([key, [loadedName, value[1]]]); @@ -1230,7 +1237,8 @@ class PartialEvaluator { resources, task, fallbackFontDict = null, - cssFontInfo = null + cssFontInfo = null, + seenRefs = null ) { const errorFont = async () => new TranslatedFont({ @@ -1366,7 +1374,7 @@ class PartialEvaluator { if (translatedFont.isType3Font) { try { - await translated.loadType3Data(this, resources, task); + await translated.loadType3Data(this, resources, task, seenRefs); } catch (reason) { throw new Error(`Type3 font load error: ${reason}`); } @@ -1577,7 +1585,8 @@ class PartialEvaluator { task, localColorSpaceCache, localTilingPatternCache, - localShadingPatternCache + localShadingPatternCache, + seenRefs ) { // compile tiling patterns const patternName = args.pop(); @@ -1619,7 +1628,8 @@ class PartialEvaluator { dict, operatorList, task, - localTilingPatternCache + localTilingPatternCache, + seenRefs ); } else if (typeNum === PatternType.SHADING) { const shading = dict.get("Shading"); @@ -1934,7 +1944,9 @@ class PartialEvaluator { operatorList, task, stateManager.state, - fallbackFontDict + fallbackFontDict, + /* cssFontInfo = */ null, + seenRefs ) .then(function (loadedName) { operatorList.addDependency(loadedName); @@ -2112,7 +2124,8 @@ class PartialEvaluator { task, localColorSpaceCache, localTilingPatternCache, - localShadingPatternCache + localShadingPatternCache, + seenRefs ) ); return; @@ -2144,7 +2157,8 @@ class PartialEvaluator { task, localColorSpaceCache, localTilingPatternCache, - localShadingPatternCache + localShadingPatternCache, + seenRefs ) ); return; @@ -2731,7 +2745,10 @@ class PartialEvaluator { fontName, fontRef, resources, - task + task, + /* fallbackFontDict = */ null, + /* cssFontInfo = */ null, + seenRefs ); textState.loadedName = translated.loadedName; @@ -4893,7 +4910,7 @@ class TranslatedFont { ); } - loadType3Data(evaluator, resources, task) { + loadType3Data(evaluator, resources, task, seenRefs = null) { if (this.#type3Loaded) { return this.#type3Loaded; } @@ -4931,6 +4948,7 @@ class TranslatedFont { task, resources: fontResources, operatorList, + prevRefs: seenRefs, }) .then(() => { // According to the PDF specification, section "9.6.5 Type 3 Fonts" diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 2aaf8dc8b..3e473651d 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -912,3 +912,4 @@ !smask_alpha_oob_transfer.pdf !smask_alpha_bc.pdf !smask_luminosity_oob_transfer.pdf +!operator_list_cycle.pdf diff --git a/test/pdfs/operator_list_cycle.pdf b/test/pdfs/operator_list_cycle.pdf new file mode 100644 index 000000000..249f49648 --- /dev/null +++ b/test/pdfs/operator_list_cycle.pdf @@ -0,0 +1,98 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Kids [3 0 R] + /Type /Pages + /Count 1 +>> +endobj +2 0 obj << + /Type /Catalog + /Pages 1 0 R +>> +endobj +3 0 obj << + /Resources 11 0 R + /Type /Page + /Contents 10 0 R + /Parent 1 0 R +>> +endobj +10 0 obj << +>> +stream +1 0 0 1 315.779 733.039 cm +1 0 0 1 2.835 -173.614 cm +1.04704 0 0 1.04704 0 0 cm +/Im6 Do +endstream +endobj +11 0 obj << + /XObject << + /Im6 12 0 R + >> +>> +endobj +12 0 obj << + /Subtype /Form + /Resources << + /XObject << + /x15 13 0 R + >> + >> +>> +stream +/x15 Do +endstream +endobj +13 0 obj << + /Subtype /Form + /Resources << + /Pattern << + /p31 14 0 R + >> + >> +>> +stream +q /Pattern cs /p31 scn /a0 gs +0 0 224.720001 160.399994 re f +Q +endstream +endobj +14 0 obj << + /PatternType 1 + /BBox [0 0 225 161] + /Resources << + /XObject << + /x47 12 0 R + >> + >> +>> +stream +/x47 Do +endstream +endobj +xref +0 15 +0000000000 65535 f +4294967295 00000 n +0000000078 00000 n +0000000131 00000 n +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000000 65535 f +0000000221 00000 n +0000000348 00000 n +0000000405 00000 n +0000000531 00000 n +0000000712 00000 n +trailer << + /Root 2 0 R + /Size 110 +>> +startxref +860 +%%EOF diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index f28150829..bc1471260 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -4452,6 +4452,19 @@ have written that much by now. So, here’s to squashing bugs.`); } ); + it("gets operator list, from a PDF with a Form -> Form -> Pattern -> Form cycle", async function () { + const loadingTask = getDocument( + buildGetDocumentParams("operator_list_cycle.pdf") + ); + const pdfDoc = await loadingTask.promise; + const pdfPage = await pdfDoc.getPage(1); + + const operatorList = await pdfPage.getOperatorList(); + expect(operatorList.lastChunk).toEqual(true); + + await loadingTask.destroy(); + }); + it("gets operator list, containing Annotation-operatorLists", async function () { const loadingTask = getDocument( buildGetDocumentParams("annotation-line.pdf")