Changeset 247148 in webkit
- Timestamp:
- Jul 5, 2019 3:25:06 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r247147 r247148 1 2019-07-05 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 <rdar://problem/51979477> 6 7 Reviewed by Dean Jackson. 8 9 Update some WK1-specific expectations. 10 11 * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt: 12 * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt: 13 1 14 2019-07-04 Zalan Bujtas <zalan@apple.com> 2 15 -
trunk/LayoutTests/imported/w3c/ChangeLog
r247024 r247148 1 2019-07-05 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 <rdar://problem/51979477> 6 7 Reviewed by Dean Jackson. 8 9 Mark the progressions in 3 WPT tests. 10 11 * web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-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 1 15 2019-07-01 Truitt Savell <tsavell@apple.com> 2 16 -
trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt
r247024 r247148 1 1 Pointer Event: Boundary event sequence at implicit capture release 2 3 Follow the test instructions with mouse. If you don't have the device skip it.4 2 5 3 When a captured pointer is implicitly released after a click, the boundary events should follow the lostpointercapture event. … … 7 5 Click on the black box with mouse and do not move the mouse after or during the click. 8 6 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" 7 PASS mouse Event sequence at implicit release on click 10 8 -
trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt
r247024 r247148 1 1 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" 2 PASS Mouse down and capture to green. 3 PASS Mouse down at green and capture to blue. 4 PASS Mouse down and capture to green, move to blue and release capture 5 5 -
trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt
r247024 r247148 17 17 The following pointer types were detected: mouse. 18 18 19 The following events were logged: pointerover@target1, gotpointercapture@target0, pointerover@target0, pointerover@target0, lostpointercapture@target0.19 The following events were logged: pointerover@target1, pointerover@target0, gotpointercapture@target0, lostpointercapture@target0. 20 20 21 21 Refresh the page to run the tests again with a different pointer type. 22 22 23 23 24 Harness Error (FAIL), message = 1 duplicate test name: "relatedTarget should not be null even when the capture is set."25 26 24 PASS pointerover shouldn't trigger for the purple rectangle while the black rectangle has capture 27 25 PASS relatedTarget should not be null even when the capture is set. 28 PASS relatedTarget should not be null even when the capture is set.29 26 -
trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt
r247024 r247148 7 7 Click on the black box with mouse and do not move the mouse after or during the click. 8 8 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"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 "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, pointermove@target" 10 10 -
trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt
r247024 r247148 17 17 The following pointer types were detected: mouse. 18 18 19 The following events were logged: pointerover@target1, gotpointercapture@target0, pointerover@target0, pointerover@target0, lostpointercapture@target0, pointerover@target0.19 The following events were logged: pointerover@target1, pointerover@target0, gotpointercapture@target0, lostpointercapture@target0, pointerover@target0. 20 20 21 21 Refresh the page to run the tests again with a different pointer type. 22 22 23 23 24 Harness Error (FAIL), message = 1 duplicate test name: "relatedTarget should not be null even when the capture is set."25 26 24 PASS pointerover shouldn't trigger for the purple rectangle while the black rectangle has capture 27 25 PASS relatedTarget should not be null even when the capture is set. 28 PASS relatedTarget should not be null even when the capture is set.29 26 -
trunk/Source/WebCore/ChangeLog
r247147 r247148 1 2019-07-05 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 <rdar://problem/51979477> 6 7 Reviewed by Dean Jackson. 8 9 Up until now, we would not account for pointer capture (see https://w3c.github.io/pointerevents/#pointer-capture) when dispatching 10 mouse boundary events (mouseover, mouseout, mouseenter, mouseleave) and their counterpart pointer events. We would also not account 11 for it when updating :hover styles. 12 13 Now, when pointer capture changes for an element, we call setCapturingMouseEventsElement() on the EventHandler such that the element 14 that would naturally hit-test is overridden by the pointer capture element when identifying which target to use for the dispatch of 15 boundary mouse events. Additionally, when calling Document::prepareMouseEvent(), we also use the pointer capture element to 16 pass down to Document::updateHoverActiveState() such that :hover styles are applied to the correct element. 17 18 * dom/Document.cpp: 19 (WebCore::Document::prepareMouseEvent): When a new event is going to be dispatched, we must run the Process Pending Capture Element 20 steps as mandated by the Pointer Events spec. Calling this will dispatch the appropriate pointer capture change events and also 21 required boundary events since EventHandler::setCapturingMouseEventsElement() calls into EventHandler::updateMouseEventTargetNode(). 22 Since this may update the capturing mouse events element, we ensure that we call updateHoverActiveState() with a flag that indicates that. 23 Finally, we use the capturing mouse events element instead of the hit-testing element to pass to updateHoverActiveState() to ensure 24 that is has :hover styles applied. 25 (WebCore::Document::updateHoverActiveState): Account for the new CaptureChange flag to force the invalidation of the :hover and :active 26 elements chain at all times when the capturing mouse events element changed. 27 * dom/Document.h: 28 * dom/PointerEvent.h: Update PointerEvent::createForPointerCapture() to take specific parameters rather than a single PointerEvent to 29 set the pointerId, isPrimary and pointerType properties of the generated event. This is required to call processPendingPointerCapture() 30 outside of PointerEvent dispatch logic since we now call it from Document::prepareMouseEvent() where we haven't yet generated such an 31 event. 32 * page/EventHandler.cpp: 33 (WebCore::EventHandler::pointerCaptureElementDidChange): When a new pointer capture element is set, call updateMouseEventTargetNode() 34 to ensure that boundary events are fired to indicate the pointer capture state change. 35 (WebCore::EventHandler::prepareMouseEvent): Keep track of the last PlatformMouseEvent used to prepare a mouse event so that we can use 36 it when setCapturingMouseEventsElement() is called. 37 * page/EventHandler.h: 38 * page/PointerCaptureController.cpp: 39 (WebCore::PointerCaptureController::pointerCaptureElement): Since Document::prepareMouseEvent() needs to know the current pointer capture 40 element, add a new public method that indicates the pointer capture element if that element is contained in the provided document. We need 41 to provide the document since PointerCaptureController is owned by the Page and may manage several documents. 42 (WebCore::PointerCaptureController::dispatchEvent): Only run the Process Pending Capture Element steps when dealing with a touch or pen 43 event since those steps are already ran for mouse events in Document::prepareMouseEvent(). Additionally, since the element target is already 44 set to be the pointer capture element with the changes made to processPendingPointerCapture(), and because on iOS pointer capture is always 45 active, we can remove the code that would retarget the event to the pointer capture element. 46 (WebCore::PointerCaptureController::pointerEventWasDispatched): 47 (WebCore::PointerCaptureController::cancelPointer): 48 (WebCore::PointerCaptureController::processPendingPointerCapture): We now call into EventHandler::setCapturingMouseEventsElement() when the 49 capture target element changes. We must be careful to call this method prior to dispatching the "gotpointercapture" event and after dispatching 50 the "lostpointercapture" event so that boundary events are fired at the right time. 51 * page/PointerCaptureController.h: 52 1 53 2019-07-04 Zalan Bujtas <zalan@apple.com> 2 54 -
trunk/Source/WebCore/dom/Document.cpp
r247024 r247148 321 321 #endif 322 322 323 #if ENABLE(POINTER_EVENTS) 324 #include "PointerCaptureController.h" 325 #endif 326 323 327 namespace WebCore { 324 328 … … 3733 3737 hitTest(request, result); 3734 3738 3735 if (!request.readOnly()) 3736 updateHoverActiveState(request, result.targetElement()); 3739 auto captureElementChanged = CaptureChange::No; 3740 if (!request.readOnly()) { 3741 auto targetElement = makeRefPtr(result.targetElement()); 3742 #if ENABLE(POINTER_EVENTS) 3743 if (auto* page = this->page()) { 3744 // Before we dispatch a new mouse event, we must run the Process Pending Capture Element steps as defined 3745 // in https://w3c.github.io/pointerevents/#process-pending-pointer-capture. 3746 auto& pointerCaptureController = page->pointerCaptureController(); 3747 auto* previousCaptureElement = pointerCaptureController.pointerCaptureElement(this, event.pointerId()); 3748 pointerCaptureController.processPendingPointerCapture(event.pointerId()); 3749 auto* captureElement = pointerCaptureController.pointerCaptureElement(this, event.pointerId()); 3750 // If the capture element has changed while running the Process Pending Capture Element steps then 3751 // we need to indicate that when calling updateHoverActiveState to be sure that the :active and :hover 3752 // element chains are updated. 3753 if (previousCaptureElement != captureElement) 3754 captureElementChanged = CaptureChange::Yes; 3755 // If we have a capture element, we must target it instead of what would normally hit-test for this event. 3756 if (captureElement) 3757 targetElement = captureElement; 3758 } 3759 #endif 3760 updateHoverActiveState(request, targetElement.get(), captureElementChanged); 3761 } 3737 3762 3738 3763 return MouseEventWithHitTestResults(event, result); … … 6741 6766 } 6742 6767 6743 void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement )6768 void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement, CaptureChange captureElementChanged) 6744 6769 { 6745 6770 ASSERT(!request.readOnly()); … … 6780 6805 // If the mouse is down and if this is a mouse move event, we want to restrict changes in 6781 6806 // :hover/:active to only apply to elements that are in the :active chain that we froze 6782 // at the time the mouse went down .6783 bool mustBeInActiveChain = request.active() && request.move() ;6807 // at the time the mouse went down, unless the capture element changed. 6808 bool mustBeInActiveChain = request.active() && request.move() && captureElementChanged == CaptureChange::No; 6784 6809 6785 6810 RefPtr<Element> oldHoveredElement = WTFMove(m_hoveredElement); -
trunk/Source/WebCore/dom/Document.h
r247024 r247148 761 761 void elementInActiveChainDidDetach(Element&); 762 762 763 void updateHoverActiveState(const HitTestRequest&, Element*); 763 enum class CaptureChange : uint8_t { Yes, No }; 764 void updateHoverActiveState(const HitTestRequest&, Element*, CaptureChange = CaptureChange::No); 764 765 765 766 // Updates for :target (CSS3 selector). -
trunk/Source/WebCore/dom/PointerEvent.h
r247024 r247148 62 62 } 63 63 64 static Ref<PointerEvent> createForPointerCapture(const AtomString& type, const PointerEvent& pointerEvent)64 static Ref<PointerEvent> createForPointerCapture(const AtomString& type, PointerID pointerId, bool isPrimary, String pointerType) 65 65 { 66 66 Init initializer; 67 67 initializer.bubbles = true; 68 initializer.pointerId = pointer Event.pointerId();69 initializer.isPrimary = pointerEvent.isPrimary();70 initializer.pointerType = pointer Event.pointerType();68 initializer.pointerId = pointerId; 69 initializer.isPrimary = isPrimary; 70 initializer.pointerType = pointerType; 71 71 return adoptRef(*new PointerEvent(type, WTFMove(initializer))); 72 72 } -
trunk/Source/WebCore/page/EventHandler.cpp
r247100 r247148 128 128 #endif 129 129 130 #if ENABLE(POINTER_EVENTS) 131 #include "RuntimeEnabledFeatures.h" 132 #endif 133 130 134 namespace WebCore { 131 135 … … 2484 2488 } 2485 2489 2490 #if ENABLE(POINTER_EVENTS) 2491 void EventHandler::pointerCaptureElementDidChange(Element* element) 2492 { 2493 if (m_capturingMouseEventsElement == element) 2494 return; 2495 2496 setCapturingMouseEventsElement(element); 2497 2498 // Now that we have a new capture element, we need to dispatch boundary mouse events. 2499 updateMouseEventTargetNode(element, m_lastPlatformMouseEvent, FireMouseOverOut::Yes); 2500 } 2501 #endif 2502 2486 2503 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mouseEvent) 2487 2504 { 2505 #if ENABLE(POINTER_EVENTS) 2506 m_lastPlatformMouseEvent = mouseEvent; 2507 #endif 2488 2508 Ref<Frame> protectedFrame(m_frame); 2489 2509 ASSERT(m_frame.document()); -
trunk/Source/WebCore/page/EventHandler.h
r247024 r247148 159 159 160 160 WEBCORE_EXPORT void setCapturingMouseEventsElement(Element*); 161 #if ENABLE(POINTER_EVENTS) 162 void pointerCaptureElementDidChange(Element*); 163 #endif 161 164 162 165 #if ENABLE(DRAG_SUPPORT) … … 593 596 WallTime m_mouseDownTimestamp; 594 597 PlatformMouseEvent m_mouseDown; 598 #if ENABLE(POINTER_EVENTS) 599 PlatformMouseEvent m_lastPlatformMouseEvent; 600 #endif 595 601 596 602 #if PLATFORM(COCOA) -
trunk/Source/WebCore/page/PointerCaptureController.cpp
r247024 r247148 49 49 } 50 50 51 Element* PointerCaptureController::pointerCaptureElement(Document* document, PointerID pointerId) 52 { 53 auto iterator = m_activePointerIdsToCapturingData.find(pointerId); 54 if (iterator != m_activePointerIdsToCapturingData.end()) { 55 auto pointerCaptureElement = iterator->value.targetOverride; 56 if (pointerCaptureElement && &pointerCaptureElement->document() == document) 57 return pointerCaptureElement.get(); 58 } 59 return nullptr; 60 } 61 51 62 ExceptionOr<void> PointerCaptureController::setPointerCapture(Element* capturingTarget, PointerID pointerId) 52 63 { … … 272 283 // https://w3c.github.io/pointerevents/#firing-events-using-the-pointerevent-interface 273 284 // If the event is not gotpointercapture or lostpointercapture, run Process Pending Pointer Capture steps for this PointerEvent. 274 processPendingPointerCapture(event); 275 276 // If the pointer capture target override has been set for the pointer, set the target to pointer capture target override object. 277 auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId()); 278 if (iterator != m_activePointerIdsToCapturingData.end()) { 279 auto& capturingData = iterator->value; 280 if (capturingData.targetOverride) 281 target = capturingData.targetOverride.get(); 282 } 285 // We only need to do this for non-mouse type since for mouse events this method will be called in Document::prepareMouseEvent(). 286 if (event.pointerType() != PointerEvent::mousePointerType()) 287 processPendingPointerCapture(event.pointerId()); 283 288 284 289 pointerEventWillBeDispatched(event, target); … … 341 346 if (event.type() == eventNames().pointerupEvent) { 342 347 capturingData.pendingTargetOverride = nullptr; 343 processPendingPointerCapture(event );348 processPendingPointerCapture(event.pointerId()); 344 349 } 345 350 … … 400 405 target->dispatchEvent(PointerEvent::create(eventNames().pointeroutEvent, pointerId, capturingData.pointerType, isPrimary)); 401 406 target->dispatchEvent(PointerEvent::create(eventNames().pointerleaveEvent, pointerId, capturingData.pointerType, isPrimary)); 402 processPendingPointerCapture(WTFMove(cancelEvent)); 403 } 404 405 void PointerCaptureController::processPendingPointerCapture(const PointerEvent& event) 406 { 407 // https://w3c.github.io/pointerevents/#process-pending-pointer-capture 408 409 auto iterator = m_activePointerIdsToCapturingData.find(event.pointerId()); 407 processPendingPointerCapture(pointerId); 408 } 409 410 void PointerCaptureController::processPendingPointerCapture(PointerID pointerId) 411 { 412 auto iterator = m_activePointerIdsToCapturingData.find(pointerId); 410 413 if (iterator == m_activePointerIdsToCapturingData.end()) 411 414 return; 415 416 if (m_processingPendingPointerCapture) 417 return; 418 419 m_processingPendingPointerCapture = true; 412 420 413 421 auto& capturingData = iterator->value; … … 416 424 auto pendingTargetOverride = capturingData.pendingTargetOverride; 417 425 426 // https://w3c.github.io/pointerevents/#process-pending-pointer-capture 418 427 // 1. If the pointer capture target override for this pointer is set and is not equal to the pending pointer capture target override, 419 428 // then fire a pointer event named lostpointercapture at the pointer capture target override node. 420 if (capturingData.targetOverride && capturingData.targetOverride->isConnected() && capturingData.targetOverride != pendingTargetOverride) 421 capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, event)); 429 if (capturingData.targetOverride && capturingData.targetOverride->isConnected() && capturingData.targetOverride != pendingTargetOverride) { 430 capturingData.targetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().lostpointercaptureEvent, pointerId, capturingData.isPrimary, capturingData.pointerType)); 431 if (capturingData.pointerType == PointerEvent::mousePointerType()) { 432 if (auto* frame = capturingData.targetOverride->document().frame()) 433 frame->eventHandler().pointerCaptureElementDidChange(nullptr); 434 } 435 } 422 436 423 437 // 2. If the pending pointer capture target override for this pointer is set and is not equal to the pointer capture target override, 424 438 // then fire a pointer event named gotpointercapture at the pending pointer capture target override. 425 if (capturingData.pendingTargetOverride && capturingData.targetOverride != pendingTargetOverride) 426 pendingTargetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().gotpointercaptureEvent, event)); 439 if (capturingData.pendingTargetOverride && capturingData.targetOverride != pendingTargetOverride) { 440 if (capturingData.pointerType == PointerEvent::mousePointerType()) { 441 if (auto* frame = pendingTargetOverride->document().frame()) 442 frame->eventHandler().pointerCaptureElementDidChange(pendingTargetOverride.get()); 443 } 444 pendingTargetOverride->dispatchEvent(PointerEvent::createForPointerCapture(eventNames().gotpointercaptureEvent, pointerId, capturingData.isPrimary, capturingData.pointerType)); 445 } 427 446 428 447 // 3. Set the pointer capture target override to the pending pointer capture target override, if set. Otherwise, clear the pointer 429 448 // capture target override. 430 449 capturingData.targetOverride = pendingTargetOverride; 450 451 m_processingPendingPointerCapture = false; 431 452 } 432 453 -
trunk/Source/WebCore/page/PointerCaptureController.h
r247024 r247148 42 42 explicit PointerCaptureController(Page&); 43 43 44 Element* pointerCaptureElement(Document*, PointerID); 44 45 ExceptionOr<void> setPointerCapture(Element*, PointerID); 45 46 ExceptionOr<void> releasePointerCapture(Element*, PointerID); … … 61 62 void dispatchEvent(PointerEvent&, EventTarget*); 62 63 WEBCORE_EXPORT void cancelPointer(PointerID, const IntPoint&); 64 void processPendingPointerCapture(PointerID); 63 65 64 66 private: … … 76 78 void pointerEventWillBeDispatched(const PointerEvent&, EventTarget*); 77 79 void pointerEventWasDispatched(const PointerEvent&); 78 void processPendingPointerCapture(const PointerEvent&);79 80 80 81 Page& m_page; … … 83 84 using PointerIdToCapturingDataMap = HashMap<int64_t, CapturingData, WTF::IntHash<int64_t>, WTF::SignedWithZeroKeyHashTraits<int64_t>>; 84 85 PointerIdToCapturingDataMap m_activePointerIdsToCapturingData; 86 bool m_processingPendingPointerCapture { false }; 85 87 }; 86 88
Note: See TracChangeset
for help on using the changeset viewer.