font_cache.rs

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