1use rust_fontconfig::{FcFontCache, FcWeight, PatternMatch};
7
8fn main() {
9 let cache = FcFontCache::build();
10
11 let families = vec![
13 "system-ui".to_string(),
14 "sans-serif".to_string(),
15 ];
16
17 let mut trace = Vec::new();
18 let chain = cache.resolve_font_chain(
19 &families,
20 FcWeight::Normal,
21 PatternMatch::False,
22 PatternMatch::False,
23 &mut trace,
24 );
25
26 let test_chars = vec![
28 ('A', "Latin Capital Letter A"),
29 ('a', "Latin Small Letter A"),
30 ('0', "Digit Zero"),
31 ('€', "Euro Sign"),
32 ('→', "Rightwards Arrow"),
33 ('中', "CJK Ideograph - China"),
34 ('日', "CJK Ideograph - Sun/Day"),
35 ('あ', "Hiragana Letter A"),
36 ('ア', "Katakana Letter A"),
37 ('한', "Hangul Syllable Han"),
38 ('א', "Hebrew Letter Alef"),
39 ('ا', "Arabic Letter Alef"),
40 ('α', "Greek Small Letter Alpha"),
41 ('Σ', "Greek Capital Letter Sigma"),
42 ('я', "Cyrillic Small Letter Ya"),
43 ('🙂', "Slightly Smiling Face"),
44 ('♠', "Black Spade Suit"),
45 ('∑', "N-ary Summation"),
46 ('∞', "Infinity"),
47 ('℃', "Degree Celsius"),
48 ];
49
50 println!("Character resolution results:\n");
51 println!("{:<6} {:<30} {:<40}", "Char", "Description", "Font");
52 println!("{}", "-".repeat(80));
53
54 for (ch, description) in test_chars {
55 let text = ch.to_string();
56 let resolved = chain.resolve_text(&cache, &text);
57
58 let font_name = resolved.first()
59 .and_then(|(_, info)| info.as_ref())
60 .and_then(|(id, _)| cache.get_metadata_by_id(id))
61 .and_then(|m| m.name.clone().or(m.family.clone()))
62 .unwrap_or_else(|| "⚠ NOT FOUND".to_string());
63
64 println!("{:<6} {:<30} {}", ch, description, font_name);
65 }
66
67 println!("\n\nFont Coverage Check\n");
69
70 let pattern = rust_fontconfig::FcPattern {
71 family: Some("Arial".to_string()),
72 ..Default::default()
73 };
74
75 if let Some(match_result) = cache.query(&pattern, &mut Vec::new()) {
76 println!("Checking Arial coverage:");
77
78 let arial_chain = cache.resolve_font_chain(
80 &vec!["Arial".to_string()],
81 FcWeight::Normal,
82 PatternMatch::False,
83 PatternMatch::False,
84 &mut Vec::new(),
85 );
86
87 let check_chars = ['A', '中', '🙂', '→'];
88 for ch in check_chars {
89 let resolved = arial_chain.resolve_text(&cache, &ch.to_string());
90 let found_in_arial = resolved.first()
91 .and_then(|(_, info)| info.as_ref())
92 .map(|(id, _)| id == &match_result.id)
93 .unwrap_or(false);
94
95 let status = if found_in_arial { "✓" } else { "✗" };
96 println!(" {} '{}' (U+{:04X})", status, ch, ch as u32);
97 }
98 }
99
100 println!("\n\nUnicode Block Coverage Summary\n");
102
103 let blocks = [
104 ("Basic Latin", 0x0020..0x007F),
105 ("Latin Extended-A", 0x0100..0x017F),
106 ("Greek", 0x0370..0x03FF),
107 ("Cyrillic", 0x0400..0x04FF),
108 ("Arabic", 0x0600..0x06FF),
109 ("CJK Unified Ideographs", 0x4E00..0x9FFF),
110 ("Hiragana", 0x3040..0x309F),
111 ("Katakana", 0x30A0..0x30FF),
112 ];
113
114 for (name, range) in blocks {
115 let sample_points: Vec<char> = range.clone()
117 .step_by(range.len() / 5)
118 .take(5)
119 .filter_map(|cp| char::from_u32(cp))
120 .collect();
121
122 let sample_text: String = sample_points.iter().collect();
123 let resolved = chain.resolve_text(&cache, &sample_text);
124
125 let fonts_used: std::collections::HashSet<_> = resolved.iter()
126 .filter_map(|(_, info)| info.as_ref())
127 .map(|(id, _)| id.clone())
128 .collect();
129
130 let coverage = resolved.iter()
131 .filter(|(_, info)| info.is_some())
132 .count() as f32 / resolved.len() as f32 * 100.0;
133
134 println!("{:<30} {:>6.1}% coverage ({} fonts)", name, coverage, fonts_used.len());
135 }
136}