read_fonts/
table_provider.rs

1//! a trait for things that can serve font tables
2
3use types::{BigEndian, Tag};
4
5use crate::{tables, FontData, FontRead, ReadError};
6
7/// A table that has an associated tag.
8///
9/// This is true of top-level tables, but not their various subtables.
10pub trait TopLevelTable {
11    /// The table's tag.
12    const TAG: Tag;
13}
14
15/// An interface for accessing tables from a font (or font-like object)
16pub trait TableProvider<'a> {
17    fn data_for_tag(&self, tag: Tag) -> Option<FontData<'a>>;
18
19    fn expect_data_for_tag(&self, tag: Tag) -> Result<FontData<'a>, ReadError> {
20        self.data_for_tag(tag).ok_or(ReadError::TableIsMissing(tag))
21    }
22
23    fn expect_table<T: TopLevelTable + FontRead<'a>>(&self) -> Result<T, ReadError> {
24        self.expect_data_for_tag(T::TAG).and_then(FontRead::read)
25    }
26
27    fn head(&self) -> Result<tables::head::Head<'a>, ReadError> {
28        self.expect_table()
29    }
30
31    fn name(&self) -> Result<tables::name::Name<'a>, ReadError> {
32        self.expect_table()
33    }
34
35    fn hhea(&self) -> Result<tables::hhea::Hhea<'a>, ReadError> {
36        self.expect_table()
37    }
38
39    fn vhea(&self) -> Result<tables::vhea::Vhea<'a>, ReadError> {
40        self.expect_table()
41    }
42
43    fn hmtx(&self) -> Result<tables::hmtx::Hmtx<'a>, ReadError> {
44        //FIXME: should we make the user pass these in?
45        let number_of_h_metrics = self.hhea().map(|hhea| hhea.number_of_h_metrics())?;
46        let data = self.expect_data_for_tag(tables::hmtx::Hmtx::TAG)?;
47        tables::hmtx::Hmtx::read(data, number_of_h_metrics)
48    }
49
50    fn hdmx(&self) -> Result<tables::hdmx::Hdmx<'a>, ReadError> {
51        let num_glyphs = self.maxp().map(|maxp| maxp.num_glyphs())?;
52        let data = self.expect_data_for_tag(tables::hdmx::Hdmx::TAG)?;
53        tables::hdmx::Hdmx::read(data, num_glyphs)
54    }
55
56    fn vmtx(&self) -> Result<tables::vmtx::Vmtx<'a>, ReadError> {
57        //FIXME: should we make the user pass these in?
58        let number_of_v_metrics = self.vhea().map(|vhea| vhea.number_of_long_ver_metrics())?;
59        let data = self.expect_data_for_tag(tables::vmtx::Vmtx::TAG)?;
60        tables::vmtx::Vmtx::read(data, number_of_v_metrics)
61    }
62
63    fn vorg(&self) -> Result<tables::vorg::Vorg<'a>, ReadError> {
64        self.expect_table()
65    }
66
67    fn fvar(&self) -> Result<tables::fvar::Fvar<'a>, ReadError> {
68        self.expect_table()
69    }
70
71    fn avar(&self) -> Result<tables::avar::Avar<'a>, ReadError> {
72        self.expect_table()
73    }
74
75    fn hvar(&self) -> Result<tables::hvar::Hvar<'a>, ReadError> {
76        self.expect_table()
77    }
78
79    fn vvar(&self) -> Result<tables::vvar::Vvar<'a>, ReadError> {
80        self.expect_table()
81    }
82
83    fn mvar(&self) -> Result<tables::mvar::Mvar<'a>, ReadError> {
84        self.expect_table()
85    }
86
87    fn maxp(&self) -> Result<tables::maxp::Maxp<'a>, ReadError> {
88        self.expect_table()
89    }
90
91    fn os2(&self) -> Result<tables::os2::Os2<'a>, ReadError> {
92        self.expect_table()
93    }
94
95    fn post(&self) -> Result<tables::post::Post<'a>, ReadError> {
96        self.expect_table()
97    }
98
99    fn gasp(&self) -> Result<tables::gasp::Gasp<'a>, ReadError> {
100        self.expect_table()
101    }
102
103    /// is_long can be optionally provided, if known, otherwise we look it up in head.
104    fn loca(&self, is_long: impl Into<Option<bool>>) -> Result<tables::loca::Loca<'a>, ReadError> {
105        let is_long = match is_long.into() {
106            Some(val) => val,
107            None => self.head()?.index_to_loc_format() == 1,
108        };
109        let data = self.expect_data_for_tag(tables::loca::Loca::TAG)?;
110        tables::loca::Loca::read(data, is_long)
111    }
112
113    fn glyf(&self) -> Result<tables::glyf::Glyf<'a>, ReadError> {
114        self.expect_table()
115    }
116
117    fn gvar(&self) -> Result<tables::gvar::Gvar<'a>, ReadError> {
118        self.expect_table()
119    }
120
121    /// Returns the array of entries for the control value table which is used
122    /// for TrueType hinting.
123    fn cvt(&self) -> Result<&'a [BigEndian<i16>], ReadError> {
124        let table_data = self.expect_data_for_tag(Tag::new(b"cvt "))?;
125        table_data.read_array(0..table_data.len())
126    }
127
128    fn cvar(&self) -> Result<tables::cvar::Cvar<'a>, ReadError> {
129        self.expect_table()
130    }
131
132    fn cff(&self) -> Result<tables::cff::Cff<'a>, ReadError> {
133        self.expect_table()
134    }
135
136    fn cff2(&self) -> Result<tables::cff2::Cff2<'a>, ReadError> {
137        self.expect_table()
138    }
139
140    fn cmap(&self) -> Result<tables::cmap::Cmap<'a>, ReadError> {
141        self.expect_table()
142    }
143
144    fn gdef(&self) -> Result<tables::gdef::Gdef<'a>, ReadError> {
145        self.expect_table()
146    }
147
148    fn gpos(&self) -> Result<tables::gpos::Gpos<'a>, ReadError> {
149        self.expect_table()
150    }
151
152    fn gsub(&self) -> Result<tables::gsub::Gsub<'a>, ReadError> {
153        self.expect_table()
154    }
155
156    fn feat(&self) -> Result<tables::feat::Feat<'a>, ReadError> {
157        self.expect_table()
158    }
159
160    fn ltag(&self) -> Result<tables::ltag::Ltag<'a>, ReadError> {
161        self.expect_table()
162    }
163
164    fn ankr(&self) -> Result<tables::ankr::Ankr<'a>, ReadError> {
165        self.expect_table()
166    }
167
168    fn trak(&self) -> Result<tables::trak::Trak<'a>, ReadError> {
169        self.expect_table()
170    }
171
172    fn morx(&self) -> Result<tables::morx::Morx<'a>, ReadError> {
173        self.expect_table()
174    }
175
176    fn kerx(&self) -> Result<tables::kerx::Kerx<'a>, ReadError> {
177        self.expect_table()
178    }
179
180    fn kern(&self) -> Result<tables::kern::Kern<'a>, ReadError> {
181        self.expect_table()
182    }
183
184    fn colr(&self) -> Result<tables::colr::Colr<'a>, ReadError> {
185        self.expect_table()
186    }
187
188    fn cpal(&self) -> Result<tables::cpal::Cpal<'a>, ReadError> {
189        self.expect_table()
190    }
191
192    fn cblc(&self) -> Result<tables::cblc::Cblc<'a>, ReadError> {
193        self.expect_table()
194    }
195
196    fn cbdt(&self) -> Result<tables::cbdt::Cbdt<'a>, ReadError> {
197        self.expect_table()
198    }
199
200    fn eblc(&self) -> Result<tables::eblc::Eblc<'a>, ReadError> {
201        self.expect_table()
202    }
203
204    fn ebdt(&self) -> Result<tables::ebdt::Ebdt<'a>, ReadError> {
205        self.expect_table()
206    }
207
208    fn sbix(&self) -> Result<tables::sbix::Sbix<'a>, ReadError> {
209        // should we make the user pass this in?
210        let num_glyphs = self.maxp().map(|maxp| maxp.num_glyphs())?;
211        let data = self.expect_data_for_tag(tables::sbix::Sbix::TAG)?;
212        tables::sbix::Sbix::read(data, num_glyphs)
213    }
214
215    fn stat(&self) -> Result<tables::stat::Stat<'a>, ReadError> {
216        self.expect_table()
217    }
218
219    fn svg(&self) -> Result<tables::svg::Svg<'a>, ReadError> {
220        self.expect_table()
221    }
222
223    fn varc(&self) -> Result<tables::varc::Varc<'a>, ReadError> {
224        self.expect_table()
225    }
226
227    #[cfg(feature = "ift")]
228    fn ift(&self) -> Result<tables::ift::Ift<'a>, ReadError> {
229        self.expect_data_for_tag(tables::ift::IFT_TAG)
230            .and_then(FontRead::read)
231    }
232
233    #[cfg(feature = "ift")]
234    fn iftx(&self) -> Result<tables::ift::Ift<'a>, ReadError> {
235        self.expect_data_for_tag(tables::ift::IFTX_TAG)
236            .and_then(FontRead::read)
237    }
238
239    fn meta(&self) -> Result<tables::meta::Meta<'a>, ReadError> {
240        self.expect_table()
241    }
242
243    fn base(&self) -> Result<tables::base::Base<'a>, ReadError> {
244        self.expect_table()
245    }
246
247    fn dsig(&self) -> Result<tables::dsig::Dsig<'a>, ReadError> {
248        self.expect_table()
249    }
250}
251
252#[cfg(test)]
253mod tests {
254
255    use super::*;
256
257    /// https://github.com/googlefonts/fontations/issues/105
258    #[test]
259    fn bug_105() {
260        // serve some dummy versions of the tables used to compute hmtx. The only
261        // fields that matter are maxp::num_glyphs and hhea::number_of_h_metrics,
262        // everything else is zero'd out
263        struct DummyProvider;
264        impl TableProvider<'static> for DummyProvider {
265            fn data_for_tag(&self, tag: Tag) -> Option<FontData<'static>> {
266                if tag == Tag::new(b"maxp") {
267                    Some(FontData::new(&[
268                        0, 0, 0x50, 0, // version 0.5
269                        0, 3, // num_glyphs = 3
270                    ]))
271                } else if tag == Tag::new(b"hhea") {
272                    Some(FontData::new(&[
273                        0, 1, 0, 0, // version 1.0
274                        0, 0, 0, 0, // ascender/descender
275                        0, 0, 0, 0, // line gap/advance width
276                        0, 0, 0, 0, // min left/right side bearing
277                        0, 0, 0, 0, // x_max, caret_slope_rise
278                        0, 0, 0, 0, // caret_slope_run, caret_offset
279                        0, 0, 0, 0, // reserved1/2
280                        0, 0, 0, 0, // reserved 3/4
281                        0, 0, 0, 1, // metric format, number_of_h_metrics
282                    ]))
283                } else if tag == Tag::new(b"hmtx") {
284                    Some(FontData::new(&[
285                        0, 4, 0, 6, // LongHorMetric: 4, 6
286                        0, 30, 0, 111, // two lsb entries
287                    ]))
288                } else {
289                    None
290                }
291            }
292        }
293
294        let number_of_h_metrics = DummyProvider.hhea().unwrap().number_of_h_metrics();
295        let num_glyphs = DummyProvider.maxp().unwrap().num_glyphs();
296        let hmtx = DummyProvider.hmtx().unwrap();
297
298        assert_eq!(number_of_h_metrics, 1);
299        assert_eq!(num_glyphs, 3);
300        assert_eq!(hmtx.h_metrics().len(), 1);
301        assert_eq!(hmtx.left_side_bearings().len(), 2);
302    }
303}