From ff9c0f88d3b7975a316f6869b5d250200178885a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 12 Oct 2026 10:33:03 -0400 Subject: [PATCH] documents: a diagram letter no font has is an export error --- src/documents/diagram.rs | 46 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/documents/diagram.rs b/src/documents/diagram.rs index 52fbcce..62ea63b 100644 --- a/src/documents/diagram.rs +++ b/src/documents/diagram.rs @@ -112,10 +112,12 @@ pub fn diagram_svg(source: &str) -> Result { }; let tree = usvg::Tree::from_data(drawn.as_bytes(), &options) .map_err(|error| SharedString::from(format!("{error}")))?; - // A label without a font vanishes: say so. - let (written, kept) = (labels(&drawn)?, texts(tree.root())); - if kept < written { - log::error!("diagram: {kept} of {written} labels found a font"); + // A letter without a font vanishes: say so. + let (mut kept, mut lost) = (0, 0); + texts(tree.root(), &mut kept, &mut lost); + let written = labels(&drawn)?; + if kept < written || lost > 0 { + log::error!("diagram: {kept} of {written} labels set, {lost} letters without a font"); return Err("no installed font could set this diagram's labels".into()); } Ok(tree.to_string(&usvg::WriteOptions::default())) @@ -135,17 +137,25 @@ fn labels(svg: &str) -> Result { .count()) } -/// Text nodes usvg set. -fn texts(group: &usvg::Group) -> usize { - group - .children() - .iter() - .map(|node| match node { - usvg::Node::Group(inner) => texts(inner), - usvg::Node::Text(_) => 1, - _ => 0, - }) - .sum() +/// Text nodes usvg set, and letters it found no glyph for. +fn texts(group: &usvg::Group, kept: &mut usize, lost: &mut usize) { + for node in group.children() { + match node { + usvg::Node::Group(inner) => texts(inner, kept, lost), + usvg::Node::Text(text) => { + *kept += 1; + let glyphs = text + .layouted() + .iter() + .flat_map(|span| &span.positioned_glyphs); + // Glyph zero is a font's blank for a missing letter. + *lost += glyphs + .filter(|glyph| glyph.id.0 == 0 && !glyph.text.trim().is_empty()) + .count(); + } + _ => {} + } + } } /// The system's fonts, read once. @@ -259,6 +269,12 @@ mod tests { assert!(!svg.contains(" B").expect_err("no glyph"); + assert!(why.contains("font"), "{why}"); + } + #[test] fn colors_write_as_hex() { assert_eq!(hex(gpui::rgb(0x2c2c2c).into()), "#2c2c2c");