1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "InProcessBrowserChildMessageManager.h"
8 #include "nsContentUtils.h"
9 #include "nsDocShell.h"
10 #include "nsIInterfaceRequestorUtils.h"
11 #include "nsComponentManagerUtils.h"
12 #include "nsFrameLoader.h"
13 #include "nsFrameLoaderOwner.h"
14 #include "nsQueryObject.h"
15 #include "xpcpublic.h"
16 #include "nsIMozBrowserFrame.h"
17 #include "mozilla/EventDispatcher.h"
18 #include "mozilla/dom/ChromeMessageSender.h"
19 #include "mozilla/dom/Document.h"
20 #include "mozilla/dom/MessageManagerBinding.h"
21 #include "mozilla/dom/SameProcessMessageQueue.h"
22 #include "mozilla/dom/ScriptLoader.h"
23 #include "mozilla/dom/WindowProxyHolder.h"
24 #include "mozilla/dom/JSActorService.h"
25 #include "mozilla/HoldDropJSObjects.h"
27 using namespace mozilla
;
28 using namespace mozilla::dom
;
29 using namespace mozilla::dom::ipc
;
32 already_AddRefed
<InProcessBrowserChildMessageManager
>
33 InProcessBrowserChildMessageManager::Create(nsDocShell
* aShell
,
35 nsFrameMessageManager
* aChrome
) {
36 RefPtr
<InProcessBrowserChildMessageManager
> mm
=
37 new InProcessBrowserChildMessageManager(aShell
, aOwner
, aChrome
);
39 NS_ENSURE_TRUE(mm
->Init(), nullptr);
41 if (XRE_IsParentProcess()) {
42 RefPtr
<JSActorService
> wasvc
= JSActorService::GetSingleton();
43 wasvc
->RegisterChromeEventTarget(mm
);
49 bool InProcessBrowserChildMessageManager::DoSendBlockingMessage(
50 const nsAString
& aMessage
, StructuredCloneData
& aData
,
51 nsTArray
<StructuredCloneData
>* aRetVal
) {
52 SameProcessMessageQueue
* queue
= SameProcessMessageQueue::Get();
55 if (mChromeMessageManager
) {
56 RefPtr
<nsFrameMessageManager
> mm
= mChromeMessageManager
;
57 RefPtr
<nsFrameLoader
> fl
= GetFrameLoader();
58 mm
->ReceiveMessage(mOwner
, fl
, aMessage
, true, &aData
, aRetVal
,
64 class nsAsyncMessageToParent
: public nsSameProcessAsyncMessageBase
,
65 public SameProcessMessageQueue::Runnable
{
67 explicit nsAsyncMessageToParent(
68 InProcessBrowserChildMessageManager
* aBrowserChild
)
69 : nsSameProcessAsyncMessageBase(), mBrowserChild(aBrowserChild
) {}
71 virtual nsresult
HandleMessage() override
{
72 RefPtr
<nsFrameLoader
> fl
= mBrowserChild
->GetFrameLoader();
73 ReceiveMessage(mBrowserChild
->mOwner
, fl
,
74 mBrowserChild
->mChromeMessageManager
);
77 RefPtr
<InProcessBrowserChildMessageManager
> mBrowserChild
;
80 nsresult
InProcessBrowserChildMessageManager::DoSendAsyncMessage(
81 const nsAString
& aMessage
, StructuredCloneData
& aData
) {
82 SameProcessMessageQueue
* queue
= SameProcessMessageQueue::Get();
83 RefPtr
<nsAsyncMessageToParent
> ev
= new nsAsyncMessageToParent(this);
85 nsresult rv
= ev
->Init(aMessage
, aData
);
94 InProcessBrowserChildMessageManager::InProcessBrowserChildMessageManager(
95 nsDocShell
* aShell
, nsIContent
* aOwner
, nsFrameMessageManager
* aChrome
)
96 : ContentFrameMessageManager(new nsFrameMessageManager(this)),
98 mLoadingScript(false),
99 mPreventEventsEscaping(false),
101 mChromeMessageManager(aChrome
) {
102 mozilla::HoldJSObjects(this);
104 // If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
105 // GetEventTargetParent implementation.
106 nsCOMPtr
<nsIMozBrowserFrame
> browserFrame
= do_QueryInterface(mOwner
);
108 mIsBrowserFrame
= browserFrame
->GetReallyIsBrowser();
110 mIsBrowserFrame
= false;
114 InProcessBrowserChildMessageManager::~InProcessBrowserChildMessageManager() {
115 if (XRE_IsParentProcess()) {
116 JSActorService::UnregisterChromeEventTarget(this);
119 mAnonymousGlobalScopes
.Clear();
120 mozilla::DropJSObjects(this);
123 // This method isn't automatically forwarded safely because it's notxpcom, so
124 // the IDL binding doesn't know what value to return.
125 void InProcessBrowserChildMessageManager::MarkForCC() {
127 MessageManagerGlobal::MarkForCC();
130 NS_IMPL_CYCLE_COLLECTION_CLASS(InProcessBrowserChildMessageManager
)
132 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
133 InProcessBrowserChildMessageManager
, DOMEventTargetHelper
)
134 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager
)
135 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell
)
136 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
138 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(
139 InProcessBrowserChildMessageManager
, DOMEventTargetHelper
)
140 tmp
->nsMessageManagerScriptExecutor::Trace(aCallbacks
, aClosure
);
141 NS_IMPL_CYCLE_COLLECTION_TRACE_END
143 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(
144 InProcessBrowserChildMessageManager
, DOMEventTargetHelper
)
145 if (XRE_IsParentProcess()) {
146 JSActorService::UnregisterChromeEventTarget(tmp
);
149 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager
)
150 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell
)
151 tmp
->nsMessageManagerScriptExecutor::Unlink();
152 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
153 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
155 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InProcessBrowserChildMessageManager
)
156 NS_INTERFACE_MAP_ENTRY(nsIMessageSender
)
157 NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager
)
158 NS_INTERFACE_MAP_ENTRY(ContentFrameMessageManager
)
159 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
160 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
162 NS_IMPL_ADDREF_INHERITED(InProcessBrowserChildMessageManager
,
163 DOMEventTargetHelper
)
164 NS_IMPL_RELEASE_INHERITED(InProcessBrowserChildMessageManager
,
165 DOMEventTargetHelper
)
167 JSObject
* InProcessBrowserChildMessageManager::WrapObject(
168 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
169 return ContentFrameMessageManager_Binding::Wrap(aCx
, this, aGivenProto
);
172 void InProcessBrowserChildMessageManager::CacheFrameLoader(
173 nsFrameLoader
* aFrameLoader
) {
174 mFrameLoader
= aFrameLoader
;
177 Nullable
<WindowProxyHolder
> InProcessBrowserChildMessageManager::GetContent(
178 ErrorResult
& aError
) {
182 return WindowProxyHolder(mDocShell
->GetBrowsingContext());
185 already_AddRefed
<nsIEventTarget
>
186 InProcessBrowserChildMessageManager::GetTabEventTarget() {
187 nsCOMPtr
<nsIEventTarget
> target
= GetMainThreadEventTarget();
188 return target
.forget();
191 void InProcessBrowserChildMessageManager::FireUnloadEvent() {
192 // We're called from Document::MaybeInitializeFinalizeFrameLoaders, so it
193 // should be safe to run script.
194 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
196 // Don't let the unload event propagate to chrome event handlers.
197 mPreventEventsEscaping
= true;
198 DOMEventTargetHelper::DispatchTrustedEvent(u
"unload"_ns
);
200 // Allow events fired during docshell destruction (pagehide, unload) to
201 // propagate to the <browser> element since chrome code depends on this.
202 mPreventEventsEscaping
= false;
205 void InProcessBrowserChildMessageManager::DisconnectEventListeners() {
207 if (nsCOMPtr
<nsPIDOMWindowOuter
> win
= mDocShell
->GetWindow()) {
208 win
->SetChromeEventHandler(win
->GetChromeEventHandler());
211 if (mListenerManager
) {
212 mListenerManager
->Disconnect();
218 void InProcessBrowserChildMessageManager::Disconnect() {
219 mChromeMessageManager
= nullptr;
221 if (mMessageManager
) {
222 static_cast<nsFrameMessageManager
*>(mMessageManager
.get())->Disconnect();
223 mMessageManager
= nullptr;
227 NS_IMETHODIMP_(nsIContent
*)
228 InProcessBrowserChildMessageManager::GetOwnerContent() { return mOwner
; }
230 void InProcessBrowserChildMessageManager::GetEventTargetParent(
231 EventChainPreVisitor
& aVisitor
) {
232 aVisitor
.mForceContentDispatch
= true;
233 aVisitor
.mCanHandle
= true;
235 if (mPreventEventsEscaping
) {
236 aVisitor
.SetParentTarget(nullptr, false);
240 if (mIsBrowserFrame
&&
241 (!mOwner
|| !nsContentUtils::IsInChromeDocshell(mOwner
->OwnerDoc()))) {
243 if (nsPIDOMWindowInner
* innerWindow
=
244 mOwner
->OwnerDoc()->GetInnerWindow()) {
245 // 'this' is already a "chrome handler", so we consider window's
246 // parent target to be part of that same part of the event path.
247 aVisitor
.SetParentTarget(innerWindow
->GetParentTarget(), false);
251 aVisitor
.SetParentTarget(mOwner
, false);
255 class nsAsyncScriptLoad
: public Runnable
{
257 nsAsyncScriptLoad(InProcessBrowserChildMessageManager
* aBrowserChild
,
258 const nsAString
& aURL
, bool aRunInGlobalScope
)
259 : mozilla::Runnable("nsAsyncScriptLoad"),
260 mBrowserChild(aBrowserChild
),
262 mRunInGlobalScope(aRunInGlobalScope
) {}
264 NS_IMETHOD
Run() override
{
265 mBrowserChild
->LoadFrameScript(mURL
, mRunInGlobalScope
);
268 RefPtr
<InProcessBrowserChildMessageManager
> mBrowserChild
;
270 bool mRunInGlobalScope
;
273 void InProcessBrowserChildMessageManager::LoadFrameScript(
274 const nsAString
& aURL
, bool aRunInGlobalScope
) {
275 if (!nsContentUtils::IsSafeToRunScript()) {
276 nsContentUtils::AddScriptRunner(
277 new nsAsyncScriptLoad(this, aURL
, aRunInGlobalScope
));
280 bool tmp
= mLoadingScript
;
281 mLoadingScript
= true;
282 JS::Rooted
<JSObject
*> mm(mozilla::dom::RootingCx(), GetOrCreateWrapper());
283 LoadScriptInternal(mm
, aURL
, !aRunInGlobalScope
);
284 mLoadingScript
= tmp
;
287 already_AddRefed
<nsFrameLoader
>
288 InProcessBrowserChildMessageManager::GetFrameLoader() {
289 RefPtr
<nsFrameLoaderOwner
> owner
= do_QueryObject(mOwner
);
290 RefPtr
<nsFrameLoader
> fl
= owner
? owner
->GetFrameLoader() : nullptr;