forked from mirrors/gecko-dev
		
	 bc14bd97eb
			
		
	
	
		bc14bd97eb
		
	
	
	
	
		
			
			Differential Revision: https://phabricator.services.mozilla.com/D30764 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			340 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
	
		
			11 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 "mozilla/BasicEvents.h"
 | |
| #include "mozilla/EventDispatcher.h"
 | |
| #include "mozilla/EventListenerManager.h"
 | |
| #include "mozilla/dom/WindowRootBinding.h"
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsWindowRoot.h"
 | |
| #include "nsPIDOMWindow.h"
 | |
| #include "nsPresContext.h"
 | |
| #include "nsLayoutCID.h"
 | |
| #include "nsContentCID.h"
 | |
| #include "nsString.h"
 | |
| #include "nsGlobalWindow.h"
 | |
| #include "nsFocusManager.h"
 | |
| #include "nsIContent.h"
 | |
| #include "nsIControllers.h"
 | |
| #include "nsIController.h"
 | |
| #include "xpcpublic.h"
 | |
| #include "nsCycleCollectionParticipant.h"
 | |
| #include "mozilla/dom/BrowserParent.h"
 | |
| #include "mozilla/dom/HTMLTextAreaElement.h"
 | |
| #include "mozilla/dom/HTMLInputElement.h"
 | |
| #include "mozilla/dom/JSWindowActorService.h"
 | |
| 
 | |
| #ifdef MOZ_XUL
 | |
| #  include "nsXULElement.h"
 | |
| #endif
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom;
 | |
| 
 | |
| nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow) {
 | |
|   mWindow = aWindow;
 | |
| 
 | |
|   // Keyboard indicators are not shown on Mac by default.
 | |
| #if defined(XP_MACOSX)
 | |
|   mShowAccelerators = false;
 | |
|   mShowFocusRings = false;
 | |
| #else
 | |
|   mShowAccelerators = true;
 | |
|   mShowFocusRings = true;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| nsWindowRoot::~nsWindowRoot() {
 | |
|   if (mListenerManager) {
 | |
|     mListenerManager->Disconnect();
 | |
|   }
 | |
| 
 | |
|   JSWindowActorService::UnregisterWindowRoot(this);
 | |
| }
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsWindowRoot, mWindow, mListenerManager,
 | |
|                                       mParent)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot)
 | |
|   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
|   NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot)
 | |
|   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot)
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot)
 | |
| 
 | |
| bool nsWindowRoot::DispatchEvent(Event& aEvent, CallerType aCallerType,
 | |
|                                  ErrorResult& aRv) {
 | |
|   nsEventStatus status = nsEventStatus_eIgnore;
 | |
|   nsresult rv = EventDispatcher::DispatchDOMEvent(
 | |
|       static_cast<EventTarget*>(this), nullptr, &aEvent, nullptr, &status);
 | |
|   bool retval = !aEvent.DefaultPrevented(aCallerType);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     aRv.Throw(rv);
 | |
|   }
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| bool nsWindowRoot::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| EventListenerManager* nsWindowRoot::GetOrCreateListenerManager() {
 | |
|   if (!mListenerManager) {
 | |
|     mListenerManager =
 | |
|         new EventListenerManager(static_cast<EventTarget*>(this));
 | |
|   }
 | |
| 
 | |
|   return mListenerManager;
 | |
| }
 | |
| 
 | |
| EventListenerManager* nsWindowRoot::GetExistingListenerManager() const {
 | |
|   return mListenerManager;
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
 | |
|   aVisitor.mCanHandle = true;
 | |
|   aVisitor.mForceContentDispatch = true;  // FIXME! Bug 329119
 | |
|   // To keep mWindow alive
 | |
|   aVisitor.mItemData = static_cast<nsISupports*>(mWindow);
 | |
|   aVisitor.SetParentTarget(mParent, false);
 | |
| }
 | |
| 
 | |
