Title: [167689] trunk
Revision
167689
Author
rn...@webkit.org
Date
2014-04-22 16:25:59 -0700 (Tue, 22 Apr 2014)

Log Message

REGRESSION (r157328): popover to check into flight ba.com dismisses instantly when focusing form
https://bugs.webkit.org/show_bug.cgi?id=131949

Reviewed by Darin Adler.

Source/WebCore:
The regression was caused by two bugs:
1. The event didn't stop propagating itself even when it should.
   If the related target is same as the event origin, the event propagation should stop when the event reaches
   the root of the related target's tree scope. Otherwise, it should stop when it reaches the related target.

2. Mouse event's related target exposed nodes inside a user-agent shadow DOM when the related target appeared
   inside the origin.

Fixed the bugs by re-introducing path shrinkage algorithm removed in r157328 into EventPath::setRelatedTarget
and adding an algorithm to determine the least common ancestor of the related target and the current target
in moveToParentOrShadowHost. The latter algorithm doesn't match the shadow DOM specification:
http://www.w3.org/TR/2013/WD-shadow-dom-20130514/
but it's good enough in terms of the Web exposed behavior as we don't support author defined insertion points.

Test: fast/events/shadow-event-path.html

* dom/EventDispatcher.cpp:
(WebCore::EventRelatedNodeResolver::moveToParentOrShadowHost):
(WebCore::EventRelatedNodeResolver::findHostOfTreeScopeInTargetTreeScope): Added.
(WebCore::EventDispatcher::dispatchEvent):
(WebCore::EventPath::setRelatedTarget):

LayoutTests:
Add a test that dumps the event target and the related target of every mouse event
when dispatched inside an input element inside a details element.

This catches the regression as well as other bugs I encountered while fixing the bug.

We need a WK2 specific results because WK1 mac results contain an extra fake mouse move event.

* fast/events/shadow-event-path-expected.txt: Added.
* fast/events/shadow-event-path.html: Added.
* platform/mac-wk2/fast/events/shadow-event-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (167688 => 167689)


--- trunk/LayoutTests/ChangeLog	2014-04-22 23:05:53 UTC (rev 167688)
+++ trunk/LayoutTests/ChangeLog	2014-04-22 23:25:59 UTC (rev 167689)
@@ -1,5 +1,23 @@
 2014-04-22  Ryosuke Niwa  <rn...@webkit.org>
 
+        REGRESSION (r157328): popover to check into flight ba.com dismisses instantly when focusing form
+        https://bugs.webkit.org/show_bug.cgi?id=131949
+
+        Reviewed by Darin Adler.
+
+        Add a test that dumps the event target and the related target of every mouse event
+        when dispatched inside an input element inside a details element.
+
+        This catches the regression as well as other bugs I encountered while fixing the bug.
+
+        We need a WK2 specific results because WK1 mac results contain an extra fake mouse move event.
+
+        * fast/events/shadow-event-path-expected.txt: Added.
+        * fast/events/shadow-event-path.html: Added.
+        * platform/mac-wk2/fast/events/shadow-event-expected.txt: Added.
+
+2014-04-22  Ryosuke Niwa  <rn...@webkit.org>
+
         Rollout r156635 since the old behavior was intentional.
 
         * editing/caret/selection-with-caret-type-progress-expected.txt: Removed.

Added: trunk/LayoutTests/fast/events/shadow-event-path-expected.txt (0 => 167689)


--- trunk/LayoutTests/fast/events/shadow-event-path-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/shadow-event-path-expected.txt	2014-04-22 23:25:59 UTC (rev 167689)
@@ -0,0 +1,338 @@
+This test records target and relatedTarget at each element while dispatching a mouse click event at an input element.
+
+
+Content:<div id="detailsContainer"><details><summary><div id="divInsideSummary"><input id="target" type="text" size="10"></div></summary></details></div>
+
+mouseover@input#target
+    target:input#target
+    relatedTarget:null
+
+mouseover@div#divInsideSummary
+    target:input#target
+    relatedTarget:null
+
+mouseover@summary
+    target:input#target
+    relatedTarget:null
+
+mouseover@details
+    target:input#target
+    relatedTarget:null
+
+mouseover@div#detailsContainer
+    target:input#target
+    relatedTarget:null
+
+mouseover@body
+    target:input#target
+    relatedTarget:null
+
+mouseover@html
+    target:input#target
+    relatedTarget:null
+
+mouseover@document
+    target:input#target
+    relatedTarget:null
+
+mouseover@window
+    target:input#target
+    relatedTarget:null
+
+mouseenter@input#target
+    target:input#target
+    relatedTarget:null
+
+mouseenter@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseenter@summary
+    target:summary
+    relatedTarget:null
+
+mouseenter@details
+    target:details
+    relatedTarget:null
+
+mouseenter@div#detailsContainer
+    target:div#detailsContainer
+    relatedTarget:null
+
+mouseenter@body
+    target:body
+    relatedTarget:null
+
+mouseenter@html
+    target:html
+    relatedTarget:null
+
+mousemove@input#target
+    target:input#target
+    relatedTarget:null
+
+mousemove@div#divInsideSummary
+    target:input#target
+    relatedTarget:null
+
+mousemove@summary
+    target:input#target
+    relatedTarget:null
+
+mousemove@details
+    target:input#target
+    relatedTarget:null
+
+mousemove@div#detailsContainer
+    target:input#target
+    relatedTarget:null
+
+mousemove@body
+    target:input#target
+    relatedTarget:null
+
+mousemove@html
+    target:input#target
+    relatedTarget:null
+
+mousemove@document
+    target:input#target
+    relatedTarget:null
+
+mousemove@window
+    target:input#target
+    relatedTarget:null
+
+mouseout@input#target
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@div#divInsideSummary
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@summary
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@details
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@div#detailsContainer
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@body
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@html
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@document
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@window
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseleave@input#target
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseover@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@summary
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@details
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@body
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@html
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@document
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@window
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mousemove@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+

