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());