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