x-graphics 0.2.1

Graphics framework for X
Documentation
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;
}