1pub use inner::test_fonts;
2
3#[cfg(all(unix, feature = "fontconfig"))]
4mod inner {
5 use fc::{FcChar32, FcCharSet, FcConfig, FcPattern, FcResultMatch, FcSetSystem};
6 use fontconfig::fontconfig as fc;
7 use std::collections::HashSet;
8 use std::ptr;
9
10 pub fn test_fonts(
11 sextants: &mut HashSet<char>,
12 octants: &mut HashSet<char>,
13 ) -> Option<()> {
14 let config = load_config()?;
15 let (count, patterns) = get_patterns(config)?;
16 for index in 0..count {
17 let pattern = match get_pattern(patterns, index) {
18 Some(pattern) => pattern,
19 None => continue,
20 };
21 let charset = match get_charset(pattern) {
22 Some(charset) => charset,
23 None => continue,
24 };
25 test_charset(sextants, octants, charset);
26 if octants.is_empty() {
27 break;
28 }
29 }
30 Some(())
31 }
32
33 fn load_config() -> Option<*mut FcConfig> {
34 let result = unsafe { fc::FcInit() };
35 if result != 0 {
36 let config = unsafe { fc::FcInitLoadConfigAndFonts() };
37 if !config.is_null() {
38 return Some(config);
39 }
40 }
41 None
42 }
43
44 fn get_patterns(config: *mut FcConfig) -> Option<(isize, *mut *mut FcPattern)> {
45 let fonts = unsafe { fc::FcConfigGetFonts(config, FcSetSystem) };
46 if !fonts.is_null() {
47 let count = unsafe { (*fonts).nfont as isize };
48 let patterns = unsafe { (*fonts).fonts };
49 Some((count, patterns))
50 } else {
51 None
52 }
53 }
54
55 fn get_pattern(patterns: *mut *mut FcPattern, index: isize) -> Option<*mut FcPattern> {
56 let pattern = unsafe { *patterns.offset(index) };
57 if !pattern.is_null() {
58 Some(pattern)
59 } else {
60 None
61 }
62 }
63
64 fn get_charset(pattern: *mut FcPattern) -> Option<*mut FcCharSet> {
65 let mut charset: *mut FcCharSet = ptr::null_mut();
66 let object = b"charset\0".as_ptr() as *const _;
67 let result = unsafe { fc::FcPatternGetCharSet(pattern, object, 0, &mut charset) };
68 if result == FcResultMatch && !charset.is_null() {
69 Some(charset)
70 } else {
71 None
72 }
73 }
74
75 fn test_charset(
76 sextants: &mut HashSet<char>,
77 octants: &mut HashSet<char>,
78 charset: *mut FcCharSet,
79 ) {
80 const MAP_SIZE: usize = 256 / 32; let mut map: [FcChar32; MAP_SIZE] = [0; MAP_SIZE];
82 let mut next: FcChar32 = 0;
83 let mut page = unsafe { fc::FcCharSetFirstPage(charset, map.as_mut_ptr(), &mut next as *mut _) };
84 while page != !0_u32 {
85 for (index, &chunk) in map.iter().enumerate() {
86 let bits = chunk as u32;
87 for bit in 0..32_u32 {
88 if bits & (1_u32 << bit) != 0 {
89 let cp = page.wrapping_add((index as u32) * 32 + bit);
90 if let Some(char) = char::from_u32(cp) {
91 sextants.remove(&char);
92 octants.remove(&char);
93 }
94 }
95 }
96 }
97 page = unsafe { fc::FcCharSetNextPage(charset, map.as_mut_ptr(), &mut next as *mut _) };
98 }
99 }
100}
101
102#[cfg(not(all(unix, feature = "fontconfig")))]
103mod inner {
104 use std::collections::HashSet;
105
106 pub fn test_fonts(
107 _sextants: &mut HashSet<char>,
108 _octants: &mut HashSet<char>,
109 ) -> Option<()> {
110 None
111 }
112}