forked from mirrors/gecko-dev
Backed out changeset 61af32f40777 (bug 1770944) Backed out changeset 4ff0c45db93b (bug 1770944) Backed out changeset 8a217eff7bcd (bug 1770944) Backed out changeset 6435f48c96bf (bug 1770944) Backed out changeset 0d2432765ca0 (bug 1770944) Backed out changeset 58e02566db85 (bug 1770944) Backed out changeset 0a8c4c2460ee (bug 1770944) Backed out changeset 9416bafd9982 (bug 1770944) Backed out changeset 79de4f83fe2e (bug 1770944) Backed out changeset 63ac518aceb0 (bug 1770944) Backed out changeset 14952f872b77 (bug 1770944) Backed out changeset f65e0967ad75 (bug 1770944) Backed out changeset bd53c42038f7 (bug 1770944) Backed out changeset 36c378ba8212 (bug 1770944) Backed out changeset 9ba54ab06348 (bug 1770944) Backed out changeset fb5a54b3cbe9 (bug 1770944)
294 lines
9.8 KiB
C++
294 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();
|
|
}
|