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
Родитель 6dae709f27
Коммит 9afefdd884
17 изменённых файлов: 152 добавлений и 173 удалений

Просмотреть файл

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

Просмотреть файл

@ -42,6 +42,11 @@
#include "nsIBrowser.h"
#include "nsTHashSet.h"
#ifdef NS_PRINTING
# include "mozilla/embedding/printingui/PrintingParent.h"
# include "nsIWebBrowserPrint.h"
#endif
using namespace mozilla::ipc;
extern mozilla::LazyLogModule gAutoplayPermissionLog;
@ -479,6 +484,120 @@ CanonicalBrowsingContext::ReplaceLoadingSessionHistoryEntryForLoad(
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(
const std::function<mozilla::CallState(CanonicalBrowsingContext*)>&
aCallback) {

Просмотреть файл

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

Просмотреть файл

@ -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(
nsIPrintSettings* aPrintSettings,
const Optional<uint64_t>& aSourceOuterWindowID, ErrorResult& aRv) {
@ -3438,60 +3380,6 @@ void nsFrameLoader::ExitPrintPreview() {
#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() {
if (!mRemoteBrowser) {
return nullptr;

Просмотреть файл

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

Просмотреть файл

@ -6,6 +6,7 @@
interface URI;
interface nsIDocShell;
interface nsISecureBrowserUI;
interface nsIPrintSettings;
interface nsIWebProgress;
interface mixin LoadContextMixin {
@ -257,6 +258,17 @@ interface CanonicalBrowsingContext : BrowsingContext {
[Throws]
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
*/

Просмотреть файл

@ -141,18 +141,6 @@ interface FrameLoader {
[ChromeOnly]
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.
*

Просмотреть файл

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

Просмотреть файл

@ -982,10 +982,10 @@ child:
/**
* 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
*/
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.

Просмотреть файл

@ -1697,7 +1697,7 @@ function RecvStartPrint(isPrintSelection, printRange)
getService(Ci.nsIPrefBranch);
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))
.catch(exception => SendPrintDone(exception.code, file.path));
}

Просмотреть файл

@ -608,7 +608,7 @@ class Page extends Domain {
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
// too early, which means the file hasn't been completely written.

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -414,7 +414,7 @@ var PrintEventHandler = {
this.printProgressIndicator.hidden = false;
let bc = this.currentPreviewBrowser.browsingContext;
await this._doPrint(bc, settings);
await bc.print(settings);
} catch (e) {
Cu.reportError(e);
}
@ -1013,17 +1013,6 @@ var PrintEventHandler = {
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
* testing purposes. The showPrintDialog() call blocks until the dialog is

Просмотреть файл

@ -370,8 +370,7 @@ var PrintUtils = {
* Optional print settings for the print operation
*/
printWindow(aBrowsingContext, aPrintSettings) {
let windowID = aBrowsingContext.currentWindowGlobal.outerWindowId;
let topBrowser = aBrowsingContext.top.embedderElement;
let wg = aBrowsingContext.currentWindowGlobal;
const printPreviewIsOpen = !!document.getElementById(
"print-preview-toolbar"
@ -388,18 +387,18 @@ var PrintUtils = {
// Set the title so that the print dialog can pick it up and
// 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) {
// 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
// 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
// rejection to telemetry?)
let promise = topBrowser.print(windowID, printSettings);
let promise = aBrowsingContext.print(printSettings);
if (printPreviewIsOpen) {
if (this._shouldSimplify) {

Просмотреть файл

@ -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) {
let rect = new DOMRect(x, y, w, h);
try {