Pārlūkot izejas kodu

LibWeb/CSS: Introduce helper methods for parsing numeric values

"Parse a style value for <foo>", where we don't care if it's a literal
<foo> or a calculated one, is a really common thing that we previously
didn't have methods for.

A couple of methods we had have been extended to parse calc(), and the
others have been filled in.

The method for parsing the `flex` property's value is renamed
`parse_flex_shorthand_value()` as it conflicted.
Sam Atkins 10 mēneši atpakaļ
vecāks
revīzija
27be8678c9

+ 188 - 25
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -2310,33 +2310,43 @@ Vector<Gfx::UnicodeRange> Parser::parse_unicode_ranges(TokenStream<ComponentValu
 
 
 RefPtr<CSSStyleValue> Parser::parse_dimension_value(TokenStream<ComponentValue>& tokens)
 RefPtr<CSSStyleValue> Parser::parse_dimension_value(TokenStream<ComponentValue>& tokens)
 {
 {
-    auto dimension = parse_dimension(tokens.peek_token());
-    if (!dimension.has_value())
-        return nullptr;
-    (void)tokens.next_token(); // dimension
+    if (auto dimension = parse_dimension(tokens.peek_token()); dimension.has_value()) {
+        (void)tokens.next_token(); // dimension
+
+        if (dimension->is_angle())
+            return AngleStyleValue::create(dimension->angle());
+        if (dimension->is_frequency())
+            return FrequencyStyleValue::create(dimension->frequency());
+        if (dimension->is_length())
+            return LengthStyleValue::create(dimension->length());
+        if (dimension->is_percentage())
+            return PercentageStyleValue::create(dimension->percentage());
+        if (dimension->is_resolution())
+            return ResolutionStyleValue::create(dimension->resolution());
+        if (dimension->is_time())
+            return TimeStyleValue::create(dimension->time());
+        VERIFY_NOT_REACHED();
+    }
 
 
-    if (dimension->is_angle())
-        return AngleStyleValue::create(dimension->angle());
-    if (dimension->is_frequency())
-        return FrequencyStyleValue::create(dimension->frequency());
-    if (dimension->is_length())
-        return LengthStyleValue::create(dimension->length());
-    if (dimension->is_percentage())
-        return PercentageStyleValue::create(dimension->percentage());
-    if (dimension->is_resolution())
-        return ResolutionStyleValue::create(dimension->resolution());
-    if (dimension->is_time())
-        return TimeStyleValue::create(dimension->time());
-    VERIFY_NOT_REACHED();
+    if (auto calc = parse_calculated_value(tokens.peek_token()); calc && calc->resolves_to_dimension()) {
+        (void)tokens.next_token(); // calc
+        return calc;
+    }
+
+    return nullptr;
 }
 }
 
 
 RefPtr<CSSStyleValue> Parser::parse_integer_value(TokenStream<ComponentValue>& tokens)
 RefPtr<CSSStyleValue> Parser::parse_integer_value(TokenStream<ComponentValue>& tokens)
 {
 {
     auto peek_token = tokens.peek_token();
     auto peek_token = tokens.peek_token();
     if (peek_token.is(Token::Type::Number) && peek_token.token().number().is_integer()) {
     if (peek_token.is(Token::Type::Number) && peek_token.token().number().is_integer()) {
-        (void)tokens.next_token();
+        (void)tokens.next_token(); // integer
         return IntegerStyleValue::create(peek_token.token().number().integer_value());
         return IntegerStyleValue::create(peek_token.token().number().integer_value());
     }
     }
+    if (auto calc = parse_calculated_value(peek_token); calc && calc->resolves_to_number()) {
+        (void)tokens.next_token(); // calc
+        return calc;
+    }
 
 
     return nullptr;
     return nullptr;
 }
 }
@@ -2345,25 +2355,178 @@ RefPtr<CSSStyleValue> Parser::parse_number_value(TokenStream<ComponentValue>& to
 {
 {
     auto peek_token = tokens.peek_token();
     auto peek_token = tokens.peek_token();
     if (peek_token.is(Token::Type::Number)) {
     if (peek_token.is(Token::Type::Number)) {
-        (void)tokens.next_token();
+        (void)tokens.next_token(); // number
         return NumberStyleValue::create(peek_token.token().number().value());
         return NumberStyleValue::create(peek_token.token().number().value());
     }
     }
+    if (auto calc = parse_calculated_value(peek_token); calc && calc->resolves_to_number()) {
+        (void)tokens.next_token(); // calc
+        return calc;
+    }
 
 
     return nullptr;
     return nullptr;
 }
 }
 
 
-RefPtr<CSSStyleValue> Parser::parse_number_or_percentage_value(TokenStream<ComponentValue>& tokens)
+RefPtr<CSSStyleValue> Parser::parse_number_percentage_value(TokenStream<ComponentValue>& tokens)
 {
 {
     auto peek_token = tokens.peek_token();
     auto peek_token = tokens.peek_token();
     if (peek_token.is(Token::Type::Number)) {
     if (peek_token.is(Token::Type::Number)) {
-        (void)tokens.next_token();
+        (void)tokens.next_token(); // number
         return NumberStyleValue::create(peek_token.token().number().value());
         return NumberStyleValue::create(peek_token.token().number().value());
     }
     }
     if (peek_token.is(Token::Type::Percentage)) {
     if (peek_token.is(Token::Type::Percentage)) {
-        (void)tokens.next_token();
+        (void)tokens.next_token(); // percentage
         return PercentageStyleValue::create(Percentage(peek_token.token().percentage()));
         return PercentageStyleValue::create(Percentage(peek_token.token().percentage()));
     }
     }
+    if (auto calc = parse_calculated_value(peek_token); calc && calc->resolves_to_number_percentage()) {
+        (void)tokens.next_token(); // calc
+        return calc;
+    }
+
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_percentage_value(TokenStream<ComponentValue>& tokens)
+{
+    auto peek_token = tokens.peek_token();
+    if (peek_token.is(Token::Type::Percentage)) {
+        (void)tokens.next_token(); // percentage
+        return PercentageStyleValue::create(Percentage(peek_token.token().percentage()));
+    }
+    if (auto calc = parse_calculated_value(peek_token); calc && calc->resolves_to_percentage()) {
+        (void)tokens.next_token(); // calc
+        return calc;
+    }
+
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_angle_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_angle()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_angle())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
 
 
+RefPtr<CSSStyleValue> Parser::parse_angle_percentage_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_angle() || dimension_value->is_percentage()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_angle_percentage())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_flex_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_flex()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_flex())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_frequency_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_frequency()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_frequency())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_frequency_percentage_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_frequency() || dimension_value->is_percentage()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_frequency_percentage())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_length_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_length()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_length())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_length_percentage_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_length() || dimension_value->is_percentage()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_length_percentage())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_resolution_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_resolution()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_resolution())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_time_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_time()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_time())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
+    return nullptr;
+}
+
+RefPtr<CSSStyleValue> Parser::parse_time_percentage_value(TokenStream<ComponentValue>& tokens)
+{
+    auto transaction = tokens.begin_transaction();
+    if (auto dimension_value = parse_dimension_value(tokens)) {
+        if (dimension_value->is_time() || dimension_value->is_percentage()
+            || (dimension_value->is_calculated() && dimension_value->as_calculated().resolves_to_time_percentage())) {
+            transaction.commit();
+            return dimension_value;
+        }
+    }
     return nullptr;
     return nullptr;
 }
 }
 
 
