1use 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#[allow(missing_debug_implementations)]
24pub struct MemSource {
25 families: Vec<FamilyEntry>,
26}
27
28impl MemSource {
29 pub fn empty() -> MemSource {
31 MemSource { families: vec![] }
32 }
33
34 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 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 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 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 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 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 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 #[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
188fn 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}