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