Backed out changeset 2320b7fd9266 (bug 1413102) for Mochitest failure on dom/tests/mochitest/pointerlock/test_pointerlock-api.html
authorDorel Luca <dluca@mozilla.com>
Wed, 14 Feb 2018 20:44:19 +0200
changeset 458867 56c8882ff0b26e1a5025033f8c1ec61eb843afce
parent 458866 532bca04e4090f2e9cfd9bb952a4e84979d3079e
child 458868 9dd1395b937eeafce2888c4d502e512fa38549d2
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1413102
milestone60.0a1
backs out2320b7fd9266924ccd4ca51c6f0f43183482d9b3
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 2320b7fd9266 (bug 1413102) for Mochitest failure on dom/tests/mochitest/pointerlock/test_pointerlock-api.html
dom/base/FragmentOrElement.cpp
dom/base/ShadowRoot.cpp
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/events/Event.cpp
dom/events/Event.h
dom/events/EventDispatcher.cpp
dom/events/EventDispatcher.h
testing/web-platform/meta/shadow-dom/event-composed-path-with-related-target.html.ini
testing/web-platform/meta/shadow-dom/event-post-dispatch.html.ini
testing/web-platform/meta/shadow-dom/event-with-related-target.html.ini
testing/web-platform/meta/shadow-dom/untriaged/events/retargeting-relatedtarget/test-001.html.ini
testing/web-platform/meta/shadow-dom/untriaged/events/retargeting-relatedtarget/test-002.html.ini
widget/BasicEvents.h
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -912,32 +912,16 @@ FindChromeAccessOnlySubtreeOwner(nsICont
     while (aContent && !chromeAccessOnly) {
       chromeAccessOnly = aContent->IsRootOfChromeAccessOnlySubtree();
       aContent = aContent->GetParent();
     }
   }
   return aContent;
 }
 
-already_AddRefed<nsINode>
-FindChromeAccessOnlySubtreeOwner(EventTarget* aTarget)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
-  if (!node || !node->ChromeOnlyAccess()) {
-    return node.forget();
-  }
-
-  if (!node->IsContent()) {
-    return nullptr;
-  }
-
-  node = FindChromeAccessOnlySubtreeOwner(node->AsContent());
-  return node.forget();
-}
-
 nsresult
 nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = true;
   aVisitor.mMayHaveListenerManager = HasListenerManager();
 
   // Don't propagate mouseover and mouseout events when mouse is moving
