From 46f42d9755650b4187b67fbdd70f0dac167eb4af Mon Sep 17 00:00:00 2001 From: MacDue Date: Sun, 20 Aug 2023 15:45:02 +0100 Subject: [PATCH] LibWeb: Add support for the SVG gradient spreadMethod attribute --- .../Libraries/LibWeb/SVG/AttributeParser.cpp | 15 +++++++++++++++ Userland/Libraries/LibWeb/SVG/AttributeParser.h | 7 +++++++ .../Libraries/LibWeb/SVG/SVGGradientElement.cpp | 11 +++++++++++ .../Libraries/LibWeb/SVG/SVGGradientElement.h | 17 +++++++++++++++++ .../LibWeb/SVG/SVGLinearGradientElement.cpp | 1 + .../LibWeb/SVG/SVGRadialGradientElement.cpp | 1 + 6 files changed, 52 insertions(+) diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp index d219c97571..f4149eb2a5 100644 --- a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp @@ -509,6 +509,21 @@ Optional AttributeParser::parse_gradient_units(StringView input) return {}; } +// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementSpreadMethodAttribute +Optional AttributeParser::parse_spread_method(StringView input) +{ + GenericLexer lexer { input }; + lexer.ignore_while(whitespace); + auto spread_method_string = lexer.consume_until(whitespace); + if (spread_method_string == "pad"sv) + return SpreadMethod::Pad; + if (spread_method_string == "repeat"sv) + return SpreadMethod::Repeat; + if (spread_method_string == "reflect"sv) + return SpreadMethod::Reflect; + return {}; +} + // https://drafts.csswg.org/css-transforms/#svg-syntax Optional> AttributeParser::parse_transform() { diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.h b/Userland/Libraries/LibWeb/SVG/AttributeParser.h index de1c72d22f..773e886970 100644 --- a/Userland/Libraries/LibWeb/SVG/AttributeParser.h +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.h @@ -93,6 +93,12 @@ enum class GradientUnits { UserSpaceOnUse }; +enum class SpreadMethod { + Pad, + Repeat, + Reflect +}; + class NumberPercentage { public: NumberPercentage(float value, bool is_percentage) @@ -144,6 +150,7 @@ public: static Optional> parse_transform(StringView input); static Optional parse_preserve_aspect_ratio(StringView input); static Optional parse_gradient_units(StringView input); + static Optional parse_spread_method(StringView input); private: AttributeParser(StringView source); diff --git a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp index 6e403c4069..972986bcca 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp @@ -22,6 +22,8 @@ void SVGGradientElement::attribute_changed(DeprecatedFlyString const& name, Depr SVGElement::attribute_changed(name, value); if (name == AttributeNames::gradientUnits) { m_gradient_units = AttributeParser::parse_gradient_units(value); + } else if (name == AttributeNames::spreadMethod) { + m_spread_method = AttributeParser::parse_spread_method(value); } else if (name == AttributeNames::gradientTransform) { if (auto transform_list = AttributeParser::parse_transform(value); transform_list.has_value()) { m_gradient_transform = transform_from_transform_list(*transform_list); @@ -40,6 +42,15 @@ GradientUnits SVGGradientElement::gradient_units() const return GradientUnits::ObjectBoundingBox; } +SpreadMethod SVGGradientElement::spread_method() const +{ + if (m_spread_method.has_value()) + return *m_spread_method; + if (auto gradient = linked_gradient()) + return gradient->spread_method(); + return SpreadMethod::Pad; +} + Optional SVGGradientElement::gradient_transform() const { if (m_gradient_transform.has_value()) diff --git a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h index 536d49038d..b4feb74b8b 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h @@ -20,6 +20,20 @@ struct SVGPaintContext { Gfx::AffineTransform transform; }; +inline Gfx::SVGGradientPaintStyle::SpreadMethod to_gfx_spread_method(SpreadMethod spread_method) +{ + switch (spread_method) { + case SpreadMethod::Pad: + return Gfx::SVGGradientPaintStyle::SpreadMethod::Pad; + case SpreadMethod::Reflect: + return Gfx::SVGGradientPaintStyle::SpreadMethod::Reflect; + case SpreadMethod::Repeat: + return Gfx::SVGGradientPaintStyle::SpreadMethod::Repeat; + default: + VERIFY_NOT_REACHED(); + } +} + class SVGGradientElement : public SVGElement { WEB_PLATFORM_OBJECT(SVGGradientElement, SVGElement); @@ -32,6 +46,8 @@ public: GradientUnits gradient_units() const; + SpreadMethod spread_method() const; + Optional gradient_transform() const; protected: @@ -61,6 +77,7 @@ protected: private: Optional m_gradient_units = {}; + Optional m_spread_method = {}; Optional m_gradient_transform = {}; }; diff --git a/Userland/Libraries/LibWeb/SVG/SVGLinearGradientElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGLinearGradientElement.cpp index 9a2363f04a..de2bee93ca 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGLinearGradientElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGLinearGradientElement.cpp @@ -131,6 +131,7 @@ Optional SVGLinearGradientElement::to_gfx_paint_style(SV } m_paint_style->set_gradient_transform(gradient_paint_transform(paint_context)); + m_paint_style->set_spread_method(to_gfx_spread_method(spread_method())); return *m_paint_style; } diff --git a/Userland/Libraries/LibWeb/SVG/SVGRadialGradientElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGRadialGradientElement.cpp index 935442662a..9a7fa7181c 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGRadialGradientElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGRadialGradientElement.cpp @@ -172,6 +172,7 @@ Optional SVGRadialGradientElement::to_gfx_paint_style(SV m_paint_style->set_end_radius(end_radius); } m_paint_style->set_gradient_transform(gradient_paint_transform(paint_context)); + m_paint_style->set_spread_method(to_gfx_spread_method(spread_method())); return *m_paint_style; }