Title: [208630] trunk
Revision
208630
Author
rn...@webkit.org
Date
2016-11-11 16:48:46 -0800 (Fri, 11 Nov 2016)

Log Message

Hovering over a slotted Text node clears hover state
https://bugs.webkit.org/show_bug.cgi?id=164002
<rdar://problem/29040471>

Reviewed by Simon Fraser.

Source/WebCore:

The bug was caused by HitTestResult::innerElement returning the parent element of a Text node without
taking the shadow root or slots into account. For hit testing, we always want to use the "flat tree"
or "composed tree" (imprecisely but close enough in this case).

Fixed the bug by making HitTestResult::innerElement use parentNodeInComposedTree. Also renamed it to
HitTestResult::targetElement to be consistent with HitTestResult::targetNode.

Tests: fast/shadow-dom/activate-over-slotted-content.html
       fast/shadow-dom/hover-over-slotted-content.html

* dom/Document.cpp:
(WebCore::Document::prepareMouseEvent):
* html/MediaElementSession.cpp:
(WebCore::isMainContentForPurposesOfAutoplay):
* page/EventHandler.cpp:
(WebCore::EventHandler::eventMayStartDrag):
(WebCore::EventHandler::hitTestResultAtPoint):
(WebCore::EventHandler::handleWheelEvent):
(WebCore::EventHandler::sendContextMenuEventForKey):
(WebCore::EventHandler::hoverTimerFired):
(WebCore::EventHandler::handleDrag):
(WebCore::EventHandler::handleTouchEvent):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::targetElement): Renamed from innerElement.
Now finds the parent element in the composed tree.
* rendering/HitTestResult.h:
(WebCore::HitTestResult::innerNode):

Source/WebKit/mac:

* WebView/WebImmediateActionController.mm:
(-[WebImmediateActionController performHitTestAtPoint:]):

Source/WebKit2:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::determinePrimarySnapshottedPlugIn):
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::performImmediateActionHitTestAtLocation):

LayoutTests:

Added two reference tests for activating and hovering over a Text node.
The text node should activate :hover and :activate rules in the shadow tree respectively.

* fast/shadow-dom/activate-over-slotted-content-expected.html: Added.
* fast/shadow-dom/activate-over-slotted-content.html: Added.
* fast/shadow-dom/hover-over-slotted-content-expected.html: Added.
* fast/shadow-dom/hover-over-slotted-content.html: Added.
* platform/ios-simulator/TestExpectations: Skip the newly added tests since iOS doesn't
support :hover or :activate via mouse down.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (208629 => 208630)


--- trunk/LayoutTests/ChangeLog	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/LayoutTests/ChangeLog	2016-11-12 00:48:46 UTC (rev 208630)
@@ -1,3 +1,21 @@
+2016-11-11  Ryosuke Niwa  <rn...@webkit.org>
+
+        Hovering over a slotted Text node clears hover state
+        https://bugs.webkit.org/show_bug.cgi?id=164002
+        <rdar://problem/29040471>
+
+        Reviewed by Simon Fraser.
+
+        Added two reference tests for activating and hovering over a Text node.
+        The text node should activate :hover and :activate rules in the shadow tree respectively.
+
+        * fast/shadow-dom/activate-over-slotted-content-expected.html: Added.
+        * fast/shadow-dom/activate-over-slotted-content.html: Added.
+        * fast/shadow-dom/hover-over-slotted-content-expected.html: Added.
+        * fast/shadow-dom/hover-over-slotted-content.html: Added.
+        * platform/ios-simulator/TestExpectations: Skip the newly added tests since iOS doesn't
+        support :hover or :activate via mouse down.
+
 2016-11-11  Brent Fulgham  <bfulg...@apple.com>
 
         Neutered ArrayBuffers are not properly serialized

Added: trunk/LayoutTests/fast/shadow-dom/activate-over-slotted-content-expected.html (0 => 208630)


