Title: [250273] branches/safari-608-branch
Revision
250273
Author
alanc...@apple.com
Date
2019-09-23 17:13:34 -0700 (Mon, 23 Sep 2019)

Log Message

Cherry-pick r250182. rdar://problem/55608034

    releasePointerCapture() not working for implicit capture; can't opt-in to pointerenter/leave for touches
    https://bugs.webkit.org/show_bug.cgi?id=199803
    <rdar://problem/53127223>

    Reviewed by Dean Jackson.

    Source/WebCore:

    In order to dispatch boundary events (pointerover/out/enter/leave) when the implicit pointer capture is released on iOS,
    we need to track the target of the pointer events that was dispatched last for a given pointer id. Then we compare that
    target with the current target when dispatching a new pointer event and determine whether we should dispatch boundary
    events using the exact same approach used to dispatch mouse boundary events in EventHandler::updateMouseEventTargetNode().

    Tests: pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html
           pointerevents/ios/boundary-events-without-pointer-capture.html

    * page/PointerCaptureController.cpp:
    (WebCore::hierarchyHasCapturingEventListeners):
    (WebCore::PointerCaptureController::dispatchEventForTouchAtIndex):
    (WebCore::PointerCaptureController::pointerEventWillBeDispatched):
    (WebCore::PointerCaptureController::ensureCapturingDataForPointerEvent):
    (WebCore::PointerCaptureController::cancelPointer):
    * page/PointerCaptureController.h:

    LayoutTests:

    Add new tests that check we correctly dispatch boundary events on iOS when pointer capture is disabled.

    * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt: Added.
    * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html: Added.
    * pointerevents/ios/boundary-events-without-pointer-capture-expected.txt: Added.
    * pointerevents/ios/boundary-events-without-pointer-capture.html: Added.
    * pointerevents/utils.js:

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

Modified Paths

Added Paths

Diff

Modified: branches/safari-608-branch/LayoutTests/ChangeLog (250272 => 250273)


--- branches/safari-608-branch/LayoutTests/ChangeLog	2019-09-24 00:13:30 UTC (rev 250272)
+++ branches/safari-608-branch/LayoutTests/ChangeLog	2019-09-24 00:13:34 UTC (rev 250273)
@@ -1,5 +1,61 @@
 2019-09-23  Alan Coon  <alanc...@apple.com>
 
+        Cherry-pick r250182. rdar://problem/55608034
+
+    releasePointerCapture() not working for implicit capture; can't opt-in to pointerenter/leave for touches
+    https://bugs.webkit.org/show_bug.cgi?id=199803
+    <rdar://problem/53127223>
+    
+    Reviewed by Dean Jackson.
+    
+    Source/WebCore:
+    
+    In order to dispatch boundary events (pointerover/out/enter/leave) when the implicit pointer capture is released on iOS,
+    we need to track the target of the pointer events that was dispatched last for a given pointer id. Then we compare that
+    target with the current target when dispatching a new pointer event and determine whether we should dispatch boundary
+    events using the exact same approach used to dispatch mouse boundary events in EventHandler::updateMouseEventTargetNode().
+    
+    Tests: pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html
+           pointerevents/ios/boundary-events-without-pointer-capture.html
+    
+    * page/PointerCaptureController.cpp:
+    (WebCore::hierarchyHasCapturingEventListeners):
+    (WebCore::PointerCaptureController::dispatchEventForTouchAtIndex):
+    (WebCore::PointerCaptureController::pointerEventWillBeDispatched):
+    (WebCore::PointerCaptureController::ensureCapturingDataForPointerEvent):
+    (WebCore::PointerCaptureController::cancelPointer):
+    * page/PointerCaptureController.h:
+    
+    LayoutTests:
+    
+    Add new tests that check we correctly dispatch boundary events on iOS when pointer capture is disabled.
+    
+    * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt: Added.
+    * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html: Added.
+    * pointerevents/ios/boundary-events-without-pointer-capture-expected.txt: Added.
+    * pointerevents/ios/boundary-events-without-pointer-capture.html: Added.
+    * pointerevents/utils.js:
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@250182 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-09-20  Antoine Quint  <grao...@apple.com>
+
+            releasePointerCapture() not working for implicit capture; can't opt-in to pointerenter/leave for touches
+            https://bugs.webkit.org/show_bug.cgi?id=199803
+            <rdar://problem/53127223>
+
+            Reviewed by Dean Jackson.
+
+            Add new tests that check we correctly dispatch boundary events on iOS when pointer capture is disabled.
+
+            * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt: Added.
+            * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html: Added.
+            * pointerevents/ios/boundary-events-without-pointer-capture-expected.txt: Added.
+            * pointerevents/ios/boundary-events-without-pointer-capture.html: Added.
+            * pointerevents/utils.js:
+
+2019-09-23  Alan Coon  <alanc...@apple.com>
+
         Apply patch. rdar://problem/55608028
 
     Tell websites why a session was cancelled https://bugs.webkit.org/show_bug.cgi?id=201912 Source/WebCore:

