use std::sync::{Arc, OnceLock};
fn fontdb() -> &'static Arc<usvg::fontdb::Database> {
static FONTDB: OnceLock<Arc<usvg::fontdb::Database>> = OnceLock::new();
FONTDB.get_or_init(|| {
let mut db = usvg::fontdb::Database::new();
db.load_system_fonts();
Arc::new(db)
})
}
pub fn options() -> usvg::Options<'static> {
let mut options = usvg::Options {
fontdb: Arc::clone(fontdb()),
..Default::default()
};
options.image_href_resolver = usvg::ImageHrefResolver {
resolve_data: usvg::ImageHrefResolver::default_data_resolver(),
resolve_string: Box::new(|_href, _options| None),
};
options
}
#[cfg(test)]
mod tests {
const ONE_PIXEL_PNG: &[u8] = &[
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44,
0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F,
0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0x63, 0x60,
0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x01, 0xE2, 0x26, 0x05, 0x9B, 0x00, 0x00, 0x00, 0x00,
0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82,
];
#[test]
fn an_svg_cannot_pull_in_a_file_of_its_own() {
let dir = tempfile::tempdir().unwrap();
let secret = dir.path().join("secret.png");
std::fs::write(&secret, ONE_PIXEL_PNG).unwrap();
let svg = format!(
r#"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="10" height="10"><image xlink:href="{}" width="10" height="10"/></svg>"#,
secret.display()
);
let tree = usvg::Tree::from_str(&svg, &super::options()).expect("a valid SVG");
fn has_image(group: &usvg::Group) -> bool {
group.children().iter().any(|node| match node {
usvg::Node::Image(_) => true,
usvg::Node::Group(inner) => has_image(inner),
_ => false,
})
}
assert!(
!has_image(tree.root()),
"the referenced file should not have been read"
);
}
#[test]
fn an_embedded_picture_still_draws() {
let png = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
let svg = format!(
r#"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="10" height="10"><image xlink:href="data:image/png;base64,{png}" width="10" height="10"/></svg>"#
);
let tree = usvg::Tree::from_str(&svg, &super::options()).expect("a valid SVG");
fn has_image(group: &usvg::Group) -> bool {
group.children().iter().any(|node| match node {
usvg::Node::Image(_) => true,
usvg::Node::Group(inner) => has_image(inner),
_ => false,
})
}
assert!(has_image(tree.root()), "embedded data should still draw");
}
}