--- trunk/LayoutTests/fast/shadow-dom/activate-over-slotted-content-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/activate-over-slotted-content-expected.html	2016-11-12 00:48:46 UTC (rev 208630)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/shadow-dom/activate-over-slotted-content.html (0 => 208630)


--- trunk/LayoutTests/fast/shadow-dom/activate-over-slotted-content.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/activate-over-slotted-content.html	2016-11-12 00:48:46 UTC (rev 208630)
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+my-host {
+    display: block;
+    width: 100px;
+    height: 100px;
+    background: purple;
+}
+</style>
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<my-host>Mouse down over this text</my-host>
+
+<script>
+const host = document.querySelector('my-host');
+host.attachShadow({mode: 'closed'}).innerHTML = `
+<a><span><slot></slot></span></a>
+<style>
+a {
+    display: block;
+    width: 80px;
+    height: 80px;
+    padding: 10px;
+    background: red;
+}
+a:active {
+    background: green;
+    color: green;
+}
+span {
+    background: green;
+}
+</style>`;
+
+if (window.eventSender) {
+    eventSender.mouseMoveTo(host.offsetLeft + 15, host.offsetTop + 15);
+    eventSender.mouseDown();
+}
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/fast/shadow-dom/hover-over-slotted-content-expected.html (0 => 208630)


--- trunk/LayoutTests/fast/shadow-dom/hover-over-slotted-content-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/hover-over-slotted-content-expected.html	2016-11-12 00:48:46 UTC (rev 208630)
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <p>Test passes if you see a single 100px by 100px green box below.</p>
+    <div style="width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/shadow-dom/hover-over-slotted-content.html (0 => 208630)


--- trunk/LayoutTests/fast/shadow-dom/hover-over-slotted-content.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/hover-over-slotted-content.html	2016-11-12 00:48:46 UTC (rev 208630)
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+my-host {
+    display: block;
+    width: 100px;
+    height: 100px;
+    background: purple;
+}
+</style>
+</head>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<my-host>Hover over this text</my-host>
+
+<script>
+const host = document.querySelector('my-host');
+host.attachShadow({mode: 'closed'}).innerHTML = `
+<div id="container"><span><slot></slot></span></div>
+<style>
+#container {
+    width: 80px;
+    height: 80px;
+    padding: 10px;
+    background: red;
+}
+#container:hover {
+    background: green;
+    color: green;
+}
+span {
+    background: green;
+}
+</style>`;
+
+if (window.eventSender)
+    eventSender.mouseMoveTo(host.offsetLeft + 15, host.offsetTop + 15);
+
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (208629 => 208630)


--- trunk/LayoutTests/platform/ios-simulator/TestExpectations	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations	2016-11-12 00:48:46 UTC (rev 208630)
@@ -341,6 +341,8 @@
 webkit.org/b/155233 fast/events/max-tabindex-focus.html [ Skip ]
 fast/shadow-dom/shadow-host-removal-crash.html [ Skip ]
 fast/shadow-dom/input-element-in-shadow.html [ Skip ]
+fast/shadow-dom/activate-over-slotted-content.html [ Skip ]
+fast/shadow-dom/hover-over-slotted-content.html [ Skip ]
 fast/events/keyboardevent-key.html [ Skip ]
 fast/events/keyboardevent-code.html [ Skip ]
 

Modified: trunk/Source/WebCore/ChangeLog (208629 => 208630)


