core_text/
font_descriptor.rs

1// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10#![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
25/*
26* CTFontTraits.h
27*/
28// actually, these are extern enums
29pub 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
182/*
183* CTFontDescriptor.h
184*/
185pub type CTFontOrientation = u32;
186pub const kCTFontDefaultOrientation: CTFontOrientation = 0; // deprecated since macOS 10.11, iOS 9
187pub const kCTFontOrientationDefault: CTFontOrientation = 0; // introduced in macOS 10.8, iOS 6
188pub const kCTFontHorizontalOrientation: CTFontOrientation = 1; // deprecated since macOS 10.11, iOS 9
189pub const kCTFontOrientationHorizontal: CTFontOrientation = 1; // introduced in macOS 10.8, iOS 6
190pub const kCTFontVerticalOrientation: CTFontOrientation = 2; // deprecated since macOS 10.11, iOS 9
191pub const kCTFontOrientationVertical: CTFontOrientation = 2; // introduced in macOS 10.8, iOS 6
192
193pub 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
216// "Font objects (CTFont, CTFontDescriptor, and associated objects) can be used
217//  simultaneously by multiple operations, work queues, or threads."
218unsafe 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    /*
361     * CTFontTraits.h
362     */
363
364    // font trait constants
365    pub static kCTFontSymbolicTrait: CFStringRef;
366    pub static kCTFontWeightTrait: CFStringRef;
367    pub static kCTFontWidthTrait: CFStringRef;
368    pub static kCTFontSlantTrait: CFStringRef;
369
370    /*
371     * CTFontDescriptor.h
372     */
373
374    // font attribute constants. Note that the name-related attributes
375    // here are somewhat flaky. Servo creates CTFont instances and
376    // then uses CTFontCopyName to get more fine-grained names.
377    pub static kCTFontURLAttribute: CFStringRef; // value: CFURLRef
378    pub static kCTFontNameAttribute: CFStringRef; // value: CFStringRef
379    pub static kCTFontDisplayNameAttribute: CFStringRef; // value: CFStringRef
380    pub static kCTFontFamilyNameAttribute: CFStringRef; // value: CFStringRef
381    pub static kCTFontStyleNameAttribute: CFStringRef; // value: CFStringRef
382    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}