1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_JSEventHandler_h_
8 #define mozilla_JSEventHandler_h_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/dom/EventHandlerBinding.h"
14 #include "nsCycleCollectionParticipant.h"
16 #include "nsIDOMEventListener.h"
17 #include "nsIScriptContext.h"
21 class TypedEventHandler
{
27 eOnBeforeUnload
= 0x3,
31 TypedEventHandler() : mBits(0) {}
33 explicit TypedEventHandler(dom::EventHandlerNonNull
* aHandler
) : mBits(0) {
34 Assign(aHandler
, eNormal
);
37 explicit TypedEventHandler(dom::OnErrorEventHandlerNonNull
* aHandler
)
39 Assign(aHandler
, eOnError
);
42 explicit TypedEventHandler(dom::OnBeforeUnloadEventHandlerNonNull
* aHandler
)
44 Assign(aHandler
, eOnBeforeUnload
);
47 TypedEventHandler(const TypedEventHandler
& aOther
) {
48 if (aOther
.HasEventHandler()) {
49 // Have to make sure we take our own ref
50 Assign(aOther
.Ptr(), aOther
.Type());
56 ~TypedEventHandler() { ReleaseHandler(); }
58 HandlerType
Type() const { return HandlerType(mBits
& eTypeBits
); }
60 bool HasEventHandler() const { return !!Ptr(); }
62 void SetHandler(const TypedEventHandler
& aHandler
) {
63 if (aHandler
.HasEventHandler()) {
65 Assign(aHandler
.Ptr(), aHandler
.Type());
71 dom::EventHandlerNonNull
* NormalEventHandler() const {
72 MOZ_ASSERT(Type() == eNormal
&& Ptr());
73 return reinterpret_cast<dom::EventHandlerNonNull
*>(Ptr());
76 void SetHandler(dom::EventHandlerNonNull
* aHandler
) {
78 Assign(aHandler
, eNormal
);
81 dom::OnBeforeUnloadEventHandlerNonNull
* OnBeforeUnloadEventHandler() const {
82 MOZ_ASSERT(Type() == eOnBeforeUnload
);
83 return reinterpret_cast<dom::OnBeforeUnloadEventHandlerNonNull
*>(Ptr());
86 void SetHandler(dom::OnBeforeUnloadEventHandlerNonNull
* aHandler
) {
88 Assign(aHandler
, eOnBeforeUnload
);
91 dom::OnErrorEventHandlerNonNull
* OnErrorEventHandler() const {
92 MOZ_ASSERT(Type() == eOnError
);
93 return reinterpret_cast<dom::OnErrorEventHandlerNonNull
*>(Ptr());
96 void SetHandler(dom::OnErrorEventHandlerNonNull
* aHandler
) {
98 Assign(aHandler
, eOnError
);
101 dom::CallbackFunction
* Ptr() const {
102 // Have to cast eTypeBits so we don't have to worry about
103 // promotion issues after the bitflip.
104 return reinterpret_cast<dom::CallbackFunction
*>(mBits
&
105 ~uintptr_t(eTypeBits
));
108 void ForgetHandler() {
113 bool operator==(const TypedEventHandler
& aOther
) const {
114 return Ptr() && aOther
.Ptr() &&
115 Ptr()->CallbackPreserveColor() ==
116 aOther
.Ptr()->CallbackPreserveColor();
120 void operator=(const TypedEventHandler
&) = delete;
122 void ReleaseHandler() {
123 nsISupports
* ptr
= Ptr();
127 void Assign(nsISupports
* aHandler
, HandlerType aType
) {
128 MOZ_ASSERT(aHandler
, "Must have handler");
130 mBits
= uintptr_t(aHandler
) | uintptr_t(aType
);
137 * Implemented by script event listeners. Used to retrieve the script object
138 * corresponding to the event target and the handler itself.
140 * Note, mTarget is a raw pointer and the owner of the JSEventHandler object
141 * is expected to call Disconnect()!
144 #define NS_JSEVENTHANDLER_IID \
146 0x4f486881, 0x1956, 0x4079, { \
147 0x8c, 0xa0, 0xf3, 0xbd, 0x60, 0x5c, 0xc2, 0x79 \
151 class JSEventHandler
: public nsIDOMEventListener
{
153 NS_DECLARE_STATIC_IID_ACCESSOR(NS_JSEVENTHANDLER_IID
)
155 JSEventHandler(nsISupports
* aTarget
, nsAtom
* aType
,
156 const TypedEventHandler
& aTypedHandler
);
158 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
160 // nsIDOMEventListener interface
161 NS_DECL_NSIDOMEVENTLISTENER
163 nsISupports
* GetEventTarget() const { return mTarget
; }
165 void Disconnect() { mTarget
= nullptr; }
167 const TypedEventHandler
& GetTypedEventHandler() const {
168 return mTypedHandler
;
171 void ForgetHandler() { mTypedHandler
.ForgetHandler(); }
173 nsAtom
* EventName() const { return mEventName
; }
175 // Set a handler for this event listener. The handler must already
176 // be bound to the right target.
177 void SetHandler(const TypedEventHandler
& aTypedHandler
) {
178 mTypedHandler
.SetHandler(aTypedHandler
);
180 void SetHandler(dom::EventHandlerNonNull
* aHandler
) {
181 mTypedHandler
.SetHandler(aHandler
);
183 void SetHandler(dom::OnBeforeUnloadEventHandlerNonNull
* aHandler
) {
184 mTypedHandler
.SetHandler(aHandler
);
186 void SetHandler(dom::OnErrorEventHandlerNonNull
* aHandler
) {
187 mTypedHandler
.SetHandler(aHandler
);
190 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const {
193 // Measurement of the following members may be added later if DMD finds it
197 // The following members are not measured:
198 // - mTypedHandler: may be shared with others
199 // - mEventName: shared with others
202 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) {
203 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
206 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(JSEventHandler
)
211 virtual ~JSEventHandler();
213 nsISupports
* mTarget
;
214 RefPtr
<nsAtom
> mEventName
;
215 TypedEventHandler mTypedHandler
;
218 NS_DEFINE_STATIC_IID_ACCESSOR(JSEventHandler
, NS_JSEVENTHANDLER_IID
)
220 } // namespace mozilla
223 * Factory function. aHandler must already be bound to aTarget.
224 * aContext is allowed to be null if aHandler is already set up.
226 nsresult
NS_NewJSEventHandler(nsISupports
* aTarget
, nsAtom
* aType
,
227 const mozilla::TypedEventHandler
& aTypedHandler
,
228 mozilla::JSEventHandler
** aReturn
);
230 #endif // mozilla_JSEventHandler_h_