--- trunk/Source/WebCore/ChangeLog	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebCore/ChangeLog	2016-11-12 00:48:46 UTC (rev 208630)
@@ -1,3 +1,39 @@
+2016-11-11  Ryosuke Niwa  <rn...@webkit.org>
+
+        Hovering over a slotted Text node clears hover state
+        https://bugs.webkit.org/show_bug.cgi?id=164002
+        <rdar://problem/29040471>
+
+        Reviewed by Simon Fraser.
+
+        The bug was caused by HitTestResult::innerElement returning the parent element of a Text node without
+        taking the shadow root or slots into account. For hit testing, we always want to use the "flat tree"
+        or "composed tree" (imprecisely but close enough in this case).
+
+        Fixed the bug by making HitTestResult::innerElement use parentNodeInComposedTree. Also renamed it to
+        HitTestResult::targetElement to be consistent with HitTestResult::targetNode.
+
+        Tests: fast/shadow-dom/activate-over-slotted-content.html
+               fast/shadow-dom/hover-over-slotted-content.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::prepareMouseEvent):
+        * html/MediaElementSession.cpp:
+        (WebCore::isMainContentForPurposesOfAutoplay):
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::eventMayStartDrag):
+        (WebCore::EventHandler::hitTestResultAtPoint):
+        (WebCore::EventHandler::handleWheelEvent):
+        (WebCore::EventHandler::sendContextMenuEventForKey):
+        (WebCore::EventHandler::hoverTimerFired):
+        (WebCore::EventHandler::handleDrag):
+        (WebCore::EventHandler::handleTouchEvent):
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::targetElement): Renamed from innerElement.
+        Now finds the parent element in the composed tree.
+        * rendering/HitTestResult.h:
+        (WebCore::HitTestResult::innerNode):
+
 2016-11-11  Brent Fulgham  <bfulg...@apple.com>
 
         Unreviewed build fix after r208628

Modified: trunk/Source/WebCore/dom/Document.cpp (208629 => 208630)


--- trunk/Source/WebCore/dom/Document.cpp	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebCore/dom/Document.cpp	2016-11-12 00:48:46 UTC (rev 208630)
@@ -3277,7 +3277,7 @@
     renderView()->hitTest(request, result);
 
     if (!request.readOnly())
-        updateHoverActiveState(request, result.innerElement());
+        updateHoverActiveState(request, result.targetElement());
 
     return MouseEventWithHitTestResults(event, result);
 }

Modified: trunk/Source/WebCore/html/MediaElementSession.cpp (208629 => 208630)


--- trunk/Source/WebCore/html/MediaElementSession.cpp	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebCore/html/MediaElementSession.cpp	2016-11-12 00:48:46 UTC (rev 208630)
@@ -676,7 +676,7 @@
     // Elements which are obscured by other elements cannot be main content.
     mainRenderView.hitTest(request, result);
     result.setToNonUserAgentShadowAncestor();
-    Element* hitElement = result.innerElement();
+    Element* hitElement = result.targetElement();
     if (hitElement != &element)
         return false;
 

Modified: trunk/Source/WebCore/page/EventHandler.cpp (208629 => 208630)


--- trunk/Source/WebCore/page/EventHandler.cpp	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2016-11-12 00:48:46 UTC (rev 208630)
@@ -892,7 +892,8 @@
     HitTestResult result(view->windowToContents(event.position()));
     renderView->hitTest(request, result);
     DragState state;
-    return result.innerElement() && page->dragController().draggableElement(&m_frame, result.innerElement(), result.roundedPointInInnerNodeFrame(), state);
+    Element* targetElement = result.targetElement();
+    return targetElement && page->dragController().draggableElement(&m_frame, targetElement, result.roundedPointInInnerNodeFrame(), state);
 }
 
 void EventHandler::updateSelectionForMouseDrag()
@@ -1159,7 +1160,7 @@
     HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
     renderView->hitTest(request, result);
     if (!request.readOnly())
-        m_frame.document()->updateHoverActiveState(request, result.innerElement());
+        m_frame.document()->updateHoverActiveState(request, result.targetElement());
 
     if (request.disallowsUserAgentShadowContent())
         result.setToNonUserAgentShadowAncestor();
@@ -2689,7 +2690,7 @@
     HitTestResult result(view->windowToContents(event.position()));
     renderView->hitTest(request, result);
 
