diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 0f1a285b9c8..61f8ebfcbf6 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/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 diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index d386f7df663..21e05cb0543 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -3811,13 +3812,23 @@ ErrorOr> Parser::parse_dimension_value(ComponentValue const& VERIFY_NOT_REACHED(); } -ErrorOr> Parser::parse_numeric_value(ComponentValue const& component_value) +ErrorOr> Parser::parse_integer_value(TokenStream& 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> Parser::parse_number_value(TokenStream& 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> Parser::parse_transform_value(Vector 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::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)) { diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 51cf8cd7a03..43c3a5d86ab 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -290,7 +290,8 @@ private: ErrorOr> parse_dynamic_value(ComponentValue const&); ErrorOr> parse_calculated_value(Vector const&); ErrorOr> parse_dimension_value(ComponentValue const&); - ErrorOr> parse_numeric_value(ComponentValue const&); + ErrorOr> parse_integer_value(TokenStream&); + ErrorOr> parse_number_value(TokenStream&); ErrorOr> parse_identifier_value(ComponentValue const&); ErrorOr> parse_color_value(ComponentValue const&); ErrorOr> parse_rect_value(ComponentValue const&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index d20cb9d87b8..53ab1e0afd9 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -244,13 +245,12 @@ Optional 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(NumericLimits::max())) + auto integer = value->as_integer().integer(); + if (integer >= NumericLimits::max()) return NumericLimits::max(); - if (integer <= static_cast(NumericLimits::min())) + if (integer <= NumericLimits::min()) return NumericLimits::min(); return static_cast(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 StyleProperties::image_rendering() const diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index ff3e7f9bc6c..f67c7008bc6 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -248,6 +249,12 @@ InitialStyleValue const& StyleValue::as_initial() const return static_cast(*this); } +IntegerStyleValue const& StyleValue::as_integer() const +{ + VERIFY(is_integer()); + return static_cast(*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(as_number().number()); } if (is_calculated()) { auto maybe_weight = const_cast(as_calculated()).resolve_integer(); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index c84b8e7e6b0..dae517ba76d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/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(const_cast(*this).as_image()); } InheritStyleValue& as_inherit() { return const_cast(const_cast(*this).as_inherit()); } InitialStyleValue& as_initial() { return const_cast(const_cast(*this).as_initial()); } + IntegerStyleValue& as_integer() { return const_cast(const_cast(*this).as_integer()); } LengthStyleValue& as_length() { return const_cast(const_cast(*this).as_length()); } LinearGradientStyleValue& as_linear_gradient() { return const_cast(const_cast(*this).as_linear_gradient()); } ListStyleStyleValue& as_list_style() { return const_cast(const_cast(*this).as_list_style()); } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.cpp new file mode 100644 index 00000000000..a8ae8beaa2b --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "IntegerStyleValue.h" + +namespace Web::CSS { + +ErrorOr IntegerStyleValue::to_string() const +{ + return String::number(m_value); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.h new file mode 100644 index 00000000000..f47fbe3be0e --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/IntegerStyleValue.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::CSS { + +class IntegerStyleValue : public StyleValueWithDefaultOperators { +public: + static ErrorOr> create(i64 value) + { + return adopt_nonnull_ref_or_enomem(new (nothrow) IntegerStyleValue(value)); + } + + i64 integer() const { return m_value; } + + virtual ErrorOr 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 }; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 276a73eae63..d1f2f97aa72 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/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; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index d1fffbf080a..bb87ac18829 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/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(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());