Skip to main content

core_text/
font_collection.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
10use crate::font_descriptor;
11use crate::font_descriptor::{CTFontDescriptor, CTFontDescriptorCreateMatchingFontDescriptors};
12use crate::font_manager::{
13    CTFontManagerCopyAvailableFontFamilyNames, CTFontManagerCopyAvailablePostScriptNames,
14};
15
16use core_foundation::array::{CFArray, CFArrayRef};
17use core_foundation::base::{CFTypeID, TCFType};
18use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
19use core_foundation::number::CFNumber;
20use core_foundation::set::CFSet;
21use core_foundation::string::{CFString, CFStringRef};
22use core_foundation::{declare_TCFType, impl_CFTypeDescription, impl_TCFType};
23
24#[repr(C)]
25pub struct __CTFontCollection(core::ffi::c_void);
26
27pub type CTFontCollectionRef = *const __CTFontCollection;
28
29declare_TCFType! {
30    CTFontCollection, CTFontCollectionRef
31}
32impl_TCFType!(
33    CTFontCollection,
34    CTFontCollectionRef,
35    CTFontCollectionGetTypeID
36);
37impl_CFTypeDescription!(CTFontCollection);
38
39impl CTFontCollection {
40    pub fn get_descriptors(&self) -> Option<CFArray<CTFontDescriptor>> {
41        unsafe {
42            let font_descriptors = CTFontCollectionCreateMatchingFontDescriptors(self.0);
43            if font_descriptors.is_null() {
44                // This returns null if there are no matching font descriptors.
45                None
46            } else {
47                Some(CFArray::wrap_under_create_rule(font_descriptors))
48            }
49        }
50    }
51}
52
53pub fn new_from_descriptors(descs: &CFArray<CTFontDescriptor>) -> CTFontCollection {
54    unsafe {
55        let key = CFString::wrap_under_get_rule(kCTFontCollectionRemoveDuplicatesOption);
56        let value = CFNumber::from(1i64);
57        let options = CFDictionary::from_CFType_pairs(&[(key.as_CFType(), value.as_CFType())]);
58        let font_collection_ref = CTFontCollectionCreateWithFontDescriptors(
59            descs.as_concrete_TypeRef(),
60            options.as_concrete_TypeRef(),
61        );
62        CTFontCollection::wrap_under_create_rule(font_collection_ref)
63    }
64}
65
66pub fn create_for_all_families() -> CTFontCollection {
67    unsafe {
68        let key = CFString::wrap_under_get_rule(kCTFontCollectionRemoveDuplicatesOption);
69        let value = CFNumber::from(1i64);
70        let options = CFDictionary::from_CFType_pairs(&[(key.as_CFType(), value.as_CFType())]);
71        let font_collection_ref =
72            CTFontCollectionCreateFromAvailableFonts(options.as_concrete_TypeRef());
73        CTFontCollection::wrap_under_create_rule(font_collection_ref)
74    }
75}
76
77pub fn create_for_family(family: &str) -> Option<CTFontCollection> {
78    use crate::font_descriptor::kCTFontFamilyNameAttribute;
79
80    unsafe {
81        let family_attr = CFString::wrap_under_get_rule(kCTFontFamilyNameAttribute);
82        let family_name: CFString = family.parse().unwrap();
83        let specified_attrs =
84            CFDictionary::from_CFType_pairs(&[(family_attr.clone(), family_name.as_CFType())]);
85
86        let wildcard_desc: CTFontDescriptor =
87            font_descriptor::new_from_attributes(&specified_attrs);
88        let mandatory_attrs = CFSet::from_slice(&[family_attr.as_CFType()]);
89        let matched_descs = CTFontDescriptorCreateMatchingFontDescriptors(
90            wildcard_desc.as_concrete_TypeRef(),
91            mandatory_attrs.as_concrete_TypeRef(),
92        );
93        if matched_descs.is_null() {
94            return None;
95        }
96        let matched_descs = CFArray::wrap_under_create_rule(matched_descs);
97        // I suppose one doesn't even need the CTFontCollection object at this point.
98        // But we stick descriptors into and out of it just to provide a nice wrapper API.
99        Some(new_from_descriptors(&matched_descs))
100    }
101}
102
103pub fn get_family_names() -> CFArray<CFString> {
104    unsafe { CFArray::wrap_under_create_rule(CTFontManagerCopyAvailableFontFamilyNames()) }
105}
106
107pub fn get_postscript_names() -> CFArray<CFString> {
108    unsafe { CFArray::wrap_under_create_rule(CTFontManagerCopyAvailablePostScriptNames()) }
109}
110
111extern "C" {
112    /*
113     * CTFontCollection.h
114     */
115
116    static kCTFontCollectionRemoveDuplicatesOption: CFStringRef;
117
118    //fn CTFontCollectionCreateCopyWithFontDescriptors(original: CTFontCollectionRef,
119    //                                                 descriptors: CFArrayRef,
120    //                                                 options: CFDictionaryRef) -> CTFontCollectionRef;
121    fn CTFontCollectionCreateFromAvailableFonts(options: CFDictionaryRef) -> CTFontCollectionRef;
122    // this stupid function doesn't actually do any wildcard expansion;
123    // it just chooses the best match. Use
124    // CTFontDescriptorCreateMatchingDescriptors instead.
125    fn CTFontCollectionCreateMatchingFontDescriptors(collection: CTFontCollectionRef)
126        -> CFArrayRef;
127    fn CTFontCollectionCreateWithFontDescriptors(
128        descriptors: CFArrayRef,
129        options: CFDictionaryRef,
130    ) -> CTFontCollectionRef;
131    //fn CTFontCollectionCreateMatchingFontDescriptorsSortedWithCallback;
132    fn CTFontCollectionGetTypeID() -> CFTypeID;
133}