diff --git a/Tests/LibWeb/Screenshot/images/svg-gradient-spreadMethod-ref.png b/Tests/LibWeb/Screenshot/images/svg-gradient-spreadMethod-ref.png index 1a141b4f9b7..7dead8f9ed8 100644 Binary files a/Tests/LibWeb/Screenshot/images/svg-gradient-spreadMethod-ref.png and b/Tests/LibWeb/Screenshot/images/svg-gradient-spreadMethod-ref.png differ diff --git a/Tests/LibWeb/Screenshot/images/svg-gradient-userSpaceOnUse-ref.png b/Tests/LibWeb/Screenshot/images/svg-gradient-userSpaceOnUse-ref.png new file mode 100644 index 00000000000..c849fa4fe56 Binary files /dev/null and b/Tests/LibWeb/Screenshot/images/svg-gradient-userSpaceOnUse-ref.png differ diff --git a/Tests/LibWeb/Screenshot/images/svg-radialGradient-ref.png b/Tests/LibWeb/Screenshot/images/svg-radialGradient-ref.png index 428658e0d2b..d5ae90402c9 100644 Binary files a/Tests/LibWeb/Screenshot/images/svg-radialGradient-ref.png and b/Tests/LibWeb/Screenshot/images/svg-radialGradient-ref.png differ diff --git a/Tests/LibWeb/Screenshot/images/svg-text-effects-ref.png b/Tests/LibWeb/Screenshot/images/svg-text-effects-ref.png index a77db2f562b..1abce3203ae 100644 Binary files a/Tests/LibWeb/Screenshot/images/svg-text-effects-ref.png and b/Tests/LibWeb/Screenshot/images/svg-text-effects-ref.png differ diff --git a/Tests/LibWeb/Screenshot/reference/svg-gradient-userSpaceOnUse-ref.html b/Tests/LibWeb/Screenshot/reference/svg-gradient-userSpaceOnUse-ref.html new file mode 100644 index 00000000000..5d8b972be61 --- /dev/null +++ b/Tests/LibWeb/Screenshot/reference/svg-gradient-userSpaceOnUse-ref.html @@ -0,0 +1,9 @@ + + diff --git a/Tests/LibWeb/Screenshot/svg-gradient-userSpaceOnUse.html b/Tests/LibWeb/Screenshot/svg-gradient-userSpaceOnUse.html new file mode 100644 index 00000000000..1b0d2a4dba3 --- /dev/null +++ b/Tests/LibWeb/Screenshot/svg-gradient-userSpaceOnUse.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Userland/Libraries/LibGfx/PaintStyle.h b/Userland/Libraries/LibGfx/PaintStyle.h index 073d8d2399e..9d227d2ae0a 100644 --- a/Userland/Libraries/LibGfx/PaintStyle.h +++ b/Userland/Libraries/LibGfx/PaintStyle.h @@ -324,9 +324,6 @@ public: m_spread_method = spread_method; } - void set_inverse_transform(AffineTransform transform) { m_inverse_transform = transform; } - void set_scale(float scale) { m_scale = scale; } - protected: Optional const& scale_adjusted_inverse_gradient_transform() const { return m_inverse_transform; } float gradient_transform_scale() const { return m_scale; } diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index a351798e2e5..cf90c6fde2f 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -591,7 +591,6 @@ set(SOURCES Painting/MediaPaintable.cpp Painting/NestedBrowsingContextPaintable.cpp Painting/PaintContext.cpp - Painting/PaintStyle.cpp Painting/Paintable.cpp Painting/PaintableBox.cpp Painting/PaintableFragment.cpp diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index 006ccd70e08..24647001120 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -937,43 +937,34 @@ static SkPaint paint_style_to_skia_paint(Painting::SVGGradientPaintStyle const& positions.append(color_stop.position); } + SkMatrix matrix; + matrix.setTranslate(bounding_rect.x(), bounding_rect.y()); + if (auto gradient_transform = paint_style.gradient_transform(); gradient_transform.has_value()) + matrix = matrix * to_skia_matrix(gradient_transform.value()); + + auto tile_mode = to_skia_tile_mode(paint_style.spread_method()); + + sk_sp shader; if (is(paint_style)) { auto const& linear_gradient_paint_style = static_cast(paint_style); - SkMatrix matrix; - auto scale = linear_gradient_paint_style.scale(); - auto start_point = linear_gradient_paint_style.start_point().scaled(scale); - auto end_point = linear_gradient_paint_style.end_point().scaled(scale); - - start_point.translate_by(bounding_rect.location()); - end_point.translate_by(bounding_rect.location()); - - Array points; - points[0] = to_skia_point(start_point); - points[1] = to_skia_point(end_point); - - auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), positions.data(), color_stops.size(), to_skia_tile_mode(paint_style.spread_method()), 0, &matrix); - paint.setShader(shader); + Array points { + to_skia_point(linear_gradient_paint_style.start_point()), + to_skia_point(linear_gradient_paint_style.end_point()), + }; + shader = SkGradientShader::MakeLinear(points.data(), colors.data(), positions.data(), color_stops.size(), tile_mode, 0, &matrix); } else if (is(paint_style)) { auto const& radial_gradient_paint_style = static_cast(paint_style); - SkMatrix matrix; - auto scale = radial_gradient_paint_style.scale(); + auto start_center = to_skia_point(radial_gradient_paint_style.start_center()); + auto end_center = to_skia_point(radial_gradient_paint_style.end_center()); - auto start_center = radial_gradient_paint_style.start_center().scaled(scale); - auto end_center = radial_gradient_paint_style.end_center().scaled(scale); - auto start_radius = radial_gradient_paint_style.start_radius() * scale; - auto end_radius = radial_gradient_paint_style.end_radius() * scale; + auto start_radius = radial_gradient_paint_style.start_radius(); + auto end_radius = radial_gradient_paint_style.end_radius(); - start_center.translate_by(bounding_rect.location()); - end_center.translate_by(bounding_rect.location()); - - auto start_sk_point = to_skia_point(start_center); - auto end_sk_point = to_skia_point(end_center); - - auto shader = SkGradientShader::MakeTwoPointConical(start_sk_point, start_radius, end_sk_point, end_radius, colors.data(), positions.data(), color_stops.size(), to_skia_tile_mode(paint_style.spread_method()), 0, &matrix); - paint.setShader(shader); + shader = SkGradientShader::MakeTwoPointConical(start_center, start_radius, end_center, end_radius, colors.data(), positions.data(), color_stops.size(), tile_mode, 0, &matrix); } + paint.setShader(shader); return paint; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintStyle.cpp b/Userland/Libraries/LibWeb/Painting/PaintStyle.cpp deleted file mode 100644 index a5ebecc8763..00000000000 --- a/Userland/Libraries/LibWeb/Painting/PaintStyle.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2024, Aliaksandr Kalenik - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace Web::Painting { - -void SVGGradientPaintStyle::set_gradient_transform(Gfx::AffineTransform transform) -{ - // Note: The scaling is removed so enough points on the gradient line are generated. - // Otherwise, if you scale a tiny path the gradient looks pixelated. - m_scale = 1.0f; - if (auto inverse = transform.inverse(); inverse.has_value()) { - auto transform_scale = transform.scale(); - m_scale = max(transform_scale.x(), transform_scale.y()); - m_inverse_transform = Gfx::AffineTransform {}.scale(m_scale, m_scale).multiply(*inverse); - } else { - m_inverse_transform = OptionalNone {}; - } -} - -} diff --git a/Userland/Libraries/LibWeb/Painting/PaintStyle.h b/Userland/Libraries/LibWeb/Painting/PaintStyle.h index 0a3aae9bd17..188a86af6e7 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintStyle.h +++ b/Userland/Libraries/LibWeb/Painting/PaintStyle.h @@ -20,19 +20,17 @@ struct ColorStop { class SVGGradientPaintStyle : public RefCounted { public: - void set_gradient_transform(Gfx::AffineTransform transform); - enum class SpreadMethod { Pad, Repeat, Reflect }; - void set_spread_method(SpreadMethod spread_method) { m_spread_method = spread_method; } + Optional const& gradient_transform() const { return m_gradient_transform; } + void set_gradient_transform(Gfx::AffineTransform transform) { m_gradient_transform = transform; } - Optional const& scale_adjusted_inverse_gradient_transform() const { return m_inverse_transform; } - float gradient_transform_scale() const { return m_scale; } SpreadMethod spread_method() const { return m_spread_method; } + void set_spread_method(SpreadMethod spread_method) { m_spread_method = spread_method; } void add_color_stop(float position, Color color, Optional transition_hint = {}) { @@ -49,16 +47,13 @@ public: ReadonlySpan color_stops() const { return m_color_stops; } Optional repeat_length() const { return m_repeat_length; } - float scale() const { return m_scale; } - virtual ~SVGGradientPaintStyle() {}; protected: Vector m_color_stops; Optional m_repeat_length; - Optional m_inverse_transform {}; - float m_scale { 1.0f }; + Optional m_gradient_transform {}; SpreadMethod m_spread_method { SpreadMethod::Pad }; }; diff --git a/Userland/Libraries/LibWeb/Painting/SVGPathPaintable.cpp b/Userland/Libraries/LibWeb/Painting/SVGPathPaintable.cpp index cdee8fe5b03..1b1045c3ce5 100644 --- a/Userland/Libraries/LibWeb/Painting/SVGPathPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/SVGPathPaintable.cpp @@ -106,7 +106,6 @@ void SVGPathPaintable::paint(PaintContext& context, PaintPhase phase) const SVG::SVGPaintContext paint_context { .viewport = svg_viewport, .path_bounding_box = computed_path()->bounding_box(), - .transform = paint_transform }; auto fill_opacity = graphics_element.fill_opacity().value_or(1); diff --git a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp index 9b1186fef9d..f3bd4904c0a 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp @@ -83,15 +83,21 @@ Optional SVGGradientElement::gradient_transform_impl(HashT // The gradient transform, appropriately scaled and combined with the paint transform. Gfx::AffineTransform SVGGradientElement::gradient_paint_transform(SVGPaintContext const& paint_context) const { - auto transform = gradient_transform().value_or(Gfx::AffineTransform {}); - if (gradient_units() == GradientUnits::ObjectBoundingBox) { - // Adjust transform to take place in the coordinate system defined by the bounding box: - return Gfx::AffineTransform { paint_context.transform } - .translate(paint_context.path_bounding_box.location()) - .scale(paint_context.path_bounding_box.width(), paint_context.path_bounding_box.height()) - .multiply(transform); + Gfx::AffineTransform gradient_paint_transform; + auto const& bounding_box = paint_context.path_bounding_box; + + if (gradient_units() == SVGUnits::ObjectBoundingBox) { + // Scale points from 0..1 to bounding box coordinates: + gradient_paint_transform.scale(bounding_box.width(), bounding_box.height()); + } else { + // Translate points from viewport to bounding box coordinates: + gradient_paint_transform.translate(paint_context.viewport.location() - bounding_box.location()); } - return Gfx::AffineTransform { paint_context.transform }.multiply(transform); + + if (auto transform = gradient_transform(); transform.has_value()) + gradient_paint_transform.multiply(transform.value()); + + return gradient_paint_transform; } void SVGGradientElement::add_color_stops(Painting::SVGGradientPaintStyle& paint_style) const diff --git a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h index bbc05d9421a..8365179e7b7 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.h @@ -19,7 +19,6 @@ namespace Web::SVG { struct SVGPaintContext { Gfx::FloatRect viewport; Gfx::FloatRect path_bounding_box; - Gfx::AffineTransform transform; }; inline Painting::SVGGradientPaintStyle::SpreadMethod to_painting_spread_method(SpreadMethod spread_method)