| nsresult nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) {
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsPIDOMWindowOuter* nsWindowRoot::GetOwnerGlobalForBindingsInternal() {
 | |
|   return mWindow;
 | |
| }
 | |
| 
 | |
| nsIGlobalObject* nsWindowRoot::GetOwnerGlobal() const {
 | |
|   nsCOMPtr<nsIGlobalObject> global =
 | |
|       do_QueryInterface(mWindow->GetCurrentInnerWindow());
 | |
|   // We're still holding a ref to it, so returning the raw pointer is ok...
 | |
|   return global;
 | |
| }
 | |
| 
 | |
| nsPIDOMWindowOuter* nsWindowRoot::GetWindow() { return mWindow; }
 | |
| 
 | |
| nsresult nsWindowRoot::GetControllers(bool aForVisibleWindow,
 | |
|                                       nsIControllers** aResult) {
 | |
|   *aResult = nullptr;
 | |
| 
 | |
|   // XXX: we should fix this so there's a generic interface that
 | |
|   // describes controllers, so this code would have no special
 | |
|   // knowledge of what object might have controllers.
 | |
| 
 | |
|   nsFocusManager::SearchRange searchRange =
 | |
|       aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
 | |
|                         : nsFocusManager::eIncludeAllDescendants;
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
 | |
|   nsIContent* focusedContent = nsFocusManager::GetFocusedDescendant(
 | |
|       mWindow, searchRange, getter_AddRefs(focusedWindow));
 | |
|   if (focusedContent) {
 | |
| #ifdef MOZ_XUL
 | |
|     RefPtr<nsXULElement> xulElement = nsXULElement::FromNode(focusedContent);
 | |
|     if (xulElement) {
 | |
|       ErrorResult rv;
 | |
|       *aResult = xulElement->GetControllers(rv);
 | |
|       NS_IF_ADDREF(*aResult);
 | |
|       return rv.StealNSResult();
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     HTMLTextAreaElement* htmlTextArea =
 | |
|         HTMLTextAreaElement::FromNode(focusedContent);
 | |
|     if (htmlTextArea) return htmlTextArea->GetControllers(aResult);
 | |
| 
 | |
|     HTMLInputElement* htmlInputElement =
 | |
|         HTMLInputElement::FromNode(focusedContent);
 | |
|     if (htmlInputElement) return htmlInputElement->GetControllers(aResult);
 | |
| 
 | |
|     if (focusedContent->IsEditable() && focusedWindow)
 | |
|       return focusedWindow->GetControllers(aResult);
 | |
|   } else {
 | |
|     return focusedWindow->GetControllers(aResult);
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult nsWindowRoot::GetControllerForCommand(const char* aCommand,
 | |
|                                                bool aForVisibleWindow,
 | |
|                                                nsIController** _retval) {
 | |
|   NS_ENSURE_ARG_POINTER(_retval);
 | |
|   *_retval = nullptr;
 | |
| 
 | |
|   {
 | |
|     nsCOMPtr<nsIControllers> controllers;
 | |
|     GetControllers(aForVisibleWindow, getter_AddRefs(controllers));
 | |
|     if (controllers) {
 | |
|       nsCOMPtr<nsIController> controller;
 | |
|       controllers->GetControllerForCommand(aCommand,
 | |
|                                            getter_AddRefs(controller));
 | |
|       if (controller) {
 | |
|         controller.forget(_retval);
 | |
|         return NS_OK;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsFocusManager::SearchRange searchRange =
 | |
|       aForVisibleWindow ? nsFocusManager::eIncludeVisibleDescendants
 | |
|                         : nsFocusManager::eIncludeAllDescendants;
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
 | |
|   nsFocusManager::GetFocusedDescendant(mWindow, searchRange,
 | |
|                                        getter_AddRefs(focusedWindow));
 | |
|   while (focusedWindow) {
 | |
|     nsCOMPtr<nsIControllers> controllers;
 | |
|     focusedWindow->GetControllers(getter_AddRefs(controllers));
 | |
|     if (controllers) {
 | |
|       nsCOMPtr<nsIController> controller;
 | |
|       controllers->GetControllerForCommand(aCommand,
 | |
|                                            getter_AddRefs(controller));
 | |
|       if (controller) {
 | |
|         controller.forget(_retval);
 | |
|         return NS_OK;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // XXXndeakin P3 is this casting safe?
 | |
|     nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
 | |
|     focusedWindow = win->GetPrivateParent();
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::GetEnabledDisabledCommandsForControllers(
 | |
|     nsIControllers* aControllers,
 | |
|     nsTHashtable<nsCStringHashKey>& aCommandsHandled,
 | |
|     nsTArray<nsCString>& aEnabledCommands,
 | |
|     nsTArray<nsCString>& aDisabledCommands) {
 | |
|   uint32_t controllerCount;
 | |
|   aControllers->GetControllerCount(&controllerCount);
 | |
|   for (uint32_t c = 0; c < controllerCount; c++) {
 | |
|     nsCOMPtr<nsIController> controller;
 | |
|     aControllers->GetControllerAt(c, getter_AddRefs(controller));
 | |
| 
 | |
|     nsCOMPtr<nsICommandController> commandController(
 | |
|         do_QueryInterface(controller));
 | |
|     if (commandController) {
 | |
|       // All of our default command controllers have 20-60 commands.  Let's just
 | |
|       // leave enough space here for all of them so we probably don't need to
 | |
|       // heap-allocate.
 | |
|       AutoTArray<nsCString, 64> commands;
 | |
|       if (NS_SUCCEEDED(commandController->GetSupportedCommands(commands))) {
 | |
|         for (auto& commandStr : commands) {
 | |
|           // Use a hash to determine which commands have already been handled by
 | |
|           // earlier controllers, as the earlier controller's result should get
 | |
|           // priority.
 | |
|           if (aCommandsHandled.EnsureInserted(commandStr)) {
 | |
|             // We inserted a new entry into aCommandsHandled.
 | |
|             bool enabled = false;
 | |
|             controller->IsCommandEnabled(commandStr.get(), &enabled);
 | |
| 
 | |
|             if (enabled) {
 | |
|               aEnabledCommands.AppendElement(commandStr);
 | |
|             } else {
 | |
|               aDisabledCommands.AppendElement(commandStr);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::GetEnabledDisabledCommands(
 | |
|     nsTArray<nsCString>& aEnabledCommands,
 | |
|     nsTArray<nsCString>& aDisabledCommands) {
 | |
|   nsTHashtable<nsCStringHashKey> commandsHandled;
 | |
| 
 | |
|   nsCOMPtr<nsIControllers> controllers;
 | |
|   GetControllers(false, getter_AddRefs(controllers));
 | |
|   if (controllers) {
 | |
|     GetEnabledDisabledCommandsForControllers(
 | |
|         controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
 | |
|   nsFocusManager::GetFocusedDescendant(mWindow,
 | |
|                                        nsFocusManager::eIncludeAllDescendants,
 | |
|                                        getter_AddRefs(focusedWindow));
 | |
|   while (focusedWindow) {
 | |
|     focusedWindow->GetControllers(getter_AddRefs(controllers));
 | |
|     if (controllers) {
 | |
|       GetEnabledDisabledCommandsForControllers(
 | |
|           controllers, commandsHandled, aEnabledCommands, aDisabledCommands);
 | |
|     }
 | |
| 
 | |
|     nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(focusedWindow);
 | |
|     focusedWindow = win->GetPrivateParent();
 | |
|   }
 | |
| }
 | |
| 
 | |
| already_AddRefed<nsINode> nsWindowRoot::GetPopupNode() {
 | |
|   nsCOMPtr<nsINode> popupNode = do_QueryReferent(mPopupNode);
 | |
|   return popupNode.forget();
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::SetPopupNode(nsINode* aNode) {
 | |
|   mPopupNode = do_GetWeakReference(aNode);
 | |
| }
 | |
| 
 | |
| nsIGlobalObject* nsWindowRoot::GetParentObject() {
 | |
|   return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
 | |
| }
 | |
| 
 | |
| JSObject* nsWindowRoot::WrapObject(JSContext* aCx,
 | |
|                                    JS::Handle<JSObject*> aGivenProto) {
 | |
|   return mozilla::dom::WindowRoot_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::AddBrowser(mozilla::dom::BrowserParent* aBrowser) {
 | |
|   nsWeakPtr weakBrowser =
 | |
|       do_GetWeakReference(static_cast<nsIRemoteTab*>(aBrowser));
 | |
|   mWeakBrowsers.PutEntry(weakBrowser);
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::RemoveBrowser(mozilla::dom::BrowserParent* aBrowser) {
 | |
|   nsWeakPtr weakBrowser =
 | |
|       do_GetWeakReference(static_cast<nsIRemoteTab*>(aBrowser));
 | |
|   mWeakBrowsers.RemoveEntry(weakBrowser);
 | |
| }
 | |
| 
 | |
| void nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg) {
 | |
|   // Collect strong references to all browsers in a separate array in
 | |
|   // case aEnumFunc alters mWeakBrowsers.
 | |
|   nsTArray<RefPtr<BrowserParent>> browserParents;
 | |
|   for (auto iter = mWeakBrowsers.ConstIter(); !iter.Done(); iter.Next()) {
 | |
|     nsCOMPtr<nsIRemoteTab> browserParent(
 | |
|         do_QueryReferent(iter.Get()->GetKey()));
 | |
|     if (BrowserParent* tab = BrowserParent::GetFrom(browserParent)) {
 | |
|       browserParents.AppendElement(tab);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (uint32_t i = 0; i < browserParents.Length(); ++i) {
 | |
|     aEnumFunc(browserParents[i], aArg);
 | |
|   }
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| already_AddRefed<EventTarget> NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow) {
 | |
|   nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
 | |
| 
 | |
|   RefPtr<JSWindowActorService> wasvc = JSWindowActorService::GetSingleton();
 | |
|   if (wasvc) {
 | |
|     wasvc->RegisterWindowRoot(result);
 | |
|   }
 | |
| 
 | |
|   return result.forget();
 | |
| }
 |