use core_foundation::{
base::{CFType, TCFType},
dictionary::CFMutableDictionary,
number::CFNumber,
string::CFString,
};
use core_graphics::{affine_transform::CGAffineTransform, base::CGFloat, font::CGGlyph, path::CGPathRef};
use core_text::{
font::{self, CTFont, CTFontRef},
font_descriptor::{
self, kCTFontBoldTrait, kCTFontFamilyNameAttribute, kCTFontItalicTrait, kCTFontSymbolicTrait, kCTFontTraitsAttribute, kCTFontWeightTrait,
CTFontSymbolicTraits,
},
};
use crate::{
font::{FontStyle, FontWeight},
Float,
};
#[derive(Clone, Debug)]
pub(super) struct Font {
font: CTFont,
}
impl Font {
pub(super) fn new(family: &str, style: FontStyle, weight: FontWeight, size: Float) -> Font {
let mut font_traits = CFMutableDictionary::<CFString, CFNumber>::new();
let mut traits: CTFontSymbolicTraits = 0;
if weight >= FontWeight::Bold {
traits |= kCTFontBoldTrait;
}
if style.contains(FontStyle::Italic) {
traits |= kCTFontItalicTrait;
}
let symbolic_trait_key = unsafe { CFString::wrap_under_get_rule(kCTFontSymbolicTrait) };
font_traits.set(symbolic_trait_key, CFNumber::from(traits as i64));
let weight_trait_key = unsafe { CFString::wrap_under_get_rule(kCTFontWeightTrait) };
let weight: CGFloat = weight.into();
font_traits.set(weight_trait_key, CFNumber::from(weight));
let mut font_attributes = CFMutableDictionary::<CFString, CFType>::new();
let family_name_key = unsafe { CFString::wrap_under_get_rule(kCTFontFamilyNameAttribute) };
font_attributes.set(family_name_key, CFString::from(family).as_CFType());
let traits_attribute_key = unsafe { CFString::wrap_under_get_rule(kCTFontTraitsAttribute) };
font_attributes.set(traits_attribute_key, font_traits.as_CFType());
let font_descriptor = font_descriptor::new_from_attributes(&font_attributes.to_immutable());
Self {
font: font::new_from_descriptor(&font_descriptor, size),
}
}
pub(super) fn font(&self) -> &CTFont {
&self.font
}
}
impl From<FontWeight> for CGFloat {
fn from(weight: FontWeight) -> Self {
match weight {
FontWeight::Thin => -0.8,
FontWeight::ExtraLight => -0.6,
FontWeight::Light => -0.4,
FontWeight::Normal => 0.0,
FontWeight::Medium => 0.23,
FontWeight::SemiBold => 0.3,
FontWeight::Bold => 0.4,
FontWeight::ExtraBold => 0.56,
FontWeight::Black => 0.62,
FontWeight::ExtraBlack => 0.75,
}
}
}
#[link(name = "CoreText", kind = "framework")]
extern "C" {
pub fn CTFontCreatePathForGlyph(font: CTFontRef, glyph: CGGlyph, matrix: *const CGAffineTransform) -> CGPathRef;
}