From 84b4f53ed60432b85cb1d63f085160d4302925ea Mon Sep 17 00:00:00 2001 From: Yury Delendik <ydelendik@mozilla.com> Date: Fri, 18 May 2012 11:14:09 -0500 Subject: [PATCH 01/10] Adjusts MacRoman switch heuristics threshold --- src/fonts.js | 6 +++--- test/pdfs/issue1709.pdf.link | 1 + test/test_manifest.json | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 test/pdfs/issue1709.pdf.link diff --git a/src/fonts.js b/src/fonts.js index 22037e724..9e4189462 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -1976,9 +1976,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; 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/test_manifest.json b/test/test_manifest.json index 5ec9e850f..3caaf3bd4 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", From ed02be835222091a62797b6d5c69286ed8c97fb2 Mon Sep 17 00:00:00 2001 From: Yury Delendik <ydelendik@mozilla.com> Date: Fri, 18 May 2012 16:51:55 -0500 Subject: [PATCH 02/10] Removes the CID data from the CFF font --- src/fonts.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/fonts.js b/src/fonts.js index 22037e724..d235881df 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -3477,7 +3477,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 { @@ -3568,7 +3568,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; @@ -3623,6 +3623,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() { From ec6c185cf5b5f8ac3af3f9e2f45f3bf40b32e22f Mon Sep 17 00:00:00 2001 From: Yury Delendik <ydelendik@mozilla.com> Date: Sun, 20 May 2012 13:44:03 -0500 Subject: [PATCH 03/10] Allow parsing of the "glued" commands --- src/evaluator.js | 64 ++++++------------------------------- src/parser.js | 11 +++++-- test/unit/evaluator_spec.js | 30 +++++++++++++++++ 3 files changed, 48 insertions(+), 57 deletions(-) diff --git a/src/evaluator.js b/src/evaluator.js index ae443fa81..2c07db88c 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -108,38 +108,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // Compatibility BX: 'beginCompat', - EX: 'endCompat' - }; - - 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; - } - } + EX: 'endCompat', - return result; - } + // (reserved partial commands for the lexer) + BM: null, + BD: null + }; PartialEvaluator.prototype = { getOperatorList: function PartialEvaluator_getOperatorList(stream, @@ -284,39 +258,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 diff --git a/src/parser.js b/src/parser.js index 2855018a6..3a2218f0d 100644 --- a/src/parser.js +++ b/src/parser.js @@ -264,8 +264,9 @@ var Parser = (function ParserClosure() { })(); var Lexer = (function LexerClosure() { - function Lexer(stream) { + function Lexer(stream, knownCommands) { this.stream = stream; + this.knownCommands = knownCommands; } Lexer.isSpace = function Lexer_isSpace(ch) { @@ -529,12 +530,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/unit/evaluator_spec.js b/test/unit/evaluator_spec.js index 4ee0768a7..286b8158a 100644 --- a/test/unit/evaluator_spec.js +++ b/test/unit/evaluator_spec.js @@ -78,6 +78,36 @@ 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); + }); }); }); From 43f1946c7a57b42cf1306c5857859cec9209edbc Mon Sep 17 00:00:00 2001 From: Yury Delendik <ydelendik@mozilla.com> Date: Sun, 20 May 2012 14:05:23 -0500 Subject: [PATCH 04/10] Add prefixes for literals --- src/evaluator.js | 10 +++++++++- test/unit/evaluator_spec.js | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/evaluator.js b/src/evaluator.js index 2c07db88c..1dab7de0b 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -112,7 +112,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // (reserved partial commands for the lexer) BM: null, - BD: null + BD: null, + 'true': null, + fa: null, + fal: null, + fals: null, + 'false': null, + nu: null, + nul: null, + 'null': null }; PartialEvaluator.prototype = { diff --git a/test/unit/evaluator_spec.js b/test/unit/evaluator_spec.js index 286b8158a..e31a525ac 100644 --- a/test/unit/evaluator_spec.js +++ b/test/unit/evaluator_spec.js @@ -108,6 +108,24 @@ describe('evaluator', function() { 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); + }); }); }); From 874357aac1762f111192c212452ba43bc9d0ee70 Mon Sep 17 00:00:00 2001 From: Yury Delendik <ydelendik@mozilla.com> Date: Mon, 21 May 2012 15:23:49 -0500 Subject: [PATCH 05/10] Comment for knownCommands --- src/parser.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/parser.js b/src/parser.js index 3a2218f0d..6c9b4e67f 100644 --- a/src/parser.js +++ b/src/parser.js @@ -266,6 +266,13 @@ var Parser = (function ParserClosure() { var Lexer = (function LexerClosure() { 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; } From 6971aec9f33558c8459733330b05fcc2f555ffd0 Mon Sep 17 00:00:00 2001 From: Yury Delendik <ydelendik@mozilla.com> Date: Mon, 21 May 2012 22:15:09 -0500 Subject: [PATCH 06/10] Adjust heuristic to properly handle unicode characters --- src/evaluator.js | 5 +++-- test/pdfs/issue1721.pdf.link | 1 + test/test_manifest.json | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 test/pdfs/issue1721.pdf.link diff --git a/src/evaluator.js b/src/evaluator.js index 1dab7de0b..1a8db1473 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -611,8 +611,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/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..be30d6c81 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -550,6 +550,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", From 424f52205c67262ebfc7fe05c3e94d0673d10bcf Mon Sep 17 00:00:00 2001 From: Artur Adib <arturadib@gmail.com> Date: Tue, 22 May 2012 18:56:12 -0400 Subject: [PATCH 07/10] Fixed moz-central manifest; bundling Mochitests --- extensions/firefox/chrome-mozcentral.manifest | 8 ++ make.js | 10 +- test/mozcentral/Makefile.in | 21 ++++ test/mozcentral/browser_pdfjs_main.js | 102 ++++++++++++++++++ test/mozcentral/file_pdfjs_test.pdf | Bin 0 -> 14234 bytes test/mozcentral/head.js | 21 ++++ 6 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 extensions/firefox/chrome-mozcentral.manifest create mode 100644 test/mozcentral/Makefile.in create mode 100644 test/mozcentral/browser_pdfjs_main.js create mode 100644 test/mozcentral/file_pdfjs_test.pdf create mode 100644 test/mozcentral/head.js diff --git a/extensions/firefox/chrome-mozcentral.manifest b/extensions/firefox/chrome-mozcentral.manifest new file mode 100644 index 000000000..8348f377e --- /dev/null +++ b/extensions/firefox/chrome-mozcentral.manifest @@ -0,0 +1,8 @@ +resource pdf.js content/ +component {6457a96b-2d68-439a-bcfa-44465fbcdbb1} components/PdfStreamConverter.js +contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {6457a96b-2d68-439a-bcfa-44465fbcdbb1} + +# Additional resources for pdf.js + +# PDFJS_SUPPORTED_LOCALES + diff --git a/make.js b/make.js index 88f7c69a0..05c9cceff 100755 --- a/make.js +++ b/make.js @@ -377,9 +377,10 @@ 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', @@ -415,6 +416,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 @@ -457,6 +460,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/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 0000000000000000000000000000000000000000..ea5ebe39538ca03715041d802ad769005141f200 GIT binary patch literal 14234 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 literal 0 HcmV?d00001 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); +} From ea60f2a0880ba015e4af0c6cf04b3e0aee7429da Mon Sep 17 00:00:00 2001 From: Artur Adib <arturadib@gmail.com> Date: Tue, 22 May 2012 19:20:24 -0400 Subject: [PATCH 08/10] addr reviewer comments --- extensions/firefox/chrome-mozcentral.manifest | 5 ----- make.js | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/extensions/firefox/chrome-mozcentral.manifest b/extensions/firefox/chrome-mozcentral.manifest index 8348f377e..2618c476b 100644 --- a/extensions/firefox/chrome-mozcentral.manifest +++ b/extensions/firefox/chrome-mozcentral.manifest @@ -1,8 +1,3 @@ resource pdf.js content/ component {6457a96b-2d68-439a-bcfa-44465fbcdbb1} components/PdfStreamConverter.js contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {6457a96b-2d68-439a-bcfa-44465fbcdbb1} - -# Additional resources for pdf.js - -# PDFJS_SUPPORTED_LOCALES - diff --git a/make.js b/make.js index 05c9cceff..7862b1dc5 100755 --- a/make.js +++ b/make.js @@ -394,8 +394,7 @@ target.mozcentral = function() { DEFAULT_LOCALE_FILES = [LOCALE_SRC_DIR + 'en-US/viewer.properties'], FIREFOX_MC_EXTENSION_FILES = - ['bootstrap.js', - 'icon.png', + ['icon.png', 'icon64.png', 'chrome.manifest', 'components', From d5bfd71c02999d53e5e35db236806023949d9d0f Mon Sep 17 00:00:00 2001 From: Sam <Sam@babelzilla.org> Date: Tue, 22 May 2012 19:33:39 -0500 Subject: [PATCH 09/10] Czech locale --- l10n/cs/metadata.inc | 8 +++++++ l10n/cs/viewer.properties | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 l10n/cs/metadata.inc create mode 100644 l10n/cs/viewer.properties 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 @@ + <em:localized> + <Description> + <em:locale>cs</em:locale> + <em:name>PDF Viewer</em:name> + <em:description>Používá HTML5 pro zobrazení PDF souborů přímo ve Firefoxu.</em:description> + </Description> + </em:localized> + 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: From 4bee4c6ee862eebdebd880fceb86b206067a17d9 Mon Sep 17 00:00:00 2001 From: Brendan Dahl <brendan.dahl@gmail.com> Date: Wed, 23 May 2012 15:57:14 -0700 Subject: [PATCH 10/10] Use different id's for moz central and extension. --- extensions/firefox/chrome-mozcentral.manifest | 4 +-- .../firefox/components/PdfStreamConverter.js | 12 ++++----- extensions/firefox/install.rdf.in | 27 ------------------- make.js | 20 +++++++++----- 4 files changed, 21 insertions(+), 42 deletions(-) delete mode 100644 extensions/firefox/install.rdf.in diff --git a/extensions/firefox/chrome-mozcentral.manifest b/extensions/firefox/chrome-mozcentral.manifest index 2618c476b..a2a6757c3 100644 --- a/extensions/firefox/chrome-mozcentral.manifest +++ b/extensions/firefox/chrome-mozcentral.manifest @@ -1,3 +1,3 @@ resource pdf.js content/ -component {6457a96b-2d68-439a-bcfa-44465fbcdbb1} components/PdfStreamConverter.js -contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {6457a96b-2d68-439a-bcfa-44465fbcdbb1} +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 1bcccbe22..2c984e86c 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,7 +160,7 @@ ChromeActions.prototype = { } }, pdfBugEnabled: function() { - return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false); + return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false); } }; @@ -190,7 +190,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 @@ -<?xml version="1.0"?> - -#filter substitution - -<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:em="http://www.mozilla.org/2004/em-rdf#"> - - <Description about="urn:mozilla:install-manifest"> - <em:id>uriloader@pdf.js</em:id> - <!-- PDFJS_LOCALIZED_METADATA --> - <em:name>PDF Viewer</em:name> - <em:version>PDFJSSCRIPT_VERSION</em:version> - <em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>@FIREFOX_VERSION@</em:minVersion> - <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion> - </Description> - </em:targetApplication> - <em:strictCompatibility>true</em:strictCompatibility> - <em:bootstrap>true</em:bootstrap> - <em:creator>Mozilla</em:creator> - <em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description> - <em:homepageURL>https://support.mozilla.org/kb/Opening%20PDF%20files%20within%20Firefox</em:homepageURL> - <em:type>2</em:type> - </Description> -</RDF> diff --git a/make.js b/make.js index 7862b1dc5..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'); @@ -383,20 +390,17 @@ target.mozcentral = function() { 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 = - ['icon.png', - 'icon64.png', - 'chrome.manifest', + ['chrome.manifest', 'components', 'content', 'LICENSE']; @@ -448,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 = '';