mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:57: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:
parent
2a2efdedf7
commit
87a30418bf
6 changed files with 169 additions and 2 deletions
|
@ -47,6 +47,7 @@ set(SOURCES
|
|||
CSS/StyleSheet.cpp
|
||||
CSS/StyleSheetList.cpp
|
||||
CSS/StyleValue.cpp
|
||||
CSS/Supports.cpp
|
||||
CSS/ValueID.cpp
|
||||
CSS/ValueID.h
|
||||
Cookie/ParsedCookie.cpp
|
||||
|
|
|
@ -1604,7 +1604,7 @@ RefPtr<PropertyOwningCSSStyleDeclaration> Parser::convert_to_declaration(Nonnull
|
|||
return parse_a_list_of_declarations(stream);
|
||||
}
|
||||
|
||||
Optional<StyleProperty> Parser::convert_to_style_property(StyleDeclarationRule& declaration)
|
||||
Optional<StyleProperty> Parser::convert_to_style_property(StyleDeclarationRule const& declaration)
|
||||
{
|
||||
auto& property_name = declaration.m_name;
|
||||
auto property_id = property_id_from_string(property_name);
|
||||
|
|
|
@ -106,6 +106,9 @@ public:
|
|||
|
||||
RefPtr<StyleValue> parse_as_css_value(PropertyID);
|
||||
|
||||
// FIXME: This is a hack, while CSS::Supports is using a StyleDeclarationRule
|
||||
[[nodiscard]] Optional<StyleProperty> convert_to_style_property(StyleDeclarationRule const&);
|
||||
|
||||
private:
|
||||
enum class ParsingResult {
|
||||
Done,
|
||||
|
@ -176,7 +179,6 @@ private:
|
|||
|
||||
[[nodiscard]] RefPtr<CSSRule> convert_to_rule(NonnullRefPtr<StyleRule>);
|
||||
[[nodiscard]] RefPtr<PropertyOwningCSSStyleDeclaration> convert_to_declaration(NonnullRefPtr<StyleBlockRule>);
|
||||
[[nodiscard]] Optional<StyleProperty> convert_to_style_property(StyleDeclarationRule&);
|
||||
|
||||
static Optional<float> try_parse_float(StringView string);
|
||||
static Optional<Color> parse_color(ParsingContext const&, StyleComponentValueRule const&);
|
||||
|
|
79
Userland/Libraries/LibWeb/CSS/Supports.cpp
Normal file
79
Userland/Libraries/LibWeb/CSS/Supports.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
84
Userland/Libraries/LibWeb/CSS/Supports.h
Normal file
84
Userland/Libraries/LibWeb/CSS/Supports.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWeb/CSS/Parser/StyleDeclarationRule.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class Supports final : public RefCounted<Supports> {
|
||||
friend class Parser;
|
||||
|
||||
private:
|
||||
enum class MatchResult {
|
||||
False,
|
||||
True,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
static MatchResult negate(MatchResult value)
|
||||
{
|
||||
switch (value) {
|
||||
case MatchResult::False:
|
||||
return MatchResult::True;
|
||||
case MatchResult::True:
|
||||
return MatchResult::False;
|
||||
case MatchResult::Unknown:
|
||||
return MatchResult::Unknown;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
public:
|
||||
struct GeneralEnclosed {
|
||||
};
|
||||
|
||||
struct Feature {
|
||||
// FIXME: Using this internal parser class is a bit of a hack.
|
||||
StyleDeclarationRule declaration;
|
||||
MatchResult evaluate() const;
|
||||
};
|
||||
|
||||
struct Condition;
|
||||
struct InParens {
|
||||
Variant<NonnullOwnPtr<Condition>, Feature, GeneralEnclosed> value;
|
||||
|
||||
MatchResult evaluate() const;
|
||||
};
|
||||
|
||||
struct Condition {
|
||||
enum class Type {
|
||||
Not,
|
||||
And,
|
||||
Or,
|
||||
};
|
||||
Type type;
|
||||
Vector<InParens> children;
|
||||
|
||||
MatchResult evaluate() const;
|
||||
};
|
||||
|
||||
static NonnullRefPtr<Supports> create(NonnullOwnPtr<Condition>&& condition)
|
||||
{
|
||||
return adopt_ref(*new Supports(move(condition)));
|
||||
}
|
||||
|
||||
bool matches() const { return m_matches; }
|
||||
|
||||
private:
|
||||
Supports(NonnullOwnPtr<Condition>&&);
|
||||
|
||||
NonnullOwnPtr<Condition> m_condition;
|
||||
bool m_matches { false };
|
||||
};
|
||||
|
||||
}
|
|
@ -39,6 +39,7 @@ class Selector;
|
|||
class StyleProperties;
|
||||
class StyleComputer;
|
||||
class StyleSheet;
|
||||
class Supports;
|
||||
|
||||
class StyleValue;
|
||||
class BackgroundRepeatStyleValue;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue