From 611eb9f5a92ea70c3a19ea964d521232184f8649 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 08:44:31 +0200 Subject: [PATCH 01/13] fonts: port complex-text shaping to harfrust 0.14 --- crates/fonts/src/complex.rs | 47 ++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/crates/fonts/src/complex.rs b/crates/fonts/src/complex.rs index 6193f3f80..1d76f813e 100644 --- a/crates/fonts/src/complex.rs +++ b/crates/fonts/src/complex.rs @@ -8,6 +8,7 @@ use std::ops::Range; use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::sync::Arc; use cadcraft_geom::Vec2; @@ -182,28 +183,31 @@ struct Glyph { /// Shape characters `r` of `cs` (one direction, one face) into glyphs in display order. fn shape_run(face: &Face, cs: &[char], r: Range, rtl: bool) -> Vec { let run = cs.get(r.clone()).unwrap_or_default(); - let Ok(font) = harfrust::FontRef::from_index(&face.bytes, face.index) else { return Vec::new() }; - let data = harfrust::ShaperData::new(&font); - let shaper = data.shaper(&font).build(); - let mut buf = harfrust::UnicodeBuffer::new(); + // Shares the face's bytes instead of copying them. + let bytes: Arc + Send + Sync> = face.bytes.clone(); + let Some(font) = harfrust::Font::new(bytes, face.index) else { return Vec::new() }; + let shaper = harfrust::ShaperFont::new(&font); + let mut buf = harfrust::Buffer::new(); let arabic = run.iter().any(|c| matches!(*c, '\u{0600}'..='\u{08FF}')); if arabic && !face.has_joining_features() { for (c, i) in bidi::presentation_forms(run, |p| face.has_glyph(p)) { - buf.add(c, u32::try_from(r.start + i).unwrap_or(u32::MAX)); + buf.push(u32::from(c), u32::try_from(r.start + i).unwrap_or(u32::MAX)); } } else { for (i, c) in run.iter().enumerate() { - buf.add(*c, u32::try_from(r.start + i).unwrap_or(u32::MAX)); + buf.push(u32::from(*c), u32::try_from(r.start + i).unwrap_or(u32::MAX)); } } buf.set_direction(if rtl { harfrust::Direction::RightToLeft } else { harfrust::Direction::LeftToRight }); buf.guess_segment_properties(); - let shaped = shaper.shape(buf, harfrust::ShapeOptions::new()); - let k = 1000.0 / f64::from(shaper.units_per_em().max(1)); - shaped - .glyph_infos() + // Without a plan, shaping fails only on an already shaped buffer or an unset direction. + if harfrust::shape(&shaper, &mut buf, harfrust::ShapeOptions::new()).is_err() { + return Vec::new(); + } + let k = 1000.0 / f64::from(font.units_per_em().max(1)); + buf.glyph_infos() .iter() - .zip(shaped.glyph_positions()) + .zip(buf.glyph_positions()) .map(|(gi, gp)| Glyph { gid: gi.glyph_id, cluster: usize::try_from(gi.cluster).unwrap_or(usize::MAX), @@ -291,6 +295,27 @@ mod tests { assert!((crate::line_width("قیمت 25 تومان", 1.0, 1.0) - sh.width).abs() < 1e-9); } + #[test] + fn devanagari_run_is_reordered_with_line_clusters_and_advances_per_1000_em() { + use skrifa::MetadataProvider; + use skrifa::instance::{LocationRef, Size}; + let Some(face) = ttf::fallback_for('\u{0915}') else { return }; + let Some(ka) = nominal(&face, '\u{0915}') else { return }; + // "कि" after two other characters of the line: the vowel sign i is drawn before the + // consonant (Indic reordering, which needs the script the shaper guesses from the text), + // both glyphs carry the cluster of the consonant's index in the line, not in the run. + let cs: Vec = "ab\u{0915}\u{093F}".chars().collect(); + let gs = shape_run(&face, &cs, 2..4, false); + let gids: Vec = gs.iter().map(|g| g.gid).collect(); + assert_eq!(gids.len(), 2, "{gids:?}"); + assert!(gids.first() != Some(&ka) && gids.last() == Some(&ka), "vowel sign before ka: {gids:?}"); + assert!(gs.iter().all(|g| g.cluster == 2), "{:?}", gs.iter().map(|g| g.cluster).collect::>()); + // Advances come out at 1000 units per em, whatever the font's own em. + let hmtx = face.font().and_then(|f| f.glyph_metrics(Size::new(1000.0), LocationRef::default()).advance_width(skrifa::GlyphId::new(ka))); + let adv = gs.last().map(|g| g.advance); + assert!(matches!((adv, hmtx), (Some(a), Some(h)) if (a - f64::from(h)).abs() < 1e-3), "{adv:?} vs {hmtx:?}"); + } + #[test] fn hostile_rtl_lines_never_panic() { for s in ["\u{202E}%%u\u{05D0}%%", "\u{2067}\u{0644}\u{0627}\u{2069}%%o", "\u{064E}\u{064E}\u{05D0}", "\u{05D0}\u{E000}\u{10FFFF}"] { From e61e328edb1e08a3f3f767dc9391e6abc716331a Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 08:50:32 +0200 Subject: [PATCH 02/13] io: read SVG element and attribute names with quick-xml 0.42 --- crates/io/src/svg_read.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/io/src/svg_read.rs b/crates/io/src/svg_read.rs index 1d150fc8b..4b2892c3d 100644 --- a/crates/io/src/svg_read.rs +++ b/crates/io/src/svg_read.rs @@ -207,15 +207,15 @@ impl Parser { match reader.read_event().map_err(parse_err)? { Event::Start(e) => { let name = e.name(); - self.on_start(name.as_ref(), &e)?; + self.on_start(name.into_inner().as_bytes(), &e)?; } Event::Empty(e) => { let name = e.name(); - self.on_element(name.as_ref(), &e)?; + self.on_element(name.into_inner().as_bytes(), &e)?; } Event::End(e) => { let name = e.name(); - self.on_end(name.as_ref()); + self.on_end(name.into_inner().as_bytes()); } Event::Eof => break, _ => {} @@ -578,7 +578,7 @@ fn hidden(e: &BytesStart) -> bool { fn attr(e: &BytesStart, name: &[u8]) -> Option { for a in e.attributes().flatten() { - if a.key.as_ref() == name { + if a.key.into_inner().as_bytes() == name { return a.normalized_value(XmlVersion::Explicit1_0).ok().map(|v| v.into_owned()); } } From f344cf4460be9916958c97639d8a1d1833e03c03 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 08:50:32 +0200 Subject: [PATCH 03/13] engine: pass the query envelope by value to rstar 0.13 --- crates/engine/src/spatial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/engine/src/spatial.rs b/crates/engine/src/spatial.rs index 98999b71f..ca15bd4c4 100644 --- a/crates/engine/src/spatial.rs +++ b/crates/engine/src/spatial.rs @@ -208,7 +208,7 @@ impl SpatialIndex { let pad = (b.width() + b.height()) * 1e-9 + (b.min.x.abs() + b.min.y.abs() + b.max.x.abs() + b.max.y.abs()) * 1e-12 + 1e-300; let env = AABB::from_corners([b.min.x - pad, b.min.y - pad], [b.max.x + pad, b.max.y + pad]); let mut out: Vec = - self.tree.locate_in_envelope_intersecting(&env).filter_map(|it| self.offsets.get(&it.data.0).map(|off| off + it.data.1)).collect(); + self.tree.locate_in_envelope_intersecting(env).filter_map(|it| self.offsets.get(&it.data.0).map(|off| off + it.data.1)).collect(); if with_infinite { out.extend_from_slice(&self.infinite); } From 5648a06ac438c54fff1392f17d57448e83e31817 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 09:14:51 +0200 Subject: [PATCH 04/13] Hold the egui crates at 0.36 until craft-ui moves to 0.37 (craft-libs#199) --- Cargo.lock | 489 ++++++++++++++++++++--------------------------------- Cargo.toml | 8 +- 2 files changed, 192 insertions(+), 305 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1bf96a72..e5076e82e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,11 +13,11 @@ dependencies = [ "byteorder", "encoding_rs", "flate2", - "foldhash 0.2.0", + "foldhash", "indexmap", "itoa", "memmap2", - "nom 7.1.3", + "nom", "oem_cp", "once_cell", "rayon", @@ -31,15 +31,6 @@ name = "accesskit" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3b7f7f85a7e5f68090000ed7622545829afd484d210358702ae4cb97dd0c320" -dependencies = [ - "uuid", -] - -[[package]] -name = "accesskit" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad442f58ee04714aaa0ba0a2768c1ea1935b29507bb22ddece8cbbc76db02932" dependencies = [ "enumn", "serde", @@ -48,51 +39,57 @@ dependencies = [ [[package]] name = "accesskit_atspi_common" -version = "0.21.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c182f9c282ac9c5638d876d551d15e5f7d397ec263349a0c6a2b61595dd5e4" +checksum = "1e8c61bee90b42a772d39d06a740207dc71a4e780004ace1db8d99fb1baaa954" dependencies = [ - "accesskit 0.25.1", - "accesskit_consumer", + "accesskit", + "accesskit_consumer 0.36.0", "atspi-common", - "phf 0.14.0", + "phf 0.13.1", "serde", "zvariant", ] [[package]] name = "accesskit_consumer" -version = "0.39.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a45e2bb300bea6d5f33a82c3e051c3ddc6f41c209750f68a0acbe991a284344" +checksum = "53cf47daed85312e763fbf85ceca136e0d7abc68e0a7e12abe11f48172bc3b10" dependencies = [ - "accesskit 0.25.1", - "hashbrown 0.17.1", + "accesskit", + "hashbrown 0.16.1", ] [[package]] -name = "accesskit_ios" -version = "0.2.1" +name = "accesskit_consumer" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e539d64b27fd4c14de8f78ada8f7c944c092f52f7e49fb63316507a57f6937" +checksum = "25e0d7e25d06f4dc21d1774d67146e9e80d6789216cbd4d1e88185b0095dba60" dependencies = [ - "accesskit 0.25.1", - "accesskit_consumer", - "hashbrown 0.17.1", - "objc2 0.5.3", - "objc2-foundation 0.2.2", - "objc2-ui-kit 0.2.2", + "accesskit", + "hashbrown 0.16.1", +] + +[[package]] +name = "accesskit_consumer" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d10a236f96f87d70732e44520046785431ef01d5bcd6b041317bfadd2f88245" +dependencies = [ + "accesskit", + "hashbrown 0.16.1", ] [[package]] name = "accesskit_macos" -version = "0.27.1" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5701624bf6a11efb6d4c8e922bf44126ed96250e5faa9a7a0468c979635839a4" +checksum = "ce02dc63b43f0c9296af9ac946312a2dc8814427d7a64d2d600971dac55b6076" dependencies = [ - "accesskit 0.25.1", - "accesskit_consumer", - "hashbrown 0.17.1", + "accesskit", + "accesskit_consumer 0.38.0", + "hashbrown 0.16.1", "objc2 0.5.3", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", @@ -100,11 +97,11 @@ dependencies = [ [[package]] name = "accesskit_unix" -version = "0.24.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202f24df034a7476d07b7f74284de84f6d62aabd858dbe7ee9cad3b7ad6f8f9d" +checksum = "b016ca8db0ea0ea2ceff29a9d6240391492d960716aa471967c00e8cc8cb197c" dependencies = [ - "accesskit 0.25.1", + "accesskit", "accesskit_atspi_common", "async-channel", "async-executor", @@ -118,13 +115,13 @@ dependencies = [ [[package]] name = "accesskit_windows" -version = "0.35.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce63f35d6bdcf59f26b76b3379063f738e6412cef46999cc772d46aa3de35adb" +checksum = "eff7009f1a532e917d66970a1e80c965140c6cfbbabbdde3d64e5431e6c78e21" dependencies = [ - "accesskit 0.25.1", - "accesskit_consumer", - "hashbrown 0.17.1", + "accesskit", + "accesskit_consumer 0.35.0", + "hashbrown 0.16.1", "static_assertions", "windows", "windows-core", @@ -132,12 +129,11 @@ dependencies = [ [[package]] name = "accesskit_winit" -version = "0.34.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee96dd150375c05912d8a473f98c2fb155fb3234fac88292d396548a2460fa77" +checksum = "1fe9a94394896352cc4660ca2288bd4ef883d83238853c038b44070c8f134313" dependencies = [ - "accesskit 0.25.1", - "accesskit_ios", + "accesskit", "accesskit_macos", "accesskit_unix", "accesskit_windows", @@ -228,7 +224,6 @@ dependencies = [ "parking_lot", "percent-encoding", "windows-sys 0.61.2", - "wl-clipboard-rs", "x11rb", ] @@ -560,7 +555,7 @@ dependencies = [ "cadcraft-ui-egui", "chrono", "eframe", - "egui 0.37.0", + "egui", "hidapi", "log", "muda", @@ -725,7 +720,7 @@ dependencies = [ "cadcraft-render", "chrono", "craft-ui", - "egui 0.37.0", + "egui", "egui-wgpu", "egui_kittest", "image", @@ -744,7 +739,7 @@ dependencies = [ "cadcraft-io", "cadcraft-ui-egui", "eframe", - "egui 0.37.0", + "egui", "log", "serde_json", "wasm-bindgen", @@ -766,18 +761,42 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "calloop" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b32313e937c8721c9d17ee9bf60699a6402b4b7c2cb6ac1bee0ffcaa4b4e5e" +dependencies = [ + "bitflags 2.13.2", + "polling", + "rustix 1.1.5", + "tracing", +] + [[package]] name = "calloop-wayland-source" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ - "calloop", + "calloop 0.13.0", "rustix 0.38.44", "wayland-backend", "wayland-client", ] +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.5", + "rustix 1.1.5", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cc" version = "1.6.0" @@ -934,7 +953,7 @@ name = "craft-ui" version = "0.1.0" source = "git+https://github.com/storytold/craft-libs?rev=5c874d51eeb3de70e735c8ce87a59a7dedd47675#5c874d51eeb3de70e735c8ce87a59a7dedd47675" dependencies = [ - "egui 0.36.2", + "egui", "serde", ] @@ -1070,31 +1089,22 @@ name = "ecolor" version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0656a7530b9e2841ee7a5f983965bdd9840c32f4012f759cfd44b912cced6b34" -dependencies = [ - "emath 0.36.2", -] - -[[package]] -name = "ecolor" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31bcbef0d4263a63eb32c4834e5d711613035ce1333468e107d928923e21e6e2" dependencies = [ "bytemuck", - "emath 0.37.0", + "emath", "serde", ] [[package]] name = "eframe" -version = "0.37.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5642501a65ca657d05f00c643a5c14ff2346cb3818032bfe23d58e1f8e5f84" +checksum = "55ad41fac6e3149abb4866e93df37dbd33baa95db525c3368c944584e95a5dc2" dependencies = [ "ahash", "bytemuck", "document-features", - "egui 0.37.0", + "egui", "egui-wgpu", "egui-winit", "egui_glow", @@ -1112,7 +1122,6 @@ dependencies = [ "profiling", "raw-window-handle", "ron", - "send_wrapper", "serde", "static_assertions", "wasm-bindgen", @@ -1129,31 +1138,11 @@ version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc938cc27cd911415e1e4d151bc56ff9df063d8db081374e87aeb805ea74b2ba" dependencies = [ - "accesskit 0.24.1", + "accesskit", "ahash", "bitflags 2.13.2", - "emath 0.36.2", - "epaint 0.36.2", - "itertools", - "log", - "nohash-hasher", - "profiling", - "smallvec", - "unicode-segmentation", - "web-sys", -] - -[[package]] -name = "egui" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec9144f49b7a28b5f395d3147e325b4fe3e77ba686eac11d1bdf0a7da3f375f" -dependencies = [ - "accesskit 0.25.1", - "ahash", - "bitflags 2.13.2", - "emath 0.37.0", - "epaint 0.37.0", + "emath", + "epaint", "itertools", "log", "nohash-hasher", @@ -1167,15 +1156,15 @@ dependencies = [ [[package]] name = "egui-wgpu" -version = "0.37.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0309cbe1febed48af5b974e4bcc424b35e9664863a4d402697147b57a488c864" +checksum = "5cef1f6d1bba40b09a4d0d62cb822b81030922cfbf65c5373398c3a3caafc5bd" dependencies = [ "ahash", "bytemuck", "document-features", - "egui 0.37.0", - "epaint 0.37.0", + "egui", + "epaint", "log", "profiling", "thiserror 2.0.21", @@ -1187,37 +1176,35 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.37.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e449f4c4a2a60c7ccb4ba7fa4078417bfe1f9ddc03b5e05ce75748e33a70de" +checksum = "98466000559d66ba4db786a30448b01483946add4188e7f10f522a27b4fb89cc" dependencies = [ "accesskit_winit", "arboard", - "block2 0.6.2", "bytemuck", - "egui 0.37.0", + "egui", "log", "objc2 0.6.5", - "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", "objc2-ui-kit 0.3.2", "profiling", "raw-window-handle", "serde", + "smithay-clipboard", "web-time", "webbrowser", - "windows-sys 0.61.2", "winit", ] [[package]] name = "egui_glow" -version = "0.37.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9275ca5cc35a6b7c94e0e8cedf22542f66cb0cf45ed8ab2657c78ff49fec7268" +checksum = "606ed4167daf341e5753d703285c4c1d562324b2c07aa8f405cd7d066fe58f3b" dependencies = [ "bytemuck", - "egui 0.37.0", + "egui", "glow", "log", "profiling", @@ -1226,13 +1213,13 @@ dependencies = [ [[package]] name = "egui_kittest" -version = "0.37.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0979c2e37860fcf13a2bea77508607f067a9a6a84ba9bd47b5e298582fb59b86" +checksum = "5eb3f3effb2726fee23449293e67acbf6cc6ce35525b1722bd5743bb348114d5" dependencies = [ "dify", "eframe", - "egui 0.37.0", + "egui", "egui-wgpu", "image", "kittest", @@ -1256,12 +1243,6 @@ name = "emath" version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52c8d4141cf0f60fb2f7aefaf352d3ffa5171ef0ab09731c64391801e95e48f1" - -[[package]] -name = "emath" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73ce90f54750be8672c02be0743fe47530e6f251e066f0ee2869b59eb297af5" dependencies = [ "bytemuck", "serde", @@ -1324,34 +1305,11 @@ name = "epaint" version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0ec0308dc23130fc1a7d4623a8534c2ed069c6dc84e258ee4f3de99615aa1a3" -dependencies = [ - "ahash", - "ecolor 0.36.2", - "emath 0.36.2", - "font-types", - "harfrust 0.12.0", - "log", - "nohash-hasher", - "parking_lot", - "profiling", - "self_cell", - "skrifa 0.44.0", - "smallvec", - "unicode-general-category", - "unicode-segmentation", - "vello_cpu 0.1.0", -] - -[[package]] -name = "epaint" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97bac86ae3dde93fc3951e790951caea739ff39a6c89d909cdaf1d9278dbb1bd" dependencies = [ "ahash", "bytemuck", - "ecolor 0.37.0", - "emath 0.37.0", + "ecolor", + "emath", "epaint_default_fonts", "font-types", "harfrust 0.12.0", @@ -1364,16 +1322,15 @@ dependencies = [ "skrifa 0.44.0", "smallvec", "unicode-general-category", - "unicode-properties", "unicode-segmentation", - "vello_cpu 0.2.0", + "vello_cpu", ] [[package]] name = "epaint_default_fonts" -version = "0.37.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc1cc505827f4c23eedc297975a0fd038268d41293f389dd8ff3b574aefab19" +checksum = "773fa9c96dd0dbef887e39d0ed6177f141cce4d68e6041df77570aa3702dfa13" [[package]] name = "equivalent" @@ -1459,12 +1416,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - [[package]] name = "flate2" version = "1.1.10" @@ -1482,12 +1433,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -1655,29 +1600,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed4a1bb24121291d27230c1b1b44e07d6a9b28cefdb32fe1581dfb84e14f940a" dependencies = [ "bytemuck", - "foldhash 0.2.0", + "foldhash", "hashbrown 0.17.1", "log", "peniko", "skrifa 0.44.0", "smallvec", - "vello_common 0.1.0", -] - -[[package]] -name = "glifo" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a26c1e23de04bdab3e34a21b6f877a479b96737792516b9b8b8f69b6661be" -dependencies = [ - "bytemuck", - "foldhash 0.2.0", - "hashbrown 0.17.1", - "log", - "peniko", - "skrifa 0.44.0", - "smallvec", - "vello_common 0.2.0", + "vello_common", ] [[package]] @@ -1826,15 +1755,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -1843,7 +1763,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -1852,7 +1772,7 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -2164,12 +2084,12 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kittest" -version = "0.5.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb81a721ba76aa095b7f45deb180504f786904e56ca4b8e141f66eb89a78b75" +checksum = "90ceaa75eb0036a32b6b9833962eb18137449e9817e2e586006471925b727fd5" dependencies = [ - "accesskit 0.25.1", - "accesskit_consumer", + "accesskit", + "accesskit_consumer 0.35.0", ] [[package]] @@ -2481,15 +2401,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nom" -version = "8.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" -dependencies = [ - "memchr", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2887,16 +2798,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "os_pipe" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "parking" version = "2.2.1" @@ -2945,17 +2846,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "petgraph" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" -dependencies = [ - "fixedbitset", - "hashbrown 0.15.5", - "indexmap", -] - [[package]] name = "phf" version = "0.11.3" @@ -2967,33 +2857,33 @@ dependencies = [ [[package]] name = "phf" -version = "0.14.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_macros", - "phf_shared 0.14.0", + "phf_shared 0.13.1", "serde", ] [[package]] name = "phf_generator" -version = "0.14.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.14.0", + "phf_shared 0.13.1", ] [[package]] name = "phf_macros" -version = "0.14.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa8d0ca26d424d27630da600c6624696e7dec8bf7b3b492b383c5dc49e5e085" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ "phf_generator", - "phf_shared 0.14.0", + "phf_shared 0.13.1", "proc-macro2", "quote", "syn 2.0.119", @@ -3010,9 +2900,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.14.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -3281,7 +3171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4edc8db0d972de88e53a085b1f01fb3fbdae7bb0cb7a0ce2b2f8285a412fe3ef" dependencies = [ "bytemuck", - "foldhash 0.2.0", + "foldhash", "font-types", "once_cell", "yoke", @@ -3464,12 +3354,6 @@ version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - [[package]] name = "serde" version = "1.0.229" @@ -3628,8 +3512,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ "bitflags 2.13.2", - "calloop", - "calloop-wayland-source", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", "cursor-icon", "libc", "log", @@ -3646,6 +3530,44 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.13.2", + "calloop 0.14.5", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.1.5", + "thiserror 2.0.21", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" +dependencies = [ + "libc", + "smithay-client-toolkit 0.20.0", + "wayland-backend", +] + [[package]] name = "smol_str" version = "0.2.2" @@ -3902,6 +3824,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3927,17 +3850,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tree_magic_mini" -version = "3.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6" -dependencies = [ - "memchr", - "nom 8.0.0", - "petgraph", -] - [[package]] name = "type-map" version = "0.5.1" @@ -3982,12 +3894,6 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" -[[package]] -name = "unicode-properties" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" - [[package]] name = "unicode-segmentation" version = "1.13.3" @@ -4044,21 +3950,6 @@ dependencies = [ "thiserror 2.0.21", ] -[[package]] -name = "vello_common" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb2141a2bca6e6d598e471fd4d1d7eed8e020aad6a28187edda07f091a325dd" -dependencies = [ - "bytemuck", - "fearless_simd", - "guillotiere", - "log", - "peniko", - "smallvec", - "thiserror 2.0.21", -] - [[package]] name = "vello_cpu" version = "0.1.0" @@ -4066,21 +3957,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac7349e1f55f6b801c7c277958df4ea53e7f20f21e8014910ad888b2ecda93ea" dependencies = [ "bytemuck", - "glifo 0.2.0", + "glifo", "hashbrown 0.17.1", - "vello_common 0.1.0", -] - -[[package]] -name = "vello_cpu" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace506ca414548966fcf3c283be94eb1cad8254de488791ee698bf438b0890a9" -dependencies = [ - "bytemuck", - "glifo 0.3.0", - "hashbrown 0.17.1", - "vello_common 0.2.0", + "vello_common", ] [[package]] @@ -4224,6 +4103,32 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.13.2", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" +dependencies = [ + "bitflags 2.13.2", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-plasma" version = "0.3.12" @@ -4720,7 +4625,7 @@ dependencies = [ "bitflags 2.13.2", "block2 0.5.1", "bytemuck", - "calloop", + "calloop 0.13.0", "cfg_aliases", "concurrent-queue", "core-foundation", @@ -4741,7 +4646,7 @@ dependencies = [ "raw-window-handle", "redox_syscall 0.4.1", "rustix 0.38.44", - "smithay-client-toolkit", + "smithay-client-toolkit 0.19.2", "smol_str", "tracing", "unicode-segmentation", @@ -4784,24 +4689,6 @@ version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" -[[package]] -name = "wl-clipboard-rs" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d7888ccd4896447b2d14d3a9350a85df2aeb6f181e2e7a31349d104ac46cac1" -dependencies = [ - "libc", - "log", - "os_pipe", - "rustix 1.1.5", - "thiserror 2.0.21", - "tree_magic_mini", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-wlr", -] - [[package]] name = "writeable" version = "0.6.4" diff --git a/Cargo.toml b/Cargo.toml index 958318b38..a0aea6574 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,10 +51,10 @@ quick-xml = "0.42" # ui craft-ui = { version = "0.1.0", git = "https://github.com/storytold/craft-libs", rev = "5c874d51eeb3de70e735c8ce87a59a7dedd47675", features = ["serde"] } -egui = "0.37" -egui_kittest = "0.37" -eframe = { version = "0.37", default-features = false } -egui-wgpu = "0.37" +egui = "0.36" +egui_kittest = "0.36" +eframe = { version = "0.36", default-features = false } +egui-wgpu = "0.36" rfd = "0.17" arboard = { version = "3.6", default-features = false } From 9621dcbd9442606f640e489d664733c85a3e5679 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 09:30:10 +0200 Subject: [PATCH 05/13] dwg: drop the dimension bit-0 inversion that acadrust 0.6.5 now does itself --- crates/dwg/src/lib.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/crates/dwg/src/lib.rs b/crates/dwg/src/lib.rs index 273229247..f8a48f2a0 100644 --- a/crates/dwg/src/lib.rs +++ b/crates/dwg/src/lib.rs @@ -107,7 +107,6 @@ mod native { current_style_names(&mut doc); table_merges(&mut doc); table_style_rows(&mut doc, false); - dimension_flags(&mut doc, false); let orphans = drop_orphaned_dgn_components(&mut doc); if orphans > 0 { let (s, were) = if orphans == 1 { ("", "was") } else { ("s", "were") }; @@ -291,24 +290,14 @@ mod native { } } - /// The DWG dimension flags byte. Its bit 0 is the opposite of DXF group 70's bit 128 (set: the - /// text is at its default position) and its bit 1 is group 70's bit 32 (ODA DWG - /// specification, common dimension data), while acadrust 0.6.4 reads and writes bit 0 as - /// `text_user_positioned` itself and keeps no bit 32 from DXF. Without this, every dimension - /// of a DWG CADCraft writes is user-positioned for AutoCAD (#1094), and every dimension of an - /// AutoCAD DWG is read as user-positioned. `to_dwg` sets the fields up for the writer: - /// bit 32 as CADCraft's DXF writer always sets it, and bit 0 through the inverted field; - /// otherwise the field is read from bit 0 after a DWG is read. - fn dimension_flags(doc: &mut acadrust::CadDocument, to_dwg: bool) { + /// The DWG dimension flags byte. Its bit 1 is DXF group 70's bit 32 (ODA DWG specification, + /// common dimension data), which acadrust keeps no copy of from DXF: it is set here as + /// CADCraft's DXF writer always sets it (#1094). Bit 0, the opposite of group 70's bit 128, + /// acadrust 0.6.5 reads and writes itself. + fn dimension_flags(doc: &mut acadrust::CadDocument) { for e in doc.entities_mut() { let acadrust::entities::EntityType::Dimension(d) = e else { continue }; - let b = d.base_mut(); - if to_dwg { - b.dwg_flags_byte |= 0x02; - b.text_user_positioned = !b.text_user_positioned; - } else { - b.text_user_positioned = b.dwg_flags_byte & 0x01 == 0; - } + d.base_mut().dwg_flags_byte |= 0x02; } } @@ -549,7 +538,7 @@ mod native { } other_layout_owners(&mut doc); table_style_rows(&mut doc, true); - dimension_flags(&mut doc, true); + dimension_flags(&mut doc); drop_unwritable(&mut doc); current_dimstyle(&mut doc); current_text_style(&mut doc); From 51db2d52e417578159bdbd0c1820e2d7a905ba2a Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 09:49:38 +0200 Subject: [PATCH 06/13] dependabot: leave the egui crates at 0.36 until craft-ui moves to 0.37 (craft-libs#199) --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2c4b8cb1a..093325ba7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,6 +14,17 @@ updates: - "*" commit-message: prefix: "chore(deps)" + # craft-ui is still on egui 0.36, and two eguis in the graph don't build (#1990). Remove this + # once craft-ui moves to egui 0.37 (storytold/craft-libs#199). + ignore: + - dependency-name: "egui" + versions: [">=0.37"] + - dependency-name: "eframe" + versions: [">=0.37"] + - dependency-name: "egui-wgpu" + versions: [">=0.37"] + - dependency-name: "egui_kittest" + versions: [">=0.37"] # Maintain GitHub Actions workflows - package-ecosystem: "github-actions" From 251fddb658a606cd950573fe576bd9894f41c429 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 09:49:38 +0200 Subject: [PATCH 07/13] fonts: harfrust comment names both versions; the advance check skips fonts at 1000 per em --- Cargo.toml | 4 ++-- crates/fonts/src/complex.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a0aea6574..cabb8a06c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,8 +40,8 @@ rayon = "1" tiny-skia = { version = "0.12", default-features = false, features = ["std", "simd", "png-format"] } lyon_tessellation = "1.0.22" skrifa = "0.48" -# Text shaping (OpenType GSUB/GPOS, HarfBuzz port on read-fonts; the version egui's epaint uses) -# and the Unicode Bidirectional Algorithm for right-to-left drawing text. +# Text shaping (OpenType GSUB/GPOS, HarfBuzz port on read-fonts; egui's epaint is still on 0.12, +# so the graph has both) and the Unicode Bidirectional Algorithm for right-to-left drawing text. harfrust = "0.14" unicode-bidi = "0.3.18" image = { version = "0.25", default-features = false, features = ["png", "jpeg"] } diff --git a/crates/fonts/src/complex.rs b/crates/fonts/src/complex.rs index 1d76f813e..dafabdc7c 100644 --- a/crates/fonts/src/complex.rs +++ b/crates/fonts/src/complex.rs @@ -310,8 +310,13 @@ mod tests { assert_eq!(gids.len(), 2, "{gids:?}"); assert!(gids.first() != Some(&ka) && gids.last() == Some(&ka), "vowel sign before ka: {gids:?}"); assert!(gs.iter().all(|g| g.cluster == 2), "{:?}", gs.iter().map(|g| g.cluster).collect::>()); - // Advances come out at 1000 units per em, whatever the font's own em. - let hmtx = face.font().and_then(|f| f.glyph_metrics(Size::new(1000.0), LocationRef::default()).advance_width(skrifa::GlyphId::new(ka))); + // Advances come out at 1000 units per em, whatever the font's own em. A font that is + // already at 1000 per em could not tell a missing scale apart, so it checks nothing here. + let Some(font) = face.font() else { return }; + if font.metrics(Size::unscaled(), LocationRef::default()).units_per_em == 1000 { + return; + } + let hmtx = font.glyph_metrics(Size::new(1000.0), LocationRef::default()).advance_width(skrifa::GlyphId::new(ka)); let adv = gs.last().map(|g| g.advance); assert!(matches!((adv, hmtx), (Some(a), Some(h)) if (a - f64::from(h)).abs() < 1e-3), "{adv:?} vs {hmtx:?}"); } From 8ad9a3ce158a983c5aa4146a5503ddca81bb54f5 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 14:54:19 +0200 Subject: [PATCH 08/13] dwg: require acadrust 0.6.5, the first version that inverts dimension bit 0 itself --- crates/dwg/Cargo.toml | 2 +- crates/io/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/dwg/Cargo.toml b/crates/dwg/Cargo.toml index 398df0a35..a409e5b90 100644 --- a/crates/dwg/Cargo.toml +++ b/crates/dwg/Cargo.toml @@ -10,4 +10,4 @@ workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # MPL-2.0: used as an unmodified dependency only (see plan/adr/0001 and NOTICE). -acadrust = "0.6.4" +acadrust = "0.6.5" diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml index b056603c1..395ec4966 100644 --- a/crates/io/Cargo.toml +++ b/crates/io/Cargo.toml @@ -24,5 +24,5 @@ quick-xml = { workspace = true } [dev-dependencies] # Reads CADCraft's DWG output as written (tests only; the same version as cadcraft-dwg's). -acadrust = "0.6.4" +acadrust = "0.6.5" tiny-skia = { workspace = true } From 78decf80f79ead81870e4826c51b765779d90aef Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Fri, 23 Oct 2026 11:16:34 -0400 Subject: [PATCH 09/13] web: allow browser zoom in the viewport meta (SonarCloud Web:S7926) (#1974) user-scalable=no stops people with low vision from zooming the page. The canvas keeps its own pinch/pan handling: eframe already prevent_default()s touch and gesture events on the canvas, so dropping the flag only restores browser zoom (and accessibility zoom) outside of the app's gestures. --- apps/cadcraft-web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cadcraft-web/index.html b/apps/cadcraft-web/index.html index c8e2e9603..6cd4ab971 100644 --- a/apps/cadcraft-web/index.html +++ b/apps/cadcraft-web/index.html @@ -2,7 +2,7 @@ - + CADCraft