From 937e0617f06d1615338ccf2a6bad3380647bb0e8 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 2 Sep 2020 15:13:14 +0000 Subject: [PATCH] Bug 1653319. Use the new FrameLoader.printPreview API in the frontend. r=mstriemer,emalysz,emilio Differential Revision: https://phabricator.services.mozilla.com/D88704 --- layout/printing/nsPrintJob.cpp | 46 ++++++++-- toolkit/components/printing/content/print.js | 88 +++++--------------- 2 files changed, 60 insertions(+), 74 deletions(-) diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index c9110ebf1df2..6f361145f5ad 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -651,10 +651,28 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview, // The dialog is not shown, but this means we don't need to access the printer // driver from the child, which causes sandboxing issues. if (!mIsCreatingPrintPreview || printingViaParent) { - bool printSilently = false; - printData->mPrintSettings->GetPrintSilent(&printSilently); - if (StaticPrefs::print_always_print_silent()) { - printSilently = true; + bool printSilentOnSettings = false; + printData->mPrintSettings->GetPrintSilent(&printSilentOnSettings); + + bool printSilently = + printSilentOnSettings || StaticPrefs::print_always_print_silent(); + + // The new print UI does not need to enter ShowPrintDialog below to spin + // the event loop and fetch real printer settings from the parent process, + // since it always passes complete print settings. (In fact, trying to + // fetch them from the parent can cause crashes.) Here we check for that + // case so that we can avoid calling ShowPrintDialog below. To err on the + // safe side, we exclude the old UI and non-frontend callers + // (Extensions.tabs.saveAsPDF()) which set `printSilent` on the settings + // object. + // We should remove the exception for tabx.saveAsPDF soon: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1662222 + // Slightly longer term we'll remove the old print UI, and even change the + // check for `isInitializedFromPrinter` to a MOZ_DIAGNOSTIC_ASSERT. + bool settingsAreComplete = false; + if (StaticPrefs::print_tab_modal_enabled() && !printSilentOnSettings) { + printData->mPrintSettings->GetIsInitializedFromPrinter( + &settingsAreComplete); } // Ask dialog to be Print Shown via the Plugable Printing Dialog Service @@ -662,7 +680,7 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview, // If printing silently or you can't get the service continue on // If printing via the parent then we need to confirm that the pref is set // and get a remote print job, but the parent won't display a prompt. - if (!printSilently || printingViaParent) { + if (!settingsAreComplete && (!printSilently || printingViaParent)) { nsCOMPtr printPromptService( do_GetService(kPrintingPromptService)); if (printPromptService) { @@ -752,7 +770,16 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview, // No dialog service available rv = NS_ERROR_NOT_IMPLEMENTED; } - } else { + } else if (printSilently && !printingViaParent) { + // The condition above is only so contorted in order to enter this block + // under the exact same circumstances as we used to, in order to + // minimize risk for this change which may be getting late Beta uplift. + // Frankly calling SetupSilentPrinting should not be necessary any more + // since nsDeviceContextSpecGTK::EndDocument does what we need using a + // Runnable instead of spinning an event loop in a risk place like here. + // Additionally we should never need to do this when setting up print + // preview, we would only need it for printing. + // Call any code that requires a run of the event loop. rv = printData->mPrintSettings->SetupSilentPrinting(); } @@ -1077,6 +1104,11 @@ nsresult nsPrintJob::CleanupOnFailure(nsresult aResult, bool aIsPrinting) { //--------------------------------------------------------------------- void nsPrintJob::FirePrintingErrorEvent(nsresult aPrintError) { + if (mPrintPreviewCallback) { + mPrintPreviewCallback(PrintPreviewResultInfo(0, 0)); // signal error + mPrintPreviewCallback = nullptr; + } + nsCOMPtr cv = do_QueryInterface(mDocViewerPrint); if (NS_WARN_IF(!cv)) { return; @@ -2422,7 +2454,7 @@ nsresult nsPrintJob::EnablePOsForPrinting() { // NOTE: All POs have been "turned off" for printing // this is where we decided which POs get printed. - if (!printData->mPrintSettings) { + if (!printData || !printData->mPrintSettings) { return NS_ERROR_FAILURE; } diff --git a/toolkit/components/printing/content/print.js b/toolkit/components/printing/content/print.js index 0822a561b392..52db661b482d 100644 --- a/toolkit/components/printing/content/print.js +++ b/toolkit/components/printing/content/print.js @@ -178,9 +178,7 @@ var PrintEventHandler = { }, unload() { - this.previewBrowser.messageManager.sendAsyncMessage( - "Printing:Preview:Exit" - ); + this.previewBrowser.frameLoader.exitPrintPreview(); }, _createPreviewBrowser(sourceBrowsingContext) { @@ -251,7 +249,6 @@ var PrintEventHandler = { async print(systemDialogSettings) { let settings = systemDialogSettings || this.settings; - settings.printSilent = true; if (settings.printerName == PrintUtils.SAVE_TO_PDF_PRINTER) { try { @@ -363,77 +360,32 @@ var PrintEventHandler = { * Create a print preview for the provided source browsingContext, or refresh * the preview with new settings when omitted. * - * @param browsingContext {BrowsingContext} [optional] + * @param sourceBrowsingContext {BrowsingContext} [optional] * The source BrowsingContext (the one associated with a tab or * subdocument) that should be previewed. * * @return {Promise} Resolves when the preview has been updated. */ - async _updatePrintPreview(browsingContext) { + async _updatePrintPreview(sourceBrowsingContext) { let { previewBrowser, settings } = this; + + // We never want the progress dialog to show + settings.showPrintProgress = false; + let stack = previewBrowser.parentElement; stack.setAttribute("rendering", true); document.body.setAttribute("rendering", true); - let networkDone = false; - let documentDone = false; - - let totalPages = await new Promise(resolve => { - let numPages; - - function onStateChange(msg) { - // We get 2 STATE_STOP events, make sure they've both completed. - if (msg.data.stateFlags & Ci.nsIWebProgressListener.STATE_STOP) { - networkDone = - networkDone || - msg.data.stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK; - documentDone = - documentDone || - msg.data.stateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT; - - if (networkDone && documentDone) { - cleanup(); - resolve(numPages); - } - } - } - - function onUpdatePageCount(msg) { - numPages = msg.data.totalPages; - } - - function cleanup() { - previewBrowser.messageManager.removeMessageListener( - "Printing:Preview:UpdatePageCount", - onUpdatePageCount - ); - previewBrowser.messageManager.removeMessageListener( - "Printing:Preview:StateChange", - onStateChange - ); - } - - previewBrowser.messageManager.addMessageListener( - "Printing:Preview:StateChange", - onStateChange - ); - previewBrowser.messageManager.addMessageListener( - "Printing:Preview:UpdatePageCount", - onUpdatePageCount - ); - - previewBrowser.messageManager.sendAsyncMessage("Printing:Preview:Enter", { - changingBrowsers: false, - lastUsedPrinterName: settings.printerName, - simplifiedMode: false, - browsingContextId: - browsingContext?.id || previewBrowser.browsingContext.id, - outputFormat: settings.outputFormat, - startPageRange: settings.startPageRange, - endPageRange: settings.endPageRange, - printRange: settings.printRange, - }); - }); + let sourceWinId; + if (sourceBrowsingContext) { + sourceWinId = sourceBrowsingContext.currentWindowGlobal.outerWindowId; + } + // This resolves with a PrintPreviewSuccessInfo dictionary. That also has + // a `sheetCount` property available which we should use (bug 1662331). + let { totalPageCount } = await previewBrowser.frameLoader.printPreview( + settings, + sourceWinId + ); if (this._queuedPreviewUpdatePromise) { // Now that we're done, the queued update (if there is one) will start. @@ -441,13 +393,15 @@ var PrintEventHandler = { this._queuedPreviewUpdatePromise = null; } else { // No other update queued, send the page count and show the preview. - let numPages = totalPages; + let numPages = totalPageCount; // Adjust number of pages if the user specifies the pages they want printed if (settings.printRange == Ci.nsIPrintSettings.kRangeSpecifiedPageRange) { numPages = settings.endPageRange - settings.startPageRange + 1; } document.dispatchEvent( - new CustomEvent("page-count", { detail: { numPages, totalPages } }) + new CustomEvent("page-count", { + detail: { numPages, totalPages: totalPageCount }, + }) ); stack.removeAttribute("rendering");