summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock31
-rw-r--r--Cargo.toml6
-rw-r--r--crates/typst-render/src/lib.rs17
-rw-r--r--crates/typst/src/visualize/image/svg.rs91
4 files changed, 76 insertions, 69 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 92ae6f32..de95a90a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1736,12 +1736,6 @@ dependencies = [
]
[[package]]
-name = "rctree"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f"
-
-[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1798,9 +1792,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "resvg"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4"
+checksum = "5c34501046959e06470ba62a2dc7f31c15f94ac250d842a45f9e012f4ee40c1e"
dependencies = [
"gif",
"jpeg-decoder",
@@ -2170,12 +2164,14 @@ checksum = "09eab8a83bff89ba2200bd4c59be45c7c787f988431b936099a5a266c957f2f9"
[[package]]
name = "svg2pdf"
version = "0.9.1"
-source = "git+https://github.com/typst/svg2pdf?rev=11f34c7#11f34c7f407d504c49db19e4e2b521fce4c8622f"
+source = "git+https://github.com/typst/svg2pdf?rev=49891ef#49891ef48eee1a03f2ed090541d88fd0193bf2c9"
dependencies = [
"image",
"miniz_oxide",
"once_cell",
"pdf-writer",
+ "resvg",
+ "tiny-skia",
"usvg",
]
@@ -2859,9 +2855,9 @@ dependencies = [
[[package]]
name = "usvg"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756"
+checksum = "377f62b4a3c173de8654c1aa80ab1dac1154e6f13a779a9943e53780120d1625"
dependencies = [
"base64",
"log",
@@ -2874,9 +2870,9 @@ dependencies = [
[[package]]
name = "usvg-parser"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bd4e3c291f45d152929a31f0f6c819245e2921bfd01e7bd91201a9af39a2bdc"
+checksum = "351a05e6f2023d6b4e946f734240a3927aefdcf930d7d42587a2c8a8869814b0"
dependencies = [
"data-url",
"flate2",
@@ -2892,9 +2888,9 @@ dependencies = [
[[package]]
name = "usvg-text-layout"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d383a3965de199d7f96d4e11a44dd859f46e86de7f3dca9a39bf82605da0a37c"
+checksum = "8c41888b9d5cf431fe852eaf9d047bbde83251b98f1749c2f08b1071e6db46e2"
dependencies = [
"fontdb",
"kurbo",
@@ -2908,11 +2904,10 @@ dependencies = [
[[package]]
name = "usvg-tree"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3"
+checksum = "18863e0404ed153d6e56362c5b1146db9f4f262a3244e3cf2dbe7d8a85909f05"
dependencies = [
- "rctree",
"strict-num",
"svgtypes",
"tiny-skia-path",
diff --git a/Cargo.toml b/Cargo.toml
index ad1d416a..8f93a190 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -76,7 +76,7 @@ pulldown-cmark = "0.9"
quote = "1"
rayon = "1.7.0"
regex = "1"
-resvg = { version = "0.37.0", default-features = false, features = ["raster-images"] }
+resvg = { version = "0.38.0", default-features = false, features = ["raster-images"] }
roxmltree = "0.19"
rustls = "0.21" # in sync with ureq
rustls-pemfile = "1" # in sync with rustls
@@ -91,7 +91,7 @@ siphasher = "1"
smallvec = { version = "1.11.1", features = ["union", "const_generics", "const_new"] }
stacker = "0.1.15"
subsetter = "0.1.1"
-svg2pdf = { git = "https://github.com/typst/svg2pdf", rev = "11f34c7" }
+svg2pdf = { git = "https://github.com/typst/svg2pdf", rev = "49891ef" }
syn = { version = "2", features = ["full", "extra-traits"] }
syntect = { version = "5", default-features = false, features = ["parsing", "regex-fancy", "plist-load", "yaml-load"] }
tar = "0.4"
@@ -111,7 +111,7 @@ unicode-script = "0.5"
unicode-segmentation = "1"
unscanny = "0.1"
ureq = "2"
-usvg = { version = "0.37", default-features = false, features = ["text"] }
+usvg = { version = "0.38.0", default-features = false, features = ["text"] }
walkdir = "2"
wasmi = "0.31.0"
xmlparser = "0.13.5"
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);
+ }
}
}