use crate::{arc, cf, cg, define_cf_type};
define_cf_type!(
#[doc(alias = "CGFontRef")]
Font(cf::Type)
);
#[doc(alias = "CGFontIndex")]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(transparent)]
pub struct Index(pub u16);
#[doc(alias = "CGGlyph")]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(transparent)]
pub struct Glyph(pub Index);
impl Glyph {
pub fn new(index: u16) -> Self {
Self(Index(index))
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(i32)]
pub enum FontPostScriptFormat {
Type1 = 1,
Type3 = 3,
Type42 = 42,
}
impl Index {
#[doc(alias = "kCGFontIndexMax")]
pub const MAX: Self = Self(u16::MAX - 1);
#[doc(alias = "kCGFontIndexInvalid")]
pub const INVALID: Self = Self(u16::MAX);
}
impl Font {
#[doc(alias = "CGFontGetTypeID")]
#[inline]
pub fn type_id() -> cf::TypeId {
unsafe { CGFontGetTypeID() }
}
#[doc(alias = "CGFontCreateWithFontName")]
#[inline]
pub fn with_name(name: &cf::String) -> Option<arc::R<Self>> {
unsafe { CGFontCreateWithFontName(name) }
}
#[doc(alias = "CGFontCreateCopyWithVariations")]
#[inline]
pub fn with_variations(&self, variations: Option<&cf::Dictionary>) -> Option<arc::R<Self>> {
unsafe { CGFontCreateCopyWithVariations(self, variations) }
}
#[doc(alias = "CGFontGetNumberOfGlyphs")]
#[inline]
pub fn nglyphs(&self) -> usize {
unsafe { CGFontGetNumberOfGlyphs(self) }
}
#[doc(alias = "CGFontGetUnitsPerEm")]
#[inline]
pub fn units_per_em(&self) -> i32 {
unsafe { CGFontGetUnitsPerEm(self) }
}
#[doc(alias = "CGFontCopyPostScriptName")]
#[inline]
pub fn post_script_name(&self) -> arc::R<cf::String> {
unsafe { CGFontCopyPostScriptName(self) }
}
#[doc(alias = "CGFontCopyFullName")]
#[inline]
pub fn full_name(&self) -> arc::R<cf::String> {
unsafe { CGFontCopyFullName(self) }
}
#[doc(alias = "CGFontGetAscent")]
#[inline]
pub fn ascent(&self) -> i32 {
unsafe { CGFontGetAscent(self) }
}
#[doc(alias = "CGFontGetDescent")]
#[inline]
pub fn descent(&self) -> i32 {
unsafe { CGFontGetDescent(self) }
}
#[doc(alias = "CGFontGetLeading")]
#[inline]
pub fn leading(&self) -> i32 {
unsafe { CGFontGetLeading(self) }
}
#[doc(alias = "CGFontGetCapHeight")]
#[inline]
pub fn cap_height(&self) -> i32 {
unsafe { CGFontGetCapHeight(self) }
}
#[doc(alias = "CGFontGetXHeight")]
#[inline]
pub fn x_height(&self) -> i32 {
unsafe { CGFontGetXHeight(self) }
}
#[doc(alias = "CGFontGetFontBBox")]
#[inline]
pub fn bbox(&self) -> cg::Rect {
unsafe { CGFontGetFontBBox(self) }
}
#[doc(alias = "CGFontGetItalicAngle")]
#[inline]
pub fn italic_angle(&self) -> cg::Float {
unsafe { CGFontGetItalicAngle(self) }
}
#[doc(alias = "CGFontGetStemV")]
#[inline]
pub fn stem_v(&self) -> cg::Float {
unsafe { CGFontGetStemV(self) }
}
#[doc(alias = "CGFontCopyVariationAxes")]
#[inline]
pub fn variation_axes(&self) -> Option<arc::R<cf::Array>> {
unsafe { CGFontCopyVariationAxes(self) }
}
#[doc(alias = "CGFontCopyVariations")]
#[inline]
pub fn variations(&self) -> Option<arc::R<cf::Array>> {
unsafe { CGFontCopyVariations(self) }
}
#[inline]
pub fn glyph_advances(&self, glyphs: &[Glyph]) -> Result<Vec<i32>, ()> {
let len = glyphs.len();
let mut result = Vec::<std::mem::MaybeUninit<i32>>::with_capacity(len);
unsafe {
if CGFontGetGlyphAdvances(self, glyphs.as_ptr(), len, result.as_mut_ptr() as _) {
result.set_len(len);
Ok(std::mem::transmute(result))
} else {
Err(())
}
}
}
#[inline]
pub fn glyph_advances_u16(&self, glyphs: &[u16]) -> Result<Vec<i32>, ()> {
unsafe { self.glyph_advances(std::mem::transmute(glyphs)) }
}
#[inline]
pub fn glyph_bboxes(&self, glyphs: &[Glyph]) -> Result<Vec<cg::Rect>, ()> {
let len = glyphs.len();
let mut result = Vec::<std::mem::MaybeUninit<cg::Rect>>::with_capacity(len);
unsafe {
if CGFontGetGlyphBBoxes(self, glyphs.as_ptr(), len, result.as_mut_ptr() as _) {
result.set_len(len);
Ok(std::mem::transmute(result))
} else {
Err(())
}
}
}
#[inline]
pub fn glyph_bboxes_u16(&self, glyphs: &[u16]) -> Result<Vec<cg::Rect>, ()> {
unsafe { self.glyph_bboxes(std::mem::transmute(glyphs)) }
}
#[inline]
pub fn glyph_with_name(&self, name: &cf::String) -> Glyph {
unsafe { CGFontGetGlyphWithGlyphName(self, name) }
}
#[inline]
pub fn name_for_glyph(&self, glyph: Glyph) -> Option<arc::R<cf::String>> {
unsafe { CGFontCopyGlyphNameForGlyph(self, glyph) }
}
#[inline]
pub fn name_for_glyph_u16(&self, glyph: u16) -> Option<arc::R<cf::String>> {
self.name_for_glyph(Glyph::new(glyph))
}
#[inline]
pub fn can_create_post_script_subset(&self, format: FontPostScriptFormat) -> bool {
unsafe { CGFontCanCreatePostScriptSubset(self, format) }
}
}
#[link(name = "CoreGraphics", kind = "framework")]
unsafe extern "C-unwind" {
fn CGFontGetTypeID() -> cf::TypeId;
fn CGFontCreateWithFontName(name: &cf::String) -> Option<arc::R<Font>>;
fn CGFontCreateCopyWithVariations(
font: &Font,
variations: Option<&cf::Dictionary>,
) -> Option<arc::R<Font>>;
fn CGFontGetNumberOfGlyphs(font: &Font) -> usize;
fn CGFontGetUnitsPerEm(font: &Font) -> i32;
fn CGFontCopyPostScriptName(font: &Font) -> arc::R<cf::String>;
fn CGFontCopyFullName(font: &Font) -> arc::R<cf::String>;
fn CGFontGetAscent(font: &Font) -> i32;
fn CGFontGetDescent(font: &Font) -> i32;
fn CGFontGetLeading(font: &Font) -> i32;
fn CGFontGetCapHeight(font: &Font) -> i32;
fn CGFontGetXHeight(font: &Font) -> i32;
fn CGFontGetFontBBox(font: &Font) -> cg::Rect;
fn CGFontGetItalicAngle(font: &Font) -> cg::Float;
fn CGFontGetStemV(font: &Font) -> cg::Float;
fn CGFontCopyVariationAxes(font: &Font) -> Option<arc::R<cf::Array>>;
fn CGFontCopyVariations(font: &Font) -> Option<arc::R<cf::Array>>;
fn CGFontGetGlyphAdvances(
font: &Font,
glyphs: *const Glyph,
count: usize,
advances: *mut i32,
) -> bool;
fn CGFontGetGlyphBBoxes(
font: &Font,
glyphs: *const Glyph,
count: usize,
bboxes: *mut cg::Rect,
) -> bool;
fn CGFontGetGlyphWithGlyphName(font: &Font, name: &cf::String) -> Glyph;
fn CGFontCopyGlyphNameForGlyph(font: &Font, glyph: Glyph) -> Option<arc::R<cf::String>>;
fn CGFontCanCreatePostScriptSubset(font: &Font, format: FontPostScriptFormat) -> bool;
}
#[cfg(test)]
mod tests {
use crate::{cf, cg};
#[test]
fn basics() {
let font = cg::Font::with_name(&cf::String::from_str("Helvetica")).unwrap();
let copy = font.with_variations(None).unwrap();
copy.show();
assert_eq!(font.nglyphs(), 2252);
assert_eq!(font.units_per_em(), 2048);
assert_eq!(font.post_script_name().to_string(), "Helvetica");
assert_eq!(font.full_name().to_string(), "Helvetica");
assert_eq!(font.ascent(), 1577);
assert_eq!(font.descent(), -471);
assert_eq!(font.leading(), 0);
assert_eq!(font.cap_height(), 1469);
assert_eq!(font.bbox(), cg::Rect::new(-1947.0, -985.0, 4908.0, 3282.0));
assert_eq!(font.italic_angle(), 0.0);
assert!(font.variation_axes().is_none());
assert!(font.variations().is_none());
let advances = font.glyph_advances_u16(&[0, 1, 2]).unwrap();
println!("{:?}", advances);
let bboxes = font.glyph_bboxes_u16(&[0, 1, 2]).unwrap();
println!("{:?}", bboxes);
let name = font.name_for_glyph_u16(45).unwrap();
assert_eq!(name.to_string(), "J");
assert!(!font.can_create_post_script_subset(cg::FontPostScriptFormat::Type3));
assert!(font.can_create_post_script_subset(cg::FontPostScriptFormat::Type1));
assert!(font.can_create_post_script_subset(cg::FontPostScriptFormat::Type42));
}
}