LibWeb: Don't crash from svg mask reference cycles

This commit is contained in:
Gingeh
2025-12-18 16:26:19 +11:00
committed by Andreas Kling
parent 7f709c6502
commit 690c48d912
5 changed files with 62 additions and 0 deletions

View File

@@ -833,6 +833,15 @@ void TreeBuilder::update_layout_tree_after_children(DOM::Node& dom_node, GC::Ref
auto layout_mask_or_clip_path = [&](GC::Ptr<SVG::SVGElement const> mask_or_clip_path) {
TemporaryChange<bool> layout_mask(context.layout_svg_mask_or_clip_path, true);
push_parent(as<NodeWithStyle>(*layout_node));
// Check for reference cycle
for (GC::Ref<NodeWithStyle> ancestor : m_ancestor_stack) {
if (ancestor->dom_node() == mask_or_clip_path) {
// FIXME: Somehow either remove ancestor from the layout tree or mark it as invalid.
pop_parent();
return;
}
}
update_layout_tree(const_cast<SVG::SVGElement&>(*mask_or_clip_path), context, MustCreateSubtree::Yes);
pop_parent();
};

View File

@@ -118,6 +118,9 @@ RefPtr<Gfx::ImmutableBitmap> SVGMaskable::calculate_mask_of_svg(DisplayListRecor
if (!mask_bitmap)
mask_bitmap = clip_bitmap;
}
if (!mask_bitmap)
return nullptr;
return Gfx::ImmutableBitmap::create(*mask_bitmap);
}

View File

@@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip0">
<rect width="1" height="1" clip-path="url(#clip)" />
</clipPath>
<clipPath id="clip2">
<rect width="100" height="100" clip-path="url(#clip0)"/>
</clipPath>
<clipPath id="clip">
<rect width="1" height="1" clip-path="url(#clip2)"/>
</clipPath>
<mask id="mask1" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox">
<rect width="1" height="1" clip-path="url(#clip)" />
</mask>
</defs>
<circle r="500" mask="url(#mask1)"/>
</svg>

After

Width:  |  Height:  |  Size: 520 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="50" width="50" height="50" fill="red" />
<rect x="50" y="150" width="50" height="50" fill="red"/>
</svg>

After

Width:  |  Height:  |  Size: 242 B

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="testmeta">
<title>CSS Masking: clipPath recursion 2</title>
<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/>
<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/>
<html:link rel="match" href="../../../../../expected/wpt-import/css/css-masking/clip-path-svg-content/reference/clip-path-recursion-002-ref.svg" />
<metadata class="flags">svg</metadata>
<desc class="assert">
A clipPath recursion counts as invalid clipping path.
</desc>
</g>
<defs>
<rect x="50" y="150" width="50" height="50" id="rect" fill="none" clip-path="url(#clipPath_1)"/>
</defs>
<clipPath id="clipPath_0">
<rect x="50" width="50" height="50" clip-path="url(#clipPath_0)"/>
</clipPath>
<clipPath id="clipPath_1">
<use xlink:href="#rect"/>
</clipPath>
<rect x="50" width="100" height="100" fill="red" clip-path="url(#clipPath_0)"/>
<rect x="50" y="150" width="100" height="100" fill="red" clip-path="url(#clipPath_1)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB