/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, Tobias Christiansen * Copyright (c) 2021-2023, Sam Atkins * Copyright (c) 2022-2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::CSS { template struct ValueComparingNonnullRefPtr : public NonnullRefPtr { using NonnullRefPtr::NonnullRefPtr; ValueComparingNonnullRefPtr(NonnullRefPtr const& other) : NonnullRefPtr(other) { } ValueComparingNonnullRefPtr(NonnullRefPtr&& other) : NonnullRefPtr(move(other)) { } bool operator==(ValueComparingNonnullRefPtr const& other) const { return this->ptr() == other.ptr() || this->ptr()->equals(*other); } private: using NonnullRefPtr::operator==; }; template struct ValueComparingRefPtr : public RefPtr { using RefPtr::RefPtr; ValueComparingRefPtr(RefPtr const& other) : RefPtr(other) { } ValueComparingRefPtr(RefPtr&& other) : RefPtr(move(other)) { } template bool operator==(ValueComparingNonnullRefPtr const& other) const { return this->ptr() == other.ptr() || (this->ptr() && this->ptr()->equals(*other)); } bool operator==(ValueComparingRefPtr const& other) const { return this->ptr() == other.ptr() || (this->ptr() && other.ptr() && this->ptr()->equals(*other)); } private: using RefPtr::operator==; }; using StyleValueVector = Vector>; class StyleValue : public RefCounted { public: virtual ~StyleValue() = default; enum class Type { Angle, Background, BackgroundRepeat, BackgroundSize, Border, BorderRadius, BorderRadiusShorthand, Calculated, Color, ConicGradient, Content, Display, Edge, FilterValueList, Flex, FlexFlow, Font, Frequency, GridAreaShorthand, GridTemplateArea, GridTrackPlacement, GridTrackPlacementShorthand, GridTrackSizeList, GridTrackSizeListShorthand, Identifier, Image, Inherit, Initial, Invalid, Length, LinearGradient, ListStyle, Numeric, Overflow, Percentage, Position, RadialGradient, Rect, Resolution, Shadow, String, TextDecoration, Time, Transformation, Unresolved, Unset, Url, ValueList }; Type type() const { return m_type; } bool is_abstract_image() const { return AK::first_is_one_of(type(), Type::Image, Type::LinearGradient, Type::ConicGradient, Type::RadialGradient); } bool is_angle() const { return type() == Type::Angle; } bool is_background() const { return type() == Type::Background; } bool is_background_repeat() const { return type() == Type::BackgroundRepeat; } bool is_background_size() const { return type() == Type::BackgroundSize; } bool is_border() const { return type() == Type::Border; } bool is_border_radius() const { return type() == Type::BorderRadius; } bool is_border_radius_shorthand() const { return type() == Type::BorderRadiusShorthand; } bool is_calculated() const { return type() == Type::Calculated; } bool is_color() const { return type() == Type::Color; } bool is_conic_gradient() const { return type() == Type::ConicGradient; } bool is_content() const { return type() == Type::Content; } bool is_display() const { return type() == Type::Display; } bool is_edge() const { return type() == Type::Edge; } bool is_filter_value_list() const { return type() == Type::FilterValueList; } bool is_flex() const { return type() == Type::Flex; } bool is_flex_flow() const { return type() == Type::FlexFlow; } bool is_font() const { return type() == Type::Font; } bool is_frequency() const { return type() == Type::Frequency; } bool is_grid_area_shorthand() const { return type() == Type::GridAreaShorthand; } bool is_grid_template_area() const { return type() == Type::GridTemplateArea; } bool is_grid_track_placement() const { return type() == Type::GridTrackPlacement; } bool is_grid_track_placement_shorthand() const { return type() == Type::GridTrackPlacementShorthand; } bool is_grid_track_size_list() const { return type() == Type::GridTrackSizeList; } bool is_grid_track_size_list_shorthand() const { return type() == Type::GridTrackSizeListShorthand; } bool is_identifier() const { return type() == Type::Identifier; } 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_length() const { return type() == Type::Length; } bool is_linear_gradient() const { return type() == Type::LinearGradient; } bool is_list_style() const { return type() == Type::ListStyle; } bool is_numeric() const { return type() == Type::Numeric; } bool is_overflow() const { return type() == Type::Overflow; } bool is_percentage() const { return type() == Type::Percentage; } bool is_position() const { return type() == Type::Position; } bool is_radial_gradient() const { return type() == Type::RadialGradient; } bool is_rect() const { return type() == Type::Rect; } bool is_resolution() const { return type() == Type::Resolution; } bool is_shadow() const { return type() == Type::Shadow; } bool is_string() const { return type() == Type::String; } bool is_text_decoration() const { return type() == Type::TextDecoration; } bool is_time() const { return type() == Type::Time; } bool is_transformation() const { return type() == Type::Transformation; } bool is_unresolved() const { return type() == Type::Unresolved; } bool is_unset() const { return type() == Type::Unset; } bool is_url() const { return type() == Type::Url; } bool is_value_list() const { return type() == Type::ValueList; } bool is_builtin() const { return is_inherit() || is_initial() || is_unset(); } AbstractImageStyleValue const& as_abstract_image() const; AngleStyleValue const& as_angle() const; BackgroundStyleValue const& as_background() const; BackgroundRepeatStyleValue const& as_background_repeat() const; BackgroundSizeStyleValue const& as_background_size() const; BorderRadiusStyleValue const& as_border_radius() const; BorderRadiusShorthandStyleValue const& as_border_radius_shorthand() const; BorderStyleValue const& as_border() const; CalculatedStyleValue const& as_calculated() const; ColorStyleValue const& as_color() const; ConicGradientStyleValue const& as_conic_gradient() const; ContentStyleValue const& as_content() const; DisplayStyleValue const& as_display() const; EdgeStyleValue const& as_edge() const; FilterValueListStyleValue const& as_filter_value_list() const; FlexFlowStyleValue const& as_flex_flow() const; FlexStyleValue const& as_flex() const; FontStyleValue const& as_font() const; FrequencyStyleValue const& as_frequency() const; GridAreaShorthandStyleValue const& as_grid_area_shorthand() const; GridTemplateAreaStyleValue const& as_grid_template_area() const; GridTrackPlacementShorthandStyleValue const& as_grid_track_placement_shorthand() const; GridTrackPlacementStyleValue const& as_grid_track_placement() const; GridTrackSizeListShorthandStyleValue const& as_grid_track_size_list_shorthand() const; GridTrackSizeListStyleValue const& as_grid_track_size_list() const; IdentifierStyleValue const& as_identifier() const; ImageStyleValue const& as_image() const; InheritStyleValue const& as_inherit() const; InitialStyleValue const& as_initial() const; LengthStyleValue const& as_length() const; LinearGradientStyleValue const& as_linear_gradient() const; ListStyleStyleValue const& as_list_style() const; NumericStyleValue const& as_numeric() const; OverflowStyleValue const& as_overflow() const; PercentageStyleValue const& as_percentage() const; PositionStyleValue const& as_position() const; RadialGradientStyleValue const& as_radial_gradient() const; RectStyleValue const& as_rect() const; ResolutionStyleValue const& as_resolution() const; ShadowStyleValue const& as_shadow() const; StringStyleValue const& as_string() const; TextDecorationStyleValue const& as_text_decoration() const; TimeStyleValue const& as_time() const; TransformationStyleValue const& as_transformation() const; UnresolvedStyleValue const& as_unresolved() const; UnsetStyleValue const& as_unset() const; URLStyleValue const& as_url() const; StyleValueList const& as_value_list() const; AbstractImageStyleValue& as_abstract_image() { return const_cast(const_cast(*this).as_abstract_image()); } AngleStyleValue& as_angle() { return const_cast(const_cast(*this).as_angle()); } BackgroundStyleValue& as_background() { return const_cast(const_cast(*this).as_background()); } BackgroundRepeatStyleValue& as_background_repeat() { return const_cast(const_cast(*this).as_background_repeat()); } BackgroundSizeStyleValue& as_background_size() { return const_cast(const_cast(*this).as_background_size()); } BorderRadiusStyleValue& as_border_radius() { return const_cast(const_cast(*this).as_border_radius()); } BorderRadiusShorthandStyleValue& as_border_radius_shorthand() { return const_cast(const_cast(*this).as_border_radius_shorthand()); } BorderStyleValue& as_border() { return const_cast(const_cast(*this).as_border()); } CalculatedStyleValue& as_calculated() { return const_cast(const_cast(*this).as_calculated()); } ColorStyleValue& as_color() { return const_cast(const_cast(*this).as_color()); } ConicGradientStyleValue& as_conic_gradient() { return const_cast(const_cast(*this).as_conic_gradient()); } ContentStyleValue& as_content() { return const_cast(const_cast(*this).as_content()); } DisplayStyleValue& as_display() { return const_cast(const_cast(*this).as_display()); } EdgeStyleValue& as_edge() { return const_cast(const_cast(*this).as_edge()); } FilterValueListStyleValue& as_filter_value_list() { return const_cast(const_cast(*this).as_filter_value_list()); } FlexFlowStyleValue& as_flex_flow() { return const_cast(const_cast(*this).as_flex_flow()); } FlexStyleValue& as_flex() { return const_cast(const_cast(*this).as_flex()); } FontStyleValue& as_font() { return const_cast(const_cast(*this).as_font()); } FrequencyStyleValue& as_frequency() { return const_cast(const_cast(*this).as_frequency()); } GridAreaShorthandStyleValue& as_grid_area_shorthand() { return const_cast(const_cast(*this).as_grid_area_shorthand()); } GridTemplateAreaStyleValue& as_grid_template_area() { return const_cast(const_cast(*this).as_grid_template_area()); } GridTrackPlacementShorthandStyleValue& as_grid_track_placement_shorthand() { return const_cast(const_cast(*this).as_grid_track_placement_shorthand()); } GridTrackPlacementStyleValue& as_grid_track_placement() { return const_cast(const_cast(*this).as_grid_track_placement()); } GridTrackSizeListShorthandStyleValue& as_grid_track_size_list_shorthand() { return const_cast(const_cast(*this).as_grid_track_size_list_shorthand()); } GridTrackSizeListStyleValue& as_grid_track_size_list() { return const_cast(const_cast(*this).as_grid_track_size_list()); } IdentifierStyleValue& as_identifier() { return const_cast(const_cast(*this).as_identifier()); } 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()); } 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()); } NumericStyleValue& as_numeric() { return const_cast(const_cast(*this).as_numeric()); } OverflowStyleValue& as_overflow() { return const_cast(const_cast(*this).as_overflow()); } PercentageStyleValue& as_percentage() { return const_cast(const_cast(*this).as_percentage()); } PositionStyleValue& as_position() { return const_cast(const_cast(*this).as_position()); } RadialGradientStyleValue& as_radial_gradient() { return const_cast(const_cast(*this).as_radial_gradient()); } RectStyleValue& as_rect() { return const_cast(const_cast(*this).as_rect()); } ResolutionStyleValue& as_resolution() { return const_cast(const_cast(*this).as_resolution()); } ShadowStyleValue& as_shadow() { return const_cast(const_cast(*this).as_shadow()); } StringStyleValue& as_string() { return const_cast(const_cast(*this).as_string()); } TextDecorationStyleValue& as_text_decoration() { return const_cast(const_cast(*this).as_text_decoration()); } TimeStyleValue& as_time() { return const_cast(const_cast(*this).as_time()); } TransformationStyleValue& as_transformation() { return const_cast(const_cast(*this).as_transformation()); } UnresolvedStyleValue& as_unresolved() { return const_cast(const_cast(*this).as_unresolved()); } UnsetStyleValue& as_unset() { return const_cast(const_cast(*this).as_unset()); } URLStyleValue& as_url() { return const_cast(const_cast(*this).as_url()); } StyleValueList& as_value_list() { return const_cast(const_cast(*this).as_value_list()); } bool has_auto() const; virtual bool has_color() const { return false; } virtual bool has_length() const { return false; } virtual bool has_rect() const { return false; } virtual bool has_number() const { return false; } virtual bool has_integer() const { return false; } virtual ErrorOr> absolutized(CSSPixelRect const& viewport_rect, Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const; virtual Color to_color(Optional) const { return {}; } ValueID to_identifier() const; virtual Length to_length() const { VERIFY_NOT_REACHED(); } virtual float to_number() const { return 0; } virtual float to_integer() const { return 0; } virtual ErrorOr to_string() const = 0; virtual bool equals(StyleValue const& other) const = 0; bool operator==(StyleValue const& other) const { return this->equals(other); } protected: explicit StyleValue(Type); private: Type m_type { Type::Invalid }; }; template struct StyleValueWithDefaultOperators : public StyleValue { using StyleValue::StyleValue; virtual bool equals(StyleValue const& other) const override { if (type() != other.type()) return false; auto const& typed_other = static_cast(other); return static_cast(*this).properties_equal(typed_other); } }; } template<> struct AK::Formatter : Formatter { ErrorOr format(FormatBuilder& builder, Web::CSS::StyleValue const& style_value) { return Formatter::format(builder, TRY(style_value.to_string())); } };