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 }