diff --git a/src/core/obj.js b/src/core/obj.js index f38effe8b..a8bd5d3df 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -534,6 +534,19 @@ var Catalog = (function CatalogClosure() { var obj = this.catDict.get('Names'); var javaScript = []; + function appendIfJavaScriptDict(jsDict) { + var type = jsDict.get('S'); + if (!isName(type) || type.name !== 'JavaScript') { + return; + } + var js = jsDict.get('JS'); + if (isStream(js)) { + js = bytesToString(js.getBytes()); + } else if (!isString(js)) { + return; + } + javaScript.push(stringToPDFString(js)); + } if (obj && obj.has('JavaScript')) { var nameTree = new NameTree(obj.getRaw('JavaScript'), xref); var names = nameTree.getAll(); @@ -544,36 +557,25 @@ var Catalog = (function CatalogClosure() { // We don't really use the JavaScript right now. This code is // defensive so we don't cause errors on document load. var jsDict = names[name]; - if (!isDict(jsDict)) { - continue; + if (isDict(jsDict)) { + appendIfJavaScriptDict(jsDict); } - var type = jsDict.get('S'); - if (!isName(type) || type.name !== 'JavaScript') { - continue; - } - var js = jsDict.get('JS'); - if (!isString(js) && !isStream(js)) { - continue; - } - if (isStream(js)) { - js = bytesToString(js.getBytes()); - } - javaScript.push(stringToPDFString(js)); } } // Append OpenAction actions to javaScript array var openactionDict = this.catDict.get('OpenAction'); - if (isDict(openactionDict)) { - var objType = openactionDict.get('Type'); + if (isDict(openactionDict, 'Action')) { var actionType = openactionDict.get('S'); - var action = openactionDict.get('N'); - var isPrintAction = (isName(objType) && objType.name === 'Action' && - isName(actionType) && actionType.name === 'Named' && - isName(action) && action.name === 'Print'); - - if (isPrintAction) { - javaScript.push('print(true);'); + if (isName(actionType) && actionType.name === 'Named') { + // The named Print action is not a part of the PDF 1.7 specification, + // but is supported by many PDF readers/writers (including Adobe's). + var action = openactionDict.get('N'); + if (isName(action) && action.name === 'Print') { + javaScript.push('print({});'); + } + } else { + appendIfJavaScriptDict(openactionDict); } } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index a79dc29b0..a186388cc 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -146,4 +146,6 @@ !issue6068.pdf !issue6081.pdf !issue6069.pdf +!issue6106.pdf +!bug1001080.pdf !issue6108.pdf diff --git a/test/pdfs/bug1001080.pdf b/test/pdfs/bug1001080.pdf new file mode 100644 index 000000000..0f60ca9d6 Binary files /dev/null and b/test/pdfs/bug1001080.pdf differ diff --git a/test/pdfs/issue6106.pdf b/test/pdfs/issue6106.pdf new file mode 100644 index 000000000..21b545220 --- /dev/null +++ b/test/pdfs/issue6106.pdf @@ -0,0 +1,70 @@ +%PDF-1.4 +% To manually verify that PDF.js works as expected, open this PDF file with +% PDF.js and check whether the browser attempts to print the PDF. +1 0 obj +<< +/Type /Catalog +/Pages 2 0 R +/OpenAction 3 0 R +>> +endobj +2 0 obj +<< +/Type /Pages +/Count 1 +/Kids [4 0 R] +>> +endobj +3 0 obj +<< +/Type /Action +/S /JavaScript +% This is a verbatim copy from a PDF generated by Google Drive (20 July 2015) +/JS (this.print\({bUI:true,bSilent:false,bShrinkToFit:true}\);) +>> +endobj +4 0 obj +<< +/Parent 2 0 R +/Contents 6 0 R +/Type /Page +/Resources 5 0 R +/MediaBox [0 0 400 200] +>> +endobj +5 0 obj +<< +/Font + << + /F1 + << + /Type /Font + /Subtype /Type1 + /BaseFont /Arial + >> + >> +>> +endobj +6 0 obj +<> +stream +BT/F1 20 Tf 70 88 Td(Should trigger a print action.) Tj ET +endstream +endobj +xref +0 7 +0000000000 65535 f +0000000151 00000 n +0000000218 00000 n +0000000275 00000 n +0000000467 00000 n +0000000571 00000 n +0000000685 00000 n +trailer +<< +/Root 1 0 R +/Size 7 +>> +startxref +791 +%%EOF diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 895039beb..474734270 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -147,6 +147,32 @@ describe('api', function() { expect(data).toEqual([]); }); }); + // Keep this in sync with the pattern in viewer.js. The pattern is used to + // detect whether or not to automatically start printing. + var viewerPrintRegExp = /\bprint\s*\(/; + it('gets javascript with printing instructions (Print action)', function() { + // PDF document with "Print" Named action in OpenAction + var pdfUrl = combineUrl(window.location.href, '../pdfs/bug1001080.pdf'); + var promise = PDFJS.getDocument(pdfUrl).then(function(doc) { + return doc.getJavaScript(); + }); + waitsForPromiseResolved(promise, function (data) { + expect(data).toEqual(['print({});']); + expect(data[0]).toMatch(viewerPrintRegExp); + }); + }); + it('gets javascript with printing instructions (JS action)', function() { + // PDF document with "JavaScript" action in OpenAction + var pdfUrl = combineUrl(window.location.href, '../pdfs/issue6106.pdf'); + var promise = PDFJS.getDocument(pdfUrl).then(function(doc) { + return doc.getJavaScript(); + }); + waitsForPromiseResolved(promise, function (data) { + expect(data).toEqual( + ['this.print({bUI:true,bSilent:false,bShrinkToFit:true});']); + expect(data[0]).toMatch(viewerPrintRegExp); + }); + }); it('gets outline', function() { var promise = doc.getOutline(); waitsForPromiseResolved(promise, function(outline) { diff --git a/web/viewer.js b/web/viewer.js index a662e16b4..cbeda49ef 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -820,7 +820,7 @@ var PDFViewerApplication = { self.fallback(PDFJS.UNSUPPORTED_FEATURES.javaScript); } // Hack to support auto printing. - var regex = /\bprint\s*\(/g; + var regex = /\bprint\s*\(/; for (var i = 0, ii = javaScript.length; i < ii; i++) { var js = javaScript[i]; if (js && regex.test(js)) {