michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "EventListenerService.h" michael@0: #ifdef MOZ_JSDEBUGGER michael@0: #include "jsdIDebuggerService.h" michael@0: #endif michael@0: #include "mozilla/BasicEvents.h" michael@0: #include "mozilla/EventDispatcher.h" michael@0: #include "mozilla/EventListenerManager.h" michael@0: #include "mozilla/JSEventHandler.h" michael@0: #include "mozilla/Maybe.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsCxPusher.h" michael@0: #include "nsDOMClassInfoID.h" michael@0: #include "nsIXPConnect.h" michael@0: #include "nsJSUtils.h" michael@0: #include "nsMemory.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: using namespace dom; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::EventListenerInfo michael@0: ******************************************************************************/ michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(EventListenerInfo, mListener) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerInfo) michael@0: NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerInfo) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerInfo) michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::GetType(nsAString& aType) michael@0: { michael@0: aType = mType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::GetCapturing(bool* aCapturing) michael@0: { michael@0: *aCapturing = mCapturing; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::GetAllowsUntrusted(bool* aAllowsUntrusted) michael@0: { michael@0: *aAllowsUntrusted = mAllowsUntrusted; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::GetInSystemEventGroup(bool* aInSystemEventGroup) michael@0: { michael@0: *aInSystemEventGroup = mInSystemEventGroup; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::GetListenerObject(JSContext* aCx, michael@0: JS::MutableHandle aObject) michael@0: { michael@0: Maybe ac; michael@0: GetJSVal(aCx, ac, aObject); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::EventListenerService michael@0: ******************************************************************************/ michael@0: michael@0: NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService) michael@0: michael@0: bool michael@0: EventListenerInfo::GetJSVal(JSContext* aCx, michael@0: Maybe& aAc, michael@0: JS::MutableHandle aJSVal) michael@0: { michael@0: aJSVal.setNull(); michael@0: nsCOMPtr wrappedJS = do_QueryInterface(mListener); michael@0: if (wrappedJS) { michael@0: JS::Rooted object(aCx, wrappedJS->GetJSObject()); michael@0: if (!object) { michael@0: return false; michael@0: } michael@0: aAc.construct(aCx, object); michael@0: aJSVal.setObject(*object); michael@0: return true; michael@0: } michael@0: michael@0: nsCOMPtr jsHandler = do_QueryInterface(mListener); michael@0: if (jsHandler && jsHandler->GetTypedEventHandler().HasEventHandler()) { michael@0: JS::Handle handler = michael@0: jsHandler->GetTypedEventHandler().Ptr()->Callable(); michael@0: if (handler) { michael@0: aAc.construct(aCx, handler); michael@0: aJSVal.setObject(*handler); michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::ToSource(nsAString& aResult) michael@0: { michael@0: aResult.SetIsVoid(true); michael@0: michael@0: AutoSafeJSContext cx; michael@0: Maybe ac; michael@0: JS::Rooted v(cx); michael@0: if (GetJSVal(cx, ac, &v)) { michael@0: JSString* str = JS_ValueToSource(cx, v); michael@0: if (str) { michael@0: nsDependentJSString depStr; michael@0: if (depStr.init(cx, str)) { michael@0: aResult.Assign(depStr); michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerInfo::GetDebugObject(nsISupports** aRetVal) michael@0: { michael@0: *aRetVal = nullptr; michael@0: michael@0: #ifdef MOZ_JSDEBUGGER michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr jsd = michael@0: do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv); michael@0: NS_ENSURE_SUCCESS(rv, NS_OK); michael@0: michael@0: bool isOn = false; michael@0: jsd->GetIsOn(&isOn); michael@0: NS_ENSURE_TRUE(isOn, NS_OK); michael@0: michael@0: AutoSafeJSContext cx; michael@0: Maybe ac; michael@0: JS::Rooted v(cx); michael@0: if (GetJSVal(cx, ac, &v)) { michael@0: nsCOMPtr jsdValue; michael@0: rv = jsd->WrapValue(v, getter_AddRefs(jsdValue)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: jsdValue.forget(aRetVal); michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget, michael@0: uint32_t* aCount, michael@0: nsIEventListenerInfo*** aOutArray) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEventTarget); michael@0: *aCount = 0; michael@0: *aOutArray = nullptr; michael@0: nsCOMArray listenerInfos; michael@0: michael@0: nsCOMPtr eventTarget = do_QueryInterface(aEventTarget); michael@0: NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); michael@0: michael@0: EventListenerManager* elm = eventTarget->GetExistingListenerManager(); michael@0: if (elm) { michael@0: elm->GetListenerInfo(&listenerInfos); michael@0: } michael@0: michael@0: int32_t count = listenerInfos.Count(); michael@0: if (count == 0) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: *aOutArray = michael@0: static_cast( michael@0: nsMemory::Alloc(sizeof(nsIEventListenerInfo*) * count)); michael@0: NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: NS_ADDREF((*aOutArray)[i] = listenerInfos[i]); michael@0: } michael@0: *aCount = count; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget, michael@0: uint32_t* aCount, michael@0: nsIDOMEventTarget*** aOutArray) michael@0: { michael@0: *aCount = 0; michael@0: *aOutArray = nullptr; michael@0: NS_ENSURE_ARG(aEventTarget); michael@0: WidgetEvent event(true, NS_EVENT_NULL); michael@0: nsCOMArray targets; michael@0: nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event, michael@0: nullptr, nullptr, nullptr, &targets); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: int32_t count = targets.Count(); michael@0: if (count == 0) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: *aOutArray = michael@0: static_cast( michael@0: nsMemory::Alloc(sizeof(nsIDOMEventTarget*) * count)); michael@0: NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: NS_ADDREF((*aOutArray)[i] = targets[i]); michael@0: } michael@0: *aCount = count; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget, michael@0: const nsAString& aType, michael@0: bool* aRetVal) michael@0: { michael@0: nsCOMPtr eventTarget = do_QueryInterface(aEventTarget); michael@0: NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); michael@0: michael@0: EventListenerManager* elm = eventTarget->GetExistingListenerManager(); michael@0: *aRetVal = elm && elm->HasListenersFor(aType); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget, michael@0: const nsAString& aType, michael@0: nsIDOMEventListener* aListener, michael@0: bool aUseCapture) michael@0: { michael@0: NS_PRECONDITION(aTarget, "Missing target"); michael@0: NS_PRECONDITION(aListener, "Missing listener"); michael@0: michael@0: nsCOMPtr eventTarget = do_QueryInterface(aTarget); michael@0: NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); michael@0: michael@0: EventListenerManager* manager = eventTarget->GetOrCreateListenerManager(); michael@0: NS_ENSURE_STATE(manager); michael@0: michael@0: EventListenerFlags flags = michael@0: aUseCapture ? TrustedEventsAtSystemGroupCapture() : michael@0: TrustedEventsAtSystemGroupBubble(); michael@0: manager->AddEventListenerByType(aListener, aType, flags); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget, michael@0: const nsAString& aType, michael@0: nsIDOMEventListener* aListener, michael@0: bool aUseCapture) michael@0: { michael@0: NS_PRECONDITION(aTarget, "Missing target"); michael@0: NS_PRECONDITION(aListener, "Missing listener"); michael@0: michael@0: nsCOMPtr eventTarget = do_QueryInterface(aTarget); michael@0: NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); michael@0: michael@0: EventListenerManager* manager = eventTarget->GetExistingListenerManager(); michael@0: if (manager) { michael@0: EventListenerFlags flags = michael@0: aUseCapture ? TrustedEventsAtSystemGroupCapture() : michael@0: TrustedEventsAtSystemGroupBubble(); michael@0: manager->RemoveEventListenerByType(aListener, aType, flags); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget, michael@0: nsIDOMEventListener* aListener, michael@0: bool aUseCapture, michael@0: bool aWantsUntrusted, michael@0: bool aSystemEventGroup) michael@0: { michael@0: NS_ENSURE_STATE(aTarget && aListener); michael@0: michael@0: nsCOMPtr eventTarget = do_QueryInterface(aTarget); michael@0: NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); michael@0: michael@0: EventListenerManager* manager = eventTarget->GetOrCreateListenerManager(); michael@0: NS_ENSURE_STATE(manager); michael@0: manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted, michael@0: aSystemEventGroup); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: EventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget, michael@0: nsIDOMEventListener* aListener, michael@0: bool aUseCapture, michael@0: bool aSystemEventGroup) michael@0: { michael@0: NS_ENSURE_STATE(aTarget && aListener); michael@0: michael@0: nsCOMPtr eventTarget = do_QueryInterface(aTarget); michael@0: NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); michael@0: michael@0: EventListenerManager* manager = eventTarget->GetExistingListenerManager(); michael@0: if (manager) { michael@0: manager->RemoveListenerForAllEvents(aListener, aUseCapture, aSystemEventGroup); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: michael@0: nsresult michael@0: NS_NewEventListenerService(nsIEventListenerService** aResult) michael@0: { michael@0: *aResult = new mozilla::EventListenerService(); michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: }