Changeset 235865 in webkit


Ignore:
Timestamp:
Sep 10, 2018 2:54:14 PM (6 years ago)
Author:
rniwa@webkit.org
Message:

mouseenter and mouseleave events don't get dispatched even when there is a capturing event listener for a slot ancestor
https://bugs.webkit.org/show_bug.cgi?id=188561

Reviewed by Darin Adler.

Source/WebCore:

This patch makes mouseenter and mouseleave events to work with shadow trees and slots therein, and makes them uncomposed
as discussed in https://github.com/w3c/uievents/issues/208.

This patch also makes these events dispatched on DOM tree ancestors of the currently hovered element instead of
render tree's hover ancestors to be consistent with the check in hierarchyHasCapturingEventListeners and other browsers.
In particular, using hover ancestors is problematic when there is an element with display: contents such as slot elements,
which do not have a render object.

Tests: fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary.html

fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree.html
fast/shadow-dom/mouseenter-mouseleave-on-slot-parent.html

  • dom/MouseEvent.cpp:

(WebCore::MouseEvent::create):

  • page/EventHandler.cpp:

(WebCore::nearestCommonHoverAncestor): Deleted.
(WebCore::hierarchyHasCapturingEventListeners): Use parentInComposedTree. Else we would miss capturing event listeners
on inclusive ancestors of slots.
(WebCore::EventHandler::updateMouseEventTargetNode): Use the composed tree's ancestor chain to fire mouseenter and
mouseleave events. This is needed to dispatch mouseenter / mouseleave events on slot elements. Also removed comments
which just state what is self-evident from the code beneath them.

LayoutTests:

Added tests for listening to mouseenter and mouseleave events using capturing and bubbling event listeners
across shadow boundaries.

  • fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary-expected.txt: Added.
  • fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary.html: Added.
  • fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree-expected.txt: Added.
  • fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree.html: Added.
  • fast/shadow-dom/mouseenter-mouseleave-on-slot-parent-expected.txt: Added.
  • fast/shadow-dom/mouseenter-mouseleave-on-slot-parent.html: Added.
  • platform/ios/TestExpectations: Skip the new tests since mouse events aren't supported on iOS.
