From bf698e0fcc184fe62bdf5bdf4df571a9b7cc589b Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Tue, 5 May 2026 17:52:20 +0200 Subject: [PATCH] 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 = "";