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);
+ });
});
});