diff --git a/LICENSE b/LICENSE index d96b927a3..f8a848205 100644 --- a/LICENSE +++ b/LICENSE @@ -8,6 +8,7 @@ Justin D'Arcangelo Yury Delendik Kalervo Kujala + Adil Allawi <@ironymark> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Makefile b/Makefile index 0ca269642..fb4ffe9cb 100644 --- a/Makefile +++ b/Makefile @@ -55,30 +55,30 @@ browser-test: --browserManifestFile=$(PDF_BROWSERS) \ --manifestFile=$(PDF_TESTS) -# make shell-test -# -# This target runs all of the tests that can be run in a JS shell. -# The shell used is taken from the JS_SHELL environment variable. If -# that variable is not defined, the script will attempt to use the copy -# of Rhino that comes with the Closure compiler used for producing the -# website. -SHELL_TARGET = $(NULL) -ifeq ($(JS_SHELL),) -JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar" -JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main" -SHELL_TARGET = compiler -endif - -shell-test: shell-msg $(SHELL_TARGET) font-test -shell-msg: -ifeq ($(SHELL_TARGET), compiler) - @echo "No JS_SHELL env variable present." - @echo "The default is to find a copy of Rhino and try that." -endif - @echo "JS shell command is: $(JS_SHELL)" - -font-test: - @echo "font test stub." +# # make shell-test +# # +# # This target runs all of the tests that can be run in a JS shell. +# # The shell used is taken from the JS_SHELL environment variable. If +# # that variable is not defined, the script will attempt to use the copy +# # of Rhino that comes with the Closure compiler used for producing the +# # website. +# SHELL_TARGET = $(NULL) +# ifeq ($(JS_SHELL),) +# JS_SHELL := "java -cp $(BUILD_DIR)/compiler.jar" +# JS_SHELL += "com.google.javascript.jscomp.mozilla.rhino.tools.shell.Main" +# SHELL_TARGET = compiler +# endif +# +# shell-test: shell-msg $(SHELL_TARGET) font-test +# shell-msg: +# ifeq ($(SHELL_TARGET), compiler) +# @echo "No JS_SHELL env variable present." +# @echo "The default is to find a copy of Rhino and try that." +# endif +# @echo "JS shell command is: $(JS_SHELL)" +# +# font-test: +# @echo "font test stub." # make lint # @@ -133,18 +133,18 @@ $(GH_PAGES)/web/%: web/% $(GH_PAGES)/web/images/%: web/images/% @cp $< $@ -# make compiler -# -# This target downloads the Closure compiler, and places it in the -# build directory. This target is also useful when the user doesn't -# have a JS shell available--we can have them use the Rhino shell that -# comes with Closure. -COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip - -compiler: $(BUILD_DIR)/compiler.zip -$(BUILD_DIR)/compiler.zip: | $(BUILD_DIR) - curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip; - cd $(BUILD_DIR); unzip compiler.zip compiler.jar; +# # make compiler +# # +# # This target downloads the Closure compiler, and places it in the +# # build directory. This target is also useful when the user doesn't +# # have a JS shell available--we can have them use the Rhino shell that +# # comes with Closure. +# COMPILER_URL = http://closure-compiler.googlecode.com/files/compiler-latest.zip +# +# compiler: $(BUILD_DIR)/compiler.zip +# $(BUILD_DIR)/compiler.zip: | $(BUILD_DIR) +# curl $(COMPILER_URL) > $(BUILD_DIR)/compiler.zip; +# cd $(BUILD_DIR); unzip compiler.zip compiler.jar; # make firefox-extension # diff --git a/README.md b/README.md index 0d439b139..252934cb7 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,84 @@ # pdf.js -pdf.js is a technology demonstrator prototype to explore whether the HTML5 -platform is complete enough to faithfully and efficiently render the ISO -32000-1:2008 Portable Document Format (PDF) without native code assistance. -pdf.js is not currently part of the Mozilla project, and there is no plan -yet to integrate it into Firefox. We will explore that possibility once -pdf.js is production ready. Until then we aim to publish a Firefox -PDF reader extension powered by pdf.js. + +## Overview + +pdf.js is an HTML5 technology experiment that explores building a faithful +and efficient Portable Document Format (PDF) renderer without native code +assistance. + +pdf.js is community-driven and supported by Mozilla Labs. Our goal is to +create a general-purpose, web standards-based platform for parsing and +rendering PDFs, and eventually release a PDF reader extension powered by +pdf.js. Integration with Firefox is a possibility if the experiment proves +successful. + + + +## Getting started + +**Online demo** + +For an online demo, visit: + + http://andreasgal.github.com/pdf.js/web/viewer.html + +This demo provides an interactive interface for displaying and browsing PDFs +using the pdf.js API. + +**Hello world** + +For a "hello world" example, take a look at: + + examples/helloworld/ + +This example illustrates the bare minimum ingredients for integrating pdf.js +in a custom project. + + + +## Running the Tests + +pdf.js comes with browser-level regression tests that allow one to probe +whether it's able to successfully parse PDFs, as well as compare its output +against reference images, pixel-by-pixel. + +To run the tests, first configure the browser manifest file at: + + test/resources/browser_manifests/browser_manifest.json + +Sample manifests for different platforms are provided in that directory. + +To run all the bundled tests, type: + + $ make test + +and cross your fingers. Different types of tests are available, see the test +manifest file at: + + test/test_manifest.json + +The test type `eq` tests whether the output images are identical to reference +images. The test type `load` simply tests whether the file loads without +raising any errors. + + +## Contributing + +pdf.js is a community-driver project, so contributors are always welcome. +Simply fork our repo and contribute away. A great place to start is our +open issues. + +For better consistency and long-term stability, please do look around the +code and try to follow our conventions. + + +## Additional resources Our demo site is here: - http://andreasgal.github.com/pdf.js/ + http://andreasgal.github.com/pdf.js/web/viewer.html You can read more about pdf.js here: @@ -19,14 +86,14 @@ You can read more about pdf.js here: http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/ -follow us on twitter: @pdfjs +Follow us on twitter: @pdfjs http://twitter.com/#!/pdfjs -join our mailing list: +Join our mailing list: dev-pdf-js@lists.mozilla.org -and talk to us on IRC: +Talk to us on IRC: #pdfjs on irc.mozilla.org diff --git a/examples/helloworld/README.md b/examples/helloworld/README.md new file mode 100644 index 000000000..8395733f3 --- /dev/null +++ b/examples/helloworld/README.md @@ -0,0 +1,16 @@ +## "Hello World" overview + +This example is a minimalistic application of the pdf.js project. The file +`helloworld.pdf` is from the GNUpdf project (see [Introduction to PDF at GNUpdf](http://gnupdf.org/Introduction_to_PDF), and contains a simple and +human-readable PDF. + + +## Getting started + +Point your browser to `index.html`. Voila. Take a peek at `hello.js` to see +how to make basic calls to `pdf.js`. + + +## Additional resources + ++ [GNUpdf - Introduction to PDF](http://gnupdf.org/Introduction_to_PDF) diff --git a/examples/helloworld/hello.js b/examples/helloworld/hello.js new file mode 100644 index 000000000..21799c33a --- /dev/null +++ b/examples/helloworld/hello.js @@ -0,0 +1,49 @@ +// +// See README for overview +// + + +// +// Ajax GET request, for binary files +// (like jQuery's $.get(), but supports the binary type ArrayBuffer) +// +var ajaxGet = function(url, callback){ + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.mozResponseType = xhr.responseType = 'arraybuffer'; + xhr.expected = (document.URL.indexOf('file:') === 0) ? 0 : 200; + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === xhr.expected) { + var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse || + xhr.responseArrayBuffer || xhr.response); + + callback(data); + } + }; + xhr.send(null); +} + +// +// This is where the fun happens +// +ajaxGet('helloworld.pdf', function(data){ + // + // Instantiate PDFDoc with PDF data + // + var pdf = new PDFDoc(new Stream(data)); + var page = pdf.getPage(1); + var scale = 1.5; + + // + // Prepare canvas using PDF page dimensions + // + var canvas = document.getElementById('the-canvas'); + var context = canvas.getContext('2d'); + canvas.height = page.height * scale; + canvas.width = page.width * scale; + + // + // Render PDF page into canvas context + // + page.startRendering(context); +}); diff --git a/examples/helloworld/helloworld.pdf b/examples/helloworld/helloworld.pdf new file mode 100644 index 000000000..d98b4e1db --- /dev/null +++ b/examples/helloworld/helloworld.pdf @@ -0,0 +1,68 @@ +%PDF-1.7 + +1 0 obj % entry point +<< + /Type /Catalog + /Pages 2 0 R +>> +endobj + +2 0 obj +<< + /Type /Pages + /MediaBox [ 0 0 200 200 ] + /Count 1 + /Kids [ 3 0 R ] +>> +endobj + +3 0 obj +<< + /Type /Page + /Parent 2 0 R + /Resources << + /Font << + /F1 4 0 R + >> + >> + /Contents 5 0 R +>> +endobj + +4 0 obj +<< + /Type /Font + /Subtype /Type1 + /BaseFont /Times-Roman +>> +endobj + +5 0 obj % page content +<< + /Length 44 +>> +stream +BT +70 50 TD +/F1 12 Tf +(Hello, world!) Tj +ET +endstream +endobj + +xref +0 6 +0000000000 65535 f +0000000010 00000 n +0000000079 00000 n +0000000173 00000 n +0000000301 00000 n +0000000380 00000 n +trailer +<< + /Size 6 + /Root 1 0 R +>> +startxref +492 +%%EOF \ No newline at end of file diff --git a/examples/helloworld/index.html b/examples/helloworld/index.html new file mode 100644 index 000000000..c353b6a89 --- /dev/null +++ b/examples/helloworld/index.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/fonts.js b/fonts.js index 4f107ef80..3beac011a 100644 --- a/fonts.js +++ b/fonts.js @@ -12,6 +12,9 @@ var kMaxWaitForFontFace = 1000; // Unicode Private Use Area var kCmapGlyphOffset = 0xE000; +// PDF Glyph Space Units are one Thousandth of a TextSpace Unit except for Type 3 fonts +var kPDFGlyphSpaceUnits = 1000; + // Until hinting is fully supported this constant can be used var kHintingEnabled = false; @@ -536,6 +539,10 @@ var Font = (function Font() { }; function createOpenTypeHeader(sfnt, file, numTables) { + // Windows hates the Mac TrueType sfnt version number + if (sfnt == 'true') + sfnt = string32(0x00010000); + // sfnt version (4 bytes) var header = sfnt; @@ -665,7 +672,9 @@ var Font = (function Font() { format314); }; - function createOS2Table(properties) { + function createOS2Table(properties, override) { + var override = override || {}; + var ulUnicodeRange1 = 0; var ulUnicodeRange2 = 0; var ulUnicodeRange3 = 0; @@ -696,6 +705,21 @@ var Font = (function Font() { } } + var unitsPerEm = override.unitsPerEm || kPDFGlyphSpaceUnits; + var typoAscent = override.ascent || properties.ascent; + var typoDescent = override.descent || properties.descent; + var winAscent = override.yMax || typoAscent; + var winDescent = -override.yMin || -typoDescent; + + // if there is a units per em value but no other override then scale the calculated ascent + if (unitsPerEm != kPDFGlyphSpaceUnits && 'undefined' == typeof(override.ascent)) { + // if the font units differ to the PDF glyph space units then scale up the values + typoAscent = Math.round(typoAscent * unitsPerEm / kPDFGlyphSpaceUnits); + typoDescent = Math.round(typoDescent * unitsPerEm / kPDFGlyphSpaceUnits); + winAscent = typoAscent; + winDescent = -typoDescent; + } + return '\x00\x03' + // version '\x02\x24' + // xAvgCharWidth '\x01\xF4' + // usWeightClass @@ -724,11 +748,11 @@ var Font = (function Font() { string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex string16(lastCharIndex || properties.lastChar) + // usLastCharIndex - string16(properties.ascent) + // sTypoAscender - string16(properties.descent) + // sTypoDescender + string16(typoAscent) + // sTypoAscender + string16(typoDescent) + // sTypoDescender '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value) - string16(properties.ascent) + // usWinAscent - string16(-properties.descent) + // usWinDescent + string16(winAscent) + // usWinAscent + string16(winDescent) + // usWinDescent '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31) '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight @@ -835,9 +859,11 @@ var Font = (function Font() { var data = file.getBytes(length); file.pos = previousPosition; - if (tag == 'head') + if (tag == 'head') { // clearing checksum adjustment data[8] = data[9] = data[10] = data[11] = 0; + data[17] |= 0x20; //Set font optimized for cleartype flag + } return { tag: tag, @@ -1010,7 +1036,7 @@ var Font = (function Font() { var header = readOpenTypeHeader(font); var numTables = header.numTables; - var cmap, maxp, hhea, hmtx, vhea, vmtx; + var cmap, maxp, hhea, hmtx, vhea, vmtx, head; var tables = []; for (var i = 0; i < numTables; i++) { var table = readTableEntry(font); @@ -1024,6 +1050,8 @@ var Font = (function Font() { hhea = table; else if (table.tag == 'hmtx') hmtx = table; + else if (table.tag == 'head') + head = table; requiredTables.splice(index, 1); } else { @@ -1050,9 +1078,18 @@ var Font = (function Font() { createOpenTypeHeader(header.version, ttf, numTables); if (requiredTables.indexOf('OS/2') != -1) { + //extract some more font properties from the OpenType head and hhea tables + var override = { + unitsPerEm: int16([head.data[18], head.data[19]]), + yMax: int16([head.data[42], head.data[43]]), + yMin: int16([head.data[38], head.data[39]]) - 0x10000, //always negative + ascent: int16([hhea.data[4], hhea.data[5]]), + descent: int16([hhea.data[6], hhea.data[7]]) - 0x10000 //always negative + } + tables.push({ tag: 'OS/2', - data: stringToArray(createOS2Table(properties)) + data: stringToArray(createOS2Table(properties, override)) }); } diff --git a/pdf.js b/pdf.js index 0c10e5865..975792141 100644 --- a/pdf.js +++ b/pdf.js @@ -3224,7 +3224,14 @@ var XRef = (function() { error('bad XRef entry'); } if (this.encrypt && !suppressEncryption) { - e = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + try { + e = parser.getObj(this.encrypt.createCipherTransform(num, gen)); + } catch(ex) { + // almost all streams must to encrypted, but sometimes + // they are not probably due to some broken generators + // re-trying without encryption + return this.fetch(ref, true); + } } else { e = parser.getObj(); } @@ -4381,7 +4388,7 @@ var PartialEvaluator = (function() { if (type == 'TrueType' && dict.has('ToUnicode') && differences) { var cmapObj = dict.get('ToUnicode'); if (IsRef(cmapObj)) { - cmapObj = xref.fetch(cmapObj, true); + cmapObj = xref.fetch(cmapObj); } if (IsName(cmapObj)) { error('ToUnicode file cmap translation not implemented'); @@ -6056,8 +6063,8 @@ var PDFImage = (function() { this.decode = dict.get('Decode', 'D'); - var mask = xref.fetchIfRef(image.dict.get('Mask')); - var smask = xref.fetchIfRef(image.dict.get('SMask')); + var mask = xref.fetchIfRef(dict.get('Mask')); + var smask = xref.fetchIfRef(dict.get('SMask')); if (mask) { TODO('masked images'); diff --git a/test/driver.js b/test/driver.js index f3e45a53d..14f1280a6 100644 --- a/test/driver.js +++ b/test/driver.js @@ -8,6 +8,7 @@ 'use strict'; var appPath, browser, canvas, currentTaskIdx, manifest, stdout; +var inFlightRequests = 0; function queryParams() { var qs = window.location.search.substring(1); @@ -42,7 +43,8 @@ function load() { if (r.readyState == 4) { log('done\n'); manifest = JSON.parse(r.responseText); - currentTaskIdx = 0, nextTask(); + currentTaskIdx = 0; + nextTask(); } }; r.send(null); @@ -73,7 +75,8 @@ function nextTask() { failure = 'load PDF doc : ' + e.toString(); } - task.pageNum = 1, nextPage(task, failure); + task.pageNum = 1; + nextPage(task, failure); } }; r.send(null); @@ -89,7 +92,8 @@ function nextPage(task, loadError) { if (!task.pdfDoc) { sendTaskResult(canvas.toDataURL('image/png'), task, failure); log('done' + (failure ? ' (failed !: ' + failure + ')' : '') + '\n'); - ++currentTaskIdx, nextTask(); + ++currentTaskIdx; + nextTask(); return; } @@ -98,7 +102,8 @@ function nextPage(task, loadError) { log(' Round ' + (1 + task.round) + '\n'); task.pageNum = 1; } else { - ++currentTaskIdx, nextTask(); + ++currentTaskIdx; + nextTask(); return; } } @@ -123,7 +128,7 @@ function nextPage(task, loadError) { page.startRendering( ctx, function(e) { - snapshotCurrentPage(page, task, (!failure && e) ? + snapshotCurrentPage(task, (!failure && e) ? ('render : ' + e) : failure); } ); @@ -135,11 +140,11 @@ function nextPage(task, loadError) { if (failure) { // Skip right to snapshotting if there was a failure, since the // fonts might be in an inconsistent state. - snapshotCurrentPage(page, task, failure); + snapshotCurrentPage(task, failure); } } -function snapshotCurrentPage(page, task, failure) { +function snapshotCurrentPage(task, failure) { log('done, snapshotting... '); sendTaskResult(canvas.toDataURL('image/png'), task, failure); @@ -149,7 +154,8 @@ function snapshotCurrentPage(page, task, failure) { var backoff = (inFlightRequests > 0) ? inFlightRequests * 10 : 0; setTimeout( function() { - ++task.pageNum, nextPage(task); + ++task.pageNum; + nextPage(task); }, backoff ); @@ -182,7 +188,6 @@ function done() { } } -var inFlightRequests = 0; function sendTaskResult(snapshot, task, failure) { var result = { browser: browser, id: task.id, @@ -201,7 +206,7 @@ function sendTaskResult(snapshot, task, failure) { if (r.readyState == 4) { inFlightRequests--; } - } + }; document.getElementById('inFlightCount').innerHTML = inFlightRequests++; r.send(JSON.stringify(result)); } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 95de9fb8e..77c89ece6 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -1,3 +1,13 @@ -pdf.pdf +DiwanProfile.pdf +artofwar.pdf +cable.pdf +ecma262.pdf +hmm.pdf +i9.pdf intelisa.pdf openweb_tm-PRINT.pdf +pdf.pdf +pdkids.pdf +shavian.pdf +jai.pdf + diff --git a/test/pdfs/wdsg_fitc.pdf.link b/test/pdfs/wdsg_fitc.pdf.link new file mode 100644 index 000000000..77d3b590d --- /dev/null +++ b/test/pdfs/wdsg_fitc.pdf.link @@ -0,0 +1 @@ +http://www.airgid.com/book/wdsg_fitc.pdf diff --git a/test/resources/browser_manifests/.gitignore b/test/resources/browser_manifests/.gitignore new file mode 100644 index 000000000..ca57ac505 --- /dev/null +++ b/test/resources/browser_manifests/.gitignore @@ -0,0 +1,2 @@ +browser_manifest.json + diff --git a/test/test_manifest.json b/test/test_manifest.json index 9dda57760..00e126cd4 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -116,6 +116,12 @@ "rounds": 1, "type": "eq" }, + { "id": "wdsg_fitc", + "file": "pdfs/wdsg_fitc.pdf", + "link": true, + "rounds": 1, + "type": "eq" + }, { "id": "fips197", "file": "pdfs/fips197.pdf", "link": true, diff --git a/utils/cffStandardStrings.js b/utils/cffStandardStrings.js index 326f298b0..8a6570551 100644 --- a/utils/cffStandardStrings.js +++ b/utils/cffStandardStrings.js @@ -560,7 +560,7 @@ var CFFDictDataMap = { '18': { name: 'ExpansionFactor' }, - '9': { + '19': { name: 'initialRandomSeed' }, '20': { diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js index 4826a09a1..a51469c53 100644 --- a/utils/fonts_utils.js +++ b/utils/fonts_utils.js @@ -69,7 +69,7 @@ function readCharstringEncoding(aString) { } else if (value <= 31) { token = CFFEncodingMap[value]; } else if (value < 247) { - token = parseInt(value) - 139; + token = parseInt(value, 10) - 139; } else if (value < 251) { token = ((value - 247) * 256) + aString[i++] + 108; } else if (value < 255) { @@ -113,7 +113,7 @@ function readFontDictData(aString, aMap) { while (!parsed) { var byte = aString[i++]; - var nibbles = [parseInt(byte / 16), parseInt(byte % 16)]; + var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)]; for (var j = 0; j < nibbles.length; j++) { var nibble = nibbles[j]; switch (nibble) { @@ -144,7 +144,7 @@ function readFontDictData(aString, aMap) { } else if (value <= 31) { token = aMap[value]; } else if (value <= 246) { - token = parseInt(value) - 139; + token = parseInt(value, 10) - 139; } else if (value <= 250) { token = ((value - 247) * 256) + aString[i++] + 108; } else if (value <= 254) { @@ -193,7 +193,7 @@ function readFontIndexData(aStream, aIsByte) { } error(offsize + ' is not a valid offset size'); return null; - }; + } var offsets = []; for (var i = 0; i < count + 1; i++) @@ -236,7 +236,7 @@ var Type2Parser = function(aFilePath) { function dump(aStr) { if (debug) log(aStr); - }; + } function parseAsToken(aString, aMap) { var decoded = readFontDictData(aString, aMap); @@ -277,7 +277,7 @@ var Type2Parser = function(aFilePath) { } } } - }; + } this.parse = function(aStream) { font.set('major', aStream.getByte()); @@ -353,7 +353,7 @@ var Type2Parser = function(aFilePath) { aStream.pos = charsetEntry; var charset = readCharset(aStream, charStrings); } - } + }; }; /* diff --git a/web/compatibility.js b/web/compatibility.js index 63ebecb63..2301678d5 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -1,6 +1,8 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +'use strict'; + // Checking if the typed arrays are supported (function() { if (typeof Uint8Array !== 'undefined') @@ -10,8 +12,9 @@ return this.slice(start, end); } - function set_(array, offset) { - if (arguments.length < 2) offset = 0; + function set_function(array, offset) { + if (arguments.length < 2) + offset = 0; for (var i = 0, n = array.length; i < n; ++i, ++offset) this[offset] = array[i] & 0xFF; } @@ -19,15 +22,17 @@ function TypedArray(arg1) { var result; if (typeof arg1 === 'number') { - result = new Array(arg1); - for (var i = 0; i < arg1; ++i) - result[i] = 0; + result = []; + for (var i = 0; i < arg1; ++i) + result[i] = 0; } else - result = arg1.slice(0); + result = arg1.slice(0); + result.subarray = subarray; result.buffer = result; result.byteLength = result.length; - result.set = set_; + result.set = set_function; + if (typeof arg1 === 'object' && arg1.buffer) result.buffer = arg1.buffer; diff --git a/web/viewer.js b/web/viewer.js index d7c9d6b66..520cf4efa 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -98,7 +98,7 @@ var PDFView = { }, get page() { - return parseInt(document.location.hash.substring(1)) || 1; + return parseInt(document.location.hash.substring(1), 10) || 1; }, open: function(url, scale) { @@ -170,7 +170,7 @@ var PDFView = { } this.setScale(scale || kDefaultScale, true); - this.page = parseInt(document.location.hash.substring(1)) || 1; + this.page = parseInt(document.location.hash.substring(1), 10) || 1; this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; if (pdf.catalog.documentOutline) { @@ -209,7 +209,7 @@ var PDFView = { var currentHeight = kBottomMargin; var windowTop = window.pageYOffset; - for (var i = 1; i <= pages.length; i++) { + for (var i = 1; i <= pages.length; ++i) { var page = pages[i - 1]; var pageHeight = page.height * page.scale + kBottomMargin; if (currentHeight + pageHeight > windowTop) @@ -219,10 +219,11 @@ var PDFView = { } var windowBottom = window.pageYOffset + window.innerHeight; - for (; i <= pages.length && currentHeight < windowBottom; i++) { - var page = pages[i - 1]; - visiblePages.push({ id: page.id, y: currentHeight, view: page }); - currentHeight += page.height * page.scale + kBottomMargin; + for (; i <= pages.length && currentHeight < windowBottom; ++i) { + var singlePage = pages[i - 1]; + visiblePages.push({ id: singlePage.id, y: currentHeight, + view: singlePage }); + currentHeight += singlePage.height * singlePage.scale + kBottomMargin; } return visiblePages; @@ -256,13 +257,13 @@ var PageView = function(container, content, id, width, height, div.removeAttribute('data-loaded'); }; - function setupLinks(canvas, content, scale) { + function setupLinks(content, scale) { function bindLink(link, dest) { link.onclick = function() { if (dest) PDFView.navigateTo(dest); return false; - } + }; } var links = content.getLinks(); for (var i = 0; i < links.length; i++) { @@ -283,8 +284,6 @@ var PageView = function(container, content, id, width, height, var width = 0, height = 0, widthScale, heightScale; var scale = 0; switch (dest[1].name) { - default: - return; case 'XYZ': x = dest[2]; y = dest[3]; @@ -315,6 +314,8 @@ var PageView = function(container, content, id, width, height, height / kCssUnits; scale = Math.min(widthScale, heightScale); break; + default: + return; } var boundingRect = [ @@ -369,7 +370,7 @@ var PageView = function(container, content, id, width, height, stats.begin = Date.now(); this.content.startRendering(ctx, this.updateStats); - setupLinks(canvas, this.content, this.scale); + setupLinks(this.content, this.scale); div.setAttribute('data-loaded', true); return true; diff --git a/worker/canvas.js b/worker/canvas.js index 5a9237d9a..d8b0dd338 100644 --- a/worker/canvas.js +++ b/worker/canvas.js @@ -39,7 +39,7 @@ function GradientProxy(cmdQueue, x0, y0, x1, y1) { cmdQueue.push(['$createLinearGradient', [x0, y0, x1, y1]]); this.addColorStop = function(i, rgba) { cmdQueue.push(['$addColorStop', [i, rgba]]); - } + }; } // Really simple PatternProxy. @@ -72,7 +72,7 @@ function CanvasProxy(width, height) { throw 'CanvasProxy can only provide a 2d context.'; } return ctx; - } + }; // Expose only the minimum of the canvas object - there is no dom to do // more here. @@ -127,7 +127,7 @@ function CanvasProxy(width, height) { return function() { // console.log("funcCall", name) cmdQueue.push([name, Array.prototype.slice.call(arguments)]); - } + }; } var name; for (var i = 0; i < ctxFunc.length; i++) { @@ -139,11 +139,11 @@ function CanvasProxy(width, height) { ctx.createPattern = function(object, kind) { return new PatternProxy(cmdQueue, object, kind); - } + }; ctx.createLinearGradient = function(x0, y0, x1, y1) { return new GradientProxy(cmdQueue, x0, y0, x1, y1); - } + }; ctx.getImageData = function(x, y, w, h) { return { @@ -151,11 +151,11 @@ function CanvasProxy(width, height) { height: h, data: Uint8ClampedArray(w * h * 4) }; - } + }; ctx.putImageData = function(data, x, y, width, height) { cmdQueue.push(['$putImageData', [data, x, y, width, height]]); - } + }; ctx.drawImage = function(image, x, y, width, height, sx, sy, swidth, sheight) { @@ -168,7 +168,7 @@ function CanvasProxy(width, height) { } else { throw 'unkown type to drawImage'; } - } + }; // Setup property access to `ctx`. var ctxProp = { @@ -195,14 +195,14 @@ function CanvasProxy(width, height) { function buildGetter(name) { return function() { return ctx['$' + name]; - } + }; } function buildSetter(name) { return function(value) { cmdQueue.push(['$', name, value]); - return ctx['$' + name] = value; - } + return (ctx['$' + name] = value); + }; } // Setting the value to `stroke|fillStyle` needs special handling, as it @@ -215,9 +215,9 @@ function CanvasProxy(width, height) { cmdQueue.push(['$' + name + 'Pattern', [value.id]]); } else { cmdQueue.push(['$', name, value]); - return ctx['$' + name] = value; + return (ctx['$' + name] = value); } - } + }; } for (var name in ctxProp) { diff --git a/worker/client.js b/worker/client.js index a20a4179f..36a0ae03a 100644 --- a/worker/client.js +++ b/worker/client.js @@ -58,7 +58,7 @@ FontWorker.prototype = { 'fonts': function(data) { // console.log("got processed fonts from worker", Object.keys(data)); - for (name in data) { + for (var name in data) { // Update the encoding property. var font = Fonts.lookup(name); font.properties = { @@ -176,7 +176,7 @@ function WorkerPDFDoc(canvas) { // Copy over the imageData. var len = imageRealData.length; while (len--) - imgRealData[len] = imageRealData[len]; + imgRealData[len] = imageRealData[len]; this.putImageData(imgData, x, y); }, @@ -273,7 +273,7 @@ function WorkerPDFDoc(canvas) { }, 'pdf_num_pages': function(data) { - this.numPages = parseInt(data); + this.numPages = parseInt(data, 10); if (this.loadCallback) { this.loadCallback(); } @@ -302,8 +302,8 @@ function WorkerPDFDoc(canvas) { 'setup_page': function(data) { var size = data.split(','); var canvas = this.canvas, ctx = this.ctx; - canvas.width = parseInt(size[0]); - canvas.height = parseInt(size[1]); + canvas.width = parseInt(size[0], 10); + canvas.height = parseInt(size[1], 10); }, 'fonts': function(data) { @@ -397,7 +397,7 @@ WorkerPDFDoc.prototype.open = function(url, callback) { }; WorkerPDFDoc.prototype.showPage = function(numPage) { - this.numPage = parseInt(numPage); + this.numPage = parseInt(numPage, 10); console.log('=== start rendering page ' + numPage + ' ==='); console.time('>>> total page display time:'); this.worker.postMessage(numPage); @@ -407,11 +407,12 @@ WorkerPDFDoc.prototype.showPage = function(numPage) { }; WorkerPDFDoc.prototype.nextPage = function() { - if (this.numPage == this.numPages) return; - this.showPage(++this.numPage); + if (this.numPage != this.numPages) + this.showPage(++this.numPage); }; WorkerPDFDoc.prototype.prevPage = function() { - if (this.numPage == 1) return; - this.showPage(--this.numPage); + if (this.numPage != 1) + this.showPage(--this.numPage); }; + diff --git a/worker/console.js b/worker/console.js index fc49583a6..43ec1af88 100644 --- a/worker/console.js +++ b/worker/console.js @@ -25,3 +25,4 @@ var console = { this.log('Timer:', name, Date.now() - time); } }; + diff --git a/worker/font.js b/worker/font.js index 549b73101..44a4782f0 100644 --- a/worker/font.js +++ b/worker/font.js @@ -64,3 +64,4 @@ this.onmessage = function(event) { throw 'Unkown action from worker: ' + data.action; } }; + diff --git a/worker/pdf.js b/worker/pdf.js index 8cb6342db..7a72ac824 100644 --- a/worker/pdf.js +++ b/worker/pdf.js @@ -58,7 +58,7 @@ onmessage = function(event) { console.time('compile'); // Let's try to render the first page... - var page = pdfDocument.getPage(parseInt(data)); + var page = pdfDocument.getPage(parseInt(data, 10)); var pdfToCssUnitsCoef = 96.0 / 72.0; var pageWidth = (page.mediaBox[2] - page.mediaBox[0]) * pdfToCssUnitsCoef;