Added: branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt (0 => 250273)


--- branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt	2019-09-24 00:13:34 UTC (rev 250273)
@@ -0,0 +1,3 @@
+
+PASS Testing that "pointerover", "pointerenter", "pointerout" and "pointerleave" events are dispatched correctly with capture disabled as a touch moves between elements in a hierarchy. 
+

Added: branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html (0 => 250273)


--- branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html	2019-09-24 00:13:34 UTC (rev 250273)
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+
+body {
+    /* Ensure we get pointer events for all touch events. */
+    touch-action: none;
+}
+
+#container, #container div {
+    position: absolute;
+    top: 0;
+    height: 100px;
+}
+
+#container {
+    left: 50px;
+    width: 400px;
+    background-color: black;
+}
+
+#leaf-one {
+    width: 100px;
+    background-color: blue;
+}
+
+#nested-container {
+    left: 150px;
+    width: 250px;
+    background-color: green;
+}
+
+#nested-leaf-one {
+    width: 100px;
+    background-color: pink;
+}
+
+#nested-leaf-two {
+    left: 100px;
+    width: 100px;
+    background-color: yellow;
+}
+
+</style>
+</head>
+<body>
+<div id="container">
+    <div id="leaf-one"></div>
+    <div id="nested-container">
+        <div id="nested-leaf-one"></div>
+        <div id="nested-leaf-two"></div>
+    </div>
+</div>
+
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+async_test(test => {
+    const eventsLog = [];
+    const logger = event => eventsLog.push(`${event.type}@${event.currentTarget.id}`);
+    for (let node of document.querySelectorAll("div")) {
+        for (let eventType of ["pointerover", "pointerenter", "pointerout", "pointerleave"])
+            node.addEventListener(eventType, logger);
+    }
+
+    // Ensure we disable pointer capture.
+    document.body.addEventListener("pointerdown", event => event.currentTarget.releasePointerCapture(event.pointerId));
+
+    const _one_ = ui.finger();
+    ui.sequence([
+        one.begin({ x: 10, y: 50 }), // We start outside of the bounds of any <div>.
+        one.move({ x: 100, y: 50 }), // Step 1: we enter the bounds of both #container and #leaf-one.
+        one.move({ x: 160, y: 50 }), // Step 2: we leave the bounds of #leaf-one, remaining within #container.
+        one.move({ x: 210, y: 50 }), // Step 3: we enter the bounds of #nested-container and #nested-leaf-one, remaining within #container.
+        one.move({ x: 310, y: 50 }), // Step 4: we leave the bounds of #nested-leaf-one and enter the bounds of #nested-leaf-two, remaining within #nested-container and #container.
+        one.move({ x: 410, y: 50 }), // Step 5: we leave the bounds of #nested-leaf-two, remaining within #nested-container and #container.
+        one.move({ x: 460, y: 50 }), // Step 6: we leave the bounds of any <div>.
+        one.end()
+    ]).then(() => {
+        assert_array_equals(eventsLog, [
+            // Step 1.
+            "pointerover@leaf-one", "pointerover@container", "pointerenter@container", "pointerenter@leaf-one",
+            // Step 2.
+            "pointerout@leaf-one", "pointerout@container", "pointerleave@leaf-one", "pointerover@container",
+            // Step 3.
+            "pointerout@container", "pointerover@nested-leaf-one", "pointerover@nested-container", "pointerover@container", "pointerenter@nested-container", "pointerenter@nested-leaf-one",
+            // Step 4.
+            "pointerout@nested-leaf-one", "pointerout@nested-container", "pointerout@container", "pointerleave@nested-leaf-one", "pointerover@nested-leaf-two", "pointerover@nested-container", "pointerover@container", "pointerenter@nested-leaf-two",
+            // Step 5.
+            "pointerout@nested-leaf-two", "pointerout@nested-container", "pointerout@container", "pointerleave@nested-leaf-two", "pointerover@nested-container", "pointerover@container",
+            // Step 6.
+            "pointerout@nested-container", "pointerout@container", "pointerleave@nested-container", "pointerleave@container"
+        ]);
+        test.done();
+    });
+}, `Testing that "pointerover", "pointerenter", "pointerout" and "pointerleave" events are dispatched correctly with capture disabled as a touch moves between elements in a hierarchy.`);
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-without-pointer-capture-expected.txt (0 => 250273)


--- branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-without-pointer-capture-expected.txt	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-without-pointer-capture-expected.txt	2019-09-24 00:13:34 UTC (rev 250273)
@@ -0,0 +1,3 @@
+
+PASS Testing that "pointerover", "pointerenter", "pointerout" and "pointerleave" events are dispatched correctly with capture disabled as a touch moves between elements. 
+

Added: branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-without-pointer-capture.html (0 => 250273)


--- branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-without-pointer-capture.html	                        (rev 0)
+++ branches/safari-608-branch/LayoutTests/pointerevents/ios/boundary-events-without-pointer-capture.html	2019-09-24 00:13:34 UTC (rev 250273)
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+async_test(test => {
+    const firstTarget = makeTarget(test, { x: "100px", y: "100px", width: "100px", height: "100px" });
+    firstTarget.id = "one";
+
+    const secondTarget = makeTarget(test, { x: "200px", y: "100px", width: "100px", height: "100px" });
+    secondTarget.id = "two";
+
+    const eventsLog = [];
+    const logger = event => eventsLog.push(`${event.type}@${event.currentTarget.id}`);
+    for (let eventType of ["pointerover", "pointerenter", "pointerout", "pointerleave"]) {
+        firstTarget.addEventListener(eventType, logger);
+        secondTarget.addEventListener(eventType, logger);
+    }
+
+    // Ensure we get pointer events for all touch events.
+    document.body.style.touchAction = "none";
+
+    // Ensure we disable pointer capture.
+    document.body.addEventListener("pointerdown", event => event.currentTarget.releasePointerCapture(event.pointerId));
+
+    const _one_ = ui.finger();
+    ui.sequence([
+        one.begin({ x: 50, y: 150 }),
+        one.move({ x: 150, y: 150 }),
+        one.move({ x: 250, y: 150 }),
+        one.move({ x: 350, y: 150 }),
+        one.end()
+    ]).then(() => {
+        assert_array_equals(eventsLog, ["pointerover@one", "pointerenter@one", "pointerout@one", "pointerleave@one", "pointerover@two", "pointerenter@two", "pointerout@two", "pointerleave@two"]);
+        test.done();
+    });
+}, `Testing that "pointerover", "pointerenter", "pointerout" and "pointerleave" events are dispatched correctly with capture disabled as a touch moves between elements.`);
+
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: branches/safari-608-branch/LayoutTests/pointerevents/utils.js (250272 => 250273)


--- branches/safari-608-branch/LayoutTests/pointerevents/utils.js	2019-09-24 00:13:30 UTC (rev 250272)
+++ branches/safari-608-branch/LayoutTests/pointerevents/utils.js	2019-09-24 00:13:34 UTC (rev 250273)
@@ -18,20 +18,24 @@
     options.height = options.height || "100%";
 
     async_test(test => {
-        const target = document.body.appendChild(document.createElement("div"));
-        target.setAttribute("style", `
-            position: absolute;
-            left: ${options.x};
-            top: ${options.y};
-            width: ${options.width};
-            height: ${options.height};
-        `);
-        test.add_cleanup(() => target.remove());
-
-        continutation(target, test);
+        continutation(makeTarget(test, options), test);
     }, description);
 }
 
