Type: an SVG glyph's image is an SVG image by its plain href first

The check for images of SVG documents looked at href and xlink:href alike, so an image whose href is a PNG was cut for an SVG xlink:href; it now reads href, else xlink:href, as the importer does (SVG 2).
This commit is contained in:
Jürg Lehni
2026-10-24 07:12:16 +07:00
committed by bflatastic
parent 767f06b20e
commit deb517fbbe
2 changed files with 30 additions and 4 deletions
+3 -4
View File
@@ -99,11 +99,10 @@ fn glyph(svg: &str, id: &str, color: &str) -> Option<Glyph> {
// Edits: byte ranges to cut and what to put in their place, in order.
let mut edits: Vec<(Range<usize>, String)> = vec![];
// Cut with the left-out elements: images of SVG documents, as the table asks (a glyph draws no
// documents inside it).
// documents inside it). Their link is `href`, else `xlink:href`, as the importer reads it.
let svg_image = |n: &roxmltree::Node| {
n.tag_name().name() == "image"
&& n.attributes()
.any(|a| a.name() == "href" && a.value().trim_start().get(..14).is_some_and(|v| v.eq_ignore_ascii_case("data:image/svg")))
let href = n.attribute("href").or_else(|| n.attribute(("http://www.w3.org/1999/xlink", "href")));
n.tag_name().name() == "image" && href.and_then(|h| h.trim_start().get(..14)).is_some_and(|v| v.eq_ignore_ascii_case("data:image/svg"))
};
for n in root.descendants().filter(|n| n.is_element() && (LEFT_OUT.contains(&n.tag_name().name()) || svg_image(n))) {
edits.push((n.range(), String::new()));
+27
View File
@@ -230,3 +230,30 @@ fn svg_images_are_left_out() {
assert!(fills.contains(&Paint::solid(Color::rgb8(0, 0, 255))), "the glyph's own art");
assert!(!fills.contains(&Paint::solid(Color::rgb8(255, 0, 0))), "not the images' documents: {fills:?}");
}
/// Of `href` and `xlink:href`, the plain one counts, as the importer reads them (SVG 2): an image
/// whose `href` is a PNG stays, whatever its `xlink:href`; one whose `href` is a document goes.
#[test]
fn an_images_plain_href_decides_whether_it_is_an_svg_image() {
let png = vectorcraft_svg::base64_encode(&vectorcraft_text::test_fonts::solid_png(4, [0, 0, 255, 255]));
let svg = vectorcraft_svg::base64_encode(
br##"<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect width="10" height="10" fill="#f00"/></svg>"##,
);
let image = |href: &str, xlink: &str| {
format!(
r##"<image width="500" height="500" href="data:image/{href};base64,{}" xlink:href="data:image/{xlink};base64,{}"/>"##,
if href == "png" { &png } else { &svg },
if xlink == "png" { &png } else { &svg }
)
};
let images = |inner: String| {
let doc = format!(
r##"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="glyph1"><path d="M0 0h1v-1z"/>{inner}</g></svg>"##
);
let mut n = 0;
art(&doc, 1).unwrap().walk(&mut |c| n += usize::from(matches!(c.kind, NodeKind::Image(_))));
n
};
assert_eq!(images(image("png", "svg+xml")), 1, "the PNG stays");
assert_eq!(images(image("svg+xml", "png")), 0, "the document goes");
}