From fc3282db560d6f19612e371e0ab9b24771218910 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 16 Dec 2015 18:37:43 -0600 Subject: [PATCH] Adds RequireJS to worker. --- external/builder/builder.js | 30 ------------ external/umdutils/verifier.js | 2 +- make.js | 35 ++++++++++++-- src/core/network.js | 14 ++++++ src/core/worker.js | 90 ++++++++++++++++++++--------------- src/display/api.js | 51 ++++++++++++++------ src/display/svg.js | 4 +- src/worker_loader.js | 69 +++------------------------ 8 files changed, 143 insertions(+), 152 deletions(-) diff --git a/external/builder/builder.js b/external/builder/builder.js index 7552ad048..e1d2cf03d 100644 --- a/external/builder/builder.js +++ b/external/builder/builder.js @@ -303,36 +303,6 @@ function build(setup) { } exports.build = build; -function getWorkerSrcFiles(filePath) { - var src = fs.readFileSync(filePath).toString(); - var reSrcFiles = /var\s+otherFiles\s*=\s*(\[[^\]]*\])/; - var match = reSrcFiles.exec(src); - if (!match) { - throw new Error('Cannot find otherFiles array in ' + filePath); - } - - var files = match[1].replace(/'/g, '"').replace(/^\s*\/\/.*/gm, '') - .replace(/,\s*]$/, ']'); - try { - files = JSON.parse(files); - } catch (e) { - throw new Error('Failed to parse otherFiles in ' + filePath + ' as JSON, ' + - e); - } - - var srcFiles = files.filter(function(name) { - return name.indexOf('external') === -1; - }); - var externalSrcFiles = files.filter(function(name) { - return name.indexOf('external') > -1; - }); - return { - srcFiles: srcFiles, - externalSrcFiles: externalSrcFiles - }; -} -exports.getWorkerSrcFiles = getWorkerSrcFiles; - /** * Merge two defines arrays. Values in the second param will override values in * the first. diff --git a/external/umdutils/verifier.js b/external/umdutils/verifier.js index fc9f17436..864739091 100644 --- a/external/umdutils/verifier.js +++ b/external/umdutils/verifier.js @@ -59,7 +59,7 @@ function parseUmd(filePath) { var umdStart = '\\(function\\s\\(root,\\sfactory\\)\\s\\{'; var umdImports = '\\}\\(this,\\sfunction\\s\\(exports\\b'; var umdBody = '\\)\\s\\{'; - var umdEnd = '\\}\\)\\);\\s*$'; + var umdEnd = '\\}\\)\\);\\s*(//#endif\\s*)?$'; var m, re; m = new RegExp(umdStart + '([\\s\\S]*?)' + umdImports + '([\\s\\S]*?)' + umdBody + '([\\s\\S]*?)' + umdEnd).exec(jscode); diff --git a/make.js b/make.js index b46026ed7..410642051 100644 --- a/make.js +++ b/make.js @@ -542,8 +542,37 @@ target.bundle = function(args) { 'display/svg.js' ]); - var srcFiles = builder.getWorkerSrcFiles('src/worker_loader.js'); - var WORKER_SRC_FILES = srcFiles.srcFiles; + var WORKER_SRC_FILES = [ + 'core/network.js', + 'core/arithmetic_decoder.js', + 'core/charsets.js', + 'core/glyphlist.js', + 'core/jpg.js', + 'core/metrics.js', + 'core/bidi.js', + 'core/chunked_stream.js', + 'core/jbig2.js', + 'core/jpx.js', + 'core/murmurhash3.js', + 'core/primitives.js', + 'core/stream.js', + 'core/crypto.js', + 'core/font_renderer.js', + 'core/parser.js', + 'core/cmap.js', + 'core/obj.js', + 'core/ps_parser.js', + 'core/fonts.js', + 'core/function.js', + 'core/colorspace.js', + 'core/image.js', + 'core/pattern.js', + 'core/evaluator.js', + 'core/annotation.js', + 'core/document.js', + 'core/pdf_manager.js', + 'core/worker.js' + ]; if (!defines.SINGLE_FILE) { // We want shared_src_files in both pdf.js and pdf.worker.js @@ -555,7 +584,7 @@ target.bundle = function(args) { MAIN_SRC_FILES = MAIN_SRC_FILES.concat(WORKER_SRC_FILES); } - var EXT_SRC_FILES = srcFiles.externalSrcFiles; + var EXT_SRC_FILES = []; cd(SRC_DIR); diff --git a/src/core/network.js b/src/core/network.js index fa0974996..c36066eac 100644 --- a/src/core/network.js +++ b/src/core/network.js @@ -291,3 +291,17 @@ var NetworkManager = (function NetworkManagerClosure() { return NetworkManager; })(); + +//#if !(FIREFOX || MOZCENTRAL) +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define('pdfjs/core/network', ['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.pdfjsCoreNetwork = {})); + } +}(this, function (exports) { + exports.NetworkManager = NetworkManager; +})); +//#endif diff --git a/src/core/worker.js b/src/core/worker.js index 2a157c62b..37f2fc756 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -84,7 +84,13 @@ var WorkerTask = (function WorkerTaskClosure() { var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { setup: function wphSetup(handler, port) { + var testMessageProcessed = false; handler.on('test', function wphSetupTest(data) { + if (testMessageProcessed) { + return; // we already processed 'test' message once + } + testMessageProcessed = true; + // check if Uint8Array can be sent to worker if (!(data instanceof Uint8Array)) { handler.send('test', 'main', false); @@ -611,51 +617,57 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { } }; -var consoleTimer = {}; - -var workerConsole = { - log: function log() { - var args = Array.prototype.slice.call(arguments); - globalScope.postMessage({ - targetName: 'main', - action: 'console_log', - data: args - }); - }, - - error: function error() { - var args = Array.prototype.slice.call(arguments); - globalScope.postMessage({ - targetName: 'main', - action: 'console_error', - data: args - }); - throw 'pdf.js execution error'; - }, - - time: function time(name) { - consoleTimer[name] = Date.now(); - }, - - timeEnd: function timeEnd(name) { - var time = consoleTimer[name]; - if (!time) { - error('Unknown timer name ' + name); - } - this.log('Timer:', name, Date.now() - time); - } -}; - - -// Worker thread? -if (typeof window === 'undefined' && - !(typeof module !== 'undefined' && module.require)) { +function initializeWorker() { +//#if !MOZCENTRAL if (!('console' in globalScope)) { + var consoleTimer = {}; + + var workerConsole = { + log: function log() { + var args = Array.prototype.slice.call(arguments); + globalScope.postMessage({ + targetName: 'main', + action: 'console_log', + data: args + }); + }, + + error: function error() { + var args = Array.prototype.slice.call(arguments); + globalScope.postMessage({ + targetName: 'main', + action: 'console_error', + data: args + }); + throw 'pdf.js execution error'; + }, + + time: function time(name) { + consoleTimer[name] = Date.now(); + }, + + timeEnd: function timeEnd(name) { + var time = consoleTimer[name]; + if (!time) { + error('Unknown timer name ' + name); + } + this.log('Timer:', name, Date.now() - time); + } + }; + globalScope.console = workerConsole; } +//#endif var handler = new MessageHandler('worker', 'main', self); WorkerMessageHandler.setup(handler, self); + handler.send('ready', null); +} + +// Worker thread (and not node.js)? +if (typeof window === 'undefined' && + !(typeof module !== 'undefined' && module.require)) { + initializeWorker(); } exports.WorkerTask = WorkerTask; diff --git a/src/display/api.js b/src/display/api.js index 2167757de..e342cb0c7 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -414,7 +414,7 @@ PDFJS.getDocument = function getDocument(src, var transport = new WorkerTransport(messageHandler, task, rangeTransport); task._transport = transport; }); - }, task._capability.reject); + }).catch(task._capability.reject); return task; }; @@ -1186,14 +1186,14 @@ var PDFWorker = (function PDFWorkerClosure() { // pdf.worker.js file is needed. //#if !PRODUCTION if (typeof amdRequire === 'function') { - amdRequire(['pdfjs/core/worker'], function () { + amdRequire(['pdfjs/core/network', 'pdfjs/core/worker'], function () { PDFJS.fakeWorkerFilesLoadedCapability.resolve(); }); } else if (typeof require === 'function') { require('../core/worker.js'); PDFJS.fakeWorkerFilesLoadedCapability.resolve(); } else { - Util.loadScript(PDFJS.workerSrc); + throw new Error('AMD or CommonJS must be used to load fake worker.'); } //#endif //#if PRODUCTION && SINGLE_FILE @@ -1253,7 +1253,6 @@ var PDFWorker = (function PDFWorkerClosure() { // 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')); @@ -1284,16 +1283,40 @@ var PDFWorker = (function PDFWorkerClosure() { console.error.apply(console, 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); - } + messageHandler.on('ready', function (data) { + if (this.destroyed) { + this._readyCapability.reject(new Error('Worker was destroyed')); + messageHandler.destroy(); + worker.terminate(); + return; // worker was destroyed + } + try { + sendTest(); + } catch (e) { + // We need fallback to a faked worker. + this._setupFakeWorker(); + } + }.bind(this)); + + var sendTest = function () { + 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); + } + }; + + // It might take time for worker to initialize (especially when AMD + // loader is used). We will try to send test immediately, and then + // when 'ready' message will arrive. The worker shall process only + // first received 'test'. + sendTest(); return; } catch (e) { info('The worker has been disabled.'); diff --git a/src/display/svg.js b/src/display/svg.js index 472287e4f..15048b451 100644 --- a/src/display/svg.js +++ b/src/display/svg.js @@ -16,6 +16,7 @@ 'use strict'; +//#if (GENERIC || SINGLE_FILE) (function (root, factory) { if (typeof define === 'function' && define.amd) { define('pdfjs/display/svg', ['exports', 'pdfjs/shared/util'], factory); @@ -25,7 +26,6 @@ factory((root.pdfjsDisplaySVG = {}), root.pdfjsSharedUtil); } }(this, function (exports, sharedUtil) { -//#if (GENERIC || SINGLE_FILE) var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX; var IDENTITY_MATRIX = sharedUtil.IDENTITY_MATRIX; @@ -1209,5 +1209,5 @@ var SVGGraphics = (function SVGGraphicsClosure() { PDFJS.SVGGraphics = SVGGraphics; exports.SVGGraphics = SVGGraphics; -//#endif })); +//#endif diff --git a/src/worker_loader.js b/src/worker_loader.js index dc11706b8..ea480c741 100644 --- a/src/worker_loader.js +++ b/src/worker_loader.js @@ -12,70 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* globals PDFJS, Util */ 'use strict'; -// List of shared files to include; -var sharedFiles = [ - 'shared/global.js', - 'shared/util.js' -]; +importScripts('../node_modules/requirejs/require.js'); -// List of other files to include; -var otherFiles = [ - 'core/network.js', - 'core/arithmetic_decoder.js', - 'core/charsets.js', - 'core/glyphlist.js', - 'core/jpg.js', - 'core/metrics.js', - 'core/bidi.js', - 'core/chunked_stream.js', - 'core/jbig2.js', - 'core/jpx.js', - 'core/murmurhash3.js', - 'core/primitives.js', - 'core/stream.js', - 'core/crypto.js', - 'core/font_renderer.js', - 'core/parser.js', - 'core/cmap.js', - 'core/obj.js', - 'core/ps_parser.js', - 'core/fonts.js', - 'core/function.js', - 'core/colorspace.js', - 'core/image.js', - 'core/pattern.js', - 'core/evaluator.js', - 'core/annotation.js', - 'core/document.js', - 'core/pdf_manager.js', - 'core/worker.js' -]; - -function loadInOrder(index, path, files) { - if (index >= files.length) { - PDFJS.fakeWorkerFilesLoadedCapability.resolve(); - return; - } - PDFJS.Util.loadScript(path + files[index], - loadInOrder.bind(null, ++index, path, files)); -} - -// Load all the files. -if (typeof PDFJS === 'undefined' || !PDFJS.fakeWorkerFilesLoadedCapability) { - var files = sharedFiles.concat(otherFiles); - for (var i = 0; i < files.length; i++) { - importScripts(files[i]); - } -} else { - var src = PDFJS.workerSrc; - var path = src.substr(0, src.indexOf('worker_loader.js')); - // If Util is available, we assume that shared files are already loaded. Can - // happen that they are not if PDF.js is bundled inside a special namespace. - var skipShared = typeof Util !== 'undefined'; - var files = skipShared ? otherFiles : sharedFiles.concat(otherFiles); - loadInOrder(0, path, files); -} +require.config({paths: {'pdfjs': '.'}}); +require(['pdfjs/core/network', 'pdfjs/core/worker'], + function (network, worker) { + // Worker is loaded at this point. +});