Title: [246674] trunk
Revision
246674
Author
[email protected]
Date
2019-06-21 01:47:26 -0700 (Fri, 21 Jun 2019)

Log Message

[Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
https://bugs.webkit.org/show_bug.cgi?id=198999

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

Record progressions in two WPT tests and mark updated failures in two other WPT tests.

* web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
* web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt:
* web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:

Source/WebCore:

Up until now, we would not account for pointer capture (see https://w3c.github.io/pointerevents/#pointer-capture) when dispatching
mouse boundary events (mouseover, mouseout, mouseenter, mouseleave) and their counterpart pointer events. We would also not account
for it when updating :hover styles.

Now, when pointer capture changes for an element, we call setCapturingMouseEventsElement() on the EventHandler such that the element
that would naturally hit-test is overridden by the pointer capture element when identifying which target to use for the dispatch of
boundary mouse events. Additionally, when calling EventHandler::prepareMouseEvent(), we also use the pointer capture element to
eventually pass down to Document::updateHoverActiveState() such that :hover styles are applied to the correct element.

This also means that we need to re-run EventHandler::prepareMouseEvent() during mouse state changes to ensure that the :hover styles
are applied correctly should the pointer capture element change during dispatch of boundary mouse events.

* dom/Document.cpp:
(WebCore::Document::prepareMouseEvent): If there is one, use the pointer capture element instead of the hit-test target.
(WebCore::Document::updateHoverActiveState): Relax the mustBeInActiveChain condition in case the pointer capture element changed when
updating the :hover/:active chains.
* page/EventHandler.cpp:
(WebCore::EventHandler::handleMousePressEvent): Re-process the mouse event if the pointer capture element changed during event dispatch.
(WebCore::EventHandler::handleMouseMoveEvent): Re-process the mouse event if the pointer capture element changed during event dispatch.
(WebCore::EventHandler::handleMouseReleaseEvent): As we know the pointer capture element will be reset as part of the mouse being
released, we reset the pointer capture element and EventHandler's capture element prior to invalidating hover styles and boundary events.
(WebCore::EventHandler::setCapturingMouseEventsElement): Dispatch boundary events when a new element is set.
(WebCore::EventHandler::dispatchMouseEvent): New dispatchMouseEvent() variant that re-processes the provided MouseEventWithHitTestResults
in case the pointer capture element changes during event dispatch, as called by handleMousePressEvent() and handleMouseMoveEvent().
* page/EventHandler.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::pointerCaptureElement): We now need to query whay the pointer capture element might be from EventHandler,
so expose a new method to access it.
(WebCore::PointerCaptureController::releasePointerCapture): Since we may not call processPendingPointerCapture() until the dispatch of the
next event, we must reset EventHandler's capturing mouse element right now so that the next event processed does not use it as an overriding target.
(WebCore::PointerCaptureController::hasPointerCapture): We would mistakenly return true if the provided element was null, which could be the
case of EventHandler's capturing element. Rather than changing call sites to check that the provided value exists, we change the method to
return false when the provided element is null. Note that this does not affect the API since it's exposed on Element itself.
(WebCore::PointerCaptureController::dispatchEventForTouchAtIndex): Call dispatchEvent() instead of calling pointerEventWillBeDispatched() and
pointerEventWasDispatched().
(WebCore::PointerCaptureController::dispatchEvent): Remove all code specific to pointer capture since now the events will be dispatched on the
pointer capture element by EventHandler.
(WebCore::PointerCaptureController::processPendingPointerCapture): Make sure this method is not re-entrant since it dispatches events.
* page/PointerCaptureController.h:
* rendering/HitTestRequest.h:
(WebCore::HitTestRequest::pointerCaptureElementChanged const): Add a new HitTestRequestType bit such that we can indicate to Document::updateHoverActiveState()
that it must be update the :hover/:active chains when the pointer capture element has just changed.

LayoutTests:

Record progressions in two WPT tests and mark updated failures in two other WPT tests.

* platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt: Removed.
* platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt: Removed.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt: Added.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame-expected.txt: Removed.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246673 => 246674)


--- trunk/LayoutTests/ChangeLog	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/ChangeLog	2019-06-21 08:47:26 UTC (rev 246674)
@@ -1,5 +1,21 @@
 2019-06-20  Antoine Quint  <[email protected]>
 
