pub(super) fn reflow_font_stack(family: &str) -> String {
const SANS_MARKERS: [&str; 6] = [
"gothic",
"sans",
"grotesk",
"grotesque",
"helvetica",
"arial",
];
let lower = family.to_ascii_lowercase();
let safe: String = family
.chars()
.filter(|c| !matches!(c, '\'' | '"' | '\\' | '<' | '>'))
.collect();
if is_monospace_family(family) {
format!("'{safe}', 'DejaVu Sans Mono', Menlo, Consolas, monospace")
} else if SANS_MARKERS.iter().any(|m| lower.contains(m)) {
format!("'{safe}', 'Noto Sans CJK JP', 'Hiragino Sans', sans-serif")
} else {
format!("'{safe}', 'Noto Serif CJK JP', 'Hiragino Mincho ProN', Georgia, serif")
}
}
pub(super) fn is_monospace_family(family: &str) -> bool {
const MONO_MARKERS: [&str; 6] = ["mono", "courier", "consol", "menlo", "typewriter", "teletype"];
let lower = family.to_ascii_lowercase();
MONO_MARKERS.iter().any(|m| lower.contains(m))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_reflow_stack_names_the_face_first_and_always_ends_in_a_generic() {
let mincho = reflow_font_stack("IPAexMincho");
assert!(mincho.starts_with("'IPAexMincho',"), "{mincho}");
assert!(mincho.ends_with("serif"), "{mincho}");
assert!(!mincho.contains('"'), "{mincho}");
assert!(!reflow_font_stack("Od\"d'Name").contains('"'));
let gothic = reflow_font_stack("IPAexGothic");
assert!(gothic.ends_with("sans-serif"), "{gothic}");
assert!(reflow_font_stack("Junicode").ends_with("serif"));
assert!(!reflow_font_stack("Junicode").ends_with("sans-serif"));
}
#[test]
fn a_fixed_pitch_face_ends_in_monospace_and_beats_the_sans_marker() {
let lm = reflow_font_stack("LMMono10");
assert!(lm.starts_with("'LMMono10',"), "{lm}");
assert!(lm.ends_with("monospace"), "{lm}");
assert!(reflow_font_stack("DejaVu Sans Mono").ends_with("monospace"));
assert!(!is_monospace_family("Junicode"));
assert!(!is_monospace_family("IPAexGothic"));
}
}