diff --git a/src/display/api.js b/src/display/api.js index 43954cabd..3b1ca159c 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -229,7 +229,7 @@ const DefaultStandardFontDataFactory = * already populated with data, or a parameter object. * @returns {PDFDocumentLoadingTask} */ -function getDocument(src) { +function getDocument(src = {}) { if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { if (typeof src === "string" || src instanceof URL) { src = { url: src }; @@ -237,14 +237,6 @@ function getDocument(src) { src = { data: src }; } } - if (typeof src !== "object") { - throw new Error("Invalid parameter in getDocument, need parameter object."); - } - if (!src.url && !src.data && !src.range) { - throw new Error( - "Invalid parameter object: need either .data, .range or .url" - ); - } const task = new PDFDocumentLoadingTask(); const { docId } = task; @@ -423,6 +415,9 @@ function getDocument(src) { if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) { throw new Error("Not implemented: createPDFNetworkStream"); } + if (!url) { + throw new Error("getDocument - no `url` parameter provided."); + } const createPDFNetworkStream = params => { if ( typeof PDFJSDev !== "undefined" && @@ -2091,6 +2086,14 @@ class PDFWorker { return this._readyCapability.promise; } + #resolve() { + this._readyCapability.resolve(); + // Send global setting, e.g. verbosity level. + this._messageHandler.send("configure", { + verbosity: this.verbosity, + }); + } + /** * The current `workerPort`, when it exists. * @type {Worker} @@ -2117,11 +2120,7 @@ class PDFWorker { // Ignoring "ready" event -- MessageHandler should already be initialized // and ready to accept messages. }); - this._readyCapability.resolve(); - // Send global setting, e.g. verbosity level. - this._messageHandler.send("configure", { - verbosity: this.verbosity, - }); + this.#resolve(); } _initialize() { @@ -2129,103 +2128,99 @@ class PDFWorker { // support, create a new web worker and test if it/the browser fulfills // 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.) + // Uint8Array as it arrives on the worker. if ( - !PDFWorkerUtil.isWorkerDisabled && - !PDFWorker.#mainThreadWorkerMessageHandler + PDFWorkerUtil.isWorkerDisabled || + PDFWorker.#mainThreadWorkerMessageHandler ) { - let { workerSrc } = PDFWorker; + this._setupFakeWorker(); + return; + } + let { workerSrc } = PDFWorker; - try { - // Wraps workerSrc path into blob URL, if the former does not belong - // to the same origin. - if ( - typeof PDFJSDev !== "undefined" && - PDFJSDev.test("GENERIC") && - !PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc) - ) { - workerSrc = PDFWorkerUtil.createCDNWrapper( - new URL(workerSrc, window.location).href - ); + try { + // Wraps workerSrc path into blob URL, if the former does not belong + // to the same origin. + if ( + typeof PDFJSDev !== "undefined" && + PDFJSDev.test("GENERIC") && + !PDFWorkerUtil.isSameOrigin(window.location.href, workerSrc) + ) { + workerSrc = PDFWorkerUtil.createCDNWrapper( + new URL(workerSrc, window.location).href + ); + } + + const worker = new Worker(workerSrc, { type: "module" }); + const messageHandler = new MessageHandler("main", "worker", worker); + const terminateEarly = () => { + ac.abort(); + messageHandler.destroy(); + worker.terminate(); + if (this.destroyed) { + this._readyCapability.reject(new Error("Worker was destroyed")); + } else { + // Fall back to fake worker if the termination is caused by an + // error (e.g. NetworkError / SecurityError). + this._setupFakeWorker(); } + }; - const worker = new Worker(workerSrc, { type: "module" }); - const messageHandler = new MessageHandler("main", "worker", worker); - const terminateEarly = () => { - worker.removeEventListener("error", onWorkerError); - messageHandler.destroy(); - worker.terminate(); - if (this.destroyed) { - this._readyCapability.reject(new Error("Worker was destroyed")); - } else { - // Fall back to fake worker if the termination is caused by an - // error (e.g. NetworkError / SecurityError). - this._setupFakeWorker(); - } - }; - - const onWorkerError = () => { + const ac = new AbortController(); + worker.addEventListener( + "error", + () => { if (!this._webWorker) { // Worker failed to initialize due to an error. Clean up and fall // back to the fake worker. terminateEarly(); } - }; - worker.addEventListener("error", onWorkerError); + }, + { signal: ac.signal } + ); - messageHandler.on("test", data => { - worker.removeEventListener("error", onWorkerError); - if (this.destroyed) { - terminateEarly(); - return; // worker was destroyed - } - if (data) { - this._messageHandler = messageHandler; - this._port = worker; - this._webWorker = worker; + messageHandler.on("test", data => { + ac.abort(); + if (this.destroyed || !data) { + terminateEarly(); + return; + } + this._messageHandler = messageHandler; + this._port = worker; + this._webWorker = worker; - this._readyCapability.resolve(); - // Send global setting, e.g. verbosity level. - messageHandler.send("configure", { - verbosity: this.verbosity, - }); - } else { - this._setupFakeWorker(); - messageHandler.destroy(); - worker.terminate(); - } - }); + this.#resolve(); + }); - messageHandler.on("ready", data => { - worker.removeEventListener("error", onWorkerError); - if (this.destroyed) { - terminateEarly(); - return; // worker was destroyed - } - try { - sendTest(); - } catch { - // We need fallback to a faked worker. - this._setupFakeWorker(); - } - }); + messageHandler.on("ready", data => { + ac.abort(); + if (this.destroyed) { + terminateEarly(); + return; + } + try { + sendTest(); + } catch { + // We need fallback to a faked worker. + this._setupFakeWorker(); + } + }); - const sendTest = () => { - const testObj = new Uint8Array(); - // Ensure that we can use `postMessage` transfers. - messageHandler.send("test", testObj, [testObj.buffer]); - }; + const sendTest = () => { + const testObj = new Uint8Array(); + // Ensure that we can use `postMessage` transfers. + messageHandler.send("test", testObj, [testObj.buffer]); + }; - // It might take time for the worker to initialize. We will try to send - // the "test" message immediately, and once the "ready" message arrives. - // The worker shall process only the first received "test" message. - sendTest(); - return; - } catch { - info("The worker has been disabled."); - } + // It might take time for the worker to initialize. We will try to send + // the "test" message immediately, and once the "ready" message arrives. + // The worker shall process only the first received "test" message. + sendTest(); + return; + } catch { + info("The worker has been disabled."); } - // Either workers are disabled, not supported or have thrown an exception. + // Either workers are not supported or have thrown an exception. // Thus, we fallback to a faked worker. this._setupFakeWorker(); } @@ -2253,13 +2248,8 @@ class PDFWorker { const workerHandler = new MessageHandler(id + "_worker", id, port); WorkerMessageHandler.setup(workerHandler, port); - const messageHandler = new MessageHandler(id, id + "_worker", port); - this._messageHandler = messageHandler; - this._readyCapability.resolve(); - // Send global setting, e.g. verbosity level. - messageHandler.send("configure", { - verbosity: this.verbosity, - }); + this._messageHandler = new MessageHandler(id, id + "_worker", port); + this.#resolve(); }) .catch(reason => { this._readyCapability.reject(