+        [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
+        https://bugs.webkit.org/show_bug.cgi?id=198999
+
+        Reviewed by Dean Jackson.
+
+        Record progressions in two WPT tests and mark updated failures in two other WPT tests.
+
+        * platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt: Removed.
+        * platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt: Removed.
+        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
+        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt: Added.
+        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame-expected.txt: Removed.
+        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
+
+2019-06-20  Antoine Quint  <[email protected]>
+
         fast/events/ios/click-event-and-display-contents.html times out on iPad
         https://bugs.webkit.org/show_bug.cgi?id=199068
         <rdar://problem/51899547>

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (246673 => 246674)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2019-06-21 08:47:26 UTC (rev 246674)
@@ -1,3 +1,17 @@
+2019-06-20  Antoine Quint  <[email protected]>
+
+        [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
+        https://bugs.webkit.org/show_bug.cgi?id=198999
+
+        Reviewed by Dean Jackson.
+
+        Record progressions in two WPT tests and mark updated failures in two other WPT tests.
+
+        * web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
+        * web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt:
+        * web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
+        * web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
+
 2019-06-19  Rob Buis  <[email protected]>
 
         Make preload/link-header-preload-imagesrcset.html work on DPR != 1

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt (246673 => 246674)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -6,5 +6,5 @@
 
 Click on the black box with mouse and do not move the mouse after or during the click.
 
-FAIL mouse Event sequence at implicit release on click assert_equals: expected "pointerout@target, pointerleave@target, pointerover@capture-target, pointerenter@capture-target, gotpointercapture@capture-target, pointerup@capture-target, lostpointercapture@capture-target, pointerout@capture-target, pointerleave@capture-target, pointerover@target, pointerenter@target" but got "gotpointercapture@capture-target, pointerup@capture-target, lostpointercapture@capture-target"
+FAIL mouse Event sequence at implicit release on click assert_equals: expected "pointerout@target, pointerleave@target, pointerover@capture-target, pointerenter@capture-target, gotpointercapture@capture-target, pointerup@capture-target, lostpointercapture@capture-target, pointerout@capture-target, pointerleave@capture-target, pointerover@target, pointerenter@target" but got "pointerout@target, pointerleave@target, pointerover@capture-target, pointerenter@capture-target, gotpointercapture@capture-target, pointerup@target, lostpointercapture@capture-target, pointerout@capture-target, pointerleave@capture-target, pointerover@target, pointerenter@target"
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt (246673 => 246674)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -9,7 +9,7 @@
 
 
 
-FAIL mouse click target during capture assert_equals: An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets expected "pointerdown@green,gotpointercapture@blue,pointerup@blue,click@grey,lostpointercapture@blue" but got "pointerdown@green,gotpointercapture@blue,pointerup@blue,lostpointercapture@blue"
+FAIL mouse click target during capture assert_equals: An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets expected "pointerdown@green,gotpointercapture@blue,pointerup@blue,click@grey,lostpointercapture@blue" but got "pointerdown@green,gotpointercapture@blue,pointerup@green,lostpointercapture@blue"
 PASS Click target when pointerup/down targeted at the same element with no capture 
 PASS Click target when pointerup/down targeted at different elements with no capture 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt (246673 => 246674)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -1,5 +1,5 @@
 
-FAIL Mouse down and capture to green. assert_array_equals: Received events: green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received gotpointercapture,green received pointermove,green received pointerout,green received pointerleave,green received pointerover,green received pointerenter,green received pointermove lengths differ, expected 7 got 11
-FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received pointermove,green received pointermove,green received pointermove lengths differ, expected 11 got 7
-FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received lostpointercapture,green received pointermove,green received pointerout,green received pointerleave,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointermove property 0, expected "green received pointerover" but got "green received pointerout"
+PASS Mouse down and capture to green. 
+PASS Mouse down at green and capture to blue. 
+PASS Mouse down and capture to green, move to blue and release capture 
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt (246673 => 246674)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -16,14 +16,11 @@
 
 The following pointer types were detected: mouse.
 
-The following events were logged: pointerover@target1, gotpointercapture@target0, pointerover@target0, pointerover@target0, lostpointercapture@target0.
+The following events were logged: pointerover@target1, pointerover@target0, gotpointercapture@target0, lostpointercapture@target0.
 
 Refresh the page to run the tests again with a different pointer type.
 
 
-Harness Error (FAIL), message = 1 duplicate test name: "relatedTarget should not be null even when the capture is set."
-
 PASS pointerover shouldn't trigger for the purple rectangle while the black rectangle has capture 
 PASS relatedTarget should not be null even when the capture is set. 
-PASS relatedTarget should not be null even when the capture is set. 
 

Modified: trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt (246673 => 246674)


--- trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -6,5 +6,5 @@
 
 Click on the black box with mouse and do not move the mouse after or during the click.
 
-FAIL mouse Event sequence at implicit release on click assert_equals: expected "pointerout@target, pointerleave@target, pointerover@capture-target, pointerenter@capture-target, gotpointercapture@capture-target, pointerup@capture-target, lostpointercapture@capture-target, pointerout@capture-target, pointerleave@capture-target, pointerover@target, pointerenter@target" but got "gotpointercapture@capture-target, pointerup@capture-target, lostpointercapture@capture-target, pointermove@target"
+FAIL mouse Event sequence at implicit release on click assert_equals: expected "pointerout@target, pointerleave@target, pointerover@capture-target, pointerenter@capture-target, gotpointercapture@capture-target, pointerup@capture-target, lostpointercapture@capture-target, pointerout@capture-target, pointerleave@capture-target, pointerover@target, pointerenter@target" but got "pointerout@target, pointerleave@target, pointerover@capture-target, pointerenter@capture-target, gotpointercapture@capture-target, pointerup@target, lostpointercapture@capture-target, pointerout@capture-target, pointerleave@capture-target, pointerover@target, pointerenter@target, pointermove@target"
 

Copied: trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt (from rev 246673, trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt) (0 => 246674)


--- trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -0,0 +1,15 @@
+Pointer Event: click event during capture
+
+Follow the test instructions with mouse. If you don't have the device skip it.
+
+Test Description: Click event should be sent to the first common ancestor of the pointerdown and pointerup targets.
+Click on the green box with the left button of mouse.
+Press down the left button on the blue box and drag to the green box and release the button.
+Repeat the two steps above once again.
+
+
+
+FAIL mouse click target during capture assert_equals: An element should only receive click when it is the first common ancestor of pointerdown and pointerup targets expected "pointerdown@green,gotpointercapture@blue,pointerup@blue,click@grey,lostpointercapture@blue" but got "pointerdown@green,gotpointercapture@blue,pointerup@blue,lostpointercapture@blue"
+PASS Click target when pointerup/down targeted at the same element with no capture 
+PASS Click target when pointerup/down targeted at different elements with no capture 
+

Deleted: trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame-expected.txt (246673 => 246674)


--- trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -1,7 +0,0 @@
-
-
-FAIL Test pointer capture event route across the same-origin frame: Mouse down at inner frame and set pointer capture. assert_array_equals: Received events: innerFrame received pointermove,innerFrame received pointerdown,innerFrame received gotpointercapture,innerFrame received pointermove,innerFrame received pointermove,innerFrame received pointerup,innerFrame received lostpointercapture,outerFrame received pointermove lengths differ, expected 7 got 8
-FAIL Test pointer capture event route across the same-origin frame: Mouse down at outer frame body and set pointer capture. assert_array_equals: Received events: outerFrame received pointermove,outerFrame received pointerdown,outerFrame received gotpointercapture,outerFrame received pointermove,outerFrame received pointerup,outerFrame received lostpointercapture,innerFrame received pointermove lengths differ, expected 6 got 7
-FAIL Test pointer capture event route across the same-origin frame: Mouse down with set capture at inner frame, then release on next mouse move. assert_array_equals: Received events: innerFrame received pointermove,innerFrame received pointerdown,innerFrame received gotpointercapture,innerFrame received pointermove,innerFrame received lostpointercapture,innerFrameDocument received pointermove,outerFrame received pointerup,innerFrameDocument received pointermove,outerFrame received pointermove lengths differ, expected 7 got 9
-FAIL Test pointercapture event route across the same-origin frame: Mouse down with set capture at outer frame, then release on next mouse move. assert_array_equals: Received events: outerFrame received pointermove,outerFrame received pointerdown,outerFrame received gotpointercapture,outerFrame received pointermove,outerFrame received lostpointercapture,innerFrameElement received pointermove,innerFrameElement received pointerup,innerFrame received pointermove lengths differ, expected 7 got 8
-

Modified: trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt (246673 => 246674)


--- trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt	2019-06-21 08:47:26 UTC (rev 246674)
@@ -16,14 +16,11 @@
 
 The following pointer types were detected: mouse.
 
-The following events were logged: pointerover@target1, gotpointercapture@target0, pointerover@target0, pointerover@target0, lostpointercapture@target0, pointerover@target0.
+The following events were logged: pointerover@target1, pointerover@target0, gotpointercapture@target0, lostpointercapture@target0.
 
 Refresh the page to run the tests again with a different pointer type.
 
 
-Harness Error (FAIL), message = 1 duplicate test name: "relatedTarget should not be null even when the capture is set."
-
 PASS pointerover shouldn't trigger for the purple rectangle while the black rectangle has capture 
 PASS relatedTarget should not be null even when the capture is set. 
-PASS relatedTarget should not be null even when the capture is set. 
 

Modified: trunk/Source/WebCore/ChangeLog (246673 => 246674)


--- trunk/Source/WebCore/ChangeLog	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/ChangeLog	2019-06-21 08:47:26 UTC (rev 246674)
@@ -1,3 +1,53 @@
+2019-06-20  Antoine Quint  <[email protected]>
+
+        [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
+        https://bugs.webkit.org/show_bug.cgi?id=198999
+
+        Reviewed by Dean Jackson.
+
+        Up until now, we would not account for pointer capture (see https://w3c.github.io/pointerevents/#pointer-capture) when dispatching
+        mouse boundary events (mouseover, mouseout, mouseenter, mouseleave) and their counterpart pointer events. We would also not account
+        for it when updating :hover styles.
+
+        Now, when pointer capture changes for an element, we call setCapturingMouseEventsElement() on the EventHandler such that the element
+        that would naturally hit-test is overridden by the pointer capture element when identifying which target to use for the dispatch of
+        boundary mouse events. Additionally, when calling EventHandler::prepareMouseEvent(), we also use the pointer capture element to
+        eventually pass down to Document::updateHoverActiveState() such that :hover styles are applied to the correct element.
+
+        This also means that we need to re-run EventHandler::prepareMouseEvent() during mouse state changes to ensure that the :hover styles
+        are applied correctly should the pointer capture element change during dispatch of boundary mouse events.
+
+        * dom/Document.cpp:
+        (WebCore::Document::prepareMouseEvent): If there is one, use the pointer capture element instead of the hit-test target.
+        (WebCore::Document::updateHoverActiveState): Relax the mustBeInActiveChain condition in case the pointer capture element changed when
+        updating the :hover/:active chains.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::handleMousePressEvent): Re-process the mouse event if the pointer capture element changed during event dispatch.
+        (WebCore::EventHandler::handleMouseMoveEvent): Re-process the mouse event if the pointer capture element changed during event dispatch.
+        (WebCore::EventHandler::handleMouseReleaseEvent): As we know the pointer capture element will be reset as part of the mouse being
+        released, we reset the pointer capture element and EventHandler's capture element prior to invalidating hover styles and boundary events.
+        (WebCore::EventHandler::setCapturingMouseEventsElement): Dispatch boundary events when a new element is set.
+        (WebCore::EventHandler::dispatchMouseEvent): New dispatchMouseEvent() variant that re-processes the provided MouseEventWithHitTestResults
+        in case the pointer capture element changes during event dispatch, as called by handleMousePressEvent() and handleMouseMoveEvent().
+        * page/EventHandler.h:
+        * page/PointerCaptureController.cpp:
+        (WebCore::PointerCaptureController::pointerCaptureElement): We now need to query whay the pointer capture element might be from EventHandler,
+        so expose a new method to access it.
+        (WebCore::PointerCaptureController::releasePointerCapture): Since we may not call processPendingPointerCapture() until the dispatch of the
+        next event, we must reset EventHandler's capturing mouse element right now so that the next event processed does not use it as an overriding target.
+        (WebCore::PointerCaptureController::hasPointerCapture): We would mistakenly return true if the provided element was null, which could be the
+        case of EventHandler's capturing element. Rather than changing call sites to check that the provided value exists, we change the method to
+        return false when the provided element is null. Note that this does not affect the API since it's exposed on Element itself.
+        (WebCore::PointerCaptureController::dispatchEventForTouchAtIndex): Call dispatchEvent() instead of calling pointerEventWillBeDispatched() and
+        pointerEventWasDispatched().
+        (WebCore::PointerCaptureController::dispatchEvent): Remove all code specific to pointer capture since now the events will be dispatched on the
+        pointer capture element by EventHandler.
+        (WebCore::PointerCaptureController::processPendingPointerCapture): Make sure this method is not re-entrant since it dispatches events.
+        * page/PointerCaptureController.h:
+        * rendering/HitTestRequest.h:
+        (WebCore::HitTestRequest::pointerCaptureElementChanged const): Add a new HitTestRequestType bit such that we can indicate to Document::updateHoverActiveState()
+        that it must be update the :hover/:active chains when the pointer capture element has just changed.
+
 2019-06-20  Carlos Garcia Campos  <[email protected]>
 
         [GTK] Stop pretending WebCore::Widget can have a platform widget

Modified: trunk/Source/WebCore/dom/Document.cpp (246673 => 246674)


--- trunk/Source/WebCore/dom/Document.cpp	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/dom/Document.cpp	2019-06-21 08:47:26 UTC (rev 246674)
@@ -320,6 +320,10 @@
 #include "GPUCanvasContext.h"
 #endif
 
+#if ENABLE(POINTER_EVENTS)
+#include "PointerCaptureController.h"
+#endif
+
 namespace WebCore {
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(Document);
@@ -3732,8 +3736,16 @@
     HitTestResult result(documentPoint);
     hitTest(request, result);
 
-    if (!request.readOnly())
-        updateHoverActiveState(request, result.targetElement());
+    if (!request.readOnly()) {
+        auto targetElement = makeRefPtr(result.targetElement());
+#if ENABLE(POINTER_EVENTS)
+        if (auto* page = this->page()) {
+            if (auto* captureElement = page->pointerCaptureController().pointerCaptureElement(mousePointerID))
+                targetElement = captureElement;
+        }
+#endif
+        updateHoverActiveState(request, targetElement.get());
+    }
 
     return MouseEventWithHitTestResults(event, result);
 }
@@ -6776,8 +6788,9 @@
 
     // If the mouse is down and if this is a mouse move event, we want to restrict changes in
     // :hover/:active to only apply to elements that are in the :active chain that we froze
-    // at the time the mouse went down.
-    bool mustBeInActiveChain = request.active() && request.move();
+    // at the time the mouse went down. Unless the pointer capture element was changed, in which
+    // case we want to invalidate the chains anyway.
+    bool mustBeInActiveChain = request.active() && request.move() && !request.pointerCaptureElementChanged();
 
     RefPtr<Element> oldHoveredElement = WTFMove(m_hoveredElement);
 

Modified: trunk/Source/WebCore/page/EventHandler.cpp (246673 => 246674)


--- trunk/Source/WebCore/page/EventHandler.cpp	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2019-06-21 08:47:26 UTC (rev 246674)
@@ -127,6 +127,12 @@
 #include "PointerLockController.h"
 #endif
 
+#if ENABLE(POINTER_EVENTS)
+#include "PointerCaptureController.h"
+#include "Quirks.h"
+#include "RuntimeEnabledFeatures.h"
+#endif
+
 namespace WebCore {
 
 using namespace HTMLNames;
@@ -1789,7 +1795,11 @@
 
     m_frame.selection().setCaretBlinkingSuspended(true);
 
+#if ENABLE(POINTER_EVENTS)
+    bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true, request, mouseEvent);
+#else
     bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
+#endif
     m_capturesDragging = !swallowEvent || mouseEvent.scrollbar();
 
     // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
@@ -2035,7 +2045,12 @@
     if (swallowEvent)
         return true;
     
+#if ENABLE(POINTER_EVENTS)
+    swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true, request, mouseEvent);
+#else
     swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true);
+#endif
+
 #if ENABLE(DRAG_SUPPORT)
     if (!swallowEvent)
         swallowEvent = handleMouseDraggedEvent(mouseEvent);
@@ -2139,6 +2154,20 @@
         return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, platformMouseEvent, setUnder);
     }
 
