diff --git a/crates/resvg/tests/integration/render.rs b/crates/resvg/tests/integration/render.rs index 8d585dc9e..43fb0be5d 100644 --- a/crates/resvg/tests/integration/render.rs +++ b/crates/resvg/tests/integration/render.rs @@ -1227,6 +1227,7 @@ use crate::render; #[test] fn structure_symbol_unused_symbol() { assert_eq!(render("tests/structure/symbol/unused-symbol"), 0); } #[test] fn structure_symbol_with_custom_use_size() { assert_eq!(render("tests/structure/symbol/with-custom-use-size"), 0); } #[test] fn structure_symbol_with_overflow_visible() { assert_eq!(render("tests/structure/symbol/with-overflow-visible"), 0); } +#[test] fn structure_symbol_with_size_on_use_and_relative_units() { assert_eq!(render("tests/structure/symbol/with-size-on-use-and-relative-units"), 0); } #[test] fn structure_symbol_with_transform_on_use_no_size() { assert_eq!(render("tests/structure/symbol/with-transform-on-use-no-size"), 0); } #[test] fn structure_symbol_with_transform_on_use() { assert_eq!(render("tests/structure/symbol/with-transform-on-use"), 0); } #[test] fn structure_symbol_with_transform() { assert_eq!(render("tests/structure/symbol/with-transform"), 0); } diff --git a/crates/resvg/tests/tests/structure/symbol/with-size-on-use-and-relative-units.png b/crates/resvg/tests/tests/structure/symbol/with-size-on-use-and-relative-units.png new file mode 100644 index 000000000..7b6af1b80 Binary files /dev/null and b/crates/resvg/tests/tests/structure/symbol/with-size-on-use-and-relative-units.png differ diff --git a/crates/resvg/tests/tests/structure/symbol/with-size-on-use-and-relative-units.svg b/crates/resvg/tests/tests/structure/symbol/with-size-on-use-and-relative-units.svg new file mode 100644 index 000000000..82445219e --- /dev/null +++ b/crates/resvg/tests/tests/structure/symbol/with-size-on-use-and-relative-units.svg @@ -0,0 +1,14 @@ + + With size on `use` and relative units + + + + + + + + + + + \ No newline at end of file diff --git a/crates/usvg/src/parser/use_node.rs b/crates/usvg/src/parser/use_node.rs index 20dc17f7a..723a0107b 100644 --- a/crates/usvg/src/parser/use_node.rs +++ b/crates/usvg/src/parser/use_node.rs @@ -54,6 +54,32 @@ pub(crate) fn convert( let linked_to_symbol = child.tag_name() == Some(EId::Symbol); if linked_to_symbol { + // If a `use` element has a width/height attribute and references a symbol + // then relative units (like percentages) should be resolved relative + // to the width/height of the `use` element, and not the original SVG. + // This is why we need to (potentially) adapt the view box here. + use_state.view_box = { + let def = Length::new(100.0, LengthUnit::Percent); + let x = use_state.view_box.x(); + let y = use_state.view_box.y(); + + let width = if node.has_attribute(AId::Width) { + node.convert_user_length(AId::Width, &use_state, def) + } else { + use_state.view_box.width() + }; + + let height = if node.has_attribute(AId::Height) { + node.convert_user_length(AId::Height, &use_state, def) + } else { + use_state.view_box.height() + }; + + NonZeroRect::from_xywh(x, y, width, height) + // Fail silently if the rect is not valid. + .unwrap_or(use_state.view_box) + }; + if let Some(ts) = viewbox_transform(node, child, &use_state) { new_ts = new_ts.pre_concat(ts); }