Added: trunk/LayoutTests/fast/events/shadow-event-path.html (0 => 167689)


--- trunk/LayoutTests/fast/events/shadow-event-path.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/shadow-event-path.html	2014-04-22 23:25:59 UTC (rev 167689)
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This test records target and relatedTarget at each element while dispatching a mouse click event at an input element.</p>
+<div id="detailsContainer"><details><summary><div id="divInsideSummary"><input id="target" type="text" size="10"></summary></div></detials></div>
+<pre id="log"></pre>
+<script>
+
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+function targetIdentifier(target) {
+    if (target === undefined || target === null)
+        return target;
+    if (target === window)
+        return 'window';
+    if (target === document)
+        return 'document';
+    return target.localName + (target.id ? '#' + target.id : '');
+}
+
+function attachListeners(eventname) {
+    var targets = Array.prototype.slice.call(document.querySelectorAll('*'));
+    targets.push(window);
+    targets.push(document);
+    targets.forEach(function (target) {
+        target.addEventListener(eventname, function (event) {
+            log.textContent += eventname + '@' + targetIdentifier(target) + '\n'
+                + '    target:' + targetIdentifier(event.target) + '\n'
+                + '    relatedTarget:' + targetIdentifier(event.relatedTarget) + '\n\n';
+        });
+    });
+}
+
+var log = document.getElementById('log');
+log.textContent = 'Content:' + detailsContainer.outerHTML + '\n\n';
+var target = document.getElementById('target');
+
+attachListeners('mousemove');
+attachListeners('mousedown');
+attachListeners('mouseover');
+attachListeners('mouseout');
+attachListeners('mouseenter');
+attachListeners('mouseleave');
+attachListeners('mouseup');
+attachListeners('click');
+
+function runTest() {
+    testRunner.waitUntilDone();
+    eventSender.mouseMoveTo(target.offsetLeft + target.offsetWidth / 2, target.offsetTop + target.offsetHeight / 2);
+    eventSender.mouseMoveTo(target.offsetLeft + target.offsetWidth + 100, target.offsetTop + target.offsetHeight / 2);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    testRunner.notifyDone();
+}
+
+if (window.testRunner && !window.eventSender)
+    log.textContent += 'This test requires eventSender.';
+else if (window.eventSender) {
+    window._onload_ = runTest;
+}
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/platform/mac-wk2/fast/events/shadow-event-path-expected.txt (0 => 167689)


