font_kit/sources/
mem.rs

1// font-kit/src/sources/mem.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 keeps fonts in memory.
12
13use crate::error::{FontLoadingError, SelectionError};
14use crate::family_handle::FamilyHandle;
15use crate::family_name::FamilyName;
16use crate::font::Font;
17use crate::handle::Handle;
18use crate::properties::Properties;
19use crate::source::Source;
20use std::any::Any;
21
22/// A source that keeps fonts in memory.
23#[allow(missing_debug_implementations)]
24pub struct MemSource {
25    families: Vec<FamilyEntry>,
26}
27
28impl MemSource {
29    /// Creates a new empty memory source.
30    pub fn empty() -> MemSource {
31        MemSource { families: vec![] }
32    }
33
34    /// Creates a new memory source that contains the given set of font handles.
35    ///
36    /// The fonts referenced by the handles are eagerly loaded into memory.
37    pub fn from_fonts<I>(fonts: I) -> Result<MemSource, FontLoadingError>
38    where
39        I: Iterator<Item = Handle>,
40    {
41        let mut families = vec![];
42        for handle in fonts {
43            add_font(handle, &mut families)?;
44        }
45        families.sort_by(|a, b| a.family_name.cmp(&b.family_name));
46        Ok(MemSource { families })
47    }
48
49    /// Add an existing font handle to a `MemSource`.
50    ///
51    /// Returns the font that was just added.
52    ///
53    /// Note that adding fonts to an existing `MemSource` is slower than creating a new one from a
54    /// `Handle` iterator, since this method sorts after every addition, rather than once at the
55    /// end.
56    pub fn add_font(&mut self, handle: Handle) -> Result<Font, FontLoadingError> {
57        let font = add_font(handle, &mut self.families)?;
58        self.families
59            .sort_by(|a, b| a.family_name.cmp(&b.family_name));
60        Ok(font)
61    }
62
63    /// Add a number of existing font handles to a `MemSource`.
64    ///
65    /// Note that adding fonts to an existing `MemSource` is slower than creating a new one from a
66    /// `Handle` iterator, because extra unnecessary sorting with occur with every call to this
67    /// method.
68    pub fn add_fonts(
69        &mut self,
70        handles: impl Iterator<Item = Handle>,
71    ) -> Result<(), FontLoadingError> {
72        for handle in handles {
73            add_font(handle, &mut self.families)?;
74        }
75        self.families
76            .sort_by(|a, b| a.family_name.cmp(&b.family_name));
77        Ok(())
78    }
79
80    /// Returns paths of all fonts installed on the system.
81    pub fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
82        Ok(self
83            .families
84            .iter()
85            .map(|family| family.font.clone())
86            .collect())
87    }
88
89    /// Returns the names of all families installed on the system.
90    pub fn all_families(&self) -> Result<Vec<String>, SelectionError> {
91        let mut families = vec![];
92        for family in &self.families {
93            if families.last() == Some(&family.family_name) {
94                continue;
95            }
96
97            families.push(family.family_name.clone());
98        }
99
100        Ok(families)
101    }
102
103    /// Looks up a font family by name and returns the handles of all the fonts in that family.
104    ///
105    /// FIXME(pcwalton): Case-insensitive comparison.
106    pub fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
107        let mut first_family_index = self
108            .families
109            .binary_search_by(|family| (*family.family_name).cmp(family_name))
110            .map_err(|_| SelectionError::NotFound)?;
111
112        while first_family_index > 0
113            && self.families[first_family_index - 1].family_name == family_name
114        {
115            first_family_index -= 1
116        }
117        let mut last_family_index = first_family_index;
118        while last_family_index + 1 < self.families.len()
119            && self.families[last_family_index + 1].family_name == family_name
120        {
121            last_family_index += 1
122        }
123
124        let families = &self.families[first_family_index..(last_family_index + 1)];
125        Ok(FamilyHandle::from_font_handles(
126            families.iter().map(|family| family.font.clone()),
127        ))
128    }
129
130    /// Selects a font by PostScript name, which should be a unique identifier.
131    ///
132    /// The default implementation, which is used by the DirectWrite and the filesystem backends,
133    /// does a brute-force search of installed fonts to find the one that matches.
134    pub fn select_by_postscript_name(
135        &self,
136        postscript_name: &str,
137    ) -> Result<Handle, SelectionError> {
138        self.families
139            .iter()
140            .filter(|family_entry| family_entry.postscript_name == postscript_name)
141            .map(|family_entry| family_entry.font.clone())
142            .next()
143            .ok_or(SelectionError::NotFound)
144    }
145
146    /// Performs font matching according to the CSS Fonts Level 3 specification and returns the
147    /// handle.
148    #[inline]
149    pub fn select_best_match(
150        &self,
151        family_names: &[FamilyName],
152        properties: &Properties,
153    ) -> Result<Handle, SelectionError> {
154        <Self as Source>::select_best_match(self, family_names, properties)
155    }
156}
157
158impl Source for MemSource {
159    #[inline]
160    fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
161        self.all_fonts()
162    }
163
164    #[inline]
165    fn all_families(&self) -> Result<Vec<String>, SelectionError> {
166        self.all_families()
167    }
168
169    fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
170        self.select_family_by_name(family_name)
171    }
172
173    fn select_by_postscript_name(&self, postscript_name: &str) -> Result<Handle, SelectionError> {
174        self.select_by_postscript_name(postscript_name)
175    }
176
177    #[inline]
178    fn as_any(&self) -> &dyn Any {
179        self
180    }
181
182    #[inline]
183    fn as_mut_any(&mut self) -> &mut dyn Any {
184        self
185    }
186}
187
188/// Adds a font, but doesn't sort. Returns the font that was created to check for validity.
189fn add_font(handle: Handle, families: &mut Vec<FamilyEntry>) -> Result<Font, FontLoadingError> {
190    let font = Font::from_handle(&handle)?;
191    if let Some(postscript_name) = font.postscript_name() {
192        families.push(FamilyEntry {
193            family_name: font.family_name(),
194            postscript_name,
195            font: handle,
196        })
197    }
198    Ok(font)
199}
200
201struct FamilyEntry {
202    family_name: String,
203    postscript_name: String,
204    font: Handle,
205}