+    bool shouldFireBoundaryEventsWithClick = true;
+#if ENABLE(POINTER_EVENTS)
+    if (m_frame.page()->pointerCaptureController().hasPointerCapture(m_capturingMouseEventsElement.get(), mousePointerID)) {
+        // If we have pointer capture enabled, it will be disabled by virtue of receiving a "pointerup" event. For :active and :hover
+        // styles to be set correctly when prepareMouseEvent() is called below, we should already reset pointer capture.
+        // We must also reset m_capturingMouseEventsElement to ensure boundary mouse events are dispatched on the hit-testing target.
+        // Finally, the click event target may differ from the hit-testing target, so let's not dispatch boundary mouse events as part of
+        // dispatching the click event below.
+        m_frame.page()->pointerCaptureController().releasePointerCapture(m_capturingMouseEventsElement.get(), mousePointerID);
+        m_capturingMouseEventsElement = nullptr;
+        shouldFireBoundaryEventsWithClick = false;
+    }
+#endif
+
     HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
     MouseEventWithHitTestResults mouseEvent = prepareMouseEvent(request, platformMouseEvent);
     Frame* subframe = m_capturingMouseEventsElement.get() ? subframeForTargetNode(m_capturingMouseEventsElement.get()) : subframeForHitTestResult(mouseEvent);
