Explorar el Código

LibWeb: Implement IntegerStyleValue, for holding `<integer>`

Having one StyleValue for `<number>` and `<integer>` is making user code
more complicated than it needs to be. We know based on the property
being parsed, whether it wants a `<number>` or an `<integer>`, so we
can use separate StyleValue types for these.
Sam Atkins hace 2 años
padre
commit
1160d8186b

+ 1 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -96,6 +96,7 @@ set(SOURCES
     CSS/StyleValues/GridTrackSizeListStyleValue.cpp
     CSS/StyleValues/IdentifierStyleValue.cpp
     CSS/StyleValues/ImageStyleValue.cpp
+    CSS/StyleValues/IntegerStyleValue.cpp
     CSS/StyleValues/LengthStyleValue.cpp
     CSS/StyleValues/LinearGradientStyleValue.cpp
     CSS/StyleValues/ListStyleStyleValue.cpp

+ 28 - 12
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -62,6 +62,7 @@
 #include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
 #include <LibWeb/CSS/StyleValues/InheritStyleValue.h>
 #include <LibWeb/CSS/StyleValues/InitialStyleValue.h>
+#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LinearGradientStyleValue.h>
 #include <LibWeb/CSS/StyleValues/ListStyleStyleValue.h>
@@ -3811,13 +3812,23 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_dimension_value(ComponentValue const&
     VERIFY_NOT_REACHED();
 }
 
-ErrorOr<RefPtr<StyleValue>> Parser::parse_numeric_value(ComponentValue const& component_value)
+ErrorOr<RefPtr<StyleValue>> Parser::parse_integer_value(TokenStream<ComponentValue>& tokens)
 {
-    if (component_value.is(Token::Type::Number)) {
-        auto const& number = component_value.token();
-        if (number.number().is_integer())
-            return NumberStyleValue::create_integer(number.to_integer());
-        return NumberStyleValue::create_float(number.number_value());
+    auto peek_token = tokens.peek_token();
+    if (peek_token.is(Token::Type::Number) && peek_token.token().number().is_integer()) {
+        (void)tokens.next_token();
+        return IntegerStyleValue::create(peek_token.token().number().integer_value());
+    }
+
+    return nullptr;
+}
+
+ErrorOr<RefPtr<StyleValue>> Parser::parse_number_value(TokenStream<ComponentValue>& tokens)
+{
+    auto peek_token = tokens.peek_token();
+    if (peek_token.is(Token::Type::Number)) {
+        (void)tokens.next_token();
+        return NumberStyleValue::create_float(peek_token.token().number().value());
     }
 
     return nullptr;
@@ -6313,7 +6324,9 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_transform_value(Vector<ComponentValue>
                 if (maybe_calc_value && maybe_calc_value->resolves_to_number()) {
                     values.append(maybe_calc_value.release_nonnull());
                 } else {
-                    auto number = TRY(parse_numeric_value(value));
+                    // FIXME: Remove this reconsume once all parsing functions are TokenStream-based.
+                    argument_tokens.reconsume_current_input_token();
+                    auto number = TRY(parse_number_value(argument_tokens));
                     if (!number)
                         return nullptr;
                     values.append(number.release_nonnull());
@@ -7436,11 +7449,14 @@ ErrorOr<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readonl
     bool property_accepts_numeric = property_accepting_integer.has_value() || property_accepting_number.has_value();
 
     if (peek_token.is(Token::Type::Number) && property_accepts_numeric) {
-        auto numeric = TRY(parse_numeric_value(peek_token));
-        (void)tokens.next_token();
-        if (numeric->as_number().has_integer() && property_accepting_integer.has_value())
-            return PropertyAndValue { *property_accepting_integer, numeric };
-        return PropertyAndValue { property_accepting_integer.value_or(property_accepting_number.value()), numeric };
+        if (property_accepting_integer.has_value()) {
+            if (auto integer = TRY(parse_integer_value(tokens)))
+                return PropertyAndValue { *property_accepting_integer, integer };
+        }
+        if (property_accepting_number.has_value()) {
+            if (auto number = TRY(parse_number_value(tokens)))
+                return PropertyAndValue { *property_accepting_number, number };
+        }
     }
 
     if (peek_token.is(Token::Type::Percentage)) {

+ 2 - 1
Userland/Libraries/LibWeb/CSS/Parser/Parser.h

@@ -290,7 +290,8 @@ private:
     ErrorOr<RefPtr<StyleValue>> parse_dynamic_value(ComponentValue const&);
     ErrorOr<RefPtr<CalculatedStyleValue>> parse_calculated_value(Vector<ComponentValue> const&);
     ErrorOr<RefPtr<StyleValue>> parse_dimension_value(ComponentValue const&);
-    ErrorOr<RefPtr<StyleValue>> parse_numeric_value(ComponentValue const&);
+    ErrorOr<RefPtr<StyleValue>> parse_integer_value(TokenStream<ComponentValue>&);
+    ErrorOr<RefPtr<StyleValue>> parse_number_value(TokenStream<ComponentValue>&);
     ErrorOr<RefPtr<StyleValue>> parse_identifier_value(ComponentValue const&);
     ErrorOr<RefPtr<StyleValue>> parse_color_value(ComponentValue const&);
     ErrorOr<RefPtr<StyleValue>> parse_rect_value(ComponentValue const&);

+ 7 - 7
Userland/Libraries/LibWeb/CSS/StyleProperties.cpp

@@ -15,6 +15,7 @@
 #include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
 #include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
+#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
 #include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
 #include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
@@ -244,13 +245,12 @@ Optional<int> StyleProperties::z_index() const
     auto value = property(CSS::PropertyID::ZIndex);
     if (value->has_auto())
         return {};
-    if (value->is_number() && value->as_number().has_integer()) {
+    if (value->is_integer()) {
         // Clamp z-index to the range of a signed 32-bit integer for consistency with other engines.
-        // NOTE: Casting between 32-bit float and 32-bit integer is finicky here, since INT32_MAX is not representable as a 32-bit float!
-        auto integer = value->as_number().integer();
-        if (integer >= static_cast<float>(NumericLimits<int>::max()))
+        auto integer = value->as_integer().integer();
+        if (integer >= NumericLimits<int>::max())
             return NumericLimits<int>::max();
-        if (integer <= static_cast<float>(NumericLimits<int>::min()))
+        if (integer <= NumericLimits<int>::min())
             return NumericLimits<int>::min();
         return static_cast<int>(integer);
     }
@@ -362,9 +362,9 @@ float StyleProperties::flex_shrink() const
 int StyleProperties::order() const
 {
     auto value = property(CSS::PropertyID::Order);
-    if (!value->is_number() || !value->as_number().has_integer())
+    if (!value->is_integer())
         return 0;
-    return value->as_number().integer();
+    return value->as_integer().integer();
 }
 
 Optional<CSS::ImageRendering> StyleProperties::image_rendering() const

+ 9 - 2
Userland/Libraries/LibWeb/CSS/StyleValue.cpp

@@ -40,6 +40,7 @@
 #include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
 #include <LibWeb/CSS/StyleValues/InheritStyleValue.h>
 #include <LibWeb/CSS/StyleValues/InitialStyleValue.h>
+#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LinearGradientStyleValue.h>
 #include <LibWeb/CSS/StyleValues/ListStyleStyleValue.h>
@@ -248,6 +249,12 @@ InitialStyleValue const& StyleValue::as_initial() const
     return static_cast<InitialStyleValue const&>(*this);
 }
 
+IntegerStyleValue const& StyleValue::as_integer() const
+{
+    VERIFY(is_integer());
+    return static_cast<IntegerStyleValue const&>(*this);
+}
+
 LengthStyleValue const& StyleValue::as_length() const
 {
     VERIFY(is_length());
@@ -409,8 +416,8 @@ int StyleValue::to_font_weight() const
             return Gfx::FontWeight::Regular;
         }
     }
-    if (is_number() && as_number().has_integer()) {
-        return as_number().integer();
+    if (is_number()) {
+        return round_to<int>(as_number().number());
     }
     if (is_calculated()) {
         auto maybe_weight = const_cast<CalculatedStyleValue&>(as_calculated()).resolve_integer();

+ 4 - 0
Userland/Libraries/LibWeb/CSS/StyleValue.h

@@ -117,6 +117,7 @@ public:
         Image,
         Inherit,
         Initial,
+        Integer,
         Length,
         LinearGradient,
         ListStyle,
@@ -172,6 +173,7 @@ public:
     bool is_image() const { return type() == Type::Image; }
     bool is_inherit() const { return type() == Type::Inherit; }
     bool is_initial() const { return type() == Type::Initial; }
+    bool is_integer() const { return type() == Type::Integer; }
     bool is_length() const { return type() == Type::Length; }
     bool is_linear_gradient() const { return type() == Type::LinearGradient; }
     bool is_list_style() const { return type() == Type::ListStyle; }
@@ -226,6 +228,7 @@ public:
     ImageStyleValue const& as_image() const;
     InheritStyleValue const& as_inherit() const;
     InitialStyleValue const& as_initial() const;
+    IntegerStyleValue const& as_integer() const;
     LengthStyleValue const& as_length() const;
     LinearGradientStyleValue const& as_linear_gradient() const;
     ListStyleStyleValue const& as_list_style() const;
@@ -277,6 +280,7 @@ public:
     ImageStyleValue& as_image() { return const_cast<ImageStyleValue&>(const_cast<StyleValue const&>(*this).as_image()); }
     InheritStyleValue& as_inherit() { return const_cast<InheritStyleValue&>(const_cast<StyleValue const&>(*this).as_inherit()); }
     InitialStyleValue& as_initial() { return const_cast<InitialStyleValue&>(const_cast<StyleValue const&>(*this).as_initial()); }
+    IntegerStyleValue& as_integer() { return const_cast<IntegerStyleValue&>(const_cast<StyleValue const&>(*this).as_integer()); }
     LengthStyleValue& as_length() { return const_cast<LengthStyleValue&>(const_cast<StyleValue const&>(*this).as_length()); }
     LinearGradientStyleValue& as_linear_gradient() { return const_cast<LinearGradientStyleValue&>(const_cast<StyleValue const&>(*this).as_linear_gradient()); }
     ListStyleStyleValue& as_list_style() { return const_cast<ListStyleStyleValue&>(const_cast<StyleValue const&>(*this).as_list_style()); }

+ 16 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.cpp

@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "IntegerStyleValue.h"
+
+namespace Web::CSS {
+
+ErrorOr<String> IntegerStyleValue::to_string() const
+{
+    return String::number(m_value);
+}
+
+}

+ 36 - 0
Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.h

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/CSS/StyleValue.h>
+
+namespace Web::CSS {
+
+class IntegerStyleValue : public StyleValueWithDefaultOperators<IntegerStyleValue> {
+public:
+    static ErrorOr<ValueComparingNonnullRefPtr<IntegerStyleValue>> create(i64 value)
+    {
+        return adopt_nonnull_ref_or_enomem(new (nothrow) IntegerStyleValue(value));
+    }
+
+    i64 integer() const { return m_value; }
+
+    virtual ErrorOr<String> to_string() const override;
+
+    bool properties_equal(IntegerStyleValue const& other) const { return m_value == other.m_value; }
+
+private:
+    explicit IntegerStyleValue(i64 value)
+        : StyleValueWithDefaultOperators(Type::Integer)
+        , m_value(value)
+    {
+    }
+
+    i64 m_value { 0 };
+};
+
+}

+ 1 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -117,6 +117,7 @@ class IdentifierStyleValue;
 class ImageStyleValue;
 class InheritStyleValue;
 class InitialStyleValue;
+class IntegerStyleValue;
 class Length;
 class LengthBox;
 class LengthOrCalculated;

+ 1 - 1
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -295,7 +295,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
     //       That's why it has to be set before everything else.
     m_font = computed_style.computed_font();
     computed_values.set_font_size(computed_style.property(CSS::PropertyID::FontSize)->as_length().length().to_px(*this).value());
-    computed_values.set_font_weight(computed_style.property(CSS::PropertyID::FontWeight)->as_number().integer());
+    computed_values.set_font_weight(round_to<int>(computed_style.property(CSS::PropertyID::FontWeight)->as_number().number()));
     m_line_height = computed_style.line_height(*this);
 
     computed_values.set_vertical_align(computed_style.vertical_align());