atmos/kernel/font_select.rs
1//! ウェイト付きフォントを選んでよいかの判定(純粋モジュール)。
2//!
3//! 仕様は `spec/webfont_loading.md`。
4//!
5//! Google Fonts は `unicode-range` でファイルを分割して配信するため、
6//! 「Noto Sans JP のウェイト 700」が Latin だけのサブセットということがある。
7//! 太字だからと無条件にそのファイルを選ぶと、収録されていない文字が欠ける。
8//!
9//! フォントもハードウェアも要らない純粋な判定なので、QEMU 抜きで検証できる。
10
11/// `s` に含まれる文字を**すべて**描けるなら `true`。
12///
13/// `has_glyph` は「そのフォント自身が字形を持っているか」を返す述語
14/// (代替チェーンを辿った結果ではない点が要点。辿ってしまうと
15/// 「持っている」と誤判定してサブセットを選んでしまう)。
16///
17/// # 先頭 1 文字では足りない
18///
19/// 【2026-08-05】当初は先頭の非空白文字 1 つだけを見ていた。
20/// 「同じ文字体系が続くはず」という前提を置いたが、**これは誤り**。
21/// 実サイトには
22///
23/// ```text
24/// IoT、情報家電、AI技術を駆使して
25/// ```
26///
27/// のように 1 つの文字列で書体が混ざる例がふつうにある。
28/// 先頭が `I` なので Latin サブセットが選ばれ、後続の日本語が
29/// 豆腐(■)になっていた。全文字を確かめる必要がある。
30///
31/// 空白は書体を問わないので除く。空文字列・空白のみは `true`
32/// (描くものが無いので、どのフォントを選んでも結果は変わらない)。
33///
34/// 計算量: **O(L)**(L は文字数)。文字列は短く、
35/// 1 回の描画につきウェイト候補の数だけしか呼ばれない。
36pub fn covers_all(s: &str, has_glyph: impl Fn(char) -> bool) -> bool {
37 s.chars().filter(|c| !c.is_whitespace()).all(has_glyph)
38}