Skip to main content

read_fonts/model/font/
cache.rs

1//! Tables parsed once for a font and kept.
2//!
3//! A parsed table borrows the bytes it came from, so it cannot simply be
4//! stored beside them. [`Yoke`] makes that expressible by holding the parsed
5//! value together with the tables it borrows, behind an [`Arc`] that outlives
6//! both however they are dropped.
7//!
8//! Every table gets its own cell, so reading one never drags in another.
9//! That matters for `glyf` and `loca`, which outlines and metrics in both
10//! directions all read, and for `gvar`, which is typically about half a
11//! variable font and must not be read to answer what another table can.
12
13use super::Tables;
14use crate::model::glyph::outline::varc;
15use crate::ps::cff::CffFontRef;
16use crate::tables::{
17    cbdt::Cbdt,
18    cblc::Cblc,
19    colr::Colr,
20    cpal::Cpal,
21    ebdt::Ebdt,
22    eblc::Eblc,
23    glyf::Glyf,
24    gvar::SelectedGvar,
25    hmtx::GlyphMetricRecords,
26    hvar::Hvar,
27    loca::Loca,
28    sbix::Sbix,
29    variations::{DeltaSetIndexMap, ItemVariationStore},
30    vorg::Vorg,
31    vvar::Vvar,
32};
33use crate::TableProvider;
34
35use alloc::sync::Arc;
36use yoke::{Yoke, Yokeable};
37
38/// Returns the design units per em that the font's metrics use.
39fn units_per_em<'a>(tables: &impl TableProvider<'a>) -> u16 {
40    crate::model::metrics::units_per_em(tables.head().map_or(0, |head| head.units_per_em()))
41}
42
43/// A parsed table held beside the tables it borrows.
44pub(crate) struct TableCache<Y: for<'a> Yokeable<'a>>(Yoke<Y, Arc<Tables>>);
45
46impl<Y: for<'a> Yokeable<'a>> TableCache<Y> {
47    /// Parses once, with `read`, and keeps the result.
48    pub(crate) fn read<F>(tables: Arc<Tables>, read: F) -> Self
49    where
50        F: for<'a> FnOnce(&'a Tables) -> <Y as Yokeable<'a>>::Output,
51    {
52        Self(Yoke::attach_to_cart(tables, read))
53    }
54
55    /// Returns the parsed table, borrowed for no longer than this.
56    #[inline]
57    pub(crate) fn get(&self) -> &<Y as Yokeable<'_>>::Output {
58        self.0.get()
59    }
60}
61
62/// The outline tables.
63///
64/// These are read as a pair because neither is usable alone: `loca` gives
65/// the offset of each glyph in `glyf`.
66#[derive(Clone, Default, Yokeable)]
67pub(crate) struct GlyfLoca<'a>(pub(crate) Option<(Glyf<'a>, Loca<'a>)>);
68
69impl<'a> GlyfLoca<'a> {
70    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
71        Self(tables.selected_glyf_loca(None).ok())
72    }
73}
74
75/// The glyph metrics of one direction.
76#[derive(Clone, Default, Yokeable)]
77pub(crate) struct MetricsTable<'a>(pub(crate) GlyphMetricRecords<'a>);
78
79/// The table of horizontal metric variations.
80#[derive(Clone, Default, Yokeable)]
81pub(crate) struct HvarTable<'a>(pub(crate) Option<Hvar<'a>>);
82
83impl<'a> HvarTable<'a> {
84    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
85        Self(tables.hvar().ok())
86    }
87}
88
89/// The table of vertical metric variations.
90#[derive(Clone, Default, Yokeable)]
91pub(crate) struct VvarTable<'a>(pub(crate) Option<Vvar<'a>>);
92
93impl<'a> VvarTable<'a> {
94    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
95        Self(tables.vvar().ok())
96    }
97}
98
99/// The table that varies `glyf` outlines.
100///
101/// Outlines read it at a location away from the default. Metrics read it
102/// where `HVAR` or `VVAR` is absent, from the phantom points of each glyph.
103#[derive(Clone, Default, Yokeable)]
104pub(crate) struct GvarTable<'a>(pub(crate) Option<SelectedGvar<'a>>);
105
106impl<'a> GvarTable<'a> {
107    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
108        Self(tables.selected_gvar().ok())
109    }
110}
111
112/// Charstring outlines from the `CFF2` table.
113#[derive(Clone, Default, Yokeable)]
114pub(crate) struct Cff2Font<'a>(pub(crate) Option<CffFontRef<'a>>);
115
116impl<'a> Cff2Font<'a> {
117    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
118        let upem = Some(units_per_em(tables) as i32);
119        Self(
120            tables
121                .cff2()
122                .ok()
123                .and_then(|cff2| CffFontRef::new(cff2.offset_data().as_bytes(), 0, upem).ok()),
124        )
125    }
126}
127
128/// Charstring outlines from the `CFF` table.
129///
130/// This is separate from [`Cff2Font`] so that a caller can choose either
131/// table when a font has both.
132#[derive(Clone, Default, Yokeable)]
133pub(crate) struct CffFont<'a>(pub(crate) Option<CffFontRef<'a>>);
134
135impl<'a> CffFont<'a> {
136    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
137        let upem = Some(units_per_em(tables) as i32);
138        Self(
139            tables
140                .cff()
141                .ok()
142                .and_then(|cff| CffFontRef::new(cff.offset_data().as_bytes(), 0, upem).ok()),
143        )
144    }
145}
146
147/// The table of glyph vertical origins.
148///
149/// Used only for vertical text, where it takes precedence over every other
150/// source of the origin.
151#[derive(Clone, Default, Yokeable)]
152pub(crate) struct VorgTable<'a>(pub(crate) Option<Vorg<'a>>);
153
154impl<'a> VorgTable<'a> {
155    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
156        Self(tables.vorg().ok())
157    }
158}
159
160impl<'a> varc::Outlines<'a> {
161    /// Reads the variable composites, with their coverage and variation
162    /// store resolved.
163    ///
164    /// Returns `None` if the font has no `VARC` table.
165    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Option<Self> {
166        let varc = tables.varc().ok()?;
167        let upem = units_per_em(tables);
168        // A static VARC font may omit fvar and use the axes retained in gvar
169        // or the CFF2 variation store for component-internal coordinates.
170        let mut axis_count = tables
171            .fvar()
172            .map(|fvar| fvar.axis_count() as usize)
173            .unwrap_or_default();
174        if let Ok(gvar) = tables.gvar() {
175            axis_count = axis_count.max(gvar.axis_count() as usize);
176        }
177        if let Ok(gvar) = tables.gvar_extended() {
178            axis_count = axis_count.max(gvar.axis_count() as usize);
179        }
180        if let Some(count) = tables
181            .cff2()
182            .ok()
183            .and_then(|cff2| CffFontRef::new(cff2.offset_data().as_bytes(), 0, None).ok())
184            .and_then(|cff| cff.var_store()?.variation_region_list().ok())
185            .map(|regions| regions.axis_count() as usize)
186        {
187            axis_count = axis_count.max(count);
188        }
189        varc::Outlines::new(varc, upem, axis_count).ok()
190    }
191}
192
193/// The `COLR` table and the variation tables its paints use.
194#[derive(Clone, Yokeable)]
195pub(crate) struct ColrTables<'a> {
196    pub(crate) colr: Colr<'a>,
197    pub(crate) index_map: Option<DeltaSetIndexMap<'a>>,
198    pub(crate) var_store: Option<ItemVariationStore<'a>>,
199}
200
201impl<'a> ColrTables<'a> {
202    /// Reads the tables, or returns `None` if the font has no `COLR` table.
203    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Option<Self> {
204        tables.colr().ok().map(Self::new)
205    }
206
207    pub(crate) fn new(colr: Colr<'a>) -> Self {
208        Self {
209            index_map: colr.var_index_map().and_then(|map| map.ok()),
210            var_store: colr.item_variation_store().and_then(|store| store.ok()),
211            colr,
212        }
213    }
214}
215
216/// The color palettes in `CPAL`.
217#[derive(Clone, Default, Yokeable)]
218pub(crate) struct CpalTable<'a>(pub(crate) Option<Cpal<'a>>);
219
220impl<'a> CpalTable<'a> {
221    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
222        Self(tables.cpal().ok())
223    }
224}
225
226/// PNG bitmaps in `sbix`.
227#[derive(Clone, Default, Yokeable)]
228pub(crate) struct SbixTable<'a>(pub(crate) Option<Sbix<'a>>);
229
230impl<'a> SbixTable<'a> {
231    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
232        Self(tables.sbix().ok())
233    }
234}
235
236/// Color bitmaps in `CBDT`, with the `CBLC` that locates them.
237#[derive(Clone, Default, Yokeable)]
238pub(crate) struct CbdtTables<'a>(pub(crate) Option<(Cblc<'a>, Cbdt<'a>)>);
239
240impl<'a> CbdtTables<'a> {
241    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
242        Self(tables.cblc().ok().zip(tables.cbdt().ok()))
243    }
244}
245
246/// Monochrome and grayscale bitmaps in `EBDT`, with the `EBLC` that locates
247/// them.
248#[derive(Clone, Default, Yokeable)]
249pub(crate) struct EbdtTables<'a>(pub(crate) Option<(Eblc<'a>, Ebdt<'a>)>);
250
251impl<'a> EbdtTables<'a> {
252    pub(crate) fn read(tables: &impl TableProvider<'a>) -> Self {
253        Self(tables.eblc().ok().zip(tables.ebdt().ok()))
254    }
255}