1// font-kit/src/sources/multi.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 encapsulates multiple sources and allows them to be queried as a group.
12//!
13//! This is useful when an application wants a library of fonts consisting of the installed system
14//! fonts plus some other application-supplied fonts.
15
16use crate::error::SelectionError;
17use crate::family_handle::FamilyHandle;
18use crate::family_name::FamilyName;
19use crate::handle::Handle;
20use crate::properties::Properties;
21use crate::source::Source;
22use std::{
23 any::Any,
24 fmt,
25 ops::{Index, IndexMut},
26 slice,
27};
28
29/// A source that encapsulates multiple sources and allows them to be queried as a group.
30///
31/// This is useful when an application wants a library of fonts consisting of the installed system
32/// fonts plus some other application-supplied fonts.
33#[allow(missing_debug_implementations)]
34pub struct MultiSource {
35 subsources: Vec<Box<dyn Source>>,
36}
37
38impl MultiSource {
39 /// Creates a new source that contains all the fonts in the supplied sources.
40 pub fn from_sources(subsources: Vec<Box<dyn Source>>) -> MultiSource {
41 MultiSource { subsources }
42 }
43
44 /// Returns paths of all fonts installed on the system.
45 pub fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
46 let mut handles = vec![];
47 for subsource in &self.subsources {
48 handles.extend(subsource.all_fonts()?.into_iter())
49 }
50 Ok(handles)
51 }
52
53 /// Returns the names of all families installed on the system.
54 pub fn all_families(&self) -> Result<Vec<String>, SelectionError> {
55 let mut families = vec![];
56 for subsource in &self.subsources {
57 families.extend(subsource.all_families()?.into_iter())
58 }
59 Ok(families)
60 }
61
62 /// Looks up a font family by name and returns the handles of all the fonts in that family.
63 pub fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
64 for subsource in &self.subsources {
65 match subsource.select_family_by_name(family_name) {
66 Ok(family) => return Ok(family),
67 Err(SelectionError::NotFound) => {}
68 Err(err) => return Err(err),
69 }
70 }
71 Err(SelectionError::NotFound)
72 }
73
74 /// Selects a font by PostScript name, which should be a unique identifier.
75 pub fn select_by_postscript_name(
76 &self,
77 postscript_name: &str,
78 ) -> Result<Handle, SelectionError> {
79 for subsource in &self.subsources {
80 match subsource.select_by_postscript_name(postscript_name) {
81 Ok(font) => return Ok(font),
82 Err(SelectionError::NotFound) => {}
83 Err(err) => return Err(err),
84 }
85 }
86 Err(SelectionError::NotFound)
87 }
88
89 /// Performs font matching according to the CSS Fonts Level 3 specification and returns the
90 /// handle.
91 #[inline]
92 pub fn select_best_match(
93 &self,
94 family_names: &[FamilyName],
95 properties: &Properties,
96 ) -> Result<Handle, SelectionError> {
97 <Self as Source>::select_best_match(self, family_names, properties)
98 }
99
100 /// Returns an iterator over the contained sources.
101 #[inline]
102 pub fn iter<'a>(&'a self) -> MultiIter<'a> {
103 MultiIter(self.subsources.iter())
104 }
105
106 /// Returns an iterator over the contained sources with mutable access.
107 #[inline]
108 pub fn iter_mut<'a>(&'a mut self) -> MultiIterMut<'a> {
109 MultiIterMut(self.subsources.iter_mut())
110 }
111
112 /// A convenience method to get the first source with the given type.
113 ///
114 /// Returns `None` if no source of the given type was found.
115 pub fn find_source<T: Source + 'static>(&self) -> Option<&T> {
116 self.iter().find_map(|v| v.as_any().downcast_ref())
117 }
118
119 /// A convenience method to get the first source with the given type.
120 ///
121 /// Returns `None` if no source of the given type was found.
122 pub fn find_source_mut<T: Source + 'static>(&mut self) -> Option<&mut T> {
123 self.iter_mut().find_map(|v| v.as_mut_any().downcast_mut())
124 }
125}
126
127impl Source for MultiSource {
128 #[inline]
129 fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
130 self.all_fonts()
131 }
132
133 #[inline]
134 fn all_families(&self) -> Result<Vec<String>, SelectionError> {
135 self.all_families()
136 }
137
138 #[inline]
139 fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
140 self.select_family_by_name(family_name)
141 }
142
143 #[inline]
144 fn select_by_postscript_name(&self, postscript_name: &str) -> Result<Handle, SelectionError> {
145 self.select_by_postscript_name(postscript_name)
146 }
147
148 fn as_any(&self) -> &dyn Any {
149 self
150 }
151
152 fn as_mut_any(&mut self) -> &mut dyn Any {
153 self
154 }
155}
156
157impl Index<usize> for MultiSource {
158 type Output = dyn Source;
159
160 fn index(&self, idx: usize) -> &Self::Output {
161 &*self.subsources[idx]
162 }
163}
164
165impl IndexMut<usize> for MultiSource {
166 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
167 &mut *self.subsources[idx]
168 }
169}
170
171/// An iterator over the sources in a [`MultiSource`].
172pub struct MultiIter<'a>(slice::Iter<'a, Box<dyn Source>>);
173
174impl<'a> Iterator for MultiIter<'a> {
175 type Item = &'a dyn Source;
176
177 fn next(&mut self) -> Option<Self::Item> {
178 self.0.next().map(|v: &Box| &**v)
179 }
180}
181
182impl fmt::Debug for MultiIter<'_> {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 f.debug_struct(name:"MultiIter").finish()
185 }
186}
187
188/// An iterator over the mutable sources in a [`MultiSource`].
189pub struct MultiIterMut<'a>(slice::IterMut<'a, Box<dyn Source>>);
190
191impl<'a> Iterator for MultiIterMut<'a> {
192 type Item = &'a mut dyn Source;
193
194 fn next(&mut self) -> Option<Self::Item> {
195 self.0.next().map(|v: &mut Box| &mut **v)
196 }
197}
198
199impl fmt::Debug for MultiIterMut<'_> {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 f.debug_struct(name:"MultiIterMut").finish()
202 }
203}
204