From 067759c0e907c752c2226af62953cba005da4acd Mon Sep 17 00:00:00 2001 From: MacDue Date: Fri, 28 Oct 2022 20:44:00 +0100 Subject: [PATCH] LibWeb: Add ConicGradientStyleValue This commit adds a simple style value (which is an abstract image) to represent conic-gradient()s. This commit also starts to factor out some reusable parts of the linear-gradient() style value for other gradient types. --- Userland/Libraries/LibWeb/CSS/StyleValue.cpp | 97 +++++++++++++------- Userland/Libraries/LibWeb/CSS/StyleValue.h | 89 ++++++++++++++---- Userland/Libraries/LibWeb/Forward.h | 1 + 3 files changed, 139 insertions(+), 48 deletions(-) diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp index 869cab95c5..8eb5fc8864 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.cpp @@ -90,6 +90,12 @@ ColorStyleValue const& StyleValue::as_color() const return static_cast(*this); } +ConicGradientStyleValue const& StyleValue::as_conic_gradient() const +{ + VERIFY(is_conic_gradient()); + return static_cast(*this); +} + ContentStyleValue const& StyleValue::as_content() const { VERIFY(is_content()); @@ -1697,6 +1703,26 @@ void ImageStyleValue::paint(PaintContext& context, Gfx::IntRect const& dest_rect context.painter().draw_scaled_bitmap(dest_rect, *m_bitmap, m_bitmap->rect(), 1.0f, to_gfx_scaling_mode(image_rendering)); } +static void serialize_color_stop_list(StringBuilder& builder, auto const& color_stop_list) +{ + bool first = true; + for (auto const& element : color_stop_list) { + if (!first) + builder.append(", "sv); + + if (element.transition_hint.has_value()) { + builder.appendff("{}, "sv, element.transition_hint->value.to_string()); + } + + serialize_a_srgb_value(builder, element.color_stop.color); + for (auto position : Array { &element.color_stop.position, &element.color_stop.second_position }) { + if (position->has_value()) + builder.appendff(" {}"sv, (*position)->to_string()); + } + first = false; + } +} + String LinearGradientStyleValue::to_string() const { StringBuilder builder; @@ -1736,22 +1762,7 @@ String LinearGradientStyleValue::to_string() const builder.appendff("{}, "sv, angle.to_string()); }); - bool first = true; - for (auto const& element : m_color_stop_list) { - if (!first) - builder.append(", "sv); - - if (element.transition_hint.has_value()) { - builder.appendff("{}, "sv, element.transition_hint->value.to_string()); - } - - serialize_a_srgb_value(builder, element.color_stop.color); - for (auto position : Array { &element.color_stop.position, &element.color_stop.second_position }) { - if (position->has_value()) - builder.appendff(" {}"sv, (*position)->to_string()); - } - first = false; - } + serialize_color_stop_list(builder, m_color_stop_list); builder.append(")"sv); return builder.to_string(); } @@ -1765,21 +1776,6 @@ static bool operator==(LinearGradientStyleValue::GradientDirection const& a, Lin return false; } -static bool operator==(GradientColorHint const& a, GradientColorHint const& b) -{ - return a.value == b.value; -} - -static bool operator==(GradientColorStop const& a, GradientColorStop const& b) -{ - return a.color == b.color && a.position == b.position && a.second_position == b.second_position; -} - -static bool operator==(ColorStopListElement const& a, ColorStopListElement const& b) -{ - return a.transition_hint == b.transition_hint && a.color_stop == b.color_stop; -} - static bool operator==(EdgeRect const& a, EdgeRect const& b) { return a.top_edge == b.top_edge && a.right_edge == b.right_edge && a.bottom_edge == b.bottom_edge && a.left_edge == b.left_edge; @@ -1857,6 +1853,45 @@ void LinearGradientStyleValue::paint(PaintContext& context, Gfx::IntRect const& Painting::paint_linear_gradient(context, dest_rect, m_resolved->data); } +String ConicGradientStyleValue::to_string() const +{ + StringBuilder builder; + builder.append("conic-gradient("sv); + bool has_from_angle = false; + bool has_at_position = false; + if ((has_from_angle = m_from_angle.to_degrees() != 0)) + builder.appendff("from {}", m_from_angle.to_string()); + if ((has_at_position = m_position != PositionValue::center())) { + if (has_from_angle) + builder.append(' '); + builder.appendff("at "sv); + m_position.serialize(builder); + } + if (has_from_angle || has_at_position) + builder.append(", "sv); + serialize_color_stop_list(builder, m_color_stop_list); + builder.append(')'); + return builder.to_string(); +} + +void ConicGradientStyleValue::resolve_for_size(Layout::Node const&, Gfx::FloatSize const&) const +{ +} + +void ConicGradientStyleValue::paint(PaintContext&, Gfx::IntRect const&, CSS::ImageRendering) const +{ +} + +bool ConicGradientStyleValue::equals(StyleValue const&) const +{ + return false; +} + +float ConicGradientStyleValue::angle_degrees() const +{ + return m_from_angle.to_degrees(); +} + bool InheritStyleValue::equals(StyleValue const& other) const { return type() == other.type(); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h index 991b57a4cf..77a8bc57f2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h @@ -74,21 +74,28 @@ enum class SideOrCorner { BottomRight }; -struct GradientColorStop { - Color color; - Optional position; - Optional second_position = {}; -}; - -struct GradientColorHint { - LengthPercentage value; -}; - +template struct ColorStopListElement { - Optional transition_hint; - GradientColorStop color_stop; + 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; + struct EdgeRect { Length top_edge; Length right_edge; @@ -173,6 +180,7 @@ public: BorderRadiusShorthand, Calculated, Color, + ConicGradient, Content, FilterValueList, Flex, @@ -208,7 +216,7 @@ public: Type type() const { return m_type; } - bool is_abstract_image() const { return AK::first_is_one_of(type(), Type::Image, Type::LinearGradient); } + bool is_abstract_image() const { return AK::first_is_one_of(type(), Type::Image, Type::LinearGradient, Type::ConicGradient); } 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; } @@ -218,6 +226,7 @@ public: 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; } @@ -261,6 +270,7 @@ public: 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; @@ -302,6 +312,7 @@ public: 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()); } @@ -1141,6 +1152,50 @@ private: RefPtr m_bitmap; }; +class ConicGradientStyleValue final : public AbstractImageStyleValue { +public: + static NonnullRefPtr create(Angle from_angle, PositionValue position, Vector color_stop_list) + { + VERIFY(color_stop_list.size() >= 2); + return adopt_ref(*new ConicGradientStyleValue(from_angle, position, move(color_stop_list))); + } + + virtual String to_string() const override; + + void paint(PaintContext&, Gfx::IntRect const& dest_rect, CSS::ImageRendering) const override; + + virtual bool equals(StyleValue const& other) const override; + + Vector const& color_stop_list() const + { + return m_color_stop_list; + } + + float angle_degrees() const; + + bool is_paintable() const override { return true; } + + void resolve_for_size(Layout::Node const&, Gfx::FloatSize const&) const override; + + virtual ~ConicGradientStyleValue() override = default; + + Gfx::FloatPoint resolve_position(Layout::Node const&, Gfx::FloatRect const&) const; + +private: + ConicGradientStyleValue(Angle from_angle, PositionValue position, Vector color_stop_list) + : AbstractImageStyleValue(Type::ConicGradient) + , m_from_angle(from_angle) + , m_position(position) + , m_color_stop_list(move(color_stop_list)) + { + } + + // FIXME: Support + Angle m_from_angle; + PositionValue m_position; + Vector m_color_stop_list; +}; + class LinearGradientStyleValue final : public AbstractImageStyleValue { public: using GradientDirection = Variant; @@ -1155,7 +1210,7 @@ public: No }; - static NonnullRefPtr create(GradientDirection direction, Vector color_stop_list, GradientType type, Repeating repeating) + static NonnullRefPtr create(GradientDirection direction, Vector color_stop_list, GradientType type, Repeating repeating) { VERIFY(color_stop_list.size() >= 2); return adopt_ref(*new LinearGradientStyleValue(direction, move(color_stop_list), type, repeating)); @@ -1165,7 +1220,7 @@ public: virtual ~LinearGradientStyleValue() override = default; virtual bool equals(StyleValue const& other) const override; - Vector const& color_stop_list() const + Vector const& color_stop_list() const { return m_color_stop_list; } @@ -1180,7 +1235,7 @@ public: void paint(PaintContext& context, Gfx::IntRect const& dest_rect, CSS::ImageRendering image_rendering) const override; private: - LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list, GradientType type, Repeating repeating) + LinearGradientStyleValue(GradientDirection direction, Vector color_stop_list, GradientType type, Repeating repeating) : AbstractImageStyleValue(Type::LinearGradient) , m_direction(direction) , m_color_stop_list(move(color_stop_list)) @@ -1190,7 +1245,7 @@ private: } GradientDirection m_direction; - Vector m_color_stop_list; + Vector m_color_stop_list; GradientType m_gradient_type; Repeating m_repeating; diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index e39ecebdee..053690612d 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -36,6 +36,7 @@ class BorderStyleValue; class Clip; class CalculatedStyleValue; class ColorStyleValue; +class ConicGradientStyleValue; class ContentStyleValue; class CSSConditionRule; class CSSGroupingRule;