Title: [290257] trunk
Revision
290257
Author
an...@apple.com
Date
2022-02-21 11:48:07 -0800 (Mon, 21 Feb 2022)

Log Message

[CSS Container Queries] Support nested container queries
https://bugs.webkit.org/show_bug.cgi?id=236963

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

* web-platform-tests/css/css-contain/container-queries/container-nested-expected.txt: Added.
* web-platform-tests/css/css-contain/container-queries/container-nested.html: Added.

Source/WebCore:

"Style rules defined on an element inside multiple nested container queries apply when all of the wrapping container queries are true for that element."

https://drafts.csswg.org/css-contain-3/#container-rule

Test: imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested.html

* style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::collectMatchingRulesForList):
(WebCore::Style::ElementRuleCollector::containerQueriesMatch):

All nested queries need to match.

(WebCore::Style::ElementRuleCollector::containerQueryMatches): Deleted.
* style/ElementRuleCollector.h:
* style/RuleSet.h:
(WebCore::Style::RuleSet::hasContainerQueries const):
(WebCore::Style:: const):
(WebCore::Style::RuleSet::containerQueryFor const): Deleted.

Return all nested queries.
Don't unnecessarily copy FilteredContainerQuery, refer to the StyleRuleContainer instead.

* style/RuleSetBuilder.cpp:
(WebCore::Style::RuleSetBuilder::addChildRules):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (290256 => 290257)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2022-02-21 19:32:30 UTC (rev 290256)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2022-02-21 19:48:07 UTC (rev 290257)
@@ -1,3 +1,13 @@
+2022-02-21  Antti Koivisto  <an...@apple.com>
+
+        [CSS Container Queries] Support nested container queries
+        https://bugs.webkit.org/show_bug.cgi?id=236963
+
+        Reviewed by Simon Fraser.
+
+        * web-platform-tests/css/css-contain/container-queries/container-nested-expected.txt: Added.
+        * web-platform-tests/css/css-contain/container-queries/container-nested.html: Added.
+
 2022-02-21  Noam Rosenthal  <n...@webkit.org>
 
         PerformanceObserver: buffered flag not working in Paint Timing

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested-expected.txt (0 => 290257)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested-expected.txt	2022-02-21 19:48:07 UTC (rev 290257)
@@ -0,0 +1,16 @@
+
+PASS Nearest
+PASS Nearest, outer failing
+PASS Nearest, inner failing
+PASS Outer named, inner named
+PASS Outer named, inner named (reverse)
+PASS Failing outer name
+PASS Failing inner name
+PASS Outer named, inner nearest
+PASS Inner named, outer nearest
+PASS Inner named, outer nearest (reverse)
+PASS Three levels
+PASS Three levels, middle fail
+PASS Named inner invalidation
+PASS Nearest outer invalidation
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested.html (0 => 290257)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested.html	2022-02-21 19:48:07 UTC (rev 290257)
@@ -0,0 +1,235 @@
+<!doctype html>
+<title>@container (nested)</title>
+<link rel="help" href=""
+<script src=""
+<script src=""
+<script src=""
+<style>
+
+#outer {
+  container-name: outer;
+  container-type: size;
+  width: 100px;
+  height: 100px;
+}
+
+#inner {
+  container-name: inner;
+  container-type: size;
+  width: 50px;
+  height: 50px;
+}
+</style>
+<div id=outer>
+  <div id=inner>
+    <div id=child></div>
+  </div>
+</div>
+<script>
+  setup(() => assert_implements_container_queries());
+</script>
+
+
+<style>
+  @container size(width: 50px) {
+    @container size(height: 50px) {
+      #child { --nearest:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--nearest'), 'true');
+  }, 'Nearest');
+</script>
+
+
+<style>
+  @container size(width: 70px) {
+    @container size(height: 50px) {
+      #child { --nearest-outer-fail:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--nearest-outer-fail'), '');
+  }, 'Nearest, outer failing');
+</script>
+
+
+<style>
+  @container size(width: 50px) {
+    @container size(height: 70px) {
+      #child { --nearest-inner-fail:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--nearest-inner-fail'), '');
+  }, 'Nearest, inner failing');
+</script>
+
+
+<style>
+  @container outer size(width: 100px) {
+    @container inner size(height: 50px) {
+      #child { --named-outer-inner:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner'), 'true');
+  }, 'Outer named, inner named');
+</script>
+
+
+<style>
+  @container inner size(width: 50px) {
+    @container outer size(height: 100px) {
+      #child { --named-outer-inner-reverse:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner-reverse'), 'true');
+  }, 'Outer named, inner named (reverse)');
+</script>
+
+
+<style>
+  @container unknown size(width: 100px) {
+    @container inner size(height: 50px) {
+      #child { --named-failing-outer:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--named-failing-outer'), '');
+  }, 'Failing outer name');
+</script>
+
+<style>
+  @container outer size(width: 100px) {
+    @container unknown size(height: 50px) {
+      #child { --named-failing-inner:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--named-failing-inner'), '');
+  }, 'Failing inner name');
+</script>
+
+
+<style>
+  @container outer size(width: 100px) {
+    @container size(height: 50px) {
+      #child { --named-outer-inner-nearest:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--named-outer-inner-nearest'), 'true');
+  }, 'Outer named, inner nearest');
+</script>
+
+
+<style>
+  @container size(width: 50px) {
+    @container inner size(height: 50px) {
+      #child { --nearest-outer-inner-named:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--nearest-outer-inner-named'), 'true');
+  }, 'Inner named, outer nearest');
+</script>
+
+
+<style>
+  @container size(width: 50px) {
+    @container outer size(height: 100px) {
+      #child { --nearest-outer-inner-named-reverse:true; }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--nearest-outer-inner-named-reverse'), 'true');
+  }, 'Inner named, outer nearest (reverse)');
+</script>
+
+
+<style>
+  @container size(width > 1px) {
+    @container size(width > 2px) {
+      @container size(width > 3px) {
+        #child { --three-levels:true; }
+      }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--three-levels'), 'true');
+  }, 'Three levels');
+</script>
+
+
+<style>
+  @container size(width > 1px) {
+    @container size(width > 2000px) {
+      @container size(width > 3px) {
+        #child { --three-levels-middle-fail:true; }
+      }
+    }
+  }
+</style>
+<script>
+  test(() => {
+    assert_equals(getComputedStyle(child).getPropertyValue('--three-levels-middle-fail'), '');
+  }, 'Three levels, middle fail');
+</script>
+
+
+<style>
+  @container size(width: 50px) {
+    @container outer size(height: 100px) {
+      #child { --inner-named-invalidation:true; }
+    }
+  }
+</style>
+<script>
+  test((t) => {
+    t.add_cleanup(() => { outer.style = ''; });
+    assert_equals(getComputedStyle(child).getPropertyValue('--inner-named-invalidation'), 'true');
+    outer.style.height = '200px';
+    assert_equals(getComputedStyle(child).getPropertyValue('--inner-named-invalidation'), '');
+  }, 'Named inner invalidation');
+</script>
+
+
+<style>
+  @container size(width: 50px) {
+    @container outer size(height: 100px) {
+      #child { --outer-nearest-invalidation:true; }
+    }
+  }
+</style>
+<script>
+  test((t) => {
+    t.add_cleanup(() => { inner.style = ''; });
+    assert_equals(getComputedStyle(child).getPropertyValue('--outer-nearest-invalidation'), 'true');
+    inner.style.width = '200px';
+    assert_equals(getComputedStyle(child).getPropertyValue('--outer-nearest-invalidation'), '');
+  }, 'Nearest outer invalidation');
+</script>

