LibWeb: Resolve SVG gradient references within shadow trees

Previously, the `linked_gradient()` lookup only searched the document
for gradient IDs, so gradients inheriting stops via href inside a
shadow DOM would fail to find the correct target and be rendered black.
We now check any containing shadow root first, before checking the
document for linked gradient IDs.
This commit is contained in:
Tim Ledbetter 2026-05-27 08:40:27 +01:00 committed by Andreas Kling
parent 402e151b62
commit b0f926d16b
3 changed files with 27 additions and 2 deletions

View file

@ -132,7 +132,6 @@ void SVGGradientElement::add_color_stops(Painting::GradientPaintStyle& paint_sty
GC::Ptr<SVGGradientElement const> SVGGradientElement::linked_gradient(GC::RootHashTable<SVGGradientElement const*>& seen_gradients) const
{
// FIXME: This entire function is an ad-hoc hack!
// It can only resolve #<ids> in the same document.
auto link = has_attribute(AttributeNames::href) ? get_attribute(AttributeNames::href) : get_attribute("xlink:href"_fly_string);
if (auto href = link; href.has_value() && !link->is_empty()) {
@ -142,7 +141,11 @@ GC::Ptr<SVGGradientElement const> SVGGradientElement::linked_gradient(GC::RootHa
auto id = url->fragment();
if (!id.has_value() || id->is_empty())
return {};
auto element = document().get_element_by_id(id.value());
GC::Ptr<DOM::Element> element;
if (auto containing_shadow = containing_shadow_root())
element = containing_shadow->get_element_by_id(id.value());
if (!element)
element = document().get_element_by_id(id.value());
if (!element)
return {};
if (element == this)

View file

@ -0,0 +1,4 @@
<!DOCTYPE html>
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="green"/>
</svg>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<link rel="match" href="../../expected/svg/gradient-in-shadow-dom-ref.html" />
<div id="host"></div>
<script>
const host = document.getElementById('host');
const shadow = host.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="base" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="green"/>
<stop offset="1" stop-color="green"/>
</linearGradient>
<linearGradient id="ref" href="#base"/>
</defs>
<rect width="100" height="100" fill="url(#ref)"/>
</svg>`;
</script>