1use crate::{
2 fonts::{Features, FontId, Metrics, Properties},
3 geometry::vector::{vec2f, Vector2F},
4 platform,
5 text_layout::LineWrapper,
6};
7use anyhow::{anyhow, Result};
8use ordered_float::OrderedFloat;
9use parking_lot::{RwLock, RwLockUpgradableReadGuard};
10use std::{
11 collections::HashMap,
12 ops::{Deref, DerefMut},
13 sync::Arc,
14};
15use ts_rs::TS;
16
17#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
18#[derive(TS)]
19#[ts(export, export_to = "theme/types/")]
20pub struct FamilyId(usize);
21
22struct Family {
23 name: Arc<str>,
24 font_features: Features,
25 font_ids: Vec<FontId>,
26}
27
28pub struct FontCache(RwLock<FontCacheState>);
29
30pub struct FontCacheState {
31 font_system: Arc<dyn platform::FontSystem>,
32 families: Vec<Family>,
33 default_family: Option<FamilyId>,
34 font_selections: HashMap<FamilyId, HashMap<Properties, FontId>>,
35 metrics: HashMap<FontId, Metrics>,
36 wrapper_pool: HashMap<(FontId, OrderedFloat<f32>), Vec<LineWrapper>>,
37}
38
39pub struct LineWrapperHandle {
40 wrapper: Option<LineWrapper>,
41 font_cache: Arc<FontCache>,
42}
43
44unsafe impl Send for FontCache {}
45
46impl FontCache {
47 pub fn new(fonts: Arc<dyn platform::FontSystem>) -> Self {
48 Self(RwLock::new(FontCacheState {
49 font_system: fonts,
50 families: Default::default(),
51 default_family: None,
52 font_selections: Default::default(),
53 metrics: Default::default(),
54 wrapper_pool: Default::default(),
55 }))
56 }
57
58 pub fn family_name(&self, family_id: FamilyId) -> Result<Arc<str>> {
59 self.0
60 .read()
61 .families
62 .get(family_id.0)
63 .ok_or_else(|| anyhow!("invalid family id"))
64 .map(|family| family.name.clone())
65 }
66
67 pub fn load_family(&self, names: &[&str], features: &Features) -> Result<FamilyId> {
68 for name in names {
69 let state = self.0.upgradable_read();
70
71 if let Some(ix) = state
72 .families
73 .iter()
74 .position(|f| f.name.as_ref() == *name && f.font_features == *features)
75 {
76 return Ok(FamilyId(ix));
77 }
78
79 let mut state = RwLockUpgradableReadGuard::upgrade(state);
80
81 if let Ok(font_ids) = state.font_system.load_family(name, features) {
82 if font_ids.is_empty() {
83 continue;
84 }
85
86 let family_id = FamilyId(state.families.len());
87 for font_id in &font_ids {
88 if state.font_system.glyph_for_char(*font_id, 'm').is_none() {
89 return Err(anyhow!("font must contain a glyph for the 'm' character"));
90 }
91 }
92
93 state.families.push(Family {
94 name: Arc::from(*name),
95 font_features: features.clone(),
96 font_ids,
97 });
98 return Ok(family_id);
99 }
100 }
101
102 Err(anyhow!(
103 "could not find a non-empty font family matching one of the given names"
104 ))
105 }
106
107 /// Returns an arbitrary font family that is available on the system.
108 pub fn known_existing_family(&self) -> FamilyId {
109 if let Some(family_id) = self.0.read().default_family {
110 return family_id;
111 }
112
113 let default_family = self
114 .load_family(
115 &["Courier", "Helvetica", "Arial", "Verdana"],
116 &Default::default(),
117 )
118 .unwrap_or_else(|_| {
119 let all_family_names = self.0.read().font_system.all_families();
120 let all_family_names: Vec<_> = all_family_names
121 .iter()
122 .map(|string| string.as_str())
123 .collect();
124 self.load_family(&all_family_names, &Default::default())
125 .expect("could not load any default font family")
126 });
127
128 self.0.write().default_family = Some(default_family);
129 default_family
130 }
131
132 pub fn default_font(&self, family_id: FamilyId) -> FontId {
133 self.select_font(family_id, &Properties::default()).unwrap()
134 }
135
136 pub fn select_font(&self, family_id: FamilyId, properties: &Properties) -> Result<FontId> {
137 let inner = self.0.upgradable_read();
138 if let Some(font_id) = inner
139 .font_selections
140 .get(&family_id)
141 .and_then(|f| f.get(properties))
142 {
143 Ok(*font_id)
144 } else {
145 let mut inner = RwLockUpgradableReadGuard::upgrade(inner);
146 let family = &inner.families[family_id.0];
147 let font_id = inner
148 .font_system
149 .select_font(&family.font_ids, properties)
150 .unwrap_or(family.font_ids[0]);
151
152 inner
153 .font_selections
154 .entry(family_id)
155 .or_default()
156 .insert(*properties, font_id);
157 Ok(font_id)
158 }
159 }
160
161 pub fn metric<F, T>(&self, font_id: FontId, f: F) -> T
162 where
163 F: FnOnce(&Metrics) -> T,
164 T: 'static,
165 {
166 let state = self.0.upgradable_read();
167 if let Some(metrics) = state.metrics.get(&font_id) {
168 f(metrics)
169 } else {
170 let metrics = state.font_system.font_metrics(font_id);
171 let metric = f(&metrics);
172 let mut state = RwLockUpgradableReadGuard::upgrade(state);
173 state.metrics.insert(font_id, metrics);
174 metric
175 }
176 }
177
178 pub fn bounding_box(&self, font_id: FontId, font_size: f32) -> Vector2F {
179 let bounding_box = self.metric(font_id, |m| m.bounding_box);
180 let width = bounding_box.width() * self.em_scale(font_id, font_size);
181 let height = bounding_box.height() * self.em_scale(font_id, font_size);
182 vec2f(width, height)
183 }
184
185 pub fn em_width(&self, font_id: FontId, font_size: f32) -> f32 {
186 let glyph_id;
187 let bounds;
188 {
189 let state = self.0.read();
190 glyph_id = state.font_system.glyph_for_char(font_id, 'm').unwrap();
191 bounds = state
192 .font_system
193 .typographic_bounds(font_id, glyph_id)
194 .unwrap();
195 }
196 bounds.width() * self.em_scale(font_id, font_size)
197 }
198
199 pub fn em_advance(&self, font_id: FontId, font_size: f32) -> f32 {
200 let glyph_id;
201 let advance;
202 {
203 let state = self.0.read();
204 glyph_id = state.font_system.glyph_for_char(font_id, 'm').unwrap();
205 advance = state.font_system.advance(font_id, glyph_id).unwrap();
206 }
207 advance.x() * self.em_scale(font_id, font_size)
208 }
209
210 pub fn line_height(&self, font_size: f32) -> f32 {
211 (font_size * 1.618).round()
212 }
213
214 pub fn cap_height(&self, font_id: FontId, font_size: f32) -> f32 {
215 self.metric(font_id, |m| m.cap_height) * self.em_scale(font_id, font_size)
216 }
217
218 pub fn x_height(&self, font_id: FontId, font_size: f32) -> f32 {
219 self.metric(font_id, |m| m.x_height) * self.em_scale(font_id, font_size)
220 }
221
222 pub fn ascent(&self, font_id: FontId, font_size: f32) -> f32 {
223 self.metric(font_id, |m| m.ascent) * self.em_scale(font_id, font_size)
224 }
225
226 pub fn descent(&self, font_id: FontId, font_size: f32) -> f32 {
227 self.metric(font_id, |m| -m.descent) * self.em_scale(font_id, font_size)
228 }
229
230 pub fn em_scale(&self, font_id: FontId, font_size: f32) -> f32 {
231 font_size / self.metric(font_id, |m| m.units_per_em as f32)
232 }
233
234 pub fn baseline_offset(&self, font_id: FontId, font_size: f32) -> f32 {
235 let line_height = self.line_height(font_size);
236 let ascent = self.ascent(font_id, font_size);
237 let descent = self.descent(font_id, font_size);
238 let padding_top = (line_height - ascent - descent) / 2.;
239 padding_top + ascent
240 }
241
242 pub fn line_wrapper(self: &Arc<Self>, font_id: FontId, font_size: f32) -> LineWrapperHandle {
243 let mut state = self.0.write();
244 let wrappers = state
245 .wrapper_pool
246 .entry((font_id, OrderedFloat(font_size)))
247 .or_default();
248 let wrapper = wrappers
249 .pop()
250 .unwrap_or_else(|| LineWrapper::new(font_id, font_size, state.font_system.clone()));
251 LineWrapperHandle {
252 wrapper: Some(wrapper),
253 font_cache: self.clone(),
254 }
255 }
256}
257
258impl Drop for LineWrapperHandle {
259 fn drop(&mut self) {
260 let mut state = self.font_cache.0.write();
261 let wrapper = self.wrapper.take().unwrap();
262 state
263 .wrapper_pool
264 .get_mut(&(wrapper.font_id, OrderedFloat(wrapper.font_size)))
265 .unwrap()
266 .push(wrapper);
267 }
268}
269
270impl Deref for LineWrapperHandle {
271 type Target = LineWrapper;
272
273 fn deref(&self) -> &Self::Target {
274 self.wrapper.as_ref().unwrap()
275 }
276}
277
278impl DerefMut for LineWrapperHandle {
279 fn deref_mut(&mut self) -> &mut Self::Target {
280 self.wrapper.as_mut().unwrap()
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287 use crate::{
288 fonts::{Style, Weight},
289 platform::{test, Platform as _},
290 };
291
292 #[test]
293 fn test_select_font() {
294 let platform = test::platform();
295 let fonts = FontCache::new(platform.fonts());
296 let arial = fonts
297 .load_family(
298 &["Arial"],
299 &Features {
300 calt: Some(false),
301 ..Default::default()
302 },
303 )
304 .unwrap();
305 let arial_regular = fonts.select_font(arial, &Properties::new()).unwrap();
306 let arial_italic = fonts
307 .select_font(arial, Properties::new().style(Style::Italic))
308 .unwrap();
309 let arial_bold = fonts
310 .select_font(arial, Properties::new().weight(Weight::BOLD))
311 .unwrap();
312 assert_ne!(arial_regular, arial_italic);
313 assert_ne!(arial_regular, arial_bold);
314 assert_ne!(arial_italic, arial_bold);
315
316 let arial_with_calt = fonts
317 .load_family(
318 &["Arial"],
319 &Features {
320 calt: Some(true),
321 ..Default::default()
322 },
323 )
324 .unwrap();
325 assert_ne!(arial_with_calt, arial);
326 }
327}