Files
ladybird/Tests/LibWeb/Text/input/SVG/svg-foreignobject-abspos-outside-cb-text-change.html
Aliaksandr Kalenik 01334c4481 LibWeb: Fix partial relayout of abspos with containing block outside SVG
When a text node changes inside an absolutely positioned element within
an SVG <foreignObject>, and the abspos element's containing block is
outside the SVG subtree, the layout invalidation was incorrectly
stopping at the SVG root boundary. This triggered partial SVG relayout,
which cannot re-layout the abspos element since it's laid out by its
containing block's formatting context (outside the SVG).

The previous check only tested whether `this` (the node triggering
invalidation, e.g. a text node) was absolutely positioned, missing the
case where an abspos *ancestor* in the path has its containing block
outside the SVG. Fix this by walking from `this` up to the SVG root and
checking every abspos node in the path. If any has a containing block
outside the SVG subtree, skip the SVG boundary so layout propagation
continues upward and a full layout runs.
2026-02-13 17:47:49 +01:00

47 lines
1.4 KiB
HTML

<!DOCTYPE html>
<script src="../include.js"></script>
<style>
html, body { margin: 0; }
.container {
position: relative;
width: 300px;
height: 200px;
}
.abspos {
position: absolute;
left: 10px;
top: 10px;
white-space: nowrap;
background: #8f8;
}
</style>
<div class="container">
<svg width="100" height="100">
<foreignObject width="100" height="100">
<div class="abspos" id="abspos"><span id="text">short</span></div>
</foreignObject>
</svg>
</div>
<script>
asyncTest(done => {
const abspos = document.getElementById("abspos");
const text = document.getElementById("text");
document.body.offsetWidth;
const before = abspos.getBoundingClientRect();
// This mutates a text node inside an abspos element whose containing
// block is outside the SVG subtree.
text.firstChild.data = "this is a much much longer text inside abspos";
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const after = abspos.getBoundingClientRect();
println(`width-grew=${after.width > before.width}`);
println(`position-stable=${after.x === before.x && after.y === before.y}`);
done();
});
});
});
</script>