|
1 /* -*- Mode: C++; tab-width: 2; 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 #include "EventListenerService.h" |
|
7 #ifdef MOZ_JSDEBUGGER |
|
8 #include "jsdIDebuggerService.h" |
|
9 #endif |
|
10 #include "mozilla/BasicEvents.h" |
|
11 #include "mozilla/EventDispatcher.h" |
|
12 #include "mozilla/EventListenerManager.h" |
|
13 #include "mozilla/JSEventHandler.h" |
|
14 #include "mozilla/Maybe.h" |
|
15 #include "nsCOMArray.h" |
|
16 #include "nsCxPusher.h" |
|
17 #include "nsDOMClassInfoID.h" |
|
18 #include "nsIXPConnect.h" |
|
19 #include "nsJSUtils.h" |
|
20 #include "nsMemory.h" |
|
21 #include "nsServiceManagerUtils.h" |
|
22 |
|
23 namespace mozilla { |
|
24 |
|
25 using namespace dom; |
|
26 |
|
27 /****************************************************************************** |
|
28 * mozilla::EventListenerInfo |
|
29 ******************************************************************************/ |
|
30 |
|
31 NS_IMPL_CYCLE_COLLECTION(EventListenerInfo, mListener) |
|
32 |
|
33 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerInfo) |
|
34 NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo) |
|
35 NS_INTERFACE_MAP_ENTRY(nsISupports) |
|
36 NS_INTERFACE_MAP_END |
|
37 |
|
38 NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerInfo) |
|
39 NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerInfo) |
|
40 |
|
41 NS_IMETHODIMP |
|
42 EventListenerInfo::GetType(nsAString& aType) |
|
43 { |
|
44 aType = mType; |
|
45 return NS_OK; |
|
46 } |
|
47 |
|
48 NS_IMETHODIMP |
|
49 EventListenerInfo::GetCapturing(bool* aCapturing) |
|
50 { |
|
51 *aCapturing = mCapturing; |
|
52 return NS_OK; |
|
53 } |
|
54 |
|
55 NS_IMETHODIMP |
|
56 EventListenerInfo::GetAllowsUntrusted(bool* aAllowsUntrusted) |
|
57 { |
|
58 *aAllowsUntrusted = mAllowsUntrusted; |
|
59 return NS_OK; |
|
60 } |
|
61 |
|
62 NS_IMETHODIMP |
|
63 EventListenerInfo::GetInSystemEventGroup(bool* aInSystemEventGroup) |
|
64 { |
|
65 *aInSystemEventGroup = mInSystemEventGroup; |
|
66 return NS_OK; |
|
67 } |
|
68 |
|
69 NS_IMETHODIMP |
|
70 EventListenerInfo::GetListenerObject(JSContext* aCx, |
|
71 JS::MutableHandle<JS::Value> aObject) |
|
72 { |
|
73 Maybe<JSAutoCompartment> ac; |
|
74 GetJSVal(aCx, ac, aObject); |
|
75 return NS_OK; |
|
76 } |
|
77 |
|
78 /****************************************************************************** |
|
79 * mozilla::EventListenerService |
|
80 ******************************************************************************/ |
|
81 |
|
82 NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService) |
|
83 |
|
84 bool |
|
85 EventListenerInfo::GetJSVal(JSContext* aCx, |
|
86 Maybe<JSAutoCompartment>& aAc, |
|
87 JS::MutableHandle<JS::Value> aJSVal) |
|
88 { |
|
89 aJSVal.setNull(); |
|
90 nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener); |
|
91 if (wrappedJS) { |
|
92 JS::Rooted<JSObject*> object(aCx, wrappedJS->GetJSObject()); |
|
93 if (!object) { |
|
94 return false; |
|
95 } |
|
96 aAc.construct(aCx, object); |
|
97 aJSVal.setObject(*object); |
|
98 return true; |
|
99 } |
|
100 |
|
101 nsCOMPtr<JSEventHandler> jsHandler = do_QueryInterface(mListener); |
|
102 if (jsHandler && jsHandler->GetTypedEventHandler().HasEventHandler()) { |
|
103 JS::Handle<JSObject*> handler = |
|
104 jsHandler->GetTypedEventHandler().Ptr()->Callable(); |
|
105 if (handler) { |
|
106 aAc.construct(aCx, handler); |
|
107 aJSVal.setObject(*handler); |
|
108 return true; |
|
109 } |
|
110 } |
|
111 return false; |
|
112 } |
|
113 |
|
114 NS_IMETHODIMP |
|
115 EventListenerInfo::ToSource(nsAString& aResult) |
|
116 { |
|
117 aResult.SetIsVoid(true); |
|
118 |
|
119 AutoSafeJSContext cx; |
|
120 Maybe<JSAutoCompartment> ac; |
|
121 JS::Rooted<JS::Value> v(cx); |
|
122 if (GetJSVal(cx, ac, &v)) { |
|
123 JSString* str = JS_ValueToSource(cx, v); |
|
124 if (str) { |
|
125 nsDependentJSString depStr; |
|
126 if (depStr.init(cx, str)) { |
|
127 aResult.Assign(depStr); |
|
128 } |
|
129 } |
|
130 } |
|
131 return NS_OK; |
|
132 } |
|
133 |
|
134 NS_IMETHODIMP |
|
135 EventListenerInfo::GetDebugObject(nsISupports** aRetVal) |
|
136 { |
|
137 *aRetVal = nullptr; |
|
138 |
|
139 #ifdef MOZ_JSDEBUGGER |
|
140 nsresult rv = NS_OK; |
|
141 nsCOMPtr<jsdIDebuggerService> jsd = |
|
142 do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv); |
|
143 NS_ENSURE_SUCCESS(rv, NS_OK); |
|
144 |
|
145 bool isOn = false; |
|
146 jsd->GetIsOn(&isOn); |
|
147 NS_ENSURE_TRUE(isOn, NS_OK); |
|
148 |
|
149 AutoSafeJSContext cx; |
|
150 Maybe<JSAutoCompartment> ac; |
|
151 JS::Rooted<JS::Value> v(cx); |
|
152 if (GetJSVal(cx, ac, &v)) { |
|
153 nsCOMPtr<jsdIValue> jsdValue; |
|
154 rv = jsd->WrapValue(v, getter_AddRefs(jsdValue)); |
|
155 NS_ENSURE_SUCCESS(rv, rv); |
|
156 jsdValue.forget(aRetVal); |
|
157 } |
|
158 #endif |
|
159 |
|
160 return NS_OK; |
|
161 } |
|
162 |
|
163 NS_IMETHODIMP |
|
164 EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget, |
|
165 uint32_t* aCount, |
|
166 nsIEventListenerInfo*** aOutArray) |
|
167 { |
|
168 NS_ENSURE_ARG_POINTER(aEventTarget); |
|
169 *aCount = 0; |
|
170 *aOutArray = nullptr; |
|
171 nsCOMArray<nsIEventListenerInfo> listenerInfos; |
|
172 |
|
173 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget); |
|
174 NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); |
|
175 |
|
176 EventListenerManager* elm = eventTarget->GetExistingListenerManager(); |
|
177 if (elm) { |
|
178 elm->GetListenerInfo(&listenerInfos); |
|
179 } |
|
180 |
|
181 int32_t count = listenerInfos.Count(); |
|
182 if (count == 0) { |
|
183 return NS_OK; |
|
184 } |
|
185 |
|
186 *aOutArray = |
|
187 static_cast<nsIEventListenerInfo**>( |
|
188 nsMemory::Alloc(sizeof(nsIEventListenerInfo*) * count)); |
|
189 NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY); |
|
190 |
|
191 for (int32_t i = 0; i < count; ++i) { |
|
192 NS_ADDREF((*aOutArray)[i] = listenerInfos[i]); |
|
193 } |
|
194 *aCount = count; |
|
195 return NS_OK; |
|
196 } |
|
197 |
|
198 NS_IMETHODIMP |
|
199 EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget, |
|
200 uint32_t* aCount, |
|
201 nsIDOMEventTarget*** aOutArray) |
|
202 { |
|
203 *aCount = 0; |
|
204 *aOutArray = nullptr; |
|
205 NS_ENSURE_ARG(aEventTarget); |
|
206 WidgetEvent event(true, NS_EVENT_NULL); |
|
207 nsCOMArray<EventTarget> targets; |
|
208 nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event, |
|
209 nullptr, nullptr, nullptr, &targets); |
|
210 NS_ENSURE_SUCCESS(rv, rv); |
|
211 int32_t count = targets.Count(); |
|
212 if (count == 0) { |
|
213 return NS_OK; |
|
214 } |
|
215 |
|
216 *aOutArray = |
|
217 static_cast<nsIDOMEventTarget**>( |
|
218 nsMemory::Alloc(sizeof(nsIDOMEventTarget*) * count)); |
|
219 NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY); |
|
220 |
|
221 for (int32_t i = 0; i < count; ++i) { |
|
222 NS_ADDREF((*aOutArray)[i] = targets[i]); |
|
223 } |
|
224 *aCount = count; |
|
225 |
|
226 return NS_OK; |
|
227 } |
|
228 |
|
229 NS_IMETHODIMP |
|
230 EventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget, |
|
231 const nsAString& aType, |
|
232 bool* aRetVal) |
|
233 { |
|
234 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget); |
|
235 NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); |
|
236 |
|
237 EventListenerManager* elm = eventTarget->GetExistingListenerManager(); |
|
238 *aRetVal = elm && elm->HasListenersFor(aType); |
|
239 return NS_OK; |
|
240 } |
|
241 |
|
242 NS_IMETHODIMP |
|
243 EventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget, |
|
244 const nsAString& aType, |
|
245 nsIDOMEventListener* aListener, |
|
246 bool aUseCapture) |
|
247 { |
|
248 NS_PRECONDITION(aTarget, "Missing target"); |
|
249 NS_PRECONDITION(aListener, "Missing listener"); |
|
250 |
|
251 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget); |
|
252 NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); |
|
253 |
|
254 EventListenerManager* manager = eventTarget->GetOrCreateListenerManager(); |
|
255 NS_ENSURE_STATE(manager); |
|
256 |
|
257 EventListenerFlags flags = |
|
258 aUseCapture ? TrustedEventsAtSystemGroupCapture() : |
|
259 TrustedEventsAtSystemGroupBubble(); |
|
260 manager->AddEventListenerByType(aListener, aType, flags); |
|
261 return NS_OK; |
|
262 } |
|
263 |
|
264 NS_IMETHODIMP |
|
265 EventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget, |
|
266 const nsAString& aType, |
|
267 nsIDOMEventListener* aListener, |
|
268 bool aUseCapture) |
|
269 { |
|
270 NS_PRECONDITION(aTarget, "Missing target"); |
|
271 NS_PRECONDITION(aListener, "Missing listener"); |
|
272 |
|
273 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget); |
|
274 NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); |
|
275 |
|
276 EventListenerManager* manager = eventTarget->GetExistingListenerManager(); |
|
277 if (manager) { |
|
278 EventListenerFlags flags = |
|
279 aUseCapture ? TrustedEventsAtSystemGroupCapture() : |
|
280 TrustedEventsAtSystemGroupBubble(); |
|
281 manager->RemoveEventListenerByType(aListener, aType, flags); |
|
282 } |
|
283 |
|
284 return NS_OK; |
|
285 } |
|
286 |
|
287 NS_IMETHODIMP |
|
288 EventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget, |
|
289 nsIDOMEventListener* aListener, |
|
290 bool aUseCapture, |
|
291 bool aWantsUntrusted, |
|
292 bool aSystemEventGroup) |
|
293 { |
|
294 NS_ENSURE_STATE(aTarget && aListener); |
|
295 |
|
296 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget); |
|
297 NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); |
|
298 |
|
299 EventListenerManager* manager = eventTarget->GetOrCreateListenerManager(); |
|
300 NS_ENSURE_STATE(manager); |
|
301 manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted, |
|
302 aSystemEventGroup); |
|
303 return NS_OK; |
|
304 } |
|
305 |
|
306 NS_IMETHODIMP |
|
307 EventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget, |
|
308 nsIDOMEventListener* aListener, |
|
309 bool aUseCapture, |
|
310 bool aSystemEventGroup) |
|
311 { |
|
312 NS_ENSURE_STATE(aTarget && aListener); |
|
313 |
|
314 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget); |
|
315 NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE); |
|
316 |
|
317 EventListenerManager* manager = eventTarget->GetExistingListenerManager(); |
|
318 if (manager) { |
|
319 manager->RemoveListenerForAllEvents(aListener, aUseCapture, aSystemEventGroup); |
|
320 } |
|
321 return NS_OK; |
|
322 } |
|
323 |
|
324 } // namespace mozilla |
|
325 |
|
326 nsresult |
|
327 NS_NewEventListenerService(nsIEventListenerService** aResult) |
|
328 { |
|
329 *aResult = new mozilla::EventListenerService(); |
|
330 NS_ADDREF(*aResult); |
|
331 return NS_OK; |
|
332 } |