forked from mirrors/gecko-dev
		
	 f206ae96e4
			
		
	
	
		f206ae96e4
		
	
	
	
	
		
			
			There's a pattern of clearing JS things when calling mozilla::DropJSObjects, but mozilla::DropJSObjects already clears the JS things itself by calling CycleCollectedJSRuntime::RemoveJSHolder. Differential Revision: https://phabricator.services.mozilla.com/D115885
		
			
				
	
	
		
			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)
 | |
|       : nsSameProcessAsyncMessageBase(), 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(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 = GetMainThreadEventTarget();
 | |
|   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();
 | |
| }
 |