From 7a93e6b59db009cfeefd5ab0d75923bf622b7097 Mon Sep 17 00:00:00 2001 From: "nico.burns" Date: Sat, 8 Aug 2026 02:34:19 +0000 Subject: [PATCH] Intrinsic sizing for inline SVG; SVG content clipping --- packages/blitz-dom/src/node/element.rs | 7 ++++++- packages/blitz-paint/src/render.rs | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/blitz-dom/src/node/element.rs b/packages/blitz-dom/src/node/element.rs index e036ae085..b03cbb92f 100644 --- a/packages/blitz-dom/src/node/element.rs +++ b/packages/blitz-dom/src/node/element.rs @@ -468,8 +468,13 @@ impl ElementData { #[cfg(feature = "svg")] pub fn svg_data(&self) -> Option<&usvg::Tree> { + self.svg_image_data().map(|data| &*data.tree) + } + + #[cfg(feature = "svg")] + pub fn svg_image_data(&self) -> Option<&SvgImageData> { match self.image_data()? { - ImageData::Svg(data) => Some(&data.tree), + ImageData::Svg(data) => Some(data), _ => None, } } diff --git a/packages/blitz-paint/src/render.rs b/packages/blitz-paint/src/render.rs index bb9ce9bcf..1d094e2c1 100644 --- a/packages/blitz-paint/src/render.rs +++ b/packages/blitz-paint/src/render.rs @@ -262,10 +262,29 @@ impl<'dom, 'a> BlitzDomPainter<'dom, 'a> { // TODO: account for overflow_x vs overflow_y let overflow_x = styles.get_box().overflow_x; let overflow_y = styles.get_box().overflow_y; - let is_image = node + // A blended SVG is not clipped: the isolated buffer a clip layer + // introduces would make its blend modes composite against a transparent + // backdrop instead of the actual one. + #[cfg(feature = "svg")] + fn blends_with_backdrop(group: &usvg::Group) -> bool { + group.blend_mode() != usvg::BlendMode::Normal + || (!group.isolate() + && group.children().iter().any( + |child| matches!(child, usvg::Node::Group(g) if blends_with_backdrop(g)), + )) + } + #[cfg(feature = "svg")] + let is_svg = node .element_data() - .and_then(|e| e.raster_image_data()) - .is_some(); + .and_then(|e| e.svg_data()) + .is_some_and(|tree| !blends_with_backdrop(tree.root())); + #[cfg(not(feature = "svg"))] + let is_svg = false; + let is_image = is_svg + || node + .element_data() + .and_then(|e| e.raster_image_data()) + .is_some(); let is_sub_doc = node .element_data() .and_then(|el| el.sub_doc_data()) @@ -937,6 +956,7 @@ impl ElementCx<'_, '_> { let width = self.frame.content_box.width() as u32; let height = self.frame.content_box.height() as u32; + let svg_size = svg.size(); let x = self.frame.content_box.origin().x;