-    RefPtr<Element> element = result.innerElement();
+    RefPtr<Element> element = result.targetElement();
     RefPtr<ContainerNode> scrollableContainer;
     WeakPtr<ScrollableArea> scrollableArea;
     bool isOverWidget = result.isOverWidget();
@@ -2875,7 +2876,7 @@
     // Use the focused node as the target for hover and active.
     HitTestResult result(position);
     result.setInnerNode(targetNode);
-    doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent, result.innerElement());
+    doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent, result.targetElement());
 
     // The contextmenu event is a mouse event even when invoked using the keyboard.
     // This is required for web compatibility.
@@ -2997,7 +2998,7 @@
             HitTestRequest request(HitTestRequest::Move | HitTestRequest::DisallowUserAgentShadowContent);
             HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
             renderView->hitTest(request, result);
-            m_frame.document()->updateHoverActiveState(request, result.innerElement());
+            m_frame.document()->updateHoverActiveState(request, result.targetElement());
         }
     }
 }
@@ -3442,7 +3443,7 @@
         HitTestResult result(m_mouseDownPos);
         m_frame.contentRenderer()->hitTest(request, result);
         if (m_frame.page())
-            dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.innerElement(), m_mouseDownPos, dragState());
+            dragState().source = m_frame.page()->dragController().draggableElement(&m_frame, result.targetElement(), m_mouseDownPos, dragState());
         
         if (!dragState().source)
             m_mouseDownMayStartDrag = false; // no element is draggable
@@ -3915,14 +3916,13 @@
             } else
                 continue;
 
-            // FIXME: This code should use Element* instead of Node*.
-            Node* node = result.innerElement();
-            ASSERT(node);
+            Element* element = result.targetElement();
+            ASSERT(element);
 
-            if (node && InspectorInstrumentation::handleTouchEvent(m_frame, *node))
+            if (element && InspectorInstrumentation::handleTouchEvent(m_frame, *element))
                 return true;
 
-            Document& doc = node->document();
+            Document& doc = element->document();
             // Record the originating touch document even if it does not have a touch listener.
             if (freshTouchEvents) {
                 m_originatingTouchPointDocument = &doc;
@@ -3930,8 +3930,8 @@
             }
             if (!doc.hasTouchEventHandlers())
                 continue;
-            m_originatingTouchPointTargets.set(touchPointTargetKey, node);
-            touchTarget = node;
+            m_originatingTouchPointTargets.set(touchPointTargetKey, element);
+            touchTarget = element;
         } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
             // No need to perform a hit-test since we only need to unset :hover and :active states.
             if (!shouldGesturesTriggerActive() && allTouchReleased)

Modified: trunk/Source/WebCore/rendering/HitTestResult.cpp (208629 => 208630)


--- trunk/Source/WebCore/rendering/HitTestResult.cpp	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebCore/rendering/HitTestResult.cpp	2016-11-12 00:48:46 UTC (rev 208630)
@@ -764,14 +764,13 @@
     return node;
 }
 
-Element* HitTestResult::innerElement() const
+Element* HitTestResult::targetElement() const
 {
-    Node* node = m_innerNode.get();
-    if (!node)
-        return nullptr;
-    if (is<Element>(*node))
-        return downcast<Element>(node);
-    return node->parentElement();
+    for (Node* node = m_innerNode.get(); node; node = node->parentInComposedTree()) {
+        if (is<Element>(*node))
+            return downcast<Element>(node);
+    }
+    return nullptr;
 }
 
 Element* HitTestResult::innerNonSharedElement() const

Modified: trunk/Source/WebCore/rendering/HitTestResult.h (208629 => 208630)


--- trunk/Source/WebCore/rendering/HitTestResult.h	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebCore/rendering/HitTestResult.h	2016-11-12 00:48:46 UTC (rev 208630)
@@ -59,7 +59,6 @@
     WEBCORE_EXPORT HitTestResult& operator=(const HitTestResult&);
 
     Node* innerNode() const { return m_innerNode.get(); }
