Merge pull request #13813 from Snuffleupagus/rm-closure-API
Remove a couple of closures in the `src/display/api.js` file
This commit is contained in:
commit
99b14a9da0
@ -524,111 +524,81 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
|
||||
* The loading task controls the operations required to load a PDF document
|
||||
* (such as network requests) and provides a way to listen for completion,
|
||||
* after which individual pages can be rendered.
|
||||
*
|
||||
* @typedef {Object} PDFDocumentLoadingTask
|
||||
* @property {string} docId - Unique identifier for the document loading task.
|
||||
* @property {boolean} destroyed - Whether the loading task is destroyed or not.
|
||||
* @property {function} [onPassword] - Callback to request a password if a wrong
|
||||
* or no password was provided. The callback receives two parameters: a
|
||||
* function that should be called with the new password, and a reason (see
|
||||
* {@link PasswordResponses}).
|
||||
* @property {function} [onProgress] - Callback to be able to monitor the
|
||||
* loading progress of the PDF file (necessary to implement e.g. a loading
|
||||
* bar). The callback receives an {@link OnProgressParameters} argument.
|
||||
* @property {function} [onUnsupportedFeature] - Callback for when an
|
||||
* unsupported feature is used in the PDF document. The callback receives an
|
||||
* {@link UNSUPPORTED_FEATURES} argument.
|
||||
* @property {Promise<PDFDocumentProxy>} promise - Promise for document loading
|
||||
* task completion.
|
||||
* @property {function} destroy - Abort all network requests and destroy
|
||||
* the worker. Returns a promise that is resolved when destruction is
|
||||
* completed.
|
||||
*/
|
||||
class PDFDocumentLoadingTask {
|
||||
static get idCounters() {
|
||||
return shadow(this, "idCounters", { doc: 0 });
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {any}
|
||||
* @ignore
|
||||
*/
|
||||
const PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
|
||||
let nextDocumentId = 0;
|
||||
constructor() {
|
||||
this._capability = createPromiseCapability();
|
||||
this._transport = null;
|
||||
this._worker = null;
|
||||
|
||||
/**
|
||||
* Unique identifier for the document loading task.
|
||||
* @type {string}
|
||||
*/
|
||||
this.docId = `d${PDFDocumentLoadingTask.idCounters.doc++}`;
|
||||
|
||||
/**
|
||||
* Whether the loading task is destroyed or not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.destroyed = false;
|
||||
|
||||
/**
|
||||
* Callback to request a password if a wrong or no password was provided.
|
||||
* The callback receives two parameters: a function that should be called
|
||||
* with the new password, and a reason (see {@link PasswordResponses}).
|
||||
* @type {function}
|
||||
*/
|
||||
this.onPassword = null;
|
||||
|
||||
/**
|
||||
* Callback to be able to monitor the loading progress of the PDF file
|
||||
* (necessary to implement e.g. a loading bar).
|
||||
* The callback receives an {@link OnProgressParameters} argument.
|
||||
* @type {function}
|
||||
*/
|
||||
this.onProgress = null;
|
||||
|
||||
/**
|
||||
* Callback for when an unsupported feature is used in the PDF document.
|
||||
* The callback receives an {@link UNSUPPORTED_FEATURES} argument.
|
||||
* @type {function}
|
||||
*/
|
||||
this.onUnsupportedFeature = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The loading task controls the operations required to load a PDF document
|
||||
* (such as network requests) and provides a way to listen for completion,
|
||||
* after which individual pages can be rendered.
|
||||
* Promise for document loading task completion.
|
||||
* @type {Promise<PDFDocumentProxy>}
|
||||
*/
|
||||
// eslint-disable-next-line no-shadow
|
||||
class PDFDocumentLoadingTask {
|
||||
constructor() {
|
||||
this._capability = createPromiseCapability();
|
||||
this._transport = null;
|
||||
this._worker = null;
|
||||
|
||||
/**
|
||||
* Unique identifier for the document loading task.
|
||||
* @type {string}
|
||||
*/
|
||||
this.docId = "d" + nextDocumentId++;
|
||||
|
||||
/**
|
||||
* Whether the loading task is destroyed or not.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.destroyed = false;
|
||||
|
||||
/**
|
||||
* Callback to request a password if a wrong or no password was provided.
|
||||
* The callback receives two parameters: a function that should be called
|
||||
* with the new password, and a reason (see {@link PasswordResponses}).
|
||||
* @type {function}
|
||||
*/
|
||||
this.onPassword = null;
|
||||
|
||||
/**
|
||||
* Callback to be able to monitor the loading progress of the PDF file
|
||||
* (necessary to implement e.g. a loading bar).
|
||||
* The callback receives an {@link OnProgressParameters} argument.
|
||||
* @type {function}
|
||||
*/
|
||||
this.onProgress = null;
|
||||
|
||||
/**
|
||||
* Callback for when an unsupported feature is used in the PDF document.
|
||||
* The callback receives an {@link UNSUPPORTED_FEATURES} argument.
|
||||
* @type {function}
|
||||
*/
|
||||
this.onUnsupportedFeature = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Promise for document loading task completion.
|
||||
* @type {Promise<PDFDocumentProxy>}
|
||||
*/
|
||||
get promise() {
|
||||
return this._capability.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>} A promise that is resolved when destruction is
|
||||
* completed.
|
||||
*/
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
|
||||
const transportDestroyed = !this._transport
|
||||
? Promise.resolve()
|
||||
: this._transport.destroy();
|
||||
return transportDestroyed.then(() => {
|
||||
this._transport = null;
|
||||
if (this._worker) {
|
||||
this._worker.destroy();
|
||||
this._worker = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
get promise() {
|
||||
return this._capability.promise;
|
||||
}
|
||||
return PDFDocumentLoadingTask;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Abort all network requests and destroy the worker.
|
||||
* @returns {Promise<void>} A promise that is resolved when destruction is
|
||||
* completed.
|
||||
*/
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
|
||||
const transportDestroyed = !this._transport
|
||||
? Promise.resolve()
|
||||
: this._transport.destroy();
|
||||
return transportDestroyed.then(() => {
|
||||
this._transport = null;
|
||||
if (this._worker) {
|
||||
this._worker.destroy();
|
||||
this._worker = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class to support range requests file loading.
|
||||
@ -1935,8 +1905,8 @@ class LoopbackPort {
|
||||
* @typedef {Object} PDFWorkerParameters
|
||||
* @property {string} [name] - The name of the worker.
|
||||
* @property {Object} [port] - The `workerPort` object.
|
||||
* @property {number} [verbosity] - Controls the logging level; the
|
||||
* constants from {@link VerbosityLevel} should be used.
|
||||
* @property {number} [verbosity] - Controls the logging level;
|
||||
* the constants from {@link VerbosityLevel} should be used.
|
||||
*/
|
||||
|
||||
/** @type {any} */
|
||||
@ -1953,13 +1923,11 @@ const PDFWorker = (function PDFWorkerClosure() {
|
||||
// Workers aren't supported in Node.js, force-disabling them there.
|
||||
isWorkerDisabled = true;
|
||||
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("LIB")) {
|
||||
fallbackWorkerSrc = "../pdf.worker.js";
|
||||
} else {
|
||||
fallbackWorkerSrc = "./pdf.worker.js";
|
||||
}
|
||||
} else if (typeof document === "object" && "currentScript" in document) {
|
||||
const pdfjsFilePath = document.currentScript?.src;
|
||||
fallbackWorkerSrc = PDFJSDev.test("LIB")
|
||||
? "../pdf.worker.js"
|
||||
: "./pdf.worker.js";
|
||||
} else if (typeof document === "object") {
|
||||
const pdfjsFilePath = document?.currentScript?.src;
|
||||
if (pdfjsFilePath) {
|
||||
fallbackWorkerSrc = pdfjsFilePath.replace(
|
||||
/(\.(?:min\.)?js)(\?.*)?$/i,
|
||||
@ -1983,16 +1951,14 @@ const PDFWorker = (function PDFWorkerClosure() {
|
||||
}
|
||||
|
||||
function getMainThreadWorkerMessageHandler() {
|
||||
let mainWorkerMessageHandler;
|
||||
try {
|
||||
mainWorkerMessageHandler = globalThis.pdfjsWorker?.WorkerMessageHandler;
|
||||
return globalThis.pdfjsWorker?.WorkerMessageHandler || null;
|
||||
} catch (ex) {
|
||||
/* Ignore errors. */
|
||||
return null;
|
||||
}
|
||||
return mainWorkerMessageHandler || null;
|
||||
}
|
||||
|
||||
// Loads worker code into main thread.
|
||||
// Loads worker code into main-thread.
|
||||
function setupFakeWorkerGlobal() {
|
||||
if (fakeWorkerCapability) {
|
||||
return fakeWorkerCapability.promise;
|
||||
@ -3093,181 +3059,179 @@ class RenderTask {
|
||||
* For internal use only.
|
||||
* @ignore
|
||||
*/
|
||||
const InternalRenderTask = (function InternalRenderTaskClosure() {
|
||||
const canvasInRendering = new WeakSet();
|
||||
class InternalRenderTask {
|
||||
static get canvasInUse() {
|
||||
return shadow(this, "canvasInUse", new WeakSet());
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
class InternalRenderTask {
|
||||
constructor({
|
||||
callback,
|
||||
params,
|
||||
objs,
|
||||
commonObjs,
|
||||
operatorList,
|
||||
pageIndex,
|
||||
canvasFactory,
|
||||
useRequestAnimationFrame = false,
|
||||
pdfBug = false,
|
||||
}) {
|
||||
this.callback = callback;
|
||||
this.params = params;
|
||||
this.objs = objs;
|
||||
this.commonObjs = commonObjs;
|
||||
this.operatorListIdx = null;
|
||||
this.operatorList = operatorList;
|
||||
this._pageIndex = pageIndex;
|
||||
this.canvasFactory = canvasFactory;
|
||||
this._pdfBug = pdfBug;
|
||||
constructor({
|
||||
callback,
|
||||
params,
|
||||
objs,
|
||||
commonObjs,
|
||||
operatorList,
|
||||
pageIndex,
|
||||
canvasFactory,
|
||||
useRequestAnimationFrame = false,
|
||||
pdfBug = false,
|
||||
}) {
|
||||
this.callback = callback;
|
||||
this.params = params;
|
||||
this.objs = objs;
|
||||
this.commonObjs = commonObjs;
|
||||
this.operatorListIdx = null;
|
||||
this.operatorList = operatorList;
|
||||
this._pageIndex = pageIndex;
|
||||
this.canvasFactory = canvasFactory;
|
||||
this._pdfBug = pdfBug;
|
||||
|
||||
this.running = false;
|
||||
this.graphicsReadyCallback = null;
|
||||
this.graphicsReady = false;
|
||||
this._useRequestAnimationFrame =
|
||||
useRequestAnimationFrame === true && typeof window !== "undefined";
|
||||
this.cancelled = false;
|
||||
this.capability = createPromiseCapability();
|
||||
this.task = new RenderTask(this);
|
||||
// caching this-bound methods
|
||||
this._cancelBound = this.cancel.bind(this);
|
||||
this._continueBound = this._continue.bind(this);
|
||||
this._scheduleNextBound = this._scheduleNext.bind(this);
|
||||
this._nextBound = this._next.bind(this);
|
||||
this._canvas = params.canvasContext.canvas;
|
||||
this.running = false;
|
||||
this.graphicsReadyCallback = null;
|
||||
this.graphicsReady = false;
|
||||
this._useRequestAnimationFrame =
|
||||
useRequestAnimationFrame === true && typeof window !== "undefined";
|
||||
this.cancelled = false;
|
||||
this.capability = createPromiseCapability();
|
||||
this.task = new RenderTask(this);
|
||||
// caching this-bound methods
|
||||
this._cancelBound = this.cancel.bind(this);
|
||||
this._continueBound = this._continue.bind(this);
|
||||
this._scheduleNextBound = this._scheduleNext.bind(this);
|
||||
this._nextBound = this._next.bind(this);
|
||||
this._canvas = params.canvasContext.canvas;
|
||||
}
|
||||
|
||||
get completed() {
|
||||
return this.capability.promise.catch(function () {
|
||||
// Ignoring errors, since we only want to know when rendering is
|
||||
// no longer pending.
|
||||
});
|
||||
}
|
||||
|
||||
initializeGraphics({ transparency = false, optionalContentConfig }) {
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
if (this._canvas) {
|
||||
if (InternalRenderTask.canvasInUse.has(this._canvas)) {
|
||||
throw new Error(
|
||||
"Cannot use the same canvas during multiple render() operations. " +
|
||||
"Use different canvas or ensure previous operations were " +
|
||||
"cancelled or completed."
|
||||
);
|
||||
}
|
||||
InternalRenderTask.canvasInUse.add(this._canvas);
|
||||
}
|
||||
|
||||
get completed() {
|
||||
return this.capability.promise.catch(function () {
|
||||
// Ignoring errors, since we only want to know when rendering is
|
||||
// no longer pending.
|
||||
if (this._pdfBug && globalThis.StepperManager?.enabled) {
|
||||
this.stepper = globalThis.StepperManager.create(this._pageIndex);
|
||||
this.stepper.init(this.operatorList);
|
||||
this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
|
||||
}
|
||||
const { canvasContext, viewport, transform, imageLayer, background } =
|
||||
this.params;
|
||||
|
||||
this.gfx = new CanvasGraphics(
|
||||
canvasContext,
|
||||
this.commonObjs,
|
||||
this.objs,
|
||||
this.canvasFactory,
|
||||
imageLayer,
|
||||
optionalContentConfig
|
||||
);
|
||||
this.gfx.beginDrawing({
|
||||
transform,
|
||||
viewport,
|
||||
transparency,
|
||||
background,
|
||||
});
|
||||
this.operatorListIdx = 0;
|
||||
this.graphicsReady = true;
|
||||
if (this.graphicsReadyCallback) {
|
||||
this.graphicsReadyCallback();
|
||||
}
|
||||
}
|
||||
|
||||
cancel(error = null) {
|
||||
this.running = false;
|
||||
this.cancelled = true;
|
||||
if (this.gfx) {
|
||||
this.gfx.endDrawing();
|
||||
}
|
||||
if (this._canvas) {
|
||||
InternalRenderTask.canvasInUse.delete(this._canvas);
|
||||
}
|
||||
this.callback(
|
||||
error ||
|
||||
new RenderingCancelledException(
|
||||
`Rendering cancelled, page ${this._pageIndex + 1}`,
|
||||
"canvas"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
operatorListChanged() {
|
||||
if (!this.graphicsReady) {
|
||||
if (!this.graphicsReadyCallback) {
|
||||
this.graphicsReadyCallback = this._continueBound;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.stepper) {
|
||||
this.stepper.updateOperatorList(this.operatorList);
|
||||
}
|
||||
|
||||
if (this.running) {
|
||||
return;
|
||||
}
|
||||
this._continue();
|
||||
}
|
||||
|
||||
_continue() {
|
||||
this.running = true;
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
if (this.task.onContinue) {
|
||||
this.task.onContinue(this._scheduleNextBound);
|
||||
} else {
|
||||
this._scheduleNext();
|
||||
}
|
||||
}
|
||||
|
||||
_scheduleNext() {
|
||||
if (this._useRequestAnimationFrame) {
|
||||
window.requestAnimationFrame(() => {
|
||||
this._nextBound().catch(this._cancelBound);
|
||||
});
|
||||
} else {
|
||||
Promise.resolve().then(this._nextBound).catch(this._cancelBound);
|
||||
}
|
||||
}
|
||||
|
||||
initializeGraphics({ transparency = false, optionalContentConfig }) {
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
if (this._canvas) {
|
||||
if (canvasInRendering.has(this._canvas)) {
|
||||
throw new Error(
|
||||
"Cannot use the same canvas during multiple render() operations. " +
|
||||
"Use different canvas or ensure previous operations were " +
|
||||
"cancelled or completed."
|
||||
);
|
||||
}
|
||||
canvasInRendering.add(this._canvas);
|
||||
}
|
||||
|
||||
if (this._pdfBug && globalThis.StepperManager?.enabled) {
|
||||
this.stepper = globalThis.StepperManager.create(this._pageIndex);
|
||||
this.stepper.init(this.operatorList);
|
||||
this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
|
||||
}
|
||||
const { canvasContext, viewport, transform, imageLayer, background } =
|
||||
this.params;
|
||||
|
||||
this.gfx = new CanvasGraphics(
|
||||
canvasContext,
|
||||
this.commonObjs,
|
||||
this.objs,
|
||||
this.canvasFactory,
|
||||
imageLayer,
|
||||
optionalContentConfig
|
||||
);
|
||||
this.gfx.beginDrawing({
|
||||
transform,
|
||||
viewport,
|
||||
transparency,
|
||||
background,
|
||||
});
|
||||
this.operatorListIdx = 0;
|
||||
this.graphicsReady = true;
|
||||
if (this.graphicsReadyCallback) {
|
||||
this.graphicsReadyCallback();
|
||||
}
|
||||
async _next() {
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancel(error = null) {
|
||||
this.operatorListIdx = this.gfx.executeOperatorList(
|
||||
this.operatorList,
|
||||
this.operatorListIdx,
|
||||
this._continueBound,
|
||||
this.stepper
|
||||
);
|
||||
if (this.operatorListIdx === this.operatorList.argsArray.length) {
|
||||
this.running = false;
|
||||
this.cancelled = true;
|
||||
if (this.gfx) {
|
||||
if (this.operatorList.lastChunk) {
|
||||
this.gfx.endDrawing();
|
||||
}
|
||||
if (this._canvas) {
|
||||
canvasInRendering.delete(this._canvas);
|
||||
}
|
||||
this.callback(
|
||||
error ||
|
||||
new RenderingCancelledException(
|
||||
`Rendering cancelled, page ${this._pageIndex + 1}`,
|
||||
"canvas"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
operatorListChanged() {
|
||||
if (!this.graphicsReady) {
|
||||
if (!this.graphicsReadyCallback) {
|
||||
this.graphicsReadyCallback = this._continueBound;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.stepper) {
|
||||
this.stepper.updateOperatorList(this.operatorList);
|
||||
}
|
||||
|
||||
if (this.running) {
|
||||
return;
|
||||
}
|
||||
this._continue();
|
||||
}
|
||||
|
||||
_continue() {
|
||||
this.running = true;
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
if (this.task.onContinue) {
|
||||
this.task.onContinue(this._scheduleNextBound);
|
||||
} else {
|
||||
this._scheduleNext();
|
||||
}
|
||||
}
|
||||
|
||||
_scheduleNext() {
|
||||
if (this._useRequestAnimationFrame) {
|
||||
window.requestAnimationFrame(() => {
|
||||
this._nextBound().catch(this._cancelBound);
|
||||
});
|
||||
} else {
|
||||
Promise.resolve().then(this._nextBound).catch(this._cancelBound);
|
||||
}
|
||||
}
|
||||
|
||||
async _next() {
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
this.operatorListIdx = this.gfx.executeOperatorList(
|
||||
this.operatorList,
|
||||
this.operatorListIdx,
|
||||
this._continueBound,
|
||||
this.stepper
|
||||
);
|
||||
if (this.operatorListIdx === this.operatorList.argsArray.length) {
|
||||
this.running = false;
|
||||
if (this.operatorList.lastChunk) {
|
||||
this.gfx.endDrawing();
|
||||
if (this._canvas) {
|
||||
canvasInRendering.delete(this._canvas);
|
||||
}
|
||||
this.callback();
|
||||
if (this._canvas) {
|
||||
InternalRenderTask.canvasInUse.delete(this._canvas);
|
||||
}
|
||||
this.callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
return InternalRenderTask;
|
||||
})();
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
const version =
|
||||
|
@ -385,6 +385,26 @@ describe("api", function () {
|
||||
|
||||
await loadingTask.destroy();
|
||||
});
|
||||
|
||||
it("checks that `docId`s are unique and increasing", async function () {
|
||||
const loadingTask1 = getDocument(basicApiGetDocumentParams);
|
||||
await loadingTask1.promise;
|
||||
const docId1 = loadingTask1.docId;
|
||||
|
||||
const loadingTask2 = getDocument(basicApiGetDocumentParams);
|
||||
await loadingTask2.promise;
|
||||
const docId2 = loadingTask2.docId;
|
||||
|
||||
expect(docId1).not.toEqual(docId2);
|
||||
|
||||
const docIdRegExp = /^d(\d)+$/,
|
||||
docNum1 = docIdRegExp.exec(docId1)?.[1],
|
||||
docNum2 = docIdRegExp.exec(docId2)?.[1];
|
||||
|
||||
expect(+docNum1).toBeLessThan(+docNum2);
|
||||
|
||||
await Promise.all([loadingTask1.destroy(), loadingTask2.destroy()]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PDFWorker", function () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user