Skip to main content

core_graphics2/
font.rs

1use std::ptr::null;
2
3use core_foundation::{
4    array::{CFArray, CFArrayRef},
5    base::{CFType, CFTypeID, TCFType},
6    data::{CFData, CFDataRef},
7    dictionary::{CFDictionary, CFDictionaryRef},
8    impl_CFTypeDescription, impl_TCFType,
9    number::CFNumber,
10    string::{CFString, CFStringRef},
11};
12use libc::{c_int, c_ushort, c_void, size_t};
13
14use crate::{
15    base::CGFloat,
16    data_provider::{CGDataProvider, CGDataProviderRef},
17    geometry::CGRect,
18};
19
20#[repr(C)]
21pub struct __CGFont(c_void);
22
23pub type CGFontRef = *mut __CGFont;
24
25pub type CGFontIndex = c_ushort;
26
27pub type CGGlyph = CGFontIndex;
28
29#[repr(i32)]
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31pub enum CGFontPostScriptFormat {
32    #[doc(alias = "kCGFontPostScriptFormatType1")]
33    Type1  = 1,
34    #[doc(alias = "kCGFontPostScriptFormatType3")]
35    Type3  = 3,
36    #[doc(alias = "kCGFontPostScriptFormatType42")]
37    Type42 = 42,
38}
39
40pub const kCGFontIndexMax: CGFontIndex = u16::MAX - 1;
41pub const kCGFontIndexInvalid: CGFontIndex = u16::MAX;
42pub const kCGGlyphMax: CGFontIndex = kCGFontIndexMax;
43
44extern "C" {
45    pub fn CGFontGetTypeID() -> CFTypeID;
46    pub fn CGFontCreateWithPlatformFont(platformFontReference: *mut c_void) -> CGFontRef;
47    pub fn CGFontCreateWithDataProvider(provider: CGDataProviderRef) -> CGFontRef;
48    pub fn CGFontCreateWithFontName(name: CFStringRef) -> CGFontRef;
49    pub fn CGFontCreateCopyWithVariations(font: CGFontRef, variations: CFDictionaryRef) -> CGFontRef;
50    pub fn CGFontRetain(font: CGFontRef) -> CGFontRef;
51    pub fn CGFontRelease(font: CGFontRef);
52    pub fn CGFontGetNumberOfGlyphs(font: CGFontRef) -> size_t;
53    pub fn CGFontGetUnitsPerEm(font: CGFontRef) -> c_int;
54    pub fn CGFontCopyPostScriptName(font: CGFontRef) -> CFStringRef;
55    pub fn CGFontCopyFullName(font: CGFontRef) -> CFStringRef;
56    pub fn CGFontGetAscent(font: CGFontRef) -> c_int;
57    pub fn CGFontGetDescent(font: CGFontRef) -> c_int;
58    pub fn CGFontGetLeading(font: CGFontRef) -> c_int;
59    pub fn CGFontGetCapHeight(font: CGFontRef) -> c_int;
60    pub fn CGFontGetXHeight(font: CGFontRef) -> c_int;
61    pub fn CGFontGetFontBBox(font: CGFontRef) -> CGRect;
62    pub fn CGFontGetItalicAngle(font: CGFontRef) -> CGFloat;
63    pub fn CGFontGetStemV(font: CGFontRef) -> CGFloat;
64    pub fn CGFontCopyVariationAxes(font: CGFontRef) -> CFArrayRef;
65    pub fn CGFontCopyVariations(font: CGFontRef) -> CFDictionaryRef;
66    pub fn CGFontGetGlyphAdvances(font: CGFontRef, glyphs: *const CGGlyph, count: size_t, advances: *mut c_int) -> bool;
67    pub fn CGFontGetGlyphBBoxes(font: CGFontRef, glyphs: *const CGGlyph, count: size_t, bboxes: *mut CGRect) -> bool;
68    pub fn CGFontGetGlyphWithGlyphName(font: CGFontRef, name: CFStringRef) -> CGGlyph;
69    pub fn CGFontCopyGlyphNameForGlyph(font: CGFontRef, glyph: CGGlyph) -> CFStringRef;
70    pub fn CGFontCanCreatePostScriptSubset(font: CGFontRef, format: CGFontPostScriptFormat) -> bool;
71    pub fn CGFontCreatePostScriptSubset(
72        font: CGFontRef,
73        subsetName: CFStringRef,
74        format: CGFontPostScriptFormat,
75        glyphs: *const CGGlyph,
76        count: size_t,
77        encoding: *const CGGlyph,
78    ) -> CFDataRef;
79    pub fn CGFontCreatePostScriptEncoding(font: CGFontRef, encoding: *const CGGlyph) -> CFDataRef;
80    pub fn CGFontCopyTableTags(font: CGFontRef) -> CFArrayRef;
81    pub fn CGFontCopyTableForTag(font: CGFontRef, tag: u32) -> CFDataRef;
82
83    pub static kCGFontVariationAxisName: CFStringRef;
84    pub static kCGFontVariationAxisMinValue: CFStringRef;
85    pub static kCGFontVariationAxisMaxValue: CFStringRef;
86    pub static kCGFontVariationAxisDefaultValue: CFStringRef;
87}
88
89pub struct CGFont(CGFontRef);
90
91impl Drop for CGFont {
92    fn drop(&mut self) {
93        unsafe { CGFontRelease(self.0) }
94    }
95}
96
97impl_TCFType!(CGFont, CGFontRef, CGFontGetTypeID);
98impl_CFTypeDescription!(CGFont);
99
100impl CGFont {
101    pub fn from_data_provider(provider: &CGDataProvider) -> Option<Self> {
102        unsafe {
103            let font = CGFontCreateWithDataProvider(provider.as_concrete_TypeRef());
104            if font.is_null() {
105                None
106            } else {
107                Some(TCFType::wrap_under_create_rule(font))
108            }
109        }
110    }
111
112    pub fn from_name(name: &CFString) -> Option<Self> {
113        unsafe {
114            let font = CGFontCreateWithFontName(name.as_concrete_TypeRef());
115            if font.is_null() {
116                None
117            } else {
118                Some(TCFType::wrap_under_create_rule(font))
119            }
120        }
121    }
122
123    pub fn new_copy_from_variations(&self, variations: Option<&CFDictionary<CFString, CFNumber>>) -> Option<CGFont> {
124        unsafe {
125            let font = CGFontCreateCopyWithVariations(self.as_concrete_TypeRef(), variations.as_ref().map_or(null(), |v| v.as_concrete_TypeRef()));
126            if font.is_null() {
127                None
128            } else {
129                Some(TCFType::wrap_under_create_rule(font))
130            }
131        }
132    }
133
134    pub fn number_of_glyphs(&self) -> usize {
135        unsafe { CGFontGetNumberOfGlyphs(self.as_concrete_TypeRef()) }
136    }
137
138    pub fn units_per_em(&self) -> i32 {
139        unsafe { CGFontGetUnitsPerEm(self.as_concrete_TypeRef()) as i32 }
140    }
141
142    pub fn copy_post_script_name(&self) -> CFString {
143        unsafe {
144            let name = CGFontCopyPostScriptName(self.as_concrete_TypeRef());
145            TCFType::wrap_under_create_rule(name)
146        }
147    }
148
149    pub fn copy_full_name(&self) -> CFString {
150        unsafe {
151            let name = CGFontCopyFullName(self.as_concrete_TypeRef());
152            TCFType::wrap_under_create_rule(name)
153        }
154    }
155
156    pub fn ascent(&self) -> i32 {
157        unsafe { CGFontGetAscent(self.as_concrete_TypeRef()) as i32 }
158    }
159
160    pub fn descent(&self) -> i32 {
161        unsafe { CGFontGetDescent(self.as_concrete_TypeRef()) as i32 }
162    }
163
164    pub fn leading(&self) -> i32 {
165        unsafe { CGFontGetLeading(self.as_concrete_TypeRef()) as i32 }
166    }
167
168    pub fn cap_height(&self) -> i32 {
169        unsafe { CGFontGetCapHeight(self.as_concrete_TypeRef()) as i32 }
170    }
171
172    pub fn x_height(&self) -> i32 {
173        unsafe { CGFontGetXHeight(self.as_concrete_TypeRef()) as i32 }
174    }
175
176    pub fn font_b_box(&self) -> CGRect {
177        unsafe { CGFontGetFontBBox(self.as_concrete_TypeRef()) }
178    }
179
180    pub fn italic_angle(&self) -> CGFloat {
181        unsafe { CGFontGetItalicAngle(self.as_concrete_TypeRef()) }
182    }
183
184    pub fn stem_v(&self) -> CGFloat {
185        unsafe { CGFontGetStemV(self.as_concrete_TypeRef()) }
186    }
187
188    pub fn copy_variation_axes(&self) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
189        unsafe {
190            let axes = CGFontCopyVariationAxes(self.as_concrete_TypeRef());
191            if axes.is_null() {
192                None
193            } else {
194                Some(TCFType::wrap_under_create_rule(axes))
195            }
196        }
197    }
198
199    pub fn copy_variations(&self) -> Option<CFDictionary<CFString, CFNumber>> {
200        let variations = unsafe { CGFontCopyVariations(self.as_concrete_TypeRef()) };
201        if !variations.is_null() {
202            Some(unsafe { TCFType::wrap_under_create_rule(variations) })
203        } else {
204            None
205        }
206    }
207
208    pub fn glyph_advances(&self, glyphs: &[CGGlyph], advances: &mut [c_int]) -> bool {
209        if glyphs.len() > advances.len() {
210            return false;
211        }
212
213        unsafe { CGFontGetGlyphAdvances(self.as_concrete_TypeRef(), glyphs.as_ptr(), glyphs.len(), advances.as_mut_ptr()) }
214    }
215
216    pub fn glyph_b_boxes(&self, glyphs: &[CGGlyph], bboxes: &mut [CGRect]) -> bool {
217        if glyphs.len() > bboxes.len() {
218            return false;
219        }
220
221        unsafe { CGFontGetGlyphBBoxes(self.as_concrete_TypeRef(), glyphs.as_ptr(), glyphs.len(), bboxes.as_mut_ptr()) }
222    }
223
224    pub fn glyph_with_glyph_name(&self, name: &CFString) -> CGGlyph {
225        unsafe { CGFontGetGlyphWithGlyphName(self.as_concrete_TypeRef(), name.as_concrete_TypeRef()) }
226    }
227
228    pub fn copy_glyph_name_for_glyph(&self, glyph: CGGlyph) -> CFString {
229        unsafe {
230            let name = CGFontCopyGlyphNameForGlyph(self.as_concrete_TypeRef(), glyph);
231            TCFType::wrap_under_create_rule(name)
232        }
233    }
234
235    pub fn copy_table_tags(&self) -> CFArray<u32> {
236        unsafe { TCFType::wrap_under_create_rule(CGFontCopyTableTags(self.as_concrete_TypeRef())) }
237    }
238
239    pub fn copy_table_for_tag(&self, tag: u32) -> Option<CFData> {
240        let data = unsafe { CGFontCopyTableForTag(self.as_concrete_TypeRef(), tag) };
241        if data.is_null() {
242            None
243        } else {
244            Some(unsafe { TCFType::wrap_under_create_rule(data) })
245        }
246    }
247}
248
249pub enum CGFontVariationAxis {
250    Name,
251    MinValue,
252    MaxValue,
253    DefaultValue,
254}
255
256impl From<CGFontVariationAxis> for CFStringRef {
257    fn from(axis: CGFontVariationAxis) -> Self {
258        unsafe {
259            match axis {
260                CGFontVariationAxis::Name => kCGFontVariationAxisName,
261                CGFontVariationAxis::MinValue => kCGFontVariationAxisMinValue,
262                CGFontVariationAxis::MaxValue => kCGFontVariationAxisMaxValue,
263                CGFontVariationAxis::DefaultValue => kCGFontVariationAxisDefaultValue,
264            }
265        }
266    }
267}
268
269impl From<CGFontVariationAxis> for CFString {
270    fn from(axis: CGFontVariationAxis) -> Self {
271        unsafe { CFString::wrap_under_get_rule(CFStringRef::from(axis)) }
272    }
273}