diff --git a/extensions/firefox/chrome-mozcentral.manifest b/extensions/firefox/chrome-mozcentral.manifest new file mode 100644 index 000000000..a2a6757c3 --- /dev/null +++ b/extensions/firefox/chrome-mozcentral.manifest @@ -0,0 +1,3 @@ +resource pdf.js content/ +component {d0c5195d-e798-49d4-b1d3-9324328b2291} components/PdfStreamConverter.js +contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {d0c5195d-e798-49d4-b1d3-9324328b2291} diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index f866a6b2f..f7ed3cd3a 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -11,7 +11,7 @@ const Cr = Components.results; const Cu = Components.utils; const PDFJS_EVENT_ID = 'pdf.js.message'; const PDF_CONTENT_TYPE = 'application/pdf'; -const EXT_PREFIX = 'extensions.uriloader@pdf.js'; +const PREF_PREFIX = 'PDFJSSCRIPT_PREF_PREFIX'; const MAX_DATABASE_LENGTH = 4096; const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'; const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'; @@ -57,7 +57,7 @@ function getStringPref(pref, def) { } function log(aMsg) { - if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false)) + if (!getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false)) return; let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg); Services.console.logStringMessage(msg); @@ -136,12 +136,12 @@ ChromeActions.prototype = { // Protect against something sending tons of data to setDatabase. if (data.length > MAX_DATABASE_LENGTH) return; - setStringPref(EXT_PREFIX + '.database', data); + setStringPref(PREF_PREFIX + '.database', data); }, getDatabase: function() { if (inPrivateBrowsing) return '{}'; - return getStringPref(EXT_PREFIX + '.database', '{}'); + return getStringPref(PREF_PREFIX + '.database', '{}'); }, getLocale: function() { return getStringPref('general.useragent.locale', 'en-US'); @@ -160,10 +160,10 @@ ChromeActions.prototype = { } }, pdfBugEnabled: function() { - return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false); + return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false); }, searchEnabled: function() { - return getBoolPref(EXT_PREFIX + '.searchEnabled', false); + return getBoolPref(PREF_PREFIX + '.searchEnabled', false); } }; @@ -193,7 +193,7 @@ function PdfStreamConverter() { PdfStreamConverter.prototype = { // properties required for XPCOM registration: - classID: Components.ID('{6457a96b-2d68-439a-bcfa-44465fbcdbb1}'), + classID: Components.ID('{PDFJSSCRIPT_STREAM_CONVERTER_ID}'), classDescription: 'pdf.js Component', contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*', diff --git a/extensions/firefox/install.rdf.in b/extensions/firefox/install.rdf.in deleted file mode 100644 index 084d6dc2d..000000000 --- a/extensions/firefox/install.rdf.in +++ /dev/null @@ -1,27 +0,0 @@ - - -#filter substitution - - - - - uriloader@pdf.js - - PDF Viewer - PDFJSSCRIPT_VERSION - - - {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - @FIREFOX_VERSION@ - @FIREFOX_VERSION@ - - - true - true - Mozilla - Uses HTML5 to display PDF files directly in Firefox. - https://support.mozilla.org/kb/Opening%20PDF%20files%20within%20Firefox - 2 - - diff --git a/l10n/cs/metadata.inc b/l10n/cs/metadata.inc new file mode 100644 index 000000000..ed5c2a1c7 --- /dev/null +++ b/l10n/cs/metadata.inc @@ -0,0 +1,8 @@ + + + cs + PDF Viewer + Používá HTML5 pro zobrazení PDF souborů přímo ve Firefoxu. + + + diff --git a/l10n/cs/viewer.properties b/l10n/cs/viewer.properties new file mode 100644 index 000000000..96b596b16 --- /dev/null +++ b/l10n/cs/viewer.properties @@ -0,0 +1,45 @@ +bookmark.title=Aktuální zobrazení(zkopírovat nebo otevřít v novém okně) +previous.title=Předchozí stránka +next.title=Další stránka +print.title=Tisk +download.title=Stáhnout +zoom_out.title=Zmenšit +zoom_in.title=Zvětšit +error_more_info=Více informací +error_less_info=Méně informací +error_close=Zavřít +error_build=PDF.JS Build: {{build}} +error_message=Zpráva:{{message}} +error_stack=Stack:{{stack}} +error_file=Soubor:{{file}} +error_line=Řádek:{{line}} +page_scale_width=Šířka stránky +page_scale_fit=Stránka +page_scale_auto=Automatické přibližení +page_scale_actual=Skutečná velikost +toggle_slider.title=Přepnout posuvník +thumbs.title=Zobrazit náhledy +outline.title=Zobrazit osnovu dokumentu +loading=Načítám... {{percent}}% +loading_error_indicator=Chyba +loading_error=Došlo k chybě při načítání PDF. +rendering_error=Došlo k chybě při vykreslování stránky. +page_label=Stránka: +page_of=z{{pageCount}} +no_outline=Žádné osnovy k dispozici +open_file.title=Otevřít soubor +text_annotation_type=[{{type}}Anotace] +toggle_slider_label=Přepnout posuvník +thumbs_label=Náhledy +outline_label=Přehled dokumentu +bookmark_label=Aktuální zobrazení +previous_label=Předchozí +next_label=Další +print_label=Tisk +download_label=Stáhnout +zoom_out_label=Zmenšit +zoom_in_label=Přiblížit +zoom.title=Zvětšit +thumb_page_title=Stránka{{page}} +thumb_page_canvas=Náhled stránky {{page}} +request_password=PDF je chráněn heslem: diff --git a/make.js b/make.js index 88f7c69a0..e5202b296 100755 --- a/make.js +++ b/make.js @@ -9,7 +9,11 @@ var ROOT_DIR = __dirname + '/', // absolute path to project's root LOCALE_SRC_DIR = 'l10n/', GH_PAGES_DIR = BUILD_DIR + 'gh-pages/', REPO = 'git@github.com:mozilla/pdf.js.git', - PYTHON_BIN = 'python2.7'; + PYTHON_BIN = 'python2.7', + MOZCENTRAL_PREF_PREFIX = 'pdfjs', + FIREFOX_PREF_PREFIX = 'extensions.uriloader@pdf.js', + MOZCENTRAL_STREAM_CONVERTER_ID = 'd0c5195d-e798-49d4-b1d3-9324328b2291', + FIREFOX_STREAM_CONVERTER_ID = '6457a96b-2d68-439a-bcfa-44465fbcdbb1'; // // make all @@ -348,6 +352,9 @@ target.firefox = function() { sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, FIREFOX_BUILD_DIR + '/install.rdf'); sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, FIREFOX_BUILD_DIR + '/update.rdf'); + sed('-i', /PDFJSSCRIPT_STREAM_CONVERTER_ID/, FIREFOX_STREAM_CONVERTER_ID, FIREFOX_BUILD_DIR + 'components/PdfStreamConverter.js'); + sed('-i', /PDFJSSCRIPT_PREF_PREFIX/, FIREFOX_PREF_PREFIX, FIREFOX_BUILD_DIR + 'components/PdfStreamConverter.js'); + // Update localized metadata var localizedMetadata = cat(EXTENSION_SRC_DIR + '/firefox/metadata.inc'); sed('-i', /.*PDFJS_LOCALIZED_METADATA.*\n/, localizedMetadata, FIREFOX_BUILD_DIR + '/install.rdf'); @@ -377,26 +384,23 @@ target.mozcentral = function() { echo('### Building mozilla-central extension'); var MOZCENTRAL_DIR = BUILD_DIR + 'mozcentral/', - MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + 'browser/app/profile/extensions/uriloader@pdf.js/', + MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + 'browser/extensions/pdfjs/', MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_EXTENSION_DIR + 'content/', MOZCENTRAL_L10N_DIR = MOZCENTRAL_DIR + 'browser/locales/en-US/pdfviewer/', + MOZCENTRAL_TEST_DIR = MOZCENTRAL_EXTENSION_DIR + 'test/', FIREFOX_CONTENT_DIR = EXTENSION_SRC_DIR + '/firefox/content/', FIREFOX_EXTENSION_FILES_TO_COPY = - ['*.js', + ['components/*.js', '*.svg', '*.png', '*.manifest', - 'install.rdf.in', 'README.mozilla', 'components', '../../LICENSE'], DEFAULT_LOCALE_FILES = [LOCALE_SRC_DIR + 'en-US/viewer.properties'], FIREFOX_MC_EXTENSION_FILES = - ['bootstrap.js', - 'icon.png', - 'icon64.png', - 'chrome.manifest', + ['chrome.manifest', 'components', 'content', 'LICENSE']; @@ -415,6 +419,8 @@ target.mozcentral = function() { // Copy extension files cd('extensions/firefox'); cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + MOZCENTRAL_EXTENSION_DIR); + mv('-f', ROOT_DIR + MOZCENTRAL_EXTENSION_DIR + '/chrome-mozcentral.manifest', + ROOT_DIR + MOZCENTRAL_EXTENSION_DIR + '/chrome.manifest') cd(ROOT_DIR); // Copy a standalone version of pdf.js inside the content directory @@ -446,9 +452,11 @@ target.mozcentral = function() { cp(DEFAULT_LOCALE_FILES, MOZCENTRAL_L10N_DIR); // Update the build version number - sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'install.rdf.in'); sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'README.mozilla'); + sed('-i', /PDFJSSCRIPT_STREAM_CONVERTER_ID/, MOZCENTRAL_STREAM_CONVERTER_ID, MOZCENTRAL_EXTENSION_DIR + 'components/PdfStreamConverter.js'); + sed('-i', /PDFJSSCRIPT_PREF_PREFIX/, MOZCENTRAL_PREF_PREFIX, MOZCENTRAL_EXTENSION_DIR + 'components/PdfStreamConverter.js'); + // List all files for mozilla-central cd(MOZCENTRAL_EXTENSION_DIR); var extensionFiles = ''; @@ -457,6 +465,11 @@ target.mozcentral = function() { extensionFiles += file+'\n'; }); extensionFiles.to('extension-files'); + cd(ROOT_DIR); + + // Copy test files + mkdir('-p', MOZCENTRAL_TEST_DIR); + cp('-Rf', 'test/mozcentral/*', MOZCENTRAL_TEST_DIR); }; // diff --git a/src/evaluator.js b/src/evaluator.js index f99e79a37..99f3f3bda 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -108,39 +108,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // Compatibility BX: 'beginCompat', - EX: 'endCompat' + EX: 'endCompat', + + // (reserved partial commands for the lexer) + BM: null, + BD: null, + 'true': null, + fa: null, + fal: null, + fals: null, + 'false': null, + nu: null, + nul: null, + 'null': null }; - function splitCombinedOperations(operations) { - // Two or more operations can be combined together, trying to find which - // operations were concatenated. - var result = []; - var opIndex = 0; - - if (!operations) { - return null; - } - - while (opIndex < operations.length) { - var currentOp = ''; - for (var op in OP_MAP) { - if (op == operations.substr(opIndex, op.length) && - op.length > currentOp.length) { - currentOp = op; - } - } - - if (currentOp.length > 0) { - result.push(operations.substr(opIndex, currentOp.length)); - opIndex += currentOp.length; - } else { - return null; - } - } - - return result; - } - PartialEvaluator.prototype = { getOperatorList: function PartialEvaluator_getOperatorList(stream, resources, @@ -285,39 +267,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { resources = resources || new Dict(); var xobjs = resources.get('XObject') || new Dict(); var patterns = resources.get('Pattern') || new Dict(); - var parser = new Parser(new Lexer(stream), false, xref); + var parser = new Parser(new Lexer(stream, OP_MAP), false, xref); var res = resources; - var hasNextObj = false, nextObjs; var args = [], obj; var TILING_PATTERN = 1, SHADING_PATTERN = 2; while (true) { - if (hasNextObj) { - obj = nextObjs.pop(); - hasNextObj = (nextObjs.length > 0); - } else { - obj = parser.getObj(); - if (isEOF(obj)) - break; - } + obj = parser.getObj(); + if (isEOF(obj)) + break; if (isCmd(obj)) { var cmd = obj.cmd; var fn = OP_MAP[cmd]; - if (!fn) { - // invalid content command, trying to recover - var cmds = splitCombinedOperations(cmd); - if (cmds) { - cmd = cmds[0]; - fn = OP_MAP[cmd]; - // feeding other command on the next iteration - hasNextObj = true; - nextObjs = []; - for (var idx = 1; idx < cmds.length; idx++) { - nextObjs.push(Cmd.get(cmds[idx])); - } - } - } assertWellFormed(fn, 'Unknown command "' + cmd + '"'); // TODO figure out how to type-check vararg functions @@ -725,8 +687,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } } else if (octet == 0x3E) { if (token.length) { - // XXX guessing chars size by checking number size in the CMap - if (token.length <= 2 && properties.composite) + // Heuristic: guessing chars size by checking numbers sizes + // in the CMap entries. + if (token.length == 2 && properties.composite) properties.wideChars = false; if (token.length <= 4) { diff --git a/src/fonts.js b/src/fonts.js index 9dfaff87e..252dd11da 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -2706,9 +2706,9 @@ var Font = (function FontClosure() { this.isSymbolicFont = false; } - // heuristics: if removed more than 2 glyphs encoding WinAnsiEncoding - // does not set properly - if (glyphsRemoved > 2) { + // heuristics: if removed more than 10 glyphs encoding WinAnsiEncoding + // does not set properly (broken PDFs have about 100 removed glyphs) + if (glyphsRemoved > 10) { warn('Switching TrueType encoding to MacRomanEncoding for ' + this.name + ' font'); encoding = Encodings.MacRomanEncoding; @@ -4208,7 +4208,7 @@ var CFFFont = (function CFFFontClosure() { this.properties = properties; var parser = new CFFParser(file, properties); - var cff = parser.parse(); + var cff = parser.parse(true); var compiler = new CFFCompiler(cff); this.readExtra(cff); try { @@ -4299,7 +4299,7 @@ var CFFParser = (function CFFParserClosure() { this.properties = properties; } CFFParser.prototype = { - parse: function CFFParser_parse() { + parse: function CFFParser_parse(normalizeCIDData) { var properties = this.properties; var cff = new CFF(); this.cff = cff; @@ -4354,6 +4354,21 @@ var CFFParser = (function CFFParserClosure() { cff.charset = charset; cff.encoding = encoding; + if (!cff.isCIDFont || !normalizeCIDData) + return cff; + + // DirectWrite does not like CID fonts data. Trying to convert/flatten + // the font data and remove CID properties. + if (cff.fdArray.length !== 1) + error('Unable to normalize CID font in CFF data'); + + var fontDict = cff.fdArray[0]; + fontDict.setByKey(17, topDict.getByName('CharStrings')); + cff.topDict = fontDict; + cff.isCIDFont = false; + delete cff.fdArray; + delete cff.fdSelect; + return cff; }, parseHeader: function CFFParser_parseHeader() { diff --git a/src/parser.js b/src/parser.js index 2855018a6..6c9b4e67f 100644 --- a/src/parser.js +++ b/src/parser.js @@ -264,8 +264,16 @@ var Parser = (function ParserClosure() { })(); var Lexer = (function LexerClosure() { - function Lexer(stream) { + function Lexer(stream, knownCommands) { this.stream = stream; + // The PDFs might have "glued" commands with other commands, operands or + // literals, e.g. "q1". The knownCommands is a dictionary of the valid + // commands and their prefixes. The prefixes are built the following way: + // if there a command that is a prefix of the other valid command or + // literal (e.g. 'f' and 'false') the following prefixes must be included, + // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no + // other commands or literals as a prefix. The knowCommands is optional. + this.knownCommands = knownCommands; } Lexer.isSpace = function Lexer_isSpace(ch) { @@ -529,12 +537,18 @@ var Lexer = (function LexerClosure() { // command var str = ch; + var knownCommands = this.knownCommands; + var knownCommandFound = knownCommands && (str in knownCommands); while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) { + // stop if known command is found and next character does not make + // the str a command + if (knownCommandFound && !((str + ch) in knownCommands)) + break; stream.skip(); if (str.length == 128) error('Command token too long: ' + str.length); - str += ch; + knownCommandFound = knownCommands && (str in knownCommands); } if (str == 'true') return true; diff --git a/test/mozcentral/Makefile.in b/test/mozcentral/Makefile.in new file mode 100644 index 000000000..8c9face17 --- /dev/null +++ b/test/mozcentral/Makefile.in @@ -0,0 +1,21 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = browser/extensions/pdfjs/test + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_BROWSER_TEST_FILES = \ + head.js \ + browser_pdfjs_main.js \ + file_pdfjs_test.pdf \ + $(NULL) + +libs:: $(_BROWSER_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir) diff --git a/test/mozcentral/browser_pdfjs_main.js b/test/mozcentral/browser_pdfjs_main.js new file mode 100644 index 000000000..d3f5dd646 --- /dev/null +++ b/test/mozcentral/browser_pdfjs_main.js @@ -0,0 +1,102 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const RELATIVE_DIR = "browser/extensions/pdfjs/test/"; +const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; + +function test() { + waitForExplicitFinish(); + + var tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf"); + var newTabBrowser = gBrowser.getBrowserForTab(tab); + newTabBrowser.addEventListener("pagechange", function onPageChange() { + newTabBrowser.removeEventListener("pagechange", onPageChange, true); + + var document = newTabBrowser.contentDocument, + window = newTabBrowser.contentWindow; + + // + // Overall sanity tests + // + ok(document.querySelector('div#viewer'), "document content has viewer UI"); + ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object"); + + // + // Sidebar: open + // + var sidebar = document.querySelector('button#sidebarToggle'), + outerContainer = document.querySelector('div#outerContainer'); + + sidebar.click(); + ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click'); + + // Thumbnails are created asynchronously - wait for them + waitForElement(document, 'canvas#thumbnail2', function(error) { + if (error) + finish(); + + // + // Page change from thumbnail click + // + var pageNumber = document.querySelector('input#pageNumber'); + is(parseInt(pageNumber.value), 1, 'initial page is 1'); + + var thumbnail = document.querySelector('canvas#thumbnail2'); + ok(thumbnail, 'thumbnail2 is available'); + if (thumbnail) { + thumbnail.click(); + is(parseInt(pageNumber.value), 2, 'clicking on thumbnail changes page'); + } + + // + // Sidebar: close + // + sidebar.click(); + ok(!outerContainer.classList.contains('sidebarOpen'), 'sidebar closes on click'); + + // + // Page change from prev/next buttons + // + var prevPage = document.querySelector('button#previous'), + nextPage = document.querySelector('button#next'); + + nextPage.click(); + is(parseInt(pageNumber.value), 2, 'page increases after clicking on next'); + + prevPage.click(); + is(parseInt(pageNumber.value), 1, 'page decreases after clicking on previous'); + + // + // Bookmark button + // + var viewBookmark = document.querySelector('a#viewBookmark'); + viewBookmark.click(); + ok(viewBookmark.href.length > 0, 'viewBookmark button has href'); + + // + // Zoom in/out + // + var zoomOut = document.querySelector('button.zoomOut'), + zoomIn = document.querySelector('button.zoomIn'); + + // Zoom in + var oldWidth = document.querySelector('canvas#page1').width; + zoomIn.click(); + var newWidth = document.querySelector('canvas#page1').width; + ok(oldWidth < newWidth, 'zooming in increases page width (old: '+oldWidth+', new: '+newWidth+')'); + + // Zoom out + var oldWidth = document.querySelector('canvas#page1').width; + zoomOut.click(); + var newWidth = document.querySelector('canvas#page1').width; + ok(oldWidth > newWidth, 'zooming out decreases page width (old: '+oldWidth+', new: '+newWidth+')'); + + finish(); + }); + }, true, true); + + registerCleanupFunction(function() { + gBrowser.removeTab(tab); + }); +} diff --git a/test/mozcentral/file_pdfjs_test.pdf b/test/mozcentral/file_pdfjs_test.pdf new file mode 100644 index 000000000..ea5ebe395 Binary files /dev/null and b/test/mozcentral/file_pdfjs_test.pdf differ diff --git a/test/mozcentral/head.js b/test/mozcentral/head.js new file mode 100644 index 000000000..6ee421b2f --- /dev/null +++ b/test/mozcentral/head.js @@ -0,0 +1,21 @@ +// Waits for element 'el' to exist in the DOM of 'doc' before executing 'callback' +// Useful when elements are created asynchronously, e.g. after a Web Worker task +function waitForElement(doc, el, callback) { + var time = 0, + interval = 10, + timeout = 5000; + + var checkEl = setInterval(function() { + if (doc.querySelector(el)) { + clearInterval(checkEl); + if (callback) callback(); + } + + time += interval; + if (time > timeout) { + ok(false, 'waitForElement timed out on element: '+el); + clearInterval(checkEl); + if (callback) callback(true); + } + }, interval); +} diff --git a/test/pdfs/issue1709.pdf.link b/test/pdfs/issue1709.pdf.link new file mode 100644 index 000000000..ca5121b2d --- /dev/null +++ b/test/pdfs/issue1709.pdf.link @@ -0,0 +1 @@ +http://www.mft-online.de/files/medizinerreport_2012.pdf diff --git a/test/pdfs/issue1721.pdf.link b/test/pdfs/issue1721.pdf.link new file mode 100644 index 000000000..5a36166d8 --- /dev/null +++ b/test/pdfs/issue1721.pdf.link @@ -0,0 +1 @@ +http://www.lezarts.org/07oforhom/Faitsdivers/Hadopi/Le%20Rapport%20Hadopi,%20Intox.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 4706b68c4..25d2a2080 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -402,6 +402,14 @@ "link": true, "type": "eq" }, + { "id": "issue1709", + "file": "pdfs/issue1709.pdf", + "md5": "84497bd23b7c82d03d2681a1cb1d9ed0", + "rounds": 1, + "pageLimit": 10, + "link": true, + "type": "eq" + }, { "id": "issue1015", "file": "pdfs/issue1015.pdf", "md5": "b61503d1b445742b665212866afb60e2", @@ -550,6 +558,14 @@ "link": false, "type": "eq" }, + { "id": "issue1721", + "file": "pdfs/issue1721.pdf", + "md5": "b47177f9e5197a76ec498733ecab60e6", + "rounds": 1, + "pageLimit": 2, + "link": true, + "type": "eq" + }, { "id": "issue1243", "file": "pdfs/issue1243.pdf", "md5": "130c849b83513d5ac5e03c6421fc7489", diff --git a/test/unit/evaluator_spec.js b/test/unit/evaluator_spec.js index 4ee0768a7..e31a525ac 100644 --- a/test/unit/evaluator_spec.js +++ b/test/unit/evaluator_spec.js @@ -78,6 +78,54 @@ describe('evaluator', function() { expect(result.fnArray[1]).toEqual('save'); expect(result.fnArray[2]).toEqual('save'); }); + + it('should handle three glued operations #2', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var resources = new ResourcesMock(); + resources.Res1 = {}; + var stream = new StringStream('B*BBMC'); + var result = evaluator.getOperatorList(stream, resources, []); + + expect(!!result.fnArray && !!result.argsArray).toEqual(true); + expect(result.fnArray.length).toEqual(3); + expect(result.fnArray[0]).toEqual('eoFillStroke'); + expect(result.fnArray[1]).toEqual('fillStroke'); + expect(result.fnArray[2]).toEqual('beginMarkedContent'); + }); + + it('should handle glued operations and operands', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var stream = new StringStream('q5 Ts'); + var result = evaluator.getOperatorList(stream, new ResourcesMock(), []); + + expect(!!result.fnArray && !!result.argsArray).toEqual(true); + expect(result.fnArray.length).toEqual(2); + expect(result.fnArray[0]).toEqual('save'); + expect(result.fnArray[1]).toEqual('setTextRise'); + expect(result.argsArray.length).toEqual(2); + expect(result.argsArray[1].length).toEqual(1); + expect(result.argsArray[1][0]).toEqual(5); + }); + + it('should handle glued operations and literals', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var stream = new StringStream('trueifalserinulli'); + var result = evaluator.getOperatorList(stream, new ResourcesMock(), []); + + expect(!!result.fnArray && !!result.argsArray).toEqual(true); + expect(result.fnArray.length).toEqual(3); + expect(result.fnArray[0]).toEqual('setFlatness'); + expect(result.fnArray[1]).toEqual('setRenderingIntent'); + expect(result.fnArray[2]).toEqual('setFlatness'); + expect(result.argsArray.length).toEqual(3); + expect(result.argsArray[0].length).toEqual(1); + expect(result.argsArray[0][0]).toEqual(true); + expect(result.argsArray[1].length).toEqual(1); + expect(result.argsArray[1][0]).toEqual(false); + }); }); });