1include!("../../generated/generated_variations.rs");
4
5pub use read_fonts::tables::variations::{DeltaRunType, TupleIndex, TupleVariationCount};
6
7pub mod ivs_builder;
8
9impl TupleVariationHeader {
10 pub fn new(
11 variation_data_size: u16,
12 shared_tuple_idx: Option<u16>,
13 peak_tuple: Option<Tuple>,
14 intermediate_region: Option<(Tuple, Tuple)>,
15 has_private_points: bool,
16 ) -> Self {
17 assert!(
18 shared_tuple_idx.is_some() != peak_tuple.is_some(),
19 "one and only one of peak_tuple or shared_tuple_idx must be present"
20 );
21 let mut idx = shared_tuple_idx.unwrap_or_default();
22 if peak_tuple.is_some() {
23 idx |= TupleIndex::EMBEDDED_PEAK_TUPLE;
24 }
25 if intermediate_region.is_some() {
26 idx |= TupleIndex::INTERMEDIATE_REGION;
27 }
28 if has_private_points {
29 idx |= TupleIndex::PRIVATE_POINT_NUMBERS;
30 }
31 let (intermediate_start_tuple, intermediate_end_tuple) = intermediate_region
32 .map(|(start, end)| (start.values, end.values))
33 .unwrap_or_default();
34
35 TupleVariationHeader {
36 variation_data_size,
37 tuple_index: TupleIndex::from_bits(idx),
38 peak_tuple: peak_tuple.map(|tup| tup.values).unwrap_or_default(),
39 intermediate_start_tuple,
40 intermediate_end_tuple,
41 }
42 }
43
44 pub fn compute_size(&self) -> u16 {
46 let len: usize = 2 + 2 + self.peak_tuple.len() * F2Dot14::RAW_BYTE_LEN
48 + self.intermediate_start_tuple.len() * F2Dot14::RAW_BYTE_LEN
49 + self.intermediate_end_tuple.len() * F2Dot14::RAW_BYTE_LEN;
50 len.try_into().unwrap()
51 }
52}
53
54#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub enum PackedPointNumbers {
58 #[default]
60 All,
61 Some(Vec<u16>),
63}
64
65#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
67#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
68pub struct PackedDeltas {
69 deltas: Vec<i32>,
70}
71
72impl Validate for PackedDeltas {
73 fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
74}
75
76impl FontWrite for PackedDeltas {
77 fn write_into(&self, writer: &mut TableWriter) {
78 for run in self.iter_runs() {
79 run.write_into(writer)
80 }
81 }
82}
83
84impl PackedDeltas {
85 pub fn new(deltas: Vec<i32>) -> Self {
87 Self { deltas }
88 }
89
90 pub(crate) fn compute_size(&self) -> u16 {
92 self.iter_runs().fold(0u16, |acc, run| {
93 acc.checked_add(run.compute_size()).unwrap()
94 })
95 }
96
97 fn iter_runs(&self) -> impl Iterator<Item = PackedDeltaRun<'_>> {
98 const MAX_POINTS_PER_RUN: usize = 64;
100
101 fn preferred_run_type(v: i32) -> DeltaRunType {
103 match v {
104 0 => DeltaRunType::Zero,
105 _ if v > i16::MAX as i32 || v < i16::MIN as i32 => DeltaRunType::I32,
106 _ if v > i8::MAX as i32 || v < i8::MIN as i32 => DeltaRunType::I16,
107 _ => DeltaRunType::I8,
108 }
109 }
110
111 fn count_leading_zeros(slice: &[i32]) -> u8 {
112 slice
113 .iter()
114 .take(MAX_POINTS_PER_RUN)
115 .take_while(|v| **v == 0)
116 .count() as u8
117 }
118
119 fn next_run_len(slice: &[i32]) -> (usize, DeltaRunType) {
121 let first = *slice.first().expect("bounds checked before here");
122 debug_assert!(first != 0, "Zeroes are supposed to be handled separately");
123 let run_type = preferred_run_type(first);
124
125 let mut idx = 1;
126 while idx < MAX_POINTS_PER_RUN && idx < slice.len() {
127 let cur = slice[idx];
128 let cur_type = preferred_run_type(cur);
129 let next_type = slice.get(idx + 1).copied().map(preferred_run_type);
130
131 if run_type == DeltaRunType::I8 {
133 match cur_type {
137 DeltaRunType::Zero if next_type == Some(DeltaRunType::Zero) => break,
138 DeltaRunType::I16 | DeltaRunType::I32 => break,
139 _ => (),
140 }
141 } else if run_type == DeltaRunType::I16 {
142 match (cur_type, next_type) {
145 (DeltaRunType::Zero | DeltaRunType::I32, _) => break,
146 (DeltaRunType::I8, Some(DeltaRunType::Zero | DeltaRunType::I8)) => break,
150 _ => (),
151 }
152 } else if run_type == DeltaRunType::I32 && cur_type != DeltaRunType::I32 {
153 break;
154 }
155
156 idx += 1;
157 }
158 (idx, run_type)
159 }
160
161 let mut deltas = self.deltas.as_slice();
162
163 std::iter::from_fn(move || {
164 let run_start = *deltas.first()?;
165 if run_start == 0 {
166 let n_zeros = count_leading_zeros(deltas);
167 deltas = &deltas[n_zeros as usize..];
168 Some(PackedDeltaRun::Zeros(n_zeros))
169 } else {
170 let (len, value_type) = next_run_len(deltas);
171 let (head, tail) = deltas.split_at(len);
172 deltas = tail;
173 Some(match value_type {
174 DeltaRunType::I32 => PackedDeltaRun::FourBytes(head),
175 DeltaRunType::I16 => PackedDeltaRun::TwoBytes(head),
176 DeltaRunType::I8 => PackedDeltaRun::OneByte(head),
177 _ => {
178 unreachable!("We should have taken the other branch for first={run_start}")
179 }
180 })
181 }
182 })
183 }
184}
185
186#[derive(Clone, Debug, PartialEq, Eq)]
187enum PackedDeltaRun<'a> {
188 Zeros(u8),
189 OneByte(&'a [i32]),
190 TwoBytes(&'a [i32]),
191 FourBytes(&'a [i32]),
192}
193
194impl PackedDeltaRun<'_> {
195 fn compute_flag(&self) -> u8 {
196 const DELTAS_ARE_ZERO: u8 = 0x80;
199 const DELTAS_ARE_WORDS: u8 = 0x40;
201
202 match self {
203 PackedDeltaRun::Zeros(count) => (count - 1) | DELTAS_ARE_ZERO,
204 PackedDeltaRun::OneByte(deltas) => deltas.len() as u8 - 1,
205 PackedDeltaRun::TwoBytes(deltas) => (deltas.len() as u8 - 1) | DELTAS_ARE_WORDS,
206 PackedDeltaRun::FourBytes(deltas) => {
207 (deltas.len() as u8 - 1) | DELTAS_ARE_WORDS | DELTAS_ARE_ZERO
208 }
209 }
210 }
211
212 fn compute_size(&self) -> u16 {
213 match self {
214 PackedDeltaRun::Zeros(_) => 1,
215 PackedDeltaRun::OneByte(vals) => vals.len() as u16 + 1,
216 PackedDeltaRun::TwoBytes(vals) => vals.len() as u16 * 2 + 1,
217 PackedDeltaRun::FourBytes(vals) => vals.len() as u16 * 4 + 1,
218 }
219 }
220}
221
222impl FontWrite for PackedDeltaRun<'_> {
223 fn write_into(&self, writer: &mut TableWriter) {
224 self.compute_flag().write_into(writer);
225 match self {
226 PackedDeltaRun::Zeros(_) => (),
227 PackedDeltaRun::OneByte(deltas) => {
228 deltas.iter().for_each(|v| (*v as i8).write_into(writer))
229 }
230 PackedDeltaRun::TwoBytes(deltas) => {
231 deltas.iter().for_each(|v| (*v as i16).write_into(writer))
232 }
233 PackedDeltaRun::FourBytes(deltas) => deltas.iter().for_each(|v| v.write_into(writer)),
234 }
235 }
236}
237
238impl crate::validate::Validate for PackedPointNumbers {
239 fn validate_impl(&self, ctx: &mut ValidationCtx) {
240 if let PackedPointNumbers::Some(pts) = self {
241 if pts.len() > 0x7FFF {
242 ctx.report("length cannot be stored in 15 bites");
243 }
244 }
245 }
246}
247
248impl FontWrite for PackedPointNumbers {
249 fn write_into(&self, writer: &mut TableWriter) {
250 match self.as_slice().len() {
252 len @ 0..=127 => (len as u8).write_into(writer),
253 len => (len as u16 | 0x8000u16).write_into(writer),
254 }
255 for run in self.iter_runs() {
256 run.write_into(writer);
257 }
258 }
259}
260
261impl PackedPointNumbers {
262 pub(crate) fn compute_size(&self) -> u16 {
264 let mut count = match self {
265 PackedPointNumbers::All => return 1,
266 PackedPointNumbers::Some(pts) if pts.len() < 128 => 1u16,
267 PackedPointNumbers::Some(_) => 2,
268 };
269 for run in self.iter_runs() {
270 count = count.checked_add(run.compute_size()).unwrap();
271 }
272 count
273 }
274
275 fn as_slice(&self) -> &[u16] {
276 match self {
277 PackedPointNumbers::All => &[],
278 PackedPointNumbers::Some(pts) => pts.as_slice(),
279 }
280 }
281
282 fn iter_runs(&self) -> impl Iterator<Item = PackedPointRun<'_>> {
283 const U8_MAX: u16 = u8::MAX as u16;
284 const MAX_POINTS_PER_RUN: usize = 128;
285
286 let mut points = match self {
287 PackedPointNumbers::Some(pts) => pts.as_slice(),
288 PackedPointNumbers::All => &[],
289 };
290
291 let mut prev_point = 0u16;
292
293 std::iter::from_fn(move || {
296 let next = points.first()?;
297 let are_words = (next - prev_point) > U8_MAX;
298 let run_len = points
299 .iter()
300 .take(MAX_POINTS_PER_RUN)
301 .scan(prev_point, |prev, point| {
302 let take_this = if are_words {
303 (point - *prev) > U8_MAX
304 } else {
305 (point - *prev) <= U8_MAX
306 };
307 *prev = *point;
308 take_this.then_some(point)
309 })
310 .count();
311
312 let (head, tail) = points.split_at(run_len);
313 points = tail;
314 let last_point = prev_point;
315 prev_point = head.last().copied().unwrap();
316
317 Some(PackedPointRun {
318 last_point,
319 are_words,
320 points: head,
321 })
322 })
323 }
324}
325
326#[derive(Debug, PartialEq, Eq)]
327struct PackedPointRun<'a> {
328 last_point: u16,
329 are_words: bool,
330 points: &'a [u16],
331}
332
333impl PackedPointRun<'_> {
334 fn compute_size(&self) -> u16 {
335 const LEN_BYTE: u16 = 1;
336 let per_point_len = if self.are_words { 2 } else { 1 };
337 self.points.len() as u16 * per_point_len + LEN_BYTE
338 }
339}
340
341impl FontWrite for PackedPointRun<'_> {
342 fn write_into(&self, writer: &mut TableWriter) {
343 assert!(!self.points.is_empty() && self.points.len() <= 128);
344 let mut len = self.points.len() as u8 - 1;
345 if self.are_words {
346 len |= 0x80;
347 }
348 len.write_into(writer);
349 let mut last_point = self.last_point;
350 for point in self.points {
351 let delta = point - last_point;
352 last_point = *point;
353 if self.are_words {
354 delta.write_into(writer);
355 } else {
356 debug_assert!(delta <= u8::MAX as u16);
357 (delta as u8).write_into(writer);
358 }
359 }
360 }
361}
362
363impl FontWrite for TupleIndex {
364 fn write_into(&self, writer: &mut TableWriter) {
365 self.bits().write_into(writer)
366 }
367}
368
369impl<'a> FromObjRef<Option<read_fonts::tables::variations::Tuple<'a>>> for Vec<F2Dot14> {
372 fn from_obj_ref(
373 from: &Option<read_fonts::tables::variations::Tuple<'a>>,
374 _data: FontData,
375 ) -> Self {
376 from.as_ref()
377 .map(|tup| tup.values.iter().map(BigEndian::get).collect())
378 .unwrap_or_default()
379 }
380}
381
382impl Tuple {
383 pub fn len(&self) -> u16 {
384 self.values.len().try_into().unwrap()
385 }
386
387 pub fn is_empty(&self) -> bool {
388 self.values.is_empty()
389 }
390}
391
392impl DeltaSetIndexMap {
393 fn get_entry_format(mapping: &[u32]) -> EntryFormat {
401 let ored = mapping.iter().fold(0, |acc, idx| acc | *idx);
402
403 let inner = (ored & 0xFFFF) as u16;
404 let inner_bits = (16 - inner.leading_zeros() as u8).max(1);
405 assert!(inner_bits <= 16);
406
407 let ored = (ored >> (16 - inner_bits)) | (ored & ((1 << inner_bits) - 1));
408 let entry_size = match ored {
409 0..=0xFF => 1,
410 0x100..=0xFFFF => 2,
411 0x10000..=0xFFFFFF => 3,
412 _ => 4,
413 };
414
415 EntryFormat::from_bits(((entry_size - 1) << 4) | (inner_bits - 1)).unwrap()
416 }
417
418 fn pack_map_data(mapping: &[u32]) -> (EntryFormat, Vec<u8>) {
427 let fmt = DeltaSetIndexMap::get_entry_format(mapping);
428 let inner_bits = fmt.bit_count();
429 let inner_mask = (1 << inner_bits as u32) - 1;
430 let outer_shift = 16 - inner_bits;
431 let entry_size = fmt.entry_size();
432 assert!((1..=4).contains(&entry_size));
433
434 let mut map_count = mapping.len();
437 while map_count > 1 && mapping[map_count - 1] == mapping[map_count - 2] {
438 map_count -= 1;
439 }
440
441 let mut map_data = Vec::with_capacity(map_count * entry_size as usize);
442 for idx in mapping.iter().take(map_count) {
443 let idx = ((idx & 0xFFFF0000) >> outer_shift) | (idx & inner_mask);
444 map_data.extend_from_slice(&idx.to_be_bytes()[4 - entry_size as usize..]);
446 }
447 assert_eq!(map_data.len(), map_count * entry_size as usize);
448 (fmt, map_data)
449 }
450}
451
452impl<I> FromIterator<I> for DeltaSetIndexMap
453where
454 I: Into<u32>,
455{
456 fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
458 let mapping: Vec<u32> = iter.into_iter().map(|v| v.into()).collect();
459 let (fmt, map_data) = DeltaSetIndexMap::pack_map_data(&mapping);
460 let map_count = map_data.len() / fmt.entry_size() as usize;
461 let delta_set_index_map: DeltaSetIndexMap = if map_count <= u16::MAX as usize {
462 DeltaSetIndexMap::format_0(fmt, map_count as u16, map_data)
463 } else {
464 DeltaSetIndexMap::format_1(fmt, map_count as u32, map_data)
465 };
466 delta_set_index_map
467 }
468}
469
470#[cfg(test)]
471mod tests {
472 use super::*;
473 use rstest::rstest;
474
475 #[test]
476 fn point_pack_words() {
477 let thing = PackedPointNumbers::Some(vec![1002, 2002, 8408, 12228]);
478
479 let runs = thing.iter_runs().collect::<Vec<_>>();
480 assert_eq!(runs.len(), 1);
481 assert!(runs[0].are_words);
482 assert_eq!(runs[0].last_point, 0);
483 assert_eq!(runs[0].points, &[1002, 2002, 8408, 12228]);
484 }
485
486 #[test]
487 fn serialize_packed_points() {
488 let thing = PackedPointNumbers::Some(vec![1002, 2002, 8408, 12228]);
489
490 let bytes = crate::dump_table(&thing).unwrap();
491 assert_eq!(thing.compute_size() as usize, bytes.len());
492 let (read, _) = read_fonts::tables::variations::PackedPointNumbers::split_off_front(
493 FontData::new(&bytes),
494 );
495 assert_eq!(thing.as_slice(), read.iter().collect::<Vec<_>>());
496 }
497
498 #[test]
499 fn point_pack_runs() {
500 let thing = PackedPointNumbers::Some(vec![5, 25, 225, 1002, 2002, 2008, 2228]);
501
502 let runs = thing.iter_runs().collect::<Vec<_>>();
503 assert!(!runs[0].are_words);
504 assert_eq!(runs[0].last_point, 0);
505 assert_eq!(runs[0].points, &[5, 25, 225]);
506
507 assert!(runs[1].are_words);
508 assert_eq!(runs[1].last_point, 225);
509 assert_eq!(runs[1].points, &[1002, 2002]);
510
511 assert!(!runs[2].are_words);
512 assert_eq!(runs[2].last_point, 2002);
513 assert_eq!(runs[2].points, &[2008, 2228]);
514
515 assert_eq!(runs.len(), 3);
516 }
517
518 #[test]
519 fn point_pack_long_runs() {
520 let mut numbers = vec![0u16; 130];
521 numbers.extend(1u16..=130u16);
522 let thing = PackedPointNumbers::Some(numbers);
523
524 let runs = thing.iter_runs().collect::<Vec<_>>();
525 assert!(!runs[0].are_words);
526 assert_eq!(runs[0].points.len(), 128);
527 assert_eq!(runs[1].last_point, 0);
528 assert_eq!(runs[1].points.len(), 128);
529 assert_eq!(runs[2].last_point, 126);
530 assert_eq!(runs[2].points, &[127, 128, 129, 130]);
531 assert!(runs.get(3).is_none());
532 }
533
534 #[test]
535 fn point_pack_write_one_byte() {
536 let thing = PackedPointNumbers::Some(vec![5, 25, 225, 1002, 2002, 2008, 2228, 10000]);
537
538 let bytes = crate::dump_table(&thing).unwrap();
539 assert_eq!(thing.compute_size() as usize, bytes.len());
540 let (read, _) = read_fonts::tables::variations::PackedPointNumbers::split_off_front(
541 FontData::new(&bytes),
542 );
543 assert_eq!(thing.as_slice(), read.iter().collect::<Vec<_>>());
544 }
545
546 #[test]
547 fn point_pack_write_two_byte() {
548 let thing = PackedPointNumbers::Some(vec![0; 200]);
549
550 let bytes = crate::dump_table(&thing).unwrap();
551 assert_eq!(thing.compute_size() as usize, bytes.len());
552 let (read, _) = read_fonts::tables::variations::PackedPointNumbers::split_off_front(
553 FontData::new(&bytes),
554 );
555 assert_eq!(thing.as_slice(), read.iter().collect::<Vec<_>>());
556 }
557
558 static PACKED_DELTA_BYTES: &[u8] = &[
559 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
560 ];
561
562 #[test]
564 fn packed_deltas_spec_runs() {
565 let deltas = PackedDeltas::new(vec![10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228]);
566 let runs = deltas.iter_runs().collect::<Vec<_>>();
567 assert_eq!(
568 runs,
569 vec![
570 PackedDeltaRun::OneByte(&[10, -105, 0, -58]),
571 PackedDeltaRun::Zeros(8),
572 PackedDeltaRun::TwoBytes(&[4130, -1228]),
573 ]
574 );
575 }
576
577 #[test]
578 fn packed_deltas_spec_write() {
579 let deltas = PackedDeltas::new(vec![10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228]);
580 let bytes = crate::dump_table(&deltas).unwrap();
581 assert_eq!(bytes, PACKED_DELTA_BYTES);
582 let read = read_fonts::tables::variations::PackedDeltas::consume_all(FontData::new(&bytes));
583 let decoded = read.iter().collect::<Vec<_>>();
584 assert_eq!(deltas.deltas.len(), decoded.len());
585 assert_eq!(deltas.deltas, decoded);
586 assert_eq!(bytes, PACKED_DELTA_BYTES);
587 }
588
589 #[test]
590 fn empty_deltas() {
591 let deltas = PackedDeltas::new(vec![]);
592 let bytes = crate::dump_table(&deltas).unwrap();
593 assert!(bytes.is_empty());
594 }
595
596 #[test]
597 fn lots_of_zero() {
598 let num_zeroes = 65;
599 let deltas = PackedDeltas::new(vec![0; num_zeroes]);
600 assert_eq!(
601 vec![PackedDeltaRun::Zeros(64), PackedDeltaRun::Zeros(1)],
602 deltas.iter_runs().collect::<Vec<_>>()
603 );
604 }
605
606 #[test]
607 fn respect_my_run_length_authority() {
608 let mut values = (1..196).collect::<Vec<_>>();
609 values.extend([0, 0, 0]);
610 values.push(i16::MAX as i32 + 1);
611 values.push(i16::MIN as i32 - 1);
612 values.push(i16::MAX as i32 * 2);
613 let deltas = PackedDeltas::new(values);
614 assert_eq!(
615 vec![
616 PackedDeltaRun::OneByte(&(1..65).collect::<Vec<i32>>()),
618 PackedDeltaRun::OneByte(&(65..128).collect::<Vec<i32>>()),
620 PackedDeltaRun::TwoBytes(&(128..192).collect::<Vec<i32>>()),
622 PackedDeltaRun::TwoBytes(&(192..=195).collect::<Vec<i32>>()),
624 PackedDeltaRun::Zeros(3),
625 PackedDeltaRun::FourBytes(&[
626 i16::MAX as i32 + 1,
627 i16::MIN as i32 - 1,
628 i16::MAX as i32 * 2
629 ]),
630 ],
631 deltas.iter_runs().collect::<Vec<_>>()
632 )
633 }
634
635 #[test]
636 fn inline_single_zeros_with_bytes() {
637 let packed = PackedDeltas::new(vec![1, 2, 0, 3]);
638 assert_eq!(packed.iter_runs().count(), 1)
639 }
640
641 #[test]
642 fn split_two_zeros_in_bytes() {
643 let packed = PackedDeltas::new(vec![1, 2, 0, 0, 3]);
644 assert_eq!(packed.iter_runs().count(), 3)
645 }
646
647 #[test]
648 fn split_single_zero_in_words() {
649 let packed = PackedDeltas::new(vec![150, 200, 0, -300]);
650 assert_eq!(packed.iter_runs().count(), 3)
651 }
652
653 #[test]
654 fn inline_single_byte_in_words() {
655 let packed = PackedDeltas::new(vec![150, 200, 1, -300]);
656 assert_eq!(packed.iter_runs().count(), 1)
657 }
658
659 #[test]
660 fn split_double_byte_in_words() {
661 let packed = PackedDeltas::new(vec![150, 200, 1, 3, -300]);
662 assert_eq!(packed.iter_runs().count(), 3)
663 }
664
665 #[test]
666 fn split_byte_then_zero_after_words() {
667 let packed = PackedDeltas::new(vec![150, 200, 1, 0, 1]);
670 assert_eq!(packed.iter_runs().count(), 2);
671 assert_eq!(packed.compute_size(), 9);
672 }
673
674 #[rstest]
675 #[case::one_byte_one_inner_bit(
678 vec![0, 1, 1], 0b00_0000, 1, 1, b"\x00\x01",
679 )]
680 #[case::one_byte_two_inner_bits(
681 vec![0, 1, 2], 0b00_0001, 1, 2, b"\x00\x01\x02",
682 )]
683 #[case::one_byte_three_inner_bits(
684 vec![0, 1, 4], 0b00_0010, 1, 3, b"\x00\x01\x04",
685 )]
686 #[case::one_byte_four_inner_bits(
687 vec![0, 1, 8], 0b00_0011, 1, 4, b"\x00\x01\x08",
688 )]
689 #[case::two_bytes_nine_inner_bits(
691 vec![0, 1, 256], 0b01_1000, 2, 9, b"\x00\x00\x00\x01\x01\x00",
692 )]
693 #[case::two_bytes_sixteen_inner_bits(
694 vec![0, 1, 0x8000], 0b01_1111, 2, 16, b"\x00\x00\x00\x01\x80\x00",
695 )]
696 #[case::one_byte_one_inner_bit_two_vardatas(
701 vec![0, 1, 0x01_0000], 0b00_0000, 1, 1, b"\x00\x01\x02",
702 )]
703 #[case::three_bytes_sixteen_inner_bits(
704 vec![0, 0xFFFF, 0x01_0000],
705 0b10_1111,
706 3,
707 16,
708 b"\x00\x00\x00\x00\xFF\xFF\x01\x00\x00",
709 )]
710 #[case::four_bytes_sixteen_inner_bits(
711 vec![0, 0xFFFF, 0xFFFF_FFFF],
712 0b11_1111,
713 4,
714 16,
715 b"\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
716 )]
717 #[test]
718 fn delta_set_index_map_entry_format_and_packed_data(
719 #[case] mapping: Vec<u32>,
720 #[case] expected_format_bits: u8,
721 #[case] expected_entry_size: u8,
722 #[case] expected_inner_bit_count: u8,
723 #[case] expected_map_data: &[u8],
724 ) {
725 let (format, data) = DeltaSetIndexMap::pack_map_data(&mapping);
726 assert_eq!(format.bits(), expected_format_bits);
727 assert_eq!(format.entry_size(), expected_entry_size);
728 assert_eq!(format.bit_count(), expected_inner_bit_count);
729 assert_eq!(data, expected_map_data);
730
731 let dsim: DeltaSetIndexMap = mapping.iter().copied().collect();
732 assert!(matches!(dsim, DeltaSetIndexMap::Format0 { .. }));
735
736 let raw_dsim = crate::dump_table(&dsim).unwrap();
738 let dsim2 =
739 read_fonts::tables::variations::DeltaSetIndexMap::read(FontData::new(&raw_dsim))
740 .unwrap();
741 assert_eq!(
742 (0..mapping.len())
743 .map(|i| {
744 let index = dsim2.get(i as u32).unwrap();
745 ((index.outer as u32) << 16) | index.inner as u32
746 })
747 .collect::<Vec<_>>(),
748 mapping
749 );
750 }
751
752 #[test]
753 fn delta_set_index_map_from_variation_index_iterator() {
754 use crate::tables::layout::VariationIndex;
756
757 let mapping = vec![
758 VariationIndex::new(0, 0),
759 VariationIndex::new(0, 1),
760 VariationIndex::new(0, 2),
761 VariationIndex::new(1, 0),
762 VariationIndex::new(1, 1),
763 VariationIndex::new(1, 2),
764 ];
765
766 let dsim: DeltaSetIndexMap = mapping.into_iter().collect();
767 let DeltaSetIndexMap::Format0(dsim) = dsim else {
768 panic!("expected DeltaSetIndexMap::Format0, got {:?}", dsim);
769 };
770 assert_eq!(dsim.map_count, 6);
771 assert_eq!(dsim.entry_format.bits(), 0b000001);
772 assert_eq!(dsim.entry_format.entry_size(), 1); assert_eq!(dsim.entry_format.bit_count(), 2);
774 assert_eq!(
777 dsim.map_data,
778 vec![
779 0b00_00, 0b00_01, 0b00_10, 0b01_00, 0b01_01, 0b01_10, ]
786 );
787 }
788
789 #[test]
790 fn huge_mapping_generates_format_1_delta_set_index_map() {
791 let mapping = (0..=0xFFFF).collect::<Vec<u32>>();
793 let map_count = mapping.len() as u32;
794 let dsim: DeltaSetIndexMap = mapping.into_iter().collect();
795 let DeltaSetIndexMap::Format1(dsim) = dsim else {
796 panic!("expected DeltaSetIndexMap::Format1, got {:?}", dsim);
797 };
798 assert_eq!(dsim.map_count, map_count);
799 }
800}