tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EventDispatcher.cpp (62502B)


      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 "mozilla/EventDispatcher.h"
      8 
      9 #include <new>
     10 
     11 #include "AnimationEvent.h"
     12 #include "BeforeUnloadEvent.h"
     13 #include "ClipboardEvent.h"
     14 #include "CommandEvent.h"
     15 #include "CompositionEvent.h"
     16 #include "DeviceMotionEvent.h"
     17 #include "DragEvent.h"
     18 #include "KeyboardEvent.h"
     19 #include "mozilla/Assertions.h"
     20 #include "mozilla/BasePrincipal.h"
     21 #include "mozilla/ContentEvents.h"
     22 #include "mozilla/EventListenerManager.h"
     23 #include "mozilla/MiscEvents.h"
     24 #include "mozilla/MouseEvents.h"
     25 #include "mozilla/ProfilerLabels.h"
     26 #include "mozilla/ProfilerMarkers.h"
     27 #include "mozilla/ScopeExit.h"
     28 #include "mozilla/TextEvents.h"
     29 #include "mozilla/TouchEvents.h"
     30 #include "mozilla/dom/BrowserParent.h"
     31 #include "mozilla/dom/CloseEvent.h"
     32 #include "mozilla/dom/CustomEvent.h"
     33 #include "mozilla/dom/DeviceOrientationEvent.h"
     34 #include "mozilla/dom/Document.h"
     35 #include "mozilla/dom/EventTarget.h"
     36 #include "mozilla/dom/FocusEvent.h"
     37 #include "mozilla/dom/HashChangeEvent.h"
     38 #include "mozilla/dom/InputEvent.h"
     39 #include "mozilla/dom/MessageEvent.h"
     40 #include "mozilla/dom/MouseScrollEvent.h"
     41 #include "mozilla/dom/NotifyPaintEvent.h"
     42 #include "mozilla/dom/PageTransitionEvent.h"
     43 #include "mozilla/dom/PerformanceEventTiming.h"
     44 #include "mozilla/dom/PerformanceMainThread.h"
     45 #include "mozilla/dom/PointerEvent.h"
     46 #include "mozilla/dom/RootedDictionary.h"
     47 #include "mozilla/dom/ScriptSettings.h"
     48 #include "mozilla/dom/ScrollAreaEvent.h"
     49 #include "mozilla/dom/SimpleGestureEvent.h"
     50 #include "mozilla/dom/StorageEvent.h"
     51 #include "mozilla/dom/TextEvent.h"
     52 #include "mozilla/dom/TimeEvent.h"
     53 #include "mozilla/dom/TouchEvent.h"
     54 #include "mozilla/dom/TransitionEvent.h"
     55 #include "mozilla/dom/WheelEvent.h"
     56 #include "mozilla/dom/WorkerPrivate.h"
     57 #include "mozilla/dom/XULCommandEvent.h"
     58 #include "mozilla/ipc/MessageChannel.h"
     59 #include "nsContentUtils.h"
     60 #include "nsDocShell.h"
     61 #include "nsError.h"
     62 #include "nsIContent.h"
     63 #include "nsIContentInlines.h"
     64 #include "nsINode.h"
     65 #include "nsIScriptObjectPrincipal.h"
     66 #include "nsPIDOMWindow.h"
     67 #include "nsPresContext.h"
     68 #include "nsRefreshDriver.h"
     69 
     70 namespace mozilla {
     71 
     72 using namespace dom;
     73 
     74 class ELMCreationDetector {
     75 public:
     76  ELMCreationDetector()
     77      // We can do this optimization only in the main thread.
     78      : mNonMainThread(!NS_IsMainThread()),
     79        mInitialCount(mNonMainThread
     80                          ? 0
     81                          : EventListenerManager::sMainThreadCreatedCount) {}
     82 
     83  bool MayHaveNewListenerManager() {
     84    return mNonMainThread ||
     85           mInitialCount != EventListenerManager::sMainThreadCreatedCount;
     86  }
     87 
     88  bool IsMainThread() { return !mNonMainThread; }
     89 
     90 private:
     91  bool mNonMainThread;
     92  uint32_t mInitialCount;
     93 };
     94 
     95 static bool IsEventTargetChrome(EventTarget* aEventTarget,
     96                                Document** aDocument = nullptr) {
     97  if (aDocument) {
     98    *aDocument = nullptr;
     99  }
    100 
    101  Document* doc = nullptr;
    102  if (nsINode* node = nsINode::FromEventTargetOrNull(aEventTarget)) {
    103    doc = node->OwnerDoc();
    104  } else if (nsPIDOMWindowInner* window =
    105                 nsPIDOMWindowInner::FromEventTargetOrNull(aEventTarget)) {
    106    doc = window->GetExtantDoc();
    107  }
    108 
    109  // nsContentUtils::IsChromeDoc is null-safe.
    110  bool isChrome = false;
    111  if (doc) {
    112    isChrome = nsContentUtils::IsChromeDoc(doc);
    113    if (aDocument) {
    114      nsCOMPtr<Document> retVal = doc;
    115      retVal.swap(*aDocument);
    116    }
    117  } else if (nsCOMPtr<nsIScriptObjectPrincipal> sop =
    118                 do_QueryInterface(aEventTarget->GetOwnerGlobal())) {
    119    isChrome = sop->GetPrincipal()->IsSystemPrincipal();
    120  }
    121  return isChrome;
    122 }
    123 
    124 // EventTargetChainItem represents a single item in the event target chain.
    125 class EventTargetChainItem {
    126 public:
    127  explicit EventTargetChainItem(EventTarget* aTarget)
    128      : mTarget(aTarget), mItemFlags(0) {
    129    MOZ_COUNT_CTOR(EventTargetChainItem);
    130  }
    131 
    132  MOZ_COUNTED_DTOR(EventTargetChainItem)
    133 
    134  static EventTargetChainItem* Create(nsTArray<EventTargetChainItem>& aChain,
    135                                      EventTarget* aTarget,
    136                                      EventTargetChainItem* aChild = nullptr) {
    137    // The last item which can handle the event must be aChild.
    138    MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
    139    MOZ_ASSERT(!aTarget || aTarget == aTarget->GetTargetForEventTargetChain());
    140    EventTargetChainItem* etci = aChain.AppendElement(aTarget);
    141    return etci;
    142  }
    143 
    144  static void DestroyLast(nsTArray<EventTargetChainItem>& aChain,
    145                          EventTargetChainItem* aItem) {
    146    MOZ_ASSERT(&aChain.LastElement() == aItem);
    147    aChain.RemoveLastElement();
    148  }
    149 
    150  static EventTargetChainItem* GetFirstCanHandleEventTarget(
    151      nsTArray<EventTargetChainItem>& aChain) {
    152    return &aChain[GetFirstCanHandleEventTargetIdx(aChain)];
    153  }
    154 
    155  static uint32_t GetFirstCanHandleEventTargetIdx(
    156      nsTArray<EventTargetChainItem>& aChain) {
    157    // aChain[i].PreHandleEventOnly() = true only when the target element wants
    158    // PreHandleEvent and set mCanHandle=false. So we find the first element
    159    // which can handle the event.
    160    for (uint32_t i = 0; i < aChain.Length(); ++i) {
    161      if (!aChain[i].PreHandleEventOnly()) {
    162        return i;
    163      }
    164    }
    165    MOZ_ASSERT(false);
    166    return 0;
    167  }
    168 
    169  static EventTargetChainItem* GetLastCanHandleEventTarget(
    170      nsTArray<EventTargetChainItem>& aChain) {
    171    // Fine the last item which can handle the event.
    172    for (int32_t i = aChain.Length() - 1; i >= 0; --i) {
    173      if (!aChain[i].PreHandleEventOnly()) {
    174        return &aChain[i];
    175      }
    176    }
    177    return nullptr;
    178  }
    179 
    180  bool IsValid() const {
    181    NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
    182    return !!(mTarget);
    183  }
    184 
    185  EventTarget* GetNewTarget() const { return mNewTarget; }
    186 
    187  void SetNewTarget(EventTarget* aNewTarget) { mNewTarget = aNewTarget; }
    188 
    189  EventTarget* GetRetargetedRelatedTarget() { return mRetargetedRelatedTarget; }
    190 
    191  void SetRetargetedRelatedTarget(EventTarget* aTarget) {
    192    mRetargetedRelatedTarget = aTarget;
    193  }
    194 
    195  void SetRetargetedTouchTarget(
    196      Maybe<nsTArray<RefPtr<EventTarget>>>&& aTargets) {
    197    mRetargetedTouchTargets = std::move(aTargets);
    198  }
    199 
    200  bool HasRetargetTouchTargets() const {
    201    return mRetargetedTouchTargets.isSome() || mInitialTargetTouches.isSome();
    202  }
    203 
    204  void RetargetTouchTargets(WidgetTouchEvent* aTouchEvent, Event* aDOMEvent) {
    205    MOZ_ASSERT(HasRetargetTouchTargets());
    206    MOZ_ASSERT(aTouchEvent,
    207               "mRetargetedTouchTargets should be empty when dispatching "
    208               "non-touch events.");
    209 
    210    if (mRetargetedTouchTargets.isSome()) {
    211      WidgetTouchEvent::TouchArray& touches = aTouchEvent->mTouches;
    212      MOZ_ASSERT(!touches.Length() ||
    213                 touches.Length() == mRetargetedTouchTargets->Length());
    214      for (uint32_t i = 0; i < touches.Length(); ++i) {
    215        touches[i]->mTarget = mRetargetedTouchTargets->ElementAt(i);
    216      }
    217    }
    218 
    219    if (aDOMEvent) {
    220      // The number of touch objects in targetTouches list may change depending
    221      // on the retargeting.
    222      TouchEvent* touchDOMEvent = static_cast<TouchEvent*>(aDOMEvent);
    223      TouchList* targetTouches = touchDOMEvent->GetExistingTargetTouches();
    224      if (targetTouches) {
    225        targetTouches->Clear();
    226        if (mInitialTargetTouches.isSome()) {
    227          for (uint32_t i = 0; i < mInitialTargetTouches->Length(); ++i) {
    228            Touch* touch = mInitialTargetTouches->ElementAt(i);
    229            if (touch) {
    230              touch->mTarget = touch->mOriginalTarget;
    231            }
    232            targetTouches->Append(touch);
    233          }
    234        }
    235      }
    236    }
    237  }
    238 
    239  void SetInitialTargetTouches(
    240      Maybe<nsTArray<RefPtr<dom::Touch>>>&& aInitialTargetTouches) {
    241    mInitialTargetTouches = std::move(aInitialTargetTouches);
    242  }
    243 
    244  void SetForceContentDispatch(bool aForce) {
    245    mFlags.mForceContentDispatch = aForce;
    246  }
    247 
    248  bool ForceContentDispatch() const { return mFlags.mForceContentDispatch; }
    249 
    250  void SetWantsWillHandleEvent(bool aWants) {
    251    mFlags.mWantsWillHandleEvent = aWants;
    252  }
    253 
    254  bool WantsWillHandleEvent() const { return mFlags.mWantsWillHandleEvent; }
    255 
    256  void SetWantsPreHandleEvent(bool aWants) {
    257    mFlags.mWantsPreHandleEvent = aWants;
    258  }
    259 
    260  bool WantsPreHandleEvent() const { return mFlags.mWantsPreHandleEvent; }
    261 
    262  void SetPreHandleEventOnly(bool aWants) {
    263    mFlags.mPreHandleEventOnly = aWants;
    264  }
    265 
    266  bool PreHandleEventOnly() const { return mFlags.mPreHandleEventOnly; }
    267 
    268  void SetRootOfClosedTree(bool aSet) { mFlags.mRootOfClosedTree = aSet; }
    269 
    270  bool IsRootOfClosedTree() const { return mFlags.mRootOfClosedTree; }
    271 
    272  void SetItemInShadowTree(bool aSet) { mFlags.mItemInShadowTree = aSet; }
    273 
    274  bool IsItemInShadowTree() const { return mFlags.mItemInShadowTree; }
    275 
    276  void SetIsSlotInClosedTree(bool aSet) { mFlags.mIsSlotInClosedTree = aSet; }
    277 
    278  bool IsSlotInClosedTree() const { return mFlags.mIsSlotInClosedTree; }
    279 
    280  void SetIsChromeHandler(bool aSet) { mFlags.mIsChromeHandler = aSet; }
    281 
    282  bool IsChromeHandler() const { return mFlags.mIsChromeHandler; }
    283 
    284  void SetMayHaveListenerManager(bool aMayHave) {
    285    mFlags.mMayHaveManager = aMayHave;
    286  }
    287 
    288  bool MayHaveListenerManager() { return mFlags.mMayHaveManager; }
    289 
    290  EventTarget* CurrentTarget() const { return mTarget; }
    291 
    292  /**
    293   * Dispatches event through the event target chain.
    294   * Handles capture, target and bubble phases both in default
    295   * and system event group and calls also PostHandleEvent for each
    296   * item in the chain.
    297   */
    298  MOZ_CAN_RUN_SCRIPT
    299  static void HandleEventTargetChain(nsTArray<EventTargetChainItem>& aChain,
    300                                     EventChainPostVisitor& aVisitor,
    301                                     EventDispatchingCallback* aCallback,
    302                                     ELMCreationDetector& aCd);
    303 
    304  /**
    305   * Resets aVisitor object and calls GetEventTargetParent.
    306   * Copies mItemFlags and mItemData to the current EventTargetChainItem.
    307   */
    308  void GetEventTargetParent(EventChainPreVisitor& aVisitor);
    309 
    310  /**
    311   * Copies mItemFlags, mItemData to aVisitor,
    312   * calls LegacyPreActivationBehavior and copies both members back
    313   * to this EventTargetChainitem.
    314   */
    315  void LegacyPreActivationBehavior(EventChainVisitor& aVisitor);
    316 
    317  /**
    318   * Copies mItemFlags and mItemData to aVisitor and calls ActivationBehavior.
    319   */
    320  MOZ_CAN_RUN_SCRIPT
    321  void ActivationBehavior(EventChainPostVisitor& aVisitor);
    322 
    323  /**
    324   * Copies mItemFlags and mItemData to aVisitor and
    325   * calls LegacyCanceledActivationBehavior.
    326   */
    327  void LegacyCanceledActivationBehavior(EventChainPostVisitor& aVisitor);
    328 
    329  /**
    330   * Copies mItemFlags and mItemData to aVisitor.
    331   * Calls PreHandleEvent for those items which called SetWantsPreHandleEvent.
    332   */
    333  void PreHandleEvent(EventChainVisitor& aVisitor);
    334 
    335  /**
    336   * If the current item in the event target chain has an event listener
    337   * manager, this method calls EventListenerManager::HandleEvent().
    338   */
    339  void HandleEvent(EventChainPostVisitor& aVisitor, ELMCreationDetector& aCd) {
    340    if (WantsWillHandleEvent()) {
    341      mTarget->WillHandleEvent(aVisitor);
    342    }
    343    if (aVisitor.mEvent->PropagationStopped()) {
    344      return;
    345    }
    346    if (aVisitor.mEvent->mFlags.mOnlySystemGroupDispatch &&
    347        !aVisitor.mEvent->mFlags.mInSystemGroup) {
    348      return;
    349    }
    350    if (aVisitor.mEvent->mFlags.mOnlySystemGroupDispatchInContent &&
    351        !aVisitor.mEvent->mFlags.mInSystemGroup && !IsCurrentTargetChrome()) {
    352      return;
    353    }
    354    if (!mManager) {
    355      if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
    356        return;
    357      }
    358      mManager = mTarget->GetExistingListenerManager();
    359    }
    360    if (mManager) {
    361      NS_ASSERTION(aVisitor.mEvent->mCurrentTarget == nullptr,
    362                   "CurrentTarget should be null!");
    363 
    364      mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
    365                            &aVisitor.mDOMEvent, CurrentTarget(),
    366                            &aVisitor.mEventStatus, IsItemInShadowTree());
    367      NS_ASSERTION(aVisitor.mEvent->mCurrentTarget == nullptr,
    368                   "CurrentTarget should be null!");
    369    }
    370  }
    371 
    372  /**
    373   * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
    374   */
    375  MOZ_CAN_RUN_SCRIPT void PostHandleEvent(EventChainPostVisitor& aVisitor);
    376 
    377 private:
    378  const nsCOMPtr<EventTarget> mTarget;
    379  nsCOMPtr<EventTarget> mRetargetedRelatedTarget;
    380  Maybe<nsTArray<RefPtr<EventTarget>>> mRetargetedTouchTargets;
    381  Maybe<nsTArray<RefPtr<dom::Touch>>> mInitialTargetTouches;
    382 
    383  class EventTargetChainFlags {
    384   public:
    385    explicit EventTargetChainFlags() { SetRawFlags(0); }
    386    // Cached flags for each EventTargetChainItem which are set when calling
    387    // GetEventTargetParent to create event target chain. They are used to
    388    // manage or speedup event dispatching.
    389    bool mForceContentDispatch : 1;
    390    bool mWantsWillHandleEvent : 1;
    391    bool mMayHaveManager : 1;
    392    bool mChechedIfChrome : 1;
    393    bool mIsChromeContent : 1;
    394    bool mWantsPreHandleEvent : 1;
    395    bool mPreHandleEventOnly : 1;
    396    bool mRootOfClosedTree : 1;
    397    bool mItemInShadowTree : 1;
    398    bool mIsSlotInClosedTree : 1;
    399    bool mIsChromeHandler : 1;
    400 
    401   private:
    402    using RawFlags = uint32_t;
    403    void SetRawFlags(RawFlags aRawFlags) {
    404      static_assert(
    405          sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
    406          "EventTargetChainFlags must not be bigger than the RawFlags");
    407      memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
    408    }
    409  } mFlags;
    410 
    411  uint16_t mItemFlags;
    412  nsCOMPtr<nsISupports> mItemData;
    413  // Event retargeting must happen whenever mNewTarget is non-null.
    414  nsCOMPtr<EventTarget> mNewTarget;
    415  // Cache mTarget's event listener manager.
    416  RefPtr<EventListenerManager> mManager;
    417 
    418  bool IsCurrentTargetChrome() {
    419    if (!mFlags.mChechedIfChrome) {
    420      mFlags.mChechedIfChrome = true;
    421      if (IsEventTargetChrome(mTarget)) {
    422        mFlags.mIsChromeContent = true;
    423      }
    424    }
    425    return mFlags.mIsChromeContent;
    426  }
    427 };
    428 
    429 void EventTargetChainItem::GetEventTargetParent(
    430    EventChainPreVisitor& aVisitor) {
    431  aVisitor.Reset();
    432  mTarget->GetEventTargetParent(aVisitor);
    433  SetForceContentDispatch(aVisitor.mForceContentDispatch);
    434  SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
    435  SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
    436  SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
    437  SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
    438  SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
    439  SetItemInShadowTree(aVisitor.mItemInShadowTree);
    440  SetRetargetedRelatedTarget(aVisitor.mRetargetedRelatedTarget);
    441  SetRetargetedTouchTarget(std::move(aVisitor.mRetargetedTouchTargets));
    442  mItemFlags = aVisitor.mItemFlags;
    443  mItemData = aVisitor.mItemData;
    444 }
    445 
    446 void EventTargetChainItem::LegacyPreActivationBehavior(
    447    EventChainVisitor& aVisitor) {
    448  aVisitor.mItemFlags = mItemFlags;
    449  aVisitor.mItemData = mItemData;
    450  mTarget->LegacyPreActivationBehavior(aVisitor);
    451  mItemFlags = aVisitor.mItemFlags;
    452  mItemData = aVisitor.mItemData;
    453 }
    454 
    455 void EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor) {
    456  if (!WantsPreHandleEvent()) {
    457    return;
    458  }
    459  aVisitor.mItemFlags = mItemFlags;
    460  aVisitor.mItemData = mItemData;
    461  (void)mTarget->PreHandleEvent(aVisitor);
    462  MOZ_ASSERT(mItemFlags == aVisitor.mItemFlags);
    463  MOZ_ASSERT(mItemData == aVisitor.mItemData);
    464 }
    465 
    466 void EventTargetChainItem::ActivationBehavior(EventChainPostVisitor& aVisitor) {
    467  aVisitor.mItemFlags = mItemFlags;
    468  aVisitor.mItemData = mItemData;
    469  mTarget->ActivationBehavior(aVisitor);
    470  MOZ_ASSERT(mItemFlags == aVisitor.mItemFlags);
    471  MOZ_ASSERT(mItemData == aVisitor.mItemData);
    472 }
    473 
    474 void EventTargetChainItem::LegacyCanceledActivationBehavior(
    475    EventChainPostVisitor& aVisitor) {
    476  aVisitor.mItemFlags = mItemFlags;
    477  aVisitor.mItemData = mItemData;
    478  mTarget->LegacyCanceledActivationBehavior(aVisitor);
    479  MOZ_ASSERT(mItemFlags == aVisitor.mItemFlags);
    480  MOZ_ASSERT(mItemData == aVisitor.mItemData);
    481 }
    482 
    483 void EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor) {
    484  aVisitor.mItemFlags = mItemFlags;
    485  aVisitor.mItemData = mItemData;
    486  mTarget->PostHandleEvent(aVisitor);
    487  MOZ_ASSERT(mItemFlags == aVisitor.mItemFlags);
    488  MOZ_ASSERT(mItemData == aVisitor.mItemData);
    489 }
    490 
    491 void EventTargetChainItem::HandleEventTargetChain(
    492    nsTArray<EventTargetChainItem>& aChain, EventChainPostVisitor& aVisitor,
    493    EventDispatchingCallback* aCallback, ELMCreationDetector& aCd) {
    494  // Save the target so that it can be restored later.
    495  nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
    496  nsCOMPtr<EventTarget> firstRelatedTarget = aVisitor.mEvent->mRelatedTarget;
    497  Maybe<AutoTArray<nsCOMPtr<EventTarget>, 10>> firstTouchTargets;
    498  WidgetTouchEvent* touchEvent = nullptr;
    499  if (aVisitor.mEvent->mClass == eTouchEventClass) {
    500    touchEvent = aVisitor.mEvent->AsTouchEvent();
    501    if (!aVisitor.mEvent->mFlags.mInSystemGroup) {
    502      firstTouchTargets.emplace();
    503      WidgetTouchEvent* touchEvent = aVisitor.mEvent->AsTouchEvent();
    504      WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
    505      for (uint32_t i = 0; i < touches.Length(); ++i) {
    506        firstTouchTargets->AppendElement(touches[i]->mTarget);
    507      }
    508    }
    509  }
    510 
    511  uint32_t chainLength = aChain.Length();
    512  EventTargetChainItem* chain = aChain.Elements();
    513  uint32_t firstCanHandleEventTargetIdx =
    514      EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
    515 
    516  // Capture
    517  aVisitor.mEvent->mFlags.mInCapturePhase = true;
    518  aVisitor.mEvent->mFlags.mInBubblingPhase = false;
    519  aVisitor.mEvent->mFlags.mInTargetPhase = false;
    520  for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
    521    EventTargetChainItem& item = chain[i];
    522    if (item.PreHandleEventOnly()) {
    523      continue;
    524    }
    525    if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
    526         item.ForceContentDispatch()) &&
    527        !aVisitor.mEvent->PropagationStopped()) {
    528      item.HandleEvent(aVisitor, aCd);
    529    }
    530 
    531    if (item.GetNewTarget()) {
    532      // item is at anonymous boundary. Need to retarget for the child items.
    533      for (uint32_t j = i; j > 0; --j) {
    534        uint32_t childIndex = j - 1;
    535        EventTarget* newTarget = chain[childIndex].GetNewTarget();
    536        if (newTarget) {
    537          aVisitor.mEvent->mTarget = newTarget;
    538          break;
    539        }
    540      }
    541    }
    542 
    543    // https://dom.spec.whatwg.org/#dispatching-events
    544    // Step 14.2
    545    // "Set event's relatedTarget to tuple's relatedTarget."
    546    // Note, the initial retargeting was done already when creating
    547    // event target chain, so we need to do this only after calling
    548    // HandleEvent, not before, like in the specification.
    549    if (item.GetRetargetedRelatedTarget()) {
    550      bool found = false;
    551      for (uint32_t j = i; j > 0; --j) {
    552        uint32_t childIndex = j - 1;
    553        EventTarget* relatedTarget =
    554            chain[childIndex].GetRetargetedRelatedTarget();
    555        if (relatedTarget) {
    556          found = true;
    557          aVisitor.mEvent->mRelatedTarget = relatedTarget;
    558          break;
    559        }
    560      }
    561      if (!found) {
    562        aVisitor.mEvent->mRelatedTarget =
    563            aVisitor.mEvent->mOriginalRelatedTarget;
    564      }
    565    }
    566 
    567    if (item.HasRetargetTouchTargets()) {
    568      bool found = false;
    569      for (uint32_t j = i; j > 0; --j) {
    570        uint32_t childIndex = j - 1;
    571        if (chain[childIndex].HasRetargetTouchTargets()) {
    572          found = true;
    573          chain[childIndex].RetargetTouchTargets(touchEvent,
    574                                                 aVisitor.mDOMEvent);
    575          break;
    576        }
    577      }
    578      if (!found) {
    579        WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
    580        for (uint32_t i = 0; i < touches.Length(); ++i) {
    581          touches[i]->mTarget = touches[i]->mOriginalTarget;
    582        }
    583      }
    584    }
    585  }
    586 
    587  // Target
    588  aVisitor.mEvent->mFlags.mInTargetPhase = true;
    589  EventTargetChainItem& targetItem = chain[firstCanHandleEventTargetIdx];
    590  // Need to explicitly retarget touch targets so that initial targets get set
    591  // properly in case nothing else retargeted touches.
    592  if (targetItem.HasRetargetTouchTargets()) {
    593    targetItem.RetargetTouchTargets(touchEvent, aVisitor.mDOMEvent);
    594  }
    595  if (!aVisitor.mEvent->PropagationStopped() &&
    596      (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
    597       targetItem.ForceContentDispatch())) {
    598    targetItem.HandleEvent(aVisitor, aCd);
    599  }
    600  aVisitor.mEvent->mFlags.mInCapturePhase = false;
    601  aVisitor.mEvent->mFlags.mInBubblingPhase = true;
    602  if (!aVisitor.mEvent->PropagationStopped() &&
    603      (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
    604       targetItem.ForceContentDispatch())) {
    605    targetItem.HandleEvent(aVisitor, aCd);
    606  }
    607 
    608  if (aVisitor.mEvent->mFlags.mInSystemGroup) {
    609    targetItem.PostHandleEvent(aVisitor);
    610  }
    611  aVisitor.mEvent->mFlags.mInTargetPhase = false;
    612 
    613  // Bubble
    614  for (uint32_t i = firstCanHandleEventTargetIdx + 1; i < chainLength; ++i) {
    615    EventTargetChainItem& item = chain[i];
    616    if (item.PreHandleEventOnly()) {
    617      continue;
    618    }
    619    EventTarget* newTarget = item.GetNewTarget();
    620    if (newTarget) {
    621      // Item is at anonymous boundary. Need to retarget for the current item
    622      // and for parent items.
    623      aVisitor.mEvent->mTarget = newTarget;
    624    }
    625 
    626    // https://dom.spec.whatwg.org/#dispatching-events
    627    // Step 15.2
    628    // "Set event's relatedTarget to tuple's relatedTarget."
    629    EventTarget* relatedTarget = item.GetRetargetedRelatedTarget();
    630    if (relatedTarget) {
    631      aVisitor.mEvent->mRelatedTarget = relatedTarget;
    632    }
    633 
    634    if (item.HasRetargetTouchTargets()) {
    635      item.RetargetTouchTargets(touchEvent, aVisitor.mDOMEvent);
    636    }
    637 
    638    if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
    639      if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
    640           item.ForceContentDispatch()) &&
    641          !aVisitor.mEvent->PropagationStopped()) {
    642        item.HandleEvent(aVisitor, aCd);
    643      }
    644      if (aVisitor.mEvent->mFlags.mInSystemGroup) {
    645        item.PostHandleEvent(aVisitor);
    646      }
    647    }
    648  }
    649  aVisitor.mEvent->mFlags.mInBubblingPhase = false;
    650 
    651  if (!aVisitor.mEvent->mFlags.mInSystemGroup &&
    652      aVisitor.mEvent->IsAllowedToDispatchInSystemGroup()) {
    653    // Dispatch to the system event group.  Make sure to clear the
    654    // STOP_DISPATCH flag since this resets for each event group.
    655    aVisitor.mEvent->mFlags.mPropagationStopped = false;
    656    aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
    657 
    658    // Setting back the original target of the event.
    659    aVisitor.mEvent->mTarget = aVisitor.mEvent->mOriginalTarget;
    660    aVisitor.mEvent->mRelatedTarget = aVisitor.mEvent->mOriginalRelatedTarget;
    661    if (firstTouchTargets) {
    662      WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
    663      for (uint32_t i = 0; i < touches.Length(); ++i) {
    664        touches[i]->mTarget = touches[i]->mOriginalTarget;
    665      }
    666    }
    667 
    668    // Special handling if PresShell (or some other caller)
    669    // used a callback object.
    670    if (aCallback) {
    671      aCallback->HandleEvent(aVisitor);
    672    }
    673 
    674    // Retarget for system event group (which does the default handling too).
    675    // Setting back the target which was used also for default event group.
    676    aVisitor.mEvent->mTarget = firstTarget;
    677    aVisitor.mEvent->mRelatedTarget = firstRelatedTarget;
    678    if (firstTouchTargets) {
    679      WidgetTouchEvent::TouchArray& touches = touchEvent->mTouches;
    680      for (uint32_t i = 0; i < firstTouchTargets->Length(); ++i) {
    681        touches[i]->mTarget = firstTouchTargets->ElementAt(i);
    682      }
    683    }
    684 
    685    aVisitor.mEvent->mFlags.mInSystemGroup = true;
    686    HandleEventTargetChain(aChain, aVisitor, aCallback, aCd);
    687    aVisitor.mEvent->mFlags.mInSystemGroup = false;
    688 
    689    // After dispatch, clear all the propagation flags so that
    690    // system group listeners don't affect to the event.
    691    aVisitor.mEvent->mFlags.mPropagationStopped = false;
    692    aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
    693  }
    694 }
    695 
    696 // There are often 2 nested event dispatches ongoing at the same time, so
    697 // have 2 separate caches.
    698 static const uint32_t kCachedMainThreadChainSize = 128;
    699 struct CachedChains {
    700  nsTArray<EventTargetChainItem> mChain1;
    701  nsTArray<EventTargetChainItem> mChain2;
    702 };
    703 static CachedChains* sCachedMainThreadChains = nullptr;
    704 
    705 /* static */
    706 void EventDispatcher::Shutdown() {
    707  delete sCachedMainThreadChains;
    708  sCachedMainThreadChains = nullptr;
    709 }
    710 
    711 EventTargetChainItem* EventTargetChainItemForChromeTarget(
    712    nsTArray<EventTargetChainItem>& aChain, nsINode* aNode,
    713    EventTargetChainItem* aChild = nullptr) {
    714  if (!aNode->IsInComposedDoc()) {
    715    return nullptr;
    716  }
    717  nsPIDOMWindowInner* win = aNode->OwnerDoc()->GetInnerWindow();
    718  EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
    719  NS_ENSURE_TRUE(piTarget, nullptr);
    720 
    721  EventTargetChainItem* etci = EventTargetChainItem::Create(
    722      aChain, piTarget->GetTargetForEventTargetChain(), aChild);
    723  if (!etci->IsValid()) {
    724    EventTargetChainItem::DestroyLast(aChain, etci);
    725    return nullptr;
    726  }
    727  return etci;
    728 }
    729 
    730 /* static */ EventTargetChainItem* MayRetargetToChromeIfCanNotHandleEvent(
    731    nsTArray<EventTargetChainItem>& aChain, EventChainPreVisitor& aPreVisitor,
    732    EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
    733    nsINode* aContent) {
    734  if (!aPreVisitor.mWantsPreHandleEvent) {
    735    // Keep EventTargetChainItem if we need to call PreHandleEvent on it.
    736    EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
    737  }
    738  if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
    739    aPreVisitor.mRelatedTargetRetargetedInCurrentScope = false;
    740    // Event target couldn't handle the event. Try to propagate to chrome.
    741    EventTargetChainItem* chromeTargetEtci =
    742        EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
    743    if (chromeTargetEtci) {
    744      // If we propagate to chrome, need to ensure we mark
    745      // EventTargetChainItem to be chrome handler so that event.composedPath()
    746      // can return the right value.
    747      chromeTargetEtci->SetIsChromeHandler(true);
    748      chromeTargetEtci->GetEventTargetParent(aPreVisitor);
    749      return chromeTargetEtci;
    750    }
    751  }
    752  return nullptr;
    753 }
    754 
    755 static bool ShouldClearTargets(WidgetEvent* aEvent) {
    756  if (auto* finalTarget = nsIContent::FromEventTargetOrNull(aEvent->mTarget)) {
    757    if (finalTarget->IsInShadowTree()) {
    758      return true;
    759    }
    760  }
    761 
    762  if (auto* finalRelatedTarget =
    763          nsIContent::FromEventTargetOrNull(aEvent->mRelatedTarget)) {
    764    if (finalRelatedTarget->IsInShadowTree()) {
    765      return true;
    766    }
    767  }
    768  // XXXsmaug Check also all the touch objects.
    769 
    770  return false;
    771 }
    772 
    773 static void DescribeEventTargetForProfilerMarker(const EventTarget* aTarget,
    774                                                 nsACString& aDescription) {
    775  auto* node = aTarget->GetAsNode();
    776  if (node) {
    777    if (node->IsElement()) {
    778      nsAutoString nodeDescription;
    779      node->AsElement()->Describe(nodeDescription, true);
    780      aDescription = NS_ConvertUTF16toUTF8(nodeDescription);
    781    } else if (node->IsDocument()) {
    782      aDescription.AssignLiteral("document");
    783    } else if (node->IsText()) {
    784      aDescription.AssignLiteral("text");
    785    } else if (node->IsDocumentFragment()) {
    786      aDescription.AssignLiteral("document fragment");
    787    }
    788  } else if (aTarget->IsInnerWindow() || aTarget->IsOuterWindow()) {
    789    aDescription.AssignLiteral("window");
    790  } else if (aTarget->IsRootWindow()) {
    791    aDescription.AssignLiteral("root window");
    792  } else {
    793    // Probably something that inherits from DOMEventTargetHelper.
    794  }
    795 }
    796 
    797 /**
    798 * https://w3c.github.io/touch-events/#cancelability
    799 * https://w3c.github.io/uievents/#cancelability-of-wheel-events
    800 */
    801 static bool IsUncancelableIfOnlyPassiveListeners(const WidgetEvent* aEvent) {
    802  if (!aEvent->IsTrusted() || !aEvent->mFlags.mCancelable) {
    803    return false;
    804  }
    805 
    806  switch (aEvent->mMessage) {
    807    case eTouchStart:
    808    case eTouchEnd:
    809    case eTouchMove:
    810    case eWheel:
    811    case eLegacyMouseLineOrPageScroll:
    812    case eLegacyMousePixelScroll:
    813      break;
    814    default:
    815      return false;
    816  }
    817 
    818  // There might be non-passive listeners in the remote document
    819  // So return false if we are in the parent process with remote target
    820  nsCOMPtr<nsIContent> target =
    821      nsIContent::FromEventTargetOrNull(aEvent->mOriginalTarget);
    822  return !(XRE_IsParentProcess() && BrowserParent::GetFrom(target));
    823 }
    824 
    825 struct DOMEventMarker : public BaseMarkerType<DOMEventMarker> {
    826  static constexpr const char* Name = "DOMEvent";
    827 
    828  using MS = MarkerSchema;
    829  static constexpr MS::PayloadField PayloadFields[] = {
    830      {"target", MS::InputType::CString, "Event Target", MS::Format::String,
    831       MS::PayloadFlags::Searchable},
    832      {"latency", MS::InputType::TimeDuration, "Latency", MS::Format::Duration,
    833       MS::PayloadFlags::None},
    834      {"eventType", MS::InputType::String, "Event Type", MS::Format::String,
    835       MS::PayloadFlags::Searchable}};
    836 
    837  static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
    838                                               MS::Location::MarkerTable,
    839                                               MS::Location::TimelineOverview};
    840  static constexpr const char* TableLabel =
    841      "{marker.data.eventType} - {marker.data.target}";
    842  static constexpr const char* TooltipLabel =
    843      "{marker.data.eventType} - DOMEvent";
    844  static constexpr const char* ChartLabel = "{marker.data.eventType}";
    845 
    846  static constexpr bool IsStackBased = true;
    847 
    848  static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
    849                                   const nsCString& aTarget,
    850                                   const TimeDuration& aLatency,
    851                                   const ProfilerString16View& aEventType) {
    852    aWriter.StringProperty("eventType", NS_ConvertUTF16toUTF8(aEventType));
    853    if (!aTarget.IsEmpty()) {
    854      aWriter.StringProperty("target", aTarget);
    855    }
    856    aWriter.DoubleProperty("latency", aLatency.ToMilliseconds());
    857  }
    858 };
    859 
    860 /* static */
    861 nsresult EventDispatcher::Dispatch(EventTarget* aTarget,
    862                                   nsPresContext* aPresContext,
    863                                   WidgetEvent* aEvent, Event* aDOMEvent,
    864                                   nsEventStatus* aEventStatus,
    865                                   EventDispatchingCallback* aCallback,
    866                                   nsTArray<EventTarget*>* aTargets) {
    867  AUTO_PROFILER_LABEL_HOT("EventDispatcher::Dispatch", OTHER);
    868 
    869  NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!");
    870  NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched,
    871                 NS_ERROR_DOM_INVALID_STATE_ERR);
    872  NS_ASSERTION(!aTargets || !aEvent->mMessage, "Wrong parameters!");
    873 
    874  // If we're dispatching an already created DOMEvent object, make
    875  // sure it is initialized!
    876  // If aTargets is non-null, the event isn't going to be dispatched.
    877  NS_ENSURE_TRUE(aEvent->mMessage || !aDOMEvent || aTargets,
    878                 NS_ERROR_DOM_INVALID_STATE_ERR);
    879 
    880  // Events shall not be fired while we are in stable state to prevent anything
    881  // visible from the scripts.
    882  MOZ_ASSERT(!nsContentUtils::IsInStableOrMetaStableState());
    883  NS_ENSURE_TRUE(!nsContentUtils::IsInStableOrMetaStableState(),
    884                 NS_ERROR_DOM_INVALID_STATE_ERR);
    885 
    886  nsCOMPtr<EventTarget> target(aTarget);
    887 
    888  RefPtr<PerformanceEventTiming> eventTimingEntry;
    889  // Similar to PerformancePaintTiming, we don't need to
    890  // expose them for printing documents
    891  if (aPresContext && !aPresContext->IsPrintingOrPrintPreview()) {
    892    eventTimingEntry =
    893        PerformanceEventTiming::TryGenerateEventTiming(target, aEvent);
    894 
    895    if (aEvent->IsTrusted() && aEvent->mMessage == eScroll) {
    896      if (auto* perf = aPresContext->GetPerformanceMainThread()) {
    897        if (!perf->HasDispatchedScrollEvent()) {
    898          perf->SetHasDispatchedScrollEvent();
    899        }
    900      }
    901    }
    902  }
    903 
    904  bool retargeted = false;
    905 
    906  if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
    907    nsIContent* content = nsIContent::FromEventTargetOrNull(target);
    908    if (content && content->IsInNativeAnonymousSubtree()) {
    909      nsCOMPtr<EventTarget> newTarget =
    910          content->FindFirstNonChromeOnlyAccessContent();
    911      NS_ENSURE_STATE(newTarget);
    912 
    913      aEvent->mOriginalTarget = target;
    914      target = newTarget;
    915      retargeted = true;
    916    }
    917  }
    918 
    919  if (aEvent->mFlags.mOnlyChromeDispatch) {
    920    nsCOMPtr<Document> doc;
    921    if (!IsEventTargetChrome(target, getter_AddRefs(doc)) && doc) {
    922      nsPIDOMWindowInner* win = doc->GetInnerWindow();
    923      // If we can't dispatch the event to chrome, do nothing.
    924      EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
    925      if (!piTarget) {
    926        return NS_OK;
    927      }
    928 
    929      // Set the target to be the original dispatch target,
    930      aEvent->mTarget = target;
    931      // but use chrome event handler or BrowserChildMessageManager for event
    932      // target chain.
    933      target = piTarget;
    934    } else if (NS_WARN_IF(!doc)) {
    935      return NS_ERROR_UNEXPECTED;
    936    }
    937  }
    938 
    939 #ifdef DEBUG
    940  if (NS_IsMainThread() && aEvent->mMessage != eVoidEvent &&
    941      !nsContentUtils::IsSafeToRunScript()) {
    942    static const auto warn = [](bool aIsSystem) {
    943      if (aIsSystem) {
    944        NS_WARNING("Fix the caller!");
    945      } else {
    946        MOZ_CRASH("This is unsafe! Fix the caller!");
    947      }
    948    };
    949    if (nsINode* node = nsINode::FromEventTargetOrNull(target)) {
    950      // If this is a node, it's possible that this is some sort of DOM tree
    951      // that is never accessed by script (for example an SVG image or XBL
    952      // binding document or whatnot).  We really only want to warn/assert here
    953      // if there might be actual scripted listeners for this event, so restrict
    954      // the warnings/asserts to the case when script can or once could touch
    955      // this node's document.
    956      Document* doc = node->OwnerDoc();
    957      bool hasHadScriptHandlingObject;
    958      nsIGlobalObject* global =
    959          doc->GetScriptHandlingObject(hasHadScriptHandlingObject);
    960      if (global || hasHadScriptHandlingObject) {
    961        warn(nsContentUtils::IsChromeDoc(doc));
    962      }
    963    } else if (nsCOMPtr<nsIGlobalObject> global = target->GetOwnerGlobal()) {
    964      warn(global->PrincipalOrNull()->IsSystemPrincipal());
    965    }
    966  }
    967 
    968  if (aDOMEvent) {
    969    WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr();
    970    NS_ASSERTION(innerEvent == aEvent,
    971                 "The inner event of aDOMEvent is not the same as aEvent!");
    972  }
    973 #endif
    974 
    975  nsresult rv = NS_OK;
    976  bool externalDOMEvent = !!(aDOMEvent);
    977 
    978  // If we have a PresContext, make sure it doesn't die before
    979  // event dispatching is finished.
    980  RefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
    981 
    982  ELMCreationDetector cd;
    983  nsTArray<EventTargetChainItem> chain;
    984  if (cd.IsMainThread()) {
    985    if (!sCachedMainThreadChains) {
    986      sCachedMainThreadChains = new CachedChains();
    987    }
    988 
    989    if (sCachedMainThreadChains->mChain1.Capacity() ==
    990        kCachedMainThreadChainSize) {
    991      chain = std::move(sCachedMainThreadChains->mChain1);
    992    } else if (sCachedMainThreadChains->mChain2.Capacity() ==
    993               kCachedMainThreadChainSize) {
    994      chain = std::move(sCachedMainThreadChains->mChain2);
    995    } else {
    996      chain.SetCapacity(kCachedMainThreadChainSize);
    997    }
    998  }
    999 
   1000  // Create the event target chain item for the event target.
   1001  EventTargetChainItem* targetEtci = EventTargetChainItem::Create(
   1002      chain, target->GetTargetForEventTargetChain());
   1003  MOZ_ASSERT(&chain[0] == targetEtci);
   1004  if (!targetEtci->IsValid()) {
   1005    EventTargetChainItem::DestroyLast(chain, targetEtci);
   1006    return NS_ERROR_FAILURE;
   1007  }
   1008 
   1009  // Make sure that Event::target and Event::originalTarget
   1010  // point to the last item in the chain.
   1011  if (!aEvent->mTarget) {
   1012    // Note, CurrentTarget() points always to the object returned by
   1013    // GetTargetForEventTargetChain().
   1014    aEvent->mTarget = targetEtci->CurrentTarget();
   1015  } else {
   1016    // XXX But if the target is already set, use that. This is a hack
   1017    //     for the 'load', 'beforeunload' and 'unload' events,
   1018    //     which are dispatched to |window| but have document as their target.
   1019    //
   1020    // Make sure that the event target points to the right object.
   1021    aEvent->mTarget = aEvent->mTarget->GetTargetForEventTargetChain();
   1022    NS_ENSURE_STATE(aEvent->mTarget);
   1023  }
   1024 
   1025  if (retargeted) {
   1026    aEvent->mOriginalTarget =
   1027        aEvent->mOriginalTarget->GetTargetForEventTargetChain();
   1028    NS_ENSURE_STATE(aEvent->mOriginalTarget);
   1029  } else {
   1030    aEvent->mOriginalTarget = aEvent->mTarget;
   1031  }
   1032 
   1033  aEvent->mOriginalRelatedTarget = aEvent->mRelatedTarget;
   1034 
   1035  bool clearTargets = false;
   1036 
   1037  nsCOMPtr<nsIContent> content =
   1038      nsIContent::FromEventTargetOrNull(aEvent->mOriginalTarget);
   1039 
   1040  const bool isInAnon = content && content->ChromeOnlyAccessForEvents();
   1041  aEvent->mFlags.mIsBeingDispatched = true;
   1042 
   1043  Maybe<uint32_t> activationTargetItemIndex;
   1044 
   1045  // Create visitor object and start event dispatching.
   1046  // GetEventTargetParent for the original target.
   1047  nsEventStatus status = aDOMEvent && aDOMEvent->DefaultPrevented()
   1048                             ? nsEventStatus_eConsumeNoDefault
   1049                         : aEventStatus ? *aEventStatus
   1050                                        : nsEventStatus_eIgnore;
   1051  nsCOMPtr<EventTarget> targetForPreVisitor = aEvent->mTarget;
   1052  EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
   1053                                  isInAnon, targetForPreVisitor);
   1054  preVisitor.mMaybeUncancelable = IsUncancelableIfOnlyPassiveListeners(aEvent);
   1055  targetEtci->GetEventTargetParent(preVisitor);
   1056 
   1057  if (preVisitor.mWantsActivationBehavior) {
   1058    MOZ_ASSERT(&chain[0] == targetEtci);
   1059    activationTargetItemIndex.emplace(0);
   1060  }
   1061 
   1062  if (!preVisitor.mCanHandle) {
   1063    targetEtci = MayRetargetToChromeIfCanNotHandleEvent(
   1064        chain, preVisitor, targetEtci, nullptr, content);
   1065  }
   1066  if (!preVisitor.mCanHandle) {
   1067    // The original target and chrome target (mAutomaticChromeDispatch=true)
   1068    // can not handle the event but we still have to call their PreHandleEvent.
   1069    for (uint32_t i = 0; i < chain.Length(); ++i) {
   1070      chain[i].PreHandleEvent(preVisitor);
   1071    }
   1072 
   1073    clearTargets = ShouldClearTargets(aEvent);
   1074  } else {
   1075    if (preVisitor.mMaybeUncancelable && preVisitor.mMayHaveListenerManager) {
   1076      if (EventListenerManager* const manager =
   1077              targetEtci->CurrentTarget()->GetExistingListenerManager()) {
   1078        preVisitor.mMaybeUncancelable =
   1079            !manager->HasNonPassiveListenersFor(aEvent);
   1080      }
   1081    }
   1082 
   1083    // At least the original target can handle the event.
   1084    // Setting the retarget to the |target| simplifies retargeting code.
   1085    nsCOMPtr<EventTarget> t = aEvent->mTarget;
   1086    targetEtci->SetNewTarget(t);
   1087    // In order to not change the targetTouches array passed to TouchEvents
   1088    // when dispatching events from JS, we need to store the initial Touch
   1089    // objects on the list.
   1090    if (aEvent->mClass == eTouchEventClass && aDOMEvent) {
   1091      TouchEvent* touchEvent = static_cast<TouchEvent*>(aDOMEvent);
   1092      TouchList* targetTouches = touchEvent->GetExistingTargetTouches();
   1093      if (targetTouches) {
   1094        Maybe<nsTArray<RefPtr<dom::Touch>>> initialTargetTouches;
   1095        initialTargetTouches.emplace();
   1096        for (uint32_t i = 0; i < targetTouches->Length(); ++i) {
   1097          initialTargetTouches->AppendElement(targetTouches->Item(i));
   1098        }
   1099        targetEtci->SetInitialTargetTouches(std::move(initialTargetTouches));
   1100        targetTouches->Clear();
   1101      }
   1102    }
   1103    EventTargetChainItem* topEtci = targetEtci;
   1104    targetEtci = nullptr;
   1105    while (preVisitor.GetParentTarget()) {
   1106      EventTarget* parentTarget = preVisitor.GetParentTarget();
   1107      EventTargetChainItem* parentEtci =
   1108          EventTargetChainItem::Create(chain, parentTarget, topEtci);
   1109      if (!parentEtci->IsValid()) {
   1110        EventTargetChainItem::DestroyLast(chain, parentEtci);
   1111        rv = NS_ERROR_FAILURE;
   1112        break;
   1113      }
   1114 
   1115      parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
   1116      parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
   1117 
   1118      // Item needs event retargetting.
   1119      if (preVisitor.mEventTargetAtParent) {
   1120        // Need to set the target of the event
   1121        // so that also the next retargeting works.
   1122        preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
   1123        preVisitor.mEvent->mTarget = preVisitor.mEventTargetAtParent;
   1124        parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
   1125      }
   1126 
   1127      if (preVisitor.mRetargetedRelatedTarget) {
   1128        preVisitor.mEvent->mRelatedTarget = preVisitor.mRetargetedRelatedTarget;
   1129      }
   1130 
   1131      parentEtci->GetEventTargetParent(preVisitor);
   1132 
   1133      if (preVisitor.mWantsActivationBehavior &&
   1134          activationTargetItemIndex.isNothing() && aEvent->mFlags.mBubbles) {
   1135        MOZ_ASSERT(&chain.LastElement() == parentEtci);
   1136        activationTargetItemIndex.emplace(chain.Length() - 1);
   1137      }
   1138 
   1139      if (!preVisitor.mCanHandle) {
   1140        bool ignoreBecauseOfShadowDOM = preVisitor.mIgnoreBecauseOfShadowDOM;
   1141        nsCOMPtr<nsINode> disabledTarget =
   1142            nsINode::FromEventTargetOrNull(parentTarget);
   1143        parentEtci = MayRetargetToChromeIfCanNotHandleEvent(
   1144            chain, preVisitor, parentEtci, topEtci, disabledTarget);
   1145        if (parentEtci && preVisitor.mCanHandle) {
   1146          EventTargetChainItem* item =
   1147              EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
   1148          if (!ignoreBecauseOfShadowDOM) {
   1149            // If we ignored the target because of Shadow DOM retargeting, we
   1150            // shouldn't treat the target to be in the event path at all.
   1151            item->SetNewTarget(parentTarget);
   1152          }
   1153        }
   1154      }
   1155 
   1156      if (parentEtci && preVisitor.mCanHandle) {
   1157        preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
   1158        topEtci = parentEtci;
   1159      } else {
   1160        break;
   1161      }
   1162 
   1163      if (preVisitor.mMaybeUncancelable && preVisitor.mMayHaveListenerManager) {
   1164        if (EventListenerManager* const manager =
   1165                parentEtci->CurrentTarget()->GetExistingListenerManager()) {
   1166          preVisitor.mMaybeUncancelable =
   1167              !manager->HasNonPassiveListenersFor(aEvent);
   1168        }
   1169      }
   1170    }
   1171 
   1172    if (activationTargetItemIndex) {
   1173      chain[activationTargetItemIndex.value()].LegacyPreActivationBehavior(
   1174          preVisitor);
   1175    }
   1176 
   1177    if (NS_SUCCEEDED(rv)) {
   1178      if (preVisitor.mMaybeUncancelable) {
   1179        aEvent->mFlags.mCancelable = false;
   1180      }
   1181 
   1182      if (aTargets) {
   1183        aTargets->Clear();
   1184        uint32_t numTargets = chain.Length();
   1185        EventTarget** targets = aTargets->AppendElements(numTargets);
   1186        for (uint32_t i = 0; i < numTargets; ++i) {
   1187          targets[i] = chain[i].CurrentTarget()->GetTargetForDOMEvent();
   1188        }
   1189      } else {
   1190        // Event target chain is created. PreHandle the chain.
   1191        for (uint32_t i = 0; i < chain.Length(); ++i) {
   1192          chain[i].PreHandleEvent(preVisitor);
   1193        }
   1194 
   1195        RefPtr<nsRefreshDriver> refreshDriver;
   1196        if (aEvent->IsTrusted() &&
   1197            (aEvent->mMessage == eKeyPress ||
   1198             aEvent->mMessage == ePointerClick) &&
   1199            aPresContext && aPresContext->GetRootPresContext()) {
   1200          refreshDriver = aPresContext->GetRootPresContext()->RefreshDriver();
   1201          if (refreshDriver) {
   1202            refreshDriver->EnterUserInputProcessing();
   1203          }
   1204        }
   1205        auto cleanup = MakeScopeExit([&] {
   1206          if (refreshDriver) {
   1207            refreshDriver->ExitUserInputProcessing();
   1208          }
   1209        });
   1210 
   1211        clearTargets = ShouldClearTargets(aEvent);
   1212 
   1213        // Handle the chain.
   1214        EventChainPostVisitor postVisitor(preVisitor);
   1215        MOZ_RELEASE_ASSERT(!aEvent->mPath);
   1216        aEvent->mPath = &chain;
   1217 
   1218        if (profiler_is_active()) {
   1219          // Add a profiler label and a profiler marker for the actual
   1220          // dispatch of the event.
   1221          // This is a very hot code path, so we need to make sure not to
   1222          // do this extra work when we're not profiling.
   1223          if (!postVisitor.mDOMEvent) {
   1224            // This is tiny bit slow, but happens only once per event.
   1225            // Similar code also in EventListenerManager.
   1226            RefPtr<Event> event = EventDispatcher::CreateEvent(
   1227                aEvent->mOriginalTarget, aPresContext, aEvent, u""_ns);
   1228            event.swap(postVisitor.mDOMEvent);
   1229          }
   1230          nsAutoString typeStr;
   1231          postVisitor.mDOMEvent->GetType(typeStr);
   1232          AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
   1233              "EventDispatcher::Dispatch", OTHER, typeStr);
   1234 
   1235          MarkerInnerWindowId innerWindowId;
   1236          if (nsIGlobalObject* global = aEvent->mTarget->GetOwnerGlobal()) {
   1237            if (nsPIDOMWindowInner* inner = global->GetAsInnerWindow()) {
   1238              innerWindowId = MarkerInnerWindowId{inner->WindowID()};
   1239            }
   1240          }
   1241 
   1242          nsAutoCString target;
   1243          DescribeEventTargetForProfilerMarker(aEvent->mTarget, target);
   1244 
   1245          auto startTime = TimeStamp::Now();
   1246          auto latency = startTime - aEvent->mTimeStamp;
   1247          profiler_add_marker("DOMEvent", geckoprofiler::category::DOM,
   1248                              {MarkerTiming::IntervalStart(startTime),
   1249                               MarkerInnerWindowId(innerWindowId)},
   1250                              DOMEventMarker{}, target, latency, typeStr);
   1251 
   1252          EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
   1253                                                       aCallback, cd);
   1254 
   1255          profiler_add_marker(
   1256              "DOMEvent", geckoprofiler::category::DOM,
   1257              {MarkerTiming::IntervalEnd(), std::move(innerWindowId)},
   1258              DOMEventMarker{}, target, latency, typeStr);
   1259        } else {
   1260          EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
   1261                                                       aCallback, cd);
   1262        }
   1263        aEvent->mPath = nullptr;
   1264 
   1265        if (aEvent->IsTrusted() &&
   1266            (aEvent->mMessage == eKeyPress ||
   1267             aEvent->mMessage == ePointerClick) &&
   1268            aPresContext && aPresContext->GetRootPresContext()) {
   1269          nsRefreshDriver* driver =
   1270              aPresContext->GetRootPresContext()->RefreshDriver();
   1271          if (driver && driver->HasPendingTick()) {
   1272            switch (aEvent->mMessage) {
   1273              case eKeyPress:
   1274                driver->RegisterCompositionPayload(
   1275                    {layers::CompositionPayloadType::eKeyPress,
   1276                     aEvent->mTimeStamp});
   1277                break;
   1278              case ePointerClick: {
   1279                if (aEvent->AsMouseEvent()->mInputSource ==
   1280                        MouseEvent_Binding::MOZ_SOURCE_MOUSE ||
   1281                    aEvent->AsMouseEvent()->mInputSource ==
   1282                        MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
   1283                  driver->RegisterCompositionPayload(
   1284                      {layers::CompositionPayloadType::eMouseUpFollowedByClick,
   1285                       aEvent->mTimeStamp});
   1286                }
   1287                break;
   1288              }
   1289              default:
   1290                break;
   1291            }
   1292          }
   1293        }
   1294 
   1295        preVisitor.mEventStatus = postVisitor.mEventStatus;
   1296        // If the DOM event was created during event flow.
   1297        if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
   1298          preVisitor.mDOMEvent = postVisitor.mDOMEvent;
   1299        }
   1300      }
   1301    }
   1302  }
   1303 
   1304  // Note, EventTargetChainItem objects are deleted when the chain goes out of
   1305  // the scope.
   1306 
   1307  aEvent->mFlags.mIsBeingDispatched = false;
   1308  aEvent->mFlags.mDispatchedAtLeastOnce = true;
   1309 
   1310  if (eventTimingEntry) {
   1311    eventTimingEntry->FinalizeEventTiming(aEvent);
   1312  }
   1313  // https://dom.spec.whatwg.org/#concept-event-dispatch
   1314  // step 10. If clearTargets, then:
   1315  //          1. Set event's target to null.
   1316  //          2. Set event's relatedTarget to null.
   1317  //          3. Set event's touch target list to the empty list.
   1318  if (clearTargets) {
   1319    aEvent->mTarget = nullptr;
   1320    aEvent->mOriginalTarget = nullptr;
   1321    aEvent->mRelatedTarget = nullptr;
   1322    aEvent->mOriginalRelatedTarget = nullptr;
   1323    // XXXsmaug Check also all the touch objects.
   1324  }
   1325 
   1326  if (activationTargetItemIndex) {
   1327    EventChainPostVisitor postVisitor(preVisitor);
   1328    if (preVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
   1329      chain[activationTargetItemIndex.value()].LegacyCanceledActivationBehavior(
   1330          postVisitor);
   1331    } else {
   1332      chain[activationTargetItemIndex.value()].ActivationBehavior(postVisitor);
   1333    }
   1334    preVisitor.mEventStatus = postVisitor.mEventStatus;
   1335    // If the DOM event was created during event flow.
   1336    if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
   1337      preVisitor.mDOMEvent = postVisitor.mDOMEvent;
   1338    }
   1339  }
   1340 
   1341  if (!externalDOMEvent && preVisitor.mDOMEvent) {
   1342    // A dom::Event was created while dispatching the event.
   1343    // Duplicate private data if someone holds a pointer to it.
   1344    nsrefcnt rc = 0;
   1345    NS_RELEASE2(preVisitor.mDOMEvent, rc);
   1346    if (preVisitor.mDOMEvent) {
   1347      preVisitor.mDOMEvent->DuplicatePrivateData();
   1348    }
   1349  }
   1350 
   1351  if (aEventStatus) {
   1352    *aEventStatus = preVisitor.mEventStatus;
   1353  }
   1354 
   1355  if (cd.IsMainThread() && chain.Capacity() == kCachedMainThreadChainSize &&
   1356      sCachedMainThreadChains) {
   1357    if (sCachedMainThreadChains->mChain1.Capacity() !=
   1358        kCachedMainThreadChainSize) {
   1359      chain.ClearAndRetainStorage();
   1360      chain.SwapElements(sCachedMainThreadChains->mChain1);
   1361    } else if (sCachedMainThreadChains->mChain2.Capacity() !=
   1362               kCachedMainThreadChainSize) {
   1363      chain.ClearAndRetainStorage();
   1364      chain.SwapElements(sCachedMainThreadChains->mChain2);
   1365    }
   1366  }
   1367 
   1368  return rv;
   1369 }
   1370 
   1371 /* static */
   1372 nsresult EventDispatcher::DispatchDOMEvent(EventTarget* aTarget,
   1373                                           WidgetEvent* aEvent,
   1374                                           Event* aDOMEvent,
   1375                                           nsPresContext* aPresContext,
   1376                                           nsEventStatus* aEventStatus) {
   1377  if (aDOMEvent) {
   1378    WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr();
   1379    NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE);
   1380 
   1381    // Don't modify the event if it's being dispatched right now.
   1382    if (innerEvent->mFlags.mIsBeingDispatched) {
   1383      return NS_ERROR_DOM_INVALID_STATE_ERR;
   1384    }
   1385 
   1386    bool dontResetTrusted = false;
   1387    if (innerEvent->mFlags.mDispatchedAtLeastOnce) {
   1388      innerEvent->mTarget = nullptr;
   1389      innerEvent->mOriginalTarget = nullptr;
   1390    } else {
   1391      dontResetTrusted = aDOMEvent->IsTrusted();
   1392    }
   1393 
   1394    if (!dontResetTrusted) {
   1395      // Check security state to determine if dispatcher is trusted
   1396      bool trusted = NS_IsMainThread()
   1397                         ? nsContentUtils::LegacyIsCallerChromeOrNativeCode()
   1398                         : IsCurrentThreadRunningChromeWorker();
   1399      aDOMEvent->SetTrusted(trusted);
   1400    }
   1401 
   1402    return EventDispatcher::Dispatch(aTarget, aPresContext, innerEvent,
   1403                                     aDOMEvent, aEventStatus);
   1404  } else if (aEvent) {
   1405    return EventDispatcher::Dispatch(aTarget, aPresContext, aEvent, aDOMEvent,
   1406                                     aEventStatus);
   1407  }
   1408  return NS_ERROR_ILLEGAL_VALUE;
   1409 }
   1410 
   1411 /* static */ already_AddRefed<dom::Event> EventDispatcher::CreateEvent(
   1412    EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent,
   1413    const nsAString& aEventType, CallerType aCallerType) {
   1414  if (aEvent) {
   1415    switch (aEvent->mClass) {
   1416      case eGUIEventClass:
   1417      case eScrollPortEventClass:
   1418      case eUIEventClass:
   1419        return NS_NewDOMUIEvent(aOwner, aPresContext, aEvent->AsGUIEvent());
   1420      case eScrollAreaEventClass:
   1421        return NS_NewDOMScrollAreaEvent(aOwner, aPresContext,
   1422                                        aEvent->AsScrollAreaEvent());
   1423      case eKeyboardEventClass:
   1424        return NS_NewDOMKeyboardEvent(aOwner, aPresContext,
   1425                                      aEvent->AsKeyboardEvent());
   1426      case eCompositionEventClass:
   1427        return NS_NewDOMCompositionEvent(aOwner, aPresContext,
   1428                                         aEvent->AsCompositionEvent());
   1429      case eMouseEventClass:
   1430        return NS_NewDOMMouseEvent(aOwner, aPresContext,
   1431                                   aEvent->AsMouseEvent());
   1432      case eFocusEventClass:
   1433        return NS_NewDOMFocusEvent(aOwner, aPresContext,
   1434                                   aEvent->AsFocusEvent());
   1435      case eMouseScrollEventClass:
   1436        return NS_NewDOMMouseScrollEvent(aOwner, aPresContext,
   1437                                         aEvent->AsMouseScrollEvent());
   1438      case eWheelEventClass:
   1439        return NS_NewDOMWheelEvent(aOwner, aPresContext,
   1440                                   aEvent->AsWheelEvent());
   1441      case eEditorInputEventClass:
   1442        return NS_NewDOMInputEvent(aOwner, aPresContext,
   1443                                   aEvent->AsEditorInputEvent());
   1444      case eLegacyTextEventClass:
   1445        return NS_NewDOMTextEvent(aOwner, aPresContext,
   1446                                  aEvent->AsLegacyTextEvent());
   1447      case eDragEventClass:
   1448        return NS_NewDOMDragEvent(aOwner, aPresContext, aEvent->AsDragEvent());
   1449      case eClipboardEventClass:
   1450        return NS_NewDOMClipboardEvent(aOwner, aPresContext,
   1451                                       aEvent->AsClipboardEvent());
   1452      case eSMILTimeEventClass:
   1453        return NS_NewDOMTimeEvent(aOwner, aPresContext,
   1454                                  aEvent->AsSMILTimeEvent());
   1455      case eCommandEventClass:
   1456        return NS_NewDOMCommandEvent(aOwner, aPresContext,
   1457                                     aEvent->AsCommandEvent());
   1458      case eSimpleGestureEventClass:
   1459        return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext,
   1460                                           aEvent->AsSimpleGestureEvent());
   1461      case ePointerEventClass:
   1462        return NS_NewDOMPointerEvent(aOwner, aPresContext,
   1463                                     aEvent->AsPointerEvent());
   1464      case eTouchEventClass:
   1465        return NS_NewDOMTouchEvent(aOwner, aPresContext,
   1466                                   aEvent->AsTouchEvent());
   1467      case eTransitionEventClass:
   1468        return NS_NewDOMTransitionEvent(aOwner, aPresContext,
   1469                                        aEvent->AsTransitionEvent());
   1470      case eAnimationEventClass:
   1471        return NS_NewDOMAnimationEvent(aOwner, aPresContext,
   1472                                       aEvent->AsAnimationEvent());
   1473      default:
   1474        // For all other types of events, create a vanilla event object.
   1475        return NS_NewDOMEvent(aOwner, aPresContext, aEvent);
   1476    }
   1477  }
   1478 
   1479  // And if we didn't get an event, check the type argument.
   1480 
   1481  if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
   1482      aEventType.LowerCaseEqualsLiteral("mouseevents")) {
   1483    return NS_NewDOMMouseEvent(aOwner, aPresContext, nullptr);
   1484  }
   1485  if (aEventType.LowerCaseEqualsLiteral("dragevent")) {
   1486    return NS_NewDOMDragEvent(aOwner, aPresContext, nullptr);
   1487  }
   1488  if (aEventType.LowerCaseEqualsLiteral("keyboardevent")) {
   1489    return NS_NewDOMKeyboardEvent(aOwner, aPresContext, nullptr);
   1490  }
   1491  if (aEventType.LowerCaseEqualsLiteral("compositionevent")) {
   1492    return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr);
   1493  }
   1494  if (aEventType.LowerCaseEqualsLiteral("textevent")) {
   1495    if (!StaticPrefs::dom_events_textevent_enabled()) {
   1496      return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr);
   1497    }
   1498    return NS_NewDOMTextEvent(aOwner, aPresContext, nullptr);
   1499  }
   1500  if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent")) {
   1501    DeviceOrientationEventInit init;
   1502    RefPtr<Event> event =
   1503        DeviceOrientationEvent::Constructor(aOwner, u""_ns, init);
   1504    event->MarkUninitialized();
   1505    return event.forget();
   1506  }
   1507  if (aEventType.LowerCaseEqualsLiteral("devicemotionevent")) {
   1508    return NS_NewDOMDeviceMotionEvent(aOwner, aPresContext, nullptr);
   1509  }
   1510  if (aEventType.LowerCaseEqualsLiteral("uievent") ||
   1511      aEventType.LowerCaseEqualsLiteral("uievents")) {
   1512    return NS_NewDOMUIEvent(aOwner, aPresContext, nullptr);
   1513  }
   1514  if (aEventType.LowerCaseEqualsLiteral("event") ||
   1515      aEventType.LowerCaseEqualsLiteral("events") ||
   1516      aEventType.LowerCaseEqualsLiteral("htmlevents") ||
   1517      aEventType.LowerCaseEqualsLiteral("svgevents")) {
   1518    return NS_NewDOMEvent(aOwner, aPresContext, nullptr);
   1519  }
   1520  if (aEventType.LowerCaseEqualsLiteral("messageevent")) {
   1521    RefPtr<Event> event = new MessageEvent(aOwner, aPresContext, nullptr);
   1522    return event.forget();
   1523  }
   1524  if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent")) {
   1525    return NS_NewDOMBeforeUnloadEvent(aOwner, aPresContext, nullptr);
   1526  }
   1527  if (aEventType.LowerCaseEqualsLiteral("touchevent") &&
   1528      TouchEvent::LegacyAPIEnabled(
   1529          nsContentUtils::GetDocShellForEventTarget(aOwner),
   1530          aCallerType == CallerType::System)) {
   1531    return NS_NewDOMTouchEvent(aOwner, aPresContext, nullptr);
   1532  }
   1533  if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) {
   1534    HashChangeEventInit init;
   1535    RefPtr<Event> event = HashChangeEvent::Constructor(aOwner, u""_ns, init);
   1536    event->MarkUninitialized();
   1537    return event.forget();
   1538  }
   1539  if (aEventType.LowerCaseEqualsLiteral("customevent")) {
   1540    return NS_NewDOMCustomEvent(aOwner, aPresContext, nullptr);
   1541  }
   1542  if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
   1543    RefPtr<Event> event =
   1544        StorageEvent::Constructor(aOwner, u""_ns, StorageEventInit());
   1545    event->MarkUninitialized();
   1546    return event.forget();
   1547  }
   1548  if (aEventType.LowerCaseEqualsLiteral("focusevent")) {
   1549    RefPtr<Event> event = NS_NewDOMFocusEvent(aOwner, aPresContext, nullptr);
   1550    event->MarkUninitialized();
   1551    return event.forget();
   1552  }
   1553 
   1554  // Only allow these events for chrome
   1555  if (aCallerType == CallerType::System) {
   1556    if (aEventType.LowerCaseEqualsLiteral("simplegestureevent")) {
   1557      return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext, nullptr);
   1558    }
   1559    if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
   1560        aEventType.LowerCaseEqualsLiteral("xulcommandevents")) {
   1561      return NS_NewDOMXULCommandEvent(aOwner, aPresContext, nullptr);
   1562    }
   1563  }
   1564 
   1565  // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT
   1566  // CONSTRUCTORS
   1567 
   1568  return nullptr;
   1569 }
   1570 
   1571 struct CurrentTargetPathInfo {
   1572  uint32_t mIndex;
   1573  int32_t mHiddenSubtreeLevel;
   1574 };
   1575 
   1576 static CurrentTargetPathInfo TargetPathInfo(
   1577    const nsTArray<EventTargetChainItem>& aEventPath,
   1578    const EventTarget& aCurrentTarget) {
   1579  int32_t currentTargetHiddenSubtreeLevel = 0;
   1580  for (uint32_t index = aEventPath.Length(); index--;) {
   1581    const EventTargetChainItem& item = aEventPath.ElementAt(index);
   1582    if (item.PreHandleEventOnly()) {
   1583      continue;
   1584    }
   1585 
   1586    if (item.IsRootOfClosedTree()) {
   1587      currentTargetHiddenSubtreeLevel++;
   1588    }
   1589 
   1590    if (item.CurrentTarget() == &aCurrentTarget) {
   1591      return {index, currentTargetHiddenSubtreeLevel};
   1592    }
   1593 
   1594    if (item.IsSlotInClosedTree()) {
   1595      currentTargetHiddenSubtreeLevel--;
   1596    }
   1597  }
   1598  MOZ_ASSERT_UNREACHABLE("No target found?");
   1599  return {0, 0};
   1600 }
   1601 
   1602 // https://dom.spec.whatwg.org/#dom-event-composedpath
   1603 void EventDispatcher::GetComposedPathFor(WidgetEvent* aEvent,
   1604                                         nsTArray<RefPtr<EventTarget>>& aPath) {
   1605  MOZ_ASSERT(aPath.IsEmpty());
   1606  nsTArray<EventTargetChainItem>* path = aEvent->mPath;
   1607  if (!path || path->IsEmpty() || !aEvent->mCurrentTarget) {
   1608    return;
   1609  }
   1610 
   1611  EventTarget* currentTarget =
   1612      aEvent->mCurrentTarget->GetTargetForEventTargetChain();
   1613  if (!currentTarget) {
   1614    return;
   1615  }
   1616 
   1617  CurrentTargetPathInfo currentTargetInfo =
   1618      TargetPathInfo(*path, *currentTarget);
   1619 
   1620  {
   1621    int32_t maxHiddenLevel = currentTargetInfo.mHiddenSubtreeLevel;
   1622    int32_t currentHiddenLevel = currentTargetInfo.mHiddenSubtreeLevel;
   1623    for (uint32_t index = currentTargetInfo.mIndex; index--;) {
   1624      EventTargetChainItem& item = path->ElementAt(index);
   1625      if (item.PreHandleEventOnly()) {
   1626        continue;
   1627      }
   1628 
   1629      if (item.IsRootOfClosedTree()) {
   1630        currentHiddenLevel++;
   1631      }
   1632 
   1633      if (currentHiddenLevel <= maxHiddenLevel) {
   1634        aPath.AppendElement(item.CurrentTarget()->GetTargetForDOMEvent());
   1635      }
   1636 
   1637      if (item.IsChromeHandler()) {
   1638        break;
   1639      }
   1640 
   1641      if (item.IsSlotInClosedTree()) {
   1642        currentHiddenLevel--;
   1643        maxHiddenLevel = std::min(maxHiddenLevel, currentHiddenLevel);
   1644      }
   1645    }
   1646 
   1647    aPath.Reverse();
   1648  }
   1649 
   1650  aPath.AppendElement(currentTarget->GetTargetForDOMEvent());
   1651 
   1652  {
   1653    int32_t maxHiddenLevel = currentTargetInfo.mHiddenSubtreeLevel;
   1654    int32_t currentHiddenLevel = currentTargetInfo.mHiddenSubtreeLevel;
   1655    for (uint32_t index = currentTargetInfo.mIndex + 1; index < path->Length();
   1656         ++index) {
   1657      EventTargetChainItem& item = path->ElementAt(index);
   1658      if (item.PreHandleEventOnly()) {
   1659        continue;
   1660      }
   1661 
   1662      if (item.IsSlotInClosedTree()) {
   1663        currentHiddenLevel++;
   1664      }
   1665 
   1666      if (item.IsChromeHandler()) {
   1667        break;
   1668      }
   1669 
   1670      if (currentHiddenLevel <= maxHiddenLevel) {
   1671        aPath.AppendElement(item.CurrentTarget()->GetTargetForDOMEvent());
   1672      }
   1673 
   1674      if (item.IsRootOfClosedTree()) {
   1675        currentHiddenLevel--;
   1676        maxHiddenLevel = std::min(maxHiddenLevel, currentHiddenLevel);
   1677      }
   1678    }
   1679  }
   1680 }
   1681 
   1682 void EventChainPreVisitor::IgnoreCurrentTargetBecauseOfShadowDOMRetargeting() {
   1683  mCanHandle = false;
   1684  mIgnoreBecauseOfShadowDOM = true;
   1685 
   1686  EventTarget* target = nullptr;
   1687 
   1688  auto getWindow = [this]() -> nsPIDOMWindowOuter* {
   1689    nsINode* node = nsINode::FromEventTargetOrNull(this->mParentTarget);
   1690    if (!node) {
   1691      return nullptr;
   1692    }
   1693    Document* doc = node->GetComposedDoc();
   1694    if (!doc) {
   1695      return nullptr;
   1696    }
   1697 
   1698    return doc->GetWindow();
   1699  };
   1700 
   1701  // The HTMLEditor is registered to nsWindowRoot, so we
   1702  // want to dispatch events to it.
   1703  if (nsCOMPtr<nsPIDOMWindowOuter> win = getWindow()) {
   1704    target = win->GetParentTarget();
   1705  }
   1706  SetParentTarget(target, false);
   1707 
   1708  mEventTargetAtParent = nullptr;
   1709 }
   1710 
   1711 }  // namespace mozilla