From da5332b5df78ad0957f94853b421de31e6a975bb Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 12 Oct 2026 06:37:15 -0400 Subject: [PATCH] Lists: draw an installed symbol font's bullet from its own glyph A bare-code Wingdings bullet drawn as U+25AA came from a fallback face whose taller ascent made every bulleted line about 1 pt taller than Word's. Where the symbol font is installed, its glyph at the private-use code is drawn instead, with the font's own metrics. Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/layout/src/para.rs | 12 +++++++++--- crates/layout/src/tests.rs | 12 +++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/crates/layout/src/para.rs b/crates/layout/src/para.rs index 93483ea3a..604cfea1e 100644 --- a/crates/layout/src/para.rs +++ b/crates/layout/src/para.rs @@ -1245,9 +1245,15 @@ pub fn layout_para(p: &Paragraph, env: &ParaEnv) -> ParaLayout { let r = wordcraft_fonts::word::resolve(&rc.font, rc.bold, rc.italic); let text: String = text .chars() - .map(|c| match wordcraft_fonts::word::symbol_font_char(&rc.font, c) { - Some(u) if r.substituted || !r.face.covers(c) => u, - _ => c, + .map(|c| { + // A bare code (`ยง` = 0xA7) in a symbol font that is installed: its glyph sits at the + // private-use code (U+F0A7); drawn from that font, the line keeps Word's metrics. + let private = (u32::from(c) < 0x100).then(|| char::from_u32(0xF000 + u32::from(c))).flatten(); + match (private, wordcraft_fonts::word::symbol_font_char(&rc.font, c)) { + (Some(pc), Some(_)) if !r.substituted && !r.face.covers(c) && r.face.covers(pc) => pc, + (_, Some(u)) if r.substituted || !r.face.covers(c) => u, + _ => c, + } }) .collect(); let before_c = b.clusters.len(); diff --git a/crates/layout/src/tests.rs b/crates/layout/src/tests.rs index 65c325c84..f2e5973a6 100644 --- a/crates/layout/src/tests.rs +++ b/crates/layout/src/tests.rs @@ -3963,7 +3963,17 @@ fn bare_code_wingdings_bullet_draws_its_square() { d.format_paragraphs(&Pos::body(0, 0), &Pos::body(0, 0), &|p| p.numbering = Some(wordcraft_doc::props::NumRef { num: id, level: 0 })).unwrap(); let l = lay(&d); let label = l.pages[0].items.iter().find_map(|it| if let Placed::Lines { para, .. } = it { para.label.clone() } else { None }).unwrap(); + // Where Wingdings is installed (Windows) its own glyph at the private-use code is drawn, + // which keeps Word's line height; elsewhere the standard square. let wd = wordcraft_fonts::word::resolve("Wingdings", false, false); - let expected = if wd.substituted || !wd.face.covers('\u{A7}') { "\u{25AA}" } else { "\u{A7}" }; + let expected = if wd.substituted { + "\u{25AA}" + } else if wd.face.covers('\u{A7}') { + "\u{A7}" + } else if wd.face.covers('\u{F0A7}') { + "\u{F0A7}" + } else { + "\u{25AA}" + }; assert_eq!(label.text, expected); }