Title: [281798] trunk
Revision
281798
Author
[email protected]
Date
2021-08-31 04:48:10 -0700 (Tue, 31 Aug 2021)

Log Message

[CSS Cascade Layers] Compute order correctly for late added sublayers
https://bugs.webkit.org/show_bug.cgi?id=229666

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

* web-platform-tests/css/css-cascade/layer-basic-expected.txt:

Source/WebCore:

In cases like

    @layer a.b { ... }
    @layer c { ... }
    @layer a.d { ... }

'c' should have higher priority than 'a.d'.

Replace the per-RuleData layer order vector with references (indexes) to layer entry vector.
These entries have order field that can be recomputed.

* style/RuleSet.cpp:
(WebCore::Style::RuleSet::addRule):
(WebCore::Style::RuleSet::Builder::addStyleRule):
(WebCore::Style::RuleSet::Builder::pushCascadeLayer):

Instead of computing order directly we just give each layer an identifier and add an entry for it to the layer vector.

(WebCore::Style::RuleSet::Builder::popCascadeLayer):
(WebCore::Style::RuleSet::Builder::~Builder):

Compute layer order after building for all layers.

(WebCore::Style::RuleSet::shrinkToFit):
* style/RuleSet.h:
(WebCore::Style::RuleSet::cascadeLayerForIdentifier):
(WebCore::Style::RuleSet::cascadeLayerForIdentifier const):
(WebCore::Style::RuleSet::cascadeLayerOrderFor const):

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (281797 => 281798)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-08-31 11:48:10 UTC (rev 281798)
@@ -1,3 +1,12 @@
+2021-08-31  Antti Koivisto  <[email protected]>
+
+        [CSS Cascade Layers] Compute order correctly for late added sublayers
+        https://bugs.webkit.org/show_bug.cgi?id=229666
+
+        Reviewed by Simon Fraser.
+
+        * web-platform-tests/css/css-cascade/layer-basic-expected.txt:
+
 2021-08-31  Youenn Fablet  <[email protected]>
 
         Add support for RTCIceTransport

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt (281797 => 281798)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt	2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt	2021-08-31 11:48:10 UTC (rev 281798)
@@ -17,20 +17,20 @@
 PASS B7 Named layers
 PASS B8 Named layers
 PASS B9 Named layers
-FAIL B10 Named layers assert_equals: B10 Named layers, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS B10 Named layers
 PASS C1 Named layers shorthand
 PASS C2 Named layers shorthand
-FAIL C3 Named layers shorthand assert_equals: C3 Named layers shorthand, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS C3 Named layers shorthand
 PASS C4 Named layers shorthand
-FAIL C5 Named layers shorthand assert_equals: C5 Named layers shorthand, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS C5 Named layers shorthand
 PASS D1 Mixed named and anonymous layers
 PASS D2 Mixed named and anonymous layers
 PASS D3 Mixed named and anonymous layers
-FAIL D4 Mixed named and anonymous layers assert_equals: D4 Mixed named and anonymous layers, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS D4 Mixed named and anonymous layers
 PASS D5 Mixed named and anonymous layers
 PASS E1 Statement syntax
 PASS E2 Statement syntax
 PASS E3 Statement syntax
 PASS E4 Statement syntax
-FAIL E5 Statement syntax assert_equals: E5 Statement syntax, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS E5 Statement syntax
 

Modified: trunk/Source/WebCore/ChangeLog (281797 => 281798)


