unicode_aware_fonts/
unicode_aware_fonts.rs1use rust_fontconfig::{FcFontCache, FcWeight, PatternMatch};
6
7fn main() {
8 let cache = FcFontCache::build();
10
11 println!("=== Unicode-Aware Font Selection ===\n");
12
13 println!("Step 1: Resolve font chain for 'sans-serif'");
15 let mut trace = Vec::new();
16 let chain = cache.resolve_font_chain(
17 &vec!["sans-serif".to_string()],
18 FcWeight::Normal,
19 PatternMatch::False, PatternMatch::False, &mut trace,
22 );
23
24 println!(" Font chain has {} CSS fallbacks and {} unicode fallbacks\n",
25 chain.css_fallbacks.len(),
26 chain.unicode_fallbacks.len());
27
28 println!("Step 2: Resolve various texts against the font chain\n");
30
31 let latin_text = "Hello World";
33 println!("Latin text: '{}'", latin_text);
34 print_text_resolution(&cache, &chain, latin_text);
35
36 let cjk_text = "你好世界";
38 println!("\nCJK text: '{}'", cjk_text);
39 print_text_resolution(&cache, &chain, cjk_text);
40
41 let japanese_text = "こんにちは世界";
43 println!("\nJapanese text: '{}'", japanese_text);
44 print_text_resolution(&cache, &chain, japanese_text);
45
46 let arabic_text = "مرحبا بالعالم";
48 println!("\nArabic text: '{}'", arabic_text);
49 print_text_resolution(&cache, &chain, arabic_text);
50
51 let cyrillic_text = "Привет мир";
53 println!("\nCyrillic text: '{}'", cyrillic_text);
54 print_text_resolution(&cache, &chain, cyrillic_text);
55
56 let mixed_text = "Hello 世界 Привет";
58 println!("\nMixed text: '{}'", mixed_text);
59 print_text_resolution(&cache, &chain, mixed_text);
60
61 println!("\n=== Summary ===");
62 println!("The workflow is:");
63 println!("1. resolve_font_chain() - creates a fallback chain from CSS font-family");
64 println!("2. chain.resolve_text() - maps each character to a font in the chain");
65 println!("3. Use the font IDs to load and render glyphs");
66}
67
68fn print_text_resolution(
69 cache: &FcFontCache,
70 chain: &rust_fontconfig::FontFallbackChain,
71 text: &str,
72) {
73 let resolved = chain.resolve_text(cache, text);
74
75 let mut current_font: Option<String> = None;
77 let mut current_segment = String::new();
78
79 for (ch, font_info) in resolved {
80 let font_name = font_info.map(|(id, _)| {
81 cache.get_metadata_by_id(&id)
82 .and_then(|p| p.name.clone().or(p.family.clone()))
83 .unwrap_or_else(|| format!("{:?}", id))
84 });
85
86 if font_name != current_font {
87 if !current_segment.is_empty() {
88 println!(" '{}' -> {}",
89 current_segment,
90 current_font.as_deref().unwrap_or("[NO FONT]"));
91 current_segment.clear();
92 }
93 current_font = font_name;
94 }
95 current_segment.push(ch);
96 }
97
98 if !current_segment.is_empty() {
99 println!(" '{}' -> {}",
100 current_segment,
101 current_font.as_deref().unwrap_or("[NO FONT]"));
102 }
103}