Bug 1705757 - Move FrameLoader.print to BrowsingContext.print. r=nika,remote-protocol-reviewers,marionette-reviewers,extension-reviewers,zombie

This makes it trivial to choose the right BrowserParent to print a
browsing context, by removing the OuterWindowID / FrameLoader
indirections.

Differential Revision: https://phabricator.services.mozilla.com/D112412
This commit is contained in:
Emilio Cobos Álvarez
2021-04-17 18:41:11 +00:00
parent 3853ead982
commit 0e55bca38f
17 changed files with 152 additions and 173 deletions

View File

@@ -1407,8 +1407,8 @@ this.tabs = class extends ExtensionAPI {
printSettings.footerStrRight = pageSettings.footerRight; printSettings.footerStrRight = pageSettings.footerRight;
} }
activeTab.linkedBrowser activeTab.linkedBrowser.browsingContext
.print(activeTab.linkedBrowser.outerWindowID, printSettings) .print(printSettings)
.then(() => resolve(retval == 0 ? "saved" : "replaced")) .then(() => resolve(retval == 0 ? "saved" : "replaced"))
.catch(() => .catch(() =>
resolve(retval == 0 ? "not_saved" : "not_replaced") resolve(retval == 0 ? "not_saved" : "not_replaced")

View File

@@ -42,6 +42,11 @@
#include "nsIBrowser.h" #include "nsIBrowser.h"
#include "nsTHashSet.h" #include "nsTHashSet.h"
#ifdef NS_PRINTING
# include "mozilla/embedding/printingui/PrintingParent.h"
# include "nsIWebBrowserPrint.h"
#endif
using namespace mozilla::ipc; using namespace mozilla::ipc;
extern mozilla::LazyLogModule gAutoplayPermissionLog; extern mozilla::LazyLogModule gAutoplayPermissionLog;
@@ -479,6 +484,120 @@ CanonicalBrowsingContext::ReplaceLoadingSessionHistoryEntryForLoad(
return MakeUnique<LoadingSessionHistoryInfo>(newEntry, aInfo->mLoadId); return MakeUnique<LoadingSessionHistoryInfo>(newEntry, aInfo->mLoadId);
} }
#ifdef NS_PRINTING
class PrintListenerAdapter final : public nsIWebProgressListener {
public:
explicit PrintListenerAdapter(Promise* aPromise) : mPromise(aPromise) {}
NS_DECL_ISUPPORTS
// NS_DECL_NSIWEBPROGRESSLISTENER
NS_IMETHOD OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) override {
if (aStateFlags & nsIWebProgressListener::STATE_STOP &&
aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT && mPromise) {
mPromise->MaybeResolveWithUndefined();
mPromise = nullptr;
}
return NS_OK;
}
NS_IMETHOD OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsresult aStatus,
const char16_t* aMessage) override {
if (aStatus != NS_OK && mPromise) {
mPromise->MaybeReject(ErrorResult(aStatus));
mPromise = nullptr;
}
return NS_OK;
}
NS_IMETHOD OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) override {
return NS_OK;
}
NS_IMETHOD OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, nsIURI* aLocation,
uint32_t aFlags) override {
return NS_OK;
}
NS_IMETHOD OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aState) override {
return NS_OK;
}
NS_IMETHOD OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aEvent) override {
return NS_OK;
}
private:
~PrintListenerAdapter() = default;
RefPtr<Promise> mPromise;
};
NS_IMPL_ISUPPORTS(PrintListenerAdapter, nsIWebProgressListener)
#endif
already_AddRefed<Promise> CanonicalBrowsingContext::Print(
nsIPrintSettings* aPrintSettings, ErrorResult& aRv) {
RefPtr<Promise> promise = Promise::Create(GetIncumbentGlobal(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return promise.forget();
}
#ifndef NS_PRINTING
promise->MaybeReject(ErrorResult(NS_ERROR_NOT_AVAILABLE));
return promise.forget();
#else
auto listener = MakeRefPtr<PrintListenerAdapter>(promise);
if (IsInProcess()) {
RefPtr<nsGlobalWindowOuter> outerWindow =
nsGlobalWindowOuter::Cast(GetDOMWindow());
if (NS_WARN_IF(!outerWindow)) {
promise->MaybeReject(ErrorResult(NS_ERROR_FAILURE));
return promise.forget();
}
ErrorResult rv;
outerWindow->Print(aPrintSettings, listener,
/* aDocShellToCloneInto = */ nullptr,
nsGlobalWindowOuter::IsPreview::No,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
/* aPrintPreviewCallback = */ nullptr, rv);
if (rv.Failed()) {
promise->MaybeReject(std::move(rv));
}
return promise.forget();
}
auto* browserParent = GetBrowserParent();
if (NS_WARN_IF(!browserParent)) {
promise->MaybeReject(ErrorResult(NS_ERROR_FAILURE));
return promise.forget();
}
RefPtr<embedding::PrintingParent> printingParent =
browserParent->Manager()->GetPrintingParent();
embedding::PrintData printData;
nsresult rv = printingParent->SerializeAndEnsureRemotePrintJob(
aPrintSettings, listener, nullptr, &printData);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(ErrorResult(rv));
return promise.forget();
}
if (NS_WARN_IF(!browserParent->SendPrint(this, printData))) {
promise->MaybeReject(ErrorResult(NS_ERROR_FAILURE));
}
return promise.forget();
#endif
}
void CanonicalBrowsingContext::CallOnAllTopDescendants( void CanonicalBrowsingContext::CallOnAllTopDescendants(
const std::function<mozilla::CallState(CanonicalBrowsingContext*)>& const std::function<mozilla::CallState(CanonicalBrowsingContext*)>&
aCallback) { aCallback) {

View File

@@ -24,6 +24,7 @@
class nsISHistory; class nsISHistory;
class nsIWidget; class nsIWidget;
class nsIPrintSettings;
class nsSHistory; class nsSHistory;
class nsBrowserStatusFilter; class nsBrowserStatusFilter;
class nsSecureBrowserUI; class nsSecureBrowserUI;
@@ -127,6 +128,9 @@ class CanonicalBrowsingContext final : public BrowsingContext {
UniquePtr<LoadingSessionHistoryInfo> ReplaceLoadingSessionHistoryEntryForLoad( UniquePtr<LoadingSessionHistoryInfo> ReplaceLoadingSessionHistoryEntryForLoad(
LoadingSessionHistoryInfo* aInfo, nsIChannel* aChannel); LoadingSessionHistoryInfo* aInfo, nsIChannel* aChannel);
already_AddRefed<Promise> Print(nsIPrintSettings* aPrintSettings,
ErrorResult& aRv);
// Call the given callback on all top-level descendant BrowsingContexts. // Call the given callback on all top-level descendant BrowsingContexts.
// Return Callstate::Stop from the callback to stop calling // Return Callstate::Stop from the callback to stop calling
// further children. // further children.

View File

@@ -3252,64 +3252,6 @@ void nsFrameLoader::RequestSHistoryUpdate(bool aImmediately) {
} }
} }
#ifdef NS_PRINTING
class WebProgressListenerToPromise final : public nsIWebProgressListener {
public:
explicit WebProgressListenerToPromise(Promise* aPromise)
: mPromise(aPromise) {}
NS_DECL_ISUPPORTS
// NS_DECL_NSIWEBPROGRESSLISTENER
NS_IMETHOD OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) override {
if (aStateFlags & nsIWebProgressListener::STATE_STOP &&
aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT && mPromise) {
mPromise->MaybeResolveWithUndefined();
mPromise = nullptr;
}
return NS_OK;
}
NS_IMETHOD OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsresult aStatus,
const char16_t* aMessage) override {
if (aStatus != NS_OK && mPromise) {
mPromise->MaybeReject(ErrorResult(aStatus));
mPromise = nullptr;
}
return NS_OK;
}
NS_IMETHOD OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) override {
return NS_OK;
}
NS_IMETHOD OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, nsIURI* aLocation,
uint32_t aFlags) override {
return NS_OK;
}
NS_IMETHOD OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aState) override {
return NS_OK;
}
NS_IMETHOD OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aEvent) override {
return NS_OK;
}
private:
~WebProgressListenerToPromise() = default;
RefPtr<Promise> mPromise;
};
NS_IMPL_ISUPPORTS(WebProgressListenerToPromise, nsIWebProgressListener)
#endif
already_AddRefed<Promise> nsFrameLoader::PrintPreview( already_AddRefed<Promise> nsFrameLoader::PrintPreview(
nsIPrintSettings* aPrintSettings, nsIPrintSettings* aPrintSettings,
const Optional<uint64_t>& aSourceOuterWindowID, ErrorResult& aRv) { const Optional<uint64_t>& aSourceOuterWindowID, ErrorResult& aRv) {
@@ -3438,60 +3380,6 @@ void nsFrameLoader::ExitPrintPreview() {
#endif #endif
} }
already_AddRefed<Promise> nsFrameLoader::Print(uint64_t aOuterWindowID,
nsIPrintSettings* aPrintSettings,
ErrorResult& aRv) {
RefPtr<Promise> promise =
Promise::Create(GetOwnerDoc()->GetOwnerGlobal(), aRv);
#ifndef NS_PRINTING
promise->MaybeReject(ErrorResult(NS_ERROR_NOT_AVAILABLE));
return promise.forget();
#else
RefPtr<WebProgressListenerToPromise> listener(
new WebProgressListenerToPromise(promise));
if (auto* browserParent = GetBrowserParent()) {
RefPtr<embedding::PrintingParent> printingParent =
browserParent->Manager()->GetPrintingParent();
embedding::PrintData printData;
nsresult rv = printingParent->SerializeAndEnsureRemotePrintJob(
aPrintSettings, listener, nullptr, &printData);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(ErrorResult(rv));
return promise.forget();
}
bool success = browserParent->SendPrint(aOuterWindowID, printData);
if (!success) {
promise->MaybeReject(ErrorResult(NS_ERROR_FAILURE));
}
return promise.forget();
}
RefPtr<nsGlobalWindowOuter> outerWindow =
nsGlobalWindowOuter::GetOuterWindowWithId(aOuterWindowID);
if (NS_WARN_IF(!outerWindow)) {
promise->MaybeReject(ErrorResult(NS_ERROR_FAILURE));
return promise.forget();
}
ErrorResult rv;
outerWindow->Print(aPrintSettings, listener,
/* aDocShellToCloneInto = */ nullptr,
nsGlobalWindowOuter::IsPreview::No,
nsGlobalWindowOuter::IsForWindowDotPrint::No,
/* aPrintPreviewCallback = */ nullptr, rv);
if (rv.Failed()) {
promise->MaybeReject(std::move(rv));
}
return promise.forget();
#endif
}
already_AddRefed<nsIRemoteTab> nsFrameLoader::GetRemoteTab() { already_AddRefed<nsIRemoteTab> nsFrameLoader::GetRemoteTab() {
if (!mRemoteBrowser) { if (!mRemoteBrowser) {
return nullptr; return nullptr;

View File

@@ -236,10 +236,6 @@ class nsFrameLoader final : public nsStubMutationObserver,
void ExitPrintPreview(); void ExitPrintPreview();
already_AddRefed<Promise> Print(uint64_t aOuterWindowID,
nsIPrintSettings* aPrintSettings,
mozilla::ErrorResult& aRv);
void StartPersistence(BrowsingContext* aContext, void StartPersistence(BrowsingContext* aContext,
nsIWebBrowserPersistDocumentReceiver* aRecv, nsIWebBrowserPersistDocumentReceiver* aRecv,
mozilla::ErrorResult& aRv); mozilla::ErrorResult& aRv);

View File

@@ -6,6 +6,7 @@
interface URI; interface URI;
interface nsIDocShell; interface nsIDocShell;
interface nsISecureBrowserUI; interface nsISecureBrowserUI;
interface nsIPrintSettings;
interface nsIWebProgress; interface nsIWebProgress;
interface mixin LoadContextMixin { interface mixin LoadContextMixin {
@@ -257,6 +258,17 @@ interface CanonicalBrowsingContext : BrowsingContext {
[Throws] [Throws]
void loadURI(DOMString aURI, optional LoadURIOptions aOptions = {}); void loadURI(DOMString aURI, optional LoadURIOptions aOptions = {});
/**
* Print the current document.
*
* @param aOuterWindowID the ID of the outer window to print
* @param aPrintSettings print settings to use; printSilent can be
* set to prevent prompting.
* @return A Promise that resolves once printing is finished.
*/
[Throws]
Promise<void> print(nsIPrintSettings aPrintSettings);
/** /**
* These methods implement the nsIWebNavigation methods of the same names * These methods implement the nsIWebNavigation methods of the same names
*/ */

View File

@@ -141,18 +141,6 @@ interface FrameLoader {
[ChromeOnly] [ChromeOnly]
void exitPrintPreview(); void exitPrintPreview();
/**
* Print the current document.
*
* @param aOuterWindowID the ID of the outer window to print
* @param aPrintSettings optional print settings to use; printSilent can be
* set to prevent prompting.
* @return A Promise that resolves once printing is finished.
*/
[Throws]
Promise<void> print(unsigned long long aOuterWindowID,
nsIPrintSettings aPrintSettings);
/** /**
* The element which owns this frame loader. * The element which owns this frame loader.
* *

View File

@@ -552,8 +552,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
mozilla::ipc::IPCResult RecvExitPrintPreview(); mozilla::ipc::IPCResult RecvExitPrintPreview();
mozilla::ipc::IPCResult RecvPrint(const uint64_t& aOuterWindowID, mozilla::ipc::IPCResult RecvPrint(const MaybeDiscardedBrowsingContext&,
const PrintData& aPrintData); const PrintData&);
mozilla::ipc::IPCResult RecvUpdateNativeWindowHandle( mozilla::ipc::IPCResult RecvUpdateNativeWindowHandle(
const uintptr_t& aNewHandle); const uintptr_t& aNewHandle);

View File

@@ -982,10 +982,10 @@ child:
/** /**
* Tell the child to print the current page with the given settings. * Tell the child to print the current page with the given settings.
* *
* @param aOuterWindowID the ID of the outer window to print * @param aBrowsingContext the browsing context to print.
* @param aPrintData the serialized settings to print with * @param aPrintData the serialized settings to print with
*/ */
async Print(uint64_t aOuterWindowID, PrintData aPrintData); async Print(MaybeDiscardedBrowsingContext aBC, PrintData aPrintData);
/** /**
* Update the child with the tab's current top-level native window handle. * Update the child with the tab's current top-level native window handle.

View File

@@ -1697,7 +1697,7 @@ function RecvStartPrint(isPrintSelection, printRange)
getService(Ci.nsIPrefBranch); getService(Ci.nsIPrefBranch);
ps.printInColor = prefs.getBoolPref("print.print_in_color", true); ps.printInColor = prefs.getBoolPref("print.print_in_color", true);
g.browser.print(g.browser.outerWindowID, ps) g.browser.browsingContext.print(ps)
.then(() => SendPrintDone(Cr.NS_OK, file.path)) .then(() => SendPrintDone(Cr.NS_OK, file.path))
.catch(exception => SendPrintDone(exception.code, file.path)); .catch(exception => SendPrintDone(exception.code, file.path));
} }

View File

@@ -608,7 +608,7 @@ class Page extends Domain {
const { linkedBrowser } = this.session.target.tab; const { linkedBrowser } = this.session.target.tab;
await linkedBrowser.print(linkedBrowser.outerWindowID, printSettings); await linkedBrowser.browsingContext.print(printSettings);
// Bug 1603739 - With e10s enabled the promise returned by print() resolves // Bug 1603739 - With e10s enabled the promise returned by print() resolves
// too early, which means the file hasn't been completely written. // too early, which means the file hasn't been completely written.

View File

@@ -3099,11 +3099,7 @@ GeckoDriver.prototype.print = async function(cmd) {
assert.boolean(settings.printBackground); assert.boolean(settings.printBackground);
const linkedBrowser = this.curBrowser.tab.linkedBrowser; const linkedBrowser = this.curBrowser.tab.linkedBrowser;
const filePath = await print.printToFile( const filePath = await print.printToFile(linkedBrowser, settings);
linkedBrowser,
linkedBrowser.outerWindowID,
settings
);
// return all data as a base64 encoded string // return all data as a base64 encoded string
let bytes; let bytes;

View File

@@ -98,7 +98,7 @@ function getPrintSettings(settings, filePath) {
return printSettings; return printSettings;
} }
print.printToFile = async function(browser, outerWindowID, settings) { print.printToFile = async function(browser, settings) {
// Create a unique filename for the temporary PDF file // Create a unique filename for the temporary PDF file
const basePath = OS.Path.join(OS.Constants.Path.tmpDir, "marionette.pdf"); const basePath = OS.Path.join(OS.Constants.Path.tmpDir, "marionette.pdf");
const { file, path: filePath } = await OS.File.openUnique(basePath); const { file, path: filePath } = await OS.File.openUnique(basePath);
@@ -106,7 +106,7 @@ print.printToFile = async function(browser, outerWindowID, settings) {
let printSettings = getPrintSettings(settings, filePath); let printSettings = getPrintSettings(settings, filePath);
await browser.print(outerWindowID, printSettings); await browser.browsingContext.print(printSettings);
// Bug 1603739 - With e10s enabled the promise returned by print() resolves // Bug 1603739 - With e10s enabled the promise returned by print() resolves
// too early, which means the file hasn't been completely written. // too early, which means the file hasn't been completely written.

View File

@@ -785,11 +785,7 @@ browserRect.height: ${browserRect.height}`);
printBackground: true, printBackground: true,
}); });
const filePath = await print.printToFile( const filePath = await print.printToFile(win.gBrowser, settings);
win.gBrowser.frameLoader,
win.gBrowser.outerWindowID,
settings
);
const fp = await OS.File.open(filePath, { read: true }); const fp = await OS.File.open(filePath, { read: true });
try { try {

View File

@@ -414,7 +414,7 @@ var PrintEventHandler = {
this.printProgressIndicator.hidden = false; this.printProgressIndicator.hidden = false;
let bc = this.currentPreviewBrowser.browsingContext; let bc = this.currentPreviewBrowser.browsingContext;
await this._doPrint(bc, settings); await bc.print(settings);
} catch (e) { } catch (e) {
Cu.reportError(e); Cu.reportError(e);
} }
@@ -1013,17 +1013,6 @@ var PrintEventHandler = {
Services.telemetry.keyedScalarAdd("printing.error", aMessage, 1); Services.telemetry.keyedScalarAdd("printing.error", aMessage, 1);
}, },
/**
* Prints the window. This method has been abstracted into a helper for
* testing purposes.
*/
_doPrint(aBrowsingContext, aSettings) {
return aBrowsingContext.top.embedderElement.print(
aBrowsingContext.currentWindowGlobal.outerWindowId,
aSettings
);
},
/** /**
* Shows the system dialog. This method has been abstracted into a helper for * Shows the system dialog. This method has been abstracted into a helper for
* testing purposes. The showPrintDialog() call blocks until the dialog is * testing purposes. The showPrintDialog() call blocks until the dialog is

View File

@@ -370,8 +370,7 @@ var PrintUtils = {
* Optional print settings for the print operation * Optional print settings for the print operation
*/ */
printWindow(aBrowsingContext, aPrintSettings) { printWindow(aBrowsingContext, aPrintSettings) {
let windowID = aBrowsingContext.currentWindowGlobal.outerWindowId; let wg = aBrowsingContext.currentWindowGlobal;
let topBrowser = aBrowsingContext.top.embedderElement;
const printPreviewIsOpen = !!document.getElementById( const printPreviewIsOpen = !!document.getElementById(
"print-preview-toolbar" "print-preview-toolbar"
@@ -388,18 +387,18 @@ var PrintUtils = {
// Set the title so that the print dialog can pick it up and // Set the title so that the print dialog can pick it up and
// use it to generate the filename for save-to-PDF. // use it to generate the filename for save-to-PDF.
printSettings.title = this._originalTitle || topBrowser.contentTitle; printSettings.title = this._originalTitle || wg.documentTitle;
if (this._shouldSimplify) { if (this._shouldSimplify) {
// The generated document for simplified print preview has "about:blank" // The generated document for simplified print preview has "about:blank"
// as its URL. We need to set docURL here so that the print header/footer // as its URL. We need to set docURL here so that the print header/footer
// can be given the original document's URL. // can be given the original document's URL.
printSettings.docURL = this._originalURL || topBrowser.currentURI.spec; printSettings.docURL = this._originalURL || wg.documentURI;
} }
// At some point we should handle the Promise that this returns (report // At some point we should handle the Promise that this returns (report
// rejection to telemetry?) // rejection to telemetry?)
let promise = topBrowser.print(windowID, printSettings); let promise = aBrowsingContext.print(printSettings);
if (printPreviewIsOpen) { if (printPreviewIsOpen) {
if (this._shouldSimplify) { if (this._shouldSimplify) {

View File

@@ -1731,14 +1731,6 @@
}; };
} }
print(aOuterWindowID, aPrintSettings) {
if (!this.frameLoader) {
throw Components.Exception("No frame loader.", Cr.NS_ERROR_FAILURE);
}
return this.frameLoader.print(aOuterWindowID, aPrintSettings);
}
async drawSnapshot(x, y, w, h, scale, backgroundColor) { async drawSnapshot(x, y, w, h, scale, backgroundColor) {
let rect = new DOMRect(x, y, w, h); let rect = new DOMRect(x, y, w, h);
try { try {