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