+function makeTarget(test, options)
+{
+    const target = document.body.appendChild(document.createElement("div"));
+    target.setAttribute("style", `
+        position: absolute;
+        left: ${options.x};
+        top: ${options.y};
+        width: ${options.width};
+        height: ${options.height};
+    `);
+    test.add_cleanup(() => target.remove());
+    return target;
+}
+
 class EventTracker
 {
     constructor(target, eventNames)

Modified: branches/safari-608-branch/Source/WebCore/ChangeLog (250272 => 250273)


--- branches/safari-608-branch/Source/WebCore/ChangeLog	2019-09-24 00:13:30 UTC (rev 250272)
+++ branches/safari-608-branch/Source/WebCore/ChangeLog	2019-09-24 00:13:34 UTC (rev 250273)
@@ -1,5 +1,69 @@
 2019-09-23  Alan Coon  <alanc...@apple.com>
 
+        Cherry-pick r250182. rdar://problem/55608034
+
+    releasePointerCapture() not working for implicit capture; can't opt-in to pointerenter/leave for touches
+    https://bugs.webkit.org/show_bug.cgi?id=199803
+    <rdar://problem/53127223>
+    
+    Reviewed by Dean Jackson.
+    
+    Source/WebCore:
+    
+    In order to dispatch boundary events (pointerover/out/enter/leave) when the implicit pointer capture is released on iOS,
+    we need to track the target of the pointer events that was dispatched last for a given pointer id. Then we compare that
+    target with the current target when dispatching a new pointer event and determine whether we should dispatch boundary
+    events using the exact same approach used to dispatch mouse boundary events in EventHandler::updateMouseEventTargetNode().
+    
+    Tests: pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html
+           pointerevents/ios/boundary-events-without-pointer-capture.html
+    
+    * page/PointerCaptureController.cpp:
+    (WebCore::hierarchyHasCapturingEventListeners):
+    (WebCore::PointerCaptureController::dispatchEventForTouchAtIndex):
+    (WebCore::PointerCaptureController::pointerEventWillBeDispatched):
+    (WebCore::PointerCaptureController::ensureCapturingDataForPointerEvent):
+    (WebCore::PointerCaptureController::cancelPointer):
+    * page/PointerCaptureController.h:
+    
+    LayoutTests:
+    
+    Add new tests that check we correctly dispatch boundary events on iOS when pointer capture is disabled.
+    
+    * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture-expected.txt: Added.
+    * pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html: Added.
+    * pointerevents/ios/boundary-events-without-pointer-capture-expected.txt: Added.
+    * pointerevents/ios/boundary-events-without-pointer-capture.html: Added.
+    * pointerevents/utils.js:
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@250182 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-09-20  Antoine Quint  <grao...@apple.com>
+
+            releasePointerCapture() not working for implicit capture; can't opt-in to pointerenter/leave for touches
+            https://bugs.webkit.org/show_bug.cgi?id=199803
+            <rdar://problem/53127223>
+
+            Reviewed by Dean Jackson.
+
+            In order to dispatch boundary events (pointerover/out/enter/leave) when the implicit pointer capture is released on iOS,
+            we need to track the target of the pointer events that was dispatched last for a given pointer id. Then we compare that
+            target with the current target when dispatching a new pointer event and determine whether we should dispatch boundary
+            events using the exact same approach used to dispatch mouse boundary events in EventHandler::updateMouseEventTargetNode().
+
+            Tests: pointerevents/ios/boundary-events-through-hierarchy-without-pointer-capture.html
+                   pointerevents/ios/boundary-events-without-pointer-capture.html
+
+            * page/PointerCaptureController.cpp:
+            (WebCore::hierarchyHasCapturingEventListeners):
+            (WebCore::PointerCaptureController::dispatchEventForTouchAtIndex):
+            (WebCore::PointerCaptureController::pointerEventWillBeDispatched):
+            (WebCore::PointerCaptureController::ensureCapturingDataForPointerEvent):
+            (WebCore::PointerCaptureController::cancelPointer):
+            * page/PointerCaptureController.h:
+
+2019-09-23  Alan Coon  <alanc...@apple.com>
+
         Apply patch. rdar://problem/55608031
 
     Clean up handling of summary items and payment method updates https://bugs.webkit.org/show_bug.cgi?id=202018 <rdar://problem/55470632>

Modified: branches/safari-608-branch/Source/WebCore/page/PointerCaptureController.cpp (250272 => 250273)


--- branches/safari-608-branch/Source/WebCore/page/PointerCaptureController.cpp	2019-09-24 00:13:30 UTC (rev 250272)
+++ branches/safari-608-branch/Source/WebCore/page/PointerCaptureController.cpp	2019-09-24 00:13:34 UTC (rev 250273)
@@ -183,16 +183,24 @@
 }
 
 #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