-    WEBCORE_EXPORT Element* innerElement() const;
     Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); }
     WEBCORE_EXPORT Element* innerNonSharedElement() const;
     Element* URLElement() const { return m_innerURLElement.get(); }
@@ -151,6 +150,7 @@
     Vector<String> dictationAlternatives() const;
 
     Node* targetNode() const;
+    WEBCORE_EXPORT Element* targetElement() const;
 
 private:
     NodeSet& mutableRectBasedTestResult(); // See above.

Modified: trunk/Source/WebKit/mac/ChangeLog (208629 => 208630)


--- trunk/Source/WebKit/mac/ChangeLog	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebKit/mac/ChangeLog	2016-11-12 00:48:46 UTC (rev 208630)
@@ -1,3 +1,14 @@
+2016-11-11  Ryosuke Niwa  <rn...@webkit.org>
+
+        Hovering over a slotted Text node clears hover state
+        https://bugs.webkit.org/show_bug.cgi?id=164002
+        <rdar://problem/29040471>
+
+        Reviewed by Simon Fraser.
+
+        * WebView/WebImmediateActionController.mm:
+        (-[WebImmediateActionController performHitTestAtPoint:]):
+
 2016-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [WK2] autocorrect and autocapitalize attributes do not work in contenteditable elements

Modified: trunk/Source/WebKit/mac/WebView/WebImmediateActionController.mm (208629 => 208630)


--- trunk/Source/WebKit/mac/WebView/WebImmediateActionController.mm	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebKit/mac/WebView/WebImmediateActionController.mm	2016-11-12 00:48:46 UTC (rev 208630)
@@ -150,7 +150,7 @@
     _hitTestResult = coreFrame->eventHandler().hitTestResultAtPoint(IntPoint(viewPoint));
     coreFrame->eventHandler().setImmediateActionStage(ImmediateActionStage::PerformedHitTest);
 
-    if (Element* element = _hitTestResult.innerElement())
+    if (Element* element = _hitTestResult.targetElement())
         _contentPreventsDefault = element->dispatchMouseForceWillBegin();
 }
 

Modified: trunk/Source/WebKit2/ChangeLog (208629 => 208630)


--- trunk/Source/WebKit2/ChangeLog	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebKit2/ChangeLog	2016-11-12 00:48:46 UTC (rev 208630)
@@ -1,3 +1,16 @@
+2016-11-11  Ryosuke Niwa  <rn...@webkit.org>
+
+        Hovering over a slotted Text node clears hover state
+        https://bugs.webkit.org/show_bug.cgi?id=164002
+        <rdar://problem/29040471>
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::determinePrimarySnapshottedPlugIn):
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::performImmediateActionHitTestAtLocation):
+
 2016-11-11  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [WK2] autocorrect and autocapitalize attributes do not work in contenteditable elements

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (208629 => 208630)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2016-11-12 00:48:46 UTC (rev 208630)
@@ -5281,7 +5281,7 @@
             HitTestResult hitTestResult(plugInRectRelativeToTopDocument.center());
             mainRenderView.hitTest(request, hitTestResult);
 
-            Element* element = hitTestResult.innerElement();
+            Element* element = hitTestResult.targetElement();
             if (!element)
                 continue;
 

Modified: trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm (208629 => 208630)


--- trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm	2016-11-12 00:40:52 UTC (rev 208629)
+++ trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm	2016-11-12 00:48:46 UTC (rev 208630)
@@ -1001,7 +1001,7 @@
     HitTestResult hitTestResult = mainFrame.eventHandler().hitTestResultAtPoint(locationInContentCoordinates);
 
     bool immediateActionHitTestPreventsDefault = false;
-    Element* element = hitTestResult.innerElement();
+    Element* element = hitTestResult.targetElement();
 
     mainFrame.eventHandler().setImmediateActionStage(ImmediateActionStage::PerformedHitTest);
     if (element)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to