--- trunk/Source/WebCore/ChangeLog	2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/Source/WebCore/ChangeLog	2021-08-31 11:48:10 UTC (rev 281798)
@@ -1,3 +1,39 @@
+2021-08-31  Antti Koivisto  <[email protected]>
+
+        [CSS Cascade Layers] Compute order correctly for late added sublayers
+        https://bugs.webkit.org/show_bug.cgi?id=229666
+
+        Reviewed by Simon Fraser.
+
+        In cases like
+
+            @layer a.b { ... }
+            @layer c { ... }
+            @layer a.d { ... }
+
+        'c' should have higher priority than 'a.d'.
+
+        Replace the per-RuleData layer order vector with references (indexes) to layer entry vector.
+        These entries have order field that can be recomputed.
+
+        * style/RuleSet.cpp:
+        (WebCore::Style::RuleSet::addRule):
+        (WebCore::Style::RuleSet::Builder::addStyleRule):
+        (WebCore::Style::RuleSet::Builder::pushCascadeLayer):
+
+        Instead of computing order directly we just give each layer an identifier and add an entry for it to the layer vector.
+
+        (WebCore::Style::RuleSet::Builder::popCascadeLayer):
+        (WebCore::Style::RuleSet::Builder::~Builder):
+
+        Compute layer order after building for all layers.
+
+        (WebCore::Style::RuleSet::shrinkToFit):
+        * style/RuleSet.h:
+        (WebCore::Style::RuleSet::cascadeLayerForIdentifier):
+        (WebCore::Style::RuleSet::cascadeLayerForIdentifier const):
+        (WebCore::Style::RuleSet::cascadeLayerOrderFor const):
+
 2021-08-31  Philippe Normand  <[email protected]>
 
         Unreviewed, OpenXR build warning fix.

Modified: trunk/Source/WebCore/style/RuleSet.cpp (281797 => 281798)


--- trunk/Source/WebCore/style/RuleSet.cpp	2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/Source/WebCore/style/RuleSet.cpp	2021-08-31 11:48:10 UTC (rev 281798)
@@ -83,15 +83,15 @@
     return leftmostSelector->match() == CSSSelector::PseudoClass && leftmostSelector->pseudoClassType() == CSSSelector::PseudoClassHost;
 }
 
