diff options
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/typst-render/src/lib.rs | 17 | ||||
| -rw-r--r-- | crates/typst/src/visualize/image/svg.rs | 91 |
2 files changed, 60 insertions, 48 deletions
diff --git a/crates/typst-render/src/lib.rs b/crates/typst-render/src/lib.rs index 5718a7c0..afdfeeef 100644 --- a/crates/typst-render/src/lib.rs +++ b/crates/typst-render/src/lib.rs @@ -19,7 +19,7 @@ use typst::visualize::{ Color, DashPattern, FixedStroke, Geometry, Gradient, Image, ImageKind, LineCap, LineJoin, Paint, Path, PathItem, Pattern, RasterFormat, RelativeTo, Shape, }; -use usvg::{NodeExt, TreeParsing}; +use usvg::TreeParsing; /// Export a frame into a raster image. /// @@ -272,8 +272,8 @@ fn render_svg_glyph( // Parse SVG. let opts = usvg::Options::default(); - let usvg_tree = usvg::Tree::from_xmltree(&document, &opts).ok()?; - let tree = resvg::Tree::from_usvg(&usvg_tree); + let mut tree = usvg::Tree::from_xmltree(&document, &opts).ok()?; + tree.calculate_bounding_boxes(); let view_box = tree.view_box.rect; // If there's no viewbox defined, use the em square for our scale @@ -298,10 +298,8 @@ fn render_svg_glyph( // See https://github.com/RazrFalcon/resvg/issues/602 for why // using the svg size is problematic here. let mut bbox = usvg::BBox::default(); - for node in usvg_tree.root.descendants() { - if let Some(rect) = node.calculate_bbox() { - bbox = bbox.expand(rect); - } + if let Some(tree_bbox) = tree.root.bounding_box { + bbox = bbox.expand(tree_bbox); } // Compute the bbox after the transform is applied. @@ -320,7 +318,7 @@ fn render_svg_glyph( // We offset our transform so that the pixmap starts at the edge of the bbox. let ts = ts.post_translate(-bbox.left() as f32, -bbox.top() as f32); - tree.render(ts, &mut pixmap.as_mut()); + resvg::render(&tree, ts, &mut pixmap.as_mut()); canvas.draw_pixmap( bbox.left(), @@ -757,12 +755,11 @@ fn scaled_texture(image: &Image, w: u32, h: u32) -> Option<Arc<sk::Pixmap>> { // of `with`. ImageKind::Svg(svg) => unsafe { svg.with(|tree| { - let tree = resvg::Tree::from_usvg(tree); let ts = tiny_skia::Transform::from_scale( w as f32 / tree.size.width(), h as f32 / tree.size.height(), ); - tree.render(ts, &mut pixmap.as_mut()) + resvg::render(tree, ts, &mut pixmap.as_mut()) }); }, } diff --git a/crates/typst/src/visualize/image/svg.rs b/crates/typst/src/visualize/image/svg.rs index a4cf3807..20e1b0b9 100644 --- a/crates/typst/src/visualize/image/svg.rs +++ b/crates/typst/src/visualize/image/svg.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use comemo::Tracked; use ecow::EcoString; use siphasher::sip128::Hasher128; -use usvg::{NodeExt, TreeParsing, TreeTextToPath}; +use usvg::{Node, PostProcessingSteps, TreeParsing, TreePostProc}; use crate::diag::{format_xml_like_error, StrResult}; use crate::foundations::Bytes; @@ -56,10 +56,11 @@ impl SvgImage { let mut tree = usvg::Tree::from_data(&data, &opts).map_err(format_usvg_error)?; let mut font_hash = 0; if tree.has_text_nodes() { - let (fontdb, hash) = load_svg_fonts(world, &tree, families); - tree.convert_text(&fontdb); + let (fontdb, hash) = load_svg_fonts(world, &mut tree, families); + tree.postprocess(PostProcessingSteps::default(), &fontdb); font_hash = hash; } + tree.calculate_bounding_boxes(); Ok(Self(Arc::new(Repr { data, size: tree_size(&tree), @@ -128,7 +129,7 @@ impl Hash for Repr { /// Discover and load the fonts referenced by an SVG. fn load_svg_fonts( world: Tracked<dyn World + '_>, - tree: &usvg::Tree, + tree: &mut usvg::Tree, families: &[String], ) -> (fontdb::Database, u128) { let book = world.book(); @@ -153,56 +154,70 @@ fn load_svg_fonts( }; // Determine the best font for each text node. - traverse_svg(&tree.root, &mut |node| { - let usvg::NodeKind::Text(text) = &mut *node.borrow_mut() else { return }; - for chunk in &mut text.chunks { - 'spans: for span in &mut chunk.spans { - let Some(text) = chunk.text.get(span.start..span.end) else { continue }; - let variant = FontVariant { - style: span.font.style.into(), - weight: FontWeight::from_number(span.font.weight), - stretch: span.font.stretch.into(), - }; - - // Find a font that covers the whole text among the span's fonts - // and the current document font families. - let mut like = None; - for family in span.font.families.iter().chain(families) { - let Some(id) = book.select(&family.to_lowercase(), variant) else { + for child in &mut tree.root.children { + traverse_svg(child, &mut |node| { + let usvg::Node::Text(ref mut text) = node else { return }; + for chunk in &mut text.chunks { + 'spans: for span in &mut chunk.spans { + let Some(text) = chunk.text.get(span.start..span.end) else { continue; }; - let Some(info) = book.info(id) else { continue }; - like.get_or_insert(info); + let variant = FontVariant { + style: span.font.style.into(), + weight: FontWeight::from_number(span.font.weight), + stretch: span.font.stretch.into(), + }; - if text.chars().all(|c| info.coverage.contains(c as u32)) { - if let Some(usvg_family) = load_into_db(id) { - span.font.families = vec![usvg_family]; - continue 'spans; + // Find a font that covers the whole text among the span's fonts + // and the current document font families. + let mut like = None; + for family in span.font.families.iter().chain(families) { + let Some(id) = book.select(&family.to_lowercase(), variant) + else { + continue; + }; + let Some(info) = book.info(id) else { continue }; + like.get_or_insert(info); + + if text.chars().all(|c| info.coverage.contains(c as u32)) { + if let Some(usvg_family) = load_into_db(id) { + span.font.families = vec![usvg_family]; + continue 'spans; + } } } - } - // If we didn't find a match, select a fallback font. - if let Some(id) = book.select_fallback(like, variant, text) { - if let Some(usvg_family) = load_into_db(id) { - span.font.families = vec![usvg_family]; + // If we didn't find a match, select a fallback font. + if let Some(id) = book.select_fallback(like, variant, text) { + if let Some(usvg_family) = load_into_db(id) { + span.font.families = vec![usvg_family]; + } } } } - } - }); + }); + } (fontdb, hasher.finish128().as_u128()) } /// Search for all font families referenced by an SVG. -fn traverse_svg<F>(node: &usvg::Node, f: &mut F) +fn traverse_svg<F>(node: &mut usvg::Node, f: &mut F) where - F: FnMut(&usvg::Node), + F: FnMut(&mut usvg::Node), { - for descendant in node.descendants() { - f(&descendant); - descendant.subroots(|subroot| traverse_svg(&subroot, f)) + f(node); + + node.subroots_mut(|subroot| { + for child in &mut subroot.children { + traverse_svg(child, f); + } + }); + + if let Node::Group(ref mut group) = node { + for child in &mut group.children { + traverse_svg(child, f); + } } } |
