fix(text): keep private-use bullets in named Unicode symbol fonts; .notdef falls back to a dot

Private-use codes are mapped by code only when no bullet font is named or it is a legacy symbol
font. A bullet that the cascaded face still cannot draw uses the dot instead of .notdef.
This commit is contained in:
Harrison Booth committed 2026-10-27 19:17:11 -05:00
1 parent b5257f9446
commit 9d32bc4da9
3 files changed
+8 -3

No files matched your search

+4
View File
@@ -91,6 +91,10 @@ pub(crate) fn shape_para(
None => map_symbol_bullet(char, props.bullet_font.as_deref()),
};
bullet_face(db, &mut st, &ch);
// A face the cascade still picks may lack the bullet: draw the dot rather than .notdef.
let chars: Vec<char> = ch.chars().collect();
let ch = if deckcraft_fonts::covers_cluster(&st.face, &chars) { ch } else { "•".into() };
bullet_face(db, &mut st, &ch);
Some((ch, st))
}
Some(Bullet::AutoNum { scheme, start_at }) => {
+2 -2
View File
@@ -276,8 +276,8 @@ pub fn map_symbol_bullet(c: &str, font: Option<&str>) -> String {
return m.to_string();
}
// Only the legacy symbol fonts: "Noto Sans Symbols" and the like are Unicode fonts whose
// characters (❑ ❖) are drawn as they are.
if f.contains("wingdings") || f == "symbol" || ('\u{f000}'..='\u{f0ff}').contains(&first) {
// characters (❑ ❖) are drawn as they are. Private-use codes are mapped only when no font is named.
if f.contains("wingdings") || f == "symbol" || (font.is_none() && ('\u{f000}'..='\u{f0ff}').contains(&first)) {
let code = (first as u32) & 0xff;
// Wingdings 2 and 3 put different shapes at the same codes.
if f.starts_with("wingdings 2") {
+2 -1
View File
@@ -180,7 +180,7 @@ fn only_the_first_character_of_a_bullet_is_drawn() {
#[test]
fn bullet_in_an_unavailable_unicode_symbol_font_keeps_its_character() {
// Google Slides bullets in "Noto Sans Symbols" (not installed) draw ❑ ❖, not a generic dot (#1347).
for c in ["\u{2751}", "\u{2756}"] {
for c in ["\u{2751}", "\u{2756}", "\u{f0a7}"] {
assert_eq!(map_symbol_bullet(c, Some("Noto Sans Symbols")), c);
}
// The legacy symbol fonts still map their codes.
@@ -192,6 +192,7 @@ fn bullet_in_an_unavailable_unicode_symbol_font_keeps_its_character() {
let l = lay(&p, &sh, 600.0, 300.0);
let bullet = l.runs.iter().find(|r| r.chars == (0, 0)).expect("bullet run");
assert_eq!(bullet.glyphs.len(), 1);
assert_ne!(bullet.glyphs[0].0, 0, "the bullet is drawn, not .notdef");
}
#[test]