@@ -948,22 +932,34 @@ nsIContent::GetEventTargetParent(EventCh
        aVisitor.mEvent->mMessage == eMouseOut ||
        aVisitor.mEvent->mMessage == ePointerOver ||
        aVisitor.mEvent->mMessage == ePointerOut) &&
       // Check if we should stop event propagation when event has just been
       // dispatched or when we're about to propagate from
       // chrome access only subtree or if we are about to propagate out of
       // a shadow root to a shadow root host.
       ((this == aVisitor.mEvent->mOriginalTarget &&
-        !ChromeOnlyAccess()) || isAnonForEvents)) {
+        !ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
      nsCOMPtr<nsIContent> relatedTarget =
        do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
     if (relatedTarget &&
         relatedTarget->OwnerDoc() == OwnerDoc()) {
 
+      // In the web components case, we may need to stop propagation of events
+      // at shadow root host.
+      if (GetShadowRoot()) {
+        nsIContent* adjustedTarget =
+          Event::GetShadowRelatedTarget(this, relatedTarget);
+        if (this == adjustedTarget) {
+          aVisitor.SetParentTarget(nullptr, false);
+          aVisitor.mCanHandle = false;
+          return NS_OK;
+        }
+      }
+
       // If current target is anonymous for events or we know that related
       // target is descendant of an element which is anonymous for events,
       // we may want to stop event propagation.
       // If this is the original target, aVisitor.mRelatedTargetIsInAnon
       // must be updated.
       if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon ||
           (aVisitor.mEvent->mOriginalTarget == this &&
            (aVisitor.mRelatedTargetIsInAnon =
@@ -1069,114 +1065,16 @@ nsIContent::GetEventTargetParent(EventCh
       ShadowRoot* root = slot->GetContainingShadow();
       if (root && root->IsClosed()) {
         aVisitor.mParentIsSlotInClosedTree = true;
       }
     }
   } else {
     aVisitor.SetParentTarget(GetComposedDoc(), false);
   }
-
-  if (!ChromeOnlyAccess() && !aVisitor.mRelatedTargetRetargetedInCurrentScope) {
-    // We don't support Shadow DOM in native anonymous content yet.
-    aVisitor.mRelatedTargetRetargetedInCurrentScope = true;
-    if (aVisitor.mEvent->mOriginalRelatedTarget) {
-      // https://dom.spec.whatwg.org/#concept-event-dispatch
-      // Step 3.
-      // "Let relatedTarget be the result of retargeting event's relatedTarget
-      //  against target if event's relatedTarget is non-null, and null
-      //  otherwise."
-      //
-      // This is a bit complicated because the event might be from native
-      // anonymous content, but we need to deal with non-native anonymous
-      // content there.
-      bool initialTarget = this == aVisitor.mEvent->mOriginalTarget;
-      nsCOMPtr<nsINode> originalTargetAsNode;
-      // Use of mOriginalTargetIsInAnon is an optimization here.
-      if (!initialTarget && aVisitor.mOriginalTargetIsInAnon) {
-        originalTargetAsNode =
-          FindChromeAccessOnlySubtreeOwner(aVisitor.mEvent->mOriginalTarget);
-        initialTarget = originalTargetAsNode == this;
-      }
-      if (initialTarget) {
-        nsCOMPtr<nsINode> relatedTargetAsNode =
-          FindChromeAccessOnlySubtreeOwner(aVisitor.mEvent->mOriginalRelatedTarget);
-        if (!originalTargetAsNode) {
-          originalTargetAsNode =
-            do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
-        }
-
-        if (relatedTargetAsNode && originalTargetAsNode) {
-          nsINode* retargetedRelatedTarget =
-            nsContentUtils::Retarget(relatedTargetAsNode, originalTargetAsNode);
-          if (originalTargetAsNode == retargetedRelatedTarget &&
-              retargetedRelatedTarget != relatedTargetAsNode) {
-            // Step 4.
-            // "If target is relatedTarget and target is not event's
-            //  relatedTarget, then return true."
-            aVisitor.IgnoreCurrentTarget();
-            // Old code relies on mTarget to point to the first element which
-            // was not added to the event target chain because of mCanHandle
-            // being false, but in Shadow DOM case mTarget really should
-            // point to a node in Shadow DOM.
-            aVisitor.mEvent->mTarget = aVisitor.mTargetInKnownToBeHandledScope;
-            return NS_OK;
-          }
-
-          // Part of step 5. Retargeting target has happened already higher
-          // up in this method.
-          // "Append to an event path with event, target, targetOverride,
-          //  relatedTarget, and false."
-          aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
-        }
-      } else {
-        nsCOMPtr<nsINode> relatedTargetAsNode =
-          FindChromeAccessOnlySubtreeOwner(aVisitor.mEvent->mOriginalRelatedTarget);
-        if (relatedTargetAsNode) {
-          // Step 11.3.
-          // "Let relatedTarget be the result of retargeting event's
-          // relatedTarget against parent if event's relatedTarget is non-null,
-          // and null otherwise.".
-          nsINode* retargetedRelatedTarget =
-            nsContentUtils::Retarget(relatedTargetAsNode, this);
-          nsCOMPtr<nsINode> targetInKnownToBeHandledScope =
-            FindChromeAccessOnlySubtreeOwner(aVisitor.mTargetInKnownToBeHandledScope);
-          if (nsContentUtils::ContentIsShadowIncludingDescendantOf(
-                this, targetInKnownToBeHandledScope->SubtreeRoot())) {
-            // Part of step 11.4.
-            // "If target's root is a shadow-including inclusive ancestor of
-            //  parent, then"
-            // "...Append to an event path with event, parent, null, relatedTarget,
-            // "   and slot-in-closed-tree."
-            aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
-          } else if (this == retargetedRelatedTarget) {
-            // Step 11.5
-            // "Otherwise, if parent and relatedTarget are identical, then set
-            //  parent to null."
-            aVisitor.IgnoreCurrentTarget();
-            // Old code relies on mTarget to point to the first element which
-            // was not added to the event target chain because of mCanHandle
-            // being false, but in Shadow DOM case mTarget really should
-            // point to a node in Shadow DOM.
-            aVisitor.mEvent->mTarget = aVisitor.mTargetInKnownToBeHandledScope;
-            return NS_OK;
-          } else {
-            // Step 11.6
-            aVisitor.mRetargetedRelatedTarget = retargetedRelatedTarget;
-          }
-        }
-      }
-    }
-  }
-
-  if (slot) {
-    // Inform that we're about to exit the current scope.
-    aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
-  }
-
   return NS_OK;
 }
 
 bool
 nsIContent::IsFocusable(int32_t* aTabIndex, bool aWithMouse)
 {
   bool focusable = IsFocusableInternal(aTabIndex, aWithMouse);
   // Ensure that the return value and aTabIndex are consistent in the case
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -296,18 +296,16 @@ ShadowRoot::RemoveFromIdTable(Element* a
   }
 }
 
 nsresult
 ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   aVisitor.mRootOfClosedTree = IsClosed();
-  // Inform that we're about to exit the current scope.
-  aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
 
   // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
   if (!aVisitor.mEvent->mFlags.mComposed) {
     nsCOMPtr<nsIContent> originalTarget =
       do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
     if (originalTarget->GetContainingShadow() == this) {
       // If we do stop propagation, we still want to propagate
       // the event to chrome (nsPIDOMWindow::GetParentTarget()).
@@ -320,20 +318,22 @@ ShadowRoot::GetEventTargetParent(EventCh
       aVisitor.SetParentTarget(parentTarget, true);
       return NS_OK;
     }
   }
 
   nsIContent* shadowHost = GetHost();
   aVisitor.SetParentTarget(shadowHost, false);
 
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
-  if (content && content->GetBindingParent() == shadowHost) {
-    aVisitor.mEventTargetAtParent = shadowHost;
-  }
+  if (aVisitor.mOriginalTargetIsInAnon) {
+    nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
+    if (content && content->GetBindingParent() == shadowHost) {
+      aVisitor.mEventTargetAtParent = shadowHost;
+    }
+ }
 
   return NS_OK;
 }
 
 const HTMLSlotElement*
 ShadowRoot::AssignSlotFor(nsIContent* aContent)
 {
   nsAutoString slotName;
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -2553,44 +2553,16 @@ nsContentUtils::ContentIsHostIncludingDe
     } else {
       aPossibleDescendant = aPossibleDescendant->GetParentNode();
     }
   } while (aPossibleDescendant);
 
   return false;
 }
 
