1include!("../../generated/generated_variations.rs");
4
5pub use fontcull_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<fontcull_read_fonts::tables::variations::Tuple<'a>>> for Vec<F2Dot14> {
372 fn from_obj_ref(
373 from: &Option<fontcull_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, _) =
493 fontcull_read_fonts::tables::variations::PackedPointNumbers::split_off_front(
494 FontData::new(&bytes),
495 );
496 assert_eq!(thing.as_slice(), read.iter().collect::<Vec<_>>());
497 }
498
499 #[test]
500 fn point_pack_runs() {
501 let thing = PackedPointNumbers::Some(vec![5, 25, 225, 1002, 2002, 2008, 2228]);
502
503 let runs = thing.iter_runs().collect::<Vec<_>>();
504 assert!(!runs[0].are_words);
505 assert_eq!(runs[0].last_point, 0);
506 assert_eq!(runs[0].points, &[5, 25, 225]);
507
508 assert!(runs[1].are_words);
509 assert_eq!(runs[1].last_point, 225);
510 assert_eq!(runs[1].points, &[1002, 2002]);
511
512 assert!(!runs[2].are_words);
513 assert_eq!(runs[2].last_point, 2002);
514 assert_eq!(runs[2].points, &[2008, 2228]);
515
516 assert_eq!(runs.len(), 3);
517 }
518
519 #[test]
520 fn point_pack_long_runs() {
521 let mut numbers = vec![0u16; 130];
522 numbers.extend(1u16..=130u16);
523 let thing = PackedPointNumbers::Some(numbers);
524
525 let runs = thing.iter_runs().collect::<Vec<_>>();
526 assert!(!runs[0].are_words);
527 assert_eq!(runs[0].points.len(), 128);
528 assert_eq!(runs[1].last_point, 0);
529 assert_eq!(runs[1].points.len(), 128);
530 assert_eq!(runs[2].last_point, 126);
531 assert_eq!(runs[2].points, &[127, 128, 129, 130]);
532 assert!(runs.get(3).is_none());
533 }
534
535 #[test]
536 fn point_pack_write_one_byte() {
537 let thing = PackedPointNumbers::Some(vec![5, 25, 225, 1002, 2002, 2008, 2228, 10000]);
538
539 let bytes = crate::dump_table(&thing).unwrap();
540 assert_eq!(thing.compute_size() as usize, bytes.len());
541 let (read, _) =
542 fontcull_read_fonts::tables::variations::PackedPointNumbers::split_off_front(
543 FontData::new(&bytes),
544 );
545 assert_eq!(thing.as_slice(), read.iter().collect::<Vec<_>>());
546 }
547
548 #[test]
549 fn point_pack_write_two_byte() {
550 let thing = PackedPointNumbers::Some(vec![0; 200]);
551
552 let bytes = crate::dump_table(&thing).unwrap();
553 assert_eq!(thing.compute_size() as usize, bytes.len());
554 let (read, _) =
555 fontcull_read_fonts::tables::variations::PackedPointNumbers::split_off_front(
556 FontData::new(&bytes),
557 );
558 assert_eq!(thing.as_slice(), read.iter().collect::<Vec<_>>());
559 }
560
561 static PACKED_DELTA_BYTES: &[u8] = &[
562 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
563 ];
564
565 #[test]
567 fn packed_deltas_spec_runs() {
568 let deltas = PackedDeltas::new(vec![10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228]);
569 let runs = deltas.iter_runs().collect::<Vec<_>>();
570 assert_eq!(
571 runs,
572 vec![
573 PackedDeltaRun::OneByte(&[10, -105, 0, -58]),
574 PackedDeltaRun::Zeros(8),
575 PackedDeltaRun::TwoBytes(&[4130, -1228]),
576 ]
577 );
578 }
579
580 #[test]
581 fn packed_deltas_spec_write() {
582 let deltas = PackedDeltas::new(vec![10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228]);
583 let bytes = crate::dump_table(&deltas).unwrap();
584 assert_eq!(bytes, PACKED_DELTA_BYTES);
585 let read = fontcull_read_fonts::tables::variations::PackedDeltas::consume_all(
586 FontData::new(&bytes),
587 );
588 let decoded = read.iter().collect::<Vec<_>>();
589 assert_eq!(deltas.deltas.len(), decoded.len());
590 assert_eq!(deltas.deltas, decoded);
591 assert_eq!(bytes, PACKED_DELTA_BYTES);
592 }
593
594 #[test]
595 fn empty_deltas() {
596 let deltas = PackedDeltas::new(vec![]);
597 let bytes = crate::dump_table(&deltas).unwrap();
598 assert!(bytes.is_empty());
599 }
600
601 #[test]
602 fn lots_of_zero() {
603 let num_zeroes = 65;
604 let deltas = PackedDeltas::new(vec![0; num_zeroes]);
605 assert_eq!(
606 vec![PackedDeltaRun::Zeros(64), PackedDeltaRun::Zeros(1)],
607 deltas.iter_runs().collect::<Vec<_>>()
608 );
609 }
610
611 #[test]
612 fn respect_my_run_length_authority() {
613 let mut values = (1..196).collect::<Vec<_>>();
614 values.extend([0, 0, 0]);
615 values.push(i16::MAX as i32 + 1);
616 values.push(i16::MIN as i32 - 1);
617 values.push(i16::MAX as i32 * 2);
618 let deltas = PackedDeltas::new(values);
619 assert_eq!(
620 vec![
621 PackedDeltaRun::OneByte(&(1..65).collect::<Vec<i32>>()),
623 PackedDeltaRun::OneByte(&(65..128).collect::<Vec<i32>>()),
625 PackedDeltaRun::TwoBytes(&(128..192).collect::<Vec<i32>>()),
627 PackedDeltaRun::TwoBytes(&(192..=195).collect::<Vec<i32>>()),
629 PackedDeltaRun::Zeros(3),
630 PackedDeltaRun::FourBytes(&[
631 i16::MAX as i32 + 1,
632 i16::MIN as i32 - 1,
633 i16::MAX as i32 * 2
634 ]),
635 ],
636 deltas.iter_runs().collect::<Vec<_>>()
637 )
638 }
639
640 #[test]
641 fn inline_single_zeros_with_bytes() {
642 let packed = PackedDeltas::new(vec![1, 2, 0, 3]);
643 assert_eq!(packed.iter_runs().count(), 1)
644 }
645
646 #[test]
647 fn split_two_zeros_in_bytes() {
648 let packed = PackedDeltas::new(vec![1, 2, 0, 0, 3]);
649 assert_eq!(packed.iter_runs().count(), 3)
650 }
651
652 #[test]
653 fn split_single_zero_in_words() {
654 let packed = PackedDeltas::new(vec![150, 200, 0, -300]);
655 assert_eq!(packed.iter_runs().count(), 3)
656 }
657
658 #[test]
659 fn inline_single_byte_in_words() {
660 let packed = PackedDeltas::new(vec![150, 200, 1, -300]);
661 assert_eq!(packed.iter_runs().count(), 1)
662 }
663
664 #[test]
665 fn split_double_byte_in_words() {
666 let packed = PackedDeltas::new(vec![150, 200, 1, 3, -300]);
667 assert_eq!(packed.iter_runs().count(), 3)
668 }
669
670 #[test]
671 fn split_byte_then_zero_after_words() {
672 let packed = PackedDeltas::new(vec![150, 200, 1, 0, 1]);
675 assert_eq!(packed.iter_runs().count(), 2);
676 assert_eq!(packed.compute_size(), 9);
677 }
678
679 #[rstest]
680 #[case::one_byte_one_inner_bit(
683 vec![0, 1, 1], 0b00_0000, 1, 1, b"\x00\x01",
684 )]
685 #[case::one_byte_two_inner_bits(
686 vec![0, 1, 2], 0b00_0001, 1, 2, b"\x00\x01\x02",
687 )]
688 #[case::one_byte_three_inner_bits(
689 vec![0, 1, 4], 0b00_0010, 1, 3, b"\x00\x01\x04",
690 )]
691 #[case::one_byte_four_inner_bits(
692 vec![0, 1, 8], 0b00_0011, 1, 4, b"\x00\x01\x08",
693 )]
694 #[case::two_bytes_nine_inner_bits(
696 vec![0, 1, 256], 0b01_1000, 2, 9, b"\x00\x00\x00\x01\x01\x00",
697 )]
698 #[case::two_bytes_sixteen_inner_bits(
699 vec![0, 1, 0x8000], 0b01_1111, 2, 16, b"\x00\x00\x00\x01\x80\x00",
700 )]
701 #[case::one_byte_one_inner_bit_two_vardatas(
706 vec![0, 1, 0x01_0000], 0b00_0000, 1, 1, b"\x00\x01\x02",
707 )]
708 #[case::three_bytes_sixteen_inner_bits(
709 vec![0, 0xFFFF, 0x01_0000],
710 0b10_1111,
711 3,
712 16,
713 b"\x00\x00\x00\x00\xFF\xFF\x01\x00\x00",
714 )]
715 #[case::four_bytes_sixteen_inner_bits(
716 vec![0, 0xFFFF, 0xFFFF_FFFF],
717 0b11_1111,
718 4,
719 16,
720 b"\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
721 )]
722 #[test]
723 fn delta_set_index_map_entry_format_and_packed_data(
724 #[case] mapping: Vec<u32>,
725 #[case] expected_format_bits: u8,
726 #[case] expected_entry_size: u8,
727 #[case] expected_inner_bit_count: u8,
728 #[case] expected_map_data: &[u8],
729 ) {
730 let (format, data) = DeltaSetIndexMap::pack_map_data(&mapping);
731 assert_eq!(format.bits(), expected_format_bits);
732 assert_eq!(format.entry_size(), expected_entry_size);
733 assert_eq!(format.bit_count(), expected_inner_bit_count);
734 assert_eq!(data, expected_map_data);
735
736 let dsim: DeltaSetIndexMap = mapping.iter().copied().collect();
737 assert!(matches!(dsim, DeltaSetIndexMap::Format0 { .. }));
740
741 let raw_dsim = crate::dump_table(&dsim).unwrap();
743 let dsim2 = fontcull_read_fonts::tables::variations::DeltaSetIndexMap::read(FontData::new(
744 &raw_dsim,
745 ))
746 .unwrap();
747 assert_eq!(
748 (0..mapping.len())
749 .map(|i| {
750 let index = dsim2.get(i as u32).unwrap();
751 ((index.outer as u32) << 16) | index.inner as u32
752 })
753 .collect::<Vec<_>>(),
754 mapping
755 );
756 }
757
758 #[test]
759 fn delta_set_index_map_from_variation_index_iterator() {
760 use crate::tables::layout::VariationIndex;
762
763 let mapping = vec![
764 VariationIndex::new(0, 0),
765 VariationIndex::new(0, 1),
766 VariationIndex::new(0, 2),
767 VariationIndex::new(1, 0),
768 VariationIndex::new(1, 1),
769 VariationIndex::new(1, 2),
770 ];
771
772 let dsim: DeltaSetIndexMap = mapping.into_iter().collect();
773 let DeltaSetIndexMap::Format0(dsim) = dsim else {
774 panic!("expected DeltaSetIndexMap::Format0, got {:?}", dsim);
775 };
776 assert_eq!(dsim.map_count, 6);
777 assert_eq!(dsim.entry_format.bits(), 0b000001);
778 assert_eq!(dsim.entry_format.entry_size(), 1); assert_eq!(dsim.entry_format.bit_count(), 2);
780 assert_eq!(
783 dsim.map_data,
784 vec![
785 0b00_00, 0b00_01, 0b00_10, 0b01_00, 0b01_01, 0b01_10, ]
792 );
793 }
794
795 #[test]
796 fn huge_mapping_generates_format_1_delta_set_index_map() {
797 let mapping = (0..=0xFFFF).collect::<Vec<u32>>();
799 let map_count = mapping.len() as u32;
800 let dsim: DeltaSetIndexMap = mapping.into_iter().collect();
801 let DeltaSetIndexMap::Format1(dsim) = dsim else {
802 panic!("expected DeltaSetIndexMap::Format1, got {:?}", dsim);
803 };
804 assert_eq!(dsim.map_count, map_count);
805 }
806}