diff --git a/Makefile b/Makefile index 80003bdf6..3e385b175 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,12 @@ -REPO = git@github.com:andreasgal/pdf.js.git +REPO = git@github.com:mozilla/pdf.js.git BUILD_DIR := build BUILD_TARGET := $(BUILD_DIR)/pdf.js DEFAULT_BROWSERS := resources/browser_manifests/browser_manifest.json DEFAULT_TESTS := test_manifest.json -EXTENSION_SRC := ./extensions/firefox -EXTENSION_NAME := pdf.js.xpi +EXTENSION_SRC := ./extensions/ +FIREFOX_EXTENSION_NAME := pdf.js.xpi +CHROME_EXTENSION_NAME := pdf.js.crx all: bundle @@ -125,7 +126,7 @@ browser-test: # # SRC_DIRS := . src utils web test examples/helloworld extensions/firefox \ - extensions/firefox/components + extensions/firefox/components extensions/chrome GJSLINT_FILES = $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)/*.js)) lint: gjslint --nojsdoc $(GJSLINT_FILES) @@ -139,12 +140,11 @@ lint: # TODO: Use the Closure compiler to optimize the pdf.js files. # GH_PAGES = $(BUILD_DIR)/gh-pages -web: | production extension compiler pages-repo \ - $(addprefix $(GH_PAGES)/, $(BUILD_TARGET)) \ - $(addprefix $(GH_PAGES)/, $(wildcard web/*.*)) \ - $(addprefix $(GH_PAGES)/, $(wildcard web/images/*.*)) \ - $(addprefix $(GH_PAGES)/, $(wildcard $(EXTENSION_SRC)/*.xpi)) - +web: | production extension compiler pages-repo + @cp $(BUILD_TARGET) $(GH_PAGES)/$(BUILD_TARGET) + @cp -R web/* $(GH_PAGES)/web + @cp web/images/* $(GH_PAGES)/web/images + @cp $(EXTENSION_SRC)/firefox/*.xpi $(GH_PAGES)/$(EXTENSION_SRC)/firefox/ @cp $(GH_PAGES)/web/index.html.template $(GH_PAGES)/index.html; @mv -f $(GH_PAGES)/web/viewer-production.html $(GH_PAGES)/web/viewer.html; @cd $(GH_PAGES); git add -A; @@ -167,19 +167,7 @@ pages-repo: | $(BUILD_DIR) @mkdir -p $(GH_PAGES)/web; @mkdir -p $(GH_PAGES)/web/images; @mkdir -p $(GH_PAGES)/build; - @mkdir -p $(GH_PAGES)/$(EXTENSION_SRC); - -$(GH_PAGES)/$(BUILD_DIR)/%.js: build/%.js - @cp $< $@ - -$(GH_PAGES)/web/%: web/% - @cp $< $@ - -$(GH_PAGES)/web/images/%: web/images/% - @cp $< $@ - -$(GH_PAGES)/$(EXTENSION_SRC)/%: $(EXTENSION_SRC)/% - @cp -R $< $@ + @mkdir -p $(GH_PAGES)/$(EXTENSION_SRC)/firefox; # # make compiler # # @@ -199,6 +187,8 @@ $(GH_PAGES)/$(EXTENSION_SRC)/%: $(EXTENSION_SRC)/% # This target produce a restartless firefox extension containing a # copy of the pdf.js source. CONTENT_DIR := content +FIREFOX_CONTENT_DIR := $(EXTENSION_SRC)/firefox/$(CONTENT_DIR)/ +CHROME_CONTENT_DIR := $(EXTENSION_SRC)/chrome/$(CONTENT_DIR)/ PDF_WEB_FILES = \ web/images \ web/compatibility.js \ @@ -208,16 +198,28 @@ PDF_WEB_FILES = \ $(NULL) extension: | production # Copy a standalone version of pdf.js inside the content directory - @rm -Rf $(EXTENSION_SRC)/$(CONTENT_DIR)/ - @mkdir -p $(EXTENSION_SRC)/$(CONTENT_DIR)/$(BUILD_DIR) - @mkdir -p $(EXTENSION_SRC)/$(CONTENT_DIR)/web - @cp $(BUILD_TARGET) $(EXTENSION_SRC)/$(CONTENT_DIR)/$(BUILD_DIR) - @cp -r $(PDF_WEB_FILES) $(EXTENSION_SRC)/$(CONTENT_DIR)/web/ - @mv -f $(EXTENSION_SRC)/$(CONTENT_DIR)/web/viewer-production.html $(EXTENSION_SRC)/$(CONTENT_DIR)/web/viewer.html + @rm -Rf $(FIREFOX_CONTENT_DIR) + @mkdir -p $(FIREFOX_CONTENT_DIR)/$(BUILD_DIR) + @mkdir -p $(FIREFOX_CONTENT_DIR)/web + @cp $(BUILD_TARGET) $(FIREFOX_CONTENT_DIR)/$(BUILD_DIR) + @cp -r $(PDF_WEB_FILES) $(FIREFOX_CONTENT_DIR)/web/ + @mv -f $(FIREFOX_CONTENT_DIR)/web/viewer-production.html $(FIREFOX_CONTENT_DIR)/web/viewer.html # Create the xpi - @cd $(EXTENSION_SRC); zip -r $(EXTENSION_NAME) * - @echo "extension created: " $(EXTENSION_NAME) + @cd $(EXTENSION_SRC)/firefox; zip -r $(FIREFOX_EXTENSION_NAME) * + @echo "extension created: " $(FIREFOX_EXTENSION_NAME) + + # Copy a standalone version of pdf.js inside the extension directory + @rm -Rf $(CHROME_CONTENT_DIR) + @mkdir -p $(CHROME_CONTENT_DIR)/$(BUILD_DIR) + @mkdir -p $(CHROME_CONTENT_DIR)/web + @cp $(BUILD_TARGET) $(CHROME_CONTENT_DIR)/$(BUILD_DIR) + @cp -r $(PDF_WEB_FILES) $(CHROME_CONTENT_DIR)/web/ + @mv -f $(CHROME_CONTENT_DIR)/web/viewer-production.html $(CHROME_CONTENT_DIR)/web/viewer.html + + # Create the crx + #TODO + # Make sure there's a build directory. diff --git a/README.md b/README.md index 42669da28..deb925601 100644 --- a/README.md +++ b/README.md @@ -22,24 +22,28 @@ successful. For an online demo, visit: -+ http://andreasgal.github.com/pdf.js/web/viewer.html ++ http://mozilla.github.com/pdf.js/web/viewer.html This demo provides an interactive interface for displaying and browsing PDFs using the pdf.js API. ### Extension -A Firefox extension is also available: +An up-to-date Firefox extension is also available: -+ http://andreasgal.github.com/pdf.js/extensions/firefox/pdf.js.xpi ++ http://mozilla.github.com/pdf.js/extensions/firefox/pdf.js.xpi -However, note that the extension might not reflect the latest source in our master branch. +(The above link is updated upon every merge to our master branch). + +For an experimental Chrome extension, get the code as explained below and issue `make extension`. +Then open Chrome with the flag `--enable-experimental-extension-apis`, go to `Tools > Extension` +and load the (unpackaged) extension from the directory `extensions/chrome`. ### Getting the code To get a local copy of the current code, clone it using git: - $ git clone git://github.com/andreasgal/pdf.js.git pdfjs + $ git clone git://github.com/mozilla/pdf.js.git pdfjs $ cd pdfjs Next, you need to start a local web server as some browsers don't allow opening @@ -73,7 +77,7 @@ Additional resources are available in a separate section below. For a "hello world" example, take a look at: -+ [examples/helloworld/hello.js](https://github.com/andreasgal/pdf.js/blob/master/examples/helloworld/hello.js) ++ [examples/helloworld/hello.js](https://github.com/mozilla/pdf.js/blob/master/examples/helloworld/hello.js) This example illustrates the bare minimum ingredients for integrating pdf.js in a custom project. @@ -92,19 +96,19 @@ workings of PDF and pdf.js: pdf.js is a community-driven project, so contributors are always welcome. Simply fork our repo and contribute away. A great place to start is our -[open issues](https://github.com/andreasgal/pdf.js/issues). For better consistency and +[open issues](https://github.com/mozilla/pdf.js/issues). For better consistency and long-term stability, please do look around the code and try to follow our conventions. More information about the contributor process can be found on the -[contributor wiki page](https://github.com/andreasgal/pdf.js/wiki/Contributing). +[contributor wiki page](https://github.com/mozilla/pdf.js/wiki/Contributing). If you don't want to hack on the project or have little spare time, __you still can help!__ Just open PDFs in the -[online demo](http://andreasgal.github.com/pdf.js/web/viewer.html) and report +[online demo](http://mozilla.github.com/pdf.js/web/viewer.html) and report any breakage in rendering. Our Github contributors so far: -+ https://github.com/andreasgal/pdf.js/contributors ++ https://github.com/mozilla/pdf.js/contributors You can add your name to it! :) @@ -143,14 +147,14 @@ against reference images before merging pull requests. See the bot repo for details: -+ https://github.com/arturadib/pdf.js-bot ++ https://github.com/mozilla/pdf.js-bot ## Additional resources Our demo site is here: -+ http://andreasgal.github.com/pdf.js/web/viewer.html ++ http://mozilla.github.com/pdf.js/web/viewer.html You can read more about pdf.js here: diff --git a/examples/helloworld/index.html b/examples/helloworld/index.html index b10e9eaeb..a48e3705b 100644 --- a/examples/helloworld/index.html +++ b/examples/helloworld/index.html @@ -3,27 +3,33 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + diff --git a/extensions/chrome/manifest.json b/extensions/chrome/manifest.json new file mode 100644 index 000000000..629e41b31 --- /dev/null +++ b/extensions/chrome/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "uriloader@pdf.js", + "version": "0.1", + "description": "Read PDF Document", + "permissions": [ + "experimental", + "http://*/*.pdf", + "file:///*/*.pdf" + ], + "background_page": "pdfHandler.html" +} diff --git a/extensions/chrome/pdfHandler.html b/extensions/chrome/pdfHandler.html new file mode 100644 index 000000000..c13e24c57 --- /dev/null +++ b/extensions/chrome/pdfHandler.html @@ -0,0 +1,18 @@ + + + diff --git a/extensions/firefox/bootstrap.js b/extensions/firefox/bootstrap.js index 5384a05df..e51df28f8 100644 --- a/extensions/firefox/bootstrap.js +++ b/extensions/firefox/bootstrap.js @@ -16,21 +16,31 @@ function log(str) { function startup(aData, aReason) { let manifestPath = 'chrome.manifest'; - let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile); + let manifest = Cc['@mozilla.org/file/local;1'] + .createInstance(Ci.nsILocalFile); try { - file.initWithPath(aData.installPath.path); - file.append(manifestPath); - Cm.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(file); + manifest.initWithPath(aData.installPath.path); + manifest.append(manifestPath); + Cm.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(manifest); + Services.prefs.setBoolPref('extensions.pdf.js.active', true); } catch (e) { log(e); } } function shutdown(aData, aReason) { + if (Services.prefs.getBoolPref('extensions.pdf.js.active')) + Services.prefs.setBoolPref('extensions.pdf.js.active', false); } function install(aData, aReason) { let url = 'chrome://pdf.js/content/web/viewer.html?file=%s'; Services.prefs.setCharPref('extensions.pdf.js.url', url); + Services.prefs.setBoolPref('extensions.pdf.js.active', false); +} + +function uninstall(aData, aReason) { + Services.prefs.clearUserPref('extensions.pdf.js.url'); + Services.prefs.clearUserPref('extensions.pdf.js.active'); } diff --git a/extensions/firefox/components/pdfContentHandler.js b/extensions/firefox/components/pdfContentHandler.js index 7746e41b6..67459b759 100644 --- a/extensions/firefox/components/pdfContentHandler.js +++ b/extensions/firefox/components/pdfContentHandler.js @@ -32,6 +32,9 @@ pdfContentHandler.prototype = { if (!(aRequest instanceof Ci.nsIChannel)) throw NS_ERROR_WONT_HANDLE_CONTENT; + if (!Services.prefs.getBoolPref('extensions.pdf.js.active')) + throw NS_ERROR_WONT_HANDLE_CONTENT; + let window = null; let callbacks = aRequest.notificationCallbacks || aRequest.loadGroup.notificationCallbacks; @@ -49,11 +52,11 @@ pdfContentHandler.prototype = { } let targetUrl = aRequest.URI.spec; - if (targetUrl.indexOf('?pdfjs.action=download') >= 0) + if (targetUrl.indexOf('#pdfjs.action=download') >= 0) throw NS_ERROR_WONT_HANDLE_CONTENT; aRequest.cancel(Cr.NS_BINDING_ABORTED); - window.location = url.replace('%s', targetUrl); + window.location = url.replace('%s', encodeURIComponent(targetUrl)); }, classID: Components.ID('{2278dfd0-b75c-11e0-8257-1ba3d93c9f1a}'), diff --git a/extensions/firefox/install.rdf b/extensions/firefox/install.rdf index 0dfd6bf57..26b2192b6 100644 --- a/extensions/firefox/install.rdf +++ b/extensions/firefox/install.rdf @@ -19,6 +19,6 @@ true Vivien Nicolas pdf.js uri loader - https://github.com/andreasgal/pdf.js/ + https://github.com/mozilla/pdf.js/ diff --git a/src/canvas.js b/src/canvas.js index d22023776..9759a8deb 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -24,13 +24,18 @@ var CanvasExtraState = (function canvasExtraState() { this.wordSpacing = 0; this.textHScale = 1; // Color spaces + this.fillColorSpace = new DeviceGrayCS(); this.fillColorSpaceObj = null; + this.strokeColorSpace = new DeviceGrayCS(); this.strokeColorSpaceObj = null; this.fillColorObj = null; this.strokeColorObj = null; // Default fore and background colors this.fillColor = '#000000'; this.strokeColor = '#000000'; + // Note: fill alpha applies to all non-stroking operations + this.fillAlpha = 1; + this.strokeAlpha = 1; this.old = old; } @@ -120,7 +125,7 @@ var CanvasGraphics = (function canvasGraphics() { this[fnArray[i]].apply(this, argsArray[i]); } else { var deps = argsArray[i]; - for (var n = 0; n < deps.length; n++) { + for (var n = 0, nn = deps.length; n < nn; n++) { var depObjId = deps[n]; // If the promise isn't resolved yet, add the continueCallback @@ -179,7 +184,7 @@ var CanvasGraphics = (function canvasGraphics() { TODO('set flatness: ' + flatness); }, setGState: function canvasGraphicsSetGState(states) { - for (var i = 0; i < states.length; i++) { + for (var i = 0, ii = states.length; i < ii; i++) { var state = states[i]; var key = state[0]; var value = state[1]; @@ -209,6 +214,13 @@ var CanvasGraphics = (function canvasGraphics() { case 'Font': this.setFont(state[1], state[2]); break; + case 'CA': + this.current.strokeAlpha = state[1]; + break; + case 'ca': + this.current.fillAlpha = state[1]; + this.ctx.globalAlpha = state[1]; + break; } } }, @@ -257,9 +269,13 @@ var CanvasGraphics = (function canvasGraphics() { rectangle: function canvasGraphicsRectangle(x, y, width, height) { this.ctx.rect(x, y, width, height); }, - stroke: function canvasGraphicsStroke() { + stroke: function canvasGraphicsStroke(consumePath) { + consumePath = typeof consumePath !== 'undefined' ? consumePath : true; var ctx = this.ctx; var strokeColor = this.current.strokeColor; + // For stroke we want to temporarily change the global alpha to the + // stroking alpha. + ctx.globalAlpha = this.current.strokeAlpha; if (strokeColor && strokeColor.hasOwnProperty('type') && strokeColor.type === 'Pattern') { // for patterns, we transform to pattern space, calculate @@ -271,14 +287,17 @@ var CanvasGraphics = (function canvasGraphics() { } else { ctx.stroke(); } - - this.consumePath(); + if (consumePath) + this.consumePath(); + // Restore the global alpha to the fill alpha + ctx.globalAlpha = this.current.fillAlpha; }, closeStroke: function canvasGraphicsCloseStroke() { this.closePath(); this.stroke(); }, - fill: function canvasGraphicsFill() { + fill: function canvasGraphicsFill(consumePath) { + consumePath = typeof consumePath !== 'undefined' ? consumePath : true; var ctx = this.ctx; var fillColor = this.current.fillColor; @@ -291,8 +310,8 @@ var CanvasGraphics = (function canvasGraphics() { } else { ctx.fill(); } - - this.consumePath(); + if (consumePath) + this.consumePath(); }, eoFill: function canvasGraphicsEoFill() { var savedFillRule = this.setEOFillRule(); @@ -300,29 +319,8 @@ var CanvasGraphics = (function canvasGraphics() { this.restoreFillRule(savedFillRule); }, fillStroke: function canvasGraphicsFillStroke() { - var ctx = this.ctx; - - var fillColor = this.current.fillColor; - if (fillColor && fillColor.hasOwnProperty('type') && - fillColor.type === 'Pattern') { - ctx.save(); - ctx.fillStyle = fillColor.getPattern(ctx); - ctx.fill(); - ctx.restore(); - } else { - ctx.fill(); - } - - var strokeColor = this.current.strokeColor; - if (strokeColor && strokeColor.hasOwnProperty('type') && - strokeColor.type === 'Pattern') { - ctx.save(); - ctx.strokeStyle = strokeColor.getPattern(ctx); - ctx.stroke(); - ctx.restore(); - } else { - ctx.stroke(); - } + this.fill(false); + this.stroke(false); this.consumePath(); }, @@ -332,10 +330,12 @@ var CanvasGraphics = (function canvasGraphics() { this.restoreFillRule(savedFillRule); }, closeFillStroke: function canvasGraphicsCloseFillStroke() { - return this.fillStroke(); + this.closePath(); + this.fillStroke(); }, closeEOFillStroke: function canvasGraphicsCloseEOFillStroke() { var savedFillRule = this.setEOFillRule(); + this.closePath(); this.fillStroke(); this.restoreFillRule(savedFillRule); }, @@ -537,8 +537,7 @@ var CanvasGraphics = (function canvasGraphics() { }, // Color - setStrokeColorSpace: - function canvasGraphicsSetStrokeColorSpacefunction(raw) { + setStrokeColorSpace: function canvasGraphicsSetStrokeColorSpace(raw) { this.current.strokeColorSpace = ColorSpace.fromIR(raw); }, setFillColorSpace: function canvasGraphicsSetFillColorSpace(raw) { @@ -549,7 +548,7 @@ var CanvasGraphics = (function canvasGraphics() { var color = cs.getRgb(arguments); this.setStrokeRGBColor.apply(this, color); }, - getColorN_IR_Pattern: function(IR, cs) { + getColorN_IR_Pattern: function canvasGraphicsGetColorN_IR_Pattern(IR, cs) { if (IR[0] == 'TilingPattern') { var args = IR[1]; var base = cs.base; @@ -665,8 +664,8 @@ var CanvasGraphics = (function canvasGraphics() { error('Should not call beginImageData'); }, - paintFormXObjectBegin: - function canvasGraphicsPaintFormXObject(matrix, bbox) { + paintFormXObjectBegin: function canvasGraphicsPaintFormXObjectBegin(matrix, + bbox) { this.save(); if (matrix && isArray(matrix) && 6 == matrix.length) @@ -681,11 +680,11 @@ var CanvasGraphics = (function canvasGraphics() { } }, - paintFormXObjectEnd: function() { + paintFormXObjectEnd: function canvasGraphicsPaintFormXObjectEnd() { this.restore(); }, - paintJpegXObject: function(objId, w, h) { + paintJpegXObject: function canvasGraphicsPaintJpegXObject(objId, w, h) { var image = this.objs.get(objId); if (!image) { error('Dependent image isn\'t ready yet'); @@ -704,7 +703,8 @@ var CanvasGraphics = (function canvasGraphics() { this.restore(); }, - paintImageMaskXObject: function(imgArray, inverseDecode, width, height) { + paintImageMaskXObject: function canvasGraphicsPaintImageMaskXObject( + imgArray, inverseDecode, width, height) { function applyStencilMask(buffer, inverseDecode) { var imgArrayPos = 0; var i, j, mask, buf; @@ -752,7 +752,7 @@ var CanvasGraphics = (function canvasGraphics() { this.restore(); }, - paintImageXObject: function(imgData) { + paintImageXObject: function canvasGraphicsPaintImageXObject(imgData) { this.save(); var ctx = this.ctx; var w = imgData.width; diff --git a/src/colorspace.js b/src/colorspace.js index 1c5c291f4..946a1bdf4 100644 --- a/src/colorspace.js +++ b/src/colorspace.js @@ -12,31 +12,26 @@ var ColorSpace = (function colorSpaceColorSpace() { constructor.prototype = { // Input: array of size numComps representing color component values // Output: array of rgb values, each value ranging from [0.1] - getRgb: function cs_getRgb(color) { + getRgb: function colorSpaceGetRgb(color) { error('Should not call ColorSpace.getRgb: ' + color); }, // Input: Uint8Array of component values, each value scaled to [0,255] // Output: Uint8Array of rgb values, each value scaled to [0,255] - getRgbBuffer: function cs_getRgbBuffer(input) { + getRgbBuffer: function colorSpaceGetRgbBuffer(input) { error('Should not call ColorSpace.getRgbBuffer: ' + input); } }; - constructor.parse = function colorspace_parse(cs, xref, res) { - var IR = constructor.parseToIR(cs, xref, res, true); + constructor.parse = function colorSpaceParse(cs, xref, res) { + var IR = constructor.parseToIR(cs, xref, res); if (IR instanceof SeparationCS) return IR; return constructor.fromIR(IR); }; - constructor.fromIR = function(IR) { - var name; - if (isArray(IR)) { - name = IR[0]; - } else { - name = IR; - } + constructor.fromIR = function colorSpaceFromIR(IR) { + var name = isArray(IR) ? IR[0] : IR; switch (name) { case 'DeviceGrayCS': @@ -46,32 +41,28 @@ var ColorSpace = (function colorSpaceColorSpace() { case 'DeviceCmykCS': return new DeviceCmykCS(); case 'PatternCS': - var baseCS = IR[1]; - if (baseCS == null) { - return new PatternCS(null); - } else { - return new PatternCS(ColorSpace.fromIR(baseCS)); - } + var basePatternCS = IR[1]; + if (basePatternCS) + basePatternCS = ColorSpace.fromIR(basePatternCS); + return new PatternCS(basePatternCS); case 'IndexedCS': - var baseCS = IR[1]; + var baseIndexedCS = IR[1]; var hiVal = IR[2]; var lookup = IR[3]; - return new IndexedCS(ColorSpace.fromIR(baseCS), hiVal, lookup); + return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup); case 'SeparationCS': var alt = IR[1]; var tintFnIR = IR[2]; - return new SeparationCS( - ColorSpace.fromIR(alt), - PDFFunction.fromIR(tintFnIR) - ); + return new SeparationCS(ColorSpace.fromIR(alt), + PDFFunction.fromIR(tintFnIR)); default: error('Unkown name ' + name); } return null; - } + }; - constructor.parseToIR = function colorspace_parse(cs, xref, res, parseOnly) { + constructor.parseToIR = function colorSpaceParseToIR(cs, xref, res) { if (isName(cs)) { var colorSpaces = xref.fetchIfRef(res.get('ColorSpace')); if (isDict(colorSpaces)) { @@ -82,9 +73,10 @@ var ColorSpace = (function colorSpaceColorSpace() { } cs = xref.fetchIfRef(cs); + var mode; if (isName(cs)) { - var mode = cs.name; + mode = cs.name; this.mode = mode; switch (mode) { @@ -103,7 +95,7 @@ var ColorSpace = (function colorSpaceColorSpace() { error('unrecognized colorspace ' + mode); } } else if (isArray(cs)) { - var mode = cs[0].name; + mode = cs[0].name; this.mode = mode; switch (mode) { @@ -132,15 +124,15 @@ var ColorSpace = (function colorSpaceColorSpace() { return 'DeviceCmykCS'; break; case 'Pattern': - var baseCS = cs[1]; - if (baseCS) - baseCS = ColorSpace.parseToIR(baseCS, xref, res); - return ['PatternCS', baseCS]; + var basePatternCS = cs[1]; + if (basePatternCS) + basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res); + return ['PatternCS', basePatternCS]; case 'Indexed': - var baseCS = ColorSpace.parseToIR(cs[1], xref, res); + var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res); var hiVal = cs[2] + 1; var lookup = xref.fetchIfRef(cs[3]); - return ['IndexedCS', baseCS, hiVal, lookup]; + return ['IndexedCS', baseIndexedCS, hiVal, lookup]; case 'Separation': var alt = ColorSpace.parseToIR(cs[2], xref, res); var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3])); @@ -164,7 +156,6 @@ var SeparationCS = (function separationCS() { this.name = 'Separation'; this.numComps = 1; this.defaultColor = [1]; - this.base = base; this.tintFn = tintFn; } @@ -178,12 +169,11 @@ var SeparationCS = (function separationCS() { var tintFn = this.tintFn; var base = this.base; var scale = 1 / ((1 << bits) - 1); - var length = input.length; var pos = 0; - var numComps = base.numComps; var baseBuf = new Uint8Array(numComps * length); + for (var i = 0; i < length; ++i) { var scaled = input[i] * scale; var tinted = tintFn([scaled]); @@ -212,13 +202,13 @@ var IndexedCS = (function indexedCS() { this.name = 'Indexed'; this.numComps = 1; this.defaultColor = [0]; - this.base = base; - var baseNumComps = base.numComps; this.highVal = highVal; + var baseNumComps = base.numComps; var length = baseNumComps * highVal; var lookupArray = new Uint8Array(length); + if (isStream(lookup)) { var bytes = lookup.getBytes(length); lookupArray.set(bytes); @@ -234,7 +224,6 @@ var IndexedCS = (function indexedCS() { constructor.prototype = { getRgb: function indexcs_getRgb(color) { var numComps = this.base.numComps; - var start = color[0] * numComps; var c = []; @@ -248,9 +237,9 @@ var IndexedCS = (function indexedCS() { var numComps = base.numComps; var lookup = this.lookup; var length = input.length; - var baseBuf = new Uint8Array(length * numComps); var baseBufPos = 0; + for (var i = 0; i < length; ++i) { var lookupPos = input[i] * numComps; for (var j = 0; j < numComps; ++j) { @@ -293,7 +282,7 @@ var DeviceGrayCS = (function deviceGrayCS() { })(); var DeviceRgbCS = (function deviceRgbCS() { - function constructor(bits) { + function constructor() { this.name = 'DeviceRGB'; this.numComps = 3; this.defaultColor = [0, 0, 0]; @@ -336,41 +325,41 @@ var DeviceCmykCS = (function deviceCmykCS() { r += 0.1373 * x; g += 0.1216 * x; b += 0.1255 * x; - x = c1 * m1 * y * k1; // 0 0 1 0 + x = c1 * m1 * y * k1; // 0 0 1 0 r += x; g += 0.9490 * x; - x = c1 * m1 * y * k; // 0 0 1 1 + x = c1 * m1 * y * k; // 0 0 1 1 r += 0.1098 * x; g += 0.1020 * x; - x = c1 * m * y1 * k1; // 0 1 0 0 + x = c1 * m * y1 * k1; // 0 1 0 0 r += 0.9255 * x; b += 0.5490 * x; - x = c1 * m * y1 * k; // 0 1 0 1 + x = c1 * m * y1 * k; // 0 1 0 1 r += 0.1412 * x; - x = c1 * m * y * k1; // 0 1 1 0 + x = c1 * m * y * k1; // 0 1 1 0 r += 0.9294 * x; g += 0.1098 * x; b += 0.1412 * x; - x = c1 * m * y * k; // 0 1 1 1 + x = c1 * m * y * k; // 0 1 1 1 r += 0.1333 * x; - x = c * m1 * y1 * k1; // 1 0 0 0 + x = c * m1 * y1 * k1; // 1 0 0 0 g += 0.6784 * x; b += 0.9373 * x; - x = c * m1 * y1 * k; // 1 0 0 1 + x = c * m1 * y1 * k; // 1 0 0 1 g += 0.0588 * x; b += 0.1412 * x; - x = c * m1 * y * k1; // 1 0 1 0 + x = c * m1 * y * k1; // 1 0 1 0 g += 0.6510 * x; b += 0.3137 * x; - x = c * m1 * y * k; // 1 0 1 1 + x = c * m1 * y * k; // 1 0 1 1 g += 0.0745 * x; - x = c * m * y1 * k1; // 1 1 0 0 + x = c * m * y1 * k1; // 1 1 0 0 r += 0.1804 * x; g += 0.1922 * x; b += 0.5725 * x; - x = c * m * y1 * k; // 1 1 0 1 + x = c * m * y1 * k; // 1 1 0 1 b += 0.0078 * x; - x = c * m * y * k1; // 1 1 1 0 + x = c * m * y * k1; // 1 1 1 0 r += 0.2118 * x; g += 0.2119 * x; b += 0.2235 * x; diff --git a/src/core.js b/src/core.js index e7241acfa..43c059b56 100644 --- a/src/core.js +++ b/src/core.js @@ -7,7 +7,6 @@ var globalScope = (typeof window === 'undefined') ? this : window; var ERRORS = 0, WARNINGS = 1, TODOS = 5; var verbosity = WARNINGS; -var useWorker = false; // The global PDFJS object exposes the API // In production, it will be declared outside a global wrapper @@ -153,12 +152,11 @@ var Page = (function pagePage() { return shadow(this, 'rotate', rotate); }, - startRenderingFromIRQueue: function startRenderingFromIRQueue( + startRenderingFromIRQueue: function pageStartRenderingFromIRQueue( IRQueue, fonts) { var self = this; this.IRQueue = IRQueue; var gfx = new CanvasGraphics(this.ctx, this.objs); - var startTime = Date.now(); var displayContinuation = function pageDisplayContinuation() { // Always defer call to display() to work around bug in @@ -173,12 +171,13 @@ var Page = (function pagePage() { }); }; - this.ensureFonts(fonts, function() { + this.ensureFonts(fonts, + function pageStartRenderingFromIRQueueEnsureFonts() { displayContinuation(); }); }, - getIRQueue: function(handler, dependency) { + getIRQueue: function pageGetIRQueue(handler, dependency) { if (this.IRQueue) { // content was compiled return this.IRQueue; @@ -198,20 +197,20 @@ var Page = (function pagePage() { var pe = this.pe = new PartialEvaluator( xref, handler, 'p' + this.pageNumber + '_'); var IRQueue = {}; - return this.IRQueue = pe.getIRQueue( - content, resources, IRQueue, dependency); + return (this.IRQueue = pe.getIRQueue(content, resources, IRQueue, + dependency)); }, - ensureFonts: function(fonts, callback) { + ensureFonts: function pageEnsureFonts(fonts, callback) { // Convert the font names to the corresponding font obj. - for (var i = 0; i < fonts.length; i++) { + for (var i = 0, ii = fonts.length; i < ii; i++) { fonts[i] = this.objs.objs[fonts[i]].data; } // Load all the fonts var fontObjs = FontLoader.bind( fonts, - function(fontObjs) { + function pageEnsureFontsFontObjs(fontObjs) { this.stats.fonts = Date.now(); callback.call(this); @@ -220,7 +219,7 @@ var Page = (function pagePage() { ); }, - display: function(gfx, callback) { + display: function pageDisplay(gfx, callback) { var xref = this.xref; var resources = xref.fetchIfRef(this.resources); var mediaBox = xref.fetchIfRef(this.mediaBox); @@ -238,7 +237,6 @@ var Page = (function pagePage() { var IRQueue = this.IRQueue; var self = this; - var startTime = Date.now(); function next() { startIdx = gfx.executeIRQueue(IRQueue, startIdx, next); if (startIdx == length) { @@ -305,7 +303,7 @@ var Page = (function pagePage() { } return links; }, - startRendering: function(ctx, callback) { + startRendering: function pageStartRendering(ctx, callback) { this.ctx = ctx; this.callback = callback; @@ -446,7 +444,7 @@ var PDFDocModel = (function pdfDoc() { return constructor; })(); -var PDFDoc = (function() { +var PDFDoc = (function pdfDoc() { function constructor(arg, callback) { var stream = null; var data = null; @@ -469,115 +467,156 @@ var PDFDoc = (function() { this.objs = new PDFObjects(); this.pageCache = []; - - if (useWorker) { - var worker = new Worker('../src/worker_loader.js'); - } else { - // If we don't use a worker, just post/sendMessage to the main thread. - var worker = { - postMessage: function(obj) { - worker.onmessage({data: obj}); - }, - terminate: function() {} - }; - } - this.worker = worker; - this.fontsLoading = {}; - - var processorHandler = this.processorHandler = - new MessageHandler('main', worker); - - processorHandler.on('page', function(data) { - var pageNum = data.pageNum; - var page = this.pageCache[pageNum]; - var depFonts = data.depFonts; - - page.startRenderingFromIRQueue(data.IRQueue, depFonts); - }, this); - - processorHandler.on('obj', function(data) { - var id = data[0]; - var type = data[1]; - - switch (type) { - case 'JpegStream': - var IR = data[2]; - new JpegImage(id, IR, this.objs); - break; - case 'Font': - var name = data[2]; - var file = data[3]; - var properties = data[4]; - - if (file) { - var fontFileDict = new Dict(); - fontFileDict.map = file.dict.map; - - var fontFile = new Stream(file.bytes, file.start, - file.end - file.start, fontFileDict); - - // Check if this is a FlateStream. Otherwise just use the created - // Stream one. This makes complex_ttf_font.pdf work. - var cmf = file.bytes[0]; - if ((cmf & 0x0f) == 0x08) { - file = new FlateStream(fontFile); - } else { - file = fontFile; - } - } - - // For now, resolve the font object here direclty. The real font - // object is then created in FontLoader.bind(). - this.objs.resolve(id, { - name: name, - file: file, - properties: properties - }); - break; - default: - throw 'Got unkown object type ' + type; - } - }, this); - - processorHandler.on('font_ready', function(data) { - var id = data[0]; - var font = new FontShape(data[1]); - - // If there is no string, then there is nothing to attach to the DOM. - if (!font.str) { - this.objs.resolve(id, font); - } else { - this.objs.setData(id, font); - } - }.bind(this)); - - if (!useWorker) { - // If the main thread is our worker, setup the handling for the messages - // the main thread sends to it self. - WorkerProcessorHandler.setup(processorHandler); - } - this.workerReadyPromise = new Promise('workerReady'); - setTimeout(function() { - processorHandler.send('doc', this.data); - this.workerReadyPromise.resolve(true); - }.bind(this)); + + // If worker support isn't disabled explicit and the browser has worker + // support, create a new web worker and test if it/the browser fullfills + // all requirements to run parts of pdf.js in a web worker. + // Right now, the requirement is, that an Uint8Array is still an Uint8Array + // as it arrives on the worker. Chrome added this with version 15. + if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') { + var workerSrc = PDFJS.workerSrc; + if (typeof workerSrc === 'undefined') { + throw 'No PDFJS.workerSrc specified'; + } + + var worker + try { + worker = new Worker(workerSrc); + } catch (e) { + // Some versions of FF can't create a worker on localhost, see: + // https://bugzilla.mozilla.org/show_bug.cgi?id=683280 + globalScope.PDFJS.disableWorker = true; + this.setupFakeWorker(); + return; + } + + var messageHandler = new MessageHandler('main', worker); + + // Tell the worker the file it was created from. + messageHandler.send('workerSrc', workerSrc); + + messageHandler.on('test', function pdfDocTest(supportTypedArray) { + if (supportTypedArray) { + this.worker = worker; + this.setupMessageHandler(messageHandler); + } else { + this.setupFakeWorker(); + } + }.bind(this)); + + var testObj = new Uint8Array(1); + messageHandler.send('test', testObj); + } else { + this.setupFakeWorker(); + } } constructor.prototype = { + setupFakeWorker: function() { + // If we don't use a worker, just post/sendMessage to the main thread. + var fakeWorker = { + postMessage: function pdfDocPostMessage(obj) { + fakeWorker.onmessage({data: obj}); + }, + terminate: function pdfDocTerminate() {} + }; + + var messageHandler = new MessageHandler('main', fakeWorker); + this.setupMessageHandler(messageHandler); + + // If the main thread is our worker, setup the handling for the messages + // the main thread sends to it self. + WorkerMessageHandler.setup(messageHandler); + }, + + + setupMessageHandler: function(messageHandler) { + this.messageHandler = messageHandler; + + messageHandler.on('page', function pdfDocPage(data) { + var pageNum = data.pageNum; + var page = this.pageCache[pageNum]; + var depFonts = data.depFonts; + + page.startRenderingFromIRQueue(data.IRQueue, depFonts); + }, this); + + messageHandler.on('obj', function pdfDocObj(data) { + var id = data[0]; + var type = data[1]; + + switch (type) { + case 'JpegStream': + var IR = data[2]; + new JpegImage(id, IR, this.objs); + break; + case 'Font': + var name = data[2]; + var file = data[3]; + var properties = data[4]; + + if (file) { + var fontFileDict = new Dict(); + fontFileDict.map = file.dict.map; + + var fontFile = new Stream(file.bytes, file.start, + file.end - file.start, fontFileDict); + + // Check if this is a FlateStream. Otherwise just use the created + // Stream one. This makes complex_ttf_font.pdf work. + var cmf = file.bytes[0]; + if ((cmf & 0x0f) == 0x08) { + file = new FlateStream(fontFile); + } else { + file = fontFile; + } + } + + // For now, resolve the font object here direclty. The real font + // object is then created in FontLoader.bind(). + this.objs.resolve(id, { + name: name, + file: file, + properties: properties + }); + break; + default: + throw 'Got unkown object type ' + type; + } + }, this); + + messageHandler.on('font_ready', function pdfDocFontReady(data) { + var id = data[0]; + var font = new FontShape(data[1]); + + // If there is no string, then there is nothing to attach to the DOM. + if (!font.str) { + this.objs.resolve(id, font); + } else { + this.objs.setData(id, font); + } + }.bind(this)); + + setTimeout(function pdfDocFontReadySetTimeout() { + messageHandler.send('doc', this.data); + this.workerReadyPromise.resolve(true); + }.bind(this)); + }, + get numPages() { return this.pdf.numPages; }, - startRendering: function(page) { + startRendering: function pdfDocStartRendering(page) { // The worker might not be ready to receive the page request yet. - this.workerReadyPromise.then(function() { - this.processorHandler.send('page_request', page.pageNumber + 1); + this.workerReadyPromise.then(function pdfDocStartRenderingThen() { + this.messageHandler.send('page_request', page.pageNumber + 1); }.bind(this)); }, - getPage: function(n) { + getPage: function pdfDocGetPage(n) { if (this.pageCache[n]) return this.pageCache[n]; @@ -586,10 +625,10 @@ var PDFDoc = (function() { // to the CanvasGraphics and so on. page.objs = this.objs; page.pdf = this; - return this.pageCache[n] = page; + return (this.pageCache[n] = page); }, - destroy: function() { + destroy: function pdfDocDestroy() { if (this.worker) this.worker.terminate(); diff --git a/src/crypto.js b/src/crypto.js index 2c86038f0..955598644 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -26,7 +26,6 @@ var ARCFourCipher = (function arcFourCipher() { var a = this.a, b = this.b, s = this.s; var output = new Uint8Array(n); for (i = 0; i < n; ++i) { - var tmp; a = (a + 1) & 0xFF; tmp = s[a]; b = (b + tmp) & 0xFF; @@ -75,8 +74,8 @@ var calculateMD5 = (function calculateMD5() { padded[i] = data[offset++]; padded[i++] = 0x80; n = paddedLength - 8; - for (; i < n; ++i) - padded[i] = 0; + while (i < n) + padded[i++] = 0; padded[i++] = (length << 3) & 0xFF; padded[i++] = (length >> 5) & 0xFF; padded[i++] = (length >> 13) & 0xFF; @@ -322,12 +321,12 @@ var AES128Cipher = (function aes128Cipher() { state[10] = state[2]; state[6] = t; state[2] = u; t = state[15]; u = state[11]; v = state[7]; state[15] = state[3]; state[11] = t; state[7] = u; state[3] = v; - // InvSubBytes - for (j = 0; j < 16; ++j) + for (j = 0; j < 16; ++j) { + // InvSubBytes state[j] = inv_s[state[j]]; - // AddRoundKey - for (j = 0; j < 16; ++j) + // AddRoundKey state[j] ^= key[j]; + } return state; } @@ -338,7 +337,7 @@ var AES128Cipher = (function aes128Cipher() { } function decryptBlock2(data) { - var i, j, sourceLength = data.length, + var i, j, ii, sourceLength = data.length, buffer = this.buffer, bufferLength = this.bufferPosition, result = [], iv = this.iv; for (i = 0; i < sourceLength; ++i) { @@ -366,7 +365,7 @@ var AES128Cipher = (function aes128Cipher() { return result[0]; // combining plain text blocks into one var output = new Uint8Array(16 * result.length); - for (i = 0, j = 0; i < result.length; ++i, j += 16) + for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) output.set(result[i], j); return output; } @@ -471,11 +470,11 @@ var CipherTransformFactory = (function cipherTransformFactory() { cipher = new ARCFourCipher(encryptionKey); var checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); n = encryptionKey.length; - var derrivedKey = new Uint8Array(n), k; + var derivedKey = new Uint8Array(n), k; for (j = 1; j <= 19; ++j) { for (k = 0; k < n; ++k) - derrivedKey[k] = encryptionKey[k] ^ j; - cipher = new ARCFourCipher(derrivedKey); + derivedKey[k] = encryptionKey[k] ^ j; + cipher = new ARCFourCipher(derivedKey); checkData = cipher.encryptBlock(checkData); } } else { diff --git a/src/evaluator.js b/src/evaluator.js index bb2efaa14..619a633b2 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -123,7 +123,7 @@ var PartialEvaluator = (function partialEvaluator() { function insertDependency(depList) { fnArray.push('dependency'); argsArray.push(depList); - for (var i = 0; i < depList.length; i++) { + for (var i = 0, ii = depList.length; i < ii; i++) { var dep = depList[i]; if (dependency.indexOf(dep) == -1) { dependency.push(depList[i]); @@ -145,12 +145,12 @@ var PartialEvaluator = (function partialEvaluator() { var font = xref.fetchIfRef(fontRef); assertWellFormed(isDict(font)); if (!font.translated) { - font.translated = self.translateFont(font, xref, resources, handler, - uniquePrefix, dependency); + font.translated = self.translateFont(font, xref, resources, + dependency); if (font.translated) { // keep track of each font we translated so the caller can // load them asynchronously before calling display on a page - loadedName = 'font_' + uniquePrefix + ++self.objIdCounter; + loadedName = 'font_' + uniquePrefix + (++self.objIdCounter); font.translated.properties.loadedName = loadedName; font.loadedName = loadedName; @@ -180,7 +180,7 @@ var PartialEvaluator = (function partialEvaluator() { var h = dict.get('Height', 'H'); if (image instanceof JpegStream) { - var objId = 'img_' + uniquePrefix + ++self.objIdCounter; + var objId = 'img_' + uniquePrefix + (++self.objIdCounter); handler.send('obj', [objId, 'JpegStream', image.getIR()]); // Add the dependency on the image object. @@ -405,6 +405,8 @@ var PartialEvaluator = (function partialEvaluator() { case 'D': case 'RI': case 'FL': + case 'CA': + case 'ca': gsStateObj.push([key, value]); break; case 'Font': @@ -428,8 +430,6 @@ var PartialEvaluator = (function partialEvaluator() { case 'SA': case 'BM': case 'SMask': - case 'CA': - case 'ca': case 'AIS': case 'TK': TODO('graphic state operator ' + key); @@ -498,7 +498,7 @@ var PartialEvaluator = (function partialEvaluator() { if (encoding.has('Differences')) { var diffEncoding = encoding.get('Differences'); var index = 0; - for (var j = 0; j < diffEncoding.length; j++) { + for (var j = 0, jj = diffEncoding.length; j < jj; j++) { var data = diffEncoding[j]; if (isNum(data)) index = data; @@ -529,7 +529,7 @@ var PartialEvaluator = (function partialEvaluator() { var beginArrayToken = {}; var cmap = cmapObj.getBytes(cmapObj.length); - for (var i = 0; i < cmap.length; i++) { + for (var i = 0, ii = cmap.length; i < ii; i++) { var byte = cmap[i]; if (byte == 0x20 || byte == 0x0D || byte == 0x0A || byte == 0x3C || byte == 0x5B || byte == 0x5D) { @@ -548,7 +548,7 @@ var PartialEvaluator = (function partialEvaluator() { case 'endcidrange': case 'endbfrange': - for (var j = 0; j < tokens.length; j += 3) { + for (var j = 0, jj = tokens.length; j < jj; j += 3) { var startRange = tokens[j]; var endRange = tokens[j + 1]; var code = tokens[j + 2]; @@ -561,7 +561,7 @@ var PartialEvaluator = (function partialEvaluator() { case 'endcidchar': case 'endbfchar': - for (var j = 0; j < tokens.length; j += 2) { + for (var j = 0, jj = tokens.length; j < jj; j += 2) { var index = tokens[j]; var code = tokens[j + 1]; charToUnicode[index] = code; @@ -611,7 +611,7 @@ var PartialEvaluator = (function partialEvaluator() { // Set encoding 0 to later verify the font has an encoding var result = []; - for (var j = 0; j < glyphsData.length; j++) { + for (var j = 0, jj = glyphsData.length; j < jj; j++) { var glyphID = (glyphsData[j++] << 8) | glyphsData[j]; if (glyphID == 0) continue; @@ -634,10 +634,10 @@ var PartialEvaluator = (function partialEvaluator() { var widths = xref.fetchIfRef(dict.get('W')); if (widths) { var start = 0, end = 0; - for (var i = 0; i < widths.length; i++) { + for (var i = 0, ii = widths.length; i < ii; i++) { var code = widths[i]; if (isArray(code)) { - for (var j = 0; j < code.length; j++) + for (var j = 0, jj = code.length; j < jj; j++) glyphsWidths[start++] = code[j]; start = 0; } else if (start) { @@ -654,8 +654,9 @@ var PartialEvaluator = (function partialEvaluator() { var firstChar = properties.firstChar; var widths = xref.fetchIfRef(dict.get('Widths')); if (widths) { - for (var i = 0, j = firstChar; i < widths.length; i++, j++) - glyphsWidths[j] = widths[i]; + var j = firstChar; + for (var i = 0, ii = widths.length; i < ii; i++) + glyphsWidths[j++] = widths[i]; defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0; } else { // Trying get the BaseFont metrics (see comment above). @@ -689,7 +690,7 @@ var PartialEvaluator = (function partialEvaluator() { }, translateFont: function partialEvaluatorTranslateFont(dict, xref, resources, - queue, handler, uniquePrefix, dependency) { + dependency) { var baseDict = dict; var type = dict.get('Subtype'); assertWellFormed(isName(type), 'invalid font Subtype'); @@ -759,7 +760,6 @@ var PartialEvaluator = (function partialEvaluator() { // a variant. var firstChar = xref.fetchIfRef(dict.get('FirstChar')) || 0; var lastChar = xref.fetchIfRef(dict.get('LastChar')) || maxCharIndex; - var fontName = xref.fetchIfRef(descriptor.get('FontName')); assertWellFormed(isName(fontName), 'invalid font name'); diff --git a/src/fonts.js b/src/fonts.js index c3fcb3c8a..116bb4dfc 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -393,7 +393,7 @@ var FontLoader = { bind: function fontLoaderBind(fonts, callback) { function checkFontsLoaded() { - for (var i = 0; i < objs.length; i++) { + for (var i = 0, ii = objs.length; i < ii; i++) { var fontObj = objs[i]; if (fontObj.loading) { return false; @@ -409,7 +409,7 @@ var FontLoader = { var rules = [], names = [], objs = []; - for (var i = 0; i < fonts.length; i++) { + for (var i = 0, ii = fonts.length; i < ii; i++) { var font = fonts[i]; // If there is already a fontObj on the font, then it was loaded/attached @@ -490,7 +490,7 @@ var FontLoader = { 'width: 10px; height: 10px;' + 'position: absolute; top: 0px; left: 0px;'); var html = ''; - for (var i = 0; i < names.length; ++i) { + for (var i = 0, ii = names.length; i < ii; ++i) { html += 'Hi'; } div.innerHTML = html; @@ -501,7 +501,7 @@ var FontLoader = { 'message', function fontLoaderMessage(e) { var fontNames = JSON.parse(e.data); - for (var i = 0; i < objs.length; ++i) { + for (var i = 0, ii = objs.length; i < ii; ++i) { var font = objs[i]; font.loading = false; } @@ -517,13 +517,13 @@ var FontLoader = { // pdfjsFontLoadFailed? var src = ''; src += ''; src += ''; - for (var i = 0; i < names.length; ++i) { + for (var i = 0, ii = names.length; i < ii; ++i) { src += '

