-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactoring of printing code and mozPrintCallback polyfill #7697
Conversation
return pdfPage.render(renderContext).promise; | ||
}).then(function() { | ||
img.src = canvas.toDataURL(); | ||
wrapper.appendChild(img); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To try and save memory you probably want to clear the canvas
explicitly as soon as it's no longer needed, as is done e.g. in
Lines 170 to 174 in f8bd3d4
// Zeroing the width and height causes Firefox to release graphics | |
// resources immediately, which can greatly reduce memory consumption. | |
this.canvas.width = 0; | |
this.canvas.height = 0; | |
delete this.canvas; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed: using one canvas for all pages and disposing it at the end.
<progress value="0" max="100"></progress> | ||
<span class="relative-progress">0%</span> | ||
</div> | ||
<div class="row"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you want class="buttonRow"
instead here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
I didn't decide about one thing:
|
After reading the comment about bug 851441, I removed page hack for firefox print service in the second commit. |
} | ||
// The beforePrint is a sync method and we need to know layout before | ||
// returning from this method. Ensure that we can get sizes of the pages. | ||
var alertNotReady = !this.pdfViewer.pageViewsReady; | ||
if (alertNotReady) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point I don't think that you need the intermediate alertNotReady
variable any more, so
if (!this.pdfViewer.pageViewsReady) {
should suffice here.
if (this.printing) { | ||
this.printService.destroy(); | ||
this.printService = null; | ||
this.printing = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the way that this.printing
/this.printService
is now used, we (basically) track the same state twice.
I'm wondering if we couldn't just get rid of the this.printing
from this file and just check the new this.printService
instead (possibly with !!this.printService
where we actually want a boolean, such as e.g. in forceRendering
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by adding "printing" getter (just in case if people use the property) or as in case above (for simplicity). Internally in app.js it's mostly used as printService
|
||
function renderPage(pdfDocument, pageNumber, size, wrapper) { | ||
if (!scratchCanvas) { | ||
scratchCanvas = document.createElement('canvas'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Why did you remove the mozPrintCallback polyfill? Now the code has two code paths, one where mozPrintCallback is available and one where it is not. How does this not affect printing behavior (or how does the change improve the behavior)? |
code was just moved to the pdf_print_service.js
For simplicity, web/demo viewer will never use mozPrintCallback -- it is in bad shape now (see 1308259 and 1308579) and performs rasterization like we do, and yes, for the extension we continue using mozPrintCallback just not create a drastic change. If decision to improve/remove mozPrintCallback will be made we can either use firefox_print_callback in the pdf_print_callback or remove firefox_print_callback.
The changes are:
@Rob--W, I hope I answered the questions. Thanks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a quick pass through the code and these are my findings so far. In general I really like the direction of this patch, but this still requires more in-depth review and testing.
var CSS_UNITS = uiUtils.CSS_UNITS; | ||
var PDFPrintServiceFactory = app.PDFPrintServiceFactory; | ||
|
||
function composePage(pdfDocument, pageNumber, size, printContainer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is called renderPage
in pdf_print_service.js
. Can we name it renderPage
here too for consistency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, I added a comments to pdf_print_service
dispatchEvent('beforeprint'); | ||
} finally { | ||
if (!activeService) { | ||
console.error('Expected print service to the initialized.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: to be initialized
throw new Error('The print service is created and active.'); | ||
} | ||
activeService = new PDFPrintService(pdfDocument, pagesOverview, | ||
printContainer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: add one more space
* Returns sizes of the pages. | ||
* @returns {Array} Array of objects with width/height fields. | ||
*/ | ||
getPagesOverview: function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would getPageSizes
perhaps be a better name, or do you want to keep it general to add more properties later on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latter, but I don't want to think now what to add :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good. I have found a few minor issues, commented below.
Now the mozPrintCallback polyfill is integrated, it does not need to be so generic any more and the implementation can be simplified. But I can do that since I exactly know the purpose of each line in the polyfill.
return pdfPage.render(renderContext).promise; | ||
}).then(function() { | ||
img.src = scratchCanvas.toDataURL(); | ||
wrapper.appendChild(img); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that you have to wait until img.onload
is fired.
return new Promise(function(resolve, reject) {
img.onload = resolve;
img.onerror = reject;
});
Some food for thought: Would canvas.toBlob()
over toDataURL
improve memory usage or performance? In theory, after painting the browser does not need to keep the very long data URL around, which leads to a reduced memory usage. Here is a code sample: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Getting_a_file_representing_the_canvas
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed and improved.
scratchCanvas = null; | ||
} | ||
ensureOverlay().then(function () { | ||
OverlayManager.close('printServiceOverlay'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I send a print request and close the print dialog, an error is thrown here:
Uncaught (in promise) Error: The overlay is currently not active.(…) overlay_manager.js:117
(anonymous function) @ overlay_manager.js:117
overlayManagerClose @ overlay_manager.js:113
(anonymous function) @ pdf_print_service.js:140
I think that the fact that destroy()
is called twice causes this issue.
abort
below calls.destroy()
- In app.js, the afterprint event handler calls
destroy()
as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check to not perform double close() added
@@ -162,6 +162,13 @@ var PDFViewer = (function pdfViewer() { | |||
}, | |||
|
|||
/** | |||
* @returns {boolean} true if all page views are initialized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is a "page view"? The data structure behind a PDF page? A canvas element?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment fixed.
<div id="printServiceOverlay" class="container hidden"> | ||
<div class="dialog"> | ||
<div class="row"> | ||
<span>Preparing document for printing...</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The localization comment disappeared. Don't we want to localize this any more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good find. I really think we should localize this and I think it's easier now that it's part of viewer.html
. Otherwise we should add back the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment does not work with proprocessor
intent: 'print' | ||
}; | ||
return pdfPage.render(renderContext).promise; | ||
}).then(function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need an if-check here to see if the print job is still active.
|
||
renderPages: function () { | ||
var pageCount = this.pagesOverview.length; | ||
var renderNextPage = function (resolve, reject) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need an if-check to see if the print request is still active, and exit if it is not.
var progressPerc = progressContainer.querySelector('.relative-progress'); | ||
progressBar.value = progress; | ||
progressPerc.textContent = progress + '%'; | ||
progressContainer.onclick = abort; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned on IRC, I think that the onclick
handler should be attached to the printCancel
button rather than the entire overlay container.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Nits addressed and additional checks are added. /botio-linux preview |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me; but let's have Rob and Tim sign off on this too before merging.
In my testing this works great, and the re-factoring improves readability of the code quite a bit!
Looks good from the users perspective.
The unticked checkboxes are still a TODO. Any volunteers? ;) Tested scenarios:
Note: When I use Esc while the PDF is being prepared, in Firefox the following error appears after a few seconds. I think that the dialog is already closed by the esc keydown handler in the OverlayManager, when the
|
Tomorrow I'll have access to a computer with Windows, so I can take care of the remaining checkboxes and review this as well so we can land it. @yurydelendik Could you look into the error mentioned above? The |
More of a note to myself for testing, but here is a list of issues/PRs possibly affected by these patches:
|
5268933
to
55c3b13
Compare
Added guard against closing closed overlay and removed esc handling from print service. |
}, this); | ||
if (!hasEqualPageSizes) { | ||
console.warn('Not all pages have the same size. The printed ' + | ||
'result may be incorrect!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: remove one space
if (scratchCanvas) { | ||
scratchCanvas.width = scratchCanvas.height = 0; | ||
scratchCanvas = null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we clear this.wrappers
and the associated div
s here as well to save memory?
55c3b13
to
1a056ca
Compare
/botio-linux preview |
From: Bot.io (Linux)ReceivedCommand cmd_preview from @timvandermeij received. Current queue size: 0 Live output at: http://107.21.233.14:8877/e5a7d5049c83aeb/output.txt |
From: Bot.io (Linux)SuccessFull output at http://107.21.233.14:8877/e5a7d5049c83aeb/output.txt Total script time: 1.02 mins Published |
Awesome work! I tested this in all major browsers and found no issues. |
I am facing similar issues while trying to print huge PDFs (that are being rendered using PDFJS) on IE11. Upgrading to latest version of PDFJS hasn't helped either. The above conversation hints that the issue may be already fixed. Where can I get the sample code? Any pointers? |
Refactoring of printing code and mozPrintCallback polyfill
Two things happens: moves all print related code to the single file and makes the polyfill as a first-class citizen. My finding says that Firefox now rasterizes mozPrintCallback output which aligns it with other browsers by functionality. Another finding (and lots of bugs confirm) that mozPrintCallback will not print using font that were not used during viewing. So migrating generic/demo viewer to not use mozPrintCallback will be good first step to produce consistent results across browsers. Converting canvas to PNG saves memory and improves print quality for Chrome.