From bf698e0fcc184fe62bdf5bdf4df571a9b7cc589b Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Tue, 5 May 2026 17:52:20 +0200 Subject: [PATCH 1/2] usvg/parser: fix width/height computation when only one is specified In case only one of the height/width attributes are set and we have a viewBox, we currently report an incorrect size: the height/width that is set and 100% of the viewbox's attribute for the other attribute. This is incorrect, and we should instead compute the missing attribute value from the specified one and the viewBox' aspect ratio, like was done by https://github.com/linebender/resvg/pull/715. I have validated that this fixes servo's https://github.com/servo/servo/issues/41273 Signed-off-by: Simon Martin --- crates/usvg/src/parser/converter.rs | 11 ++++++++++- crates/usvg/tests/parser.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/crates/usvg/src/parser/converter.rs b/crates/usvg/src/parser/converter.rs index 38bdbdbff..09d7c2565 100644 --- a/crates/usvg/src/parser/converter.rs +++ b/crates/usvg/src/parser/converter.rs @@ -540,7 +540,16 @@ fn resolve_svg_size(svg: &SvgNode, opt: &Options) -> (Result, bool) svg.convert_user_length(AId::Height, &state, def) }; - Size::from_wh(w, h) + // If only one of height/width is not specified, its value should be + // computed from the other and the viewbox' aspect ratio. + match ( + svg.attribute::(AId::Width), + svg.attribute::(AId::Height), + ) { + (Some(_), None) => Size::from_wh(w, vbox.height() * w / vbox.width()), + (None, Some(_)) => Size::from_wh(vbox.width() * h / vbox.height(), h), + (_, _) => Size::from_wh(w, h), + } } else { Size::from_wh( svg.convert_user_length(AId::Width, &state, def), diff --git a/crates/usvg/tests/parser.rs b/crates/usvg/tests/parser.rs index d2786d801..17eb4e89e 100644 --- a/crates/usvg/tests/parser.rs +++ b/crates/usvg/tests/parser.rs @@ -217,6 +217,34 @@ fn size_detection_5() { assert_eq!(tree.size(), usvg::Size::from_wh(100.0, 100.0).unwrap()); } +#[test] +fn size_detection_6() { + let svg = ""; + let tree = usvg::Tree::from_str(&svg, &usvg::Options::default()).unwrap(); + assert_eq!(tree.size(), usvg::Size::from_wh(30.0, 30.0).unwrap()); +} + +#[test] +fn size_detection_7() { + let svg = ""; + let tree = usvg::Tree::from_str(&svg, &usvg::Options::default()).unwrap(); + assert_eq!(tree.size(), usvg::Size::from_wh(30.0, 60.0).unwrap()); +} + +#[test] +fn size_detection_8() { + let svg = ""; + let tree = usvg::Tree::from_str(&svg, &usvg::Options::default()).unwrap(); + assert_eq!(tree.size(), usvg::Size::from_wh(30.0, 30.0).unwrap()); +} + +#[test] +fn size_detection_9() { + let svg = ""; + let tree = usvg::Tree::from_str(&svg, &usvg::Options::default()).unwrap(); + assert_eq!(tree.size(), usvg::Size::from_wh(15.0, 30.0).unwrap()); +} + #[test] fn invalid_size_1() { let svg = ""; From 702c5d0fb2e0fa56eff9e28aaa4a826aa2fc38ae Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl Date: Sat, 1 Aug 2026 09:01:30 +0200 Subject: [PATCH 2/2] simplify comment --- crates/usvg/src/parser/converter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/usvg/src/parser/converter.rs b/crates/usvg/src/parser/converter.rs index 09d7c2565..c54a55d9a 100644 --- a/crates/usvg/src/parser/converter.rs +++ b/crates/usvg/src/parser/converter.rs @@ -540,8 +540,8 @@ fn resolve_svg_size(svg: &SvgNode, opt: &Options) -> (Result, bool) svg.convert_user_length(AId::Height, &state, def) }; - // If only one of height/width is not specified, its value should be - // computed from the other and the viewbox' aspect ratio. + // If exactly one of width and height is specified, compute the missing + // dimension from the specified one and the viewBox aspect ratio. match ( svg.attribute::(AId::Width), svg.attribute::(AId::Height),