mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-06-19 00:01:59 +00:00
A given element may be a container in different ways, depending on its `container-type` property. For a container query to match an element, that element must have the required container type for each feature that the query checks. This commit implement a step to collect those required types, so that we can quickly eliminate potential container elements that lack a required containment type.
169 lines
5.4 KiB
C++
169 lines
5.4 KiB
C++
/*
|
||
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include <AK/StringBuilder.h>
|
||
#include <LibWeb/CSS/BooleanExpression.h>
|
||
|
||
namespace Web::CSS {
|
||
|
||
bool BooleanExpression::evaluate_to_boolean(BooleanExpressionEvaluationContext const& context) const
|
||
{
|
||
return evaluate(context) == MatchResult::True;
|
||
}
|
||
|
||
void BooleanExpression::indent(StringBuilder& builder, int levels)
|
||
{
|
||
builder.append_repeated(" "sv, levels);
|
||
}
|
||
|
||
void GeneralEnclosed::collect_container_query_feature_requirements(ContainerQueryFeatureRequirements& requirements) const
|
||
{
|
||
requirements.has_unknown_or_unsupported_feature = true;
|
||
}
|
||
|
||
void GeneralEnclosed::dump(StringBuilder& builder, int indent_levels) const
|
||
{
|
||
indent(builder, indent_levels);
|
||
builder.appendff("GeneralEnclosed: {}\n", to_string());
|
||
}
|
||
|
||
MatchResult BooleanNotExpression::evaluate(BooleanExpressionEvaluationContext const& context) const
|
||
{
|
||
// https://drafts.csswg.org/css-values-5/#boolean-logic
|
||
// `not test` evaluates to true if its contained test is false, false if it’s true, and unknown if it’s unknown.
|
||
switch (m_child->evaluate(context)) {
|
||
case MatchResult::False:
|
||
return MatchResult::True;
|
||
case MatchResult::True:
|
||
return MatchResult::False;
|
||
case MatchResult::Unknown:
|
||
return MatchResult::Unknown;
|
||
}
|
||
VERIFY_NOT_REACHED();
|
||
}
|
||
|
||
void BooleanNotExpression::collect_container_query_feature_requirements(ContainerQueryFeatureRequirements& requirements) const
|
||
{
|
||
m_child->collect_container_query_feature_requirements(requirements);
|
||
}
|
||
|
||
String BooleanNotExpression::to_string() const
|
||
{
|
||
return MUST(String::formatted("not {}", m_child->to_string()));
|
||
}
|
||
|
||
void BooleanNotExpression::dump(StringBuilder& builder, int indent_levels) const
|
||
{
|
||
indent(builder, indent_levels);
|
||
builder.append("NOT:\n"sv);
|
||
m_child->dump(builder, indent_levels + 1);
|
||
}
|
||
|
||
MatchResult BooleanExpressionInParens::evaluate(BooleanExpressionEvaluationContext const& context) const
|
||
{
|
||
return m_child->evaluate(context);
|
||
}
|
||
|
||
void BooleanExpressionInParens::collect_container_query_feature_requirements(ContainerQueryFeatureRequirements& requirements) const
|
||
{
|
||
m_child->collect_container_query_feature_requirements(requirements);
|
||
}
|
||
|
||
String BooleanExpressionInParens::to_string() const
|
||
{
|
||
return MUST(String::formatted("({})", m_child->to_string()));
|
||
}
|
||
|
||
void BooleanExpressionInParens::dump(StringBuilder& builder, int indent_levels) const
|
||
{
|
||
indent(builder, indent_levels);
|
||
builder.append("(\n"sv);
|
||
m_child->dump(builder, indent_levels + 1);
|
||
indent(builder, indent_levels);
|
||
builder.append(")\n"sv);
|
||
}
|
||
|
||
MatchResult BooleanAndExpression::evaluate(BooleanExpressionEvaluationContext const& context) const
|
||
{
|
||
// https://drafts.csswg.org/css-values-5/#boolean-logic
|
||
// Multiple tests connected with `and` evaluate to true if all of those tests are true, false if any of them are
|
||
// false, and unknown otherwise (i.e. if at least one unknown, but no false).
|
||
size_t true_results = 0;
|
||
for (auto const& child : m_children) {
|
||
auto child_match = child->evaluate(context);
|
||
if (child_match == MatchResult::False)
|
||
return MatchResult::False;
|
||
if (child_match == MatchResult::True)
|
||
true_results++;
|
||
}
|
||
if (true_results == m_children.size())
|
||
return MatchResult::True;
|
||
return MatchResult::Unknown;
|
||
}
|
||
|
||
void BooleanAndExpression::collect_container_query_feature_requirements(ContainerQueryFeatureRequirements& requirements) const
|
||
{
|
||
for (auto const& child : m_children)
|
||
child->collect_container_query_feature_requirements(requirements);
|
||
}
|
||
|
||
String BooleanAndExpression::to_string() const
|
||
{
|
||
return MUST(String::join(" and "sv, m_children));
|
||
}
|
||
|
||
void BooleanAndExpression::dump(StringBuilder& builder, int indent_levels) const
|
||
{
|
||
indent(builder, indent_levels);
|
||
builder.append("AND:\n"sv);
|
||
for (auto const& child : m_children)
|
||
child->dump(builder, indent_levels + 1);
|
||
}
|
||
|
||
MatchResult BooleanOrExpression::evaluate(BooleanExpressionEvaluationContext const& context) const
|
||
{
|
||
// https://drafts.csswg.org/css-values-5/#boolean-logic
|
||
// Multiple tests connected with `or` evaluate to true if any of those tests are true, false if all of them are
|
||
// false, and unknown otherwise (i.e. at least one unknown, but no true).
|
||
size_t false_results = 0;
|
||
for (auto const& child : m_children) {
|
||
auto child_match = child->evaluate(context);
|
||
if (child_match == MatchResult::True)
|
||
return MatchResult::True;
|
||
if (child_match == MatchResult::False)
|
||
false_results++;
|
||
}
|
||
if (false_results == m_children.size())
|
||
return MatchResult::False;
|
||
return MatchResult::Unknown;
|
||
}
|
||
|
||
void BooleanOrExpression::collect_container_query_feature_requirements(ContainerQueryFeatureRequirements& requirements) const
|
||
{
|
||
for (auto const& child : m_children)
|
||
child->collect_container_query_feature_requirements(requirements);
|
||
}
|
||
|
||
String BooleanOrExpression::to_string() const
|
||
{
|
||
return MUST(String::join(" or "sv, m_children));
|
||
}
|
||
|
||
void BooleanOrExpression::dump(StringBuilder& builder, int indent_levels) const
|
||
{
|
||
indent(builder, indent_levels);
|
||
builder.append("OR:\n"sv);
|
||
for (auto const& child : m_children)
|
||
child->dump(builder, indent_levels + 1);
|
||
}
|
||
|
||
void ConstantBooleanExpression::dump(StringBuilder& builder, int indent_levels) const
|
||
{
|
||
indent(builder, indent_levels);
|
||
builder.appendff("CONSTANT: {}\n", to_string());
|
||
}
|
||
|
||
}
|