Bug 1525427 - Part 1: Expose WindowGlobalParent & Element on BrowsingContext, r=farre

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nika Layzell 2019-04-17 00:51:36 +00:00
Родитель 7f4ecdea61
Коммит 0bc40288dc
11 изменённых файлов: 108 добавлений и 4 удалений

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

@ -13,9 +13,12 @@
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/LocationBinding.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
@ -201,6 +204,27 @@ void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
mIsInProcess = true;
}
void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
mEmbedderElement = aEmbedder;
// Notify the parent process of the embedding status. We don't need to do
// this when clearing our embedder, as we're being destroyed either way.
if (mEmbedderElement) {
nsCOMPtr<nsPIDOMWindowInner> embedderGlobal =
do_QueryInterface(mEmbedderElement->GetOwnerGlobal());
RefPtr<WindowGlobalChild> wgc = embedderGlobal->GetWindowGlobalChild();
// If we're in-process, synchronously perform the update to ensure we don't
// get out of sync.
// XXX(nika): This is super gross, and I don't like it one bit.
if (RefPtr<WindowGlobalParent> wgp = wgc->GetParentActor()) {
Canonical()->SetEmbedderWindowGlobal(wgp);
} else {
wgc->SendDidEmbedBrowsingContext(this);
}
}
}
void BrowsingContext::Attach(bool aFromIPC) {
MOZ_LOG(GetLog(), LogLevel::Debug,
("%s: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
@ -518,7 +542,8 @@ bool BrowsingContext::GetUserGestureActivation() {
NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup,
mEmbedderElement)
if (XRE_IsParentProcess()) {
CanonicalBrowsingContext::Cast(tmp)->Unlink();
}
@ -526,7 +551,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell, mChildren, mParent, mGroup)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell, mChildren, mParent, mGroup,
mEmbedderElement)
if (XRE_IsParentProcess()) {
CanonicalBrowsingContext::Cast(tmp)->Traverse(cb);
}

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

@ -46,6 +46,7 @@ class BrowsingContent;
class BrowsingContextGroup;
class CanonicalBrowsingContext;
class ContentParent;
class Element;
template <typename>
struct Nullable;
template <typename T>
@ -123,6 +124,11 @@ class BrowsingContext : public nsWrapperCache,
void SetDocShell(nsIDocShell* aDocShell);
void ClearDocShell() { mDocShell = nullptr; }
// Get the embedder element for this BrowsingContext if the embedder is
// in-process, or null if it's not.
Element* GetEmbedderElement() const { return mEmbedderElement; }
void SetEmbedderElement(Element* aEmbedder);
// Get the outer window object for this BrowsingContext if it is in-process
// and still has a docshell, or null otherwise.
nsPIDOMWindowOuter* GetDOMWindow() const {
@ -439,6 +445,8 @@ class BrowsingContext : public nsWrapperCache,
Children mChildren;
nsCOMPtr<nsIDocShell> mDocShell;
RefPtr<Element> mEmbedderElement;
// This is not a strong reference, but using a JS::Heap for that should be
// fine. The JSObject stored in here should be a proxy with a
// nsOuterWindowProxy handler, which will update the pointer from its

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

@ -116,6 +116,20 @@ void CanonicalBrowsingContext::SetCurrentWindowGlobal(
mCurrentWindowGlobal = aGlobal;
}
void CanonicalBrowsingContext::SetEmbedderWindowGlobal(
WindowGlobalParent* aGlobal) {
MOZ_RELEASE_ASSERT(aGlobal, "null embedder");
if (RefPtr<BrowsingContext> parent = GetParent()) {
MOZ_RELEASE_ASSERT(aGlobal->BrowsingContext() == parent,
"Embedder has incorrect browsing context");
} else {
MOZ_RELEASE_ASSERT(aGlobal->IsInProcess(),
"Toplevel must have a parent-process embedder");
}
mEmbedderWindowGlobal = aGlobal;
}
bool CanonicalBrowsingContext::ValidateTransaction(
const Transaction& aTransaction, ContentParent* aProcess) {
// Check that the correct process is performing sets for transactions with
@ -137,12 +151,14 @@ JSObject* CanonicalBrowsingContext::WrapObject(
void CanonicalBrowsingContext::Traverse(
nsCycleCollectionTraversalCallback& cb) {
CanonicalBrowsingContext* tmp = this;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobals);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobals, mCurrentWindowGlobal,
mEmbedderWindowGlobal);
}
void CanonicalBrowsingContext::Unlink() {
CanonicalBrowsingContext* tmp = this;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobals);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobals, mCurrentWindowGlobal,
mEmbedderWindowGlobal);
}
void CanonicalBrowsingContext::NotifyStartDelayedAutoplayMedia() {

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

@ -52,6 +52,11 @@ class CanonicalBrowsingContext final : public BrowsingContext {
}
void SetCurrentWindowGlobal(WindowGlobalParent* aGlobal);
WindowGlobalParent* GetEmbedderWindowGlobal() const {
return mEmbedderWindowGlobal;
}
void SetEmbedderWindowGlobal(WindowGlobalParent* aGlobal);
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
@ -97,6 +102,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// All live window globals within this browsing context.
nsTHashtable<nsRefPtrHashKey<WindowGlobalParent>> mWindowGlobals;
RefPtr<WindowGlobalParent> mCurrentWindowGlobal;
RefPtr<WindowGlobalParent> mEmbedderWindowGlobal;
// Generation information for each content process which has interacted with
// this CanonicalBrowsingContext, by ChildID.

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

@ -1893,6 +1893,10 @@ void nsFrameLoader::SetOwnerContent(Element* aContent) {
}
mOwnerContent = aContent;
if (RefPtr<BrowsingContext> browsingContext = GetBrowsingContext()) {
browsingContext->SetEmbedderElement(mOwnerContent);
}
AutoJSAPI jsapi;
jsapi.Init();
@ -2009,6 +2013,8 @@ nsresult nsFrameLoader::MaybeCreateDocShell() {
RefPtr<nsDocShell> docShell = nsDocShell::Create(mBrowsingContext);
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
mBrowsingContext->SetEmbedderElement(mOwnerContent);
mIsTopLevelContent =
mBrowsingContext->IsContent() && !mBrowsingContext->GetParent();
if (!mNetworkCreated && !mIsTopLevelContent) {
@ -2604,6 +2610,8 @@ bool nsFrameLoader::TryRemoteBrowser() {
// If we're in a content process, create a BrowserBridgeChild actor.
if (XRE_IsContentProcess()) {
mBrowsingContext->SetEmbedderElement(mOwnerContent);
mBrowserBridgeChild = BrowserBridgeChild::Create(
this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
mBrowsingContext);

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

@ -22,6 +22,8 @@ interface BrowsingContext {
readonly attribute nsIDocShell? docShell;
readonly attribute Element? embedderElement;
readonly attribute unsigned long long id;
readonly attribute BrowsingContext? opener;
@ -41,6 +43,8 @@ interface CanonicalBrowsingContext : BrowsingContext {
[Throws]
readonly attribute DOMString? currentRemoteType;
readonly attribute WindowGlobalParent? embedderWindowGlobal;
void notifyStartDelayedAutoplayMedia();
};

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

@ -1148,6 +1148,8 @@ TabParent* ContentParent::CreateBrowser(const TabContext& aContext,
}
}
aBrowsingContext->SetEmbedderElement(aFrameElement);
// Ensure that our content process is subscribed to our newly created
// BrowsingContextGroup.
aBrowsingContext->Group()->EnsureSubscribed(constructorSender);

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

@ -36,6 +36,10 @@ parent:
/// Notify the parent that this PWindowGlobal is now the current global.
async BecomeCurrentWindowGlobal();
/// Notify the parent that this PWindowGlobal has embedded the given
/// BrowsingContext.
async DidEmbedBrowsingContext(BrowsingContext aContext);
async Destroy();
};

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

@ -334,6 +334,21 @@ void TabParent::SetOwnerElement(Element* aElement) {
if (mRenderFrame.IsInitialized()) {
mRenderFrame.OwnerContentChanged();
}
// Set our BrowsingContext's embedder if we're not embedded within a
// BrowserBridgeParent.
if (!GetBrowserBridgeParent() && mBrowsingContext) {
mBrowsingContext->SetEmbedderElement(mFrameElement);
}
// Ensure all TabParent actors within BrowserBridges are also updated.
const auto& browserBridges = ManagedPBrowserBridgeParent();
for (auto iter = browserBridges.ConstIter(); !iter.Done(); iter.Next()) {
BrowserBridgeParent* browserBridge =
static_cast<BrowserBridgeParent*>(iter.Get()->GetKey());
browserBridge->GetTabParent()->SetOwnerElement(aElement);
}
}
NS_IMETHODIMP TabParent::GetOwnerElement(Element** aElement) {

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

@ -87,6 +87,12 @@ void WindowGlobalParent::Init(const WindowGlobalInit& aInit) {
// Attach ourself to the browsing context.
mBrowsingContext->RegisterWindowGlobal(this);
// If there is no current window global, assume we're about to become it
// optimistically.
if (!mBrowsingContext->GetCurrentWindowGlobal()) {
mBrowsingContext->SetCurrentWindowGlobal(this);
}
// Determine what toplevel frame element our WindowGlobalParent is being
// embedded in.
RefPtr<Element> frameElement;
@ -252,6 +258,13 @@ bool WindowGlobalParent::IsCurrentGlobal() {
return !mIPCClosed && mBrowsingContext->GetCurrentWindowGlobal() == this;
}
IPCResult WindowGlobalParent::RecvDidEmbedBrowsingContext(
dom::BrowsingContext* aContext) {
MOZ_ASSERT(aContext);
aContext->Canonical()->SetEmbedderWindowGlobal(this);
return IPC_OK();
}
void WindowGlobalParent::ActorDestroy(ActorDestroyReason aWhy) {
mIPCClosed = true;
gWindowGlobalParentsById->Remove(mInnerWindowId);

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

@ -111,6 +111,8 @@ class WindowGlobalParent final : public nsISupports,
mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aActorName,
const nsString& aMessageName,
const ClonedMessageData& aData);
mozilla::ipc::IPCResult RecvDidEmbedBrowsingContext(
dom::BrowsingContext* aContext);
void ActorDestroy(ActorDestroyReason aWhy) override;