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 
12 use font_descriptor;
13 use font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation};
14 use font_descriptor::{CTFontSymbolicTraits, CTFontTraits, SymbolicTraitAccessors, TraitAccessors};
15 use font_manager::create_font_descriptor;
16 
17 use core_foundation::array::{CFArray, CFArrayRef};
18 use core_foundation::base::{CFIndex, CFOptionFlags, CFType, CFTypeID, CFTypeRef, TCFType};
19 use core_foundation::data::{CFData, CFDataRef};
20 use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
21 use core_foundation::number::CFNumber;
22 use core_foundation::string::{CFString, CFStringRef, UniChar};
23 use core_foundation::url::{CFURL, CFURLRef};
24 use core_graphics::base::CGFloat;
25 use core_graphics::context::CGContext;
26 use core_graphics::font::{CGGlyph, CGFont};
27 use core_graphics::geometry::{CGAffineTransform, CGPoint, CGRect, CGSize};
28 use core_graphics::path::CGPath;
29 
30 use foreign_types::ForeignType;
31 use libc::{self, size_t};
32 use std::os::raw::c_void;
33 use std::ptr;
34 
35 type CGContextRef = *mut <CGContext as ForeignType>::CType;
36 type CGFontRef = *mut <CGFont as ForeignType>::CType;
37 type CGPathRef = *mut <CGPath as ForeignType>::CType;
38 
39 pub type CTFontUIFontType = u32;
40 // kCTFontNoFontType: CTFontUIFontType = -1;
41 pub const kCTFontUserFontType: CTFontUIFontType = 0;
42 pub const kCTFontUserFixedPitchFontType: CTFontUIFontType = 1;
43 pub const kCTFontSystemFontType: CTFontUIFontType = 2;
44 pub const kCTFontEmphasizedSystemFontType: CTFontUIFontType = 3;
45 pub const kCTFontSmallSystemFontType: CTFontUIFontType = 4;
46 pub const kCTFontSmallEmphasizedSystemFontType: CTFontUIFontType = 5;
47 pub const kCTFontMiniSystemFontType: CTFontUIFontType = 6;
48 pub const kCTFontMiniEmphasizedSystemFontType: CTFontUIFontType = 7;
49 pub const kCTFontViewsFontType: CTFontUIFontType = 8;
50 pub const kCTFontApplicationFontType: CTFontUIFontType = 9;
51 pub const kCTFontLabelFontType: CTFontUIFontType = 10;
52 pub const kCTFontMenuTitleFontType: CTFontUIFontType = 11;
53 pub const kCTFontMenuItemFontType: CTFontUIFontType = 12;
54 pub const kCTFontMenuItemMarkFontType: CTFontUIFontType = 13;
55 pub const kCTFontMenuItemCmdKeyFontType: CTFontUIFontType = 14;
56 pub const kCTFontWindowTitleFontType: CTFontUIFontType = 15;
57 pub const kCTFontPushButtonFontType: CTFontUIFontType = 16;
58 pub const kCTFontUtilityWindowTitleFontType: CTFontUIFontType = 17;
59 pub const kCTFontAlertHeaderFontType: CTFontUIFontType = 18;
60 pub const kCTFontSystemDetailFontType: CTFontUIFontType = 19;
61 pub const kCTFontEmphasizedSystemDetailFontType: CTFontUIFontType = 20;
62 pub const kCTFontToolbarFontType: CTFontUIFontType = 21;
63 pub const kCTFontSmallToolbarFontType: CTFontUIFontType = 22;
64 pub const kCTFontMessageFontType: CTFontUIFontType = 23;
65 pub const kCTFontPaletteFontType: CTFontUIFontType = 24;
66 pub const kCTFontToolTipFontType: CTFontUIFontType = 25;
67 pub const kCTFontControlContentFontType: CTFontUIFontType = 26;
68 
69 pub type CTFontTableTag = u32;
70 // TODO: create bindings for enum with 'chars' values
71 
72 pub type CTFontTableOptions = u32;
73 pub const kCTFontTableOptionsNoOptions: CTFontTableOptions = 0;
74 pub const kCTFontTableOptionsExcludeSynthetic: CTFontTableOptions = 1 << 0;
75 
76 pub type CTFontOptions = CFOptionFlags;
77 pub const kCTFontOptionsDefault: CTFontOptions = 0;
78 pub const kCTFontOptionsPreventAutoActivation: CTFontOptions = 1 << 0;
79 pub const kCTFontOptionsPreferSystemFont: CTFontOptions = 1 << 2;
80 
81 #[repr(C)]
82 pub struct __CTFont(c_void);
83 
84 pub type CTFontRef = *const __CTFont;
85 
86 declare_TCFType! {
87     CTFont, CTFontRef
88 }
89 impl_TCFType!(CTFont, CTFontRef, CTFontGetTypeID);
90 impl_CFTypeDescription!(CTFont);
91 
92 unsafe impl Send for CTFont {}
93 unsafe impl Sync for CTFont {}
94 
new_from_CGFont(cgfont: &CGFont, pt_size: f64) -> CTFont95 pub fn new_from_CGFont(cgfont: &CGFont, pt_size: f64) -> CTFont {
96     unsafe {
97         let font_ref = CTFontCreateWithGraphicsFont(cgfont.as_ptr() as *mut _,
98                                                     pt_size as CGFloat,
99                                                     ptr::null(),
100                                                     ptr::null());
101         CTFont::wrap_under_create_rule(font_ref)
102     }
103 }
104 
new_from_CGFont_with_variations(cgfont: &CGFont, pt_size: f64, variations: &CFDictionary<CFString, CFNumber>) -> CTFont105 pub fn new_from_CGFont_with_variations(cgfont: &CGFont,
106                                        pt_size: f64,
107                                        variations: &CFDictionary<CFString, CFNumber>)
108                                        -> CTFont {
109     unsafe {
110         let font_desc = font_descriptor::new_from_variations(variations);
111         let font_ref = CTFontCreateWithGraphicsFont(cgfont.as_ptr() as *mut _,
112                                                     pt_size as CGFloat,
113                                                     ptr::null(),
114                                                     font_desc.as_concrete_TypeRef());
115         CTFont::wrap_under_create_rule(font_ref)
116     }
117 }
118 
new_from_descriptor(desc: &CTFontDescriptor, pt_size: f64) -> CTFont119 pub fn new_from_descriptor(desc: &CTFontDescriptor, pt_size: f64) -> CTFont {
120     unsafe {
121         let font_ref = CTFontCreateWithFontDescriptor(desc.as_concrete_TypeRef(),
122                                                       pt_size as CGFloat,
123                                                       ptr::null());
124         CTFont::wrap_under_create_rule(font_ref)
125     }
126 }
127 
new_from_buffer(buffer: &[u8]) -> Result<CTFont, ()>128 pub fn new_from_buffer(buffer: &[u8]) -> Result<CTFont, ()> {
129     let ct_font_descriptor = create_font_descriptor(buffer)?;
130     Ok(new_from_descriptor(&ct_font_descriptor, 16.0))
131 }
132 
new_from_name(name: &str, pt_size: f64) -> Result<CTFont, ()>133 pub fn new_from_name(name: &str, pt_size: f64) -> Result<CTFont, ()> {
134     unsafe {
135         let name: CFString = name.parse().unwrap();
136         let font_ref = CTFontCreateWithName(name.as_concrete_TypeRef(),
137                                             pt_size as CGFloat,
138                                             ptr::null());
139         if font_ref.is_null() {
140             Err(())
141         } else {
142             Ok(CTFont::wrap_under_create_rule(font_ref))
143         }
144     }
145 }
146 
147 impl CTFont {
148     // Properties
symbolic_traits(&self) -> CTFontSymbolicTraits149     pub fn symbolic_traits(&self) -> CTFontSymbolicTraits {
150         unsafe {
151             CTFontGetSymbolicTraits(self.0)
152         }
153     }
154 }
155 
156 impl CTFont {
157     // Creation methods
copy_to_CGFont(&self) -> CGFont158     pub fn copy_to_CGFont(&self) -> CGFont {
159         unsafe {
160             let cgfont_ref = CTFontCopyGraphicsFont(self.0, ptr::null_mut());
161             CGFont::from_ptr(cgfont_ref as *mut _)
162         }
163     }
164 
copy_descriptor(&self) -> CTFontDescriptor165     pub fn copy_descriptor(&self) -> CTFontDescriptor {
166         unsafe {
167             let desc = CTFontCopyFontDescriptor(self.0);
168             CTFontDescriptor::wrap_under_create_rule(desc)
169         }
170     }
171 
clone_with_font_size(&self, size: f64) -> CTFont172     pub fn clone_with_font_size(&self, size: f64) -> CTFont {
173         unsafe {
174             let font_ref = CTFontCreateCopyWithAttributes(self.0,
175                                                           size as CGFloat,
176                                                           ptr::null(),
177                                                           ptr::null());
178             CTFont::wrap_under_create_rule(font_ref)
179         }
180     }
181 
clone_with_symbolic_traits(&self, trait_value: CTFontSymbolicTraits, trait_mask: CTFontSymbolicTraits) -> Option<CTFont>182     pub fn clone_with_symbolic_traits(&self,
183                                       trait_value: CTFontSymbolicTraits,
184                                       trait_mask: CTFontSymbolicTraits)
185                                       -> Option<CTFont> {
186         unsafe {
187             let font_ref = CTFontCreateCopyWithSymbolicTraits(self.0,
188                                                               0.0,
189                                                               ptr::null(),
190                                                               trait_value,
191                                                               trait_mask);
192             if font_ref.is_null() {
193                 None
194             } else {
195                 Some(CTFont::wrap_under_create_rule(font_ref))
196             }
197         }
198     }
199 
200     // Names
family_name(&self) -> String201     pub fn family_name(&self) -> String {
202         unsafe {
203             let value = get_string_by_name_key(self, kCTFontFamilyNameKey);
204             value.expect("Fonts should always have a family name.")
205         }
206     }
207 
face_name(&self) -> String208     pub fn face_name(&self) -> String {
209         unsafe {
210             let value = get_string_by_name_key(self, kCTFontSubFamilyNameKey);
211             value.expect("Fonts should always have a face name.")
212         }
213     }
214 
unique_name(&self) -> String215     pub fn unique_name(&self) -> String {
216         unsafe {
217             let value = get_string_by_name_key(self, kCTFontUniqueNameKey);
218             value.expect("Fonts should always have a unique name.")
219         }
220     }
221 
postscript_name(&self) -> String222     pub fn postscript_name(&self) -> String {
223         unsafe {
224             let value = get_string_by_name_key(self, kCTFontPostScriptNameKey);
225             value.expect("Fonts should always have a PostScript name.")
226         }
227     }
228 
display_name(&self) -> String229     pub fn display_name(&self) -> String {
230         unsafe {
231             let value = get_string_by_name_key(self, kCTFontFullNameKey);
232             value.expect("Fonts should always have a PostScript name.")
233         }
234     }
235 
style_name(&self) -> String236     pub fn style_name(&self) -> String {
237         unsafe {
238             let value = get_string_by_name_key(self, kCTFontStyleNameKey);
239             value.expect("Fonts should always have a style name.")
240         }
241     }
242 
all_traits(&self) -> CTFontTraits243     pub fn all_traits(&self) -> CTFontTraits {
244         unsafe {
245             CTFontTraits::wrap_under_create_rule(CTFontCopyTraits(self.0))
246         }
247     }
248 
249     // Font metrics
ascent(&self) -> CGFloat250     pub fn ascent(&self) -> CGFloat {
251         unsafe {
252             CTFontGetAscent(self.0)
253         }
254     }
255 
descent(&self) -> CGFloat256     pub fn descent(&self) -> CGFloat {
257         unsafe {
258             CTFontGetDescent(self.0)
259         }
260     }
261 
underline_thickness(&self) -> CGFloat262     pub fn underline_thickness(&self) -> CGFloat {
263         unsafe {
264             CTFontGetUnderlineThickness(self.0)
265         }
266     }
267 
underline_position(&self) -> CGFloat268     pub fn underline_position(&self) -> CGFloat {
269         unsafe {
270             CTFontGetUnderlinePosition(self.0)
271         }
272     }
273 
slant_angle(&self) -> CGFloat274     pub fn slant_angle(&self) -> CGFloat {
275         unsafe {
276             CTFontGetSlantAngle(self.0)
277         }
278     }
279 
cap_height(&self) -> CGFloat280     pub fn cap_height(&self) -> CGFloat {
281         unsafe {
282             CTFontGetCapHeight(self.0)
283         }
284     }
285 
bounding_box(&self) -> CGRect286     pub fn bounding_box(&self) -> CGRect {
287         unsafe {
288             CTFontGetBoundingBox(self.0)
289         }
290     }
291 
leading(&self) -> CGFloat292     pub fn leading(&self) -> CGFloat {
293         unsafe {
294             CTFontGetLeading(self.0)
295         }
296     }
297 
units_per_em(&self) -> libc::c_uint298     pub fn units_per_em(&self) -> libc::c_uint {
299         unsafe {
300             CTFontGetUnitsPerEm(self.0)
301         }
302     }
303 
x_height(&self) -> CGFloat304     pub fn x_height(&self) -> CGFloat {
305         unsafe {
306             CTFontGetXHeight(self.0)
307         }
308     }
309 
pt_size(&self) -> CGFloat310     pub fn pt_size(&self) -> CGFloat {
311         unsafe {
312             CTFontGetSize(self.0)
313         }
314     }
315 
get_glyph_with_name(&self, glyph_name: &str) -> CGGlyph316     pub fn get_glyph_with_name(&self, glyph_name: &str) -> CGGlyph {
317         let glyph_name = CFString::new(glyph_name);
318         unsafe {
319             CTFontGetGlyphWithName(self.0, glyph_name.as_concrete_TypeRef())
320         }
321     }
322 
get_glyphs_for_characters(&self, characters: *const UniChar, glyphs: *mut CGGlyph, count: CFIndex) -> bool323     pub unsafe fn get_glyphs_for_characters(&self,
324                                             characters: *const UniChar,
325                                             glyphs: *mut CGGlyph,
326                                             count: CFIndex)
327                                             -> bool {
328         CTFontGetGlyphsForCharacters(self.0, characters, glyphs, count)
329     }
330 
get_advances_for_glyphs(&self, orientation: CTFontOrientation, glyphs: *const CGGlyph, advances: *mut CGSize, count: CFIndex) -> f64331     pub unsafe fn get_advances_for_glyphs(&self,
332                                           orientation: CTFontOrientation,
333                                           glyphs: *const CGGlyph,
334                                           advances: *mut CGSize,
335                                           count: CFIndex)
336                                           -> f64 {
337         CTFontGetAdvancesForGlyphs(self.0, orientation, glyphs, advances, count) as f64
338     }
339 
get_vertical_translations_for_glyphs(&self, orientation: CTFontOrientation, glyphs: *const CGGlyph, translations: *mut CGSize, count: CFIndex)340     pub unsafe fn get_vertical_translations_for_glyphs(&self,
341                                                        orientation: CTFontOrientation,
342                                                        glyphs: *const CGGlyph,
343                                                        translations: *mut CGSize,
344                                                        count: CFIndex) {
345         CTFontGetVerticalTranslationsForGlyphs(self.0,
346                                                orientation,
347                                                glyphs,
348                                                translations,
349                                                count)
350     }
351 
get_font_table(&self, tag: u32) -> Option<CFData>352     pub fn get_font_table(&self, tag: u32) -> Option<CFData> {
353         unsafe {
354             let result = CTFontCopyTable(self.0,
355                                          tag as CTFontTableTag,
356                                          kCTFontTableOptionsExcludeSynthetic);
357             if result.is_null() {
358                 None
359             } else {
360                 Some(CFData::wrap_under_create_rule(result))
361             }
362         }
363     }
364 
get_available_font_tables(&self) -> Option<CFArray<CTFontTableTag>>365     pub fn get_available_font_tables(&self) -> Option<CFArray<CTFontTableTag>> {
366         unsafe {
367             let result = CTFontCopyAvailableTables(self.0, kCTFontTableOptionsExcludeSynthetic);
368             if result.is_null() {
369                 None
370             } else {
371                 Some(TCFType::wrap_under_create_rule(result))
372             }
373         }
374     }
375 
get_bounding_rects_for_glyphs(&self, orientation: CTFontOrientation, glyphs: &[CGGlyph]) -> CGRect376     pub fn get_bounding_rects_for_glyphs(&self, orientation: CTFontOrientation, glyphs: &[CGGlyph])
377                                          -> CGRect {
378         unsafe {
379             CTFontGetBoundingRectsForGlyphs(self.as_concrete_TypeRef(),
380                                             orientation,
381                                             glyphs.as_ptr(),
382                                             ptr::null_mut(),
383                                             glyphs.len() as CFIndex)
384         }
385     }
386 
draw_glyphs(&self, glyphs: &[CGGlyph], positions: &[CGPoint], context: CGContext)387     pub fn draw_glyphs(&self, glyphs: &[CGGlyph], positions: &[CGPoint], context: CGContext) {
388         assert_eq!(glyphs.len(), positions.len());
389         unsafe {
390             CTFontDrawGlyphs(self.as_concrete_TypeRef(),
391                              glyphs.as_ptr(),
392                              positions.as_ptr(),
393                              glyphs.len() as size_t,
394                              context.as_ptr())
395         }
396     }
397 
url(&self) -> Option<CFURL>398     pub fn url(&self) -> Option<CFURL> {
399         unsafe {
400             let result = CTFontCopyAttribute(self.0, kCTFontURLAttribute);
401             if result.is_null() {
402                 None
403             } else {
404                 Some(CFURL::wrap_under_create_rule(result as CFURLRef))
405             }
406         }
407     }
408 
get_variation_axes(&self) -> Option<CFArray<CFDictionary<CFString, CFType>>>409     pub fn get_variation_axes(&self) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
410         unsafe {
411             let axes = CTFontCopyVariationAxes(self.0);
412             if axes.is_null() {
413                 return None;
414             }
415             Some(TCFType::wrap_under_create_rule(axes))
416         }
417     }
418 
create_path_for_glyph(&self, glyph: CGGlyph, matrix: &CGAffineTransform) -> Result<CGPath, ()>419     pub fn create_path_for_glyph(&self, glyph: CGGlyph, matrix: &CGAffineTransform)
420                                  -> Result<CGPath, ()> {
421         unsafe {
422             let path = CTFontCreatePathForGlyph(self.0, glyph, matrix);
423             if path.is_null() {
424                 Err(())
425             } else {
426                 Ok(CGPath::from_ptr(path))
427             }
428         }
429     }
430 
431     #[inline]
glyph_count(&self) -> CFIndex432     pub fn glyph_count(&self) -> CFIndex {
433         unsafe {
434             CTFontGetGlyphCount(self.0)
435         }
436     }
437 }
438 
439 // Helper methods
get_string_by_name_key(font: &CTFont, name_key: CFStringRef) -> Option<String>440 fn get_string_by_name_key(font: &CTFont, name_key: CFStringRef) -> Option<String> {
441     unsafe {
442         let result = CTFontCopyName(font.as_concrete_TypeRef(), name_key);
443         if result.is_null() {
444             None
445         } else {
446             Some(CFString::wrap_under_create_rule(result).to_string())
447         }
448     }
449 }
450 
debug_font_names(font: &CTFont)451 pub fn debug_font_names(font: &CTFont) {
452     fn get_key(font: &CTFont, key: CFStringRef) -> String {
453         get_string_by_name_key(font, key).unwrap()
454     }
455 
456     unsafe {
457         println!("kCTFontFamilyNameKey: {}", get_key(font, kCTFontFamilyNameKey));
458         println!("kCTFontSubFamilyNameKey: {}", get_key(font, kCTFontSubFamilyNameKey));
459         println!("kCTFontStyleNameKey: {}", get_key(font, kCTFontStyleNameKey));
460         println!("kCTFontUniqueNameKey: {}", get_key(font, kCTFontUniqueNameKey));
461         println!("kCTFontFullNameKey: {}", get_key(font, kCTFontFullNameKey));
462         println!("kCTFontPostScriptNameKey: {}", get_key(font, kCTFontPostScriptNameKey));
463     }
464 }
465 
debug_font_traits(font: &CTFont)466 pub fn debug_font_traits(font: &CTFont) {
467     let sym = font.symbolic_traits();
468     println!("kCTFontItalicTrait: {}", sym.is_italic());
469     println!("kCTFontBoldTrait: {}", sym.is_bold());
470     println!("kCTFontExpandedTrait: {}", sym.is_expanded());
471     println!("kCTFontCondensedTrait: {}", sym.is_condensed());
472     println!("kCTFontMonoSpaceTrait: {}", sym.is_monospace());
473 
474     let traits = font.all_traits();
475     println!("kCTFontWeightTrait: {}", traits.normalized_weight());
476     println!("kCTFontWidthTrait: {}", traits.normalized_width());
477 //    println!("kCTFontSlantTrait: {}", traits.normalized_slant());
478 }
479 
480 #[cfg(feature = "mountainlion")]
cascade_list_for_languages(font: &CTFont, language_pref_list: &CFArray<CFString>) -> CFArray<CTFontDescriptor>481 pub fn cascade_list_for_languages(font: &CTFont, language_pref_list: &CFArray<CFString>) -> CFArray<CTFontDescriptor> {
482     unsafe {
483         let font_collection_ref =
484             CTFontCopyDefaultCascadeListForLanguages(font.as_concrete_TypeRef(),
485                                                      language_pref_list.as_concrete_TypeRef());
486         CFArray::wrap_under_create_rule(font_collection_ref)
487     }
488 }
489 
490 #[link(name = "CoreText", kind = "framework")]
491 extern {
492     /*
493      * CTFont.h
494      */
495 
496     /* Name Specifier Constants */
497     //static kCTFontCopyrightNameKey: CFStringRef;
498     static kCTFontFamilyNameKey: CFStringRef;
499     static kCTFontSubFamilyNameKey: CFStringRef;
500     static kCTFontStyleNameKey: CFStringRef;
501     static kCTFontUniqueNameKey: CFStringRef;
502     static kCTFontFullNameKey: CFStringRef;
503     //static kCTFontVersionNameKey: CFStringRef;
504     static kCTFontPostScriptNameKey: CFStringRef;
505     //static kCTFontTrademarkNameKey: CFStringRef;
506     //static kCTFontManufacturerNameKey: CFStringRef;
507     //static kCTFontDesignerNameKey: CFStringRef;
508     //static kCTFontDescriptionNameKey: CFStringRef;
509     //static kCTFontVendorURLNameKey: CFStringRef;
510     //static kCTFontDesignerURLNameKey: CFStringRef;
511     //static kCTFontLicenseNameKey: CFStringRef;
512     //static kCTFontLicenseURLNameKey: CFStringRef;
513     //static kCTFontSampleTextNameKey: CFStringRef;
514     //static kCTFontPostScriptCIDNameKey: CFStringRef;
515 
516     //static kCTFontVariationAxisIdentifierKey: CFStringRef;
517     //static kCTFontVariationAxisMinimumValueKey: CFStringRef;
518     //static kCTFontVariationAxisMaximumValueKey: CFStringRef;
519     //static kCTFontVariationAxisDefaultValueKey: CFStringRef;
520     //static kCTFontVariationAxisNameKey: CFStringRef;
521 
522     //static kCTFontFeatureTypeIdentifierKey: CFStringRef;
523     //static kCTFontFeatureTypeNameKey: CFStringRef;
524     //static kCTFontFeatureTypeExclusiveKey: CFStringRef;
525     //static kCTFontFeatureTypeSelectorsKey: CFStringRef;
526     //static kCTFontFeatureSelectorIdentifierKey: CFStringRef;
527     //static kCTFontFeatureSelectorNameKey: CFStringRef;
528     //static kCTFontFeatureSelectorDefaultKey: CFStringRef;
529     //static kCTFontFeatureSelectorSettingKey: CFStringRef;
530 
531     static kCTFontURLAttribute: CFStringRef;
532 
533     // N.B. Unlike most Cocoa bindings, this extern block is organized according
534     // to the documentation's Functions By Task listing, because there so many functions.
535 
536     /* Creating Fonts */
CTFontCreateWithName(name: CFStringRef, size: CGFloat, matrix: *const CGAffineTransform) -> CTFontRef537     fn CTFontCreateWithName(name: CFStringRef, size: CGFloat, matrix: *const CGAffineTransform) -> CTFontRef;
538     //fn CTFontCreateWithNameAndOptions
CTFontCreateWithFontDescriptor(descriptor: CTFontDescriptorRef, size: CGFloat, matrix: *const CGAffineTransform) -> CTFontRef539     fn CTFontCreateWithFontDescriptor(descriptor: CTFontDescriptorRef, size: CGFloat,
540                                       matrix: *const CGAffineTransform) -> CTFontRef;
541     //fn CTFontCreateWithFontDescriptorAndOptions
542     #[cfg(test)]
CTFontCreateUIFontForLanguage(uiType: CTFontUIFontType, size: CGFloat, language: CFStringRef) -> CTFontRef543     fn CTFontCreateUIFontForLanguage(uiType: CTFontUIFontType, size: CGFloat, language: CFStringRef) -> CTFontRef;
CTFontCreateCopyWithAttributes(font: CTFontRef, size: CGFloat, matrix: *const CGAffineTransform, attributes: CTFontDescriptorRef) -> CTFontRef544     fn CTFontCreateCopyWithAttributes(font: CTFontRef, size: CGFloat, matrix: *const CGAffineTransform,
545                                       attributes: CTFontDescriptorRef) -> CTFontRef;
CTFontCreateCopyWithSymbolicTraits(font: CTFontRef, size: CGFloat, matrix: *const CGAffineTransform, symTraitValue: CTFontSymbolicTraits, symTraitMask: CTFontSymbolicTraits) -> CTFontRef546     fn CTFontCreateCopyWithSymbolicTraits(font: CTFontRef,
547                                           size: CGFloat,
548                                           matrix: *const CGAffineTransform,
549                                           symTraitValue: CTFontSymbolicTraits,
550                                           symTraitMask: CTFontSymbolicTraits)
551                                           -> CTFontRef;
552     //fn CTFontCreateCopyWithFamily
553     //fn CTFontCreateForString
554 
555     /* Getting Font Data */
CTFontCopyFontDescriptor(font: CTFontRef) -> CTFontDescriptorRef556     fn CTFontCopyFontDescriptor(font: CTFontRef) -> CTFontDescriptorRef;
CTFontCopyAttribute(font: CTFontRef, attribute: CFStringRef) -> CFTypeRef557     fn CTFontCopyAttribute(font: CTFontRef, attribute: CFStringRef) -> CFTypeRef;
CTFontGetSize(font: CTFontRef) -> CGFloat558     fn CTFontGetSize(font: CTFontRef) -> CGFloat;
559     //fn CTFontGetMatrix
CTFontGetSymbolicTraits(font: CTFontRef) -> CTFontSymbolicTraits560     fn CTFontGetSymbolicTraits(font: CTFontRef) -> CTFontSymbolicTraits;
CTFontCopyTraits(font: CTFontRef) -> CFDictionaryRef561     fn CTFontCopyTraits(font: CTFontRef) -> CFDictionaryRef;
562 
563     /* Getting Font Names */
564     //fn CTFontCopyPostScriptName(font: CTFontRef) -> CFStringRef;
565     //fn CTFontCopyFamilyName(font: CTFontRef) -> CFStringRef;
566     //fn CTFontCopyFullName(font: CTFontRef) -> CFStringRef;
567     //fn CTFontCopyDisplayName(font: CTFontRef) -> CFStringRef;
CTFontCopyName(font: CTFontRef, nameKey: CFStringRef) -> CFStringRef568     fn CTFontCopyName(font: CTFontRef, nameKey: CFStringRef) -> CFStringRef;
569     //fn CTFontCopyLocalizedName(font: CTFontRef, nameKey: CFStringRef,
570     //                           language: *CFStringRef) -> CFStringRef;
571     #[cfg(feature = "mountainlion")]
CTFontCopyDefaultCascadeListForLanguages(font: CTFontRef, languagePrefList: CFArrayRef) -> CFArrayRef572     fn CTFontCopyDefaultCascadeListForLanguages(font: CTFontRef, languagePrefList: CFArrayRef) -> CFArrayRef;
573 
574 
575     /* Working With Encoding */
576     //fn CTFontCopyCharacterSet
577     //fn CTFontGetStringEncoding
578     //fn CTFontCopySupportedLanguages
579 
580     /* Getting Font Metrics */
CTFontGetAscent(font: CTFontRef) -> CGFloat581     fn CTFontGetAscent(font: CTFontRef) -> CGFloat;
CTFontGetDescent(font: CTFontRef) -> CGFloat582     fn CTFontGetDescent(font: CTFontRef) -> CGFloat;
CTFontGetLeading(font: CTFontRef) -> CGFloat583     fn CTFontGetLeading(font: CTFontRef) -> CGFloat;
CTFontGetUnitsPerEm(font: CTFontRef) -> libc::c_uint584     fn CTFontGetUnitsPerEm(font: CTFontRef) -> libc::c_uint;
CTFontGetGlyphCount(font: CTFontRef) -> CFIndex585     fn CTFontGetGlyphCount(font: CTFontRef) -> CFIndex;
CTFontGetBoundingBox(font: CTFontRef) -> CGRect586     fn CTFontGetBoundingBox(font: CTFontRef) -> CGRect;
CTFontGetUnderlinePosition(font: CTFontRef) -> CGFloat587     fn CTFontGetUnderlinePosition(font: CTFontRef) -> CGFloat;
CTFontGetUnderlineThickness(font: CTFontRef) -> CGFloat588     fn CTFontGetUnderlineThickness(font: CTFontRef) -> CGFloat;
CTFontGetSlantAngle(font: CTFontRef) -> CGFloat589     fn CTFontGetSlantAngle(font: CTFontRef) -> CGFloat;
CTFontGetCapHeight(font: CTFontRef) -> CGFloat590     fn CTFontGetCapHeight(font: CTFontRef) -> CGFloat;
CTFontGetXHeight(font: CTFontRef) -> CGFloat591     fn CTFontGetXHeight(font: CTFontRef) -> CGFloat;
592 
593     /* Getting Glyph Data */
CTFontCreatePathForGlyph(font: CTFontRef, glyph: CGGlyph, matrix: *const CGAffineTransform) -> CGPathRef594     fn CTFontCreatePathForGlyph(font: CTFontRef, glyph: CGGlyph, matrix: *const CGAffineTransform)
595                                 -> CGPathRef;
CTFontGetGlyphWithName(font: CTFontRef, glyphName: CFStringRef) -> CGGlyph596     fn CTFontGetGlyphWithName(font: CTFontRef, glyphName: CFStringRef) -> CGGlyph;
CTFontGetBoundingRectsForGlyphs(font: CTFontRef, orientation: CTFontOrientation, glyphs: *const CGGlyph, boundingRects: *mut CGRect, count: CFIndex) -> CGRect597     fn CTFontGetBoundingRectsForGlyphs(font: CTFontRef,
598                                        orientation: CTFontOrientation,
599                                        glyphs: *const CGGlyph,
600                                        boundingRects: *mut CGRect,
601                                        count: CFIndex)
602                                        -> CGRect;
CTFontGetAdvancesForGlyphs(font: CTFontRef, orientation: CTFontOrientation, glyphs: *const CGGlyph, advances: *mut CGSize, count: CFIndex) -> libc::c_double603     fn CTFontGetAdvancesForGlyphs(font: CTFontRef,
604                                   orientation: CTFontOrientation,
605                                   glyphs: *const CGGlyph,
606                                   advances: *mut CGSize,
607                                   count: CFIndex)
608                                   -> libc::c_double;
CTFontGetVerticalTranslationsForGlyphs(font: CTFontRef, orientation: CTFontOrientation, glyphs: *const CGGlyph, translations: *mut CGSize, count: CFIndex)609     fn CTFontGetVerticalTranslationsForGlyphs(font: CTFontRef,
610                                               orientation: CTFontOrientation,
611                                               glyphs: *const CGGlyph,
612                                               translations: *mut CGSize,
613                                               count: CFIndex);
614 
615     /* Working With Font Variations */
CTFontCopyVariationAxes(font: CTFontRef) -> CFArrayRef616     fn CTFontCopyVariationAxes(font: CTFontRef) -> CFArrayRef;
617     //fn CTFontCopyVariation
618 
619     /* Getting Font Features */
620     //fn CTFontCopyFeatures
621     //fn CTFontCopyFeatureSettings
622 
623     /* Working with Glyphs */
CTFontGetGlyphsForCharacters(font: CTFontRef, characters: *const UniChar, glyphs: *mut CGGlyph, count: CFIndex) -> bool624     fn CTFontGetGlyphsForCharacters(font: CTFontRef, characters: *const UniChar, glyphs: *mut CGGlyph, count: CFIndex) -> bool;
CTFontDrawGlyphs(font: CTFontRef, glyphs: *const CGGlyph, positions: *const CGPoint, count: size_t, context: CGContextRef)625     fn CTFontDrawGlyphs(font: CTFontRef,
626                         glyphs: *const CGGlyph,
627                         positions: *const CGPoint,
628                         count: size_t,
629                         context: CGContextRef);
630     //fn CTFontGetLigatureCaretPositions
631 
632     /* Converting Fonts */
CTFontCopyGraphicsFont(font: CTFontRef, attributes: *mut CTFontDescriptorRef) -> CGFontRef633     fn CTFontCopyGraphicsFont(font: CTFontRef, attributes: *mut CTFontDescriptorRef)
634                               -> CGFontRef;
CTFontCreateWithGraphicsFont(graphicsFont: CGFontRef, size: CGFloat, matrix: *const CGAffineTransform, attributes: CTFontDescriptorRef) -> CTFontRef635     fn CTFontCreateWithGraphicsFont(graphicsFont: CGFontRef, size: CGFloat,
636                                     matrix: *const CGAffineTransform,
637                                     attributes: CTFontDescriptorRef) -> CTFontRef;
638     //fn CTFontGetPlatformFont
639     //fn CTFontCreateWithPlatformFont
640     //fn CTFontCreateWithQuickdrawInstance
641 
642     /* Getting Font Table Data */
CTFontCopyAvailableTables(font: CTFontRef, options: CTFontTableOptions) -> CFArrayRef643     fn CTFontCopyAvailableTables(font: CTFontRef, options: CTFontTableOptions) -> CFArrayRef;
CTFontCopyTable(font: CTFontRef, table: CTFontTableTag, options: CTFontTableOptions) -> CFDataRef644     fn CTFontCopyTable(font: CTFontRef, table: CTFontTableTag, options: CTFontTableOptions) -> CFDataRef;
645 
CTFontGetTypeID() -> CFTypeID646     fn CTFontGetTypeID() -> CFTypeID;
647 }
648 
649 #[test]
copy_font()650 fn copy_font() {
651     use std::io::Read;
652     let mut f = std::fs::File::open("/System/Library/Fonts/ZapfDingbats.ttf").unwrap();
653     let mut font_data = Vec::new();
654     f.read_to_end(&mut font_data).unwrap();
655     let desc = crate::font_manager::create_font_descriptor(&font_data).unwrap();
656     let font = new_from_descriptor(&desc, 12.);
657     drop(desc);
658     let desc = font.copy_descriptor();
659     drop(font);
660     let font = new_from_descriptor(&desc, 14.);
661     assert_eq!(font.family_name(), "Zapf Dingbats");
662 }
663 
664 #[cfg(test)]
macos_version() -> (i32, i32, i32)665 fn macos_version() -> (i32, i32, i32) {
666     use std::io::Read;
667 
668     // This is the same approach that Firefox uses for detecting versions
669     let file = "/System/Library/CoreServices/SystemVersion.plist";
670     let mut f = std::fs::File::open(file).unwrap();
671     let mut system_version_data = Vec::new();
672     f.read_to_end(&mut system_version_data).unwrap();
673 
674     use core_foundation::propertylist;
675     let (list, _) = propertylist::create_with_data(core_foundation::data::CFData::from_buffer(&system_version_data), propertylist::kCFPropertyListImmutable).unwrap();
676     let k = unsafe { propertylist::CFPropertyList::wrap_under_create_rule(list) };
677 
678     let dict = unsafe { std::mem::transmute::<_, CFDictionary<CFType, CFType>>(k.downcast::<CFDictionary>().unwrap()) };
679 
680     let version = dict.find(&CFString::new("ProductVersion").as_CFType())
681         .as_ref().unwrap()
682         .downcast::<CFString>().unwrap()
683         .to_string();
684 
685     match version.split(".").map(|x| x.parse().unwrap()).collect::<Vec<_>>()[..] {
686         [a, b, c] => (a, b, c),
687         [a, b] => (a, b, 0),
688         _ => panic!()
689     }
690 }
691 
692 #[test]
copy_system_font()693 fn copy_system_font() {
694     let small = unsafe {
695         CTFont::wrap_under_create_rule(
696             CTFontCreateUIFontForLanguage(kCTFontSystemDetailFontType, 19., std::ptr::null())
697         )
698     };
699     let big = small.clone_with_font_size(20.);
700 
701     // ensure that we end up with different fonts for the different sizes before 10.15
702     if macos_version() < (10, 15, 0) {
703         assert_ne!(big.url(), small.url());
704     } else {
705         assert_eq!(big.url(), small.url());
706     }
707 
708     let ps = small.postscript_name();
709     let desc = small.copy_descriptor();
710 
711     // check that we can construct a new vesion by descriptor
712     let ctfont = new_from_descriptor(&desc, 20.);
713     assert_eq!(big.postscript_name(), ctfont.postscript_name());
714 
715     // on newer versions of macos we can't construct by name anymore
716     if macos_version() < (10, 13, 0) {
717         let ui_font_by_name = new_from_name(&small.postscript_name(), 19.).unwrap();
718         assert_eq!(ui_font_by_name.postscript_name(), small.postscript_name());
719 
720         let ui_font_by_name = new_from_name(&small.postscript_name(), 20.).unwrap();
721         assert_eq!(ui_font_by_name.postscript_name(), small.postscript_name());
722 
723         let ui_font_by_name = new_from_name(&big.postscript_name(), 20.).unwrap();
724         assert_eq!(ui_font_by_name.postscript_name(), big.postscript_name());
725     }
726 
727     // but we can still construct the CGFont by name
728     let cgfont = CGFont::from_name(&CFString::new(&ps)).unwrap();
729     let cgfont = new_from_CGFont(&cgfont, 0.);
730     println!("{:?}", cgfont);
731     let desc = cgfont.copy_descriptor();
732     let matching  = unsafe { crate::font_descriptor::CTFontDescriptorCreateMatchingFontDescriptor(desc.as_concrete_TypeRef(), std::ptr::null()) };
733     let matching =         unsafe { CTFontDescriptor::wrap_under_create_rule(matching) };
734 
735     println!("{:?}", cgfont.copy_descriptor());
736     assert!(desc.attributes().find(CFString::from_static_string("NSFontSizeAttribute")).is_some());
737 
738     println!("{:?}", matching);
739     println!("{:?}", matching.attributes().find(CFString::from_static_string("NSFontSizeAttribute")));
740 
741     assert!(matching.attributes().find(CFString::from_static_string("NSFontSizeAttribute")).is_none());
742 
743     assert_eq!(small.postscript_name(), cgfont.postscript_name());
744 }