[Pointer Events] Removing the capture element prevents future pointer events from...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Aug 2019 16:55:31 +0000 (16:55 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Aug 2019 16:55:31 +0000 (16:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200887
<rdar://problem/54104147>

Patch by Antoine Quint <graouts@apple.com> on 2019-08-19
Reviewed by Dean Jackson.

Source/WebCore:

Test: pointerevents/mouse/pointer-capture-element-removal.html

While we should only dispatch a lostpointercapture event to a connected element, clearing the capture element set on the frame's EventHandler
should always happen, regardless of the connected status of the previous capture element, since otherwise all future mouse and pointer events
would be targeted at the now-disconnected, former capture element.

* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::processPendingPointerCapture):

LayoutTests:

* pointerevents/mouse/pointer-capture-element-removal-expected.txt: Added.
* pointerevents/mouse/pointer-capture-element-removal.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/pointerevents/mouse/pointer-capture-element-removal-expected.txt [new file with mode: 0644]
LayoutTests/pointerevents/mouse/pointer-capture-element-removal.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/PointerCaptureController.cpp

index 6f0ce5b..f256a5a 100644 (file)
@@ -1,3 +1,14 @@
+2019-08-19  Antoine Quint  <graouts@apple.com>
+
+        [Pointer Events] Removing the capture element prevents future pointer events from being dispatched on macOS
+        https://bugs.webkit.org/show_bug.cgi?id=200887
+        <rdar://problem/54104147>
+
+        Reviewed by Dean Jackson.
+
+        * pointerevents/mouse/pointer-capture-element-removal-expected.txt: Added.
+        * pointerevents/mouse/pointer-capture-element-removal.html: Added.
+
 2019-08-19  Youenn Fablet  <youenn@apple.com>
 
         enumerateDevices should return the same JS objects if called twice
diff --git a/LayoutTests/pointerevents/mouse/pointer-capture-element-removal-expected.txt b/LayoutTests/pointerevents/mouse/pointer-capture-element-removal-expected.txt
new file mode 100644 (file)
index 0000000..97433b5
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Testing that removing the capture element from the DOM doesn't prevent future pointer events to be dispatched. 
+
diff --git a/LayoutTests/pointerevents/mouse/pointer-capture-element-removal.html b/LayoutTests/pointerevents/mouse/pointer-capture-element-removal.html
new file mode 100644 (file)
index 0000000..8172bda
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+
+.target {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100px;
+    height: 100px;
+}
+
+</style>
+</head>
+<body>
+<div class="target" id="second"></div>
+<div class="target" id="first"></div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../utils.js"></script>
+<script>
+
+'use strict';
+
+test(() => {
+
+    let numberOfPointerDownEvents = 0;
+    document.body.addEventListener("pointerdown", event => {
+        numberOfPointerDownEvents++;
+        if (numberOfPointerDownEvents == 1) {
+            event.target.setPointerCapture(event.pointerId);
+            assert_equals(event.target.id, "first");
+        } else if (numberOfPointerDownEvents == 2)
+            assert_equals(event.target.id, "second");
+        else
+            assert_unreached("There were more than two pointerdown events dispatched.");
+    });
+
+    document.body.addEventListener("pointerup", event => event.target.remove(), { once: true });
+
+    // Move the mouse pointer over both of the stacked targets.
+    eventSender.mouseMoveTo(50, 50);
+
+    // Click once, this will set pointer capture on "first" and then remove it when the pointer is released.
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+
+    // Click a second time, this should target "second".
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+
+    assert_equals(numberOfPointerDownEvents, 2, "There were two pointerdown events dispatched.");
+}, `Testing that removing the capture element from the DOM doesn't prevent future pointer events to be dispatched.`);
+
+</script>
+</body>
+</html>
\ No newline at end of file
index d2b2b0e..5a9bede 100644 (file)
@@ -1,3 +1,20 @@
+2019-08-19  Antoine Quint  <graouts@apple.com>
+
+        [Pointer Events] Removing the capture element prevents future pointer events from being dispatched on macOS
+        https://bugs.webkit.org/show_bug.cgi?id=200887
+        <rdar://problem/54104147>
+
+        Reviewed by Dean Jackson.
+
+        Test: pointerevents/mouse/pointer-capture-element-removal.html
+
+        While we should only dispatch a lostpointercapture event to a connected element, clearing the capture element set on the frame's EventHandler
+        should always happen, regardless of the connected status of the previous capture element, since otherwise all future mouse and pointer events
+        would be targeted at the now-disconnected, former capture element.
+
+        * page/PointerCaptureController.cpp:
+        (WebCore::PointerCaptureController::processPendingPointerCapture):
+
 2019-08-19  Youenn Fablet  <youenn@apple.com>
 
         Remove SessionID::emptySessionID()
index 0e023f5..2fa1b87 100644 (file)
@@ -426,8 +426,9 @@ void PointerCaptureController::processPendingPointerCapture(PointerID pointerId)
     // https://w3c.github.io/pointerevents/#process-pending-pointer-capture
     // 1. If the pointer capture target override for this pointer is set and is not equal to the pending pointer capture target override,
     // then fire a pointer event named lostpointercapture at the pointer capture target override node.
-    if (capturingData.targetOverride && capturingData.targetOverride->isConnected() && capturingData.targetOverride != pendingTargetOverride) {
-        capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, pointerId, capturingData.isPrimary, capturingData.pointerType));
+    if (capturingData.targetOverride && capturingData.targetOverride != pendingTargetOverride) {
+        if (capturingData.targetOverride->isConnected())
+            capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, pointerId, capturingData.isPrimary, capturingData.pointerType));
         if (capturingData.pointerType == PointerEvent::mousePointerType()) {
             if (auto* frame = capturingData.targetOverride->document().frame())
                 frame->eventHandler().pointerCaptureElementDidChange(nullptr);