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#"{zalgo}{zalgo}"# + ); + + // 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.