Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
void SetIsOnMainThread() {
MOZ_ASSERT(NS_IsMainThread());
mRefCnt.SetIsOnMainThread();
}
#ifndef NS_BUILD_REFCNT_LOGGING
MozExternalRefCountType NonVirtualAddRef();
MozExternalRefCountType NonVirtualRelease();
#endif
// WebIDL API
static already_AddRefed<EventTarget> Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv);
void AddEventListener(const nsAString& aType, EventListener* aCallback,
const AddEventListenerOptionsOrBoolean& aOptions,
const Nullable<bool>& 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<bool>& 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<bool>());
}
nsresult AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener, bool aUseCapture,
bool aWantsUntrusted) {
return AddEventListener(aType, aListener, aUseCapture,
Nullable<bool>(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<bool>());
}
/**
* 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<bool>(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* GetAsInnerWindow();
const nsPIDOMWindowInner* GetAsInnerWindow() const;
nsPIDOMWindowOuter* GetAsOuterWindow();
const nsPIDOMWindowOuter* GetAsOuterWindow() const;
inline nsPIWindowRoot* GetAsWindowRoot();
inline const nsPIWindowRoot* GetAsWindowRoot() const;
nsPIDOMWindowInner* AsInnerWindow();
const nsPIDOMWindowInner* AsInnerWindow() const;
nsPIDOMWindowOuter* AsOuterWindow();
const nsPIDOMWindowOuter* AsOuterWindow() 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<nsAtom> 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<WindowProxyHolder> 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<EventCallbackDebuggerNotificationType>
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 on the activation target during dispatch of activation events.
*/
virtual void LegacyPreActivationBehavior(EventChainVisitor& aVisitor) {}
/**
* Called on the activation target during dispatch of activation events.
*/
MOZ_CAN_RUN_SCRIPT
virtual void ActivationBehavior(EventChainPostVisitor& aVisitor) {}
/**
* Called on the activation target during dispatch of activation events.
*/
virtual void LegacyCanceledActivationBehavior(
EventChainPostVisitor& aVisitor) {}
/**
* 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<bool>& 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<bool>& aWantsUntrusted);
};
NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)
#define NS_IMPL_FROMEVENTTARGET_GENERIC(_class, _check, _const) \
template <typename T> \
static auto FromEventTarget(_const T& aEventTarget) \
-> decltype(static_cast<_const _class*>(&aEventTarget)) { \
return aEventTarget._check ? static_cast<_const _class*>(&aEventTarget) \
: nullptr; \
} \
template <typename T> \
static _const _class* FromEventTarget(_const T* aEventTarget) { \
MOZ_DIAGNOSTIC_ASSERT(aEventTarget); \
return FromEventTarget(*aEventTarget); \
} \
template <typename T> \
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 <typename T> \
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<EventTarget*>(aEventTarget)) \
: nullptr; \
} \
template <typename T> \
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 <typename T> \
static _const _class* FromEventTarget(_const T* aEventTarget) { \
return aEventTarget->_getter; \
} \
template <typename T> \
static _const _class* FromEventTargetOrNull(_const T* aEventTarget) { \
return aEventTarget ? aEventTarget->_getter : nullptr; \
}
#define NS_IMPL_FROMEVENTTARGET_HELPER_WITH_GETTER_INNER(_class, _getter) \
template <typename T> \
static _class* FromEventTarget(T&& aEventTarget) { \
return aEventTarget->_getter; \
} \
template <typename T> \
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
#ifdef NS_BUILD_REFCNT_LOGGING
# define NON_VIRTUAL_ADDREF_RELEASE(class_) /* Nothing */
#else
# define NON_VIRTUAL_ADDREF_RELEASE(class_) \
namespace mozilla { \
template <> \
class RefPtrTraits<class_> { \
public: \
static void Release(class_* aObject) { aObject->NonVirtualRelease(); } \
static void AddRef(class_* aObject) { aObject->NonVirtualAddRef(); } \
}; \
}
#endif
NON_VIRTUAL_ADDREF_RELEASE(mozilla::dom::EventTarget)
#endif // mozilla_dom_EventTarget_h_