Changeset 291098 in webkit
- Timestamp:
- Mar 10, 2022 2:22:14 AM (4 months ago)
- Location:
- trunk
- Files:
-
- 11 edited
-
LayoutTests/imported/w3c/ChangeLog (modified) (1 diff)
-
LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt (modified) (2 diffs)
-
LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/css/ContainerQuery.cpp (modified) (2 diffs)
-
Source/WebCore/css/ContainerQuery.h (modified) (2 diffs)
-
Source/WebCore/css/ContainerQueryParser.cpp (modified) (2 diffs)
-
Source/WebCore/css/ContainerQueryParser.h (modified) (2 diffs)
-
Source/WebCore/css/parser/CSSParserImpl.cpp (modified) (3 diffs)
-
Source/WebCore/style/ContainerQueryEvaluator.cpp (modified) (11 diffs)
-
Source/WebCore/style/ContainerQueryEvaluator.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/imported/w3c/ChangeLog
r291092 r291098 1 2022-03-10 Antti Koivisto <antti@apple.com> 2 3 [CSS Container Queries] Implement new container selection algorithm 4 https://bugs.webkit.org/show_bug.cgi?id=237657 5 6 Reviewed by Antoine Quint. 7 8 * web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt: 9 * web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt: 10 1 11 2022-03-09 Youenn Fablet <youenn@apple.com> 2 12 -
trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt
r291036 r291098 3 3 PASS (height: 16px) for .inline > .size > span 4 4 PASS (width: 16px) for .inline > .size > span 5 FAIL (height: 32px) for .size > .inline > span assert_equals: expected "true" but got "" 5 PASS (height: 32px) for .size > .inline > span 6 6 PASS (height: 16px) for .size > .inline > span 7 7 PASS a (width: 32px) for .a-size > .b-size > span … … 15 15 PASS a (width: 8px) for .a-size > .b-size > .a-inline > span 16 16 PASS b (width: 16px) for .a-size > .b-size > .a-inline > span 17 FAIL a (height: 32px) for .a-size > .b-size > .a-inline > span assert_equals: expected "true" but got "" 17 PASS a (height: 32px) for .a-size > .b-size > .a-inline > span 18 18 PASS a (height) for .a-inline > .b-size 19 19 PASS a (inline-size: 8px) for .a-size > .b-size > .a-inline > span 20 20 PASS b (inline-size: 16px) for .a-size > .b-size > .a-inline > span 21 FAIL a (block-size: 32px) for .a-size > .b-size > .a-inline > span assert_equals: expected "true" but got "" 21 PASS a (block-size: 32px) for .a-size > .b-size > .a-inline > span 22 22 PASS a (block-size) for .a-inline > .b-size 23 23 -
trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt
r291036 r291098 3 3 PASS (width > 0px) 4 4 PASS (height > 0px) 5 FAIL ((height > 0px) or (width > 0px)) assert_equals: expected "" but got "true" 6 FAIL ((width > 0px) or (height > 0px)) assert_equals: expected "" but got "true" 7 FAIL ((orientation: landscape) or (width > 0px)) assert_equals: expected "" but got "true" 8 FAIL ((width > 0px) or (orientation: landscape)) assert_equals: expected "" but got "true" 5 PASS ((height > 0px) or (width > 0px)) 6 PASS ((width > 0px) or (height > 0px)) 7 PASS ((orientation: landscape) or (width > 0px)) 8 PASS ((width > 0px) or (orientation: landscape)) 9 9 PASS ((height > 0px) or (orientation: landscape)) 10 10 PASS ((height > 0px) or (orientation: landscape)), with contain:size -
trunk/Source/WebCore/ChangeLog
r291096 r291098 1 2022-03-10 Antti Koivisto <antti@apple.com> 2 3 [CSS Container Queries] Implement new container selection algorithm 4 https://bugs.webkit.org/show_bug.cgi?id=237657 5 6 Reviewed by Antoine Quint. 7 8 "For each element, the query container to be queried is selected from among the element’s 9 ancestor query containers that have a valid container-type for all the container features 10 in the <container-condition>." 11 12 https://drafts.csswg.org/css-contain-3/#container-rule 13 14 * css/ContainerQuery.cpp: 15 (WebCore::CQ::requiredAxesForFeature): 16 * css/ContainerQuery.h: 17 * css/ContainerQueryParser.cpp: 18 (WebCore::ContainerQueryParser::consumeFilteredContainerQuery): 19 20 Move container name parsing to ContainerQueryParser too. 21 22 (WebCore::ContainerQueryParser::consumeSizeQuery): 23 24 Collect required axes during parsing. 25 26 * css/ContainerQueryParser.h: 27 * css/parser/CSSParserImpl.cpp: 28 (WebCore::CSSParserImpl::consumeContainerRule): 29 * style/ContainerQueryEvaluator.cpp: 30 (WebCore::Style::ContainerQueryEvaluator::evaluate const): 31 (WebCore::Style::ContainerQueryEvaluator::selectContainer const): 32 33 Select container based on required axes for the features being used. 34 35 (WebCore::Style::ContainerQueryEvaluator::evaluateQuery const): 36 (WebCore::Style::ContainerQueryEvaluator::evaluateCondition const): 37 (WebCore::Style::ContainerQueryEvaluator::evaluateSizeFeature const): 38 39 No need to check axes during evaluation anymore. We only evaluate against containers that support them. 40 41 (WebCore::Style::ContainerQueryEvaluator::resolveContainer const): Deleted. 42 43 Rename resolveContainer -> selectContainer to match the spec. 44 45 * style/ContainerQueryEvaluator.h: 46 1 47 2022-03-07 Carlos Garcia Campos <cgarcia@igalia.com> 2 48 -
trunk/Source/WebCore/css/ContainerQuery.cpp
r289838 r291098 28 28 #include <wtf/NeverDestroyed.h> 29 29 30 namespace WebCore::CQ::FeatureNames { 30 namespace WebCore::CQ { 31 32 namespace FeatureNames { 31 33 32 34 const AtomString& width() … … 68 70 } 69 71 72 OptionSet<Axis> requiredAxesForFeature(const AtomString& featureName) 73 { 74 if (featureName == FeatureNames::width()) 75 return { Axis::Width }; 76 if (featureName == FeatureNames::height()) 77 return { Axis::Height }; 78 if (featureName == FeatureNames::inlineSize()) 79 return { Axis::Inline }; 80 if (featureName == FeatureNames::blockSize()) 81 return { Axis::Block }; 82 if (featureName == FeatureNames::aspectRatio() || featureName == FeatureNames::orientation()) 83 return { Axis::Inline, Axis::Block }; 84 return { }; 85 } 86 87 } 88 -
trunk/Source/WebCore/css/ContainerQuery.h
r290037 r291098 75 75 }; 76 76 77 enum class Axis : uint8_t { 78 Block = 1 << 0, 79 Inline = 1 << 1, 80 Width = 1 << 2, 81 Height = 1 << 3, 82 }; 83 OptionSet<Axis> requiredAxesForFeature(const AtomString&); 84 77 85 } 78 86 … … 81 89 struct FilteredContainerQuery { 82 90 AtomString nameFilter; 91 OptionSet<CQ::Axis> axisFilter; 83 92 ContainerQuery query; 84 93 }; -
trunk/Source/WebCore/css/ContainerQueryParser.cpp
r291046 r291098 31 31 namespace WebCore { 32 32 33 std::optional< ContainerQuery> ContainerQueryParser::consumeContainerQuery(CSSParserTokenRange& range, const CSSParserContext& context)33 std::optional<FilteredContainerQuery> ContainerQueryParser::consumeFilteredContainerQuery(CSSParserTokenRange& range, const CSSParserContext& context) 34 34 { 35 35 ContainerQueryParser parser(context); 36 return parser.consumeContainerQuery(range); 36 return parser.consumeFilteredContainerQuery(range); 37 } 38 39 std::optional<FilteredContainerQuery> ContainerQueryParser::consumeFilteredContainerQuery(CSSParserTokenRange& range) 40 { 41 auto consumeName = [&]() -> AtomString { 42 if (range.peek().type() == LeftParenthesisToken || range.peek().type() == FunctionToken) 43 return nullAtom(); 44 auto nameValue = CSSPropertyParserHelpers::consumeSingleContainerName(range); 45 if (!nameValue) 46 return nullAtom(); 47 return nameValue->stringValue(); 48 }; 49 50 auto name = consumeName(); 51 52 m_requiredAxes = { }; 53 54 auto query = consumeContainerQuery(range); 55 if (!query) 56 return { }; 57 58 return FilteredContainerQuery { name, m_requiredAxes, *query }; 37 59 } 38 60 … … 138 160 if (!sizeFeature) 139 161 return { }; 162 163 m_requiredAxes.add(CQ::requiredAxesForFeature(sizeFeature->name)); 140 164 141 165 return { *sizeFeature }; -
trunk/Source/WebCore/css/ContainerQueryParser.h
r290037 r291098 35 35 class ContainerQueryParser { 36 36 public: 37 static std::optional< ContainerQuery> consumeContainerQuery(CSSParserTokenRange&, const CSSParserContext&);37 static std::optional<FilteredContainerQuery> consumeFilteredContainerQuery(CSSParserTokenRange&, const CSSParserContext&); 38 38 39 39 private: 40 std::optional<FilteredContainerQuery> consumeFilteredContainerQuery(CSSParserTokenRange&); 40 41 std::optional<CQ::ContainerQuery> consumeContainerQuery(CSSParserTokenRange&); 41 42 std::optional<CQ::SizeQuery> consumeSizeQuery(CSSParserTokenRange&); … … 50 51 51 52 const CSSParserContext m_context; 53 54 OptionSet<CQ::Axis> m_requiredAxes; 52 55 }; 53 56 -
trunk/Source/WebCore/css/parser/CSSParserImpl.cpp
r289742 r291098 856 856 return nullptr; 857 857 858 auto consumeName = [&]() -> AtomString { 859 if (prelude.peek().type() == LeftParenthesisToken || prelude.peek().type() == FunctionToken) 860 return nullAtom(); 861 auto nameValue = CSSPropertyParserHelpers::consumeSingleContainerName(prelude); 862 if (!nameValue) 863 return nullAtom(); 864 return nameValue->stringValue(); 865 }; 866 867 auto name = consumeName(); 868 869 auto query = ContainerQueryParser::consumeContainerQuery(prelude, m_context); 858 auto query = ContainerQueryParser::consumeFilteredContainerQuery(prelude, m_context); 870 859 if (!query) 871 860 return nullptr; … … 876 865 877 866 if (m_deferredParser) 878 return StyleRuleContainer::create( { name, *query }, makeUnique<DeferredStyleGroupRuleList>(block, *m_deferredParser));867 return StyleRuleContainer::create(WTFMove(*query), makeUnique<DeferredStyleGroupRuleList>(block, *m_deferredParser)); 879 868 880 869 Vector<RefPtr<StyleRuleBase>> rules; … … 894 883 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block)); 895 884 896 return StyleRuleContainer::create( { name, *query }, WTFMove(rules));885 return StyleRuleContainer::create(WTFMove(*query), WTFMove(rules)); 897 886 } 898 887 -
trunk/Source/WebCore/style/ContainerQueryEvaluator.cpp
r290681 r291098 39 39 namespace WebCore::Style { 40 40 41 struct ContainerQueryEvaluator:: ResolvedContainer {41 struct ContainerQueryEvaluator::SelectedContainer { 42 42 const RenderBox* renderer { nullptr }; 43 43 CSSToLengthConversionData conversionData; … … 53 53 bool ContainerQueryEvaluator::evaluate(const FilteredContainerQuery& filteredContainerQuery) const 54 54 { 55 auto container = resolveContainer(filteredContainerQuery);55 auto container = selectContainer(filteredContainerQuery); 56 56 if (!container) 57 57 return false; … … 60 60 } 61 61 62 auto ContainerQueryEvaluator::resolveContainer(const FilteredContainerQuery& filteredContainerQuery) const -> std::optional<ResolvedContainer> 63 { 64 auto makeResolvedContainer = [](const Element& element) -> ResolvedContainer { 62 auto ContainerQueryEvaluator::selectContainer(const FilteredContainerQuery& filteredContainerQuery) const -> std::optional<SelectedContainer> 63 { 64 // "For each element, the query container to be queried is selected from among the element’s 65 // ancestor query containers that have a valid container-type for all the container features 66 // in the <container-condition>. The optional <container-name> filters the set of query containers 67 // considered to just those with a matching query container name." 68 // https://drafts.csswg.org/css-contain-3/#container-rule 69 70 auto makeSelectedContainer = [](const Element& element) -> SelectedContainer { 65 71 auto* renderer = dynamicDowncast<RenderBox>(element.renderer()); 66 72 if (!renderer) 67 73 return { }; 68 74 auto& view = renderer->view(); 69 return ResolvedContainer{75 return { 70 76 renderer, 71 77 CSSToLengthConversionData { &renderer->style(), &view.style(), nullptr, &view, 1 } 72 78 }; 79 }; 80 81 auto computeUnsupportedAxes = [&](ContainerType containerType, const RenderElement* principalBox) -> OptionSet<CQ::Axis> { 82 switch (containerType) { 83 case ContainerType::Size: 84 return { }; 85 case ContainerType::InlineSize: 86 // Without a principal box the container matches but the query against it will evaluate to Unknown. 87 if (!principalBox) 88 return { }; 89 if (!principalBox->isHorizontalWritingMode()) 90 return { CQ::Axis::Width, CQ::Axis::Block }; 91 return { CQ::Axis::Height, CQ::Axis::Block }; 92 case ContainerType::None: 93 return { CQ::Axis::Width, CQ::Axis::Height, CQ::Axis::Inline, CQ::Axis::Block }; 94 } 95 RELEASE_ASSERT_NOT_REACHED(); 73 96 }; 74 97 … … 77 100 if (!style) 78 101 return false; 79 if (style->containerType() == ContainerType::None) 102 auto unsupportedAxes = computeUnsupportedAxes(style->containerType(), element.renderer()); 103 if (filteredContainerQuery.axisFilter.containsAny(unsupportedAxes)) 80 104 return false; 81 105 if (filteredContainerQuery.nameFilter.isEmpty()) 82 106 return true; 83 return style->containerNames().contains(filteredContainerQuery.nameFilter);107 return element.existingComputedStyle()->containerNames().contains(filteredContainerQuery.nameFilter); 84 108 }; 85 109 … … 87 111 for (auto& container : makeReversedRange(m_selectorMatchingState->queryContainers)) { 88 112 if (isContainerForQuery(container)) 89 return make ResolvedContainer(container);113 return makeSelectedContainer(container); 90 114 } 91 115 return { }; … … 94 118 if (m_pseudoId != PseudoId::None) { 95 119 if (isContainerForQuery(m_element)) 96 return make ResolvedContainer(m_element);120 return makeSelectedContainer(m_element); 97 121 } 98 122 99 123 for (auto& ancestor : composedTreeAncestors(const_cast<Element&>(m_element.get()))) { 100 124 if (isContainerForQuery(ancestor)) 101 return make ResolvedContainer(ancestor);125 return makeSelectedContainer(ancestor); 102 126 } 103 127 return { }; 104 128 } 105 129 106 107 auto ContainerQueryEvaluator::evaluateQuery(const CQ::ContainerQuery& containerQuery, const ResolvedContainer& container) const -> EvaluationResult 130 auto ContainerQueryEvaluator::evaluateQuery(const CQ::ContainerQuery& containerQuery, const SelectedContainer& container) const -> EvaluationResult 108 131 { 109 132 return WTF::switchOn(containerQuery, [&](const CQ::ContainerCondition& containerCondition) { … … 116 139 } 117 140 118 auto ContainerQueryEvaluator::evaluateQuery(const CQ::SizeQuery& sizeQuery, const ResolvedContainer& container) const -> EvaluationResult141 auto ContainerQueryEvaluator::evaluateQuery(const CQ::SizeQuery& sizeQuery, const SelectedContainer& container) const -> EvaluationResult 119 142 { 120 143 return WTF::switchOn(sizeQuery, [&](const CQ::SizeCondition& sizeCondition) { … … 126 149 127 150 template<typename ConditionType> 128 auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, const ResolvedContainer& container) const -> EvaluationResult151 auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, const SelectedContainer& container) const -> EvaluationResult 129 152 { 130 153 if (condition.queries.isEmpty()) … … 177 200 } 178 201 179 auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFeature, const ResolvedContainer& container) const -> EvaluationResult202 auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFeature, const SelectedContainer& container) const -> EvaluationResult 180 203 { 181 204 // "If the query container does not have a principal box ... then the result of evaluating the size feature is unknown." … … 250 273 }; 251 274 252 enum class Axis : uint8_t { Both, Block, Inline, Width, Height }; 253 auto containerSupportsRequiredAxis = [&](Axis axis) { 254 switch (renderer.style().containerType()) { 255 case ContainerType::Size: 256 return true; 257 case ContainerType::InlineSize: 258 if (axis == Axis::Width) 259 return renderer.isHorizontalWritingMode(); 260 if (axis == Axis::Height) 261 return !renderer.isHorizontalWritingMode(); 262 return axis == Axis::Inline; 263 case ContainerType::None: 264 RELEASE_ASSERT_NOT_REACHED(); 265 } 266 RELEASE_ASSERT_NOT_REACHED(); 267 }; 268 269 if (sizeFeature.name == CQ::FeatureNames::width()) { 270 if (!containerSupportsRequiredAxis(Axis::Width)) 271 return EvaluationResult::Unknown; 272 275 if (sizeFeature.name == CQ::FeatureNames::width()) 273 276 return evaluateSize(renderer.contentWidth()); 274 } 275 276 if (sizeFeature.name == CQ::FeatureNames::height()) { 277 if (!containerSupportsRequiredAxis(Axis::Height)) 278 return EvaluationResult::Unknown; 279 277 278 if (sizeFeature.name == CQ::FeatureNames::height()) 280 279 return evaluateSize(renderer.contentHeight()); 281 } 282 283 if (sizeFeature.name == CQ::FeatureNames::inlineSize()) { 284 if (!containerSupportsRequiredAxis(Axis::Inline)) 285 return EvaluationResult::Unknown; 286 280 281 if (sizeFeature.name == CQ::FeatureNames::inlineSize()) 287 282 return evaluateSize(renderer.contentLogicalWidth()); 288 } 289 290 if (sizeFeature.name == CQ::FeatureNames::blockSize()) { 291 if (!containerSupportsRequiredAxis(Axis::Block)) 292 return EvaluationResult::Unknown; 293 283 284 if (sizeFeature.name == CQ::FeatureNames::blockSize()) 294 285 return evaluateSize(renderer.contentLogicalHeight()); 295 }296 286 297 287 if (sizeFeature.name == CQ::FeatureNames::aspectRatio()) { 298 if (!containerSupportsRequiredAxis(Axis::Both))299 return EvaluationResult::Unknown;300 301 288 auto boxRatio = renderer.contentWidth().toDouble() / renderer.contentHeight().toDouble(); 302 289 … … 311 298 312 299 if (sizeFeature.name == CQ::FeatureNames::orientation()) { 313 if (!containerSupportsRequiredAxis(Axis::Both))314 return EvaluationResult::Unknown;315 316 300 if (!sizeFeature.rightComparison) 317 301 return EvaluationResult::Unknown; -
trunk/Source/WebCore/style/ContainerQueryEvaluator.h
r290681 r291098 44 44 45 45 private: 46 struct ResolvedContainer;47 std::optional< ResolvedContainer> resolveContainer(const FilteredContainerQuery&) const;46 struct SelectedContainer; 47 std::optional<SelectedContainer> selectContainer(const FilteredContainerQuery&) const; 48 48 49 EvaluationResult evaluateQuery(const CQ::ContainerQuery&, const ResolvedContainer&) const;50 EvaluationResult evaluateQuery(const CQ::SizeQuery&, const ResolvedContainer&) const;51 template<typename ConditionType> EvaluationResult evaluateCondition(const ConditionType&, const ResolvedContainer&) const;52 EvaluationResult evaluateSizeFeature(const CQ::SizeFeature&, const ResolvedContainer&) const;49 EvaluationResult evaluateQuery(const CQ::ContainerQuery&, const SelectedContainer&) const; 50 EvaluationResult evaluateQuery(const CQ::SizeQuery&, const SelectedContainer&) const; 51 template<typename ConditionType> EvaluationResult evaluateCondition(const ConditionType&, const SelectedContainer&) const; 52 EvaluationResult evaluateSizeFeature(const CQ::SizeFeature&, const SelectedContainer&) const; 53 53 54 54 const Ref<const Element> m_element;
Note: See TracChangeset
for help on using the changeset viewer.