--- trunk/LayoutTests/platform/mac-wk2/fast/events/shadow-event-path-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac-wk2/fast/events/shadow-event-path-expected.txt	2014-04-22 23:25:59 UTC (rev 167689)
@@ -0,0 +1,306 @@
+This test records target and relatedTarget at each element while dispatching a mouse click event at an input element.
+
+
+Content:<div id="detailsContainer"><details><summary><div id="divInsideSummary"><input id="target" type="text" size="10"></div></summary></details></div>
+
+mouseover@input#target
+    target:input#target
+    relatedTarget:null
+
+mouseover@div#divInsideSummary
+    target:input#target
+    relatedTarget:null
+
+mouseover@summary
+    target:input#target
+    relatedTarget:null
+
+mouseover@details
+    target:input#target
+    relatedTarget:null
+
+mouseover@div#detailsContainer
+    target:input#target
+    relatedTarget:null
+
+mouseover@body
+    target:input#target
+    relatedTarget:null
+
+mouseover@html
+    target:input#target
+    relatedTarget:null
+
+mouseover@document
+    target:input#target
+    relatedTarget:null
+
+mouseover@window
+    target:input#target
+    relatedTarget:null
+
+mouseenter@input#target
+    target:input#target
+    relatedTarget:null
+
+mouseenter@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseenter@summary
+    target:summary
+    relatedTarget:null
+
+mouseenter@details
+    target:details
+    relatedTarget:null
+
+mouseenter@div#detailsContainer
+    target:div#detailsContainer
+    relatedTarget:null
+
+mouseenter@body
+    target:body
+    relatedTarget:null
+
+mouseenter@html
+    target:html
+    relatedTarget:null
+
+mousemove@input#target
+    target:input#target
+    relatedTarget:null
+
+mousemove@div#divInsideSummary
+    target:input#target
+    relatedTarget:null
+
+mousemove@summary
+    target:input#target
+    relatedTarget:null
+
+mousemove@details
+    target:input#target
+    relatedTarget:null
+
+mousemove@div#detailsContainer
+    target:input#target
+    relatedTarget:null
+
+mousemove@body
+    target:input#target
+    relatedTarget:null
+
+mousemove@html
+    target:input#target
+    relatedTarget:null
+
+mousemove@document
+    target:input#target
+    relatedTarget:null
+
+mousemove@window
+    target:input#target
+    relatedTarget:null
+
+mouseout@input#target
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@div#divInsideSummary
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@summary
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@details
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@div#detailsContainer
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@body
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@html
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@document
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseout@window
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseleave@input#target
+    target:input#target
+    relatedTarget:div#divInsideSummary
+
+mouseover@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@summary
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@details
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@body
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@html
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@document
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mouseover@window
+    target:div#divInsideSummary
+    relatedTarget:input#target
+
+mousemove@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousemove@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mousedown@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+mouseup@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@div#divInsideSummary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@summary
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@details
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@div#detailsContainer
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@body
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@html
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@document
+    target:div#divInsideSummary
+    relatedTarget:null
+
+click@window
+    target:div#divInsideSummary
+    relatedTarget:null
+
+

Modified: trunk/Source/WebCore/ChangeLog (167688 => 167689)


--- trunk/Source/WebCore/ChangeLog	2014-04-22 23:05:53 UTC (rev 167688)
+++ trunk/Source/WebCore/ChangeLog	2014-04-22 23:25:59 UTC (rev 167689)
@@ -1,5 +1,34 @@
 2014-04-22  Ryosuke Niwa  <rn...@webkit.org>
 
+        REGRESSION (r157328): popover to check into flight ba.com dismisses instantly when focusing form
+        https://bugs.webkit.org/show_bug.cgi?id=131949
+
+        Reviewed by Darin Adler.
+
+        The regression was caused by two bugs:
+        1. The event didn't stop propagating itself even when it should.
+           If the related target is same as the event origin, the event propagation should stop when the event reaches
+           the root of the related target's tree scope. Otherwise, it should stop when it reaches the related target.
+
+        2. Mouse event's related target exposed nodes inside a user-agent shadow DOM when the related target appeared
+           inside the origin.
+
+        Fixed the bugs by re-introducing path shrinkage algorithm removed in r157328 into EventPath::setRelatedTarget
+        and adding an algorithm to determine the least common ancestor of the related target and the current target
+        in moveToParentOrShadowHost. The latter algorithm doesn't match the shadow DOM specification:
+        http://www.w3.org/TR/2013/WD-shadow-dom-20130514/
+        but it's good enough in terms of the Web exposed behavior as we don't support author defined insertion points.
+
+        Test: fast/events/shadow-event-path.html
+
+        * dom/EventDispatcher.cpp:
+        (WebCore::EventRelatedNodeResolver::moveToParentOrShadowHost):
+        (WebCore::EventRelatedNodeResolver::findHostOfTreeScopeInTargetTreeScope): Added.
+        (WebCore::EventDispatcher::dispatchEvent):
+        (WebCore::EventPath::setRelatedTarget):
+
+2014-04-22  Ryosuke Niwa  <rn...@webkit.org>
+
         Rollout r156635 since the old behavior was intentional.
 
         * page/EventHandler.cpp:

Modified: trunk/Source/WebCore/dom/EventDispatcher.cpp (167688 => 167689)


--- trunk/Source/WebCore/dom/EventDispatcher.cpp	2014-04-22 23:05:53 UTC (rev 167688)
+++ trunk/Source/WebCore/dom/EventDispatcher.cpp	2014-04-22 23:25:59 UTC (rev 167689)
@@ -90,7 +90,7 @@
 #if ENABLE(TOUCH_EVENTS)
     void updateTouchLists(const TouchEvent&);
 #endif
