core_text/
font_descriptor.rs1#![allow(non_upper_case_globals)]
11
12use core_foundation::array::CFArrayRef;
13use core_foundation::base::{CFType, CFTypeID, CFTypeRef, TCFType};
14use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
15use core_foundation::number::{CFNumber, CFNumberRef};
16use core_foundation::set::CFSetRef;
17use core_foundation::string::{CFString, CFStringRef};
18use core_foundation::url::{CFURLRef, CFURL};
19use core_foundation::{declare_TCFType, impl_CFTypeDescription, impl_TCFType};
20use core_graphics::base::CGFloat;
21
22use std::os::raw::c_void;
23use std::path::PathBuf;
24
25pub type CTFontFormat = u32;
30pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
31pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
32pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
33pub const kCTFontFormatTrueType: CTFontFormat = 3;
34pub const kCTFontFormatPostScript: CTFontFormat = 4;
35pub const kCTFontFormatBitmap: CTFontFormat = 5;
36
37pub const kCTFontClassMaskShift: u32 = 28;
38
39pub type CTFontSymbolicTraits = u32;
40pub const kCTFontItalicTrait: CTFontSymbolicTraits = 1 << 0;
41pub const kCTFontBoldTrait: CTFontSymbolicTraits = 1 << 1;
42pub const kCTFontExpandedTrait: CTFontSymbolicTraits = 1 << 5;
43pub const kCTFontCondensedTrait: CTFontSymbolicTraits = 1 << 6;
44pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = 1 << 10;
45pub const kCTFontVerticalTrait: CTFontSymbolicTraits = 1 << 11;
46pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = 1 << 12;
47pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = 1 << 13;
48pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = 15 << kCTFontClassMaskShift;
49
50pub trait SymbolicTraitAccessors {
51 fn is_italic(&self) -> bool;
52 fn is_bold(&self) -> bool;
53 fn is_expanded(&self) -> bool;
54 fn is_condensed(&self) -> bool;
55 fn is_monospace(&self) -> bool;
56 fn is_vertical(&self) -> bool;
57}
58
59impl SymbolicTraitAccessors for CTFontSymbolicTraits {
60 fn is_italic(&self) -> bool {
61 (*self & kCTFontItalicTrait) != 0
62 }
63 fn is_bold(&self) -> bool {
64 (*self & kCTFontBoldTrait) != 0
65 }
66 fn is_expanded(&self) -> bool {
67 (*self & kCTFontExpandedTrait) != 0
68 }
69 fn is_condensed(&self) -> bool {
70 (*self & kCTFontCondensedTrait) != 0
71 }
72 fn is_monospace(&self) -> bool {
73 (*self & kCTFontMonoSpaceTrait) != 0
74 }
75 fn is_vertical(&self) -> bool {
76 (*self & kCTFontVerticalTrait) != 0
77 }
78}
79
80pub type CTFontStylisticClass = u32;
81pub const kCTFontUnknownClass: CTFontStylisticClass = 0 << kCTFontClassMaskShift;
82pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = 1 << kCTFontClassMaskShift;
83pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = 2 << kCTFontClassMaskShift;
84pub const kCTFontModernSerifsClass: CTFontStylisticClass = 3 << kCTFontClassMaskShift;
85pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = 4 << kCTFontClassMaskShift;
86pub const kCTFontSlabSerifsClass: CTFontStylisticClass = 5 << kCTFontClassMaskShift;
87pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = 7 << kCTFontClassMaskShift;
88pub const kCTFontSansSerifClass: CTFontStylisticClass = 8 << kCTFontClassMaskShift;
89pub const kCTFontOrnamentalsClass: CTFontStylisticClass = 9 << kCTFontClassMaskShift;
90pub const kCTFontScriptsClass: CTFontStylisticClass = 10 << kCTFontClassMaskShift;
91pub const kCTFontSymbolicClass: CTFontStylisticClass = 12 << kCTFontClassMaskShift;
92
93pub trait StylisticClassAccessors {
94 fn is_serif(&self) -> bool;
95 fn is_sans_serif(&self) -> bool;
96 fn is_script(&self) -> bool;
97 fn is_fantasy(&self) -> bool;
98 fn is_symbols(&self) -> bool;
99}
100
101impl StylisticClassAccessors for CTFontStylisticClass {
102 fn is_serif(&self) -> bool {
103 let any_serif_class = kCTFontOldStyleSerifsClass
104 | kCTFontTransitionalSerifsClass
105 | kCTFontModernSerifsClass
106 | kCTFontClarendonSerifsClass
107 | kCTFontSlabSerifsClass
108 | kCTFontFreeformSerifsClass;
109
110 (*self & any_serif_class) != 0
111 }
112
113 fn is_sans_serif(&self) -> bool {
114 (*self & kCTFontSansSerifClass) != 0
115 }
116
117 fn is_script(&self) -> bool {
118 (*self & kCTFontScriptsClass) != 0
119 }
120
121 fn is_fantasy(&self) -> bool {
122 (*self & kCTFontOrnamentalsClass) != 0
123 }
124
125 fn is_symbols(&self) -> bool {
126 (*self & kCTFontSymbolicClass) != 0
127 }
128}
129
130pub type CTFontAttributes = CFDictionary;
131
132pub type CTFontTraits = CFDictionary<CFString, CFType>;
133
134pub trait TraitAccessors {
135 fn symbolic_traits(&self) -> CTFontSymbolicTraits;
136 fn normalized_weight(&self) -> f64;
137 fn normalized_width(&self) -> f64;
138 fn normalized_slant(&self) -> f64;
139}
140
141trait TraitAccessorPrivate {
142 fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
143}
144
145impl TraitAccessorPrivate for CTFontTraits {
146 fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
147 let cftype = self.get(key);
148 cftype.downcast::<CFNumber>().unwrap()
149 }
150}
151
152impl TraitAccessors for CTFontTraits {
153 fn symbolic_traits(&self) -> CTFontSymbolicTraits {
154 unsafe {
155 let number = self.extract_number_for_key(kCTFontSymbolicTrait);
156 number.to_i64().unwrap() as u32
157 }
158 }
159
160 fn normalized_weight(&self) -> f64 {
161 unsafe {
162 let number = self.extract_number_for_key(kCTFontWeightTrait);
163 number.to_f64().unwrap()
164 }
165 }
166
167 fn normalized_width(&self) -> f64 {
168 unsafe {
169 let number = self.extract_number_for_key(kCTFontWidthTrait);
170 number.to_f64().unwrap()
171 }
172 }
173
174 fn normalized_slant(&self) -> f64 {
175 unsafe {
176 let number = self.extract_number_for_key(kCTFontSlantTrait);
177 number.to_f64().unwrap()
178 }
179 }
180}
181
182pub type CTFontOrientation = u32;
186pub const kCTFontDefaultOrientation: CTFontOrientation = 0; pub const kCTFontOrientationDefault: CTFontOrientation = 0; pub const kCTFontHorizontalOrientation: CTFontOrientation = 1; pub const kCTFontOrientationHorizontal: CTFontOrientation = 1; pub const kCTFontVerticalOrientation: CTFontOrientation = 2; pub const kCTFontOrientationVertical: CTFontOrientation = 2; pub type CTFontPriority = u32;
194pub const kCTFontPrioritySystem: CTFontPriority = 10000;
195pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
196pub const kCTFontPriorityComputer: CTFontPriority = 30000;
197pub const kCTFontPriorityUser: CTFontPriority = 40000;
198pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
199pub const kCTFontPriorityProcess: CTFontPriority = 60000;
200
201#[repr(C)]
202pub struct __CTFontDescriptor(c_void);
203
204pub type CTFontDescriptorRef = *const __CTFontDescriptor;
205
206declare_TCFType! {
207 CTFontDescriptor, CTFontDescriptorRef
208}
209impl_TCFType!(
210 CTFontDescriptor,
211 CTFontDescriptorRef,
212 CTFontDescriptorGetTypeID
213);
214impl_CFTypeDescription!(CTFontDescriptor);
215
216unsafe impl Send for CTFontDescriptor {}
219unsafe impl Sync for CTFontDescriptor {}
220
221impl CTFontDescriptor {
222 fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
223 unsafe {
224 let value = CTFontDescriptorCopyAttribute(self.0, attribute);
225 if value.is_null() {
226 return None;
227 }
228
229 let value = CFType::wrap_under_create_rule(value);
230 assert!(value.instance_of::<CFString>());
231 let s = CFString::wrap_under_get_rule(value.as_CFTypeRef() as CFStringRef);
232 Some(s.to_string())
233 }
234 }
235}
236
237impl CTFontDescriptor {
238 pub fn family_name(&self) -> String {
239 unsafe {
240 let value = self.get_string_attribute(kCTFontFamilyNameAttribute);
241 value.expect("A font must have a non-null family name.")
242 }
243 }
244
245 pub fn font_name(&self) -> String {
246 unsafe {
247 let value = self.get_string_attribute(kCTFontNameAttribute);
248 value.expect("A font must have a non-null name.")
249 }
250 }
251
252 pub fn style_name(&self) -> String {
253 unsafe {
254 let value = self.get_string_attribute(kCTFontStyleNameAttribute);
255 value.expect("A font must have a non-null style name.")
256 }
257 }
258
259 pub fn display_name(&self) -> String {
260 unsafe {
261 let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
262 value.expect("A font must have a non-null display name.")
263 }
264 }
265
266 pub fn font_format(&self) -> Option<CTFontFormat> {
267 unsafe {
268 let value = CTFontDescriptorCopyAttribute(self.0, kCTFontFormatAttribute);
269 if value.is_null() {
270 return None;
271 }
272
273 let value = CFType::wrap_under_create_rule(value);
274 assert!(value.instance_of::<CFNumber>());
275 let format = CFNumber::wrap_under_get_rule(value.as_CFTypeRef() as CFNumberRef);
276 format.to_i32().map(|x| x as CTFontFormat)
277 }
278 }
279
280 pub fn font_path(&self) -> Option<PathBuf> {
281 unsafe {
282 let value = CTFontDescriptorCopyAttribute(self.0, kCTFontURLAttribute);
283 if value.is_null() {
284 return None;
285 }
286
287 let value = CFType::wrap_under_create_rule(value);
288 assert!(value.instance_of::<CFURL>());
289 let url = CFURL::wrap_under_get_rule(value.as_CFTypeRef() as CFURLRef);
290 url.to_path()
291 }
292 }
293
294 pub fn traits(&self) -> CTFontTraits {
295 unsafe {
296 let value = CTFontDescriptorCopyAttribute(self.0, kCTFontTraitsAttribute);
297 assert!(!value.is_null());
298 let value = CFType::wrap_under_create_rule(value);
299 assert!(value.instance_of::<CFDictionary>());
300 CFDictionary::wrap_under_get_rule(value.as_CFTypeRef() as CFDictionaryRef)
301 }
302 }
303
304 pub fn create_copy_with_attributes(&self, attr: CFDictionary) -> Result<CTFontDescriptor, ()> {
305 unsafe {
306 let desc = CTFontDescriptorCreateCopyWithAttributes(
307 self.as_concrete_TypeRef(),
308 attr.as_concrete_TypeRef(),
309 );
310 if desc.is_null() {
311 return Err(());
312 }
313 Ok(CTFontDescriptor::wrap_under_create_rule(desc))
314 }
315 }
316
317 pub fn attributes(&self) -> CFDictionary<CFString, CFType> {
318 unsafe {
319 let attrs = CTFontDescriptorCopyAttributes(self.as_concrete_TypeRef());
320 CFDictionary::wrap_under_create_rule(attrs)
321 }
322 }
323}
324
325pub fn new_from_attributes(attributes: &CFDictionary<CFString, CFType>) -> CTFontDescriptor {
326 unsafe {
327 let result: CTFontDescriptorRef =
328 CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
329 CTFontDescriptor::wrap_under_create_rule(result)
330 }
331}
332
333pub fn new_from_variations(variations: &CFDictionary<CFString, CFNumber>) -> CTFontDescriptor {
334 unsafe {
335 let var_key = CFString::wrap_under_get_rule(kCTFontVariationAttribute);
336 let var_val = CFType::wrap_under_get_rule(variations.as_CFTypeRef());
337 let attributes = CFDictionary::from_CFType_pairs(&[(var_key, var_val)]);
338 new_from_attributes(&attributes)
339 }
340}
341
342pub fn new_from_postscript_name(name: &CFString) -> CTFontDescriptor {
343 unsafe {
344 let result: CTFontDescriptorRef =
345 CTFontDescriptorCreateWithNameAndSize(name.as_concrete_TypeRef(), 0.0);
346 CTFontDescriptor::wrap_under_create_rule(result)
347 }
348}
349
350pub fn debug_descriptor(desc: &CTFontDescriptor) {
351 println!("family: {}", desc.family_name());
352 println!("name: {}", desc.font_name());
353 println!("style: {}", desc.style_name());
354 println!("display: {}", desc.display_name());
355 println!("path: {:?}", desc.font_path());
356 desc.show();
357}
358
359extern "C" {
360 pub static kCTFontSymbolicTrait: CFStringRef;
366 pub static kCTFontWeightTrait: CFStringRef;
367 pub static kCTFontWidthTrait: CFStringRef;
368 pub static kCTFontSlantTrait: CFStringRef;
369
370 pub static kCTFontURLAttribute: CFStringRef; pub static kCTFontNameAttribute: CFStringRef; pub static kCTFontDisplayNameAttribute: CFStringRef; pub static kCTFontFamilyNameAttribute: CFStringRef; pub static kCTFontStyleNameAttribute: CFStringRef; pub static kCTFontTraitsAttribute: CFStringRef;
383 pub static kCTFontVariationAttribute: CFStringRef;
384 pub static kCTFontSizeAttribute: CFStringRef;
385 pub static kCTFontMatrixAttribute: CFStringRef;
386 pub static kCTFontCascadeListAttribute: CFStringRef;
387 pub static kCTFontCharacterSetAttribute: CFStringRef;
388 pub static kCTFontLanguagesAttribute: CFStringRef;
389 pub static kCTFontBaselineAdjustAttribute: CFStringRef;
390 pub static kCTFontMacintoshEncodingsAttribute: CFStringRef;
391 pub static kCTFontFeaturesAttribute: CFStringRef;
392 pub static kCTFontFeatureSettingsAttribute: CFStringRef;
393 pub static kCTFontFixedAdvanceAttribute: CFStringRef;
394 pub static kCTFontOrientationAttribute: CFStringRef;
395 pub static kCTFontFormatAttribute: CFStringRef;
396 pub static kCTFontRegistrationScopeAttribute: CFStringRef;
397 pub static kCTFontPriorityAttribute: CFStringRef;
398 pub static kCTFontEnabledAttribute: CFStringRef;
399
400 pub fn CTFontDescriptorCopyAttribute(
401 descriptor: CTFontDescriptorRef,
402 attribute: CFStringRef,
403 ) -> CFTypeRef;
404 pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
405 pub fn CTFontDescriptorCopyLocalizedAttribute(
406 descriptor: CTFontDescriptorRef,
407 attribute: CFStringRef,
408 language: *mut CFStringRef,
409 ) -> CFTypeRef;
410 pub fn CTFontDescriptorCreateCopyWithAttributes(
411 original: CTFontDescriptorRef,
412 attributes: CFDictionaryRef,
413 ) -> CTFontDescriptorRef;
414 pub fn CTFontDescriptorCreateCopyWithFeature(
415 original: CTFontDescriptorRef,
416 featureTypeIdentifier: CFNumberRef,
417 featureSelectorIdentifier: CFNumberRef,
418 ) -> CTFontDescriptorRef;
419 pub fn CTFontDescriptorCreateCopyWithVariation(
420 original: CTFontDescriptorRef,
421 variationIdentifier: CFNumberRef,
422 variationValue: CGFloat,
423 ) -> CTFontDescriptorRef;
424 pub fn CTFontDescriptorCreateMatchingFontDescriptor(
425 descriptor: CTFontDescriptorRef,
426 mandatoryAttributes: CFSetRef,
427 ) -> CTFontDescriptorRef;
428 pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef)
429 -> CTFontDescriptorRef;
430 pub fn CTFontDescriptorCreateWithNameAndSize(
431 name: CFStringRef,
432 size: CGFloat,
433 ) -> CTFontDescriptorRef;
434 pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
435}
436
437extern "C" {
438 pub fn CTFontDescriptorCreateMatchingFontDescriptors(
439 descriptor: CTFontDescriptorRef,
440 mandatoryAttributes: CFSetRef,
441 ) -> CFArrayRef;
442}