click event does not dispatch to parent when child target stops hit testing after...
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jul 2017 19:14:12 +0000 (19:14 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jul 2017 19:14:12 +0000 (19:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174564
<rdar://problem/33340234>

Reviewed by Simon Fraser.

Source/WebCore:

As per [1], if the mouse down node and the mouse release node differ, then we are supposed to
fire the click event at their common ancestor, if such node exists. This patch implements this
logic. This also aligns our behavior with Blink.

[1] https://w3c.github.io/uievents/#events-mouseevent-event-order

Test: fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html

* page/EventHandler.cpp:
(WebCore::targetNodeForClickEvent):

LayoutTests:

Add layout test coverage.

* fast/events/mouse-click-different-mouseDown-mouseUp-nodes-expected.txt: Added.
* fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219568 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/events/mouse-click-different-mouseDown-mouseUp-nodes-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/page/EventHandler.cpp

index bf991f6..cadbf6c 100644 (file)
@@ -1,3 +1,16 @@
+2017-07-17  Chris Dumez  <cdumez@apple.com>
+
+        click event does not dispatch to parent when child target stops hit testing after mousedown
+        https://bugs.webkit.org/show_bug.cgi?id=174564
+        <rdar://problem/33340234>
+
+        Reviewed by Simon Fraser.
+
+        Add layout test coverage.
+
+        * fast/events/mouse-click-different-mouseDown-mouseUp-nodes-expected.txt: Added.
+        * fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html: Added.
+
 2017-07-17  Antoine Quint  <graouts@apple.com>
 
         REGRESSION: order of AirPlay and volume controls is inconsistent between <audio> and <video>
diff --git a/LayoutTests/fast/events/mouse-click-different-mouseDown-mouseUp-nodes-expected.txt b/LayoutTests/fast/events/mouse-click-different-mouseDown-mouseUp-nodes-expected.txt
new file mode 100644 (file)
index 0000000..e96c15a
--- /dev/null
@@ -0,0 +1,11 @@
+Tests that the click event is fired at the common ancestor if the mouseDown / mouseUp nodes differ.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS parentGotClickEvent is true
+PASS childGotClickEvent is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html b/LayoutTests/fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html
new file mode 100644 (file)
index 0000000..eccbb1b
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<style>
+    div {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+    }
+
+    .button {
+        background-color: blue;
+    }
+
+    .icon {
+        background-color: black;
+    }
+
+    .button:active .icon {
+        transform: scale(0.25);
+    }
+</style>
+</head>
+<body>
+<div id="parentDiv" class="button" onclick="alert('clicked')">
+    <div id="childDiv" class="icon"></div>
+</div>
+<script>
+description("Tests that the click event is fired at the common ancestor if the mouseDown / mouseUp nodes differ.");
+jsTestIsAsync = true;
+
+parentGotClickEvent = false;
+childGotClickEvent = false;
+
+document.getElementById("parentDiv").onclick = function() {
+    parentGotClickEvent = true;
+};
+
+document.getElementById("childDiv").onclick = function() {
+    childGotClickEvent = true;
+};
+
+onload = function() {
+    if (window.eventSender) {
+        eventSender.mouseMoveTo(10, 300);
+        eventSender.mouseDown();
+        eventSender.mouseUp();    
+    }
+
+    setTimeout(function() {
+        shouldBeTrue("parentGotClickEvent");
+        shouldBeFalse("childGotClickEvent");
+        finishJSTest();
+    }, 0);
+}
+</script>
+</body>
+</html>
index 973d5ea..6be7c40 100644 (file)
@@ -387,6 +387,7 @@ fast/forms/range/disabled-while-dragging.html [ Skip ]
 fast/forms/range/range-drag-when-toggled-disabled.html [ Skip ]
 fast/media/video-element-in-details-collapse.html [ Skip ]
 fast/frames/user-gesture-timestamp-propagation.html [ Failure ]
+fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html [ Skip ]
 
 # The file-wrapper part of <attachment> is not yet working on iOS
 fast/attachment/attachment-type-attribute.html [ Skip ]
index e8f1113..bf4926c 100644 (file)
@@ -1,3 +1,22 @@
+2017-07-17  Chris Dumez  <cdumez@apple.com>
+
+        click event does not dispatch to parent when child target stops hit testing after mousedown
+        https://bugs.webkit.org/show_bug.cgi?id=174564
+        <rdar://problem/33340234>
+
+        Reviewed by Simon Fraser.
+
+        As per [1], if the mouse down node and the mouse release node differ, then we are supposed to
+        fire the click event at their common ancestor, if such node exists. This patch implements this
+        logic. This also aligns our behavior with Blink.
+
+        [1] https://w3c.github.io/uievents/#events-mouseevent-event-order
+
+        Test: fast/events/mouse-click-different-mouseDown-mouseUp-nodes.html
+
+        * page/EventHandler.cpp:
+        (WebCore::targetNodeForClickEvent):
+
 2017-07-17  Brady Eidson  <beidson@apple.com>
 
         WKHTTPCookieStore observing only works on the default cookie store.
index e978429..617b325 100644 (file)
@@ -70,6 +70,7 @@
 #include "PlatformKeyboardEvent.h"
 #include "PlatformWheelEvent.h"
 #include "PluginDocument.h"
+#include "Range.h"
 #include "RenderFrameSet.h"
 #include "RenderLayer.h"
 #include "RenderListBox.h"
@@ -1999,6 +2000,12 @@ static Node* targetNodeForClickEvent(Node* mousePressNode, Node* mouseReleaseNod
     if (mousePressNode == mouseReleaseNode)
         return mouseReleaseNode;
 
+    // If mousePressNode and mouseReleaseNode differ, we should fire the event at their common ancestor if there is one.
+    if (&mousePressNode->document() == &mouseReleaseNode->document()) {
+        if (auto* commonAncestor = Range::commonAncestorContainer(mousePressNode, mouseReleaseNode))
+            return commonAncestor;
+    }
+
     Element* mouseReleaseShadowHost = mouseReleaseNode->shadowHost();
     if (mouseReleaseShadowHost && mouseReleaseShadowHost == mousePressNode->shadowHost()) {
         // We want to dispatch the click to the shadow tree host element to give listeners the illusion that the