1 //! a trait for things that can serve font tables
2 
3 use types::Tag;
4 
5 use 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.
10 pub 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)
16 pub trait TableProvider<'a> {
data_for_tag(&self, tag: Tag) -> Option<FontData<'a>>17     fn data_for_tag(&self, tag: Tag) -> Option<FontData<'a>>;
18 
expect_data_for_tag(&self, tag: Tag) -> Result<FontData<'a>, ReadError>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 
expect_table<T: TopLevelTable + FontRead<'a>>(&self) -> Result<T, ReadError>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 
head(&self) -> Result<tables::head::Head<'a>, ReadError>27     fn head(&self) -> Result<tables::head::Head<'a>, ReadError> {
28         self.expect_table()
29     }
30 
name(&self) -> Result<tables::name::Name<'a>, ReadError>31     fn name(&self) -> Result<tables::name::Name<'a>, ReadError> {
32         self.expect_table()
33     }
34 
hhea(&self) -> Result<tables::hhea::Hhea<'a>, ReadError>35     fn hhea(&self) -> Result<tables::hhea::Hhea<'a>, ReadError> {
36         self.expect_table()
37     }
38 
vhea(&self) -> Result<tables::vhea::Vhea<'a>, ReadError>39     fn vhea(&self) -> Result<tables::vhea::Vhea<'a>, ReadError> {
40         self.expect_table()
41     }
42 
hmtx(&self) -> Result<tables::hmtx::Hmtx<'a>, ReadError>43     fn hmtx(&self) -> Result<tables::hmtx::Hmtx<'a>, ReadError> {
44         //FIXME: should we make the user pass these in?
45         let num_glyphs = self.maxp().map(|maxp| maxp.num_glyphs())?;
46         let number_of_h_metrics = self.hhea().map(|hhea| hhea.number_of_long_metrics())?;
47         let data = self.expect_data_for_tag(tables::hmtx::Hmtx::TAG)?;
48         tables::hmtx::Hmtx::read(data, number_of_h_metrics, num_glyphs)
49     }
50 
vmtx(&self) -> Result<tables::vmtx::Vmtx<'a>, ReadError>51     fn vmtx(&self) -> Result<tables::vmtx::Vmtx<'a>, ReadError> {
52         //FIXME: should we make the user pass these in?
53         let num_glyphs = self.maxp().map(|maxp| maxp.num_glyphs())?;
54         let number_of_v_metrics = self.vhea().map(|vhea| vhea.number_of_long_ver_metrics())?;
55         let data = self.expect_data_for_tag(tables::vmtx::Vmtx::TAG)?;
56         tables::vmtx::Vmtx::read(data, number_of_v_metrics, num_glyphs)
57     }
58 
fvar(&self) -> Result<tables::fvar::Fvar<'a>, ReadError>59     fn fvar(&self) -> Result<tables::fvar::Fvar<'a>, ReadError> {
60         self.expect_table()
61     }
62 
avar(&self) -> Result<tables::avar::Avar<'a>, ReadError>63     fn avar(&self) -> Result<tables::avar::Avar<'a>, ReadError> {
64         self.expect_table()
65     }
66 
hvar(&self) -> Result<tables::hvar::Hvar<'a>, ReadError>67     fn hvar(&self) -> Result<tables::hvar::Hvar<'a>, ReadError> {
68         self.expect_table()
69     }
70 
vvar(&self) -> Result<tables::vvar::Vvar<'a>, ReadError>71     fn vvar(&self) -> Result<tables::vvar::Vvar<'a>, ReadError> {
72         self.expect_table()
73     }
74 
mvar(&self) -> Result<tables::mvar::Mvar<'a>, ReadError>75     fn mvar(&self) -> Result<tables::mvar::Mvar<'a>, ReadError> {
76         self.expect_table()
77     }
78 
maxp(&self) -> Result<tables::maxp::Maxp<'a>, ReadError>79     fn maxp(&self) -> Result<tables::maxp::Maxp<'a>, ReadError> {
80         self.expect_table()
81     }
82 
os2(&self) -> Result<tables::os2::Os2<'a>, ReadError>83     fn os2(&self) -> Result<tables::os2::Os2<'a>, ReadError> {
84         self.expect_table()
85     }
86 
post(&self) -> Result<tables::post::Post<'a>, ReadError>87     fn post(&self) -> Result<tables::post::Post<'a>, ReadError> {
88         self.expect_table()
89     }
90 
91     /// is_long can be optionally provided, if known, otherwise we look it up in head.
loca(&self, is_long: impl Into<Option<bool>>) -> Result<tables::loca::Loca<'a>, ReadError>92     fn loca(&self, is_long: impl Into<Option<bool>>) -> Result<tables::loca::Loca<'a>, ReadError> {
93         let is_long = match is_long.into() {
94             Some(val) => val,
95             None => self.head()?.index_to_loc_format() == 1,
96         };
97         let data = self.expect_data_for_tag(tables::loca::Loca::TAG)?;
98         tables::loca::Loca::read(data, is_long)
99     }
100 
glyf(&self) -> Result<tables::glyf::Glyf<'a>, ReadError>101     fn glyf(&self) -> Result<tables::glyf::Glyf<'a>, ReadError> {
102         self.expect_table()
103     }
104 
gvar(&self) -> Result<tables::gvar::Gvar<'a>, ReadError>105     fn gvar(&self) -> Result<tables::gvar::Gvar<'a>, ReadError> {
106         self.expect_table()
107     }
108 
cff(&self) -> Result<tables::cff::Cff<'a>, ReadError>109     fn cff(&self) -> Result<tables::cff::Cff<'a>, ReadError> {
110         self.expect_table()
111     }
112 
cff2(&self) -> Result<tables::cff2::Cff2<'a>, ReadError>113     fn cff2(&self) -> Result<tables::cff2::Cff2<'a>, ReadError> {
114         self.expect_table()
115     }
116 
cmap(&self) -> Result<tables::cmap::Cmap<'a>, ReadError>117     fn cmap(&self) -> Result<tables::cmap::Cmap<'a>, ReadError> {
118         self.expect_table()
119     }
120 
gdef(&self) -> Result<tables::gdef::Gdef<'a>, ReadError>121     fn gdef(&self) -> Result<tables::gdef::Gdef<'a>, ReadError> {
122         self.expect_table()
123     }
124 
gpos(&self) -> Result<tables::gpos::Gpos<'a>, ReadError>125     fn gpos(&self) -> Result<tables::gpos::Gpos<'a>, ReadError> {
126         self.expect_table()
127     }
128 
gsub(&self) -> Result<tables::gsub::Gsub<'a>, ReadError>129     fn gsub(&self) -> Result<tables::gsub::Gsub<'a>, ReadError> {
130         self.expect_table()
131     }
132 
colr(&self) -> Result<tables::colr::Colr<'a>, ReadError>133     fn colr(&self) -> Result<tables::colr::Colr<'a>, ReadError> {
134         self.expect_table()
135     }
136 
cpal(&self) -> Result<tables::cpal::Cpal<'a>, ReadError>137     fn cpal(&self) -> Result<tables::cpal::Cpal<'a>, ReadError> {
138         self.expect_table()
139     }
140 
cblc(&self) -> Result<tables::cblc::Cblc<'a>, ReadError>141     fn cblc(&self) -> Result<tables::cblc::Cblc<'a>, ReadError> {
142         self.expect_table()
143     }
144 
cbdt(&self) -> Result<tables::cbdt::Cbdt<'a>, ReadError>145     fn cbdt(&self) -> Result<tables::cbdt::Cbdt<'a>, ReadError> {
146         self.expect_table()
147     }
148 
eblc(&self) -> Result<tables::eblc::Eblc<'a>, ReadError>149     fn eblc(&self) -> Result<tables::eblc::Eblc<'a>, ReadError> {
150         self.expect_table()
151     }
152 
ebdt(&self) -> Result<tables::ebdt::Ebdt<'a>, ReadError>153     fn ebdt(&self) -> Result<tables::ebdt::Ebdt<'a>, ReadError> {
154         self.expect_table()
155     }
156 
sbix(&self) -> Result<tables::sbix::Sbix<'a>, ReadError>157     fn sbix(&self) -> Result<tables::sbix::Sbix<'a>, ReadError> {
158         // should we make the user pass this in?
159         let num_glyphs = self.maxp().map(|maxp| maxp.num_glyphs())?;
160         let data = self.expect_data_for_tag(tables::sbix::Sbix::TAG)?;
161         tables::sbix::Sbix::read(data, num_glyphs)
162     }
163 
stat(&self) -> Result<tables::stat::Stat<'a>, ReadError>164     fn stat(&self) -> Result<tables::stat::Stat<'a>, ReadError> {
165         self.expect_table()
166     }
167 }
168 
169 #[cfg(test)]
170 mod tests {
171 
172     use super::*;
173 
174     /// https://github.com/googlefonts/fontations/issues/105
175     #[test]
bug_105()176     fn bug_105() {
177         // serve some dummy versions of the tables used to compute hmtx. The only
178         // fields that matter are maxp::num_glyphs and hhea::number_of_h_metrics,
179         // everything else is zero'd out
180         struct DummyProvider;
181         impl TableProvider<'static> for DummyProvider {
182             fn data_for_tag(&self, tag: Tag) -> Option<FontData<'static>> {
183                 if tag == Tag::new(b"maxp") {
184                     Some(FontData::new(&[
185                         0, 0, 0x50, 0, // version 0.5
186                         0, 3, // num_glyphs = 3
187                     ]))
188                 } else if tag == Tag::new(b"hhea") {
189                     Some(FontData::new(&[
190                         0, 1, 0, 0, // version 1.0
191                         0, 0, 0, 0, // ascender/descender
192                         0, 0, 0, 0, // line gap/advance width
193                         0, 0, 0, 0, // min left/right side bearing
194                         0, 0, 0, 0, // x_max, caret_slope_rise
195                         0, 0, 0, 0, // caret_slope_run, caret_offset
196                         0, 0, 0, 0, // reserved1/2
197                         0, 0, 0, 0, // reserved 3/4
198                         0, 0, 0, 1, // metric format, number_of_h_metrics
199                     ]))
200                 } else if tag == Tag::new(b"hmtx") {
201                     Some(FontData::new(&[
202                         0, 4, 0, 6, // LongHorMetric: 4, 6
203                         0, 30, 0, 111, // two lsb entries
204                     ]))
205                 } else {
206                     None
207                 }
208             }
209         }
210 
211         let number_of_h_metrics = DummyProvider.hhea().unwrap().number_of_long_metrics();
212         let num_glyphs = DummyProvider.maxp().unwrap().num_glyphs();
213         let hmtx = DummyProvider.hmtx().unwrap();
214 
215         assert_eq!(number_of_h_metrics, 1);
216         assert_eq!(num_glyphs, 3);
217         assert_eq!(hmtx.h_metrics().len(), 1);
218         assert_eq!(hmtx.left_side_bearings().len(), 2);
219     }
220 }
221