diff options
Diffstat (limited to 'dom/base/nsWindowRoot.cpp')
-rw-r--r-- | dom/base/nsWindowRoot.cpp | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/dom/base/nsWindowRoot.cpp b/dom/base/nsWindowRoot.cpp new file mode 100644 index 000000000..b839a0ee5 --- /dev/null +++ b/dom/base/nsWindowRoot.cpp @@ -0,0 +1,435 @@ +/* -*- 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 "nsIDOMHTMLInputElement.h" +#include "nsIDOMHTMLTextAreaElement.h" +#include "nsIControllers.h" +#include "nsIController.h" +#include "xpcpublic.h" +#include "nsCycleCollectionParticipant.h" +#include "mozilla/dom/TabParent.h" + +#ifdef MOZ_XUL +#include "nsIDOMXULElement.h" +#endif + +using namespace mozilla; +using namespace mozilla::dom; + +nsWindowRoot::nsWindowRoot(nsPIDOMWindowOuter* aWindow) +{ + mWindow = aWindow; + MOZ_ASSERT(mWindow->IsOuterWindow()); + + // 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(); + } +} + +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_AMBIGUOUS(nsISupports, nsIDOMEventTarget) + NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot) + NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) + NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot) + +NS_IMPL_DOMTARGET_DEFAULTS(nsWindowRoot) + +NS_IMETHODIMP +nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture) +{ + if (RefPtr<EventListenerManager> elm = GetExistingListenerManager()) { + elm->RemoveEventListener(aType, aListener, aUseCapture); + } + return NS_OK; +} + +NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot) + +NS_IMETHODIMP +nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal) +{ + nsEventStatus status = nsEventStatus_eIgnore; + nsresult rv = EventDispatcher::DispatchDOMEvent( + static_cast<EventTarget*>(this), nullptr, aEvt, nullptr, &status); + *aRetVal = (status != nsEventStatus_eConsumeNoDefault); + return rv; +} + +nsresult +nsWindowRoot::DispatchDOMEvent(WidgetEvent* aEvent, + nsIDOMEvent* aDOMEvent, + nsPresContext* aPresContext, + nsEventStatus* aEventStatus) +{ + return EventDispatcher::DispatchDOMEvent(static_cast<EventTarget*>(this), + aEvent, aDOMEvent, + aPresContext, aEventStatus); +} + +NS_IMETHODIMP +nsWindowRoot::AddEventListener(const nsAString& aType, + nsIDOMEventListener *aListener, + bool aUseCapture, bool aWantsUntrusted, + uint8_t aOptionalArgc) +{ + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, + "Won't check if this is chrome, you want to set " + "aWantsUntrusted to false or make the aWantsUntrusted " + "explicit by making optional_argc non-zero."); + + EventListenerManager* elm = GetOrCreateListenerManager(); + NS_ENSURE_STATE(elm); + elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); + return NS_OK; +} + +void +nsWindowRoot::AddEventListener(const nsAString& aType, + EventListener* aListener, + const AddEventListenerOptionsOrBoolean& aOptions, + const Nullable<bool>& aWantsUntrusted, + ErrorResult& aRv) +{ + bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value(); + EventListenerManager* elm = GetOrCreateListenerManager(); + if (!elm) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return; + } + elm->AddEventListener(aType, aListener, aOptions, wantsUntrusted); +} + + +NS_IMETHODIMP +nsWindowRoot::AddSystemEventListener(const nsAString& aType, + nsIDOMEventListener *aListener, + bool aUseCapture, + bool aWantsUntrusted, + uint8_t aOptionalArgc) +{ + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, + "Won't check if this is chrome, you want to set " + "aWantsUntrusted to false or make the aWantsUntrusted " + "explicit by making optional_argc non-zero."); + + return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, + aWantsUntrusted); +} + +EventListenerManager* +nsWindowRoot::GetOrCreateListenerManager() +{ + if (!mListenerManager) { + mListenerManager = + new EventListenerManager(static_cast<EventTarget*>(this)); + } + + return mListenerManager; +} + +EventListenerManager* +nsWindowRoot::GetExistingListenerManager() const +{ + return mListenerManager; +} + +nsIScriptContext* +nsWindowRoot::GetContextForEventHandlers(nsresult* aRv) +{ + *aRv = NS_OK; + return nullptr; +} + +nsresult +nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor) +{ + aVisitor.mCanHandle = true; + aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119 + // To keep mWindow alive + aVisitor.mItemData = static_cast<nsISupports *>(mWindow); + aVisitor.mParentTarget = mParent; + return NS_OK; +} + +nsresult +nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) +{ + return NS_OK; +} + +nsPIDOMWindowOuter* +nsWindowRoot::GetOwnerGlobalForBindings() +{ + return GetWindow(); +} + +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(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. + + nsCOMPtr<nsPIDOMWindowOuter> focusedWindow; + nsIContent* focusedContent = + nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); + if (focusedContent) { +#ifdef MOZ_XUL + nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(focusedContent)); + if (xulElement) + return xulElement->GetControllers(aResult); +#endif + + nsCOMPtr<nsIDOMHTMLTextAreaElement> htmlTextArea = + do_QueryInterface(focusedContent); + if (htmlTextArea) + return htmlTextArea->GetControllers(aResult); + + nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement = + do_QueryInterface(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, + nsIController** _retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nullptr; + + { + nsCOMPtr<nsIControllers> controllers; + GetControllers(getter_AddRefs(controllers)); + if (controllers) { + nsCOMPtr<nsIController> controller; + controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller)); + if (controller) { + controller.forget(_retval); + return NS_OK; + } + } + } + + nsCOMPtr<nsPIDOMWindowOuter> focusedWindow; + nsFocusManager::GetFocusedDescendant(mWindow, true, 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? + nsGlobalWindow *win = nsGlobalWindow::Cast(focusedWindow); + focusedWindow = win->GetPrivateParent(); + } + + return NS_OK; +} + +void +nsWindowRoot::GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers, + nsTHashtable<nsCharPtrHashKey>& 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) { + uint32_t commandsCount; + char** commands; + if (NS_SUCCEEDED(commandController->GetSupportedCommands(&commandsCount, &commands))) { + for (uint32_t e = 0; e < commandsCount; e++) { + // 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.Contains(commands[e])) { + aCommandsHandled.PutEntry(commands[e]); + + bool enabled = false; + controller->IsCommandEnabled(commands[e], &enabled); + + const nsDependentCSubstring commandStr(commands[e], strlen(commands[e])); + if (enabled) { + aEnabledCommands.AppendElement(commandStr); + } else { + aDisabledCommands.AppendElement(commandStr); + } + } + } + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(commandsCount, commands); + } + } + } +} + +void +nsWindowRoot::GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands, + nsTArray<nsCString>& aDisabledCommands) +{ + nsTHashtable<nsCharPtrHashKey> commandsHandled; + + nsCOMPtr<nsIControllers> controllers; + GetControllers(getter_AddRefs(controllers)); + if (controllers) { + GetEnabledDisabledCommandsForControllers(controllers, commandsHandled, + aEnabledCommands, aDisabledCommands); + } + + nsCOMPtr<nsPIDOMWindowOuter> focusedWindow; + nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); + while (focusedWindow) { + focusedWindow->GetControllers(getter_AddRefs(controllers)); + if (controllers) { + GetEnabledDisabledCommandsForControllers(controllers, commandsHandled, + aEnabledCommands, aDisabledCommands); + } + + nsGlobalWindow* win = nsGlobalWindow::Cast(focusedWindow); + focusedWindow = win->GetPrivateParent(); + } +} + +nsIDOMNode* +nsWindowRoot::GetPopupNode() +{ + nsCOMPtr<nsIDOMNode> popupNode = do_QueryReferent(mPopupNode); + return popupNode; +} + +void +nsWindowRoot::SetPopupNode(nsIDOMNode* 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::WindowRootBinding::Wrap(aCx, this, aGivenProto); +} + +void +nsWindowRoot::AddBrowser(mozilla::dom::TabParent* aBrowser) +{ + nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser)); + mWeakBrowsers.PutEntry(weakBrowser); +} + +void +nsWindowRoot::RemoveBrowser(mozilla::dom::TabParent* aBrowser) +{ + nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(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<TabParent>> tabParents; + for (auto iter = mWeakBrowsers.ConstIter(); !iter.Done(); iter.Next()) { + nsCOMPtr<nsITabParent> tabParent(do_QueryReferent(iter.Get()->GetKey())); + if (TabParent* tab = TabParent::GetFrom(tabParent)) { + tabParents.AppendElement(tab); + } + } + + for (uint32_t i = 0; i < tabParents.Length(); ++i) { + aEnumFunc(tabParents[i], aArg); + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +already_AddRefed<EventTarget> +NS_NewWindowRoot(nsPIDOMWindowOuter* aWindow) +{ + nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow); + return result.forget(); +} |