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 "nsPresContext.h"
8 #include "nsContentUtils.h"
9 #include "nsError.h"
10 #include <new>
11 #include "nsIContent.h"
12 #include "nsIDocument.h"
13 #include "nsINode.h"
14 #include "nsPIDOMWindow.h"
15 #include "AnimationEvent.h"
16 #include "BeforeUnloadEvent.h"
17 #include "ClipboardEvent.h"
18 #include "CommandEvent.h"
19 #include "CompositionEvent.h"
20 #include "DeviceMotionEvent.h"
21 #include "DragEvent.h"
22 #include "GeckoProfiler.h"
23 #include "KeyboardEvent.h"
24 #include "mozilla/ContentEvents.h"
25 #include "mozilla/dom/CloseEvent.h"
26 #include "mozilla/dom/CustomEvent.h"
27 #include "mozilla/dom/DeviceOrientationEvent.h"
28 #include "mozilla/dom/EventTarget.h"
29 #include "mozilla/dom/FocusEvent.h"
30 #include "mozilla/dom/HashChangeEvent.h"
31 #include "mozilla/dom/InputEvent.h"
32 #include "mozilla/dom/MessageEvent.h"
33 #include "mozilla/dom/MouseScrollEvent.h"
34 #include "mozilla/dom/MutationEvent.h"
35 #include "mozilla/dom/NotifyPaintEvent.h"
36 #include "mozilla/dom/PageTransitionEvent.h"
37 #include "mozilla/dom/PointerEvent.h"
38 #include "mozilla/dom/RootedDictionary.h"
39 #include "mozilla/dom/ScrollAreaEvent.h"
40 #include "mozilla/dom/SimpleGestureEvent.h"
41 #include "mozilla/dom/ScriptSettings.h"
42 #include "mozilla/dom/StorageEvent.h"
43 #include "mozilla/dom/TimeEvent.h"
44 #include "mozilla/dom/TouchEvent.h"
45 #include "mozilla/dom/TransitionEvent.h"
46 #include "mozilla/dom/WheelEvent.h"
47 #include "mozilla/dom/WorkerPrivate.h"
48 #include "mozilla/dom/XULCommandEvent.h"
49 #include "mozilla/EventDispatcher.h"
50 #include "mozilla/EventListenerManager.h"
51 #include "mozilla/InternalMutationEvent.h"
52 #include "mozilla/ipc/MessageChannel.h"
53 #include "mozilla/MiscEvents.h"
54 #include "mozilla/MouseEvents.h"
55 #include "mozilla/Telemetry.h"
56 #include "mozilla/TextEvents.h"
57 #include "mozilla/TouchEvents.h"
58 #include "mozilla/Unused.h"
59 
60 #ifdef MOZ_TASK_TRACER
61 #include "GeckoTaskTracer.h"
62 #include "mozilla/dom/Element.h"
63 #include "mozilla/Likely.h"
64 using namespace mozilla::tasktracer;
65 #endif
66 
67 namespace mozilla {
68 
69 using namespace dom;
70 
71 class ELMCreationDetector {
72  public:
ELMCreationDetector()73   ELMCreationDetector()
74       // We can do this optimization only in the main thread.
75       : mNonMainThread(!NS_IsMainThread()),
76         mInitialCount(mNonMainThread
77                           ? 0
78                           : EventListenerManager::sMainThreadCreatedCount) {}
79 
MayHaveNewListenerManager()80   bool MayHaveNewListenerManager() {
81     return mNonMainThread ||
82            mInitialCount != EventListenerManager::sMainThreadCreatedCount;
83   }
84 
IsMainThread()85   bool IsMainThread() { return !mNonMainThread; }
86 
87  private:
88   bool mNonMainThread;
89   uint32_t mInitialCount;
90 };
91 
IsEventTargetChrome(EventTarget * aEventTarget,nsIDocument ** aDocument=nullptr)92 static bool IsEventTargetChrome(EventTarget* aEventTarget,
93                                 nsIDocument** aDocument = nullptr) {
94   if (aDocument) {
95     *aDocument = nullptr;
96   }
97 
98   nsIDocument* doc = nullptr;
99   nsCOMPtr<nsINode> node = do_QueryInterface(aEventTarget);
100   if (node) {
101     doc = node->OwnerDoc();
102   } else {
103     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aEventTarget);
104     if (!window) {
105       return false;
106     }
107     doc = window->GetExtantDoc();
108   }
109 
110   // nsContentUtils::IsChromeDoc is null-safe.
111   bool isChrome = nsContentUtils::IsChromeDoc(doc);
112   if (aDocument && doc) {
113     nsCOMPtr<nsIDocument> retVal = doc;
114     retVal.swap(*aDocument);
115   }
116   return isChrome;
117 }
118 
119 // EventTargetChainItem represents a single item in the event target chain.
120 class EventTargetChainItem {
121  private:
122   explicit EventTargetChainItem(EventTarget* aTarget);
123 
124  public:
EventTargetChainItem()125   EventTargetChainItem() : mItemFlags(0) {}
126 
Create(nsTArray<EventTargetChainItem> & aChain,EventTarget * aTarget,EventTargetChainItem * aChild=nullptr)127   static EventTargetChainItem* Create(nsTArray<EventTargetChainItem>& aChain,
128                                       EventTarget* aTarget,
129                                       EventTargetChainItem* aChild = nullptr) {
130     // The last item which can handle the event must be aChild.
131     MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
132     return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
133   }
134 
DestroyLast(nsTArray<EventTargetChainItem> & aChain,EventTargetChainItem * aItem)135   static void DestroyLast(nsTArray<EventTargetChainItem>& aChain,
136                           EventTargetChainItem* aItem) {
137     uint32_t lastIndex = aChain.Length() - 1;
138     MOZ_ASSERT(&aChain[lastIndex] == aItem);
139     aChain.RemoveElementAt(lastIndex);
140   }
141 
GetFirstCanHandleEventTarget(nsTArray<EventTargetChainItem> & aChain)142   static EventTargetChainItem* GetFirstCanHandleEventTarget(
143       nsTArray<EventTargetChainItem>& aChain) {
144     return &aChain[GetFirstCanHandleEventTargetIdx(aChain)];
145   }
146 
GetFirstCanHandleEventTargetIdx(nsTArray<EventTargetChainItem> & aChain)147   static uint32_t GetFirstCanHandleEventTargetIdx(
148       nsTArray<EventTargetChainItem>& aChain) {
149     // aChain[i].PreHandleEventOnly() = true only when the target element wants
150     // PreHandleEvent and set mCanHandle=false. So we find the first element
151     // which can handle the event.
152     for (uint32_t i = 0; i < aChain.Length(); ++i) {
153       if (!aChain[i].PreHandleEventOnly()) {
154         return i;
155       }
156     }
157     MOZ_ASSERT(false);
158     return 0;
159   }
160 
GetLastCanHandleEventTarget(nsTArray<EventTargetChainItem> & aChain)161   static EventTargetChainItem* GetLastCanHandleEventTarget(
162       nsTArray<EventTargetChainItem>& aChain) {
163     // Fine the last item which can handle the event.
164     for (int32_t i = aChain.Length() - 1; i >= 0; --i) {
165       if (!aChain[i].PreHandleEventOnly()) {
166         return &aChain[i];
167       }
168     }
169     return nullptr;
170   }
171 
IsValid()172   bool IsValid() {
173     NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
174     return !!(mTarget);
175   }
176 
GetNewTarget()177   EventTarget* GetNewTarget() { return mNewTarget; }
178 
SetNewTarget(EventTarget * aNewTarget)179   void SetNewTarget(EventTarget* aNewTarget) { mNewTarget = aNewTarget; }
180 
GetRetargetedRelatedTarget()181   EventTarget* GetRetargetedRelatedTarget() { return mRetargetedRelatedTarget; }
182 
SetRetargetedRelatedTarget(EventTarget * aTarget)183   void SetRetargetedRelatedTarget(EventTarget* aTarget) {
184     mRetargetedRelatedTarget = aTarget;
185   }
186 
SetForceContentDispatch(bool aForce)187   void SetForceContentDispatch(bool aForce) {
188     mFlags.mForceContentDispatch = aForce;
189   }
190 
ForceContentDispatch()191   bool ForceContentDispatch() { return mFlags.mForceContentDispatch; }
192 
SetWantsWillHandleEvent(bool aWants)193   void SetWantsWillHandleEvent(bool aWants) {
194     mFlags.mWantsWillHandleEvent = aWants;
195   }
196 
WantsWillHandleEvent()197   bool WantsWillHandleEvent() { return mFlags.mWantsWillHandleEvent; }
198 
SetWantsPreHandleEvent(bool aWants)199   void SetWantsPreHandleEvent(bool aWants) {
200     mFlags.mWantsPreHandleEvent = aWants;
201   }
202 
WantsPreHandleEvent()203   bool WantsPreHandleEvent() { return mFlags.mWantsPreHandleEvent; }
204 
SetPreHandleEventOnly(bool aWants)205   void SetPreHandleEventOnly(bool aWants) {
206     mFlags.mPreHandleEventOnly = aWants;
207   }
208 
PreHandleEventOnly()209   bool PreHandleEventOnly() { return mFlags.mPreHandleEventOnly; }
210 
SetRootOfClosedTree(bool aSet)211   void SetRootOfClosedTree(bool aSet) { mFlags.mRootOfClosedTree = aSet; }
212 
IsRootOfClosedTree()213   bool IsRootOfClosedTree() { return mFlags.mRootOfClosedTree; }
214 
SetIsSlotInClosedTree(bool aSet)215   void SetIsSlotInClosedTree(bool aSet) { mFlags.mIsSlotInClosedTree = aSet; }
216 
IsSlotInClosedTree()217   bool IsSlotInClosedTree() { return mFlags.mIsSlotInClosedTree; }
218 
SetIsChromeHandler(bool aSet)219   void SetIsChromeHandler(bool aSet) { mFlags.mIsChromeHandler = aSet; }
220 
IsChromeHandler()221   bool IsChromeHandler() { return mFlags.mIsChromeHandler; }
222 
SetMayHaveListenerManager(bool aMayHave)223   void SetMayHaveListenerManager(bool aMayHave) {
224     mFlags.mMayHaveManager = aMayHave;
225   }
226 
MayHaveListenerManager()227   bool MayHaveListenerManager() { return mFlags.mMayHaveManager; }
228 
CurrentTarget()229   EventTarget* CurrentTarget() { return mTarget; }
230 
231   /**
232    * Dispatches event through the event target chain.
233    * Handles capture, target and bubble phases both in default
234    * and system event group and calls also PostHandleEvent for each
235    * item in the chain.
236    */
237   static void HandleEventTargetChain(nsTArray<EventTargetChainItem>& aChain,
238                                      EventChainPostVisitor& aVisitor,
239                                      EventDispatchingCallback* aCallback,
240                                      ELMCreationDetector& aCd);
241 
242   /**
243    * Resets aVisitor object and calls GetEventTargetParent.
244    * Copies mItemFlags and mItemData to the current EventTargetChainItem.
245    */
246   void GetEventTargetParent(EventChainPreVisitor& aVisitor);
247 
248   /**
249    * Calls PreHandleEvent for those items which called SetWantsPreHandleEvent.
250    */
251   void PreHandleEvent(EventChainVisitor& aVisitor);
252 
253   /**
254    * If the current item in the event target chain has an event listener
255    * manager, this method calls EventListenerManager::HandleEvent().
256    */
HandleEvent(EventChainPostVisitor & aVisitor,ELMCreationDetector & aCd)257   void HandleEvent(EventChainPostVisitor& aVisitor, ELMCreationDetector& aCd) {
258     if (WantsWillHandleEvent()) {
259       mTarget->WillHandleEvent(aVisitor);
260     }
261     if (aVisitor.mEvent->PropagationStopped()) {
262       return;
263     }
264     if (aVisitor.mEvent->mFlags.mOnlySystemGroupDispatchInContent &&
265         !aVisitor.mEvent->mFlags.mInSystemGroup && !IsCurrentTargetChrome()) {
266       return;
267     }
268     if (!mManager) {
269       if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
270         return;
271       }
272       mManager = mTarget->GetExistingListenerManager();
273     }
274     if (mManager) {
275       NS_ASSERTION(aVisitor.mEvent->mCurrentTarget == nullptr,
276                    "CurrentTarget should be null!");
277       mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
278                             &aVisitor.mDOMEvent, CurrentTarget(),
279                             &aVisitor.mEventStatus);
280       NS_ASSERTION(aVisitor.mEvent->mCurrentTarget == nullptr,
281                    "CurrentTarget should be null!");
282     }
283   }
284 
285   /**
286    * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
287    */
288   void PostHandleEvent(EventChainPostVisitor& aVisitor);
289 
290  private:
291   nsCOMPtr<EventTarget> mTarget;
292   nsCOMPtr<EventTarget> mRetargetedRelatedTarget;
293 
294   class EventTargetChainFlags {
295    public:
EventTargetChainFlags()296     explicit EventTargetChainFlags() { SetRawFlags(0); }
297     // Cached flags for each EventTargetChainItem which are set when calling
298     // GetEventTargetParent to create event target chain. They are used to
299     // manage or speedup event dispatching.
300     bool mForceContentDispatch : 1;
301     bool mWantsWillHandleEvent : 1;
302     bool mMayHaveManager : 1;
303     bool mChechedIfChrome : 1;
304     bool mIsChromeContent : 1;
305     bool mWantsPreHandleEvent : 1;
306     bool mPreHandleEventOnly : 1;
307     bool mRootOfClosedTree : 1;
308     bool mIsSlotInClosedTree : 1;
309     bool mIsChromeHandler : 1;
310 
311    private:
312     typedef uint32_t RawFlags;
SetRawFlags(RawFlags aRawFlags)313     void SetRawFlags(RawFlags aRawFlags) {
314       static_assert(
315           sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
316           "EventTargetChainFlags must not be bigger than the RawFlags");
317       memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
318     }
319   } mFlags;
320 
321   uint16_t mItemFlags;
322   nsCOMPtr<nsISupports> mItemData;
323   // Event retargeting must happen whenever mNewTarget is non-null.
324   nsCOMPtr<EventTarget> mNewTarget;
325   // Cache mTarget's event listener manager.
326   RefPtr<EventListenerManager> mManager;
327 
IsCurrentTargetChrome()328   bool IsCurrentTargetChrome() {
329     if (!mFlags.mChechedIfChrome) {
330       mFlags.mChechedIfChrome = true;
331       if (IsEventTargetChrome(mTarget)) {
332         mFlags.mIsChromeContent = true;
333       }
334     }
335     return mFlags.mIsChromeContent;
336   }
337 };
338 
EventTargetChainItem(EventTarget * aTarget)339 EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
340     : mTarget(aTarget), mItemFlags(0) {
341   MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
342 }
343 
GetEventTargetParent(EventChainPreVisitor & aVisitor)344 void EventTargetChainItem::GetEventTargetParent(
345     EventChainPreVisitor& aVisitor) {
346   aVisitor.Reset();
347   Unused << mTarget->GetEventTargetParent(aVisitor);
348   SetForceContentDispatch(aVisitor.mForceContentDispatch);
349   SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
350   SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
351   SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
352   SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
353   SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
354   SetRetargetedRelatedTarget(aVisitor.mRetargetedRelatedTarget);
355   mItemFlags = aVisitor.mItemFlags;
356   mItemData = aVisitor.mItemData;
357 }
358 
PreHandleEvent(EventChainVisitor & aVisitor)359 void EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor) {
360   if (!WantsPreHandleEvent()) {
361     return;
362   }
363   aVisitor.mItemFlags = mItemFlags;
364   aVisitor.mItemData = mItemData;
365   Unused << mTarget->PreHandleEvent(aVisitor);
366 }
367 
PostHandleEvent(EventChainPostVisitor & aVisitor)368 void EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor) {
369   aVisitor.mItemFlags = mItemFlags;
370   aVisitor.mItemData = mItemData;
371   mTarget->PostHandleEvent(aVisitor);
372 }
373 
HandleEventTargetChain(nsTArray<EventTargetChainItem> & aChain,EventChainPostVisitor & aVisitor,EventDispatchingCallback * aCallback,ELMCreationDetector & aCd)374 void EventTargetChainItem::HandleEventTargetChain(
375     nsTArray<EventTargetChainItem>& aChain, EventChainPostVisitor& aVisitor,
376     EventDispatchingCallback* aCallback, ELMCreationDetector& aCd) {
377   // Save the target so that it can be restored later.
378   nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
379   nsCOMPtr<EventTarget> firstRelatedTarget = aVisitor.mEvent->mRelatedTarget;
380   uint32_t chainLength = aChain.Length();
381   uint32_t firstCanHandleEventTargetIdx =
382       EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
383 
384   // Capture
385   aVisitor.mEvent->mFlags.mInCapturePhase = true;
386   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
387   for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
388     EventTargetChainItem& item = aChain[i];
389     if (item.PreHandleEventOnly()) {
390       continue;
391     }
392     if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
393          item.ForceContentDispatch()) &&
394         !aVisitor.mEvent->PropagationStopped()) {
395       item.HandleEvent(aVisitor, aCd);
396     }
397 
398     if (item.GetNewTarget()) {
399       // item is at anonymous boundary. Need to retarget for the child items.
400       for (uint32_t j = i; j > 0; --j) {
401         uint32_t childIndex = j - 1;
402         EventTarget* newTarget = aChain[childIndex].GetNewTarget();
403         if (newTarget) {
404           aVisitor.mEvent->mTarget = newTarget;
405           break;
406         }
407       }
408     }
409 
410     // https://dom.spec.whatwg.org/#dispatching-events
411     // Step 14.2
412     // "Set event's relatedTarget to tuple's relatedTarget."
413     // Note, the initial retargeting was done already when creating
414     // event target chain, so we need to do this only after calling
415     // HandleEvent, not before, like in the specification.
416     if (item.GetRetargetedRelatedTarget()) {
417       bool found = false;
418       for (uint32_t j = i; j > 0; --j) {
419         uint32_t childIndex = j - 1;
420         EventTarget* relatedTarget =
421             aChain[childIndex].GetRetargetedRelatedTarget();
422         if (relatedTarget) {
423           found = true;
424           aVisitor.mEvent->mRelatedTarget = relatedTarget;
425           break;
426         }
427       }
428       if (!found) {
429         aVisitor.mEvent->mRelatedTarget =
430             aVisitor.mEvent->mOriginalRelatedTarget;
431       }
432     }
433   }
434 
435   // Target
436   aVisitor.mEvent->mFlags.mInBubblingPhase = true;
437   EventTargetChainItem& targetItem = aChain[firstCanHandleEventTargetIdx];
438   if (!aVisitor.mEvent->PropagationStopped() &&
439       (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
440        targetItem.ForceContentDispatch())) {
441     targetItem.HandleEvent(aVisitor, aCd);
442   }
443   if (aVisitor.mEvent->mFlags.mInSystemGroup) {
444     targetItem.PostHandleEvent(aVisitor);
445   }
446 
447   // Bubble
448   aVisitor.mEvent->mFlags.mInCapturePhase = false;
449   for (uint32_t i = firstCanHandleEventTargetIdx + 1; i < chainLength; ++i) {
450     EventTargetChainItem& item = aChain[i];
451     if (item.PreHandleEventOnly()) {
452       continue;
453     }
454     EventTarget* newTarget = item.GetNewTarget();
455     if (newTarget) {
456       // Item is at anonymous boundary. Need to retarget for the current item
457       // and for parent items.
458       aVisitor.mEvent->mTarget = newTarget;
459     }
460 
461     // https://dom.spec.whatwg.org/#dispatching-events
462     // Step 15.2
463     // "Set event's relatedTarget to tuple's relatedTarget."
464     EventTarget* relatedTarget = item.GetRetargetedRelatedTarget();
465     if (relatedTarget) {
466       aVisitor.mEvent->mRelatedTarget = relatedTarget;
467     }
468 
469     if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
470       if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
471            item.ForceContentDispatch()) &&
472           !aVisitor.mEvent->PropagationStopped()) {
473         item.HandleEvent(aVisitor, aCd);
474       }
475       if (aVisitor.mEvent->mFlags.mInSystemGroup) {
476         item.PostHandleEvent(aVisitor);
477       }
478     }
479   }
480   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
481 
482   if (!aVisitor.mEvent->mFlags.mInSystemGroup &&
483       aVisitor.mEvent->IsAllowedToDispatchInSystemGroup()) {
484     // Dispatch to the system event group.  Make sure to clear the
485     // STOP_DISPATCH flag since this resets for each event group.
486     aVisitor.mEvent->mFlags.mPropagationStopped = false;
487     aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
488 
489     // Setting back the original target of the event.
490     aVisitor.mEvent->mTarget = aVisitor.mEvent->mOriginalTarget;
491     aVisitor.mEvent->mRelatedTarget = aVisitor.mEvent->mOriginalRelatedTarget;
492 
493     // Special handling if PresShell (or some other caller)
494     // used a callback object.
495     if (aCallback) {
496       aCallback->HandleEvent(aVisitor);
497     }
498 
499     // Retarget for system event group (which does the default handling too).
500     // Setting back the target which was used also for default event group.
501     aVisitor.mEvent->mTarget = firstTarget;
502     aVisitor.mEvent->mRelatedTarget = firstRelatedTarget;
503     aVisitor.mEvent->mFlags.mInSystemGroup = true;
504     HandleEventTargetChain(aChain, aVisitor, aCallback, aCd);
505     aVisitor.mEvent->mFlags.mInSystemGroup = false;
506 
507     // After dispatch, clear all the propagation flags so that
508     // system group listeners don't affect to the event.
509     aVisitor.mEvent->mFlags.mPropagationStopped = false;
510     aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
511   }
512 }
513 
514 static nsTArray<EventTargetChainItem>* sCachedMainThreadChain = nullptr;
515 
Shutdown()516 /* static */ void EventDispatcher::Shutdown() {
517   delete sCachedMainThreadChain;
518   sCachedMainThreadChain = nullptr;
519 }
520 
EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem> & aChain,nsINode * aNode,EventTargetChainItem * aChild=nullptr)521 EventTargetChainItem* EventTargetChainItemForChromeTarget(
522     nsTArray<EventTargetChainItem>& aChain, nsINode* aNode,
523     EventTargetChainItem* aChild = nullptr) {
524   if (!aNode->IsInComposedDoc()) {
525     return nullptr;
526   }
527   nsPIDOMWindowInner* win = aNode->OwnerDoc()->GetInnerWindow();
528   EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
529   NS_ENSURE_TRUE(piTarget, nullptr);
530 
531   EventTargetChainItem* etci = EventTargetChainItem::Create(
532       aChain, piTarget->GetTargetForEventTargetChain(), aChild);
533   if (!etci->IsValid()) {
534     EventTargetChainItem::DestroyLast(aChain, etci);
535     return nullptr;
536   }
537   return etci;
538 }
539 
MayRetargetToChromeIfCanNotHandleEvent(nsTArray<EventTargetChainItem> & aChain,EventChainPreVisitor & aPreVisitor,EventTargetChainItem * aTargetEtci,EventTargetChainItem * aChildEtci,nsINode * aContent)540 /* static */ EventTargetChainItem* MayRetargetToChromeIfCanNotHandleEvent(
541     nsTArray<EventTargetChainItem>& aChain, EventChainPreVisitor& aPreVisitor,
542     EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
543     nsINode* aContent) {
544   if (!aPreVisitor.mWantsPreHandleEvent) {
545     // Keep EventTargetChainItem if we need to call PreHandleEvent on it.
546     EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
547   }
548   if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
549     aPreVisitor.mRelatedTargetRetargetedInCurrentScope = false;
550     // Event target couldn't handle the event. Try to propagate to chrome.
551     EventTargetChainItem* chromeTargetEtci =
552         EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
553     if (chromeTargetEtci) {
554       chromeTargetEtci->GetEventTargetParent(aPreVisitor);
555       return chromeTargetEtci;
556     }
557   }
558   return nullptr;
559 }
560 
Dispatch(nsISupports * aTarget,nsPresContext * aPresContext,WidgetEvent * aEvent,nsIDOMEvent * aDOMEvent,nsEventStatus * aEventStatus,EventDispatchingCallback * aCallback,nsTArray<EventTarget * > * aTargets)561 /* static */ nsresult EventDispatcher::Dispatch(
562     nsISupports* aTarget, nsPresContext* aPresContext, WidgetEvent* aEvent,
563     nsIDOMEvent* aDOMEvent, nsEventStatus* aEventStatus,
564     EventDispatchingCallback* aCallback, nsTArray<EventTarget*>* aTargets) {
565   AUTO_PROFILER_LABEL("EventDispatcher::Dispatch", EVENTS);
566 
567   NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!");
568   NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched,
569                  NS_ERROR_DOM_INVALID_STATE_ERR);
570   NS_ASSERTION(!aTargets || !aEvent->mMessage, "Wrong parameters!");
571 
572   // If we're dispatching an already created DOMEvent object, make
573   // sure it is initialized!
574   // If aTargets is non-null, the event isn't going to be dispatched.
575   NS_ENSURE_TRUE(aEvent->mMessage || !aDOMEvent || aTargets,
576                  NS_ERROR_DOM_INVALID_STATE_ERR);
577 
578   // Events shall not be fired while we are in stable state to prevent anything
579   // visible from the scripts.
580   MOZ_ASSERT(!nsContentUtils::IsInStableOrMetaStableState());
581   NS_ENSURE_TRUE(!nsContentUtils::IsInStableOrMetaStableState(),
582                  NS_ERROR_DOM_INVALID_STATE_ERR);
583 
584 #ifdef MOZ_TASK_TRACER
585   if (MOZ_UNLIKELY(mozilla::tasktracer::IsStartLogging())) {
586     nsAutoCString eventType;
587     nsAutoString eventTypeU16;
588     if (aDOMEvent) {
589       aDOMEvent->GetType(eventTypeU16);
590     } else {
591       Event::GetWidgetEventType(aEvent, eventTypeU16);
592     }
593     eventType = NS_ConvertUTF16toUTF8(eventTypeU16);
594 
595     nsCOMPtr<Element> element = do_QueryInterface(aTarget);
596     nsAutoString elementId;
597     nsAutoString elementTagName;
598     if (element) {
599       element->GetId(elementId);
600       element->GetTagName(elementTagName);
601     }
602     AddLabel("Event [%s] dispatched at target [id:%s tag:%s]", eventType.get(),
603              NS_ConvertUTF16toUTF8(elementId).get(),
604              NS_ConvertUTF16toUTF8(elementTagName).get());
605   }
606 #endif
607 
608   nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
609 
610   bool retargeted = false;
611 
612   if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
613     nsCOMPtr<nsIContent> content = do_QueryInterface(target);
614     if (content && content->IsInNativeAnonymousSubtree()) {
615       nsCOMPtr<EventTarget> newTarget =
616           do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
617       NS_ENSURE_STATE(newTarget);
618 
619       aEvent->mOriginalTarget = target;
620       target = newTarget;
621       retargeted = true;
622     }
623   }
624 
625   if (aEvent->mFlags.mOnlyChromeDispatch) {
626     nsCOMPtr<nsIDocument> doc;
627     if (!IsEventTargetChrome(target, getter_AddRefs(doc)) && doc) {
628       nsPIDOMWindowInner* win = doc->GetInnerWindow();
629       // If we can't dispatch the event to chrome, do nothing.
630       EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
631       if (!piTarget) {
632         return NS_OK;
633       }
634 
635       // Set the target to be the original dispatch target,
636       aEvent->mTarget = target;
637       // but use chrome event handler or TabChildGlobal for event target chain.
638       target = piTarget;
639     } else if (NS_WARN_IF(!doc)) {
640       return NS_ERROR_UNEXPECTED;
641     }
642   }
643 
644 #ifdef DEBUG
645   if (aEvent->mMessage != eVoidEvent && !nsContentUtils::IsSafeToRunScript()) {
646     nsresult rv = NS_ERROR_FAILURE;
647     if (target->GetContextForEventHandlers(&rv) || NS_FAILED(rv)) {
648       nsCOMPtr<nsINode> node = do_QueryInterface(target);
649       if (node && nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
650         NS_WARNING("Fix the caller!");
651       } else {
652         NS_ERROR("This is unsafe! Fix the caller!");
653       }
654     }
655   }
656 
657   if (aDOMEvent) {
658     WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr();
659     NS_ASSERTION(innerEvent == aEvent,
660                  "The inner event of aDOMEvent is not the same as aEvent!");
661   }
662 #endif
663 
664   nsresult rv = NS_OK;
665   bool externalDOMEvent = !!(aDOMEvent);
666 
667   // If we have a PresContext, make sure it doesn't die before
668   // event dispatching is finished.
669   RefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
670 
671   ELMCreationDetector cd;
672   nsTArray<EventTargetChainItem> chain;
673   if (cd.IsMainThread()) {
674     if (!sCachedMainThreadChain) {
675       sCachedMainThreadChain = new nsTArray<EventTargetChainItem>();
676     }
677     chain.SwapElements(*sCachedMainThreadChain);
678     chain.SetCapacity(128);
679   }
680 
681   // Create the event target chain item for the event target.
682   EventTargetChainItem* targetEtci = EventTargetChainItem::Create(
683       chain, target->GetTargetForEventTargetChain());
684   MOZ_ASSERT(&chain[0] == targetEtci);
685   if (!targetEtci->IsValid()) {
686     EventTargetChainItem::DestroyLast(chain, targetEtci);
687     return NS_ERROR_FAILURE;
688   }
689 
690   // Make sure that nsIDOMEvent::target and nsIDOMEvent::originalTarget
691   // point to the last item in the chain.
692   if (!aEvent->mTarget) {
693     // Note, CurrentTarget() points always to the object returned by
694     // GetTargetForEventTargetChain().
695     aEvent->mTarget = targetEtci->CurrentTarget();
696   } else {
697     // XXX But if the target is already set, use that. This is a hack
698     //     for the 'load', 'beforeunload' and 'unload' events,
699     //     which are dispatched to |window| but have document as their target.
700     //
701     // Make sure that the event target points to the right object.
702     aEvent->mTarget = aEvent->mTarget->GetTargetForEventTargetChain();
703     NS_ENSURE_STATE(aEvent->mTarget);
704   }
705 
706   if (retargeted) {
707     aEvent->mOriginalTarget =
708         aEvent->mOriginalTarget->GetTargetForEventTargetChain();
709     NS_ENSURE_STATE(aEvent->mOriginalTarget);
710   } else {
711     aEvent->mOriginalTarget = aEvent->mTarget;
712   }
713 
714   aEvent->mOriginalRelatedTarget = aEvent->mRelatedTarget;
715 
716   nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mOriginalTarget);
717   bool isInAnon = content && content->IsInAnonymousSubtree();
718 
719   aEvent->mFlags.mIsBeingDispatched = true;
720 
721   // Create visitor object and start event dispatching.
722   // GetEventTargetParent for the original target.
723   nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
724   EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
725                                   isInAnon, aEvent->mTarget);
726   targetEtci->GetEventTargetParent(preVisitor);
727 
728   if (!preVisitor.mCanHandle) {
729     targetEtci = MayRetargetToChromeIfCanNotHandleEvent(
730         chain, preVisitor, targetEtci, nullptr, content);
731   }
732   if (!preVisitor.mCanHandle) {
733     // The original target and chrome target (mAutomaticChromeDispatch=true)
734     // can not handle the event but we still have to call their PreHandleEvent.
735     for (uint32_t i = 0; i < chain.Length(); ++i) {
736       chain[i].PreHandleEvent(preVisitor);
737     }
738   } else {
739     // At least the original target can handle the event.
740     // Setting the retarget to the |target| simplifies retargeting code.
741     nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->mTarget);
742     targetEtci->SetNewTarget(t);
743     EventTargetChainItem* topEtci = targetEtci;
744     targetEtci = nullptr;
745     while (preVisitor.GetParentTarget()) {
746       EventTarget* parentTarget = preVisitor.GetParentTarget();
747       EventTargetChainItem* parentEtci =
748           EventTargetChainItem::Create(chain, parentTarget, topEtci);
749       if (!parentEtci->IsValid()) {
750         EventTargetChainItem::DestroyLast(chain, parentEtci);
751         rv = NS_ERROR_FAILURE;
752         break;
753       }
754 
755       parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
756       parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
757 
758       // Item needs event retargetting.
759       if (preVisitor.mEventTargetAtParent) {
760         // Need to set the target of the event
761         // so that also the next retargeting works.
762         preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
763         preVisitor.mEvent->mTarget = preVisitor.mEventTargetAtParent;
764         parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
765       }
766 
767       if (preVisitor.mRetargetedRelatedTarget) {
768         preVisitor.mEvent->mRelatedTarget = preVisitor.mRetargetedRelatedTarget;
769       }
770 
771       parentEtci->GetEventTargetParent(preVisitor);
772       if (preVisitor.mCanHandle) {
773         preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
774         topEtci = parentEtci;
775       } else {
776         nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
777         parentEtci = MayRetargetToChromeIfCanNotHandleEvent(
778             chain, preVisitor, parentEtci, topEtci, disabledTarget);
779         if (parentEtci && preVisitor.mCanHandle) {
780           preVisitor.mTargetInKnownToBeHandledScope =
781               preVisitor.mEvent->mTarget;
782           EventTargetChainItem* item =
783               EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
784           item->SetNewTarget(parentTarget);
785           topEtci = parentEtci;
786           continue;
787         }
788         break;
789       }
790     }
791     if (NS_SUCCEEDED(rv)) {
792       if (aTargets) {
793         aTargets->Clear();
794         uint32_t numTargets = chain.Length();
795         EventTarget** targets = aTargets->AppendElements(numTargets);
796         for (uint32_t i = 0; i < numTargets; ++i) {
797           targets[i] = chain[i].CurrentTarget()->GetTargetForDOMEvent();
798         }
799       } else {
800         // Event target chain is created. PreHandle the chain.
801         for (uint32_t i = 0; i < chain.Length(); ++i) {
802           chain[i].PreHandleEvent(preVisitor);
803         }
804         // Handle the chain.
805         EventChainPostVisitor postVisitor(preVisitor);
806         MOZ_RELEASE_ASSERT(!aEvent->mPath);
807         aEvent->mPath = &chain;
808         EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
809                                                      aCallback, cd);
810         aEvent->mPath = nullptr;
811 
812         preVisitor.mEventStatus = postVisitor.mEventStatus;
813         // If the DOM event was created during event flow.
814         if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
815           preVisitor.mDOMEvent = postVisitor.mDOMEvent;
816         }
817       }
818     }
819   }
820 
821   // Note, EventTargetChainItem objects are deleted when the chain goes out of
822   // the scope.
823 
824   aEvent->mFlags.mIsBeingDispatched = false;
825   aEvent->mFlags.mDispatchedAtLeastOnce = true;
826 
827   // https://dom.spec.whatwg.org/#concept-event-dispatch
828   // Step 18
829   // "If target's root is a shadow root, then set event's target attribute and
830   //  event's relatedTarget to null."
831   nsCOMPtr<nsIContent> finalTarget = do_QueryInterface(aEvent->mTarget);
832   if (finalTarget && finalTarget->SubtreeRoot()->IsShadowRoot()) {
833     aEvent->mTarget = nullptr;
834     aEvent->mOriginalTarget = nullptr;
835     aEvent->mRelatedTarget = nullptr;
836     aEvent->mOriginalRelatedTarget = nullptr;
837   }
838 
839   if (!externalDOMEvent && preVisitor.mDOMEvent) {
840     // An dom::Event was created while dispatching the event.
841     // Duplicate private data if someone holds a pointer to it.
842     nsrefcnt rc = 0;
843     NS_RELEASE2(preVisitor.mDOMEvent, rc);
844     if (preVisitor.mDOMEvent) {
845       preVisitor.mDOMEvent->DuplicatePrivateData();
846     }
847   }
848 
849   if (aEventStatus) {
850     *aEventStatus = preVisitor.mEventStatus;
851   }
852 
853   if (cd.IsMainThread() && chain.Capacity() == 128 && sCachedMainThreadChain) {
854     chain.ClearAndRetainStorage();
855     chain.SwapElements(*sCachedMainThreadChain);
856   }
857 
858   return rv;
859 }
860 
DispatchDOMEvent(nsISupports * aTarget,WidgetEvent * aEvent,nsIDOMEvent * aDOMEvent,nsPresContext * aPresContext,nsEventStatus * aEventStatus)861 /* static */ nsresult EventDispatcher::DispatchDOMEvent(
862     nsISupports* aTarget, WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent,
863     nsPresContext* aPresContext, nsEventStatus* aEventStatus) {
864   if (aDOMEvent) {
865     WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr();
866     NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE);
867 
868     bool dontResetTrusted = false;
869     if (innerEvent->mFlags.mDispatchedAtLeastOnce) {
870       innerEvent->mTarget = nullptr;
871       innerEvent->mOriginalTarget = nullptr;
872     } else {
873       aDOMEvent->GetIsTrusted(&dontResetTrusted);
874     }
875 
876     if (!dontResetTrusted) {
877       // Check security state to determine if dispatcher is trusted
878       bool trusted = NS_IsMainThread()
879                          ? nsContentUtils::LegacyIsCallerChromeOrNativeCode()
880                          : IsCurrentThreadRunningChromeWorker();
881       aDOMEvent->SetTrusted(trusted);
882     }
883 
884     return EventDispatcher::Dispatch(aTarget, aPresContext, innerEvent,
885                                      aDOMEvent, aEventStatus);
886   } else if (aEvent) {
887     return EventDispatcher::Dispatch(aTarget, aPresContext, aEvent, aDOMEvent,
888                                      aEventStatus);
889   }
890   return NS_ERROR_ILLEGAL_VALUE;
891 }
892 
CreateEvent(EventTarget * aOwner,nsPresContext * aPresContext,WidgetEvent * aEvent,const nsAString & aEventType,CallerType aCallerType)893 /* static */ already_AddRefed<dom::Event> EventDispatcher::CreateEvent(
894     EventTarget* aOwner, nsPresContext* aPresContext, WidgetEvent* aEvent,
895     const nsAString& aEventType, CallerType aCallerType) {
896   if (aEvent) {
897     switch (aEvent->mClass) {
898       case eMutationEventClass:
899         return NS_NewDOMMutationEvent(aOwner, aPresContext,
900                                       aEvent->AsMutationEvent());
901       case eGUIEventClass:
902       case eScrollPortEventClass:
903       case eUIEventClass:
904         return NS_NewDOMUIEvent(aOwner, aPresContext, aEvent->AsGUIEvent());
905       case eScrollAreaEventClass:
906         return NS_NewDOMScrollAreaEvent(aOwner, aPresContext,
907                                         aEvent->AsScrollAreaEvent());
908       case eKeyboardEventClass:
909         return NS_NewDOMKeyboardEvent(aOwner, aPresContext,
910                                       aEvent->AsKeyboardEvent());
911       case eCompositionEventClass:
912         return NS_NewDOMCompositionEvent(aOwner, aPresContext,
913                                          aEvent->AsCompositionEvent());
914       case eMouseEventClass:
915         return NS_NewDOMMouseEvent(aOwner, aPresContext,
916                                    aEvent->AsMouseEvent());
917       case eFocusEventClass:
918         return NS_NewDOMFocusEvent(aOwner, aPresContext,
919                                    aEvent->AsFocusEvent());
920       case eMouseScrollEventClass:
921         return NS_NewDOMMouseScrollEvent(aOwner, aPresContext,
922                                          aEvent->AsMouseScrollEvent());
923       case eWheelEventClass:
924         return NS_NewDOMWheelEvent(aOwner, aPresContext,
925                                    aEvent->AsWheelEvent());
926       case eEditorInputEventClass:
927         return NS_NewDOMInputEvent(aOwner, aPresContext,
928                                    aEvent->AsEditorInputEvent());
929       case eDragEventClass:
930         return NS_NewDOMDragEvent(aOwner, aPresContext, aEvent->AsDragEvent());
931       case eClipboardEventClass:
932         return NS_NewDOMClipboardEvent(aOwner, aPresContext,
933                                        aEvent->AsClipboardEvent());
934       case eSMILTimeEventClass:
935         return NS_NewDOMTimeEvent(aOwner, aPresContext,
936                                   aEvent->AsSMILTimeEvent());
937       case eCommandEventClass:
938         return NS_NewDOMCommandEvent(aOwner, aPresContext,
939                                      aEvent->AsCommandEvent());
940       case eSimpleGestureEventClass:
941         return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext,
942                                            aEvent->AsSimpleGestureEvent());
943       case ePointerEventClass:
944         return NS_NewDOMPointerEvent(aOwner, aPresContext,
945                                      aEvent->AsPointerEvent());
946       case eTouchEventClass:
947         return NS_NewDOMTouchEvent(aOwner, aPresContext,
948                                    aEvent->AsTouchEvent());
949       case eTransitionEventClass:
950         return NS_NewDOMTransitionEvent(aOwner, aPresContext,
951                                         aEvent->AsTransitionEvent());
952       case eAnimationEventClass:
953         return NS_NewDOMAnimationEvent(aOwner, aPresContext,
954                                        aEvent->AsAnimationEvent());
955       default:
956         // For all other types of events, create a vanilla event object.
957         return NS_NewDOMEvent(aOwner, aPresContext, aEvent);
958     }
959   }
960 
961   // And if we didn't get an event, check the type argument.
962 
963   if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
964       aEventType.LowerCaseEqualsLiteral("mouseevents")) {
965     return NS_NewDOMMouseEvent(aOwner, aPresContext, nullptr);
966   }
967   if (aEventType.LowerCaseEqualsLiteral("mousescrollevents")) {
968     return NS_NewDOMMouseScrollEvent(aOwner, aPresContext, nullptr);
969   }
970   if (aEventType.LowerCaseEqualsLiteral("dragevent")) {
971     return NS_NewDOMDragEvent(aOwner, aPresContext, nullptr);
972   }
973   if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
974       aEventType.LowerCaseEqualsLiteral("keyevents")) {
975     return NS_NewDOMKeyboardEvent(aOwner, aPresContext, nullptr);
976   }
977   if (aEventType.LowerCaseEqualsLiteral("compositionevent") ||
978       aEventType.LowerCaseEqualsLiteral("textevent")) {
979     return NS_NewDOMCompositionEvent(aOwner, aPresContext, nullptr);
980   }
981   if (aEventType.LowerCaseEqualsLiteral("mutationevent") ||
982       aEventType.LowerCaseEqualsLiteral("mutationevents")) {
983     return NS_NewDOMMutationEvent(aOwner, aPresContext, nullptr);
984   }
985   if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent")) {
986     DeviceOrientationEventInit init;
987     RefPtr<Event> event =
988         DeviceOrientationEvent::Constructor(aOwner, EmptyString(), init);
989     event->MarkUninitialized();
990     return event.forget();
991   }
992   if (aEventType.LowerCaseEqualsLiteral("devicemotionevent")) {
993     return NS_NewDOMDeviceMotionEvent(aOwner, aPresContext, nullptr);
994   }
995   if (aEventType.LowerCaseEqualsLiteral("uievent") ||
996       aEventType.LowerCaseEqualsLiteral("uievents")) {
997     return NS_NewDOMUIEvent(aOwner, aPresContext, nullptr);
998   }
999   if (aEventType.LowerCaseEqualsLiteral("event") ||
1000       aEventType.LowerCaseEqualsLiteral("events") ||
1001       aEventType.LowerCaseEqualsLiteral("htmlevents") ||
1002       aEventType.LowerCaseEqualsLiteral("svgevents")) {
1003     return NS_NewDOMEvent(aOwner, aPresContext, nullptr);
1004   }
1005   if (aEventType.LowerCaseEqualsLiteral("timeevent")) {
1006     return NS_NewDOMTimeEvent(aOwner, aPresContext, nullptr);
1007   }
1008   if (aEventType.LowerCaseEqualsLiteral("messageevent")) {
1009     RefPtr<Event> event = new MessageEvent(aOwner, aPresContext, nullptr);
1010     return event.forget();
1011   }
1012   if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent")) {
1013     return NS_NewDOMBeforeUnloadEvent(aOwner, aPresContext, nullptr);
1014   }
1015   if (aEventType.LowerCaseEqualsLiteral("scrollareaevent")) {
1016     return NS_NewDOMScrollAreaEvent(aOwner, aPresContext, nullptr);
1017   }
1018   if (aEventType.LowerCaseEqualsLiteral("touchevent") &&
1019       TouchEvent::PrefEnabled(
1020           nsContentUtils::GetDocShellForEventTarget(aOwner))) {
1021     return NS_NewDOMTouchEvent(aOwner, aPresContext, nullptr);
1022   }
1023   if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) {
1024     HashChangeEventInit init;
1025     RefPtr<Event> event =
1026         HashChangeEvent::Constructor(aOwner, EmptyString(), init);
1027     event->MarkUninitialized();
1028     return event.forget();
1029   }
1030   if (aEventType.LowerCaseEqualsLiteral("customevent")) {
1031     return NS_NewDOMCustomEvent(aOwner, aPresContext, nullptr);
1032   }
1033   if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
1034     RefPtr<Event> event =
1035         StorageEvent::Constructor(aOwner, EmptyString(), StorageEventInit());
1036     event->MarkUninitialized();
1037     return event.forget();
1038   }
1039   if (aEventType.LowerCaseEqualsLiteral("focusevent")) {
1040     RefPtr<Event> event = NS_NewDOMFocusEvent(aOwner, aPresContext, nullptr);
1041     event->MarkUninitialized();
1042     return event.forget();
1043   }
1044 
1045   // Only allow these events for chrome
1046   if (aCallerType == CallerType::System) {
1047     if (aEventType.LowerCaseEqualsLiteral("simplegestureevent")) {
1048       return NS_NewDOMSimpleGestureEvent(aOwner, aPresContext, nullptr);
1049     }
1050     if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
1051         aEventType.LowerCaseEqualsLiteral("xulcommandevents")) {
1052       return NS_NewDOMXULCommandEvent(aOwner, aPresContext, nullptr);
1053     }
1054   }
1055 
1056   // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT
1057   // CONSTRUCTORS
1058 
1059   return nullptr;
1060 }
1061 
1062 // static
GetComposedPathFor(WidgetEvent * aEvent,nsTArray<RefPtr<EventTarget>> & aPath)1063 void EventDispatcher::GetComposedPathFor(WidgetEvent* aEvent,
1064                                          nsTArray<RefPtr<EventTarget>>& aPath) {
1065   nsTArray<EventTargetChainItem>* path = aEvent->mPath;
1066   if (!path || path->IsEmpty() || !aEvent->mCurrentTarget) {
1067     return;
1068   }
1069 
1070   EventTarget* currentTarget =
1071       aEvent->mCurrentTarget->GetTargetForEventTargetChain();
1072   if (!currentTarget) {
1073     return;
1074   }
1075 
1076   AutoTArray<EventTarget*, 128> reversedComposedPath;
1077   bool hasSeenCurrentTarget = false;
1078   uint32_t hiddenSubtreeLevel = 0;
1079   for (uint32_t i = path->Length(); i;) {
1080     --i;
1081 
1082     EventTargetChainItem& item = path->ElementAt(i);
1083     if (item.PreHandleEventOnly()) {
1084       continue;
1085     }
1086 
1087     if (!hasSeenCurrentTarget && currentTarget == item.CurrentTarget()) {
1088       hasSeenCurrentTarget = true;
1089     } else if (hasSeenCurrentTarget && item.IsRootOfClosedTree()) {
1090       ++hiddenSubtreeLevel;
1091     }
1092 
1093     if (hiddenSubtreeLevel == 0) {
1094       reversedComposedPath.AppendElement(item.CurrentTarget());
1095     }
1096 
1097     if (item.IsSlotInClosedTree() && hiddenSubtreeLevel > 0) {
1098       --hiddenSubtreeLevel;
1099     }
1100 
1101     if (item.IsChromeHandler()) {
1102       if (hasSeenCurrentTarget) {
1103         // The current behavior is to include only EventTargets from
1104         // either chrome side of event path or content side, not from both.
1105         break;
1106       }
1107 
1108       // Need to start all over to collect the composed path on content side.
1109       reversedComposedPath.Clear();
1110     }
1111   }
1112 
1113   aPath.SetCapacity(reversedComposedPath.Length());
1114   for (uint32_t i = reversedComposedPath.Length(); i;) {
1115     --i;
1116     aPath.AppendElement(reversedComposedPath[i]->GetTargetForDOMEvent());
1117   }
1118 }
1119 
1120 }  // namespace mozilla
1121