-bool
-nsContentUtils::ContentIsShadowIncludingDescendantOf(
-  const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor)
-{
-  MOZ_ASSERT(aPossibleDescendant, "The possible descendant is null!");
-  MOZ_ASSERT(aPossibleAncestor, "The possible ancestor is null!");
-
-  if (aPossibleAncestor == aPossibleDescendant->GetComposedDoc()) {
-    return true;
-  }
-
-  do {
-    if (aPossibleDescendant == aPossibleAncestor) {
-      return true;
-    }
-
-    if (aPossibleDescendant->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE) {
-      ShadowRoot* shadowRoot =
-        ShadowRoot::FromNode(const_cast<nsINode*>(aPossibleDescendant));
-      aPossibleDescendant = shadowRoot ? shadowRoot->GetHost() : nullptr;
-    } else {
-      aPossibleDescendant = aPossibleDescendant->GetParentNode();
-    }
-  } while (aPossibleDescendant);
-
-  return false;
-}
-
 // static
 bool
 nsContentUtils::ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
                                               nsINode* aPossibleAncestor)
 {
   NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
   NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
 
@@ -2639,40 +2611,16 @@ nsContentUtils::ContentIsFlattenedTreeDe
     aPossibleDescendant =
       aPossibleDescendant->GetFlattenedTreeParentNodeForStyle();
   } while (aPossibleDescendant);
 
   return false;
 }
 
 // static
