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