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