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