summaryrefslogtreecommitdiffstats
path: root/dom/base/nsWindowRoot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsWindowRoot.cpp')
-rw-r--r--dom/base/nsWindowRoot.cpp435
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();
+}