Title: [210564] trunk
Revision
210564
Author
[email protected]
Date
2017-01-10 15:34:51 -0800 (Tue, 10 Jan 2017)

Log Message

:active and :hover states may not be updated across slots
https://bugs.webkit.org/show_bug.cgi?id=166881
<rdar://problem/29944582>

Reviewed by Antti Koivisto.

Source/WebCore:

The bug was caused by updateHoverActiveState not updating :hover and :active states on elements
when nodes are assigned to slots because they were walking up the tree using parentOrShadowHostElement
and parentNode. Fixed the bug by using parentElementInComposedTree instead since :hover and :active
states need to be updated in accordance with the render tree, which is created from the "flat tree"
or the "composed tree" in WebKit's terminology (this is old terminology in the spec).

Tests: fast/shadow-dom/clear-active-state-in-shadow.html
       fast/shadow-dom/hover-over-nested-slotted-content.html

* dom/Document.cpp:
(WebCore::Document::updateHoverActiveState): Fixed the bug.
* dom/Node.cpp:
(WebCore::Node::parentElementInComposedTree): Added.
* dom/Node.h:

LayoutTests:

Added two regression tests; one for clearing :active state across a slot, and another one for clearing
a hover state on an ancestor of a slot to which a slot with the hovered element is assigned.

* fast/shadow-dom/clear-active-state-in-shadow-expected.html: Added.
* fast/shadow-dom/clear-active-state-in-shadow.html: Added.
* fast/shadow-dom/hover-over-nested-slotted-content-expected.html: Added.
* fast/shadow-dom/hover-over-nested-slotted-content.html: Added.
* platform/ios-simulator/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (210563 => 210564)


--- trunk/LayoutTests/ChangeLog	2017-01-10 23:17:42 UTC (rev 210563)
+++ trunk/LayoutTests/ChangeLog	2017-01-10 23:34:51 UTC (rev 210564)
@@ -1,3 +1,20 @@
+2017-01-10  Ryosuke Niwa  <[email protected]>
+
+        :active and :hover states may not be updated across slots
+        https://bugs.webkit.org/show_bug.cgi?id=166881
+        <rdar://problem/29944582>
+
+        Reviewed by Antti Koivisto.
+
+        Added two regression tests; one for clearing :active state across a slot, and another one for clearing
+        a hover state on an ancestor of a slot to which a slot with the hovered element is assigned.
+
+        * fast/shadow-dom/clear-active-state-in-shadow-expected.html: Added.
+        * fast/shadow-dom/clear-active-state-in-shadow.html: Added.
+        * fast/shadow-dom/hover-over-nested-slotted-content-expected.html: Added.
+        * fast/shadow-dom/hover-over-nested-slotted-content.html: Added.
+        * platform/ios-simulator/TestExpectations:
+
 2017-01-10  Wenson Hsieh  <[email protected]>
 
         Implement "proximity" scroll snapping

Added: trunk/LayoutTests/fast/shadow-dom/clear-active-state-in-shadow-expected.html (0 => 210564)


--- trunk/LayoutTests/fast/shadow-dom/clear-active-state-in-shadow-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/clear-active-state-in-shadow-expected.html	2017-01-10 23:34:51 UTC (rev 210564)
@@ -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/clear-active-state-in-shadow.html (0 => 210564)


--- trunk/LayoutTests/fast/shadow-dom/clear-active-state-in-shadow.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/clear-active-state-in-shadow.html	2017-01-10 23:34:51 UTC (rev 210564)
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div><span>click here</span></div>
+<style>
+div {
+    display: block;
+    width: 100px;
+    height: 100px;
+    background: green;
+}
+</style>
+<script src=""
+<script>
+
+var div = document.querySelector('div');
+div.attachShadow({mode: 'closed'}).innerHTML = `
+    <style>
+    a, ::slotted(*) {
+        display: block;
+        width: 100%;
+        height: 100%;
+    }
+
+    a:active {
+        background: red;
+    }
+    </style>
+    <a href="" _onclick_="this.style.color = this.matches(':active') ? 'black' : 'green'"><slot></slot></a>`;
+
+if (window.testRunner)
+    UIHelper.wait(UIHelper.activateAt(div.offsetLeft + 5, div.offsetTop + 5));
+
+</script>
+</body>
+</html>

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


--- trunk/LayoutTests/fast/shadow-dom/hover-over-nested-slotted-content-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/hover-over-nested-slotted-content-expected.html	2017-01-10 23:34:51 UTC (rev 210564)
@@ -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-nested-slotted-content.html (0 => 210564)


--- trunk/LayoutTests/fast/shadow-dom/hover-over-nested-slotted-content.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/hover-over-nested-slotted-content.html	2017-01-10 23:34:51 UTC (rev 210564)
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Test passes if you see a single 100px by 100px green box below.</p>
+<div></div>
+<style>
+div {
+    display: block;
+    width: 100px;
+    height: 100px;
+    background: red;
+}
+</style>
+<script src=""
+<script>
+
+var div = document.querySelector('div');
+var outerShadow = div.attachShadow({mode: 'closed'});
+outerShadow.innerHTML = `
+    <style>
+    div { width: 100%; height: 100%; }
+    </style>
+    <div><slot>hover over this text</slot></div>`;
+
+outerShadow.querySelector('div').attachShadow({mode: 'closed'}).innerHTML = `
+<style>
+div { background: yellow; width: 100%; height: 100%; }
+div:hover { background: green; color: green; }
+</style>
+<div><slot></slot></div>`;
+
+if (window.eventSender)
+    eventSender.mouseMoveTo(div.offsetLeft + 10, div.offsetTop + 10);
+
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (210563 => 210564)


