Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (291097 => 291098)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2022-03-10 10:22:14 UTC (rev 291098)
@@ -1,3 +1,13 @@
+2022-03-10 Antti Koivisto <[email protected]>
+
+ [CSS Container Queries] Implement new container selection algorithm
+ https://bugs.webkit.org/show_bug.cgi?id=237657
+
+ Reviewed by Antoine Quint.
+
+ * web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt:
+ * web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt:
+
2022-03-09 Youenn Fablet <[email protected]>
imported/w3c/web-platform-tests/webrtc-extensions/transfer-datachannel.html is flaky
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt (291097 => 291098)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt 2022-03-10 10:22:14 UTC (rev 291098)
@@ -2,7 +2,7 @@
PASS (width: 16px) for .size > .inline > span
PASS (height: 16px) for .inline > .size > span
PASS (width: 16px) for .inline > .size > span
-FAIL (height: 32px) for .size > .inline > span assert_equals: expected "true" but got ""
+PASS (height: 32px) for .size > .inline > span
PASS (height: 16px) for .size > .inline > span
PASS a (width: 32px) for .a-size > .b-size > span
PASS b (width: 16px) for .a-size > .b-size > span
@@ -14,10 +14,10 @@
PASS c (width) for .ab-size > .size > span
PASS a (width: 8px) for .a-size > .b-size > .a-inline > span
PASS b (width: 16px) for .a-size > .b-size > .a-inline > span
-FAIL a (height: 32px) for .a-size > .b-size > .a-inline > span assert_equals: expected "true" but got ""
+PASS a (height: 32px) for .a-size > .b-size > .a-inline > span
PASS a (height) for .a-inline > .b-size
PASS a (inline-size: 8px) for .a-size > .b-size > .a-inline > span
PASS b (inline-size: 16px) for .a-size > .b-size > .a-inline > span
-FAIL a (block-size: 32px) for .a-size > .b-size > .a-inline > span assert_equals: expected "true" but got ""
+PASS a (block-size: 32px) for .a-size > .b-size > .a-inline > span
PASS a (block-size) for .a-inline > .b-size
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt (291097 => 291098)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt 2022-03-10 10:22:14 UTC (rev 291098)
@@ -2,10 +2,10 @@
PASS (width > 0px)
PASS (height > 0px)
-FAIL ((height > 0px) or (width > 0px)) assert_equals: expected "" but got "true"
-FAIL ((width > 0px) or (height > 0px)) assert_equals: expected "" but got "true"
-FAIL ((orientation: landscape) or (width > 0px)) assert_equals: expected "" but got "true"
-FAIL ((width > 0px) or (orientation: landscape)) assert_equals: expected "" but got "true"
+PASS ((height > 0px) or (width > 0px))
+PASS ((width > 0px) or (height > 0px))
+PASS ((orientation: landscape) or (width > 0px))
+PASS ((width > 0px) or (orientation: landscape))
PASS ((height > 0px) or (orientation: landscape))
PASS ((height > 0px) or (orientation: landscape)), with contain:size
PASS (inline-size > 0px)
Modified: trunk/Source/WebCore/ChangeLog (291097 => 291098)
--- trunk/Source/WebCore/ChangeLog 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/ChangeLog 2022-03-10 10:22:14 UTC (rev 291098)
@@ -1,3 +1,49 @@
+2022-03-10 Antti Koivisto <[email protected]>
+
+ [CSS Container Queries] Implement new container selection algorithm
+ https://bugs.webkit.org/show_bug.cgi?id=237657
+
+ Reviewed by Antoine Quint.
+
+ "For each element, the query container to be queried is selected from among the element’s
+ ancestor query containers that have a valid container-type for all the container features
+ in the <container-condition>."
+
+ https://drafts.csswg.org/css-contain-3/#container-rule
+
+ * css/ContainerQuery.cpp:
+ (WebCore::CQ::requiredAxesForFeature):
+ * css/ContainerQuery.h:
+ * css/ContainerQueryParser.cpp:
+ (WebCore::ContainerQueryParser::consumeFilteredContainerQuery):
+
+ Move container name parsing to ContainerQueryParser too.
+
+ (WebCore::ContainerQueryParser::consumeSizeQuery):
+
+ Collect required axes during parsing.
+
+ * css/ContainerQueryParser.h:
+ * css/parser/CSSParserImpl.cpp:
+ (WebCore::CSSParserImpl::consumeContainerRule):
+ * style/ContainerQueryEvaluator.cpp:
+ (WebCore::Style::ContainerQueryEvaluator::evaluate const):
+ (WebCore::Style::ContainerQueryEvaluator::selectContainer const):
+
+ Select container based on required axes for the features being used.
+
+ (WebCore::Style::ContainerQueryEvaluator::evaluateQuery const):
+ (WebCore::Style::ContainerQueryEvaluator::evaluateCondition const):
+ (WebCore::Style::ContainerQueryEvaluator::evaluateSizeFeature const):
+
+ No need to check axes during evaluation anymore. We only evaluate against containers that support them.
+
+ (WebCore::Style::ContainerQueryEvaluator::resolveContainer const): Deleted.
+
+ Rename resolveContainer -> selectContainer to match the spec.
+
+ * style/ContainerQueryEvaluator.h:
+
2022-03-07 Carlos Garcia Campos <[email protected]>
[GTK][WPE] Add initial adwaita style for PDF.js
Modified: trunk/Source/WebCore/css/ContainerQuery.cpp (291097 => 291098)
--- trunk/Source/WebCore/css/ContainerQuery.cpp 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/css/ContainerQuery.cpp 2022-03-10 10:22:14 UTC (rev 291098)
@@ -27,8 +27,10 @@
#include <wtf/NeverDestroyed.h>
-namespace WebCore::CQ::FeatureNames {
+namespace WebCore::CQ {
+namespace FeatureNames {
+
const AtomString& width()
{
static MainThreadNeverDestroyed<AtomString> name { "width"_s };
@@ -67,3 +69,20 @@
}
+OptionSet<Axis> requiredAxesForFeature(const AtomString& featureName)
+{
+ if (featureName == FeatureNames::width())
+ return { Axis::Width };
+ if (featureName == FeatureNames::height())
+ return { Axis::Height };
+ if (featureName == FeatureNames::inlineSize())
+ return { Axis::Inline };
+ if (featureName == FeatureNames::blockSize())
+ return { Axis::Block };
+ if (featureName == FeatureNames::aspectRatio() || featureName == FeatureNames::orientation())
+ return { Axis::Inline, Axis::Block };
+ return { };
+}
+
+}
+
Modified: trunk/Source/WebCore/css/ContainerQuery.h (291097 => 291098)
--- trunk/Source/WebCore/css/ContainerQuery.h 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/css/ContainerQuery.h 2022-03-10 10:22:14 UTC (rev 291098)
@@ -74,6 +74,14 @@
const AtomString& orientation();
};
+enum class Axis : uint8_t {
+ Block = 1 << 0,
+ Inline = 1 << 1,
+ Width = 1 << 2,
+ Height = 1 << 3,
+};
+OptionSet<Axis> requiredAxesForFeature(const AtomString&);
+
}
using ContainerQuery = CQ::ContainerQuery;
@@ -80,6 +88,7 @@
struct FilteredContainerQuery {
AtomString nameFilter;
+ OptionSet<CQ::Axis> axisFilter;
ContainerQuery query;
};
Modified: trunk/Source/WebCore/css/ContainerQueryParser.cpp (291097 => 291098)
--- trunk/Source/WebCore/css/ContainerQueryParser.cpp 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/css/ContainerQueryParser.cpp 2022-03-10 10:22:14 UTC (rev 291098)
@@ -30,12 +30,34 @@
namespace WebCore {
-std::optional<ContainerQuery> ContainerQueryParser::consumeContainerQuery(CSSParserTokenRange& range, const CSSParserContext& context)
+std::optional<FilteredContainerQuery> ContainerQueryParser::consumeFilteredContainerQuery(CSSParserTokenRange& range, const CSSParserContext& context)
{
ContainerQueryParser parser(context);
- return parser.consumeContainerQuery(range);
+ return parser.consumeFilteredContainerQuery(range);
}
+std::optional<FilteredContainerQuery> ContainerQueryParser::consumeFilteredContainerQuery(CSSParserTokenRange& range)
+{
+ auto consumeName = [&]() -> AtomString {
+ if (range.peek().type() == LeftParenthesisToken || range.peek().type() == FunctionToken)
+ return nullAtom();
+ auto nameValue = CSSPropertyParserHelpers::consumeSingleContainerName(range);
+ if (!nameValue)
+ return nullAtom();
+ return nameValue->stringValue();
+ };
+
+ auto name = consumeName();
+
+ m_requiredAxes = { };
+
+ auto query = consumeContainerQuery(range);
+ if (!query)
+ return { };
+
+ return FilteredContainerQuery { name, m_requiredAxes, *query };
+}
+
std::optional<CQ::ContainerQuery> ContainerQueryParser::consumeContainerQuery(CSSParserTokenRange& range)
{
if (range.peek().type() == FunctionToken) {
@@ -138,6 +160,8 @@
if (!sizeFeature)
return { };
+ m_requiredAxes.add(CQ::requiredAxesForFeature(sizeFeature->name));
+
return { *sizeFeature };
}
Modified: trunk/Source/WebCore/css/ContainerQueryParser.h (291097 => 291098)
--- trunk/Source/WebCore/css/ContainerQueryParser.h 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/css/ContainerQueryParser.h 2022-03-10 10:22:14 UTC (rev 291098)
@@ -34,9 +34,10 @@
class ContainerQueryParser {
public:
- static std::optional<ContainerQuery> consumeContainerQuery(CSSParserTokenRange&, const CSSParserContext&);
+ static std::optional<FilteredContainerQuery> consumeFilteredContainerQuery(CSSParserTokenRange&, const CSSParserContext&);
private:
+ std::optional<FilteredContainerQuery> consumeFilteredContainerQuery(CSSParserTokenRange&);
std::optional<CQ::ContainerQuery> consumeContainerQuery(CSSParserTokenRange&);
std::optional<CQ::SizeQuery> consumeSizeQuery(CSSParserTokenRange&);
template<typename ConditionType> std::optional<ConditionType> consumeCondition(CSSParserTokenRange&);
@@ -49,6 +50,8 @@
: m_context(context) { }
const CSSParserContext m_context;
+
+ OptionSet<CQ::Axis> m_requiredAxes;
};
}
Modified: trunk/Source/WebCore/css/parser/CSSParserImpl.cpp (291097 => 291098)
--- trunk/Source/WebCore/css/parser/CSSParserImpl.cpp 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/css/parser/CSSParserImpl.cpp 2022-03-10 10:22:14 UTC (rev 291098)
@@ -855,18 +855,7 @@
if (prelude.atEnd())
return nullptr;
- auto consumeName = [&]() -> AtomString {
- if (prelude.peek().type() == LeftParenthesisToken || prelude.peek().type() == FunctionToken)
- return nullAtom();
- auto nameValue = CSSPropertyParserHelpers::consumeSingleContainerName(prelude);
- if (!nameValue)
- return nullAtom();
- return nameValue->stringValue();
- };
-
- auto name = consumeName();
-
- auto query = ContainerQueryParser::consumeContainerQuery(prelude, m_context);
+ auto query = ContainerQueryParser::consumeFilteredContainerQuery(prelude, m_context);
if (!query)
return nullptr;
@@ -875,7 +864,7 @@
return nullptr;
if (m_deferredParser)
- return StyleRuleContainer::create({ name, *query }, makeUnique<DeferredStyleGroupRuleList>(block, *m_deferredParser));
+ return StyleRuleContainer::create(WTFMove(*query), makeUnique<DeferredStyleGroupRuleList>(block, *m_deferredParser));
Vector<RefPtr<StyleRuleBase>> rules;
@@ -893,7 +882,7 @@
if (m_observerWrapper)
m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
- return StyleRuleContainer::create({ name, *query }, WTFMove(rules));
+ return StyleRuleContainer::create(WTFMove(*query), WTFMove(rules));
}
RefPtr<StyleRuleKeyframe> CSSParserImpl::consumeKeyframeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
Modified: trunk/Source/WebCore/style/ContainerQueryEvaluator.cpp (291097 => 291098)
--- trunk/Source/WebCore/style/ContainerQueryEvaluator.cpp 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/style/ContainerQueryEvaluator.cpp 2022-03-10 10:22:14 UTC (rev 291098)
@@ -38,7 +38,7 @@
namespace WebCore::Style {
-struct ContainerQueryEvaluator::ResolvedContainer {
+struct ContainerQueryEvaluator::SelectedContainer {
const RenderBox* renderer { nullptr };
CSSToLengthConversionData conversionData;
};
@@ -52,7 +52,7 @@
bool ContainerQueryEvaluator::evaluate(const FilteredContainerQuery& filteredContainerQuery) const
{
- auto container = resolveContainer(filteredContainerQuery);
+ auto container = selectContainer(filteredContainerQuery);
if (!container)
return false;
@@ -59,34 +59,58 @@
return evaluateQuery(filteredContainerQuery.query, *container) == EvaluationResult::True;
}
-auto ContainerQueryEvaluator::resolveContainer(const FilteredContainerQuery& filteredContainerQuery) const -> std::optional<ResolvedContainer>
+auto ContainerQueryEvaluator::selectContainer(const FilteredContainerQuery& filteredContainerQuery) const -> std::optional<SelectedContainer>
{
- auto makeResolvedContainer = [](const Element& element) -> ResolvedContainer {
+ // "For each element, the query container to be queried is selected from among the element’s
+ // ancestor query containers that have a valid container-type for all the container features
+ // in the <container-condition>. The optional <container-name> filters the set of query containers
+ // considered to just those with a matching query container name."
+ // https://drafts.csswg.org/css-contain-3/#container-rule
+
+ auto makeSelectedContainer = [](const Element& element) -> SelectedContainer {
auto* renderer = dynamicDowncast<RenderBox>(element.renderer());
if (!renderer)
return { };
auto& view = renderer->view();
- return ResolvedContainer {
+ return {
renderer,
CSSToLengthConversionData { &renderer->style(), &view.style(), nullptr, &view, 1 }
};
};
+ auto computeUnsupportedAxes = [&](ContainerType containerType, const RenderElement* principalBox) -> OptionSet<CQ::Axis> {
+ switch (containerType) {
+ case ContainerType::Size:
+ return { };
+ case ContainerType::InlineSize:
+ // Without a principal box the container matches but the query against it will evaluate to Unknown.
+ if (!principalBox)
+ return { };
+ if (!principalBox->isHorizontalWritingMode())
+ return { CQ::Axis::Width, CQ::Axis::Block };
+ return { CQ::Axis::Height, CQ::Axis::Block };
+ case ContainerType::None:
+ return { CQ::Axis::Width, CQ::Axis::Height, CQ::Axis::Inline, CQ::Axis::Block };
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ };
+
auto isContainerForQuery = [&](const Element& element) {
auto* style = element.existingComputedStyle();
if (!style)
return false;
- if (style->containerType() == ContainerType::None)
+ auto unsupportedAxes = computeUnsupportedAxes(style->containerType(), element.renderer());
+ if (filteredContainerQuery.axisFilter.containsAny(unsupportedAxes))
return false;
if (filteredContainerQuery.nameFilter.isEmpty())
return true;
- return style->containerNames().contains(filteredContainerQuery.nameFilter);
+ return element.existingComputedStyle()->containerNames().contains(filteredContainerQuery.nameFilter);
};
if (m_selectorMatchingState) {
for (auto& container : makeReversedRange(m_selectorMatchingState->queryContainers)) {
if (isContainerForQuery(container))
- return makeResolvedContainer(container);
+ return makeSelectedContainer(container);
}
return { };
}
@@ -93,18 +117,17 @@
if (m_pseudoId != PseudoId::None) {
if (isContainerForQuery(m_element))
- return makeResolvedContainer(m_element);
+ return makeSelectedContainer(m_element);
}
for (auto& ancestor : composedTreeAncestors(const_cast<Element&>(m_element.get()))) {
if (isContainerForQuery(ancestor))
- return makeResolvedContainer(ancestor);
+ return makeSelectedContainer(ancestor);
}
return { };
}
-
-auto ContainerQueryEvaluator::evaluateQuery(const CQ::ContainerQuery& containerQuery, const ResolvedContainer& container) const -> EvaluationResult
+auto ContainerQueryEvaluator::evaluateQuery(const CQ::ContainerQuery& containerQuery, const SelectedContainer& container) const -> EvaluationResult
{
return WTF::switchOn(containerQuery, [&](const CQ::ContainerCondition& containerCondition) {
return evaluateCondition(containerCondition, container);
@@ -115,7 +138,7 @@
});
}
-auto ContainerQueryEvaluator::evaluateQuery(const CQ::SizeQuery& sizeQuery, const ResolvedContainer& container) const -> EvaluationResult
+auto ContainerQueryEvaluator::evaluateQuery(const CQ::SizeQuery& sizeQuery, const SelectedContainer& container) const -> EvaluationResult
{
return WTF::switchOn(sizeQuery, [&](const CQ::SizeCondition& sizeCondition) {
return evaluateCondition(sizeCondition, container);
@@ -125,7 +148,7 @@
}
template<typename ConditionType>
-auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, const ResolvedContainer& container) const -> EvaluationResult
+auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, const SelectedContainer& container) const -> EvaluationResult
{
if (condition.queries.isEmpty())
return EvaluationResult::Unknown;
@@ -176,7 +199,7 @@
return primitiveValue.computeLength<LayoutUnit>(conversionData);
}
-auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFeature, const ResolvedContainer& container) const -> EvaluationResult
+auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFeature, const SelectedContainer& container) const -> EvaluationResult
{
// "If the query container does not have a principal box ... then the result of evaluating the size feature is unknown."
// https://drafts.csswg.org/css-contain-3/#size-container
@@ -249,55 +272,19 @@
return toEvaluationResult(compare(comparison->op, left, right));
};
- enum class Axis : uint8_t { Both, Block, Inline, Width, Height };
- auto containerSupportsRequiredAxis = [&](Axis axis) {
- switch (renderer.style().containerType()) {
- case ContainerType::Size:
- return true;
- case ContainerType::InlineSize:
- if (axis == Axis::Width)
- return renderer.isHorizontalWritingMode();
- if (axis == Axis::Height)
- return !renderer.isHorizontalWritingMode();
- return axis == Axis::Inline;
- case ContainerType::None:
- RELEASE_ASSERT_NOT_REACHED();
- }
- RELEASE_ASSERT_NOT_REACHED();
- };
-
- if (sizeFeature.name == CQ::FeatureNames::width()) {
- if (!containerSupportsRequiredAxis(Axis::Width))
- return EvaluationResult::Unknown;
-
+ if (sizeFeature.name == CQ::FeatureNames::width())
return evaluateSize(renderer.contentWidth());
- }
- if (sizeFeature.name == CQ::FeatureNames::height()) {
- if (!containerSupportsRequiredAxis(Axis::Height))
- return EvaluationResult::Unknown;
-
+ if (sizeFeature.name == CQ::FeatureNames::height())
return evaluateSize(renderer.contentHeight());
- }
- if (sizeFeature.name == CQ::FeatureNames::inlineSize()) {
- if (!containerSupportsRequiredAxis(Axis::Inline))
- return EvaluationResult::Unknown;
-
+ if (sizeFeature.name == CQ::FeatureNames::inlineSize())
return evaluateSize(renderer.contentLogicalWidth());
- }
- if (sizeFeature.name == CQ::FeatureNames::blockSize()) {
- if (!containerSupportsRequiredAxis(Axis::Block))
- return EvaluationResult::Unknown;
-
+ if (sizeFeature.name == CQ::FeatureNames::blockSize())
return evaluateSize(renderer.contentLogicalHeight());
- }
if (sizeFeature.name == CQ::FeatureNames::aspectRatio()) {
- if (!containerSupportsRequiredAxis(Axis::Both))
- return EvaluationResult::Unknown;
-
auto boxRatio = renderer.contentWidth().toDouble() / renderer.contentHeight().toDouble();
if (!sizeFeature.leftComparison && !sizeFeature.rightComparison)
@@ -310,9 +297,6 @@
}
if (sizeFeature.name == CQ::FeatureNames::orientation()) {
- if (!containerSupportsRequiredAxis(Axis::Both))
- return EvaluationResult::Unknown;
-
if (!sizeFeature.rightComparison)
return EvaluationResult::Unknown;
Modified: trunk/Source/WebCore/style/ContainerQueryEvaluator.h (291097 => 291098)
--- trunk/Source/WebCore/style/ContainerQueryEvaluator.h 2022-03-10 10:19:47 UTC (rev 291097)
+++ trunk/Source/WebCore/style/ContainerQueryEvaluator.h 2022-03-10 10:22:14 UTC (rev 291098)
@@ -43,13 +43,13 @@
bool evaluate(const FilteredContainerQuery&) const;
private:
- struct ResolvedContainer;
- std::optional<ResolvedContainer> resolveContainer(const FilteredContainerQuery&) const;
+ struct SelectedContainer;
+ std::optional<SelectedContainer> selectContainer(const FilteredContainerQuery&) const;
- EvaluationResult evaluateQuery(const CQ::ContainerQuery&, const ResolvedContainer&) const;
- EvaluationResult evaluateQuery(const CQ::SizeQuery&, const ResolvedContainer&) const;
- template<typename ConditionType> EvaluationResult evaluateCondition(const ConditionType&, const ResolvedContainer&) const;
- EvaluationResult evaluateSizeFeature(const CQ::SizeFeature&, const ResolvedContainer&) const;
+ EvaluationResult evaluateQuery(const CQ::ContainerQuery&, const SelectedContainer&) const;
+ EvaluationResult evaluateQuery(const CQ::SizeQuery&, const SelectedContainer&) const;
+ template<typename ConditionType> EvaluationResult evaluateCondition(const ConditionType&, const SelectedContainer&) const;
+ EvaluationResult evaluateSizeFeature(const CQ::SizeFeature&, const SelectedContainer&) const;
const Ref<const Element> m_element;
const PseudoId m_pseudoId;