/* -*- 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_1(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_ISUPPORTS1(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; }