Title: [227956] trunk
Revision
227956
Author
[email protected]
Date
2018-02-01 01:01:01 -0800 (Thu, 01 Feb 2018)

Log Message

Invalidate style for sibling combinators accurately on class change
https://bugs.webkit.org/show_bug.cgi?id=182336

Reviewed by Zalan Bujtas.

Source/WebCore:

Use Style::Invalidator to invalidate only those elements that may be affected by a class
change for sibling combinators and nth pseudo classes.

* css/RuleFeature.cpp:

Add new AllSiblings MatchElement to use for nth pseudo classes with subselectors.

(WebCore::isSiblingOrSubject):

Add a helper.

(WebCore::RuleFeatureSet::computeNextMatchElement):
(WebCore::RuleFeatureSet::computeSubSelectorMatchElement):

Compute and propage MatchElement::AllSiblings.

* css/RuleFeature.h:
* dom/Node.cpp:
(WebCore::Node::updateAncestorsForStyleRecalc):

Don't need to test for childrenAffectedByPropertyBasedBackwardPositionalRules anymore (an oddly named bit for nth pseudo classes).

* style/StyleInvalidator.cpp:
(WebCore::Style::Invalidator::invalidateStyleWithMatchElement):

Invalidate only the potentially affected elements.
The old code would just unconditionally invalidate the current element. This would propagate to descedants of siblings via
affectedByPreviousSibling bits. That mechanism can be removed when everything has been switched to accurate invalidation.

LayoutTests:

Adapt to progressions.

* fast/css/direct-adjacent-style-update-optimization-expected.txt:
* fast/css/direct-adjacent-style-update-optimization.html:
* fast/css/indirect-adjacent-style-update-optimization-expected.txt:
* fast/css/indirect-adjacent-style-update-optimization.html:
* fast/css/nth-last-child-of-style-update-optimization.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (227955 => 227956)


--- trunk/LayoutTests/ChangeLog	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/LayoutTests/ChangeLog	2018-02-01 09:01:01 UTC (rev 227956)
@@ -1,3 +1,18 @@
+2018-02-01  Antti Koivisto  <[email protected]>
+
+        Invalidate style for sibling combinators accurately on class change
+        https://bugs.webkit.org/show_bug.cgi?id=182336
+
+        Reviewed by Zalan Bujtas.
+
+        Adapt to progressions.
+
+        * fast/css/direct-adjacent-style-update-optimization-expected.txt:
+        * fast/css/direct-adjacent-style-update-optimization.html:
+        * fast/css/indirect-adjacent-style-update-optimization-expected.txt:
+        * fast/css/indirect-adjacent-style-update-optimization.html:
+        * fast/css/nth-last-child-of-style-update-optimization.html:
+
 2018-01-31  Antoine Quint  <[email protected]>
 
         [Modern Media Controls] Turn media/modern-media-controls/macos-inline-media-controls back on

Modified: trunk/LayoutTests/fast/css/direct-adjacent-style-update-optimization-expected.txt (227955 => 227956)


--- trunk/LayoutTests/fast/css/direct-adjacent-style-update-optimization-expected.txt	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-update-optimization-expected.txt	2018-02-01 09:01:01 UTC (rev 227956)
@@ -18,8 +18,8 @@
 PASS getComputedStyle(document.querySelectorAll("target")[1]).backgroundColor is "rgb(1, 2, 3)"
 PASS elementsWithTagnameNeedsStyleRecalc([]) is true
 Let's remove the class "property".
-Source should require a style recalc.
-PASS elementsWithTagnameNeedsStyleRecalc(["SOURCE"]) is true
+Target should require a style recalc.
+PASS elementsWithTagnameNeedsStyleRecalc(["TARGET"]) is true
 We should no longer have a match. Let's add back the class "property". Then we get the style of everything except <source> and <target>. Since none of the style touched above are related to the dirty elements, <source> should still require a style recalc.
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[0]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[1]).backgroundColor is "rgb(255, 254, 253)"
@@ -33,7 +33,7 @@
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[9]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll("target")[0]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll("target")[1]).backgroundColor is "rgb(255, 254, 253)"
-PASS elementsWithTagnameNeedsStyleRecalc(["SOURCE"]) is true
+PASS elementsWithTagnameNeedsStyleRecalc(["TARGET"]) is true
 We should match again now that property is back.
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[0]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[1]).backgroundColor is "rgb(255, 254, 253)"

