Changeset 246674 in webkit


Ignore:
Timestamp:
Jun 21, 2019 1:47:26 AM (5 years ago)
Author:
graouts@webkit.org
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:
Location:
trunk
Files:
3 deleted
15 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r246673 r246674  
     12019-06-20  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
     4        https://bugs.webkit.org/show_bug.cgi?id=198999
     5
     6        Reviewed by Dean Jackson.
     7
     8        Record progressions in two WPT tests and mark updated failures in two other WPT tests.
     9
     10        * platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt: Removed.
     11        * platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt: Removed.
     12        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
     13        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt: Added.
     14        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame-expected.txt: Removed.
     15        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
     16
    1172019-06-20  Antoine Quint  <graouts@apple.com>
    218
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r246629 r246674  
     12019-06-20  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
     4        https://bugs.webkit.org/show_bug.cgi?id=198999
     5
     6        Reviewed by Dean Jackson.
     7
     8        Record progressions in two WPT tests and mark updated failures in two other WPT tests.
     9
     10        * web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
     11        * web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt:
     12        * web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
     13        * web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
     14
    1152019-06-19  Rob Buis  <rbuis@igalia.com>
    216
  • trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt

    r244393 r246674  
    77Click on the black box with mouse and do not move the mouse after or during the click.
    88
    9 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"
     9FAIL 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"
    1010
  • trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_click_during_capture-expected.txt

    r244393 r246674  
    1010
    1111
    12 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"
     12FAIL 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"
    1313PASS Click target when pointerup/down targeted at the same element with no capture
    1414PASS Click target when pointerup/down targeted at different elements with no capture
  • trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt

    r246122 r246674  
    11
    2 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
    3 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
    4 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"
     2PASS Mouse down and capture to green.
     3PASS Mouse down at green and capture to blue.
     4PASS Mouse down and capture to green, move to blue and release capture
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt

    r244393 r246674  
    1717The following pointer types were detected: mouse.
    1818
    19 The following events were logged: pointerover@target1, gotpointercapture@target0, pointerover@target0, pointerover@target0, lostpointercapture@target0.
     19The following events were logged: pointerover@target1, pointerover@target0, gotpointercapture@target0, lostpointercapture@target0.
    2020
    2121Refresh the page to run the tests again with a different pointer type.
    2222
    2323
    24 Harness Error (FAIL), message = 1 duplicate test name: "relatedTarget should not be null even when the capture is set."
    25 
    2624PASS pointerover shouldn't trigger for the purple rectangle while the black rectangle has capture
    2725PASS relatedTarget should not be null even when the capture is set.
    28 PASS relatedTarget should not be null even when the capture is set.
    2926
  • trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt

    r244393 r246674  
    77Click on the black box with mouse and do not move the mouse after or during the click.
    88
    9 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"
     9FAIL 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"
    1010
  • trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt

    r244393 r246674  
    1717The following pointer types were detected: mouse.
    1818
    19 The following events were logged: pointerover@target1, gotpointercapture@target0, pointerover@target0, pointerover@target0, lostpointercapture@target0, pointerover@target0.
     19The following events were logged: pointerover@target1, pointerover@target0, gotpointercapture@target0, lostpointercapture@target0.
    2020
    2121Refresh the page to run the tests again with a different pointer type.
    2222
    2323
    24 Harness Error (FAIL), message = 1 duplicate test name: "relatedTarget should not be null even when the capture is set."
    25 
    2624PASS pointerover shouldn't trigger for the purple rectangle while the black rectangle has capture
    2725PASS relatedTarget should not be null even when the capture is set.
    28 PASS relatedTarget should not be null even when the capture is set.
    2926
  • trunk/Source/WebCore/ChangeLog

    r246669 r246674  
     12019-06-20  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
     4        https://bugs.webkit.org/show_bug.cgi?id=198999
     5
     6        Reviewed by Dean Jackson.
     7
     8        Up until now, we would not account for pointer capture (see https://w3c.github.io/pointerevents/#pointer-capture) when dispatching
     9        mouse boundary events (mouseover, mouseout, mouseenter, mouseleave) and their counterpart pointer events. We would also not account
     10        for it when updating :hover styles.
     11
     12        Now, when pointer capture changes for an element, we call setCapturingMouseEventsElement() on the EventHandler such that the element
     13        that would naturally hit-test is overridden by the pointer capture element when identifying which target to use for the dispatch of
     14        boundary mouse events. Additionally, when calling EventHandler::prepareMouseEvent(), we also use the pointer capture element to
     15        eventually pass down to Document::updateHoverActiveState() such that :hover styles are applied to the correct element.
     16
     17        This also means that we need to re-run EventHandler::prepareMouseEvent() during mouse state changes to ensure that the :hover styles
     18        are applied correctly should the pointer capture element change during dispatch of boundary mouse events.
     19
     20        * dom/Document.cpp:
     21        (WebCore::Document::prepareMouseEvent): If there is one, use the pointer capture element instead of the hit-test target.
     22        (WebCore::Document::updateHoverActiveState): Relax the mustBeInActiveChain condition in case the pointer capture element changed when
     23        updating the :hover/:active chains.
     24        * page/EventHandler.cpp:
     25        (WebCore::EventHandler::handleMousePressEvent): Re-process the mouse event if the pointer capture element changed during event dispatch.
     26        (WebCore::EventHandler::handleMouseMoveEvent): Re-process the mouse event if the pointer capture element changed during event dispatch.
     27        (WebCore::EventHandler::handleMouseReleaseEvent): As we know the pointer capture element will be reset as part of the mouse being
     28        released, we reset the pointer capture element and EventHandler's capture element prior to invalidating hover styles and boundary events.
     29        (WebCore::EventHandler::setCapturingMouseEventsElement): Dispatch boundary events when a new element is set.
     30        (WebCore::EventHandler::dispatchMouseEvent): New dispatchMouseEvent() variant that re-processes the provided MouseEventWithHitTestResults
     31        in case the pointer capture element changes during event dispatch, as called by handleMousePressEvent() and handleMouseMoveEvent().
     32        * page/EventHandler.h:
     33        * page/PointerCaptureController.cpp:
     34        (WebCore::PointerCaptureController::pointerCaptureElement): We now need to query whay the pointer capture element might be from EventHandler,
     35        so expose a new method to access it.
     36        (WebCore::PointerCaptureController::releasePointerCapture): Since we may not call processPendingPointerCapture() until the dispatch of the
     37        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.
     38        (WebCore::PointerCaptureController::hasPointerCapture): We would mistakenly return true if the provided element was null, which could be the
     39        case of EventHandler's capturing element. Rather than changing call sites to check that the provided value exists, we change the method to
     40        return false when the provided element is null. Note that this does not affect the API since it's exposed on Element itself.
     41        (WebCore::PointerCaptureController::dispatchEventForTouchAtIndex): Call dispatchEvent() instead of calling pointerEventWillBeDispatched() and
     42        pointerEventWasDispatched().
     43        (WebCore::PointerCaptureController::dispatchEvent): Remove all code specific to pointer capture since now the events will be dispatched on the
     44        pointer capture element by EventHandler.
     45        (WebCore::PointerCaptureController::processPendingPointerCapture): Make sure this method is not re-entrant since it dispatches events.
     46        * page/PointerCaptureController.h:
     47        * rendering/HitTestRequest.h:
     48        (WebCore::HitTestRequest::pointerCaptureElementChanged const): Add a new HitTestRequestType bit such that we can indicate to Document::updateHoverActiveState()
     49        that it must be update the :hover/:active chains when the pointer capture element has just changed.
     50
    1512019-06-20  Carlos Garcia Campos  <cgarcia@igalia.com>
    252
  • trunk/Source/WebCore/dom/Document.cpp

    r246490 r246674  
    321321#endif
    322322
     323#if ENABLE(POINTER_EVENTS)
     324#include "PointerCaptureController.h"
     325#endif
     326
    323327namespace WebCore {
    324328
     
    37333737    hitTest(request, result);
    37343738
    3735     if (!request.readOnly())
    3736         updateHoverActiveState(request, result.targetElement());
     3739    if (!request.readOnly()) {
     3740        auto targetElement = makeRefPtr(result.targetElement());
     3741#if ENABLE(POINTER_EVENTS)
     3742        if (auto* page = this->page()) {
     3743            if (auto* captureElement = page->pointerCaptureController().pointerCaptureElement(mousePointerID))
     3744                targetElement = captureElement;
     3745        }
     3746#endif
     3747        updateHoverActiveState(request, targetElement.get());
     3748    }
    37373749
    37383750    return MouseEventWithHitTestResults(event, result);
     
    67776789    // If the mouse is down and if this is a mouse move event, we want to restrict changes in
    67786790    // :hover/:active to only apply to elements that are in the :active chain that we froze
    6779     // at the time the mouse went down.
    6780     bool mustBeInActiveChain = request.active() && request.move();
     6791    // at the time the mouse went down. Unless the pointer capture element was changed, in which
     6792    // case we want to invalidate the chains anyway.
     6793    bool mustBeInActiveChain = request.active() && request.move() && !request.pointerCaptureElementChanged();
    67816794
    67826795    RefPtr<Element> oldHoveredElement = WTFMove(m_hoveredElement);
  • trunk/Source/WebCore/page/EventHandler.cpp

    r246490 r246674  
    128128#endif
    129129
     130#if ENABLE(POINTER_EVENTS)
     131#include "PointerCaptureController.h"
     132#include "Quirks.h"
     133#include "RuntimeEnabledFeatures.h"
     134#endif
     135
    130136namespace WebCore {
    131137
     
    17901796    m_frame.selection().setCaretBlinkingSuspended(true);
    17911797
     1798#if ENABLE(POINTER_EVENTS)
     1799    bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true, request, mouseEvent);
     1800#else
    17921801    bool swallowEvent = !dispatchMouseEvent(eventNames().mousedownEvent, mouseEvent.targetNode(), true, m_clickCount, platformMouseEvent, true);
     1802#endif
    17931803    m_capturesDragging = !swallowEvent || mouseEvent.scrollbar();
    17941804
     
    20362046        return true;
    20372047   
     2048#if ENABLE(POINTER_EVENTS)
     2049    swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true, request, mouseEvent);
     2050#else
    20382051    swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true);
     2052#endif
     2053
    20392054#if ENABLE(DRAG_SUPPORT)
    20402055    if (!swallowEvent)
     
    21392154        return !dispatchMouseEvent(eventNames().mouseupEvent, m_lastElementUnderMouse.get(), cancelable, m_clickCount, platformMouseEvent, setUnder);
    21402155    }
     2156
     2157    bool shouldFireBoundaryEventsWithClick = true;
     2158#if ENABLE(POINTER_EVENTS)
     2159    if (m_frame.page()->pointerCaptureController().hasPointerCapture(m_capturingMouseEventsElement.get(), mousePointerID)) {
     2160        // If we have pointer capture enabled, it will be disabled by virtue of receiving a "pointerup" event. For :active and :hover
     2161        // styles to be set correctly when prepareMouseEvent() is called below, we should already reset pointer capture.
     2162        // We must also reset m_capturingMouseEventsElement to ensure boundary mouse events are dispatched on the hit-testing target.
     2163        // Finally, the click event target may differ from the hit-testing target, so let's not dispatch boundary mouse events as part of
     2164        // dispatching the click event below.
     2165        m_frame.page()->pointerCaptureController().releasePointerCapture(m_capturingMouseEventsElement.get(), mousePointerID);
     2166        m_capturingMouseEventsElement = nullptr;
     2167        shouldFireBoundaryEventsWithClick = false;
     2168    }
     2169#endif
    21412170
    21422171    HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
     
    21532182
    21542183    Node* nodeToClick = targetNodeForClickEvent(m_clickNode.get(), mouseEvent.targetNode());
    2155     bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, true);
     2184    bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, shouldFireBoundaryEventsWithClick);
     2185
     2186    // Since we did not dispatch boundary mouse events while dispatching the click event, since the click node would have been used,
     2187    // we need to dispatch them now accounting for the hit-testing node.
     2188    if (!shouldFireBoundaryEventsWithClick)
     2189        updateMouseEventTargetNode(mouseEvent.targetNode(), platformMouseEvent, FireMouseOverOut::Yes);
    21562190
    21572191    if (m_resizeLayer) {
     
    24792513void EventHandler::setCapturingMouseEventsElement(Element* element)
    24802514{
     2515    if (m_capturingMouseEventsElement == element)
     2516        return;
     2517
    24812518    m_capturingMouseEventsElement = element;
    24822519    m_eventHandlerWillResetCapturingMouseEventsElement = false;
     2520
     2521#if ENABLE(POINTER_EVENTS)
     2522    // If we have a new capture element, we need to dispatch boundary mouse events.
     2523    if (element && !element->document().quirks().shouldDisablePointerEventsQuirk() && RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled())
     2524        updateMouseEventTargetNode(element, m_mouseDown, FireMouseOverOut::Yes);
     2525#endif
    24832526}
    24842527
     
    26032646    }
    26042647}
     2648
     2649#if ENABLE(POINTER_EVENTS)
     2650bool EventHandler::dispatchMouseEvent(const AtomString& eventType, Node* targetNode, bool cancelable, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder, const HitTestRequest& request, MouseEventWithHitTestResults& mouseEvent)
     2651{
     2652    if (!RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled() || (targetNode && targetNode->ownerDocument() && targetNode->document().quirks().shouldDisablePointerEventsQuirk()))
     2653        return dispatchMouseEvent(eventType, targetNode, cancelable, clickCount, platformMouseEvent, setUnder);
     2654
     2655    auto& pointerCaptureController = m_frame.page()->pointerCaptureController();
     2656    auto* oldCaptureElement = pointerCaptureController.pointerCaptureElement(mousePointerID);
     2657    bool defaultPrevented = dispatchMouseEvent(eventType, targetNode, cancelable, clickCount, platformMouseEvent, setUnder);
     2658    auto* newCaptureElement = pointerCaptureController.pointerCaptureElement(mousePointerID);
     2659    if (oldCaptureElement != newCaptureElement)
     2660        mouseEvent = prepareMouseEvent(HitTestRequest(request.type() | HitTestRequest::PointerCaptureElementChanged), platformMouseEvent);
     2661    return defaultPrevented;
     2662}
     2663#endif
    26052664
    26062665bool EventHandler::dispatchMouseEvent(const AtomString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& platformMouseEvent, bool setUnder)
  • trunk/Source/WebCore/page/EventHandler.h

    r246490 r246674  
    414414
    415415    bool dispatchMouseEvent(const AtomString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
     416#if ENABLE(POINTER_EVENTS)
     417    bool dispatchMouseEvent(const AtomString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder, const HitTestRequest&, MouseEventWithHitTestResults&);
     418#endif
    416419
    417420#if ENABLE(DRAG_SUPPORT)
  • trunk/Source/WebCore/page/PointerCaptureController.cpp

    r246445 r246674  
    4949}
    5050
     51Element* PointerCaptureController::pointerCaptureElement(PointerID pointerId)
     52{
     53    auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
     54    if (iterator != m_activePointerIdsToCapturingData.end())
     55        return iterator->value.pendingTargetOverride.get();
     56    return nullptr;
     57}
     58
    5159ExceptionOr<void> PointerCaptureController::setPointerCapture(Element* capturingTarget, PointerID pointerId)
    5260{
     
    99107    iterator->value.pendingTargetOverride = nullptr;
    100108
     109    // Since we may not call processPendingPointerCapture() until the dispatch of the next event,
     110    // we must reset EventHandler's capturing mouse element right now so that the next event processed
     111    // does not use it as an overriding target.
     112    m_page.mainFrame().eventHandler().setCapturingMouseEventsElement(nullptr);
     113
    101114    return { };
    102115}
     
    109122    // In particular, returns true if the pending pointer capture target override for pointerId is set to the element on which this method is
    110123    // invoked, and false otherwise.
     124
     125    if (!capturingTarget)
     126        return false;
    111127
    112128    auto iterator = m_activePointerIdsToCapturingData.find(pointerId);
     
    175191void PointerCaptureController::dispatchEventForTouchAtIndex(EventTarget& target, const PlatformTouchEvent& platformTouchEvent, unsigned index, bool isPrimary, WindowProxy& view)
    176192{
    177     auto dispatchEvent = [&](const String& type) {
     193    auto dispatchOverOrOutEvent = [&](const String& type) {
    178194        target.dispatchEvent(PointerEvent::create(type, platformTouchEvent, index, isPrimary, view));
    179195    };
     
    214230        // 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
    215231        // pointerenter prior to dispatching the pointerdown event.
    216         dispatchEvent(eventNames().pointeroverEvent);
     232        dispatchOverOrOutEvent(eventNames().pointeroverEvent);
    217233        dispatchEnterOrLeaveEvent(eventNames().pointerenterEvent);
    218234    }
    219235
    220     pointerEventWillBeDispatched(pointerEvent, &target);
    221     target.dispatchEvent(pointerEvent);
    222     pointerEventWasDispatched(pointerEvent);
     236    dispatchEvent(pointerEvent, &target);
    223237
    224238    if (pointerEvent->type() == eventNames().pointerupEvent) {
     
    226240        // For input devices that do not support hover, a user agent MUST also fire a pointer event named pointerout followed by a
    227241        // pointer event named pointerleave after dispatching the pointerup event.
    228         dispatchEvent(eventNames().pointeroutEvent);
     242        dispatchOverOrOutEvent(eventNames().pointeroutEvent);
    229243        dispatchEnterOrLeaveEvent(eventNames().pointerleaveEvent);
    230244    }
     
    269283void PointerCaptureController::dispatchEvent(PointerEvent& event, EventTarget* target)
    270284{
    271     auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId());
    272     if (iterator != m_activePointerIdsToCapturingData.end()) {
    273         auto& capturingData = iterator->value;
    274         if (capturingData.pendingTargetOverride && capturingData.targetOverride)
    275             target = capturingData.targetOverride.get();
    276     }
    277 
    278     if (!target || event.target())
    279         return;
    280 
    281285    pointerEventWillBeDispatched(event, target);
    282286    target->dispatchEvent(event);
     
    402406void PointerCaptureController::processPendingPointerCapture(const PointerEvent& event)
    403407{
     408    if (m_processingPendingPointerCapture)
     409        return;
     410   
     411    m_processingPendingPointerCapture = true;
     412   
    404413    // https://w3c.github.io/pointerevents/#process-pending-pointer-capture
    405414
     
    412421    // 1. If the pointer capture target override for this pointer is set and is not equal to the pending pointer capture target override,
    413422    // then fire a pointer event named lostpointercapture at the pointer capture target override node.
    414     if (capturingData.targetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride)
     423    if (capturingData.targetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride) {
     424        m_page.mainFrame().eventHandler().setCapturingMouseEventsElement(nullptr);
    415425        capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, event));
     426    }
    416427
    417428    // 2. If the pending pointer capture target override for this pointer is set and is not equal to the pointer capture target override,
    418429    // then fire a pointer event named gotpointercapture at the pending pointer capture target override.
    419     if (capturingData.pendingTargetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride)
     430    if (capturingData.pendingTargetOverride && capturingData.targetOverride != capturingData.pendingTargetOverride) {
     431        m_page.mainFrame().eventHandler().setCapturingMouseEventsElement(capturingData.pendingTargetOverride.get());
    420432        capturingData.pendingTargetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().gotpointercaptureEvent, event));
     433    }
    421434
    422435    // 3. Set the pointer capture target override to the pending pointer capture target override, if set. Otherwise, clear the pointer
    423436    // capture target override.
    424437    capturingData.targetOverride = capturingData.pendingTargetOverride;
     438
     439    m_processingPendingPointerCapture = false;
    425440}
    426441
  • trunk/Source/WebCore/page/PointerCaptureController.h

    r246103 r246674  
    6161    void dispatchEvent(PointerEvent&, EventTarget*);
    6262    WEBCORE_EXPORT void cancelPointer(PointerID, const IntPoint&);
     63    Element* pointerCaptureElement(PointerID);
    6364
    6465private:
     
    8384    using PointerIdToCapturingDataMap = HashMap<int64_t, CapturingData, WTF::IntHash<int64_t>, WTF::SignedWithZeroKeyHashTraits<int64_t>>;
    8485    PointerIdToCapturingDataMap m_activePointerIdsToCapturingData;
     86    bool m_processingPendingPointerCapture { false };
    8587};
    8688
  • trunk/Source/WebCore/rendering/HitTestRequest.h

    r219961 r246674  
    4545        CollectMultipleElements = 1 << 13,
    4646        // When using list-based testing, continue hit testing even after a hit has been found.
    47         IncludeAllElementsUnderPoint = 1 << 14
     47        IncludeAllElementsUnderPoint = 1 << 14,
     48        // When the pointer capture target has changed, we should disregard the move and active bits when invalidating the :active and :hover chains.
     49        PointerCaptureElementChanged = 1 << 15
    4850    };
    4951
     
    7072    bool resultIsElementList() const { return m_requestType & CollectMultipleElements; }
    7173    bool includesAllElementsUnderPoint() const { return m_requestType & IncludeAllElementsUnderPoint; }
     74    bool pointerCaptureElementChanged() const { return m_requestType & PointerCaptureElementChanged; }
    7275
    7376    // Convenience functions
Note: See TracChangeset for help on using the changeset viewer.