1include!("../../generated/generated_gvar.rs");
5
6use super::{
7 glyf::{CompositeGlyphFlags, Glyf, Glyph, PointCoord},
8 loca::Loca,
9 variations::{
10 PackedPointNumbers, Tuple, TupleDelta, TupleVariationCount, TupleVariationData,
11 TupleVariationHeader,
12 },
13};
14
15pub type GlyphVariationData<'a> = TupleVariationData<'a, GlyphDelta>;
17
18#[derive(Clone, Copy, Debug)]
19pub struct U16Or32(u32);
20
21impl ReadArgs for U16Or32 {
22 type Args = GvarFlags;
23}
24
25impl ComputeSize for U16Or32 {
26 fn compute_size(args: &GvarFlags) -> Result<usize, ReadError> {
27 Ok(if args.contains(GvarFlags::LONG_OFFSETS) {
28 4
29 } else {
30 2
31 })
32 }
33}
34
35impl FontReadWithArgs<'_> for U16Or32 {
36 fn read_with_args(data: FontData<'_>, args: &Self::Args) -> Result<Self, ReadError> {
37 if args.contains(GvarFlags::LONG_OFFSETS) {
38 data.read_at::<u32>(0).map(Self)
39 } else {
40 data.read_at::<u16>(0).map(|v| Self(v as u32 * 2))
41 }
42 }
43}
44
45impl U16Or32 {
46 #[inline]
47 pub fn get(self) -> u32 {
48 self.0
49 }
50}
51
52impl<'a> GlyphVariationDataHeader<'a> {
53 fn raw_tuple_header_data(&self) -> FontData<'a> {
54 let range = self.shape.tuple_variation_headers_byte_range();
55 self.data.split_off(range.start).unwrap()
56 }
57}
58
59impl<'a> Gvar<'a> {
60 pub fn data_for_gid(&self, gid: GlyphId) -> Result<Option<FontData<'a>>, ReadError> {
64 let range = self.data_range_for_gid(gid)?;
65 if range.is_empty() {
66 return Ok(None);
67 }
68 match self.data.slice(range) {
69 Some(data) => Ok(Some(data)),
70 None => Err(ReadError::OutOfBounds),
71 }
72 }
73
74 pub fn glyph_variation_data_for_range(
75 &self,
76 offset_range: Range<usize>,
77 ) -> Result<FontData<'a>, ReadError> {
78 let base = self.glyph_variation_data_array_offset() as usize;
79 let start = base
80 .checked_add(offset_range.start)
81 .ok_or(ReadError::OutOfBounds)?;
82 let end = base
83 .checked_add(offset_range.end)
84 .ok_or(ReadError::OutOfBounds)?;
85 self.data.slice(start..end).ok_or(ReadError::OutOfBounds)
86 }
87
88 pub fn as_bytes(&self) -> &[u8] {
89 self.data.as_bytes()
90 }
91
92 fn data_range_for_gid(&self, gid: GlyphId) -> Result<Range<usize>, ReadError> {
93 let start_idx = gid.to_u32() as usize;
94 let end_idx = start_idx + 1;
95 let data_start = self.glyph_variation_data_array_offset();
96 let start =
97 data_start.checked_add(self.glyph_variation_data_offsets().get(start_idx)?.get());
98 let end = data_start.checked_add(self.glyph_variation_data_offsets().get(end_idx)?.get());
99 let (Some(start), Some(end)) = (start, end) else {
100 return Err(ReadError::OutOfBounds);
101 };
102 Ok(start as usize..end as usize)
103 }
104
105 pub fn glyph_variation_data(
110 &self,
111 gid: GlyphId,
112 ) -> Result<Option<GlyphVariationData<'a>>, ReadError> {
113 let shared_tuples = self.shared_tuples()?;
114 let axis_count = self.axis_count();
115 let data = self.data_for_gid(gid)?;
116 data.map(|data| GlyphVariationData::new(data, axis_count, shared_tuples))
117 .transpose()
118 }
119
120 pub fn phantom_point_deltas(
126 &self,
127 glyf: &Glyf,
128 loca: &Loca,
129 coords: &[F2Dot14],
130 glyph_id: GlyphId,
131 ) -> Result<Option<[Point<Fixed>; 4]>, ReadError> {
132 let (glyph_id, point_count) = find_glyph_and_point_count(glyf, loca, glyph_id, 0)?;
143 let mut phantom_deltas = [Point::default(); 4];
144 let phantom_range = point_count..point_count + 4;
145 let Some(var_data) = self.glyph_variation_data(glyph_id)? else {
146 return Ok(None);
147 };
148 for (tuple, scalar) in var_data.active_tuples_at(coords) {
151 for tuple_delta in tuple.deltas() {
152 let ix = tuple_delta.position as usize;
153 if phantom_range.contains(&ix) {
154 phantom_deltas[ix - phantom_range.start] += tuple_delta.apply_scalar(scalar);
155 }
156 }
157 }
158 Ok(Some(phantom_deltas))
159 }
160}
161
162impl<'a> GlyphVariationData<'a> {
163 pub(crate) fn new(
164 data: FontData<'a>,
165 axis_count: u16,
166 shared_tuples: SharedTuples<'a>,
167 ) -> Result<Self, ReadError> {
168 let header = GlyphVariationDataHeader::read(data)?;
169
170 let header_data = header.raw_tuple_header_data();
171 let count = header.tuple_variation_count();
172 let data = header.serialized_data()?;
173
174 let (shared_point_numbers, serialized_data) =
176 if header.tuple_variation_count().shared_point_numbers() {
177 let (packed, data) = PackedPointNumbers::split_off_front(data);
178 (Some(packed), data)
179 } else {
180 (None, data)
181 };
182
183 Ok(GlyphVariationData {
184 tuple_count: count,
185 axis_count,
186 shared_tuples: Some(shared_tuples),
187 shared_point_numbers,
188 header_data,
189 serialized_data,
190 _marker: std::marker::PhantomData,
191 })
192 }
193}
194
195#[derive(Clone, Copy, Debug, PartialEq, Eq)]
197pub struct GlyphDelta {
198 pub position: u16,
200 pub x_delta: i32,
202 pub y_delta: i32,
204}
205
206impl GlyphDelta {
207 pub fn apply_scalar<D: PointCoord>(self, scalar: Fixed) -> Point<D> {
209 let scalar = D::from_fixed(scalar);
210 Point::new(self.x_delta, self.y_delta).map(D::from_i32) * scalar
211 }
212}
213
214impl TupleDelta for GlyphDelta {
215 fn is_point() -> bool {
216 true
217 }
218
219 fn new(position: u16, x: i32, y: i32) -> Self {
220 Self {
221 position,
222 x_delta: x,
223 y_delta: y,
224 }
225 }
226}
227
228fn find_glyph_and_point_count(
238 glyf: &Glyf,
239 loca: &Loca,
240 glyph_id: GlyphId,
241 recurse_depth: usize,
242) -> Result<(GlyphId, usize), ReadError> {
243 const RECURSION_LIMIT: usize = 64;
245 if recurse_depth > RECURSION_LIMIT {
246 return Err(ReadError::MalformedData(
247 "nesting too deep in composite glyph",
248 ));
249 }
250 let glyph = loca.get_glyf(glyph_id, glyf)?;
251 let Some(glyph) = glyph else {
252 return Ok((glyph_id, 0));
255 };
256 match glyph {
257 Glyph::Simple(simple) => {
258 Ok((glyph_id, simple.num_points()))
260 }
261 Glyph::Composite(composite) => {
262 let mut count = 0;
267 for component in composite.components() {
268 count += 1;
269 if component
270 .flags
271 .contains(CompositeGlyphFlags::USE_MY_METRICS)
272 {
273 return find_glyph_and_point_count(
274 glyf,
275 loca,
276 component.glyph.into(),
277 recurse_depth + 1,
278 );
279 }
280 }
281 Ok((glyph_id, count))
282 }
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 use font_test_data::bebuffer::BeBuffer;
289
290 use super::*;
291 use crate::{FontRef, TableProvider};
292
293 static SKIA_GVAR_SHARED_TUPLES_DATA: FontData = FontData::new(&[
297 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0,
298 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x40, 0x00, 0x40, 0x00, 0xC0, 0x00,
299 0x40, 0x00,
300 ]);
301
302 static SKIA_GVAR_I_DATA: FontData = FontData::new(&[
303 0x00, 0x08, 0x00, 0x24, 0x00, 0x33, 0x20, 0x00, 0x00, 0x15, 0x20, 0x01, 0x00, 0x1B, 0x20,
304 0x02, 0x00, 0x24, 0x20, 0x03, 0x00, 0x15, 0x20, 0x04, 0x00, 0x26, 0x20, 0x07, 0x00, 0x0D,
305 0x20, 0x06, 0x00, 0x1A, 0x20, 0x05, 0x00, 0x40, 0x01, 0x01, 0x01, 0x81, 0x80, 0x43, 0xFF,
306 0x7E, 0xFF, 0x7E, 0xFF, 0x7E, 0xFF, 0x7E, 0x00, 0x81, 0x45, 0x01, 0x01, 0x01, 0x03, 0x01,
307 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x02, 0x80, 0x40, 0x00, 0x82, 0x81, 0x81, 0x04, 0x3A,
308 0x5A, 0x3E, 0x43, 0x20, 0x81, 0x04, 0x0E, 0x40, 0x15, 0x45, 0x7C, 0x83, 0x00, 0x0D, 0x9E,
309 0xF3, 0xF2, 0xF0, 0xF0, 0xF0, 0xF0, 0xF3, 0x9E, 0xA0, 0xA1, 0xA1, 0xA1, 0x9F, 0x80, 0x00,
310 0x91, 0x81, 0x91, 0x00, 0x0D, 0x0A, 0x0A, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
311 0x0A, 0x0A, 0x0A, 0x0B, 0x80, 0x00, 0x15, 0x81, 0x81, 0x00, 0xC4, 0x89, 0x00, 0xC4, 0x83,
312 0x00, 0x0D, 0x80, 0x99, 0x98, 0x96, 0x96, 0x96, 0x96, 0x99, 0x80, 0x82, 0x83, 0x83, 0x83,
313 0x81, 0x80, 0x40, 0xFF, 0x18, 0x81, 0x81, 0x04, 0xE6, 0xF9, 0x10, 0x21, 0x02, 0x81, 0x04,
314 0xE8, 0xE5, 0xEB, 0x4D, 0xDA, 0x83, 0x00, 0x0D, 0xCE, 0xD3, 0xD4, 0xD3, 0xD3, 0xD3, 0xD5,
315 0xD2, 0xCE, 0xCC, 0xCD, 0xCD, 0xCD, 0xCD, 0x80, 0x00, 0xA1, 0x81, 0x91, 0x00, 0x0D, 0x07,
316 0x03, 0x04, 0x02, 0x02, 0x02, 0x03, 0x03, 0x07, 0x07, 0x08, 0x08, 0x08, 0x07, 0x80, 0x00,
317 0x09, 0x81, 0x81, 0x00, 0x28, 0x40, 0x00, 0xA4, 0x02, 0x24, 0x24, 0x66, 0x81, 0x04, 0x08,
318 0xFA, 0xFA, 0xFA, 0x28, 0x83, 0x00, 0x82, 0x02, 0xFF, 0xFF, 0xFF, 0x83, 0x02, 0x01, 0x01,
319 0x01, 0x84, 0x91, 0x00, 0x80, 0x06, 0x07, 0x08, 0x08, 0x08, 0x08, 0x0A, 0x07, 0x80, 0x03,
320 0xFE, 0xFF, 0xFF, 0xFF, 0x81, 0x00, 0x08, 0x81, 0x82, 0x02, 0xEE, 0xEE, 0xEE, 0x8B, 0x6D,
321 0x00,
322 ]);
323
324 #[test]
325 fn test_shared_tuples() {
326 #[allow(overflowing_literals)]
327 const MINUS_ONE: F2Dot14 = F2Dot14::from_bits(0xC000);
328 assert_eq!(MINUS_ONE, F2Dot14::from_f32(-1.0));
329
330 static EXPECTED: &[(F2Dot14, F2Dot14)] = &[
331 (F2Dot14::ONE, F2Dot14::ZERO),
332 (MINUS_ONE, F2Dot14::ZERO),
333 (F2Dot14::ZERO, F2Dot14::ONE),
334 (F2Dot14::ZERO, MINUS_ONE),
335 (MINUS_ONE, MINUS_ONE),
336 (F2Dot14::ONE, MINUS_ONE),
337 (F2Dot14::ONE, F2Dot14::ONE),
338 (MINUS_ONE, F2Dot14::ONE),
339 ];
340
341 const N_AXES: u16 = 2;
342
343 let tuples =
344 SharedTuples::read(SKIA_GVAR_SHARED_TUPLES_DATA, EXPECTED.len() as u16, N_AXES)
345 .unwrap();
346 let tuple_vec: Vec<_> = tuples
347 .tuples()
348 .iter()
349 .map(|tup| {
350 let values = tup.unwrap().values();
351 assert_eq!(values.len(), N_AXES as usize);
352 (values[0].get(), values[1].get())
353 })
354 .collect();
355
356 assert_eq!(tuple_vec, EXPECTED);
357 }
358
359 #[test]
361 fn smoke_test() {
362 let header = GlyphVariationDataHeader::read(SKIA_GVAR_I_DATA).unwrap();
363 assert_eq!(header.serialized_data_offset(), 36);
364 assert_eq!(header.tuple_variation_count().count(), 8);
365 let shared_tuples = SharedTuples::read(SKIA_GVAR_SHARED_TUPLES_DATA, 8, 2).unwrap();
366
367 let vardata = GlyphVariationData::new(SKIA_GVAR_I_DATA, 2, shared_tuples).unwrap();
368 assert_eq!(vardata.tuple_count(), 8);
369 let deltas = vardata
370 .tuples()
371 .next()
372 .unwrap()
373 .deltas()
374 .collect::<Vec<_>>();
375 assert_eq!(deltas.len(), 18);
376 static EXPECTED: &[(i32, i32)] = &[
377 (257, 0),
378 (-127, 0),
379 (-128, 58),
380 (-130, 90),
381 (-130, 62),
382 (-130, 67),
383 (-130, 32),
384 (-127, 0),
385 (257, 0),
386 (259, 14),
387 (260, 64),
388 (260, 21),
389 (260, 69),
390 (258, 124),
391 (0, 0),
392 (130, 0),
393 (0, 0),
394 (0, 0),
395 ];
396 let expected = EXPECTED
397 .iter()
398 .copied()
399 .enumerate()
400 .map(|(pos, (x_delta, y_delta))| GlyphDelta {
401 position: pos as _,
402 x_delta,
403 y_delta,
404 })
405 .collect::<Vec<_>>();
406
407 for (a, b) in deltas.iter().zip(expected.iter()) {
408 assert_eq!(a, b);
409 }
410 }
411
412 #[test]
413 fn vazirmatn_var_a() {
414 let gvar = FontRef::new(font_test_data::VAZIRMATN_VAR)
415 .unwrap()
416 .gvar()
417 .unwrap();
418 let a_glyph_var = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
419 assert_eq!(a_glyph_var.axis_count, 1);
420 let mut tuples = a_glyph_var.tuples();
421 let tup1 = tuples.next().unwrap();
422 assert_eq!(tup1.peak().values(), &[F2Dot14::from_f32(-1.0)]);
423 assert_eq!(tup1.deltas().count(), 18);
424 let x_vals = &[
425 -90, -134, 4, -6, -81, 18, -25, -33, -109, -121, -111, -111, -22, -22, 0, -113, 0, 0,
426 ];
427 let y_vals = &[
428 83, 0, 0, 0, 0, 0, 83, 0, 0, 0, -50, 54, 54, -50, 0, 0, -21, 0,
429 ];
430 assert_eq!(tup1.deltas().map(|d| d.x_delta).collect::<Vec<_>>(), x_vals);
431 assert_eq!(tup1.deltas().map(|d| d.y_delta).collect::<Vec<_>>(), y_vals);
432 let tup2 = tuples.next().unwrap();
433 assert_eq!(tup2.peak().values(), &[F2Dot14::from_f32(1.0)]);
434 let x_vals = &[
435 20, 147, -33, -53, 59, -90, 37, -6, 109, 90, -79, -79, -8, -8, 0, 59, 0, 0,
436 ];
437 let y_vals = &[
438 -177, 0, 0, 0, 0, 0, -177, 0, 0, 0, 4, -109, -109, 4, 0, 0, 9, 0,
439 ];
440
441 assert_eq!(tup2.deltas().map(|d| d.x_delta).collect::<Vec<_>>(), x_vals);
442 assert_eq!(tup2.deltas().map(|d| d.y_delta).collect::<Vec<_>>(), y_vals);
443 assert!(tuples.next().is_none());
444 }
445
446 #[test]
447 fn vazirmatn_var_agrave() {
448 let gvar = FontRef::new(font_test_data::VAZIRMATN_VAR)
449 .unwrap()
450 .gvar()
451 .unwrap();
452 let agrave_glyph_var = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
453 let mut tuples = agrave_glyph_var.tuples();
454 let tup1 = tuples.next().unwrap();
455 assert_eq!(
456 tup1.deltas()
457 .map(|d| (d.position, d.x_delta, d.y_delta))
458 .collect::<Vec<_>>(),
459 &[(1, -51, 8), (3, -113, 0)]
460 );
461 let tup2 = tuples.next().unwrap();
462 assert_eq!(
463 tup2.deltas()
464 .map(|d| (d.position, d.x_delta, d.y_delta))
465 .collect::<Vec<_>>(),
466 &[(1, -54, -1), (3, 59, 0)]
467 );
468 }
469
470 #[test]
471 fn vazirmatn_var_grave() {
472 let gvar = FontRef::new(font_test_data::VAZIRMATN_VAR)
473 .unwrap()
474 .gvar()
475 .unwrap();
476 let grave_glyph_var = gvar.glyph_variation_data(GlyphId::new(3)).unwrap().unwrap();
477 let mut tuples = grave_glyph_var.tuples();
478 let tup1 = tuples.next().unwrap();
479 let tup2 = tuples.next().unwrap();
480 assert!(tuples.next().is_none());
481 assert_eq!(tup1.deltas().count(), 8);
482 assert_eq!(
483 tup2.deltas().map(|d| d.y_delta).collect::<Vec<_>>(),
484 &[0, -20, -20, 0, 0, 0, 0, 0]
485 );
486 }
487
488 #[test]
489 fn phantom_point_deltas() {
490 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
491 #[rustfmt::skip]
492 let a_cases = [
493 (&[0.0], [(0.0, 0.0); 4]),
495 (&[1.0], [(0.0, 0.0), (59.0, 0.0), (0.0, 9.0), (0.0, 0.0)]),
496 (&[-1.0], [(0.0, 0.0), (-113.0, 0.0), (0.0, -21.0), (0.0, 0.0)]),
497 (&[0.5], [(0.0, 0.0), (29.5, 0.0), (0.0, 4.5), (0.0, 0.0)]),
498 (&[-0.5], [(0.0, 0.0), (-56.5, 0.0), (0.0, -10.5), (0.0, 0.0)]),
499 ];
500 for (coords, deltas) in a_cases {
501 assert_eq!(
503 compute_phantom_deltas(&font, coords, GlyphId::new(1)),
504 deltas
505 );
506 assert_eq!(
509 compute_phantom_deltas(&font, coords, GlyphId::new(2)),
510 deltas
511 );
512 }
513 #[rustfmt::skip]
514 let grave_cases = [
515 (&[0.0], [(0.0, 0.0); 4]),
517 (&[1.0], [(0.0, 0.0), (63.0, 0.0), (0.0, 0.0), (0.0, 0.0)]),
518 (&[-1.0], [(0.0, 0.0), (-96.0, 0.0), (0.0, 0.0), (0.0, 0.0)]),
519 (&[0.5], [(0.0, 0.0), (31.5, 0.0), (0.0, 0.0), (0.0, 0.0)]),
520 (&[-0.5], [(0.0, 0.0), (-48.0, 0.0), (0.0, 0.0), (0.0, 0.0)]),
521 ];
522 for (coords, deltas) in grave_cases {
524 assert_eq!(
525 compute_phantom_deltas(&font, coords, GlyphId::new(3)),
526 deltas
527 );
528 }
529 }
530
531 fn compute_phantom_deltas(
532 font: &FontRef,
533 coords: &[f32],
534 glyph_id: GlyphId,
535 ) -> [(f32, f32); 4] {
536 let loca = font.loca(None).unwrap();
537 let glyf = font.glyf().unwrap();
538 let gvar = font.gvar().unwrap();
539 let coords = coords
540 .iter()
541 .map(|coord| F2Dot14::from_f32(*coord))
542 .collect::<Vec<_>>();
543 gvar.phantom_point_deltas(&glyf, &loca, &coords, glyph_id)
544 .unwrap()
545 .unwrap()
546 .map(|delta| delta.map(Fixed::to_f32))
547 .map(|p| (p.x, p.y))
548 }
549
550 #[test]
553 fn avoid_data_range_overflow() {
554 let mut buf = BeBuffer::new();
557 buf = buf.push(1u16).push(0u16);
559 buf = buf.push(0u16);
561 buf = buf.push(0u16).push(0u32);
563 buf = buf.push(1u16);
565 buf = buf.push(1u16);
567 buf = buf.push(u32::MAX - 10);
569 buf = buf.push(0u32).push(11u32);
571 let gvar = Gvar::read(buf.data().into()).unwrap();
572 let _ = gvar.data_range_for_gid(GlyphId::new(0));
574 }
575}