summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-render/src/lib.rs17
-rw-r--r--crates/typst/src/visualize/image/svg.rs91
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);
+ }
}
}