Skip to main content

character_resolution/
character_resolution.rs

1//! Character resolution example
2//!
3//! Demonstrates how to resolve individual characters to fonts using font chains.
4//! Useful for debugging font coverage issues (e.g. CJK, emoji, symbols).
5//!
6//! Run with:
7//!   cargo run --example character_resolution
8
9use rust_fontconfig::{FcFontCache, FcWeight, PatternMatch};
10
11fn main() {
12    let cache = FcFontCache::build();
13
14    // Create a font chain with typical web defaults
15    let families = vec!["system-ui".to_string(), "sans-serif".to_string()];
16
17    let chain = cache.resolve_font_chain(
18        &families,
19        FcWeight::Normal,
20        PatternMatch::False,
21        PatternMatch::False,
22        &mut Vec::new(),
23    );
24
25    // Test characters from different Unicode blocks
26    let test_chars = [
27        ('A', "Latin Capital Letter A"),
28        ('a', "Latin Small Letter A"),
29        ('0', "Digit Zero"),
30        ('€', "Euro Sign"),
31        ('→', "Rightwards Arrow"),
32        ('中', "CJK Ideograph - China"),
33        ('日', "CJK Ideograph - Sun/Day"),
34        ('あ', "Hiragana Letter A"),
35        ('ア', "Katakana Letter A"),
36        ('한', "Hangul Syllable Han"),
37        ('א', "Hebrew Letter Alef"),
38        ('ا', "Arabic Letter Alef"),
39        ('α', "Greek Small Letter Alpha"),
40        ('я', "Cyrillic Small Letter Ya"),
41        ('🙂', "Slightly Smiling Face"),
42        ('♠', "Black Spade Suit"),
43        ('∑', "N-ary Summation"),
44        ('∞', "Infinity"),
45    ];
46
47    println!("Character resolution results:\n");
48    println!("{:<6} {:<30} {:<40}", "Char", "Description", "Font");
49    println!("{}", "-".repeat(76));
50
51    for (ch, description) in &test_chars {
52        let text = ch.to_string();
53        let resolved = chain.resolve_text(&cache, &text);
54
55        let font_name = resolved
56            .first()
57            .and_then(|(_, info)| info.as_ref())
58            .and_then(|(id, _)| cache.get_metadata_by_id(id))
59            .and_then(|m| m.name.clone().or(m.family.clone()))
60            .unwrap_or_else(|| "⚠ NOT FOUND".to_string());
61
62        println!("{:<6} {:<30} {}", ch, description, font_name);
63    }
64
65    // Check specific font coverage
66    println!("\n\nArial coverage check:");
67    let arial_chain = cache.resolve_font_chain(
68        &["Arial".to_string()],
69        FcWeight::Normal,
70        PatternMatch::False,
71        PatternMatch::False,
72        &mut Vec::new(),
73    );
74
75    let arial_result = cache.query(
76        &rust_fontconfig::FcPattern {
77            family: Some("Arial".to_string()),
78            ..Default::default()
79        },
80        &mut Vec::new(),
81    );
82
83    if let Some(arial_match) = arial_result {
84        for ch in ['A', '中', '🙂', '→'] {
85            let resolved = arial_chain.resolve_text(&cache, &ch.to_string());
86            let in_arial = resolved
87                .first()
88                .and_then(|(_, info)| info.as_ref())
89                .map(|(id, _)| id == &arial_match.id)
90                .unwrap_or(false);
91
92            println!(
93                "  {} '{}' (U+{:04X})",
94                if in_arial { "✓" } else { "✗" },
95                ch,
96                ch as u32
97            );
98        }
99    } else {
100        println!("  Arial not found on this system");
101    }
102}