font_kit/sources/
directwrite.rs

1// font-kit/src/sources/directwrite.rs
2//
3// Copyright © 2018 The Pathfinder Project Developers.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! A source that contains the installed fonts on Windows.
12
13use dwrote::Font as DWriteFont;
14use dwrote::FontCollection as DWriteFontCollection;
15use std::any::Any;
16
17use crate::error::SelectionError;
18use crate::family_handle::FamilyHandle;
19use crate::family_name::FamilyName;
20use crate::handle::Handle;
21use crate::properties::Properties;
22use crate::source::Source;
23
24/// A source that contains the installed fonts on Windows.
25#[allow(missing_debug_implementations)]
26pub struct DirectWriteSource {
27    system_font_collection: DWriteFontCollection,
28}
29
30impl DirectWriteSource {
31    /// Opens the system font collection.
32    pub fn new() -> DirectWriteSource {
33        DirectWriteSource {
34            system_font_collection: DWriteFontCollection::system(),
35        }
36    }
37
38    /// Returns paths of all fonts installed on the system.
39    pub fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
40        let mut handles = Vec::new();
41
42        for dwrite_family in self.system_font_collection.families_iter() {
43            for font_index in 0..dwrite_family.get_font_count() {
44                let Ok(dwrite_font) = dwrite_family.font(font_index) else {
45                    continue;
46                };
47                handles.push(self.create_handle_from_dwrite_font(dwrite_font))
48            }
49        }
50
51        Ok(handles)
52    }
53
54    /// Returns the names of all families installed on the system.
55    pub fn all_families(&self) -> Result<Vec<String>, SelectionError> {
56        Ok(self
57            .system_font_collection
58            .families_iter()
59            .filter_map(|dwrite_family| dwrite_family.family_name().ok())
60            .collect())
61    }
62
63    /// Looks up a font family by name and returns the handles of all the fonts in that family.
64    ///
65    /// TODO(pcwalton): Case-insensitivity.
66    pub fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
67        let mut family = FamilyHandle::new();
68        let dwrite_family = match self.system_font_collection.font_family_by_name(family_name) {
69            Ok(Some(dwrite_family)) => dwrite_family,
70            Err(_) | Ok(None) => return Err(SelectionError::NotFound),
71        };
72        for font_index in 0..dwrite_family.get_font_count() {
73            let Ok(dwrite_font) = dwrite_family.font(font_index) else {
74                continue;
75            };
76            family.push(self.create_handle_from_dwrite_font(dwrite_font));
77        }
78        Ok(family)
79    }
80
81    /// Selects a font by PostScript name, which should be a unique identifier.
82    ///
83    /// On the DirectWrite backend, this does a brute-force search of installed fonts to find the
84    /// one that matches.
85    pub fn select_by_postscript_name(
86        &self,
87        postscript_name: &str,
88    ) -> Result<Handle, SelectionError> {
89        <Self as Source>::select_by_postscript_name(self, postscript_name)
90    }
91
92    /// Performs font matching according to the CSS Fonts Level 3 specification and returns the
93    /// handle.
94    #[inline]
95    pub fn select_best_match(
96        &self,
97        family_names: &[FamilyName],
98        properties: &Properties,
99    ) -> Result<Handle, SelectionError> {
100        <Self as Source>::select_best_match(self, family_names, properties)
101    }
102
103    fn create_handle_from_dwrite_font(&self, dwrite_font: DWriteFont) -> Handle {
104        let dwrite_font_face = dwrite_font.create_font_face();
105        let dwrite_font_files = dwrite_font_face.get_files();
106        Handle::Path {
107            path: dwrite_font_files[0].get_font_file_path().unwrap(),
108            font_index: dwrite_font_face.get_index(),
109        }
110    }
111}
112
113impl Source for DirectWriteSource {
114    #[inline]
115    fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
116        self.all_fonts()
117    }
118
119    #[inline]
120    fn all_families(&self) -> Result<Vec<String>, SelectionError> {
121        self.all_families()
122    }
123
124    #[inline]
125    fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
126        self.select_family_by_name(family_name)
127    }
128
129    #[inline]
130    fn as_any(&self) -> &dyn Any {
131        self
132    }
133
134    #[inline]
135    fn as_mut_any(&mut self) -> &mut dyn Any {
136        self
137    }
138}