mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3916 from lehni/fix/svg-glyph-svg-images
Type: SVG glyphs leave out images of SVG documents
This commit is contained in:
@@ -17,7 +17,7 @@ use crate::ImportOptions;
|
||||
const MAX_SVG_GLYPH_BYTES: u64 = 1 << 20;
|
||||
|
||||
/// Elements left out of a glyph, as the `SVG ` table rules them out: text (type inside type),
|
||||
/// embedded content and scripts.
|
||||
/// embedded content and scripts (and images of SVG documents, in [`glyph`]).
|
||||
const LEFT_OUT: [&str; 3] = ["text", "foreignObject", "script"];
|
||||
|
||||
/// Glyph `gid`'s art from its SVG `document` (possibly gzipped), in a font of `upem` units per em:
|
||||
@@ -98,7 +98,14 @@ fn glyph(svg: &str, id: &str, color: &str) -> Option<Glyph> {
|
||||
let at = target.range();
|
||||
// Edits: byte ranges to cut and what to put in their place, in order.
|
||||
let mut edits: Vec<(Range<usize>, String)> = vec![];
|
||||
for n in root.descendants().filter(|n| n.is_element() && LEFT_OUT.contains(&n.tag_name().name())) {
|
||||
// Cut with the left-out elements: images of SVG documents, as the table asks (a glyph draws no
|
||||
// documents inside 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")))
|
||||
};
|
||||
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()));
|
||||
}
|
||||
for a in root.attributes().filter(|a| matches!(a.name(), "width" | "height" | "color")) {
|
||||
|
||||
@@ -211,3 +211,22 @@ fn images_are_in_the_art_with_their_pixels() {
|
||||
let b = art.geometric_bounds().unwrap();
|
||||
assert!(b.x0.abs() < 1e-6 && (b.width() - 500.0).abs() < 1e-6 && (b.y0 + 500.0).abs() < 1e-6, "in font units: {b:?}");
|
||||
}
|
||||
|
||||
/// An image whose data is an SVG document is left out, as the `SVG ` table asks: a glyph draws no
|
||||
/// documents inside it.
|
||||
#[test]
|
||||
fn svg_images_are_left_out() {
|
||||
let inner = r##"<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect width="10" height="10" fill="#f00"/></svg>"##;
|
||||
let doc = format!(
|
||||
r##"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="glyph1">
|
||||
<path fill="#00f" d="M0 0h500v-500z"/>
|
||||
<image width="500" height="500" xlink:href="data:image/svg+xml;base64,{}"/>
|
||||
<image width="500" height="500" href=" DATA:image/SVG+xml;utf8,{}"/>
|
||||
</g></svg>"##,
|
||||
vectorcraft_svg::base64_encode(inner.as_bytes()),
|
||||
vectorcraft_svg::xml_escape(&inner.replace('#', "%23"))
|
||||
);
|
||||
let fills = fills(&art(&doc, 1).unwrap());
|
||||
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:?}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user