| Differences between
and this patch
- a/Source/WebCore/ChangeLog +27 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2022-02-16  Antti Koivisto  <antti@apple.com>
2
3
        [CSS Container Queries] Size queries on unsupported axis should evaluate to unknown
4
        https://bugs.webkit.org/show_bug.cgi?id=236702
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        "If ... the query container does not support container size queries on the relevant axes,
9
        then the result of evaluating the size feature is unknown."
10
11
        https://drafts.csswg.org/css-contain-3/#size-container
12
13
        * style/ContainerQueryEvaluator.cpp:
14
        (WebCore::Style::ContainerQueryEvaluator::evaluate const):
15
16
        Some cleanups.
17
18
        (WebCore::Style::ContainerQueryEvaluator::evaluateQuery const):
19
        (WebCore::Style::ContainerQueryEvaluator::evaluateCondition const):
20
        (WebCore::Style::ContainerQueryEvaluator::evaluateSizeFeature const):
21
22
        Check whether the container supports the feature axis and return Unknown of not.
23
24
        * style/ContainerQueryEvaluator.h:
25
26
        Rename EvaluationContext -> ResolvedContainer to be less generic.
27
1
2022-02-15  Nikolaos Mouchtaris  <nmouchtaris@apple.com>
28
2022-02-15  Nikolaos Mouchtaris  <nmouchtaris@apple.com>
2
29
3
        Implement parsing and animation support for offset shorthand
30
        Implement parsing and animation support for offset shorthand