@@ -2152,8 +2181,13 @@
     bool contextMenuEvent = platformMouseEvent.button() == RightButton;
 
     Node* nodeToClick = targetNodeForClickEvent(m_clickNode.get(), mouseEvent.targetNode());
-    bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, true);
+    bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, shouldFireBoundaryEventsWithClick);
 
+    // Since we did not dispatch boundary mouse events while dispatching the click event, since the click node would have been used,
+    // we need to dispatch them now accounting for the hit-testing node.
+    if (!shouldFireBoundaryEventsWithClick)
+        updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, FireMouseOverOut::Yes);
+
     if (m_resizeLayer) {
         m_resizeLayer->setInResizeMode(false);
         m_resizeLayer = nullptr;
@@ -2478,8 +2512,17 @@
 
 void EventHandler::setCapturingMouseEventsElement(Element* element)
 {
+    if (m_capturingMouseEventsElement == element)
+        return;
+
     m_capturingMouseEventsElement = element;
     m_eventHandlerWillResetCapturingMouseEventsElement = false;
+
+#if ENABLE(POINTER_EVENTS)
+    // If we have a new capture element, we need to dispatch boundary mouse events.
+    if (element && !element->document().quirks().shouldDisablePointerEventsQuirk() && RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled())
+        updateMouseEventTargetNode(element, m_mouseDown, FireMouseOverOut::Yes);
+#endif
 }
 
 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mouseEvent)
