From 23dc0dac88a248d4ac9b1be36212d065c7112629 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 3 Dec 2021 12:32:12 +0000 Subject: LibWeb: Parse and resolve UnresolvedStyleValues If a property is custom or contains a `var()` reference, it cannot be parsed into a proper StyleValue immediately, so we store it as an UnresolvedStyleValue until the property is compute. Then, at compute time, we resolve them by expanding out any `var()` references, and parsing the result. The implementation here is very naive, and involves copying the UnresolvedStyleValue's tree of StyleComponentValueRules while copying the contents of any `var()`s it finds along the way. This is quite an expensive operation to do every time that the style is computed. --- Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 44 ++++++++++++++++++++-- Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 2 + .../LibWeb/CSS/Parser/StyleFunctionRule.h | 3 +- .../Libraries/LibWeb/CSS/Parser/StyleRules.cpp | 8 +++- 4 files changed, 51 insertions(+), 6 deletions(-) (limited to 'Userland/Libraries/LibWeb/CSS/Parser') diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index f684647903..61a12a0849 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -3435,8 +3435,19 @@ RefPtr Parser::parse_as_css_value(PropertyID property_id) Result, Parser::ParsingResult> Parser::parse_css_value(PropertyID property_id, TokenStream& tokens) { + auto block_contains_var = [](StyleBlockRule const& block, auto&& recurse) -> bool { + for (auto const& token : block.values()) { + if (token.is_function() && token.function().name().equals_ignoring_case("var"sv)) + return true; + if (token.is_block() && recurse(token.block(), recurse)) + return true; + } + return false; + }; + m_context.set_current_property_id(property_id); Vector component_values; + bool contains_var = false; while (tokens.has_next_token()) { auto& token = tokens.next_token(); @@ -3446,15 +3457,27 @@ Result, Parser::ParsingResult> Parser::parse_css_value break; } - if (token.is(Token::Type::Whitespace)) - continue; + if (property_id != PropertyID::Custom) { + if (token.is(Token::Type::Whitespace)) + continue; - if (token.is(Token::Type::Ident) && has_ignored_vendor_prefix(token.token().ident())) - return ParsingResult::IncludesIgnoredVendorPrefix; + if (token.is(Token::Type::Ident) && has_ignored_vendor_prefix(token.token().ident())) + return ParsingResult::IncludesIgnoredVendorPrefix; + } + + if (!contains_var) { + if (token.is_function() && token.function().name().equals_ignoring_case("var"sv)) + contains_var = true; + else if (token.is_block() && block_contains_var(token.block(), block_contains_var)) + contains_var = true; + } component_values.append(token); } + if (property_id == PropertyID::Custom || contains_var) + return { UnresolvedStyleValue::create(move(component_values), contains_var) }; + if (component_values.is_empty()) return ParsingResult::SyntaxError; @@ -4167,6 +4190,19 @@ bool Parser::has_ignored_vendor_prefix(StringView string) return true; } +RefPtr Parser::parse_css_value(Badge, ParsingContext const& context, PropertyID property_id, Vector const& tokens) +{ + if (tokens.is_empty() || property_id == CSS::PropertyID::Invalid || property_id == CSS::PropertyID::Custom) + return {}; + + CSS::Parser parser(context, ""); + CSS::TokenStream token_stream { tokens }; + auto result = parser.parse_css_value(property_id, token_stream); + if (result.is_error()) + return {}; + return result.release_value(); +} + } namespace Web { diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 7229a6bf40..5842370f7b 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -113,6 +113,8 @@ public: RefPtr parse_as_css_value(PropertyID); + static RefPtr parse_css_value(Badge, ParsingContext const&, PropertyID, Vector const&); + private: enum class ParsingResult { Done, diff --git a/Userland/Libraries/LibWeb/CSS/Parser/StyleFunctionRule.h b/Userland/Libraries/LibWeb/CSS/Parser/StyleFunctionRule.h index 661292268f..3ed89ded67 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/StyleFunctionRule.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/StyleFunctionRule.h @@ -20,7 +20,8 @@ class StyleFunctionRule : public RefCounted { friend class Parser; public: - StyleFunctionRule(String name); + explicit StyleFunctionRule(String name); + StyleFunctionRule(String name, Vector&& values); ~StyleFunctionRule(); String const& name() const { return m_name; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/StyleRules.cpp b/Userland/Libraries/LibWeb/CSS/Parser/StyleRules.cpp index 50269c73f6..9b67b058de 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/StyleRules.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/StyleRules.cpp @@ -57,7 +57,13 @@ StyleDeclarationRule::StyleDeclarationRule() { } StyleDeclarationRule::~StyleDeclarationRule() { } StyleFunctionRule::StyleFunctionRule(String name) - : m_name(name) + : m_name(move(name)) +{ +} + +StyleFunctionRule::StyleFunctionRule(String name, Vector&& values) + : m_name(move(name)) + , m_values(move(values)) { } StyleFunctionRule::~StyleFunctionRule() { } -- cgit v1.2.3