|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef mozilla_JSEventHandler_h_ |
|
7 #define mozilla_JSEventHandler_h_ |
|
8 |
|
9 #include "mozilla/Attributes.h" |
|
10 #include "mozilla/MemoryReporting.h" |
|
11 #include "mozilla/dom/EventHandlerBinding.h" |
|
12 #include "nsCOMPtr.h" |
|
13 #include "nsCycleCollectionParticipant.h" |
|
14 #include "nsIAtom.h" |
|
15 #include "nsIDOMKeyEvent.h" |
|
16 #include "nsIDOMEventListener.h" |
|
17 #include "nsIScriptContext.h" |
|
18 |
|
19 namespace mozilla { |
|
20 |
|
21 class TypedEventHandler |
|
22 { |
|
23 public: |
|
24 enum HandlerType |
|
25 { |
|
26 eUnset = 0, |
|
27 eNormal = 0x1, |
|
28 eOnError = 0x2, |
|
29 eOnBeforeUnload = 0x3, |
|
30 eTypeBits = 0x3 |
|
31 }; |
|
32 |
|
33 TypedEventHandler() |
|
34 : mBits(0) |
|
35 { |
|
36 } |
|
37 |
|
38 TypedEventHandler(dom::EventHandlerNonNull* aHandler) |
|
39 { |
|
40 Assign(aHandler, eNormal); |
|
41 } |
|
42 |
|
43 TypedEventHandler(dom::OnErrorEventHandlerNonNull* aHandler) |
|
44 { |
|
45 Assign(aHandler, eOnError); |
|
46 } |
|
47 |
|
48 TypedEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler) |
|
49 { |
|
50 Assign(aHandler, eOnBeforeUnload); |
|
51 } |
|
52 |
|
53 TypedEventHandler(const TypedEventHandler& aOther) |
|
54 { |
|
55 if (aOther.HasEventHandler()) { |
|
56 // Have to make sure we take our own ref |
|
57 Assign(aOther.Ptr(), aOther.Type()); |
|
58 } else { |
|
59 mBits = 0; |
|
60 } |
|
61 } |
|
62 |
|
63 ~TypedEventHandler() |
|
64 { |
|
65 ReleaseHandler(); |
|
66 } |
|
67 |
|
68 HandlerType Type() const |
|
69 { |
|
70 return HandlerType(mBits & eTypeBits); |
|
71 } |
|
72 |
|
73 bool HasEventHandler() const |
|
74 { |
|
75 return !!Ptr(); |
|
76 } |
|
77 |
|
78 void SetHandler(const TypedEventHandler& aHandler) |
|
79 { |
|
80 if (aHandler.HasEventHandler()) { |
|
81 ReleaseHandler(); |
|
82 Assign(aHandler.Ptr(), aHandler.Type()); |
|
83 } else { |
|
84 ForgetHandler(); |
|
85 } |
|
86 } |
|
87 |
|
88 dom::EventHandlerNonNull* NormalEventHandler() const |
|
89 { |
|
90 MOZ_ASSERT(Type() == eNormal && Ptr()); |
|
91 return reinterpret_cast<dom::EventHandlerNonNull*>(Ptr()); |
|
92 } |
|
93 |
|
94 void SetHandler(dom::EventHandlerNonNull* aHandler) |
|
95 { |
|
96 ReleaseHandler(); |
|
97 Assign(aHandler, eNormal); |
|
98 } |
|
99 |
|
100 dom::OnBeforeUnloadEventHandlerNonNull* OnBeforeUnloadEventHandler() const |
|
101 { |
|
102 MOZ_ASSERT(Type() == eOnBeforeUnload); |
|
103 return reinterpret_cast<dom::OnBeforeUnloadEventHandlerNonNull*>(Ptr()); |
|
104 } |
|
105 |
|
106 void SetHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler) |
|
107 { |
|
108 ReleaseHandler(); |
|
109 Assign(aHandler, eOnBeforeUnload); |
|
110 } |
|
111 |
|
112 dom::OnErrorEventHandlerNonNull* OnErrorEventHandler() const |
|
113 { |
|
114 MOZ_ASSERT(Type() == eOnError); |
|
115 return reinterpret_cast<dom::OnErrorEventHandlerNonNull*>(Ptr()); |
|
116 } |
|
117 |
|
118 void SetHandler(dom::OnErrorEventHandlerNonNull* aHandler) |
|
119 { |
|
120 ReleaseHandler(); |
|
121 Assign(aHandler, eOnError); |
|
122 } |
|
123 |
|
124 dom::CallbackFunction* Ptr() const |
|
125 { |
|
126 // Have to cast eTypeBits so we don't have to worry about |
|
127 // promotion issues after the bitflip. |
|
128 return reinterpret_cast<dom::CallbackFunction*>(mBits & |
|
129 ~uintptr_t(eTypeBits)); |
|
130 } |
|
131 |
|
132 void ForgetHandler() |
|
133 { |
|
134 ReleaseHandler(); |
|
135 mBits = 0; |
|
136 } |
|
137 |
|
138 bool operator==(const TypedEventHandler& aOther) const |
|
139 { |
|
140 return |
|
141 Ptr() && aOther.Ptr() && |
|
142 Ptr()->CallbackPreserveColor() == aOther.Ptr()->CallbackPreserveColor(); |
|
143 } |
|
144 |
|
145 private: |
|
146 void operator=(const TypedEventHandler&) MOZ_DELETE; |
|
147 |
|
148 void ReleaseHandler() |
|
149 { |
|
150 nsISupports* ptr = Ptr(); |
|
151 NS_IF_RELEASE(ptr); |
|
152 } |
|
153 |
|
154 void Assign(nsISupports* aHandler, HandlerType aType) |
|
155 { |
|
156 MOZ_ASSERT(aHandler, "Must have handler"); |
|
157 NS_ADDREF(aHandler); |
|
158 mBits = uintptr_t(aHandler) | uintptr_t(aType); |
|
159 } |
|
160 |
|
161 uintptr_t mBits; |
|
162 }; |
|
163 |
|
164 /** |
|
165 * Implemented by script event listeners. Used to retrieve the script object |
|
166 * corresponding to the event target and the handler itself. |
|
167 * |
|
168 * Note, mTarget is a raw pointer and the owner of the JSEventHandler object |
|
169 * is expected to call Disconnect()! |
|
170 */ |
|
171 |
|
172 #define NS_JSEVENTHANDLER_IID \ |
|
173 { 0x4f486881, 0x1956, 0x4079, \ |
|
174 { 0x8c, 0xa0, 0xf3, 0xbd, 0x60, 0x5c, 0xc2, 0x79 } } |
|
175 |
|
176 class JSEventHandler : public nsIDOMEventListener |
|
177 { |
|
178 public: |
|
179 NS_DECLARE_STATIC_IID_ACCESSOR(NS_JSEVENTHANDLER_IID) |
|
180 |
|
181 JSEventHandler(nsISupports* aTarget, nsIAtom* aType, |
|
182 const TypedEventHandler& aTypedHandler); |
|
183 |
|
184 virtual ~JSEventHandler(); |
|
185 |
|
186 NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
|
187 |
|
188 // nsIDOMEventListener interface |
|
189 NS_DECL_NSIDOMEVENTLISTENER |
|
190 |
|
191 nsISupports* GetEventTarget() const |
|
192 { |
|
193 return mTarget; |
|
194 } |
|
195 |
|
196 void Disconnect() |
|
197 { |
|
198 mTarget = nullptr; |
|
199 } |
|
200 |
|
201 const TypedEventHandler& GetTypedEventHandler() const |
|
202 { |
|
203 return mTypedHandler; |
|
204 } |
|
205 |
|
206 void ForgetHandler() |
|
207 { |
|
208 mTypedHandler.ForgetHandler(); |
|
209 } |
|
210 |
|
211 nsIAtom* EventName() const |
|
212 { |
|
213 return mEventName; |
|
214 } |
|
215 |
|
216 // Set a handler for this event listener. The handler must already |
|
217 // be bound to the right target. |
|
218 void SetHandler(const TypedEventHandler& aTypedHandler) |
|
219 { |
|
220 mTypedHandler.SetHandler(aTypedHandler); |
|
221 } |
|
222 void SetHandler(dom::EventHandlerNonNull* aHandler) |
|
223 { |
|
224 mTypedHandler.SetHandler(aHandler); |
|
225 } |
|
226 void SetHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler) |
|
227 { |
|
228 mTypedHandler.SetHandler(aHandler); |
|
229 } |
|
230 void SetHandler(dom::OnErrorEventHandlerNonNull* aHandler) |
|
231 { |
|
232 mTypedHandler.SetHandler(aHandler); |
|
233 } |
|
234 |
|
235 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
|
236 { |
|
237 return 0; |
|
238 |
|
239 // Measurement of the following members may be added later if DMD finds it |
|
240 // is worthwhile: |
|
241 // - mTarget |
|
242 // |
|
243 // The following members are not measured: |
|
244 // - mTypedHandler: may be shared with others |
|
245 // - mEventName: shared with others |
|
246 } |
|
247 |
|
248 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) |
|
249 { |
|
250 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
|
251 } |
|
252 |
|
253 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(JSEventHandler) |
|
254 |
|
255 bool IsBlackForCC(); |
|
256 |
|
257 protected: |
|
258 nsISupports* mTarget; |
|
259 nsCOMPtr<nsIAtom> mEventName; |
|
260 TypedEventHandler mTypedHandler; |
|
261 }; |
|
262 |
|
263 NS_DEFINE_STATIC_IID_ACCESSOR(JSEventHandler, NS_JSEVENTHANDLER_IID) |
|
264 |
|
265 } // namespace mozilla |
|
266 |
|
267 /** |
|
268 * Factory function. aHandler must already be bound to aTarget. |
|
269 * aContext is allowed to be null if aHandler is already set up. |
|
270 */ |
|
271 nsresult NS_NewJSEventHandler(nsISupports* aTarget, |
|
272 nsIAtom* aType, |
|
273 const mozilla::TypedEventHandler& aTypedHandler, |
|
274 mozilla::JSEventHandler** aReturn); |
|
275 |
|
276 #endif // mozilla_JSEventHandler_h_ |
|
277 |