-nsINode*
-nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB)
-{
-  while (true && aTargetA) {
-    // If A's root is not a shadow root...
-    nsINode* root = aTargetA->SubtreeRoot();
-    if (!root->IsShadowRoot()) {
-      // ...then return A.
-      return aTargetA;
-    }
-
-    // or A's root is a shadow-including inclusive ancestor of B...
-    if (nsContentUtils::ContentIsShadowIncludingDescendantOf(aTargetB, root)) {
-      // ...then return A.
-      return aTargetA;
-    }
-
-    aTargetA = ShadowRoot::FromNode(root)->GetHost();
-  }
-
-  return nullptr;
-}
-
-// static
 nsresult
 nsContentUtils::GetAncestors(nsINode* aNode,
                              nsTArray<nsINode*>& aArray)
 {
   while (aNode) {
     aArray.AppendElement(aNode);
     aNode = aNode->GetParentNode();
   }
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -324,23 +324,16 @@ public:
    * or ShadowRoot as an ancestor of things in the corresponding DocumentFragment.
    * See the concept of "host-including inclusive ancestor" in the DOM
    * specification.
    */
   static bool ContentIsHostIncludingDescendantOf(
     const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
 
   /**
-   * Similar to above, but does special case only ShadowRoot,
-   * not HTMLTemplateElement.
-   */
-  static bool ContentIsShadowIncludingDescendantOf(
-    const nsINode* aPossibleDescendant, const nsINode* aPossibleAncestor);
-
-  /**
    * Similar to ContentIsDescendantOf except it crosses document boundaries,
    * this function uses ancestor/descendant relations in the composed document
    * (see shadow DOM spec).
    */
   static bool ContentIsCrossDocDescendantOf(nsINode* aPossibleDescendant,
                                               nsINode* aPossibleAncestor);
 
   /**
@@ -358,23 +351,16 @@ public:
    * point of view of the style system
    *
    * @see nsINode::GetFlattenedTreeParentNodeForStyle()
    */
   static bool
   ContentIsFlattenedTreeDescendantOfForStyle(const nsINode* aPossibleDescendant,
                                              const nsINode* aPossibleAncestor);
 
-  /**
-   * Retarget an object A against an object B
-   * @see https://dom.spec.whatwg.org/#retarget
-   */
-  static nsINode*
-  Retarget(nsINode* aTargetA, nsINode* aTargetB);
-
   /*
    * This method fills the |aArray| with all ancestor nodes of |aNode|
    * including |aNode| at the zero index.
    */
   static nsresult GetAncestors(nsINode* aNode,
                                nsTArray<nsINode*>& aArray);
 
   /*
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -149,17 +149,16 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Eve
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
   if (tmp->mEventIsInternal) {
     tmp->mEvent->mTarget = nullptr;
     tmp->mEvent->mCurrentTarget = nullptr;
     tmp->mEvent->mOriginalTarget = nullptr;
     tmp->mEvent->mRelatedTarget = nullptr;
-    tmp->mEvent->mOriginalRelatedTarget = nullptr;
     switch (tmp->mEvent->mClass) {
       case eDragEventClass: {
         WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
         dragEvent->mDataTransfer = nullptr;
         break;
       }
       case eClipboardEventClass:
         tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
@@ -178,17 +177,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Ev
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
   if (tmp->mEventIsInternal) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
     switch (tmp->mEvent->mClass) {
       case eDragEventClass: {
         WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
         cb.NoteXPCOMChild(dragEvent->mDataTransfer);
         break;
       }
       case eClipboardEventClass:
@@ -540,23 +538,31 @@ Event::SetEventType(const nsAString& aEv
 }
 
 already_AddRefed<EventTarget>
 Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
 {
   nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
   if (relatedTarget) {
     nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
+    nsCOMPtr<nsIContent> currentTarget =
+      do_QueryInterface(mEvent->mCurrentTarget);
 
     if (content && content->ChromeOnlyAccess() &&
         !nsContentUtils::CanAccessNativeAnon()) {
       content = content->FindFirstNonChromeOnlyAccessContent();
       relatedTarget = do_QueryInterface(content);
     }
 
+    nsIContent* shadowRelatedTarget =
+      GetShadowRelatedTarget(currentTarget, content);
+    if (shadowRelatedTarget) {
+      relatedTarget = shadowRelatedTarget;
+    }
+
     if (relatedTarget) {
       relatedTarget = relatedTarget->GetTargetForDOMEvent();
     }
   }
   return relatedTarget.forget();
 }
 
 void
@@ -1207,16 +1213,54 @@ Event::SetOwner(EventTarget* aOwner)
   }
 
 #ifdef DEBUG
   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
   MOZ_ASSERT(root, "Unexpected EventTarget!");
 #endif
 }
 
+// static
+nsIContent*
+Event::GetShadowRelatedTarget(nsIContent* aCurrentTarget,
+                              nsIContent* aRelatedTarget)
+{
+  if (!aCurrentTarget || !aRelatedTarget) {
+    return nullptr;
+  }
+
+  // Walk up the ancestor node trees of the related target until
+  // we encounter the node tree of the current target in order
+  // to find the adjusted related target. Walking up the tree may
+  // not find a common ancestor node tree if the related target is in
+  // an ancestor tree, but in that case it does not need to be adjusted.
+  ShadowRoot* currentTargetShadow = aCurrentTarget->GetContainingShadow();
+  if (!currentTargetShadow) {
+    return nullptr;
+  }
+
+  nsIContent* relatedTarget = aCurrentTarget;
+  while (relatedTarget) {
+    ShadowRoot* ancestorShadow = relatedTarget->GetContainingShadow();
+    if (currentTargetShadow == ancestorShadow) {
+      return relatedTarget;
+    }
+
+    // Didn't find the ancestor tree, thus related target does not have to
+    // adjusted.
+    if (!ancestorShadow) {
+      return nullptr;
+    }
+
+    relatedTarget = ancestorShadow->GetHost();
+  }
+
+  return nullptr;
+}
+
 void
 Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType)
 {
   if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
     aType = aEvent->mSpecifiedEventTypeString;
     return;
   }
 
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -262,16 +262,24 @@ public:
   void PreventDefaultInternal(bool aCalledByDefaultHandler,
                               nsIPrincipal* aPrincipal = nullptr);
 
   bool IsMainThreadEvent()
   {
     return mIsMainThreadEvent;
   }
 
+  /**
+   * For a given current target, returns the related target adjusted with
+   * shadow DOM retargeting rules. Returns nullptr if related target
+   * is not adjusted.
+   */
+  static nsIContent* GetShadowRelatedTarget(nsIContent* aCurrentTarget,
+                                            nsIContent* aRelatedTarget);
+
   void MarkUninitialized()
   {
     mEvent->mMessage = eVoidEvent;
     mEvent->mSpecifiedEventTypeString.Truncate();
     mEvent->mSpecifiedEventType = nullptr;
   }
 
   /**
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -195,26 +195,16 @@ public:
     return mNewTarget;
   }
 
   void SetNewTarget(EventTarget* aNewTarget)
   {
     mNewTarget = aNewTarget;
   }
 
-  EventTarget* GetRetargetedRelatedTarget()
-  {
-    return mRetargetedRelatedTarget;
-  }
-
-  void SetRetargetedRelatedTarget(EventTarget* aTarget)
-  {
-    mRetargetedRelatedTarget = aTarget;
-  }
-
   void SetForceContentDispatch(bool aForce)
   {
     mFlags.mForceContentDispatch = aForce;
   }
 
   bool ForceContentDispatch()
   {
     return mFlags.mForceContentDispatch;
@@ -355,17 +345,16 @@ public:
 
   /**
    * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
    */
   void PostHandleEvent(EventChainPostVisitor& aVisitor);
 
 private:
   nsCOMPtr<EventTarget>             mTarget;
-  nsCOMPtr<EventTarget>             mRetargetedRelatedTarget;
 
   class EventTargetChainFlags
   {
   public:
     explicit EventTargetChainFlags()
     {
       SetRawFlags(0);
     }
@@ -424,17 +413,16 @@ EventTargetChainItem::GetEventTargetPare
   aVisitor.Reset();
   Unused << mTarget->GetEventTargetParent(aVisitor);
   SetForceContentDispatch(aVisitor.mForceContentDispatch);
   SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
   SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
   SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
   SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
   SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
-  SetRetargetedRelatedTarget(aVisitor.mRetargetedRelatedTarget);
   mItemFlags = aVisitor.mItemFlags;
   mItemData = aVisitor.mItemData;
 }
 
 void
 EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor)
 {
   if (!WantsPreHandleEvent()) {
@@ -457,17 +445,16 @@ void
 EventTargetChainItem::HandleEventTargetChain(
                         nsTArray<EventTargetChainItem>& aChain,
                         EventChainPostVisitor& aVisitor,
                         EventDispatchingCallback* aCallback,
                         ELMCreationDetector& aCd)
 {
   // Save the target so that it can be restored later.
   nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
-  nsCOMPtr<EventTarget> firstRelatedTarget = aVisitor.mEvent->mRelatedTarget;
   uint32_t chainLength = aChain.Length();
   uint32_t firstCanHandleEventTargetIdx =
     EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
 
   // Capture
   aVisitor.mEvent->mFlags.mInCapturePhase = true;
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
   for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
@@ -487,40 +474,16 @@ EventTargetChainItem::HandleEventTargetC
         uint32_t childIndex = j - 1;
         EventTarget* newTarget = aChain[childIndex].GetNewTarget();
         if (newTarget) {
           aVisitor.mEvent->mTarget = newTarget;
           break;
         }
       }
     }
-
-    // https://dom.spec.whatwg.org/#dispatching-events
-    // Step 14.2
-    // "Set event's relatedTarget to tuple's relatedTarget."
-    // Note, the initial retargeting was done already when creating
-    // event target chain, so we need to do this only after calling
-    // HandleEvent, not before, like in the specification.
-    if (item.GetRetargetedRelatedTarget()) {
-      bool found = false;
-      for (uint32_t j = i; j > 0; --j) {
-        uint32_t childIndex = j - 1;
-        EventTarget* relatedTarget =
-          aChain[childIndex].GetRetargetedRelatedTarget();
-        if (relatedTarget) {
-          found = true;
-          aVisitor.mEvent->mRelatedTarget = relatedTarget;
-          break;
-        }
-      }
-      if (!found) {
-        aVisitor.mEvent->mRelatedTarget =
-          aVisitor.mEvent->mOriginalRelatedTarget;
-      }
-    }
   }
 
   // Target
   aVisitor.mEvent->mFlags.mInBubblingPhase = true;
   EventTargetChainItem& targetItem = aChain[firstCanHandleEventTargetIdx];
   if (!aVisitor.mEvent->PropagationStopped() &&
       (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
        targetItem.ForceContentDispatch())) {
@@ -539,24 +502,16 @@ EventTargetChainItem::HandleEventTargetC
     }
     EventTarget* newTarget = item.GetNewTarget();
     if (newTarget) {
       // Item is at anonymous boundary. Need to retarget for the current item
       // and for parent items.
       aVisitor.mEvent->mTarget = newTarget;
     }
 
-    // https://dom.spec.whatwg.org/#dispatching-events
-    // Step 15.2
-    // "Set event's relatedTarget to tuple's relatedTarget."
-    EventTarget* relatedTarget = item.GetRetargetedRelatedTarget();
-    if (relatedTarget) {
-      aVisitor.mEvent->mRelatedTarget = relatedTarget;
-    }
-
     if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
       if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
            item.ForceContentDispatch()) &&
           !aVisitor.mEvent->PropagationStopped()) {
         item.HandleEvent(aVisitor, aCd);
       }
       if (aVisitor.mEvent->mFlags.mInSystemGroup) {
         item.PostHandleEvent(aVisitor);
@@ -569,28 +524,26 @@ EventTargetChainItem::HandleEventTargetC
       aVisitor.mEvent->IsAllowedToDispatchInSystemGroup()) {
     // Dispatch to the system event group.  Make sure to clear the
     // STOP_DISPATCH flag since this resets for each event group.
     aVisitor.mEvent->mFlags.mPropagationStopped = false;
     aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
 
     // Setting back the original target of the event.
     aVisitor.mEvent->mTarget = aVisitor.mEvent->mOriginalTarget;
-    aVisitor.mEvent->mRelatedTarget = aVisitor.mEvent->mOriginalRelatedTarget;
 
     // Special handling if PresShell (or some other caller)
     // used a callback object.
     if (aCallback) {
       aCallback->HandleEvent(aVisitor);
     }
 
     // Retarget for system event group (which does the default handling too).
     // Setting back the target which was used also for default event group.
     aVisitor.mEvent->mTarget = firstTarget;
-    aVisitor.mEvent->mRelatedTarget = firstRelatedTarget;
     aVisitor.mEvent->mFlags.mInSystemGroup = true;
     HandleEventTargetChain(aChain,
                            aVisitor,
                            aCallback,
                            aCd);
     aVisitor.mEvent->mFlags.mInSystemGroup = false;
 
     // After dispatch, clear all the propagation flags so that
@@ -638,17 +591,16 @@ MayRetargetToChromeIfCanNotHandleEvent(
   EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
   nsINode* aContent)
 {
   if (!aPreVisitor.mWantsPreHandleEvent) {
     // Keep EventTargetChainItem if we need to call PreHandleEvent on it.
     EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
   }
   if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
-    aPreVisitor.mRelatedTargetRetargetedInCurrentScope = false;
     // Event target couldn't handle the event. Try to propagate to chrome.
     EventTargetChainItem* chromeTargetEtci =
       EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
     if (chromeTargetEtci) {
       chromeTargetEtci->GetEventTargetParent(aPreVisitor);
       return chromeTargetEtci;
     }
   }
@@ -810,28 +762,27 @@ EventDispatcher::Dispatch(nsISupports* a
     aEvent->mOriginalTarget =
       aEvent->mOriginalTarget->GetTargetForEventTargetChain();
     NS_ENSURE_STATE(aEvent->mOriginalTarget);
   }
   else {
     aEvent->mOriginalTarget = aEvent->mTarget;
   }
 
-  aEvent->mOriginalRelatedTarget = aEvent->mRelatedTarget;
-
   nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mOriginalTarget);
