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}