Modified: trunk/LayoutTests/fast/css/direct-adjacent-style-update-optimization.html (227955 => 227956)


--- trunk/LayoutTests/fast/css/direct-adjacent-style-update-optimization.html	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-update-optimization.html	2018-02-01 09:01:01 UTC (rev 227956)
@@ -63,8 +63,8 @@
 for (var i = 0; i < allSources.length; ++i)
     allSources[i].classList.remove("property");
 
-debug("Source should require a style recalc.");
-shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["SOURCE"])');
+debug("Target should require a style recalc.");
+shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["TARGET"])');
 
 debug("We should no longer have a match. Let's add back the class \"property\". Then we get the style of everything except &lt;source&gt; and &lt;target&gt;. Since none of the style touched above are related to the dirty elements, &lt;source&gt; should still require a style recalc.");
 
@@ -82,7 +82,7 @@
         debug("Something horribly wrong is happening.");
 }
 
-shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["SOURCE"])');
+shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["TARGET"])');
 
 debug("We should match again now that property is back.");
 testColor(true);

Modified: trunk/LayoutTests/fast/css/indirect-adjacent-style-update-optimization-expected.txt (227955 => 227956)


--- trunk/LayoutTests/fast/css/indirect-adjacent-style-update-optimization-expected.txt	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/LayoutTests/fast/css/indirect-adjacent-style-update-optimization-expected.txt	2018-02-01 09:01:01 UTC (rev 227956)
@@ -18,8 +18,8 @@
 PASS getComputedStyle(document.querySelectorAll("target")[1]).backgroundColor is "rgb(1, 2, 3)"
 PASS elementsWithTagnameNeedsStyleRecalc([]) is true
 Let's remove the class "property".
-Source should require a style recalc.
-PASS elementsWithTagnameNeedsStyleRecalc(["SOURCE"]) is true
+Target should require a style recalc.
+PASS elementsWithTagnameNeedsStyleRecalc(["TARGET"]) is true
 We should no longer have a match. Let's add back the class "property". Then we get the style of everything except <source> and <target>. Since none of the style touched above are related to the dirty elements, <source> should still require a style recalc.
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[0]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[1]).backgroundColor is "rgb(255, 254, 253)"
@@ -33,7 +33,7 @@
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[9]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll("target")[0]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll("target")[1]).backgroundColor is "rgb(255, 254, 253)"
-PASS elementsWithTagnameNeedsStyleRecalc(["SOURCE"]) is true
+PASS elementsWithTagnameNeedsStyleRecalc(["TARGET"]) is true
 We should match again now that property is back.
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[0]).backgroundColor is "rgb(255, 254, 253)"
 PASS getComputedStyle(document.querySelectorAll(".test-case, .test-case :not(target)")[1]).backgroundColor is "rgb(255, 254, 253)"

Modified: trunk/LayoutTests/fast/css/indirect-adjacent-style-update-optimization.html (227955 => 227956)


--- trunk/LayoutTests/fast/css/indirect-adjacent-style-update-optimization.html	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/LayoutTests/fast/css/indirect-adjacent-style-update-optimization.html	2018-02-01 09:01:01 UTC (rev 227956)
@@ -63,8 +63,8 @@
 for (var i = 0; i < allSources.length; ++i)
     allSources[i].classList.remove("property");
 
-debug("Source should require a style recalc.");
-shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["SOURCE"])');
+debug("Target should require a style recalc.");
+shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["TARGET"])');
 
 debug("We should no longer have a match. Let's add back the class \"property\". Then we get the style of everything except &lt;source&gt; and &lt;target&gt;. Since none of the style touched above are related to the dirty elements, &lt;source&gt; should still require a style recalc.");
 
@@ -82,7 +82,7 @@
         debug("Something horribly wrong is happening.");
 }
 
-shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["SOURCE"])');
+shouldBeTrue('elementsWithTagnameNeedsStyleRecalc(["TARGET"])');
 
 debug("We should match again now that property is back.");
 testColor(true);

Modified: trunk/LayoutTests/fast/css/nth-last-child-of-style-update-optimization.html (227955 => 227956)