@@ -4782,7 +4945,7 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
     return FilterValueListStyleValue::create(move(filter_value_list));
     return FilterValueListStyleValue::create(move(filter_value_list));
 }
 }
 
 
-RefPtr<CSSStyleValue> Parser::parse_flex_value(TokenStream<ComponentValue>& tokens)
+RefPtr<CSSStyleValue> Parser::parse_flex_shorthand_value(TokenStream<ComponentValue>& tokens)
 {
 {
     auto transaction = tokens.begin_transaction();
     auto transaction = tokens.begin_transaction();
 
 
@@ -5964,7 +6127,7 @@ RefPtr<CSSStyleValue> Parser::parse_transform_value(TokenStream<ComponentValue>&
                 } else {
                 } else {
                     // FIXME: Remove this reconsume once all parsing functions are TokenStream-based.
                     // FIXME: Remove this reconsume once all parsing functions are TokenStream-based.
                     argument_tokens.reconsume_current_input_token();
                     argument_tokens.reconsume_current_input_token();
-                    auto number_or_percentage = parse_number_or_percentage_value(argument_tokens);
+                    auto number_or_percentage = parse_number_percentage_value(argument_tokens);
                     if (!number_or_percentage)
                     if (!number_or_percentage)
                         return nullptr;
                         return nullptr;
                     values.append(number_or_percentage.release_nonnull());
                     values.append(number_or_percentage.release_nonnull());
@@ -7077,7 +7240,7 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
         return ParseError::SyntaxError;
         return ParseError::SyntaxError;
     case PropertyID::Flex:
     case PropertyID::Flex:
     case PropertyID::WebkitFlex:
     case PropertyID::WebkitFlex:
-        if (auto parsed_value = parse_flex_value(tokens); parsed_value && !tokens.has_next_token())
+        if (auto parsed_value = parse_flex_shorthand_value(tokens); parsed_value && !tokens.has_next_token())
             return parsed_value.release_nonnull();
             return parsed_value.release_nonnull();
         return ParseError::SyntaxError;
         return ParseError::SyntaxError;
     case PropertyID::FlexFlow:
     case PropertyID::FlexFlow:

+ 17 - 5
Userland/Libraries/LibWeb/CSS/Parser/Parser.h

@@ -238,10 +238,6 @@ private:
     // NOTE: Implemented in generated code. (GenerateCSSMathFunctions.cpp)
     // NOTE: Implemented in generated code. (GenerateCSSMathFunctions.cpp)
     OwnPtr<CalculationNode> parse_math_function(PropertyID, Function const&);
     OwnPtr<CalculationNode> parse_math_function(PropertyID, Function const&);
     OwnPtr<CalculationNode> parse_a_calc_function_node(Function const&);
     OwnPtr<CalculationNode> parse_a_calc_function_node(Function const&);
-    RefPtr<CSSStyleValue> parse_dimension_value(TokenStream<ComponentValue>&);
-    RefPtr<CSSStyleValue> parse_integer_value(TokenStream<ComponentValue>&);
-    RefPtr<CSSStyleValue> parse_number_value(TokenStream<ComponentValue>&);
-    RefPtr<CSSStyleValue> parse_number_or_percentage_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_keyword_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_keyword_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_color_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_color_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_counter_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_counter_value(TokenStream<ComponentValue>&);
@@ -262,6 +258,22 @@ private:
     RefPtr<PositionStyleValue> parse_position_value(TokenStream<ComponentValue>&, PositionParsingMode = PositionParsingMode::Normal);
     RefPtr<PositionStyleValue> parse_position_value(TokenStream<ComponentValue>&, PositionParsingMode = PositionParsingMode::Normal);
     RefPtr<CSSStyleValue> parse_filter_value_list_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_filter_value_list_value(TokenStream<ComponentValue>&);
 
 
+    RefPtr<CSSStyleValue> parse_dimension_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_angle_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_angle_percentage_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_flex_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_frequency_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_frequency_percentage_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_integer_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_length_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_length_percentage_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_number_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_number_percentage_value(TokenStream<ComponentValue>& tokens);
+    RefPtr<CSSStyleValue> parse_percentage_value(TokenStream<ComponentValue>& tokens);
+    RefPtr<CSSStyleValue> parse_resolution_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_time_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_time_percentage_value(TokenStream<ComponentValue>&);
+
     template<typename ParseFunction>
     template<typename ParseFunction>
     RefPtr<CSSStyleValue> parse_comma_separated_value_list(TokenStream<ComponentValue>&, ParseFunction);
     RefPtr<CSSStyleValue> parse_comma_separated_value_list(TokenStream<ComponentValue>&, ParseFunction);
     RefPtr<CSSStyleValue> parse_simple_comma_separated_value_list(PropertyID, TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_simple_comma_separated_value_list(PropertyID, TokenStream<ComponentValue>&);
@@ -280,7 +292,7 @@ private:
     RefPtr<CSSStyleValue> parse_counter_reset_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_counter_reset_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_counter_set_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_counter_set_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_display_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_display_value(TokenStream<ComponentValue>&);
-    RefPtr<CSSStyleValue> parse_flex_value(TokenStream<ComponentValue>&);
+    RefPtr<CSSStyleValue> parse_flex_shorthand_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_flex_flow_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_flex_flow_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_font_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_font_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_font_family_value(TokenStream<ComponentValue>&);
     RefPtr<CSSStyleValue> parse_font_family_value(TokenStream<ComponentValue>&);

+ 2 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h

@@ -117,6 +117,8 @@ public:
     Optional<double> resolve_number() const;
     Optional<double> resolve_number() const;
     Optional<i64> resolve_integer() const;
     Optional<i64> resolve_integer() const;
 
 
+    bool resolves_to_dimension() const { return m_resolved_type.matches_dimension(); }
+
     bool contains_percentage() const;
     bool contains_percentage() const;
 
 
 private:
 private: