Merge #1163: M9: fall back to the Noto symbol and math fonts on Linux (#1156) (@switch87)

# Conflicts:
#	crates/text/src/behaviour_tests.rs
#	crates/text/src/fontdb.rs
This commit is contained in:
bflatastic
2026-10-24 09:35:53 +07:00
3 changed files with 43 additions and 2 deletions
+22
View File
@@ -296,6 +296,28 @@ fn thai_comes_from_a_thai_font_when_one_is_installed() {
assert_eq!(drawn, want, "every Thai char is in a drawn cluster");
}
#[test]
fn symbols_come_from_a_symbol_font_when_one_is_installed() {
// ⌖ (U+2316) and ⤒ (U+2912) are in no Latin text face. With a symbol font that has them (Apple
// Symbols on macOS, Segoe UI Symbol on Windows, Noto Sans Symbols 2 and Noto Sans Math on
// Linux) the fallback draws them instead of the missing-glyph box (#1156). Each character
// skips on a machine with no installed fallback family that has it.
let Some(f) = face() else { return };
let families = ["Apple Symbols", "Segoe UI Symbol", "Noto Sans Symbols", "Noto Sans Symbols 2", "Noto Sans Symbols2", "Noto Sans Math"];
for c in ['\u{2316}', '\u{2912}'] {
if f.has_char(c) || !families.iter().any(|k| find_face(k, "Regular").is_some_and(|k| k.has_char(c))) {
continue;
}
let t = text(&format!("A {c}"), TextAutoResize::WidthAndHeight);
let l = layout(&t, None, None);
let drawn: Vec<_> = l.glyphs.iter().filter(|g| g.char_start == 2).collect();
assert!(!drawn.is_empty(), "U+{:04X} has a glyph", c as u32);
for g in drawn {
assert!(g.face.has_char(c), "U+{:04X} drawn by {} {}, which lacks it", c as u32, g.face.family, g.face.style);
}
}
}
#[test]
fn break_opportunities() {
// (before, after, may break between, derivation)
+8 -2
View File
@@ -405,8 +405,10 @@ fn names(f: &skrifa::FontRef) -> (Option<String>, Option<String>) {
(family, style)
}
/// Families tried, in order, for characters a text's own font lacks.
const FALLBACK_FAMILIES: [&str; 25] = [
/// Families tried, in order, for characters a text's own font lacks. The symbol fonts come last:
/// Apple Symbols (macOS), Segoe UI Symbol (Windows) and the Noto symbol and math fonts (Linux), for
/// signs such as ⌖ and ⤒ that no text face has.
const FALLBACK_FAMILIES: [&str; 29] = [
"Inter",
"Helvetica Neue",
"Arial",
@@ -432,6 +434,10 @@ const FALLBACK_FAMILIES: [&str; 25] = [
"Tahoma",
"Apple Symbols",
"Segoe UI Symbol",
"Noto Sans Symbols",
"Noto Sans Symbols 2",
"Noto Sans Symbols2",
"Noto Sans Math",
];
/// A system font file entry not yet loaded.
+13
View File
@@ -192,6 +192,19 @@ fn fallback_faces_follow_the_runs_style() {
}
}
#[test]
fn every_platform_has_a_symbol_font_in_the_fallbacks() {
// Symbols such as ⌖ (U+2316) and ⤒ (U+2912) are in no text face (#1156): macOS has Apple
// Symbols, Windows Segoe UI Symbol, and Linux the Noto symbol and math fonts (fontconfig names
// "Noto Sans Symbols 2"; some packages name it "Noto Sans Symbols2").
for family in ["Apple Symbols", "Segoe UI Symbol", "Noto Sans Symbols", "Noto Sans Symbols 2", "Noto Sans Symbols2", "Noto Sans Math"] {
assert!(FALLBACK_FAMILIES.contains(&family), "{family} is a fallback");
}
// Text faces come first: a symbol font only draws what they lack.
let at = |f: &str| FALLBACK_FAMILIES.iter().position(|x| *x == f).unwrap();
assert!(at("Noto Sans") < at("Noto Sans Symbols") && at("DejaVu Sans") < at("Noto Sans Math"));
}
#[cfg(all(unix, not(target_os = "macos")))]
#[test]
fn user_font_dirs_follow_xdg_data_home() {