--- trunk/LayoutTests/fast/css/nth-last-child-of-style-update-optimization.html	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/LayoutTests/fast/css/nth-last-child-of-style-update-optimization.html	2018-02-01 09:01:01 UTC (rev 227956)
@@ -51,8 +51,8 @@
 for (var i = 0; i < allContent.length; ++i) {
     var node = allContent[i];
     if (internals.nodeNeedsStyleRecalc(node)) {
-        if (node !== target1 && node !== target1.parentNode) {
-            testFailed("Invalidating the style of target1 should never invalidate more than target1 and its parent.");
+        if (node !== target1 && node !== target1.previousElementSibling) {
+            testFailed("Invalidating the style of target1 should never invalidate more than target1 and its siblings.");
             break;
         }
     }
@@ -68,8 +68,8 @@
 for (var i = 0; i < allContent.length; ++i) {
     var node = allContent[i];
     if (internals.nodeNeedsStyleRecalc(node)) {
-        if (node !== target2 && node !== target2.parentNode) {
-            testFailed("Invalidating the style of target1 should never invalidate more than target1 and its parent.");
+        if (node !== target2 && node !== target2.previousElementSibling) {
+            testFailed("Invalidating the style of target2 should never invalidate more than target1 and its siblings.");
             break;
         }
     }

Modified: trunk/Source/WebCore/ChangeLog (227955 => 227956)


--- trunk/Source/WebCore/ChangeLog	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/Source/WebCore/ChangeLog	2018-02-01 09:01:01 UTC (rev 227956)
@@ -1,3 +1,39 @@
+2018-02-01  Antti Koivisto  <[email protected]>
+
+        Invalidate style for sibling combinators accurately on class change
+        https://bugs.webkit.org/show_bug.cgi?id=182336
+
+        Reviewed by Zalan Bujtas.
+
+        Use Style::Invalidator to invalidate only those elements that may be affected by a class
+        change for sibling combinators and nth pseudo classes.
+
+        * css/RuleFeature.cpp:
+
+        Add new AllSiblings MatchElement to use for nth pseudo classes with subselectors.
+
+        (WebCore::isSiblingOrSubject):
+
+        Add a helper.
+
+        (WebCore::RuleFeatureSet::computeNextMatchElement):
+        (WebCore::RuleFeatureSet::computeSubSelectorMatchElement):
+
+        Compute and propage MatchElement::AllSiblings.
+
+        * css/RuleFeature.h:
+        * dom/Node.cpp:
+        (WebCore::Node::updateAncestorsForStyleRecalc):
+
+        Don't need to test for childrenAffectedByPropertyBasedBackwardPositionalRules anymore (an oddly named bit for nth pseudo classes).
+
+        * style/StyleInvalidator.cpp:
+        (WebCore::Style::Invalidator::invalidateStyleWithMatchElement):
+
+        Invalidate only the potentially affected elements.
+        The old code would just unconditionally invalidate the current element. This would propagate to descedants of siblings via
+        affectedByPreviousSibling bits. That mechanism can be removed when everything has been switched to accurate invalidation.
+
 2018-01-31  Simon Fraser  <[email protected]>
 
         Use different debug red colors for different contexts

Modified: trunk/Source/WebCore/css/RuleFeature.cpp (227955 => 227956)


--- trunk/Source/WebCore/css/RuleFeature.cpp	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/Source/WebCore/css/RuleFeature.cpp	2018-02-01 09:01:01 UTC (rev 227956)
@@ -35,9 +35,28 @@
 
 namespace WebCore {
 
+static bool isSiblingOrSubject(MatchElement matchElement)
+{
+    switch (matchElement) {
+    case MatchElement::Subject:
+    case MatchElement::IndirectSibling:
+    case MatchElement::DirectSibling:
+    case MatchElement::AnySibling:
+        return true;
+    case MatchElement::Parent:
+    case MatchElement::Ancestor:
+    case MatchElement::ParentSibling:
+    case MatchElement::AncestorSibling:
+    case MatchElement::Host:
+        return false;
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
 MatchElement RuleFeatureSet::computeNextMatchElement(MatchElement matchElement, CSSSelector::RelationType relation)
 {
-    if (matchElement == MatchElement::Subject || matchElement == MatchElement::IndirectSibling || matchElement == MatchElement::DirectSibling) {
+    if (isSiblingOrSubject(matchElement)) {
         switch (relation) {
         case CSSSelector::Subselector:
             return matchElement;
@@ -46,8 +65,12 @@
         case CSSSelector::Child:
             return MatchElement::Parent;
         case CSSSelector::IndirectAdjacent:
+            if (matchElement == MatchElement::AnySibling)
+                return MatchElement::AnySibling;
             return MatchElement::IndirectSibling;
         case CSSSelector::DirectAdjacent:
+            if (matchElement == MatchElement::AnySibling)
+                return MatchElement::AnySibling;
             return matchElement == MatchElement::Subject ? MatchElement::DirectSibling : MatchElement::IndirectSibling;
         case CSSSelector::ShadowDescendant:
             return MatchElement::Host;
@@ -76,9 +99,8 @@
     if (selector.match() == CSSSelector::PseudoClass) {
         auto type = selector.pseudoClassType();
         // For :nth-child(n of .some-subselector) where an element change may affect other elements similar to sibling combinators.
-        // FIXME: This is not entirely accurate but good enough for current users.
         if (type == CSSSelector::PseudoClassNthChild || type == CSSSelector::PseudoClassNthLastChild)
-            return MatchElement::IndirectSibling;
+            return MatchElement::AnySibling;
 
         // Similarly for :host().
         if (type == CSSSelector::PseudoClassHost)

Modified: trunk/Source/WebCore/css/RuleFeature.h (227955 => 227956)


--- trunk/Source/WebCore/css/RuleFeature.h	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/Source/WebCore/css/RuleFeature.h	2018-02-01 09:01:01 UTC (rev 227956)
@@ -33,7 +33,7 @@
 class RuleData;
 class StyleRule;
 
-enum class MatchElement { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, ParentSibling, AncestorSibling, Host };
+enum class MatchElement { Subject, Parent, Ancestor, DirectSibling, IndirectSibling, AnySibling, ParentSibling, AncestorSibling, Host };
 constexpr unsigned matchElementCount = static_cast<unsigned>(MatchElement::Host) + 1;
 
 struct RuleFeature {

Modified: trunk/Source/WebCore/dom/Node.cpp (227955 => 227956)


--- trunk/Source/WebCore/dom/Node.cpp	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/Source/WebCore/dom/Node.cpp	2018-02-01 09:01:01 UTC (rev 227956)
@@ -774,9 +774,6 @@
     if (it != end) {
         it->setDirectChildNeedsStyleRecalc();
 
-        if (it->childrenAffectedByPropertyBasedBackwardPositionalRules())
-            it->adjustStyleValidity(Style::Validity::SubtreeInvalid, Style::InvalidationMode::Normal);
-
         for (; it != end; ++it) {
             // Iterator skips over shadow roots.
             if (auto* shadowRoot = it->shadowRoot())

Modified: trunk/Source/WebCore/style/StyleInvalidator.cpp (227955 => 227956)


--- trunk/Source/WebCore/style/StyleInvalidator.cpp	2018-02-01 08:52:43 UTC (rev 227955)
+++ trunk/Source/WebCore/style/StyleInvalidator.cpp	2018-02-01 09:01:01 UTC (rev 227956)
@@ -227,11 +227,29 @@
         break;
     }
     case MatchElement::DirectSibling:
+        if (auto* sibling = element.nextElementSibling())
+            invalidateIfNeeded(*sibling, nullptr);
+        break;
     case MatchElement::IndirectSibling:
+        for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling())
+            invalidateIfNeeded(*sibling, nullptr);
+        break;
+    case MatchElement::AnySibling: {
+        auto parentChildren = childrenOfType<Element>(*element.parentNode());
+        for (auto& parentChild : parentChildren)
+            invalidateIfNeeded(parentChild, nullptr);
+        break;
+    }
     case MatchElement::ParentSibling:
+        for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
+            auto siblingChildren = childrenOfType<Element>(*sibling);
+            for (auto& siblingChild : siblingChildren)
+                invalidateIfNeeded(siblingChild, nullptr);
+        }
+        break;
     case MatchElement::AncestorSibling:
-        // FIXME: Currently sibling invalidation happens during style resolution tree walk. It should be done here too.
-        element.invalidateStyle();
+        for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling())
+            invalidateStyleForDescendants(*sibling, nullptr);
         break;
     case MatchElement::Host:
         // FIXME: Handle this here as well.
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to