Backed out changeset b73885731e73 (bug 1770944) Backed out changeset 23d0dc98eb51 (bug 1770944) Backed out changeset 15661e24d8e1 (bug 1770944) Backed out changeset 97aa839dc200 (bug 1770944) Backed out changeset 0d4318bf3239 (bug 1770944) Backed out changeset be28bb62e9f3 (bug 1770944) Backed out changeset 708b2671410e (bug 1770944) Backed out changeset 0a138f3b56b9 (bug 1770944) Backed out changeset 3a149ef794c2 (bug 1770944) Backed out changeset 4b6ae7dd0e69 (bug 1770944) Backed out changeset e3960ad85182 (bug 1770944) Backed out changeset 9ea253525227 (bug 1770944) Backed out changeset 1828b66c2f7c (bug 1770944) Backed out changeset 55b0886f9025 (bug 1770944) Backed out changeset a4197071d10a (bug 1770944) Backed out changeset 9b18524f541e (bug 1770944)
295 lines
9.8 KiB
C++
295 lines
9.8 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "InProcessBrowserChildMessageManager.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsDocShell.h"
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsFrameLoader.h"
|
|
#include "nsFrameLoaderOwner.h"
|
|
#include "nsQueryObject.h"
|
|
#include "xpcpublic.h"
|
|
#include "nsIMozBrowserFrame.h"
|
|
#include "mozilla/EventDispatcher.h"
|
|
#include "mozilla/dom/ChromeMessageSender.h"
|
|
#include "mozilla/dom/Document.h"
|
|
#include "mozilla/dom/MessageManagerBinding.h"
|
|
#include "mozilla/dom/SameProcessMessageQueue.h"
|
|
#include "mozilla/dom/ScriptLoader.h"
|
|
#include "mozilla/dom/WindowProxyHolder.h"
|
|
#include "mozilla/dom/JSActorService.h"
|
|
#include "mozilla/HoldDropJSObjects.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
using namespace mozilla::dom::ipc;
|
|
|
|
/* static */
|
|
already_AddRefed<InProcessBrowserChildMessageManager>
|
|
InProcessBrowserChildMessageManager::Create(nsDocShell* aShell,
|
|
nsIContent* aOwner,
|
|
nsFrameMessageManager* aChrome) {
|
|
RefPtr<InProcessBrowserChildMessageManager> mm =
|
|
new InProcessBrowserChildMessageManager(aShell, aOwner, aChrome);
|
|
|
|
NS_ENSURE_TRUE(mm->Init(), nullptr);
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
RefPtr<JSActorService> wasvc = JSActorService::GetSingleton();
|
|
wasvc->RegisterChromeEventTarget(mm);
|
|
}
|
|
|
|
return mm.forget();
|
|
}
|
|
|
|
bool InProcessBrowserChildMessageManager::DoSendBlockingMessage(
|
|
const nsAString& aMessage, StructuredCloneData& aData,
|
|
nsTArray<StructuredCloneData>* aRetVal) {
|
|
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
|
|
queue->Flush();
|
|
|
|
if (mChromeMessageManager) {
|
|
RefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
|
|
RefPtr<nsFrameLoader> fl = GetFrameLoader();
|
|
mm->ReceiveMessage(mOwner, fl, aMessage, true, &aData, aRetVal,
|
|
IgnoreErrors());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase,
|
|
public SameProcessMessageQueue::Runnable {
|
|
public:
|
|
explicit nsAsyncMessageToParent(
|
|
InProcessBrowserChildMessageManager* aBrowserChild)
|
|
: mBrowserChild(aBrowserChild) {}
|
|
|
|
virtual nsresult HandleMessage() override {
|
|
RefPtr<nsFrameLoader> fl = mBrowserChild->GetFrameLoader();
|
|
ReceiveMessage(mBrowserChild->mOwner, fl,
|
|
mBrowserChild->mChromeMessageManager);
|
|
return NS_OK;
|
|
}
|
|
RefPtr<InProcessBrowserChildMessageManager> mBrowserChild;
|
|
};
|
|
|
|
nsresult InProcessBrowserChildMessageManager::DoSendAsyncMessage(
|
|
const nsAString& aMessage, StructuredCloneData& aData) {
|
|
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
|
|
RefPtr<nsAsyncMessageToParent> ev = new nsAsyncMessageToParent(this);
|
|
|
|
nsresult rv = ev->Init(aMessage, aData);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
queue->Push(ev);
|
|
return NS_OK;
|
|
}
|
|
|
|
InProcessBrowserChildMessageManager::InProcessBrowserChildMessageManager(
|
|
nsDocShell* aShell, nsIContent* aOwner, nsFrameMessageManager* aChrome)
|
|
: ContentFrameMessageManager(new nsFrameMessageManager(this)),
|
|
mDocShell(aShell),
|
|
mLoadingScript(false),
|
|
mPreventEventsEscaping(false),
|
|
mOwner(aOwner),
|
|
mChromeMessageManager(aChrome) {
|
|
mozilla::HoldJSObjects(this);
|
|
|
|
// If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
|
|
// GetEventTargetParent implementation.
|
|
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
|
|
if (browserFrame) {
|
|
mIsBrowserFrame = browserFrame->GetReallyIsBrowser();
|
|
} else {
|
|
mIsBrowserFrame = false;
|
|
}
|
|
}
|
|
|
|
InProcessBrowserChildMessageManager::~InProcessBrowserChildMessageManager() {
|
|
if (XRE_IsParentProcess()) {
|
|
JSActorService::UnregisterChromeEventTarget(this);
|
|
}
|
|
|
|
mozilla::DropJSObjects(this);
|
|
}
|
|
|
|
// This method isn't automatically forwarded safely because it's notxpcom, so
|
|
// the IDL binding doesn't know what value to return.
|
|
void InProcessBrowserChildMessageManager::MarkForCC() {
|
|
MarkScopesForCC();
|
|
MessageManagerGlobal::MarkForCC();
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(InProcessBrowserChildMessageManager)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
|
|
InProcessBrowserChildMessageManager, DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(
|
|
InProcessBrowserChildMessageManager, DOMEventTargetHelper)
|
|
tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks, aClosure);
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(
|
|
InProcessBrowserChildMessageManager, DOMEventTargetHelper)
|
|
if (XRE_IsParentProcess()) {
|
|
JSActorService::UnregisterChromeEventTarget(tmp);
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
|
|
tmp->nsMessageManagerScriptExecutor::Unlink();
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InProcessBrowserChildMessageManager)
|
|
NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
|
|
NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)
|
|
NS_INTERFACE_MAP_ENTRY_CONCRETE(ContentFrameMessageManager)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(InProcessBrowserChildMessageManager,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(InProcessBrowserChildMessageManager,
|
|
DOMEventTargetHelper)
|
|
|
|
JSObject* InProcessBrowserChildMessageManager::WrapObject(
|
|
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
|
|
return ContentFrameMessageManager_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
void InProcessBrowserChildMessageManager::CacheFrameLoader(
|
|
nsFrameLoader* aFrameLoader) {
|
|
mFrameLoader = aFrameLoader;
|
|
}
|
|
|
|
Nullable<WindowProxyHolder> InProcessBrowserChildMessageManager::GetContent(
|
|
ErrorResult& aError) {
|
|
if (!mDocShell) {
|
|
return nullptr;
|
|
}
|
|
return WindowProxyHolder(mDocShell->GetBrowsingContext());
|
|
}
|
|
|
|
already_AddRefed<nsIEventTarget>
|
|
InProcessBrowserChildMessageManager::GetTabEventTarget() {
|
|
nsCOMPtr<nsIEventTarget> target = GetMainThreadSerialEventTarget();
|
|
return target.forget();
|
|
}
|
|
|
|
void InProcessBrowserChildMessageManager::FireUnloadEvent() {
|
|
// We're called from Document::MaybeInitializeFinalizeFrameLoaders, so it
|
|
// should be safe to run script.
|
|
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
|
|
|
|
// Don't let the unload event propagate to chrome event handlers.
|
|
mPreventEventsEscaping = true;
|
|
DOMEventTargetHelper::DispatchTrustedEvent(u"unload"_ns);
|
|
|
|
// Allow events fired during docshell destruction (pagehide, unload) to
|
|
// propagate to the <browser> element since chrome code depends on this.
|
|
mPreventEventsEscaping = false;
|
|
}
|
|
|
|
void InProcessBrowserChildMessageManager::DisconnectEventListeners() {
|
|
if (mDocShell) {
|
|
if (nsCOMPtr<nsPIDOMWindowOuter> win = mDocShell->GetWindow()) {
|
|
win->SetChromeEventHandler(win->GetChromeEventHandler());
|
|
}
|
|
}
|
|
if (mListenerManager) {
|
|
mListenerManager->Disconnect();
|
|
}
|
|
|
|
mDocShell = nullptr;
|
|
}
|
|
|
|
void InProcessBrowserChildMessageManager::Disconnect() {
|
|
mChromeMessageManager = nullptr;
|
|
mOwner = nullptr;
|
|
if (mMessageManager) {
|
|
static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
|
|
mMessageManager = nullptr;
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP_(nsIContent*)
|
|
InProcessBrowserChildMessageManager::GetOwnerContent() { return mOwner; }
|
|
|
|
void InProcessBrowserChildMessageManager::GetEventTargetParent(
|
|
EventChainPreVisitor& aVisitor) {
|
|
aVisitor.mForceContentDispatch = true;
|
|
aVisitor.mCanHandle = true;
|
|
|
|
if (mPreventEventsEscaping) {
|
|
aVisitor.SetParentTarget(nullptr, false);
|
|
return;
|
|
}
|
|
|
|
if (mIsBrowserFrame &&
|
|
(!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
|
|
if (mOwner) {
|
|
if (nsPIDOMWindowInner* innerWindow =
|
|
mOwner->OwnerDoc()->GetInnerWindow()) {
|
|
// 'this' is already a "chrome handler", so we consider window's
|
|
// parent target to be part of that same part of the event path.
|
|
aVisitor.SetParentTarget(innerWindow->GetParentTarget(), false);
|
|
}
|
|
}
|
|
} else {
|
|
aVisitor.SetParentTarget(mOwner, false);
|
|
}
|
|
}
|
|
|
|
class nsAsyncScriptLoad : public Runnable {
|
|
public:
|
|
nsAsyncScriptLoad(InProcessBrowserChildMessageManager* aBrowserChild,
|
|
const nsAString& aURL, bool aRunInGlobalScope)
|
|
: mozilla::Runnable("nsAsyncScriptLoad"),
|
|
mBrowserChild(aBrowserChild),
|
|
mURL(aURL),
|
|
mRunInGlobalScope(aRunInGlobalScope) {}
|
|
|
|
NS_IMETHOD Run() override {
|
|
mBrowserChild->LoadFrameScript(mURL, mRunInGlobalScope);
|
|
return NS_OK;
|
|
}
|
|
RefPtr<InProcessBrowserChildMessageManager> mBrowserChild;
|
|
nsString mURL;
|
|
bool mRunInGlobalScope;
|
|
};
|
|
|
|
void InProcessBrowserChildMessageManager::LoadFrameScript(
|
|
const nsAString& aURL, bool aRunInGlobalScope) {
|
|
if (!nsContentUtils::IsSafeToRunScript()) {
|
|
nsContentUtils::AddScriptRunner(
|
|
new nsAsyncScriptLoad(this, aURL, aRunInGlobalScope));
|
|
return;
|
|
}
|
|
bool tmp = mLoadingScript;
|
|
mLoadingScript = true;
|
|
JS::Rooted<JSObject*> mm(mozilla::dom::RootingCx(), GetOrCreateWrapper());
|
|
LoadScriptInternal(mm, aURL, !aRunInGlobalScope);
|
|
mLoadingScript = tmp;
|
|
}
|
|
|
|
already_AddRefed<nsFrameLoader>
|
|
InProcessBrowserChildMessageManager::GetFrameLoader() {
|
|
RefPtr<nsFrameLoaderOwner> owner = do_QueryObject(mOwner);
|
|
RefPtr<nsFrameLoader> fl = owner ? owner->GetFrameLoader() : nullptr;
|
|
if (!fl) {
|
|
fl = mFrameLoader;
|
|
}
|
|
return fl.forget();
|
|
}
|