/* -*- 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/. */ #ifndef mozilla_dom_EventTarget_h_ #define mozilla_dom_EventTarget_h_ #include "mozilla/dom/Nullable.h" #include "nsISupports.h" #include "nsWrapperCache.h" #include "nsAtom.h" class nsIDOMEventListener; class nsIGlobalObject; class nsINode; class nsPIDOMWindowInner; class nsPIDOMWindowOuter; class nsPIWindowRoot; namespace mozilla { class AsyncEventDispatcher; class ErrorResult; class EventChainPostVisitor; class EventChainPreVisitor; class EventChainVisitor; class EventListenerManager; namespace dom { class AddEventListenerOptionsOrBoolean; class Event; class EventListener; class EventListenerOptionsOrBoolean; class EventHandlerNonNull; class GlobalObject; class WindowProxyHolder; enum class CallerType : uint32_t; enum class EventCallbackDebuggerNotificationType : uint8_t; // IID for the dom::EventTarget interface #define NS_EVENTTARGET_IID \ { \ 0xde651c36, 0x0053, 0x4c67, { \ 0xb1, 0x3d, 0x67, 0xb9, 0x40, 0xfc, 0x82, 0xe4 \ } \ } class EventTarget : public nsISupports, public nsWrapperCache { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_EVENTTARGET_IID) // WebIDL API static already_AddRefed Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); void AddEventListener(const nsAString& aType, EventListener* aCallback, const AddEventListenerOptionsOrBoolean& aOptions, const Nullable& aWantsUntrusted, ErrorResult& aRv); void RemoveEventListener(const nsAString& aType, EventListener* aCallback, const EventListenerOptionsOrBoolean& aOptions, ErrorResult& aRv); protected: /** * This method allows addition of event listeners represented by * nsIDOMEventListener, with almost the same semantics as the * standard AddEventListener. The one difference is that it just * has a "use capture" boolean, not an EventListenerOptions. */ nsresult AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture, const Nullable& aWantsUntrusted); public: /** * Helper methods to make the nsIDOMEventListener version of * AddEventListener simpler to call for consumers. */ nsresult AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture) { return AddEventListener(aType, aListener, aUseCapture, Nullable()); } nsresult AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture, bool aWantsUntrusted) { return AddEventListener(aType, aListener, aUseCapture, Nullable(aWantsUntrusted)); } /** * This method allows the removal of event listeners represented by * nsIDOMEventListener from the event target, with the same semantics as the * standard RemoveEventListener. */ void RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture); /** * RemoveSystemEventListener() should be used if you have used * AddSystemEventListener(). */ void RemoveSystemEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture); /** * Add a system event listener with the default wantsUntrusted value. */ nsresult AddSystemEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture) { return AddSystemEventListener(aType, aListener, aUseCapture, Nullable()); } /** * Add a system event listener with the given wantsUntrusted value. */ nsresult AddSystemEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture, bool aWantsUntrusted) { return AddSystemEventListener(aType, aListener, aUseCapture, Nullable(aWantsUntrusted)); } virtual bool IsNode() const { return false; } inline nsINode* GetAsNode(); inline const nsINode* GetAsNode() const; inline nsINode* AsNode(); inline const nsINode* AsNode() const; virtual bool IsInnerWindow() const { return false; } virtual bool IsOuterWindow() const { return false; } virtual bool IsRootWindow() const { return false; } nsPIDOMWindowInner* GetAsWindowInner(); const nsPIDOMWindowInner* GetAsWindowInner() const; nsPIDOMWindowOuter* GetAsWindowOuter(); const nsPIDOMWindowOuter* GetAsWindowOuter() const; inline nsPIWindowRoot* GetAsWindowRoot(); inline const nsPIWindowRoot* GetAsWindowRoot() const; nsPIDOMWindowInner* AsWindowInner(); const nsPIDOMWindowInner* AsWindowInner() const; nsPIDOMWindowOuter* AsWindowOuter(); const nsPIDOMWindowOuter* AsWindowOuter() const; inline nsPIWindowRoot* AsWindowRoot(); inline const nsPIWindowRoot* AsWindowRoot() const; /** * Returns the EventTarget object which should be used as the target * of DOMEvents. * Usually |this| is returned, but for example Window (inner windw) returns * the WindowProxy (outer window). */ virtual EventTarget* GetTargetForDOMEvent() { return this; }; /** * Returns the EventTarget object which should be used as the target * of the event and when constructing event target chain. * Usually |this| is returned, but for example WindowProxy (outer window) * returns the Window (inner window). */ virtual EventTarget* GetTargetForEventTargetChain() { return this; } /** * The most general DispatchEvent method. This is the one the bindings call. */ // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual bool DispatchEvent(Event& aEvent, CallerType aCallerType, ErrorResult& aRv) = 0; /** * A version of DispatchEvent you can use if you really don't care whether it * succeeds or not and whether default is prevented or not. */ // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) MOZ_CAN_RUN_SCRIPT_BOUNDARY void DispatchEvent(Event& aEvent); /** * A version of DispatchEvent you can use if you really don't care whether * default is prevented or not. */ // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) MOZ_CAN_RUN_SCRIPT_BOUNDARY void DispatchEvent(Event& aEvent, ErrorResult& aRv); nsIGlobalObject* GetParentObject() const { return GetOwnerGlobal(); } // Note, this takes the type in onfoo form! EventHandlerNonNull* GetEventHandler(const nsAString& aType) { RefPtr type = NS_Atomize(aType); return GetEventHandler(type); } // Note, this takes the type in onfoo form! void SetEventHandler(const nsAString& aType, EventHandlerNonNull* aHandler, ErrorResult& rv); // For an event 'foo' aType will be 'onfoo'. virtual void EventListenerAdded(nsAtom* aType) {} // For an event 'foo' aType will be 'onfoo'. virtual void EventListenerRemoved(nsAtom* aType) {} // Returns an outer window that corresponds to the inner window this event // target is associated with. Will return null if the inner window is not the // current inner or if there is no window around at all. Nullable GetOwnerGlobalForBindings(); virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() = 0; // The global object this event target is associated with, if any. // This may be an inner window or some other global object. This // will never be an outer window. virtual nsIGlobalObject* GetOwnerGlobal() const = 0; /** * Get the event listener manager, creating it if it does not already exist. */ virtual EventListenerManager* GetOrCreateListenerManager() = 0; /** * Get the event listener manager, returning null if it does not already * exist. */ virtual EventListenerManager* GetExistingListenerManager() const = 0; virtual Maybe GetDebuggerNotificationType() const { return Nothing(); } // Called from AsyncEventDispatcher to notify it is running. virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {} // Used by APZ to determine whether this event target has non-chrome event // listeners for untrusted key events. bool HasNonSystemGroupListenersForUntrustedKeyEvents() const; // Used by APZ to determine whether this event target has non-chrome and // non-passive event listeners for untrusted key events. bool HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents() const; virtual bool IsApzAware() const; /** * Called before the capture phase of the event flow. * This is used to create the event target chain and implementations * should set the necessary members of EventChainPreVisitor. * At least aVisitor.mCanHandle must be set, * usually also aVisitor.mParentTarget if mCanHandle is true. * mCanHandle says that this object can handle the aVisitor.mEvent event and * the mParentTarget is the possible parent object for the event target chain. * @see EventDispatcher.h for more documentation about aVisitor. * * @param aVisitor the visitor object which is used to create the * event target chain for event dispatching. * * @note Only EventDispatcher should call this method. */ virtual void GetEventTargetParent(EventChainPreVisitor& aVisitor) = 0; /** * Called before the capture phase of the event flow and after event target * chain creation. This is used to handle things that must be executed before * dispatching the event to DOM. */ virtual nsresult PreHandleEvent(EventChainVisitor& aVisitor) { return NS_OK; } /** * If EventChainPreVisitor.mWantsWillHandleEvent is set true, * called just before possible event handlers on this object will be called. */ virtual void WillHandleEvent(EventChainPostVisitor& aVisitor) {} /** * Called after the bubble phase of the system event group. * The default handling of the event should happen here. * @param aVisitor the visitor object which is used during post handling. * * @see EventDispatcher.h for documentation about aVisitor. * @note Only EventDispatcher should call this method. */ MOZ_CAN_RUN_SCRIPT virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) = 0; protected: EventHandlerNonNull* GetEventHandler(nsAtom* aType); void SetEventHandler(nsAtom* aType, EventHandlerNonNull* aHandler); /** * Hook for AddEventListener that allows it to compute the right * wantsUntrusted boolean when one is not provided. If this returns failure, * the listener will not be added. * * This hook will NOT be called unless aWantsUntrusted is null in * AddEventListener. If you need to take action when event listeners are * added, use EventListenerAdded. Especially because not all event listener * additions go through AddEventListener! */ virtual bool ComputeDefaultWantsUntrusted(ErrorResult& aRv) = 0; /** * A method to compute the right wantsUntrusted value for AddEventListener. * This will call the above hook as needed. * * If aOptions is non-null, and it contains a value for mWantUntrusted, that * value takes precedence over aWantsUntrusted. */ bool ComputeWantsUntrusted(const Nullable& aWantsUntrusted, const AddEventListenerOptionsOrBoolean* aOptions, ErrorResult& aRv); /** * addSystemEventListener() adds an event listener of aType to the system * group. Typically, core code should use the system group for listening to * content (i.e., non-chrome) element's events. If core code uses * EventTarget::AddEventListener for a content node, it means * that the listener cannot listen to the event when web content calls * stopPropagation() of the event. * * @param aType An event name you're going to handle. * @param aListener An event listener. * @param aUseCapture true if you want to listen the event in capturing * phase. Otherwise, false. * @param aWantsUntrusted true if you want to handle untrusted events. * false if not. * Null if you want the default behavior. */ nsresult AddSystemEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture, const Nullable& aWantsUntrusted); }; NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID) #define NS_IMPL_FROMEVENTTARGET_GENERIC(_class, _check, _const) \ template \ static auto FromEventTarget(_const T& aEventTarget) \ ->decltype(static_cast<_const _class*>(&aEventTarget)) { \ return aEventTarget._check ? static_cast<_const _class*>(&aEventTarget) \ : nullptr; \ } \ template \ static _const _class* FromEventTarget(_const T* aEventTarget) { \ MOZ_DIAGNOSTIC_ASSERT(aEventTarget); \ return FromEventTarget(*aEventTarget); \ } \ template \ static _const _class* FromEventTargetOrNull(_const T* aEventTarget) { \ return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr; \ } #define NS_IMPL_FROMEVENTTARGET_HELPER(_class, _check) \ NS_IMPL_FROMEVENTTARGET_GENERIC(_class, _check, ) \ NS_IMPL_FROMEVENTTARGET_GENERIC(_class, _check, const) \ template \ static _class* FromEventTarget(T&& aEventTarget) { \ MOZ_DIAGNOSTIC_ASSERT(!!aEventTarget); \ /* We need the double-cast in case aEventTarget is a smartptr. Those */ \ /* can cast to superclasses of the type they're templated on, */ \ /* but not directly to subclasses. */ \ return aEventTarget->_check \ ? static_cast<_class*>(static_cast(aEventTarget)) \ : nullptr; \ } \ template \ static _class* FromEventTargetOrNull(T&& aEventTarget) { \ return aEventTarget ? FromEventTarget(aEventTarget) : nullptr; \ } // Unfortunately, nsPIDOMWindowInner and nsPIDOMWindowOuter do not inherit // EventTarget directly, but they are public interfaces which should have // these helper methods. Therefore, we cannot cast from EventTarget to // the interfaces in their header file. That's the reason why we cannot use // the zero cost casts nor decltype for the template methods which take a // reference. #define NS_IMPL_FROMEVENTTARGET_GENERIC_WITH_GETTER(_class, _getter, _const) \ static _const _class* FromEventTarget( \ _const mozilla::dom::EventTarget& aEventTarget) { \ return aEventTarget._getter; \ } \ template \ static _const _class* FromEventTarget(_const T* aEventTarget) { \ return aEventTarget->_getter; \ } \ template \ static _const _class* FromEventTargetOrNull(_const T* aEventTarget) { \ return aEventTarget ? aEventTarget->_getter : nullptr; \ } #define NS_IMPL_FROMEVENTTARGET_HELPER_WITH_GETTER_INNER(_class, _getter) \ template \ static _class* FromEventTarget(T&& aEventTarget) { \ return aEventTarget->_getter; \ } \ template \ static _class* FromEventTargetOrNull(T&& aEventTarget) { \ return aEventTarget ? aEventTarget->_getter : nullptr; \ } #define NS_IMPL_FROMEVENTTARGET_HELPER_WITH_GETTER(_class, _getter) \ NS_IMPL_FROMEVENTTARGET_GENERIC_WITH_GETTER(_class, _getter, ) \ NS_IMPL_FROMEVENTTARGET_GENERIC_WITH_GETTER(_class, _getter, const) \ NS_IMPL_FROMEVENTTARGET_HELPER_WITH_GETTER_INNER(_class, _getter) } // namespace dom } // namespace mozilla #endif // mozilla_dom_EventTarget_h_