Bug 1616353 - Part 7.3: Use nsOpenWindowInfo for initializing xul:browser elements, r=kmag

This patch adds a `openWindowInfo` XPCOM attribute to the `nsIBrowser` interface
supported by the browser custom element. This attribute is then read by
`XULFrameElement`, and passed to `nsFrameLoader` to ensure the relevant flags
are used for newly opened windows.

This patch does not add support for passing openWindowInfo into mozbrowser
elements.

Differential Revision: https://phabricator.services.mozilla.com/D67052

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nika Layzell 2020-04-07 21:39:34 +00:00
Родитель 17acacfbf5
Коммит 3fee0903f1
6 изменённых файлов: 55 добавлений и 75 удалений

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

@ -47,6 +47,7 @@
#include "nsBaseWidget.h"
#include "nsQueryObject.h"
#include "ReferrerInfo.h"
#include "nsIOpenWindowInfo.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
@ -257,7 +258,12 @@ static bool IsTopContent(BrowsingContext* aParent, Element* aOwner) {
}
static already_AddRefed<BrowsingContext> CreateBrowsingContext(
Element* aOwner, BrowsingContext* aOpener) {
Element* aOwner, nsIOpenWindowInfo* aOpenWindowInfo) {
RefPtr<BrowsingContext> opener;
if (aOpenWindowInfo && !aOpenWindowInfo->GetForceNoOpener()) {
opener = aOpenWindowInfo->GetParent();
}
Document* doc = aOwner->OwnerDoc();
// Get our parent docshell off the document of mOwnerContent
// XXXbz this is such a total hack.... We really need to have a
@ -290,7 +296,7 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
if (IsTopContent(parentContext, aOwner)) {
// Create toplevel content without a parent & as Type::Content.
RefPtr<BrowsingContext> bc = BrowsingContext::CreateDetached(
nullptr, aOpener, frameName, BrowsingContext::Type::Content);
nullptr, opener, frameName, BrowsingContext::Type::Content);
// If this is a mozbrowser frame, pretend it's windowless so that it gets
// ownership of its BrowsingContext even though it's a top-level content
@ -304,10 +310,13 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
return bc.forget();
}
MOZ_ASSERT(!aOpenWindowInfo,
"Can't have openWindowInfo for non-toplevel context");
auto type = parentContext->IsContent() ? BrowsingContext::Type::Content
: BrowsingContext::Type::Chrome;
return BrowsingContext::CreateDetached(parentContext, aOpener, frameName,
return BrowsingContext::CreateDetached(parentContext, nullptr, frameName,
type);
}
@ -339,9 +348,8 @@ static bool InitialLoadIsRemote(Element* aOwner) {
nsGkAtoms::_true, eCaseMatters);
}
already_AddRefed<nsFrameLoader> nsFrameLoader::Create(Element* aOwner,
BrowsingContext* aOpener,
bool aNetworkCreated) {
already_AddRefed<nsFrameLoader> nsFrameLoader::Create(
Element* aOwner, bool aNetworkCreated, nsIOpenWindowInfo* aOpenWindowInfo) {
NS_ENSURE_TRUE(aOwner, nullptr);
Document* doc = aOwner->OwnerDoc();
@ -370,7 +378,8 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Create(Element* aOwner,
doc->IsStaticDocument()),
nullptr);
RefPtr<BrowsingContext> context = CreateBrowsingContext(aOwner, aOpener);
RefPtr<BrowsingContext> context =
CreateBrowsingContext(aOwner, aOpenWindowInfo);
NS_ENSURE_TRUE(context, nullptr);
// Determine the initial RemoteType from the load environment. An empty or
@ -378,8 +387,6 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Create(Element* aOwner,
// denotes a remote frame.
nsAutoString remoteType(VoidString());
if (InitialLoadIsRemote(aOwner)) {
MOZ_ASSERT(!aOpener, "Cannot pass `aOpener` for a remote frame!");
// If the `remoteType` attribute is specified and valid, use it. Otherwise,
// use a default remote type.
bool hasRemoteType =
@ -391,6 +398,7 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Create(Element* aOwner,
RefPtr<nsFrameLoader> fl =
new nsFrameLoader(aOwner, context, remoteType, aNetworkCreated);
fl->mOpenWindowInfo = aOpenWindowInfo;
return fl.forget();
}
@ -411,7 +419,7 @@ already_AddRefed<nsFrameLoader> nsFrameLoader::Recreate(
RefPtr<BrowsingContext> context = aContext;
if (!context) {
context = CreateBrowsingContext(aOwner, /* opener */ nullptr);
context = CreateBrowsingContext(aOwner, /* openWindowInfo */ nullptr);
}
NS_ENSURE_TRUE(context, nullptr);
@ -2478,20 +2486,15 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
return false;
}
uint64_t nextRemoteBrowserId =
mOpenWindowInfo ? mOpenWindowInfo->GetNextRemoteBrowserId() : 0;
if (!EnsureBrowsingContextAttached()) {
return false;
}
RefPtr<ContentParent> openerContentParent;
RefPtr<nsIPrincipal> openerContentPrincipal;
RefPtr<BrowserParent> sameTabGroupAs;
if (auto* host = BrowserHost::GetFrom(parentDocShell->GetOpener())) {
openerContentParent = host->GetContentParent();
BrowserParent* openerBrowserParent = host->GetActor();
if (openerBrowserParent) {
openerContentPrincipal = openerBrowserParent->GetContentPrincipal();
}
}
// <iframe mozbrowser> gets to skip these checks.
// iframes for JS plugins also get to skip these checks. We control the URL
@ -2557,32 +2560,11 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
nsresult rv = GetNewTabContext(&context);
NS_ENSURE_SUCCESS(rv, false);
// We need to propagate the first party domain if the opener is presented.
if (openerContentPrincipal) {
context.SetFirstPartyDomainAttributes(
openerContentPrincipal->OriginAttributesRef().mFirstPartyDomain);
}
uint64_t nextRemoteTabId = 0;
if (mOwnerContent) {
nsAutoString nextBrowserParentIdAttr;
mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nextRemoteTabId,
nextBrowserParentIdAttr);
nextRemoteTabId = strtoull(
NS_ConvertUTF16toUTF8(nextBrowserParentIdAttr).get(), nullptr, 10);
// We may be in a window that was just opened, so try the
// nsIBrowserDOMWindow API as a backup.
if (!nextRemoteTabId && window) {
Unused << window->GetNextRemoteTabId(&nextRemoteTabId);
}
}
nsCOMPtr<Element> ownerElement = mOwnerContent;
mRemoteBrowser = ContentParent::CreateBrowser(
context, ownerElement, mRemoteType, mPendingBrowsingContext,
openerContentParent, nextRemoteTabId);
openerContentParent, nextRemoteBrowserId);
if (!mRemoteBrowser) {
return false;
}
@ -2592,7 +2574,7 @@ bool nsFrameLoader::TryRemoteBrowserInternal() {
// detach our original BC and take ownership of the one from the remote
// browser.
if (mPendingBrowsingContext != mRemoteBrowser->GetBrowsingContext()) {
MOZ_DIAGNOSTIC_ASSERT(nextRemoteTabId);
MOZ_DIAGNOSTIC_ASSERT(nextRemoteBrowserId);
mPendingBrowsingContext->Detach();
mPendingBrowsingContext = mRemoteBrowser->GetBrowsingContext();
}
@ -3337,14 +3319,6 @@ void nsFrameLoader::MaybeUpdatePrimaryBrowserParent(
nsresult nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
nsIURI* aURI) {
OriginAttributes attrs;
nsresult rv;
// set the userContextId on the attrs before we pass them into
// the tab context
rv = PopulateOriginContextIdsFromAttributes(attrs);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString presentationURLStr;
mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozpresentation,
presentationURLStr);
@ -3353,8 +3327,8 @@ nsresult nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(docShell);
NS_ENSURE_STATE(parentContext);
bool isPrivate = parentContext->UsePrivateBrowsing();
attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
MOZ_ASSERT(mPendingBrowsingContext->EverAttached());
OriginAttributes attrs = mPendingBrowsingContext->OriginAttributesRef();
UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
uint64_t chromeOuterWindowID = 0;

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

@ -45,6 +45,7 @@ class nsIMessageSender;
class nsIPrintSettings;
class nsIWebBrowserPersistDocumentReceiver;
class nsIWebProgressListener;
class nsIOpenWindowInfo;
namespace mozilla {
@ -101,9 +102,9 @@ class nsFrameLoader final : public nsStubMutationObserver,
public:
// Called by Frame Elements to create a new FrameLoader.
static already_AddRefed<nsFrameLoader> Create(Element* aOwner,
BrowsingContext* aOpener,
bool aNetworkCreated);
static already_AddRefed<nsFrameLoader> Create(
Element* aOwner, bool aNetworkCreated,
nsIOpenWindowInfo* aOpenWindowInfo = nullptr);
// Called by nsFrameLoaderOwner::ChangeRemoteness when switching out
// FrameLoaders.
@ -476,6 +477,7 @@ class nsFrameLoader final : public nsStubMutationObserver,
nsCOMPtr<nsIURI> mURIToLoad;
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
nsCOMPtr<nsIContentSecurityPolicy> mCsp;
nsCOMPtr<nsIOpenWindowInfo> mOpenWindowInfo;
mozilla::dom::Element* mOwnerContent; // WEAK
// After the frameloader has been removed from the DOM but before all of the

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

@ -521,8 +521,7 @@ void nsObjectLoadingContent::SetupFrameLoader(int32_t aJSPluginId) {
NS_ASSERTION(thisContent, "must be a content");
mFrameLoader =
nsFrameLoader::Create(thisContent->AsElement(),
/* aOpener = */ nullptr, mNetworkCreated);
nsFrameLoader::Create(thisContent->AsElement(), mNetworkCreated);
MOZ_ASSERT(mFrameLoader, "nsFrameLoader::Create failed");
}
@ -2546,7 +2545,7 @@ void nsObjectLoadingContent::CreateStaticClone(
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
RefPtr<nsFrameLoader> fl =
nsFrameLoader::Create(content->AsElement(), nullptr, false);
nsFrameLoader::Create(content->AsElement(), false);
if (fl) {
aDest->mFrameLoader = fl;
mFrameLoader->CreateStaticClone(fl);

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

@ -130,7 +130,7 @@ void nsGenericHTMLFrameElement::EnsureFrameLoader() {
// Strangely enough, this method doesn't actually ensure that the
// frameloader exists. It's more of a best-effort kind of thing.
mFrameLoader = nsFrameLoader::Create(this, mOpenerWindow, mNetworkCreated);
mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
}
void nsGenericHTMLFrameElement::DisallowCreateFrameLoader() {
@ -370,7 +370,7 @@ nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
if (doc->IsStaticDocument() && mFrameLoader) {
nsGenericHTMLFrameElement* dest =
static_cast<nsGenericHTMLFrameElement*>(aDest);
RefPtr<nsFrameLoader> fl = nsFrameLoader::Create(dest, nullptr, false);
RefPtr<nsFrameLoader> fl = nsFrameLoader::Create(dest, false);
NS_ENSURE_STATE(fl);
dest->mFrameLoader = fl;
mFrameLoader->CreateStaticClone(fl);

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

@ -9,6 +9,7 @@ interface nsITransportSecurityInfo;
interface nsIURI;
interface nsIWebProgress;
interface nsIReferrerInfo;
interface nsIOpenWindowInfo;
webidl FrameLoader;
@ -24,6 +25,12 @@ interface nsIBrowser : nsISupports
*/
readonly attribute FrameLoader sameProcessAsFrameLoader;
/**
* Gets the optional open window information provided by the window creation
* code and used to initialize a new browser.
*/
attribute nsIOpenWindowInfo openWindowInfo;
/*
* Called by the child to inform the parent that links are dropped into
* content area.

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

@ -5,7 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCOMPtr.h"
#include "nsIBrowser.h"
#include "nsIContent.h"
#include "nsIOpenWindowInfo.h"
#include "nsFrameLoader.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/HTMLIFrameElement.h"
@ -75,24 +77,20 @@ void XULFrameElement::LoadSrc() {
}
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
// Check if we have an opener we need to be setting
RefPtr<BrowsingContext> opener = mOpener;
if (!opener) {
// If we are a primary xul-browser, we want to take the opener property!
nsCOMPtr<nsPIDOMWindowOuter> window = OwnerDoc()->GetWindow();
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, nsGkAtoms::_true,
eIgnoreCase) &&
window) {
opener = window->TakeOpenerForInitialContentBrowser();
}
// We may have had a nsIOpenWindowInfo set on our nsIBrowser by browser
// chrome, due to being used as the target for a `window.open` call. Fetch
// that information if it's available, and clear it out so we don't read it
// again.
nsCOMPtr<nsIOpenWindowInfo> openWindowInfo;
if (nsCOMPtr<nsIBrowser> browser = AsBrowser()) {
browser->GetOpenWindowInfo(getter_AddRefs(openWindowInfo));
browser->SetOpenWindowInfo(nullptr);
}
mOpener = nullptr;
// false as the last parameter so that xul:iframe/browser/editor
// session history handling works like dynamic html:iframes.
// Usually xul elements are used in chrome, which doesn't have
// session history at all.
mFrameLoader = nsFrameLoader::Create(this, opener, false);
// false as the networkCreated parameter so that xul:iframe/browser/editor
// session history handling works like dynamic html:iframes. Usually xul
// elements are used in chrome, which doesn't have session history at all.
mFrameLoader = nsFrameLoader::Create(this, false, openWindowInfo);
if (NS_WARN_IF(!mFrameLoader)) {
return;
}