From 888908c3cb0c40c19312f2ba3bf2caed582e36e1 Mon Sep 17 00:00:00 2001 From: Andreas Farre Date: Mon, 8 Apr 2019 08:21:40 +0000 Subject: [PATCH] Bug 1523636 - Create BrowsingContext in nsFrameLoader. r=nika,qdot Differential Revision: https://phabricator.services.mozilla.com/D25039 --HG-- extra : moz-landing-system : lando --- docshell/base/BrowsingContext.cpp | 4 + docshell/base/BrowsingContext.h | 3 + dom/base/nsFrameLoader.cpp | 402 ++++++++++++----------- dom/base/nsFrameLoader.h | 21 +- dom/base/nsGlobalWindowOuter.cpp | 1 + dom/html/nsGenericHTMLFrameElement.cpp | 4 +- dom/ipc/ContentParent.cpp | 20 +- dom/ipc/ContentParent.h | 1 + dom/ipc/tests/test_force_oop_iframe.html | 3 + dom/xul/XULFrameElement.cpp | 3 +- 10 files changed, 241 insertions(+), 221 deletions(-) diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp index 810637d2c2e2..155d44160905 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -309,6 +309,10 @@ void BrowsingContext::CacheChildren(bool aFromIPC) { bool BrowsingContext::IsCached() { return sCachedBrowsingContexts->has(Id()); } +bool BrowsingContext::HasOpener() const { + return sBrowsingContexts->has(mOpenerId); +} + void BrowsingContext::GetChildren( nsTArray>& aChildren) { MOZ_ALWAYS_TRUE(aChildren.AppendElements(mChildren)); diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h index 99338438f977..91c0b556575c 100644 --- a/docshell/base/BrowsingContext.h +++ b/docshell/base/BrowsingContext.h @@ -121,6 +121,7 @@ class BrowsingContext : public nsWrapperCache, // null if it's not. nsIDocShell* GetDocShell() { return mDocShell; } void SetDocShell(nsIDocShell* aDocShell); + void ClearDocShell() { mDocShell = nullptr; } // Get the outer window object for this BrowsingContext if it is in-process // and still has a docshell, or null otherwise. @@ -161,6 +162,8 @@ class BrowsingContext : public nsWrapperCache, SetOpenerId(aOpener ? aOpener->Id() : 0); } + bool HasOpener() const; + void GetChildren(nsTArray>& aChildren); BrowsingContextGroup* Group() { return mGroup; } diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 71b45834cffc..30a1c5c1a3ad 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -152,8 +152,8 @@ typedef ScrollableLayerGuid::ViewID ViewID; // we'd need to re-institute a fixed version of bug 98158. #define MAX_DEPTH_CONTENT_FRAMES 10 -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFrameLoader, mDocShell, mMessageManager, - mChildMessageManager, mOpener, +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFrameLoader, mBrowsingContext, + mMessageManager, mChildMessageManager, mParentSHistory, mRemoteBrowser) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader) @@ -165,11 +165,11 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener, +nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext, bool aNetworkCreated) - : mOwnerContent(aOwner), + : mBrowsingContext(aBrowsingContext), + mOwnerContent(aOwner), mDetachedSubdocFrame(nullptr), - mOpener(aOpener), mRemoteBrowser(nullptr), mChildID(0), mDepthTooGreat(false), @@ -185,15 +185,15 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener, mIsRemoteFrame(false), mObservingOwnerContent(false) { mIsRemoteFrame = ShouldUseRemoteProcess(); - MOZ_ASSERT(!mIsRemoteFrame || !aOpener, + MOZ_ASSERT(!mIsRemoteFrame || !mBrowsingContext->HasOpener(), "Cannot pass aOpener for a remote frame!"); } -nsFrameLoader::nsFrameLoader(Element* aOwner, +nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext, const mozilla::dom::RemotenessOptions& aOptions) - : mOwnerContent(aOwner), + : mBrowsingContext(aBrowsingContext), + mOwnerContent(aOwner), mDetachedSubdocFrame(nullptr), - mOpener(nullptr), mRemoteBrowser(nullptr), mChildID(0), mDepthTooGreat(false), @@ -212,14 +212,6 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, (!aOptions.mRemoteType.Value().IsVoid())) { mIsRemoteFrame = true; } - bool hasOpener = - aOptions.mOpener.WasPassed() && !aOptions.mOpener.Value().IsNull(); - MOZ_ASSERT(!mIsRemoteFrame || !hasOpener, - "Cannot pass aOpener for a remote frame!"); - if (hasOpener) { - // This seems slightly unwieldy. - mOpener = aOptions.mOpener.Value().Value().get()->GetDOMWindow(); - } } nsFrameLoader::~nsFrameLoader() { @@ -229,9 +221,70 @@ nsFrameLoader::~nsFrameLoader() { MOZ_RELEASE_ASSERT(mDestroyCalled); } -/* static */ -nsFrameLoader* nsFrameLoader::Create(Element* aOwner, - nsPIDOMWindowOuter* aOpener, +static void GetFrameName(Element* aOwnerContent, nsAString& aFrameName) { + int32_t namespaceID = aOwnerContent->GetNameSpaceID(); + if (namespaceID == kNameSpaceID_XHTML && !aOwnerContent->IsInHTMLDocument()) { + aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName); + } else { + aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, aFrameName); + // XXX if no NAME then use ID, after a transition period this will be + // changed so that XUL only uses ID too (bug 254284). + if (aFrameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) { + aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName); + } + } +} + +static already_AddRefed CreateBrowsingContext( + Element* aOwner, BrowsingContext* aOpener) { + 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 + // better setup for doing this. + + // Determine our parent nsDocShell + RefPtr parentDocShell = nsDocShell::Cast(doc->GetDocShell()); + + if (NS_WARN_IF(!parentDocShell)) { + return nullptr; + } + + RefPtr parentContext = parentDocShell->GetBrowsingContext(); + + MOZ_DIAGNOSTIC_ASSERT(parentContext, "docShell must have BrowsingContext"); + + // Determine the frame name for the new browsing context. + nsAutoString frameName; + GetFrameName(aOwner, frameName); + + // Check if our new context is chrome or content + bool isContent = + parentContext->IsContent() || + aOwner->AttrValueIs( + kNameSpaceID_None, + aOwner->IsXULElement() ? nsGkAtoms::type : nsGkAtoms::mozframetype, + nsGkAtoms::content, eIgnoreCase); + + // Force mozbrowser frames to always be content, even if the mozbrowser + // interfaces are disabled. + nsCOMPtr mozbrowser = aOwner->GetAsMozBrowserFrame(); + if (!isContent && mozbrowser) { + mozbrowser->GetMozbrowser(&isContent); + } + + // If we're content but our parent isn't, we're going to want to + // start a new browsing context tree. + if (isContent && !parentContext->IsContent()) { + parentContext = nullptr; + } + + BrowsingContext::Type type = isContent ? BrowsingContext::Type::Content + : BrowsingContext::Type::Chrome; + + return BrowsingContext::Create(parentContext, aOpener, frameName, type); +} + +nsFrameLoader* nsFrameLoader::Create(Element* aOwner, BrowsingContext* aOpener, bool aNetworkCreated) { NS_ENSURE_TRUE(aOwner, nullptr); Document* doc = aOwner->OwnerDoc(); @@ -261,7 +314,8 @@ nsFrameLoader* nsFrameLoader::Create(Element* aOwner, doc->IsStaticDocument()), nullptr); - return new nsFrameLoader(aOwner, aOpener, aNetworkCreated); + RefPtr context = CreateBrowsingContext(aOwner, aOpener); + return new nsFrameLoader(aOwner, context, aNetworkCreated); } /* static */ @@ -271,7 +325,21 @@ nsFrameLoader* nsFrameLoader::Create( NS_ENSURE_TRUE(aOwner, nullptr); // This version of Create is only called for Remoteness updates, so we can // assume we need a FrameLoader here and skip the check in the other Create. - return new nsFrameLoader(aOwner, aOptions); + + bool hasOpener = + aOptions.mOpener.WasPassed() && !aOptions.mOpener.Value().IsNull(); + MOZ_ASSERT(!aOptions.mRemoteType.WasPassed() || + aOptions.mRemoteType.Value().IsVoid() || !hasOpener, + "Cannot pass aOpener for a remote frame!"); + + // This seems slightly unwieldy. + RefPtr opener; + if (hasOpener) { + opener = aOptions.mOpener.Value().Value().get(); + } + RefPtr context = CreateBrowsingContext(aOwner, opener); + + return new nsFrameLoader(aOwner, context, aOptions); } void nsFrameLoader::LoadFrame(bool aOriginalSrc) { @@ -429,8 +497,8 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() { if (NS_FAILED(rv)) { return rv; } - NS_ASSERTION(mDocShell, - "MaybeCreateDocShell succeeded with a null mDocShell"); + MOZ_ASSERT(GetDocShell(), + "MaybeCreateDocShell succeeded with a null docShell"); // Just to be safe, recheck uri. rv = CheckURILoad(mURIToLoad, mTriggeringPrincipal); @@ -532,7 +600,7 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() { mNeedsAsyncDestroy = true; loadState->SetLoadFlags(flags); loadState->SetFirstParty(false); - rv = mDocShell->LoadURI(loadState); + rv = GetDocShell()->LoadURI(loadState); mNeedsAsyncDestroy = tmpState; mURIToLoad = nullptr; NS_ENSURE_SUCCESS(rv, rv); @@ -591,11 +659,11 @@ nsDocShell* nsFrameLoader::GetDocShell(ErrorResult& aRv) { aRv.Throw(rv); return nullptr; } - NS_ASSERTION(mDocShell, - "MaybeCreateDocShell succeeded, but null mDocShell"); + MOZ_ASSERT(GetDocShell(), + "MaybeCreateDocShell succeeded, but null docShell"); } - return mDocShell; + return GetDocShell(); } static void SetTreeOwnerAndChromeEventHandlerOnDocshellTree( @@ -741,20 +809,20 @@ bool nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, if (NS_FAILED(rv)) { return false; } - NS_ASSERTION(mDocShell, "MaybeCreateDocShell succeeded, but null mDocShell"); - if (!mDocShell) { + MOZ_ASSERT(GetDocShell(), "MaybeCreateDocShell succeeded, but null docShell"); + if (!GetDocShell()) { return false; } - mDocShell->SetMarginWidth(marginWidth); - mDocShell->SetMarginHeight(marginHeight); + GetDocShell()->SetMarginWidth(marginWidth); + GetDocShell()->SetMarginHeight(marginHeight); - mDocShell->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, - scrollbarPrefX); - mDocShell->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, - scrollbarPrefY); + GetDocShell()->SetDefaultScrollbarPreferences( + nsIScrollable::ScrollOrientation_X, scrollbarPrefX); + GetDocShell()->SetDefaultScrollbarPreferences( + nsIScrollable::ScrollOrientation_Y, scrollbarPrefY); - nsCOMPtr presShell = mDocShell->GetPresShell(); + nsCOMPtr presShell = GetDocShell()->GetPresShell(); if (presShell) { // Ensure root scroll frame is reflowed in case scroll preferences or // margins have changed @@ -769,7 +837,7 @@ bool nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, nsView* view = frame->EnsureInnerView(); if (!view) return false; - RefPtr baseWindow = mDocShell; + RefPtr baseWindow = GetDocShell(); baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0, size.width, size.height); // This is kinda whacky, this "Create()" call doesn't really @@ -777,13 +845,13 @@ bool nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, // "Create"... baseWindow->Create(); baseWindow->SetVisibility(true); - NS_ENSURE_TRUE(mDocShell, false); + NS_ENSURE_TRUE(GetDocShell(), false); // Trigger editor re-initialization if midas is turned on in the // sub-document. This shouldn't be necessary, but given the way our // editor works, it is. See // https://bugzilla.mozilla.org/show_bug.cgi?id=284245 - presShell = mDocShell->GetPresShell(); + presShell = GetDocShell()->GetPresShell(); if (presShell) { Document* doc = presShell->GetDocument(); nsHTMLDocument* htmlDoc = @@ -796,7 +864,7 @@ bool nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, if (designMode.EqualsLiteral("on")) { // Hold on to the editor object to let the document reattach to the // same editor object, instead of creating a new one. - RefPtr htmlEditor = mDocShell->GetHTMLEditor(); + RefPtr htmlEditor = GetDocShell()->GetHTMLEditor(); Unused << htmlEditor; htmlDoc->SetDesignMode(NS_LITERAL_STRING("off"), Nothing(), IgnoreErrors()); @@ -806,9 +874,9 @@ bool nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, } else { // Re-initialize the presentation for contenteditable documents bool editable = false, hasEditingSession = false; - mDocShell->GetEditable(&editable); - mDocShell->GetHasEditingSession(&hasEditingSession); - RefPtr htmlEditor = mDocShell->GetHTMLEditor(); + GetDocShell()->GetEditable(&editable); + GetDocShell()->GetHasEditingSession(&hasEditingSession); + RefPtr htmlEditor = GetDocShell()->GetHTMLEditor(); if (editable && hasEditingSession && htmlEditor) { htmlEditor->PostCreate(); } @@ -828,20 +896,24 @@ bool nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, void nsFrameLoader::MarginsChanged(uint32_t aMarginWidth, uint32_t aMarginHeight) { // We assume that the margins are always zero for remote frames. - if (IsRemoteFrame()) return; + if (IsRemoteFrame()) { + return; + } // If there's no docshell, we're probably not up and running yet. // nsFrameLoader::Show() will take care of setting the right // margins. - if (!mDocShell) return; + if (!GetDocShell()) { + return; + } // Set the margins - mDocShell->SetMarginWidth(aMarginWidth); - mDocShell->SetMarginHeight(aMarginHeight); + GetDocShell()->SetMarginWidth(aMarginWidth); + GetDocShell()->SetMarginHeight(aMarginHeight); // There's a cached property declaration block // that needs to be updated - if (Document* doc = mDocShell->GetDocument()) { + if (Document* doc = GetDocShell()->GetDocument()) { for (nsINode* cur = doc; cur; cur = cur->GetNextNode()) { if (cur->IsHTMLElement(nsGkAtoms::body)) { static_cast(cur)->ClearMappedServoStyle(); @@ -851,7 +923,7 @@ void nsFrameLoader::MarginsChanged(uint32_t aMarginWidth, // Trigger a restyle if there's a prescontext // FIXME: This could do something much less expensive. - if (nsPresContext* presContext = mDocShell->GetPresContext()) { + if (nsPresContext* presContext = GetDocShell()->GetPresContext()) { // rebuild, because now the same nsMappedAttributes* will produce // a different style presContext->RebuildAllStyleData(nsChangeHint(0), @@ -940,13 +1012,15 @@ void nsFrameLoader::Hide() { return; } - if (!mDocShell) return; + if (!GetDocShell()) { + return; + } nsCOMPtr contentViewer; - mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); + GetDocShell()->GetContentViewer(getter_AddRefs(contentViewer)); if (contentViewer) contentViewer->SetSticky(false); - RefPtr baseWin = mDocShell; + RefPtr baseWin = GetDocShell(); baseWin->SetVisibility(false); baseWin->SetParentWidget(nullptr); } @@ -1657,26 +1731,26 @@ void nsFrameLoader::StartDestroy() { // Seems like this is a dynamic frame removal. if (dynamicSubframeRemoval) { - if (mDocShell) { - mDocShell->RemoveFromSessionHistory(); + if (GetDocShell()) { + GetDocShell()->RemoveFromSessionHistory(); } } // Let the tree owner know we're gone. if (mIsTopLevelContent) { - if (mDocShell) { + if (GetDocShell()) { nsCOMPtr parentItem; - mDocShell->GetParent(getter_AddRefs(parentItem)); + GetDocShell()->GetParent(getter_AddRefs(parentItem)); nsCOMPtr owner = do_GetInterface(parentItem); if (owner) { - owner->ContentShellRemoved(mDocShell); + owner->ContentShellRemoved(GetDocShell()); } } } // Let our window know that we are gone - if (mDocShell) { - nsCOMPtr win_private(mDocShell->GetWindow()); + if (GetDocShell()) { + nsCOMPtr win_private(GetDocShell()->GetWindow()); if (win_private) { win_private->SetFrameElementInternal(nullptr); } @@ -1756,10 +1830,11 @@ void nsFrameLoader::DestroyDocShell() { } // Destroy the docshell. - if (mDocShell) { - mDocShell->Destroy(); + if (GetDocShell()) { + GetDocShell()->Destroy(); } - mDocShell = nullptr; + + mBrowsingContext = nullptr; if (mChildMessageManager) { // Stop handling events in the in-process frame script. @@ -1891,37 +1966,8 @@ bool nsFrameLoader::ShouldUseRemoteProcess() { nsGkAtoms::_true, eCaseMatters); } -static already_AddRefed CreateBrowsingContext( - BrowsingContext* aParentContext, BrowsingContext* aOpenerContext, - const nsAString& aName, bool aIsContent) { - // If we're content but our parent isn't, we're going to want to start a new - // browsing context tree. - if (aIsContent && aParentContext && !aParentContext->IsContent()) { - aParentContext = nullptr; - } - - BrowsingContext::Type type = aIsContent ? BrowsingContext::Type::Content - : BrowsingContext::Type::Chrome; - - return BrowsingContext::Create(aParentContext, aOpenerContext, aName, type); -} - -static void GetFrameName(Element* aOwnerContent, nsAString& aFrameName) { - int32_t namespaceID = aOwnerContent->GetNameSpaceID(); - if (namespaceID == kNameSpaceID_XHTML && !aOwnerContent->IsInHTMLDocument()) { - aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName); - } else { - aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, aFrameName); - // XXX if no NAME then use ID, after a transition period this will be - // changed so that XUL only uses ID too (bug 254284). - if (aFrameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) { - aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName); - } - } -} - nsresult nsFrameLoader::MaybeCreateDocShell() { - if (mDocShell) { + if (GetDocShell()) { return NS_OK; } if (IsRemoteFrame()) { @@ -1950,43 +1996,20 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { return NS_ERROR_NOT_AVAILABLE; } - // Determine our parent nsDocShell RefPtr parentDocShell = nsDocShell::Cast(doc->GetDocShell()); if (NS_WARN_IF(!parentDocShell)) { return NS_ERROR_UNEXPECTED; } - RefPtr parentBC = parentDocShell->GetBrowsingContext(); - MOZ_ASSERT(parentBC, "docShell must have BrowsingContext"); + // nsDocShell::Create will attach itself to the passed browsing + // context inside of nsDocShell::Create + RefPtr docShell = nsDocShell::Create(mBrowsingContext); + NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); - // Determine the frame name for the new browsing context. - nsAutoString frameName; - GetFrameName(mOwnerContent, frameName); - - // Check if our new context is chrome or content - bool isContent = parentBC->IsContent() || - mOwnerContent->AttrValueIs(kNameSpaceID_None, TypeAttrName(), - nsGkAtoms::content, eIgnoreCase); - - // Force mozbrowser frames to always be content, even if the mozbrowser - // interfaces are disabled. - nsCOMPtr mozbrowser = - mOwnerContent->GetAsMozBrowserFrame(); - if (!isContent && mozbrowser) { - mozbrowser->GetMozbrowser(&isContent); - } - - RefPtr openerBC = - mOpener ? mOpener->GetBrowsingContext() : nullptr; - RefPtr browsingContext = - CreateBrowsingContext(parentBC, openerBC, frameName, isContent); - - mDocShell = nsDocShell::Create(browsingContext); - NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); - - mIsTopLevelContent = isContent && !parentBC->IsContent(); + mIsTopLevelContent = + mBrowsingContext->IsContent() && !mBrowsingContext->GetParent(); if (!mNetworkCreated && !mIsTopLevelContent) { - mDocShell->SetCreatedDynamically(true); + docShell->SetCreatedDynamically(true); } if (mIsTopLevelContent) { @@ -1995,19 +2018,20 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { // // XXX(nika): Consider removing the DocShellTree in the future, for // consistency between local and remote frames.. - parentDocShell->AddChild(mDocShell); + parentDocShell->AddChild(docShell); } // Now that we are part of the DocShellTree, attach our DocShell to our // parent's TreeOwner. nsCOMPtr parentTreeOwner; parentDocShell->GetTreeOwner(getter_AddRefs(parentTreeOwner)); - AddTreeItemToTreeOwner(mDocShell, parentTreeOwner); + AddTreeItemToTreeOwner(docShell, parentTreeOwner); // Make sure all nsDocShells have links back to the content element in the // nearest enclosing chrome shell. RefPtr chromeEventHandler; - if (parentBC->IsContent()) { + bool parentIsContent = parentDocShell->GetBrowsingContext()->IsContent(); + if (parentIsContent) { // Our parent shell is a content shell. Get the chrome event handler from it // and use that for our shell as well. parentDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler)); @@ -2017,15 +2041,15 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { chromeEventHandler = mOwnerContent; } - mDocShell->SetChromeEventHandler(chromeEventHandler); + docShell->SetChromeEventHandler(chromeEventHandler); - // This is nasty, this code (the mDocShell->GetWindow() below) + // This is nasty, this code (the docShell->GetWindow() below) // *must* come *after* the above call to - // mDocShell->SetChromeEventHandler() for the global window to get + // docShell->SetChromeEventHandler() for the global window to get // the right chrome event handler. // Tell the window about the frame that hosts it. - nsCOMPtr newWindow = mDocShell->GetWindow(); + nsCOMPtr newWindow = docShell->GetWindow(); if (NS_WARN_IF(!newWindow)) { // Do not call Destroy() here. See bug 472312. NS_WARNING("Something wrong when creating the docshell for a frameloader!"); @@ -2034,13 +2058,10 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { newWindow->SetFrameElementInternal(mOwnerContent); - // Set the opener window if we have one provided here XXX(nika): We - // should tell our BrowsingContext this as we create it. // TODO(farre): Remove this when nsGlobalWindowOuter::GetOpenerWindowOuter // starts using BrowsingContext::GetOpener. - if (mOpener) { - newWindow->SetOpenerWindow(mOpener, true); - mOpener = nullptr; + if (RefPtr opener = mBrowsingContext->GetOpener()) { + newWindow->SetOpenerWindow(opener->GetDOMWindow(), true); } // Allow scripts to close the docshell if specified. @@ -2054,7 +2075,6 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { // This is kinda whacky, this call doesn't really create anything, // but it must be called to make sure things are properly // initialized. - RefPtr docShell = mDocShell; if (NS_FAILED(docShell->Create())) { // Do not call Destroy() here. See bug 472312. NS_WARNING("Something wrong when creating the docshell for a frameloader!"); @@ -2067,13 +2087,13 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { if (mIsTopLevelContent && mOwnerContent->IsXULElement(nsGkAtoms::browser) && !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory)) { // XXX(nika): Set this up more explicitly? - nsresult rv = mDocShell->InitSessionHistory(); + nsresult rv = docShell->InitSessionHistory(); NS_ENSURE_SUCCESS(rv, rv); mParentSHistory = new ParentSHistory(this); } OriginAttributes attrs; - if (parentDocShell->ItemType() == mDocShell->ItemType()) { + if (parentDocShell->ItemType() == docShell->ItemType()) { attrs = parentDocShell->GetOriginAttributes(); } @@ -2084,7 +2104,7 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { // // For example, firstPartyDomain is computed from top-level document, it // doesn't exist in the top-level docshell. - if (parentBC->IsContent() && + if (parentIsContent && !nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) && !OwnerIsMozBrowserFrame()) { OriginAttributes oa = doc->NodePrincipal()->OriginAttributesRef(); @@ -2112,18 +2132,18 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { if (OwnerIsMozBrowserFrame()) { attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID; attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame(); - mDocShell->SetFrameType(nsIDocShell::FRAME_TYPE_BROWSER); + docShell->SetFrameType(nsIDocShell::FRAME_TYPE_BROWSER); } else { nsCOMPtr parentCheck; - mDocShell->GetSameTypeParent(getter_AddRefs(parentCheck)); + docShell->GetSameTypeParent(getter_AddRefs(parentCheck)); if (!!parentCheck) { - mDocShell->SetIsFrame(); + docShell->SetIsFrame(); } } // Apply sandbox flags even if our owner is not an iframe, as this copies // flags from our owning content's owning document. - // Note: ApplySandboxFlags should be called after mDocShell->SetFrameType + // Note: ApplySandboxFlags should be called after docShell->SetFrameType // because we need to get the correct presentation URL in ApplySandboxFlags. uint32_t sandboxFlags = 0; HTMLIFrameElement* iframe = HTMLIFrameElement::FromNode(mOwnerContent); @@ -2149,16 +2169,16 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { // For inproc frames, set the docshell properties. nsAutoString name; if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) { - mDocShell->SetName(name); + docShell->SetName(name); } - mDocShell->SetFullscreenAllowed( + docShell->SetFullscreenAllowed( mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) || mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)); bool isPrivate = mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing); if (isPrivate) { - if (mDocShell->GetHasLoadedNonBlankURI()) { + if (docShell->GetHasLoadedNonBlankURI()) { nsContentUtils::ReportToConsoleNonLocalized( NS_LITERAL_STRING("We should not switch to Private Browsing after " "loading a document."), @@ -2172,30 +2192,28 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { } } - nsDocShell::Cast(mDocShell)->SetOriginAttributes(attrs); + docShell->SetOriginAttributes(attrs); // Typically there will be a window, however for some cases such as printing // the document is cloned with a docshell that has no window. We check // that the window exists to ensure we don't try to gather ancestors for // those cases. nsCOMPtr win = doc->GetWindow(); - if (!mDocShell->GetIsMozBrowser() && - parentDocShell->ItemType() == mDocShell->ItemType() && + if (!docShell->GetIsMozBrowser() && + parentDocShell->ItemType() == docShell->ItemType() && !doc->IsStaticDocument() && win) { // Propagate through the ancestor principals. nsTArray> ancestorPrincipals; // Make a copy, so we can modify it. ancestorPrincipals = doc->AncestorPrincipals(); ancestorPrincipals.InsertElementAt(0, doc->NodePrincipal()); - nsDocShell::Cast(mDocShell)->SetAncestorPrincipals( - std::move(ancestorPrincipals)); + docShell->SetAncestorPrincipals(std::move(ancestorPrincipals)); // Repeat for outer window IDs. nsTArray ancestorOuterWindowIDs; ancestorOuterWindowIDs = doc->AncestorOuterWindowIDs(); ancestorOuterWindowIDs.InsertElementAt(0, win->WindowID()); - nsDocShell::Cast(mDocShell)->SetAncestorOuterWindowIDs( - std::move(ancestorOuterWindowIDs)); + docShell->SetAncestorOuterWindowIDs(std::move(ancestorOuterWindowIDs)); } ReallyLoadFrameScripts(); @@ -2252,19 +2270,19 @@ nsresult nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI) { if (NS_FAILED(rv)) { return rv; } - NS_ASSERTION(mDocShell, "MaybeCreateDocShell succeeded, but null mDocShell"); - if (!mDocShell) { + MOZ_ASSERT(GetDocShell(), "MaybeCreateDocShell succeeded, but null docShell"); + if (!GetDocShell()) { return NS_ERROR_FAILURE; } // Check that we're still in the docshell tree. nsCOMPtr treeOwner; - mDocShell->GetTreeOwner(getter_AddRefs(treeOwner)); + GetDocShell()->GetTreeOwner(getter_AddRefs(treeOwner)); NS_WARNING_ASSERTION(treeOwner, "Trying to load a new url to a docshell without owner!"); NS_ENSURE_STATE(treeOwner); - if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) { + if (GetDocShell()->ItemType() != nsIDocShellTreeItem::typeContent) { // No need to do recursion-protection here XXXbz why not?? Do we really // trust people not to screw up with non-content docshells? return NS_OK; @@ -2273,7 +2291,7 @@ nsresult nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI) { // Bug 8065: Don't exceed some maximum depth in content frames // (MAX_DEPTH_CONTENT_FRAMES) nsCOMPtr parentAsItem; - mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem)); + GetDocShell()->GetSameTypeParent(getter_AddRefs(parentAsItem)); int32_t depth = 0; while (parentAsItem) { ++depth; @@ -2305,7 +2323,7 @@ nsresult nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI) { } } int32_t matchCount = 0; - mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem)); + GetDocShell()->GetSameTypeParent(getter_AddRefs(parentAsItem)); while (parentAsItem) { // Check the parent URI with the URI we're loading nsCOMPtr parentAsNav(do_QueryInterface(parentAsItem)); @@ -2583,27 +2601,15 @@ bool nsFrameLoader::TryRemoteBrowser() { // If we're in a content process, create a BrowserBridgeChild actor. if (XRE_IsContentProcess()) { - // Determine the frame name for the new browsing context. - nsAutoString frameName; - GetFrameName(mOwnerContent, frameName); - - RefPtr parentBC; - parentDocShell->GetBrowsingContext(getter_AddRefs(parentBC)); - MOZ_ASSERT(parentBC, "docShell must have BrowsingContext"); - - // XXX(nika): due to limitations with Browsing Context Groups and multiple - // processes, we can't link up aParent yet! (Bug 1532661) - RefPtr browsingContext = - CreateBrowsingContext(parentBC, nullptr, frameName, true); - mBrowserBridgeChild = BrowserBridgeChild::Create( - this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), browsingContext); + this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), + mBrowsingContext); return !!mBrowserBridgeChild; } - mRemoteBrowser = - ContentParent::CreateBrowser(context, ownerElement, openerContentParent, - sameTabGroupAs, nextTabParentId); + mRemoteBrowser = ContentParent::CreateBrowser( + context, ownerElement, mBrowsingContext, openerContentParent, + sameTabGroupAs, nextTabParentId); if (!mRemoteBrowser) { return false; } @@ -2662,7 +2668,7 @@ bool nsFrameLoader::TryRemoteBrowser() { bool nsFrameLoader::IsRemoteFrame() { if (mIsRemoteFrame) { - MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell"); + MOZ_ASSERT(!GetDocShell(), "Found a remote frame with a DocShell"); return true; } return false; @@ -2735,13 +2741,13 @@ void nsFrameLoader::ActivateFrameEvent(const nsAString& aType, bool aCapture, nsresult nsFrameLoader::CreateStaticClone(nsFrameLoader* aDest) { aDest->MaybeCreateDocShell(); - NS_ENSURE_STATE(aDest->mDocShell); + NS_ENSURE_STATE(aDest->GetDocShell()); - nsCOMPtr kungFuDeathGrip = aDest->mDocShell->GetDocument(); + nsCOMPtr kungFuDeathGrip = aDest->GetDocShell()->GetDocument(); Unused << kungFuDeathGrip; nsCOMPtr viewer; - aDest->mDocShell->GetContentViewer(getter_AddRefs(viewer)); + aDest->GetDocShell()->GetContentViewer(getter_AddRefs(viewer)); NS_ENSURE_STATE(viewer); nsIDocShell* origDocShell = GetDocShell(IgnoreErrors()); @@ -2750,7 +2756,7 @@ nsresult nsFrameLoader::CreateStaticClone(nsFrameLoader* aDest) { nsCOMPtr doc = origDocShell->GetDocument(); NS_ENSURE_STATE(doc); - nsCOMPtr clonedDoc = doc->CreateStaticClone(aDest->mDocShell); + nsCOMPtr clonedDoc = doc->CreateStaticClone(aDest->GetDocShell()); viewer->SetDocument(clonedDoc); return NS_OK; @@ -2888,13 +2894,13 @@ nsresult nsFrameLoader::EnsureMessageManager() { if (NS_FAILED(rv)) { return rv; } - NS_ASSERTION(mDocShell, - "MaybeCreateDocShell succeeded, but null mDocShell"); - if (!mDocShell) { + MOZ_ASSERT(GetDocShell(), + "MaybeCreateDocShell succeeded, but null docShell"); + if (!GetDocShell()) { return NS_ERROR_FAILURE; } mChildMessageManager = InProcessTabChildMessageManager::Create( - mDocShell, mOwnerContent, mMessageManager); + GetDocShell(), mOwnerContent, mMessageManager); NS_ENSURE_TRUE(mChildMessageManager, NS_ERROR_UNEXPECTED); } return NS_OK; @@ -2940,7 +2946,7 @@ nsIFrame* nsFrameLoader::GetDetachedSubdocFrame( } void nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags) { - if (mDocShell) { + if (GetDocShell()) { uint32_t parentSandboxFlags = mOwnerContent->OwnerDoc()->GetSandboxFlags(); // The child can only add restrictions, never remove them. @@ -2950,11 +2956,11 @@ void nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags) { // sandboxed auxiliary navigation flag to sandboxFlags. See // https://w3c.github.io/presentation-api/#creating-a-receiving-browsing-context nsAutoString presentationURL; - nsContentUtils::GetPresentationURL(mDocShell, presentationURL); + nsContentUtils::GetPresentationURL(GetDocShell(), presentationURL); if (!presentationURL.IsEmpty()) { sandboxFlags |= SANDBOXED_AUXILIARY_NAVIGATION; } - mDocShell->SetSandboxFlags(sandboxFlags); + GetDocShell()->SetSandboxFlags(sandboxFlags); } } @@ -2980,13 +2986,13 @@ void nsFrameLoader::AttributeChanged(mozilla::dom::Element* aElement, // Notify our enclosing chrome that our type has changed. We only do this // if our parent is chrome, since in all other cases we're random content // subframes and the treeowner shouldn't worry about us. - if (!mDocShell) { + if (!GetDocShell()) { MaybeUpdatePrimaryTabParent(eTabParentChanged); return; } nsCOMPtr parentItem; - mDocShell->GetParent(getter_AddRefs(parentItem)); + GetDocShell()->GetParent(getter_AddRefs(parentItem)); if (!parentItem) { return; } @@ -3008,14 +3014,16 @@ void nsFrameLoader::AttributeChanged(mozilla::dom::Element* aElement, // when a content panel is no longer primary, hide any open popups it may have if (!is_primary) { nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); - if (pm) pm->HidePopupsInDocShell(mDocShell); + if (pm) { + pm->HidePopupsInDocShell(GetDocShell()); + } } #endif - parentTreeOwner->ContentShellRemoved(mDocShell); + parentTreeOwner->ContentShellRemoved(GetDocShell()); if (aElement->AttrValueIs(kNameSpaceID_None, TypeAttrName(), nsGkAtoms::content, eIgnoreCase)) { - parentTreeOwner->ContentShellAdded(mDocShell, is_primary); + parentTreeOwner->ContentShellAdded(GetDocShell(), is_primary); } } @@ -3120,7 +3128,8 @@ already_AddRefed nsFrameLoader::DrawSnapshot( gfx::CrossProcessPaint::StartRemote(mRemoteBrowser->GetTabId(), rect, aScale, color, promise); } else { - gfx::CrossProcessPaint::StartLocal(mDocShell, rect, aScale, color, promise); + gfx::CrossProcessPaint::StartLocal(GetDocShell(), rect, aScale, color, + promise); } return promise.forget(); @@ -3155,7 +3164,7 @@ already_AddRefed nsFrameLoader::GetBrowsingContext() { browsingContext = mBrowserBridgeChild->GetBrowsingContext(); } } else if (GetDocShell(IgnoreErrors())) { - browsingContext = nsDocShell::Cast(mDocShell)->GetBrowsingContext(); + browsingContext = GetDocShell()->GetBrowsingContext(); } return browsingContext.forget(); } @@ -3202,7 +3211,8 @@ void nsFrameLoader::StartPersistence( return; } - nsCOMPtr rootDoc = mDocShell ? mDocShell->GetDocument() : nullptr; + nsCOMPtr rootDoc = + GetDocShell() ? GetDocShell()->GetDocument() : nullptr; nsCOMPtr foundDoc; if (aOuterWindowID) { foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc, diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h index 1f0afc6c8967..a0ee6490d22e 100644 --- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -20,6 +20,7 @@ #include "nsIURI.h" #include "nsFrameMessageManager.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ParentSHistory.h" #include "mozilla/Attributes.h" @@ -49,7 +50,6 @@ namespace mozilla { class OriginAttributes; namespace dom { -class BrowsingContext; class ChromeMessageSender; class ContentParent; class InProcessTabChildMessageManager; @@ -99,7 +99,7 @@ class nsFrameLoader final : public nsStubMutationObserver, public: // Called by Frame Elements to create a new FrameLoader. static nsFrameLoader* Create(mozilla::dom::Element* aOwner, - nsPIDOMWindowOuter* aOpener, + mozilla::dom::BrowsingContext* aOpener, bool aNetworkCreated); // Called by nsFrameLoaderOwner::ChangeRemoteness when switching out @@ -118,7 +118,9 @@ class nsFrameLoader final : public nsStubMutationObserver, void StartDestroy(); void DestroyDocShell(); void DestroyComplete(); - nsIDocShell* GetExistingDocShell() { return mDocShell; } + nsIDocShell* GetExistingDocShell() const { + return mBrowsingContext ? mBrowsingContext->GetDocShell() : nullptr; + } mozilla::dom::InProcessTabChildMessageManager* GetTabChildMessageManager() const { return mChildMessageManager; @@ -368,9 +370,11 @@ class nsFrameLoader final : public nsStubMutationObserver, JS::Handle aGivenProto) override; private: - nsFrameLoader(mozilla::dom::Element* aOwner, nsPIDOMWindowOuter* aOpener, + nsFrameLoader(mozilla::dom::Element* aOwner, + mozilla::dom::BrowsingContext* aBrowsingContext, bool aNetworkCreated); nsFrameLoader(mozilla::dom::Element* aOwner, + mozilla::dom::BrowsingContext* aBrowsingContext, const mozilla::dom::RemotenessOptions& aOptions); ~nsFrameLoader(); @@ -400,6 +404,10 @@ class nsFrameLoader final : public nsStubMutationObserver, nsresult MaybeCreateDocShell(); nsresult EnsureMessageManager(); nsresult ReallyLoadFrameScripts(); + nsDocShell* GetDocShell() const { + return mBrowsingContext ? nsDocShell::Cast(mBrowsingContext->GetDocShell()) + : nullptr; + } // Updates the subdocument position and size. This gets called only // when we have our own in-process DocShell. @@ -443,7 +451,7 @@ class nsFrameLoader final : public nsStubMutationObserver, nsresult PopulateUserContextIdFromAttribute(mozilla::OriginAttributes& aAttr); - RefPtr mDocShell; + RefPtr mBrowsingContext; nsCOMPtr mURIToLoad; nsCOMPtr mTriggeringPrincipal; nsCOMPtr mCsp; @@ -464,9 +472,6 @@ class nsFrameLoader final : public nsStubMutationObserver, // a reframe, so that we know not to restore the presentation. RefPtr mContainerDocWhileDetached; - // An opener window which should be used when the docshell is created. - nsCOMPtr mOpener; - RefPtr mRemoteBrowser; uint64_t mChildID; diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index bea2dc690a84..d4aded346b18 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -2468,6 +2468,7 @@ void nsGlobalWindowOuter::DetachFromDocShell() { } mDocShell = nullptr; + mBrowsingContext->ClearDocShell(); if (mFrames) { mFrames->SetDocShell(nullptr); diff --git a/dom/html/nsGenericHTMLFrameElement.cpp b/dom/html/nsGenericHTMLFrameElement.cpp index 5e38df4b05f0..6a58074688b8 100644 --- a/dom/html/nsGenericHTMLFrameElement.cpp +++ b/dom/html/nsGenericHTMLFrameElement.cpp @@ -133,9 +133,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 ? mOpenerWindow->GetDOMWindow() : nullptr, - mNetworkCreated); + mFrameLoader = nsFrameLoader::Create(this, mOpenerWindow, mNetworkCreated); } nsresult nsGenericHTMLFrameElement::CreateRemoteFrameLoader( diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 6f82f8e8a38d..9a218acb3394 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1087,6 +1087,7 @@ mozilla::ipc::IPCResult ContentParent::RecvLaunchRDDProcess( /*static*/ TabParent* ContentParent::CreateBrowser(const TabContext& aContext, Element* aFrameElement, + BrowsingContext* aBrowsingContext, ContentParent* aOpenerContentParent, TabParent* aSameTabGroupAs, uint64_t aNextTabParentId) { @@ -1147,16 +1148,9 @@ TabParent* ContentParent::CreateBrowser(const TabContext& aContext, } } - // FIXME: This BrowsingContext should be provided by the nsFrameLoader. - // (bug 1523636) - RefPtr browsingContext = - BrowsingContext::Create(nullptr, nullptr, EmptyString(), - BrowsingContext::Type::Content) - .downcast(); - // Ensure that our content process is subscribed to our newly created // BrowsingContextGroup. - browsingContext->Group()->EnsureSubscribed(constructorSender); + aBrowsingContext->Group()->EnsureSubscribed(constructorSender); ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); cpm->RegisterRemoteFrame(tabId, ContentParentId(0), openerTabId, @@ -1188,17 +1182,19 @@ TabParent* ContentParent::CreateBrowser(const TabContext& aContext, if (tabId == 0) { return nullptr; } - RefPtr tp = new TabParent(constructorSender, tabId, aContext, - browsingContext, chromeFlags); + RefPtr tp = + new TabParent(constructorSender, tabId, aContext, + aBrowsingContext->Canonical(), chromeFlags); - browsingContext->SetOwnerProcessId(constructorSender->ChildID()); + aBrowsingContext->Canonical()->SetOwnerProcessId( + constructorSender->ChildID()); PBrowserParent* browser = constructorSender->SendPBrowserConstructor( // DeallocPBrowserParent() releases this ref. tp.forget().take(), tabId, aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0), aContext.AsIPCTabContext(), chromeFlags, constructorSender->ChildID(), - browsingContext, constructorSender->IsForBrowser()); + aBrowsingContext, constructorSender->IsForBrowser()); if (remoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) { // Tell the TabChild object that it was created due to a Large-Allocation diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 9513444e500e..9fee6c425f0c 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -208,6 +208,7 @@ class ContentParent final : public PContentParent, */ static TabParent* CreateBrowser(const TabContext& aContext, Element* aFrameElement, + BrowsingContext* aBrowsingContext, ContentParent* aOpenerContentParent, TabParent* aSameTabGroupAs, uint64_t aNextTabParentId); diff --git a/dom/ipc/tests/test_force_oop_iframe.html b/dom/ipc/tests/test_force_oop_iframe.html index b3343b59b62e..31d00242a2cd 100644 --- a/dom/ipc/tests/test_force_oop_iframe.html +++ b/dom/ipc/tests/test_force_oop_iframe.html @@ -47,6 +47,9 @@ add_task(async function() { let frameLoader = SpecialPowers.wrap(iframe).frameLoader; is(frameLoader.docShell, null); is(frameLoader.tabParent, null); + let browsingContext = frameLoader.browsingContext; + isnot(browsingContext, null); + is(browsingContext.docShell, null); await contentCreated; diff --git a/dom/xul/XULFrameElement.cpp b/dom/xul/XULFrameElement.cpp index 0a01f2df70da..63616133e6dd 100644 --- a/dom/xul/XULFrameElement.cpp +++ b/dom/xul/XULFrameElement.cpp @@ -92,8 +92,7 @@ void XULFrameElement::LoadSrc() { // 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 ? opener->GetDOMWindow() : nullptr, false); + mFrameLoader = nsFrameLoader::Create(this, opener, false); if (NS_WARN_IF(!mFrameLoader)) { return; }