1#![deny(missing_docs)]
2
3use crate::binary::read::{ReadBinary, ReadCtxt, ReadScope, ReadUnchecked};
8use crate::binary::{U16Be, U32Be};
9use crate::error::ParseError;
10use crate::tables::loca::LocaOffsets;
11use crate::tables::variable_fonts::{ReadTuple, TupleVariationStore};
12use crate::tables::F2Dot14;
13use crate::SafeFrom;
14use std::fmt;
15use std::fmt::Formatter;
16
17pub struct GvarTable<'a> {
21 pub major_version: u16,
23 pub minor_version: u16,
25 pub axis_count: u16,
30 shared_tuple_count: u16,
36 shared_tuples_scope: ReadScope<'a>,
38 pub glyph_count: u16,
43 glyph_variation_data_array_scope: ReadScope<'a>,
45 glyph_variation_data_offsets: LocaOffsets<'a>,
48}
49
50#[derive(Debug, Copy, Clone)]
53pub struct NumPoints(u32);
54
55impl NumPoints {
56 pub fn new(num: u16) -> NumPoints {
59 NumPoints(u32::from(num) + 4)
60 }
61
62 pub(crate) fn from_raw(num: u32) -> NumPoints {
65 NumPoints(num)
66 }
67
68 pub fn get(self) -> u32 {
70 self.0
71 }
72}
73
74impl fmt::Display for NumPoints {
75 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
76 self.0.fmt(f)
77 }
78}
79
80impl<'a> GvarTable<'a> {
81 pub fn glyph_variation_data(
87 &self,
88 glyph_index: u16,
89 num_points: NumPoints,
90 ) -> Result<Option<TupleVariationStore<'a, super::Gvar>>, ParseError> {
91 let glyph_index = usize::from(glyph_index);
92 let start = self
93 .glyph_variation_data_offsets
94 .get(glyph_index)
95 .map(usize::safe_from)
96 .ok_or(ParseError::BadIndex)?;
97 let end = self
98 .glyph_variation_data_offsets
99 .get(glyph_index + 1)
100 .map(usize::safe_from)
101 .ok_or(ParseError::BadIndex)?;
102 let length = end.checked_sub(start).ok_or(ParseError::BadOffset)?;
103 if length > 0 {
104 let scope = self
105 .glyph_variation_data_array_scope
106 .offset_length(start, length)?;
107 scope
108 .read_dep::<TupleVariationStore<'_, super::Gvar>>((
109 self.axis_count,
110 num_points.get(),
111 scope,
112 ))
113 .map(Some)
114 } else {
115 Ok(None)
116 }
117 }
118
119 pub fn shared_tuple(&self, index: u16) -> Result<ReadTuple<'a>, ParseError> {
121 if index >= self.shared_tuple_count {
122 return Err(ParseError::BadIndex);
123 }
124
125 let offset = usize::from(index) * usize::from(self.axis_count) * F2Dot14::SIZE;
126 let shared_tuple = self
127 .shared_tuples_scope
128 .offset(offset)
129 .ctxt()
130 .read_array::<F2Dot14>(usize::from(self.axis_count))
131 .map(ReadTuple)?;
132 Ok(shared_tuple)
133 }
134}
135
136impl ReadBinary for GvarTable<'_> {
137 type HostType<'a> = GvarTable<'a>;
138
139 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
140 let scope = ctxt.scope();
141 let major_version = ctxt.read_u16be()?;
142 ctxt.check_version(major_version == 1)?;
143 let minor_version = ctxt.read_u16be()?;
144 let axis_count = ctxt.read_u16be()?;
145 let shared_tuple_count = ctxt.read_u16be()?;
146 let shared_tuples_offset = ctxt.read_u32be()?;
147 let glyph_count = ctxt.read_u16be()?;
148 let flags = ctxt.read_u16be()?;
149 let glyph_variation_data_array_offset = ctxt.read_u32be()?;
152 let glyph_variation_data_offsets = if flags & 1 == 1 {
156 LocaOffsets::Long(ctxt.read_array::<U32Be>(usize::from(glyph_count) + 1)?)
158 } else {
159 LocaOffsets::Short(ctxt.read_array::<U16Be>(usize::from(glyph_count) + 1)?)
162 };
163
164 let shared_tuples_len =
166 usize::from(shared_tuple_count) * usize::from(axis_count) * F2Dot14::SIZE;
167 let shared_tuples_scope =
168 scope.offset_length(usize::safe_from(shared_tuples_offset), shared_tuples_len)?;
169
170 if glyph_variation_data_offsets.len() < 2 {
172 return Err(ParseError::BadIndex);
173 }
174 let glyph_variation_data_array_scope = scope.offset_length(
176 usize::safe_from(glyph_variation_data_array_offset),
177 usize::safe_from(glyph_variation_data_offsets.last().unwrap()),
178 )?;
179
180 Ok(GvarTable {
181 major_version,
182 minor_version,
183 axis_count,
184 shared_tuple_count,
185 shared_tuples_scope,
186 glyph_count,
187 glyph_variation_data_array_scope,
188 glyph_variation_data_offsets,
189 })
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use crate::binary::read::ReadScope;
197 use crate::error::ReadWriteError;
198 use crate::font_data::FontData;
199 use crate::tables::glyf::GlyfTable;
200 use crate::tables::loca::LocaTable;
201 use crate::tables::{FontTableProvider, HeadTable, MaxpTable};
202 use crate::tag;
203 use crate::tests::read_fixture;
204
205 #[test]
206 fn gvar() {
207 let buffer = read_fixture("tests/fonts/opentype/NotoSans-VF.abc.ttf");
208 let scope = ReadScope::new(&buffer);
209 let font_file = scope
210 .read::<FontData<'_>>()
211 .expect("unable to parse font file");
212 let table_provider = font_file
213 .table_provider(0)
214 .expect("unable to create font provider");
215 let stat_data = table_provider
216 .read_table_data(tag::GVAR)
217 .expect("unable to read fvar table data");
218 let gvar = ReadScope::new(&stat_data).read::<GvarTable<'_>>().unwrap();
219 assert_eq!(gvar.major_version, 1);
220 assert_eq!(gvar.minor_version, 0);
221 assert_eq!(gvar.axis_count, 3);
222 assert_eq!(gvar.shared_tuple_count, 15);
223 assert_eq!(gvar.shared_tuples_scope.data().len(), 90);
224 assert_eq!(gvar.glyph_count, 4);
225 assert_eq!(gvar.glyph_variation_data_array_scope.data().len(), 3028);
226 assert_eq!(gvar.glyph_variation_data_offsets.len(), 5);
227 }
228
229 #[test]
230 fn glyph_variation_data() -> Result<(), ReadWriteError> {
231 let buffer = read_fixture("tests/fonts/opentype/NotoSans-VF.abc.ttf");
232 let scope = ReadScope::new(&buffer);
233 let font_file = scope.read::<FontData<'_>>()?;
234 let provider = font_file.table_provider(0)?;
235 let head = ReadScope::new(&provider.read_table_data(tag::HEAD)?).read::<HeadTable>()?;
236 let maxp = ReadScope::new(&provider.read_table_data(tag::MAXP)?).read::<MaxpTable>()?;
237 let loca_data = provider.read_table_data(tag::LOCA)?;
238 let loca = ReadScope::new(&loca_data)
239 .read_dep::<LocaTable<'_>>((usize::from(maxp.num_glyphs), head.index_to_loc_format))?;
240 let glyf_data = provider.read_table_data(tag::GLYF)?;
241 let glyf = ReadScope::new(&glyf_data).read_dep::<GlyfTable<'_>>(&loca)?;
242 let gvar_data = provider.read_table_data(tag::GVAR)?;
243 let gvar = ReadScope::new(&gvar_data).read::<GvarTable<'_>>().unwrap();
244
245 let glyph = 3; let num_points = NumPoints::new(glyf.records()[3].number_of_points()?);
247 let store = gvar
248 .glyph_variation_data(glyph, num_points)?
249 .expect("variation store");
250 let variation_data = (0..store.tuple_variation_headers.len())
251 .into_iter()
252 .map(|i| store.variation_data(i as u16))
253 .collect::<Result<Vec<_>, _>>()?;
254
255 let deltas = variation_data[0].iter().collect::<Vec<_>>();
257 let expected = vec![
258 (0, (2, 0)),
259 (1, (-11, 0)),
260 (2, (-8, 13)),
261 (3, (4, 14)),
262 (4, (4, -4)),
263 (5, (4, -22)),
264 (6, (1, -21)),
265 (7, (4, -8)),
266 (8, (13, -8)),
267 (9, (8, -8)),
268 (10, (-9, -3)),
269 (11, (-5, -3)),
270 (12, (17, 45)),
271 (13, (11, 50)),
272 (14, (16, 44)),
273 (15, (15, 44)),
274 (16, (-3, 44)),
275 (17, (-37, 26)),
276 (18, (-60, 2)),
277 (19, (-60, -5)),
278 (20, (-60, -9)),
279 (21, (-49, -31)),
280 (22, (-22, -51)),
281 (23, (3, -51)),
282 (24, (-5, -51)),
283 (25, (-1, -55)),
284 (26, (0, -56)),
285 (27, (0, -3)),
286 (28, (2, 1)),
287 (29, (-3, 0)),
288 (30, (0, 0)),
289 (31, (-8, 0)),
290 (32, (0, 0)),
291 (33, (0, 0)),
292 ];
293 assert_eq!(deltas, expected);
294
295 let deltas = variation_data[4].iter().collect::<Vec<_>>();
297 let expected = vec![
298 (1, (-15, 0)),
299 (5, (-4, 0)),
300 (9, (-20, 0)),
301 (11, (-24, 0)),
302 (12, (-24, 0)),
303 (14, (-20, 0)),
304 (17, (-7, 0)),
305 (20, (-5, 0)),
306 (22, (-12, 0)),
307 (23, (-17, 0)),
308 (24, (-20, 0)),
309 (27, (-24, 0)),
310 (31, (-26, 0)),
311 ];
312 assert_eq!(deltas, expected);
313
314 Ok(())
315 }
316}