1use crate::error::SelectionError;
14use crate::family::Family;
15use crate::family_handle::FamilyHandle;
16use crate::family_name::FamilyName;
17use crate::font::Font;
18use crate::handle::Handle;
19use crate::matching;
20use crate::properties::Properties;
21use std::any::Any;
22
23#[cfg(all(
24 any(target_os = "macos", target_os = "ios"),
25 not(feature = "loader-freetype-default")
26))]
27pub use crate::sources::core_text::CoreTextSource as SystemSource;
28#[cfg(all(target_family = "windows", not(feature = "source-fontconfig-default")))]
29pub use crate::sources::directwrite::DirectWriteSource as SystemSource;
30#[cfg(all(
31 any(
32 not(any(
33 target_os = "android",
34 target_os = "macos",
35 target_os = "ios",
36 target_family = "windows",
37 target_arch = "wasm32",
38 )),
39 feature = "source-fontconfig-default"
40 ),
41 not(target_env = "ohos")
42))]
43pub use crate::sources::fontconfig::FontconfigSource as SystemSource;
44#[cfg(all(target_os = "android", not(feature = "source-fontconfig-default")))]
45pub use crate::sources::fs::FsSource as SystemSource;
46
47#[cfg(target_env = "ohos")]
48pub use crate::sources::fs::FsSource as SystemSource;
49
50#[cfg(any(target_family = "windows", target_os = "macos", target_os = "ios"))]
52const DEFAULT_FONT_FAMILY_SERIF: &'static str = "Times New Roman";
53#[cfg(any(target_family = "windows", target_os = "macos", target_os = "ios"))]
54const DEFAULT_FONT_FAMILY_SANS_SERIF: &'static str = "Arial";
55#[cfg(target_env = "ohos")]
56const DEFAULT_FONT_FAMILY_SANS_SERIF: &str = "HarmonyOS Sans";
57#[cfg(any(target_family = "windows", target_os = "macos", target_os = "ios"))]
58const DEFAULT_FONT_FAMILY_MONOSPACE: &'static str = "Courier New";
59#[cfg(target_env = "ohos")]
60const DEFAULT_FONT_FAMILY_MONOSPACE: &str = "HarmonyOS Sans";
61#[cfg(any(target_family = "windows", target_os = "macos", target_os = "ios"))]
62const DEFAULT_FONT_FAMILY_CURSIVE: &'static str = "Comic Sans MS";
63#[cfg(target_family = "windows")]
64const DEFAULT_FONT_FAMILY_FANTASY: &'static str = "Impact";
65#[cfg(any(target_os = "macos", target_os = "ios"))]
66const DEFAULT_FONT_FAMILY_FANTASY: &'static str = "Papyrus";
67
68#[cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios")))]
69const DEFAULT_FONT_FAMILY_SERIF: &str = "serif";
70#[cfg(not(any(
71 target_family = "windows",
72 target_os = "macos",
73 target_os = "ios",
74 target_env = "ohos"
75)))]
76const DEFAULT_FONT_FAMILY_SANS_SERIF: &str = "sans-serif";
77#[cfg(not(any(
78 target_family = "windows",
79 target_os = "macos",
80 target_os = "ios",
81 target_env = "ohos"
82)))]
83const DEFAULT_FONT_FAMILY_MONOSPACE: &str = "monospace";
84#[cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios")))]
85const DEFAULT_FONT_FAMILY_CURSIVE: &str = "cursive";
86#[cfg(not(any(target_family = "windows", target_os = "macos", target_os = "ios")))]
87const DEFAULT_FONT_FAMILY_FANTASY: &str = "fantasy";
88
89pub trait Source: Any {
93 fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError>;
95
96 fn all_families(&self) -> Result<Vec<String>, SelectionError>;
98
99 fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError>;
101
102 fn select_by_postscript_name(&self, postscript_name: &str) -> Result<Handle, SelectionError> {
107 for family_name in self.all_families()? {
109 if let Ok(family_handle) = self.select_family_by_name(&family_name) {
110 if let Ok(family) = Family::<Font>::from_handle(&family_handle) {
111 for (handle, font) in family_handle.fonts().iter().zip(family.fonts().iter()) {
112 if let Some(font_postscript_name) = font.postscript_name() {
113 if font_postscript_name == postscript_name {
114 return Ok((*handle).clone());
115 }
116 }
117 }
118 }
119 }
120 }
121 Err(SelectionError::NotFound)
122 }
123
124 #[doc(hidden)]
127 fn select_family_by_generic_name(
128 &self,
129 family_name: &FamilyName,
130 ) -> Result<FamilyHandle, SelectionError> {
131 match *family_name {
132 FamilyName::Title(ref title) => self.select_family_by_name(title),
133 FamilyName::Serif => self.select_family_by_name(DEFAULT_FONT_FAMILY_SERIF),
134 FamilyName::SansSerif => self.select_family_by_name(DEFAULT_FONT_FAMILY_SANS_SERIF),
135 FamilyName::Monospace => self.select_family_by_name(DEFAULT_FONT_FAMILY_MONOSPACE),
136 FamilyName::Cursive => self.select_family_by_name(DEFAULT_FONT_FAMILY_CURSIVE),
137 FamilyName::Fantasy => self.select_family_by_name(DEFAULT_FONT_FAMILY_FANTASY),
138 }
139 }
140
141 #[inline]
144 fn select_best_match(
145 &self,
146 family_names: &[FamilyName],
147 properties: &Properties,
148 ) -> Result<Handle, SelectionError> {
149 for family_name in family_names {
150 if let Ok(family_handle) = self.select_family_by_generic_name(family_name) {
151 let candidates = self.select_descriptions_in_family(&family_handle)?;
152 if let Ok(index) = matching::find_best_match(&candidates, properties) {
153 return Ok(family_handle.fonts[index].clone());
154 }
155 }
156 }
157 Err(SelectionError::NotFound)
158 }
159
160 #[doc(hidden)]
161 fn select_descriptions_in_family(
162 &self,
163 family: &FamilyHandle,
164 ) -> Result<Vec<Properties>, SelectionError> {
165 let mut fields = vec![];
166 for font_handle in family.fonts() {
167 match Font::from_handle(font_handle) {
168 Ok(font) => fields.push(font.properties()),
169 Err(e) => log::warn!("Error loading font from handle: {:?}", e),
170 }
171 }
172 Ok(fields)
173 }
174
175 fn as_any(&self) -> &dyn Any;
178
179 fn as_mut_any(&mut self) -> &mut dyn Any;
182}