diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index d7cce14091..9a6f035b4a 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -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 diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index cebf6816e3..a1177b8585 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1604,7 +1604,7 @@ RefPtr Parser::convert_to_declaration(Nonnull return parse_a_list_of_declarations(stream); } -Optional Parser::convert_to_style_property(StyleDeclarationRule& declaration) +Optional Parser::convert_to_style_property(StyleDeclarationRule const& declaration) { auto& property_name = declaration.m_name; auto property_id = property_id_from_string(property_name); diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index d3b55de014..e52575f8a4 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -106,6 +106,9 @@ public: RefPtr parse_as_css_value(PropertyID); + // FIXME: This is a hack, while CSS::Supports is using a StyleDeclarationRule + [[nodiscard]] Optional convert_to_style_property(StyleDeclarationRule const&); + private: enum class ParsingResult { Done, @@ -176,7 +179,6 @@ private: [[nodiscard]] RefPtr convert_to_rule(NonnullRefPtr); [[nodiscard]] RefPtr convert_to_declaration(NonnullRefPtr); - [[nodiscard]] Optional convert_to_style_property(StyleDeclarationRule&); static Optional try_parse_float(StringView string); static Optional parse_color(ParsingContext const&, StyleComponentValueRule const&); diff --git a/Userland/Libraries/LibWeb/CSS/Supports.cpp b/Userland/Libraries/LibWeb/CSS/Supports.cpp new file mode 100644 index 0000000000..bb96088e10 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/Supports.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::CSS { + +Supports::Supports(NonnullOwnPtr&& 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) { + 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; +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/Supports.h b/Userland/Libraries/LibWeb/CSS/Supports.h new file mode 100644 index 0000000000..6fe96351ce --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/Supports.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Web::CSS { + +class Supports final : public RefCounted { + 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, Feature, GeneralEnclosed> value; + + MatchResult evaluate() const; + }; + + struct Condition { + enum class Type { + Not, + And, + Or, + }; + Type type; + Vector children; + + MatchResult evaluate() const; + }; + + static NonnullRefPtr create(NonnullOwnPtr&& condition) + { + return adopt_ref(*new Supports(move(condition))); + } + + bool matches() const { return m_matches; } + +private: + Supports(NonnullOwnPtr&&); + + NonnullOwnPtr m_condition; + bool m_matches { false }; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index c6f3506a80..cdc6d6a33b 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -39,6 +39,7 @@ class Selector; class StyleProperties; class StyleComputer; class StyleSheet; +class Supports; class StyleValue; class BackgroundRepeatStyleValue;