Line data Source code
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/. */
6 :
7 : #include "EventListenerService.h"
8 : #include "mozilla/BasicEvents.h"
9 : #include "mozilla/EventDispatcher.h"
10 : #include "mozilla/EventListenerManager.h"
11 : #include "mozilla/JSEventHandler.h"
12 : #include "mozilla/Maybe.h"
13 : #include "nsCOMArray.h"
14 : #include "nsDOMClassInfoID.h"
15 : #include "nsIXPConnect.h"
16 : #include "nsJSUtils.h"
17 : #include "nsMemory.h"
18 : #include "nsServiceManagerUtils.h"
19 : #include "nsArray.h"
20 : #include "nsThreadUtils.h"
21 :
22 : namespace mozilla {
23 :
24 : using namespace dom;
25 :
26 : /******************************************************************************
27 : * mozilla::EventListenerChange
28 : ******************************************************************************/
29 :
30 0 : NS_IMPL_ISUPPORTS(EventListenerChange, nsIEventListenerChange)
31 :
32 0 : EventListenerChange::~EventListenerChange()
33 : {
34 0 : }
35 :
36 0 : EventListenerChange::EventListenerChange(dom::EventTarget* aTarget) :
37 0 : mTarget(aTarget)
38 : {
39 0 : mChangedListenerNames = nsArrayBase::Create();
40 0 : }
41 :
42 : void
43 0 : EventListenerChange::AddChangedListenerName(nsIAtom* aEventName)
44 : {
45 0 : mChangedListenerNames->AppendElement(aEventName, false);
46 0 : }
47 :
48 : NS_IMETHODIMP
49 0 : EventListenerChange::GetTarget(nsIDOMEventTarget** aTarget)
50 : {
51 0 : NS_ENSURE_ARG_POINTER(aTarget);
52 0 : NS_ADDREF(*aTarget = mTarget);
53 0 : return NS_OK;
54 : }
55 :
56 : NS_IMETHODIMP
57 0 : EventListenerChange::GetChangedListenerNames(nsIArray** aEventNames)
58 : {
59 0 : NS_ENSURE_ARG_POINTER(aEventNames);
60 0 : NS_ADDREF(*aEventNames = mChangedListenerNames);
61 0 : return NS_OK;
62 : }
63 :
64 : /******************************************************************************
65 : * mozilla::EventListenerInfo
66 : ******************************************************************************/
67 :
68 0 : NS_IMPL_CYCLE_COLLECTION(EventListenerInfo, mListener)
69 :
70 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerInfo)
71 0 : NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo)
72 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
73 0 : NS_INTERFACE_MAP_END
74 :
75 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerInfo)
76 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerInfo)
77 :
78 : NS_IMETHODIMP
79 0 : EventListenerInfo::GetType(nsAString& aType)
80 : {
81 0 : aType = mType;
82 0 : return NS_OK;
83 : }
84 :
85 : NS_IMETHODIMP
86 0 : EventListenerInfo::GetCapturing(bool* aCapturing)
87 : {
88 0 : *aCapturing = mCapturing;
89 0 : return NS_OK;
90 : }
91 :
92 : NS_IMETHODIMP
93 0 : EventListenerInfo::GetAllowsUntrusted(bool* aAllowsUntrusted)
94 : {
95 0 : *aAllowsUntrusted = mAllowsUntrusted;
96 0 : return NS_OK;
97 : }
98 :
99 : NS_IMETHODIMP
100 0 : EventListenerInfo::GetInSystemEventGroup(bool* aInSystemEventGroup)
101 : {
102 0 : *aInSystemEventGroup = mInSystemEventGroup;
103 0 : return NS_OK;
104 : }
105 :
106 : NS_IMETHODIMP
107 0 : EventListenerInfo::GetListenerObject(JSContext* aCx,
108 : JS::MutableHandle<JS::Value> aObject)
109 : {
110 0 : Maybe<JSAutoCompartment> ac;
111 0 : GetJSVal(aCx, ac, aObject);
112 0 : return NS_OK;
113 : }
114 :
115 : /******************************************************************************
116 : * mozilla::EventListenerService
117 : ******************************************************************************/
118 :
119 208 : NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService)
120 :
121 : bool
122 0 : EventListenerInfo::GetJSVal(JSContext* aCx,
123 : Maybe<JSAutoCompartment>& aAc,
124 : JS::MutableHandle<JS::Value> aJSVal)
125 : {
126 0 : aJSVal.setNull();
127 0 : nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
128 0 : if (wrappedJS) {
129 0 : JS::Rooted<JSObject*> object(aCx, wrappedJS->GetJSObject());
130 0 : if (!object) {
131 0 : return false;
132 : }
133 0 : aAc.emplace(aCx, object);
134 0 : aJSVal.setObject(*object);
135 0 : return true;
136 : }
137 :
138 0 : nsCOMPtr<JSEventHandler> jsHandler = do_QueryInterface(mListener);
139 0 : if (jsHandler && jsHandler->GetTypedEventHandler().HasEventHandler()) {
140 : JS::Handle<JSObject*> handler =
141 0 : jsHandler->GetTypedEventHandler().Ptr()->CallableOrNull();
142 0 : if (handler) {
143 0 : aAc.emplace(aCx, handler);
144 0 : aJSVal.setObject(*handler);
145 0 : return true;
146 : }
147 : }
148 0 : return false;
149 : }
150 :
151 : NS_IMETHODIMP
152 0 : EventListenerInfo::ToSource(nsAString& aResult)
153 : {
154 0 : aResult.SetIsVoid(true);
155 :
156 0 : AutoSafeJSContext cx;
157 0 : Maybe<JSAutoCompartment> ac;
158 0 : JS::Rooted<JS::Value> v(cx);
159 0 : if (GetJSVal(cx, ac, &v)) {
160 0 : JSString* str = JS_ValueToSource(cx, v);
161 0 : if (str) {
162 0 : nsAutoJSString autoStr;
163 0 : if (autoStr.init(cx, str)) {
164 0 : aResult.Assign(autoStr);
165 : }
166 : }
167 : }
168 0 : return NS_OK;
169 : }
170 :
171 : EventListenerService*
172 : EventListenerService::sInstance = nullptr;
173 :
174 2 : EventListenerService::EventListenerService()
175 : {
176 2 : MOZ_ASSERT(!sInstance);
177 2 : sInstance = this;
178 2 : }
179 :
180 0 : EventListenerService::~EventListenerService()
181 : {
182 0 : MOZ_ASSERT(sInstance == this);
183 0 : sInstance = nullptr;
184 0 : }
185 :
186 : NS_IMETHODIMP
187 0 : EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
188 : uint32_t* aCount,
189 : nsIEventListenerInfo*** aOutArray)
190 : {
191 0 : NS_ENSURE_ARG_POINTER(aEventTarget);
192 0 : *aCount = 0;
193 0 : *aOutArray = nullptr;
194 0 : nsCOMArray<nsIEventListenerInfo> listenerInfos;
195 :
196 0 : nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget);
197 0 : NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
198 :
199 0 : EventListenerManager* elm = eventTarget->GetExistingListenerManager();
200 0 : if (elm) {
201 0 : elm->GetListenerInfo(&listenerInfos);
202 : }
203 :
204 0 : int32_t count = listenerInfos.Count();
205 0 : if (count == 0) {
206 0 : return NS_OK;
207 : }
208 :
209 0 : listenerInfos.Forget(aOutArray);
210 0 : *aCount = count;
211 0 : return NS_OK;
212 : }
213 :
214 : NS_IMETHODIMP
215 0 : EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget,
216 : bool aComposed,
217 : uint32_t* aCount,
218 : nsIDOMEventTarget*** aOutArray)
219 : {
220 0 : *aCount = 0;
221 0 : *aOutArray = nullptr;
222 0 : NS_ENSURE_ARG(aEventTarget);
223 0 : WidgetEvent event(true, eVoidEvent);
224 0 : event.SetComposed(aComposed);
225 0 : nsTArray<EventTarget*> targets;
226 : nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event,
227 0 : nullptr, nullptr, nullptr, &targets);
228 0 : NS_ENSURE_SUCCESS(rv, rv);
229 0 : int32_t count = targets.Length();
230 0 : if (count == 0) {
231 0 : return NS_OK;
232 : }
233 :
234 0 : *aOutArray =
235 : static_cast<nsIDOMEventTarget**>(
236 0 : moz_xmalloc(sizeof(nsIDOMEventTarget*) * count));
237 0 : NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY);
238 :
239 0 : for (int32_t i = 0; i < count; ++i) {
240 0 : NS_ADDREF((*aOutArray)[i] = targets[i]);
241 : }
242 0 : *aCount = count;
243 :
244 0 : return NS_OK;
245 : }
246 :
247 : NS_IMETHODIMP
248 0 : EventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget,
249 : const nsAString& aType,
250 : bool* aRetVal)
251 : {
252 0 : nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget);
253 0 : NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
254 :
255 0 : EventListenerManager* elm = eventTarget->GetExistingListenerManager();
256 0 : *aRetVal = elm && elm->HasListenersFor(aType);
257 0 : return NS_OK;
258 : }
259 :
260 : NS_IMETHODIMP
261 14 : EventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget,
262 : const nsAString& aType,
263 : nsIDOMEventListener* aListener,
264 : bool aUseCapture)
265 : {
266 14 : NS_PRECONDITION(aTarget, "Missing target");
267 14 : NS_PRECONDITION(aListener, "Missing listener");
268 :
269 28 : nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
270 14 : NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
271 :
272 14 : EventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
273 14 : NS_ENSURE_STATE(manager);
274 :
275 : EventListenerFlags flags =
276 : aUseCapture ? TrustedEventsAtSystemGroupCapture() :
277 14 : TrustedEventsAtSystemGroupBubble();
278 14 : manager->AddEventListenerByType(aListener, aType, flags);
279 14 : return NS_OK;
280 : }
281 :
282 : NS_IMETHODIMP
283 0 : EventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget,
284 : const nsAString& aType,
285 : nsIDOMEventListener* aListener,
286 : bool aUseCapture)
287 : {
288 0 : NS_PRECONDITION(aTarget, "Missing target");
289 0 : NS_PRECONDITION(aListener, "Missing listener");
290 :
291 0 : nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
292 0 : NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
293 :
294 0 : EventListenerManager* manager = eventTarget->GetExistingListenerManager();
295 0 : if (manager) {
296 : EventListenerFlags flags =
297 : aUseCapture ? TrustedEventsAtSystemGroupCapture() :
298 0 : TrustedEventsAtSystemGroupBubble();
299 0 : manager->RemoveEventListenerByType(aListener, aType, flags);
300 : }
301 :
302 0 : return NS_OK;
303 : }
304 :
305 : NS_IMETHODIMP
306 0 : EventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget,
307 : nsIDOMEventListener* aListener,
308 : bool aUseCapture,
309 : bool aWantsUntrusted,
310 : bool aSystemEventGroup)
311 : {
312 0 : NS_ENSURE_STATE(aTarget && aListener);
313 :
314 0 : nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
315 0 : NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
316 :
317 0 : EventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
318 0 : NS_ENSURE_STATE(manager);
319 0 : manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted,
320 0 : aSystemEventGroup);
321 0 : return NS_OK;
322 : }
323 :
324 : NS_IMETHODIMP
325 0 : EventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget,
326 : nsIDOMEventListener* aListener,
327 : bool aUseCapture,
328 : bool aSystemEventGroup)
329 : {
330 0 : NS_ENSURE_STATE(aTarget && aListener);
331 :
332 0 : nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
333 0 : NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
334 :
335 0 : EventListenerManager* manager = eventTarget->GetExistingListenerManager();
336 0 : if (manager) {
337 0 : manager->RemoveListenerForAllEvents(aListener, aUseCapture, aSystemEventGroup);
338 : }
339 0 : return NS_OK;
340 : }
341 :
342 : NS_IMETHODIMP
343 0 : EventListenerService::AddListenerChangeListener(nsIListenerChangeListener* aListener)
344 : {
345 0 : if (!mChangeListeners.Contains(aListener)) {
346 0 : mChangeListeners.AppendElement(aListener);
347 : }
348 0 : return NS_OK;
349 : };
350 :
351 : NS_IMETHODIMP
352 0 : EventListenerService::RemoveListenerChangeListener(nsIListenerChangeListener* aListener)
353 : {
354 0 : mChangeListeners.RemoveElement(aListener);
355 0 : return NS_OK;
356 : };
357 :
358 : void
359 892 : EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget,
360 : nsIAtom* aName)
361 : {
362 892 : MOZ_ASSERT(NS_IsMainThread());
363 892 : MOZ_ASSERT(aTarget);
364 892 : if (mChangeListeners.IsEmpty()) {
365 892 : return;
366 : }
367 :
368 0 : if (!mPendingListenerChanges) {
369 0 : mPendingListenerChanges = nsArrayBase::Create();
370 : nsCOMPtr<nsIRunnable> runnable =
371 0 : NewRunnableMethod("EventListenerService::NotifyPendingChanges",
372 0 : this, &EventListenerService::NotifyPendingChanges);
373 0 : if (nsCOMPtr<nsIGlobalObject> global = aTarget->GetOwnerGlobal()) {
374 0 : global->Dispatch(nullptr, TaskCategory::Other, runnable.forget());
375 0 : } else if (nsCOMPtr<nsINode> node = do_QueryInterface(aTarget)) {
376 0 : node->OwnerDoc()->Dispatch(nullptr, TaskCategory::Other,
377 0 : runnable.forget());
378 : } else {
379 0 : NS_DispatchToCurrentThread(runnable);
380 : }
381 : }
382 :
383 : RefPtr<EventListenerChange> changes =
384 0 : mPendingListenerChangesSet.LookupForAdd(aTarget).OrInsert(
385 0 : [this, aTarget] () {
386 0 : EventListenerChange* c = new EventListenerChange(aTarget);
387 0 : mPendingListenerChanges->AppendElement(c, false);
388 0 : return c;
389 0 : });
390 0 : changes->AddChangedListenerName(aName);
391 : }
392 :
393 : void
394 0 : EventListenerService::NotifyPendingChanges()
395 : {
396 0 : nsCOMPtr<nsIMutableArray> changes;
397 0 : mPendingListenerChanges.swap(changes);
398 0 : mPendingListenerChangesSet.Clear();
399 :
400 : nsTObserverArray<nsCOMPtr<nsIListenerChangeListener>>::EndLimitedIterator
401 0 : iter(mChangeListeners);
402 0 : while (iter.HasMore()) {
403 0 : nsCOMPtr<nsIListenerChangeListener> listener = iter.GetNext();
404 0 : listener->ListenersChanged(changes);
405 : }
406 0 : }
407 :
408 : } // namespace mozilla
409 :
410 : nsresult
411 2 : NS_NewEventListenerService(nsIEventListenerService** aResult)
412 : {
413 2 : *aResult = new mozilla::EventListenerService();
414 2 : NS_ADDREF(*aResult);
415 2 : return NS_OK;
416 : }
|