LibWeb/SVG: Skip unwanted transformations on clip-path

This commit is contained in:
Gingeh 2025-01-08 14:44:00 +11:00 committed by Alexander Kalenik
commit 93f9ed72d2
Notes: github-actions[bot] 2025-02-01 12:39:52 +00:00
5 changed files with 44 additions and 6 deletions

View file

@ -87,7 +87,15 @@ RefPtr<Gfx::ImmutableBitmap> SVGMaskable::calculate_mask_of_svg(PaintContext& co
DisplayListRecorder display_list_recorder(*display_list); DisplayListRecorder display_list_recorder(*display_list);
display_list_recorder.translate(-mask_rect.location().to_type<int>()); display_list_recorder.translate(-mask_rect.location().to_type<int>());
auto paint_context = context.clone(display_list_recorder); auto paint_context = context.clone(display_list_recorder);
paint_context.set_svg_transform(graphics_element.get_transform()); auto const& mask_element = as<SVG::SVGGraphicsElement const>(*paintable.dom_node());
// FIXME: Nested transformations are incorrect when clipPathUnits="objectBoundingBox".
paint_context.set_svg_transform(
// Transform the mask's content into the target's space.
graphics_element.get_transform()
// Undo any transformations already applied to the mask's parents.
.multiply(mask_element.get_transform().inverse().value())
// Re-apply the mask's own transformation since that is still needed.
.multiply(mask_element.element_transform()));
paint_context.set_draw_svg_geometry_for_clip_path(is<SVGClipPaintable>(paintable)); paint_context.set_draw_svg_geometry_for_clip_path(is<SVGClipPaintable>(paintable));
StackingContext::paint_svg(paint_context, paintable, PaintPhase::Foreground); StackingContext::paint_svg(paint_context, paintable, PaintPhase::Foreground);
auto painting_surface = Gfx::PaintingSurface::wrap_bitmap(*mask_bitmap); auto painting_surface = Gfx::PaintingSurface::wrap_bitmap(*mask_bitmap);

View file

@ -67,16 +67,16 @@ public:
GC::Ptr<Geometry::DOMMatrix> get_screen_ctm(); GC::Ptr<Geometry::DOMMatrix> get_screen_ctm();
protected:
SVGGraphicsElement(DOM::Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;
virtual Gfx::AffineTransform element_transform() const virtual Gfx::AffineTransform element_transform() const
{ {
return m_transform; return m_transform;
} }
protected:
SVGGraphicsElement(DOM::Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;
Optional<Painting::PaintStyle> svg_paint_computed_value_to_gfx_paint_style(SVGPaintContext const& paint_context, Optional<CSS::SVGPaint> const& paint_value) const; Optional<Painting::PaintStyle> svg_paint_computed_value_to_gfx_paint_style(SVGPaintContext const& paint_context, Optional<CSS::SVGPaint> const& paint_value) const;
Gfx::AffineTransform m_transform = {}; Gfx::AffineTransform m_transform = {};

View file

@ -0,0 +1,10 @@
<style>
* {
margin: 0;
}
body {
background-color: white;
}
</style>
<img src="../images/svg-clip-path-transform-ref.png">

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -0,0 +1,20 @@
<link rel="match" href="../expected/svg-clip-path-transform-ref.html" />
<svg>
<g id="root" transform="scale(.5 .5)">
<g id="maskContainer" transform="scale(.5 2)">
<clipPath id="maskGroup" transform="translate(0,20)">
<path id="maskPath" d="M0 0h100v100H0z" />
</clipPath>
</g>
<g id="targetContainer" transform="rotate(5)">
<g transform="translate(20,0)">
<path d="M0 0h100v100H0z" style="fill:red" />
<path d="M0 100h100v100H0z" style="fill:red" />
</g>
<g id="targetGroup" clip-path="url(#maskGroup)" transform="translate(20,0)">
<path id="targetPath1" d="M0 0h100v100H0z" style="fill:green" />
<path id="targetPath2" d="M0 100h100v100H0z" style="fill:blue" />
</g>
</g>
</g>
</svg>