From 45ae175d0b321d3b48d81dba25cffee0e67ff8be Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Thu, 17 May 2012 17:54:24 -0500 Subject: [PATCH 01/14] Fixes CFF: moves Subrs to Private tail --- src/fonts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fonts.js b/src/fonts.js index 22037e724..1354827e5 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -4221,9 +4221,9 @@ var CFFPrivateDict = (function CFFPrivateDictClosure() { [[12, 17], 'LanguageGroup', 'num', 0], [[12, 18], 'ExpansionFactor', 'num', 0.06], [[12, 19], 'initialRandomSeed', 'num', 0], - [19, 'Subrs', 'offset', null], [20, 'defaultWidthX', 'num', 0], - [21, 'nominalWidthX', 'num', 0] + [21, 'nominalWidthX', 'num', 0], + [19, 'Subrs', 'offset', null] ]; var tables = null; function CFFPrivateDict(strings) { From 686d637aa204d44f50d3725744309e56c0c733b6 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Thu, 17 May 2012 18:34:31 -0500 Subject: [PATCH 02/14] Reference test for 1629 --- test/pdfs/issue1629.pdf.link | 1 + test/test_manifest.json | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 test/pdfs/issue1629.pdf.link diff --git a/test/pdfs/issue1629.pdf.link b/test/pdfs/issue1629.pdf.link new file mode 100644 index 000000000..1d18104b5 --- /dev/null +++ b/test/pdfs/issue1629.pdf.link @@ -0,0 +1 @@ +http://is.muni.cz/www/20544/noty/sbm/Taize/Adoramus_te_Christe.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 5ec9e850f..4706b68c4 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -451,6 +451,13 @@ "link": true, "type": "eq" }, + { "id": "issue1629", + "file": "pdfs/issue1629.pdf", + "md5": "0f2cbbf268383a377e95e6bbe36c6a9a", + "rounds": 1, + "link": true, + "type": "eq" + }, { "id": "issue1169", "file": "pdfs/issue1169.pdf", "md5": "3df3ed21fd43ac7fdb21e2015c8a7809", From 84b4f53ed60432b85cb1d63f085160d4302925ea Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 18 May 2012 11:14:09 -0500 Subject: [PATCH 03/14] 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 Date: Fri, 18 May 2012 16:51:55 -0500 Subject: [PATCH 04/14] 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 Date: Sun, 20 May 2012 13:44:03 -0500 Subject: [PATCH 05/14] 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,39 +108,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // Compatibility BX: 'beginCompat', - EX: 'endCompat' + EX: 'endCompat', + + // (reserved partial commands for the lexer) + BM: null, + BD: 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, @@ -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 Date: Sun, 20 May 2012 14:05:23 -0500 Subject: [PATCH 06/14] 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 cc3e7197b337c16c5fe7e505847b57541e6cea80 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Sun, 20 May 2012 17:12:58 -0500 Subject: [PATCH 07/14] Replaces browse button with a icon --- l10n/en-US/viewer.properties | 1 + web/images/toolbarButton-openFile.png | Bin 0 -> 708 bytes web/viewer.css | 7 ++++++- web/viewer.html | 6 +----- web/viewer.js | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 web/images/toolbarButton-openFile.png diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index d0ba6ffac..0922062a6 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -43,3 +43,4 @@ zoom.title=Zoom thumb_page_title=Page {{page}} thumb_page_canvas=Thumbnail of Page {{page}} request_password=PDF is protected by a password: +open_file_label=Open diff --git a/web/images/toolbarButton-openFile.png b/web/images/toolbarButton-openFile.png new file mode 100644 index 0000000000000000000000000000000000000000..12ce45f876b12eef3e5030b492d58d5fbb47ebbf GIT binary patch literal 708 zcmV;#0z3VQP)T2_|?DW!B>L;_wc?Zu;_6+$X4 zAyT|~3gSQD&4XUWvp4HSiY75A*^4JJ20Zj;57vN9blYWVer?F^X0u_(gN-Cjiv3`i zZyxV^^SzmmFvf6Nq*AHJJkMXLR;%}Sc6Nek95PK{b90j)3eqTG{iw zjbgFb`maDTnLIZ$GxJVW)fc1SzwH5g+k#PjYgwa*VorC z?(OZNR4Rc|3PBJM1Oe98)}ScLU$2B<__)XW%J%lQO>Nu$-Rt#MG);r1X%j@x^CmDt z2!bGhZQB*=rL=?c`huGf$0000
- - - - 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/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 = '';