From e67ebacef2fb64e043b96143a1c7b10426239598 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 9 Sep 2026 11:16:01 +0200 Subject: [PATCH] :bug: Export svg-raw shapes through WASM SVG draw_svg (#11567) SVG export treated SVGRaw like a fill/stroke leaf and never called draw_svg, so imported SVG content exported as an empty document. Relates to #10546 --- render-wasm/src/render/svg/fixtures.rs | 14 ++++++++++++ render-wasm/src/render/svg/mod.rs | 8 +++++++ render-wasm/src/render/svg/tests.rs | 30 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/render-wasm/src/render/svg/fixtures.rs b/render-wasm/src/render/svg/fixtures.rs index 1eb91c95e3..7bebcc1cf4 100644 --- a/render-wasm/src/render/svg/fixtures.rs +++ b/render-wasm/src/render/svg/fixtures.rs @@ -209,6 +209,20 @@ pub(super) fn add_group( } } +/// SVG-raw leaf with markup (same form `get-static-markup` uploads to WASM). +pub(super) fn add_svg_raw( + pool: &mut ShapesPool, + id: Uuid, + parent: Uuid, + (l, t, r, b): (f32, f32, f32, f32), + content: &str, +) { + let shape = pool.add_shape(id); + shape.set_parent(parent); + shape.set_svg_raw_content(content.to_string()); + shape.set_selrect(l, t, r, b); +} + /// Adds a single-line text shape using the embedded default font. pub(super) fn add_solid_text( pool: &mut ShapesPool, diff --git a/render-wasm/src/render/svg/mod.rs b/render-wasm/src/render/svg/mod.rs index 8f647ee52c..c192571c83 100644 --- a/render-wasm/src/render/svg/mod.rs +++ b/render-wasm/src/render/svg/mod.rs @@ -194,6 +194,14 @@ fn render_leaf( { if matches!(element.shape_type, Type::Text(_)) { render_text_fill(builder, shared, element)?; + } else if matches!(element.shape_type, Type::SVGRaw(_)) { + let matrix = element.centered_transform(); + let canvas = builder.canvas(); + canvas.save(); + canvas.concat(&matrix); + let mut renderer = VectorRenderer::new(canvas, shared, scale, false); + renderer.draw_svg(element)?; + canvas.restore(); } else { emit_fills(builder, shared, element, &element.fills, tree, scale)?; diff --git a/render-wasm/src/render/svg/tests.rs b/render-wasm/src/render/svg/tests.rs index c66c2d32dc..59a45fc0ad 100644 --- a/render-wasm/src/render/svg/tests.rs +++ b/render-wasm/src/render/svg/tests.rs @@ -125,6 +125,36 @@ fn exports_a_group_with_two_rects_and_group_opacity() { insta::assert_snapshot!(svg); } +#[test] +fn loads_svg_raw_dom_like_wasm_upload() { + // Production paints svg-raw via Dom::render after set_shape_svg_raw_content. + // Native SkSVGCanvas does not serialize those draws, so the export string + // stays empty here; we assert Dom parse + that export does not panic. + let mut pool = ShapesPool::new(); + let id = uid(1); + add_svg_raw( + &mut pool, + id, + Uuid::nil(), + (0.0, 0.0, 307.0, 243.0), + concat!( + r#""#, + r#"HOLA"#, + r#""#, + ), + ); + + let resources = crate::render::RenderResources::try_new_headless().expect("headless"); + let font_manager = skia::FontMgr::from(resources.fonts.font_provider().clone()); + { + let shape = pool.get_mut(&id).unwrap(); + shape.update_svg_raw_content(font_manager); + assert!(shape.svg.is_some(), "Dom must parse like WASM upload"); + } + + let _svg = render(&pool, id); +} + #[test] fn exports_a_clipped_frame_with_overflowing_child() { let mut pool = ShapesPool::new();