☠☠ backed out by 908b844c13c8 ☠ ☠ | |
author | Mike Conley <mconley@mozilla.com> |
Mon, 27 Oct 2014 09:49:58 -0400 | |
changeset 212519 | 4e5999f39bb7923d9db3912c70e8fa78c9aae9d7 |
parent 212518 | be2cb4fa54e3319f756b19a19fea7bf53735f42e |
child 212520 | 21d6238c711f8dc533eef72b01d1d78aa385fe47 |
push id | 27717 |
push user | kwierso@gmail.com |
push date | Tue, 28 Oct 2014 00:49:29 +0000 |
treeherder | mozilla-central@a255a234946e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Mossop |
bugs | 1082575 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -23,17 +23,17 @@ <command id="cmd_newNavigatorTab" oncommand="BrowserOpenNewTabOrWindow(event);"/> <command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/> <command id="Browser:SavePage" oncommand="saveDocument(window.content.document);"/> <command id="Browser:SendLink" oncommand="MailIntegration.sendLinkForWindow(window.content);"/> <command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/> - <command id="cmd_print" oncommand="PrintUtils.print();"/> + <command id="cmd_print" oncommand="PrintUtils.print(window.gBrowser.selectedBrowser.contentWindowAsCPOW, window.gBrowser.selectedBrowser);"/> <command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/> <command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/> <command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/> <command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/> <command id="cmd_quitApplication" oncommand="goQuitApplication()"/> <commandset id="editMenuCommands"/>
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1658,17 +1658,18 @@ function HandleAppCommandEvent(evt) { break; case "Help": openHelpLink('firefox-help'); break; case "Open": BrowserOpenFileWindow(); break; case "Print": - PrintUtils.print(); + PrintUtils.print(gBrowser.selectedBrowser.contentWindowAsCPOW, + gBrowser.selectedBrowser); break; case "Save": saveDocument(window.content.document); break; case "SendMail": MailIntegration.sendLinkForWindow(window.content); break; default:
--- a/toolkit/components/printing/content/printPreviewBindings.xml +++ b/toolkit/components/printing/content/printPreviewBindings.xml @@ -18,17 +18,17 @@ <binding id="printpreviewtoolbar" extends="chrome://global/content/bindings/toolbar.xml#toolbar"> <resources> <stylesheet src="chrome://global/skin/printPreview.css"/> </resources> <content> <xul:button label="&print.label;" accesskey="&print.accesskey;" - oncommand="PrintUtils.print();" icon="print"/> + oncommand="this.parentNode.print();" icon="print"/> <xul:button label="&pageSetup.label;" accesskey="&pageSetup.accesskey;" oncommand="this.parentNode.doPageSetup();"/> <xul:vbox align="center" pack="center"> <xul:label value="&page.label;" accesskey="&page.accesskey;" control="pageNumber"/> </xul:vbox> <xul:toolbarbutton class="home-arrow tabbable" @@ -88,17 +88,17 @@ </xul:hbox> <xul:toolbarseparator class="toolbarseparator-primary"/> <xul:button label="&close.label;" accesskey="&close.accesskey;" oncommand="PrintUtils.exitPrintPreview();" icon="close"/> <xul:data value="&customPrompt.title;"/> </content> - <implementation> + <implementation implements="nsIMessageListener"> <field name="mPrintButton"> document.getAnonymousNodes(this)[0] </field> <field name="mPageTextBox"> document.getAnonymousNodes(this)[5].childNodes[0] </field> <field name="mTotalPages"> document.getAnonymousNodes(this)[5].childNodes[2] @@ -120,26 +120,34 @@ </field> <field name="mCustomTitle"> document.getAnonymousNodes(this)[15].firstChild </field> <field name="mPrintPreviewObs"> </field> <field name="mWebProgress"> </field> - - <constructor> - <![CDATA[ - var print = PrintUtils.getPrintPreview(); - this.mTotalPages.value = print.printPreviewNumPages; - this.mPageTextBox.max = print.printPreviewNumPages; + <field name="mPPBrowser"> + null + </field> + <field name="mMessageManager"> + null + </field> - this.updateToolbar(); - ]]> - </constructor> + <method name="initialize"> + <parameter name="aPPBrowser"/> + <body> + <![CDATA[ + this.mPPBrowser = aPPBrowser; + this.mMessageManager = aPPBrowser.messageManager; + this.mMessageManager.addMessageListener("Printing:Preview:UpdatePageCount", this); + this.updateToolbar(); + ]]> + </body> + </method> <method name="doPageSetup"> <body> <![CDATA[ var didOK = PrintUtils.showPageSetup(); if (didOK) { // the changes that effect the UI this.updateToolbar(); @@ -151,48 +159,57 @@ </body> </method> <method name="navigate"> <parameter name="aDirection"/> <parameter name="aPageNum"/> <parameter name="aHomeOrEnd"/> <body> - <![CDATA[ - var print = PrintUtils.getPrintPreview(); + <![CDATA[ + const nsIWebBrowserPrint = Components.interfaces.nsIWebBrowserPrint; + let navType, pageNum; // we use only one of aHomeOrEnd, aDirection, or aPageNum - if (aHomeOrEnd) - { - var homeOrEnd; - if (aHomeOrEnd == "home") - { - homeOrEnd = print.PRINTPREVIEW_HOME; - this.mPageTextBox.value = 1; - } - else - { - homeOrEnd = print.PRINTPREVIEW_END; - this.mPageTextBox.value = print.printPreviewNumPages; + if (aHomeOrEnd) { + // We're going to either the very first page ("home"), or the + // very last page ("end"). + if (aHomeOrEnd == "home") { + navType = nsIWebBrowserPrint.PRINTPREVIEW_HOME; + this.mPageTextBox.value = 1; + } else { + navType = nsIWebBrowserPrint.PRINTPREVIEW_END; + this.mPageTextBox.value = this.mPageTextBox.max; } - - print.printPreviewNavigate(homeOrEnd, 0); - } - else if (aDirection) - { + pageNum = 0; + } else if (aDirection) { + // aDirection is either +1 or -1, and allows us to increment + // or decrement our currently viewed page. this.mPageTextBox.valueNumber += aDirection; - print.printPreviewNavigate( - print.PRINTPREVIEW_GOTO_PAGENUM, - this.mPageTextBox.valueNumber); + navType = nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM; + pageNum = this.mPageTextBox.value; // TODO: back to valueNumber? + } else { + // We're going to a specific page (aPageNum) + navType = nsIWebBrowserPrint.PRINTPREVIEW_GOTO_PAGENUM; + pageNum = aPageNum; } - else - { - print.printPreviewNavigate( - print.PRINTPREVIEW_GOTO_PAGENUM, aPageNum); - } + + this.mMessageManager.sendAsyncMessage("Printing:Preview:Navigate", { + navType: navType, + pageNum: pageNum, + }); + ]]> + </body> + </method> + + <method name="print"> + <body> + <![CDATA[ + let contentWindow = this.mPPBrowser.contentWindowAsCPOW; + PrintUtils.print(contentWindow, this.mPPBrowser); ]]> </body> </method> <method name="promptForScaleValue"> <parameter name="aValue"/> <body> <![CDATA[ @@ -285,42 +302,55 @@ } ]]> </body> </method> <method name="updateToolbar"> <body> <![CDATA[ - var print = PrintUtils.getPrintPreview(); var settings = PrintUtils.getPrintSettings(); var isPortrait = settings.orientation == Components.interfaces.nsIPrintSettings.kPortraitOrientation; this.mPortaitButton.checked = isPortrait; this.mLandscapeButton.checked = !isPortrait; if (settings.shrinkToFit) { this.mScaleCombobox.value = "ShrinkToFit"; } else { this.setScaleCombobox(settings.scaling); } - this.mTotalPages.value = print.printPreviewNumPages; - this.mPageTextBox.max = print.printPreviewNumPages; this.mPageTextBox.value = 1; + + this.mMessageManager.sendAsyncMessage("Printing:Preview:UpdatePageCount"); ]]> </body> </method> <method name="savePrintSettings"> <parameter name="settings"/> <parameter name="flags"/> <body><![CDATA[ var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"] .getService(Components.interfaces.nsIPrintSettingsService); PSSVC.savePrintSettingsToPrefs(settings, true, flags); ]]></body> </method> + + <!-- nsIMessageListener --> + <method name="receiveMessage"> + <parameter name="message"/> + <body> + <![CDATA[ + if (message.name == "Printing:Preview:UpdatePageCount") { + let numPages = message.data.numPages; + this.mTotalPages.value = numPages; + this.mPageTextBox.max = numPages; + } + ]]> + </body> + </method> </implementation> </binding> </bindings>
--- a/toolkit/components/printing/content/printUtils.js +++ b/toolkit/components/printing/content/printUtils.js @@ -1,34 +1,98 @@ - // -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/** + * PrintUtils is a utility for front-end code to trigger common print + * operations (printing, show print preview, show page settings). + * + * Unfortunately, likely due to inconsistencies in how different operating + * systems do printing natively, our XPCOM-level printing interfaces + * are a bit confusing and the method by which we do something basic + * like printing a page is quite circuitous. + * + * To compound that, we need to support remote browsers, and that means + * kicking off the print jobs in the content process. This means we send + * messages back and forth to that process. browser-content.js contains + * the object that listens and responds to the messages that PrintUtils + * sends. + * + * PrintUtils sends messages at different points in its implementation, but + * their documentation is consolidated here for ease-of-access. + * + * + * Messages sent: + * + * Printing:Print + * This message is sent to kick off a print job for a particular content + * window (which is passed along with the message). We also pass print + * settings with this message - though bug 1088070 will have us gather + * those settings from the content process instead. + * + * Printing:Preview:Enter + * This message is sent to put content into print preview mode. We pass + * the content window of the browser we're showing the preview of, and + * the target of the message is the browser that we'll be showing the + * preview in. We also pass print settings in this message, but + * bug 1088070 will have us gather those settings from the content process + * instead. + * + * Printing:Preview:Exit + * This message is sent to take content out of print preview mode. + * + * + * Messages Received + * + * Printing:Preview:Entered + * This message is sent by the content process once it has completed + * putting the content into print preview mode. We must wait for that to + * to complete before switching the chrome UI to print preview mode, + * otherwise we have layout issues. + * + * Printing:Preview:StateChange, Printing:Preview:ProgressChange + * Due to a timing issue resulting in a main-process crash, we have to + * manually open the progress dialog for print preview. The progress + * dialog is opened here in PrintUtils, and then we listen for update + * messages from the child. Bug 1088061 has been filed to investigate + * other solutions. + * + */ + var gPrintSettingsAreGlobal = false; var gSavePrintSettings = false; var gFocusedElement = null; var PrintUtils = { bailOut: function () { - let remote = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIWebNavigation) - .QueryInterface(Components.interfaces.nsILoadContext) - .useRemoteTabs; - if (remote) { + let pref = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + let allow_for_testing = false; + try { + allow_for_testing = pref.getBoolPref("print.enable_e10s_testing"); + } catch(e) { + // The pref wasn't set, so I guess we're not overriding. + } + if (this.usingRemoteTabs && !allow_for_testing) { alert("e10s printing is not implemented yet. Bug 927188."); return true; } return false; }, - showPageSetup: function () - { + /** + * Shows the page setup dialog, and saves any settings changed in + * that dialog if print.save_print_settings is set to true. + * + * @return true on success, false on failure + */ + showPageSetup: function () { if (this.bailOut()) { return; } try { var printSettings = this.getPrintSettings(); var PRINTPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"] .getService(Components.interfaces.nsIPrintingPromptService); PRINTPROMPTSVC.showPageSetup(window, printSettings, null); @@ -40,112 +104,259 @@ var PrintUtils = { } } catch (e) { dump("showPageSetup "+e+"\n"); return false; } return true; }, - print: function (aWindow) + /** + * Starts printing the contents of aWindow. + * + * @param aWindow + * An nsIDOMWindow to initiate the printing of. If the chrome window + * is not running with remote tabs, this defaults to window.content if + * omitted. If running with remote tabs, the caller must pass in the + * content window to be printed. This function throws if that invariant + * is violated. + * @param aBrowser (optional for non-remote browsers) + * The remote <xul:browser> that contains aWindow. This argument is + * not necessary if aWindow came from a non-remote browser, but is + * strictly required otherwise. This function will throw if aWindow + * comes from a remote browser and aBrowser is not provided. + */ + print: function (aWindow, aBrowser) { if (this.bailOut()) { return; } - var webBrowserPrint = this.getWebBrowserPrint(aWindow); - var printSettings = this.getPrintSettings(); - try { - webBrowserPrint.print(printSettings, null); - if (gPrintSettingsAreGlobal && gSavePrintSettings) { - var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"] - .getService(Components.interfaces.nsIPrintSettingsService); - PSSVC.savePrintSettingsToPrefs(printSettings, true, - printSettings.kInitSaveAll); - PSSVC.savePrintSettingsToPrefs(printSettings, false, - printSettings.kInitSavePrinterName); + + if (!aWindow) { + // If we're using remote browsers, chances are that window.content will + // not be defined. + if (this.usingRemoteTabs) { + throw new Error("Windows running with remote tabs must explicitly pass " + + "a content window to PrintUtils.print."); + } + // Otherwise, we should have access to window.content. + aWindow = window.content; + } + + if (Cu.isCrossProcessWrapper(aWindow)) { + if (!aBrowser) { + throw new Error("PrintUtils.print expects a remote browser passed as " + + "an argument if the content window is a CPOW."); } - } catch (e) { - // Pressing cancel is expressed as an NS_ERROR_ABORT return value, - // causing an exception to be thrown which we catch here. - // Unfortunately this will also consume helpful failures, so add a - // dump("print: "+e+"\n"); // if you need to debug + } else { + // For content windows coming from non-remote browsers, the browser can + // be resolved as the chromeEventHandler. + aBrowser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler; } + + if (!aBrowser) { + throw new Error("PrintUtils.print could not resolve content window " + + "to a browser."); + } + + let printSettings = this.getPrintSettings(); + + let mm = aBrowser.messageManager; + mm.sendAsyncMessage("Printing:Print", null, { + printSettings: printSettings, + contentWindow: aWindow, + }); }, - // If aCallback is not null, it must be an object which has the following methods: - // getPrintPreviewBrowser(), getSourceBrowser(), - // getNavToolbox(), onEnter() and onExit(). - // If aCallback is null, then printPreview must previously have been called with - // non-null aCallback and that object will be reused. - printPreview: function (aCallback) + /** + * Initializes print preview. + * + * @param aListenerObj + * An object that defines the following functions: + * + * getPrintPreviewBrowser: + * Returns the <xul:browser> to display the print preview in. + * + * getSourceBrowser: + * Returns the <xul:browser> that contains the document being + * printed. + * + * getNavToolbox: + * Returns the primary toolbox for this window. + * + * onEnter: + * Called upon entering print preview. + * + * onExit: + * Called upon exiting print preview. + * + * These methods must be defined. printPreview can be called + * with aListenerObj as null iff this window is already displaying + * print preview (in which case, the previous aListenerObj passed + * to it will be used). + */ + printPreview: function (aListenerObj) { if (this.bailOut()) { return; } - // if we're already in PP mode, don't set the callback; chances + // if we're already in PP mode, don't set the listener; chances // are it is null because someone is calling printPreview() to // get us to refresh the display. - if (!document.getElementById("print-preview-toolbar")) { - this._callback = aCallback; - this._sourceBrowser = aCallback.getSourceBrowser(); - this._originalTitle = this._sourceBrowser.contentDocument.title; + if (!this.inPrintPreview) { + this._listener = aListenerObj; + this._sourceBrowser = aListenerObj.getSourceBrowser(); + this._originalTitle = this._sourceBrowser.contentTitle; this._originalURL = this._sourceBrowser.currentURI.spec; } else { // collapse the browser here -- it will be shown in // enterPrintPreview; this forces a reflow which fixes display // issues in bug 267422. - this._sourceBrowser = this._callback.getPrintPreviewBrowser(); + this._sourceBrowser = this._listener.getPrintPreviewBrowser(); this._sourceBrowser.collapsed = true; } this._webProgressPP = {}; - var ppParams = {}; - var notifyOnOpen = {}; - var webBrowserPrint = this.getWebBrowserPrint(); - var printSettings = this.getPrintSettings(); + let ppParams = {}; + let notifyOnOpen = {}; + let printSettings = this.getPrintSettings(); // Here we get the PrintingPromptService so we can display the PP Progress from script // For the browser implemented via XUL with the PP toolbar we cannot let it be // automatically opened from the print engine because the XUL scrollbars in the PP window // will layout before the content window and a crash will occur. // Doing it all from script, means it lays out before hand and we can let printing do its own thing - var PPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"] + let PPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"] .getService(Components.interfaces.nsIPrintingPromptService); - // just in case we are already printing, - // an error code could be returned if the Prgress Dialog is already displayed + // just in case we are already printing, + // an error code could be returned if the Progress Dialog is already displayed try { - PPROMPTSVC.showProgress(window, webBrowserPrint, printSettings, this._obsPP, false, + PPROMPTSVC.showProgress(window, null, printSettings, this._obsPP, false, this._webProgressPP, ppParams, notifyOnOpen); if (ppParams.value) { ppParams.value.docTitle = this._originalTitle; ppParams.value.docURL = this._originalURL; } - // this tells us whether we should continue on with PP or + // this tells us whether we should continue on with PP or // wait for the callback via the observer - if (!notifyOnOpen.value.valueOf() || this._webProgressPP.value == null) + if (!notifyOnOpen.value.valueOf() || this._webProgressPP.value == null) { this.enterPrintPreview(); + } } catch (e) { this.enterPrintPreview(); } }, + /** + * Returns the nsIWebBrowserPrint associated with some content window. + * This method is being kept here for compatibility reasons, but should not + * be called by code hoping to support e10s / remote browsers. + * + * @param aWindow + * The window from which to get the nsIWebBrowserPrint from. + * @return nsIWebBrowserPrint + */ getWebBrowserPrint: function (aWindow) { + let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated; + let text = "getWebBrowserPrint is now deprecated, and fully unsupported for " + + "multi-process browsers. Please use a frame script to get " + + "access to nsIWebBrowserPrint from content."; + let url = "https://developer.mozilla.org/en-US/docs/Printing_from_a_XUL_App"; + Deprecated.warning(text, url); + + if (this.usingRemoteTabs) { + return {}; + } + var contentWindow = aWindow || window.content; return contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebBrowserPrint); }, + /** + * Returns the nsIWebBrowserPrint from the print preview browser's docShell. + * This method is being kept here for compatibility reasons, but should not + * be called by code hoping to support e10s / remote browsers. + * + * @return nsIWebBrowserPrint + */ getPrintPreview: function() { - return this._callback.getPrintPreviewBrowser().docShell.printPreview; + let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated; + let text = "getPrintPreview is now deprecated, and fully unsupported for " + + "multi-process browsers. Please use a frame script to get " + + "access to nsIWebBrowserPrint from content."; + let url = "https://developer.mozilla.org/en-US/docs/Printing_from_a_XUL_App"; + Deprecated.warning(text, url); + + if (this.usingRemoteTabs) { + return {}; + } + + return this._listener.getPrintPreviewBrowser().docShell.printPreview; + }, + + get inPrintPreview() { + return document.getElementById("print-preview-toolbar") != null; }, - //////////////////////////////////////// - // "private" methods. Don't use them. // - //////////////////////////////////////// + //////////////////////////////////////////////////// + // "private" methods and members. Don't use them. // + /////////////////////////////////////////////////// + + _listener: null, + _closeHandlerPP: null, + _webProgressPP: null, + _sourceBrowser: null, + _originalTitle: "", + _originalURL: "", + + get usingRemoteTabs() { + // We memoize this, since it's highly unlikely to change over the lifetime + // of the window. + let usingRemoteTabs = + window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsILoadContext) + .useRemoteTabs; + delete this.usingRemoteTabs; + return this.usingRemoteTabs = usingRemoteTabs; + }, + + receiveMessage(aMessage) { + if (!this._webProgressPP.value) { + // We somehow didn't get a nsIWebProgressListener to be updated... + // I guess there's nothing to do. + return; + } + + let listener = this._webProgressPP.value; + let data = aMessage.data; + + switch (aMessage.name) { + case "Printing:Preview:ProgressChange": { + return listener.onProgressChange(null, null, + data.curSelfProgress, + data.maxSelfProgress, + data.curTotalProgress, + data.maxTotalProgress); + break; + } + + case "Printing:Preview:StateChange": { + return listener.onStateChange(null, null, + data.stateFlags, + data.status); + break; + } + } + }, setPrinterDefaultsForSelectedPrinter: function (aPSSVC, aPrintSettings) { if (!aPrintSettings.printerName) aPrintSettings.printerName = aPSSVC.defaultPrinterName; // First get any defaults from the printer aPSSVC.initPrintSettingsFromPrinter(aPrintSettings.printerName, aPrintSettings); @@ -173,138 +384,133 @@ var PrintUtils = { printSettings = PSSVC.newPrintSettings; } } catch (e) { dump("getPrintSettings: "+e+"\n"); } return printSettings; }, - _closeHandlerPP: null, - _webProgressPP: null, - _callback: null, - _sourceBrowser: null, - _originalTitle: "", - _originalURL: "", - // This observer is called once the progress dialog has been "opened" - _obsPP: + _obsPP: { observe: function(aSubject, aTopic, aData) { // delay the print preview to show the content of the progress dialog setTimeout(function () { PrintUtils.enterPrintPreview(); }, 0); }, QueryInterface : function(iid) { if (iid.equals(Components.interfaces.nsIObserver) || iid.equals(Components.interfaces.nsISupportsWeakReference) || iid.equals(Components.interfaces.nsISupports)) - return this; + return this; throw Components.results.NS_NOINTERFACE; } }, enterPrintPreview: function () { - gFocusedElement = document.commandDispatcher.focusedElement; - - var webBrowserPrint; - var printSettings = this.getPrintSettings(); - var originalWindow = this._sourceBrowser.contentWindow; + // Send a message to the print preview browser to initialize + // print preview. If we happen to have gotten a print preview + // progress listener from nsIPrintingPromptService.showProgress + // in printPreview, we add listeners to feed that progress + // listener. + let ppBrowser = this._listener.getPrintPreviewBrowser(); + let mm = ppBrowser.messageManager; + let printSettings = this.getPrintSettings(); + mm.sendAsyncMessage("Printing:Preview:Enter", null, { + printSettings: printSettings, + contentWindow: this._sourceBrowser.contentWindowAsCPOW, + }); - try { - webBrowserPrint = this.getPrintPreview(); - webBrowserPrint.printPreview(printSettings, originalWindow, - this._webProgressPP.value); - } catch (e) { - // Pressing cancel is expressed as an NS_ERROR_ABORT return value, - // causing an exception to be thrown which we catch here. - // Unfortunately this will also consume helpful failures, so add a - // dump(e); // if you need to debug - - // Need to call enter and exit so that UI gets back to normal. - this._callback.onEnter(); - this._callback.onExit(); - return; - } - - var printPreviewTB = document.getElementById("print-preview-toolbar"); - if (printPreviewTB) { - printPreviewTB.updateToolbar(); - var browser = this._callback.getPrintPreviewBrowser(); - browser.collapsed = false; - browser.contentWindow.focus(); - return; + if (this._webProgressPP.value) { + mm.addMessageListener("Printing:Preview:StateChange", this); + mm.addMessageListener("Printing:Preview:ProgressChange", this); } - // Set the original window as an active window so any mozPrintCallbacks can - // run without delayed setTimeouts. - var docShell = originalWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIWebNavigation) - .QueryInterface(Components.interfaces.nsIDocShell); - docShell.isActive = true; + let onEntered = (message) => { + mm.removeMessageListener("Printing:PrintPreview:Entered", onEntered); + // Stash the focused element so that we can return to it after exiting + // print preview. + gFocusedElement = document.commandDispatcher.focusedElement; - // show the toolbar after we go into print preview mode so - // that we can initialize the toolbar with total num pages - var XUL_NS = - "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - printPreviewTB = document.createElementNS(XUL_NS, "toolbar"); - printPreviewTB.setAttribute("printpreview", true); - printPreviewTB.id = "print-preview-toolbar"; - printPreviewTB.className = "toolbar-primary"; + let printPreviewTB = document.getElementById("print-preview-toolbar"); + if (printPreviewTB) { + printPreviewTB.updateToolbar(); + ppBrowser.collapsed = false; + ppBrowser.focus(); + return; + } + + // Set the original window as an active window so any mozPrintCallbacks can + // run without delayed setTimeouts. + this._sourceBrowser.docShellIsActive = true; - var navToolbox = this._callback.getNavToolbox(); - navToolbox.parentNode.insertBefore(printPreviewTB, navToolbox); + // show the toolbar after we go into print preview mode so + // that we can initialize the toolbar with total num pages + const XUL_NS = + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + printPreviewTB = document.createElementNS(XUL_NS, "toolbar"); + printPreviewTB.setAttribute("printpreview", true); + printPreviewTB.id = "print-preview-toolbar"; + printPreviewTB.className = "toolbar-primary"; - // copy the window close handler - if (document.documentElement.hasAttribute("onclose")) - this._closeHandlerPP = document.documentElement.getAttribute("onclose"); - else - this._closeHandlerPP = null; - document.documentElement.setAttribute("onclose", "PrintUtils.exitPrintPreview(); return false;"); + let navToolbox = this._listener.getNavToolbox(); + navToolbox.parentNode.insertBefore(printPreviewTB, navToolbox); + printPreviewTB.initialize(ppBrowser); - // disable chrome shortcuts... - window.addEventListener("keydown", this.onKeyDownPP, true); - window.addEventListener("keypress", this.onKeyPressPP, true); + // copy the window close handler + if (document.documentElement.hasAttribute("onclose")) + this._closeHandlerPP = document.documentElement.getAttribute("onclose"); + else + this._closeHandlerPP = null; + document.documentElement.setAttribute("onclose", "PrintUtils.exitPrintPreview(); return false;"); - var browser = this._callback.getPrintPreviewBrowser(); - browser.collapsed = false; - browser.contentWindow.focus(); + // disable chrome shortcuts... + window.addEventListener("keydown", this.onKeyDownPP, true); + window.addEventListener("keypress", this.onKeyPressPP, true); - // on Enter PP Call back - this._callback.onEnter(); + ppBrowser.collapsed = false; + ppBrowser.focus(); + // on Enter PP Call back + this._listener.onEnter(); + }; + + mm.addMessageListener("Printing:Preview:Entered", onEntered); }, exitPrintPreview: function () { + let ppBrowser = this._listener.getPrintPreviewBrowser(); + let browserMM = ppBrowser.messageManager; + browserMM.sendAsyncMessage("Printing:Preview:Exit"); + browserMM.removeMessageListener("Printing:Preview:StateChange", this); + browserMM.removeMessageListener("Printing:Preview:ProgressChange", this); window.removeEventListener("keydown", this.onKeyDownPP, true); window.removeEventListener("keypress", this.onKeyPressPP, true); // restore the old close handler document.documentElement.setAttribute("onclose", this._closeHandlerPP); this._closeHandlerPP = null; - var webBrowserPrint = this.getPrintPreview(); - webBrowserPrint.exitPrintPreview(); + // remove the print preview toolbar + let printPreviewTB = document.getElementById("print-preview-toolbar"); + this._listener.getNavToolbox().parentNode.removeChild(printPreviewTB); - // remove the print preview toolbar - var printPreviewTB = document.getElementById("print-preview-toolbar"); - this._callback.getNavToolbox().parentNode.removeChild(printPreviewTB); - - var fm = Components.classes["@mozilla.org/focus-manager;1"] + let fm = Components.classes["@mozilla.org/focus-manager;1"] .getService(Components.interfaces.nsIFocusManager); if (gFocusedElement) fm.setFocus(gFocusedElement, fm.FLAG_NOSCROLL); else window.content.focus(); gFocusedElement = null; - this._callback.onExit(); + this._listener.onExit(); }, onKeyDownPP: function (aEvent) { // Esc exits the PP if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { PrintUtils.exitPrintPreview(); } @@ -324,17 +530,17 @@ var PrintUtils = { (aEvent.charCode == closeKey || aEvent.charCode == closeKey + 32)) { PrintUtils.exitPrintPreview(); } else if (isModif) { var printPreviewTB = document.getElementById("print-preview-toolbar"); var printKey = document.getElementById("printKb").getAttribute("key").toUpperCase(); var pressedKey = String.fromCharCode(aEvent.charCode).toUpperCase(); if (printKey == pressedKey) { - PrintUtils.print(); + printPreviewTB.print(); } } // cancel shortkeys if (isModif) { aEvent.preventDefault(); aEvent.stopPropagation(); } }
--- a/toolkit/content/browser-content.js +++ b/toolkit/content/browser-content.js @@ -1,18 +1,20 @@ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ let Cc = Components.classes; let Ci = Components.interfaces; let Cu = Components.utils; +let Cr = Components.results; Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); var global = this; let ClickEventHandler = { init: function init() { this._scrollable = null; this._scrolldir = ""; this._startX = null; @@ -348,8 +350,135 @@ let PopupBlocking = { {blockedPopups: this.popupData, freshPopup: freshPopup}); }, }; PopupBlocking.init(); // Set up console.* for frame scripts. let Console = Components.utils.import("resource://gre/modules/devtools/Console.jsm", {}); this.console = new Console.ConsoleAPI(); + +let Printing = { + // Bug 1088061: nsPrintEngine's DoCommonPrint currently expects the + // progress listener passed to it to QI to an nsIPrintingPromptService + // in order to know that a printing progress dialog has been shown. That's + // really all the interface is used for, hence the fact that I don't actually + // implement the interface here. Bug 1088061 has been filed to remove + // this hackery. + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, + Ci.nsIPrintingPromptService]), + + MESSAGES: [ + "Printing:Preview:Enter", + "Printing:Preview:Exit", + "Printing:Preview:Navigate", + "Printing:Preview:UpdatePageCount", + "Printing:Print", + ], + + init() { + this.MESSAGES.forEach(msgName => addMessageListener(msgName, this)); + }, + + receiveMessage(message) { + let objects = message.objects; + let data = message.data; + switch(message.name) { + case "Printing:Preview:Enter": { + this.enterPrintPreview(objects.printSettings, objects.contentWindow); + break; + } + + case "Printing:Preview:Exit": { + this.exitPrintPreview(); + break; + } + + case "Printing:Preview:Navigate": { + this.navigate(data.navType, data.pageNum); + break; + } + + case "Printing:Preview:UpdatePageCount": { + this.updatePageCount(); + break; + } + + case "Printing:Print": { + this.print(objects.printSettings, objects.contentWindow); + break; + } + } + }, + + enterPrintPreview(printSettings, contentWindow) { + // Bug 1088070 - we should instantiate nsIPrintSettings here in the + // content script instead of passing it down as a CPOW. + if (Cu.isCrossProcessWrapper(printSettings)) { + printSettings = null; + } + + // We have to wait for the print engine to finish reflowing all of the + // documents and subdocuments before we can tell the parent to flip to + // the print preview UI - otherwise, the print preview UI might ask for + // information (like the number of pages in the document) before we have + // our PresShells set up. + addEventListener("printPreviewUpdate", function onPrintPreviewReady() { + removeEventListener("printPreviewUpdate", onPrintPreviewReady); + sendAsyncMessage("Printing:Preview:Entered"); + }); + + docShell.printPreview.printPreview(printSettings, contentWindow, this); + }, + + exitPrintPreview() { + docShell.printPreview.exitPrintPreview(); + }, + + print(printSettings, contentWindow) { + // Bug 1088070 - we should instantiate nsIPrintSettings here in the + // content script instead of passing it down as a CPOW. + if (Cu.isCrossProcessWrapper(printSettings)) { + printSettings = null; + } + + let print = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebBrowserPrint); + print.print(printSettings, null); + }, + + updatePageCount() { + let numPages = docShell.printPreview.printPreviewNumPages; + sendAsyncMessage("Printing:Preview:UpdatePageCount", { + numPages: numPages, + }); + }, + + navigate(navType, pageNum) { + docShell.printPreview.printPreviewNavigate(navType, pageNum); + }, + + /* nsIWebProgressListener for print preview */ + + onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { + sendAsyncMessage("Printing:Preview:StateChange", { + stateFlags: aStateFlags, + status: aStatus, + }); + }, + + onProgressChange(aWebProgress, aRequest, aCurSelfProgress, + aMaxSelfProgress, aCurTotalProgress, + aMaxTotalProgress) { + sendAsyncMessage("Printing:Preview:ProgressChange", { + curSelfProgress: aCurSelfProgress, + maxSelfProgress: aMaxSelfProgress, + curTotalProgress: aCurTotalProgress, + maxTotalProgress: aMaxTotalProgress, + }); + }, + + onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {}, + onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {}, + onSecurityChange(aWebProgress, aRequest, aState) {}, +} +Printing.init(); +