--- trunk/LayoutTests/platform/ios-simulator/TestExpectations	2017-01-10 23:17:42 UTC (rev 210563)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations	2017-01-10 23:34:51 UTC (rev 210564)
@@ -356,6 +356,8 @@
 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/clear-active-state-in-shadow.html [ Skip ]
+fast/shadow-dom/hover-over-nested-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 (210563 => 210564)


--- trunk/Source/WebCore/ChangeLog	2017-01-10 23:17:42 UTC (rev 210563)
+++ trunk/Source/WebCore/ChangeLog	2017-01-10 23:34:51 UTC (rev 210564)
@@ -1,3 +1,26 @@
+2017-01-10  Ryosuke Niwa  <[email protected]>
+
+        :active and :hover states may not be updated across slots
+        https://bugs.webkit.org/show_bug.cgi?id=166881
+        <rdar://problem/29944582>
+
+        Reviewed by Antti Koivisto.
+
+        The bug was caused by updateHoverActiveState not updating :hover and :active states on elements
+        when nodes are assigned to slots because they were walking up the tree using parentOrShadowHostElement
+        and parentNode. Fixed the bug by using parentElementInComposedTree instead since :hover and :active
+        states need to be updated in accordance with the render tree, which is created from the "flat tree"
+        or the "composed tree" in WebKit's terminology (this is old terminology in the spec).
+
+        Tests: fast/shadow-dom/clear-active-state-in-shadow.html
+               fast/shadow-dom/hover-over-nested-slotted-content.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::updateHoverActiveState): Fixed the bug.
+        * dom/Node.cpp:
+        (WebCore::Node::parentElementInComposedTree): Added.
+        * dom/Node.h:
+
 2017-01-10  Keith Rollin  <[email protected]>
 
         Missing logging in IconLoader::startLoading

Modified: trunk/Source/WebCore/dom/Document.cpp (210563 => 210564)


--- trunk/Source/WebCore/dom/Document.cpp	2017-01-10 23:17:42 UTC (rev 210563)
+++ trunk/Source/WebCore/dom/Document.cpp	2017-01-10 23:34:51 UTC (rev 210564)
@@ -6475,9 +6475,9 @@
     Element* oldActiveElement = m_activeElement.get();
     if (oldActiveElement && !request.active()) {
         // We are clearing the :active chain because the mouse has been released.
-        for (Element* curr = oldActiveElement; curr; curr = curr->parentOrShadowHostElement()) {
-            curr->setActive(false);
-            m_userActionElements.setInActiveChain(curr, false);
+        for (Element* currentElement = oldActiveElement; currentElement; currentElement = currentElement->parentElementInComposedTree()) {
+            currentElement->setActive(false);
+            m_userActionElements.setInActiveChain(currentElement, false);
         }
         m_activeElement = nullptr;
     } else {
@@ -6515,7 +6515,7 @@
     // If it hasn't, we do not need to do anything.
     Element* newHoveredElement = innerElementInDocument;
     while (newHoveredElement && !newHoveredElement->renderer())
-        newHoveredElement = newHoveredElement->parentOrShadowHostElement();
+        newHoveredElement = newHoveredElement->parentElementInComposedTree();
 
     m_hoveredElement = newHoveredElement;
 
@@ -6534,7 +6534,7 @@
         // (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element (and its ancestors)
         // must be updated, to ensure it's normal style is re-applied.
         if (oldHoveredElement && !oldHoverObj) {
-            for (Element* element = oldHoveredElement.get(); element; element = element->parentElement()) {
+            for (Element* element = oldHoveredElement.get(); element; element = element->parentElementInComposedTree()) {
                 if (!mustBeInActiveChain || element->inActiveChain())
                     elementsToRemoveFromChain.append(element);
             }

Modified: trunk/Source/WebCore/dom/Node.cpp (210563 => 210564)


--- trunk/Source/WebCore/dom/Node.cpp	2017-01-10 23:17:42 UTC (rev 210563)
+++ trunk/Source/WebCore/dom/Node.cpp	2017-01-10 23:34:51 UTC (rev 210564)
@@ -1139,6 +1139,19 @@
     return parentNode();
 }
 
+Element* Node::parentElementInComposedTree() const
+{
+    if (auto* slot = assignedSlot())
+        return slot;
+    if (auto* parent = parentNode()) {
+        if (is<ShadowRoot>(*parent))
+            return downcast<ShadowRoot>(*parent).host();
+        if (is<Element>(*parent))
+            return downcast<Element>(parent);
+    }
+    return nullptr;
+}
+
 bool Node::isInUserAgentShadowTree() const
 {
     auto* shadowRoot = containingShadowRoot();

Modified: trunk/Source/WebCore/dom/Node.h (210563 => 210564)


--- trunk/Source/WebCore/dom/Node.h	2017-01-10 23:17:42 UTC (rev 210563)
+++ trunk/Source/WebCore/dom/Node.h	2017-01-10 23:34:51 UTC (rev 210564)
@@ -256,6 +256,7 @@
     // Node's parent or shadow tree host.
     ContainerNode* parentOrShadowHostNode() const;
     ContainerNode* parentInComposedTree() const;
+    Element* parentElementInComposedTree() const;
     Element* parentOrShadowHostElement() const;
     void setParentNode(ContainerNode*);
     Node& rootNode() const;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to