@@ -2603,6 +2646,22 @@
     }
 }
 
+#if ENABLE(POINTER_EVENTS)
+bool EventHandler::dispatchMouseEvent(const AtomString& eventType, Node* targetNode, bool cancelable, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder, const HitTestRequest& request, MouseEventWithHitTestResults& mouseEvent)
+{
+    if (!RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled() || (targetNode && targetNode->ownerDocument() && targetNode->document().quirks().shouldDisablePointerEventsQuirk()))
+        return dispatchMouseEvent(eventType, targetNode, cancelable, clickCount, platformMouseEvent, setUnder);
+
+    auto& pointerCaptureController = m_frame.page()->pointerCaptureController();
+    auto* oldCaptureElement = pointerCaptureController.pointerCaptureElement(mousePointerID);
+    bool defaultPrevented = dispatchMouseEvent(eventType, targetNode, cancelable, clickCount, platformMouseEvent, setUnder);
+    auto* newCaptureElement = pointerCaptureController.pointerCaptureElement(mousePointerID);
+    if (oldCaptureElement != newCaptureElement)
+        mouseEvent = prepareMouseEvent(HitTestRequest(request.type() | HitTestRequest::PointerCaptureElementChanged), platformMouseEvent);
+    return defaultPrevented;
+}
+#endif
+
 bool EventHandler::dispatchMouseEvent(const AtomString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder)
 {
     Ref<Frame> protectedFrame(m_frame);

Modified: trunk/Source/WebCore/page/EventHandler.h (246673 => 246674)


--- trunk/Source/WebCore/page/EventHandler.h	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/page/EventHandler.h	2019-06-21 08:47:26 UTC (rev 246674)
@@ -413,6 +413,9 @@
     MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&);
 
     bool dispatchMouseEvent(const AtomString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
+#if ENABLE(POINTER_EVENTS)
+    bool dispatchMouseEvent(const AtomString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder, const HitTestRequest&, MouseEventWithHitTestResults&);
+#endif
 
 #if ENABLE(DRAG_SUPPORT)
     bool dispatchDragEvent(const AtomString& eventType, Element& target, const PlatformMouseEvent&, DataTransfer&);

Modified: trunk/Source/WebCore/page/PointerCaptureController.cpp (246673 => 246674)


--- trunk/Source/WebCore/page/PointerCaptureController.cpp	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/page/PointerCaptureController.cpp	2019-06-21 08:47:26 UTC (rev 246674)
@@ -48,6 +48,14 @@
     reset();
 }
 
