1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 12:07:45 +00:00

LibWeb: Add CSS 'Supports' class

The name is a little awkward, but this corresponds to the condition of a
`@supports` rule or the `CSS.supports("")` function.

A supports query only gets evaluated once, since its condition cannot
change during runtime. (We either support something or we don't, and the
spec specifically mentions that user preferences that disable features
do not affect the result here.) We keep a representation of it around
though, so that it can be serialized if needed. This is a little awkward
since we hold onto a `StyleDeclarationRule` which should be an internal
Parser class. This means making some Parser functions more public.

Potentially we could evaluate the Supports inside the Parser, and have
it only store a String representation of itself. But this works for now.
:^)
This commit is contained in:
Sam Atkins 2021-10-08 15:40:19 +01:00 committed by Andreas Kling
parent 2a2efdedf7
commit 87a30418bf
6 changed files with 169 additions and 2 deletions

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/Supports.h>
namespace Web::CSS {
Supports::Supports(NonnullOwnPtr<Condition>&& condition)
: m_condition(move(condition))
{
auto result = m_condition->evaluate();
if (result == MatchResult::Unknown) {
dbgln("!!! Evaluation of CSS Supports returned 'Unknown'!");
}
m_matches = result == MatchResult::True;
}
Supports::MatchResult Supports::Condition::evaluate() const
{
switch (type) {
case Type::Not:
return negate(children.first().evaluate());
case Type::And: {
size_t true_results = 0;
for (auto& child : children) {
auto child_match = child.evaluate();
if (child_match == MatchResult::False)
return MatchResult::False;
if (child_match == MatchResult::True)
true_results++;
}
if (true_results == children.size())
return MatchResult::True;
return MatchResult::Unknown;
}
case Type::Or: {
size_t false_results = 0;
for (auto& child : children) {
auto child_match = child.evaluate();
if (child_match == MatchResult::True)
return MatchResult::True;
if (child_match == MatchResult::False)
false_results++;
}
if (false_results == children.size())
return MatchResult::False;
return MatchResult::Unknown;
}
}
VERIFY_NOT_REACHED();
}
Supports::MatchResult Supports::InParens::evaluate() const
{
return value.visit(
[&](NonnullOwnPtr<Condition>& condition) {
return condition->evaluate();
},
[&](Feature& feature) {
return feature.evaluate();
},
[&](GeneralEnclosed&) {
return MatchResult::Unknown;
});
}
Supports::MatchResult Supports::Feature::evaluate() const
{
auto style_property = Parser({}, "").convert_to_style_property(declaration);
if (style_property.has_value())
return MatchResult::True;
return MatchResult::False;
}
}