diff -r 000000000000 -r 6474c204b198 dom/events/EventListenerService.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/events/EventListenerService.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "EventListenerService.h" +#ifdef MOZ_JSDEBUGGER +#include "jsdIDebuggerService.h" +#endif +#include "mozilla/BasicEvents.h" +#include "mozilla/EventDispatcher.h" +#include "mozilla/EventListenerManager.h" +#include "mozilla/JSEventHandler.h" +#include "mozilla/Maybe.h" +#include "nsCOMArray.h" +#include "nsCxPusher.h" +#include "nsDOMClassInfoID.h" +#include "nsIXPConnect.h" +#include "nsJSUtils.h" +#include "nsMemory.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { + +using namespace dom; + +/****************************************************************************** + * mozilla::EventListenerInfo + ******************************************************************************/ + +NS_IMPL_CYCLE_COLLECTION(EventListenerInfo, mListener) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerInfo) + NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerInfo) +NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerInfo) + +NS_IMETHODIMP +EventListenerInfo::GetType(nsAString& aType) +{ + aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +EventListenerInfo::GetCapturing(bool* aCapturing) +{ + *aCapturing = mCapturing; + return NS_OK; +} + +NS_IMETHODIMP +EventListenerInfo::GetAllowsUntrusted(bool* aAllowsUntrusted) +{ + *aAllowsUntrusted = mAllowsUntrusted; + return NS_OK; +} + +NS_IMETHODIMP +EventListenerInfo::GetInSystemEventGroup(bool* aInSystemEventGroup) +{ + *aInSystemEventGroup = mInSystemEventGroup; + return NS_OK; +} + +NS_IMETHODIMP +EventListenerInfo::GetListenerObject(JSContext* aCx, + JS::MutableHandle aObject) +{ + Maybe ac; + GetJSVal(aCx, ac, aObject); + return NS_OK; +} + +/****************************************************************************** + * mozilla::EventListenerService + ******************************************************************************/ + +NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService) + +bool +EventListenerInfo::GetJSVal(JSContext* aCx, + Maybe& aAc, + JS::MutableHandle aJSVal) +{ + aJSVal.setNull(); + nsCOMPtr wrappedJS = do_QueryInterface(mListener); + if (wrappedJS) { + JS::Rooted object(aCx, wrappedJS->GetJSObject()); + if (!object) { + return false; + } + aAc.construct(aCx, object); + aJSVal.setObject(*object); + return true; + } + + nsCOMPtr jsHandler = do_QueryInterface(mListener); + if (jsHandler && jsHandler->GetTypedEventHandler().HasEventHandler()) { + JS::Handle handler = + jsHandler->GetTypedEventHandler().Ptr()->Callable(); + if (handler) { + aAc.construct(aCx, handler); + aJSVal.setObject(*handler); + return true; + } + } + return false; +} + +NS_IMETHODIMP +EventListenerInfo::ToSource(nsAString& aResult) +{ + aResult.SetIsVoid(true); + + AutoSafeJSContext cx; + Maybe ac; + JS::Rooted v(cx); + if (GetJSVal(cx, ac, &v)) { + JSString* str = JS_ValueToSource(cx, v); + if (str) { + nsDependentJSString depStr; + if (depStr.init(cx, str)) { + aResult.Assign(depStr); + } + } + } + return NS_OK; +} + +NS_IMETHODIMP +EventListenerInfo::GetDebugObject(nsISupports** aRetVal) +{ + *aRetVal = nullptr; + +#ifdef MOZ_JSDEBUGGER + nsresult rv = NS_OK; + nsCOMPtr jsd = + do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv); + NS_ENSURE_SUCCESS(rv, NS_OK); + + bool isOn = false; + jsd->GetIsOn(&isOn); + NS_ENSURE_TRUE(isOn, NS_OK); + + AutoSafeJSContext cx; + Maybe ac; + JS::Rooted v(cx); + if (GetJSVal(cx, ac, &v)) { + nsCOMPtr jsdValue; + rv = jsd->WrapValue(v, getter_AddRefs(jsdValue)); + NS_ENSURE_SUCCESS(rv, rv); + jsdValue.forget(aRetVal); + } +#endif + + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget, + uint32_t* aCount, + nsIEventListenerInfo*** aOutArray) +{ + NS_ENSURE_ARG_POINTER(aEventTarget); + *aCount = 0; + *aOutArray = nullptr; + nsCOMArray listenerInfos; + + nsCOMPtr eventTarget = do_QueryInterface(aEventTarget); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); + + EventListenerManager* elm = eventTarget->GetExistingListenerManager(); + if (elm) { + elm->GetListenerInfo(&listenerInfos); + } + + int32_t count = listenerInfos.Count(); + if (count == 0) { + return NS_OK; + } + + *aOutArray = + static_cast( + nsMemory::Alloc(sizeof(nsIEventListenerInfo*) * count)); + NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY); + + for (int32_t i = 0; i < count; ++i) { + NS_ADDREF((*aOutArray)[i] = listenerInfos[i]); + } + *aCount = count; + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget, + uint32_t* aCount, + nsIDOMEventTarget*** aOutArray) +{ + *aCount = 0; + *aOutArray = nullptr; + NS_ENSURE_ARG(aEventTarget); + WidgetEvent event(true, NS_EVENT_NULL); + nsCOMArray targets; + nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event, + nullptr, nullptr, nullptr, &targets); + NS_ENSURE_SUCCESS(rv, rv); + int32_t count = targets.Count(); + if (count == 0) { + return NS_OK; + } + + *aOutArray = + static_cast( + nsMemory::Alloc(sizeof(nsIDOMEventTarget*) * count)); + NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY); + + for (int32_t i = 0; i < count; ++i) { + NS_ADDREF((*aOutArray)[i] = targets[i]); + } + *aCount = count; + + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget, + const nsAString& aType, + bool* aRetVal) +{ + nsCOMPtr eventTarget = do_QueryInterface(aEventTarget); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); + + EventListenerManager* elm = eventTarget->GetExistingListenerManager(); + *aRetVal = elm && elm->HasListenersFor(aType); + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget, + const nsAString& aType, + nsIDOMEventListener* aListener, + bool aUseCapture) +{ + NS_PRECONDITION(aTarget, "Missing target"); + NS_PRECONDITION(aListener, "Missing listener"); + + nsCOMPtr eventTarget = do_QueryInterface(aTarget); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); + + EventListenerManager* manager = eventTarget->GetOrCreateListenerManager(); + NS_ENSURE_STATE(manager); + + EventListenerFlags flags = + aUseCapture ? TrustedEventsAtSystemGroupCapture() : + TrustedEventsAtSystemGroupBubble(); + manager->AddEventListenerByType(aListener, aType, flags); + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget, + const nsAString& aType, + nsIDOMEventListener* aListener, + bool aUseCapture) +{ + NS_PRECONDITION(aTarget, "Missing target"); + NS_PRECONDITION(aListener, "Missing listener"); + + nsCOMPtr eventTarget = do_QueryInterface(aTarget); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); + + EventListenerManager* manager = eventTarget->GetExistingListenerManager(); + if (manager) { + EventListenerFlags flags = + aUseCapture ? TrustedEventsAtSystemGroupCapture() : + TrustedEventsAtSystemGroupBubble(); + manager->RemoveEventListenerByType(aListener, aType, flags); + } + + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget, + nsIDOMEventListener* aListener, + bool aUseCapture, + bool aWantsUntrusted, + bool aSystemEventGroup) +{ + NS_ENSURE_STATE(aTarget && aListener); + + nsCOMPtr eventTarget = do_QueryInterface(aTarget); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); + + EventListenerManager* manager = eventTarget->GetOrCreateListenerManager(); + NS_ENSURE_STATE(manager); + manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted, + aSystemEventGroup); + return NS_OK; +} + +NS_IMETHODIMP +EventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget, + nsIDOMEventListener* aListener, + bool aUseCapture, + bool aSystemEventGroup) +{ + NS_ENSURE_STATE(aTarget && aListener); + + nsCOMPtr eventTarget = do_QueryInterface(aTarget); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); + + EventListenerManager* manager = eventTarget->GetExistingListenerManager(); + if (manager) { + manager->RemoveListenerForAllEvents(aListener, aUseCapture, aSystemEventGroup); + } + return NS_OK; +} + +} // namespace mozilla + +nsresult +NS_NewEventListenerService(nsIEventListenerService** aResult) +{ + *aResult = new mozilla::EventListenerService(); + NS_ADDREF(*aResult); + return NS_OK; +}