+Element* PointerCaptureController::pointerCaptureElement(PointerID pointerId)
+{
+    auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
+    if (iterator != m_activePointerIdsToCapturingData.end())
+        return iterator->value.pendingTargetOverride.get();
+    return nullptr;
+}
+
 ExceptionOr<void> PointerCaptureController::setPointerCapture(Element* capturingTarget, PointerID pointerId)
 {
     // https://w3c.github.io/pointerevents/#setting-pointer-capture
@@ -98,6 +106,11 @@
     // 3. For the specified pointerId, clear the pending pointer capture target override, if set.
     iterator->value.pendingTargetOverride = nullptr;
 
+    // Since we may not call processPendingPointerCapture() until the dispatch of the next event,
+    // we must reset EventHandler's capturing mouse element right now so that the next event processed
+    // does not use it as an overriding target.
+    m_page.mainFrame().eventHandler().setCapturingMouseEventsElement(nullptr);
+
     return { };
 }
 
@@ -109,6 +122,9 @@
     // In particular, returns true if the pending pointer capture target override for pointerId is set to the element on which this method is
     // invoked, and false otherwise.
 
+    if (!capturingTarget)
+        return false;
+
     auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
     return iterator != m_activePointerIdsToCapturingData.end() && iterator->value.pendingTargetOverride == capturingTarget;
 }
