From f4f4ec30f46d7bc7fc586056aaf7b532d1bb3d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 2 Sep 2020 11:38:10 +0200 Subject: [PATCH] print: Make the firefox printing code able to fail and be re-invoked. This fixes a set of issues described in Mozilla bug 1662426[1]. In particular, once the print callback fails once (because the printing operation has been canceled in Gecko / replaced by a newer one, for example) it can't be re-invoked. This patch fixes it by properly cancelling the render task if it throws, or if the print callback is called again while ongoing. [1]: https://bugzilla.mozilla.org/show_bug.cgi?id=1662426 --- web/firefox_print_service.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/web/firefox_print_service.js b/web/firefox_print_service.js index 98b8d0d88..9f748985f 100644 --- a/web/firefox_print_service.js +++ b/web/firefox_print_service.js @@ -41,6 +41,14 @@ function composePage( canvasWrapper.appendChild(canvas); printContainer.appendChild(canvasWrapper); + // A callback for a given page may be executed multiple times for different + // print operations (think of changing the print settings in the browser). + // + // Since we don't support queueing multiple render tasks for the same page + // (and it'd be racy anyways if painting the page is not done in one go) we + // keep track of the last scheduled task in order to properly cancel it before + // starting the next one. + let currentRenderTask = null; canvas.mozPrintCallback = function (obj) { // Printing/rendering the page. const ctx = obj.context; @@ -50,9 +58,14 @@ function composePage( ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore(); + let thisRenderTask = null; pdfDocument .getPage(pageNumber) .then(function (pdfPage) { + if (currentRenderTask) { + currentRenderTask.cancel(); + currentRenderTask = null; + } const renderContext = { canvasContext: ctx, transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], @@ -61,15 +74,25 @@ function composePage( annotationStorage: pdfDocument.annotationStorage, optionalContentConfigPromise, }; - return pdfPage.render(renderContext).promise; + currentRenderTask = thisRenderTask = pdfPage.render(renderContext); + return thisRenderTask.promise; }) .then( function () { // Tell the printEngine that rendering this canvas/page has finished. + if (currentRenderTask === thisRenderTask) { + currentRenderTask = null; + } obj.done(); }, function (error) { console.error(error); + + if (currentRenderTask === thisRenderTask) { + currentRenderTask.cancel(); + currentRenderTask = null; + } + // Tell the printEngine that rendering this canvas/page has failed. // This will make the print process stop. if ("abort" in obj) {