Bug 1032573 part 4 - Add AnimationTimeline::ToTimelineTime helper method; r=dbaron
[gecko.git] / dom / events / EventListenerManager.h
blob4f7ec1571f15d6f4fd9d8256919c7392d2354dc5
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/. */
6 #ifndef mozilla_EventListenerManager_h_
7 #define mozilla_EventListenerManager_h_
9 #include "mozilla/BasicEvents.h"
10 #include "mozilla/dom/EventListenerBinding.h"
11 #include "mozilla/JSEventHandler.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "nsCOMPtr.h"
14 #include "nsCycleCollectionParticipant.h"
15 #include "nsGkAtoms.h"
16 #include "nsIDOMEventListener.h"
17 #include "nsTObserverArray.h"
19 class nsIDOMEvent;
20 class nsIEventListenerInfo;
21 class nsIScriptContext;
22 class nsPIDOMWindow;
23 class JSTracer;
25 struct EventTypeData;
27 template<class T> class nsCOMArray;
29 namespace mozilla {
31 class ELMCreationDetector;
32 class EventListenerManager;
34 namespace dom {
35 class EventTarget;
36 class Element;
37 } // namespace dom
39 typedef dom::CallbackObjectHolder<dom::EventListener,
40 nsIDOMEventListener> EventListenerHolder;
42 struct EventListenerFlags
44 friend class EventListenerManager;
45 private:
46 // If mListenerIsJSListener is true, the listener is implemented by JS.
47 // Otherwise, it's implemented by native code or JS but it's wrapped.
48 bool mListenerIsJSListener : 1;
50 public:
51 // If mCapture is true, it means the listener captures the event. Otherwise,
52 // it's listening at bubbling phase.
53 bool mCapture : 1;
54 // If mInSystemGroup is true, the listener is listening to the events in the
55 // system group.
56 bool mInSystemGroup : 1;
57 // If mAllowUntrustedEvents is true, the listener is listening to the
58 // untrusted events too.
59 bool mAllowUntrustedEvents : 1;
61 EventListenerFlags() :
62 mListenerIsJSListener(false),
63 mCapture(false), mInSystemGroup(false), mAllowUntrustedEvents(false)
67 bool Equals(const EventListenerFlags& aOther) const
69 return (mCapture == aOther.mCapture &&
70 mInSystemGroup == aOther.mInSystemGroup &&
71 mListenerIsJSListener == aOther.mListenerIsJSListener &&
72 mAllowUntrustedEvents == aOther.mAllowUntrustedEvents);
75 bool EqualsIgnoringTrustness(const EventListenerFlags& aOther) const
77 return (mCapture == aOther.mCapture &&
78 mInSystemGroup == aOther.mInSystemGroup &&
79 mListenerIsJSListener == aOther.mListenerIsJSListener);
82 bool operator==(const EventListenerFlags& aOther) const
84 return Equals(aOther);
88 inline EventListenerFlags TrustedEventsAtBubble()
90 EventListenerFlags flags;
91 return flags;
94 inline EventListenerFlags TrustedEventsAtCapture()
96 EventListenerFlags flags;
97 flags.mCapture = true;
98 return flags;
101 inline EventListenerFlags AllEventsAtBubbe()
103 EventListenerFlags flags;
104 flags.mAllowUntrustedEvents = true;
105 return flags;
108 inline EventListenerFlags AllEventsAtCapture()
110 EventListenerFlags flags;
111 flags.mCapture = true;
112 flags.mAllowUntrustedEvents = true;
113 return flags;
116 inline EventListenerFlags TrustedEventsAtSystemGroupBubble()
118 EventListenerFlags flags;
119 flags.mInSystemGroup = true;
120 return flags;
123 inline EventListenerFlags TrustedEventsAtSystemGroupCapture()
125 EventListenerFlags flags;
126 flags.mCapture = true;
127 flags.mInSystemGroup = true;
128 return flags;
131 inline EventListenerFlags AllEventsAtSystemGroupBubble()
133 EventListenerFlags flags;
134 flags.mInSystemGroup = true;
135 flags.mAllowUntrustedEvents = true;
136 return flags;
139 inline EventListenerFlags AllEventsAtSystemGroupCapture()
141 EventListenerFlags flags;
142 flags.mCapture = true;
143 flags.mInSystemGroup = true;
144 flags.mAllowUntrustedEvents = true;
145 return flags;
149 * Event listener manager
152 class EventListenerManager MOZ_FINAL
154 ~EventListenerManager();
156 public:
157 struct Listener
159 EventListenerHolder mListener;
160 nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
161 nsString mTypeString; // for non-main-threads
162 uint16_t mEventType;
164 enum ListenerType MOZ_ENUM_TYPE(uint8_t)
166 eNativeListener = 0,
167 eJSEventListener,
168 eWrappedJSListener,
169 eWebIDLListener,
170 eListenerTypeCount
172 uint8_t mListenerType;
174 bool mListenerIsHandler : 1;
175 bool mHandlerIsString : 1;
176 bool mAllEvents : 1;
178 EventListenerFlags mFlags;
180 JSEventHandler* GetJSEventHandler() const
182 return (mListenerType == eJSEventListener) ?
183 static_cast<JSEventHandler*>(mListener.GetXPCOMCallback()) :
184 nullptr;
187 Listener()
189 MOZ_ASSERT(sizeof(mListenerType) == 1);
190 MOZ_ASSERT(eListenerTypeCount < 255);
193 ~Listener()
195 if ((mListenerType == eJSEventListener) && mListener) {
196 static_cast<JSEventHandler*>(
197 mListener.GetXPCOMCallback())->Disconnect();
201 MOZ_ALWAYS_INLINE bool IsListening(const WidgetEvent* aEvent) const
203 if (mFlags.mInSystemGroup != aEvent->mFlags.mInSystemGroup) {
204 return false;
206 // FIXME Should check !mFlags.mCapture when the event is in target
207 // phase because capture phase event listeners should not be fired.
208 // But it breaks at least <xul:dialog>'s buttons. Bug 235441.
209 return ((mFlags.mCapture && aEvent->mFlags.mInCapturePhase) ||
210 (!mFlags.mCapture && aEvent->mFlags.mInBubblingPhase));
214 EventListenerManager(dom::EventTarget* aTarget);
216 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EventListenerManager)
218 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager)
220 void AddEventListener(const nsAString& aType,
221 nsIDOMEventListener* aListener,
222 bool aUseCapture,
223 bool aWantsUntrusted)
225 EventListenerHolder holder(aListener);
226 AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
228 void AddEventListener(const nsAString& aType,
229 dom::EventListener* aListener,
230 bool aUseCapture,
231 bool aWantsUntrusted)
233 EventListenerHolder holder(aListener);
234 AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
236 void RemoveEventListener(const nsAString& aType,
237 nsIDOMEventListener* aListener,
238 bool aUseCapture)
240 EventListenerHolder holder(aListener);
241 RemoveEventListener(aType, holder, aUseCapture);
243 void RemoveEventListener(const nsAString& aType,
244 dom::EventListener* aListener,
245 bool aUseCapture)
247 EventListenerHolder holder(aListener);
248 RemoveEventListener(aType, holder, aUseCapture);
251 void AddListenerForAllEvents(nsIDOMEventListener* aListener,
252 bool aUseCapture,
253 bool aWantsUntrusted,
254 bool aSystemEventGroup);
255 void RemoveListenerForAllEvents(nsIDOMEventListener* aListener,
256 bool aUseCapture,
257 bool aSystemEventGroup);
260 * Sets events listeners of all types.
261 * @param an event listener
263 void AddEventListenerByType(nsIDOMEventListener *aListener,
264 const nsAString& type,
265 const EventListenerFlags& aFlags)
267 EventListenerHolder holder(aListener);
268 AddEventListenerByType(holder, type, aFlags);
270 void AddEventListenerByType(const EventListenerHolder& aListener,
271 const nsAString& type,
272 const EventListenerFlags& aFlags);
273 void RemoveEventListenerByType(nsIDOMEventListener *aListener,
274 const nsAString& type,
275 const EventListenerFlags& aFlags)
277 EventListenerHolder holder(aListener);
278 RemoveEventListenerByType(holder, type, aFlags);
280 void RemoveEventListenerByType(const EventListenerHolder& aListener,
281 const nsAString& type,
282 const EventListenerFlags& aFlags);
285 * Sets the current "inline" event listener for aName to be a
286 * function compiled from aFunc if !aDeferCompilation. If
287 * aDeferCompilation, then we assume that we can get the string from
288 * mTarget later and compile lazily.
290 * aElement, if not null, is the element the string is associated with.
292 // XXXbz does that play correctly with nodes being adopted across
293 // documents? Need to double-check the spec here.
294 nsresult SetEventHandler(nsIAtom *aName,
295 const nsAString& aFunc,
296 bool aDeferCompilation,
297 bool aPermitUntrustedEvents,
298 dom::Element* aElement);
300 * Remove the current "inline" event listener for aName.
302 void RemoveEventHandler(nsIAtom *aName, const nsAString& aTypeString);
304 void HandleEvent(nsPresContext* aPresContext,
305 WidgetEvent* aEvent,
306 nsIDOMEvent** aDOMEvent,
307 dom::EventTarget* aCurrentTarget,
308 nsEventStatus* aEventStatus)
310 if (mListeners.IsEmpty() || aEvent->mFlags.mPropagationStopped) {
311 return;
314 if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) {
315 return;
318 if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
319 return;
322 // Check if we already know that there is no event listener for the event.
323 if (mNoListenerForEvent == aEvent->message &&
324 (mNoListenerForEvent != NS_USER_DEFINED_EVENT ||
325 mNoListenerForEventAtom == aEvent->userType)) {
326 return;
328 HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
329 aEventStatus);
333 * Tells the event listener manager that its target (which owns it) is
334 * no longer using it (and could go away).
336 void Disconnect();
339 * Allows us to quickly determine if we have mutation listeners registered.
341 bool HasMutationListeners();
344 * Allows us to quickly determine whether we have unload or beforeunload
345 * listeners registered.
347 bool HasUnloadListeners();
350 * Returns the mutation bits depending on which mutation listeners are
351 * registered to this listener manager.
352 * @note If a listener is an nsIDOMMutationListener, all possible mutation
353 * event bits are returned. All bits are also returned if one of the
354 * event listeners is registered to handle DOMSubtreeModified events.
356 uint32_t MutationListenerBits();
359 * Returns true if there is at least one event listener for aEventName.
361 bool HasListenersFor(const nsAString& aEventName);
364 * Returns true if there is at least one event listener for aEventNameWithOn.
365 * Note that aEventNameWithOn must start with "on"!
367 bool HasListenersFor(nsIAtom* aEventNameWithOn);
370 * Returns true if there is at least one event listener.
372 bool HasListeners();
375 * Sets aList to the list of nsIEventListenerInfo objects representing the
376 * listeners managed by this listener manager.
378 nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
380 uint32_t GetIdentifierForEvent(nsIAtom* aEvent);
382 static void Shutdown();
385 * Returns true if there may be a paint event listener registered,
386 * false if there definitely isn't.
388 bool MayHavePaintEventListener() { return mMayHavePaintEventListener; }
391 * Returns true if there may be a touch event listener registered,
392 * false if there definitely isn't.
394 bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
396 bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
397 bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
399 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
401 uint32_t ListenerCount() const
403 return mListeners.Length();
406 void MarkForCC();
408 void TraceListeners(JSTracer* aTrc);
410 dom::EventTarget* GetTarget() { return mTarget; }
412 protected:
413 void HandleEventInternal(nsPresContext* aPresContext,
414 WidgetEvent* aEvent,
415 nsIDOMEvent** aDOMEvent,
416 dom::EventTarget* aCurrentTarget,
417 nsEventStatus* aEventStatus);
419 nsresult HandleEventSubType(Listener* aListener,
420 nsIDOMEvent* aDOMEvent,
421 dom::EventTarget* aCurrentTarget);
424 * Compile the "inline" event listener for aListener. The
425 * body of the listener can be provided in aBody; if this is null we
426 * will look for it on mTarget. If aBody is provided, aElement should be
427 * as well; otherwise it will also be inferred from mTarget.
429 nsresult CompileEventHandlerInternal(Listener* aListener,
430 const nsAString* aBody,
431 dom::Element* aElement);
434 * Find the Listener for the "inline" event listener for aTypeAtom.
436 Listener* FindEventHandler(uint32_t aEventType,
437 nsIAtom* aTypeAtom,
438 const nsAString& aTypeString);
441 * Set the "inline" event listener for aName to aHandler. aHandler may be
442 * have no actual handler set to indicate that we should lazily get and
443 * compile the string for this listener, but in that case aContext and
444 * aScopeGlobal must be non-null. Otherwise, aContext and aScopeGlobal are
445 * allowed to be null.
447 Listener* SetEventHandlerInternal(nsIAtom* aName,
448 const nsAString& aTypeString,
449 const TypedEventHandler& aHandler,
450 bool aPermitUntrustedEvents);
452 bool IsDeviceType(uint32_t aType);
453 void EnableDevice(uint32_t aType);
454 void DisableDevice(uint32_t aType);
456 public:
458 * Set the "inline" event listener for aEventName to aHandler. If
459 * aHandler is null, this will actually remove the event listener
461 void SetEventHandler(nsIAtom* aEventName,
462 const nsAString& aTypeString,
463 dom::EventHandlerNonNull* aHandler);
464 void SetEventHandler(dom::OnErrorEventHandlerNonNull* aHandler);
465 void SetEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler);
468 * Get the value of the "inline" event listener for aEventName.
469 * This may cause lazy compilation if the listener is uncompiled.
471 * Note: It's the caller's responsibility to make sure to call the right one
472 * of these methods. In particular, "onerror" events use
473 * OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
474 * for others.
476 dom::EventHandlerNonNull* GetEventHandler(nsIAtom* aEventName,
477 const nsAString& aTypeString)
479 const TypedEventHandler* typedHandler =
480 GetTypedEventHandler(aEventName, aTypeString);
481 return typedHandler ? typedHandler->NormalEventHandler() : nullptr;
484 dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler()
486 const TypedEventHandler* typedHandler = mIsMainThreadELM ?
487 GetTypedEventHandler(nsGkAtoms::onerror, EmptyString()) :
488 GetTypedEventHandler(nullptr, NS_LITERAL_STRING("error"));
489 return typedHandler ? typedHandler->OnErrorEventHandler() : nullptr;
492 dom::OnBeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler()
494 const TypedEventHandler* typedHandler =
495 GetTypedEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
496 return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr;
499 protected:
501 * Helper method for implementing the various Get*EventHandler above. Will
502 * return null if we don't have an event handler for this event name.
504 const TypedEventHandler* GetTypedEventHandler(nsIAtom* aEventName,
505 const nsAString& aTypeString);
507 void AddEventListener(const nsAString& aType,
508 const EventListenerHolder& aListener,
509 bool aUseCapture,
510 bool aWantsUntrusted);
511 void RemoveEventListener(const nsAString& aType,
512 const EventListenerHolder& aListener,
513 bool aUseCapture);
515 void AddEventListenerInternal(const EventListenerHolder& aListener,
516 uint32_t aType,
517 nsIAtom* aTypeAtom,
518 const nsAString& aTypeString,
519 const EventListenerFlags& aFlags,
520 bool aHandler = false,
521 bool aAllEvents = false);
522 void RemoveEventListenerInternal(const EventListenerHolder& aListener,
523 uint32_t aType,
524 nsIAtom* aUserType,
525 const nsAString& aTypeString,
526 const EventListenerFlags& aFlags,
527 bool aAllEvents = false);
528 void RemoveAllListeners();
529 const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
530 const EventTypeData* GetTypeDataForEventName(nsIAtom* aName);
531 nsPIDOMWindow* GetInnerWindowForTarget();
532 already_AddRefed<nsPIDOMWindow> GetTargetAsInnerWindow() const;
534 bool ListenerCanHandle(Listener* aListener, WidgetEvent* aEvent);
536 already_AddRefed<nsIScriptGlobalObject>
537 GetScriptGlobalAndDocument(nsIDocument** aDoc);
539 uint32_t mMayHavePaintEventListener : 1;
540 uint32_t mMayHaveMutationListeners : 1;
541 uint32_t mMayHaveCapturingListeners : 1;
542 uint32_t mMayHaveSystemGroupListeners : 1;
543 uint32_t mMayHaveTouchEventListener : 1;
544 uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
545 uint32_t mMayHavePointerEnterLeaveEventListener : 1;
546 uint32_t mClearingListeners : 1;
547 uint32_t mIsMainThreadELM : 1;
548 uint32_t mNoListenerForEvent : 23;
550 nsAutoTObserverArray<Listener, 2> mListeners;
551 dom::EventTarget* mTarget; // WEAK
552 nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
554 friend class ELMCreationDetector;
555 static uint32_t sMainThreadCreatedCount;
558 } // namespace mozilla
561 * NS_AddSystemEventListener() is a helper function for implementing
562 * EventTarget::AddSystemEventListener().
564 inline nsresult
565 NS_AddSystemEventListener(mozilla::dom::EventTarget* aTarget,
566 const nsAString& aType,
567 nsIDOMEventListener *aListener,
568 bool aUseCapture,
569 bool aWantsUntrusted)
571 mozilla::EventListenerManager* listenerManager =
572 aTarget->GetOrCreateListenerManager();
573 NS_ENSURE_STATE(listenerManager);
574 mozilla::EventListenerFlags flags;
575 flags.mInSystemGroup = true;
576 flags.mCapture = aUseCapture;
577 flags.mAllowUntrustedEvents = aWantsUntrusted;
578 listenerManager->AddEventListenerByType(aListener, aType, flags);
579 return NS_OK;
582 #endif // mozilla_EventListenerManager_h_