From e62d692205c8ecf2c754d4fec05b70a13bcf2b02 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 28 Dec 2023 12:43:38 +0000 Subject: [PATCH] LibWeb: Implement helpers for parsing CSS numeric types Frequently we want to parse "anything that's a ``" or similar, which could be a constant value or a calculation, but didn't have a nice way of doing so. That meant repeating the same "try and parse a dimension, see if it's the right type, then maybe try and parse a calculation and see if that's the right type" boilerplate code. Or more often, forgetting about calculations entirely. These helpers should make that a lot more convenient to do. And they also use TokenStream, so we can eventually drop the old `parse_length()` method. --- .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 246 ++++++++++++++++++ Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 13 + 2 files changed, 259 insertions(+) diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index fe1d562fb9..dbe83da356 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1586,6 +1586,252 @@ Optional Parser::parse_dimension(ComponentValue const& component_valu return {}; } +Optional Parser::parse_angle(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_angle()) { + transaction.commit(); + return dimension->angle(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_angle()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_angle_percentage(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_angle_percentage()) { + transaction.commit(); + return dimension->angle_percentage(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_angle_percentage()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_flex(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_flex()) { + transaction.commit(); + return dimension->flex(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_flex()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_frequency(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_frequency()) { + transaction.commit(); + return dimension->frequency(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_frequency()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_frequency_percentage(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_frequency_percentage()) { + transaction.commit(); + return dimension->frequency_percentage(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_frequency_percentage()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_integer(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (token.is(Token::Type::Number) && token.token().number().is_integer()) { + transaction.commit(); + return token.token().to_integer(); + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_number()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_length(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_length()) { + transaction.commit(); + return dimension->length(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_length()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_length_percentage(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_length_percentage()) { + transaction.commit(); + return dimension->length_percentage(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_length_percentage()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_number(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (token.is(Token::Type::Number)) { + transaction.commit(); + return token.token().number_value(); + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_number()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_resolution(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_resolution()) { + transaction.commit(); + return dimension->resolution(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_resolution()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_time(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_time()) { + transaction.commit(); + return dimension->time(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_time()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + +Optional Parser::parse_time_percentage(TokenStream& tokens) +{ + auto transaction = tokens.begin_transaction(); + auto& token = tokens.next_token(); + + if (auto dimension = parse_dimension(token); dimension.has_value()) { + if (dimension->is_time_percentage()) { + transaction.commit(); + return dimension->time_percentage(); + } + return {}; + } + + if (auto calc = parse_calculated_value(token); calc && calc->resolves_to_time_percentage()) { + transaction.commit(); + return calc.release_nonnull(); + } + + return {}; +} + Optional Parser::parse_source_size_value(ComponentValue const& component_value) { if (component_value.is_ident("auto"sv)) { diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index b093e09019..e2ecfa0090 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -171,6 +171,19 @@ private: Optional convert_to_style_property(Declaration const&); Optional parse_dimension(ComponentValue const&); + Optional parse_angle(TokenStream&); + Optional parse_angle_percentage(TokenStream&); + Optional parse_flex(TokenStream&); + Optional parse_frequency(TokenStream&); + Optional parse_frequency_percentage(TokenStream&); + Optional parse_integer(TokenStream&); + Optional parse_length(TokenStream&); + Optional parse_length_percentage(TokenStream&); + Optional parse_number(TokenStream&); + Optional parse_resolution(TokenStream&); + Optional parse_time(TokenStream&); + Optional parse_time_percentage(TokenStream&); + Optional parse_rgb_or_hsl_color(StringView function_name, Vector const&); Optional parse_color(ComponentValue const&); Optional parse_length(ComponentValue const&);