Convert PDFPageProxy
, in src/display/api.js
, to an ES6 class
This changes all occurrences of `var` to `let`/`const` in this code, and updates the signatures of a couple of methods to use object destructuring. Finally, when creating `InternalRenderTask` instances *only* the necessary parameter are now provided, since passing through the `RenderParameters` as-is seems completely unnecessary.
This commit is contained in:
parent
2c003a82d5
commit
5a0d64a6de
@ -850,385 +850,395 @@ class PDFDocumentProxy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy to a PDFPage in the worker thread.
|
* Proxy to a PDFPage in the worker thread.
|
||||||
* @class
|
|
||||||
* @alias PDFPageProxy
|
* @alias PDFPageProxy
|
||||||
*/
|
*/
|
||||||
var PDFPageProxy = (function PDFPageProxyClosure() {
|
class PDFPageProxy {
|
||||||
function PDFPageProxy(pageIndex, pageInfo, transport, pdfBug = false) {
|
constructor(pageIndex, pageInfo, transport, pdfBug = false) {
|
||||||
this.pageIndex = pageIndex;
|
this.pageIndex = pageIndex;
|
||||||
this._pageInfo = pageInfo;
|
this._pageInfo = pageInfo;
|
||||||
this.transport = transport;
|
this._transport = transport;
|
||||||
this._stats = (pdfBug ? new StatTimer() : DummyStatTimer);
|
this._stats = (pdfBug ? new StatTimer() : DummyStatTimer);
|
||||||
this._pdfBug = pdfBug;
|
this._pdfBug = pdfBug;
|
||||||
this.commonObjs = transport.commonObjs;
|
this.commonObjs = transport.commonObjs;
|
||||||
this.objs = new PDFObjects();
|
this.objs = new PDFObjects();
|
||||||
|
|
||||||
this.cleanupAfterRender = false;
|
this.cleanupAfterRender = false;
|
||||||
this.pendingCleanup = false;
|
this.pendingCleanup = false;
|
||||||
this.intentStates = Object.create(null);
|
this.intentStates = Object.create(null);
|
||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
}
|
}
|
||||||
PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {
|
|
||||||
/**
|
|
||||||
* @return {number} Page number of the page. First page is 1.
|
|
||||||
*/
|
|
||||||
get pageNumber() {
|
|
||||||
return this.pageIndex + 1;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @return {number} The number of degrees the page is rotated clockwise.
|
|
||||||
*/
|
|
||||||
get rotate() {
|
|
||||||
return this._pageInfo.rotate;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @return {Object} The reference that points to this page. It has 'num' and
|
|
||||||
* 'gen' properties.
|
|
||||||
*/
|
|
||||||
get ref() {
|
|
||||||
return this._pageInfo.ref;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @return {number} The default size of units in 1/72nds of an inch.
|
|
||||||
*/
|
|
||||||
get userUnit() {
|
|
||||||
return this._pageInfo.userUnit;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @return {Array} An array of the visible portion of the PDF page in the
|
|
||||||
* user space units - [x1, y1, x2, y2].
|
|
||||||
*/
|
|
||||||
get view() {
|
|
||||||
return this._pageInfo.view;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} scale The desired scale of the viewport.
|
* @return {number} Page number of the page. First page is 1.
|
||||||
* @param {number} rotate Degrees to rotate the viewport. If omitted this
|
*/
|
||||||
* defaults to the page rotation.
|
get pageNumber() {
|
||||||
* @param {boolean} dontFlip (optional) If true, axis Y will not be flipped.
|
return this.pageIndex + 1;
|
||||||
* @return {PageViewport} Contains 'width' and 'height' properties
|
}
|
||||||
* along with transforms required for rendering.
|
|
||||||
*/
|
|
||||||
getViewport(scale, rotate = this.rotate, dontFlip = false) {
|
|
||||||
return new PageViewport({
|
|
||||||
viewBox: this.view,
|
|
||||||
scale,
|
|
||||||
rotation: rotate,
|
|
||||||
dontFlip,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @param {GetAnnotationsParameters} params - Annotation parameters.
|
|
||||||
* @return {Promise} A promise that is resolved with an {Array} of the
|
|
||||||
* annotation objects.
|
|
||||||
*/
|
|
||||||
getAnnotations: function PDFPageProxy_getAnnotations(params) {
|
|
||||||
var intent = (params && params.intent) || null;
|
|
||||||
|
|
||||||
if (!this.annotationsPromise || this.annotationsIntent !== intent) {
|
/**
|
||||||
this.annotationsPromise = this.transport.getAnnotations(this.pageIndex,
|
* @return {number} The number of degrees the page is rotated clockwise.
|
||||||
intent);
|
*/
|
||||||
this.annotationsIntent = intent;
|
get rotate() {
|
||||||
}
|
return this._pageInfo.rotate;
|
||||||
return this.annotationsPromise;
|
}
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Begins the process of rendering a page to the desired context.
|
|
||||||
* @param {RenderParameters} params Page render parameters.
|
|
||||||
* @return {RenderTask} An object that contains the promise, which
|
|
||||||
* is resolved when the page finishes rendering.
|
|
||||||
*/
|
|
||||||
render: function PDFPageProxy_render(params) {
|
|
||||||
let stats = this._stats;
|
|
||||||
stats.time('Overall');
|
|
||||||
|
|
||||||
// If there was a pending destroy cancel it so no cleanup happens during
|
/**
|
||||||
// this call to render.
|
* @return {Object} The reference that points to this page. It has 'num' and
|
||||||
this.pendingCleanup = false;
|
* 'gen' properties.
|
||||||
|
*/
|
||||||
|
get ref() {
|
||||||
|
return this._pageInfo.ref;
|
||||||
|
}
|
||||||
|
|
||||||
var renderingIntent = (params.intent === 'print' ? 'print' : 'display');
|
/**
|
||||||
var canvasFactory = params.canvasFactory || new DOMCanvasFactory();
|
* @return {number} The default size of units in 1/72nds of an inch.
|
||||||
let webGLContext = new WebGLContext({
|
*/
|
||||||
enable: params.enableWebGL,
|
get userUnit() {
|
||||||
});
|
return this._pageInfo.userUnit;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.intentStates[renderingIntent]) {
|
/**
|
||||||
this.intentStates[renderingIntent] = Object.create(null);
|
* @return {Array} An array of the visible portion of the PDF page in the
|
||||||
}
|
* user space units - [x1, y1, x2, y2].
|
||||||
var intentState = this.intentStates[renderingIntent];
|
*/
|
||||||
|
get view() {
|
||||||
|
return this._pageInfo.view;
|
||||||
|
}
|
||||||
|
|
||||||
// If there's no displayReadyCapability yet, then the operatorList
|
/**
|
||||||
// was never requested before. Make the request and create the promise.
|
* @param {number} scale The desired scale of the viewport.
|
||||||
if (!intentState.displayReadyCapability) {
|
* @param {number} rotate Degrees to rotate the viewport. If omitted this
|
||||||
intentState.receivingOperatorList = true;
|
* defaults to the page rotation.
|
||||||
intentState.displayReadyCapability = createPromiseCapability();
|
* @param {boolean} dontFlip (optional) If true, axis Y will not be flipped.
|
||||||
intentState.operatorList = {
|
* @return {PageViewport} Contains 'width' and 'height' properties
|
||||||
fnArray: [],
|
* along with transforms required for rendering.
|
||||||
argsArray: [],
|
*/
|
||||||
lastChunk: false,
|
getViewport(scale, rotate = this.rotate, dontFlip = false) {
|
||||||
};
|
return new PageViewport({
|
||||||
|
viewBox: this.view,
|
||||||
|
scale,
|
||||||
|
rotation: rotate,
|
||||||
|
dontFlip,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
stats.time('Page Request');
|
/**
|
||||||
this.transport.messageHandler.send('RenderPageRequest', {
|
* @param {GetAnnotationsParameters} params - Annotation parameters.
|
||||||
pageIndex: this.pageNumber - 1,
|
* @return {Promise} A promise that is resolved with an {Array} of the
|
||||||
intent: renderingIntent,
|
* annotation objects.
|
||||||
renderInteractiveForms: (params.renderInteractiveForms === true),
|
*/
|
||||||
});
|
getAnnotations({ intent = null, } = {}) {
|
||||||
}
|
if (!this.annotationsPromise || this.annotationsIntent !== intent) {
|
||||||
|
this.annotationsPromise = this._transport.getAnnotations(this.pageIndex,
|
||||||
|
intent);
|
||||||
|
this.annotationsIntent = intent;
|
||||||
|
}
|
||||||
|
return this.annotationsPromise;
|
||||||
|
}
|
||||||
|
|
||||||
var complete = (error) => {
|
/**
|
||||||
var i = intentState.renderTasks.indexOf(internalRenderTask);
|
* Begins the process of rendering a page to the desired context.
|
||||||
if (i >= 0) {
|
* @param {RenderParameters} params Page render parameters.
|
||||||
intentState.renderTasks.splice(i, 1);
|
* @return {RenderTask} An object that contains the promise, which
|
||||||
}
|
* is resolved when the page finishes rendering.
|
||||||
|
*/
|
||||||
|
render({ canvasContext, viewport, intent = 'display', enableWebGL = false,
|
||||||
|
renderInteractiveForms = false, transform = null, imageLayer = null,
|
||||||
|
canvasFactory = null, background = null, }) {
|
||||||
|
const stats = this._stats;
|
||||||
|
stats.time('Overall');
|
||||||
|
|
||||||
if (this.cleanupAfterRender) {
|
// If there was a pending destroy cancel it so no cleanup happens during
|
||||||
this.pendingCleanup = true;
|
// this call to render.
|
||||||
}
|
this.pendingCleanup = false;
|
||||||
this._tryCleanup();
|
|
||||||
|
|
||||||
if (error) {
|
const renderingIntent = (intent === 'print' ? 'print' : 'display');
|
||||||
internalRenderTask.capability.reject(error);
|
const canvasFactoryInstance = canvasFactory || new DOMCanvasFactory();
|
||||||
} else {
|
const webGLContext = new WebGLContext({
|
||||||
internalRenderTask.capability.resolve();
|
enable: enableWebGL,
|
||||||
}
|
});
|
||||||
stats.timeEnd('Rendering');
|
|
||||||
stats.timeEnd('Overall');
|
if (!this.intentStates[renderingIntent]) {
|
||||||
|
this.intentStates[renderingIntent] = Object.create(null);
|
||||||
|
}
|
||||||
|
const intentState = this.intentStates[renderingIntent];
|
||||||
|
|
||||||
|
// If there's no displayReadyCapability yet, then the operatorList
|
||||||
|
// was never requested before. Make the request and create the promise.
|
||||||
|
if (!intentState.displayReadyCapability) {
|
||||||
|
intentState.receivingOperatorList = true;
|
||||||
|
intentState.displayReadyCapability = createPromiseCapability();
|
||||||
|
intentState.operatorList = {
|
||||||
|
fnArray: [],
|
||||||
|
argsArray: [],
|
||||||
|
lastChunk: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var internalRenderTask = new InternalRenderTask(complete, params,
|
stats.time('Page Request');
|
||||||
|
this._transport.messageHandler.send('RenderPageRequest', {
|
||||||
|
pageIndex: this.pageNumber - 1,
|
||||||
|
intent: renderingIntent,
|
||||||
|
renderInteractiveForms: renderInteractiveForms === true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const complete = (error) => {
|
||||||
|
const i = intentState.renderTasks.indexOf(internalRenderTask);
|
||||||
|
if (i >= 0) {
|
||||||
|
intentState.renderTasks.splice(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cleanupAfterRender) {
|
||||||
|
this.pendingCleanup = true;
|
||||||
|
}
|
||||||
|
this._tryCleanup();
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
internalRenderTask.capability.reject(error);
|
||||||
|
} else {
|
||||||
|
internalRenderTask.capability.resolve();
|
||||||
|
}
|
||||||
|
stats.timeEnd('Rendering');
|
||||||
|
stats.timeEnd('Overall');
|
||||||
|
};
|
||||||
|
|
||||||
|
const internalRenderTask = new InternalRenderTask(complete, {
|
||||||
|
canvasContext,
|
||||||
|
viewport,
|
||||||
|
transform,
|
||||||
|
imageLayer,
|
||||||
|
background,
|
||||||
|
},
|
||||||
this.objs,
|
this.objs,
|
||||||
this.commonObjs,
|
this.commonObjs,
|
||||||
intentState.operatorList,
|
intentState.operatorList,
|
||||||
this.pageNumber,
|
this.pageNumber,
|
||||||
canvasFactory,
|
canvasFactoryInstance,
|
||||||
webGLContext,
|
webGLContext,
|
||||||
this._pdfBug);
|
this._pdfBug);
|
||||||
internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print';
|
internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print';
|
||||||
if (!intentState.renderTasks) {
|
if (!intentState.renderTasks) {
|
||||||
intentState.renderTasks = [];
|
intentState.renderTasks = [];
|
||||||
}
|
}
|
||||||
intentState.renderTasks.push(internalRenderTask);
|
intentState.renderTasks.push(internalRenderTask);
|
||||||
var renderTask = internalRenderTask.task;
|
const renderTask = internalRenderTask.task;
|
||||||
|
|
||||||
intentState.displayReadyCapability.promise.then((transparency) => {
|
intentState.displayReadyCapability.promise.then((transparency) => {
|
||||||
if (this.pendingCleanup) {
|
if (this.pendingCleanup) {
|
||||||
complete();
|
complete();
|
||||||
return;
|
|
||||||
}
|
|
||||||
stats.time('Rendering');
|
|
||||||
internalRenderTask.initializeGraphics(transparency);
|
|
||||||
internalRenderTask.operatorListChanged();
|
|
||||||
}).catch(complete);
|
|
||||||
|
|
||||||
return renderTask;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {Promise} A promise resolved with an {@link PDFOperatorList}
|
|
||||||
* object that represents page's operator list.
|
|
||||||
*/
|
|
||||||
getOperatorList: function PDFPageProxy_getOperatorList() {
|
|
||||||
function operatorListChanged() {
|
|
||||||
if (intentState.operatorList.lastChunk) {
|
|
||||||
intentState.opListReadCapability.resolve(intentState.operatorList);
|
|
||||||
|
|
||||||
var i = intentState.renderTasks.indexOf(opListTask);
|
|
||||||
if (i >= 0) {
|
|
||||||
intentState.renderTasks.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderingIntent = 'oplist';
|
|
||||||
if (!this.intentStates[renderingIntent]) {
|
|
||||||
this.intentStates[renderingIntent] = Object.create(null);
|
|
||||||
}
|
|
||||||
var intentState = this.intentStates[renderingIntent];
|
|
||||||
var opListTask;
|
|
||||||
|
|
||||||
if (!intentState.opListReadCapability) {
|
|
||||||
opListTask = {};
|
|
||||||
opListTask.operatorListChanged = operatorListChanged;
|
|
||||||
intentState.receivingOperatorList = true;
|
|
||||||
intentState.opListReadCapability = createPromiseCapability();
|
|
||||||
intentState.renderTasks = [];
|
|
||||||
intentState.renderTasks.push(opListTask);
|
|
||||||
intentState.operatorList = {
|
|
||||||
fnArray: [],
|
|
||||||
argsArray: [],
|
|
||||||
lastChunk: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this._stats.time('Page Request');
|
|
||||||
this.transport.messageHandler.send('RenderPageRequest', {
|
|
||||||
pageIndex: this.pageIndex,
|
|
||||||
intent: renderingIntent,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return intentState.opListReadCapability.promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {getTextContentParameters} params - getTextContent parameters.
|
|
||||||
* @return {ReadableStream} ReadableStream to read textContent chunks.
|
|
||||||
*/
|
|
||||||
streamTextContent(params = {}) {
|
|
||||||
const TEXT_CONTENT_CHUNK_SIZE = 100;
|
|
||||||
return this.transport.messageHandler.sendWithStream('GetTextContent', {
|
|
||||||
pageIndex: this.pageNumber - 1,
|
|
||||||
normalizeWhitespace: (params.normalizeWhitespace === true),
|
|
||||||
combineTextItems: (params.disableCombineTextItems !== true),
|
|
||||||
}, {
|
|
||||||
highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
|
|
||||||
size(textContent) {
|
|
||||||
return textContent.items.length;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {getTextContentParameters} params - getTextContent parameters.
|
|
||||||
* @return {Promise} That is resolved a {@link TextContent}
|
|
||||||
* object that represent the page text content.
|
|
||||||
*/
|
|
||||||
getTextContent: function PDFPageProxy_getTextContent(params) {
|
|
||||||
params = params || {};
|
|
||||||
let readableStream = this.streamTextContent(params);
|
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
function pump() {
|
|
||||||
reader.read().then(function({ value, done, }) {
|
|
||||||
if (done) {
|
|
||||||
resolve(textContent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.assign(textContent.styles, value.styles);
|
|
||||||
textContent.items.push(...value.items);
|
|
||||||
pump();
|
|
||||||
}, reject);
|
|
||||||
}
|
|
||||||
|
|
||||||
let reader = readableStream.getReader();
|
|
||||||
let textContent = {
|
|
||||||
items: [],
|
|
||||||
styles: Object.create(null),
|
|
||||||
};
|
|
||||||
|
|
||||||
pump();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys page object.
|
|
||||||
*/
|
|
||||||
_destroy: function PDFPageProxy_destroy() {
|
|
||||||
this.destroyed = true;
|
|
||||||
this.transport.pageCache[this.pageIndex] = null;
|
|
||||||
|
|
||||||
var waitOn = [];
|
|
||||||
Object.keys(this.intentStates).forEach(function(intent) {
|
|
||||||
if (intent === 'oplist') {
|
|
||||||
// Avoid errors below, since the renderTasks are just stubs.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var intentState = this.intentStates[intent];
|
|
||||||
intentState.renderTasks.forEach(function(renderTask) {
|
|
||||||
var renderCompleted = renderTask.capability.promise.
|
|
||||||
catch(function () {}); // ignoring failures
|
|
||||||
waitOn.push(renderCompleted);
|
|
||||||
renderTask.cancel();
|
|
||||||
});
|
|
||||||
}, this);
|
|
||||||
this.objs.clear();
|
|
||||||
this.annotationsPromise = null;
|
|
||||||
this.pendingCleanup = false;
|
|
||||||
return Promise.all(waitOn);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans up resources allocated by the page.
|
|
||||||
* @param {boolean} resetStats - (optional) Reset page stats, if enabled.
|
|
||||||
* The default value is `false`.
|
|
||||||
*/
|
|
||||||
cleanup(resetStats = false) {
|
|
||||||
this.pendingCleanup = true;
|
|
||||||
this._tryCleanup(resetStats);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* For internal use only. Attempts to clean up if rendering is in a state
|
|
||||||
* where that's possible.
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
_tryCleanup(resetStats = false) {
|
|
||||||
if (!this.pendingCleanup ||
|
|
||||||
Object.keys(this.intentStates).some(function(intent) {
|
|
||||||
var intentState = this.intentStates[intent];
|
|
||||||
return (intentState.renderTasks.length !== 0 ||
|
|
||||||
intentState.receivingOperatorList);
|
|
||||||
}, this)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
stats.time('Rendering');
|
||||||
|
internalRenderTask.initializeGraphics(transparency);
|
||||||
|
internalRenderTask.operatorListChanged();
|
||||||
|
}).catch(complete);
|
||||||
|
|
||||||
Object.keys(this.intentStates).forEach(function(intent) {
|
return renderTask;
|
||||||
delete this.intentStates[intent];
|
}
|
||||||
}, this);
|
|
||||||
this.objs.clear();
|
|
||||||
this.annotationsPromise = null;
|
|
||||||
if (resetStats && this._stats instanceof StatTimer) {
|
|
||||||
this._stats = new StatTimer();
|
|
||||||
}
|
|
||||||
this.pendingCleanup = false;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* For internal use only.
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
_startRenderPage: function PDFPageProxy_startRenderPage(transparency,
|
|
||||||
intent) {
|
|
||||||
var intentState = this.intentStates[intent];
|
|
||||||
// TODO Refactor RenderPageRequest to separate rendering
|
|
||||||
// and operator list logic
|
|
||||||
if (intentState.displayReadyCapability) {
|
|
||||||
intentState.displayReadyCapability.resolve(transparency);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* For internal use only.
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
_renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
|
|
||||||
intent) {
|
|
||||||
var intentState = this.intentStates[intent];
|
|
||||||
var i, ii;
|
|
||||||
// Add the new chunk to the current operator list.
|
|
||||||
for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
|
|
||||||
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
|
|
||||||
intentState.operatorList.argsArray.push(
|
|
||||||
operatorListChunk.argsArray[i]);
|
|
||||||
}
|
|
||||||
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
|
|
||||||
|
|
||||||
// Notify all the rendering tasks there are more operators to be consumed.
|
/**
|
||||||
for (i = 0; i < intentState.renderTasks.length; i++) {
|
* @return {Promise} A promise resolved with an {@link PDFOperatorList}
|
||||||
intentState.renderTasks[i].operatorListChanged();
|
* object that represents page's operator list.
|
||||||
|
*/
|
||||||
|
getOperatorList() {
|
||||||
|
function operatorListChanged() {
|
||||||
|
if (intentState.operatorList.lastChunk) {
|
||||||
|
intentState.opListReadCapability.resolve(intentState.operatorList);
|
||||||
|
|
||||||
|
const i = intentState.renderTasks.indexOf(opListTask);
|
||||||
|
if (i >= 0) {
|
||||||
|
intentState.renderTasks.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderingIntent = 'oplist';
|
||||||
|
if (!this.intentStates[renderingIntent]) {
|
||||||
|
this.intentStates[renderingIntent] = Object.create(null);
|
||||||
|
}
|
||||||
|
const intentState = this.intentStates[renderingIntent];
|
||||||
|
let opListTask;
|
||||||
|
|
||||||
|
if (!intentState.opListReadCapability) {
|
||||||
|
opListTask = {};
|
||||||
|
opListTask.operatorListChanged = operatorListChanged;
|
||||||
|
intentState.receivingOperatorList = true;
|
||||||
|
intentState.opListReadCapability = createPromiseCapability();
|
||||||
|
intentState.renderTasks = [];
|
||||||
|
intentState.renderTasks.push(opListTask);
|
||||||
|
intentState.operatorList = {
|
||||||
|
fnArray: [],
|
||||||
|
argsArray: [],
|
||||||
|
lastChunk: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._stats.time('Page Request');
|
||||||
|
this._transport.messageHandler.send('RenderPageRequest', {
|
||||||
|
pageIndex: this.pageIndex,
|
||||||
|
intent: renderingIntent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return intentState.opListReadCapability.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {getTextContentParameters} params - getTextContent parameters.
|
||||||
|
* @return {ReadableStream} ReadableStream to read textContent chunks.
|
||||||
|
*/
|
||||||
|
streamTextContent({ normalizeWhitespace = false,
|
||||||
|
disableCombineTextItems = false, } = {}) {
|
||||||
|
const TEXT_CONTENT_CHUNK_SIZE = 100;
|
||||||
|
|
||||||
|
return this._transport.messageHandler.sendWithStream('GetTextContent', {
|
||||||
|
pageIndex: this.pageNumber - 1,
|
||||||
|
normalizeWhitespace: normalizeWhitespace === true,
|
||||||
|
combineTextItems: disableCombineTextItems !== true,
|
||||||
|
}, {
|
||||||
|
highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
|
||||||
|
size(textContent) {
|
||||||
|
return textContent.items.length;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {getTextContentParameters} params - getTextContent parameters.
|
||||||
|
* @return {Promise} That is resolved a {@link TextContent}
|
||||||
|
* object that represent the page text content.
|
||||||
|
*/
|
||||||
|
getTextContent(params = {}) {
|
||||||
|
const readableStream = this.streamTextContent(params);
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
function pump() {
|
||||||
|
reader.read().then(function({ value, done, }) {
|
||||||
|
if (done) {
|
||||||
|
resolve(textContent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object.assign(textContent.styles, value.styles);
|
||||||
|
textContent.items.push(...value.items);
|
||||||
|
pump();
|
||||||
|
}, reject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operatorListChunk.lastChunk) {
|
const reader = readableStream.getReader();
|
||||||
intentState.receivingOperatorList = false;
|
const textContent = {
|
||||||
this._tryCleanup();
|
items: [],
|
||||||
}
|
styles: Object.create(null),
|
||||||
},
|
};
|
||||||
|
pump();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {Object} Returns page stats, if enabled.
|
* Destroys page object.
|
||||||
*/
|
*/
|
||||||
get stats() {
|
_destroy() {
|
||||||
return (this._stats instanceof StatTimer ? this._stats : null);
|
this.destroyed = true;
|
||||||
},
|
this._transport.pageCache[this.pageIndex] = null;
|
||||||
};
|
|
||||||
return PDFPageProxy;
|
const waitOn = [];
|
||||||
})();
|
Object.keys(this.intentStates).forEach(function(intent) {
|
||||||
|
if (intent === 'oplist') {
|
||||||
|
// Avoid errors below, since the renderTasks are just stubs.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const intentState = this.intentStates[intent];
|
||||||
|
intentState.renderTasks.forEach(function(renderTask) {
|
||||||
|
const renderCompleted = renderTask.capability.promise.
|
||||||
|
catch(function() {}); // ignoring failures
|
||||||
|
waitOn.push(renderCompleted);
|
||||||
|
renderTask.cancel();
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
this.objs.clear();
|
||||||
|
this.annotationsPromise = null;
|
||||||
|
this.pendingCleanup = false;
|
||||||
|
return Promise.all(waitOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up resources allocated by the page.
|
||||||
|
* @param {boolean} resetStats - (optional) Reset page stats, if enabled.
|
||||||
|
* The default value is `false`.
|
||||||
|
*/
|
||||||
|
cleanup(resetStats = false) {
|
||||||
|
this.pendingCleanup = true;
|
||||||
|
this._tryCleanup(resetStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For internal use only. Attempts to clean up if rendering is in a state
|
||||||
|
* where that's possible.
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
_tryCleanup(resetStats = false) {
|
||||||
|
if (!this.pendingCleanup ||
|
||||||
|
Object.keys(this.intentStates).some(function(intent) {
|
||||||
|
const intentState = this.intentStates[intent];
|
||||||
|
return (intentState.renderTasks.length !== 0 ||
|
||||||
|
intentState.receivingOperatorList);
|
||||||
|
}, this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(this.intentStates).forEach(function(intent) {
|
||||||
|
delete this.intentStates[intent];
|
||||||
|
}, this);
|
||||||
|
this.objs.clear();
|
||||||
|
this.annotationsPromise = null;
|
||||||
|
if (resetStats && this._stats instanceof StatTimer) {
|
||||||
|
this._stats = new StatTimer();
|
||||||
|
}
|
||||||
|
this.pendingCleanup = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For internal use only.
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
_startRenderPage(transparency, intent) {
|
||||||
|
const intentState = this.intentStates[intent];
|
||||||
|
// TODO Refactor RenderPageRequest to separate rendering
|
||||||
|
// and operator list logic
|
||||||
|
if (intentState.displayReadyCapability) {
|
||||||
|
intentState.displayReadyCapability.resolve(transparency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For internal use only.
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
_renderPageChunk(operatorListChunk, intent) {
|
||||||
|
const intentState = this.intentStates[intent];
|
||||||
|
// Add the new chunk to the current operator list.
|
||||||
|
for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
|
||||||
|
intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
|
||||||
|
intentState.operatorList.argsArray.push(
|
||||||
|
operatorListChunk.argsArray[i]);
|
||||||
|
}
|
||||||
|
intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
|
||||||
|
|
||||||
|
// Notify all the rendering tasks there are more operators to be consumed.
|
||||||
|
for (let i = 0; i < intentState.renderTasks.length; i++) {
|
||||||
|
intentState.renderTasks[i].operatorListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operatorListChunk.lastChunk) {
|
||||||
|
intentState.receivingOperatorList = false;
|
||||||
|
this._tryCleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Object} Returns page stats, if enabled.
|
||||||
|
*/
|
||||||
|
get stats() {
|
||||||
|
return (this._stats instanceof StatTimer ? this._stats : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LoopbackPort {
|
class LoopbackPort {
|
||||||
constructor(defer = true) {
|
constructor(defer = true) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user