1include!("../../generated/generated_gvar.rs");
4
5use std::collections::HashMap;
6
7use indexmap::IndexMap;
8
9use crate::{
10 collections::HasLen,
11 tables::variations::{Deltas, TupleVariationStoreInputError},
12 OffsetMarker,
13};
14
15use super::variations::{
16 compute_shared_points, compute_tuple_variation_count, compute_tuple_variation_data_offset,
17 PackedDeltas, PackedPointNumbers, Tuple, TupleVariationCount, TupleVariationHeader,
18};
19
20pub use super::variations::Tent;
21
22pub mod iup;
23
24#[derive(Clone, Debug)]
26pub struct GlyphVariations {
27 gid: GlyphId,
28 variations: Vec<GlyphDeltas>,
29}
30
31pub type GlyphDeltas = Deltas<GlyphDelta>;
33
34pub type GvarInputError = TupleVariationStoreInputError<GlyphId>;
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47pub struct GlyphDelta {
48 pub x: i16,
49 pub y: i16,
50 pub required: bool,
52}
53
54impl Gvar {
55 pub fn new(
61 mut variations: Vec<GlyphVariations>,
62 axis_count: u16,
63 ) -> Result<Self, GvarInputError> {
64 fn compute_shared_peak_tuples(glyphs: &[GlyphVariations]) -> Vec<Tuple> {
65 const MAX_SHARED_TUPLES: usize = 4095;
66 let mut peak_tuple_counts = IndexMap::new();
67 for glyph in glyphs {
68 glyph.count_peak_tuples(&mut peak_tuple_counts);
69 }
70 let mut to_share = peak_tuple_counts
71 .into_iter()
72 .filter(|(_, n)| *n > 1)
73 .collect::<Vec<_>>();
74 to_share.sort_by_key(|(_, n)| std::cmp::Reverse(*n));
78 to_share.truncate(MAX_SHARED_TUPLES);
79 to_share.into_iter().map(|(t, _)| t.to_owned()).collect()
80 }
81
82 for var in &variations {
83 var.validate()?;
84 }
85
86 if let Some(bad_var) = variations
87 .iter()
88 .find(|var| var.axis_count().is_some() && var.axis_count().unwrap() != axis_count)
89 {
90 return Err(TupleVariationStoreInputError::UnexpectedAxisCount {
91 index: bad_var.gid,
92 expected: axis_count,
93 actual: bad_var.axis_count().unwrap(),
94 });
95 }
96
97 let shared = compute_shared_peak_tuples(&variations);
98 let shared_idx_map = shared
99 .iter()
100 .enumerate()
101 .map(|(i, x)| (x, i as u16))
102 .collect();
103 variations.sort_unstable_by_key(|g| g.gid);
104 let glyphs = variations
105 .into_iter()
106 .map(|raw_g| raw_g.build(&shared_idx_map))
107 .collect();
108
109 Ok(Gvar {
110 axis_count,
111 shared_tuples: SharedTuples::new(shared).into(),
112 glyph_variation_data_offsets: glyphs,
113 })
114 }
115}
116
117impl GvarExtended {
118 pub fn new(variations: Vec<GlyphVariations>, axis_count: u16) -> Result<Self, GvarInputError> {
120 let table = Gvar::new(variations, axis_count)?;
121 Ok(Self {
122 axis_count: table.axis_count,
123 shared_tuples: table.shared_tuples,
124 glyph_variation_data_offsets: table.glyph_variation_data_offsets,
125 })
126 }
127}
128
129macro_rules! impl_gvar_writer {
130 ($table:ident, $count:ty, $extended:expr, $max_count:expr) => {
131 impl $table {
132 fn compute_flags(&self) -> GvarFlags {
133 let max_offset = self
134 .glyph_variation_data_offsets
135 .iter()
136 .fold(0_u64, |acc, val| {
137 let length = val.length_for_format($extended) as u64;
138 acc + length + length % 2
139 });
140
141 if max_offset / 2 <= (u16::MAX as u64) {
142 GvarFlags::default()
143 } else {
144 GvarFlags::LONG_OFFSETS
145 }
146 }
147
148 fn compute_glyph_count(&self) -> $count {
149 self.glyph_variation_data_offsets.len().try_into().unwrap()
150 }
151
152 fn compute_shared_tuples_offset(&self) -> u32 {
153 const BASE_OFFSET: usize = MajorMinor::RAW_BYTE_LEN
154 + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN
157 + <$count>::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN; let bytes_per_offset = if self.compute_flags() == GvarFlags::LONG_OFFSETS {
161 u32::RAW_BYTE_LEN
162 } else {
163 u16::RAW_BYTE_LEN
164 };
165
166 let offsets_len = (self.glyph_variation_data_offsets.len() + 1) * bytes_per_offset;
167
168 (BASE_OFFSET + offsets_len).try_into().unwrap()
169 }
170
171 fn compute_data_array_offset(&self) -> u32 {
172 let shared_tuples_len: u32 =
173 (array_len(&self.shared_tuples) * self.axis_count as usize * 2)
174 .try_into()
175 .unwrap();
176 self.compute_shared_tuples_offset() + shared_tuples_len
177 }
178
179 fn compile_variation_data(&self) -> GlyphDataWriter<'_> {
180 GlyphDataWriter {
181 long_offsets: self.compute_flags() == GvarFlags::LONG_OFFSETS,
182 extended: $extended,
183 shared_tuples: &self.shared_tuples,
184 data: &self.glyph_variation_data_offsets,
185 }
186 }
187
188 fn validate_glyph_variation_data(&self, ctx: &mut ValidationCtx) {
189 if self.glyph_variation_data_offsets.len() > $max_count {
190 ctx.report("glyph count overflows");
191 }
192 for glyph in &self.glyph_variation_data_offsets {
193 glyph.validate_for_format(ctx, $extended);
194 }
195 let long_offsets = self.compute_flags().contains(GvarFlags::LONG_OFFSETS);
196 let data_len: u64 = self.glyph_variation_data_offsets.iter().map(|glyph| {
197 let len = glyph.length_for_format($extended) as u64;
198 len + if long_offsets { 0 } else { len % 2 }
199 }).sum();
200 let prefix_len = 18 + <$count>::RAW_BYTE_LEN as u64
201 + (self.glyph_variation_data_offsets.len() as u64 + 1) * if long_offsets { 4 } else { 2 }
202 + array_len(&self.shared_tuples) as u64 * self.axis_count as u64 * 2;
203 if prefix_len + data_len > u32::MAX as u64 {
204 ctx.report("glyph variation offsets overflow 32 bits");
205 }
206 }
207 }
208 };
209}
210
211impl_gvar_writer!(Gvar, u16, false, u16::MAX as usize);
212impl_gvar_writer!(GvarExtended, Uint24, true, usize::from(Uint24::MAX));
213
214impl GlyphVariations {
215 pub fn new(gid: GlyphId, variations: Vec<GlyphDeltas>) -> Self {
217 Self { gid, variations }
218 }
219
220 fn validate(&self) -> Result<(), GvarInputError> {
222 let (axis_count, delta_len) = self
223 .variations
224 .first()
225 .map(|var| (var.peak_tuple.len(), var.deltas.len()))
226 .unwrap_or_default();
227 for var in &self.variations {
228 if var.peak_tuple.len() != axis_count {
229 return Err(TupleVariationStoreInputError::InconsistentAxisCount(
230 self.gid,
231 ));
232 }
233 if let Some((start, end)) = var.intermediate_region.as_ref() {
234 if start.len() != axis_count || end.len() != axis_count {
235 return Err(TupleVariationStoreInputError::InconsistentTupleLengths(
236 self.gid,
237 ));
238 }
239 }
240 if var.deltas.len() != delta_len {
241 return Err(TupleVariationStoreInputError::InconsistentDeltaLength(
242 self.gid,
243 ));
244 }
245 }
246 Ok(())
247 }
248
249 pub fn axis_count(&self) -> Option<u16> {
251 self.variations.first().map(|var| var.peak_tuple.len())
252 }
253
254 fn count_peak_tuples<'a>(&'a self, counter: &mut IndexMap<&'a Tuple, usize>) {
255 for tuple in &self.variations {
256 *counter.entry(&tuple.peak_tuple).or_default() += 1;
257 }
258 }
259
260 fn build(self, shared_tuple_map: &HashMap<&Tuple, u16>) -> GlyphVariationData {
261 let shared_points = compute_shared_points(&self.variations);
262
263 let (tuple_headers, tuple_data): (Vec<_>, Vec<_>) = self
264 .variations
265 .into_iter()
266 .map(|tup| tup.build(shared_tuple_map, shared_points.as_ref()))
267 .unzip();
268
269 let mut temp = GlyphVariationData {
270 tuple_variation_headers: tuple_headers,
271 shared_point_numbers: shared_points,
272 per_tuple_data: tuple_data,
273 length: 0,
274 };
275
276 temp.length = temp.compute_size();
277 temp
278 }
279}
280
281impl GlyphDelta {
282 pub fn new(x: i16, y: i16, required: bool) -> Self {
284 Self { x, y, required }
285 }
286
287 pub fn required(x: i16, y: i16) -> Self {
289 Self::new(x, y, true)
290 }
291
292 pub fn optional(x: i16, y: i16) -> Self {
294 Self::new(x, y, false)
295 }
296}
297
298impl GlyphDeltas {
299 pub fn new(tents: Vec<Tent>, deltas: Vec<GlyphDelta>) -> Self {
304 let peak_tuple = Tuple::new(tents.iter().map(Tent::peak).collect());
305
306 let intermediate_region = if tents.iter().any(Tent::requires_intermediate) {
310 Some(tents.iter().map(Tent::bounds).unzip())
311 } else {
312 None
313 };
314
315 let best_point_packing = Self::pick_best_point_number_repr(&deltas);
320 GlyphDeltas {
321 peak_tuple,
322 intermediate_region,
323 deltas,
324 best_point_packing,
325 }
326 }
327
328 fn pick_best_point_number_repr(deltas: &[GlyphDelta]) -> PackedPointNumbers {
335 if deltas.iter().all(|d| d.required) {
336 return PackedPointNumbers::All;
337 }
338
339 let dense = Self::build_non_sparse_data(deltas);
340 let sparse = Self::build_sparse_data(deltas);
341 let dense_size = dense.compute_size();
342 let sparse_size = sparse.compute_size();
343 log::trace!("dense {dense_size}, sparse {sparse_size}");
344 if sparse_size < dense_size {
345 sparse.private_point_numbers.unwrap()
346 } else {
347 PackedPointNumbers::All
348 }
349 }
350
351 fn build_non_sparse_data(deltas: &[GlyphDelta]) -> GlyphTupleVariationData {
352 let (x_deltas, y_deltas) = deltas
353 .iter()
354 .map(|delta| (delta.x as i32, delta.y as i32))
355 .unzip();
356 GlyphTupleVariationData {
357 private_point_numbers: Some(PackedPointNumbers::All),
358 x_deltas: PackedDeltas::new(x_deltas),
359 y_deltas: PackedDeltas::new(y_deltas),
360 }
361 }
362
363 fn build_sparse_data(deltas: &[GlyphDelta]) -> GlyphTupleVariationData {
364 let (x_deltas, y_deltas) = deltas
365 .iter()
366 .filter_map(|delta| delta.required.then_some((delta.x as i32, delta.y as i32)))
367 .unzip();
368 let point_numbers = deltas
369 .iter()
370 .enumerate()
371 .filter_map(|(i, delta)| delta.required.then_some(i as u16))
372 .collect();
373 GlyphTupleVariationData {
374 private_point_numbers: Some(PackedPointNumbers::Some(point_numbers)),
375 x_deltas: PackedDeltas::new(x_deltas),
376 y_deltas: PackedDeltas::new(y_deltas),
377 }
378 }
379
380 fn build(
384 self,
385 shared_tuple_map: &HashMap<&Tuple, u16>,
386 shared_points: Option<&PackedPointNumbers>,
387 ) -> (TupleVariationHeader, GlyphTupleVariationData) {
388 let GlyphDeltas {
389 peak_tuple,
390 intermediate_region,
391 deltas,
392 best_point_packing: point_numbers,
393 } = self;
394
395 let (idx, peak_tuple) = match shared_tuple_map.get(&peak_tuple) {
396 Some(idx) => (Some(*idx), None),
397 None => (None, Some(peak_tuple)),
398 };
399
400 let has_private_points = Some(&point_numbers) != shared_points;
401 let (x_deltas, y_deltas) = match &point_numbers {
402 PackedPointNumbers::All => deltas.iter().map(|d| (d.x as i32, d.y as i32)).unzip(),
403 PackedPointNumbers::Some(pts) => pts
404 .iter()
405 .map(|idx| {
406 let delta = deltas[*idx as usize];
407 (delta.x as i32, delta.y as i32)
408 })
409 .unzip(),
410 };
411
412 let data = GlyphTupleVariationData {
413 private_point_numbers: has_private_points.then_some(point_numbers),
414 x_deltas: PackedDeltas::new(x_deltas),
415 y_deltas: PackedDeltas::new(y_deltas),
416 };
417 let data_size = data.compute_size();
418
419 let header = TupleVariationHeader::new(
420 data_size,
421 idx,
422 peak_tuple,
423 intermediate_region,
424 has_private_points,
425 );
426
427 (header, data)
428 }
429}
430
431#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
433#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
434pub struct GlyphVariationData {
435 tuple_variation_headers: Vec<TupleVariationHeader>,
436 shared_point_numbers: Option<PackedPointNumbers>,
438 per_tuple_data: Vec<GlyphTupleVariationData>,
439 length: u32,
444}
445
446#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
448#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
449struct GlyphTupleVariationData {
450 private_point_numbers: Option<PackedPointNumbers>,
452 x_deltas: PackedDeltas,
453 y_deltas: PackedDeltas,
454}
455
456impl GlyphTupleVariationData {
457 fn compute_size(&self) -> u16 {
458 self.private_point_numbers
459 .as_ref()
460 .map(PackedPointNumbers::compute_size)
461 .unwrap_or_default()
462 .checked_add(self.x_deltas.compute_size())
463 .unwrap()
464 .checked_add(self.y_deltas.compute_size())
465 .unwrap()
466 }
467}
468
469impl FontWrite for GlyphTupleVariationData {
470 fn write_into(&self, writer: &mut TableWriter) {
471 self.private_point_numbers.write_into(writer);
472 self.x_deltas.write_into(writer);
473 self.y_deltas.write_into(writer);
474 }
475}
476
477struct GlyphDataWriter<'a> {
478 long_offsets: bool,
479 extended: bool,
480 shared_tuples: &'a SharedTuples,
481 data: &'a [GlyphVariationData],
482}
483
484impl FontWrite for GlyphDataWriter<'_> {
485 fn write_into(&self, writer: &mut TableWriter) {
486 if self.long_offsets {
487 let mut last = 0u32;
488 last.write_into(writer);
489
490 for glyph in self.data {
492 last += glyph.length_for_format(self.extended);
493 last.write_into(writer);
494 }
495 } else {
496 let mut last = 0u16;
499 last.write_into(writer);
500
501 for glyph in self.data {
503 let size = glyph.length_for_format(self.extended);
504 let short_size = (size / 2) + size % 2;
506 last += short_size as u16;
507 last.write_into(writer);
508 }
509 }
510 self.shared_tuples.write_into(writer);
514 for glyph in self.data {
516 if !glyph.is_empty() {
517 glyph.write_with_format(writer, self.extended);
518 if !self.long_offsets && glyph.length_for_format(self.extended) % 2 != 0 {
521 writer.write_slice(&[0]);
522 }
523 }
524 }
525 }
526}
527
528impl GlyphVariationData {
529 fn compute_tuple_variation_count(&self) -> TupleVariationCount {
530 compute_tuple_variation_count(
531 self.tuple_variation_headers.len(),
532 self.shared_point_numbers.is_some(),
533 )
534 }
535
536 fn is_empty(&self) -> bool {
537 self.tuple_variation_headers.is_empty()
538 }
539
540 fn compute_data_offset(&self, extended: bool) -> u32 {
541 compute_tuple_variation_data_offset(
542 &self.tuple_variation_headers,
543 TupleVariationCount::RAW_BYTE_LEN + if extended { 3 } else { 2 },
544 )
545 }
546
547 fn compute_size(&self) -> u32 {
548 if self.is_empty() {
549 return 0;
550 }
551
552 let data_start = self.compute_data_offset(false);
553 let shared_point_len = self
554 .shared_point_numbers
555 .as_ref()
556 .map(|pts| pts.compute_size())
557 .unwrap_or_default() as u32;
558 let tuple_data_len = self
559 .per_tuple_data
560 .iter()
561 .fold(0u32, |acc, tup| acc + tup.compute_size() as u32);
562 data_start + shared_point_len + tuple_data_len
563 }
564
565 fn length_for_format(&self, extended: bool) -> u32 {
566 self.length + u32::from(extended && !self.is_empty())
567 }
568
569 fn validate_for_format(&self, ctx: &mut ValidationCtx, extended: bool) {
570 const MAX_TUPLE_VARIATIONS: usize = 4095;
571 if !(0..=MAX_TUPLE_VARIATIONS).contains(&self.tuple_variation_headers.len()) {
572 ctx.in_field("tuple_variation_headers", |ctx| {
573 ctx.report("expected 0-4095 tuple variation tables")
574 });
575 }
576 self.tuple_variation_headers.validate_impl(ctx);
577 let max_offset = if extended {
578 Uint24::MAX.to_u32()
579 } else {
580 u16::MAX as u32
581 };
582 if self.compute_data_offset(extended) > max_offset {
583 ctx.report("glyph variation data offset overflows");
584 }
585 }
586
587 fn write_with_format(&self, writer: &mut TableWriter, extended: bool) {
588 self.compute_tuple_variation_count().write_into(writer);
589 let offset = self.compute_data_offset(extended);
590 if extended {
591 Uint24::new(offset).write_into(writer);
592 } else {
593 (offset as u16).write_into(writer);
594 }
595 self.tuple_variation_headers.write_into(writer);
596 self.shared_point_numbers.write_into(writer);
597 self.per_tuple_data.write_into(writer);
598 }
599}
600
601impl Extend<F2Dot14> for Tuple {
602 fn extend<T: IntoIterator<Item = F2Dot14>>(&mut self, iter: T) {
603 self.values.extend(iter);
604 }
605}
606
607impl Validate for GlyphVariationData {
608 fn validate_impl(&self, ctx: &mut ValidationCtx) {
609 self.validate_for_format(ctx, false);
610 }
611}
612
613impl FontWrite for GlyphVariationData {
614 fn write_into(&self, writer: &mut TableWriter) {
615 self.write_with_format(writer, false);
616 }
617}
618
619impl HasLen for SharedTuples {
620 fn len(&self) -> usize {
621 self.tuples.len()
622 }
623}
624
625impl FontWrite for TupleVariationCount {
626 fn write_into(&self, writer: &mut TableWriter) {
627 self.bits().write_into(writer)
628 }
629}
630#[cfg(test)]
631mod tests {
632 use super::*;
633
634 #[test]
635 fn extended_gvar_roundtrip_short_and_long_offsets() {
636 for long_offsets in [false, true] {
637 let point_count = if long_offsets { 14000 } else { 4 };
638 let mut variations: Vec<_> = (0..65537)
639 .map(|gid| GlyphVariations::new(GlyphId::new(gid), vec![]))
640 .collect();
641 for gid in [0, 1, 65536] {
642 variations[gid] = GlyphVariations::new(
643 GlyphId::new(gid as u32),
644 vec![GlyphDeltas::new(
645 peaks(vec![F2Dot14::ONE]),
646 vec![GlyphDelta::required(300, -200); point_count],
647 )],
648 );
649 }
650 let table = GvarExtended::new(variations.clone(), 1).unwrap();
651 let bytes = crate::dump_table(&table).unwrap();
652 let read =
653 read_fonts::tables::gvar::GvarExtended::read(bytes.as_slice().into()).unwrap();
654 assert_eq!(read.glyph_count().to_u32(), 65537);
655 assert_eq!(read.flags().contains(GvarFlags::LONG_OFFSETS), long_offsets);
656 assert_eq!(read.glyph_variation_data_array_offset() % 2, 1);
657 for gid in [0, 1, 65536] {
658 let var = read
659 .glyph_variation_data(GlyphId::new(gid))
660 .unwrap()
661 .unwrap();
662 let tuples: Vec<_> = var.tuples().collect();
663 assert_eq!(tuples.len(), 1);
664 let deltas: Vec<_> = tuples[0].deltas().map(|d| (d.x_delta, d.y_delta)).collect();
665 assert_eq!(deltas, vec![(300, -200); point_count]);
666 }
667 assert!(read
668 .glyph_variation_data(GlyphId::new(2))
669 .unwrap()
670 .is_none());
671 let legacy = Gvar::new(variations, 1).unwrap();
672 assert!(crate::dump_table(&legacy).is_err());
673 }
674 }
675
676 #[test]
677 fn extended_gvar_data_offset_above_64k() {
678 let mut delta = GlyphDeltas::new(
679 peaks(vec![F2Dot14::ONE; 20]),
680 vec![GlyphDelta::required(1, 0)],
681 );
682 delta.intermediate_region = Some((
683 Tuple::new(vec![F2Dot14::ZERO; 20]),
684 Tuple::new(vec![F2Dot14::ONE; 20]),
685 ));
686 let variations = vec![GlyphVariations::new(GlyphId::new(0), vec![delta; 1000])];
687 let legacy = Gvar::new(variations.clone(), 20).unwrap();
688 assert!(crate::dump_table(&legacy).is_err());
689 let table = GvarExtended::new(variations, 20).unwrap();
690 let bytes = crate::dump_table(&table).unwrap();
691 let read = read_fonts::tables::gvar::GvarExtended::read(bytes.as_slice().into()).unwrap();
692 let raw = read.data_for_gid(GlyphId::new(0)).unwrap().unwrap();
693 let header = read_fonts::tables::gvar::GlyphVariationDataHeaderExtended::read(raw).unwrap();
694 assert!(header.serialized_data_offset().to_u32() > u16::MAX as u32);
695 let data = read.glyph_variation_data(GlyphId::new(0)).unwrap().unwrap();
696 assert_eq!(data.tuples().count(), 1000);
697 assert_eq!(data.active_tuples_at(&[F2Dot14::ONE; 20]).count(), 1000);
698 }
699
700 fn peaks(peaks: Vec<F2Dot14>) -> Vec<Tent> {
702 peaks
703 .into_iter()
704 .map(|peak| Tent::new(peak, None))
705 .collect()
706 }
707
708 #[test]
709 fn gvar_smoke_test() {
710 let _ = env_logger::builder().is_test(true).try_init();
711 let table = Gvar::new(
712 vec![
713 GlyphVariations::new(GlyphId::new(0), vec![]),
714 GlyphVariations::new(
715 GlyphId::new(1),
716 vec![GlyphDeltas::new(
717 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
718 vec![
719 GlyphDelta::required(30, 31),
720 GlyphDelta::required(40, 41),
721 GlyphDelta::required(-50, -49),
722 GlyphDelta::required(101, 102),
723 GlyphDelta::required(10, 11),
724 ],
725 )],
726 ),
727 GlyphVariations::new(
728 GlyphId::new(2),
729 vec![
730 GlyphDeltas::new(
731 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
732 vec![
733 GlyphDelta::required(11, -20),
734 GlyphDelta::required(69, -41),
735 GlyphDelta::required(-69, 49),
736 GlyphDelta::required(168, 101),
737 GlyphDelta::required(1, 2),
738 ],
739 ),
740 GlyphDeltas::new(
741 peaks(vec![F2Dot14::from_f32(0.8), F2Dot14::from_f32(1.0)]),
742 vec![
743 GlyphDelta::required(3, -200),
744 GlyphDelta::required(4, -500),
745 GlyphDelta::required(5, -800),
746 GlyphDelta::required(6, -1200),
747 GlyphDelta::required(7, -1500),
748 ],
749 ),
750 ],
751 ),
752 ],
753 2,
754 )
755 .unwrap();
756
757 let g2 = &table.glyph_variation_data_offsets[1];
758 let computed = g2.compute_size();
759 let actual = crate::dump_table(g2).unwrap().len();
760 assert_eq!(computed as usize, actual);
761
762 let bytes = crate::dump_table(&table).unwrap();
763 let gvar = read_fonts::tables::gvar::Gvar::read(FontData::new(&bytes)).unwrap();
764 assert_eq!(gvar.version(), MajorMinor::VERSION_1_0);
765 assert_eq!(gvar.shared_tuple_count(), 1);
766 assert_eq!(gvar.glyph_count(), 3);
767 assert_eq!(gvar.shared_tuples_offset(), Offset32::new(28));
769 assert_eq!(gvar.glyph_variation_data_array_offset(), 32);
770
771 let g1 = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
772 let g1tup = g1.tuples().collect::<Vec<_>>();
773 assert_eq!(g1tup.len(), 1);
774
775 let (x, y): (Vec<_>, Vec<_>) = g1tup[0].deltas().map(|d| (d.x_delta, d.y_delta)).unzip();
776 assert_eq!(x, vec![30, 40, -50, 101, 10]);
777 assert_eq!(y, vec![31, 41, -49, 102, 11]);
778
779 let g2 = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
780 let g2tup = g2.tuples().collect::<Vec<_>>();
781 assert_eq!(g2tup.len(), 2);
782
783 let (x, y): (Vec<_>, Vec<_>) = g2tup[0].deltas().map(|d| (d.x_delta, d.y_delta)).unzip();
784 assert_eq!(x, vec![11, 69, -69, 168, 1]);
785 assert_eq!(y, vec![-20, -41, 49, 101, 2]);
786
787 let (x, y): (Vec<_>, Vec<_>) = g2tup[1].deltas().map(|d| (d.x_delta, d.y_delta)).unzip();
788
789 assert_eq!(x, vec![3, 4, 5, 6, 7]);
790 assert_eq!(y, vec![-200, -500, -800, -1200, -1500]);
791 }
792
793 #[test]
794 fn use_iup_when_appropriate() {
795 let _ = env_logger::builder().is_test(true).try_init();
797 let gid = GlyphId::new(0);
798 let table = Gvar::new(
799 vec![GlyphVariations::new(
800 gid,
801 vec![GlyphDeltas::new(
802 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
803 vec![
804 GlyphDelta::required(30, 31),
805 GlyphDelta::optional(30, 31),
806 GlyphDelta::optional(30, 31),
807 GlyphDelta::required(101, 102),
808 GlyphDelta::required(10, 11),
809 GlyphDelta::optional(10, 11),
810 ],
811 )],
812 )],
813 2,
814 )
815 .unwrap();
816
817 let bytes = crate::dump_table(&table).unwrap();
818 let gvar = read_fonts::tables::gvar::Gvar::read(FontData::new(&bytes)).unwrap();
819 assert_eq!(gvar.version(), MajorMinor::VERSION_1_0);
820 assert_eq!(gvar.shared_tuple_count(), 0);
821 assert_eq!(gvar.glyph_count(), 1);
822
823 let g1 = gvar.glyph_variation_data(gid).unwrap().unwrap();
824 let g1tup = g1.tuples().collect::<Vec<_>>();
825 assert_eq!(g1tup.len(), 1);
826 let tuple_variation = &g1tup[0];
827
828 assert!(!tuple_variation.has_deltas_for_all_points());
829 assert_eq!(
830 vec![0, 3, 4],
831 tuple_variation.point_numbers().collect::<Vec<_>>()
832 );
833
834 let points: Vec<_> = tuple_variation
835 .deltas()
836 .map(|d| (d.x_delta, d.y_delta))
837 .collect();
838 assert_eq!(points, vec![(30, 31), (101, 102), (10, 11)]);
839 }
840
841 #[test]
842 fn disregard_iup_when_appropriate() {
843 let points = vec![
846 GlyphDelta::required(1, 2),
847 GlyphDelta::required(3, 4),
848 GlyphDelta::required(5, 6),
849 GlyphDelta::optional(5, 6),
850 GlyphDelta::required(7, 8),
851 ];
852 let gid = GlyphId::new(0);
853 let table = Gvar::new(
854 vec![GlyphVariations::new(
855 gid,
856 vec![GlyphDeltas::new(
857 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
858 points,
859 )],
860 )],
861 2,
862 )
863 .unwrap();
864 let bytes = crate::dump_table(&table).unwrap();
865 let gvar = read_fonts::tables::gvar::Gvar::read(FontData::new(&bytes)).unwrap();
866 assert_eq!(gvar.version(), MajorMinor::VERSION_1_0);
867 assert_eq!(gvar.shared_tuple_count(), 0);
868 assert_eq!(gvar.glyph_count(), 1);
869
870 let g1 = gvar.glyph_variation_data(gid).unwrap().unwrap();
871 let g1tup = g1.tuples().collect::<Vec<_>>();
872 assert_eq!(g1tup.len(), 1);
873 let tuple_variation = &g1tup[0];
874
875 assert!(tuple_variation.has_deltas_for_all_points());
876 let points: Vec<_> = tuple_variation
877 .deltas()
878 .map(|d| (d.x_delta, d.y_delta))
879 .collect();
880 assert_eq!(points, vec![(1, 2), (3, 4), (5, 6), (5, 6), (7, 8)]);
881 }
882
883 #[test]
884 fn share_points() {
885 let _ = env_logger::builder().is_test(true).try_init();
886 let variations = GlyphVariations::new(
887 GlyphId::new(0),
888 vec![
889 GlyphDeltas::new(
890 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
891 vec![
892 GlyphDelta::required(1, 2),
893 GlyphDelta::optional(3, 4),
894 GlyphDelta::required(5, 6),
895 GlyphDelta::optional(5, 6),
896 GlyphDelta::required(7, 8),
897 GlyphDelta::optional(7, 8),
898 ],
899 ),
900 GlyphDeltas::new(
901 peaks(vec![F2Dot14::from_f32(-1.0), F2Dot14::from_f32(-1.0)]),
902 vec![
903 GlyphDelta::required(10, 20),
904 GlyphDelta::optional(30, 40),
905 GlyphDelta::required(50, 60),
906 GlyphDelta::optional(50, 60),
907 GlyphDelta::required(70, 80),
908 GlyphDelta::optional(70, 80),
909 ],
910 ),
911 ],
912 );
913
914 assert_eq!(
915 compute_shared_points(&variations.variations),
916 Some(PackedPointNumbers::Some(vec![0, 2, 4]))
917 )
918 }
919
920 #[test]
921 fn share_all_points() {
922 let variations = GlyphVariations::new(
923 GlyphId::new(0),
924 vec![
925 GlyphDeltas::new(
926 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
927 vec![
928 GlyphDelta::required(1, 2),
929 GlyphDelta::required(3, 4),
930 GlyphDelta::required(5, 6),
931 ],
932 ),
933 GlyphDeltas::new(
934 peaks(vec![F2Dot14::from_f32(-1.0), F2Dot14::from_f32(-1.0)]),
935 vec![
936 GlyphDelta::required(2, 4),
937 GlyphDelta::required(6, 8),
938 GlyphDelta::required(7, 9),
939 ],
940 ),
941 ],
942 );
943
944 let shared_tups = HashMap::new();
945 let built = variations.build(&shared_tups);
946 assert_eq!(built.shared_point_numbers, Some(PackedPointNumbers::All))
947 }
948
949 #[test]
952 fn dont_share_unique_points() {
953 let variations = GlyphVariations::new(
954 GlyphId::new(0),
955 vec![
956 GlyphDeltas::new(
957 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
958 vec![
959 GlyphDelta::required(1, 2),
960 GlyphDelta::optional(3, 4),
961 GlyphDelta::required(5, 6),
962 GlyphDelta::optional(5, 6),
963 GlyphDelta::required(7, 8),
964 GlyphDelta::optional(7, 8),
965 ],
966 ),
967 GlyphDeltas::new(
968 peaks(vec![F2Dot14::from_f32(-1.0), F2Dot14::from_f32(-1.0)]),
969 vec![
970 GlyphDelta::required(10, 20),
971 GlyphDelta::required(35, 40),
972 GlyphDelta::required(50, 60),
973 GlyphDelta::optional(50, 60),
974 GlyphDelta::required(70, 80),
975 GlyphDelta::optional(70, 80),
976 ],
977 ),
978 GlyphDeltas::new(
979 peaks(vec![F2Dot14::from_f32(0.5), F2Dot14::from_f32(1.0)]),
980 vec![
981 GlyphDelta::required(1, 2),
982 GlyphDelta::optional(3, 4),
983 GlyphDelta::required(5, 6),
984 GlyphDelta::optional(5, 6),
985 GlyphDelta::optional(7, 8),
986 GlyphDelta::optional(7, 8),
987 ],
988 ),
989 ],
990 );
991
992 let shared_tups = HashMap::new();
993 let built = variations.build(&shared_tups);
994 assert!(built.shared_point_numbers.is_none());
995 }
996
997 #[test]
999 #[allow(non_snake_case)]
1000 fn oswald_Lcaron() {
1001 let _ = env_logger::builder().is_test(true).try_init();
1002 let variations = GlyphVariations::new(
1006 GlyphId::new(0),
1007 vec![
1008 GlyphDeltas::new(
1009 peaks(vec![F2Dot14::from_f32(-1.0), F2Dot14::from_f32(-1.0)]),
1010 vec![
1011 GlyphDelta::optional(0, 0),
1012 GlyphDelta::required(35, 0),
1013 GlyphDelta::optional(0, 0),
1014 GlyphDelta::required(-24, 0),
1015 GlyphDelta::optional(0, 0),
1016 GlyphDelta::optional(0, 0),
1017 ],
1018 ),
1019 GlyphDeltas::new(
1020 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
1021 vec![
1022 GlyphDelta::optional(0, 0),
1023 GlyphDelta::required(26, 15),
1024 GlyphDelta::optional(0, 0),
1025 GlyphDelta::required(46, 0),
1026 GlyphDelta::optional(0, 0),
1027 GlyphDelta::optional(0, 0),
1028 ],
1029 ),
1030 ],
1031 );
1032 assert!(compute_shared_points(&variations.variations).is_none());
1033 let tups = HashMap::new();
1034 let built = variations.build(&tups);
1035 assert_eq!(
1036 built.per_tuple_data[0].private_point_numbers,
1037 Some(PackedPointNumbers::All)
1038 );
1039 assert_eq!(
1040 built.per_tuple_data[1].private_point_numbers,
1041 Some(PackedPointNumbers::Some(vec![1, 3]))
1042 );
1043 }
1044
1045 #[test]
1046 fn compute_shared_points_is_deterministic() {
1047 let _ = env_logger::builder().is_test(true).try_init();
1055 let variations = GlyphVariations::new(
1056 GlyphId::NOTDEF,
1057 vec![
1058 GlyphDeltas::new(
1059 peaks(vec![
1060 F2Dot14::from_f32(-1.0),
1061 F2Dot14::from_f32(0.0),
1062 F2Dot14::from_f32(0.0),
1063 ]),
1064 vec![
1065 GlyphDelta::optional(0, 0),
1066 GlyphDelta::required(-17, -4),
1067 GlyphDelta::optional(0, 0),
1068 GlyphDelta::required(-28, 0),
1069 GlyphDelta::optional(0, 0),
1070 GlyphDelta::optional(0, 0),
1071 ],
1072 ),
1073 GlyphDeltas::new(
1074 peaks(vec![
1075 F2Dot14::from_f32(0.0),
1076 F2Dot14::from_f32(1.0),
1077 F2Dot14::from_f32(0.0),
1078 ]),
1079 vec![
1080 GlyphDelta::optional(0, 0),
1081 GlyphDelta::required(0, -10),
1082 GlyphDelta::optional(0, 0),
1083 GlyphDelta::required(34, 0),
1084 GlyphDelta::optional(0, 0),
1085 GlyphDelta::optional(0, 0),
1086 ],
1087 ),
1088 GlyphDeltas::new(
1089 peaks(vec![
1090 F2Dot14::from_f32(0.0),
1091 F2Dot14::from_f32(0.0),
1092 F2Dot14::from_f32(-1.0),
1093 ]),
1094 vec![
1095 GlyphDelta::required(0, 0),
1096 GlyphDelta::optional(0, 0),
1097 GlyphDelta::optional(0, 0),
1098 GlyphDelta::optional(0, 0),
1099 GlyphDelta::optional(0, 0),
1100 GlyphDelta::optional(0, 0),
1101 ],
1102 ),
1103 GlyphDeltas::new(
1104 peaks(vec![
1105 F2Dot14::from_f32(0.0),
1106 F2Dot14::from_f32(0.0),
1107 F2Dot14::from_f32(1.0),
1108 ]),
1109 vec![
1110 GlyphDelta::required(0, 0),
1111 GlyphDelta::optional(0, 0),
1112 GlyphDelta::optional(0, 0),
1113 GlyphDelta::optional(0, 0),
1114 GlyphDelta::optional(0, 0),
1115 GlyphDelta::optional(0, 0),
1116 ],
1117 ),
1118 GlyphDeltas::new(
1119 peaks(vec![
1120 F2Dot14::from_f32(-1.0),
1121 F2Dot14::from_f32(1.0),
1122 F2Dot14::from_f32(0.0),
1123 ]),
1124 vec![
1125 GlyphDelta::optional(0, 0),
1126 GlyphDelta::required(-1, 10),
1127 GlyphDelta::optional(0, 0),
1128 GlyphDelta::required(-9, 0),
1129 GlyphDelta::optional(0, 0),
1130 GlyphDelta::optional(0, 0),
1131 ],
1132 ),
1133 GlyphDeltas::new(
1134 peaks(vec![
1135 F2Dot14::from_f32(-1.0),
1136 F2Dot14::from_f32(0.0),
1137 F2Dot14::from_f32(-1.0),
1138 ]),
1139 vec![
1140 GlyphDelta::required(0, 0),
1141 GlyphDelta::optional(0, 0),
1142 GlyphDelta::optional(0, 0),
1143 GlyphDelta::optional(0, 0),
1144 GlyphDelta::optional(0, 0),
1145 GlyphDelta::optional(0, 0),
1146 ],
1147 ),
1148 GlyphDeltas::new(
1149 peaks(vec![
1150 F2Dot14::from_f32(-1.0),
1151 F2Dot14::from_f32(0.0),
1152 F2Dot14::from_f32(1.0),
1153 ]),
1154 vec![
1155 GlyphDelta::required(0, 0),
1156 GlyphDelta::optional(0, 0),
1157 GlyphDelta::optional(0, 0),
1158 GlyphDelta::optional(0, 0),
1159 GlyphDelta::optional(0, 0),
1160 GlyphDelta::optional(0, 0),
1161 ],
1162 ),
1163 ],
1164 );
1165
1166 assert_eq!(
1167 compute_shared_points(&variations.variations),
1168 Some(PackedPointNumbers::Some(vec![1, 3]))
1172 );
1173 }
1174
1175 fn make_31_bytes_of_variation_data() -> Vec<GlyphDeltas> {
1178 vec![
1179 GlyphDeltas::new(
1180 peaks(vec![F2Dot14::from_f32(-1.0), F2Dot14::from_f32(-1.0)]),
1181 vec![
1182 GlyphDelta::optional(0, 0),
1183 GlyphDelta::required(35, 0),
1184 GlyphDelta::optional(0, 0),
1185 GlyphDelta::required(-24, 0),
1186 GlyphDelta::optional(0, 0),
1187 GlyphDelta::optional(0, 0),
1188 ],
1189 ),
1190 GlyphDeltas::new(
1191 peaks(vec![F2Dot14::from_f32(1.0), F2Dot14::from_f32(1.0)]),
1192 vec![
1193 GlyphDelta::optional(0, 0),
1194 GlyphDelta::required(26, 15),
1195 GlyphDelta::optional(0, 0),
1196 GlyphDelta::required(46, 0),
1197 GlyphDelta::optional(0, 0),
1198 GlyphDelta::required(1, 0),
1199 ],
1200 ),
1201 ]
1202 }
1203
1204 #[test]
1206 fn who_tests_the_testers() {
1207 let variations = GlyphVariations::new(GlyphId::NOTDEF, make_31_bytes_of_variation_data());
1208 let mut tupl_map = HashMap::new();
1209
1210 assert_eq!(variations.clone().build(&tupl_map).length, 39);
1212
1213 tupl_map.insert(&variations.variations[0].peak_tuple, 1);
1215 tupl_map.insert(&variations.variations[1].peak_tuple, 2);
1216
1217 let built = variations.clone().build(&tupl_map);
1218 assert_eq!(built.length, 31);
1220 }
1221
1222 fn assert_test_offset_packing(n_glyphs: u16, should_be_short: bool) {
1223 let (offset_len, data_len, expected_flags) = if should_be_short {
1224 (u16::RAW_BYTE_LEN, 32, GvarFlags::empty())
1226 } else {
1227 (u32::RAW_BYTE_LEN, 31, GvarFlags::LONG_OFFSETS)
1228 };
1229
1230 let test_data = make_31_bytes_of_variation_data();
1231 let a_small_number_of_variations = (0..n_glyphs)
1232 .map(|i| GlyphVariations::new(GlyphId::from(i), test_data.clone()))
1233 .collect();
1234
1235 let gvar = Gvar::new(a_small_number_of_variations, 2).unwrap();
1236 assert_eq!(gvar.compute_flags(), expected_flags);
1237
1238 let writer = gvar.compile_variation_data();
1239 let mut sink = TableWriter::default();
1240 writer.write_into(&mut sink);
1241
1242 let bytes = sink.into_data().bytes;
1243 let expected_len = (n_glyphs + 1) as usize * offset_len + 8 + data_len * n_glyphs as usize; assert_eq!(bytes.len(), expected_len);
1247
1248 let dumped = crate::dump_table(&gvar).unwrap();
1249 let loaded = read_fonts::tables::gvar::Gvar::read(FontData::new(&dumped)).unwrap();
1250
1251 assert_eq!(loaded.glyph_count(), n_glyphs);
1252 assert_eq!(loaded.flags(), expected_flags);
1253 assert!(loaded
1254 .glyph_variation_data_offsets()
1255 .iter()
1256 .map(|off| off.unwrap().get())
1257 .enumerate()
1258 .all(|(i, off)| off as usize == i * data_len));
1259 }
1260
1261 #[test]
1262 fn prefer_short_offsets() {
1263 let _ = env_logger::builder().is_test(true).try_init();
1264 assert_test_offset_packing(5, true);
1265 }
1266
1267 #[test]
1268 fn use_long_offsets_when_necessary() {
1269 let _ = env_logger::builder().is_test(true).try_init();
1272 assert_test_offset_packing(4095, true);
1273 assert_test_offset_packing(4096, false);
1274 assert_test_offset_packing(4097, false);
1275 }
1276
1277 #[test]
1278 fn shared_tuples_stable_order() {
1279 let mut variations = Vec::new();
1282 for i in 0..2 {
1283 variations.push(GlyphVariations::new(
1284 GlyphId::new(i),
1285 vec![
1286 GlyphDeltas::new(
1287 peaks(vec![F2Dot14::from_f32(1.0)]),
1288 vec![GlyphDelta::required(10, 20)],
1289 ),
1290 GlyphDeltas::new(
1291 peaks(vec![F2Dot14::from_f32(-1.0)]),
1292 vec![GlyphDelta::required(-10, -20)],
1293 ),
1294 ],
1295 ))
1296 }
1297 for _ in 0..10 {
1298 let table = Gvar::new(variations.clone(), 1).unwrap();
1299 let bytes = crate::dump_table(&table).unwrap();
1300 let gvar = read_fonts::tables::gvar::Gvar::read(FontData::new(&bytes)).unwrap();
1301
1302 assert_eq!(gvar.shared_tuple_count(), 2);
1303 assert_eq!(
1304 gvar.shared_tuples()
1305 .unwrap()
1306 .tuples()
1307 .iter()
1308 .map(|t| t.unwrap().values.to_vec())
1309 .collect::<Vec<_>>(),
1310 vec![vec![F2Dot14::from_f32(1.0)], vec![F2Dot14::from_f32(-1.0)]]
1311 );
1312 }
1313 }
1314
1315 #[test]
1316 fn unexpected_axis_count() {
1317 let variations = GlyphVariations::new(
1318 GlyphId::NOTDEF,
1319 vec![
1320 GlyphDeltas::new(
1321 peaks(vec![F2Dot14::from_f32(1.0)]),
1322 vec![GlyphDelta::required(1, 2)],
1323 ),
1324 GlyphDeltas::new(
1325 peaks(vec![F2Dot14::from_f32(1.0)]),
1326 vec![GlyphDelta::required(1, 2)],
1327 ),
1328 ],
1329 );
1330 let gvar = Gvar::new(vec![variations], 2);
1331 assert!(matches!(
1332 gvar,
1333 Err(TupleVariationStoreInputError::UnexpectedAxisCount {
1334 index: GlyphId::NOTDEF,
1335 expected: 2,
1336 actual: 1
1337 })
1338 ));
1339 }
1340
1341 #[test]
1342 fn empty_gvar_has_expected_axis_count() {
1343 let variations = GlyphVariations::new(GlyphId::NOTDEF, vec![]);
1344 let gvar = Gvar::new(vec![variations], 2).unwrap();
1345 assert_eq!(gvar.axis_count, 2);
1346 }
1347
1348 #[test]
1349 fn intermediates_only_when_explicit_needed() {
1352 let any_points = vec![]; let deltas = GlyphDeltas::new(
1356 vec![Tent::new(F2Dot14::from_f32(0.5), None)],
1357 any_points.clone(),
1358 );
1359 assert_eq!(deltas.intermediate_region, None);
1360
1361 let deltas = GlyphDeltas::new(
1364 vec![Tent::new(
1365 F2Dot14::from_f32(0.5),
1366 Some(Tent::implied_intermediates_for_peak(F2Dot14::from_f32(0.5))),
1367 )],
1368 any_points.clone(),
1369 );
1370 assert_eq!(deltas.intermediate_region, None);
1371
1372 let deltas = GlyphDeltas::new(
1375 vec![Tent::new(
1376 F2Dot14::from_f32(0.5),
1377 Some((F2Dot14::from_f32(-0.3), F2Dot14::from_f32(0.4))),
1378 )],
1379 any_points.clone(),
1380 );
1381 assert_eq!(
1382 deltas.intermediate_region,
1383 Some((
1384 Tuple::new(vec![F2Dot14::from_f32(-0.3)]),
1385 Tuple::new(vec![F2Dot14::from_f32(0.4)]),
1386 ))
1387 );
1388 }
1389
1390 #[test]
1391 fn intermediates_only_when_at_least_one_needed() {
1394 let any_points = vec![]; let deltas = GlyphDeltas::new(
1398 vec![
1399 Tent::new(F2Dot14::from_f32(0.5), None),
1400 Tent::new(F2Dot14::from_f32(0.5), None),
1401 ],
1402 any_points.clone(),
1403 );
1404 assert_eq!(deltas.intermediate_region, None);
1405
1406 let deltas = GlyphDeltas::new(
1408 vec![
1409 Tent::new(F2Dot14::from_f32(0.5), None),
1410 Tent::new(F2Dot14::from_f32(0.5), None),
1411 Tent::new(
1412 F2Dot14::from_f32(0.5),
1413 Some((F2Dot14::from_f32(-0.3), F2Dot14::from_f32(0.4))),
1414 ),
1415 ],
1416 any_points,
1417 );
1418 assert_eq!(
1419 deltas.intermediate_region,
1420 Some((
1421 Tuple::new(vec![
1422 F2Dot14::from_f32(0.0),
1423 F2Dot14::from_f32(0.0),
1424 F2Dot14::from_f32(-0.3)
1425 ]),
1426 Tuple::new(vec![
1427 F2Dot14::from_f32(0.5),
1428 F2Dot14::from_f32(0.5),
1429 F2Dot14::from_f32(0.4)
1430 ]),
1431 ))
1432 );
1433 }
1434}