-  bool isInAnon = content && content->IsInAnonymousSubtree();
+  bool isInAnon = (content && (content->IsInAnonymousSubtree() ||
+                               content->IsInShadowTree()));
 
   aEvent->mFlags.mIsBeingDispatched = true;
 
   // Create visitor object and start event dispatching.
   // GetEventTargetParent for the original target.
   nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
   EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
-                                  isInAnon, aEvent->mTarget);
+                                  isInAnon);
   targetEtci->GetEventTargetParent(preVisitor);
 
   if (!preVisitor.mCanHandle) {
     targetEtci = MayRetargetToChromeIfCanNotHandleEvent(chain, preVisitor,
                                                         targetEtci, nullptr,
                                                         content);
   }
   if (!preVisitor.mCanHandle) {
@@ -859,38 +810,31 @@ EventDispatcher::Dispatch(nsISupports* a
 
       parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
       parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
 
       // Item needs event retargetting.
       if (preVisitor.mEventTargetAtParent) {
         // Need to set the target of the event
         // so that also the next retargeting works.
-        preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
         preVisitor.mEvent->mTarget = preVisitor.mEventTargetAtParent;
         parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
       }
 
-      if (preVisitor.mRetargetedRelatedTarget) {
-        preVisitor.mEvent->mRelatedTarget = preVisitor.mRetargetedRelatedTarget;
-      }
-
       parentEtci->GetEventTargetParent(preVisitor);
       if (preVisitor.mCanHandle) {
-        preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
         topEtci = parentEtci;
       } else {
         nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
         parentEtci = MayRetargetToChromeIfCanNotHandleEvent(chain,
                                                             preVisitor,
                                                             parentEtci,
                                                             topEtci,
                                                             disabledTarget);
         if (parentEtci && preVisitor.mCanHandle) {
-          preVisitor.mTargetInKnownToBeHandledScope = preVisitor.mEvent->mTarget;
           EventTargetChainItem* item =
             EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
           item->SetNewTarget(parentTarget);
           topEtci = parentEtci;
           continue;
         }
         break;
       }
@@ -926,28 +870,16 @@ EventDispatcher::Dispatch(nsISupports* a
   }
 
   // Note, EventTargetChainItem objects are deleted when the chain goes out of
   // the scope.
 
   aEvent->mFlags.mIsBeingDispatched = false;
   aEvent->mFlags.mDispatchedAtLeastOnce = true;
 
-  // https://dom.spec.whatwg.org/#concept-event-dispatch
-  // Step 18
-  // "If target's root is a shadow root, then set event's target attribute and
-  //  event's relatedTarget to null."
-  nsCOMPtr<nsIContent> finalTarget = do_QueryInterface(aEvent->mTarget);
-  if (finalTarget && finalTarget->SubtreeRoot()->IsShadowRoot()) {
-    aEvent->mTarget = nullptr;
-    aEvent->mOriginalTarget = nullptr;
-    aEvent->mRelatedTarget = nullptr;
-    aEvent->mOriginalRelatedTarget = nullptr;
-  }
-
   if (!externalDOMEvent && preVisitor.mDOMEvent) {
     // An dom::Event was created while dispatching the event.
     // Duplicate private data if someone holds a pointer to it.
     nsrefcnt rc = 0;
     NS_RELEASE2(preVisitor.mDOMEvent, rc);
     if (preVisitor.mDOMEvent) {
       preVisitor.mDOMEvent->DuplicatePrivateData();
     }
--- a/dom/events/EventDispatcher.h
+++ b/dom/events/EventDispatcher.h
@@ -110,79 +110,64 @@ public:
 
 class EventChainPreVisitor : public EventChainVisitor
 {
 public:
   EventChainPreVisitor(nsPresContext* aPresContext,
                        WidgetEvent* aEvent,
                        nsIDOMEvent* aDOMEvent,
                        nsEventStatus aEventStatus,
-                       bool aIsInAnon,
-                       dom::EventTarget* aTargetInKnownToBeHandledScope)
+                       bool aIsInAnon)
     : EventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus)
     , mCanHandle(true)
     , mAutomaticChromeDispatch(true)
     , mForceContentDispatch(false)
     , mRelatedTargetIsInAnon(false)
     , mOriginalTargetIsInAnon(aIsInAnon)
     , mWantsWillHandleEvent(false)
     , mMayHaveListenerManager(true)
     , mWantsPreHandleEvent(false)
     , mRootOfClosedTree(false)
     , mParentIsSlotInClosedTree(false)
     , mParentIsChromeHandler(false)
-    , mRelatedTargetRetargetedInCurrentScope(false)
     , mParentTarget(nullptr)
     , mEventTargetAtParent(nullptr)
-    , mRetargetedRelatedTarget(nullptr)
-    , mTargetInKnownToBeHandledScope(aTargetInKnownToBeHandledScope)
   {
   }
 
   void Reset()
   {
     mItemFlags = 0;
     mItemData = nullptr;
     mCanHandle = true;
     mAutomaticChromeDispatch = true;
     mForceContentDispatch = false;
     mWantsWillHandleEvent = false;
     mMayHaveListenerManager = true;
     mWantsPreHandleEvent = false;
     mRootOfClosedTree = false;
     mParentIsSlotInClosedTree = false;
     mParentIsChromeHandler = false;
-    // Note, we don't clear mRelatedTargetRetargetedInCurrentScope explicitly,
-    // since it is used during event path creation to indicate whether
-    // relatedTarget may need to be retargeted.
     mParentTarget = nullptr;
     mEventTargetAtParent = nullptr;
-    mRetargetedRelatedTarget = nullptr;
   }
 
   dom::EventTarget* GetParentTarget()
   {
     return mParentTarget;
   }
 
   void SetParentTarget(dom::EventTarget* aParentTarget, bool aIsChromeHandler)
   {
     mParentTarget = aParentTarget;
     if (mParentTarget) {
       mParentIsChromeHandler = aIsChromeHandler;
     }
   }
 
-  void IgnoreCurrentTarget()
-  {
-    mCanHandle = false;
-    SetParentTarget(nullptr, false);
-    mEventTargetAtParent = nullptr;
-  }
-
   /**
    * Member that must be set in GetEventTargetParent by event targets. If set to
    * false, indicates that this event target will not be handling the event and
    * construction of the event target chain is complete. The target that sets
    * mCanHandle to false is NOT included in the event target chain.
    */
   bool                  mCanHandle;
 
@@ -241,47 +226,28 @@ public:
    */
   bool mParentIsSlotInClosedTree;
 
   /**
    * True if mParentTarget is a chrome handler in the event path.
    */
   bool mParentIsChromeHandler;
 
-  /**
-   * True if event's related target has been already retargeted in the
-   * current 'scope'. This should be set to false initially and whenever
-   * event path creation crosses shadow boundary.
-   */
-  bool mRelatedTargetRetargetedInCurrentScope;
 private:
   /**
    * Parent item in the event target chain.
    */
   dom::EventTarget* mParentTarget;
 
 public:
   /**
    * If the event needs to be retargeted, this is the event target,
    * which should be used when the event is handled at mParentTarget.
    */
   dom::EventTarget* mEventTargetAtParent;
-
-  /**
-   * If the related target of the event needs to be retargeted, set this
-   * to a new EventTarget.
-   */
-  dom::EventTarget* mRetargetedRelatedTarget;
-
-  /**
-   * Set to the value of mEvent->mTarget of the previous scope in case of
-   * Shadow DOM or such, and if there is no anonymous content this just points
-   * to the initial target.
-   */
-  dom::EventTarget* mTargetInKnownToBeHandledScope;
 };
 
 class EventChainPostVisitor : public mozilla::EventChainVisitor
 {
 public:
   explicit EventChainPostVisitor(EventChainVisitor& aOther)
     : EventChainVisitor(aOther.mPresContext, aOther.mEvent,
                         aOther.mDOMEvent, aOther.mEventStatus)
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/shadow-dom/event-composed-path-with-related-target.html.ini
@@ -0,0 +1,43 @@
+[event-composed-path-with-related-target.html]
+  [Event path for an event with a relatedTarget. Event shoul be dispatched if 1) target and relatedTarget are same, and 2) they are not in a shadow tree.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. Event should stop at the shadow root]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. Event should not be dispatched if 1) target and relatedTarget are same, and 2) both are in a shadow tree.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. target and relaterTarget do not share any shadow-including ancestor. target is in a shadow tree.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. target and relaterTarget do not share any shadow-including ancestor. target is not in a shadow tree]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. target and relaterTarget share the same shadow-including ancestor. Both are in shadow trees.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. relaterTarget is a shadow-including ancestor of target.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. target is a shadow-including ancestor of relatedTarget.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. target is assigned to a slot.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. relatedTarget is assigned to a slot.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. Event should be dispatched at every slots.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. Event should be dispatched at every slots. relatedTarget should be correctly retargeted.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget which is identical to target. Event should be dispatched and should stop at the shadow root.]
+    expected: FAIL
+
+  [Event path for an event with a relatedTarget. relatedTarget is a shadow-including ancestor of target.]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/shadow-dom/event-post-dispatch.html.ini
@@ -0,0 +1,25 @@
+[event-post-dispatch.html]
+  [Event properties post dispatch with an open ShadowRoot (composed: false).]
+    expected: FAIL
+
+  [Event properties post dispatch with a closed ShadowRoot (composed: false).]
+    expected: FAIL
+
+  [Event properties post dispatch with nested ShadowRoots (composed: false).]
+    expected: FAIL
+
+  [Event properties post dispatch with relatedTarget in the same shadow tree. (composed: true)]
+    expected: FAIL
+
+  [Event properties post dispatch with relatedTarget in the same shadow tree. (composed: false)]
+    expected: FAIL
+
+  [Event properties post dispatch with relatedTarget in the document tree and the shadow tree. (composed: false)]
+    expected: FAIL
+
+  [Event properties post dispatch with relatedTarget in the different shadow trees. (composed: true)]
+    expected: FAIL
+
+  [Event properties post dispatch with relatedTarget in the different shadow trees. (composed: false)]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/shadow-dom/event-with-related-target.html.ini
@@ -0,0 +1,55 @@
+[event-with-related-target.html]
+  [Firing an event at B1a with relatedNode at B1 with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at B1 with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at B1b1 with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at B1b1 with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1b1 with relatedNode at B1a with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1b1 with relatedNode at B1a with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at D1 with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at D1 with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at D1 with relatedNode at B1a with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at D1 with relatedNode at B1a with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at A1a with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at A1a with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at A1a with relatedNode at B1a with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at A1a with relatedNode at B1a with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at A1a (detached) with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at B1a with relatedNode at A1a (detached) with closed mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at A1a with relatedNode at B1a (detached) with open mode shadow trees]
+    expected: FAIL
+
+  [Firing an event at A1a with relatedNode at B1a (detached) with closed mode shadow trees]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/shadow-dom/untriaged/events/retargeting-relatedtarget/test-001.html.ini
@@ -0,0 +1,4 @@
+[test-001.html]
+  [A_05_02_01_T1]
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/shadow-dom/untriaged/events/retargeting-relatedtarget/test-002.html.ini
@@ -0,0 +1,4 @@
+[test-002.html]
+  [A_05_02_02_T01]
+    expected: FAIL
+
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -561,17 +561,16 @@ public:
     , mFocusSequenceNumber(aOther.mFocusSequenceNumber)
     , mFlags(Move(aOther.mFlags))
     , mSpecifiedEventType(Move(aOther.mSpecifiedEventType))
     , mSpecifiedEventTypeString(Move(aOther.mSpecifiedEventTypeString))
     , mTarget(Move(aOther.mTarget))
     , mCurrentTarget(Move(aOther.mCurrentTarget))
     , mOriginalTarget(Move(aOther.mOriginalTarget))
     , mRelatedTarget(Move(aOther.mRelatedTarget))
