зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1630323 - Do not override user preferences when clicking on a service worker notification to open a new document, r=Gijs,nika,geckoview-reviewers,snorp
In Bug 1622749 a user preference for where to open new documents (from a service worker notification) was temporarily overriden in order to quickly fix a crash that was happening in mozilla::dom::ClientOpenWindow. The crash was ocurring when the pref "browser.link.open_newwindow" was set to 2, meaning new documents are opened in a new window, instead of a new tab. The reason the browser crashed is because the path for opening a new document is different depending on the current user setting, and in NEWWINDOW case we did not get a browsing context returned when calling mozilla::dom::OpenWindow which resulted in a failed assertion. The solution is to pass in a callback to mozilla::dom::OpenWindow as part of nsOpenWindowInfo object, and invoke that callback with a corresponding BrowsingContext in nsFrameLoader when that browsing context is ready. After we call mozilla::dom::OpenWindow, we wait on a promise, that will be resolved when the callback is invoked, before executing the rest of the code that depends on the browsing context for a newly opened document being available. Differential Revision: https://phabricator.services.mozilla.com/D72745
This commit is contained in:
Родитель
34915064c5
Коммит
28243d5736
|
@ -2218,6 +2218,7 @@ var gBrowserInit = {
|
|||
// [8]: triggeringPrincipal (nsIPrincipal)
|
||||
// [9]: allowInheritPrincipal (bool)
|
||||
// [10]: csp (nsIContentSecurityPolicy)
|
||||
// [11]: nsOpenWindowInfo
|
||||
let userContextId =
|
||||
window.arguments[5] != undefined
|
||||
? window.arguments[5]
|
||||
|
@ -6106,7 +6107,7 @@ nsBrowserAccess.prototype = {
|
|||
case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW:
|
||||
// FIXME: Bug 408379. So how come this doesn't send the
|
||||
// referrer like the other loads do?
|
||||
var url = aURI ? aURI.spec : "about:blank";
|
||||
var url = aURI && aURI.spec;
|
||||
let features = "all,dialog=no";
|
||||
if (isPrivate) {
|
||||
features += ",private";
|
||||
|
@ -6129,18 +6130,14 @@ nsBrowserAccess.prototype = {
|
|||
null,
|
||||
aTriggeringPrincipal,
|
||||
null,
|
||||
aCsp
|
||||
aCsp,
|
||||
aOpenWindowInfo
|
||||
);
|
||||
// At this point, the new browser window is just starting to load, and
|
||||
// hasn't created the content <browser> that we should return. So we
|
||||
// can't actually return a valid BrowsingContext for this load without
|
||||
// spinning the event loop.
|
||||
//
|
||||
// Fortunately, no current callers of this API who pass OPEN_NEWWINDOW
|
||||
// actually use the return value, so we're safe returning null for
|
||||
// now.
|
||||
//
|
||||
// Ideally this should be fixed.
|
||||
// hasn't created the content <browser> that we should return.
|
||||
// If the caller of this function is originating in C++, they can pass a
|
||||
// callback in nsOpenWindowInfo and it will be invoked when the browsing
|
||||
// context for a newly opened window is ready.
|
||||
browsingContext = null;
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
|
@ -6153,7 +6150,7 @@ nsBrowserAccess.prototype = {
|
|||
// we can hand back the nsIDOMWindow. The XULBrowserWindow.shouldLoadURI
|
||||
// will do the job of shuttling off the newly opened browser to run in
|
||||
// the right process once it starts loading a URI.
|
||||
let forceNotRemote = aOpenWindowInfo && !aOpenWindowInfo.remote;
|
||||
let forceNotRemote = aOpenWindowInfo && !aOpenWindowInfo.isRemote;
|
||||
let userContextId = aOpenWindowInfo
|
||||
? aOpenWindowInfo.originAttributes.userContextId
|
||||
: Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
|
||||
|
@ -6177,8 +6174,7 @@ nsBrowserAccess.prototype = {
|
|||
break;
|
||||
default:
|
||||
// OPEN_CURRENTWINDOW or an illegal value
|
||||
browsingContext =
|
||||
window.content && BrowsingContext.getFromWindow(window.content);
|
||||
browsingContext = window.gBrowser.selectedBrowser.browsingContext;
|
||||
if (aURI) {
|
||||
let loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
if (isExternal) {
|
||||
|
|
|
@ -326,6 +326,10 @@
|
|||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIAppWindow).initialOpenWindowInfo;
|
||||
|
||||
if (!openWindowInfo && window.arguments && window.arguments[11]) {
|
||||
openWindowInfo = window.arguments[11];
|
||||
}
|
||||
|
||||
let tabArgument = gBrowserInit.getTabToAdopt();
|
||||
|
||||
// We only need sameProcessAsFrameLoader in the case where we're passed a tab
|
||||
|
|
|
@ -275,8 +275,8 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
|
|||
RefPtr<BrowsingContext> opener;
|
||||
if (aOpenWindowInfo && !aOpenWindowInfo->GetForceNoOpener()) {
|
||||
opener = aOpenWindowInfo->GetParent();
|
||||
MOZ_ASSERT(opener->IsInProcess(),
|
||||
"Must create BrowsingContext with opener in-process");
|
||||
// Must create BrowsingContext with opener in-process.
|
||||
MOZ_ASSERT_IF(opener, opener->IsInProcess());
|
||||
}
|
||||
|
||||
RefPtr<nsGlobalWindowInner> parentInner =
|
||||
|
@ -2067,6 +2067,8 @@ nsresult nsFrameLoader::MaybeCreateDocShell() {
|
|||
mPendingBrowsingContext->SetEmbedderElement(mOwnerContent);
|
||||
mPendingBrowsingContext->Embed();
|
||||
|
||||
InvokeBrowsingContextReadyCallback();
|
||||
|
||||
mIsTopLevelContent = mPendingBrowsingContext->IsContent() &&
|
||||
!mPendingBrowsingContext->GetParent();
|
||||
if (!mNetworkCreated && !mIsTopLevelContent) {
|
||||
|
@ -2588,6 +2590,7 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
|
|||
mRemoteBrowser->GetBrowsingContext());
|
||||
|
||||
mRemoteBrowser->GetBrowsingContext()->Embed();
|
||||
InvokeBrowsingContextReadyCallback();
|
||||
|
||||
// Grab the reference to the actor
|
||||
RefPtr<BrowserParent> browserParent = GetBrowserParent();
|
||||
|
@ -3554,3 +3557,12 @@ bool nsFrameLoader::EnsureBrowsingContextAttached() {
|
|||
mPendingBrowsingContext->EnsureAttached();
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsFrameLoader::InvokeBrowsingContextReadyCallback() {
|
||||
if (mOpenWindowInfo) {
|
||||
if (RefPtr<nsIBrowsingContextReadyCallback> callback =
|
||||
mOpenWindowInfo->BrowsingContextReadyCallback()) {
|
||||
callback->BrowsingContextReady(mPendingBrowsingContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -465,6 +465,10 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
|
||||
bool EnsureBrowsingContextAttached();
|
||||
|
||||
// Invoke the callback from nsOpenWindowInfo to indicate that a
|
||||
// browsing context for a newly opened tab/window is ready.
|
||||
void InvokeBrowsingContextReadyCallback();
|
||||
|
||||
RefPtr<mozilla::dom::BrowsingContext> mPendingBrowsingContext;
|
||||
nsCOMPtr<nsIURI> mURIToLoad;
|
||||
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "nsPIWindowWatcher.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsWindowWatcher.h"
|
||||
#include "nsOpenWindowInfo.h"
|
||||
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
|
@ -180,43 +181,18 @@ class WebProgressListener final : public nsIWebProgressListener,
|
|||
NS_IMPL_ISUPPORTS(WebProgressListener, nsIWebProgressListener,
|
||||
nsISupportsWeakReference);
|
||||
|
||||
void OpenWindow(const ClientOpenWindowArgs& aArgs, BrowsingContext** aBC,
|
||||
struct ClientOpenWindowArgsParsed {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
};
|
||||
|
||||
void OpenWindow(const ClientOpenWindowArgsParsed& aArgsValidated,
|
||||
nsOpenWindowInfo* aOpenInfo, BrowsingContext** aBC,
|
||||
ErrorResult& aRv) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aBC);
|
||||
|
||||
// [[1. Let url be the result of parsing url with entry settings object's API
|
||||
// base URL.]]
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), aArgs.baseURL());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsPrintfCString err("Invalid base URL \"%s\"", aArgs.baseURL().get());
|
||||
aRv.ThrowTypeError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(uri), aArgs.url(), nullptr, baseURI);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsPrintfCString err("Invalid URL \"%s\"", aArgs.url().get());
|
||||
aRv.ThrowTypeError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
auto principalOrErr = PrincipalInfoToPrincipal(aArgs.principalInfo());
|
||||
if (NS_WARN_IF(principalOrErr.isErr())) {
|
||||
nsPrintfCString err("Failed to obtain principal");
|
||||
aRv.ThrowTypeError(err);
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
|
||||
MOZ_DIAGNOSTIC_ASSERT(principal);
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
if (aArgs.cspInfo().isSome()) {
|
||||
csp = CSPInfoToCSP(aArgs.cspInfo().ref(), nullptr);
|
||||
}
|
||||
|
||||
// [[6.1 Open Window]]
|
||||
|
||||
// Find the most recent browser window and open a new tab in it.
|
||||
|
@ -244,33 +220,23 @@ void OpenWindow(const ClientOpenWindowArgs& aArgs, BrowsingContext** aBC,
|
|||
aRv.ThrowTypeError("Unable to open window");
|
||||
return;
|
||||
}
|
||||
// annyG: This is a hack to fix bug 1622749.
|
||||
// We will force to open new windows in tabs so we don't crash later.
|
||||
rv = bwin->OpenURI(uri, nullptr, nsIBrowserDOMWindow::OPEN_NEWTAB,
|
||||
nsIBrowserDOMWindow::OPEN_NEW, principal, csp, aBC);
|
||||
nsresult rv = bwin->CreateContentWindow(
|
||||
nullptr, aOpenInfo, nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
|
||||
nsIBrowserDOMWindow::OPEN_NEW, aArgsValidated.principal,
|
||||
aArgsValidated.csp, aBC);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.ThrowTypeError("Unable to open window");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForLoad(const ClientOpenWindowArgs& aArgs,
|
||||
void WaitForLoad(const ClientOpenWindowArgsParsed& aArgsValidated,
|
||||
BrowsingContext* aBrowsingContext,
|
||||
ClientOpPromise::Private* aPromise) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aBrowsingContext);
|
||||
|
||||
RefPtr<ClientOpPromise::Private> promise = aPromise;
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), aArgs.baseURL());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// Shouldn't really happen, since we passed in the serialization of a URI.
|
||||
CopyableErrorResult result;
|
||||
result.ThrowSyntaxError("Bad URL");
|
||||
promise->Reject(result, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWebProgress> webProgress;
|
||||
if (nsIDocShell* docShell = aBrowsingContext->GetDocShell()) {
|
||||
// We're dealing with a non-remote frame. We have access to an nsDocShell,
|
||||
|
@ -307,14 +273,11 @@ void WaitForLoad(const ClientOpenWindowArgs& aArgs,
|
|||
promise->Reject(result, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (BrowserParent* browserParent = BrowserParent::GetFrom(element)) {
|
||||
browserParent->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<WebProgressListener> listener =
|
||||
new WebProgressListener(aBrowsingContext, baseURI, do_AddRef(promise));
|
||||
// Add a progress listener before we start the load of the service worker URI
|
||||
RefPtr<WebProgressListener> listener = new WebProgressListener(
|
||||
aBrowsingContext, aArgsValidated.baseURI, do_AddRef(promise));
|
||||
|
||||
rv = webProgress->AddProgressListener(listener,
|
||||
nsIWebProgress::NOTIFY_STATE_WINDOW);
|
||||
|
@ -326,6 +289,22 @@ void WaitForLoad(const ClientOpenWindowArgs& aArgs,
|
|||
return;
|
||||
}
|
||||
|
||||
// Load the service worker URI
|
||||
RefPtr<nsDocShellLoadState> loadState =
|
||||
new nsDocShellLoadState(aArgsValidated.uri);
|
||||
loadState->SetTriggeringPrincipal(aArgsValidated.principal);
|
||||
loadState->SetFirstParty(true);
|
||||
loadState->SetLoadFlags(
|
||||
nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL);
|
||||
|
||||
rv = aBrowsingContext->LoadURI(loadState, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
CopyableErrorResult result;
|
||||
result.ThrowInvalidStateError("Unable to start the load of the actual URI");
|
||||
promise->Reject(result, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hold the listener alive until the promise settles.
|
||||
promise->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
|
@ -335,14 +314,15 @@ void WaitForLoad(const ClientOpenWindowArgs& aArgs,
|
|||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
|
||||
void GeckoViewOpenWindow(const ClientOpenWindowArgs& aArgs,
|
||||
void GeckoViewOpenWindow(const ClientOpenWindowArgsParsed& aArgsValidated,
|
||||
ClientOpPromise::Private* aPromise) {
|
||||
RefPtr<ClientOpPromise::Private> promise = aPromise;
|
||||
|
||||
// passes the request to open a new window to GeckoView. Allowing the
|
||||
// application to decide how to hand the open window request.
|
||||
auto genericResult =
|
||||
java::GeckoRuntime::ServiceWorkerOpenWindow(aArgs.baseURL(), aArgs.url());
|
||||
nsAutoCString uri;
|
||||
MOZ_ALWAYS_SUCCEEDS(aArgsValidated.uri->GetSpec(uri));
|
||||
auto genericResult = java::GeckoRuntime::ServiceWorkerOpenWindow(uri);
|
||||
auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
|
||||
|
||||
// MozPromise containing the ID for the handling GeckoSession
|
||||
|
@ -352,7 +332,7 @@ void GeckoViewOpenWindow(const ClientOpenWindowArgs& aArgs,
|
|||
|
||||
promiseResult->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[aArgs, promise](nsString sessionId) {
|
||||
[aArgsValidated, promise](nsString sessionId) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch =
|
||||
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
|
||||
|
@ -372,7 +352,7 @@ void GeckoViewOpenWindow(const ClientOpenWindowArgs& aArgs,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WaitForLoad(aArgs, browsingContext, promise);
|
||||
WaitForLoad(aArgsValidated, browsingContext, promise);
|
||||
return NS_OK;
|
||||
},
|
||||
[promise](nsString aResult) {
|
||||
|
@ -390,23 +370,87 @@ RefPtr<ClientOpPromise> ClientOpenWindow(const ClientOpenWindowArgs& aArgs) {
|
|||
RefPtr<ClientOpPromise::Private> promise =
|
||||
new ClientOpPromise::Private(__func__);
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// If we are on Android we are GeckoView.
|
||||
GeckoViewOpenWindow(aArgs, promise);
|
||||
return promise.forget();
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
RefPtr<BrowsingContext> bc;
|
||||
ErrorResult rv;
|
||||
OpenWindow(aArgs, getter_AddRefs(bc), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
promise->Reject(rv, __func__);
|
||||
// [[1. Let url be the result of parsing url with entry settings object's API
|
||||
// base URL.]]
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), aArgs.baseURL());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsPrintfCString err("Invalid base URL \"%s\"", aArgs.baseURL().get());
|
||||
CopyableErrorResult errResult;
|
||||
errResult.ThrowTypeError(err);
|
||||
promise->Reject(errResult, __func__);
|
||||
return promise;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(bc);
|
||||
WaitForLoad(aArgs, bc, promise);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), aArgs.url(), nullptr, baseURI);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsPrintfCString err("Invalid URL \"%s\"", aArgs.url().get());
|
||||
CopyableErrorResult errResult;
|
||||
errResult.ThrowTypeError(err);
|
||||
promise->Reject(errResult, __func__);
|
||||
return promise;
|
||||
}
|
||||
|
||||
auto principalOrErr = PrincipalInfoToPrincipal(aArgs.principalInfo());
|
||||
if (NS_WARN_IF(principalOrErr.isErr())) {
|
||||
CopyableErrorResult errResult;
|
||||
errResult.ThrowTypeError("Failed to obtain principal");
|
||||
promise->Reject(errResult, __func__);
|
||||
return promise;
|
||||
}
|
||||
nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
|
||||
MOZ_DIAGNOSTIC_ASSERT(principal);
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
if (aArgs.cspInfo().isSome()) {
|
||||
csp = CSPInfoToCSP(aArgs.cspInfo().ref(), nullptr);
|
||||
}
|
||||
ClientOpenWindowArgsParsed argsValidated;
|
||||
argsValidated.uri = uri;
|
||||
argsValidated.baseURI = baseURI;
|
||||
argsValidated.principal = principal;
|
||||
argsValidated.csp = csp;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// If we are on Android we are GeckoView.
|
||||
GeckoViewOpenWindow(argsValidated, promise);
|
||||
return promise.forget();
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
RefPtr<BrowsingContextCallbackReceivedPromise::Private>
|
||||
browsingContextReadyPromise =
|
||||
new BrowsingContextCallbackReceivedPromise::Private(__func__);
|
||||
RefPtr<nsIBrowsingContextReadyCallback> callback =
|
||||
new nsBrowsingContextReadyCallback(browsingContextReadyPromise);
|
||||
|
||||
RefPtr<nsOpenWindowInfo> openInfo = new nsOpenWindowInfo();
|
||||
openInfo->mBrowsingContextReadyCallback = callback;
|
||||
openInfo->mOriginAttributes = principal->OriginAttributesRef();
|
||||
openInfo->mIsRemote = true;
|
||||
|
||||
RefPtr<BrowsingContext> bc;
|
||||
ErrorResult errResult;
|
||||
OpenWindow(argsValidated, openInfo, getter_AddRefs(bc), errResult);
|
||||
if (NS_WARN_IF(errResult.Failed())) {
|
||||
promise->Reject(errResult, __func__);
|
||||
return promise;
|
||||
}
|
||||
|
||||
browsingContextReadyPromise->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[argsValidated, promise](const RefPtr<BrowsingContext>& aBC) {
|
||||
WaitForLoad(argsValidated, aBC, promise);
|
||||
},
|
||||
[promise]() {
|
||||
// in case of failure, reject the original promise
|
||||
CopyableErrorResult result;
|
||||
result.ThrowTypeError("Unable to open window");
|
||||
promise->Reject(result, __func__);
|
||||
});
|
||||
if (bc) {
|
||||
browsingContextReadyPromise->Resolve(bc, __func__);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
typedef MozPromise<RefPtr<BrowsingContext>, CopyableErrorResult, false>
|
||||
BrowsingContextCallbackReceivedPromise;
|
||||
|
||||
MOZ_MUST_USE RefPtr<ClientOpPromise> ClientOpenWindow(
|
||||
const ClientOpenWindowArgs& aArgs);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ EXPORTS.mozilla.dom += [
|
|||
'ClientManager.h',
|
||||
'ClientManagerActors.h',
|
||||
'ClientManagerService.h',
|
||||
'ClientOpenWindowUtils.h',
|
||||
'ClientOpPromise.h',
|
||||
'ClientSource.h',
|
||||
'ClientState.h',
|
||||
|
|
|
@ -48,6 +48,13 @@ add_task(async function test() {
|
|||
SpecialPowers.Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW,
|
||||
SpecialPowers.Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
]) {
|
||||
if (prefValue == SpecialPowers.Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW) {
|
||||
// Let's open a new tab and focus on it. When the service
|
||||
// worker notification is shown, the document will open in the focused tab.
|
||||
// If we don't open a new tab, the document will be opened in the
|
||||
// current test-runner tab and mess up the test setup.
|
||||
window.open("");
|
||||
}
|
||||
info(`Setting browser.link.open_newwindow to ${prefValue}.`);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.link.open_newwindow", prefValue]],
|
||||
|
@ -72,6 +79,8 @@ add_task(async function test() {
|
|||
|
||||
// If we make it here, then we didn't crash.
|
||||
ok(true, "Didn't crash!");
|
||||
|
||||
navigator.serviceWorker.onmessage = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ import org.yaml.snakeyaml.error.YAMLException;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -195,26 +194,24 @@ public final class GeckoRuntime implements Parcelable {
|
|||
/**
|
||||
* Called by mozilla::dom::ClientOpenWindow to retrieve the window id to use
|
||||
* for a ServiceWorkerClients.openWindow() request.
|
||||
* @param baseUrl The base Url for the request.
|
||||
* @param url Url being requested to be opened in a new window.
|
||||
* @param url validated Url being requested to be opened in a new window.
|
||||
* @return SessionID to use for the request.
|
||||
*/
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private static @NonNull GeckoResult<String> serviceWorkerOpenWindow(final @NonNull String baseUrl, final @NonNull String url) {
|
||||
private static @NonNull GeckoResult<String> serviceWorkerOpenWindow(final @NonNull String url) {
|
||||
if (sRuntime != null && sRuntime.mServiceWorkerDelegate != null) {
|
||||
final URI actual = URI.create(baseUrl).resolve(url);
|
||||
GeckoResult<String> result = new GeckoResult<>();
|
||||
// perform the onOpenWindow call in the UI thread
|
||||
ThreadUtils.runOnUiThread(() -> {
|
||||
sRuntime
|
||||
.mServiceWorkerDelegate
|
||||
.onOpenWindow(actual.toString())
|
||||
.onOpenWindow(url)
|
||||
.accept( session -> {
|
||||
if (session != null) {
|
||||
if (!session.isOpen()) {
|
||||
result.completeExceptionally(new RuntimeException("Returned GeckoSession must be open."));
|
||||
} else {
|
||||
session.loadUri(actual.toString());
|
||||
session.loadUri(url);
|
||||
result.complete(session.getId());
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -19,6 +19,17 @@ class BrowserParent;
|
|||
[ref] native const_OriginAttributes(const mozilla::OriginAttributes);
|
||||
[ptr] native BrowserParent(mozilla::dom::BrowserParent);
|
||||
|
||||
/*
|
||||
* nsIBrowsingContextReadyCallback.browsingContextReady() is called within
|
||||
* nsFrameLoader to indicate that the browsing context for a newly opened
|
||||
* window/tab is ready.
|
||||
*/
|
||||
[uuid(0524ee06-7f4c-4cd3-ab80-084562745cad)]
|
||||
interface nsIBrowsingContextReadyCallback : nsISupports
|
||||
{
|
||||
void browsingContextReady(in BrowsingContext bc);
|
||||
};
|
||||
|
||||
/**
|
||||
* nsIOpenWindowInfo is a helper type which contains details used when opening
|
||||
* new content windows. This object is used to correctly create new initial
|
||||
|
@ -48,4 +59,8 @@ interface nsIOpenWindowInfo : nsISupports {
|
|||
|
||||
[notxpcom, nostdcall, binaryname(GetOriginAttributes)]
|
||||
const_OriginAttributes binaryGetOriginAttributes();
|
||||
|
||||
/* Callback to invoke when the browsing context for a new window is ready. */
|
||||
[notxpcom, nostdcall]
|
||||
nsIBrowsingContextReadyCallback browsingContextReadyCallback();
|
||||
};
|
||||
|
|
|
@ -41,3 +41,33 @@ const OriginAttributes& nsOpenWindowInfo::GetOriginAttributes() {
|
|||
BrowserParent* nsOpenWindowInfo::GetNextRemoteBrowser() {
|
||||
return mNextRemoteBrowser;
|
||||
}
|
||||
|
||||
nsIBrowsingContextReadyCallback*
|
||||
nsOpenWindowInfo::BrowsingContextReadyCallback() {
|
||||
return mBrowsingContextReadyCallback;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBrowsingContextReadyCallback,
|
||||
nsIBrowsingContextReadyCallback)
|
||||
|
||||
nsBrowsingContextReadyCallback::nsBrowsingContextReadyCallback(
|
||||
RefPtr<BrowsingContextCallbackReceivedPromise::Private> aPromise)
|
||||
: mPromise(std::move(aPromise)) {}
|
||||
|
||||
nsBrowsingContextReadyCallback::~nsBrowsingContextReadyCallback() {
|
||||
if (mPromise) {
|
||||
mPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBrowsingContextReadyCallback::BrowsingContextReady(
|
||||
BrowsingContext* aBC) {
|
||||
if (aBC) {
|
||||
mPromise->Resolve(aBC, __func__);
|
||||
} else {
|
||||
mPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
mPromise = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/ClientOpenWindowUtils.h"
|
||||
|
||||
class nsOpenWindowInfo : public nsIOpenWindowInfo {
|
||||
public:
|
||||
|
@ -19,12 +20,29 @@ class nsOpenWindowInfo : public nsIOpenWindowInfo {
|
|||
|
||||
bool mForceNoOpener = false;
|
||||
bool mIsRemote = false;
|
||||
RefPtr<BrowserParent> mNextRemoteBrowser;
|
||||
OriginAttributes mOriginAttributes;
|
||||
RefPtr<BrowsingContext> mParent;
|
||||
RefPtr<mozilla::dom::BrowserParent> mNextRemoteBrowser;
|
||||
mozilla::OriginAttributes mOriginAttributes;
|
||||
RefPtr<mozilla::dom::BrowsingContext> mParent;
|
||||
RefPtr<nsIBrowsingContextReadyCallback> mBrowsingContextReadyCallback;
|
||||
|
||||
private:
|
||||
virtual ~nsOpenWindowInfo() = default;
|
||||
};
|
||||
|
||||
class nsBrowsingContextReadyCallback : public nsIBrowsingContextReadyCallback {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIBROWSINGCONTEXTREADYCALLBACK
|
||||
|
||||
explicit nsBrowsingContextReadyCallback(
|
||||
RefPtr<mozilla::dom::BrowsingContextCallbackReceivedPromise::Private>
|
||||
aPromise);
|
||||
|
||||
private:
|
||||
virtual ~nsBrowsingContextReadyCallback();
|
||||
|
||||
RefPtr<mozilla::dom::BrowsingContextCallbackReceivedPromise::Private>
|
||||
mPromise;
|
||||
};
|
||||
|
||||
#endif // nsOpenWindowInfo_h
|
||||
|
|
Загрузка…
Ссылка в новой задаче