diff --git a/Cargo.lock b/Cargo.lock
index c86db226a5a..16078d79824 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6754,7 +6754,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
dependencies = [
- "roxmltree",
+ "roxmltree 0.20.0",
]
[[package]]
@@ -7259,16 +7259,6 @@ dependencies = [
"syn 2.0.117",
]
-[[package]]
-name = "gif"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
-dependencies = [
- "color_quant",
- "weezl",
-]
-
[[package]]
name = "gif"
version = "0.14.2"
@@ -8918,7 +8908,7 @@ dependencies = [
"byteorder-lite",
"color_quant",
"exr",
- "gif 0.14.2",
+ "gif",
"image-webp",
"moxcms",
"num-traits",
@@ -8928,8 +8918,8 @@ dependencies = [
"rayon",
"rgb",
"tiff",
- "zune-core 0.5.1",
- "zune-jpeg 0.5.15",
+ "zune-core",
+ "zune-jpeg",
]
[[package]]
@@ -8964,9 +8954,9 @@ dependencies = [
[[package]]
name = "imagesize"
-version = "0.13.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
+checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c"
[[package]]
name = "imara-diff"
@@ -9590,12 +9580,13 @@ dependencies = [
[[package]]
name = "kurbo"
-version = "0.11.3"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
+checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2"
dependencies = [
"arrayvec",
"euclid",
+ "polycool",
"smallvec",
]
@@ -10918,6 +10909,7 @@ dependencies = [
"merman",
"quick-xml 0.38.3",
"serde_json",
+ "usvg",
]
[[package]]
@@ -13672,6 +13664,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
+[[package]]
+name = "polycool"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6"
+dependencies = [
+ "arrayvec",
+]
+
[[package]]
name = "pori"
version = "0.0.0"
@@ -15337,19 +15338,19 @@ dependencies = [
[[package]]
name = "resvg"
-version = "0.45.1"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43"
+checksum = "b563218631706d614e23059436526d005b50ab5f2d506b55a17eb65c5eb83419"
dependencies = [
- "gif 0.13.3",
+ "gif",
"image-webp",
"log",
"pico-args",
"rgb",
- "svgtypes 0.15.3",
+ "svgtypes 0.16.1",
"tiny-skia",
"usvg",
- "zune-jpeg 0.4.21",
+ "zune-jpeg",
]
[[package]]
@@ -15492,6 +15493,15 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
+[[package]]
+name = "roxmltree"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "rpassword"
version = "7.5.2"
@@ -17750,11 +17760,11 @@ dependencies = [
[[package]]
name = "svgtypes"
-version = "0.15.3"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
+checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d"
dependencies = [
- "kurbo 0.11.3",
+ "kurbo 0.13.1",
"siphasher 1.0.1",
]
@@ -18549,7 +18559,7 @@ dependencies = [
"half",
"quick-error 2.0.1",
"weezl",
- "zune-jpeg 0.5.15",
+ "zune-jpeg",
]
[[package]]
@@ -19774,24 +19784,24 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "usvg"
-version = "0.45.1"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef"
+checksum = "e419dff010bb12512b0ae9e3d2f318dfbdf0167fde7eb05465134d4e8756076f"
dependencies = [
"base64 0.22.1",
"data-url",
"flate2",
"fontdb",
"imagesize",
- "kurbo 0.11.3",
+ "kurbo 0.13.1",
"log",
"pico-args",
- "roxmltree",
+ "roxmltree 0.21.1",
"rustybuzz",
"simplecss",
"siphasher 1.0.1",
"strict-num",
- "svgtypes 0.15.3",
+ "svgtypes 0.16.1",
"tiny-skia-path",
"unicode-bidi",
"unicode-script",
@@ -23498,12 +23508,6 @@ dependencies = [
name = "ztracing_macro"
version = "0.1.0"
-[[package]]
-name = "zune-core"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
-
[[package]]
name = "zune-core"
version = "0.5.1"
@@ -23519,22 +23523,13 @@ dependencies = [
"simd-adler32",
]
-[[package]]
-name = "zune-jpeg"
-version = "0.4.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713"
-dependencies = [
- "zune-core 0.4.12",
-]
-
[[package]]
name = "zune-jpeg"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
dependencies = [
- "zune-core 0.5.1",
+ "zune-core",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index d4564def4cb..54f1de8b30f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -721,6 +721,12 @@ reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662
"socks",
"stream",
], package = "zed-reqwest", version = "0.12.15-zed" }
+resvg = { version = "0.46.0", default-features = false, features = [
+ "text",
+ "system-fonts",
+ "memmap-fonts",
+ "raster-images",
+] }
rsa = "0.9.6"
runtimelib = { version = "1.4.0", default-features = false, features = [
"async-dispatcher-runtime", "aws-lc-rs"
@@ -813,6 +819,7 @@ unicode-width = "0.2"
unindent = "0.2.0"
url = "2.2"
urlencoding = "2.1.2"
+usvg = { version = "0.46.0", default-features = false }
uuid = { version = "1.1.2", features = ["v4", "v5", "v7", "serde"] }
vte = { version = "0.15.0", features = ["ansi"] }
walkdir = "2.5"
diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml
index 87cc3e3630c..64efe02f549 100644
--- a/crates/gpui/Cargo.toml
+++ b/crates/gpui/Cargo.toml
@@ -79,13 +79,8 @@ raw-window-handle = "0.6"
regex.workspace = true
refineable.workspace = true
scheduler.workspace = true
-resvg = { version = "0.45.0", default-features = false, features = [
- "text",
- "system-fonts",
- "memmap-fonts",
- "raster-images"
-] }
-usvg = { version = "0.45.0", default-features = false }
+resvg.workspace = true
+usvg.workspace = true
ttf-parser = "0.25"
util_macros.workspace = true
schemars.workspace = true
diff --git a/crates/gpui/src/svg_renderer.rs b/crates/gpui/src/svg_renderer.rs
index 3b5062f55df..5abd3341d22 100644
--- a/crates/gpui/src/svg_renderer.rs
+++ b/crates/gpui/src/svg_renderer.rs
@@ -313,6 +313,31 @@ mod tests {
db
}
+ #[test]
+ fn text_with_split_glyph_clusters_in_mixed_fonts_does_not_panic() {
+ let mut db = Database::new();
+ db.load_font_data(IBM_PLEX_REGULAR.to_vec());
+ db.load_font_data(LILEX_REGULAR.to_vec());
+ let options = usvg::Options {
+ fontdb: std::sync::Arc::new(db),
+ ..Default::default()
+ };
+
+ // A base letter followed by a stack of combining marks. Under HarfBuzz's
+ // default cluster merging every mark glyph shares the base's byte index,
+ // which is the "glyph splitting" condition that triggered the panic. The
+ // chunk must use two different fonts so the buggy merge path runs.
+ let zalgo = "e\u{0301}\u{0302}\u{0303}\u{0304}\u{0306}\u{0307}\u{0308}\u{030a}";
+ let svg = format!(
+ r#""#
+ );
+
+ // Before the fix this aborts via panic with a message like
+ // "removal index (is 5) should be < len (is 5)".
+ usvg::Tree::from_data(svg.as_bytes(), &options)
+ .expect("SVG with mixed-font text should parse");
+ }
+
#[test]
fn test_is_emoji_presentation() {
let cases = [
diff --git a/crates/mermaid_render/Cargo.toml b/crates/mermaid_render/Cargo.toml
index bf826ab6334..580165f5466 100644
--- a/crates/mermaid_render/Cargo.toml
+++ b/crates/mermaid_render/Cargo.toml
@@ -25,3 +25,4 @@ serde_json.workspace = true
[dev-dependencies]
gpui = { workspace = true, features = ["test-support"] }
mermaid_render = { path = ".", features = ["test-support"] }
+usvg.workspace = true
diff --git a/crates/mermaid_render/src/mermaid_render.rs b/crates/mermaid_render/src/mermaid_render.rs
index 5dc953c9c88..8f9ee8f5ee2 100644
--- a/crates/mermaid_render/src/mermaid_render.rs
+++ b/crates/mermaid_render/src/mermaid_render.rs
@@ -185,6 +185,31 @@ pub fn render_to_svg(source: &str, theme: &MermaidTheme) -> Result {
mod tests {
use super::*;
+ #[test]
+ fn mermaid_diagram_with_mixed_weight_combining_marks_does_not_panic() {
+ const IBM_PLEX_REGULAR: &[u8] =
+ include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-Regular.ttf");
+ const IBM_PLEX_SEMIBOLD: &[u8] =
+ include_bytes!("../../../assets/fonts/ibm-plex-sans/IBMPlexSans-SemiBold.ttf");
+
+ let zalgo = "Ne\u{0301}\u{0302}\u{0303}\u{0304}\u{0306}\u{0307}\u{0308}\u{030a}d";
+ let source = format!("flowchart TD\n A[\"**{zalgo}** {zalgo}\"]");
+ let svg = render_to_svg(&source, &MermaidTheme::default())
+ .expect("mermaid diagram should render to SVG");
+
+ let mut db = usvg::fontdb::Database::new();
+ db.load_font_data(IBM_PLEX_REGULAR.to_vec());
+ db.load_font_data(IBM_PLEX_SEMIBOLD.to_vec());
+ db.set_sans_serif_family("IBM Plex Sans");
+ let options = usvg::Options {
+ fontdb: std::sync::Arc::new(db),
+ ..Default::default()
+ };
+
+ usvg::Tree::from_data(svg.as_bytes(), &options)
+ .expect("rasterizing mermaid text should not panic");
+ }
+
/// An ER diagram whose attribute-block tokens begin with a multibyte
/// UTF-8 character (e.g. CJK type/field names) must not panic while the
/// lexer probes for the two-character `PK`/`FK`/`UK` keys.