Hi

'; } src += ''; @@ -711,7 +711,7 @@ var MacStandardGlyphOrdering = [ 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat']; function getUnicodeRangeFor(value) { - for (var i = 0; i < UnicodeRanges.length; i++) { + for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) { var range = UnicodeRanges[i]; if (value >= range.begin && value < range.end) return i; @@ -845,7 +845,7 @@ var Font = (function Font() { function stringToArray(str) { var array = []; - for (var i = 0; i < str.length; ++i) + for (var i = 0, ii = str.length; i < ii; ++i) array[i] = str.charCodeAt(i); return array; @@ -853,7 +853,7 @@ var Font = (function Font() { function arrayToString(arr) { var str = ''; - for (var i = 0; i < arr.length; ++i) + for (var i = 0, ii = arr.length; i < ii; ++i) str += String.fromCharCode(arr[i]); return str; @@ -1184,11 +1184,11 @@ var Font = (function Font() { // Mac want 1-byte per character strings while Windows want // 2-bytes per character, so duplicate the names table var stringsUnicode = []; - for (var i = 0; i < strings.length; i++) { + for (var i = 0, ii = strings.length; i < ii; i++) { var str = strings[i]; var strUnicode = ''; - for (var j = 0; j < str.length; j++) + for (var j = 0, jj = str.length; j < jj; j++) strUnicode += string16(str.charCodeAt(j)); stringsUnicode.push(strUnicode); } @@ -1206,9 +1206,9 @@ var Font = (function Font() { // Build the name records field var strOffset = 0; - for (var i = 0; i < platforms.length; i++) { + for (var i = 0, ii = platforms.length; i < ii; i++) { var strs = names[i]; - for (var j = 0; j < strs.length; j++) { + for (var j = 0, jj = strs.length; j < jj; j++) { var str = strs[j]; var nameRecord = platforms[i] + // platform ID @@ -1349,7 +1349,7 @@ var Font = (function Font() { string32(table.offset); } - for (var i = 0; i < data.length; i++) + for (var i = 0, ii = data.length; i < ii; i++) cmap.data[i] = data.charCodeAt(i); } @@ -1497,7 +1497,7 @@ var Font = (function Font() { if (numMissing > 0) { font.pos = (font.start ? font.start : 0) + metrics.offset; var entries = ''; - for (var i = 0; i < hmtx.length; i++) + for (var i = 0, ii = hmtx.length; i < ii; i++) entries += String.fromCharCode(font.getByte()); for (var i = 0; i < numMissing; i++) entries += '\x00\x00'; @@ -1743,18 +1743,18 @@ var Font = (function Font() { }); // rewrite the tables but tweak offsets - for (var i = 0; i < tables.length; i++) { + for (var i = 0, ii = tables.length; i < ii; i++) { var table = tables[i]; var data = []; var tableData = table.data; - for (var j = 0; j < tableData.length; j++) + for (var j = 0, jj = tableData.length; j < jj; j++) data.push(tableData[j]); createTableEntry(ttf, table.tag, data); } // Add the table datas - for (var i = 0; i < tables.length; i++) { + for (var i = 0, ii = tables.length; i < ii; i++) { var table = tables[i]; var tableData = table.data; ttf.file += arrayToString(tableData); @@ -1769,7 +1769,7 @@ var Font = (function Font() { convert: function font_convert(fontName, font, properties) { function isFixedPitch(glyphs) { - for (var i = 0; i < glyphs.length - 1; i++) { + for (var i = 0, ii = glyphs.length - 1; i < ii; i++) { if (glyphs[i] != glyphs[i + 1]) return false; } @@ -1868,7 +1868,7 @@ var Font = (function Font() { // Horizontal metrics 'hmtx': (function fontFieldsHmtx() { var hmtx = '\x00\x00\x00\x00'; // Fake .notdef - for (var i = 0; i < charstrings.length; i++) + for (var i = 0, ii = charstrings.length; i < ii; i++) hmtx += string16(charstrings[i].width) + string16(0); return stringToArray(hmtx); })(), @@ -1920,8 +1920,8 @@ var Font = (function Font() { if (!cidToUnicode) return; // identity encoding - var glyph = 1, i, j, k; - for (i = 0; i < cidToUnicode.length; ++i) { + var glyph = 1, i, j, k, ii; + for (i = 0, ii = cidToUnicode.length; i < ii; ++i) { var unicode = cidToUnicode[i]; if (isArray(unicode)) { var length = unicode.length; @@ -1963,12 +1963,11 @@ var Font = (function Font() { var url = ('url(data:' + this.mimetype + ';base64,' + window.btoa(data) + ');'); var rule = "@font-face { font-family:'" + fontName + "';src:" + url + '}'; - var styleSheet = document.styleSheets[0]; - if (!styleSheet) { - document.documentElement.firstChild.appendChild( - document.createElement('style')); - styleSheet = document.styleSheets[0]; - } + + document.documentElement.firstChild.appendChild( + document.createElement('style')); + + var styleSheet = document.styleSheets[document.styleSheets.length - 1]; styleSheet.insertRule(rule, styleSheet.cssRules.length); return rule; @@ -2081,7 +2080,7 @@ var Font = (function Font() { } } else { - for (var i = 0; i < chars.length; ++i) { + for (var i = 0, ii = chars.length; i < ii; ++i) { var charcode = chars.charCodeAt(i); var glyph = this.charToGlyph(charcode); glyphs.push(glyph); @@ -2383,7 +2382,7 @@ var Type1Parser = function type1Parser() { count++; var array = str.substr(start, count).split(' '); - for (var i = 0; i < array.length; i++) + for (var i = 0, ii = array.length; i < ii; i++) array[i] = parseFloat(array[i] || 0); return array; } @@ -2408,7 +2407,7 @@ var Type1Parser = function type1Parser() { this.extractFontProgram = function t1_extractFontProgram(stream) { var eexec = decrypt(stream, kEexecEncryptionKey, 4); var eexecStr = ''; - for (var i = 0; i < eexec.length; i++) + for (var i = 0, ii = eexec.length; i < ii; i++) eexecStr += String.fromCharCode(eexec[i]); var glyphsSection = false, subrsSection = false; @@ -2532,7 +2531,7 @@ var Type1Parser = function type1Parser() { this.extractFontHeader = function t1_extractFontHeader(stream, properties) { var headerString = ''; - for (var i = 0; i < stream.length; i++) + for (var i = 0, ii = stream.length; i < ii; i++) headerString += String.fromCharCode(stream[i]); var token = ''; @@ -2559,7 +2558,7 @@ var Type1Parser = function type1Parser() { var matrix = readNumberArray(headerString, i + 1); // The FontMatrix is in unitPerEm, so make it pixels - for (var j = 0; j < matrix.length; j++) + for (var j = 0, jj = matrix.length; j < jj; j++) matrix[j] *= 1000; // Make the angle into the right direction @@ -2726,7 +2725,7 @@ CFF.prototype = { } for (var i = 0; i < count; i++) { - for (var j = 0; j < objects[i].length; j++) + for (var j = 0, jj = objects[i].length; j < jj; j++) data += isByte ? String.fromCharCode(objects[i][j] & 0xFF) : objects[i][j]; } @@ -2850,6 +2849,7 @@ CFF.prototype = { }, flattenCharstring: function flattenCharstring(charstring, map) { + // charstring changes size - can't cache .length in loop for (var i = 0; i < charstring.length; i++) { var command = charstring[i]; if (command.charAt) { @@ -2894,7 +2894,7 @@ CFF.prototype = { '\x1c\x00\x00\x10'; // Encoding var boundingBox = properties.bbox; - for (var i = 0; i < boundingBox.length; i++) + for (var i = 0, ii = boundingBox.length; i < ii; i++) dict += self.encodeNumber(boundingBox[i]); dict += '\x05'; // FontBBox; @@ -2984,7 +2984,7 @@ CFF.prototype = { if (isArray(value)) { data += self.encodeNumber(value[0]); - for (var i = 1; i < value.length; i++) + for (var i = 1, ii = value.length; i < ii; i++) data += self.encodeNumber(value[i] - value[i - 1]); } else { data += self.encodeNumber(value); @@ -3005,7 +3005,7 @@ CFF.prototype = { var cff = []; for (var index in fields) { var field = fields[index]; - for (var i = 0; i < field.length; i++) + for (var i = 0, ii = field.length; i < ii; i++) cff.push(field.charCodeAt(i)); } @@ -3116,7 +3116,7 @@ var Type2CFF = (function type2CFF() { // create the mapping between charstring and glyph id var glyphIds = []; - for (var i = 0; i < charstrings.length; i++) + for (var i = 0, ii = charstrings.length; i < ii; i++) glyphIds.push(charstrings[i].gid); this.charstrings = charstrings; @@ -3133,7 +3133,7 @@ var Type2CFF = (function type2CFF() { var charstrings = []; var unicodeUsed = []; var unassignedUnicodeItems = []; - for (var i = 0; i < charsets.length; i++) { + for (var i = 0, ii = charsets.length; i < ii; i++) { var glyph = charsets[i]; var encodingFound = false; for (var charcode in encoding) { @@ -3156,7 +3156,7 @@ var Type2CFF = (function type2CFF() { } var nextUnusedUnicode = 0x21; - for (var j = 0; j < unassignedUnicodeItems.length; ++j) { + for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; ++j) { var i = unassignedUnicodeItems[j]; // giving unicode value anyway while (unicodeUsed[nextUnusedUnicode]) @@ -3199,7 +3199,7 @@ var Type2CFF = (function type2CFF() { var gid = 1; var baseEncoding = pos ? Encodings.ExpertEncoding : Encodings.StandardEncoding; - for (var i = 0; i < charset.length; i++) { + for (var i = 0, ii = charset.length; i < ii; i++) { var index = baseEncoding.indexOf(charset[i]); if (index != -1) encoding[index] = gid++; @@ -3401,16 +3401,16 @@ var Type2CFF = (function type2CFF() { getStrings: function cff_getStrings(stringIndex) { function bytesToString(bytesArray) { var str = ''; - for (var i = 0, length = bytesArray.length; i < length; i++) + for (var i = 0, ii = bytesArray.length; i < ii; i++) str += String.fromCharCode(bytesArray[i]); return str; } var stringArray = []; - for (var i = 0, length = CFFStrings.length; i < length; i++) + for (var i = 0, ii = CFFStrings.length; i < ii; i++) stringArray.push(CFFStrings[i]); - for (var i = 0, length = stringIndex.length; i < length; i++) + for (var i = 0, ii = stringIndex.length; i < ii; i++) stringArray.push(bytesToString(stringIndex.get(i).data)); return stringArray; diff --git a/src/function.js b/src/function.js index e2b191274..80c5a5460 100644 --- a/src/function.js +++ b/src/function.js @@ -3,16 +3,17 @@ 'use strict'; -var PDFFunction = (function() { +var PDFFunction = (function pdfFunction() { var CONSTRUCT_SAMPLED = 0; var CONSTRUCT_INTERPOLATED = 2; var CONSTRUCT_STICHED = 3; var CONSTRUCT_POSTSCRIPT = 4; return { - getSampleArray: function(size, outputSize, bps, str) { + getSampleArray: function pdfFunctionGetSampleArray(size, outputSize, bps, + str) { var length = 1; - for (var i = 0; i < size.length; i++) + for (var i = 0, ii = size.length; i < ii; i++) length *= size[i]; length *= outputSize; @@ -35,7 +36,7 @@ var PDFFunction = (function() { return array; }, - getIR: function(xref, fn) { + getIR: function pdfFunctionGetIR(xref, fn) { var dict = fn.dict; if (!dict) dict = fn; @@ -54,7 +55,7 @@ var PDFFunction = (function() { return typeFn.call(this, fn, dict, xref); }, - fromIR: function(IR) { + fromIR: function pdfFunctionFromIR(IR) { var type = IR[0]; switch (type) { case CONSTRUCT_SAMPLED: @@ -69,12 +70,12 @@ var PDFFunction = (function() { } }, - parse: function(xref, fn) { + parse: function pdfFunctionParse(xref, fn) { var IR = this.getIR(xref, fn); return this.fromIR(IR); }, - constructSampled: function(str, dict) { + constructSampled: function pdfFunctionConstructSampled(str, dict) { var domain = dict.get('Domain'); var range = dict.get('Range'); @@ -116,7 +117,7 @@ var PDFFunction = (function() { ]; }, - constructSampledFromIR: function(IR) { + constructSampledFromIR: function pdfFunctionConstructSampledFromIR(IR) { var inputSize = IR[1]; var domain = IR[2]; var encode = IR[3]; @@ -127,8 +128,8 @@ var PDFFunction = (function() { var bps = IR[8]; var range = IR[9]; - return function(args) { - var clip = function(v, min, max) { + return function constructSampledFromIRResult(args) { + var clip = function constructSampledFromIRClip(v, min, max) { if (v > max) v = max; else if (v < min) @@ -212,7 +213,7 @@ var PDFFunction = (function() { var length = diff.length; - return function(args) { + return function constructInterpolatedFromIRResult(args) { var x = n == 1 ? args[0] : Math.pow(args[0], n); var out = []; @@ -253,12 +254,12 @@ var PDFFunction = (function() { var fnsIR = IR[4]; var fns = []; - for (var i = 0; i < fnsIR.length; i++) { + for (var i = 0, ii = fnsIR.length; i < ii; i++) { fns.push(PDFFunction.fromIR(fnsIR[i])); } - return function(args) { - var clip = function(v, min, max) { + return function constructStichedFromIRResult(args) { + var clip = function constructStichedFromIRClip(v, min, max) { if (v > max) v = max; else if (v < min) @@ -298,7 +299,7 @@ var PDFFunction = (function() { constructPostScriptFromIR: function pdfFunctionConstructPostScriptFromIR() { TODO('unhandled type of function'); - return function() { + return function constructPostScriptFromIRResult() { return [255, 105, 180]; }; } diff --git a/src/image.js b/src/image.js index b281e21c1..71aa0f113 100644 --- a/src/image.js +++ b/src/image.js @@ -229,12 +229,12 @@ var PDFImage = (function pdfImage() { return constructor; })(); -var JpegImage = (function() { +var JpegImage = (function jpegImage() { function JpegImage(objId, imageData, objs) { var src = 'data:image/jpeg;base64,' + window.btoa(imageData); var img = new Image(); - img.onload = (function() { + img.onload = (function jpegImageOnload() { this.loaded = true; objs.resolve(objId, this); @@ -247,7 +247,7 @@ var JpegImage = (function() { } JpegImage.prototype = { - getImage: function() { + getImage: function jpegImageGetImage() { return this.domImage; } }; diff --git a/src/obj.js b/src/obj.js index 8d5684ec2..7aebb732a 100644 --- a/src/obj.js +++ b/src/obj.js @@ -178,7 +178,7 @@ var Catalog = (function catalogCatalog() { var kids = pagesDict.get('Kids'); assertWellFormed(isArray(kids), 'page dictionary kids object is not an array'); - for (var i = 0; i < kids.length; ++i) { + for (var i = 0, ii = kids.length; i < ii; ++i) { var kid = kids[i]; assertWellFormed(isRef(kid), 'page dictionary kid is not a reference'); @@ -490,12 +490,12 @@ var XRef = (function xRefXRef() { position += token.length + 1; } // reading XRef streams - for (var i = 0; i < xrefStms.length; ++i) { + for (var i = 0, ii = xrefStms.length; i < ii; ++i) { this.readXRef(xrefStms[i]); } // finding main trailer var dict; - for (var i = 0; i < trailers.length; ++i) { + for (var i = 0, ii = trailers.length; i < ii; ++i) { stream.pos = trailers[i]; var parser = new Parser(new Lexer(stream), true); var obj = parser.getObj(); @@ -642,7 +642,7 @@ var XRef = (function xRefXRef() { * inside of a worker. The `PDFObjects` implements some basic functions to * manage these objects. */ -var PDFObjects = (function() { +var PDFObjects = (function pdfObjects() { function PDFObjects() { this.objs = {}; } @@ -655,7 +655,7 @@ var PDFObjects = (function() { * Ensures there is an object defined for `objId`. Stores `data` on the * object *if* it is created. */ - ensureObj: function(objId, data) { + ensureObj: function pdfObjectsEnsureObj(objId, data) { if (this.objs[objId]) return this.objs[objId]; return this.objs[objId] = new Promise(objId, data); @@ -670,7 +670,7 @@ var PDFObjects = (function() { * function and the object is already resolved, the callback gets called * right away. */ - get: function(objId, callback) { + get: function pdfObjectsGet(objId, callback) { // If there is a callback, then the get can be async and the object is // not required to be resolved right now if (callback) { @@ -695,7 +695,7 @@ var PDFObjects = (function() { /** * Resolves the object `objId` with optional `data`. */ - resolve: function(objId, data) { + resolve: function pdfObjectsResolve(objId, data) { var objs = this.objs; // In case there is a promise already on this object, just resolve it. @@ -706,11 +706,11 @@ var PDFObjects = (function() { } }, - onData: function(objId, callback) { + onData: function pdfObjectsOnData(objId, callback) { this.ensureObj(objId).onData(callback); }, - isResolved: function(objId) { + isResolved: function pdfObjectsIsResolved(objId) { var objs = this.objs; if (!objs[objId]) { return false; @@ -719,7 +719,7 @@ var PDFObjects = (function() { } }, - hasData: function(objId) { + hasData: function pdfObjectsHasData(objId) { var objs = this.objs; if (!objs[objId]) { return false; @@ -731,7 +731,7 @@ var PDFObjects = (function() { /** * Sets the data of an object but *doesn't* resolve it. */ - setData: function(objId, data) { + setData: function pdfObjectsSetData(objId, data) { // Watchout! If you call `this.ensureObj(objId, data)` you're going to // create a *resolved* promise which shouldn't be the case! this.ensureObj(objId).data = data; diff --git a/src/pattern.js b/src/pattern.js index 8e7760e51..72d13d896 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -19,10 +19,10 @@ var Pattern = (function patternPattern() { constructor.shadingFromIR = function pattern_shadingFromIR(ctx, raw) { return Shadings[raw[0]].fromIR(ctx, raw); - } + }; - constructor.parseShading = function pattern_shading(shading, matrix, - xref, res, ctx) { + constructor.parseShading = function pattern_shading(shading, matrix, xref, + res, ctx) { var dict = isStream(shading) ? shading.dict : shading; var type = dict.get('ShadingType'); @@ -97,7 +97,7 @@ Shadings.RadialAxial = (function radialAxialShading() { this.colorStops = colorStops; } - constructor.fromIR = function(ctx, raw) { + constructor.fromIR = function radialAxialShadingGetIR(ctx, raw) { var type = raw[1]; var colorStops = raw[2]; var p0 = raw[3]; @@ -116,20 +116,21 @@ Shadings.RadialAxial = (function radialAxialShading() { p1 = Util.applyTransform(p1, userMatrix); } + var grad; if (type == 2) - var grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); + grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]); else if (type == 3) - var grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); + grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1); for (var i = 0, ii = colorStops.length; i < ii; ++i) { var c = colorStops[i]; grad.addColorStop(c[0], c[1]); } return grad; - } + }; constructor.prototype = { - getIR: function RadialAxialShading_getIR() { + getIR: function radialAxialShadingGetIR() { var coordsArr = this.coordsArr; var type = this.shadingType; if (type == 2) { @@ -164,12 +165,12 @@ Shadings.Dummy = (function dummyShading() { this.type = 'Pattern'; } - constructor.fromIR = function() { + constructor.fromIR = function dummyShadingFromIR() { return 'hotpink'; - } + }; constructor.prototype = { - getIR: function dummpy_getir() { + getIR: function dummyShadingGetIR() { return ['Dummy']; } }; @@ -242,9 +243,9 @@ var TilingPattern = (function tilingPattern() { graphics.transform.apply(graphics, tmpTranslate); if (bbox && isArray(bbox) && 4 == bbox.length) { - var bboxWidth = bbox[2] - bbox[0]; - var bboxHeight = bbox[3] - bbox[1]; - graphics.rectangle(bbox[0], bbox[1], bboxWidth, bboxHeight); + var bboxWidth = x1 - x0; + var bboxHeight = y1 - y0; + graphics.rectangle(x0, y0, bboxWidth, bboxHeight); graphics.clip(); graphics.endPath(); } @@ -264,7 +265,7 @@ var TilingPattern = (function tilingPattern() { return [ 'TilingPattern', args, codeIR, matrix, bbox, xstep, ystep, paintType ]; - } + }; TilingPattern.prototype = { getPattern: function tiling_getPattern() { diff --git a/src/pdf.js b/src/pdf.js index 34e163967..51f606548 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -4,12 +4,11 @@ var PDFJS = {}; (function pdfjsWrapper() { - // Use strict in our context only - users might not want it 'use strict'; // Files are inserted below - see Makefile /* PDFJSSCRIPT_INCLUDE_ALL */ -})(); +}).call((typeof window === 'undefined') ? this : window); diff --git a/src/stream.js b/src/stream.js index 2b10e2fbd..73b096f1e 100644 --- a/src/stream.js +++ b/src/stream.js @@ -801,7 +801,7 @@ var JpegStream = (function jpegStream() { } constructor.prototype = { - getIR: function() { + getIR: function jpegStreamGetIR() { return this.src; }, getChar: function jpegStreamGetChar() { diff --git a/src/util.js b/src/util.js index d8d50337b..4fb96f062 100644 --- a/src/util.js +++ b/src/util.js @@ -16,16 +16,15 @@ function warn(msg) { } function backtrace() { - var stackStr; try { throw new Error(); } catch (e) { - stackStr = e.stack; + return e.stack ? e.stack.split('\n').slice(2).join('\n') : ''; } - return stackStr.split('\n').slice(1).join('\n'); } function error(msg) { + log('Error: ' + msg); log(backtrace()); throw new Error(msg); } @@ -198,7 +197,7 @@ function isPDFFunction(v) { * can be set. If any of these happens twice or the data is required before * it was set, an exception is throw. */ -var Promise = (function() { +var Promise = (function promise() { var EMPTY_PROMISE = {}; /** @@ -222,19 +221,19 @@ var Promise = (function() { Promise.prototype = { hasData: false, - set data(data) { - if (data === undefined) { + set data(value) { + if (value === undefined) { return; } if (this._data !== EMPTY_PROMISE) { throw 'Promise ' + this.name + ': Cannot set the data of a promise twice'; } - this._data = data; + this._data = value; this.hasData = true; if (this.onDataCallback) { - this.onDataCallback(data); + this.onDataCallback(value); } }, @@ -245,7 +244,7 @@ var Promise = (function() { return this._data; }, - onData: function(callback) { + onData: function promiseOnData(callback) { if (this._data !== EMPTY_PROMISE) { callback(this._data); } else { @@ -253,7 +252,7 @@ var Promise = (function() { } }, - resolve: function(data) { + resolve: function promiseResolve(data) { if (this.isResolved) { throw 'A Promise can be resolved only once ' + this.name; } @@ -262,12 +261,12 @@ var Promise = (function() { this.data = data; var callbacks = this.callbacks; - for (var i = 0; i < callbacks.length; i++) { + for (var i = 0, ii = callbacks.length; i < ii; i++) { callbacks[i].call(null, data); } }, - then: function(callback) { + then: function promiseThen(callback) { if (!callback) { throw 'Requiring callback' + this.name; } diff --git a/src/worker.js b/src/worker.js index d62e0c86b..67f1bf658 100644 --- a/src/worker.js +++ b/src/worker.js @@ -43,10 +43,21 @@ MessageHandler.prototype = { } }; -var WorkerProcessorHandler = { +var WorkerMessageHandler = { setup: function wphSetup(handler) { var pdfDoc = null; + handler.on('test', function wphSetupTest(data) { + handler.send('test', data instanceof Uint8Array); + }); + + handler.on('workerSrc', function wphSetupWorkerSrc(data) { + // In development, the `workerSrc` message is handled in the + // `worker_loader.js` file. In production the workerProcessHandler is + // called for this. This servers as a dummy to prevent calling an + // undefined action `workerSrc`. + }); + handler.on('doc', function wphSetupDoc(data) { // Create only the model of the PDFDoc, which is enough for // processing the content of the pdf. @@ -75,7 +86,7 @@ var WorkerProcessorHandler = { // Filter the dependecies for fonts. var fonts = {}; - for (var i = 0; i < dependency.length; i++) { + for (var i = 0, ii = dependency.length; i < ii; i++) { var dep = dependency[i]; if (dep.indexOf('font_') == 0) { fonts[dep] = true; @@ -176,8 +187,7 @@ var workerConsole = { if (typeof window === 'undefined') { globalScope.console = workerConsole; - // Listen for messages from the main thread. - var handler = new MessageHandler('worker_processor', globalScope); - WorkerProcessorHandler.setup(handler); + var handler = new MessageHandler('worker_processor', this); + WorkerMessageHandler.setup(handler); } diff --git a/src/worker_loader.js b/src/worker_loader.js index fb37ca9c4..cb0a91071 100644 --- a/src/worker_loader.js +++ b/src/worker_loader.js @@ -3,22 +3,50 @@ 'use strict'; -importScripts('../src/core.js'); -importScripts('../src/util.js'); -importScripts('../src/canvas.js'); -importScripts('../src/obj.js'); -importScripts('../src/function.js'); -importScripts('../src/charsets.js'); -importScripts('../src/cidmaps.js'); -importScripts('../src/colorspace.js'); -importScripts('../src/crypto.js'); -importScripts('../src/evaluator.js'); -importScripts('../src/fonts.js'); -importScripts('../src/glyphlist.js'); -importScripts('../src/image.js'); -importScripts('../src/metrics.js'); -importScripts('../src/parser.js'); -importScripts('../src/pattern.js'); -importScripts('../src/stream.js'); -importScripts('../src/worker.js'); +function onMessageLoader(evt) { + // Reset the `onmessage` function as it was only set to call + // this function the first time a message is passed to the worker + // but shouldn't get called anytime afterwards. + this.onmessage = null; + if (evt.data.action !== 'workerSrc') { + throw 'Worker expects first message to be `workerSrc`'; + } + + // Content of `PDFJS.workerSrc` as defined on the main thread. + var workerSrc = evt.data.data; + + // Extract the directory that contains the source files to load. + // Assuming the source files have the same relative possition as the + // `workerSrc` file. + var dir = workerSrc.substring(0, workerSrc.lastIndexOf('/') + 1); + + // List of files to include; + var files = [ + 'core.js', + 'util.js', + 'canvas.js', + 'obj.js', + 'function.js', + 'charsets.js', + 'cidmaps.js', + 'colorspace.js', + 'crypto.js', + 'evaluator.js', + 'fonts.js', + 'glyphlist.js', + 'image.js', + 'metrics.js', + 'parser.js', + 'pattern.js', + 'stream.js', + 'worker.js' + ]; + + // Load all the files. + for (var i = 0; i < files.length; i++) { + importScripts(dir + files[i]); + } +} + +this.onmessage = onMessageLoader; diff --git a/test/driver.js b/test/driver.js index 16375c30b..e84b7c8e0 100644 --- a/test/driver.js +++ b/test/driver.js @@ -7,6 +7,11 @@ 'use strict'; +// Disable worker support for running test as +// https://github.com/mozilla/pdf.js/pull/764#issuecomment-2638944 +// "firefox-bin: Fatal IO error 12 (Cannot allocate memory) on X server :1." +PDFJS.disableWorker = true; + var appPath, browser, canvas, currentTaskIdx, manifest, stdout; var inFlightRequests = 0; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index e7eb0da43..443cb155a 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -12,4 +12,6 @@ !rotation.pdf !simpletype3font.pdf !sizes.pdf +!close-path-bug.pdf +!alphatrans.pdf diff --git a/test/pdfs/alphatrans.pdf b/test/pdfs/alphatrans.pdf new file mode 100644 index 000000000..6274ce3ac Binary files /dev/null and b/test/pdfs/alphatrans.pdf differ diff --git a/test/pdfs/cable.pdf.link b/test/pdfs/cable.pdf.link index 9cf92a5b8..671f06166 100644 --- a/test/pdfs/cable.pdf.link +++ b/test/pdfs/cable.pdf.link @@ -1 +1 @@ -http://www.wrapon.com/docs/PIPEHEATCABLE.PDF +https://wrap-on.com/docs/PIPEHEATCABLE.PDF diff --git a/test/pdfs/close-path-bug.pdf b/test/pdfs/close-path-bug.pdf new file mode 100644 index 000000000..994d4e572 --- /dev/null +++ b/test/pdfs/close-path-bug.pdf @@ -0,0 +1,69 @@ +%PDF-1.4 +1 0 obj + <> +endobj + +2 0 obj + <> +endobj + +3 0 obj + <> +endobj + +4 0 obj + <>>> +endobj + +5 0 obj + << /Length 885 >> +stream + % Draw a black line segment, using the default line width. + 150 250 m + 150 350 l + S + + % Draw a thicker, dashed line segment. + 4 w % Set line width to 4 points + [4 6] 0 d % Set dash pattern to 4 units on, 6 units off + 150 250 m + 400 250 l + S + + [] 0 d % Reset dash pattern to a solid line + 1 w % Reset line width to 1 unit + + % Draw a rectangle with a 1−unit red border, filled with light blue. + 1.0 0.0 0.0 RG % Red for stroke color + 0.5 0.75 1.0 rg % Light blue for fill color + 200 300 50 75 re + B + + % Draw a curve filled with gray and with a colored border. + 0.5 0.1 0.2 RG + 0.7 g + 300 300 m + 300 400 400 400 400 300 c + b +endstream +endobj + +6 0 obj + [/PDF] +endobj + +xref +0 7 +0000000000 65535 f +0000000009 00000 n +0000000074 00000 n +0000000120 00000 n +0000000179 00000 n +0000000300 00000 n +0000001532 00000 n + +trailer + <> +startxref +1556 +%%EOF diff --git a/test/test.py b/test/test.py index 66e1acd31..65def5d8e 100644 --- a/test/test.py +++ b/test/test.py @@ -1,4 +1,4 @@ -import json, platform, os, shutil, sys, subprocess, tempfile, threading, time, urllib, urllib2 +import json, platform, os, shutil, sys, subprocess, tempfile, threading, time, urllib, urllib2, hashlib from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer import SocketServer from optparse import OptionParser @@ -316,6 +316,28 @@ def downloadLinkedPDFs(manifestList): print 'done' +def verifyPDFs(manifestList): + error = False + for item in manifestList: + f = item['file'] + if os.access(f, os.R_OK): + fileMd5 = hashlib.md5(open(f, 'rb').read()).hexdigest() + if 'md5' not in item: + print 'ERROR: Missing md5 for file "' + f + '".', + print 'Hash for current file is "' + fileMd5 + '"' + error = True + continue + md5 = item['md5'] + if fileMd5 != md5: + print 'ERROR: MD5 of file "' + f + '" does not match file.', + print 'Expected "' + md5 + '" computed "' + fileMd5 + '"' + error = True + continue + else: + print 'ERROR: Unable to open file for reading "' + f + '".' + error = True + return not error + def setUp(options): # Only serve files from a pdf.js clone assert not ANAL or os.path.isfile('../src/pdf.js') and os.path.isdir('../.git') @@ -342,6 +364,9 @@ def setUp(options): downloadLinkedPDFs(manifestList) + if not verifyPDFs(manifestList): + raise Exception('ERROR: failed to verify pdfs.') + for b in testBrowsers: State.taskResults[b.name] = { } for item in manifestList: @@ -506,17 +531,17 @@ def maybeUpdateRefImages(options, browser): print ' Yes! The references in tmp/ can be synced with ref/.' if options.reftest: startReftest(browser, options) - if options.noPrompts or not prompt('Would you like to update the master copy in ref/?'): - print ' OK, not updating.' - else: + if options.noPrompts or prompt('Would you like to update the master copy in ref/?'): sys.stdout.write(' Updating ref/ ... ') # XXX unclear what to do on errors here ... # NB: do *NOT* pass --delete to rsync. That breaks this # entire scheme. - subprocess.check_call(( 'rsync', '-arv', 'tmp/', 'ref/' )) + subprocess.check_call(( 'rsync', '-arvq', 'tmp/', 'ref/' )) print 'done' + else: + print ' OK, not updating.' def startReftest(browser, options): url = "http://%s:%s" % (SERVER_HOST, options.port) diff --git a/test/test_manifest.json b/test/test_manifest.json index d7ac34cef..8085506a2 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -1,151 +1,178 @@ [ { "id": "tracemonkey-eq", "file": "pdfs/tracemonkey.pdf", + "md5": "9a192d8b1a7dc652a19835f6f08098bd", "rounds": 1, "type": "eq" }, { "id": "tracemonkey-fbf", "file": "pdfs/tracemonkey.pdf", + "md5": "9a192d8b1a7dc652a19835f6f08098bd", "rounds": 2, "type": "fbf" }, { "id": "html5-canvas-cheat-sheet-load", "file": "pdfs/canvas.pdf", + "md5": "59510028561daf62e00bf9f6f066b033", "rounds": 1, "type": "load" }, { "id": "intelisa-load", "file": "pdfs/intelisa.pdf", + "md5": "f3ed5487d1afa34d8b77c0c734a95c79", "link": true, "rounds": 1, "type": "load" }, { "id": "pdfspec-load", "file": "pdfs/pdf.pdf", + "md5": "dbdb23c939d2be09b43126c3c56060c7", "link": true, "rounds": 1, "type": "load" }, { "id": "shavian-load", "file": "pdfs/shavian.pdf", + "md5": "4fabf0a03e82693007435020bc446f9b", "link": true, "rounds": 1, "type": "load" }, { "id": "sizes", "file": "pdfs/sizes.pdf", + "md5": "c101ba7b44aee36048e1ac7b98f302ea", "rounds": 1, "type": "eq" }, { "id": "openweb-cover", "file": "pdfs/openweb_tm-PRINT.pdf", + "md5": "53f611dfc19ddfb50554c21c4af465c0", "link": true, "rounds": 1, "type": "eq" }, { "id": "plusminus", "file": "pdfs/Test-plusminus.pdf", + "md5": "1ec7ade5b95ac9aaba3a618af28d34c7", "rounds": 1, "type": "eq" }, { "id": "openoffice-pdf", "file": "pdfs/DiwanProfile.pdf", + "md5": "55d0c6a1a6d26c9ec9dcecaa7a471e0e", "link": true, "rounds": 1, "type": "load" }, { "id": "openofficecidtruetype-pdf", "file": "pdfs/arial_unicode_en_cidfont.pdf", + "md5": "03591cdf20214fb0b2dd5e5c3dd32d8c", "rounds": 1, "type": "load" }, { "id": "openofficearabiccidtruetype-pdf", "file": "pdfs/arial_unicode_ab_cidfont.pdf", + "md5": "35090fa7d29e7196ae3421812e554988", "rounds": 1, "type": "load" }, { "id": "arabiccidtruetype-pdf", "file": "pdfs/ArabicCIDTrueType.pdf", + "md5": "d66dbd18bdb572d3ac8b88b32de2ece6", "rounds": 1, "type": "load" }, { "id": "complexttffont-pdf", "file": "pdfs/complex_ttf_font.pdf", + "md5": "76de93f9116b01b693bf8583b3e76d91", "rounds": 1, "type": "load" }, { "id": "thuluthfont-pdf", "file": "pdfs/ThuluthFeatures.pdf", + "md5": "b7e18bf7a3d6a9c82aefa12d721072fc", "rounds": 1, "type": "eq" }, { "id": "wnv_chinese-pdf", "file": "pdfs/wnv_chinese.pdf", + "md5": "db682638e68391125e8982d3c984841e", "link": true, "rounds": 1, "type": "eq" }, { "id": "i9-pdf", "file": "pdfs/i9.pdf", + "md5": "ba7cd54fdff083bb389295bc0415f6c5", "link": true, "rounds": 1, "type": "eq" }, { "id": "hmm-pdf", "file": "pdfs/hmm.pdf", + "md5": "e08467e60101ee5f4a59716e86db6dc9", "link": true, "rounds": 1, "type": "load" }, { "id": "rotation", "file": "pdfs/rotation.pdf", + "md5": "4fb25ada00ce7528569d9791c14decf5", "rounds": 1, "type": "eq" }, { "id": "ecma262-pdf", "file": "pdfs/ecma262.pdf", + "md5": "763ead98f535578842891e5574e0af0f", "link": true, "rounds": 1, "type": "load" }, { "id": "jai-pdf", "file": "pdfs/jai.pdf", + "md5": "1f5dd128c3757420a881a155f2f8ace3", "link": true, "rounds": 1, "type": "load" }, { "id": "cable", "file": "pdfs/cable.pdf", + "md5": "09a41b9a759d60c698228224ab85b46d", "link": true, "rounds": 1, "type": "eq" }, { "id": "pdkids", "file": "pdfs/pdkids.pdf", + "md5": "278982bf016dbe46d2066f9245d9b3e6", "link": true, "rounds": 1, "type": "eq" }, { "id": "artofwar", "file": "pdfs/artofwar.pdf", + "md5": "7bdd51c327b74f1f7abdd90eedb2f912", "link": true, "rounds": 1, "type": "eq" }, { "id": "wdsg_fitc", "file": "pdfs/wdsg_fitc.pdf", + "md5": "5bb1c2b83705d4cdfc43197ee74f07f9", "link": true, "rounds": 1, "type": "eq" }, { "id": "unix01", "file": "pdfs/unix01.pdf", + "md5": "2742999f0bf9b9c035dbb0736096e220", "link": true, "rounds": 1, "type": "eq" }, { "id": "fit11-talk", "file": "pdfs/fit11-talk.pdf", + "md5": "eb7b224107205db4fea9f7df0185f77d", "link": true, "rounds": 1, "skipPages": [12,31], @@ -153,48 +180,56 @@ }, { "id": "fips197", "file": "pdfs/fips197.pdf", + "md5": "374800cf78ce4b4abd02cd10a856b57f", "link": true, "rounds": 1, "type": "eq" }, { "id": "txt2pdf", "file": "pdfs/txt2pdf.pdf", + "md5": "02cefa0f5e8d96313bb05163b2f88c8c", "link": true, "rounds": 1, "type": "load" }, { "id": "f1040", "file": "pdfs/f1040.pdf", + "md5": "7323b50c6d28d959b8b4b92c469b2469", "link": true, "rounds": 1, "type": "load" }, { "id": "hudsonsurvey", "file": "pdfs/hudsonsurvey.pdf", + "md5": "bf0e6576a7b6c2fe7485bce1b78e006f", "link": true, "rounds": 1, "type": "load" }, { "id": "extgstate", "file": "pdfs/extgstate.pdf", + "md5": "001bb4ec04463a01d93aad748361f049", "link": false, "rounds": 1, "type": "eq" }, { "id": "usmanm-bad", "file": "pdfs/usmanm-bad.pdf", + "md5": "38afb822433aaf07fc8f54807cd4f61a", "link": true, "rounds": 1, "type": "eq" }, { "id": "vesta-bad", "file": "pdfs/vesta.pdf", + "md5": "0afebc109b7c17b95619ea3fab5eafe6", "link": true, "rounds": 1, "type": "load" }, { "id": "ibwa-bad", "file": "pdfs/ibwa-bad.pdf", + "md5": "6ca059d32b74ac2688ae06f727fee755", "link": true, "rounds": 1, "skipPages": [ 16 ], @@ -202,18 +237,34 @@ }, { "id": "tcpdf_033", "file": "pdfs/tcpdf_033.pdf", + "md5": "861294df58d185aae80919173f2732ff", "link": true, "rounds": 1, "type": "eq" }, { "id": "pal-o47", "file": "pdfs/pal-o47.pdf", + "md5": "81ae15e539e89f0f0b41169d923b611b", "link": true, "rounds": 1, "type": "eq" }, { "id": "simpletype3font", "file": "pdfs/simpletype3font.pdf", + "md5": "b374c7543920840c61999e9e86939f99", + "link": false, + "rounds": 1, + "type": "eq" + }, + { "id": "close-path-bug", + "file": "pdfs/close-path-bug.pdf", + "md5": "48dd17ef58393857d2d038d33699cac5", + "rounds": 1, + "type": "eq" + }, + { "id": "alphatrans", + "file": "pdfs/alphatrans.pdf", + "md5": "5ca2d3da0c5f20b3a5a14e895ad24b65", "link": false, "rounds": 1, "type": "eq" diff --git a/test/test_slave.html b/test/test_slave.html index 7ac886769..91852d5a5 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -3,25 +3,29 @@ pdf.js test slave - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/web/compatibility.js b/web/compatibility.js index ad4c8f8a9..7d1d72553 100644 --- a/web/compatibility.js +++ b/web/compatibility.js @@ -83,6 +83,21 @@ }; })(); +// Object.keys() ? +(function checkObjectKeysCompatibility() { + if (typeof Object.keys !== 'undefined') + return; + + Object.keys = function objectKeys(obj) { + var result = []; + for (var i in obj) { + if (obj.hasOwnProperty(i)) + result.push(i); + } + return result; + }; +})(); + // No XMLHttpRequest.response ? (function checkXMLHttpRequestResponseCompatibility() { var xhrPrototype = XMLHttpRequest.prototype; diff --git a/web/index.html.template b/web/index.html.template index 12e606371..44e9a0cbe 100644 --- a/web/index.html.template +++ b/web/index.html.template @@ -3,7 +3,7 @@ - andreasgal/pdf.js @ GitHub + mozilla/pdf.js @ GitHub