-    void setRelatedTarget(EventTarget&);
+    void setRelatedTarget(Node& origin, EventTarget&);
 
     bool hasEventListeners(const AtomicString& eventType) const;
 
@@ -148,18 +148,50 @@
             ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope);
         }
 
-        if (m_relatedNodeInCurrentTreeScope) { // relatedNode is under the current tree scope
+        if (&newTreeScope == &m_relatedNodeTreeScope)
+            m_relatedNodeInCurrentTreeScope = &m_relatedNode;
+        else if (m_relatedNodeInCurrentTreeScope) {
             ASSERT(m_currentTreeScope);
             m_relatedNodeInCurrentTreeScope = &newTarget;
-        } else if (&newTreeScope == &m_relatedNodeTreeScope) // relatedNode is in the current tree scope;
-            m_relatedNodeInCurrentTreeScope = &m_relatedNode;
-        // Otherwise, we haven't reached the tree scope that contains relatedNode yet.
+        } else {
+            if (!m_currentTreeScope) {
+                TreeScope* newTreeScopeAncestor = &newTreeScope;
+                do {
+                    m_relatedNodeInCurrentTreeScope = findHostOfTreeScopeInTargetTreeScope(m_relatedNodeTreeScope, *newTreeScopeAncestor);
+                    newTreeScopeAncestor = newTreeScopeAncestor->parentTreeScope();
+                    if (newTreeScopeAncestor == &m_relatedNodeTreeScope) {
+                        m_relatedNodeInCurrentTreeScope = &m_relatedNode;
+                        break;
+                    }
+                } while (newTreeScopeAncestor && !m_relatedNodeInCurrentTreeScope);
+            }
+            ASSERT(m_relatedNodeInCurrentTreeScope || findHostOfTreeScopeInTargetTreeScope(newTreeScope, m_relatedNodeTreeScope)
+                || &newTreeScope.documentScope() != &m_relatedNodeTreeScope.documentScope());
+        }
 
         m_currentTreeScope = &newTreeScope;
 
         return m_relatedNodeInCurrentTreeScope;
     }
 
+    static Node* findHostOfTreeScopeInTargetTreeScope(const TreeScope& startingTreeScope, const TreeScope& targetScope)
+    {
+        ASSERT(&targetScope != &startingTreeScope);
+        Node* previousHost = 0;
+        for (const TreeScope* scope = &startingTreeScope; scope; scope = scope->parentTreeScope()) {
+            if (scope == &targetScope) {
+                ASSERT(previousHost);
+                ASSERT_WITH_SECURITY_IMPLICATION(&previousHost->treeScope() == &targetScope);
+                return previousHost;
+            }
+            if (scope->rootNode().isShadowRoot())
+                previousHost = toShadowRoot(scope->rootNode()).hostElement();
+            else
+                ASSERT_WITH_SECURITY_IMPLICATION(!scope->parentTreeScope());
+        }
+        return 0;
+    }
+
 private:
     Node& m_relatedNode;
     const TreeScope& m_relatedNodeTreeScope;
@@ -305,7 +337,7 @@
     EventPath eventPath(*node, *event);
 
     if (EventTarget* relatedTarget = event->relatedTarget())
-        eventPath.setRelatedTarget(*relatedTarget);
+        eventPath.setRelatedTarget(*node, *relatedTarget);
 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
     if (event->isTouchEvent())
         eventPath.updateTouchLists(*toTouchEvent(event.get()));
@@ -452,7 +484,7 @@
 }
 #endif
 
-void EventPath::setRelatedTarget(EventTarget& relatedTarget)
+void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
 {
     Node* relatedNode = relatedTarget.toNode();
     if (!relatedNode)
@@ -460,9 +492,22 @@
 
     EventRelatedNodeResolver resolver(*relatedNode);
 
+    bool originIsRelatedTarget = &origin == relatedNode;
+    Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
+
     size_t eventPathSize = m_path.size();
-    for (size_t i = 0; i < eventPathSize; i++)
-        toMouseOrFocusEventContext(*m_path[i]).setRelatedTarget(resolver.moveToParentOrShadowHost(*m_path[i]->node()));
+    size_t i = 0;
+    while (i < eventPathSize) {
+        Node* contextNode = m_path[i]->node();
+        Node* currentRelatedNode = resolver.moveToParentOrShadowHost(*contextNode);
+        if (!originIsRelatedTarget && m_path[i]->target() == currentRelatedNode)
+            break;
+        toMouseOrFocusEventContext(*m_path[i]).setRelatedTarget(currentRelatedNode);
+        i++;
+        if (originIsRelatedTarget && &rootNodeInOriginTreeScope == contextNode)
+            break;
+    }
+    m_path.shrink(i);
 }
 
 bool EventPath::hasEventListeners(const AtomicString& eventType) const
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to