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 ))
103 }
104
105 /// Returns an arbitrary font family that is available on the system.
106 pub fn known_existing_family(&self) -> FamilyId {
107 if let Some(family_id) = self.0.read().default_family {
108 return family_id;
109 }
110
111 let default_family = self
112 .load_family(
113 &["Courier", "Helvetica", "Arial", "Verdana"],
114 &Default::default(),
115 )
116 .unwrap_or_else(|_| {
117 let all_family_names = self.0.read().font_system.all_families();
118 let all_family_names: Vec<_> = all_family_names
119 .iter()
120 .map(|string| string.as_str())
121 .collect();
122 self.load_family(&all_family_names, &Default::default())
123 .expect("could not load any default font family")
124 });
125
126 self.0.write().default_family = Some(default_family);
127 default_family
128 }
129
130 pub fn default_font(&self, family_id: FamilyId) -> FontId {
131 self.select_font(family_id, &Properties::default()).unwrap()
132 }
133
134 pub fn select_font(&self, family_id: FamilyId, properties: &Properties) -> Result<FontId> {
135 let inner = self.0.upgradable_read();
136 if let Some(font_id) = inner
137 .font_selections
138 .get(&family_id)
139 .and_then(|f| f.get(properties))
140 {
141 Ok(*font_id)
142 } else {
143 let mut inner = RwLockUpgradableReadGuard::upgrade(inner);
144 let family = &inner.families[family_id.0];
145 let font_id = inner
146 .font_system
147 .select_font(&family.font_ids, properties)
148 .unwrap_or(family.font_ids[0]);
149
150 inner
151 .font_selections
152 .entry(family_id)
153 .or_default()
154 .insert(*properties, font_id);
155 Ok(font_id)
156 }
157 }
158
159 pub fn metric<F, T>(&self, font_id: FontId, f: F) -> T
160 where
161 F: FnOnce(&Metrics) -> T,
162 T: 'static,
163 {
164 let state = self.0.upgradable_read();
165 if let Some(metrics) = state.metrics.get(&font_id) {
166 f(metrics)
167 } else {
168 let metrics = state.font_system.font_metrics(font_id);
169 let metric = f(&metrics);
170 let mut state = RwLockUpgradableReadGuard::upgrade(state);
171 state.metrics.insert(font_id, metrics);
172 metric
173 }
174 }
175
176 pub fn bounding_box(&self, font_id: FontId, font_size: f32) -> Vector2F {
177 let bounding_box = self.metric(font_id, |m| m.bounding_box);
178 let width = bounding_box.width() * self.em_scale(font_id, font_size);
179 let height = bounding_box.height() * self.em_scale(font_id, font_size);
180 vec2f(width, height)
181 }
182
183 pub fn em_width(&self, font_id: FontId, font_size: f32) -> f32 {
184 let glyph_id;
185 let bounds;
186 {
187 let state = self.0.read();
188 glyph_id = state.font_system.glyph_for_char(font_id, 'm').unwrap();
189 bounds = state
190 .font_system
191 .typographic_bounds(font_id, glyph_id)
192 .unwrap();
193 }
194 bounds.width() * self.em_scale(font_id, font_size)
195 }
196
197 pub fn em_advance(&self, font_id: FontId, font_size: f32) -> f32 {
198 let glyph_id;
199 let advance;
200 {
201 let state = self.0.read();
202 glyph_id = state.font_system.glyph_for_char(font_id, 'm').unwrap();
203 advance = state.font_system.advance(font_id, glyph_id).unwrap();
204 }
205 advance.x() * self.em_scale(font_id, font_size)
206 }
207
208 pub fn line_height(&self, font_size: f32) -> f32 {
209 (font_size * 1.618).round()
210 }
211
212 pub fn cap_height(&self, font_id: FontId, font_size: f32) -> f32 {
213 self.metric(font_id, |m| m.cap_height) * self.em_scale(font_id, font_size)
214 }
215
216 pub fn x_height(&self, font_id: FontId, font_size: f32) -> f32 {
217 self.metric(font_id, |m| m.x_height) * self.em_scale(font_id, font_size)
218 }
219
220 pub fn ascent(&self, font_id: FontId, font_size: f32) -> f32 {
221 self.metric(font_id, |m| m.ascent) * self.em_scale(font_id, font_size)
222 }
223
224 pub fn descent(&self, font_id: FontId, font_size: f32) -> f32 {
225 self.metric(font_id, |m| -m.descent) * self.em_scale(font_id, font_size)
226 }
227
228 pub fn em_scale(&self, font_id: FontId, font_size: f32) -> f32 {
229 font_size / self.metric(font_id, |m| m.units_per_em as f32)
230 }
231
232 pub fn baseline_offset(&self, font_id: FontId, font_size: f32) -> f32 {
233 let line_height = self.line_height(font_size);
234 let ascent = self.ascent(font_id, font_size);
235 let descent = self.descent(font_id, font_size);
236 let padding_top = (line_height - ascent - descent) / 2.;
237 padding_top + ascent
238 }
239
240 pub fn line_wrapper(self: &Arc<Self>, font_id: FontId, font_size: f32) -> LineWrapperHandle {
241 let mut state = self.0.write();
242 let wrappers = state
243 .wrapper_pool
244 .entry((font_id, OrderedFloat(font_size)))
245 .or_default();
246 let wrapper = wrappers
247 .pop()
248 .unwrap_or_else(|| LineWrapper::new(font_id, font_size, state.font_system.clone()));
249 LineWrapperHandle {
250 wrapper: Some(wrapper),
251 font_cache: self.clone(),
252 }
253 }
254}
255
256impl Drop for LineWrapperHandle {
257 fn drop(&mut self) {
258 let mut state = self.font_cache.0.write();
259 let wrapper = self.wrapper.take().unwrap();
260 state
261 .wrapper_pool
262 .get_mut(&(wrapper.font_id, OrderedFloat(wrapper.font_size)))
263 .unwrap()
264 .push(wrapper);
265 }
266}
267
268impl Deref for LineWrapperHandle {
269 type Target = LineWrapper;
270
271 fn deref(&self) -> &Self::Target {
272 self.wrapper.as_ref().unwrap()
273 }
274}
275
276impl DerefMut for LineWrapperHandle {
277 fn deref_mut(&mut self) -> &mut Self::Target {
278 self.wrapper.as_mut().unwrap()
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285 use crate::{
286 fonts::{Style, Weight},
287 platform::{test, Platform as _},
288 };
289
290 #[test]
291 fn test_select_font() {
292 let platform = test::platform();
293 let fonts = FontCache::new(platform.fonts());
294 let arial = fonts
295 .load_family(
296 &["Arial"],
297 &Features {
298 calt: Some(false),
299 ..Default::default()
300 },
301 )
302 .unwrap();
303 let arial_regular = fonts.select_font(arial, &Properties::new()).unwrap();
304 let arial_italic = fonts
305 .select_font(arial, Properties::new().style(Style::Italic))
306 .unwrap();
307 let arial_bold = fonts
308 .select_font(arial, Properties::new().weight(Weight::BOLD))
309 .unwrap();
310 assert_ne!(arial_regular, arial_italic);
311 assert_ne!(arial_regular, arial_bold);
312 assert_ne!(arial_italic, arial_bold);
313
314 let arial_with_calt = fonts
315 .load_family(
316 &["Arial"],
317 &Features {
318 calt: Some(true),
319 ..Default::default()
320 },
321 )
322 .unwrap();
323 assert_ne!(arial_with_calt, arial);
324 }
325}