Modified: trunk/Source/WebCore/ChangeLog (290256 => 290257)


--- trunk/Source/WebCore/ChangeLog	2022-02-21 19:32:30 UTC (rev 290256)
+++ trunk/Source/WebCore/ChangeLog	2022-02-21 19:48:07 UTC (rev 290257)
@@ -1,3 +1,35 @@
+2022-02-21  Antti Koivisto  <an...@apple.com>
+
+        [CSS Container Queries] Support nested container queries
+        https://bugs.webkit.org/show_bug.cgi?id=236963
+
+        Reviewed by Simon Fraser.
+
+        "Style rules defined on an element inside multiple nested container queries apply when all of the wrapping container queries are true for that element."
+
+        https://drafts.csswg.org/css-contain-3/#container-rule
+
+        Test: imported/w3c/web-platform-tests/css/css-contain/container-queries/container-nested.html
+
+        * style/ElementRuleCollector.cpp:
+        (WebCore::Style::ElementRuleCollector::collectMatchingRulesForList):
+        (WebCore::Style::ElementRuleCollector::containerQueriesMatch):
+
+        All nested queries need to match.
+
+        (WebCore::Style::ElementRuleCollector::containerQueryMatches): Deleted.
+        * style/ElementRuleCollector.h:
+        * style/RuleSet.h:
+        (WebCore::Style::RuleSet::hasContainerQueries const):
+        (WebCore::Style:: const):
+        (WebCore::Style::RuleSet::containerQueryFor const): Deleted.
+
+        Return all nested queries.
+        Don't unnecessarily copy FilteredContainerQuery, refer to the StyleRuleContainer instead.
+
+        * style/RuleSetBuilder.cpp:
+        (WebCore::Style::RuleSetBuilder::addChildRules):
+
 2022-02-21  Nikolas Zimmermann  <nzimmerm...@igalia.com>
 
         [LBSE] Implement SVG2 rules to establish a stacking context

