/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::CSS { enum class BackgroundSize { Contain, Cover, LengthPercentage, }; enum class ShadowPlacement { Outer, Inner, }; enum class FlexBasis { Content, LengthPercentage, Auto, }; // Note: The sides must be before the corners in this enum (as this order is used in parsing). enum class SideOrCorner { Top, Bottom, Left, Right, TopLeft, TopRight, BottomLeft, BottomRight }; template struct ColorStopListElement { using PositionType = TPosition; struct ColorHint { TPosition value; inline bool operator==(ColorHint const&) const = default; }; Optional transition_hint; struct ColorStop { Color color; Optional position; Optional second_position = {}; inline bool operator==(ColorStop const&) const = default; } color_stop; inline bool operator==(ColorStopListElement const&) const = default; }; using LinearColorStopListElement = ColorStopListElement; using AngularColorStopListElement = ColorStopListElement; // FIXME: Named PositionValue to avoid conflicts with enums, but this represents a struct PositionValue { enum class HorizontalPreset { Left, Center, Right }; enum class VerticalPreset { Top, Center, Bottom }; enum class HorizontalEdge { Left, Right }; enum class VerticalEdge { Top, Bottom }; static PositionValue center() { return PositionValue { HorizontalPreset::Center, VerticalPreset::Center }; } Variant horizontal_position { HorizontalPreset::Left }; Variant vertical_position { VerticalPreset::Top }; HorizontalEdge x_relative_to { HorizontalEdge::Left }; VerticalEdge y_relative_to { VerticalEdge::Top }; CSSPixelPoint resolved(Layout::Node const& node, CSSPixelRect const& rect) const; ErrorOr serialize(StringBuilder&) const; bool operator==(PositionValue const&) const = default; }; struct EdgeRect { Length top_edge; Length right_edge; Length bottom_edge; Length left_edge; Gfx::FloatRect resolved(Layout::Node const&, Gfx::FloatRect) const; bool operator==(EdgeRect const&) const = default; }; namespace Filter { struct Blur { Optional radius {}; float resolved_radius(Layout::Node const&) const; bool operator==(Blur const&) const = default; }; struct DropShadow { Length offset_x; Length offset_y; Optional radius {}; Optional color {}; struct Resolved { float offset_x; float offset_y; float radius; Color color; }; Resolved resolved(Layout::Node const&) const; bool operator==(DropShadow const&) const = default; }; struct HueRotate { struct Zero { bool operator==(Zero const&) const = default; }; using AngleOrZero = Variant; Optional angle {}; float angle_degrees() const; bool operator==(HueRotate const&) const = default; }; struct Color { enum class Operation { Brightness, Contrast, Grayscale, Invert, Opacity, Saturate, Sepia } operation; Optional amount {}; float resolved_amount() const; bool operator==(Color const&) const = default; }; }; using FilterFunction = Variant; // FIXME: Find a better place for this helper. inline Gfx::Painter::ScalingMode to_gfx_scaling_mode(CSS::ImageRendering css_value) { switch (css_value) { case CSS::ImageRendering::Auto: case CSS::ImageRendering::HighQuality: case CSS::ImageRendering::Smooth: return Gfx::Painter::ScalingMode::BilinearBlend; case CSS::ImageRendering::CrispEdges: return Gfx::Painter::ScalingMode::NearestNeighbor; case CSS::ImageRendering::Pixelated: return Gfx::Painter::ScalingMode::SmoothPixels; } VERIFY_NOT_REACHED(); } class StyleValue : public RefCounted { public: virtual ~StyleValue() = default; enum class Type { Angle, Background, BackgroundRepeat, BackgroundSize, Border, BorderRadius, BorderRadiusShorthand, Calculated, Color, ConicGradient, Content, FilterValueList, Flex, FlexFlow, Font, Frequency, GridAreaShorthand, GridTemplateArea, GridTrackPlacement, GridTrackPlacementShorthand, GridTrackSizeList, Identifier, Image, Inherit, Initial, Invalid, Length, LinearGradient, ListStyle, Numeric, Overflow, Percentage, Position, RadialGradient, Rect, Resolution, Shadow, String, TextDecoration, Time, Transformation, Unresolved, Unset, 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_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_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_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; 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; GridTrackSizeStyleValue 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; 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()); } 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()); } GridTrackSizeStyleValue& 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()); } StyleValueList& as_value_list() { return const_cast(const_cast(*this).as_value_list()); } virtual bool has_auto() const { return false; } virtual bool has_color() const { return false; } virtual bool has_identifier() 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 NonnullRefPtr absolutized(CSSPixelRect const& viewport_rect, Gfx::FontPixelMetrics const& font_metrics, CSSPixels font_size, CSSPixels root_font_size) const; virtual Color to_color(Layout::NodeWithStyle const&) const { return {}; } virtual EdgeRect to_rect() const { VERIFY_NOT_REACHED(); } virtual CSS::ValueID to_identifier() const { return ValueID::Invalid; } 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 operator==(StyleValue const& other) const = 0; protected: explicit StyleValue(Type); private: Type m_type { Type::Invalid }; }; template struct StyleValueWithDefaultOperators : public StyleValue { using StyleValue::StyleValue; bool operator==(StyleValue const& other) const override { if (type() != other.type()) return false; auto const& typed_other = static_cast(other); return static_cast(*this).equals(typed_other); } }; class AngleStyleValue : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create(Angle angle) { return adopt_ref(*new AngleStyleValue(move(angle))); } virtual ~AngleStyleValue() override { } Angle const& angle() const { return m_angle; } virtual ErrorOr to_string() const override { return m_angle.to_string(); } bool equals(AngleStyleValue const& other) const { return m_angle == other.m_angle; } private: explicit AngleStyleValue(Angle angle) : StyleValueWithDefaultOperators(Type::Angle) , m_angle(move(angle)) { } Angle m_angle; }; class BackgroundStyleValue final : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create( NonnullRefPtr color, NonnullRefPtr image, NonnullRefPtr position, NonnullRefPtr size, NonnullRefPtr repeat, NonnullRefPtr attachment, NonnullRefPtr origin, NonnullRefPtr clip) { return adopt_ref(*new BackgroundStyleValue(move(color), move(image), move(position), move(size), move(repeat), move(attachment), move(origin), move(clip))); } virtual ~BackgroundStyleValue() override = default; size_t layer_count() const { return m_properties.layer_count; } NonnullRefPtr attachment() const { return m_properties.attachment; } NonnullRefPtr clip() const { return m_properties.clip; } NonnullRefPtr color() const { return m_properties.color; } NonnullRefPtr image() const { return m_properties.image; } NonnullRefPtr origin() const { return m_properties.origin; } NonnullRefPtr position() const { return m_properties.position; } NonnullRefPtr repeat() const { return m_properties.repeat; } NonnullRefPtr size() const { return m_properties.size; } virtual ErrorOr to_string() const override; bool equals(BackgroundStyleValue const& other) const { return m_properties == other.m_properties; } private: BackgroundStyleValue( NonnullRefPtr color, NonnullRefPtr image, NonnullRefPtr position, NonnullRefPtr size, NonnullRefPtr repeat, NonnullRefPtr attachment, NonnullRefPtr origin, NonnullRefPtr clip); struct Properties { NonnullRefPtr color; NonnullRefPtr image; NonnullRefPtr position; NonnullRefPtr size; NonnullRefPtr repeat; NonnullRefPtr attachment; NonnullRefPtr origin; NonnullRefPtr clip; size_t layer_count; bool operator==(Properties const&) const = default; } m_properties; }; class BackgroundRepeatStyleValue final : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create(Repeat repeat_x, Repeat repeat_y) { return adopt_ref(*new BackgroundRepeatStyleValue(repeat_x, repeat_y)); } virtual ~BackgroundRepeatStyleValue() override = default; Repeat repeat_x() const { return m_properties.repeat_x; } Repeat repeat_y() const { return m_properties.repeat_y; } virtual ErrorOr to_string() const override; bool equals(BackgroundRepeatStyleValue const& other) const { return m_properties == other.m_properties; } private: BackgroundRepeatStyleValue(Repeat repeat_x, Repeat repeat_y) : StyleValueWithDefaultOperators(Type::BackgroundRepeat) , m_properties { .repeat_x = repeat_x, .repeat_y = repeat_y } { } struct Properties { Repeat repeat_x; Repeat repeat_y; bool operator==(Properties const&) const = default; } m_properties; }; // NOTE: This is not used for identifier sizes, like `cover` and `contain`. class BackgroundSizeStyleValue final : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create(LengthPercentage size_x, LengthPercentage size_y) { return adopt_ref(*new BackgroundSizeStyleValue(size_x, size_y)); } virtual ~BackgroundSizeStyleValue() override = default; LengthPercentage size_x() const { return m_properties.size_x; } LengthPercentage size_y() const { return m_properties.size_y; } virtual ErrorOr to_string() const override; bool equals(BackgroundSizeStyleValue const& other) const { return m_properties == other.m_properties; } private: BackgroundSizeStyleValue(LengthPercentage size_x, LengthPercentage size_y) : StyleValueWithDefaultOperators(Type::BackgroundSize) , m_properties { .size_x = size_x, .size_y = size_y } { } struct Properties { LengthPercentage size_x; LengthPercentage size_y; bool operator==(Properties const&) const = default; } m_properties; }; class BorderStyleValue final : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create( NonnullRefPtr border_width, NonnullRefPtr border_style, NonnullRefPtr border_color) { return adopt_ref(*new BorderStyleValue(move(border_width), move(border_style), move(border_color))); } virtual ~BorderStyleValue() override = default; NonnullRefPtr border_width() const { return m_properties.border_width; } NonnullRefPtr border_style() const { return m_properties.border_style; } NonnullRefPtr border_color() const { return m_properties.border_color; } virtual ErrorOr to_string() const override; bool equals(BorderStyleValue const& other) const { return m_properties == other.m_properties; } private: BorderStyleValue( NonnullRefPtr border_width, NonnullRefPtr border_style, NonnullRefPtr border_color) : StyleValueWithDefaultOperators(Type::Border) , m_properties { .border_width = move(border_width), .border_style = move(border_style), .border_color = move(border_color) } { } struct Properties { NonnullRefPtr border_width; NonnullRefPtr border_style; NonnullRefPtr border_color; bool operator==(Properties const&) const = default; } m_properties; }; class BorderRadiusStyleValue final : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create(LengthPercentage const& horizontal_radius, LengthPercentage const& vertical_radius) { return adopt_ref(*new BorderRadiusStyleValue(horizontal_radius, vertical_radius)); } virtual ~BorderRadiusStyleValue() override = default; LengthPercentage const& horizontal_radius() const { return m_properties.horizontal_radius; } LengthPercentage const& vertical_radius() const { return m_properties.vertical_radius; } bool is_elliptical() const { return m_properties.is_elliptical; } virtual ErrorOr to_string() const override; bool equals(BorderRadiusStyleValue const& other) const { return m_properties == other.m_properties; } private: BorderRadiusStyleValue(LengthPercentage const& horizontal_radius, LengthPercentage const& vertical_radius) : StyleValueWithDefaultOperators(Type::BorderRadius) , m_properties { .is_elliptical = horizontal_radius != vertical_radius, .horizontal_radius = horizontal_radius, .vertical_radius = vertical_radius } { } virtual NonnullRefPtr absolutized(CSSPixelRect const& viewport_rect, Gfx::FontPixelMetrics const& font_metrics, CSSPixels font_size, CSSPixels root_font_size) const override; struct Properties { bool is_elliptical; LengthPercentage horizontal_radius; LengthPercentage vertical_radius; bool operator==(Properties const&) const = default; } m_properties; }; class BorderRadiusShorthandStyleValue final : public StyleValueWithDefaultOperators { public: static NonnullRefPtr create(NonnullRefPtr top_left, NonnullRefPtr top_right, NonnullRefPtr bottom_right, NonnullRefPtr bottom_left) { return adopt_ref(*new BorderRadiusShorthandStyleValue(move(top_left), move(top_right), move(bottom_right), move(bottom_left))); } virtual ~BorderRadiusShorthandStyleValue() override = default; NonnullRefPtr top_left() const { return m_properties.top_left; } NonnullRefPtr top_right() const { return m_properties.top_right; } NonnullRefPtr bottom_right() const { return m_properties.bottom_right; } NonnullRefPtr bottom_left() const { return m_properties.bottom_left; } virtual ErrorOr to_string() const override; bool equals(BorderRadiusShorthandStyleValue const& other) const { return m_properties == other.m_properties; } private: BorderRadiusShorthandStyleValue(NonnullRefPtr top_left, NonnullRefPtr top_right, NonnullRefPtr bottom_right, NonnullRefPtr bottom_left) : StyleValueWithDefaultOperators(Type::BorderRadiusShorthand) , m_properties { .top_left = move(top_left), .top_right = move(top_right), .bottom_right = move(bottom_right), .bottom_left = move(bottom_left) } { } struct Properties { NonnullRefPtr top_left; NonnullRefPtr top_right; NonnullRefPtr bottom_right; NonnullRefPtr bottom_left; bool operator==(Properties const&) const = default; } m_properties; }; class CalculatedStyleValue : public StyleValue { public: enum class ResolvedType { Angle, Frequency, Integer, Length, Number, Percentage, Time, }; enum class SumOperation { Add, Subtract, }; enum class ProductOperation { Multiply, Divide, }; using PercentageBasis = Variant; class CalculationResult { public: using Value = Variant; CalculationResult(Value value) : m_value(move(value)) { } void add(CalculationResult const& other, Layout::Node const*, PercentageBasis const& percentage_basis); void subtract(CalculationResult const& other, Layout::Node const*, PercentageBasis const& percentage_basis); void multiply_by(CalculationResult const& other, Layout::Node const*); void divide_by(CalculationResult const& other, Layout::Node const*); Value const& value() const { return m_value; } private: void add_or_subtract_internal(SumOperation op, CalculationResult const& other, Layout::Node const*, PercentageBasis const& percentage_basis); Value m_value; }; struct CalcSum; struct CalcSumPartWithOperator; struct CalcProduct; struct CalcProductPartWithOperator; struct CalcNumberSum; struct CalcNumberSumPartWithOperator; struct CalcNumberProduct; struct CalcNumberProductPartWithOperator; struct CalcNumberValue { Variant> value; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; }; struct CalcValue { Variant> value; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; bool contains_percentage() const; }; // This represents that: https://www.w3.org/TR/css-values-3/#calc-syntax struct CalcSum { CalcSum(NonnullOwnPtr first_calc_product, NonnullOwnPtrVector additional) : first_calc_product(move(first_calc_product)) , zero_or_more_additional_calc_products(move(additional)) {}; NonnullOwnPtr first_calc_product; NonnullOwnPtrVector zero_or_more_additional_calc_products; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; bool contains_percentage() const; }; struct CalcNumberSum { CalcNumberSum(NonnullOwnPtr first_calc_number_product, NonnullOwnPtrVector additional) : first_calc_number_product(move(first_calc_number_product)) , zero_or_more_additional_calc_number_products(move(additional)) {}; NonnullOwnPtr first_calc_number_product; NonnullOwnPtrVector zero_or_more_additional_calc_number_products; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; }; struct CalcProduct { CalcValue first_calc_value; NonnullOwnPtrVector zero_or_more_additional_calc_values; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; bool contains_percentage() const; }; struct CalcSumPartWithOperator { CalcSumPartWithOperator(SumOperation op, NonnullOwnPtr calc_product) : op(op) , value(move(calc_product)) {}; SumOperation op; NonnullOwnPtr value; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; bool contains_percentage() const; }; struct CalcProductPartWithOperator { ProductOperation op; Variant value; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; bool contains_percentage() const; }; struct CalcNumberProduct { CalcNumberValue first_calc_number_value; NonnullOwnPtrVector zero_or_more_additional_calc_number_values; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; }; struct CalcNumberProductPartWithOperator { ProductOperation op; CalcNumberValue value; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; }; struct CalcNumberSumPartWithOperator { CalcNumberSumPartWithOperator(SumOperation op, NonnullOwnPtr calc_number_product) : op(op) , value(move(calc_number_product)) {}; SumOperation op; NonnullOwnPtr value; ErrorOr to_string() const; Optional resolved_type() const; CalculationResult resolve(Layout::Node const*, PercentageBasis const& percentage_basis) const; }; static NonnullRefPtr create(NonnullOwnPtr calc_sum, ResolvedType resolved_type) { return adopt_ref(*new CalculatedStyleValue(move(calc_sum), resolved_type)); } ErrorOr to_string() const override; virtual bool operator==(StyleValue const& other) const override; ResolvedType resolved_type() const { return m_resolved_type; } NonnullOwnPtr const& expression() const { return m_expression; } bool resolves_to_angle() const { return m_resolved_type == ResolvedType::Angle; } Optional resolve_angle() const; Optional resolve_angle_percentage(Angle const& percentage_basis) const; bool resolves_to_frequency() const { return m_resolved_type == ResolvedType::Frequency; } Optional resolve_frequency() const; Optional resolve_frequency_percentage(Frequency const& percentage_basis) const; bool resolves_to_length() const { return m_resolved_type == ResolvedType::Length; } Optional resolve_length(Layout::Node const& layout_node) const; Optional resolve_length_percentage(Layout::Node const&, Length const& percentage_basis) const; bool resolves_to_percentage() const { return m_resolved_type == ResolvedType::Percentage; } Optional resolve_percentage() const; bool resolves_to_time() const { return m_resolved_type == ResolvedType::Time; } Optional