From 7d23abf82e34f7ca87795fdcd572b1bf3992c39c Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 30 Nov 2015 15:53:49 -0500 Subject: [PATCH] Bug 1228603 - Update pdf.js to version 1.3.42. r=bdahl --HG-- extra : rebase_source : 83b4d456ae8aac695bd1b852b2fac80af83d68cb extra : source : 2f801d6ef06489fa9dfbdf160350fcd7e4afbc5d --- browser/extensions/pdfjs/README.mozilla | 2 +- browser/extensions/pdfjs/content/PdfJs.jsm | 5 + .../pdfjs/content/PdfjsChromeUtils.jsm | 4 + browser/extensions/pdfjs/content/build/pdf.js | 587 ++++++++++++------ .../pdfjs/content/build/pdf.worker.js | 337 ++++++---- .../extensions/pdfjs/content/web/viewer.js | 34 +- .../locales/en-US/pdfviewer/viewer.properties | 2 +- 7 files changed, 670 insertions(+), 301 deletions(-) diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index 760d465ad78f..0a09b37f4995 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.3.14 +Current extension version is: 1.3.42 diff --git a/browser/extensions/pdfjs/content/PdfJs.jsm b/browser/extensions/pdfjs/content/PdfJs.jsm index 4e4a209897bc..f01502c34fb5 100644 --- a/browser/extensions/pdfjs/content/PdfJs.jsm +++ b/browser/extensions/pdfjs/content/PdfJs.jsm @@ -12,6 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* jshint esnext:true */ +/* globals Components, Services, XPCOMUtils, PdfjsChromeUtils, + PdfjsContentUtils, DEFAULT_PREFERENCES, PdfStreamConverter */ + +'use strict'; var EXPORTED_SYMBOLS = ['PdfJs']; diff --git a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm index bb9fbe1b4312..77a02cc3cab7 100644 --- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm +++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm @@ -12,6 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* jshint esnext:true */ +/* globals Components, Services, XPCOMUtils, DEFAULT_PREFERENCES */ + +'use strict'; var EXPORTED_SYMBOLS = ['PdfjsChromeUtils']; diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index 61e3a737e85e..8dc750cbb6fd 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -20,8 +20,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '1.3.14'; -PDFJS.build = 'df46b64'; +PDFJS.version = '1.3.42'; +PDFJS.build = '84a47f8'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -60,6 +60,19 @@ var AnnotationType = { LINK: 3 }; +var AnnotationFlag = { + INVISIBLE: 0x01, + HIDDEN: 0x02, + PRINT: 0x04, + NOZOOM: 0x08, + NOROTATE: 0x10, + NOVIEW: 0x20, + READONLY: 0x40, + LOCKED: 0x80, + TOGGLENOVIEW: 0x100, + LOCKEDCONTENTS: 0x200 +}; + var AnnotationBorderStyleType = { SOLID: 1, DASHED: 2, @@ -1186,26 +1199,20 @@ PDFJS.createObjectURL = (function createObjectURLClosure() { }; })(); -function MessageHandler(name, comObj) { - this.name = name; +function MessageHandler(sourceName, targetName, comObj) { + this.sourceName = sourceName; + this.targetName = targetName; this.comObj = comObj; this.callbackIndex = 1; this.postMessageTransfers = true; var callbacksCapabilities = this.callbacksCapabilities = {}; var ah = this.actionHandler = {}; - ah['console_log'] = [function ahConsoleLog(data) { - console.log.apply(console, data); - }]; - ah['console_error'] = [function ahConsoleError(data) { - console.error.apply(console, data); - }]; - ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) { - UnsupportedManager.notify(data); - }]; - - comObj.onmessage = function messageHandlerComObjOnMessage(event) { + this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) { var data = event.data; + if (data.targetName !== this.sourceName) { + return; + } if (data.isReply) { var callbackId = data.callbackId; if (data.callbackId in callbacksCapabilities) { @@ -1222,10 +1229,14 @@ function MessageHandler(name, comObj) { } else if (data.action in ah) { var action = ah[data.action]; if (data.callbackId) { + var sourceName = this.sourceName; + var targetName = data.sourceName; Promise.resolve().then(function () { return action[0].call(action[1], data.data); }).then(function (result) { comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, isReply: true, callbackId: data.callbackId, data: result @@ -1236,6 +1247,8 @@ function MessageHandler(name, comObj) { reason = reason + ''; } comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, isReply: true, callbackId: data.callbackId, error: reason @@ -1247,7 +1260,8 @@ function MessageHandler(name, comObj) { } else { error('Unknown action from worker: ' + data.action); } - }; + }.bind(this); + comObj.addEventListener('message', this._onComObjOnMessage); } MessageHandler.prototype = { @@ -1266,6 +1280,8 @@ MessageHandler.prototype = { */ send: function messageHandlerSend(actionName, data, transfers) { var message = { + sourceName: this.sourceName, + targetName: this.targetName, action: actionName, data: data }; @@ -1283,6 +1299,8 @@ MessageHandler.prototype = { function messageHandlerSendWithPromise(actionName, data, transfers) { var callbackId = this.callbackIndex++; var message = { + sourceName: this.sourceName, + targetName: this.targetName, action: actionName, data: data, callbackId: callbackId @@ -1308,6 +1326,10 @@ MessageHandler.prototype = { } else { this.comObj.postMessage(message); } + }, + + destroy: function () { + this.comObj.removeEventListener('message', this._onComObjOnMessage); } }; @@ -1476,6 +1498,9 @@ PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ? /** * (Deprecated) Opens external links in a new window if enabled. * The default behavior opens external links in the PDF.js window. + * + * NOTE: This property has been deprecated, please use + * `PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK` instead. * @var {boolean} */ PDFJS.openExternalLinksInNewWindow = ( @@ -1525,6 +1550,8 @@ PDFJS.isEvalSupported = (PDFJS.isEvalSupported === undefined ? * @property {number} rangeChunkSize - Optional parameter to specify * maximum number of bytes fetched per range request. The default value is * 2^16 = 65536. + * @property {PDFWorker} worker - The worker that will be used for the loading + * and parsing of the PDF data. */ /** @@ -1587,7 +1614,6 @@ PDFJS.getDocument = function getDocument(src, task.onPassword = passwordCallback || null; task.onProgress = progressCallback || null; - var workerInitializedCapability, transport; var source; if (typeof src === 'string') { source = { url: src }; @@ -1608,12 +1634,18 @@ PDFJS.getDocument = function getDocument(src, } var params = {}; + var rangeTransport = null; + var worker = null; for (var key in source) { if (key === 'url' && typeof window !== 'undefined') { // The full path is required in the 'url' field. params[key] = combineUrl(window.location.href, source[key]); continue; } else if (key === 'range') { + rangeTransport = source[key]; + continue; + } else if (key === 'worker') { + worker = source[key]; continue; } else if (key === 'data' && !(source[key] instanceof Uint8Array)) { // Converting string or array-like data to Uint8Array. @@ -1634,27 +1666,98 @@ PDFJS.getDocument = function getDocument(src, params[key] = source[key]; } - params.rangeChunkSize = source.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; + params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE; - workerInitializedCapability = createPromiseCapability(); - transport = new WorkerTransport(workerInitializedCapability, source.range); - workerInitializedCapability.promise.then(function transportInitialized() { - transport.fetchDocument(task, params); - }); - task._transport = transport; + if (!worker) { + // Worker was not provided -- creating and owning our own. + worker = new PDFWorker(); + task._worker = worker; + } + var docId = task.docId; + worker.promise.then(function () { + if (task.destroyed) { + throw new Error('Loading aborted'); + } + return _fetchDocument(worker, params, rangeTransport, docId).then( + function (workerId) { + if (task.destroyed) { + throw new Error('Loading aborted'); + } + var messageHandler = new MessageHandler(docId, workerId, worker.port); + messageHandler.send('Ready', null); + var transport = new WorkerTransport(messageHandler, task, rangeTransport); + task._transport = transport; + }); + }, task._capability.reject); return task; }; +/** + * Starts fetching of specified PDF document/data. + * @param {PDFWorker} worker + * @param {Object} source + * @param {PDFDataRangeTransport} pdfDataRangeTransport + * @param {string} docId Unique document id, used as MessageHandler id. + * @returns {Promise} The promise, which is resolved when worker id of + * MessageHandler is known. + * @private + */ +function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { + if (worker.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + + source.disableAutoFetch = PDFJS.disableAutoFetch; + source.disableStream = PDFJS.disableStream; + source.chunkedViewerLoading = !!pdfDataRangeTransport; + if (pdfDataRangeTransport) { + source.length = pdfDataRangeTransport.length; + source.initialData = pdfDataRangeTransport.initialData; + } + return worker.messageHandler.sendWithPromise('GetDocRequest', { + docId: docId, + source: source, + disableRange: PDFJS.disableRange, + maxImageSize: PDFJS.maxImageSize, + cMapUrl: PDFJS.cMapUrl, + cMapPacked: PDFJS.cMapPacked, + disableFontFace: PDFJS.disableFontFace, + disableCreateObjectURL: PDFJS.disableCreateObjectURL, + verbosity: PDFJS.verbosity + }).then(function (workerId) { + if (worker.destroyed) { + throw new Error('Worker was destroyed'); + } + return workerId; + }); +} + /** * PDF document loading operation. * @class * @alias PDFDocumentLoadingTask */ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { + var nextDocumentId = 0; + + /** @constructs PDFDocumentLoadingTask */ function PDFDocumentLoadingTask() { this._capability = createPromiseCapability(); this._transport = null; + this._worker = null; + + /** + * Unique document loading task id -- used in MessageHandlers. + * @type {string} + */ + this.docId = 'd' + (nextDocumentId++); + + /** + * Shows if loading task is destroyed. + * @type {boolean} + */ + this.destroyed = false; /** * Callback to request a password if wrong or no password was provided. @@ -1686,7 +1789,17 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { * is completed. */ destroy: function () { - return this._transport.destroy(); + this.destroyed = true; + + var transportDestroyed = !this._transport ? Promise.resolve() : + this._transport.destroy(); + return transportDestroyed.then(function () { + this._transport = null; + if (this._worker) { + this._worker.destroy(); + this._worker = null; + } + }.bind(this)); }, /** @@ -1915,12 +2028,20 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { * Destroys current document instance and terminates worker. */ destroy: function PDFDocumentProxy_destroy() { - return this.transport.destroy(); + return this.loadingTask.destroy(); } }; return PDFDocumentProxy; })(); +/** + * Page getTextContent parameters. + * + * @typedef {Object} getTextContentParameters + * @param {boolean} normalizeWhitespace - replaces all occurrences of + * whitespace with standard spaces (0x20). The default value is `false`. + */ + /** * Page text content. * @@ -1952,6 +2073,16 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { * @property {string} fontFamily - possible font family */ +/** + * Page annotation parameters. + * + * @typedef {Object} GetAnnotationsParameters + * @param {string} intent - Determines the annotations that will be fetched, + * can be either 'display' (viewable annotations) or 'print' + * (printable annotations). + * If the parameter is omitted, all annotations are fetched. + */ + /** * Page render parameters. * @@ -2040,12 +2171,17 @@ var PDFPageProxy = (function PDFPageProxyClosure() { return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0); }, /** + * @param {GetAnnotationsParameters} params - Annotation parameters. * @return {Promise} A promise that is resolved with an {Array} of the * annotation objects. */ - getAnnotations: function PDFPageProxy_getAnnotations() { - if (!this.annotationsPromise) { - this.annotationsPromise = this.transport.getAnnotations(this.pageIndex); + getAnnotations: function PDFPageProxy_getAnnotations(params) { + var intent = (params && params.intent) || null; + + if (!this.annotationsPromise || this.annotationsIntent !== intent) { + this.annotationsPromise = this.transport.getAnnotations(this.pageIndex, + intent); + this.annotationsIntent = intent; } return this.annotationsPromise; }, @@ -2184,12 +2320,16 @@ var PDFPageProxy = (function PDFPageProxyClosure() { }, /** + * @param {getTextContentParameters} params - getTextContent parameters. * @return {Promise} That is resolved a {@link TextContent} * object that represent the page text content. */ - getTextContent: function PDFPageProxy_getTextContent() { + getTextContent: function PDFPageProxy_getTextContent(params) { + var normalizeWhitespace = (params && params.normalizeWhitespace) || false; + return this.transport.messageHandler.sendWithPromise('GetTextContent', { - pageIndex: this.pageNumber - 1 + pageIndex: this.pageNumber - 1, + normalizeWhitespace: normalizeWhitespace, }); }, @@ -2296,17 +2436,202 @@ var PDFPageProxy = (function PDFPageProxyClosure() { return PDFPageProxy; })(); +/** + * PDF.js web worker abstraction, it controls instantiation of PDF documents and + * WorkerTransport for them. If creation of a web worker is not possible, + * a "fake" worker will be used instead. + * @class + */ +var PDFWorker = (function PDFWorkerClosure() { + var nextFakeWorkerId = 0; + + // Loads worker code into main thread. + function setupFakeWorkerGlobal() { + if (!PDFJS.fakeWorkerFilesLoadedCapability) { + PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability(); + // In the developer build load worker_loader which in turn loads all the + // other files and resolves the promise. In production only the + // pdf.worker.js file is needed. + Util.loadScript(PDFJS.workerSrc, function() { + PDFJS.fakeWorkerFilesLoadedCapability.resolve(); + }); + } + return PDFJS.fakeWorkerFilesLoadedCapability.promise; + } + + function PDFWorker(name) { + this.name = name; + this.destroyed = false; + + this._readyCapability = createPromiseCapability(); + this._port = null; + this._webWorker = null; + this._messageHandler = null; + this._initialize(); + } + + PDFWorker.prototype = /** @lends PDFWorker.prototype */ { + get promise() { + return this._readyCapability.promise; + }, + + get port() { + return this._port; + }, + + get messageHandler() { + return this._messageHandler; + }, + + _initialize: function PDFWorker_initialize() { + // 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 v.15.) + if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') { + var workerSrc = PDFJS.workerSrc; + if (!workerSrc) { + error('No PDFJS.workerSrc specified'); + } + + try { + // Some versions of FF can't create a worker on localhost, see: + // https://bugzilla.mozilla.org/show_bug.cgi?id=683280 + var worker = new Worker(workerSrc); + var messageHandler = new MessageHandler('main', 'worker', worker); + + messageHandler.on('test', function PDFWorker_test(data) { + if (this.destroyed) { + this._readyCapability.reject(new Error('Worker was destroyed')); + messageHandler.destroy(); + worker.terminate(); + return; // worker was destroyed + } + var supportTypedArray = data && data.supportTypedArray; + if (supportTypedArray) { + this._messageHandler = messageHandler; + this._port = worker; + this._webWorker = worker; + if (!data.supportTransfers) { + PDFJS.postMessageTransfers = false; + } + this._readyCapability.resolve(); + } else { + this._setupFakeWorker(); + messageHandler.destroy(); + worker.terminate(); + } + }.bind(this)); + + messageHandler.on('console_log', function (data) { + console.log.apply(console, data); + }); + messageHandler.on('console_error', function (data) { + console.error.apply(console, data); + }); + messageHandler.on('_unsupported_feature', function (data) { + UnsupportedManager.notify(data); + }); + + var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]); + // Some versions of Opera throw a DATA_CLONE_ERR on serializing the + // typed array. Also, checking if we can use transfers. + try { + messageHandler.send('test', testObj, [testObj.buffer]); + } catch (ex) { + info('Cannot use postMessage transfers'); + testObj[0] = 0; + messageHandler.send('test', testObj); + } + return; + } catch (e) { + info('The worker has been disabled.'); + } + } + // Either workers are disabled, not supported or have thrown an exception. + // Thus, we fallback to a faked worker. + this._setupFakeWorker(); + }, + + _setupFakeWorker: function PDFWorker_setupFakeWorker() { + warn('Setting up fake worker.'); + globalScope.PDFJS.disableWorker = true; + + setupFakeWorkerGlobal().then(function () { + if (this.destroyed) { + this._readyCapability.reject(new Error('Worker was destroyed')); + return; + } + + // If we don't use a worker, just post/sendMessage to the main thread. + var port = { + _listeners: [], + postMessage: function (obj) { + var e = {data: obj}; + this._listeners.forEach(function (listener) { + listener.call(this, e); + }, this); + }, + addEventListener: function (name, listener) { + this._listeners.push(listener); + }, + removeEventListener: function (name, listener) { + var i = this._listeners.indexOf(listener); + this._listeners.splice(i, 1); + }, + terminate: function () {} + }; + this._port = port; + + // All fake workers use the same port, making id unique. + var id = 'fake' + (nextFakeWorkerId++); + + // If the main thread is our worker, setup the handling for the + // messages -- the main thread sends to it self. + var workerHandler = new MessageHandler(id + '_worker', id, port); + PDFJS.WorkerMessageHandler.setup(workerHandler, port); + + var messageHandler = new MessageHandler(id, id + '_worker', port); + this._messageHandler = messageHandler; + this._readyCapability.resolve(); + }.bind(this)); + }, + + /** + * Destroys the worker instance. + */ + destroy: function PDFWorker_destroy() { + this.destroyed = true; + if (this._webWorker) { + // We need to terminate only web worker created resource. + this._webWorker.terminate(); + this._webWorker = null; + } + this._port = null; + if (this._messageHandler) { + this._messageHandler.destroy(); + this._messageHandler = null; + } + } + }; + + return PDFWorker; +})(); +PDFJS.PDFWorker = PDFWorker; + /** * For internal use only. * @ignore */ var WorkerTransport = (function WorkerTransportClosure() { - function WorkerTransport(workerInitializedCapability, pdfDataRangeTransport) { + function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport) { + this.messageHandler = messageHandler; + this.loadingTask = loadingTask; this.pdfDataRangeTransport = pdfDataRangeTransport; - this.workerInitializedCapability = workerInitializedCapability; this.commonObjs = new PDFObjects(); + this.fontLoader = new FontLoader(loadingTask.docId); - this.loadingTask = null; this.destroyed = false; this.destroyCapability = null; @@ -2314,56 +2639,7 @@ var WorkerTransport = (function WorkerTransportClosure() { this.pagePromises = []; this.downloadInfoCapability = createPromiseCapability(); - // 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 (!workerSrc) { - error('No PDFJS.workerSrc specified'); - } - - try { - // Some versions of FF can't create a worker on localhost, see: - // https://bugzilla.mozilla.org/show_bug.cgi?id=683280 - var worker = new Worker(workerSrc); - var messageHandler = new MessageHandler('main', worker); - this.messageHandler = messageHandler; - - messageHandler.on('test', function transportTest(data) { - var supportTypedArray = data && data.supportTypedArray; - if (supportTypedArray) { - this.worker = worker; - if (!data.supportTransfers) { - PDFJS.postMessageTransfers = false; - } - this.setupMessageHandler(messageHandler); - workerInitializedCapability.resolve(); - } else { - this.setupFakeWorker(); - } - }.bind(this)); - - var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]); - // Some versions of Opera throw a DATA_CLONE_ERR on serializing the - // typed array. Also, checking if we can use transfers. - try { - messageHandler.send('test', testObj, [testObj.buffer]); - } catch (ex) { - info('Cannot use postMessage transfers'); - testObj[0] = 0; - messageHandler.send('test', testObj); - } - return; - } catch (e) { - info('The worker has been disabled.'); - } - } - // Either workers are disabled, not supported or have thrown an exception. - // Thus, we fallback to a faked worker. - this.setupFakeWorker(); + this.setupMessageHandler(); } WorkerTransport.prototype = { destroy: function WorkerTransport_destroy() { @@ -2389,56 +2665,23 @@ var WorkerTransport = (function WorkerTransportClosure() { var terminated = this.messageHandler.sendWithPromise('Terminate', null); waitOn.push(terminated); Promise.all(waitOn).then(function () { - FontLoader.clear(); - if (self.worker) { - self.worker.terminate(); - } + self.fontLoader.clear(); if (self.pdfDataRangeTransport) { self.pdfDataRangeTransport.abort(); self.pdfDataRangeTransport = null; } - self.messageHandler = null; + if (self.messageHandler) { + self.messageHandler.destroy(); + self.messageHandler = null; + } self.destroyCapability.resolve(); }, this.destroyCapability.reject); return this.destroyCapability.promise; }, - setupFakeWorker: function WorkerTransport_setupFakeWorker() { - globalScope.PDFJS.disableWorker = true; - - if (!PDFJS.fakeWorkerFilesLoadedCapability) { - PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability(); - // In the developer build load worker_loader which in turn loads all the - // other files and resolves the promise. In production only the - // pdf.worker.js file is needed. - Util.loadScript(PDFJS.workerSrc, function() { - PDFJS.fakeWorkerFilesLoadedCapability.resolve(); - }); - } - PDFJS.fakeWorkerFilesLoadedCapability.promise.then(function () { - warn('Setting up fake worker.'); - // If we don't use a worker, just post/sendMessage to the main thread. - var fakeWorker = { - postMessage: function WorkerTransport_postMessage(obj) { - fakeWorker.onmessage({data: obj}); - }, - terminate: function WorkerTransport_terminate() {} - }; - - 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. - PDFJS.WorkerMessageHandler.setup(messageHandler); - - this.workerInitializedCapability.resolve(); - }.bind(this)); - }, - setupMessageHandler: - function WorkerTransport_setupMessageHandler(messageHandler) { - this.messageHandler = messageHandler; + function WorkerTransport_setupMessageHandler() { + var messageHandler = this.messageHandler; function updatePassword(password) { messageHandler.send('UpdatePassword', password); @@ -2578,7 +2821,7 @@ var WorkerTransport = (function WorkerTransportClosure() { font = new FontFaceObject(exportedData); } - FontLoader.bind( + this.fontLoader.bind( [font], function fontReady(fontObjs) { this.commonObjs.resolve(id, font); @@ -2703,34 +2946,6 @@ var WorkerTransport = (function WorkerTransportClosure() { }, this); }, - fetchDocument: function WorkerTransport_fetchDocument(loadingTask, source) { - if (this.destroyed) { - loadingTask._capability.reject(new Error('Loading aborted')); - this.destroyCapability.resolve(); - return; - } - - this.loadingTask = loadingTask; - - source.disableAutoFetch = PDFJS.disableAutoFetch; - source.disableStream = PDFJS.disableStream; - source.chunkedViewerLoading = !!this.pdfDataRangeTransport; - if (this.pdfDataRangeTransport) { - source.length = this.pdfDataRangeTransport.length; - source.initialData = this.pdfDataRangeTransport.initialData; - } - this.messageHandler.send('GetDocRequest', { - source: source, - disableRange: PDFJS.disableRange, - maxImageSize: PDFJS.maxImageSize, - cMapUrl: PDFJS.cMapUrl, - cMapPacked: PDFJS.cMapPacked, - disableFontFace: PDFJS.disableFontFace, - disableCreateObjectURL: PDFJS.disableCreateObjectURL, - verbosity: PDFJS.verbosity - }); - }, - getData: function WorkerTransport_getData() { return this.messageHandler.sendWithPromise('GetData', null); }, @@ -2763,9 +2978,11 @@ var WorkerTransport = (function WorkerTransportClosure() { return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref }); }, - getAnnotations: function WorkerTransport_getAnnotations(pageIndex) { - return this.messageHandler.sendWithPromise('GetAnnotations', - { pageIndex: pageIndex }); + getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) { + return this.messageHandler.sendWithPromise('GetAnnotations', { + pageIndex: pageIndex, + intent: intent, + }); }, getDestinations: function WorkerTransport_getDestinations() { @@ -2773,7 +2990,7 @@ var WorkerTransport = (function WorkerTransportClosure() { }, getDestination: function WorkerTransport_getDestination(id) { - return this.messageHandler.sendWithPromise('GetDestination', { id: id } ); + return this.messageHandler.sendWithPromise('GetDestination', { id: id }); }, getAttachments: function WorkerTransport_getAttachments() { @@ -2812,7 +3029,7 @@ var WorkerTransport = (function WorkerTransportClosure() { } } this.commonObjs.clear(); - FontLoader.clear(); + this.fontLoader.clear(); }.bind(this)); } }; @@ -6161,12 +6378,16 @@ var TilingPattern = (function TilingPatternClosure() { PDFJS.disableFontFace = false; -var FontLoader = { +function FontLoader(docId) { + this.docId = docId; + this.styleElement = null; +} +FontLoader.prototype = { insertRule: function fontLoaderInsertRule(rule) { - var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG'); + var styleElement = this.styleElement; if (!styleElement) { - styleElement = document.createElement('style'); - styleElement.id = 'PDFJS_FONT_STYLE_TAG'; + styleElement = this.styleElement = document.createElement('style'); + styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId; document.documentElement.getElementsByTagName('head')[0].appendChild( styleElement); } @@ -6176,7 +6397,7 @@ var FontLoader = { }, clear: function fontLoaderClear() { - var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG'); + var styleElement = this.styleElement; if (styleElement) { styleElement.parentNode.removeChild(styleElement); } @@ -6191,7 +6412,10 @@ var FontLoader = { } font.attached = true; - font.bindDOM() + var rule = font.createFontFaceRule(); + if (rule) { + this.insertRule(rule); + } } setTimeout(callback); @@ -6199,20 +6423,31 @@ var FontLoader = { }; var FontFaceObject = (function FontFaceObjectClosure() { - function FontFaceObject(name, file, properties) { + function FontFaceObject(translatedData) { this.compiledGlyphs = {}; - if (arguments.length === 1) { - // importing translated data - var data = arguments[0]; - for (var i in data) { - this[i] = data[i]; - } - return; + // importing translated data + for (var i in translatedData) { + this[i] = translatedData[i]; } } + Object.defineProperty(FontFaceObject, 'isEvalSupported', { + get: function () { + var evalSupport = false; + if (PDFJS.isEvalSupported) { + try { + /* jshint evil: true */ + new Function(''); + evalSupport = true; + } catch (e) {} + } + return shadow(this, 'isEvalSupported', evalSupport); + }, + enumerable: true, + configurable: true + }); FontFaceObject.prototype = { - bindDOM: function FontFaceObject_bindDOM() { + createFontFaceRule: function FontFaceObject_createFontFaceRule() { if (!this.data) { return null; } @@ -6229,7 +6464,6 @@ var FontFaceObject = (function FontFaceObjectClosure() { var url = ('url(data:' + this.mimetype + ';base64,' + window.btoa(data) + ');'); var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}'; - FontLoader.insertRule(rule); if (PDFJS.pdfBug && 'FontInspector' in globalScope && globalScope['FontInspector'].enabled) { @@ -6239,13 +6473,14 @@ var FontFaceObject = (function FontFaceObjectClosure() { return rule; }, - getPathGenerator: function FontLoader_getPathGenerator(objs, character) { + getPathGenerator: + function FontFaceObject_getPathGenerator(objs, character) { if (!(character in this.compiledGlyphs)) { var cmds = objs.get(this.loadedName + '_path_' + character); var current, i, len; // If we can, compile cmds into JS for MAXIMUM SPEED - if (FontLoader.isEvalSupported) { + if (FontFaceObject.isEvalSupported) { var args, js = ''; for (i = 0, len = cmds.length; i < len; i++) { current = cmds[i]; diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index 306febbe93b2..287f454b36e6 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -20,8 +20,8 @@ if (typeof PDFJS === 'undefined') { (typeof window !== 'undefined' ? window : this).PDFJS = {}; } -PDFJS.version = '1.3.14'; -PDFJS.build = 'df46b64'; +PDFJS.version = '1.3.42'; +PDFJS.build = '84a47f8'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it @@ -60,6 +60,19 @@ var AnnotationType = { LINK: 3 }; +var AnnotationFlag = { + INVISIBLE: 0x01, + HIDDEN: 0x02, + PRINT: 0x04, + NOZOOM: 0x08, + NOROTATE: 0x10, + NOVIEW: 0x20, + READONLY: 0x40, + LOCKED: 0x80, + TOGGLENOVIEW: 0x100, + LOCKEDCONTENTS: 0x200 +}; + var AnnotationBorderStyleType = { SOLID: 1, DASHED: 2, @@ -1186,26 +1199,20 @@ PDFJS.createObjectURL = (function createObjectURLClosure() { }; })(); -function MessageHandler(name, comObj) { - this.name = name; +function MessageHandler(sourceName, targetName, comObj) { + this.sourceName = sourceName; + this.targetName = targetName; this.comObj = comObj; this.callbackIndex = 1; this.postMessageTransfers = true; var callbacksCapabilities = this.callbacksCapabilities = {}; var ah = this.actionHandler = {}; - ah['console_log'] = [function ahConsoleLog(data) { - console.log.apply(console, data); - }]; - ah['console_error'] = [function ahConsoleError(data) { - console.error.apply(console, data); - }]; - ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) { - UnsupportedManager.notify(data); - }]; - - comObj.onmessage = function messageHandlerComObjOnMessage(event) { + this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) { var data = event.data; + if (data.targetName !== this.sourceName) { + return; + } if (data.isReply) { var callbackId = data.callbackId; if (data.callbackId in callbacksCapabilities) { @@ -1222,10 +1229,14 @@ function MessageHandler(name, comObj) { } else if (data.action in ah) { var action = ah[data.action]; if (data.callbackId) { + var sourceName = this.sourceName; + var targetName = data.sourceName; Promise.resolve().then(function () { return action[0].call(action[1], data.data); }).then(function (result) { comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, isReply: true, callbackId: data.callbackId, data: result @@ -1236,6 +1247,8 @@ function MessageHandler(name, comObj) { reason = reason + ''; } comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, isReply: true, callbackId: data.callbackId, error: reason @@ -1247,7 +1260,8 @@ function MessageHandler(name, comObj) { } else { error('Unknown action from worker: ' + data.action); } - }; + }.bind(this); + comObj.addEventListener('message', this._onComObjOnMessage); } MessageHandler.prototype = { @@ -1266,6 +1280,8 @@ MessageHandler.prototype = { */ send: function messageHandlerSend(actionName, data, transfers) { var message = { + sourceName: this.sourceName, + targetName: this.targetName, action: actionName, data: data }; @@ -1283,6 +1299,8 @@ MessageHandler.prototype = { function messageHandlerSendWithPromise(actionName, data, transfers) { var callbackId = this.callbackIndex++; var message = { + sourceName: this.sourceName, + targetName: this.targetName, action: actionName, data: data, callbackId: callbackId @@ -1308,6 +1326,10 @@ MessageHandler.prototype = { } else { this.comObj.postMessage(message); } + }, + + destroy: function () { + this.comObj.removeEventListener('message', this._onComObjOnMessage); } }; @@ -1861,6 +1883,10 @@ var BasePdfManager = (function BasePdfManagerClosure() { } BasePdfManager.prototype = { + get docId() { + return this._docId; + }, + onLoadedStream: function BasePdfManager_onLoadedStream() { throw new NotImplementedException(); }, @@ -1922,7 +1948,8 @@ var BasePdfManager = (function BasePdfManagerClosure() { })(); var LocalPdfManager = (function LocalPdfManagerClosure() { - function LocalPdfManager(data, password) { + function LocalPdfManager(docId, data, password) { + this._docId = docId; var stream = new Stream(data); this.pdfDocument = new PDFDocument(this, stream, password); this._loadedStreamCapability = createPromiseCapability(); @@ -1973,8 +2000,8 @@ var LocalPdfManager = (function LocalPdfManagerClosure() { })(); var NetworkPdfManager = (function NetworkPdfManagerClosure() { - function NetworkPdfManager(args, msgHandler) { - + function NetworkPdfManager(docId, args, msgHandler) { + this._docId = docId; this.msgHandler = msgHandler; var params = { @@ -2251,7 +2278,8 @@ var Page = (function PageClosure() { }); }, - extractTextContent: function Page_extractTextContent(task) { + extractTextContent: function Page_extractTextContent(task, + normalizeWhitespace) { var handler = { on: function nullHandlerOn() {}, send: function nullHandlerSend() {} @@ -2281,14 +2309,22 @@ var Page = (function PageClosure() { return partialEvaluator.getTextContent(contentStream, task, - self.resources); + self.resources, + /* stateManager = */ null, + normalizeWhitespace); }); }, - getAnnotationsData: function Page_getAnnotationsData() { + getAnnotationsData: function Page_getAnnotationsData(intent) { var annotations = this.annotations; var annotationsData = []; for (var i = 0, n = annotations.length; i < n; ++i) { + if (intent) { + if (!(intent === 'display' && annotations[i].viewable) && + !(intent === 'print' && annotations[i].printable)) { + continue; + } + } annotationsData.push(annotations[i].data); } return annotationsData; @@ -2301,8 +2337,7 @@ var Page = (function PageClosure() { for (var i = 0, n = annotationRefs.length; i < n; ++i) { var annotationRef = annotationRefs[i]; var annotation = annotationFactory.create(this.xref, annotationRef); - if (annotation && - (annotation.isViewable() || annotation.isPrintable())) { + if (annotation) { annotations.push(annotation); } } @@ -4511,7 +4546,9 @@ var Annotation = (function AnnotationClosure() { var data = this.data = {}; data.subtype = dict.get('Subtype').name; - data.annotationFlags = dict.get('F'); + + this.setFlags(dict.get('F')); + data.annotationFlags = this.flags; this.setRectangle(dict.get('Rect')); data.rect = this.rectangle; @@ -4528,6 +4565,64 @@ var Annotation = (function AnnotationClosure() { } Annotation.prototype = { + /** + * @return {boolean} + */ + get viewable() { + if (this.flags) { + return !this.hasFlag(AnnotationFlag.INVISIBLE) && + !this.hasFlag(AnnotationFlag.HIDDEN) && + !this.hasFlag(AnnotationFlag.NOVIEW); + } + return true; + }, + + /** + * @return {boolean} + */ + get printable() { + if (this.flags) { + return this.hasFlag(AnnotationFlag.PRINT) && + !this.hasFlag(AnnotationFlag.INVISIBLE) && + !this.hasFlag(AnnotationFlag.HIDDEN); + } + return false; + }, + + /** + * Set the flags. + * + * @public + * @memberof Annotation + * @param {number} flags - Unsigned 32-bit integer specifying annotation + * characteristics + * @see {@link shared/util.js} + */ + setFlags: function Annotation_setFlags(flags) { + if (isInt(flags)) { + this.flags = flags; + } else { + this.flags = 0; + } + }, + + /** + * Check if a provided flag is set. + * + * @public + * @memberof Annotation + * @param {number} flag - Hexadecimal representation for an annotation + * characteristic + * @return {boolean} + * @see {@link shared/util.js} + */ + hasFlag: function Annotation_hasFlag(flag) { + if (this.flags) { + return (this.flags & flag) > 0; + } + return false; + }, + /** * Set the rectangle. * @@ -4627,32 +4722,6 @@ var Annotation = (function AnnotationClosure() { } }, - isInvisible: function Annotation_isInvisible() { - var data = this.data; - return !!(data && - data.annotationFlags && // Default: not invisible - data.annotationFlags & 0x1); // Invisible - }, - - isViewable: function Annotation_isViewable() { - var data = this.data; - return !!(!this.isInvisible() && - data && - (!data.annotationFlags || - !(data.annotationFlags & 0x22)) && // Hidden or NoView - data.rect); // rectangle is necessary - }, - - isPrintable: function Annotation_isPrintable() { - var data = this.data; - return !!(!this.isInvisible() && - data && - data.annotationFlags && // Default: not printable - data.annotationFlags & 0x4 && // Print - !(data.annotationFlags & 0x2) && // Hidden - data.rect); // rectangle is necessary - }, - loadResources: function Annotation_loadResources(keys) { return new Promise(function (resolve, reject) { this.appearance.dict.getAsync('Resources').then(function (resources) { @@ -4719,8 +4788,8 @@ var Annotation = (function AnnotationClosure() { var annotationPromises = []; for (var i = 0, n = annotations.length; i < n; ++i) { - if (intent === 'display' && annotations[i].isViewable() || - intent === 'print' && annotations[i].isPrintable()) { + if (intent === 'display' && annotations[i].viewable || + intent === 'print' && annotations[i].printable) { annotationPromises.push( annotations[i].getOperatorList(partialEvaluator, task)); } @@ -4896,6 +4965,12 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() { data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0; this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty; + // Hide unsupported Widget signatures. + if (data.fieldType === 'Sig') { + warn('unimplemented annotation type: Widget signature'); + this.setFlags(AnnotationFlag.HIDDEN); + } + // Building the full field name by collecting the field and // its ancestors 'T' data and joining them using '.'. var fieldName = []; @@ -4929,17 +5004,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() { data.fullName = fieldName.join('.'); } - var parent = Annotation.prototype; - Util.inherit(WidgetAnnotation, Annotation, { - isViewable: function WidgetAnnotation_isViewable() { - if (this.data.fieldType === 'Sig') { - warn('unimplemented annotation type: Widget signature'); - return false; - } - - return parent.isViewable.call(this); - } - }); + Util.inherit(WidgetAnnotation, Annotation, {}); return WidgetAnnotation; })(); @@ -5038,7 +5103,7 @@ var LinkAnnotation = (function LinkAnnotationClosure() { if (!isValidUrl(url, false)) { url = ''; } - // According to ISO 32000-1:2008, section 12.6.4.7, + // 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 { @@ -10562,6 +10627,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return translated.loadType3Data(self, resources, operatorList, task). then(function () { return translated; + }, function (reason) { + return new TranslatedFont('g_font_error', + new ErrorFont('Type3 font load error: ' + reason), translated.font); }); }).then(function (translated) { state.font = translated.font; @@ -10770,7 +10838,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { // Keep track of each font we translated so the caller can // load them asynchronously before calling display on a page. - font.loadedName = 'g_font_' + (fontRefIsDict ? + font.loadedName = 'g_' + this.pdfManager.docId + '_f' + (fontRefIsDict ? fontName.replace(/\W/g, '') : fontID); font.translated = fontCapability.promise; @@ -11149,12 +11217,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { }); }, - getTextContent: function PartialEvaluator_getTextContent(stream, task, - resources, - stateManager) { + getTextContent: + function PartialEvaluator_getTextContent(stream, task, resources, + stateManager, + normalizeWhitespace) { stateManager = (stateManager || new StateManager(new TextState())); + var WhitespaceRegexp = /\s/g; + var textContent = { items: [], styles: Object.create(null) @@ -11268,11 +11339,23 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return textContentItem; } + function replaceWhitespace(str) { + // Replaces all whitespaces with standard spaces (0x20), to avoid + // alignment issues between the textLayer and the canvas if the text + // contains e.g. tabs (fixes issue6612.pdf). + var i = 0, ii = str.length, code; + while (i < ii && (code = str.charCodeAt(i)) >= 0x20 && code <= 0x7F) { + i++; + } + return (i < ii ? str.replace(WhitespaceRegexp, ' ') : str); + } + function runBidiTransform(textChunk) { var str = textChunk.str.join(''); var bidiResult = PDFJS.bidi(str, -1, textChunk.vertical); return { - str: bidiResult.str, + str: (normalizeWhitespace ? replaceWhitespace(bidiResult.str) : + bidiResult.str), dir: bidiResult.dir, width: textChunk.width, height: textChunk.height, @@ -11593,8 +11676,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } return self.getTextContent(xobj, task, - xobj.dict.get('Resources') || resources, stateManager). - then(function (formTextContent) { + xobj.dict.get('Resources') || resources, stateManager, + normalizeWhitespace).then(function (formTextContent) { Util.appendToArray(textContent.items, formTextContent.items); Util.extendObj(textContent.styles, formTextContent.styles); stateManager.restore(); @@ -33837,12 +33920,51 @@ var WorkerTask = (function WorkerTaskClosure() { })(); var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { - setup: function wphSetup(handler) { + setup: function wphSetup(handler, port) { + handler.on('test', function wphSetupTest(data) { + // check if Uint8Array can be sent to worker + if (!(data instanceof Uint8Array)) { + handler.send('test', 'main', false); + return; + } + // making sure postMessage transfers are working + var supportTransfers = data[0] === 255; + handler.postMessageTransfers = supportTransfers; + // check if the response property is supported by xhr + var xhr = new XMLHttpRequest(); + var responseExists = 'response' in xhr; + // check if the property is actually implemented + try { + var dummy = xhr.responseType; + } catch (e) { + responseExists = false; + } + if (!responseExists) { + handler.send('test', false); + return; + } + handler.send('test', { + supportTypedArray: true, + supportTransfers: supportTransfers + }); + }); + + handler.on('GetDocRequest', function wphSetupDoc(data) { + return WorkerMessageHandler.createDocumentHandler(data, port); + }); + }, + createDocumentHandler: function wphCreateDocumentHandler(docParams, port) { + // This context is actually holds references on pdfManager and handler, + // until the latter is destroyed. var pdfManager; var terminated = false; var cancelXHRs = null; var WorkerTasks = []; + var docId = docParams.docId; + var workerHandlerName = docParams.docId + '_worker'; + var handler = new MessageHandler(workerHandlerName, docId, port); + function ensureNotTerminated() { if (terminated) { throw new Error('Worker was terminated'); @@ -33900,7 +34022,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { var disableRange = data.disableRange; if (source.data) { try { - pdfManager = new LocalPdfManager(source.data, source.password); + pdfManager = new LocalPdfManager(docId, source.data, source.password); pdfManagerCapability.resolve(pdfManager); } catch (ex) { pdfManagerCapability.reject(ex); @@ -33908,7 +34030,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { return pdfManagerCapability.promise; } else if (source.chunkedViewerLoading) { try { - pdfManager = new NetworkPdfManager(source, handler); + pdfManager = new NetworkPdfManager(docId, source, handler); pdfManagerCapability.resolve(pdfManager); } catch (ex) { pdfManagerCapability.reject(ex); @@ -33965,7 +34087,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { } try { - pdfManager = new NetworkPdfManager(source, handler); + pdfManager = new NetworkPdfManager(docId, source, handler); pdfManagerCapability.resolve(pdfManager); } catch (ex) { pdfManagerCapability.reject(ex); @@ -34010,7 +34132,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { // the data is array, instantiating directly from it try { - pdfManager = new LocalPdfManager(pdfFile, source.password); + pdfManager = new LocalPdfManager(docId, pdfFile, source.password); pdfManagerCapability.resolve(pdfManager); } catch (ex) { pdfManagerCapability.reject(ex); @@ -34048,35 +34170,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { return pdfManagerCapability.promise; } - handler.on('test', function wphSetupTest(data) { - // check if Uint8Array can be sent to worker - if (!(data instanceof Uint8Array)) { - handler.send('test', false); - return; - } - // making sure postMessage transfers are working - var supportTransfers = data[0] === 255; - handler.postMessageTransfers = supportTransfers; - // check if the response property is supported by xhr - var xhr = new XMLHttpRequest(); - var responseExists = 'response' in xhr; - // check if the property is actually implemented - try { - var dummy = xhr.responseType; - } catch (e) { - responseExists = false; - } - if (!responseExists) { - handler.send('test', false); - return; - } - handler.send('test', { - supportTypedArray: true, - supportTransfers: supportTransfers - }); - }); - - handler.on('GetDocRequest', function wphSetupDoc(data) { + var setupDoc = function(data) { var onSuccess = function(doc) { ensureNotTerminated(); handler.send('GetDoc', { pdfInfo: doc }); @@ -34121,7 +34215,6 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { } pdfManager = newPdfManager; - handler.send('PDFManagerReady', null); pdfManager.onLoadedStream().then(function(stream) { handler.send('DataLoaded', { length: stream.bytes.byteLength }); @@ -34152,7 +34245,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { }); }, onFailure); }, onFailure); - }); + }; handler.on('GetPage', function wphSetupGetPage(data) { return pdfManager.getPage(data.pageIndex).then(function(page) { @@ -34185,7 +34278,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { handler.on('GetDestination', function wphSetupGetDestination(data) { - return pdfManager.ensureCatalog('getDestination', [ data.id ]); + return pdfManager.ensureCatalog('getDestination', [data.id]); } ); @@ -34233,7 +34326,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { handler.on('GetAnnotations', function wphSetupGetAnnotations(data) { return pdfManager.getPage(data.pageIndex).then(function(page) { - return pdfManager.ensure(page, 'getAnnotationsData', []); + return pdfManager.ensure(page, 'getAnnotationsData', [data.intent]); }); }); @@ -34292,12 +34385,14 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { handler.on('GetTextContent', function wphExtractText(data) { var pageIndex = data.pageIndex; + var normalizeWhitespace = data.normalizeWhitespace; return pdfManager.getPage(pageIndex).then(function(page) { var task = new WorkerTask('GetTextContent: page ' + pageIndex); startWorkerTask(task); var pageNum = pageIndex + 1; var start = Date.now(); - return page.extractTextContent(task).then(function(textContent) { + return page.extractTextContent(task, normalizeWhitespace).then( + function(textContent) { finishWorkerTask(task); info('text indexing: page=' + pageNum + ' - time=' + (Date.now() - start) + 'ms'); @@ -34332,8 +34427,19 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { task.terminate(); }); - return Promise.all(waitOn).then(function () {}); + return Promise.all(waitOn).then(function () { + // Notice that even if we destroying handler, resolved response promise + // must be sent back. + handler.destroy(); + handler = null; + }); }); + + handler.on('Ready', function wphReady(data) { + setupDoc(docParams); + docParams = null; // we don't need docParams anymore -- saving memory. + }); + return workerHandlerName; } }; @@ -34343,6 +34449,7 @@ var workerConsole = { log: function log() { var args = Array.prototype.slice.call(arguments); globalScope.postMessage({ + targetName: 'main', action: 'console_log', data: args }); @@ -34351,6 +34458,7 @@ var workerConsole = { error: function error() { var args = Array.prototype.slice.call(arguments); globalScope.postMessage({ + targetName: 'main', action: 'console_error', data: args }); @@ -34380,13 +34488,14 @@ if (typeof window === 'undefined') { // Listen for unsupported features so we can pass them on to the main thread. PDFJS.UnsupportedManager.listen(function (msg) { globalScope.postMessage({ + targetName: 'main', action: '_unsupported_feature', data: msg }); }); - var handler = new MessageHandler('worker_processor', this); - WorkerMessageHandler.setup(handler); + var handler = new MessageHandler('worker', 'main', this); + WorkerMessageHandler.setup(handler, this); } diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index 35488967ab73..49934a61142d 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -12,6 +12,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar, + DownloadManager, getFileName, getPDFFileNameFromURL, + PDFHistory, Preferences, SidebarView, ViewHistory, Stats, + PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar, + PasswordPrompt, PDFPresentationMode, PDFDocumentProperties, HandTool, + Promise, PDFLinkService, PDFOutlineView, PDFAttachmentView, + OverlayManager, PDFFindController, PDFFindBar, PDFViewer, + PDFRenderingQueue, PresentationModeState, parseQueryString, + RenderingStates, UNKNOWN_SCALE, DEFAULT_SCALE_VALUE, + IGNORE_CURRENT_POSITION_ON_ZOOM: true */ + +'use strict'; var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf'; var DEFAULT_SCALE_DELTA = 1.1; @@ -1027,7 +1039,6 @@ var PDFFindController = (function PDFFindControllerClosure() { '\u00BC': '1/4', // Vulgar fraction one quarter '\u00BD': '1/2', // Vulgar fraction one half '\u00BE': '3/4', // Vulgar fraction three quarters - '\u00A0': ' ' // No-break space }; this.findBar = options.findBar || null; @@ -3675,7 +3686,7 @@ var PDFPageView = (function PDFPageViewClosure() { } if (redrawAnnotations && this.annotationLayer) { - this.annotationLayer.setupAnnotations(this.viewport); + this.annotationLayer.setupAnnotations(this.viewport, 'display'); } }, @@ -3878,7 +3889,7 @@ var PDFPageView = (function PDFPageViewClosure() { function pdfPageRenderCallback() { pageViewDrawCallback(null); if (textLayer) { - self.pdfPage.getTextContent().then( + self.pdfPage.getTextContent({ normalizeWhitespace: true }).then( function textContentResolved(textContent) { textLayer.setTextContent(textContent); textLayer.render(TEXT_LAYER_RENDER_DELAY); @@ -3896,7 +3907,7 @@ var PDFPageView = (function PDFPageViewClosure() { this.annotationLayer = this.annotationsLayerFactory. createAnnotationsLayerBuilder(div, this.pdfPage); } - this.annotationLayer.setupAnnotations(this.viewport); + this.annotationLayer.setupAnnotations(this.viewport, 'display'); } div.setAttribute('data-loaded', true); @@ -4313,9 +4324,10 @@ var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() { /** * @param {PageViewport} viewport + * @param {string} intent (default value is 'display') */ setupAnnotations: - function AnnotationsLayerBuilder_setupAnnotations(viewport) { + function AnnotationsLayerBuilder_setupAnnotations(viewport, intent) { function bindLink(link, dest) { link.href = linkService.getDestinationHash(dest); link.onclick = function annotationsLayerBuilderLinksOnclick() { @@ -4341,8 +4353,12 @@ var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() { var linkService = this.linkService; var pdfPage = this.pdfPage; var self = this; + var getAnnotationsParams = { + intent: (intent === undefined ? 'display' : intent), + }; - pdfPage.getAnnotations().then(function (annotationsData) { + pdfPage.getAnnotations(getAnnotationsParams).then( + function (annotationsData) { viewport = viewport.clone({ dontFlip: true }); var transform = viewport.transform; var transformStr = 'matrix(' + transform.join(',') + ')'; @@ -4882,7 +4898,7 @@ var PDFViewer = (function pdfViewer() { if (!this.pdfDocument) { return; } - + var pageView = this._pages[pageNumber - 1]; if (this.isInPresentationMode) { @@ -5140,7 +5156,7 @@ var PDFViewer = (function pdfViewer() { getPageTextContent: function (pageIndex) { return this.pdfDocument.getPage(pageIndex + 1).then(function (page) { - return page.getTextContent(); + return page.getTextContent({ normalizeWhitespace: true }); }); }, @@ -7389,7 +7405,7 @@ document.addEventListener('textlayerrendered', function (e) { if (pageView.textLayer && pageView.textLayer.textDivs && pageView.textLayer.textDivs.length > 0 && !PDFViewerApplication.supportsDocumentColors) { - console.error(mozL10n.get('document_colors_disabled', null, + console.error(mozL10n.get('document_colors_not_allowed', null, 'PDF documents are not allowed to use their own colors: ' + '\'Allow pages to choose their own colors\' ' + 'is deactivated in the browser.')); diff --git a/browser/locales/en-US/pdfviewer/viewer.properties b/browser/locales/en-US/pdfviewer/viewer.properties index 5c43b50575e8..20c91956604f 100644 --- a/browser/locales/en-US/pdfviewer/viewer.properties +++ b/browser/locales/en-US/pdfviewer/viewer.properties @@ -170,4 +170,4 @@ password_cancel=Cancel printing_not_supported=Warning: Printing is not fully supported by this browser. printing_not_ready=Warning: The PDF is not fully loaded for printing. web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. -document_colors_disabled=PDF documents are not allowed to use their own colors: \'Allow pages to choose their own colors\' is deactivated in the browser. +document_colors_not_allowed=PDF documents are not allowed to use their own colors: 'Allow pages to choose their own colors' is deactivated in the browser.