Commit 88b3fbe3 authored by Nika Layzell's avatar Nika Layzell
Browse files

Bug 1580565 - Part 4: Use WindowContext to manage BrowsingContext cached status, r=farre

The existing infrastructure which stored cached BrowsingContexts on the
BrowsingContextGroup was added before WindowContexts were added, and can cause
racing issues with partially discarded trees during process switches.

Differential Revision: https://phabricator.services.mozilla.com/D71238
parent 20e0c066
......@@ -159,9 +159,11 @@ bool BrowsingContext::SameOriginWithTop() {
/* static */
already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
Type aType) {
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
const nsAString& aName, Type aType) {
MOZ_DIAGNOSTIC_ASSERT(!aParent ||
aParent->GetBrowsingContext()->mType == aType);
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->GetWindowContext());
MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());
......@@ -171,31 +173,47 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
("Creating 0x%08" PRIx64 " in %s", id,
XRE_IsParentProcess() ? "Parent" : "Child"));
RefPtr<BrowsingContext> parentBC =
aParent ? aParent->GetBrowsingContext() : nullptr;
RefPtr<WindowContext> parentWC =
aParent ? aParent->GetWindowContext() : nullptr;
// Determine which BrowsingContextGroup this context should be created in.
RefPtr<BrowsingContextGroup> group =
(aType == Type::Chrome)
? do_AddRef(BrowsingContextGroup::GetChromeGroup())
: BrowsingContextGroup::Select(aParent, aOpener);
: BrowsingContextGroup::Select(parentWC, aOpener);
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
context =
new CanonicalBrowsingContext(aParent, group, id,
new CanonicalBrowsingContext(parentWC, group, id,
/* aOwnerProcessId */ 0,
/* aEmbedderProcessId */ 0, aType, {});
} else {
context = new BrowsingContext(aParent, group, id, aType, {});
context = new BrowsingContext(parentWC, group, id, aType, {});
}
// The name and opener fields need to be explicitly initialized. Don't bother
// using transactions to set them, as we haven't been attached yet.
context->mFields.SetWithoutSyncing<IDX_Name>(aName);
if (aOpener) {
MOZ_DIAGNOSTIC_ASSERT(!aParent,
"new BC with both initial opener and parent");
MOZ_DIAGNOSTIC_ASSERT(aOpener->Group() == context->Group());
MOZ_DIAGNOSTIC_ASSERT(aOpener->mType == context->mType);
context->mFields.SetWithoutSyncing<IDX_OpenerId>(aOpener->Id());
context->mFields.SetWithoutSyncing<IDX_HadOriginalOpener>(true);
}
if (aParent) {
MOZ_DIAGNOSTIC_ASSERT(parentBC->Group() == context->Group());
MOZ_DIAGNOSTIC_ASSERT(parentBC->mType == context->mType);
context->mEmbeddedByThisProcess = true;
context->mFields.SetWithoutSyncing<IDX_EmbedderInnerWindowId>(
aParent->WindowID());
}
context->mFields.SetWithoutSyncing<IDX_EmbedderPolicy>(
nsILoadInfo::EMBEDDER_POLICY_NULL);
context->mFields.SetWithoutSyncing<IDX_OpenerPolicy>(
......@@ -215,7 +233,7 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS);
}
BrowsingContext* inherit = aParent ? aParent : aOpener;
BrowsingContext* inherit = parentBC ? parentBC.get() : aOpener;
if (inherit) {
context->mPrivateBrowsingId = inherit->mPrivateBrowsingId;
context->mUseRemoteTabs = inherit->mUseRemoteTabs;
......@@ -225,22 +243,17 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
// CORPP 3.1.3 https://mikewest.github.io/corpp/#integration-html
context->mFields.SetWithoutSyncing<IDX_EmbedderPolicy>(
inherit->GetEmbedderPolicy());
// if our parent has a parent that's loading, we need it too
bool ancestorLoading = aParent ? aParent->GetAncestorLoading() : false;
if (!ancestorLoading && aParent) {
// XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
// 1608448) Check if the parent was itself loading already
nsPIDOMWindowOuter* outer = aParent->GetDOMWindow();
if (outer) {
Document* document = nsGlobalWindowOuter::Cast(outer)->GetDocument();
auto readystate = document->GetReadyStateEnum();
if (readystate == Document::ReadyState::READYSTATE_LOADING ||
readystate == Document::ReadyState::READYSTATE_INTERACTIVE) {
ancestorLoading = true;
}
}
}
context->mFields.SetWithoutSyncing<IDX_AncestorLoading>(ancestorLoading);
}
// if our parent has a parent that's loading, we need it too
if (aParent) {
// XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
// 1608448) Check if the parent was itself loading already
auto readystate = aParent->GetDocument()->GetReadyStateEnum();
context->mFields.SetWithoutSyncing<IDX_AncestorLoading>(
parentBC->GetAncestorLoading() ||
readystate == Document::ReadyState::READYSTATE_LOADING ||
readystate == Document::ReadyState::READYSTATE_INTERACTIVE);
}
nsContentUtils::GenerateUUIDInPlace(
......@@ -301,7 +314,7 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateFromIPC(
("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
aInit.mId, originId));
RefPtr<BrowsingContext> parent = aInit.GetParent();
RefPtr<WindowContext> parent = aInit.GetParent();
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
......@@ -330,14 +343,10 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateFromIPC(
// Caller handles attaching us to the tree.
if (aInit.mCached) {
context->mEverAttached = true;
}
return context.forget();
}
BrowsingContext::BrowsingContext(BrowsingContext* aParent,
BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
BrowsingContextGroup* aGroup,
uint64_t aBrowsingContextId, Type aType,
FieldTuple&& aFields)
......@@ -345,7 +354,7 @@ BrowsingContext::BrowsingContext(BrowsingContext* aParent,
mType(aType),
mBrowsingContextId(aBrowsingContextId),
mGroup(aGroup),
mParent(aParent),
mParentWindow(aParentWindow),
mPrivateBrowsingId(0),
mEverAttached(false),
mIsInProcess(false),
......@@ -356,7 +365,10 @@ BrowsingContext::BrowsingContext(BrowsingContext* aParent,
mEmbeddedByThisProcess(false),
mUseRemoteTabs(false),
mUseRemoteSubframes(false) {
MOZ_RELEASE_ASSERT(!mParent || mParent->Group() == mGroup);
if (mParentWindow) {
MOZ_RELEASE_ASSERT(mParentWindow->Group() == mGroup);
mParent = mParentWindow->GetBrowsingContext();
}
MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
MOZ_RELEASE_ASSERT(mGroup);
}
......@@ -463,19 +475,14 @@ void BrowsingContext::Attach(bool aFromIPC) {
}
MOZ_DIAGNOSTIC_ASSERT(mGroup);
MOZ_DIAGNOSTIC_ASSERT(!mGroup->IsContextCached(this));
MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded);
Children* children = nullptr;
if (mParent) {
children = &mParent->mChildren;
BrowsingContext_Binding::ClearCachedChildrenValue(mParent);
// Add ourselves either to our parent or BrowsingContextGroup's child list.
if (mParentWindow) {
mParentWindow->AppendChildBrowsingContext(this);
} else {
children = &mGroup->Toplevels();
mGroup->Toplevels().AppendElement(this);
}
MOZ_DIAGNOSTIC_ASSERT(!children->Contains(this));
children->AppendElement(this);
if (GetIsPopupSpam()) {
PopupBlocker::RegisterOpenPopupSpam();
......@@ -503,27 +510,16 @@ void BrowsingContext::Detach(bool aFromIPC) {
XRE_IsParentProcess() ? "Parent" : "Child", Id(),
mParent ? mParent->Id() : 0));
// Unlinking might remove our group before Detach gets called.
// This will only ever be null if the cycle-collector has unlinked us. Don't
// try to detach ourselves in that case.
if (NS_WARN_IF(!mGroup)) {
return;
}
if (!mGroup->EvictCachedContext(this)) {
Children* children = nullptr;
if (mParent) {
children = &mParent->mChildren;
BrowsingContext_Binding::ClearCachedChildrenValue(mParent);
} else {
children = &mGroup->Toplevels();
}
children->RemoveElement(this);
}
if (!mChildren.IsEmpty()) {
mGroup->CacheContexts(mChildren);
mChildren.Clear();
BrowsingContext_Binding::ClearCachedChildrenValue(this);
if (mParentWindow) {
mParentWindow->RemoveChildBrowsingContext(this);
} else {
mGroup->Toplevels().RemoveElement(this);
}
{
......@@ -611,46 +607,10 @@ void BrowsingContext::PrepareForProcessChange() {
MOZ_ASSERT(!mWindowProxy);
}
void BrowsingContext::CacheChildren(bool aFromIPC) {
MOZ_LOG(GetLog(), LogLevel::Debug,
("%s: Caching children of 0x%08" PRIx64 "",
XRE_IsParentProcess() ? "Parent" : "Child", Id()));
mGroup->CacheContexts(mChildren);
mChildren.Clear();
BrowsingContext_Binding::ClearCachedChildrenValue(this);
if (!aFromIPC && XRE_IsContentProcess()) {
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendCacheBrowsingContextChildren(this);
}
bool BrowsingContext::IsCached() {
return mParentWindow && mParentWindow->IsCached();
}
void BrowsingContext::RestoreChildren(Children&& aChildren, bool aFromIPC) {
MOZ_LOG(GetLog(), LogLevel::Debug,
("%s: Restoring children of 0x%08" PRIx64 "",
XRE_IsParentProcess() ? "Parent" : "Child", Id()));
nsTArray<MaybeDiscarded<BrowsingContext>> ipcChildren(aChildren.Length());
for (BrowsingContext* child : aChildren) {
MOZ_DIAGNOSTIC_ASSERT(child->GetParent() == this);
Unused << mGroup->EvictCachedContext(child);
ipcChildren.AppendElement(child);
}
mChildren.AppendElements(aChildren);
BrowsingContext_Binding::ClearCachedChildrenValue(this);
if (!aFromIPC && XRE_IsContentProcess()) {
auto cc = ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendRestoreBrowsingContextChildren(this, ipcChildren);
}
}
bool BrowsingContext::IsCached() { return mGroup->IsContextCached(this); }
bool BrowsingContext::IsTargetable() {
return !GetClosed() && !mIsDiscarded && !IsCached();
}
......@@ -659,8 +619,16 @@ bool BrowsingContext::HasOpener() const {
return sBrowsingContexts->Contains(GetOpenerId());
}
void BrowsingContext::GetChildren(Children& aChildren) {
MOZ_ALWAYS_TRUE(aChildren.AppendElements(mChildren));
Span<RefPtr<BrowsingContext>> BrowsingContext::Children() const {
if (WindowContext* current = mCurrentWindowContext) {
return current->Children();
}
return Span<RefPtr<BrowsingContext>>();
}
void BrowsingContext::GetChildren(
nsTArray<RefPtr<BrowsingContext>>& aChildren) {
MOZ_ALWAYS_TRUE(aChildren.AppendElements(Children()));
}
void BrowsingContext::GetWindowContexts(
......@@ -671,10 +639,15 @@ void BrowsingContext::GetWindowContexts(
void BrowsingContext::RegisterWindowContext(WindowContext* aWindow) {
MOZ_ASSERT(!mWindowContexts.Contains(aWindow),
"WindowContext already registered!");
MOZ_ASSERT(aWindow->GetBrowsingContext() == this);
mWindowContexts.AppendElement(aWindow);
// If the newly registered WindowContext is for our current inner window ID,
// re-run the `DidSet` handler to re-establish the relationship.
if (aWindow->InnerWindowId() == GetCurrentInnerWindowId()) {
MOZ_ASSERT(aWindow->GetBrowsingContext() == this);
mCurrentWindowContext = aWindow;
DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext == aWindow);
}
}
......@@ -683,15 +656,9 @@ void BrowsingContext::UnregisterWindowContext(WindowContext* aWindow) {
"WindowContext not registered!");
mWindowContexts.RemoveElement(aWindow);
// Our current window global should be in our mWindowGlobals set. If it's not
// anymore, clear that reference.
// FIXME: There are probably situations where this is wrong. We should
// double-check.
// If our currently active window was unregistered, clear our reference to it.
if (aWindow == mCurrentWindowContext) {
mCurrentWindowContext = nullptr;
if (XRE_IsParentProcess()) {
BrowserParent::UpdateFocusFromBrowsingContext();
}
SetCurrentInnerWindowId(0);
}
}
......@@ -739,23 +706,23 @@ BrowsingContext* BrowsingContext::FindWithName(
BrowsingContext* current = this;
do {
Children* siblings;
Span<RefPtr<BrowsingContext>> siblings;
BrowsingContext* parent = current->mParent;
if (!parent) {
// We've reached the root of the tree, consider browsing
// contexts in the same browsing context group.
siblings = &mGroup->Toplevels();
siblings = mGroup->Toplevels();
} else if (parent->NameEquals(aName) &&
requestingContext->CanAccess(parent) &&
parent->IsTargetable()) {
found = parent;
break;
} else {
siblings = &parent->mChildren;
siblings = parent->Children();
}
for (BrowsingContext* sibling : *siblings) {
for (BrowsingContext* sibling : siblings) {
if (sibling == current) {
continue;
}
......@@ -787,7 +754,7 @@ BrowsingContext* BrowsingContext::FindChildWithName(
return nullptr;
}
for (BrowsingContext* child : mChildren) {
for (BrowsingContext* child : Children()) {
if (child->NameEquals(aName) && aRequestingContext.CanAccess(child) &&
child->IsTargetable()) {
return child;
......@@ -831,7 +798,7 @@ BrowsingContext* BrowsingContext::FindWithNameInSubtree(
return this;
}
for (BrowsingContext* child : mChildren) {
for (BrowsingContext* child : Children()) {
if (BrowsingContext* found =
child->FindWithNameInSubtree(aName, aRequestingContext)) {
return found;
......@@ -947,9 +914,9 @@ RefPtr<SessionStorageManager> BrowsingContext::GetSessionStorageManager() {
}
BrowsingContext::~BrowsingContext() {
MOZ_DIAGNOSTIC_ASSERT(!mParent || !mParent->mChildren.Contains(this));
MOZ_DIAGNOSTIC_ASSERT(!mParentWindow ||
!mParentWindow->mChildren.Contains(this));
MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->Toplevels().Contains(this));
MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->IsContextCached(this));
mDeprioritizedLoadRunner.clear();
......@@ -1316,7 +1283,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
tmp->mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mParentWindow, mParent, mGroup,
mEmbedderElement, mWindowContexts,
mCurrentWindowContext, mSessionStorageManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
......@@ -1324,8 +1291,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
mDocShell, mChildren, mParent, mGroup, mEmbedderElement, mWindowContexts,
mCurrentWindowContext, mSessionStorageManager)
mDocShell, mParentWindow, mParent, mGroup, mEmbedderElement,
mWindowContexts, mCurrentWindowContext, mSessionStorageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
class RemoteLocationProxy
......@@ -1678,8 +1645,7 @@ BrowsingContext::IPCInitializer BrowsingContext::GetIPCInitializer() {
IPCInitializer init;
init.mId = Id();
init.mParentId = mParent ? mParent->Id() : 0;
init.mCached = IsCached();
init.mParentId = mParentWindow ? mParentWindow->Id() : 0;
init.mWindowless = mWindowless;
init.mUseRemoteTabs = mUseRemoteTabs;
init.mUseRemoteSubframes = mUseRemoteSubframes;
......@@ -1688,10 +1654,10 @@ BrowsingContext::IPCInitializer BrowsingContext::GetIPCInitializer() {
return init;
}
already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetParent() {
RefPtr<BrowsingContext> parent;
already_AddRefed<WindowContext> BrowsingContext::IPCInitializer::GetParent() {
RefPtr<WindowContext> parent;
if (mParentId != 0) {
parent = BrowsingContext::Get(mParentId);
parent = WindowContext::GetById(mParentId);
MOZ_RELEASE_ASSERT(parent);
}
return parent.forget();
......@@ -1847,56 +1813,14 @@ bool BrowsingContext::CheckOnlyEmbedderCanSet(ContentParent* aSource) {
bool BrowsingContext::CanSet(FieldIndex<IDX_EmbedderInnerWindowId>,
const uint64_t& aValue, ContentParent* aSource) {
// Generally allow clearing this. We may want to be more precise about this
// check in the future.
if (aValue == 0) {
return true;
}
// If we don't have a specified source, we're the setting process. The window
// which we're setting this to must be in-process.
RefPtr<BrowsingContext> impliedParent;
if (!aSource) {
nsGlobalWindowInner* innerWindow =
nsGlobalWindowInner::GetInnerWindowWithId(aValue);
if (NS_WARN_IF(!innerWindow)) {
return false;
}
impliedParent = innerWindow->GetBrowsingContext();
}
// If in the parent process, double-check ownership and WindowGlobalParent as
// well.
if (XRE_IsParentProcess()) {
RefPtr<WindowGlobalParent> wgp =
WindowGlobalParent::GetByInnerWindowId(aValue);
if (NS_WARN_IF(!wgp)) {
return false;
}
// Deduce the implied parent from the WindowGlobalParent actor.
if (impliedParent) {
MOZ_ASSERT(impliedParent == wgp->BrowsingContext());
}
impliedParent = wgp->BrowsingContext();
// Double-check ownership if we aren't the setter.
if (aSource &&
!impliedParent->Canonical()->IsOwnedByProcess(aSource->ChildID()) &&
aSource->ChildID() !=
impliedParent->Canonical()->GetInFlightProcessId()) {
return false;
}
// If we have a parent window, our embedder inner window ID must match it.
if (mParentWindow) {
return mParentWindow->Id() == aValue;
}
// If we would have an invalid implied parent, something has gone wrong.
MOZ_ASSERT(impliedParent);
if (NS_WARN_IF(mParent && mParent != impliedParent)) {
return false;
}
return true;
// For toplevel BrowsingContext instances, this value may only be set by the
// parent process, or initialized to `0`.
return CheckOnlyEmbedderCanSet(aSource);
}
bool BrowsingContext::CanSet(FieldIndex<IDX_EmbedderElementType>,
......@@ -1937,6 +1861,14 @@ bool BrowsingContext::CanSet(FieldIndex<IDX_CurrentInnerWindowId>,
void BrowsingContext::DidSet(FieldIndex<IDX_CurrentInnerWindowId>) {
mCurrentWindowContext = WindowContext::GetById(GetCurrentInnerWindowId());
MOZ_ASSERT(
!mCurrentWindowContext || mWindowContexts.Contains(mCurrentWindowContext),
"WindowContext not registered?");
// Clear our cached `children` value, to ensure that JS sees the up-to-date
// value.
BrowsingContext_Binding::ClearCachedChildrenValue(this);
if (XRE_IsParentProcess()) {
BrowserParent::UpdateFocusFromBrowsingContext();
}
......@@ -2062,7 +1994,6 @@ void IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Write(
// Write actor ID parameters.
WriteIPDLParam(aMessage, aActor, aInit.mId);
WriteIPDLParam(aMessage, aActor, aInit.mParentId);
WriteIPDLParam(aMessage, aActor, aInit.mCached);
WriteIPDLParam(aMessage, aActor, aInit.mWindowless);
WriteIPDLParam(aMessage, aActor, aInit.mUseRemoteTabs);
WriteIPDLParam(aMessage, aActor, aInit.mUseRemoteSubframes);
......@@ -2076,7 +2007,6 @@ bool IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Read(
// Read actor ID parameters.
if (!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mId) ||
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mParentId) ||
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mCached) ||
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mWindowless) ||
!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mUseRemoteTabs) ||
!ReadIPDLParam(aMessage, aIterator, aActor,
......
......@@ -11,6 +11,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Span.h"
#include "mozilla/Tuple.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/BindingDeclarations.h"
......@@ -32,6 +33,7 @@
#include "nsILoadContext.h"
class nsDocShellLoadState;
class nsGlobalWindowInner;
class nsGlobalWindowOuter;
class nsILoadInfo;
class nsIPrincipal;
......@@ -147,8 +149,6 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
public:
enum class Type { Chrome, Content };
using Children = nsTArray<RefPtr<BrowsingContext>>;
static void Init();
static LogModule* GetLog();
static void CleanupContexts(uint64_t aProcessId);
......@@ -184,7 +184,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
// `EnsureAttached()` must be called before the BrowsingContext is used for a
// DocShell, BrowserParent, or BrowserBridgeChild.
static already_AddRefed<BrowsingContext> CreateDetached(
BrowsingContext* aParent, BrowsingContext* aOpener,
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
const nsAString& aName, Type aType);
void EnsureAttached();
......@@ -251,13 +251,6 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
// Prepare this BrowsingContext to leave the current process.
void PrepareForProcessChange();
// Remove all children from the current BrowsingContext and cache
// them to allow them to be attached again.
void CacheChildren(bool aFromIPC = false);
// Restore cached browsing contexts.
void RestoreChildren(Children&& aChildren, bool aFromIPC = false);
// Triggers a load in the process which currently owns this BrowsingContext.
nsresult LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating = false);
......@@ -271,8 +264,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void DisplayLoadError(const nsAString& aURI);
// Determine if the current BrowsingContext was 'cached' by the logic in
// CacheChildren.
// Determine if the current BrowsingContext is in the BFCache.
bool IsCached();
// Check that this browsing context is targetable for navigations (i.e. that
......@@ -300,6 +292,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
}
BrowsingContext* Top();
// NOTE: Unlike `GetEmbedderWindowGlobal`, `GetParentWindow` does not cross
// toplevel content browser boundaries.
WindowContext* GetParentWindow() const { return mParentWindow; }
already_AddRefed<BrowsingContext> GetOpener() const {
RefPtr<BrowsingContext> opener(Get(GetOpenerId()));
if (!mIsDiscarded && opener && !opener->mIsDiscarded) {
......@@ -340,8 +336,12 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
uint32_t SandboxFlags() { return GetSandboxFlags(); }
void GetChildren(Children& aChildren);
Span<RefPtr<BrowsingContext>> Children() const;
void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
const nsTArray<RefPtr<WindowContext>>& GetWindowContexts() {
return mWindowContexts;
}
void GetWindowContexts(nsTArray<RefPtr<WindowContext>>& aWindows);
void RegisterWindowContext(WindowContext* aWindow);
......@@ -449,22 +449,17 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BrowsingContext)
NS_DECL_NSILOADCONTEXT
const Children& GetChildren() { return mChildren; }
const nsTArray<RefPtr<WindowContext>>& GetWindowContexts() {
return mWindowContexts;
}
// Perform a pre-order walk of this BrowsingContext subtree.
void PreOrderWalk(const std::function<void(BrowsingContext*)>& aCallback) {
aCallback(this);
for (auto& child : GetChildren()) {
for (auto& child : Children()) {
child->PreOrderWalk(aCallback);
}
}
// Perform an post-order walk of this BrowsingContext subtree.
void PostOrderWalk(const std::function<void(BrowsingContext*)>& aCallback) {
for (auto& child : GetChildren()) {
for (auto& child : Children()) {
child->PostOrderWalk(aCallback);
}
......@@ -481,7 +476,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void Focus(CallerType aCallerType, ErrorResult& aError);
void Blur(ErrorResult& aError);
WindowProxyHolder GetFrames(ErrorResult& aError);
int32_t Length() const { return mChildren.Length(); }
int32_t Length() const { return Children().Length(); }