LibWeb/SVG: Percent-decode same-document <use> href fragments

`SVGUseElement::referenced_element()` previously passed
`m_href->fragment()` directly to `Document::get_element_by_id()`. URL
fragments are stored in their serialized form, so references to elements
whose IDs contain non-ASCII characters would fail to resolve.
This commit is contained in:
Aliaksandr Kalenik
2025-12-22 16:18:11 +01:00
committed by Alexander Kalenik
parent 0dff009b41
commit defbd0ec05
3 changed files with 53 additions and 3 deletions

View File

@@ -124,7 +124,8 @@ void SVGUseElement::svg_element_removed(SVGElement& svg_element)
return;
}
if (AK::StringUtils::matches(svg_element.get_attribute_value("id"_fly_string), m_href->fragment().value())) {
auto id = String::from_utf8_with_replacement_character(URL::percent_decode(*m_href->fragment()), String::WithBOMHandling::No);
if (AK::StringUtils::matches(svg_element.get_attribute_value("id"_fly_string), id)) {
shadow_root()->remove_all_children();
}
}
@@ -138,8 +139,10 @@ GC::Ptr<DOM::Element> SVGUseElement::referenced_element()
if (!m_href->fragment().has_value())
return nullptr;
if (is_referenced_element_same_document())
return document().get_element_by_id(*m_href->fragment());
if (is_referenced_element_same_document()) {
auto id = String::from_utf8_with_replacement_character(URL::percent_decode(*m_href->fragment()), String::WithBOMHandling::No);
return document().get_element_by_id(id);
}
if (!m_resource_request)
return nullptr;

View File

@@ -0,0 +1,32 @@
Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] [BFC] children: not-inline
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 64 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 48 0+0+8] children: inline
frag 0 from SVGSVGBox start: 0, length: 0, rect: [8,8 48x48] baseline: 48
SVGSVGBox <svg> at [8,8] [0+0+0 48 0+0+0] [0+0+0 48 0+0+0] [SVG] children: inline
TextNode <#text> (not painted)
TextNode <#text> (not painted)
TextNode <#text> (not painted)
SVGForeignObjectBox <foreignObject> at [12,12] [0+0+0 40 0+0+0] [0+0+0 40 0+0+0] [BFC] children: not-inline
BlockContainer <(anonymous)> at [12,12] [0+0+0 40 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
BlockContainer <div> at [12,12] [0+0+0 100 0+0+-60] [0+0+0 100 0+0+0] children: not-inline
BlockContainer <(anonymous)> at [12,112] [0+0+0 40 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
SVGMaskBox <mask#«r1»> at [12,12] [0+0+0 48 0+0+0] [0+0+0 48 0+0+0] children: not-inline
SVGGraphicsBox <use> at [12,12] [0+0+0 40 0+0+0] [0+0+0 40 0+0+0] children: not-inline
SVGGeometryBox <path#«r1»-blob_mask> at [12,12] [0+0+0 40 0+0+0] [0+0+0 40 0+0+0] children: not-inline
TextNode <#text> (not painted)
TextNode <#text> (not painted)
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x64]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x48]
SVGSVGPaintable (SVGSVGBox<svg>) [8,8 48x48]
SVGForeignObjectPaintable (SVGForeignObjectBox<foreignObject>) [12,12 40x40] overflow: [12,12 100x100]
PaintableWithLines (BlockContainer(anonymous)) [12,12 40x0]
PaintableWithLines (BlockContainer<DIV>) [12,12 100x100]
PaintableWithLines (BlockContainer(anonymous)) [12,112 40x0]
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x64] [children: 1] (z-index: auto)
SC for SVGForeignObjectBox<foreignObject> [12,12 40x40] [children: 0] (z-index: auto)

View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<svg width="48" height="48" viewBox="-4 -4 48 48">
<defs>
<path
d="M0 17.4545C0 11.3449 0 8.29005 1.18902 5.95647C2.23491 3.90379 3.90379 2.23491 5.95647 1.18902C8.29005 0 11.3449 0 17.4545 0H22.5455C28.6551 0 31.71 0 34.0435 1.18902C36.0962 2.23491 37.7651 3.90379 38.811 5.95647C40 8.29005 40 11.3449 40 17.4545V22.5455C40 28.6551 40 31.71 38.811 34.0435C37.7651 36.0962 36.0962 37.7651 34.0435 38.811C31.71 40 28.6551 40 22.5455 40H17.4545C11.3449 40 8.29005 40 5.95647 38.811C3.90379 37.7651 2.23491 36.0962 1.18902 34.0435C0 31.71 0 28.6551 0 22.5455V17.4545Z"
id="«r1»-blob_mask"
></path>
</defs>
<mask id="«r1»" fill="black" x="0" y="0" width="40" height="40"><use href="#«r1»-blob_mask" fill="white" class=""></use></mask>
<foreignobject mask="url(#«r1»)" x="0" y="0" width="40" height="40">
<div style="width: 100px; height: 100px; background-color: magenta"></div>
</foreignobject>
</svg>
</html>