@@ -174,7 +190,7 @@
 #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
 void PointerCaptureController::dispatchEventForTouchAtIndex(EventTarget& target, const PlatformTouchEvent& platformTouchEvent, unsigned index, bool isPrimary, WindowProxy& view)
 {
-    auto dispatchEvent = [&](const String& type) {
+    auto dispatchOverOrOutEvent = [&](const String& type) {
         target.dispatchEvent(PointerEvent::create(type, platformTouchEvent, index, isPrimary, view));
     };
 
@@ -213,19 +229,17 @@
         // 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.
-        dispatchEvent(eventNames().pointeroverEvent);
+        dispatchOverOrOutEvent(eventNames().pointeroverEvent);
         dispatchEnterOrLeaveEvent(eventNames().pointerenterEvent);
     }
 
-    pointerEventWillBeDispatched(pointerEvent, &target);
-    target.dispatchEvent(pointerEvent);
-    pointerEventWasDispatched(pointerEvent);
+    dispatchEvent(pointerEvent, &target);
 
     if (pointerEvent->type() == eventNames().pointerupEvent) {
         // 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.
-        dispatchEvent(eventNames().pointeroutEvent);
+        dispatchOverOrOutEvent(eventNames().pointeroutEvent);
         dispatchEnterOrLeaveEvent(eventNames().pointerleaveEvent);
     }
 }