Modified: trunk/Source/WebCore/style/ElementRuleCollector.cpp (290256 => 290257)


--- trunk/Source/WebCore/style/ElementRuleCollector.cpp	2022-02-21 19:32:30 UTC (rev 290256)
+++ trunk/Source/WebCore/style/ElementRuleCollector.cpp	2022-02-21 19:48:07 UTC (rev 290257)
@@ -485,10 +485,8 @@
         if (m_selectorMatchingState && m_selectorMatchingState->selectorFilter.fastRejectSelector(ruleData.descendantSelectorIdentifierHashes()))
             continue;
 
-        if (auto* containerQuery = matchRequest.ruleSet.containerQueryFor(ruleData)) {
-            if (!containerQueryMatches(*containerQuery))
-                continue;
-        }
+        if (matchRequest.ruleSet.hasContainerQueries() && !containerQueriesMatch(matchRequest.ruleSet.containerQueriesFor(ruleData)))
+            continue;
 
         auto& rule = ruleData.styleRule();
 
@@ -505,10 +503,18 @@
     }
 }
 
-bool ElementRuleCollector::containerQueryMatches(const FilteredContainerQuery& query)
+bool ElementRuleCollector::containerQueriesMatch(const Vector<const FilteredContainerQuery*>& queries)
 {
-    ContainerQueryEvaluator evaluator(element(), m_pseudoElementRequest.pseudoId , m_selectorMatchingState);
-    return evaluator.evaluate(query);
+    if (queries.isEmpty())
+        return true;
+
+    // "Style rules defined on an element inside multiple nested container queries apply when all of the wrapping container queries are true for that element."
+    ContainerQueryEvaluator evaluator(element(), m_pseudoElementRequest.pseudoId, m_selectorMatchingState);
+    for (auto* query : queries) {
+        if (!evaluator.evaluate(*query))
+            return false;
+    }
+    return true;
 }
 
 static inline bool compareRules(MatchedRule r1, MatchedRule r2)

Modified: trunk/Source/WebCore/style/ElementRuleCollector.h (290256 => 290257)


