LibWeb: Resolve mask/clip in foreignObject's own coordinate space

We were neglecting to resolve these correctly, which caused them to get
the same metrics as the nearest viewport above the foreignObject.
This commit is contained in:
Andreas Kling 2025-07-09 13:18:29 +02:00 committed by Andreas Kling
commit aae0b52403
Notes: github-actions[bot] 2025-07-09 12:37:30 +00:00
3 changed files with 35 additions and 4 deletions

View file

@ -295,10 +295,11 @@ void SVGFormattingContext::layout_svg_element(Box const& child)
child_state.set_content_offset(transformed_rect.location());
child_state.set_content_width(transformed_rect.width());
child_state.set_content_height(transformed_rect.height());
child.for_each_child_of_type<SVGMaskBox>([&](SVGMaskBox const& child) {
layout_svg_element(child);
return IterationDecision::Continue;
});
if (auto* mask_box = child.first_child_of_type<SVGMaskBox>())
layout_mask_or_clip(*mask_box);
if (auto* clip_box = child.first_child_of_type<SVGClipBox>())
layout_mask_or_clip(*clip_box);
} else if (is<SVGGraphicsBox>(child)) {
layout_graphics_element(static_cast<SVGGraphicsBox const&>(child));
}

View file

@ -0,0 +1,22 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x116 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x100 children: inline
frag 0 from SVGSVGBox start: 0, length: 0, rect: [8,8 100x100] baseline: 100
SVGSVGBox <svg> at (8,8) content-size 800x800 positioned [SVG] children: not-inline
SVGSVGBox <svg> at (8,8) content-size 100x100 [SVG] children: not-inline
SVGForeignObjectBox <foreignObject> at (8,8) content-size 40x40 [BFC] children: not-inline
BlockContainer <div#lol> at (8,8) content-size 100x100 children: not-inline
SVGMaskBox <mask#theMask> at (8,8) content-size 40x40 children: not-inline
SVGGeometryBox <circle> at (8,8) content-size 40x40 children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 808x808]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x116]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x100]
SVGSVGPaintable (SVGSVGBox<svg>) [8,8 800x800]
SVGSVGPaintable (SVGSVGBox<svg>) [8,8 100x100]
SVGForeignObjectPaintable (SVGForeignObjectBox<foreignObject>) [8,8 40x40] overflow: [8,8 100x100]
PaintableWithLines (BlockContainer<DIV>#lol) [8,8 100x100]
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x116] [children: 1] (z-index: auto)
SC for SVGForeignObjectBox<foreignObject> [8,8 40x40] [children: 0] (z-index: auto)

View file

@ -0,0 +1,8 @@
<!doctype html><style>
* { outline: 1px solid black; }
#lol {
width: 100px;
height: 100px;
background: orange;
}
</style><body><svg viewBox="0 0 1 1" style="position:absolute;"><mask id="theMask" maskContentUnits="objectBoundingBox"><circle fill="white" cx="0.5" cy="0.5" r="0.5"></circle></mask></svg><svg width="100" height="100" viewBox="0 0 100 100"><foreignObject x="0" y="0" width="40" height="40" mask="url(#theMask)"><div id="lol"></div></foreignObject></svg>