@@ -268,16 +282,6 @@
 
 void PointerCaptureController::dispatchEvent(PointerEvent& event, EventTarget* target)
 {
-    auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
-    if (iterator != m_activePointerIdsToCapturingData.end()) {
-        auto& capturingData = iterator->value;
-        if (capturingData.pendingTargetOverride && capturingData.targetOverride)
-            target = capturingData.targetOverride.get();
-    }
-
-    if (!target || event.target())
-        return;
-
     pointerEventWillBeDispatched(event, target);
     target->dispatchEvent(event);
     pointerEventWasDispatched(event);
@@ -401,6 +405,11 @@
 
 void PointerCaptureController::processPendingPointerCapture(const PointerEvent& event)
 {
+    if (m_processingPendingPointerCapture)
+        return;
+    
+    m_processingPendingPointerCapture = true;
+    
     // https://w3c.github.io/pointerevents/#process-pending-pointer-capture
 
     auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
@@ -411,17 +420,23 @@
 
     // 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 != capturingData.pendingTargetOverride)
+    if (capturingData.targetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride) {
+        m_page.mainFrame().eventHandler().setCapturingMouseEventsElement(nullptr);
         capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, event));
+    }
 
     // 2. If the pending pointer capture target override for this pointer is set and is not equal to the pointer capture target override,
     // then fire a pointer event named gotpointercapture at the pending pointer capture target override.
-    if (capturingData.pendingTargetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride)
+    if (capturingData.pendingTargetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride) {
+        m_page.mainFrame().eventHandler().setCapturingMouseEventsElement(capturingData.pendingTargetOverride.get());
         capturingData.pendingTargetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().gotpointercaptureEvent, event));
+    }
 
     // 3. Set the pointer capture target override to the pending pointer capture target override, if set. Otherwise, clear the pointer
     // capture target override.
     capturingData.targetOverride = capturingData.pendingTargetOverride;
+
+    m_processingPendingPointerCapture = false;
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/PointerCaptureController.h (246673 => 246674)


--- trunk/Source/WebCore/page/PointerCaptureController.h	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/page/PointerCaptureController.h	2019-06-21 08:47:26 UTC (rev 246674)
@@ -60,6 +60,7 @@
     bool preventsCompatibilityMouseEventsForIdentifier(PointerID);
     void dispatchEvent(PointerEvent&, EventTarget*);
     WEBCORE_EXPORT void cancelPointer(PointerID, const IntPoint&);
+    Element* pointerCaptureElement(PointerID);
 
 private:
     struct CapturingData {
@@ -82,6 +83,7 @@
     // empty and removed values, allowing any int32_t to be provided through the API for lookup in this hashmap.
     using PointerIdToCapturingDataMap = HashMap<int64_t, CapturingData, WTF::IntHash<int64_t>, WTF::SignedWithZeroKeyHashTraits<int64_t>>;
     PointerIdToCapturingDataMap m_activePointerIdsToCapturingData;
+    bool m_processingPendingPointerCapture { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/HitTestRequest.h (246673 => 246674)


--- trunk/Source/WebCore/rendering/HitTestRequest.h	2019-06-21 07:05:10 UTC (rev 246673)
+++ trunk/Source/WebCore/rendering/HitTestRequest.h	2019-06-21 08:47:26 UTC (rev 246674)
@@ -44,7 +44,9 @@
         // Collect a list of nodes instead of just one. Used for elementsFromPoint and rect-based tests.
         CollectMultipleElements = 1 << 13,
         // When using list-based testing, continue hit testing even after a hit has been found.
-        IncludeAllElementsUnderPoint = 1 << 14
+        IncludeAllElementsUnderPoint = 1 << 14,
+        // When the pointer capture target has changed, we should disregard the move and active bits when invalidating the :active and :hover chains.
+        PointerCaptureElementChanged = 1 << 15
     };
 
     typedef unsigned HitTestRequestType;
@@ -69,6 +71,7 @@
     bool isChildFrameHitTest() const { return m_requestType & ChildFrameHitTest; }
     bool resultIsElementList() const { return m_requestType & CollectMultipleElements; }
     bool includesAllElementsUnderPoint() const { return m_requestType & IncludeAllElementsUnderPoint; }
+    bool pointerCaptureElementChanged() const { return m_requestType & PointerCaptureElementChanged; }
 
     // Convenience functions
     bool touchMove() const { return move() && touchEvent(); }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to