+static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName)
+{
+    for (ContainerNode* curr = target; curr; curr = curr->parentInComposedTree()) {
+        if (curr->hasCapturingEventListeners(eventName))
+            return true;
+    }
+    return false;
+}
+
 void PointerCaptureController::dispatchEventForTouchAtIndex(EventTarget& target, const PlatformTouchEvent& platformTouchEvent, unsigned index, bool isPrimary, WindowProxy& view)
 {
-    auto dispatchOverOrOutEvent = [&](const String& type) {
-        dispatchEvent(PointerEvent::create(type, platformTouchEvent, index, isPrimary, view), &target);
+    ASSERT(is<Element>(target));
+
+    auto dispatchOverOrOutEvent = [&](const String& type, EventTarget* target) {
+        dispatchEvent(PointerEvent::create(type, platformTouchEvent, index, isPrimary, view), target);
     };
 
     auto dispatchEnterOrLeaveEvent = [&](const String& type) {
-        if (!is<Element>(&target))
-            return;
-
         auto* targetElement = &downcast<Element>(target);
 
         bool hasCapturingListenerInHierarchy = false;
@@ -220,11 +228,62 @@
 
     auto pointerEvent = PointerEvent::create(platformTouchEvent, index, isPrimary, view);
 
+    auto& capturingData = ensureCapturingDataForPointerEvent(pointerEvent);
+
+    // Check if the target changed, which would require dispatching boundary events.
+    RefPtr<Element> previousTarget = capturingData.previousTarget;
+    RefPtr<Element> currentTarget = downcast<Element>(&target);
+
+    capturingData.previousTarget = currentTarget;
+
+    if (pointerEvent->type() == eventNames().pointermoveEvent && previousTarget != currentTarget) {
+        // The pointerenter and pointerleave events are only dispatched if there is a capturing event listener on an ancestor
+        // or a normal event listener on the element itself since those events do not bubble.
+        // This optimization is necessary since these events can cause O(n^2) capturing event-handler checks. This follows the
+        // code for similar mouse events in EventHandler::updateMouseEventTargetNode().
+        bool hasCapturingPointerEnterListener = hierarchyHasCapturingEventListeners(currentTarget.get(), eventNames().pointerenterEvent);
+        bool hasCapturingPointerLeaveListener = hierarchyHasCapturingEventListeners(previousTarget.get(), eventNames().pointerleaveEvent);
+
+        Vector<Ref<Element>, 32> leftElementsChain;
+        for (Element* element = previousTarget.get(); element; element = element->parentElementInComposedTree())
+            leftElementsChain.append(*element);
+        Vector<Ref<Element>, 32> enteredElementsChain;
+        for (Element* element = currentTarget.get(); element; element = element->parentElementInComposedTree())
+            enteredElementsChain.append(*element);
+
+        if (!leftElementsChain.isEmpty() && !enteredElementsChain.isEmpty() && leftElementsChain.last().ptr() == enteredElementsChain.last().ptr()) {
+            size_t minHeight = std::min(leftElementsChain.size(), enteredElementsChain.size());
+            size_t i;
+            for (i = 0; i < minHeight; ++i) {
+                if (leftElementsChain[leftElementsChain.size() - i - 1].ptr() != enteredElementsChain[enteredElementsChain.size() - i - 1].ptr())
+                    break;
+            }
+            leftElementsChain.shrink(leftElementsChain.size() - i);
+            enteredElementsChain.shrink(enteredElementsChain.size() - i);
+        }
+
+        if (previousTarget)
+            dispatchOverOrOutEvent(eventNames().pointeroutEvent, previousTarget.get());
+
+        for (auto& chain : leftElementsChain) {
+            if (hasCapturingPointerLeaveListener || chain->hasEventListeners(eventNames().pointerleaveEvent))
+                dispatchEvent(PointerEvent::create(eventNames().pointerleaveEvent, platformTouchEvent, index, isPrimary, view), chain.ptr());
+        }
+
+        if (currentTarget)
+            dispatchOverOrOutEvent(eventNames().pointeroverEvent, currentTarget.get());
+
+        for (auto& chain : WTF::makeReversedRange(enteredElementsChain)) {
+            if (hasCapturingPointerEnterListener || chain->hasEventListeners(eventNames().pointerenterEvent))
+                dispatchEvent(PointerEvent::create(eventNames().pointerenterEvent, platformTouchEvent, index, isPrimary, view), chain.ptr());
+        }
+    }
+
     if (pointerEvent->type() == eventNames().pointerdownEvent) {
         // https://w3c.github.io/pointerevents/#the-pointerdown-event
         // For input devices that do not support hover, a user agent MUST also fire a pointer event named pointerover followed by a pointer event named
         // pointerenter prior to dispatching the pointerdown event.
-        dispatchOverOrOutEvent(eventNames().pointeroverEvent);
+        dispatchOverOrOutEvent(eventNames().pointeroverEvent, currentTarget.get());
         dispatchEnterOrLeaveEvent(eventNames().pointerenterEvent);
     }
 
@@ -234,8 +293,9 @@
         // https://w3c.github.io/pointerevents/#the-pointerup-event
         // For input devices that do not support hover, a user agent MUST also fire a pointer event named pointerout followed by a
         // pointer event named pointerleave after dispatching the pointerup event.
-        dispatchOverOrOutEvent(eventNames().pointeroutEvent);
+        dispatchOverOrOutEvent(eventNames().pointeroutEvent, currentTarget.get());
         dispatchEnterOrLeaveEvent(eventNames().pointerleaveEvent);
+        capturingData.previousTarget = nullptr;
     }
 }
 #endif
@@ -325,13 +385,20 @@
     // releasePointerCapture is not called for the pointer before the next pointer event is fired, then a gotpointercapture event will be dispatched
     // to the target (as normal) indicating that capture is active.
 
-    CapturingData capturingData;
-    capturingData.pointerType = event.pointerType();
+    auto& capturingData = ensureCapturingDataForPointerEvent(event);
     capturingData.pointerIsPressed = true;
-    m_activePointerIdsToCapturingData.set(pointerId, capturingData);
     setPointerCapture(downcast<Element>(target), pointerId);
 }
 
