mod foundation;
mod graphics_types;
mod text;
use foundation::*;
use text::*;
use crate::{Fallback, Family, Stretch, Style, Weight, XFontType};
pub struct XFont;
impl Default for XFont {
fn default() -> Self {
Self
}
}
impl XFontType for XFont {
fn fallback(&self, family: &Family, text: &str) -> Fallback {
self.fallback_impl(text, &family.name, family.weight, family.stretch, family.style)
.unwrap_or_default()
}
fn system() -> String {
let font = CTFont::ui_for_language(kCTFontSystemFontType, 0.0, core::ptr::null_mut());
font.family().unwrap_or("System Font".to_string())
}
}
impl XFont {
fn fallback_impl(&self, text: &str, name: &str, weight: Weight, stretch: Stretch, style: Style) -> Option<Fallback> {
let symbolic = build_symbolic(weight.0, stretch.0, matches!(style, Style::Italic));
let attributes = CFDictionary::from_pairs(&[
(unsafe { kCTFontFamilyNameAttribute }, CFString::new(name).into()), (
unsafe { kCTFontTraitsAttribute },
CFDictionary::from_pairs(&[
(unsafe { kCTFontWeightTrait }, CFNumber::from(conv_weight(weight.0)).into()), (unsafe { kCTFontWidthTrait }, CFNumber::from(conv_stretch(stretch.0)).into()),
(unsafe { kCTFontSymbolicTrait }, CFNumber::from(symbolic as i32).into()),
])
.into(),
),
]);
let font = CTFont::from_descriptor(&CTFontDescriptor::from_attributes(&attributes), 0.0);
let font = if text.is_empty() {
font
} else {
let text = CFString::new(text);
font.for_string(text.as_ref(), CFRange::init(0, text.char_len()))
};
Some(Fallback {
index: None,
unique: font.unique_id(),
file: font.font_path()?,
})
}
}
fn build_symbolic(weight: u16, stretch: u16, italic: bool) -> u32 {
let mut symbolic = 0u32;
if weight >= 700 {
symbolic |= kCTFontBoldTrait;
}
if italic {
symbolic |= kCTFontItalicTrait;
}
if stretch < 1000 {
symbolic |= kCTFontCondensedTrait;
} else if stretch > 1000 {
symbolic |= kCTFontExpandedTrait;
}
symbolic
}
fn conv_weight(weight: u16) -> f64 {
if weight < 150 {
-0.80
} else if weight < 250 {
-0.60
} else if weight < 350 {
-0.40
} else if weight < 450 {
0.0
} else if weight < 550 {
0.23
} else if weight < 650 {
0.30
} else if weight < 750 {
0.40
} else if weight < 850 {
0.56
} else if weight < 925 {
0.62
} else {
1.00
}
}
fn conv_stretch(stretch: u16) -> f64 {
if stretch < (500 + 625) / 2 {
-0.5
} else if stretch < (625 + 750) / 2 {
-0.37
} else if stretch < (750 + 875) / 2 {
-0.25
} else if stretch < (875 + 1000) / 2 {
-0.13
} else if stretch < (1000 + 1125) / 2 {
0.0
} else if stretch < (1125 + 1250) / 2 {
0.13
} else if stretch < (1250 + 1375) / 2 {
0.25
} else if stretch < (1375 + 1500) / 2 {
0.37
} else {
0.5
}
}