In modern C++, static constexpr member variables are automatically inline (aka weak) so the template trick is not needed. This also avoid duplication and reduces the amount of parsed code. No impact on generated binary (actually: smaller debuginfo, close to identical binary). Differential Revision: https://phabricator.services.mozilla.com/D247825
454 lines
19 KiB
C++
454 lines
19 KiB
C++
/* -*- 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_INLINE_DECL_STATIC_IID(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);
|
|
void RemoveEventListener(const nsAString& aType, EventListener* aCallback,
|
|
const EventListenerOptionsOrBoolean& aOptions);
|
|
|
|
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.
|
|
* https://dom.spec.whatwg.org/#eventtarget-legacy-pre-activation-behavior
|
|
*/
|
|
virtual void LegacyPreActivationBehavior(EventChainVisitor& aVisitor) {}
|
|
|
|
/**
|
|
* Called on the activation target during dispatch of activation events.
|
|
* https://dom.spec.whatwg.org/#eventtarget-activation-behavior
|
|
*/
|
|
MOZ_CAN_RUN_SCRIPT
|
|
virtual void ActivationBehavior(EventChainPostVisitor& aVisitor) {}
|
|
|
|
/**
|
|
* Called on the activation target during dispatch of activation events.
|
|
* https://dom.spec.whatwg.org/#eventtarget-legacy-canceled-activation-behavior
|
|
*/
|
|
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);
|
|
};
|
|
|
|
#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_
|