From ef8e5fd77c809b6589716a5f1d5f68e24862c3e6 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 8 Nov 2018 13:40:06 +0100 Subject: [PATCH 1/6] Convert `PDFDocumentLoadingTask`, in `src/display/api.js`, to an ES6 class Also deprecates the `then` method, in favour of the `promise` getter. --- examples/acroforms/acroforms.js | 3 +- examples/components/pageviewer.js | 5 +- examples/components/simpleviewer.js | 5 +- examples/components/singlepageviewer.js | 5 +- examples/learning/helloworld.html | 5 +- examples/learning/helloworld64.html | 5 +- examples/learning/prevnext.html | 3 +- examples/node/getinfo.js | 3 +- examples/node/pdf2png/pdf2png.js | 3 +- examples/node/pdf2svg.js | 5 +- examples/svgviewer/viewer.js | 5 +- examples/text-only/pdf2svg.js | 3 +- src/display/api.js | 95 +++++++++++++------------ test/driver.js | 5 +- 14 files changed, 82 insertions(+), 68 deletions(-) diff --git a/examples/acroforms/acroforms.js b/examples/acroforms/acroforms.js index 0e708f3cb..795e992b4 100644 --- a/examples/acroforms/acroforms.js +++ b/examples/acroforms/acroforms.js @@ -24,7 +24,8 @@ var DEFAULT_SCALE = 1.0; var container = document.getElementById('pageContainer'); // Fetch the PDF document from the URL using promises. -pdfjsLib.getDocument(DEFAULT_URL).then(function (doc) { +var loadingTask = pdfjsLib.getDocument(DEFAULT_URL); +loadingTask.promise.then(function(doc) { // Use a promise to fetch and render the next page. var promise = Promise.resolve(); diff --git a/examples/components/pageviewer.js b/examples/components/pageviewer.js index 3eaabc6c8..df69fdad0 100644 --- a/examples/components/pageviewer.js +++ b/examples/components/pageviewer.js @@ -37,11 +37,12 @@ var SCALE = 1.0; var container = document.getElementById('pageContainer'); // Loading document. -pdfjsLib.getDocument({ +var loadingTask = pdfjsLib.getDocument({ url: DEFAULT_URL, cMapUrl: CMAP_URL, cMapPacked: CMAP_PACKED, -}).then(function(pdfDocument) { +}); +loadingTask.promise.then(function(pdfDocument) { // Document loaded, retrieving the page. return pdfDocument.getPage(PAGE_TO_VIEW).then(function (pdfPage) { // Creating the page view with default parameters. diff --git a/examples/components/simpleviewer.js b/examples/components/simpleviewer.js index 1f801bbd2..b0b268dee 100644 --- a/examples/components/simpleviewer.js +++ b/examples/components/simpleviewer.js @@ -60,11 +60,12 @@ document.addEventListener('pagesinit', function () { }); // Loading document. -pdfjsLib.getDocument({ +var loadingTask = pdfjsLib.getDocument({ url: DEFAULT_URL, cMapUrl: CMAP_URL, cMapPacked: CMAP_PACKED, -}).then(function(pdfDocument) { +}); +loadingTask.promise.then(function(pdfDocument) { // Document loaded, specifying document for the viewer and // the (optional) linkService. pdfViewer.setDocument(pdfDocument); diff --git a/examples/components/singlepageviewer.js b/examples/components/singlepageviewer.js index d4b5da3e7..d6157f4b1 100644 --- a/examples/components/singlepageviewer.js +++ b/examples/components/singlepageviewer.js @@ -60,11 +60,12 @@ document.addEventListener('pagesinit', function () { }); // Loading document. -pdfjsLib.getDocument({ +var loadingTask = pdfjsLib.getDocument({ url: DEFAULT_URL, cMapUrl: CMAP_URL, cMapPacked: CMAP_PACKED, -}).then(function(pdfDocument) { +}); +loadingTask.promise.then(function(pdfDocument) { // Document loaded, specifying document for the viewer and // the (optional) linkService. pdfSinglePageViewer.setDocument(pdfDocument); diff --git a/examples/learning/helloworld.html b/examples/learning/helloworld.html index c4a6456d2..c73f0329d 100644 --- a/examples/learning/helloworld.html +++ b/examples/learning/helloworld.html @@ -28,11 +28,12 @@ // // Asynchronous download PDF // - pdfjsLib.getDocument(url).then(function getPdfHelloWorld(pdf) { + var loadingTask = pdfjsLib.getDocument(url); + loadingTask.promise.then(function(pdf) { // // Fetch the first page // - pdf.getPage(1).then(function getPageHelloWorld(page) { + pdf.getPage(1).then(function(page) { var scale = 1.5; var viewport = page.getViewport(scale); diff --git a/examples/learning/helloworld64.html b/examples/learning/helloworld64.html index f32d69000..d316a6a06 100644 --- a/examples/learning/helloworld64.html +++ b/examples/learning/helloworld64.html @@ -39,9 +39,10 @@ // Opening PDF by passing its binary data as a string. It is still preferable // to use Uint8Array, but string or array-like structure will work too. - pdfjsLib.getDocument({data: pdfData}).then(function getPdfHelloWorld(pdf) { + var loadingTask = pdfjsLib.getDocument({data: pdfData}); + loadingTask.promise.then(function(pdf) { // Fetch the first page. - pdf.getPage(1).then(function getPageHelloWorld(page) { + pdf.getPage(1).then(function(page) { var scale = 1.5; var viewport = page.getViewport(scale); diff --git a/examples/learning/prevnext.html b/examples/learning/prevnext.html index df1098882..32fc72476 100644 --- a/examples/learning/prevnext.html +++ b/examples/learning/prevnext.html @@ -117,7 +117,8 @@ /** * Asynchronously downloads PDF. */ - pdfjsLib.getDocument(url).then(function (pdfDoc_) { + var loadingTask = pdfjsLib.getDocument(url); + loadingTask.promise.then(function(pdfDoc_) { pdfDoc = pdfDoc_; document.getElementById('page_count').textContent = pdfDoc.numPages; diff --git a/examples/node/getinfo.js b/examples/node/getinfo.js index 61034cfa3..72eeff48e 100644 --- a/examples/node/getinfo.js +++ b/examples/node/getinfo.js @@ -17,7 +17,8 @@ var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf'; // Will be using promises to load document, pages and misc data instead of // callback. -pdfjsLib.getDocument(pdfPath).then(function (doc) { +var loadingTask = pdfjsLib.getDocument(pdfPath); +loadingTask.promise.then(function(doc) { var numPages = doc.numPages; console.log('# Document Loaded'); console.log('Number of Pages: ' + numPages); diff --git a/examples/node/pdf2png/pdf2png.js b/examples/node/pdf2png/pdf2png.js index ae739a35b..08e06aea3 100644 --- a/examples/node/pdf2png/pdf2png.js +++ b/examples/node/pdf2png/pdf2png.js @@ -57,7 +57,8 @@ var pdfURL = '../../../web/compressed.tracemonkey-pldi-09.pdf'; var rawData = new Uint8Array(fs.readFileSync(pdfURL)); // Load the PDF file. -pdfjsLib.getDocument(rawData).then(function (pdfDocument) { +var loadingTask = pdfjsLib.getDocument(rawData); +loadingTask.promise.then(function(pdfDocument) { console.log('# PDF document loaded.'); // Get the first page. diff --git a/examples/node/pdf2svg.js b/examples/node/pdf2svg.js index 4c59cb78c..fe3372bdb 100644 --- a/examples/node/pdf2svg.js +++ b/examples/node/pdf2svg.js @@ -84,11 +84,12 @@ function writeSvgToFile(svgElement, filePath) { // Will be using promises to load document, pages and misc data instead of // callback. -pdfjsLib.getDocument({ +var loadingTask = pdfjsLib.getDocument({ data: data, // Try to export JPEG images directly if they don't need any further processing. nativeImageDecoderSupport: pdfjsLib.NativeImageDecoding.DISPLAY -}).then(function (doc) { +}); +loadingTask.promise.then(function(doc) { var numPages = doc.numPages; console.log('# Document Loaded'); console.log('Number of Pages: ' + numPages); diff --git a/examples/svgviewer/viewer.js b/examples/svgviewer/viewer.js index bcea1fa08..433d981be 100644 --- a/examples/svgviewer/viewer.js +++ b/examples/svgviewer/viewer.js @@ -51,11 +51,12 @@ document.addEventListener('pagesinit', function () { }); // Loading document. -pdfjsLib.getDocument({ +var loadingTask = pdfjsLib.getDocument({ url: DEFAULT_URL, cMapUrl: CMAP_URL, cMapPacked: CMAP_PACKED, -}).then(function(pdfDocument) { +}); +loadingTask.promise.then(function(pdfDocument) { // Document loaded, specifying document for the viewer and // the (optional) linkService. pdfViewer.setDocument(pdfDocument); diff --git a/examples/text-only/pdf2svg.js b/examples/text-only/pdf2svg.js index 64395cdeb..27094c46e 100644 --- a/examples/text-only/pdf2svg.js +++ b/examples/text-only/pdf2svg.js @@ -49,7 +49,8 @@ function buildSVG(viewport, textContent) { function pageLoaded() { // Loading document and page text content - pdfjsLib.getDocument({url: PDF_PATH}).then(function (pdfDocument) { + var loadingTask = pdfjsLib.getDocument({url: PDF_PATH}); + loadingTask.promise.then(function(pdfDocument) { pdfDocument.getPage(PAGE_NUMBER).then(function (page) { var viewport = page.getViewport(PAGE_SCALE); page.getTextContent().then(function (textContent) { diff --git a/src/display/api.js b/src/display/api.js index a3ff31530..57ee38f99 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -15,10 +15,11 @@ /* globals requirejs, __non_webpack_require__ */ import { - assert, createPromiseCapability, getVerbosityLevel, info, InvalidPDFException, - isArrayBuffer, isSameOrigin, MissingPDFException, NativeImageDecoding, - PasswordException, setVerbosityLevel, shadow, stringToBytes, - UnexpectedResponseException, UnknownErrorException, unreachable, URL, warn + assert, createPromiseCapability, deprecated, getVerbosityLevel, info, + InvalidPDFException, isArrayBuffer, isSameOrigin, MissingPDFException, + NativeImageDecoding, PasswordException, setVerbosityLevel, shadow, + stringToBytes, UnexpectedResponseException, UnknownErrorException, + unreachable, URL, warn } from '../shared/util'; import { DOMCanvasFactory, DOMCMapReaderFactory, DummyStatTimer, loadScript, @@ -427,56 +428,55 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { * @class * @alias PDFDocumentLoadingTask */ -var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { - var nextDocumentId = 0; +const PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { + let nextDocumentId = 0; /** @constructs PDFDocumentLoadingTask */ - function PDFDocumentLoadingTask() { - this._capability = createPromiseCapability(); - this._transport = null; - this._worker = null; + class PDFDocumentLoadingTask { + constructor() { + this._capability = createPromiseCapability(); + this._transport = null; + this._worker = null; - /** - * Unique document loading task id -- used in MessageHandlers. - * @type {string} - */ - this.docId = 'd' + (nextDocumentId++); + /** + * Unique document loading task id -- used in MessageHandlers. + * @type {string} + */ + this.docId = 'd' + (nextDocumentId++); - /** - * Shows if loading task is destroyed. - * @type {boolean} - */ - this.destroyed = false; + /** + * Shows if loading task is destroyed. + * @type {boolean} + */ + this.destroyed = false; - /** - * Callback to request a password if wrong or no password was provided. - * The callback receives two parameters: function that needs to be called - * with new password and reason (see {PasswordResponses}). - */ - this.onPassword = null; + /** + * Callback to request a password if wrong or no password was provided. + * The callback receives two parameters: function that needs to be called + * with new password and reason (see {PasswordResponses}). + */ + 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 {Object} with the properties: {number} loaded and {number} total. - */ - this.onProgress = 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 {Object} with the properties: {number} loaded and {number} total. + */ + this.onProgress = null; - /** - * Callback to when unsupported feature is used. The callback receives - * an {UNSUPPORTED_FEATURES} argument. - */ - this.onUnsupportedFeature = null; - } + /** + * Callback to when unsupported feature is used. The callback receives + * an {UNSUPPORTED_FEATURES} argument. + */ + this.onUnsupportedFeature = null; + } - PDFDocumentLoadingTask.prototype = - /** @lends PDFDocumentLoadingTask.prototype */ { /** * @return {Promise} */ get promise() { return this._capability.promise; - }, + } /** * Aborts all network requests and destroys worker. @@ -486,7 +486,7 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { destroy() { this.destroyed = true; - var transportDestroyed = !this._transport ? Promise.resolve() : + const transportDestroyed = !this._transport ? Promise.resolve() : this._transport.destroy(); return transportDestroyed.then(() => { this._transport = null; @@ -495,7 +495,7 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { this._worker = null; } }); - }, + } /** * Registers callbacks to indicate the document loading completion. @@ -505,11 +505,12 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() { * @return {Promise} A promise that is resolved after the onFulfilled or * onRejected callback. */ - then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) { + then(onFulfilled, onRejected) { + deprecated('PDFDocumentLoadingTask.then method, ' + + 'use the `promise` getter instead.'); return this.promise.then.apply(this.promise, arguments); - }, - }; - + } + } return PDFDocumentLoadingTask; })(); diff --git a/test/driver.js b/test/driver.js index d9b3f1543..ae23dee2c 100644 --- a/test/driver.js +++ b/test/driver.js @@ -358,7 +358,7 @@ var Driver = (function DriverClosure() { // eslint-disable-line no-unused-vars let absoluteUrl = new URL(task.file, window.location).href; try { - pdfjsLib.getDocument({ + const loadingTask = pdfjsLib.getDocument({ url: absoluteUrl, password: task.password, nativeImageDecoderSupport: task.nativeImageDecoderSupport, @@ -367,7 +367,8 @@ var Driver = (function DriverClosure() { // eslint-disable-line no-unused-vars disableRange: task.disableRange, disableAutoFetch: !task.enableAutoFetch, pdfBug: true, - }).then((doc) => { + }); + loadingTask.promise.then((doc) => { task.pdfDoc = doc; this._nextPage(task, failure); }, (err) => { From 2c003a82d57b5ad778fbf221a86f1d1408c02952 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 8 Nov 2018 13:46:02 +0100 Subject: [PATCH 2/6] Convert `RenderTask`, in `src/display/api.js`, to an ES6 class Also deprecates the `then` method, in favour of the `promise` getter. --- examples/node/pdf2png/pdf2png.js | 3 +- src/display/api.js | 64 +++++++++++++++----------------- test/unit/api_spec.js | 35 ++++++++--------- test/unit/custom_spec.js | 40 ++++++++------------ 4 files changed, 63 insertions(+), 79 deletions(-) diff --git a/examples/node/pdf2png/pdf2png.js b/examples/node/pdf2png/pdf2png.js index 08e06aea3..fe0cc74af 100644 --- a/examples/node/pdf2png/pdf2png.js +++ b/examples/node/pdf2png/pdf2png.js @@ -73,7 +73,8 @@ loadingTask.promise.then(function(pdfDocument) { canvasFactory: canvasFactory }; - page.render(renderContext).then(function () { + var renderTask = page.render(renderContext); + renderTask.promise.then(function() { // Convert the canvas to an image buffer. var image = canvasAndContext.canvas.toBuffer(); fs.writeFile('output.png', image, function (error) { diff --git a/src/display/api.js b/src/display/api.js index 57ee38f99..0e4213af4 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -2280,11 +2280,10 @@ class PDFObjects { /** * Allows controlling of the rendering tasks. - * @class * @alias RenderTask */ -var RenderTask = (function RenderTaskClosure() { - function RenderTask(internalRenderTask) { +class RenderTask { + constructor(internalRenderTask) { this._internalRenderTask = internalRenderTask; /** @@ -2296,39 +2295,36 @@ var RenderTask = (function RenderTaskClosure() { this.onContinue = null; } - RenderTask.prototype = /** @lends RenderTask.prototype */ { - /** - * Promise for rendering task completion. - * @return {Promise} - */ - get promise() { - return this._internalRenderTask.capability.promise; - }, + /** + * Promise for rendering task completion. + * @return {Promise} + */ + get promise() { + return this._internalRenderTask.capability.promise; + } - /** - * Cancels the rendering task. If the task is currently rendering it will - * not be cancelled until graphics pauses with a timeout. The promise that - * this object extends will be rejected when cancelled. - */ - cancel: function RenderTask_cancel() { - this._internalRenderTask.cancel(); - }, + /** + * Cancels the rendering task. If the task is currently rendering it will + * not be cancelled until graphics pauses with a timeout. The promise that + * this object extends will be rejected when cancelled. + */ + cancel() { + this._internalRenderTask.cancel(); + } - /** - * Registers callbacks to indicate the rendering task completion. - * - * @param {function} onFulfilled The callback for the rendering completion. - * @param {function} onRejected The callback for the rendering failure. - * @return {Promise} A promise that is resolved after the onFulfilled or - * onRejected callback. - */ - then: function RenderTask_then(onFulfilled, onRejected) { - return this.promise.then.apply(this.promise, arguments); - }, - }; - - return RenderTask; -})(); + /** + * Registers callbacks to indicate the rendering task completion. + * + * @param {function} onFulfilled The callback for the rendering completion. + * @param {function} onRejected The callback for the rendering failure. + * @return {Promise} A promise that is resolved after the onFulfilled or + * onRejected callback. + */ + then(onFulfilled, onRejected) { + deprecated('RenderTask.then method, use the `promise` getter instead.'); + return this.promise.then.apply(this.promise, arguments); + } +} /** * For internal use only. diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 42a287263..ead5e5d79 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -1332,26 +1332,23 @@ describe('api', function() { // Render the first page of the given PDF file. // Fulfills the promise with the base64-encoded version of the PDF. - function renderPDF(filename) { - var loadingTask = getDocument(filename); + async function renderPDF(filename) { + const loadingTask = getDocument(filename); loadingTasks.push(loadingTask); - return loadingTask.promise - .then(function(pdf) { - pdfDocuments.push(pdf); - return pdf.getPage(1); - }).then(function(page) { - var viewport = page.getViewport(1.2); - var canvasAndCtx = CanvasFactory.create(viewport.width, - viewport.height); - return page.render({ - canvasContext: canvasAndCtx.context, - viewport, - }).then(function() { - var data = canvasAndCtx.canvas.toDataURL(); - CanvasFactory.destroy(canvasAndCtx); - return data; - }); - }); + const pdf = await loadingTask.promise; + pdfDocuments.push(pdf); + const page = await pdf.getPage(1); + const viewport = page.getViewport(1.2); + const canvasAndCtx = CanvasFactory.create(viewport.width, + viewport.height); + const renderTask = page.render({ + canvasContext: canvasAndCtx.context, + viewport, + }); + await renderTask.promise; + const data = canvasAndCtx.canvas.toDataURL(); + CanvasFactory.destroy(canvasAndCtx); + return data; } afterEach(function(done) { diff --git a/test/unit/custom_spec.js b/test/unit/custom_spec.js index 40ad3e62b..83bfca554 100644 --- a/test/unit/custom_spec.js +++ b/test/unit/custom_spec.js @@ -48,9 +48,7 @@ describe('custom canvas rendering', function() { }).then(function(data) { page = data; done(); - }).catch(function (reason) { - done.fail(reason); - }); + }).catch(done.fail); }); afterAll(function(done) { @@ -66,20 +64,16 @@ describe('custom canvas rendering', function() { var viewport = page.getViewport(1); var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); - page.render({ + const renderTask = page.render({ canvasContext: canvasAndCtx.context, viewport, - }).then(function() { - var { r, g, b, a, } = getTopLeftPixel(canvasAndCtx.context); - CanvasFactory.destroy(canvasAndCtx); - expect(r).toEqual(255); - expect(g).toEqual(255); - expect(b).toEqual(255); - expect(a).toEqual(255); - done(); - }).catch(function (reason) { - done(reason); }); + renderTask.promise.then(function() { + expect(getTopLeftPixel(canvasAndCtx.context)).toEqual( + { r: 255, g: 255, b: 255, a: 255, }); + CanvasFactory.destroy(canvasAndCtx); + done(); + }).catch(done.fail); }); it('renders to canvas with a custom background', function(done) { @@ -89,20 +83,16 @@ describe('custom canvas rendering', function() { var viewport = page.getViewport(1); var canvasAndCtx = CanvasFactory.create(viewport.width, viewport.height); - page.render({ + const renderTask = page.render({ canvasContext: canvasAndCtx.context, viewport, background: 'rgba(255,0,0,1.0)', - }).then(function() { - var { r, g, b, a, } = getTopLeftPixel(canvasAndCtx.context); - CanvasFactory.destroy(canvasAndCtx); - expect(r).toEqual(255); - expect(g).toEqual(0); - expect(b).toEqual(0); - expect(a).toEqual(255); - done(); - }).catch(function (reason) { - done(reason); }); + renderTask.promise.then(function() { + expect(getTopLeftPixel(canvasAndCtx.context)).toEqual( + { r: 255, g: 0, b: 0, a: 255, }); + CanvasFactory.destroy(canvasAndCtx); + done(); + }).catch(done.fail); }); }); From 5a0d64a6de2581526b46dd001e19ad68abba5d1b Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 8 Nov 2018 14:13:42 +0100 Subject: [PATCH 3/6] 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. --- src/display/api.js | 690 +++++++++++++++++++++++---------------------- 1 file changed, 350 insertions(+), 340 deletions(-) diff --git a/src/display/api.js b/src/display/api.js index 0e4213af4..a2a551364 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -850,385 +850,395 @@ class PDFDocumentProxy { /** * Proxy to a PDFPage in the worker thread. - * @class * @alias PDFPageProxy */ -var PDFPageProxy = (function PDFPageProxyClosure() { - function PDFPageProxy(pageIndex, pageInfo, transport, pdfBug = false) { +class PDFPageProxy { + constructor(pageIndex, pageInfo, transport, pdfBug = false) { this.pageIndex = pageIndex; this._pageInfo = pageInfo; - this.transport = transport; + this._transport = transport; this._stats = (pdfBug ? new StatTimer() : DummyStatTimer); this._pdfBug = pdfBug; this.commonObjs = transport.commonObjs; this.objs = new PDFObjects(); + this.cleanupAfterRender = false; this.pendingCleanup = false; this.intentStates = Object.create(null); 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. - * @param {number} rotate Degrees to rotate the viewport. If omitted this - * defaults to the page rotation. - * @param {boolean} dontFlip (optional) If true, axis Y will not be flipped. - * @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; + /** + * @return {number} Page number of the page. First page is 1. + */ + get pageNumber() { + return this.pageIndex + 1; + } - if (!this.annotationsPromise || this.annotationsIntent !== intent) { - this.annotationsPromise = this.transport.getAnnotations(this.pageIndex, - intent); - this.annotationsIntent = intent; - } - 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'); + /** + * @return {number} The number of degrees the page is rotated clockwise. + */ + get rotate() { + return this._pageInfo.rotate; + } - // If there was a pending destroy cancel it so no cleanup happens during - // this call to render. - this.pendingCleanup = false; + /** + * @return {Object} The reference that points to this page. It has 'num' and + * 'gen' properties. + */ + get ref() { + return this._pageInfo.ref; + } - var renderingIntent = (params.intent === 'print' ? 'print' : 'display'); - var canvasFactory = params.canvasFactory || new DOMCanvasFactory(); - let webGLContext = new WebGLContext({ - enable: params.enableWebGL, - }); + /** + * @return {number} The default size of units in 1/72nds of an inch. + */ + get userUnit() { + return this._pageInfo.userUnit; + } - if (!this.intentStates[renderingIntent]) { - this.intentStates[renderingIntent] = Object.create(null); - } - var intentState = this.intentStates[renderingIntent]; + /** + * @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; + } - // 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, - }; + /** + * @param {number} scale The desired scale of the viewport. + * @param {number} rotate Degrees to rotate the viewport. If omitted this + * defaults to the page rotation. + * @param {boolean} dontFlip (optional) If true, axis Y will not be flipped. + * @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, + }); + } - stats.time('Page Request'); - this.transport.messageHandler.send('RenderPageRequest', { - pageIndex: this.pageNumber - 1, - intent: renderingIntent, - renderInteractiveForms: (params.renderInteractiveForms === true), - }); - } + /** + * @param {GetAnnotationsParameters} params - Annotation parameters. + * @return {Promise} A promise that is resolved with an {Array} of the + * annotation objects. + */ + 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); - if (i >= 0) { - intentState.renderTasks.splice(i, 1); - } + /** + * 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({ 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) { - this.pendingCleanup = true; - } - this._tryCleanup(); + // If there was a pending destroy cancel it so no cleanup happens during + // this call to render. + this.pendingCleanup = false; - if (error) { - internalRenderTask.capability.reject(error); - } else { - internalRenderTask.capability.resolve(); - } - stats.timeEnd('Rendering'); - stats.timeEnd('Overall'); + const renderingIntent = (intent === 'print' ? 'print' : 'display'); + const canvasFactoryInstance = canvasFactory || new DOMCanvasFactory(); + const webGLContext = new WebGLContext({ + enable: enableWebGL, + }); + + 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.commonObjs, intentState.operatorList, this.pageNumber, - canvasFactory, + canvasFactoryInstance, webGLContext, this._pdfBug); - internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; - if (!intentState.renderTasks) { - intentState.renderTasks = []; - } - intentState.renderTasks.push(internalRenderTask); - var renderTask = internalRenderTask.task; + internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; + if (!intentState.renderTasks) { + intentState.renderTasks = []; + } + intentState.renderTasks.push(internalRenderTask); + const renderTask = internalRenderTask.task; - intentState.displayReadyCapability.promise.then((transparency) => { - if (this.pendingCleanup) { - 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)) { + intentState.displayReadyCapability.promise.then((transparency) => { + if (this.pendingCleanup) { + complete(); return; } + stats.time('Rendering'); + internalRenderTask.initializeGraphics(transparency); + internalRenderTask.operatorListChanged(); + }).catch(complete); - 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: 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; + return renderTask; + } - // Notify all the rendering tasks there are more operators to be consumed. - for (i = 0; i < intentState.renderTasks.length; i++) { - intentState.renderTasks[i].operatorListChanged(); + /** + * @return {Promise} A promise resolved with an {@link PDFOperatorList} + * 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) { - intentState.receivingOperatorList = false; - this._tryCleanup(); - } - }, + const reader = readableStream.getReader(); + const textContent = { + items: [], + styles: Object.create(null), + }; + pump(); + }); + } - /** - * @return {Object} Returns page stats, if enabled. - */ - get stats() { - return (this._stats instanceof StatTimer ? this._stats : null); - }, - }; - return PDFPageProxy; -})(); + /** + * Destroys page object. + */ + _destroy() { + this.destroyed = true; + this._transport.pageCache[this.pageIndex] = null; + + 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 { constructor(defer = true) { From 02e77a39ec68247c619a6f67d9b8432ad40a50bc Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 8 Nov 2018 14:33:56 +0100 Subject: [PATCH 4/6] Convert `InternalRenderTask`, in `src/display/api.js`, to an ES6 class This changes all occurrences of `var` to `let`/`const` in this code, and updates the signature of the constructor to use object destructuring for better readability (and self documentation). Also, `useRequestAnimationFrame` is changed to a parameter and the `typeof window` check is now done *once* rather than at every `_scheduleNext` call. --- src/display/api.js | 173 +++++++++++++++++++++--------------------- src/display/canvas.js | 2 +- 2 files changed, 88 insertions(+), 87 deletions(-) diff --git a/src/display/api.js b/src/display/api.js index a2a551364..4d8a069e8 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -1002,21 +1002,25 @@ class PDFPageProxy { stats.timeEnd('Overall'); }; - const internalRenderTask = new InternalRenderTask(complete, { - canvasContext, - viewport, - transform, - imageLayer, - background, - }, - this.objs, - this.commonObjs, - intentState.operatorList, - this.pageNumber, - canvasFactoryInstance, - webGLContext, - this._pdfBug); - internalRenderTask.useRequestAnimationFrame = renderingIntent !== 'print'; + const internalRenderTask = new InternalRenderTask({ + callback: complete, + params: { // Include the required properties, and *not* the entire object. + canvasContext, + viewport, + transform, + imageLayer, + background, + }, + objs: this.objs, + commonObjs: this.commonObjs, + operatorList: intentState.operatorList, + pageNumber: this.pageNumber, + canvasFactory: canvasFactoryInstance, + webGLContext, + useRequestAnimationFrame: renderingIntent !== 'print', + pdfBug: this._pdfBug, + }); + if (!intentState.renderTasks) { intentState.renderTasks = []; } @@ -2340,40 +2344,40 @@ class RenderTask { * For internal use only. * @ignore */ -var InternalRenderTask = (function InternalRenderTaskClosure() { - let canvasInRendering = new WeakSet(); +const InternalRenderTask = (function InternalRenderTaskClosure() { + const canvasInRendering = new WeakSet(); - function InternalRenderTask(callback, params, objs, commonObjs, operatorList, - pageNumber, canvasFactory, webGLContext, - pdfBug = false) { - this.callback = callback; - this.params = params; - this.objs = objs; - this.commonObjs = commonObjs; - this.operatorListIdx = null; - this.operatorList = operatorList; - this.pageNumber = pageNumber; - this.canvasFactory = canvasFactory; - this.webGLContext = webGLContext; - this._pdfBug = pdfBug; + class InternalRenderTask { + constructor({ callback, params, objs, commonObjs, operatorList, pageNumber, + canvasFactory, webGLContext, useRequestAnimationFrame = false, + pdfBug = false, }) { + this.callback = callback; + this.params = params; + this.objs = objs; + this.commonObjs = commonObjs; + this.operatorListIdx = null; + this.operatorList = operatorList; + this.pageNumber = pageNumber; + this.canvasFactory = canvasFactory; + this.webGLContext = webGLContext; + this._pdfBug = pdfBug; - this.running = false; - this.graphicsReadyCallback = null; - this.graphicsReady = false; - this.useRequestAnimationFrame = false; - this.cancelled = false; - this.capability = createPromiseCapability(); - this.task = new RenderTask(this); - // caching this-bound methods - 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._continueBound = this._continue.bind(this); + this._scheduleNextBound = this._scheduleNext.bind(this); + this._nextBound = this._next.bind(this); + this._canvas = params.canvasContext.canvas; + } - InternalRenderTask.prototype = { - - initializeGraphics(transparency) { + initializeGraphics(transparency = false) { if (this.cancelled) { return; } @@ -2393,26 +2397,27 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { this.stepper.init(this.operatorList); this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint(); } + const { + canvasContext, viewport, transform, imageLayer, background, + } = this.params; - var params = this.params; - this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs, - this.objs, this.canvasFactory, - this.webGLContext, params.imageLayer); - + this.gfx = new CanvasGraphics(canvasContext, this.commonObjs, this.objs, + this.canvasFactory, this.webGLContext, + imageLayer); this.gfx.beginDrawing({ - transform: params.transform, - viewport: params.viewport, + transform, + viewport, transparency, - background: params.background, + background, }); this.operatorListIdx = 0; this.graphicsReady = true; if (this.graphicsReadyCallback) { this.graphicsReadyCallback(); } - }, + } - cancel: function InternalRenderTask_cancel() { + cancel() { this.running = false; this.cancelled = true; if (this.gfx) { @@ -2423,9 +2428,9 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { } this.callback(new RenderingCancelledException( 'Rendering cancelled, page ' + this.pageNumber, 'canvas')); - }, + } - operatorListChanged: function InternalRenderTask_operatorListChanged() { + operatorListChanged() { if (!this.graphicsReady) { if (!this.graphicsReadyCallback) { this.graphicsReadyCallback = this._continueBound; @@ -2441,9 +2446,9 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { return; } this._continue(); - }, + } - _continue: function InternalRenderTask__continue() { + _continue() { this.running = true; if (this.cancelled) { return; @@ -2453,42 +2458,38 @@ var InternalRenderTask = (function InternalRenderTaskClosure() { } else { this._scheduleNext(); } - }, + } - _scheduleNext: function InternalRenderTask__scheduleNext() { - if (this.useRequestAnimationFrame && typeof window !== 'undefined') { + _scheduleNext() { + if (this._useRequestAnimationFrame) { window.requestAnimationFrame(() => { this._nextBound().catch(this.callback); }); } else { Promise.resolve().then(this._nextBound).catch(this.callback); } - }, + } - _next: function InternalRenderTask__next() { - return new Promise(() => { - 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(); + 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(); } - }); - }, - - }; - + } + } + } return InternalRenderTask; })(); diff --git a/src/display/canvas.js b/src/display/canvas.js index af39bf763..99c97e13f 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -726,7 +726,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { CanvasGraphics.prototype = { - beginDrawing({ transform, viewport, transparency, + beginDrawing({ transform, viewport, transparency = false, background = null, }) { // For pdfs that use blend modes we have to clear the canvas else certain // blend modes can look wrong since we'd be blending with a white From 061f7bd2f30e35d8d5f2face4a3e31aa520e77e2 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 8 Nov 2018 16:22:26 +0100 Subject: [PATCH 5/6] Convert `PDFWorker`, in `src/display/api.js`, to an ES6 class Also changes all occurrences of `var` to `let`/`const` in this code. --- src/display/api.js | 144 +++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 76 deletions(-) diff --git a/src/display/api.js b/src/display/api.js index 4d8a069e8..63faea116 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -321,16 +321,12 @@ function getDocument(src) { const workerParams = { postMessageTransfers: params.postMessageTransfers, verbosity: params.verbosity, + port: GlobalWorkerOptions.workerPort, }; // Worker was not provided -- creating and owning our own. If message port // is specified in global worker options, using it. - let workerPort = GlobalWorkerOptions.workerPort; - if (workerPort) { - workerParams.port = workerPort; - worker = PDFWorker.fromPort(workerParams); - } else { - worker = new PDFWorker(workerParams); - } + worker = workerParams.port ? PDFWorker.fromPort(workerParams) : + new PDFWorker(workerParams); task._worker = worker; } var docId = task.docId; @@ -1342,8 +1338,10 @@ class LoopbackPort { * a "fake" worker will be used instead. * @class */ -var PDFWorker = (function PDFWorkerClosure() { +const PDFWorker = (function PDFWorkerClosure() { + const pdfWorkerPorts = new WeakMap(); let nextFakeWorkerId = 0; + let fakeWorkerFilesLoadedCapability; function getWorkerSrc() { if (GlobalWorkerOptions.workerSrc) { @@ -1364,8 +1362,6 @@ var PDFWorker = (function PDFWorkerClosure() { return null; } - let fakeWorkerFilesLoadedCapability; - // Loads worker code into main thread. function setupFakeWorkerGlobal() { if (fakeWorkerFilesLoadedCapability) { @@ -1373,7 +1369,7 @@ var PDFWorker = (function PDFWorkerClosure() { } fakeWorkerFilesLoadedCapability = createPromiseCapability(); - let mainWorkerMessageHandler = getMainThreadWorkerMessageHandler(); + const mainWorkerMessageHandler = getMainThreadWorkerMessageHandler(); if (mainWorkerMessageHandler) { // The worker was already loaded using a `