+PointerCaptureController::CapturingData& PointerCaptureController::ensureCapturingDataForPointerEvent(const PointerEvent& event)
+{
+    return m_activePointerIdsToCapturingData.ensure(event.pointerId(), [&event] {
+        CapturingData capturingData;
+        capturingData.pointerType = event.pointerType();
+        return capturingData;
+    }).iterator->value;
+}
+
 void PointerCaptureController::pointerEventWasDispatched(const PointerEvent& event)
 {
     auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
@@ -390,6 +457,10 @@
     capturingData.pendingTargetOverride = nullptr;
     capturingData.cancelled = true;
 
+#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
+    capturingData.previousTarget = nullptr;
+#endif
+
     auto& target = capturingData.targetOverride;
     if (!target)
         target = m_page.mainFrame().eventHandler().hitTestResultAtPoint(documentPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent).innerNonSharedElement();

Modified: branches/safari-608-branch/Source/WebCore/page/PointerCaptureController.h (250272 => 250273)


--- branches/safari-608-branch/Source/WebCore/page/PointerCaptureController.h	2019-09-24 00:13:30 UTC (rev 250272)
+++ branches/safari-608-branch/Source/WebCore/page/PointerCaptureController.h	2019-09-24 00:13:34 UTC (rev 250273)
@@ -67,6 +67,9 @@
     struct CapturingData {
         RefPtr<Element> pendingTargetOverride;
         RefPtr<Element> targetOverride;
+#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
+        RefPtr<Element> previousTarget;
+#endif
         String pointerType;
         bool cancelled { false };
         bool isPrimary { false };
@@ -75,6 +78,7 @@
         short previousMouseButton { -1 };
     };
 
+    CapturingData& ensureCapturingDataForPointerEvent(const PointerEvent&);
     void pointerEventWillBeDispatched(const PointerEvent&, EventTarget*);
     void pointerEventWasDispatched(const PointerEvent&);
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to