LibWeb: Paint replaced backgrounds in SVG foreignObject

Paint the background phase for replaced boxes reached through SVG
foreignObject traversal before foreground content. This lets img
background images render correctly when the containing SVG establishes a
stacking context.

Add a ref test for a paint-contained SVG with a foreignObject-hosted img
that uses a transparent SVG source and a CSS background image.
This commit is contained in:
Andreas Kling 2026-05-30 18:01:40 +02:00 committed by Andreas Kling
parent 44205cd086
commit 3d3136f60d
3 changed files with 65 additions and 0 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Layout/ReplacedBox.h>
#include <LibWeb/Painting/DisplayList.h>
#include <LibWeb/Painting/DisplayListRecorder.h>
#include <LibWeb/Painting/SVGSVGPaintable.h>
@ -74,6 +75,10 @@ void SVGSVGPaintable::paint_svg_box(DisplayListRecordingContext& context, Painta
svg_box.record_hit_test_items(context, phase);
if (svg_box.layout_node().is_svg_foreign_object_box())
record_foreign_object_descendant_hit_test_items(context, svg_box);
if (!svg_box.is_svg_paintable()
&& !svg_box.is_svg_svg_paintable()
&& is<Layout::ReplacedBox>(svg_box.layout_node()))
svg_box.paint(context, PaintPhase::Background);
svg_box.paint(context, PaintPhase::Foreground);
paint_descendants(context, svg_box, phase);
}

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<style>
body {
margin: 0;
background: red;
}
.expected {
position: absolute;
left: 10px;
top: 10px;
width: 80px;
height: 80px;
background: linear-gradient(135deg, green, blue);
}
</style>
<div class="expected"></div>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<link rel="match" href="../expected/svg-foreignobject-replaced-background-in-paint-contained-svg-ref.html" />
<style>
body {
margin: 0;
background: red;
}
.host {
position: relative;
width: 100px;
height: 100px;
}
svg {
contain: paint;
position: absolute;
left: 10px;
top: 10px;
}
.stack {
display: grid;
width: 80px;
height: 80px;
}
img {
grid-area: 1 / 1;
width: 80px;
height: 80px;
background: linear-gradient(135deg, green, blue);
}
</style>
<div class="host">
<svg width="80" height="80" viewBox="0 0 80 80">
<foreignObject x="0" y="0" width="80" height="80">
<div class="stack">
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80'%3E%3C/svg%3E">
</div>
</foreignObject>
</svg>
</div>