EventListenerManager.h (27636B)
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 #ifndef mozilla_EventListenerManager_h_ 8 #define mozilla_EventListenerManager_h_ 9 10 #include "mozilla/BasicEvents.h" 11 #include "mozilla/JSEventHandler.h" 12 #include "mozilla/MemoryReporting.h" 13 #include "mozilla/dom/AbortFollower.h" 14 #include "mozilla/dom/EventListenerBinding.h" 15 #include "nsCOMPtr.h" 16 #include "nsCycleCollectionParticipant.h" 17 #include "nsGkAtoms.h" 18 #include "nsIDOMEventListener.h" 19 #include "nsTArray.h" 20 #include "nsTObserverArray.h" 21 22 class nsIEventListenerInfo; 23 class nsPIDOMWindowInner; 24 class JSTracer; 25 26 struct EventTypeData; 27 28 namespace mozilla { 29 30 class ELMCreationDetector; 31 class EventListenerManager; 32 class ListenerSignalFollower; 33 34 namespace dom { 35 class Event; 36 class EventTarget; 37 class Element; 38 } // namespace dom 39 40 using EventListenerHolder = 41 dom::CallbackObjectHolder<dom::EventListener, nsIDOMEventListener>; 42 43 struct EventListenerFlags { 44 friend class EventListenerManager; 45 46 private: 47 // If mListenerIsJSListener is true, the listener is implemented by JS. 48 // Otherwise, it's implemented by native code or JS but it's wrapped. 49 bool mListenerIsJSListener : 1; 50 51 public: 52 // If mCapture is true, it means the listener captures the event. Otherwise, 53 // it's listening at bubbling phase. 54 bool mCapture : 1; 55 // If mInSystemGroup is true, the listener is listening to the events in the 56 // system group. 57 bool mInSystemGroup : 1; 58 // If mAllowUntrustedEvents is true, the listener is listening to the 59 // untrusted events too. 60 bool mAllowUntrustedEvents : 1; 61 // If mPassive is true, the listener will not be calling preventDefault on the 62 // event. (If it does call preventDefault, we should ignore it). 63 bool mPassive : 1; 64 // If mOnce is true, the listener will be removed from the manager before it 65 // is invoked, so that it would only be invoked once. 66 bool mOnce : 1; 67 68 EventListenerFlags() 69 : mListenerIsJSListener(false), 70 mCapture(false), 71 mInSystemGroup(false), 72 mAllowUntrustedEvents(false), 73 mPassive(false), 74 mOnce(false) {} 75 76 bool EqualsForAddition(const EventListenerFlags& aOther) const { 77 return (mCapture == aOther.mCapture && 78 mInSystemGroup == aOther.mInSystemGroup && 79 mListenerIsJSListener == aOther.mListenerIsJSListener && 80 mAllowUntrustedEvents == aOther.mAllowUntrustedEvents); 81 // Don't compare mPassive or mOnce 82 } 83 84 bool EqualsForRemoval(const EventListenerFlags& aOther) const { 85 return (mCapture == aOther.mCapture && 86 mInSystemGroup == aOther.mInSystemGroup && 87 mListenerIsJSListener == aOther.mListenerIsJSListener); 88 // Don't compare mAllowUntrustedEvents, mPassive, or mOnce 89 } 90 }; 91 92 inline EventListenerFlags TrustedEventsAtBubble() { 93 EventListenerFlags flags; 94 return flags; 95 } 96 97 inline EventListenerFlags TrustedEventsAtCapture() { 98 EventListenerFlags flags; 99 flags.mCapture = true; 100 return flags; 101 } 102 103 inline EventListenerFlags AllEventsAtBubble() { 104 EventListenerFlags flags; 105 flags.mAllowUntrustedEvents = true; 106 return flags; 107 } 108 109 inline EventListenerFlags AllEventsAtCapture() { 110 EventListenerFlags flags; 111 flags.mCapture = true; 112 flags.mAllowUntrustedEvents = true; 113 return flags; 114 } 115 116 inline EventListenerFlags TrustedEventsAtSystemGroupBubble() { 117 EventListenerFlags flags; 118 flags.mInSystemGroup = true; 119 return flags; 120 } 121 122 inline EventListenerFlags TrustedEventsAtSystemGroupCapture() { 123 EventListenerFlags flags; 124 flags.mCapture = true; 125 flags.mInSystemGroup = true; 126 return flags; 127 } 128 129 inline EventListenerFlags AllEventsAtSystemGroupBubble() { 130 EventListenerFlags flags; 131 flags.mInSystemGroup = true; 132 flags.mAllowUntrustedEvents = true; 133 return flags; 134 } 135 136 inline EventListenerFlags AllEventsAtSystemGroupCapture() { 137 EventListenerFlags flags; 138 flags.mCapture = true; 139 flags.mInSystemGroup = true; 140 flags.mAllowUntrustedEvents = true; 141 return flags; 142 } 143 144 class EventListenerManagerBase { 145 protected: 146 EventListenerManagerBase(); 147 148 void ClearNoListenersForEvents() { 149 mNoListenerForEvents[0] = eVoidEvent; 150 mNoListenerForEvents[1] = eVoidEvent; 151 mNoListenerForEvents[2] = eVoidEvent; 152 } 153 154 EventMessage mNoListenerForEvents[3]; 155 uint16_t mMayHaveDOMActivateEventListener : 1; 156 uint16_t mMayHaveCapturingListeners : 1; 157 uint16_t mMayHaveSystemGroupListeners : 1; 158 uint16_t mMayHaveTouchEventListener : 1; 159 uint16_t mMayHaveMouseEnterLeaveEventListener : 1; 160 uint16_t mMayHavePointerEnterLeaveEventListener : 1; 161 uint16_t mMayHavePointerRawUpdateEventListener : 1; 162 uint16_t mMayHaveSelectionChangeEventListener : 1; 163 uint16_t mMayHaveFormSelectEventListener : 1; 164 uint16_t mMayHaveTransitionEventListener : 1; 165 uint16_t mMayHaveSMILTimeEventListener : 1; 166 uint16_t mClearingListeners : 1; 167 uint16_t mIsMainThreadELM : 1; 168 uint16_t mMayHaveListenersForUntrustedEvents : 1; 169 // 2 unused flag. 170 }; 171 172 /* 173 * Event listener manager 174 */ 175 176 class EventListenerManager final : public EventListenerManagerBase { 177 ~EventListenerManager(); 178 179 public: 180 struct Listener; 181 class ListenerSignalFollower : public dom::AbortFollower { 182 public: 183 explicit ListenerSignalFollower(EventListenerManager* aListenerManager, 184 Listener* aListener, nsAtom* aTypeAtom); 185 186 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 187 NS_DECL_CYCLE_COLLECTION_CLASS(ListenerSignalFollower) 188 189 void RunAbortAlgorithm() override; 190 191 void Disconnect() { 192 mListenerManager = nullptr; 193 mListener.Reset(); 194 Unfollow(); 195 } 196 197 protected: 198 ~ListenerSignalFollower() = default; 199 200 EventListenerManager* mListenerManager; 201 EventListenerHolder mListener; 202 RefPtr<nsAtom> mTypeAtom; 203 bool mAllEvents; 204 EventListenerFlags mFlags; 205 }; 206 207 struct Listener { 208 RefPtr<ListenerSignalFollower> mSignalFollower; 209 EventListenerHolder mListener; 210 211 enum ListenerType : uint8_t { 212 // No listener. 213 eNoListener, 214 // A generic C++ implementation of nsIDOMEventListener. 215 eNativeListener, 216 // An event handler attribute using JSEventHandler. 217 eJSEventListener, 218 // A scripted EventListener. 219 eWebIDLListener, 220 }; 221 ListenerType mListenerType; 222 223 bool mListenerIsHandler : 1; 224 bool mHandlerIsString : 1; 225 bool mAllEvents : 1; 226 bool mEnabled : 1; 227 228 EventListenerFlags mFlags; 229 230 JSEventHandler* GetJSEventHandler() const { 231 return (mListenerType == eJSEventListener) 232 ? static_cast<JSEventHandler*>(mListener.GetXPCOMCallback()) 233 : nullptr; 234 } 235 236 Listener() 237 : mListenerType(eNoListener), 238 mListenerIsHandler(false), 239 mHandlerIsString(false), 240 mAllEvents(false), 241 mEnabled(true) {} 242 243 Listener(Listener&& aOther) 244 : mSignalFollower(std::move(aOther.mSignalFollower)), 245 mListener(std::move(aOther.mListener)), 246 mListenerType(aOther.mListenerType), 247 mListenerIsHandler(aOther.mListenerIsHandler), 248 mHandlerIsString(aOther.mHandlerIsString), 249 mAllEvents(aOther.mAllEvents), 250 mEnabled(aOther.mEnabled), 251 mFlags(aOther.mFlags) { 252 aOther.mListenerType = eNoListener; 253 aOther.mListenerIsHandler = false; 254 aOther.mHandlerIsString = false; 255 aOther.mAllEvents = false; 256 aOther.mEnabled = true; 257 } 258 259 ~Listener() { 260 if ((mListenerType == eJSEventListener) && mListener) { 261 static_cast<JSEventHandler*>(mListener.GetXPCOMCallback()) 262 ->Disconnect(); 263 } 264 if (mSignalFollower) { 265 mSignalFollower->Disconnect(); 266 } 267 } 268 269 MOZ_ALWAYS_INLINE bool MatchesEventGroup(const WidgetEvent* aEvent) const { 270 return mFlags.mInSystemGroup == aEvent->mFlags.mInSystemGroup; 271 } 272 273 MOZ_ALWAYS_INLINE bool MatchesEventPhase(const WidgetEvent* aEvent) const { 274 return ((mFlags.mCapture && aEvent->mFlags.mInCapturePhase) || 275 (!mFlags.mCapture && aEvent->mFlags.mInBubblingPhase)); 276 } 277 278 // Allow only trusted events, except when listener permits untrusted 279 // events. 280 MOZ_ALWAYS_INLINE bool AllowsEventTrustedness( 281 const WidgetEvent* aEvent) const { 282 return aEvent->IsTrusted() || mFlags.mAllowUntrustedEvents; 283 } 284 }; 285 286 /** 287 * A reference counted subclass of a listener observer array. 288 */ 289 struct ListenerArray final : public nsAutoTObserverArray<Listener, 1> { 290 NS_INLINE_DECL_REFCOUNTING(EventListenerManager::ListenerArray); 291 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; 292 293 protected: 294 ~ListenerArray() = default; 295 }; 296 297 /** 298 * An entry in the event listener map for a certain event type, carrying the 299 * array of listeners for that type. 300 */ 301 struct EventListenerMapEntry { 302 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; 303 304 // The event type. Null if this entry is for "all events" listeners. 305 RefPtr<nsAtom> mTypeAtom; 306 // The array of listeners. New listeners are always added at the end. 307 // Always non-null. 308 // This is a RefPtr rather than an inline member for two reasons: 309 // - It needs to be a separate heap allocation so that, if the array of 310 // entries is mutated during iteration, the ListenerArray remains in a 311 // stable place. 312 // - It's a RefPtr rather than a UniquePtr so that iteration can share 313 // ownership of it and make sure that the listener array remains alive 314 // even if the entry is removed during iteration. 315 RefPtr<ListenerArray> mListeners; 316 }; 317 318 /** 319 * The map of event listeners, keyed by event type atom. 320 */ 321 struct EventListenerMap { 322 bool IsEmpty() const { return mEntries.IsEmpty(); } 323 void Clear() { mEntries.Clear(); } 324 325 Maybe<size_t> EntryIndexForType(nsAtom* aTypeAtom) const; 326 Maybe<size_t> EntryIndexForAllEvents() const; 327 328 // Returns null if no entry is present for the given type. 329 RefPtr<ListenerArray> GetListenersForType(nsAtom* aTypeAtom) const; 330 RefPtr<ListenerArray> GetListenersForAllEvents() const; 331 332 // Never returns null, creates a new empty entry if needed. 333 RefPtr<ListenerArray> GetOrCreateListenersForType(nsAtom* aTypeAtom); 334 RefPtr<ListenerArray> GetOrCreateListenersForAllEvents(); 335 336 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; 337 338 // The array of entries, ordered by event type atom (specifically by the 339 // nsAtom* address). If mEntries contains an entry for "all events" 340 // listeners, that entry will be the first entry, because its atom will be 341 // null so it will be ordered to the front. 342 // All entries have non-empty listener arrays. If a non-empty listener 343 // entry becomes empty, it is removed immediately. 344 AutoTArray<EventListenerMapEntry, 2> mEntries; 345 }; 346 347 explicit EventListenerManager(dom::EventTarget* aTarget); 348 349 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EventListenerManager) 350 351 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager) 352 353 void AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, 354 bool aUseCapture, bool aWantsUntrusted) { 355 AddEventListener(aType, EventListenerHolder(aListener), aUseCapture, 356 aWantsUntrusted); 357 } 358 void AddEventListener(const nsAString& aType, dom::EventListener* aListener, 359 const dom::AddEventListenerOptionsOrBoolean& aOptions, 360 bool aWantsUntrusted) { 361 AddEventListener(aType, EventListenerHolder(aListener), aOptions, 362 aWantsUntrusted); 363 } 364 void RemoveEventListener(const nsAString& aType, 365 nsIDOMEventListener* aListener, bool aUseCapture) { 366 RemoveEventListener(aType, EventListenerHolder(aListener), aUseCapture); 367 } 368 void RemoveEventListener(const nsAString& aType, 369 dom::EventListener* aListener, 370 const dom::EventListenerOptionsOrBoolean& aOptions) { 371 RemoveEventListener(aType, EventListenerHolder(aListener), aOptions); 372 } 373 374 void AddListenerForAllEvents(dom::EventListener* aListener, bool aUseCapture, 375 bool aWantsUntrusted, bool aSystemEventGroup); 376 void RemoveListenerForAllEvents(dom::EventListener* aListener, 377 bool aUseCapture, bool aSystemEventGroup); 378 379 /** 380 * Sets events listeners of all types. 381 * @param an event listener 382 */ 383 void AddEventListenerByType(nsIDOMEventListener* aListener, 384 const nsAString& type, 385 const EventListenerFlags& aFlags) { 386 AddEventListenerByType(EventListenerHolder(aListener), type, aFlags); 387 } 388 void AddEventListenerByType(dom::EventListener* aListener, 389 const nsAString& type, 390 const EventListenerFlags& aFlags) { 391 AddEventListenerByType(EventListenerHolder(aListener), type, aFlags); 392 } 393 void AddEventListenerByType( 394 EventListenerHolder aListener, const nsAString& type, 395 const EventListenerFlags& aFlags, 396 const dom::Optional<bool>& aPassive = dom::Optional<bool>(), 397 dom::AbortSignal* aSignal = nullptr); 398 void RemoveEventListenerByType(nsIDOMEventListener* aListener, 399 const nsAString& type, 400 const EventListenerFlags& aFlags) { 401 RemoveEventListenerByType(EventListenerHolder(aListener), type, aFlags); 402 } 403 void RemoveEventListenerByType(dom::EventListener* aListener, 404 const nsAString& type, 405 const EventListenerFlags& aFlags) { 406 RemoveEventListenerByType(EventListenerHolder(aListener), type, aFlags); 407 } 408 void RemoveEventListenerByType(EventListenerHolder aListener, 409 const nsAString& type, 410 const EventListenerFlags& aFlags); 411 412 /** 413 * Sets the current "inline" event listener for aName to be a 414 * function compiled from aFunc if !aDeferCompilation. If 415 * aDeferCompilation, then we assume that we can get the string from 416 * mTarget later and compile lazily. 417 * 418 * aElement, if not null, is the element the string is associated with. 419 */ 420 // XXXbz does that play correctly with nodes being adopted across 421 // documents? Need to double-check the spec here. 422 nsresult SetEventHandler(nsAtom* aName, const nsAString& aFunc, 423 bool aDeferCompilation, bool aPermitUntrustedEvents, 424 dom::Element* aElement); 425 /** 426 * Remove the current "inline" event listener for aName. 427 */ 428 void RemoveEventHandler(nsAtom* aName); 429 430 // We only get called from the event dispatch code, which knows to be careful 431 // with what it's doing. We could annotate ourselves as MOZ_CAN_RUN_SCRIPT, 432 // but then the event dispatch code would need a ton of MOZ_KnownLive for 433 // things that come from slightly complicated stack-lifetime data structures. 434 MOZ_CAN_RUN_SCRIPT_BOUNDARY 435 void HandleEvent(nsPresContext* aPresContext, WidgetEvent* aEvent, 436 dom::Event** aDOMEvent, dom::EventTarget* aCurrentTarget, 437 nsEventStatus* aEventStatus, bool aItemInShadowTree) { 438 if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) { 439 return; 440 } 441 442 if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) { 443 return; 444 } 445 446 if (!aEvent->IsTrusted() && !mMayHaveListenersForUntrustedEvents) { 447 return; 448 } 449 450 // Check if we already know that there is no event listener for the event. 451 if (aEvent->mMessage == eUnidentifiedEvent) { 452 if (mNoListenerForEventAtom == aEvent->mSpecifiedEventType) { 453 return; 454 } 455 } else if (mNoListenerForEvents[0] == aEvent->mMessage || 456 mNoListenerForEvents[1] == aEvent->mMessage || 457 mNoListenerForEvents[2] == aEvent->mMessage) { 458 return; 459 } 460 461 if (mListenerMap.IsEmpty() || aEvent->PropagationStopped()) { 462 return; 463 } 464 465 HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget, 466 aEventStatus, aItemInShadowTree); 467 } 468 469 /** 470 * Tells the event listener manager that its target (which owns it) is 471 * no longer using it (and could go away). 472 */ 473 void Disconnect(); 474 475 /** 476 * Allows us to quickly determine whether we have unload listeners registered. 477 */ 478 bool HasUnloadListeners(); 479 480 /** 481 * Allows us to quickly determine whether we have beforeunload listeners 482 * registered. 483 */ 484 bool HasBeforeUnloadListeners(); 485 486 /** 487 * Returns true if there is at least one event listener for aEventName. 488 */ 489 bool HasListenersFor(const nsAString& aEventName) const; 490 491 /** 492 * Returns true if there is at least one event listener for aEventNameWithOn. 493 * Note that aEventNameWithOn must start with "on"! 494 */ 495 bool HasListenersFor(nsAtom* aEventNameWithOn) const; 496 497 bool HasNonPassiveListenersFor(const WidgetEvent* aEvent) const; 498 499 /** 500 * Similar to HasListenersFor, but ignores system group listeners. 501 */ 502 bool HasNonSystemGroupListenersFor(nsAtom* aEventNameWithOn) const; 503 504 /** 505 * Returns true if there is at least one event listener. 506 */ 507 bool HasListeners() const; 508 509 /** 510 * Sets aList to the list of nsIEventListenerInfo objects representing the 511 * listeners managed by this listener manager. 512 */ 513 nsresult GetListenerInfo(nsTArray<RefPtr<nsIEventListenerInfo>>& aList); 514 515 nsresult IsListenerEnabled(nsAString& aType, JSObject* aListener, 516 bool aCapturing, bool aAllowsUntrusted, 517 bool aInSystemEventGroup, bool aIsHandler, 518 bool* aEnabled); 519 520 nsresult SetListenerEnabled(nsAString& aType, JSObject* aListener, 521 bool aCapturing, bool aAllowsUntrusted, 522 bool aInSystemEventGroup, bool aIsHandler, 523 bool aEnabled); 524 525 uint32_t GetIdentifierForEvent(nsAtom* aEvent); 526 527 bool MayHaveDOMActivateListeners() const { 528 return mMayHaveDOMActivateEventListener; 529 } 530 531 /** 532 * Returns true if there may be a touch event listener registered, 533 * false if there definitely isn't. 534 */ 535 bool MayHaveTouchEventListener() const { return mMayHaveTouchEventListener; } 536 537 bool MayHaveMouseEnterLeaveEventListener() const { 538 return mMayHaveMouseEnterLeaveEventListener; 539 } 540 bool MayHavePointerEnterLeaveEventListener() const { 541 return mMayHavePointerEnterLeaveEventListener; 542 } 543 bool MayHavePointerRawUpdateEventListener() const { 544 return mMayHavePointerRawUpdateEventListener; 545 } 546 bool MayHaveSelectionChangeEventListener() const { 547 return mMayHaveSelectionChangeEventListener; 548 } 549 bool MayHaveFormSelectEventListener() const { 550 return mMayHaveFormSelectEventListener; 551 } 552 bool MayHaveTransitionEventListener() { 553 return mMayHaveTransitionEventListener; 554 } 555 bool MayHaveSMILTimeEventListener() const { 556 return mMayHaveSMILTimeEventListener; 557 } 558 559 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; 560 561 uint32_t ListenerCount() const; 562 563 void MarkForCC(); 564 565 void TraceListeners(JSTracer* aTrc); 566 567 dom::EventTarget* GetTarget() { return mTarget; } 568 569 bool HasNonSystemGroupListenersForUntrustedKeyEvents(); 570 bool HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents(); 571 572 bool HasApzAwareListeners(); 573 bool IsApzAwareEvent(nsAtom* aEvent); 574 575 bool HasNonPassiveWheelListener(); 576 577 /** 578 * Remove all event listeners from the event target this EventListenerManager 579 * is for. 580 */ 581 void RemoveAllListeners(); 582 583 protected: 584 MOZ_CAN_RUN_SCRIPT 585 void HandleEventInternal(nsPresContext* aPresContext, WidgetEvent* aEvent, 586 dom::Event** aDOMEvent, 587 dom::EventTarget* aCurrentTarget, 588 nsEventStatus* aEventStatus, bool aItemInShadowTree); 589 590 /** 591 * Iterate the listener array and calls the matching listeners. 592 * 593 * Returns true if any listener matching the event group was found. 594 */ 595 MOZ_CAN_RUN_SCRIPT 596 bool HandleEventWithListenerArray( 597 ListenerArray* aListeners, nsAtom* aTypeAtom, EventMessage aEventMessage, 598 nsPresContext* aPresContext, WidgetEvent* aEvent, dom::Event** aDOMEvent, 599 dom::EventTarget* aCurrentTarget, bool aItemInShadowTree); 600 601 /** 602 * Call the listener. 603 * 604 * Returns true if we should proceed iterating over the remaining listeners, 605 * or false if iteration should be stopped. 606 */ 607 MOZ_CAN_RUN_SCRIPT 608 bool HandleEventSingleListener(Listener* aListener, nsAtom* aTypeAtom, 609 WidgetEvent* aEvent, dom::Event* aDOMEvent, 610 dom::EventTarget* aCurrentTarget, 611 bool aItemInShadowTree); 612 613 /** 614 * If the given EventMessage has a legacy version that we support, then this 615 * function returns that legacy version. Otherwise, this function simply 616 * returns the passed-in EventMessage. 617 */ 618 static EventMessage GetLegacyEventMessage(EventMessage aEventMessage); 619 620 /** 621 * Get the event message for the given event name. 622 */ 623 EventMessage GetEventMessage(nsAtom* aEventName) const; 624 625 /** 626 * Get the event message and atom for the given event type. 627 */ 628 EventMessage GetEventMessageAndAtomForListener(const nsAString& aType, 629 nsAtom** aAtom); 630 631 void ProcessApzAwareEventListenerAdd(); 632 633 /** 634 * Compile the "inline" event listener for aListener. The 635 * body of the listener can be provided in aBody; if this is null we 636 * will look for it on mTarget. If aBody is provided, aElement should be 637 * as well; otherwise it will also be inferred from mTarget. 638 */ 639 nsresult CompileEventHandlerInternal(Listener* aListener, nsAtom* aTypeAtom, 640 const nsAString* aBody, 641 dom::Element* aElement); 642 643 /** 644 * Find the Listener for the "inline" event listener for aTypeAtom. 645 */ 646 Listener* FindEventHandler(nsAtom* aTypeAtom); 647 648 /** 649 * Set the "inline" event listener for aName to aHandler. aHandler may be 650 * have no actual handler set to indicate that we should lazily get and 651 * compile the string for this listener, but in that case aContext and 652 * aScopeGlobal must be non-null. Otherwise, aContext and aScopeGlobal are 653 * allowed to be null. 654 */ 655 Listener* SetEventHandlerInternal(nsAtom* aName, 656 const TypedEventHandler& aHandler, 657 bool aPermitUntrustedEvents); 658 659 bool IsDeviceType(nsAtom* aTypeAtom); 660 void EnableDevice(nsAtom* aTypeAtom); 661 void DisableDevice(nsAtom* aTypeAtom); 662 663 bool HasListenersForInternal(nsAtom* aEventNameWithOn, 664 bool aIgnoreSystemGroup) const; 665 666 Listener* GetListenerFor(nsAString& aType, JSObject* aListener, 667 bool aCapturing, bool aAllowsUntrusted, 668 bool aInSystemEventGroup, bool aIsHandler); 669 670 public: 671 /** 672 * Set the "inline" event listener for aEventName to aHandler. If 673 * aHandler is null, this will actually remove the event listener 674 */ 675 void SetEventHandler(nsAtom* aEventName, dom::EventHandlerNonNull* aHandler); 676 void SetEventHandler(dom::OnErrorEventHandlerNonNull* aHandler); 677 void SetEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler); 678 679 /** 680 * Get the value of the "inline" event listener for aEventName. 681 * This may cause lazy compilation if the listener is uncompiled. 682 * 683 * Note: It's the caller's responsibility to make sure to call the right one 684 * of these methods. In particular, "onerror" events use 685 * OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull 686 * for others. 687 */ 688 dom::EventHandlerNonNull* GetEventHandler(nsAtom* aEventName) { 689 const TypedEventHandler* typedHandler = GetTypedEventHandler(aEventName); 690 return typedHandler ? typedHandler->NormalEventHandler() : nullptr; 691 } 692 693 dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler() { 694 const TypedEventHandler* typedHandler = 695 GetTypedEventHandler(nsGkAtoms::onerror); 696 return typedHandler ? typedHandler->OnErrorEventHandler() : nullptr; 697 } 698 699 dom::OnBeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler() { 700 const TypedEventHandler* typedHandler = 701 GetTypedEventHandler(nsGkAtoms::onbeforeunload); 702 return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr; 703 } 704 705 private: 706 already_AddRefed<nsPIDOMWindowInner> WindowFromListener( 707 Listener* aListener, nsAtom* aTypeAtom, bool aItemInShadowTree); 708 709 protected: 710 /** 711 * Helper method for implementing the various Get*EventHandler above. Will 712 * return null if we don't have an event handler for this event name. 713 */ 714 const TypedEventHandler* GetTypedEventHandler(nsAtom* aEventName); 715 716 void AddEventListener(const nsAString& aType, EventListenerHolder aListener, 717 const dom::AddEventListenerOptionsOrBoolean& aOptions, 718 bool aWantsUntrusted); 719 void AddEventListener(const nsAString& aType, EventListenerHolder aListener, 720 bool aUseCapture, bool aWantsUntrusted); 721 void RemoveEventListener(const nsAString& aType, 722 EventListenerHolder aListener, 723 const dom::EventListenerOptionsOrBoolean& aOptions); 724 void RemoveEventListener(const nsAString& aType, 725 EventListenerHolder aListener, bool aUseCapture); 726 727 void AddEventListenerInternal(EventListenerHolder aListener, 728 EventMessage aEventMessage, nsAtom* aTypeAtom, 729 const EventListenerFlags& aFlags, 730 bool aHandler = false, bool aAllEvents = false, 731 dom::AbortSignal* aSignal = nullptr); 732 void RemoveEventListenerInternal(EventListenerHolder aListener, 733 nsAtom* aUserType, 734 const EventListenerFlags& aFlags, 735 bool aAllEvents = false); 736 void RemoveAllListenersSilently(); 737 void NotifyEventListenerRemoved(nsAtom* aUserType); 738 const EventTypeData* GetTypeDataForIID(const nsIID& aIID); 739 const EventTypeData* GetTypeDataForEventName(nsAtom* aName); 740 nsPIDOMWindowInner* GetInnerWindowForTarget(); 741 already_AddRefed<nsPIDOMWindowInner> GetTargetAsInnerWindow() const; 742 743 bool ListenerCanHandle(const Listener* aListener, 744 const WidgetEvent* aEvent) const; 745 746 // BE AWARE, a lot of instances of EventListenerManager will be created. 747 // Therefor, we need to keep this class compact. When you add integer 748 // members, please add them to EventListenerManagerBase and check the size 749 // at build time. 750 751 already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalAndDocument( 752 mozilla::dom::Document** aDoc); 753 754 void MaybeMarkPassive(EventMessage aMessage, EventListenerFlags& aFlags); 755 756 EventListenerMap mListenerMap; 757 dom::EventTarget* MOZ_NON_OWNING_REF mTarget; 758 RefPtr<nsAtom> mNoListenerForEventAtom; 759 760 friend class ELMCreationDetector; 761 static uint32_t sMainThreadCreatedCount; 762 }; 763 764 } // namespace mozilla 765 766 #endif // mozilla_EventListenerManager_h_