- a/Source/WebCore/style/ContainerQueryEvaluator.cpp -41 / +81 lines
Lines 37-44 a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec1
37
37
38
namespace WebCore::Style {
38
namespace WebCore::Style {
39
39
40
struct ContainerQueryEvaluator::EvaluationContext {
40
struct ContainerQueryEvaluator::ResolvedContainer {
41
    RenderBox& renderer;
41
    const RenderBox& renderer;
42
    CSSToLengthConversionData conversionData;
42
    CSSToLengthConversionData conversionData;
43
};
43
};
44
44
Lines 52-115 bool ContainerQueryEvaluator::evaluate(const FilteredContainerQuery& filteredCon a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec2
52
    if (m_containers.isEmpty())
52
    if (m_containers.isEmpty())
53
        return false;
53
        return false;
54
54
55
    auto containerRendererForFilter = [&]() -> RenderBox* {
55
    auto makeResolvedContainer = [&](const RenderBox& renderer) -> ResolvedContainer {
56
        auto& view = renderer.view();
57
        return {
58
            renderer,
59
            CSSToLengthConversionData { &renderer.style(), &view.style(), nullptr, &view, 1 }
60
        };
61
    };
62
63
    auto resolveContainer = [&]() -> std::optional<ResolvedContainer> {
56
        for (auto& container : makeReversedRange(m_containers)) {
64
        for (auto& container : makeReversedRange(m_containers)) {
57
            auto* renderer = dynamicDowncast<RenderBox>(container->renderer());
65
            auto* renderer = dynamicDowncast<RenderBox>(container->renderer());
58
            if (!renderer)
66
            if (!renderer)
59
                return nullptr;
67
                return { };
60
            if (filteredContainerQuery.nameFilter.isEmpty())
68
            if (filteredContainerQuery.nameFilter.isEmpty())
61
                return renderer;
69
                return makeResolvedContainer(*renderer);
62
            // FIXME: Support type filter.
70
            // FIXME: Support type filter.
63
            if (renderer->style().containerNames().contains(filteredContainerQuery.nameFilter))
71
            if (renderer->style().containerNames().contains(filteredContainerQuery.nameFilter))
64
                return renderer;
72
                return makeResolvedContainer(*renderer);
65
        }
73
        }
66
        return nullptr;
74
        return { };
67
    };
75
    };
68
76
69
    auto* renderer = containerRendererForFilter();
77
    auto container = resolveContainer();
70
    if (!renderer)
78
    if (!container)
71
        return false;
79
        return { };
72
73
    auto& view = renderer->view();
74
    CSSToLengthConversionData { &renderer->style(), &view.style(), nullptr, &view, 1 };
75
76
    EvaluationContext evaluationContext {
77
        *renderer,
78
        CSSToLengthConversionData { &renderer->style(), &view.style(), nullptr, &view, 1 }
79
    };
80
80
81
    return evaluateQuery(filteredContainerQuery.query, evaluationContext) == EvaluationResult::True;
81
    return evaluateQuery(filteredContainerQuery.query, *container) == EvaluationResult::True;
82
}
82
}
83
83
84
auto ContainerQueryEvaluator::evaluateQuery(const CQ::ContainerQuery& containerQuery, const EvaluationContext& context) const -> EvaluationResult
84
auto ContainerQueryEvaluator::evaluateQuery(const CQ::ContainerQuery& containerQuery, const ResolvedContainer& container) const -> EvaluationResult
85
{
85
{
86
    return WTF::switchOn(containerQuery, [&](const CQ::ContainerCondition& containerCondition) {
86
    return WTF::switchOn(containerQuery, [&](const CQ::ContainerCondition& containerCondition) {
87
        return evaluateCondition(containerCondition, context);
87
        return evaluateCondition(containerCondition, container);
88
    }, [&](const CQ::SizeQuery& sizeQuery) {
88
    }, [&](const CQ::SizeQuery& sizeQuery) {
89
        return evaluateQuery(sizeQuery, context);
89
        return evaluateQuery(sizeQuery, container);
90
    }, [&](const CQ::UnknownQuery&) {
90
    }, [&](const CQ::UnknownQuery&) {
91
        return EvaluationResult::Unknown;
91
        return EvaluationResult::Unknown;
92
    });
92
    });
93
}
93
}
94
94
95
auto ContainerQueryEvaluator::evaluateQuery(const CQ::SizeQuery& sizeQuery, const EvaluationContext& context) const -> EvaluationResult
95
auto ContainerQueryEvaluator::evaluateQuery(const CQ::SizeQuery& sizeQuery, const ResolvedContainer& container) const -> EvaluationResult
96
{
96
{
97
    return WTF::switchOn(sizeQuery, [&](const CQ::SizeCondition& sizeCondition) {
97
    return WTF::switchOn(sizeQuery, [&](const CQ::SizeCondition& sizeCondition) {
98
        return evaluateCondition(sizeCondition, context);
98
        return evaluateCondition(sizeCondition, container);
99
    }, [&](const CQ::SizeFeature& sizeFeature) {
99
    }, [&](const CQ::SizeFeature& sizeFeature) {
100
        return evaluateSizeFeature(sizeFeature, context);
100
        return evaluateSizeFeature(sizeFeature, container);
101
    });
101
    });
102
}
102
}
103
103
104
template<typename ConditionType>
104
template<typename ConditionType>
105
auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, const EvaluationContext& context) const -> EvaluationResult
105
auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, const ResolvedContainer& container) const -> EvaluationResult
106
{
106
{
107
    if (condition.queries.isEmpty())
107
    if (condition.queries.isEmpty())
108
        return EvaluationResult::Unknown;
108
        return EvaluationResult::Unknown;
109
109
110
    switch (condition.logicalOperator) {
110
    switch (condition.logicalOperator) {
111
    case CQ::LogicalOperator::Not: {
111
    case CQ::LogicalOperator::Not: {
112
        switch (evaluateQuery(condition.queries.first(), context)) {
112
        switch (evaluateQuery(condition.queries.first(), container)) {
113
        case EvaluationResult::True:
113
        case EvaluationResult::True:
114
            return EvaluationResult::False;
114
            return EvaluationResult::False;
115
        case EvaluationResult::False:
115
        case EvaluationResult::False:
Lines 121-127 auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec3
121
    case CQ::LogicalOperator::And: {
121
    case CQ::LogicalOperator::And: {
122
        auto result = EvaluationResult::True;
122
        auto result = EvaluationResult::True;
123
        for (auto query : condition.queries) {
123
        for (auto query : condition.queries) {
124
            auto queryResult = evaluateQuery(query, context);
124
            auto queryResult = evaluateQuery(query, container);
125
            if (queryResult == EvaluationResult::False)
125
            if (queryResult == EvaluationResult::False)
126
                return EvaluationResult::False;
126
                return EvaluationResult::False;
127
            if (queryResult == EvaluationResult::Unknown)
127
            if (queryResult == EvaluationResult::Unknown)
Lines 132-138 auto ContainerQueryEvaluator::evaluateCondition(const ConditionType& condition, a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec4
132
    case CQ::LogicalOperator::Or: {
132
    case CQ::LogicalOperator::Or: {
133
        auto result = EvaluationResult::False;
133
        auto result = EvaluationResult::False;
134
        for (auto query : condition.queries) {
134
        for (auto query : condition.queries) {
135
            auto queryResult = evaluateQuery(query, context);
135
            auto queryResult = evaluateQuery(query, container);
136
            if (queryResult == EvaluationResult::True)
136
            if (queryResult == EvaluationResult::True)
137
                return EvaluationResult::True;
137
                return EvaluationResult::True;
138
            if (queryResult == EvaluationResult::Unknown)
138
            if (queryResult == EvaluationResult::Unknown)
Lines 160-166 static std::optional<LayoutUnit> computeSize(const CSSValue* value, const CSSToL a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec5
160
    return primitiveValue.computeLength<LayoutUnit>(conversionData);
160
    return primitiveValue.computeLength<LayoutUnit>(conversionData);
161
}
161
}
162
162
163
auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFeature, const EvaluationContext& context) const -> EvaluationResult
163
auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFeature, const ResolvedContainer& container) const -> EvaluationResult
164
{
164
{
165
    auto toEvaluationResult = [](bool boolean) {
165
    auto toEvaluationResult = [](bool boolean) {
166
        return boolean ? EvaluationResult::True : EvaluationResult::False;
166
        return boolean ? EvaluationResult::True : EvaluationResult::False;
Lines 188-214 auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFea a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec6
188
        if (sizeFeature.comparisonOperator == CQ::ComparisonOperator::True)
188
        if (sizeFeature.comparisonOperator == CQ::ComparisonOperator::True)
189
            return toEvaluationResult(!!size);
189
            return toEvaluationResult(!!size);
190
190
191
        auto expressionSize = computeSize(sizeFeature.value.get(), context.conversionData);
191
        auto expressionSize = computeSize(sizeFeature.value.get(), container.conversionData);
192
        if (!expressionSize)
192
        if (!expressionSize)
193
            return EvaluationResult::Unknown;
193
            return EvaluationResult::Unknown;
194
194
195
        return toEvaluationResult(compare(size, *expressionSize));
195
        return toEvaluationResult(compare(size, *expressionSize));
196
    };
196
    };
197
197
198
    if (sizeFeature.name == CQ::FeatureNames::width())
198
    enum class Axis : uint8_t { Both, Block, Inline, Width, Height };
199
        return evaluateSize(context.renderer.contentWidth());
199
    auto containerSupportsRequiredAxis = [&](Axis axis) {
200
        if (axis == Axis::Width)
201
            axis = container.renderer.isHorizontalWritingMode() ? Axis::Inline : Axis::Block;
202
        else if (axis == Axis::Height)
203
            axis = container.renderer.isHorizontalWritingMode() ? Axis::Block : Axis::Inline;
204
205
        switch (container.renderer.style().containerType()) {
206
        case ContainerType::Size:
207
            return true;
208
        case ContainerType::InlineSize:
209
            return axis == Axis::Inline;
210
        case ContainerType::None:
211
            ASSERT_NOT_REACHED();
212
            return false;
213
        }
214
    };
200
215
201
    if (sizeFeature.name == CQ::FeatureNames::height())
216
    if (sizeFeature.name == CQ::FeatureNames::width()) {
202
        return evaluateSize(context.renderer.contentHeight());
217
        if (!containerSupportsRequiredAxis(Axis::Width))
218
            return EvaluationResult::Unknown;
203
219
204
    if (sizeFeature.name == CQ::FeatureNames::inlineSize())
220
        return evaluateSize(container.renderer.contentWidth());
205
        return evaluateSize(context.renderer.contentLogicalWidth());
221
    }
206
222
207
    if (sizeFeature.name == CQ::FeatureNames::blockSize())
223
    if (sizeFeature.name == CQ::FeatureNames::height()) {
208
        return evaluateSize(context.renderer.contentLogicalHeight());
224
        if (!containerSupportsRequiredAxis(Axis::Height))
225
            return EvaluationResult::Unknown;
226
227
        return evaluateSize(container.renderer.contentHeight());
228
    }
229
230
    if (sizeFeature.name == CQ::FeatureNames::inlineSize()) {
231
        if (!containerSupportsRequiredAxis(Axis::Inline))
232
            return EvaluationResult::Unknown;
233
234
        return evaluateSize(container.renderer.contentLogicalWidth());
235
    }
236
237
    if (sizeFeature.name == CQ::FeatureNames::blockSize()) {
238
        if (!containerSupportsRequiredAxis(Axis::Block))
239
            return EvaluationResult::Unknown;
240
241
        return evaluateSize(container.renderer.contentLogicalHeight());
242
    }
209
243
210
    if (sizeFeature.name == CQ::FeatureNames::aspectRatio()) {
244
    if (sizeFeature.name == CQ::FeatureNames::aspectRatio()) {
211
        auto boxRatio = context.renderer.contentWidth().toDouble() / context.renderer.contentHeight().toDouble();
245
        if (!containerSupportsRequiredAxis(Axis::Both))
246
            return EvaluationResult::Unknown;
247
248
        auto boxRatio = container.renderer.contentWidth().toDouble() / container.renderer.contentHeight().toDouble();
212
        if (sizeFeature.comparisonOperator == CQ::ComparisonOperator::True)
249
        if (sizeFeature.comparisonOperator == CQ::ComparisonOperator::True)
213
            return toEvaluationResult(!!boxRatio);
250
            return toEvaluationResult(!!boxRatio);
214
251
Lines 231-242 auto ContainerQueryEvaluator::evaluateSizeFeature(const CQ::SizeFeature& sizeFea a/Source/WebCore/style/ContainerQueryEvaluator.cpp_sec7
231
    }
268
    }
232
269
233
    if (sizeFeature.name == CQ::FeatureNames::orientation()) {
270
    if (sizeFeature.name == CQ::FeatureNames::orientation()) {
271
        if (!containerSupportsRequiredAxis(Axis::Both))
272
            return EvaluationResult::Unknown;
273
234
        if (!is<CSSPrimitiveValue>(sizeFeature.value) || sizeFeature.comparisonOperator != CQ::ComparisonOperator::Equal)
274
        if (!is<CSSPrimitiveValue>(sizeFeature.value) || sizeFeature.comparisonOperator != CQ::ComparisonOperator::Equal)
235
            return EvaluationResult::Unknown;
275
            return EvaluationResult::Unknown;
236
276
237
        auto& value = downcast<CSSPrimitiveValue>(*sizeFeature.value);
277
        auto& value = downcast<CSSPrimitiveValue>(*sizeFeature.value);
238
278
239
        bool isPortrait = context.renderer.contentHeight() >= context.renderer.contentWidth();
279
        bool isPortrait = container.renderer.contentHeight() >= container.renderer.contentWidth();
240
        if (value.valueID() == CSSValuePortrait)
280
        if (value.valueID() == CSSValuePortrait)
241
            return toEvaluationResult(isPortrait);
281
            return toEvaluationResult(isPortrait);
242
        if (value.valueID() == CSSValueLandscape)
282
        if (value.valueID() == CSSValueLandscape)
- a/Source/WebCore/style/ContainerQueryEvaluator.h -5 / +5 lines
Lines 40-52 public: a/Source/WebCore/style/ContainerQueryEvaluator.h_sec1
40
    bool evaluate(const FilteredContainerQuery&) const;
40
    bool evaluate(const FilteredContainerQuery&) const;
41
41
42
private:
42
private:
43
    struct EvaluationContext;
43
    struct ResolvedContainer;
44
    enum class EvaluationResult : uint8_t { False, True, Unknown };
44
    enum class EvaluationResult : uint8_t { False, True, Unknown };
45
45
46
    EvaluationResult evaluateQuery(const CQ::ContainerQuery&, const EvaluationContext&) const;
46
    EvaluationResult evaluateQuery(const CQ::ContainerQuery&, const ResolvedContainer&) const;
47
    EvaluationResult evaluateQuery(const CQ::SizeQuery&, const EvaluationContext&) const;
47
    EvaluationResult evaluateQuery(const CQ::SizeQuery&, const ResolvedContainer&) const;
48
    template<typename ConditionType> EvaluationResult evaluateCondition(const ConditionType&, const EvaluationContext&) const;
48
    template<typename ConditionType> EvaluationResult evaluateCondition(const ConditionType&, const ResolvedContainer&) const;
49
    EvaluationResult evaluateSizeFeature(const CQ::SizeFeature&, const EvaluationContext&) const;
49
    EvaluationResult evaluateSizeFeature(const CQ::SizeFeature&, const ResolvedContainer&) const;
50
50
51
    const Vector<Ref<const Element>>& m_containers;
51
    const Vector<Ref<const Element>>& m_containers;
52
};
52
};
- a/LayoutTests/imported/w3c/ChangeLog +11 lines
Lines 1-3 a/LayoutTests/imported/w3c/ChangeLog_sec1
1
2022-02-16  Antti Koivisto  <antti@apple.com>
2
3
        [CSS Container Queries] Size queries on unsupported axis should evaluate to unknown
4
        https://bugs.webkit.org/show_bug.cgi?id=236702
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * web-platform-tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation-expected.txt:
9
        * web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt:
10
        * web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt:
11
1
2022-02-15  Nikolaos Mouchtaris  <nmouchtaris@apple.com>
12
2022-02-15  Nikolaos Mouchtaris  <nmouchtaris@apple.com>
2
13
3
        Implement parsing and animation support for offset shorthand
14
        Implement parsing and animation support for offset shorthand
- a/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation-expected.txt -1 / +1 lines
Lines 1-4 a/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/aspect-ratio-feature-evaluation-expected.txt_sec1
1
1
2
FAIL @container queries with aspect-ratio and size containment assert_equals: Should not match for inline-size containment expected "rgb(255, 0, 0)" but got "rgb(0, 128, 0)"
2
PASS @container queries with aspect-ratio and size containment
3
FAIL @container query with aspect-ratio change after resize assert_equals: Should match 2/1 min-ratio expected "rgb(0, 255, 0)" but got "rgba(0, 0, 0, 0)"
3
FAIL @container query with aspect-ratio change after resize assert_equals: Should match 2/1 min-ratio expected "rgb(0, 255, 0)" but got "rgba(0, 0, 0, 0)"
4
4
- a/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt -1 / +1 lines
Lines 2-8 a/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/container-selection-expected.txt_sec1
2
PASS size(width: 16px) for .size > .inline > span
2
PASS size(width: 16px) for .size > .inline > span
3
PASS size(height: 16px) for .inline > .size > span
3
PASS size(height: 16px) for .inline > .size > span
4
PASS size(width: 16px) for .inline > .size > span
4
PASS size(width: 16px) for .inline > .size > span
5
FAIL size(height) for .size > .inline > span assert_equals: expected "" but got "true"
5
PASS size(height) for .size > .inline > span
6
FAIL type(inline-size) size(width: 16px) for .inline > .size > span assert_equals: expected "true" but got ""
6
FAIL type(inline-size) size(width: 16px) for .inline > .size > span assert_equals: expected "true" but got ""
7
FAIL type(inline-size) size(width: 16px) for .size > .inline > span assert_equals: expected "true" but got ""
7
FAIL type(inline-size) size(width: 16px) for .size > .inline > span assert_equals: expected "true" but got ""
8
FAIL type(size) size(height: 16px) for .inline > .size > span assert_equals: expected "true" but got ""
8
FAIL type(size) size(height: 16px) for .inline > .size > span assert_equals: expected "true" but got ""
- a/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt -5 / +5 lines
Lines 1-14 a/LayoutTests/imported/w3c/web-platform-tests/css/css-contain/container-queries/unsupported-axis-expected.txt_sec1
1
Test
1
Test
2
2
3
PASS size(width > 0px)
3
PASS size(width > 0px)
4
FAIL size(height > 0px) assert_equals: expected "" but got "true"
4
PASS size(height > 0px)
5
PASS size((height > 0px) or (width > 0px))
5
PASS size((height > 0px) or (width > 0px))
6
PASS size((width > 0px) or (height > 0px))
6
PASS size((width > 0px) or (height > 0px))
7
PASS size((orientation: landscape) or (width > 0px))
7
PASS size((orientation: landscape) or (width > 0px))
8
PASS size((width > 0px) or (orientation: landscape))
8
PASS size((width > 0px) or (orientation: landscape))
9
FAIL size((height > 0px) or (orientation: landscape)) assert_equals: expected "" but got "true"
9
PASS size((height > 0px) or (orientation: landscape))
10
FAIL size((height > 0px) or (orientation: landscape)), with contain:size assert_equals: expected "" but got "true"
10
PASS size((height > 0px) or (orientation: landscape)), with contain:size
11
PASS size(inline-size > 0px)
11
PASS size(inline-size > 0px)
12
FAIL size(block-size > 0px) assert_equals: expected "" but got "true"
12
PASS size(block-size > 0px)
13
FAIL size(block-size > 0px), with writing-mode:vertical-rl assert_equals: expected "" but got "true"
13
PASS size(block-size > 0px), with writing-mode:vertical-rl
14
14

Return to Bug 236702