pub use inner::test_fonts;
#[cfg(all(unix, feature = "fontconfig"))]
mod inner {
use fc::{FcChar32, FcCharSet, FcConfig, FcPattern, FcResultMatch, FcSetSystem};
use fontconfig::fontconfig as fc;
use std::collections::HashSet;
use std::ptr;
pub fn test_fonts(
sextants: &mut HashSet<char>,
octants: &mut HashSet<char>,
) -> Option<()> {
let config = load_config()?;
let (count, patterns) = get_patterns(config)?;
for index in 0..count {
let pattern = match get_pattern(patterns, index) {
Some(pattern) => pattern,
None => continue,
};
let charset = match get_charset(pattern) {
Some(charset) => charset,
None => continue,
};
test_charset(sextants, octants, charset);
if octants.is_empty() {
break;
}
}
Some(())
}
fn load_config() -> Option<*mut FcConfig> {
let result = unsafe { fc::FcInit() };
if result != 0 {
let config = unsafe { fc::FcInitLoadConfigAndFonts() };
if !config.is_null() {
return Some(config);
}
}
None
}
fn get_patterns(config: *mut FcConfig) -> Option<(isize, *mut *mut FcPattern)> {
let fonts = unsafe { fc::FcConfigGetFonts(config, FcSetSystem) };
if !fonts.is_null() {
let count = unsafe { (*fonts).nfont as isize };
let patterns = unsafe { (*fonts).fonts };
Some((count, patterns))
} else {
None
}
}
fn get_pattern(patterns: *mut *mut FcPattern, index: isize) -> Option<*mut FcPattern> {
let pattern = unsafe { *patterns.offset(index) };
if !pattern.is_null() {
Some(pattern)
} else {
None
}
}
fn get_charset(pattern: *mut FcPattern) -> Option<*mut FcCharSet> {
let mut charset: *mut FcCharSet = ptr::null_mut();
let object = b"charset\0".as_ptr() as *const _;
let result = unsafe { fc::FcPatternGetCharSet(pattern, object, 0, &mut charset) };
if result == FcResultMatch && !charset.is_null() {
Some(charset)
} else {
None
}
}
fn test_charset(
sextants: &mut HashSet<char>,
octants: &mut HashSet<char>,
charset: *mut FcCharSet,
) {
const MAP_SIZE: usize = 256 / 32; let mut map: [FcChar32; MAP_SIZE] = [0; MAP_SIZE];
let mut next: FcChar32 = 0;
let mut page = unsafe { fc::FcCharSetFirstPage(charset, map.as_mut_ptr(), &mut next as *mut _) };
while page != !0_u32 {
for (index, &chunk) in map.iter().enumerate() {
let bits = chunk as u32;
for bit in 0..32_u32 {
if bits & (1_u32 << bit) != 0 {
let cp = page.wrapping_add((index as u32) * 32 + bit);
if let Some(char) = char::from_u32(cp) {
sextants.remove(&char);
octants.remove(&char);
}
}
}
}
page = unsafe { fc::FcCharSetNextPage(charset, map.as_mut_ptr(), &mut next as *mut _) };
}
}
}
#[cfg(not(all(unix, feature = "fontconfig")))]
mod inner {
use std::collections::HashSet;
pub fn test_fonts(
_sextants: &mut HashSet<char>,
_octants: &mut HashSet<char>,
) -> Option<()> {
None
}
}