From e12ac009661fc0f0e9fb6cbf458d405331b08d9d Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 26 May 2015 19:32:18 -0400 Subject: [PATCH] Bug 1168547 - Update pdf.js to version 1.1.165. r=yury --- browser/extensions/pdfjs/README.mozilla | 2 +- browser/extensions/pdfjs/content/build/pdf.js | 16 +- .../pdfjs/content/build/pdf.worker.js | 81 ++++++++-- .../extensions/pdfjs/content/web/viewer.css | 12 +- .../extensions/pdfjs/content/web/viewer.js | 140 +++++++++++++----- 5 files changed, 185 insertions(+), 66 deletions(-) diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index 931fe46a7a4a..64b69962cf50 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,3 +1,3 @@ This is the pdf.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 1.1.114 +Current extension version is: 1.1.165 diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index 681e85baf3b9..52c77b7dc71e 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -22,8 +22,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '1.1.114'; -PDFJS.build = '3fd44fd'; +PDFJS.version = '1.1.165'; +PDFJS.build = '39d2103'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -919,6 +919,10 @@ function stringToUTF8String(str) { return decodeURIComponent(escape(str)); } +function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); +} + function isEmptyObj(obj) { for (var key in obj) { return false; @@ -2009,6 +2013,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() { this.commonObjs, intentState.operatorList, this.pageNumber); + internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; if (!intentState.renderTasks) { intentState.renderTasks = []; } @@ -2814,6 +2819,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { this.running = false; this.graphicsReadyCallback = null; this.graphicsReady = false; + this.useRequestAnimationFrame = false; this.cancelled = false; this.capability = createPromiseCapability(); this.task = new RenderTask(this); @@ -2887,7 +2893,11 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { }, _scheduleNext: function InternalRenderTask__scheduleNext() { - window.requestAnimationFrame(this._nextBound); + if (this.useRequestAnimationFrame) { + window.requestAnimationFrame(this._nextBound); + } else { + Promise.resolve(undefined).then(this._nextBound); + } }, _next: function InternalRenderTask__next() { diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index 9a0a0a792e70..3c6b1301ebe5 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -22,8 +22,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '1.1.114'; -PDFJS.build = '3fd44fd'; +PDFJS.version = '1.1.165'; +PDFJS.build = '39d2103'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -919,6 +919,10 @@ function stringToUTF8String(str) { return decodeURIComponent(escape(str)); } +function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); +} + function isEmptyObj(obj) { for (var key in obj) { return false; @@ -3583,12 +3587,13 @@ var XRef = (function XRefClosure() { trailers.push(position); position += skipUntil(buffer, position, startxrefBytes); } else if ((m = /^(\d+)\s+(\d+)\s+obj\b/.exec(token))) { - this.entries[m[1]] = { - offset: position, - gen: m[2] | 0, - uncompressed: true - }; - + if (typeof this.entries[m[1]] === 'undefined') { + this.entries[m[1]] = { + offset: position, + gen: m[2] | 0, + uncompressed: true + }; + } var contentLength = skipUntil(buffer, position, endobjBytes) + 7; var content = buffer.subarray(position, position + contentLength); @@ -4811,7 +4816,15 @@ var LinkAnnotation = (function LinkAnnotationClosure() { if (!isValidUrl(url, false)) { url = ''; } - data.url = url; + // According to ISO 32000-1:2008, section 12.6.4.7, + // URI should to be encoded in 7-bit ASCII. + // Some bad PDFs may have URIs in UTF-8 encoding, see Bugzilla 1122280. + try { + data.url = stringToUTF8String(url); + } catch (e) { + // Fall back to a simple copy. + data.url = url; + } } else if (linkType === 'GoTo') { data.dest = action.get('D'); } else if (linkType === 'GoToR') { @@ -9094,6 +9107,14 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var fileIdBytes = stringToBytes(fileId); var passwordBytes; if (password) { + if (revision === 6) { + try { + password = utf8StringToString(password); + } catch (ex) { + warn('CipherTransformFactory: ' + + 'Unable to convert UTF8 encoded password.'); + } + } passwordBytes = stringToBytes(password); } @@ -9198,7 +9219,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { CipherTransformFactory.prototype = { createCipherTransform: - function CipherTransformFactory_createCipherTransform(num, gen) { + function CipherTransformFactory_createCipherTransform(num, gen) { if (this.algorithm === 4 || this.algorithm === 5) { return new CipherTransform( buildCipherConstructor(this.cf, this.stmf, @@ -10932,6 +10953,17 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var tsm = [textState.fontSize * textState.textHScale, 0, 0, textState.fontSize, 0, textState.textRise]; + + if (font.isType3Font && + textState.fontMatrix !== FONT_IDENTITY_MATRIX && + textState.fontSize === 1) { + var glyphHeight = font.bbox[3] - font.bbox[1]; + if (glyphHeight > 0) { + glyphHeight = glyphHeight * textState.fontMatrix[3]; + tsm[3] *= glyphHeight; + } + } + var trm = textChunk.transform = Util.transform(textState.ctm, Util.transform(textState.textMatrix, tsm)); if (!font.vertical) { @@ -10985,16 +11017,23 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // var x = pt[0]; // var y = pt[1]; + var charSpacing = 0; + if (textChunk.str.length > 0) { + // Apply char spacing only when there are chars. + // As a result there is only spacing between glyphs. + charSpacing = textState.charSpacing; + } + var tx = 0; var ty = 0; if (!font.vertical) { var w0 = glyphWidth * textState.fontMatrix[0]; - tx = (w0 * textState.fontSize + textState.charSpacing) * + tx = (w0 * textState.fontSize + charSpacing) * textState.textHScale; width += tx; } else { var w1 = glyphWidth * textState.fontMatrix[0]; - ty = w1 * textState.fontSize + textState.charSpacing; + ty = w1 * textState.fontSize + charSpacing; height += ty; } textState.translateTextMatrix(tx, ty); @@ -11260,8 +11299,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var data = diffEncoding[j]; if (isNum(data)) { index = data; - } else { + } else if (isName(data)) { differences[index++] = data.name; + } else if (isRef(data)) { + diffEncoding[j--] = xref.fetch(data); + continue; + } else { + error('Invalid entry in \'Differences\' array: ' + data); } } } @@ -11610,6 +11654,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // is a tagged pdf. Create a barbebones one to get by. descriptor = new Dict(null); descriptor.set('FontName', Name.get(type)); + descriptor.set('FontBBox', dict.get('FontBBox')); } else { // Before PDF 1.5 if the font was one of the base 14 fonts, having a // FontDescriptor was not required. @@ -16029,6 +16074,7 @@ var Font = (function FontClosure() { this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS; this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS; this.fontMatrix = properties.fontMatrix; + this.bbox = properties.bbox; this.toUnicode = properties.toUnicode = this.buildToUnicode(properties); @@ -16840,7 +16886,10 @@ var Font = (function FontClosure() { } } - if (!potentialTable) { + if (potentialTable) { + font.pos = start + potentialTable.offset; + } + if (!potentialTable || font.peekByte() === -1) { warn('Could not find a preferred cmap table.'); return { platformId: -1, @@ -16850,7 +16899,6 @@ var Font = (function FontClosure() { }; } - font.pos = start + potentialTable.offset; var format = font.getUint16(); var length = font.getUint16(); var language = font.getUint16(); @@ -17285,6 +17333,9 @@ var Font = (function FontClosure() { default: warn('Unknown/unsupported post table version ' + version); valid = false; + if (properties.defaultEncoding) { + glyphNames = properties.defaultEncoding; + } break; } properties.glyphNames = glyphNames; diff --git a/browser/extensions/pdfjs/content/web/viewer.css b/browser/extensions/pdfjs/content/web/viewer.css index bf57df853431..80f7d6215bf8 100644 --- a/browser/extensions/pdfjs/content/web/viewer.css +++ b/browser/extensions/pdfjs/content/web/viewer.css @@ -1172,7 +1172,6 @@ html[dir='rtl'] .verticalToolbarSeparator { } .thumbnailImage { - transition-duration: 150ms; border: 1px solid transparent; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3); opacity: 0.8; @@ -1184,7 +1183,6 @@ html[dir='rtl'] .verticalToolbarSeparator { .thumbnailSelectionRing { border-radius: 2px; padding: 7px; - transition-duration: 150ms; } a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage, @@ -1400,10 +1398,6 @@ html[dir='rtl'] .attachmentsItem > button { .dialog .toolbarField { margin: 5px 0; } -.dialog .toolbarField:hover, -.dialog .toolbarField:focus { - border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42); -} .dialog .separator { display: block; @@ -1750,10 +1744,14 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * { body[data-mozPrintCallback] #printContainer { display: block; } - #printContainer canvas { + /* wrapper around (scaled) print canvas elements */ + #printContainer > div { position: relative; top: 0; left: 0; + overflow: hidden; + } + #printContainer canvas { display: block; } } diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index 68631c3204af..f20ed97e9a69 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -3520,10 +3520,15 @@ var PDFPageView = (function PDFPageViewClosure() { // better output until bug 811002 is fixed in FF. var PRINT_OUTPUT_SCALE = 2; var canvas = document.createElement('canvas'); + + // The logical size of the canvas. canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE; canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE; - canvas.style.width = (PRINT_OUTPUT_SCALE * viewport.width) + 'pt'; - canvas.style.height = (PRINT_OUTPUT_SCALE * viewport.height) + 'pt'; + + // The rendered size of the canvas, relative to the size of canvasWrapper. + canvas.style.width = (PRINT_OUTPUT_SCALE * 100) + '%'; + canvas.style.height = (PRINT_OUTPUT_SCALE * 100) + '%'; + var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' + (1 / PRINT_OUTPUT_SCALE) + ')'; CustomStyle.setProp('transform' , canvas, cssScale); @@ -4201,11 +4206,11 @@ var PDFViewer = (function pdfViewer() { PDFViewer.prototype = /** @lends PDFViewer.prototype */{ get pagesCount() { - return this.pages.length; + return this._pages.length; }, getPageView: function (index) { - return this.pages[index]; + return this._pages[index]; }, get currentPageNumber() { @@ -4289,9 +4294,9 @@ var PDFViewer = (function pdfViewer() { set pagesRotation(rotation) { this._pagesRotation = rotation; - for (var i = 0, l = this.pages.length; i < l; i++) { - var page = this.pages[i]; - page.update(page.scale, rotation); + for (var i = 0, l = this._pages.length; i < l; i++) { + var pageView = this._pages[i]; + pageView.update(pageView.scale, rotation); } this._setScale(this._currentScaleValue, true); @@ -4373,7 +4378,7 @@ var PDFViewer = (function pdfViewer() { annotationsLayerFactory: this }); bindOnAfterAndBeforeDraw(pageView); - this.pages.push(pageView); + this._pages.push(pageView); } // Fetch all the pages since the viewport is needed before printing @@ -4384,7 +4389,7 @@ var PDFViewer = (function pdfViewer() { var getPagesLeft = pagesCount; for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) { - var pageView = self.pages[pageNum - 1]; + var pageView = self._pages[pageNum - 1]; if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } @@ -4417,12 +4422,12 @@ var PDFViewer = (function pdfViewer() { }, _resetView: function () { - this.pages = []; + this._pages = []; this._currentPageNumber = 1; this._currentScale = UNKNOWN_SCALE; this._currentScaleValue = null; this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE); - this.location = null; + this._location = null; this._pagesRotation = 0; this._pagesRequests = []; @@ -4437,8 +4442,8 @@ var PDFViewer = (function pdfViewer() { return; } this.update(); - for (var i = 0, ii = this.pages.length; i < ii; i++) { - this.pages[i].updatePosition(); + for (var i = 0, ii = this._pages.length; i < ii; i++) { + this._pages[i].updatePosition(); } }, @@ -4463,18 +4468,18 @@ var PDFViewer = (function pdfViewer() { return; } - for (var i = 0, ii = this.pages.length; i < ii; i++) { - this.pages[i].update(newScale); + for (var i = 0, ii = this._pages.length; i < ii; i++) { + this._pages[i].update(newScale); } this._currentScale = newScale; if (!noScroll) { var page = this._currentPageNumber, dest; - if (this.location && !IGNORE_CURRENT_POSITION_ON_ZOOM && + if (this._location && !IGNORE_CURRENT_POSITION_ON_ZOOM && !(this.isInPresentationMode || this.isChangingPresentationMode)) { - page = this.location.pageNumber; - dest = [null, { name: 'XYZ' }, this.location.left, - this.location.top, null]; + page = this._location.pageNumber; + dest = [null, { name: 'XYZ' }, this._location.left, + this._location.top, null]; } this.scrollPageIntoView(page, dest); } @@ -4491,7 +4496,7 @@ var PDFViewer = (function pdfViewer() { if (scale > 0) { this._setScaleUpdatePages(scale, value, noScroll, false); } else { - var currentPage = this.pages[this._currentPageNumber - 1]; + var currentPage = this._pages[this._currentPageNumber - 1]; if (!currentPage) { return; } @@ -4541,7 +4546,7 @@ var PDFViewer = (function pdfViewer() { */ scrollPageIntoView: function PDFViewer_scrollPageIntoView(pageNumber, dest) { - var pageView = this.pages[pageNumber - 1]; + var pageView = this._pages[pageNumber - 1]; if (this.isInPresentationMode) { if (this.linkService.page !== pageView.id) { @@ -4644,7 +4649,7 @@ var PDFViewer = (function pdfViewer() { var pageNumber = firstPage.id; var pdfOpenParams = '#page=' + pageNumber; pdfOpenParams += '&zoom=' + normalizedScaleValue; - var currentPageView = this.pages[pageNumber - 1]; + var currentPageView = this._pages[pageNumber - 1]; var container = this.container; var topLeft = currentPageView.getPagePoint( (container.scrollLeft - firstPage.x), @@ -4653,7 +4658,7 @@ var PDFViewer = (function pdfViewer() { var intTop = Math.round(topLeft[1]); pdfOpenParams += ',' + intLeft + ',' + intTop; - this.location = { + this._location = { pageNumber: pageNumber, scale: normalizedScaleValue, top: intTop, @@ -4707,6 +4712,7 @@ var PDFViewer = (function pdfViewer() { var event = document.createEvent('UIEvents'); event.initUIEvent('updateviewarea', true, true, window, 0); + event.location = this._location; this.container.dispatchEvent(event); }, @@ -4733,22 +4739,22 @@ var PDFViewer = (function pdfViewer() { _getVisiblePages: function () { if (!this.isInPresentationMode) { - return getVisibleElements(this.container, this.pages, true); + return getVisibleElements(this.container, this._pages, true); } else { // The algorithm in getVisibleElements doesn't work in all browsers and // configurations when presentation mode is active. var visible = []; - var currentPage = this.pages[this._currentPageNumber - 1]; + var currentPage = this._pages[this._currentPageNumber - 1]; visible.push({ id: currentPage.id, view: currentPage }); return { first: currentPage, last: currentPage, views: visible }; } }, cleanup: function () { - for (var i = 0, ii = this.pages.length; i < ii; i++) { - if (this.pages[i] && - this.pages[i].renderingState !== RenderingStates.FINISHED) { - this.pages[i].reset(); + for (var i = 0, ii = this._pages.length; i < ii; i++) { + if (this._pages[i] && + this._pages[i].renderingState !== RenderingStates.FINISHED) { + this._pages[i].reset(); } } }, @@ -4779,7 +4785,7 @@ var PDFViewer = (function pdfViewer() { forceRendering: function (currentlyVisiblePages) { var visiblePages = currentlyVisiblePages || this._getVisiblePages(); var pageView = this.renderingQueue.getHighestPriority(visiblePages, - this.pages, + this._pages, this.scroll.down); if (pageView) { this._ensurePdfPageLoaded(pageView).then(function () { @@ -5042,12 +5048,11 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() { /** * @private */ - _getPageDrawContext: function PDFThumbnailView_getPageDrawContext() { + _getPageDrawContext: + function PDFThumbnailView_getPageDrawContext(noCtxScale) { var canvas = document.createElement('canvas'); canvas.id = this.renderingId; - canvas.width = this.canvasWidth; - canvas.height = this.canvasHeight; canvas.className = 'thumbnailImage'; canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas', {page: this.id}, 'Thumbnail of Page {{page}}')); @@ -5056,7 +5061,16 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() { this.div.setAttribute('data-loaded', true); this.ring.appendChild(canvas); - return canvas.getContext('2d'); + var ctx = canvas.getContext('2d'); + var outputScale = getOutputScale(ctx); + canvas.width = (this.canvasWidth * outputScale.sx) | 0; + canvas.height = (this.canvasHeight * outputScale.sy) | 0; + canvas.style.width = this.canvasWidth + 'px'; + canvas.style.height = this.canvasHeight + 'px'; + if (!noCtxScale && outputScale.scaled) { + ctx.scale(outputScale.sx, outputScale.sy); + } + return ctx; }, draw: function PDFThumbnailView_draw() { @@ -5139,7 +5153,7 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() { this.hasImage = true; this.renderingState = RenderingStates.FINISHED; - var ctx = this._getPageDrawContext(); + var ctx = this._getPageDrawContext(true); var canvas = ctx.canvas; if (img.width <= 2 * canvas.width) { @@ -5739,7 +5753,7 @@ var PDFViewerApplication = { newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2); newScale = Math.ceil(newScale * 10) / 10; newScale = Math.min(MAX_SCALE, newScale); - } while (--ticks && newScale < MAX_SCALE); + } while (--ticks > 0 && newScale < MAX_SCALE); this.setScale(newScale, true); }, @@ -5749,7 +5763,7 @@ var PDFViewerApplication = { newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2); newScale = Math.floor(newScale * 10) / 10; newScale = Math.max(MIN_SCALE, newScale); - } while (--ticks && newScale > MIN_SCALE); + } while (--ticks > 0 && newScale > MIN_SCALE); this.setScale(newScale, true); }, @@ -6691,6 +6705,35 @@ var PDFViewerApplication = { var body = document.querySelector('body'); body.setAttribute('data-mozPrintCallback', true); + + if (!this.hasEqualPageSizes) { + console.warn('Not all pages have the same size. The printed result ' + + 'may be incorrect!'); + } + + // Insert a @page + size rule to make sure that the page size is correctly + // set. Note that we assume that all pages have the same size, because + // variable-size pages are not supported yet (at least in Chrome & Firefox). + // TODO(robwu): Use named pages when size calculation bugs get resolved + // (e.g. https://crbug.com/355116) AND when support for named pages is + // added (http://www.w3.org/TR/css3-page/#using-named-pages). + // In browsers where @page + size is not supported (such as Firefox, + // https://bugzil.la/851441), the next stylesheet will be ignored and the + // user has to select the correct paper size in the UI if wanted. + this.pageStyleSheet = document.createElement('style'); + var pageSize = this.pdfViewer.getPageView(0).pdfPage.getViewport(1); + this.pageStyleSheet.textContent = + // "size: " is what we need. But also add "A4" because + // Firefox incorrectly reports support for the other value. + '@supports ((size:A4) and (size:1pt 1pt)) {' + + '@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' + + // The canvas and each ancestor node must have a height of 100% to make + // sure that each canvas is printed on exactly one page. + '#printContainer {height:100%}' + + '#printContainer > div {width:100% !important;height:100% !important;}' + + '}'; + body.appendChild(this.pageStyleSheet); + for (i = 0, ii = this.pagesCount; i < ii; ++i) { this.pdfViewer.getPageView(i).beforePrint(); } @@ -6700,12 +6743,30 @@ var PDFViewerApplication = { })); }, + // Whether all pages of the PDF have the same width and height. + get hasEqualPageSizes() { + var firstPage = this.pdfViewer.getPageView(0); + for (var i = 1, ii = this.pagesCount; i < ii; ++i) { + var pageView = this.pdfViewer.getPageView(i); + if (pageView.width !== firstPage.width || + pageView.height !== firstPage.height) { + return false; + } + } + return true; + }, + afterPrint: function pdfViewSetupAfterPrint() { var div = document.getElementById('printContainer'); while (div.hasChildNodes()) { div.removeChild(div.lastChild); } + if (this.pageStyleSheet && this.pageStyleSheet.parentNode) { + this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet); + this.pageStyleSheet = null; + } + this.printing = false; this.forceRendering(); }, @@ -7009,12 +7070,11 @@ function updateViewarea() { PDFViewerApplication.pdfViewer.update(); } -window.addEventListener('updateviewarea', function () { +window.addEventListener('updateviewarea', function (evt) { if (!PDFViewerApplication.initialized) { return; } - - var location = PDFViewerApplication.pdfViewer.location; + var location = evt.location; PDFViewerApplication.store.initializedPromise.then(function() { PDFViewerApplication.store.setMultiple({