debug_azul_fonts/
debug_azul_fonts.rs1use rust_fontconfig::{FcFontCache, FcPattern, FcWeight, PatternMatch};
10
11fn main() {
12 println!("=== System Font Italic Race Condition Test ===\n");
13
14 println!("Building font cache (scanning system fonts)...");
16 let cache = FcFontCache::build();
17 let all_fonts = cache.list();
18 println!("Cache built: {} patterns\n", all_fonts.len());
19
20 println!("--- ALL fonts containing 'system' or 'sfns' in name/family ---");
22 for (pattern, id) in all_fonts {
23 let name_lower = pattern.name.as_deref().unwrap_or("").to_lowercase();
24 let family_lower = pattern.family.as_deref().unwrap_or("").to_lowercase();
25 if name_lower.contains("system") || name_lower.contains("sfns")
26 || family_lower.contains("system") || family_lower.contains("sfns") {
27 let style_score = FcFontCache::calculate_style_score(
28 &FcPattern {
29 weight: FcWeight::Normal,
30 italic: PatternMatch::False,
31 oblique: PatternMatch::False,
32 ..Default::default()
33 },
34 pattern,
35 );
36 println!(
37 " id={} name={:?} family={:?} italic={:?} bold={:?} weight={:?} stretch={:?} style_score={} subfamily={:?}",
38 id,
39 pattern.name.as_deref().unwrap_or("?"),
40 pattern.family.as_deref().unwrap_or("?"),
41 pattern.italic,
42 pattern.bold,
43 pattern.weight,
44 pattern.stretch,
45 style_score,
46 pattern.metadata.font_subfamily.as_deref().unwrap_or("?"),
47 );
48 }
49 }
50 println!();
51
52 let families = vec!["System Font".to_string()];
54 let mut trace = Vec::new();
55
56 let chain = cache.resolve_font_chain(
57 &families,
58 FcWeight::Normal,
59 PatternMatch::False, PatternMatch::False, &mut trace,
62 );
63
64 println!("Font chain for 'System Font' (italic=False, weight=Normal):");
65 for group in &chain.css_fallbacks {
66 println!(" CSS name: '{}'", group.css_name);
67 for (i, font_match) in group.fonts.iter().enumerate() {
68 let meta = cache.get_metadata_by_id(&font_match.id);
69 if let Some(pattern) = meta {
70 let style_score = FcFontCache::calculate_style_score(
71 &FcPattern {
72 weight: FcWeight::Normal,
73 italic: PatternMatch::False,
74 oblique: PatternMatch::False,
75 ..Default::default()
76 },
77 pattern,
78 );
79 println!(
80 " [{}] id={} name={:?} family={:?} italic={:?} bold={:?} weight={:?} style_score={} subfamily={:?}",
81 i,
82 font_match.id,
83 pattern.name.as_deref().unwrap_or("?"),
84 pattern.family.as_deref().unwrap_or("?"),
85 pattern.italic,
86 pattern.bold,
87 pattern.weight,
88 style_score,
89 pattern.metadata.font_subfamily.as_deref().unwrap_or("?"),
90 );
91 } else {
92 println!(" [{}] id={} (no metadata)", i, font_match.id);
93 }
94 }
95 }
96
97 let first_font = chain.css_fallbacks
99 .iter()
100 .flat_map(|g| g.fonts.iter())
101 .next();
102
103 if let Some(font) = first_font {
104 if let Some(meta) = cache.get_metadata_by_id(&font.id) {
105 if meta.italic == PatternMatch::True {
106 eprintln!("\n❌ FAIL: First matched font is ITALIC!");
107 eprintln!(" Font: {:?} (id={})", meta.name, font.id);
108 eprintln!(" This is the italic race condition bug.");
109 std::process::exit(1);
110 } else {
111 println!("\n✅ PASS: First matched font is NOT italic.");
112 println!(" Font: {:?} (id={})", meta.name, font.id);
113 }
114 }
115 } else {
116 eprintln!("\n⚠ WARNING: No fonts matched 'System Font'");
117 }
118
119 println!("\n--- Comparison: italic=DontCare ---");
121 let mut trace2 = Vec::new();
122 let chain2 = cache.resolve_font_chain(
123 &families,
124 FcWeight::Normal,
125 PatternMatch::DontCare,
126 PatternMatch::DontCare,
127 &mut trace2,
128 );
129
130 for group in &chain2.css_fallbacks {
131 for (i, font_match) in group.fonts.iter().enumerate() {
132 if let Some(pattern) = cache.get_metadata_by_id(&font_match.id) {
133 println!(
134 " [{}] {:?} italic={:?} weight={:?}",
135 i,
136 pattern.name.as_deref().unwrap_or("?"),
137 pattern.italic,
138 pattern.weight,
139 );
140 }
141 }
142 }
143
144 println!("\n--- Determinism check (10 runs) ---");
146 let mut all_same = true;
147 let mut first_result = None;
148
149 for run in 0..10 {
150 let mut trace_n = Vec::new();
152 let chain_n = cache.resolve_font_chain(
153 &families,
154 FcWeight::Normal,
155 PatternMatch::False,
156 PatternMatch::False,
157 &mut trace_n,
158 );
159
160 let first_id = chain_n.css_fallbacks
161 .iter()
162 .flat_map(|g| g.fonts.iter())
163 .next()
164 .map(|f| f.id);
165
166 if let Some(id) = first_id {
167 if first_result.is_none() {
168 first_result = Some(id);
169 } else if first_result != Some(id) {
170 println!(" Run {}: id={} — DIFFERENT from first run!", run, id);
171 all_same = false;
172 }
173 }
174 }
175
176 if all_same {
177 println!(" All 10 runs returned the same first font. ✅");
178 } else {
179 println!(" Results varied across runs! ❌");
180 }
181
182 println!("\n=== Test complete ===");
183}