-    , mOriginalRelatedTarget(Move(aOther.mOriginalRelatedTarget))
     , mPath(Move(aOther.mPath))
   {
     MOZ_COUNT_CTOR(WidgetEvent);
   }
   WidgetEvent& operator=(WidgetEvent&& aOther) = default;
 
   virtual WidgetEvent* Duplicate() const
   {
@@ -611,17 +610,16 @@ public:
   // Note that when you need event target for DOM event, you should use
   // Get*DOMEventTarget() instead of accessing these members directly.
   nsCOMPtr<dom::EventTarget> mTarget;
   nsCOMPtr<dom::EventTarget> mCurrentTarget;
   nsCOMPtr<dom::EventTarget> mOriginalTarget;
 
   /// The possible related target
   nsCOMPtr<dom::EventTarget> mRelatedTarget;
-  nsCOMPtr<dom::EventTarget> mOriginalRelatedTarget;
 
   nsTArray<EventTargetChainItem>* mPath;
 
   dom::EventTarget* GetDOMEventTarget() const;
   dom::EventTarget* GetCurrentDOMEventTarget() const;
   dom::EventTarget* GetOriginalDOMEventTarget() const;
 
   void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets)
@@ -634,18 +632,16 @@ public:
     AssignEventTime(aEvent);
     // mFlags should be copied manually if it's necessary.
     mSpecifiedEventType = aEvent.mSpecifiedEventType;
     // mSpecifiedEventTypeString should be copied manually if it's necessary.
     mTarget = aCopyTargets ? aEvent.mTarget : nullptr;
     mCurrentTarget = aCopyTargets ? aEvent.mCurrentTarget : nullptr;
     mOriginalTarget = aCopyTargets ? aEvent.mOriginalTarget : nullptr;
     mRelatedTarget = aCopyTargets ? aEvent.mRelatedTarget : nullptr;
-    mOriginalRelatedTarget =
-      aCopyTargets ? aEvent.mOriginalRelatedTarget : nullptr;
   }
 
   /**
    * Helper methods for methods of DOM Event.
    */
   void StopPropagation() { mFlags.StopPropagation(); }
   void StopImmediatePropagation() { mFlags.StopImmediatePropagation(); }
   void PreventDefault(bool aCalledByDefaultHandler = true,