From 2008f741851a04bd711cf39821d77c3284d6198f Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 7 May 2014 18:15:25 -0500 Subject: [PATCH] Refactors MessageHandler.send to remove callbacks --- src/core/evaluator.js | 4 +- src/core/image.js | 11 ++- src/core/worker.js | 63 ++++++----------- src/display/api.js | 159 +++++++++++++++++------------------------- src/shared/util.js | 76 ++++++++++++++------ 5 files changed, 147 insertions(+), 166 deletions(-) diff --git a/src/core/evaluator.js b/src/core/evaluator.js index e4951b2af..e7cf53c58 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -214,7 +214,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { then(function(imageObj) { var imgData = imageObj.createImageData(/* forceRGBA = */ false); self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData], - null, [imgData.data.buffer]); + [imgData.data.buffer]); }).then(null, function (reason) { warn('Unable to decode image: ' + reason); self.handler.send('obj', [objId, self.pageIndex, 'Image', null]); @@ -1592,7 +1592,7 @@ var OperatorList = (function OperatorListClosure() { }, pageIndex: this.pageIndex, intent: this.intent - }, null, transfers); + }, transfers); this.dependencies = {}; this.fnArray.length = 0; this.argsArray.length = 0; diff --git a/src/core/image.js b/src/core/image.js index 2ada50e99..08838e14e 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -31,14 +31,11 @@ var PDFImage = (function PDFImageClosure() { var colorSpace = dict.get('ColorSpace', 'CS'); colorSpace = ColorSpace.parse(colorSpace, xref, res); var numComps = colorSpace.numComps; - var resolvePromise; - handler.send('JpegDecode', [image.getIR(), numComps], function(message) { + var decodePromise = handler.sendWithPromise('JpegDecode', + [image.getIR(), numComps]); + return decodePromise.then(function (message) { var data = message.data; - var stream = new Stream(data, 0, data.length, image.dict); - resolvePromise(stream); - }); - return new Promise(function (resolve) { - resolvePromise = resolve; + return new Stream(data, 0, data.length, image.dict); }); } else { return Promise.resolve(image); diff --git a/src/core/worker.js b/src/core/worker.js index 5b29698de..d98aa3aeb 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -279,60 +279,47 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { }); }); - handler.on('GetPageIndex', function wphSetupGetPageIndex(data, deferred) { + handler.on('GetPageIndex', function wphSetupGetPageIndex(data) { var ref = new Ref(data.ref.num, data.ref.gen); var catalog = pdfManager.pdfDocument.catalog; - catalog.getPageIndex(ref).then(function (pageIndex) { - deferred.resolve(pageIndex); - }, deferred.reject); + return catalog.getPageIndex(ref); }); handler.on('GetDestinations', - function wphSetupGetDestinations(data, deferred) { - pdfManager.ensureCatalog('destinations').then(function(destinations) { - deferred.resolve(destinations); - }); + function wphSetupGetDestinations(data) { + return pdfManager.ensureCatalog('destinations'); } ); handler.on('GetAttachments', - function wphSetupGetAttachments(data, deferred) { - pdfManager.ensureCatalog('attachments').then(function(attachments) { - deferred.resolve(attachments); - }, deferred.reject); + function wphSetupGetAttachments(data) { + return pdfManager.ensureCatalog('attachments'); } ); handler.on('GetJavaScript', - function wphSetupGetJavaScript(data, deferred) { - pdfManager.ensureCatalog('javaScript').then(function (js) { - deferred.resolve(js); - }, deferred.reject); + function wphSetupGetJavaScript(data) { + return pdfManager.ensureCatalog('javaScript'); } ); handler.on('GetOutline', - function wphSetupGetOutline(data, deferred) { - pdfManager.ensureCatalog('documentOutline').then(function (outline) { - deferred.resolve(outline); - }, deferred.reject); + function wphSetupGetOutline(data) { + return pdfManager.ensureCatalog('documentOutline'); } ); handler.on('GetMetadata', - function wphSetupGetMetadata(data, deferred) { - Promise.all([pdfManager.ensureDoc('documentInfo'), - pdfManager.ensureCatalog('metadata')]).then( - function (results) { - deferred.resolve(results); - }, deferred.reject); + function wphSetupGetMetadata(data) { + return Promise.all([pdfManager.ensureDoc('documentInfo'), + pdfManager.ensureCatalog('metadata')]); } ); - handler.on('GetData', function wphSetupGetData(data, deferred) { + handler.on('GetData', function wphSetupGetData(data) { pdfManager.requestLoadedStream(); - pdfManager.onLoadedStream().then(function(stream) { - deferred.resolve(stream.bytes); + return pdfManager.onLoadedStream().then(function(stream) { + return stream.bytes; }); }); @@ -398,29 +385,25 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { }); }, this); - handler.on('GetTextContent', function wphExtractText(data, deferred) { - pdfManager.getPage(data.pageIndex).then(function(page) { + handler.on('GetTextContent', function wphExtractText(data) { + return pdfManager.getPage(data.pageIndex).then(function(page) { var pageNum = data.pageIndex + 1; var start = Date.now(); - page.extractTextContent().then(function(textContent) { - deferred.resolve(textContent); + return page.extractTextContent().then(function(textContent) { info('text indexing: page=' + pageNum + ' - time=' + (Date.now() - start) + 'ms'); - }, function (e) { - // Skip errored pages - deferred.reject(e); + return textContent; }); }); }); - handler.on('Cleanup', function wphCleanup(data, deferred) { + handler.on('Cleanup', function wphCleanup(data) { pdfManager.cleanup(); - deferred.resolve(true); + return true; }); - handler.on('Terminate', function wphTerminate(data, deferred) { + handler.on('Terminate', function wphTerminate(data) { pdfManager.terminate(); - deferred.resolve(); }); } }; diff --git a/src/display/api.js b/src/display/api.js index 977fb8c7e..9d8de4dd0 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -546,15 +546,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() { * object that represent the page text content. */ getTextContent: function PDFPageProxy_getTextContent() { - return new Promise(function (resolve) { - this.transport.messageHandler.send('GetTextContent', { - pageIndex: this.pageNumber - 1 - }, - function textContentCallback(textContent) { - resolve(textContent); - } - ); - }.bind(this)); + return this.transport.messageHandler.sendWithPromise('GetTextContent', { + pageIndex: this.pageNumber - 1 + }); }, /** * Destroys resources allocated by the page. @@ -682,7 +676,7 @@ var WorkerTransport = (function WorkerTransportClosure() { // 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, null, [testObj.buffer]); + messageHandler.send('test', testObj, [testObj.buffer]); } catch (ex) { info('Cannot use postMessage transfers'); testObj[0] = 0; @@ -707,7 +701,7 @@ var WorkerTransport = (function WorkerTransportClosure() { this.pageCache = []; this.pageCapabilities = []; var self = this; - this.messageHandler.send('Terminate', null, function () { + this.messageHandler.sendWithPromise('Terminate', null).then(function () { FontLoader.clear(); if (self.worker) { self.worker.terminate(); @@ -934,9 +928,9 @@ var WorkerTransport = (function WorkerTransportClosure() { this.workerReadyCapability.reject(data); }, this); - messageHandler.on('PageError', function transportError(data, intent) { + messageHandler.on('PageError', function transportError(data) { var page = this.pageCache[data.pageNum - 1]; - var intentState = page.intentStates[intent]; + var intentState = page.intentStates[data.intent]; if (intentState.displayReadyCapability.promise) { intentState.displayReadyCapability.reject(data.error); } else { @@ -944,40 +938,47 @@ var WorkerTransport = (function WorkerTransportClosure() { } }, this); - messageHandler.on('JpegDecode', function(data, deferred) { + messageHandler.on('JpegDecode', function(data) { var imageUrl = data[0]; var components = data[1]; if (components != 3 && components != 1) { - error('Only 3 component or 1 component can be returned'); + return Promise.reject( + new Error('Only 3 component or 1 component can be returned')); } - var img = new Image(); - img.onload = (function messageHandler_onloadClosure() { - var width = img.width; - var height = img.height; - var size = width * height; - var rgbaLength = size * 4; - var buf = new Uint8Array(size * components); - var tmpCanvas = createScratchCanvas(width, height); - var tmpCtx = tmpCanvas.getContext('2d'); - tmpCtx.drawImage(img, 0, 0); - var data = tmpCtx.getImageData(0, 0, width, height).data; - var i, j; + return new Promise(function (resolve, reject) { + var img = new Image(); + img.onload = function () { + var width = img.width; + var height = img.height; + var size = width * height; + var rgbaLength = size * 4; + var buf = new Uint8Array(size * components); + var tmpCanvas = createScratchCanvas(width, height); + var tmpCtx = tmpCanvas.getContext('2d'); + tmpCtx.drawImage(img, 0, 0); + var data = tmpCtx.getImageData(0, 0, width, height).data; + var i, j; - if (components == 3) { - for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { - buf[j] = data[i]; - buf[j + 1] = data[i + 1]; - buf[j + 2] = data[i + 2]; + if (components == 3) { + for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { + buf[j] = data[i]; + buf[j + 1] = data[i + 1]; + buf[j + 2] = data[i + 2]; + } + } else if (components == 1) { + for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { + buf[j] = data[i]; + } } - } else if (components == 1) { - for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { - buf[j] = data[i]; - } - } - deferred.resolve({ data: buf, width: width, height: height}); - }).bind(this); - img.src = imageUrl; + resolve({ data: buf, width: width, height: height}); + }; + img.onerror = function () { + reject(new Error('JpegDecode failed to load image')); + }; + img.src = imageUrl; + }); + }); }, @@ -1019,13 +1020,7 @@ var WorkerTransport = (function WorkerTransportClosure() { }, getPageIndex: function WorkerTransport_getPageIndexByRef(ref) { - return new Promise(function (resolve) { - this.messageHandler.send('GetPageIndex', { ref: ref }, - function (pageIndex) { - resolve(pageIndex); - } - ); - }.bind(this)); + return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref }); }, getAnnotations: function WorkerTransport_getAnnotations(pageIndex) { @@ -1034,71 +1029,43 @@ var WorkerTransport = (function WorkerTransportClosure() { }, getDestinations: function WorkerTransport_getDestinations() { - return new Promise(function (resolve) { - this.messageHandler.send('GetDestinations', null, - function transportDestinations(destinations) { - resolve(destinations); - } - ); - }.bind(this)); + return this.messageHandler.sendWithPromise('GetDestinations', null); }, getAttachments: function WorkerTransport_getAttachments() { - return new Promise(function (resolve) { - this.messageHandler.send('GetAttachments', null, - function transportAttachments(attachments) { - resolve(attachments); - } - ); - }.bind(this)); + return this.messageHandler.sendWithPromise('GetAttachments', null); }, getJavaScript: function WorkerTransport_getJavaScript() { - return new Promise(function (resolve) { - this.messageHandler.send('GetJavaScript', null, - function transportJavaScript(js) { - resolve(js); - } - ); - }.bind(this)); + return this.messageHandler.sendWithPromise('GetJavaScript', null); }, getOutline: function WorkerTransport_getOutline() { - return new Promise(function (resolve) { - this.messageHandler.send('GetOutline', null, - function transportOutline(outline) { - resolve(outline); - } - ); - }.bind(this)); + return this.messageHandler.sendWithPromise('GetOutline', null); }, getMetadata: function WorkerTransport_getMetadata() { - return new Promise(function (resolve) { - this.messageHandler.send('GetMetadata', null, - function transportMetadata(results) { - resolve({ - info: results[0], - metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null) - }); - } - ); - }.bind(this)); + return this.messageHandler.sendWithPromise('GetMetadata', null). + then(function transportMetadata(results) { + return { + info: results[0], + metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null) + }; + }); }, startCleanup: function WorkerTransport_startCleanup() { - this.messageHandler.send('Cleanup', null, - function endCleanup() { - for (var i = 0, ii = this.pageCache.length; i < ii; i++) { - var page = this.pageCache[i]; - if (page) { - page.destroy(); - } + this.messageHandler.sendWithPromise('Cleanup', null). + then(function endCleanup() { + for (var i = 0, ii = this.pageCache.length; i < ii; i++) { + var page = this.pageCache[i]; + if (page) { + page.destroy(); } - this.commonObjs.clear(); - FontLoader.clear(); - }.bind(this) - ); + } + this.commonObjs.clear(); + FontLoader.clear(); + }.bind(this)); } }; return WorkerTransport; diff --git a/src/shared/util.js b/src/shared/util.js index dc7b00a1e..aabb000d6 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -1366,7 +1366,7 @@ function MessageHandler(name, comObj) { this.comObj = comObj; this.callbackIndex = 1; this.postMessageTransfers = true; - var callbacks = this.callbacks = {}; + var callbacksCapabilities = this.callbacksCapabilities = {}; var ah = this.actionHandler = {}; ah['console_log'] = [function ahConsoleLog(data) { @@ -1383,35 +1383,40 @@ function MessageHandler(name, comObj) { var data = event.data; if (data.isReply) { var callbackId = data.callbackId; - if (data.callbackId in callbacks) { - var callback = callbacks[callbackId]; - delete callbacks[callbackId]; - callback(data.data); + if (data.callbackId in callbacksCapabilities) { + var callback = callbacksCapabilities[callbackId]; + delete callbacksCapabilities[callbackId]; + if ('error' in data) { + callback.reject(data.error); + } else { + callback.resolve(data.data); + } } else { error('Cannot resolve callback ' + callbackId); } } else if (data.action in ah) { var action = ah[data.action]; if (data.callbackId) { - var deferred = {}; - var promise = new Promise(function (resolve, reject) { - deferred.resolve = resolve; - deferred.reject = reject; - }); - deferred.promise = promise; - promise.then(function(resolvedData) { + Promise.resolve().then(function () { + return action[0].call(action[1], data.data); + }).then(function (result) { comObj.postMessage({ isReply: true, callbackId: data.callbackId, - data: resolvedData + data: result + }); + }, function (reason) { + comObj.postMessage({ + isReply: true, + callbackId: data.callbackId, + error: reason }); }); - action[0].call(action[1], data.data, deferred); } else { action[0].call(action[1], data.data); } } else { - error('Unkown action from worker: ' + data.action); + error('Unknown action from worker: ' + data.action); } }; } @@ -1428,19 +1433,48 @@ MessageHandler.prototype = { * Sends a message to the comObj to invoke the action with the supplied data. * @param {String} actionName Action to call. * @param {JSON} data JSON data to send. - * @param {function} [callback] Optional callback that will handle a reply. * @param {Array} [transfers] Optional list of transfers/ArrayBuffers */ - send: function messageHandlerSend(actionName, data, callback, transfers) { + send: function messageHandlerSend(actionName, data, transfers) { var message = { action: actionName, data: data }; - if (callback) { - var callbackId = this.callbackIndex++; - this.callbacks[callbackId] = callback; - message.callbackId = callbackId; + this.postMessage(message, transfers); + }, + /** + * Sends a message to the comObj to invoke the action with the supplied data. + * Expects that other side will callback with the response. + * @param {String} actionName Action to call. + * @param {JSON} data JSON data to send. + * @param {Array} [transfers] Optional list of transfers/ArrayBuffers. + * @param {boolean} withPromise true if response if expected. + * @returns {Promise} Promise to be resolved with response data. + */ + sendWithPromise: + function messageHandlerSendWithPromise(actionName, data, transfers) { + var callbackId = this.callbackIndex++; + var message = { + action: actionName, + data: data, + callbackId: callbackId + }; + var capability = createPromiseCapability(); + this.callbacksCapabilities[callbackId] = capability; + try { + this.postMessage(message, transfers); + } catch (e) { + capability.reject(e); } + return capability.promise; + }, + /** + * Sends raw message to the comObj. + * @private + * @param message {Object} Raw message. + * @param transfers List of transfers/ArrayBuffers, or undefined. + */ + postMessage: function (message, transfers) { if (transfers && this.postMessageTransfers) { this.comObj.postMessage(message, transfers); } else {