-void RuleSet::addRule(const StyleRule& rule, unsigned selectorIndex, unsigned selectorListIndex, unsigned cascadeLayerOrder, MediaQueryCollector* mediaQueryCollector)
+void RuleSet::addRule(const StyleRule& rule, unsigned selectorIndex, unsigned selectorListIndex, unsigned cascadeLayerIdentifier, MediaQueryCollector* mediaQueryCollector)
 {
     RuleData ruleData(rule, selectorIndex, selectorListIndex, m_ruleCount++);
 
-    if (cascadeLayerOrder) {
-        auto oldSize = m_cascadeLayerOrderForPosition.size();
-        m_cascadeLayerOrderForPosition.grow(m_ruleCount);
-        std::fill(m_cascadeLayerOrderForPosition.begin() + oldSize, m_cascadeLayerOrderForPosition.end(), 0);
-        m_cascadeLayerOrderForPosition.last() = cascadeLayerOrder;
+    if (cascadeLayerIdentifier) {
+        auto oldSize = m_cascadeLayerIdentifierForRulePosition.size();
+        m_cascadeLayerIdentifierForRulePosition.grow(m_ruleCount);
+        std::fill(m_cascadeLayerIdentifierForRulePosition.begin() + oldSize, m_cascadeLayerIdentifierForRulePosition.end(), 0);
+        m_cascadeLayerIdentifierForRulePosition.last() = cascadeLayerIdentifier;
     }
 
     m_features.collectFeatures(ruleData);
@@ -385,6 +385,12 @@
     addChildRules(sheet.childRules());
 }
 
+RuleSet::Builder::~Builder()
+{
+    if (mode == Mode::Normal && !cascadeLayerIdentifierMap.isEmpty())
+        updateCascadeLayerOrder();
+}
+
 void RuleSet::Builder::addStyleRule(const StyleRule& rule)
 {
     auto& selectorList = rule.selectorList();
@@ -392,7 +398,7 @@
         return;
     unsigned selectorListIndex = 0;
     for (size_t selectorIndex = 0; selectorIndex != notFound; selectorIndex = selectorList.indexOfNextSelectorAfter(selectorIndex))
-        ruleSet->addRule(rule, selectorIndex, selectorListIndex++, cascadeLayerOrder, &mediaQueryCollector);
+        ruleSet->addRule(rule, selectorIndex, selectorListIndex++, currentCascadeLayerIdentifier, &mediaQueryCollector);
 }
 
 void RuleSet::Builder::pushCascadeLayer(const CascadeLayerName& name)
@@ -399,6 +405,14 @@
 {
     if (mode != Mode::Normal)
         return;
+
+    if (cascadeLayerIdentifierMap.isEmpty() && !ruleSet->m_cascadeLayers.isEmpty()) {
+        // For incremental build, reconstruct the name->identifier map.
+        CascadeLayerIdentifier identifier = 0;
+        for (auto& layer : ruleSet->m_cascadeLayers)
+            cascadeLayerIdentifierMap.add(layer.resolvedName, ++identifier);
+    }
+
     auto nameResolvingAnonymous = [&] {
         if (name.isEmpty()) {
             // Make unique name for an anonymous layer.
@@ -411,9 +425,10 @@
     // For hierarchical names we register the containing layers individually first.
     for (auto& nameSegment : nameResolvingAnonymous()) {
         resolvedCascadeLayerName.append(nameSegment);
-        cascadeLayerOrder = ruleSet->m_cascadeLayerOrderMap.ensure(resolvedCascadeLayerName, [&] {
-            // FIXME: This is not correct when adding a sublayer to an already registered layer after it has gained siblings.
-            return ruleSet->m_cascadeLayerOrderMap.size() + 1;
+        currentCascadeLayerIdentifier = cascadeLayerIdentifierMap.ensure(resolvedCascadeLayerName, [&] {
+            // Previously unseen layer.
+            ruleSet->m_cascadeLayers.append({ resolvedCascadeLayerName, currentCascadeLayerIdentifier });
+            return ruleSet->m_cascadeLayers.size();
         }).iterator->value;
     }
 }
@@ -422,11 +437,44 @@
 {
     if (mode != Mode::Normal)
         return;
-    auto size = name.isEmpty() ? 1 : name.size();
-    resolvedCascadeLayerName.shrink(resolvedCascadeLayerName.size() - size);
-    cascadeLayerOrder = resolvedCascadeLayerName.isEmpty() ? 0 : ruleSet->m_cascadeLayerOrderMap.get(resolvedCascadeLayerName);
+
+    for (auto size = name.isEmpty() ? 1 : name.size(); size--;) {
+        resolvedCascadeLayerName.removeLast();
+        currentCascadeLayerIdentifier = ruleSet->cascadeLayerForIdentifier(currentCascadeLayerIdentifier).parentIdentifier;
+    }
 }
 
+void RuleSet::Builder::updateCascadeLayerOrder()
+{
+    auto compare = [&](CascadeLayerIdentifier a, CascadeLayerIdentifier b) {
+        while (a && b) {
+            // Identifiers are in parse order which almost corresponds to the layer priority order.
+            // The only exception is when a sublayer gets added to a layer after adding other non-sublayers.
+            // To resolve this we need look for a shared ancestor layer.
+            auto aParent = ruleSet->cascadeLayerForIdentifier(a).parentIdentifier;
+            auto bParent = ruleSet->cascadeLayerForIdentifier(b).parentIdentifier;
+            if (aParent == bParent || aParent == b || bParent == a)
+                break;
+            if (aParent > bParent)
+                a = aParent;
+            else
+                b = bParent;
+        }
+        return a < b;
+    };
+
+    Vector<CascadeLayerIdentifier> orderVector;
+    auto layerCount = ruleSet->m_cascadeLayers.size();
+    orderVector.reserveInitialCapacity(layerCount);
+    for (CascadeLayerIdentifier identifier = 1; identifier <= layerCount; ++identifier)
+        orderVector.uncheckedAppend(identifier);
+
+    std::sort(orderVector.begin(), orderVector.end(), compare);
+
+    for (unsigned i = 0; i < orderVector.size(); ++i)
+        ruleSet->cascadeLayerForIdentifier(orderVector[i]).order = i + 1;
+}
+
 template<typename Function>
 void RuleSet::traverseRuleDatas(Function&& function)
 {
@@ -561,7 +609,8 @@
 
     shrinkDynamicRules(m_dynamicMediaQueryRules);
 
-    m_cascadeLayerOrderForPosition.shrinkToFit();
+    m_cascadeLayers.shrinkToFit();
+    m_cascadeLayerIdentifierForRulePosition.shrinkToFit();
 }
 
 RuleSet::MediaQueryCollector::~MediaQueryCollector() = default;

Modified: trunk/Source/WebCore/style/RuleSet.h (281797 => 281798)


--- trunk/Source/WebCore/style/RuleSet.h	2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/Source/WebCore/style/RuleSet.h	2021-08-31 11:48:10 UTC (rev 281798)
@@ -150,6 +150,8 @@
 private:
     RuleSet();
 
+    using CascadeLayerIdentifier = unsigned;
+
     struct Builder {
         enum class Mode { Normal, ResolverMutationScan };
 
@@ -158,9 +160,12 @@
         Style::Resolver* resolver { nullptr };
         Mode mode { Mode::Normal };
         CascadeLayerName resolvedCascadeLayerName { };
-        unsigned cascadeLayerOrder { 0 };
+        HashMap<CascadeLayerName, CascadeLayerIdentifier> cascadeLayerIdentifierMap { };
+        CascadeLayerIdentifier currentCascadeLayerIdentifier { 0 };
 
         void addRulesFromSheet(const StyleSheetContents&);
+
+        ~Builder();
         
     private:
         void addChildRules(const Vector<RefPtr<StyleRuleBase>>&);
@@ -168,6 +173,7 @@
 
         void pushCascadeLayer(const CascadeLayerName&);
         void popCascadeLayer(const CascadeLayerName&);
+        void updateCascadeLayerOrder();
     };
 
     struct CollectedMediaQueryChanges {
@@ -179,6 +185,14 @@
 
     template<typename Function> void traverseRuleDatas(Function&&);
 
+    struct CascadeLayer {
+        CascadeLayerName resolvedName;
+        CascadeLayerIdentifier parentIdentifier;
+        unsigned order { 0 };
+    };
+    CascadeLayer& cascadeLayerForIdentifier(CascadeLayerIdentifier identifier) { return m_cascadeLayers[identifier - 1]; }
+    const CascadeLayer& cascadeLayerForIdentifier(CascadeLayerIdentifier identifier) const { return m_cascadeLayers[identifier - 1]; }
+
     AtomRuleMap m_idRules;
     AtomRuleMap m_classRules;
     AtomRuleMap m_tagLocalNameRules;
@@ -199,9 +213,9 @@
     HashMap<Vector<size_t>, Ref<const RuleSet>> m_mediaQueryInvalidationRuleSetCache;
     unsigned m_ruleCount { 0 };
 
-    HashMap<CascadeLayerName, unsigned> m_cascadeLayerOrderMap;
-    // This is a side vector to hold layer order without bloating RuleData.
-    Vector<unsigned> m_cascadeLayerOrderForPosition;
+    Vector<CascadeLayer> m_cascadeLayers;
+    // This is a side vector to hold layer identifiers without bloating RuleData.
+    Vector<CascadeLayerIdentifier> m_cascadeLayerIdentifierForRulePosition;
 
     bool m_hasHostPseudoClassRulesMatchingInShadowTree { false };
     bool m_autoShrinkToFitEnabled { true };
@@ -220,11 +234,13 @@
 
 inline unsigned RuleSet::cascadeLayerOrderFor(const RuleData& ruleData) const
 {
-    if (m_cascadeLayerOrderForPosition.size() > ruleData.position())
-        return m_cascadeLayerOrderForPosition[ruleData.position()];
-    return 0;
+    if (m_cascadeLayerIdentifierForRulePosition.size() <= ruleData.position())
+        return 0;
+    auto identifier = m_cascadeLayerIdentifierForRulePosition[ruleData.position()];
+    if (!identifier)
+        return 0;
+    return cascadeLayerForIdentifier(identifier).order;
 }
 
-
 } // namespace Style
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to