--- trunk/Source/WebCore/style/ElementRuleCollector.h	2022-02-21 19:32:30 UTC (rev 290256)
+++ trunk/Source/WebCore/style/ElementRuleCollector.h	2022-02-21 19:48:07 UTC (rev 290257)
@@ -112,7 +112,7 @@
     void collectMatchingRules(const MatchRequest&);
     void collectMatchingRulesForList(const RuleSet::RuleDataVector*, const MatchRequest&);
     bool ruleMatches(const RuleData&, unsigned& specificity, ScopeOrdinal);
-    bool containerQueryMatches(const FilteredContainerQuery&);
+    bool containerQueriesMatch(const Vector<const FilteredContainerQuery*>&);
 
     void sortMatchedRules();
 

Modified: trunk/Source/WebCore/style/RuleSet.h (290256 => 290257)


--- trunk/Source/WebCore/style/RuleSet.h	2022-02-21 19:32:30 UTC (rev 290256)
+++ trunk/Source/WebCore/style/RuleSet.h	2022-02-21 19:48:07 UTC (rev 290257)
@@ -108,8 +108,10 @@
     static constexpr auto cascadeLayerPriorityForUnlayered = std::numeric_limits<CascadeLayerPriority>::max();
 
     CascadeLayerPriority cascadeLayerPriorityFor(const RuleData&) const;
-    const FilteredContainerQuery* containerQueryFor(const RuleData&) const;
 
+    bool hasContainerQueries() const { return !m_containerQueries.isEmpty(); }
+    Vector<const FilteredContainerQuery*> containerQueriesFor(const RuleData&) const;
+
 private:
     friend class RuleSetBuilder;
 
@@ -144,7 +146,7 @@
     CascadeLayerPriority cascadeLayerPriorityForIdentifier(CascadeLayerIdentifier) const;
 
     struct ContainerQueryAndParent {
-        FilteredContainerQuery query;
+        Ref<StyleRuleContainer> containerRule;
         ContainerQueryIdentifier parent;
     };
 
@@ -221,16 +223,21 @@
     return cascadeLayerPriorityForIdentifier(identifier);
 }
 
-inline const FilteredContainerQuery* RuleSet::containerQueryFor(const RuleData& ruleData) const
+inline Vector<const FilteredContainerQuery*> RuleSet::containerQueriesFor(const RuleData& ruleData) const
 {
     if (m_containerQueryIdentifierForRulePosition.size() <= ruleData.position())
-        return nullptr;
+        return { };
 
+    Vector<const FilteredContainerQuery*> queries;
+
     auto identifier = m_containerQueryIdentifierForRulePosition[ruleData.position()];
-    if (!identifier)
-        return nullptr;
+    while (identifier) {
+        auto& query = m_containerQueries[identifier - 1];
+        queries.append(&query.containerRule->filteredQuery());
+        identifier = query.parent;
+    };
 
-    return &m_containerQueries[identifier - 1].query;
+    return queries;
 }
 
 

Modified: trunk/Source/WebCore/style/RuleSetBuilder.cpp (290256 => 290257)


--- trunk/Source/WebCore/style/RuleSetBuilder.cpp	2022-02-21 19:32:30 UTC (rev 290256)
+++ trunk/Source/WebCore/style/RuleSetBuilder.cpp	2022-02-21 19:48:07 UTC (rev 290257)
@@ -113,7 +113,7 @@
             auto& containerRule = downcast<StyleRuleContainer>(*rule);
             auto previousContainerQueryIdentifier = m_currentContainerQueryIdentifier;
             if (m_ruleSet) {
-                m_ruleSet->m_containerQueries.append({ containerRule.filteredQuery(), previousContainerQueryIdentifier });
+                m_ruleSet->m_containerQueries.append({ containerRule, previousContainerQueryIdentifier });
                 m_currentContainerQueryIdentifier = m_ruleSet->m_containerQueries.size();
             }
             addChildRules(containerRule.childRules());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to