Backed out 7 changesets (bug 1580565) for Gecko-view failures in Test.crashParent. CLOSED TREE

Backed out changeset 7da9785ebb06 (bug 1580565)
Backed out changeset a80e177a91b2 (bug 1580565)
Backed out changeset 2cf821f2a6ea (bug 1580565)
Backed out changeset a30f158eba45 (bug 1580565)
Backed out changeset 276b131190a8 (bug 1580565)
Backed out changeset 3c15e4c600c4 (bug 1580565)
Backed out changeset bf8877cdb10f (bug 1580565)
This commit is contained in:
Dorel Luca 2020-04-22 18:42:24 +03:00
Родитель 7b824820e7
Коммит 7daa9a6695
37 изменённых файлов: 893 добавлений и 680 удалений

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

@ -93,14 +93,10 @@ static void Register(BrowsingContext* aBrowsingContext) {
aBrowsingContext->Group()->Register(aBrowsingContext);
}
BrowsingContext* BrowsingContext::GetParent() const {
return mParentWindow ? mParentWindow->GetBrowsingContext() : nullptr;
}
BrowsingContext* BrowsingContext::Top() {
BrowsingContext* bc = this;
while (bc->mParentWindow) {
bc = bc->GetParent();
while (bc->mParent) {
bc = bc->mParent;
}
return bc;
}
@ -163,11 +159,9 @@ bool BrowsingContext::SameOriginWithTop() {
/* static */
already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
const nsAString& aName, Type aType) {
MOZ_DIAGNOSTIC_ASSERT(!aParent ||
aParent->GetBrowsingContext()->mType == aType);
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->GetWindowContext());
BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
Type aType) {
MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());
@ -177,47 +171,31 @@ 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(parentWC, aOpener);
: BrowsingContextGroup::Select(aParent, aOpener);
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
context =
new CanonicalBrowsingContext(parentWC, group, id,
new CanonicalBrowsingContext(aParent, group, id,
/* aOwnerProcessId */ 0,
/* aEmbedderProcessId */ 0, aType, {});
} else {
context = new BrowsingContext(parentWC, group, id, aType, {});
context = new BrowsingContext(aParent, 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>(
@ -237,7 +215,7 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS);
}
BrowsingContext* inherit = parentBC ? parentBC.get() : aOpener;
BrowsingContext* inherit = aParent ? aParent : aOpener;
if (inherit) {
context->mPrivateBrowsingId = inherit->mPrivateBrowsingId;
context->mUseRemoteTabs = inherit->mUseRemoteTabs;
@ -247,17 +225,22 @@ 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
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);
// 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);
}
nsContentUtils::GenerateUUIDInPlace(
@ -278,11 +261,19 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
return context.forget();
}
already_AddRefed<BrowsingContext> BrowsingContext::CreateIndependent(
already_AddRefed<BrowsingContext> BrowsingContext::Create(
BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
Type aType) {
RefPtr<BrowsingContext> bc(
CreateDetached(nullptr, nullptr, EmptyString(), aType));
bc->mWindowless = bc->IsContent();
RefPtr<BrowsingContext> bc(CreateDetached(aParent, aOpener, aName, aType));
bc->EnsureAttached();
return bc.forget();
}
already_AddRefed<BrowsingContext> BrowsingContext::CreateWindowless(
BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
Type aType) {
RefPtr<BrowsingContext> bc(CreateDetached(aParent, aOpener, aName, aType));
bc->mWindowless = true;
bc->EnsureAttached();
return bc.forget();
}
@ -297,14 +288,14 @@ void BrowsingContext::EnsureAttached() {
Register(this);
// Attach the browsing context to the tree.
Attach(/* aFromIPC */ false, /* aOriginProcess */ nullptr);
Attach();
}
}
/* static */
void BrowsingContext::CreateFromIPC(BrowsingContext::IPCInitializer&& aInit,
BrowsingContextGroup* aGroup,
ContentParent* aOriginProcess) {
already_AddRefed<BrowsingContext> BrowsingContext::CreateFromIPC(
BrowsingContext::IPCInitializer&& aInit, BrowsingContextGroup* aGroup,
ContentParent* aOriginProcess) {
MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess());
MOZ_DIAGNOSTIC_ASSERT(aGroup);
@ -318,7 +309,7 @@ void BrowsingContext::CreateFromIPC(BrowsingContext::IPCInitializer&& aInit,
("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
aInit.mId, originId));
RefPtr<WindowContext> parent = aInit.GetParent();
RefPtr<BrowsingContext> parent = aInit.GetParent();
RefPtr<BrowsingContext> context;
if (XRE_IsParentProcess()) {
@ -345,10 +336,16 @@ void BrowsingContext::CreateFromIPC(BrowsingContext::IPCInitializer&& aInit,
Register(context);
context->Attach(/* aFromIPC */ true, aOriginProcess);
// Caller handles attaching us to the tree.
if (aInit.mCached) {
context->mEverAttached = true;
}
return context.forget();
}
BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
BrowsingContext::BrowsingContext(BrowsingContext* aParent,
BrowsingContextGroup* aGroup,
uint64_t aBrowsingContextId, Type aType,
FieldTuple&& aFields)
@ -356,7 +353,7 @@ BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
mType(aType),
mBrowsingContextId(aBrowsingContextId),
mGroup(aGroup),
mParentWindow(aParentWindow),
mParent(aParent),
mPrivateBrowsingId(0),
mEverAttached(false),
mIsInProcess(false),
@ -367,7 +364,7 @@ BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
mEmbeddedByThisProcess(false),
mUseRemoteTabs(false),
mUseRemoteSubframes(false) {
MOZ_RELEASE_ASSERT(!mParentWindow || mParentWindow->Group() == mGroup);
MOZ_RELEASE_ASSERT(!mParent || mParent->Group() == mGroup);
MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
MOZ_RELEASE_ASSERT(mGroup);
}
@ -458,7 +455,7 @@ void BrowsingContext::Embed() {
}
}
void BrowsingContext::Attach(bool aFromIPC, ContentParent* aOriginProcess) {
void BrowsingContext::Attach(bool aFromIPC) {
MOZ_DIAGNOSTIC_ASSERT(!mEverAttached);
mEverAttached = true;
@ -469,37 +466,40 @@ void BrowsingContext::Attach(bool aFromIPC, ContentParent* aOriginProcess) {
("%s: Connecting 0x%08" PRIx64 " to 0x%08" PRIx64
" (private=%d, remote=%d, fission=%d, oa=%s)",
XRE_IsParentProcess() ? "Parent" : "Child", Id(),
GetParent() ? GetParent()->Id() : 0, (int)mPrivateBrowsingId,
mParent ? mParent->Id() : 0, (int)mPrivateBrowsingId,
(int)mUseRemoteTabs, (int)mUseRemoteSubframes, suffix.get()));
}
MOZ_DIAGNOSTIC_ASSERT(mGroup);
MOZ_DIAGNOSTIC_ASSERT(!mGroup->IsContextCached(this));
MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded);
// Add ourselves either to our parent or BrowsingContextGroup's child list.
if (mParentWindow) {
mParentWindow->AppendChildBrowsingContext(this);
Children* children = nullptr;
if (mParent) {
children = &mParent->mChildren;
BrowsingContext_Binding::ClearCachedChildrenValue(mParent);
} else {
mGroup->Toplevels().AppendElement(this);
children = &mGroup->Toplevels();
}
MOZ_DIAGNOSTIC_ASSERT(!children->Contains(this));
children->AppendElement(this);
if (GetIsPopupSpam()) {
PopupBlocker::RegisterOpenPopupSpam();
}
if (XRE_IsContentProcess() && !aFromIPC) {
if (!aFromIPC) {
// Send attach to our parent if we need to.
ContentChild::GetSingleton()->SendCreateBrowsingContext(
mGroup->Id(), GetIPCInitializer());
} else if (XRE_IsParentProcess()) {
mGroup->EachOtherParent(aOriginProcess, [&](ContentParent* aParent) {
MOZ_DIAGNOSTIC_ASSERT(IsContent(),
"chrome BCG cannot be synced to content process");
if (!Canonical()->IsEmbeddedInProcess(aParent->ChildID())) {
Unused << aParent->SendCreateBrowsingContext(mGroup->Id(),
GetIPCInitializer());
}
});
if (XRE_IsContentProcess()) {
ContentChild::GetSingleton()->SendAttachBrowsingContext(
GetIPCInitializer());
} else if (IsContent()) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
mGroup->EachParent([&](ContentParent* aParent) {
Unused << aParent->SendAttachBrowsingContext(GetIPCInitializer());
});
}
}
}
@ -509,18 +509,29 @@ void BrowsingContext::Detach(bool aFromIPC) {
MOZ_LOG(GetLog(), LogLevel::Debug,
("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child", Id(),
GetParent() ? GetParent()->Id() : 0));
mParent ? mParent->Id() : 0));
// This will only ever be null if the cycle-collector has unlinked us. Don't
// try to detach ourselves in that case.
// Unlinking might remove our group before Detach gets called.
if (NS_WARN_IF(!mGroup)) {
return;
}
if (mParentWindow) {
mParentWindow->RemoveChildBrowsingContext(this);
} else {
mGroup->Toplevels().RemoveElement(this);
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);
}
{
@ -539,12 +550,12 @@ void BrowsingContext::Detach(bool aFromIPC) {
// destroyed.
if (!Canonical()->IsEmbeddedInProcess(aParent->ChildID()) &&
!Canonical()->IsOwnedByProcess(aParent->ChildID())) {
aParent->SendDiscardBrowsingContext(this, callback, callback);
aParent->SendDetachBrowsingContext(Id(), callback, callback);
}
});
} else if (!aFromIPC) {
ContentChild::GetSingleton()->SendDiscardBrowsingContext(this, callback,
callback);
ContentChild::GetSingleton()->SendDetachBrowsingContext(Id(), callback,
callback);
}
}
@ -574,14 +585,6 @@ void BrowsingContext::Detach(bool aFromIPC) {
mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
}
// As we're discarded, we no longer have a currently active inner window.
// Clear the stored value to `0`, and run the `DidSet` handler to update
// related fields.
mFields.SetWithoutSyncing<IDX_CurrentInnerWindowId>(0);
DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
MOZ_DIAGNOSTIC_ASSERT(!mCurrentWindowContext,
"Discarded BC has no current WindowContext");
AssertOriginAttributesMatchPrivateBrowsing();
if (XRE_IsParentProcess()) {
@ -616,10 +619,46 @@ void BrowsingContext::PrepareForProcessChange() {
MOZ_ASSERT(!mWindowProxy);
}
bool BrowsingContext::IsCached() {
return mParentWindow && mParentWindow->IsCached();
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);
}
}
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();
}
@ -628,16 +667,8 @@ bool BrowsingContext::HasOpener() const {
return sBrowsingContexts->Contains(GetOpenerId());
}
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::GetChildren(Children& aChildren) {
MOZ_ALWAYS_TRUE(aChildren.AppendElements(mChildren));
}
void BrowsingContext::GetWindowContexts(
@ -648,15 +679,10 @@ 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()) {
DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext == aWindow);
MOZ_ASSERT(aWindow->GetBrowsingContext() == this);
mCurrentWindowContext = aWindow;
}
}
@ -665,9 +691,15 @@ void BrowsingContext::UnregisterWindowContext(WindowContext* aWindow) {
"WindowContext not registered!");
mWindowContexts.RemoveElement(aWindow);
// If our currently active window was unregistered, clear our reference to it.
// 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 (aWindow == mCurrentWindowContext) {
SetCurrentInnerWindowId(0);
mCurrentWindowContext = nullptr;
if (XRE_IsParentProcess()) {
BrowserParent::UpdateFocusFromBrowsingContext();
}
}
}
@ -715,23 +747,23 @@ BrowsingContext* BrowsingContext::FindWithName(
BrowsingContext* current = this;
do {
Span<RefPtr<BrowsingContext>> siblings;
BrowsingContext* parent = current->GetParent();
Children* 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->Children();
siblings = &parent->mChildren;
}
for (BrowsingContext* sibling : siblings) {
for (BrowsingContext* sibling : *siblings) {
if (sibling == current) {
continue;
}
@ -763,7 +795,7 @@ BrowsingContext* BrowsingContext::FindChildWithName(
return nullptr;
}
for (BrowsingContext* child : Children()) {
for (BrowsingContext* child : mChildren) {
if (child->NameEquals(aName) && aRequestingContext.CanAccess(child) &&
child->IsTargetable()) {
return child;
@ -783,8 +815,8 @@ BrowsingContext* BrowsingContext::FindWithSpecialName(
}
if (aName.LowerCaseEqualsLiteral("_parent")) {
if (BrowsingContext* parent = GetParent()) {
return aRequestingContext.CanAccess(parent) ? parent : nullptr;
if (mParent) {
return aRequestingContext.CanAccess(mParent) ? mParent.get() : nullptr;
}
return this;
}
@ -807,7 +839,7 @@ BrowsingContext* BrowsingContext::FindWithNameInSubtree(
return this;
}
for (BrowsingContext* child : Children()) {
for (BrowsingContext* child : mChildren) {
if (BrowsingContext* found =
child->FindWithNameInSubtree(aName, aRequestingContext)) {
return found;
@ -923,9 +955,9 @@ RefPtr<SessionStorageManager> BrowsingContext::GetSessionStorageManager() {
}
BrowsingContext::~BrowsingContext() {
MOZ_DIAGNOSTIC_ASSERT(!mParentWindow ||
!mParentWindow->mChildren.Contains(this));
MOZ_DIAGNOSTIC_ASSERT(!mParent || !mParent->mChildren.Contains(this));
MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->Toplevels().Contains(this));
MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->IsContextCached(this));
mDeprioritizedLoadRunner.clear();
@ -1204,8 +1236,8 @@ NS_IMETHODIMP BrowsingContext::GetUseTrackingProtection(
return NS_OK;
}
if (GetParent()) {
return GetParent()->GetUseTrackingProtection(aUseTrackingProtection);
if (mParent) {
return mParent->GetUseTrackingProtection(aUseTrackingProtection);
}
return NS_OK;
@ -1292,7 +1324,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
tmp->mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mParentWindow, mGroup,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup,
mEmbedderElement, mWindowContexts,
mCurrentWindowContext, mSessionStorageManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@ -1300,7 +1332,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
mDocShell, mParentWindow, mGroup, mEmbedderElement, mWindowContexts,
mDocShell, mChildren, mParent, mGroup, mEmbedderElement, mWindowContexts,
mCurrentWindowContext, mSessionStorageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -1547,17 +1579,17 @@ void BrowsingContext::GetOpener(JSContext* aCx,
}
}
// We never throw an error, but the implementation in nsGlobalWindow does and
// we need to use the same signature.
Nullable<WindowProxyHolder> BrowsingContext::GetParent(ErrorResult& aError) {
if (mIsDiscarded) {
return nullptr;
}
if (GetParent()) {
return WindowProxyHolder(GetParent());
// We never throw an error, but the implementation in nsGlobalWindow does and
// we need to use the same signature.
if (!mParent) {
return WindowProxyHolder(this);
}
return WindowProxyHolder(this);
return WindowProxyHolder(mParent.get());
}
void BrowsingContext::PostMessageMoz(JSContext* aCx,
@ -1654,7 +1686,8 @@ BrowsingContext::IPCInitializer BrowsingContext::GetIPCInitializer() {
IPCInitializer init;
init.mId = Id();
init.mParentId = mParentWindow ? mParentWindow->Id() : 0;
init.mParentId = mParent ? mParent->Id() : 0;
init.mCached = IsCached();
init.mWindowless = mWindowless;
init.mUseRemoteTabs = mUseRemoteTabs;
init.mUseRemoteSubframes = mUseRemoteSubframes;
@ -1663,10 +1696,10 @@ BrowsingContext::IPCInitializer BrowsingContext::GetIPCInitializer() {
return init;
}
already_AddRefed<WindowContext> BrowsingContext::IPCInitializer::GetParent() {
RefPtr<WindowContext> parent;
already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetParent() {
RefPtr<BrowsingContext> parent;
if (mParentId != 0) {
parent = WindowContext::GetById(mParentId);
parent = BrowsingContext::Get(mParentId);
MOZ_RELEASE_ASSERT(parent);
}
return parent.forget();
@ -1728,7 +1761,7 @@ void BrowsingContext::DidSet(FieldIndex<IDX_UserActivationState>) {
}
void BrowsingContext::DidSet(FieldIndex<IDX_Muted>) {
MOZ_ASSERT(!GetParent(), "Set muted flag on non top-level context!");
MOZ_ASSERT(!mParent, "Set muted flag on non top-level context!");
USER_ACTIVATION_LOG("Set audio muted %d for %s browsing context 0x%08" PRIx64,
GetMuted(), XRE_IsParentProcess() ? "Parent" : "Child",
Id());
@ -1822,14 +1855,56 @@ bool BrowsingContext::CheckOnlyEmbedderCanSet(ContentParent* aSource) {
bool BrowsingContext::CanSet(FieldIndex<IDX_EmbedderInnerWindowId>,
const uint64_t& aValue, ContentParent* aSource) {
// If we have a parent window, our embedder inner window ID must match it.
if (mParentWindow) {
return mParentWindow->Id() == aValue;
// Generally allow clearing this. We may want to be more precise about this
// check in the future.
if (aValue == 0) {
return true;
}
// For toplevel BrowsingContext instances, this value may only be set by the
// parent process, or initialized to `0`.
return CheckOnlyEmbedderCanSet(aSource);
// 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 would have an invalid implied parent, something has gone wrong.
MOZ_ASSERT(impliedParent);
if (NS_WARN_IF(mParent && mParent != impliedParent)) {
return false;
}
return true;
}
bool BrowsingContext::CanSet(FieldIndex<IDX_EmbedderElementType>,
@ -1870,14 +1945,6 @@ 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();
}
@ -2003,6 +2070,7 @@ 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);
@ -2016,6 +2084,7 @@ 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,7 +11,6 @@
#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"
@ -33,7 +32,6 @@
#include "nsILoadContext.h"
class nsDocShellLoadState;
class nsGlobalWindowInner;
class nsGlobalWindowOuter;
class nsILoadInfo;
class nsIPrincipal;
@ -74,15 +72,13 @@ class WindowProxyHolder;
// Fields are, by default, settable by any process and readable by any process.
// Racy sets will be resolved as-if they occurred in the order the parent
// process finds out about them.
//
// The `DidSet` and `CanSet` methods may be overloaded to provide different
// behavior for a specific field.
// * `DidSet` is called to run code in every process whenever the value is
// updated (This currently occurs even if the value didn't change, though
// this may change in the future).
// * `CanSet` is called before attempting to set the value, in both the process
// which calls `Set`, and the parent process, and will kill the misbehaving
// process if it fails.
// This defines the default do-nothing implementations for DidSet()
// and CanSet() for all the fields. They may be overloaded to provide
// different behavior for a specific field.
// DidSet() is used to run code in any process that sees the
// the value updated (note: even if the value itself didn't change).
// CanSet() is used to verify that the setting is allowed, and will
// assert if it fails in Debug builds.
#define MOZ_EACH_BC_FIELD(FIELD) \
FIELD(Name, nsString) \
FIELD(Closed, bool) \
@ -149,6 +145,8 @@ 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);
@ -166,25 +164,26 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return GetFromWindow(aProxy);
}
// Create a brand-new toplevel BrowsingContext with no relationships to other
// BrowsingContexts, and which is not embedded within any <browser> or frame
// element.
//
// This BrowsingContext is immediately attached, and cannot have LoadContext
// flags customized unless it is of `Type::Chrome`.
//
// The process which created this BrowsingContext is responsible for detaching
// it.
static already_AddRefed<BrowsingContext> CreateIndependent(Type aType);
// Create a brand-new BrowsingContext object.
static already_AddRefed<BrowsingContext> Create(BrowsingContext* aParent,
BrowsingContext* aOpener,
const nsAString& aName,
Type aType);
// Create a brand-new BrowsingContext object, but does not immediately attach
// it. State such as OriginAttributes and PrivateBrowsingId may be customized
// to configure the BrowsingContext before it is attached.
//
// Same as the above, but does not immediately attach the browsing context.
// `EnsureAttached()` must be called before the BrowsingContext is used for a
// DocShell, BrowserParent, or BrowserBridgeChild.
static already_AddRefed<BrowsingContext> CreateDetached(
nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
BrowsingContext* aParent, BrowsingContext* aOpener,
const nsAString& aName, Type aType);
// Same as Create, but for a BrowsingContext which does not belong to a
// visible window, and will always be detached by the process that created it.
// In contrast, any top-level BrowsingContext created in a content process
// using Create() is assumed to belong to a <browser> element in the parent
// process, which will be responsible for detaching it.
static already_AddRefed<BrowsingContext> CreateWindowless(
BrowsingContext* aParent, BrowsingContext* aOpener,
const nsAString& aName, Type aType);
void EnsureAttached();
@ -238,6 +237,12 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return mDocShell ? mDocShell->GetWindow() : nullptr;
}
// Attach the current BrowsingContext to its parent, in both the child and the
// parent process. BrowsingContext objects are created attached by default, so
// this method need only be called when restoring cached BrowsingContext
// objects.
void Attach(bool aFromIPC = false);
// Detach the current BrowsingContext from its parent, in both the
// child and the parent process.
void Detach(bool aFromIPC = false);
@ -245,6 +250,13 @@ 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);
@ -258,7 +270,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void DisplayLoadError(const nsAString& aURI);
// Determine if the current BrowsingContext is in the BFCache.
// Determine if the current BrowsingContext was 'cached' by the logic in
// CacheChildren.
bool IsCached();
// Check that this browsing context is targetable for navigations (i.e. that
@ -280,13 +293,12 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool IsContentSubframe() const { return IsContent() && GetParent(); }
uint64_t Id() const { return mBrowsingContextId; }
BrowsingContext* GetParent() const;
BrowsingContext* GetParent() const {
MOZ_ASSERT_IF(mParent, mParent->mType == mType);
return mParent;
}
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) {
@ -327,12 +339,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
uint32_t SandboxFlags() { return GetSandboxFlags(); }
Span<RefPtr<BrowsingContext>> Children() const;
void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
void GetChildren(Children& aChildren);
const nsTArray<RefPtr<WindowContext>>& GetWindowContexts() {
return mWindowContexts;
}
void GetWindowContexts(nsTArray<RefPtr<WindowContext>>& aWindows);
void RegisterWindowContext(WindowContext* aWindow);
@ -440,17 +448,22 @@ 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 : Children()) {
for (auto& child : GetChildren()) {
child->PreOrderWalk(aCallback);
}
}
// Perform an post-order walk of this BrowsingContext subtree.
void PostOrderWalk(const std::function<void(BrowsingContext*)>& aCallback) {
for (auto& child : Children()) {
for (auto& child : GetChildren()) {
child->PostOrderWalk(aCallback);
}
@ -467,7 +480,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 Children().Length(); }
int32_t Length() const { return mChildren.Length(); }
Nullable<WindowProxyHolder> GetTop(ErrorResult& aError);
void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aOpener,
ErrorResult& aError) const;
@ -508,35 +521,27 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
// deserialized before other BrowsingContext in the BrowsingContextGroup
// have been initialized.
uint64_t mParentId = 0;
already_AddRefed<WindowContext> GetParent();
already_AddRefed<BrowsingContext> GetParent();
already_AddRefed<BrowsingContext> GetOpener();
uint64_t GetOpenerId() const { return mozilla::Get<IDX_OpenerId>(mFields); }
bool mCached = false;
bool mWindowless = false;
bool mUseRemoteTabs = false;
bool mUseRemoteSubframes = false;
OriginAttributes mOriginAttributes;
FieldTuple mFields;
bool operator==(const IPCInitializer& aOther) const {
return mId == aOther.mId && mParentId == aOther.mParentId &&
mWindowless == aOther.mWindowless &&
mUseRemoteTabs == aOther.mUseRemoteTabs &&
mUseRemoteSubframes == aOther.mUseRemoteSubframes &&
mOriginAttributes == aOther.mOriginAttributes &&
mFields == aOther.mFields;
}
};
// Create an IPCInitializer object for this BrowsingContext.
IPCInitializer GetIPCInitializer();
// Create a BrowsingContext object from over IPC.
static void CreateFromIPC(IPCInitializer&& aInitializer,
BrowsingContextGroup* aGroup,
ContentParent* aOriginProcess);
static already_AddRefed<BrowsingContext> CreateFromIPC(
IPCInitializer&& aInitializer, BrowsingContextGroup* aGroup,
ContentParent* aOriginProcess);
// Performs access control to check that 'this' can access 'aTarget'.
bool CanAccess(BrowsingContext* aTarget, bool aConsiderOpener = true);
@ -558,13 +563,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
protected:
virtual ~BrowsingContext();
BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,
BrowsingContext(BrowsingContext* aParent, BrowsingContextGroup* aGroup,
uint64_t aBrowsingContextId, Type aType,
FieldTuple&& aFields);
private:
void Attach(bool aFromIPC, ContentParent* aOriginProcess);
// Find the special browsing context if aName is '_self', '_parent',
// '_top', but not '_blank'. The latter is handled in FindWithName
BrowsingContext* FindWithSpecialName(const nsAString& aName,
@ -708,7 +711,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
const uint64_t mBrowsingContextId;
RefPtr<BrowsingContextGroup> mGroup;
RefPtr<WindowContext> mParentWindow;
RefPtr<BrowsingContext> mParent;
// Note: BrowsingContext_Binding::ClearCachedChildrenValue must be called any
// time this array is mutated to keep the JS-exposed reflection in sync.
Children mChildren;
nsCOMPtr<nsIDocShell> mDocShell;
RefPtr<Element> mEmbedderElement;
@ -817,6 +823,7 @@ extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
using BrowsingContextTransaction = BrowsingContext::BaseTransaction;
using BrowsingContextInitializer = BrowsingContext::IPCInitializer;
using BrowsingContextChildren = BrowsingContext::Children;
using MaybeDiscardedBrowsingContext = MaybeDiscarded<BrowsingContext>;
// Specialize the transaction object for every translation unit it's used in.

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

@ -16,31 +16,13 @@
namespace mozilla {
namespace dom {
static StaticRefPtr<BrowsingContextGroup> sChromeGroup;
static StaticAutoPtr<
nsDataHashtable<nsUint64HashKey, RefPtr<BrowsingContextGroup>>>
sBrowsingContextGroups;
already_AddRefed<BrowsingContextGroup> BrowsingContextGroup::GetOrCreate(
uint64_t aId) {
if (!sBrowsingContextGroups) {
sBrowsingContextGroups =
new nsDataHashtable<nsUint64HashKey, RefPtr<BrowsingContextGroup>>();
ClearOnShutdown(&sBrowsingContextGroups);
BrowsingContextGroup::BrowsingContextGroup() {
if (XRE_IsContentProcess()) {
ContentChild::GetSingleton()->HoldBrowsingContextGroup(this);
} else {
ContentParent::HoldBrowsingContextGroup(this);
}
auto entry = sBrowsingContextGroups->LookupForAdd(aId);
RefPtr<BrowsingContextGroup> group =
entry.OrInsert([&] { return do_AddRef(new BrowsingContextGroup(aId)); });
return group.forget();
}
already_AddRefed<BrowsingContextGroup> BrowsingContextGroup::Create() {
return GetOrCreate(nsContentUtils::GenerateBrowsingContextId());
}
BrowsingContextGroup::BrowsingContextGroup(uint64_t aId) : mId(aId) {
mTimerEventQueue = ThrottledEventQueue::Create(
GetMainThreadSerialEventTarget(), "BrowsingContextGroup timer queue");
@ -54,10 +36,6 @@ bool BrowsingContextGroup::Contains(BrowsingContext* aBrowsingContext) {
void BrowsingContextGroup::Register(BrowsingContext* aBrowsingContext) {
MOZ_DIAGNOSTIC_ASSERT(aBrowsingContext);
MOZ_DIAGNOSTIC_ASSERT(this == sChromeGroup ? aBrowsingContext->IsChrome()
: aBrowsingContext->IsContent(),
"Only chrome BCs may exist in the chrome group, and "
"only content BCs may exist in other groups");
mContexts.PutEntry(aBrowsingContext);
}
@ -70,7 +48,11 @@ void BrowsingContextGroup::Unregister(BrowsingContext* aBrowsingContext) {
// all subscribers.
UnsubscribeAllContentParents();
sBrowsingContextGroups->Remove(Id());
if (XRE_IsContentProcess()) {
ContentChild::GetSingleton()->ReleaseBrowsingContextGroup(this);
} else {
ContentParent::ReleaseBrowsingContextGroup(this);
}
// We may have been deleted here as the ContentChild/Parent may
// have held the last references to `this`.
// Do not access any members at this point.
@ -87,35 +69,6 @@ void BrowsingContextGroup::Unsubscribe(ContentParent* aOriginProcess) {
MOZ_DIAGNOSTIC_ASSERT(aOriginProcess);
mSubscribers.RemoveEntry(aOriginProcess);
aOriginProcess->OnBrowsingContextGroupUnsubscribe(this);
// If this origin process still embeds any non-discarded BrowsingContexts in
// this BrowsingContextGroup, make sure to discard them, as this process is
// going away.
nsTArray<RefPtr<BrowsingContext>> toDiscard;
for (auto& context : mContexts) {
if (context.GetKey()->Canonical()->IsEmbeddedInProcess(
aOriginProcess->ChildID())) {
toDiscard.AppendElement(context.GetKey());
}
}
for (auto& context : toDiscard) {
context->Detach(/* aFromIPC */ true);
}
}
static void CollectContextInitializers(
Span<RefPtr<BrowsingContext>> aContexts,
nsTArray<SyncedContextInitializer>& aInits) {
// The order that we record these initializers is important, as it will keep
// the order that children are attached to their parent in the newly connected
// content process consistent.
for (auto& context : aContexts) {
aInits.AppendElement(context->GetIPCInitializer());
for (auto& window : context->GetWindowContexts()) {
aInits.AppendElement(window->GetIPCInitializer());
CollectContextInitializers(window->Children(), aInits);
}
}
}
void BrowsingContextGroup::EnsureSubscribed(ContentParent* aProcess) {
@ -126,33 +79,79 @@ void BrowsingContextGroup::EnsureSubscribed(ContentParent* aProcess) {
Subscribe(aProcess);
// FIXME: This won't send non-discarded children of discarded BCs, but those
// BCs will be in the process of being destroyed anyway.
// FIXME: Prevent that situation from occuring.
nsTArray<SyncedContextInitializer> inits(mContexts.Count() * 2);
CollectContextInitializers(mToplevels, inits);
bool sendFocused = false;
bool sendActive = false;
BrowsingContext* focused = nullptr;
BrowsingContext* active = nullptr;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
focused = fm->GetFocusedBrowsingContextInChrome();
active = fm->GetActiveBrowsingContextInChrome();
}
nsTArray<BrowsingContext::IPCInitializer> inits(mContexts.Count());
nsTArray<WindowContext::IPCInitializer> windowInits(mContexts.Count());
auto addInits = [&](BrowsingContext* aContext) {
inits.AppendElement(aContext->GetIPCInitializer());
if (focused == aContext) {
sendFocused = true;
}
if (active == aContext) {
sendActive = true;
}
for (auto& window : aContext->GetWindowContexts()) {
windowInits.AppendElement(window->GetIPCInitializer());
}
};
// First, perform a pre-order walk of our BrowsingContext objects from our
// toplevels. This should visit every active BrowsingContext.
for (auto& context : mToplevels) {
MOZ_DIAGNOSTIC_ASSERT(!IsContextCached(context),
"cached contexts must have a parent");
context->PreOrderWalk(addInits);
}
// Ensure that cached BrowsingContext objects are also visited, by visiting
// them after mToplevels.
for (auto iter = mCachedContexts.Iter(); !iter.Done(); iter.Next()) {
iter.Get()->GetKey()->PreOrderWalk(addInits);
}
// We should have visited every browsing context.
MOZ_DIAGNOSTIC_ASSERT(inits.Length() == mContexts.Count(),
"Visited the wrong number of contexts!");
// Send all of our contexts to the target content process.
Unused << aProcess->SendRegisterBrowsingContextGroup(Id(), inits);
Unused << aProcess->SendRegisterBrowsingContextGroup(inits, windowInits);
// If the focused or active BrowsingContexts belong in this group, tell the
// newly subscribed process.
if (nsFocusManager* fm = nsFocusManager::GetFocusManager()) {
BrowsingContext* focused = fm->GetFocusedBrowsingContextInChrome();
if (focused && focused->Group() != this) {
focused = nullptr;
}
BrowsingContext* active = fm->GetActiveBrowsingContextInChrome();
if (active && active->Group() != this) {
active = nullptr;
}
if (focused || active) {
Unused << aProcess->SendSetupFocusedAndActive(focused, active);
}
if (sendActive || sendFocused) {
Unused << aProcess->SendSetupFocusedAndActive(
sendFocused ? focused : nullptr, sendActive ? active : nullptr);
}
}
bool BrowsingContextGroup::IsContextCached(BrowsingContext* aContext) const {
MOZ_DIAGNOSTIC_ASSERT(aContext);
return mCachedContexts.Contains(aContext);
}
void BrowsingContextGroup::CacheContext(BrowsingContext* aContext) {
mCachedContexts.PutEntry(aContext);
}
void BrowsingContextGroup::CacheContexts(
const BrowsingContext::Children& aContexts) {
for (BrowsingContext* child : aContexts) {
mCachedContexts.PutEntry(child);
}
}
bool BrowsingContextGroup::EvictCachedContext(BrowsingContext* aContext) {
return mCachedContexts.EnsureRemoved(aContext);
}
BrowsingContextGroup::~BrowsingContextGroup() {
UnsubscribeAllContentParents();
}
@ -214,11 +213,13 @@ void BrowsingContextGroup::FlushPostMessageEvents() {
}
}
static StaticRefPtr<BrowsingContextGroup> sChromeGroup;
/* static */
BrowsingContextGroup* BrowsingContextGroup::GetChromeGroup() {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
if (!sChromeGroup && XRE_IsParentProcess()) {
sChromeGroup = BrowsingContextGroup::Create();
sChromeGroup = new BrowsingContextGroup();
ClearOnShutdown(&sChromeGroup);
}
@ -259,32 +260,8 @@ void BrowsingContextGroup::RemoveDocument(const nsACString& aKey,
}
}
already_AddRefed<BrowsingContextGroup> BrowsingContextGroup::Select(
WindowContext* aParent, BrowsingContext* aOpener) {
if (aParent) {
return do_AddRef(aParent->Group());
}
if (aOpener) {
return do_AddRef(aOpener->Group());
}
return Create();
}
void BrowsingContextGroup::GetAllGroups(
nsTArray<RefPtr<BrowsingContextGroup>>& aGroups) {
aGroups.Clear();
if (!sBrowsingContextGroups) {
return;
}
aGroups.SetCapacity(sBrowsingContextGroups->Count());
for (auto& group : *sBrowsingContextGroups) {
aGroups.AppendElement(group.GetData());
}
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BrowsingContextGroup, mContexts,
mToplevels, mSubscribers,
mToplevels, mSubscribers, mCachedContexts,
mTimerEventQueue, mWorkerEventQueue)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContextGroup, AddRef)

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

@ -21,7 +21,6 @@ class ThrottledEventQueue;
namespace dom {
class BrowsingContext;
class WindowContext;
class ContentParent;
// A BrowsingContextGroup represents the Unit of Related Browsing Contexts in
@ -48,24 +47,46 @@ class BrowsingContextGroup final : public nsWrapperCache {
// Force the given ContentParent to subscribe to our BrowsingContextGroup.
void EnsureSubscribed(ContentParent* aProcess);
// Methods interacting with cached contexts.
bool IsContextCached(BrowsingContext* aContext) const;
void CacheContext(BrowsingContext* aContext);
void CacheContexts(const BrowsingContext::Children& aContexts);
bool EvictCachedContext(BrowsingContext* aContext);
// Get a reference to the list of toplevel contexts in this
// BrowsingContextGroup.
nsTArray<RefPtr<BrowsingContext>>& Toplevels() { return mToplevels; }
void GetToplevels(nsTArray<RefPtr<BrowsingContext>>& aToplevels) {
BrowsingContext::Children& Toplevels() { return mToplevels; }
void GetToplevels(BrowsingContext::Children& aToplevels) {
aToplevels.AppendElements(mToplevels);
}
uint64_t Id() { return mId; }
nsISupports* GetParentObject() const;
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// Get or create a BrowsingContextGroup with the given ID.
static already_AddRefed<BrowsingContextGroup> GetOrCreate(uint64_t aId);
static already_AddRefed<BrowsingContextGroup> Create();
BrowsingContextGroup();
static already_AddRefed<BrowsingContextGroup> Select(
WindowContext* aParent, BrowsingContext* aOpener);
BrowsingContext* aParent, BrowsingContext* aOpener) {
if (aParent) {
return do_AddRef(aParent->Group());
}
if (aOpener) {
return do_AddRef(aOpener->Group());
}
return MakeAndAddRef<BrowsingContextGroup>();
}
static already_AddRefed<BrowsingContextGroup> Select(uint64_t aParentId,
uint64_t aOpenerId) {
RefPtr<BrowsingContext> parent = BrowsingContext::Get(aParentId);
MOZ_RELEASE_ASSERT(parent || aParentId == 0);
RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerId);
MOZ_RELEASE_ASSERT(opener || aOpenerId == 0);
return Select(parent, opener);
}
// For each 'ContentParent', except for 'aExcludedParent',
// associated with this group call 'aCallback'.
@ -114,25 +135,20 @@ class BrowsingContextGroup final : public nsWrapperCache {
return mWorkerEventQueue;
}
static void GetAllGroups(nsTArray<RefPtr<BrowsingContextGroup>>& aGroups);
private:
friend class CanonicalBrowsingContext;
explicit BrowsingContextGroup(uint64_t aId);
~BrowsingContextGroup();
void UnsubscribeAllContentParents();
uint64_t mId;
// A BrowsingContextGroup contains a series of BrowsingContext objects. They
// are addressed using a hashtable to avoid linear lookup when adding or
// removing elements from the set.
nsTHashtable<nsRefPtrHashKey<BrowsingContext>> mContexts;
// The set of toplevel browsing contexts in the current BrowsingContextGroup.
nsTArray<RefPtr<BrowsingContext>> mToplevels;
BrowsingContext::Children mToplevels;
// DocGroups are thread-safe, and not able to be cycle collected,
// but we still keep strong pointers. When all Documents are removed
@ -142,6 +158,9 @@ class BrowsingContextGroup final : public nsWrapperCache {
ContentParents mSubscribers;
// Map of cached contexts that need to stay alive due to bfcache.
nsTHashtable<nsRefPtrHashKey<BrowsingContext>> mCachedContexts;
// A queue to store postMessage events during page load, the queue will be
// flushed once the page is loaded
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;

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

@ -33,14 +33,14 @@ extern mozilla::LazyLogModule gUserInteractionPRLog;
#define USER_ACTIVATION_LOG(msg, ...) \
MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
CanonicalBrowsingContext::CanonicalBrowsingContext(WindowContext* aParentWindow,
CanonicalBrowsingContext::CanonicalBrowsingContext(BrowsingContext* aParent,
BrowsingContextGroup* aGroup,
uint64_t aBrowsingContextId,
uint64_t aOwnerProcessId,
uint64_t aEmbedderProcessId,
BrowsingContext::Type aType,
FieldTuple&& aFields)
: BrowsingContext(aParentWindow, aGroup, aBrowsingContextId, aType,
: BrowsingContext(aParent, aGroup, aBrowsingContextId, aType,
std::move(aFields)),
mProcessId(aOwnerProcessId),
mEmbedderProcessId(aEmbedderProcessId) {

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

@ -134,7 +134,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
void CanonicalDiscard();
using Type = BrowsingContext::Type;
CanonicalBrowsingContext(WindowContext* aParentWindow,
CanonicalBrowsingContext(BrowsingContext* aParent,
BrowsingContextGroup* aGroup,
uint64_t aBrowsingContextId,
uint64_t aOwnerProcessId,

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

@ -45,43 +45,10 @@ WindowGlobalParent* WindowContext::Canonical() {
return static_cast<WindowGlobalParent*>(this);
}
bool WindowContext::IsCached() const {
return mBrowsingContext->mCurrentWindowContext != this;
}
nsIGlobalObject* WindowContext::GetParentObject() const {
return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
}
void WindowContext::AppendChildBrowsingContext(
BrowsingContext* aBrowsingContext) {
MOZ_DIAGNOSTIC_ASSERT(Group() == aBrowsingContext->Group(),
"Mismatched groups?");
MOZ_DIAGNOSTIC_ASSERT(!mChildren.Contains(aBrowsingContext));
mChildren.AppendElement(aBrowsingContext);
// If we're the current WindowContext in our BrowsingContext, make sure to
// clear any cached `children` value.
if (!IsCached()) {
BrowsingContext_Binding::ClearCachedChildrenValue(mBrowsingContext);
}
}
void WindowContext::RemoveChildBrowsingContext(
BrowsingContext* aBrowsingContext) {
MOZ_DIAGNOSTIC_ASSERT(Group() == aBrowsingContext->Group(),
"Mismatched groups?");
mChildren.RemoveElement(aBrowsingContext);
// If we're the current WindowContext in our BrowsingContext, make sure to
// clear any cached `children` value.
if (!IsCached()) {
BrowsingContext_Binding::ClearCachedChildrenValue(mBrowsingContext);
}
}
void WindowContext::SendCommitTransaction(ContentParent* aParent,
const BaseTransaction& aTxn,
uint64_t aEpoch) {
@ -193,13 +160,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WindowContext)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildren)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WindowContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(WindowContext)

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

@ -7,7 +7,6 @@
#ifndef mozilla_dom_WindowContext_h
#define mozilla_dom_WindowContext_h
#include "mozilla/Span.h"
#include "mozilla/dom/MaybeDiscarded.h"
#include "mozilla/dom/SyncedContext.h"
#include "mozilla/net/NeckoChannelParams.h"
@ -15,8 +14,6 @@
namespace mozilla {
namespace dom {
class WindowGlobalParent;
#define MOZ_EACH_WC_FIELD(FIELD) \
FIELD(OuterWindowId, uint64_t) \
FIELD(CookieJarSettings, Maybe<mozilla::net::CookieJarSettingsArgs>) \
@ -39,10 +36,6 @@ class WindowContext : public nsISupports, public nsWrapperCache {
uint64_t OuterWindowId() const { return GetOuterWindowId(); }
bool IsDiscarded() const { return mIsDiscarded; }
bool IsCached() const;
Span<RefPtr<BrowsingContext>> Children() { return mChildren; }
// Cast this object to it's parent-process canonical form.
WindowGlobalParent* Canonical();
@ -57,12 +50,6 @@ class WindowContext : public nsISupports, public nsWrapperCache {
uint64_t mBrowsingContextId;
FieldTuple mFields;
bool operator==(const IPCInitializer& aOther) const {
return mInnerWindowId == aOther.mInnerWindowId &&
mBrowsingContextId == aOther.mBrowsingContextId &&
mFields == aOther.mFields;
}
};
IPCInitializer GetIPCInitializer() {
return {mInnerWindowId, mBrowsingContext->Id(), mFields.Fields()};
@ -79,11 +66,6 @@ class WindowContext : public nsISupports, public nsWrapperCache {
void Init();
private:
friend class BrowsingContext;
void AppendChildBrowsingContext(BrowsingContext* aBrowsingContext);
void RemoveChildBrowsingContext(BrowsingContext* aBrowsingContext);
// Send a given `BaseTransaction` object to the correct remote.
void SendCommitTransaction(ContentParent* aParent,
const BaseTransaction& aTxn, uint64_t aEpoch);
@ -118,12 +100,6 @@ class WindowContext : public nsISupports, public nsWrapperCache {
uint64_t mInnerWindowId;
RefPtr<BrowsingContext> mBrowsingContext;
// --- NEVER CHANGE `mChildren` DIRECTLY! ---
// Changes to this list need to be synchronized to the list within our
// `mBrowsingContext`, and should only be performed through the
// `AppendChildBrowsingContext` and `RemoveChildBrowsingContext` methods.
nsTArray<RefPtr<BrowsingContext>> mChildren;
bool mIsDiscarded = false;
};

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

@ -7145,6 +7145,12 @@ nsresult nsDocShell::RestoreFromHistory() {
// Order the mContentViewer setup just like Embed does.
mContentViewer = nullptr;
if (!mWillChangeProcess) {
// Move the browsing context's children to the cache. If we're
// detaching them, we'll detach them from there.
mBrowsingContext->CacheChildren();
}
// Now that we're about to switch documents, forget all of our children.
// Note that we cached them as needed up in CaptureState above.
DestroyChildren();
@ -7263,6 +7269,7 @@ nsresult nsDocShell::RestoreFromHistory() {
// <head> is parsed.
document->NotifyPossibleTitleChange(false);
BrowsingContext::Children contexts(childShells.Count());
// Now we simulate appending child docshells for subframes.
for (i = 0; i < childShells.Count(); ++i) {
nsIDocShellTreeItem* childItem = childShells.ObjectAt(i);
@ -7299,6 +7306,8 @@ nsresult nsDocShell::RestoreFromHistory() {
// child inherits our mPrivateBrowsingId, which is what we want.
AddChild(childItem);
contexts.AppendElement(childShell->GetBrowsingContext());
childShell->SetAllowJavascript(allowJavascript);
childShell->SetAllowMetaRedirects(allowRedirects);
childShell->SetAllowSubframes(allowSubframes);
@ -7314,6 +7323,10 @@ nsresult nsDocShell::RestoreFromHistory() {
NS_ENSURE_SUCCESS(rv, rv);
}
if (!contexts.IsEmpty()) {
mBrowsingContext->RestoreChildren(std::move(contexts));
}
// Make sure to restore the window state after adding the child shells back
// to the tree. This is necessary for Thaw() and Resume() to propagate
// properly.
@ -7866,6 +7879,10 @@ nsresult nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer,
mContentViewer = nullptr;
// Move the browsing ontext's children to the cache. If we're
// detaching them, we'll detach them from there.
mBrowsingContext->CacheChildren();
// Now that we're about to switch documents, forget all of our children.
// Note that we cached them as needed up in CaptureState above.
DestroyChildren();

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

@ -386,7 +386,7 @@ nsresult nsSHistory::WalkHistoryEntries(nsISHEntry* aRootEntry,
BrowsingContext* childBC = nullptr;
if (aBC) {
for (BrowsingContext* child : aBC->Children()) {
for (BrowsingContext* child : aBC->GetChildren()) {
// If the SH pref is on, or we are in the parent process, update
// canonical BC directly
if (StaticPrefs::fission_sessionHistoryInParent() ||

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

@ -2217,12 +2217,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
cb.NoteXPCOMChild(it.Key());
CycleCollectionNoteChild(cb, it.UserData(), "mL10nProtoElements value");
}
for (size_t i = 0; i < tmp->mPendingFrameStaticClones.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingFrameStaticClones[i].mElement);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
mPendingFrameStaticClones[i].mStaticCloneOf);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_CLASS(Document)
@ -2348,8 +2342,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
mql = next;
}
tmp->mPendingFrameStaticClones.Clear();
tmp->mInUnlinkOrDeletion = false;
if (tmp->mResizeObserverController) {
@ -10459,7 +10451,7 @@ bool Document::CanSavePresentation(nsIRequest* aNewRequest,
// BFCache is currently not compatible with remote subframes (bug 1609324)
if (RefPtr<BrowsingContext> browsingContext = GetBrowsingContext()) {
for (auto& child : browsingContext->Children()) {
for (auto& child : browsingContext->GetChildren()) {
if (!child->IsInProcess()) {
aBFCacheCombo |= BFCacheStatus::CONTAINS_REMOTE_SUBFRAMES;
ret = false;
@ -11158,7 +11150,7 @@ void Document::NotifyLoading(bool aNewParentIsLoading,
// readystates of the subdocument. In the child process it will call
// NotifyLoading() to notify the innerwindow/TimeoutManager, and then
// iterate it's children
for (auto& child : context->Children()) {
for (auto& child : context->GetChildren()) {
MOZ_LOG(gTimeoutDeferralLog, mozilla::LogLevel::Debug,
("bc: %p SetAncestorLoading(%d)", (void*)child, is_loading));
child->SetAncestorLoading(is_loading);
@ -16297,19 +16289,5 @@ bool Document::HasRecentlyStartedForegroundLoads() {
return false;
}
nsTArray<Document::PendingFrameStaticClone>
Document::TakePendingFrameStaticClones() {
MOZ_ASSERT(mIsStaticDocument,
"Cannot have pending frame static clones in non-static documents");
return std::move(mPendingFrameStaticClones);
}
void Document::AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
nsFrameLoader* aStaticCloneOf) {
PendingFrameStaticClone* clone = mPendingFrameStaticClones.AppendElement();
clone->mElement = aElement;
clone->mStaticCloneOf = aStaticCloneOf;
}
} // namespace dom
} // namespace mozilla

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

@ -87,7 +87,6 @@ class nsContentList;
class nsDocShell;
class nsDOMNavigationTiming;
class nsFrameLoader;
class nsFrameLoaderOwner;
class nsGlobalWindowInner;
class nsHtml5TreeOpExecutor;
class nsHTMLCSSStyleSheet;
@ -3906,20 +3905,6 @@ class Document : public nsINode,
already_AddRefed<Promise> AddCertException(bool aIsTemporary);
// Subframes need to be static cloned after the main document has been
// embedded within a script global. A `PendingFrameStaticClone` is a static
// clone which has not yet been performed.
//
// The getter returns a direct reference to an internal array which is
// manipulated from within printing code.
struct PendingFrameStaticClone {
RefPtr<nsFrameLoaderOwner> mElement;
RefPtr<nsFrameLoader> mStaticCloneOf;
};
nsTArray<PendingFrameStaticClone> TakePendingFrameStaticClones();
void AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
nsFrameLoader* aStaticCloneOf);
protected:
void DoUpdateSVGUseElementShadowTrees();
@ -4971,8 +4956,6 @@ class Document : public nsINode,
nsTArray<nsCOMPtr<nsIRunnable>> mFrameLoaderFinalizers;
RefPtr<nsRunnableMethod<Document>> mFrameLoaderRunner;
nsTArray<PendingFrameStaticClone> mPendingFrameStaticClones;
// The layout history state that should be used by nodes in this
// document. We only actually store a pointer to it when:
// 1) We have no script global object.

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

@ -95,7 +95,7 @@ bool RemoteOuterWindowProxy::getOwnPropertyDescriptor(
BrowsingContext* bc = GetBrowsingContext(aProxy);
uint32_t index = GetArrayIndexFromId(aId);
if (IsArrayIndex(index)) {
Span<RefPtr<BrowsingContext>> children = bc->Children();
const BrowsingContext::Children& children = bc->GetChildren();
if (index < children.Length()) {
return WrapResult(aCx, aProxy, children[index],
JSPROP_READONLY | JSPROP_ENUMERATE, aDesc);
@ -120,7 +120,7 @@ bool RemoteOuterWindowProxy::getOwnPropertyDescriptor(
return false;
}
for (BrowsingContext* child : bc->Children()) {
for (BrowsingContext* child : bc->GetChildren()) {
if (child->NameEquals(str)) {
return WrapResult(aCx, aProxy, child, JSPROP_READONLY, aDesc);
}
@ -132,7 +132,7 @@ bool RemoteOuterWindowProxy::getOwnPropertyDescriptor(
bool AppendIndexedPropertyNames(JSContext* aCx, BrowsingContext* aContext,
JS::MutableHandleVector<jsid> aIndexedProps) {
int32_t length = aContext->Children().Length();
int32_t length = aContext->GetChildren().Length();
if (!aIndexedProps.reserve(aIndexedProps.length() + length)) {
return false;
}

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

@ -169,7 +169,7 @@ bool WindowNamedPropertiesHandler::ownPropNames(
nsGlobalWindowOuter* outer = win->GetOuterWindowInternal();
if (outer) {
if (BrowsingContext* bc = outer->GetBrowsingContext()) {
for (const auto& child : bc->Children()) {
for (const auto& child : bc->GetChildren()) {
const nsString& name = child->Name();
if (!name.IsEmpty() && !names.Contains(name)) {
// Make sure we really would expose it from getOwnPropDescriptor.

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

@ -564,7 +564,9 @@ void AutoSuppressEventHandlingAndSuspend::SuppressBrowsingContext(
}
}
for (const auto& bc : aBC->Children()) {
BrowsingContext::Children children;
aBC->GetChildren(children);
for (const auto& bc : children) {
SuppressBrowsingContext(bc);
}
}

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

@ -148,7 +148,7 @@ typedef ScrollableLayerGuid::ViewID ViewID;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFrameLoader, mPendingBrowsingContext,
mMessageManager, mChildMessageManager,
mRemoteBrowser)
mRemoteBrowser, mStaticCloneOf)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
@ -274,18 +274,24 @@ 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");
}
RefPtr<nsGlobalWindowInner> parentInner =
nsGlobalWindowInner::Cast(aOwner->OwnerDoc()->GetInnerWindow());
if (NS_WARN_IF(!parentInner) || parentInner->IsDying()) {
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<nsDocShell> parentDocShell = nsDocShell::Cast(doc->GetDocShell());
if (NS_WARN_IF(!parentDocShell)) {
return nullptr;
}
BrowsingContext* parentBC = parentInner->GetBrowsingContext();
if (NS_WARN_IF(!parentBC) || parentBC->IsDiscarded()) {
RefPtr<BrowsingContext> parentContext = parentDocShell->GetBrowsingContext();
// Don't create a child docshell for a discarded browsing context.
if (NS_WARN_IF(!parentContext) || parentContext->IsDiscarded()) {
return nullptr;
}
@ -299,7 +305,7 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
// currently active. And in that latter case, if we try to attach our BC now,
// it will wind up attached as a child of the currently active inner window
// for the BrowsingContext, and cause no end of trouble.
if (IsTopContent(parentBC, aOwner)) {
if (IsTopContent(parentContext, aOwner)) {
// Create toplevel content without a parent & as Type::Content.
return BrowsingContext::CreateDetached(nullptr, opener, frameName,
BrowsingContext::Type::Content);
@ -308,8 +314,11 @@ static already_AddRefed<BrowsingContext> CreateBrowsingContext(
MOZ_ASSERT(!aOpenWindowInfo,
"Can't have openWindowInfo for non-toplevel context");
return BrowsingContext::CreateDetached(parentInner, nullptr, frameName,
parentBC->GetType());
auto type = parentContext->IsContent() ? BrowsingContext::Type::Content
: BrowsingContext::Type::Chrome;
return BrowsingContext::CreateDetached(parentContext, nullptr, frameName,
type);
}
static bool InitialLoadIsRemote(Element* aOwner) {
@ -818,7 +827,7 @@ void nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
static bool AllDescendantsOfType(BrowsingContext* aParent,
BrowsingContext::Type aType) {
for (auto& child : aParent->Children()) {
for (auto& child : aParent->GetChildren()) {
if (child->GetType() != aType || !AllDescendantsOfType(child, aType)) {
return false;
}
@ -2710,51 +2719,48 @@ void nsFrameLoader::ActivateFrameEvent(const nsAString& aType, bool aCapture,
}
}
nsresult nsFrameLoader::FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsIDocShell** aCloneDocShell,
Document** aCloneDocument) {
MOZ_DIAGNOSTIC_ASSERT(
!nsContentUtils::IsSafeToRunScript(),
"A script blocker should be on the stack while FinishStaticClone is run");
// NOTE: We don't check `aStaticCloneOf->IsDead()` here, as the nsFrameLoader
// which we're a static clone of may be in the process of being destroyed. It
// won't be fully destroyed when `FinishStaticClone` is called, as a script
// blocker on our caller's stack is preventing it from becoming finalized.
//
// This is quite fragile, but is quite difficult to work around without
// getting print-preview to stop re-cloning and replacing the previewed
// document when changing layout.
if (NS_WARN_IF(IsDead())) {
return NS_ERROR_UNEXPECTED;
}
if (NS_WARN_IF(aStaticCloneOf->IsRemoteFrame())) {
nsresult nsFrameLoader::CreateStaticClone(nsFrameLoader* aDest) {
if (NS_WARN_IF(IsRemoteFrame())) {
return NS_ERROR_NOT_IMPLEMENTED;
}
MaybeCreateDocShell();
RefPtr<nsDocShell> docShell = GetDocShell();
NS_ENSURE_STATE(docShell);
aDest->mPendingBrowsingContext->EnsureAttached();
nsCOMPtr<Document> kungFuDeathGrip = docShell->GetDocument();
// Ensure that the embedder element is set correctly.
aDest->mPendingBrowsingContext->SetEmbedderElement(aDest->mOwnerContent);
aDest->mPendingBrowsingContext->Embed();
aDest->mStaticCloneOf = this;
return NS_OK;
}
nsresult nsFrameLoader::FinishStaticClone() {
// After cloning is complete, discard the reference to the original
// nsFrameLoader, as it is no longer needed.
auto exitGuard = MakeScopeExit([&] { mStaticCloneOf = nullptr; });
if (NS_WARN_IF(!mStaticCloneOf || IsDead())) {
return NS_ERROR_UNEXPECTED;
}
MaybeCreateDocShell();
NS_ENSURE_STATE(GetDocShell());
nsCOMPtr<Document> kungFuDeathGrip = GetDocShell()->GetDocument();
Unused << kungFuDeathGrip;
nsCOMPtr<nsIContentViewer> viewer;
docShell->GetContentViewer(getter_AddRefs(viewer));
GetDocShell()->GetContentViewer(getter_AddRefs(viewer));
NS_ENSURE_STATE(viewer);
nsIDocShell* origDocShell = aStaticCloneOf->GetDocShell(IgnoreErrors());
nsIDocShell* origDocShell = mStaticCloneOf->GetDocShell(IgnoreErrors());
NS_ENSURE_STATE(origDocShell);
nsCOMPtr<Document> doc = origDocShell->GetDocument();
NS_ENSURE_STATE(doc);
nsCOMPtr<Document> clonedDoc = doc->CreateStaticClone(docShell);
nsCOMPtr<Document> clonedDoc = doc->CreateStaticClone(GetDocShell());
viewer->SetDocument(clonedDoc);
docShell.forget(aCloneDocShell);
clonedDoc.forget(aCloneDocument);
return NS_OK;
}

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

@ -133,19 +133,17 @@ class nsFrameLoader final : public nsStubMutationObserver,
nsresult UpdatePositionAndSize(nsSubDocumentFrame* aIFrame);
void SendIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement);
// When creating a nsFrameLoaderOwner which is a static clone, a
// `nsFrameLoader` is not immediately attached to it. Instead, it is added to
// the static clone document's `PendingFrameStaticClones` list.
// When creating a nsFrameLoader which is a static clone, two methods are
// called at different stages. The `CreateStaticClone` method is first called
// on the source nsFrameLoader, passing in the destination frameLoader as the
// `aDest` argument. This is done during the static clone operation on the
// original document.
//
// After the parent document has been fully cloned, a new frameloader will be
// created for the cloned iframe, and `FinishStaticClone` will be called on
// it, which will clone the inner document of the source nsFrameLoader.
//
// The `aCloneDocShell` and `aCloneDocument` outparameters will be filled with
// the values from the newly cloned subframe.
nsresult FinishStaticClone(nsFrameLoader* aStaticCloneOf,
nsIDocShell** aCloneDocShell,
Document** aCloneDocument);
// After the original document's clone is complete, the `FinishStaticClone`
// method is called on the target nsFrameLoader, which clones the inner
// document of the source nsFrameLoader.
nsresult CreateStaticClone(nsFrameLoader* aDest);
nsresult FinishStaticClone();
// WebIDL methods
@ -488,6 +486,10 @@ class nsFrameLoader final : public nsStubMutationObserver,
// a reframe, so that we know not to restore the presentation.
RefPtr<Document> mContainerDocWhileDetached;
// When performing a static clone, this holds the other nsFrameLoader which
// this object is a static clone of.
RefPtr<nsFrameLoader> mStaticCloneOf;
// When performing a process switch, this value is used rather than mURIToLoad
// to identify the process-switching load which should be resumed in the
// target process.

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

@ -5391,7 +5391,10 @@ CallState nsGlobalWindowInner::CallOnInProcessChildren(Method aMethod,
return state;
}
for (const RefPtr<BrowsingContext>& bc : GetBrowsingContext()->Children()) {
BrowsingContext::Children children;
GetBrowsingContext()->GetChildren(children);
for (const RefPtr<BrowsingContext>& bc : children) {
nsCOMPtr<nsPIDOMWindowOuter> pWin = bc->GetDOMWindow();
if (!pWin) {
continue;

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

@ -3424,7 +3424,7 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
BrowsingContext* bc = GetBrowsingContext();
NS_ENSURE_TRUE(bc, nullptr);
Span<RefPtr<BrowsingContext>> children = bc->Children();
const BrowsingContext::Children& children = bc->GetChildren();
if (aIndex < children.Length()) {
return WindowProxyHolder(children[aIndex]);
}
@ -4192,7 +4192,7 @@ double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
uint32_t nsGlobalWindowOuter::Length() {
BrowsingContext* bc = GetBrowsingContext();
return bc ? bc->Children().Length() : 0;
return bc ? bc->GetChildren().Length() : 0;
}
Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {

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

@ -2537,15 +2537,18 @@ void nsObjectLoadingContent::CreateStaticClone(
if (thisObj->mPrintFrame.IsAlive()) {
aDest->mPrintFrame = thisObj->mPrintFrame;
} else {
aDest->mPrintFrame = thisObj->GetExistingFrame();
aDest->mPrintFrame =
const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame();
}
if (mFrameLoader) {
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
Document* doc = content->OwnerDoc();
if (doc->IsStaticDocument()) {
doc->AddPendingFrameStaticClone(aDest, mFrameLoader);
RefPtr<nsFrameLoader> fl =
nsFrameLoader::Create(content->AsElement(), false);
if (fl) {
aDest->mFrameLoader = fl;
mFrameLoader->CreateStaticClone(fl);
}
}
}

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

@ -68,7 +68,7 @@ static nsresult AddNonJSSizeOfWindowAndItsDescendents(
}
// Measure this window's descendents.
for (const auto& frame : bc->Children()) {
for (const auto& frame : bc->GetChildren()) {
if (auto* childWin = nsGlobalWindowOuter::Cast(frame->GetDOMWindow())) {
MOZ_TRY(AddNonJSSizeOfWindowAndItsDescendents(childWin, aSizes));
}

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

@ -121,7 +121,7 @@ Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() {
}
void nsGenericHTMLFrameElement::EnsureFrameLoader() {
if (!IsInComposedDoc() || mFrameLoader || OwnerDoc()->IsStaticDocument()) {
if (!IsInComposedDoc() || mFrameLoader) {
// If frame loader is there, we just keep it around, cached
return;
}
@ -320,7 +320,10 @@ nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
if (doc->IsStaticDocument() && mFrameLoader) {
nsGenericHTMLFrameElement* dest =
static_cast<nsGenericHTMLFrameElement*>(aDest);
doc->AddPendingFrameStaticClone(dest, mFrameLoader);
RefPtr<nsFrameLoader> fl = nsFrameLoader::Create(dest, false);
NS_ENSURE_STATE(fl);
dest->mFrameLoader = fl;
mFrameLoader->CreateStaticClone(fl);
}
return rv;

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

@ -4066,19 +4066,56 @@ void BrowserParent::OnSubFrameCrashed() {
if (mBrowsingContext->IsDiscarded()) {
return;
}
BrowserBridgeParent* bridge = GetBrowserBridgeParent();
if (!bridge || !bridge->CanSend()) {
auto processId = Manager()->ChildID();
BrowsingContext* parent = mBrowsingContext->GetParent();
ContentParent* embedderProcess = parent->Canonical()->GetContentParent();
if (!embedderProcess) {
return;
}
// Set the owner process of the root context belonging to a crashed process to
// the embedding process, since we'll be showing the crashed page in that
// process.
mBrowsingContext->SetOwnerProcessId(bridge->Manager()->Manager()->ChildID());
mBrowsingContext->SetCurrentInnerWindowId(0);
ContentParent* manager = Manager();
// Set the owner process of a browsing context belonging to a
// crashed process to the parent context's process, since
// we'll be showing the crashed page in that process.
mBrowsingContext->SetOwnerProcessId(embedderProcess->ChildID());
// Find all same process sub tree nodes and detach them, cache all
// other nodes in the sub tree.
mBrowsingContext->PostOrderWalk([&](auto* aContext) {
// By iterating in reverse we can deal with detach removing the child that
// we're currently on
for (auto it = aContext->GetChildren().rbegin();
it != aContext->GetChildren().rend(); it++) {
RefPtr<BrowsingContext> context = *it;
if (context->Canonical()->IsOwnedByProcess(processId)) {
// Hold a reference to `context` until the response comes back to
// ensure it doesn't die while messages relating to this context are
// in-flight.
auto resolve = [context](bool) {};
auto reject = [context](ResponseRejectReason) {};
context->Group()->EachOtherParent(manager, [&](auto* aParent) {
aParent->SendDetachBrowsingContext(context->Id(), resolve, reject);
});
context->Detach(/* aFromIPC */ true);
}
}
// Cache all the children not owned by crashing process. Note that
// all remaining children are out of process, which makes it ok to
// just cache.
aContext->Group()->EachOtherParent(manager, [&](auto* aParent) {
Unused << aParent->SendCacheBrowsingContextChildren(aContext);
});
aContext->CacheChildren(/* aFromIPC */ true);
});
MOZ_DIAGNOSTIC_ASSERT(!mBrowsingContext->GetChildren().Length());
// Tell the browser bridge to show the subframe crashed page.
Unused << bridge->SendSubFrameCrashed(mBrowsingContext);
if (GetBrowserBridgeParent()) {
Unused << GetBrowserBridgeParent()->SendSubFrameCrashed(mBrowsingContext);
}
}
mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingProtectedMedia(

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

@ -2201,6 +2201,8 @@ void ContentChild::ActorDestroy(ActorDestroyReason why) {
mIdleObservers.Clear();
mBrowsingContextGroupHolder.Clear();
nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
if (svc) {
svc->UnregisterListener(mConsoleListener);
@ -3612,81 +3614,106 @@ PContentChild::Result ContentChild::OnMessageReceived(const Message& aMsg,
return result;
}
mozilla::ipc::IPCResult ContentChild::RecvCreateBrowsingContext(
uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
// We can't already have a BrowsingContext with this ID.
if (RefPtr<BrowsingContext> existing = BrowsingContext::Get(aInit.mId)) {
return IPC_FAIL(this, "Browsing context already exists");
mozilla::ipc::IPCResult ContentChild::RecvAttachBrowsingContext(
BrowsingContext::IPCInitializer&& aInit) {
RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
MOZ_RELEASE_ASSERT(!child || child->IsCached());
if (!child) {
// Determine the BrowsingContextGroup from our parent or opener fields.
RefPtr<BrowsingContextGroup> group =
BrowsingContextGroup::Select(aInit.mParentId, aInit.GetOpenerId());
child = BrowsingContext::CreateFromIPC(std::move(aInit), group, nullptr);
}
RefPtr<WindowContext> parent = WindowContext::GetById(aInit.mParentId);
if (!parent && aInit.mParentId != 0) {
// Handle this case by ignoring the request, as parent must be in the
// process of being discarded.
// In the future it would be nice to avoid sending this message to the child
// at all.
NS_WARNING("Attempt to attach BrowsingContext to discarded parent");
return IPC_OK();
}
child->Attach(/* aFromIPC */ true);
RefPtr<BrowsingContextGroup> group =
BrowsingContextGroup::GetOrCreate(aGroupId);
BrowsingContext::CreateFromIPC(std::move(aInit), group, nullptr);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvDiscardBrowsingContext(
const MaybeDiscarded<BrowsingContext>& aContext,
DiscardBrowsingContextResolver&& aResolve) {
if (!aContext.IsNullOrDiscarded()) {
aContext.get()->Detach(/* aFromIPC */ true);
mozilla::ipc::IPCResult ContentChild::RecvDetachBrowsingContext(
uint64_t aContextId, DetachBrowsingContextResolver&& aResolve) {
// NOTE: Immediately resolve the promise, as we've received the message. This
// will allow the parent process to discard references to this BC.
aResolve(true);
// If we can't find a BrowsingContext with the given ID, it's already been
// collected and we can ignore the request.
RefPtr<BrowsingContext> context = BrowsingContext::Get(aContextId);
if (context) {
context->Detach(/* aFromIPC */ true);
}
// Immediately resolve the promise, as we've received the message. This will
// allow the parent process to discard references to this BC.
aResolve(true);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvCacheBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext) {
if (aContext.IsNullOrDiscarded()) {
return IPC_OK();
}
aContext.get()->CacheChildren(/* aFromIPC */ true);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvRestoreBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext,
const nsTArray<MaybeDiscarded<BrowsingContext>>& aChildren) {
if (aContext.IsNullOrDiscarded()) {
return IPC_OK();
}
nsTArray<RefPtr<BrowsingContext>> children(aChildren.Length());
for (const auto& child : aChildren) {
if (!child.IsNullOrDiscarded()) {
children.AppendElement(child.get());
}
}
aContext.get()->RestoreChildren(std::move(children), /* aFromIPC */ true);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvRegisterBrowsingContextGroup(
uint64_t aGroupId, nsTArray<SyncedContextInitializer>&& aInits) {
RefPtr<BrowsingContextGroup> group =
BrowsingContextGroup::GetOrCreate(aGroupId);
nsTArray<BrowsingContext::IPCInitializer>&& aInits,
nsTArray<WindowContext::IPCInitializer>&& aWindowInits) {
RefPtr<BrowsingContextGroup> group = new BrowsingContextGroup();
// Each of the initializers in aInits is sorted in pre-order, so our parent
// should always be available before the element itself.
for (auto& initUnion : aInits) {
switch (initUnion.type()) {
case SyncedContextInitializer::TBrowsingContextInitializer: {
auto& init = initUnion.get_BrowsingContextInitializer();
for (auto& init : aInits) {
#ifdef DEBUG
RefPtr<BrowsingContext> existing = BrowsingContext::Get(init.mId);
MOZ_ASSERT(!existing, "BrowsingContext must not exist yet!");
RefPtr<BrowsingContext> existing = BrowsingContext::Get(init.mId);
MOZ_ASSERT(!existing, "BrowsingContext must not exist yet!");
RefPtr<WindowContext> parent = init.GetParent();
MOZ_ASSERT_IF(parent, parent->Group() == group);
RefPtr<BrowsingContext> parent = init.GetParent();
MOZ_ASSERT_IF(parent, parent->Group() == group);
#endif
bool cached = init.mCached;
RefPtr<BrowsingContext> ctxt =
BrowsingContext::CreateFromIPC(std::move(init), group, nullptr);
break;
}
case SyncedContextInitializer::TWindowContextInitializer: {
auto& init = initUnion.get_WindowContextInitializer();
// If the browsing context is cached don't attach it, but add it
// to the cache here as well
if (cached) {
ctxt->Group()->CacheContext(ctxt);
} else {
ctxt->Attach(/* aFromIPC */ true);
}
}
for (auto& init : aWindowInits) {
#ifdef DEBUG
RefPtr<WindowContext> existing =
WindowContext::GetById(init.mInnerWindowId);
MOZ_ASSERT(!existing, "WindowContext must not exist yet!");
RefPtr<BrowsingContext> parent =
BrowsingContext::Get(init.mBrowsingContextId);
MOZ_ASSERT(parent && parent->Group() == group);
RefPtr<WindowContext> existing =
WindowContext::GetById(init.mInnerWindowId);
MOZ_ASSERT(!existing, "WindowContext must not exist yet!");
RefPtr<BrowsingContext> parent =
BrowsingContext::Get(init.mBrowsingContextId);
MOZ_ASSERT(parent && parent->Group() == group);
#endif
WindowContext::CreateFromIPC(std::move(init));
break;
};
default:
MOZ_ASSERT_UNREACHABLE();
}
WindowContext::CreateFromIPC(std::move(init));
}
return IPC_OK();
@ -3981,16 +4008,6 @@ mozilla::ipc::IPCResult ContentChild::RecvCommitWindowContextTransaction(
mozilla::ipc::IPCResult ContentChild::RecvCreateWindowContext(
WindowContext::IPCInitializer&& aInit) {
RefPtr<BrowsingContext> bc = BrowsingContext::Get(aInit.mBrowsingContextId);
if (!bc) {
// Handle this case by ignoring the request, as bc must be in the process of
// being discarded.
// In the future it would be nice to avoid sending this message to the child
// at all.
NS_WARNING("Attempt to attach WindowContext to discarded parent");
return IPC_OK();
}
WindowContext::CreateFromIPC(std::move(aInit));
return IPC_OK();
}
@ -4009,6 +4026,14 @@ mozilla::ipc::IPCResult ContentChild::RecvDiscardWindowContext(
return IPC_OK();
}
void ContentChild::HoldBrowsingContextGroup(BrowsingContextGroup* aBCG) {
mBrowsingContextGroupHolder.AppendElement(aBCG);
}
void ContentChild::ReleaseBrowsingContextGroup(BrowsingContextGroup* aBCG) {
mBrowsingContextGroupHolder.RemoveElement(aBCG);
}
mozilla::ipc::IPCResult ContentChild::RecvScriptError(
const nsString& aMessage, const nsString& aSourceName,
const nsString& aSourceLine, const uint32_t& aLineNumber,

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

@ -691,6 +691,10 @@ class ContentChild final
PFileDescriptorSetChild* SendPFileDescriptorSetConstructor(
const FileDescriptor& aFD) override;
const nsTArray<RefPtr<BrowsingContextGroup>>& BrowsingContextGroups() const {
return mBrowsingContextGroupHolder;
}
private:
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
void StartForceKillTimer();
@ -706,15 +710,22 @@ class ContentChild final
virtual void OnChannelReceivedMessage(const Message& aMsg) override;
mozilla::ipc::IPCResult RecvCreateBrowsingContext(
uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit);
mozilla::ipc::IPCResult RecvAttachBrowsingContext(
BrowsingContext::IPCInitializer&& aInit);
mozilla::ipc::IPCResult RecvDiscardBrowsingContext(
mozilla::ipc::IPCResult RecvDetachBrowsingContext(
uint64_t aContextId, DetachBrowsingContextResolver&& aResolve);
mozilla::ipc::IPCResult RecvCacheBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext);
mozilla::ipc::IPCResult RecvRestoreBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext,
DiscardBrowsingContextResolver&& aResolve);
const nsTArray<MaybeDiscarded<BrowsingContext>>& aChildren);
mozilla::ipc::IPCResult RecvRegisterBrowsingContextGroup(
uint64_t aGroupId, nsTArray<SyncedContextInitializer>&& aInits);
nsTArray<BrowsingContext::IPCInitializer>&& aInits,
nsTArray<WindowContext::IPCInitializer>&& aWindowInits);
mozilla::ipc::IPCResult RecvWindowClose(
const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller);
@ -868,6 +879,8 @@ class ContentChild final
uint32_t mNetworkLinkType = 0;
nsTArray<RefPtr<BrowsingContextGroup>> mBrowsingContextGroupHolder;
// See `BrowsingContext::mEpochs` for an explanation of this field.
uint64_t mBrowsingContextFieldEpoch = 0;

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

@ -586,6 +586,8 @@ StaticAutoPtr<LinkedList<ContentParent>> ContentParent::sContentParents;
UniquePtr<SandboxBrokerPolicyFactory>
ContentParent::sSandboxBrokerPolicyFactory;
#endif
StaticAutoPtr<nsTArray<RefPtr<BrowsingContextGroup>>>
ContentParent::sBrowsingContextGroupHolder;
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
StaticAutoPtr<std::vector<std::string>> ContentParent::sMacSandboxParams;
#endif
@ -644,6 +646,9 @@ void ContentParent::StartUp() {
// child process
sCanLaunchSubprocesses = true;
sBrowsingContextGroupHolder = new nsTArray<RefPtr<BrowsingContextGroup>>();
ClearOnShutdown(&sBrowsingContextGroupHolder);
if (!XRE_IsParentProcess()) {
return;
}
@ -5895,54 +5900,56 @@ mozilla::ipc::IPCResult ContentParent::RecvSessionStorageData(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
RefPtr<WindowGlobalParent> parent;
mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
BrowsingContext::IPCInitializer&& aInit) {
RefPtr<CanonicalBrowsingContext> parent;
if (aInit.mParentId != 0) {
parent = WindowGlobalParent::GetByInnerWindowId(aInit.mParentId);
if (!parent) {
return IPC_FAIL(this, "Parent doesn't exist in parent process");
}
parent = CanonicalBrowsingContext::Get(aInit.mParentId);
MOZ_RELEASE_ASSERT(parent, "Parent doesn't exist in parent process");
}
if (parent && parent->GetContentParent() != this) {
if (parent && !parent->IsOwnedByProcess(ChildID())) {
// We're trying attach a child BrowsingContext to a parent
// WindowContext in another process. This is illegal since the
// only thing that could create that child BrowsingContext is the parent
// window's process.
return IPC_FAIL(this,
"Must create BrowsingContext from the parent's process");
}
// BrowsingContext in another process. This is illegal since the
// only thing that could create that child BrowsingContext is a
// parent docshell in the same process as that BrowsingContext.
MOZ_DIAGNOSTIC_ASSERT(false,
"Trying to attach to out of process parent context");
RefPtr<BrowsingContext> opener;
if (aInit.GetOpenerId() != 0) {
opener = BrowsingContext::Get(aInit.GetOpenerId());
if (!opener) {
return IPC_FAIL(this, "Opener doesn't exist in parent process");
}
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
("ParentIPC: Trying to attach to out of process parent context "
"0x%08" PRIx64,
aInit.mParentId));
return IPC_OK();
}
RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
if (child) {
// This is highly suspicious. BrowsingContexts should only be created once,
// so finding one indicates that someone is doing something they shouldn't.
return IPC_FAIL(this, "A BrowsingContext with this ID already exists");
if (child && !child->IsCached()) {
// This is highly suspicious. BrowsingContexts should only be
// attached at most once, but finding one indicates that someone
// is doing something they shouldn't.
MOZ_DIAGNOSTIC_ASSERT(false,
"Trying to attach already attached browsing context");
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
("ParentIPC: Trying to attach already attached 0x%08" PRIx64
" to 0x%08" PRIx64,
aInit.mId, aInit.mParentId));
return IPC_OK();
}
// Ensure that the passed-in BrowsingContextGroup is valid.
RefPtr<BrowsingContextGroup> group =
BrowsingContextGroup::GetOrCreate(aGroupId);
if (parent && parent->Group() != group) {
return IPC_FAIL(this, "Parent is not in the given group");
}
if (opener && opener->Group() != group) {
return IPC_FAIL(this, "Opener is not in the given group");
}
if (!parent && !opener && !group->Toplevels().IsEmpty()) {
return IPC_FAIL(this, "Unrelated context must be created in a new group");
if (!child) {
RefPtr<BrowsingContextGroup> group =
BrowsingContextGroup::Select(aInit.mParentId, aInit.GetOpenerId());
child = BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
}
BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
child->Attach(/* aFromIPC */ true);
child->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
Unused << aParent->SendAttachBrowsingContext(child->GetIPCInitializer());
});
return IPC_OK();
}
@ -5972,21 +5979,95 @@ bool ContentParent::CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
return true;
}
mozilla::ipc::IPCResult ContentParent::RecvDiscardBrowsingContext(
const MaybeDiscarded<BrowsingContext>& aContext,
DiscardBrowsingContextResolver&& aResolve) {
if (!aContext.IsNullOrDiscarded()) {
RefPtr<CanonicalBrowsingContext> context = aContext.get_canonical();
if (!CheckBrowsingContextEmbedder(context, "discard")) {
return IPC_FAIL(this, "Illegal Discard attempt");
}
mozilla::ipc::IPCResult ContentParent::RecvDetachBrowsingContext(
uint64_t aContextId, DetachBrowsingContextResolver&& aResolve) {
// NOTE: Immediately resolve the promise, as we've received the message. This
// will allow the content process to discard references to this BC.
aResolve(true);
context->Detach(/* aFromIPC */ true);
// NOTE: It's OK if we don't have this context anymore. It was just already
// detached, return.
RefPtr<CanonicalBrowsingContext> context =
CanonicalBrowsingContext::Get(aContextId);
if (!context || context->IsDiscarded()) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to detach already detached"));
return IPC_OK();
}
// Resolve the promise, as we've received and handled the message. This will
// allow the content process to fully-discard references to this BC.
aResolve(true);
if (!CheckBrowsingContextEmbedder(context, "detach")) {
return IPC_FAIL(this, "Illegal Detach() attempt");
}
context->Detach(/* aFromIPC */ true);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvCacheBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext) {
if (aContext.IsNullOrDiscarded()) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to cache already detached"));
return IPC_OK();
}
CanonicalBrowsingContext* context = aContext.get_canonical();
if (!CheckBrowsingContextOwnership(context, "cache")) {
// We're trying to cache a child BrowsingContext in another child
// process. This is illegal since the owner of the BrowsingContext
// is the proccess with the in-process docshell, which is tracked
// by OwnerProcessId.
return IPC_OK();
}
context->CacheChildren(/* aFromIPC */ true);
context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
Unused << aParent->SendCacheBrowsingContextChildren(context);
});
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvRestoreBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext,
nsTArray<MaybeDiscarded<BrowsingContext>>&& aChildren) {
if (aContext.IsNullOrDiscarded()) {
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
("ParentIPC: Trying to restore already detached"));
return IPC_OK();
}
CanonicalBrowsingContext* context = aContext.get_canonical();
if (!CheckBrowsingContextOwnership(context, "restore")) {
// We're trying to cache a child BrowsingContext in another child
// process. This is illegal since the owner of the BrowsingContext
// is the proccess with the in-process docshell, which is tracked
// by OwnerProcessId.
return IPC_OK();
}
// Remove any null or discarded child BrowsingContexts, creating a list with
// only active contexts.
// Modify the existing BrowsingContext as it will be passed to each other
// process using `SendRestoreBrowsingContextChildren`.
nsTArray<RefPtr<BrowsingContext>> children(aChildren.Length());
aChildren.RemoveElementsBy(
[&](const MaybeDiscarded<BrowsingContext>& child) -> bool {
if (child.IsNullOrDiscarded()) {
return true;
}
children.AppendElement(child.get());
return false;
});
context->RestoreChildren(std::move(children), /* aFromIPC */ true);
context->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
Unused << aParent->SendRestoreBrowsingContextChildren(context, aChildren);
});
return IPC_OK();
}
@ -6299,6 +6380,18 @@ mozilla::ipc::IPCResult ContentParent::RecvWindowPostMessage(
return IPC_OK();
}
/* static */
void ContentParent::HoldBrowsingContextGroup(BrowsingContextGroup* aBCG) {
sBrowsingContextGroupHolder->AppendElement(aBCG);
}
/* static */
void ContentParent::ReleaseBrowsingContextGroup(BrowsingContextGroup* aBCG) {
if (sBrowsingContextGroupHolder) {
sBrowsingContextGroupHolder->RemoveElement(aBCG);
}
}
void ContentParent::OnBrowsingContextGroupSubscribe(
BrowsingContextGroup* aGroup) {
MOZ_DIAGNOSTIC_ASSERT(aGroup);

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

@ -640,12 +640,18 @@ class ContentParent final
static bool IsInputEventQueueSupported();
mozilla::ipc::IPCResult RecvCreateBrowsingContext(
uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit);
mozilla::ipc::IPCResult RecvAttachBrowsingContext(
BrowsingContext::IPCInitializer&& aInit);
mozilla::ipc::IPCResult RecvDiscardBrowsingContext(
mozilla::ipc::IPCResult RecvDetachBrowsingContext(
uint64_t aContextId, DetachBrowsingContextResolver&& aResolve);
mozilla::ipc::IPCResult RecvCacheBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext);
mozilla::ipc::IPCResult RecvRestoreBrowsingContextChildren(
const MaybeDiscarded<BrowsingContext>& aContext,
DiscardBrowsingContextResolver&& aResolve);
nsTArray<MaybeDiscarded<BrowsingContext>>&& aChildren);
mozilla::ipc::IPCResult RecvWindowClose(
const MaybeDiscarded<BrowsingContext>& aContext, bool aTrustedCaller);
@ -1291,6 +1297,9 @@ class ContentParent final
const bool& aMinimizeMemoryUsage,
const Maybe<FileDescriptor>& aDMDFile) override;
static void HoldBrowsingContextGroup(BrowsingContextGroup* aBCG);
static void ReleaseBrowsingContextGroup(BrowsingContextGroup* aBCG);
void OnBrowsingContextGroupSubscribe(BrowsingContextGroup* aGroup);
void OnBrowsingContextGroupUnsubscribe(BrowsingContextGroup* aGroup);

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

@ -342,12 +342,6 @@ struct KeyValuePair
nsString value;
};
union SyncedContextInitializer
{
BrowsingContextInitializer;
WindowContextInitializer;
};
/**
* The PContent protocol is a top-level protocol between the UI process
* and a content process. There is exactly one PContentParent/PContentChild pair
@ -832,7 +826,8 @@ child:
// Begin subscribing to a new BrowsingContextGroup, sending down the current
// value for every individual BrowsingContext.
async RegisterBrowsingContextGroup(uint64_t aGroupId, SyncedContextInitializer[] aInits);
async RegisterBrowsingContextGroup(BrowsingContextInitializer[] aInits,
WindowContextInitializer[] aWindowInits);
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
// Initialize top-level actor for testing content process sandbox.
@ -1569,23 +1564,44 @@ both:
uint32_t flags);
/**
* Creates a new BrowsingContext, initialized with the values provided in
* `BrowsingContextInitializer`.
*
* This message may only be sent to the parent in limited situations. If the
* new BrowsingContext has a parent window, it must be owned by the
* embedding process, otherwise it must be owned by the opener, if set.
* Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
* parent, and attach it to the BrowsingContext 'aParentContext'. If
* 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
* BrowsingContext tree. AttachBrowsingContext must only be called at most
* once for any child BrowsingContext, and only for BrowsingContexts where
* the parent and the child context contains their nsDocShell.
*/
async CreateBrowsingContext(uint64_t aGroupId, BrowsingContextInitializer aInit);
async AttachBrowsingContext(BrowsingContextInitializer aInit);
/**
* Discards the passed-in BrowsingContext. If the BrowsingContext has
* already been discarded, this message does nothing.
* The response promise is fulfilled when the process has flagged the
* BrowsingContext as discarded.
* Remove the synced BrowsingContext with id 'aContextId' from the parent.
* DetachBrowsingContext is only needed to be called once for any
* BrowsingContext, since detaching a node in the BrowsingContext detaches
* the entire sub-tree rooted at that node. Calling DetachBrowsingContext
* with an already detached BrowsingContext effectively does nothing. Note
* that it is not an error to call DetachBrowsingContext on a
* BrowsingContext belonging to an already detached subtree.
*
* As the passed-in context is allowed to already be detached, it is passed
* by id, rather than using BrowsingContext's serializer.
*
* Callers should keep the BrowsingContext alive until this async request is
* resolved or rejected, in order to ensure that in-flight messages still
* have valid targets.
*/
async DiscardBrowsingContext(MaybeDiscardedBrowsingContext aContext)
returns (bool unused);
async DetachBrowsingContext(uint64_t aContextId) returns (bool unused);
/**
* Removes all of 'aContext'\'s children, and caches them in the
* BrowsingContextGroup.
*/
async CacheBrowsingContextChildren(MaybeDiscardedBrowsingContext aContext);
/**
* Re-attach all BrowsingContexts in a 'aContext'.
*/
async RestoreBrowsingContextChildren(MaybeDiscardedBrowsingContext aContext,
MaybeDiscardedBrowsingContext[] aChildren);
async WindowClose(MaybeDiscardedBrowsingContext aContext,
bool aTrustedCaller);

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

@ -11081,7 +11081,7 @@ void PresShell::SetIsUnderHiddenEmbedderElement(
BrowsingContext* bc = docShell->GetBrowsingContext();
// Propagate to children.
for (BrowsingContext* child : bc->Children()) {
for (BrowsingContext* child : bc->GetChildren()) {
Element* embedderElement = child->GetEmbedderElement();
if (!embedderElement) {
// TODO: We shouldn't need to null check here since `child` and the

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

@ -9,7 +9,6 @@
#include "nsDocShell.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "nsQueryObject.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/ComputedStyleInlines.h"
@ -409,41 +408,43 @@ static void MapContentToWebShells(const UniquePtr<nsPrintObject>& aRootPO,
* The outparam aDocList returns a (depth first) flat list of all the
* nsPrintObjects created.
*/
static void BuildNestedPrintObjects(Document* aDocument,
static void BuildNestedPrintObjects(BrowsingContext* aBrowsingContext,
const UniquePtr<nsPrintObject>& aPO,
nsTArray<nsPrintObject*>* aDocList) {
MOZ_ASSERT(aDocument, "Pointer is null!");
MOZ_ASSERT(aBrowsingContext, "Pointer is null!");
MOZ_ASSERT(aDocList, "Pointer is null!");
MOZ_ASSERT(aPO, "Pointer is null!");
nsTArray<Document::PendingFrameStaticClone> pendingClones =
aDocument->TakePendingFrameStaticClones();
for (auto& clone : pendingClones) {
if (NS_WARN_IF(!clone.mStaticCloneOf)) {
for (auto& childBC : aBrowsingContext->GetChildren()) {
// if we no longer have a nsFrameLoader for this BrowsingContext, it's
// probably being torn down.
nsCOMPtr<nsFrameLoaderOwner> flo =
do_QueryInterface(childBC->GetEmbedderElement());
RefPtr<nsFrameLoader> frameLoader = flo ? flo->GetFrameLoader() : nullptr;
if (!frameLoader) {
continue;
}
RefPtr<Element> element = do_QueryObject(clone.mElement);
RefPtr<nsFrameLoader> frameLoader =
nsFrameLoader::Create(element, /* aNetworkCreated */ false);
clone.mElement->SetFrameLoader(frameLoader);
nsCOMPtr<nsIDocShell> docshell;
RefPtr<Document> doc;
nsresult rv = frameLoader->FinishStaticClone(
clone.mStaticCloneOf, getter_AddRefs(docshell), getter_AddRefs(doc));
// Finish performing the static clone for this BrowsingContext.
nsresult rv = frameLoader->FinishStaticClone();
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
auto window = childBC->GetDOMWindow();
if (!window) {
// XXXfission - handle OOP-iframes
continue;
}
auto childPO = MakeUnique<nsPrintObject>();
rv = childPO->InitAsNestedObject(docshell, doc, aPO.get());
rv = childPO->InitAsNestedObject(childBC->GetDocShell(),
window->GetExtantDoc(), aPO.get());
if (NS_FAILED(rv)) {
MOZ_ASSERT_UNREACHABLE("Init failed?");
}
aPO->mKids.AppendElement(std::move(childPO));
aDocList->AppendElement(aPO->mKids.LastElement().get());
BuildNestedPrintObjects(doc, aPO->mKids.LastElement(), aDocList);
BuildNestedPrintObjects(childBC, aPO->mKids.LastElement(), aDocList);
}
}
@ -795,8 +796,9 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
printData->mPrintObject->mFrameType =
printData->mIsParentAFrameSet ? eFrameSet : eDoc;
BuildNestedPrintObjects(printData->mPrintObject->mDocument,
printData->mPrintObject, &printData->mPrintDocList);
BuildNestedPrintObjects(
printData->mPrintObject->mDocShell->GetBrowsingContext(),
printData->mPrintObject, &printData->mPrintDocList);
}
// The nsAutoScriptBlocker above will now have been destroyed, which may
@ -3195,7 +3197,7 @@ static void DumpViews(nsIDocShell* aDocShell, FILE* out) {
// dump the views of the sub documents
int32_t i, n;
BrowsingContext* bc = nsDocShell::Cast(aDocShell)->GetBrowsingContext();
for (auto& child : bc->Children()) {
for (auto& child : bc->GetChildren()) {
if (auto childDS = child->GetDocShell()) {
DumpViews(childAsShell, out);
}

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

@ -76,7 +76,9 @@ nsresult nsPrintObject::InitAsRootObject(nsIDocShell* aDocShell, Document* aDoc,
// is detached from any browser window or tab.
// Create a new BrowsingContext to create our DocShell in.
RefPtr<BrowsingContext> bc = BrowsingContext::CreateIndependent(
RefPtr<BrowsingContext> bc = BrowsingContext::CreateWindowless(
/* aParent */ nullptr,
/* aOpener */ nullptr, EmptyString(),
nsDocShell::Cast(aDocShell)->GetBrowsingContext()->GetType());
// Create a container docshell for printing.

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

@ -41,7 +41,12 @@ nsTArray<RefPtr<PerformanceInfoPromise>> CollectPerformanceInfo() {
}
nsTArray<RefPtr<BrowsingContextGroup>> groups;
BrowsingContextGroup::GetAllGroups(groups);
if (XRE_IsContentProcess()) {
groups.AppendElements(
ContentChild::GetSingleton()->BrowsingContextGroups());
} else {
groups.AppendElements(ContentParent::BrowsingContextGroups());
}
nsTArray<DocGroup*> docGroups;
for (auto& browsingContextGroup : groups) {
@ -94,7 +99,7 @@ nsresult GetTabSizes(nsGlobalWindowOuter* aWindow, nsTabSizes* aSizes) {
}
// Measure this window's descendents.
for (const auto& frame : bc->Children()) {
for (const auto& frame : bc->GetChildren()) {
if (auto* childWin = nsGlobalWindowOuter::Cast(frame->GetDOMWindow())) {
MOZ_TRY(GetTabSizes(childWin, aSizes));
}

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

@ -487,7 +487,7 @@ int CollectPositions(BrowsingContext* aBrowsingContext,
/* Collect data from all child frame */
// This is not going to work for fission. Bug 1572084 for tracking it.
for (auto& child : aBrowsingContext->Children()) {
for (auto& child : aBrowsingContext->GetChildren()) {
aPositionDescendants[currentIdx] +=
CollectPositions(child, aPositions, aPositionDescendants);
}
@ -576,7 +576,7 @@ int CollectInputs(BrowsingContext* aBrowsingContext,
/* Collect data from all child frame */
// This is not going to work for fission. Bug 1572084 for tracking it.
for (auto& child : aBrowsingContext->Children()) {
for (auto& child : aBrowsingContext->GetChildren()) {
aInputs[currentIdx].descendants +=
CollectInputs(child, aInputs, aIdVals, aXPathVals);
}

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

@ -1169,7 +1169,7 @@ void SessionStoreUtils::CollectedSessionStorage(
}
// This is not going to work for fission. Bug 1572084 for tracking it.
for (BrowsingContext* child : aBrowsingContext->Children()) {
for (BrowsingContext* child : aBrowsingContext->GetChildren()) {
window = child->GetDOMWindow();
if (!window) {
return;
@ -1279,7 +1279,7 @@ static void CollectFrameTreeData(JSContext* aCx,
uint32_t trailingNullCounter = 0;
// This is not going to work for fission. Bug 1572084 for tracking it.
for (auto& child : aBrowsingContext->Children()) {
for (auto& child : aBrowsingContext->GetChildren()) {
NullableRootedDictionary<CollectedData> data(aCx);
CollectFrameTreeData(aCx, child, data, aFunc);
if (data.IsNull()) {

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

@ -118,8 +118,7 @@ class ThreadMetrics : public ::testing::Test {
protected:
virtual void SetUp() {
// building the DocGroup structure
RefPtr<dom::BrowsingContextGroup> group =
dom::BrowsingContextGroup::Create();
RefPtr<dom::BrowsingContextGroup> group = new dom::BrowsingContextGroup();
mDocGroup = group->AddDocument(NS_LITERAL_CSTRING("key"), nullptr);
mDocGroup2 = group->AddDocument(NS_LITERAL_CSTRING("key2"), nullptr);
mCounter = mDocGroup->GetPerformanceCounter();

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

@ -233,7 +233,8 @@ nsresult AppWindow::Initialize(nsIAppWindow* aParent, nsIAppWindow* aOpener,
// to pass in the opener window here. The opener is set later, if needed, by
// nsWindowWatcher.
RefPtr<BrowsingContext> browsingContext =
BrowsingContext::CreateIndependent(BrowsingContext::Type::Chrome);
BrowsingContext::Create(/* aParent */ nullptr, /* aOpener */ nullptr,
EmptyString(), BrowsingContext::Type::Chrome);
// Create web shell
mDocShell = nsDocShell::Create(browsingContext);

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

@ -449,7 +449,8 @@ nsAppShellService::CreateWindowlessBrowser(bool aIsChrome,
NS_ENSURE_SUCCESS(rv, rv);
// Create a BrowsingContext for our windowless browser.
RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateIndependent(
RefPtr<BrowsingContext> browsingContext = BrowsingContext::CreateWindowless(
nullptr, nullptr, EmptyString(),
aIsChrome ? BrowsingContext::Type::Chrome
: BrowsingContext::Type::Content);