Location:
trunk
Files:
6 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r235860 r235865  
     12018-09-07  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        mouseenter and mouseleave events don't get dispatched even when there is a capturing event listener for a slot ancestor
     4        https://bugs.webkit.org/show_bug.cgi?id=188561
     5
     6        Reviewed by Darin Adler.
     7
     8        Added tests for listening to mouseenter and mouseleave events using capturing and bubbling event listeners
     9        across shadow boundaries.
     10
     11        * fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary-expected.txt: Added.
     12        * fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary.html: Added.
     13        * fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree-expected.txt: Added.
     14        * fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree.html: Added.
     15        * fast/shadow-dom/mouseenter-mouseleave-on-slot-parent-expected.txt: Added.
     16        * fast/shadow-dom/mouseenter-mouseleave-on-slot-parent.html: Added.
     17        * platform/ios/TestExpectations: Skip the new tests since mouse events aren't supported on iOS.
     18
    1192018-09-10  Daniel Bates  <dabates@apple.com>
    220
  • trunk/LayoutTests/platform/ios/TestExpectations

    r235806 r235865  
    684684fast/selectors/not-active-hover-strict.html [ Skip ]
    685685fast/shapes/shape-outside-floats/shape-outside-clip-path-selection.html [ Skip ]
     686fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary.html [ Skip ]
     687fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree.html [ Skip ]
     688fast/shadow-dom/mouseenter-mouseleave-on-slot-parent.html [ Skip ]
    686689fast/table/hittest-self-painting.html [ Skip ]
    687690fast/text/atsui-pointtooffset-calls-cg.html [ Skip ]
  • trunk/Source/WebCore/ChangeLog

    r235864 r235865  
     12018-09-07  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        mouseenter and mouseleave events don't get dispatched even when there is a capturing event listener for a slot ancestor
     4        https://bugs.webkit.org/show_bug.cgi?id=188561
     5
     6        Reviewed by Darin Adler.
     7
     8        This patch makes mouseenter and mouseleave events to work with shadow trees and slots therein, and makes them uncomposed
     9        as discussed in https://github.com/w3c/uievents/issues/208.
     10
     11        This patch also makes these events dispatched on DOM tree ancestors of the currently hovered element instead of
     12        render tree's hover ancestors to be consistent with the check in hierarchyHasCapturingEventListeners and other browsers.
     13        In particular, using hover ancestors is problematic when there is an element with display: contents such as slot elements,
     14        which do not have a render object.
     15
     16        Tests: fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary.html
     17               fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree.html
     18               fast/shadow-dom/mouseenter-mouseleave-on-slot-parent.html
     19
     20        * dom/MouseEvent.cpp:
     21        (WebCore::MouseEvent::create):
     22        * page/EventHandler.cpp:
     23        (WebCore::nearestCommonHoverAncestor): Deleted.
     24        (WebCore::hierarchyHasCapturingEventListeners): Use parentInComposedTree. Else we would miss capturing event listeners
     25        on inclusive ancestors of slots.
     26        (WebCore::EventHandler::updateMouseEventTargetNode): Use the composed tree's ancestor chain to fire mouseenter and
     27        mouseleave events. This is needed to dispatch mouseenter / mouseleave events on slot elements. Also removed comments
     28        which just state what is self-evident from the code beneath them.
     29
     30
    1312018-09-08  Ryosuke Niwa  <rniwa@webkit.org>
    232
  • trunk/Source/WebCore/dom/MouseEvent.cpp

    r235335 r235865  
    5050    auto isCancelable = eventType != eventNames().mousemoveEvent && !isMouseEnterOrLeave ? IsCancelable::Yes : IsCancelable::No;
    5151    auto canBubble = !isMouseEnterOrLeave ? CanBubble::Yes : CanBubble::No;
    52 
    53     return MouseEvent::create(eventType, canBubble, isCancelable, IsComposed::Yes, event.timestamp().approximateMonotonicTime(), WTFMove(view), detail,
     52    auto isComposed = !isMouseEnterOrLeave ? IsComposed::Yes : IsComposed::No;
     53
     54    return MouseEvent::create(eventType, canBubble, isCancelable, isComposed, event.timestamp().approximateMonotonicTime(), WTFMove(view), detail,
    5455        event.globalPosition(), event.position(),
    5556#if ENABLE(POINTER_LOCK)
  • trunk/Source/WebCore/page/EventHandler.cpp

    r235331 r235865  
    3434#include "Chrome.h"
    3535#include "ChromeClient.h"
     36#include "ComposedTreeAncestorIterator.h"
    3637#include "CursorList.h"
    3738#include "DocumentMarkerController.h"
     
    24452446}
    24462447
    2447 static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
    2448 {
    2449     if (!obj1 || !obj2)
    2450         return nullptr;
    2451 
    2452     for (RenderElement* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
    2453         for (RenderElement* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
    2454             if (currObj1 == currObj2)
    2455                 return currObj1;
    2456         }
    2457     }
    2458 
    2459     return nullptr;
    2460 }
    2461 
    24622448static bool hierarchyHasCapturingEventListeners(Element* element, const AtomicString& eventName)
    24632449{
    2464     for (ContainerNode* curr = element; curr; curr = curr->parentOrShadowHostNode()) {
     2450    for (ContainerNode* curr = element; curr; curr = curr->parentInComposedTree()) {
    24652451        if (curr->hasCapturingEventListeners(eventName))
    24662452            return true;
     
    25362522            bool hasCapturingMouseLeaveListener = hierarchyHasCapturingEventListeners(m_lastElementUnderMouse.get(), eventNames().mouseleaveEvent);
    25372523
    2538             RenderElement* oldHoverRenderer = m_lastElementUnderMouse ? m_lastElementUnderMouse->renderer() : nullptr;
    2539             RenderElement* newHoverRenderer = m_elementUnderMouse ? m_elementUnderMouse->renderer() : nullptr;
    2540             RenderElement* ancestor = nearestCommonHoverAncestor(oldHoverRenderer, newHoverRenderer);
    2541 
    25422524            Vector<Ref<Element>, 32> leftElementsChain;
    2543             if (oldHoverRenderer) {
    2544                 for (RenderElement* curr = oldHoverRenderer; curr && curr != ancestor; curr = curr->hoverAncestor()) {
    2545                     if (Element* element = curr->element())
    2546                         leftElementsChain.append(*element);
     2525            for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElementInComposedTree())
     2526                leftElementsChain.append(*element);
     2527            Vector<Ref<Element>, 32> enteredElementsChain;
     2528            for (Element* element = m_elementUnderMouse.get(); element; element = element->parentElementInComposedTree())
     2529                enteredElementsChain.append(*element);
     2530
     2531            if (!leftElementsChain.isEmpty() && !enteredElementsChain.isEmpty() && leftElementsChain.last().ptr() == enteredElementsChain.last().ptr()) {
     2532                size_t minHeight = std::min(leftElementsChain.size(), enteredElementsChain.size());
     2533                size_t i;
     2534                for (i = 0; i < minHeight; ++i) {
     2535                    if (leftElementsChain[leftElementsChain.size() - i - 1].ptr() != enteredElementsChain[enteredElementsChain.size() - i - 1].ptr())
     2536                        break;
    25472537                }
    2548             } else {
    2549                 // If the old hovered element is not null but it's renderer is, it was probably detached.
    2550                 // In this case, the old hovered element (and its ancestors) must be updated, to ensure it's normal style is re-applied.
    2551                 for (Element* element = m_lastElementUnderMouse.get(); element; element = element->parentElement())
    2552                     leftElementsChain.append(*element);
     2538                leftElementsChain.shrink(leftElementsChain.size() - i);
     2539                enteredElementsChain.shrink(enteredElementsChain.size() - i);
    25532540            }
    25542541
    2555             Vector<Ref<Element>, 32> enteredElementsChain;
    2556             const Element* ancestorElement = ancestor ? ancestor->element() : nullptr;
    2557             for (RenderElement* curr = newHoverRenderer; curr; curr = curr->hoverAncestor()) {
    2558                 if (Element *element = curr->element()) {
    2559                     if (element == ancestorElement)
    2560                         break;
    2561                     enteredElementsChain.append(*element);
    2562                 }
    2563             }
    2564 
    2565             // Send mouseout event to the old node.
    25662542            if (m_lastElementUnderMouse)
    25672543                m_lastElementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoutEvent, 0, m_elementUnderMouse.get());
    25682544
    2569             // Send mouseleave to the node hierarchy no longer under the mouse.
    25702545            for (auto& chain : leftElementsChain) {
    25712546                if (hasCapturingMouseLeaveListener || chain->hasEventListeners(eventNames().mouseleaveEvent))
     
    25732548            }
    25742549
    2575             // Send mouseover event to the new node.
    25762550            if (m_elementUnderMouse)
    25772551                m_elementUnderMouse->dispatchMouseEvent(platformMouseEvent, eventNames().mouseoverEvent, 0, m_lastElementUnderMouse.get());
    25782552
    2579             // Send mouseleave event to the nodes hierarchy under the mouse.
    25802553            for (auto& chain : enteredElementsChain) {
    25812554                if (hasCapturingMouseEnterListener || chain->hasEventListeners(eventNames().mouseenterEvent))
Note: See TracChangeset for help on using the changeset viewer.