1include!("../../generated/generated_variations.rs");
4
5use super::{
6 glyf::{PointCoord, PointFlags, PointMarker},
7 gvar::GlyphDelta,
8};
9
10pub const NO_VARIATION_INDEX: u32 = 0xFFFFFFFF;
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct DeltaSetIndex {
14 pub outer: u16,
16 pub inner: u16,
18}
19
20impl DeltaSetIndex {
21 pub const NO_VARIATION_INDEX: Self = Self {
22 outer: (NO_VARIATION_INDEX >> 16) as u16,
23 inner: (NO_VARIATION_INDEX & 0xFFFF) as u16,
24 };
25}
26
27#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct TupleIndex(u16);
30
31impl TupleIndex {
32 pub const EMBEDDED_PEAK_TUPLE: u16 = 0x8000;
39
40 pub const INTERMEDIATE_REGION: u16 = 0x4000;
46 pub const PRIVATE_POINT_NUMBERS: u16 = 0x2000;
53 pub const TUPLE_INDEX_MASK: u16 = 0x0FFF;
57
58 #[inline(always)]
59 fn tuple_len(self, axis_count: u16, flag: usize) -> usize {
60 if flag == 0 {
61 self.embedded_peak_tuple() as usize * axis_count as usize
62 } else {
63 self.intermediate_region() as usize * axis_count as usize
64 }
65 }
66
67 pub fn bits(self) -> u16 {
68 self.0
69 }
70
71 pub fn from_bits(bits: u16) -> Self {
72 TupleIndex(bits)
73 }
74
75 pub fn embedded_peak_tuple(self) -> bool {
77 (self.0 & Self::EMBEDDED_PEAK_TUPLE) != 0
78 }
79
80 pub fn intermediate_region(self) -> bool {
82 (self.0 & Self::INTERMEDIATE_REGION) != 0
83 }
84
85 pub fn private_point_numbers(self) -> bool {
87 (self.0 & Self::PRIVATE_POINT_NUMBERS) != 0
88 }
89
90 pub fn tuple_records_index(self) -> Option<u16> {
91 (!self.embedded_peak_tuple()).then_some(self.0 & Self::TUPLE_INDEX_MASK)
92 }
93}
94
95impl types::Scalar for TupleIndex {
96 type Raw = <u16 as types::Scalar>::Raw;
97 fn to_raw(self) -> Self::Raw {
98 self.0.to_raw()
99 }
100 fn from_raw(raw: Self::Raw) -> Self {
101 let t = <u16>::from_raw(raw);
102 Self(t)
103 }
104}
105
106#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114pub struct TupleVariationCount(u16);
115
116impl TupleVariationCount {
117 pub const SHARED_POINT_NUMBERS: u16 = 0x8000;
123
124 pub const COUNT_MASK: u16 = 0x0FFF;
126
127 pub fn bits(self) -> u16 {
128 self.0
129 }
130
131 pub fn from_bits(bits: u16) -> Self {
132 Self(bits)
133 }
134
135 pub fn shared_point_numbers(self) -> bool {
137 (self.0 & Self::SHARED_POINT_NUMBERS) != 0
138 }
139
140 pub fn count(self) -> u16 {
141 self.0 & Self::COUNT_MASK
142 }
143}
144
145impl types::Scalar for TupleVariationCount {
146 type Raw = <u16 as types::Scalar>::Raw;
147 fn to_raw(self) -> Self::Raw {
148 self.0.to_raw()
149 }
150 fn from_raw(raw: Self::Raw) -> Self {
151 let t = <u16>::from_raw(raw);
152 Self(t)
153 }
154}
155
156impl<'a> TupleVariationHeader<'a> {
157 #[cfg(feature = "experimental_traverse")]
158 fn traverse_tuple_index(&self) -> traversal::FieldType<'a> {
159 self.tuple_index().0.into()
160 }
161
162 #[inline(always)]
166 pub fn peak_tuple(&self) -> Option<Tuple<'a>> {
167 self.tuple_index().embedded_peak_tuple().then(|| {
168 let range = self.peak_tuple_byte_range();
169 Tuple {
170 values: self.data.read_array(range).unwrap(),
171 }
172 })
173 }
174
175 #[inline(always)]
178 pub fn intermediate_start_tuple(&self) -> Option<Tuple<'a>> {
179 self.tuple_index().intermediate_region().then(|| {
180 let range = self.intermediate_start_tuple_byte_range();
181 Tuple {
182 values: self.data.read_array(range).unwrap(),
183 }
184 })
185 }
186
187 #[inline(always)]
190 pub fn intermediate_end_tuple(&self) -> Option<Tuple<'a>> {
191 self.tuple_index().intermediate_region().then(|| {
192 let range = self.intermediate_end_tuple_byte_range();
193 Tuple {
194 values: self.data.read_array(range).unwrap(),
195 }
196 })
197 }
198
199 #[inline(always)]
202 pub fn intermediate_tuples(&self) -> Option<(Tuple<'a>, Tuple<'a>)> {
203 self.tuple_index().intermediate_region().then(|| {
204 let start_range = self.intermediate_start_tuple_byte_range();
205 let end_range = self.intermediate_end_tuple_byte_range();
206 (
207 Tuple {
208 values: self.data.read_array(start_range).unwrap(),
209 },
210 Tuple {
211 values: self.data.read_array(end_range).unwrap(),
212 },
213 )
214 })
215 }
216
217 #[inline(always)]
219 fn byte_len(&self, axis_count: u16) -> usize {
220 const FIXED_LEN: usize = u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN;
221 let tuple_byte_len = F2Dot14::RAW_BYTE_LEN * axis_count as usize;
222 let index = self.tuple_index();
223 FIXED_LEN
224 + if index.embedded_peak_tuple() {
225 tuple_byte_len
226 } else {
227 Default::default()
228 }
229 + if index.intermediate_region() {
230 tuple_byte_len * 2
231 } else {
232 Default::default()
233 }
234 }
235}
236
237impl Tuple<'_> {
238 pub fn len(&self) -> usize {
239 self.values().len()
240 }
241
242 pub fn is_empty(&self) -> bool {
243 self.values.is_empty()
244 }
245
246 #[inline(always)]
247 pub fn get(&self, idx: usize) -> Option<F2Dot14> {
248 self.values.get(idx).map(BigEndian::get)
249 }
250}
251
252#[allow(clippy::derivable_impls)]
254impl Default for Tuple<'_> {
255 fn default() -> Self {
256 Self {
257 values: Default::default(),
258 }
259 }
260}
261
262#[derive(Clone, Default, Debug)]
264pub struct PackedPointNumbers<'a> {
265 data: FontData<'a>,
266}
267
268impl<'a> PackedPointNumbers<'a> {
269 pub fn split_off_front(data: FontData<'a>) -> (Self, FontData<'a>) {
271 let this = PackedPointNumbers { data };
272 let total_len = this.total_len();
273 let remainder = data.split_off(total_len).unwrap_or_default();
274 (this, remainder)
275 }
276
277 pub fn count(&self) -> u16 {
279 self.count_and_count_bytes().0
280 }
281
282 fn count_and_count_bytes(&self) -> (u16, usize) {
284 match self.data.read_at::<u8>(0).unwrap_or(0) {
285 0 => (0, 1),
286 count @ 1..=127 => (count as u16, 1),
287 _ => {
288 let count = self.data.read_at::<u16>(0).unwrap_or_default() & 0x7FFF;
293 if count == 0 {
296 (0, 2)
297 } else {
298 (count & 0x7FFF, 2)
299 }
300 }
301 }
302 }
303
304 #[inline(never)]
306 fn total_len(&self) -> usize {
307 let (n_points, mut n_bytes) = self.count_and_count_bytes();
308 if n_points == 0 {
309 return n_bytes;
310 }
311 let mut cursor = self.data.cursor();
312 cursor.advance_by(n_bytes);
313
314 let mut n_seen = 0;
315 while n_seen < n_points {
316 let Some((count, two_bytes)) = read_control_byte(&mut cursor) else {
317 return n_bytes;
318 };
319 let word_size = 1 + usize::from(two_bytes);
320 let run_size = word_size * count as usize;
321 n_bytes += run_size + 1; cursor.advance_by(run_size);
323 n_seen += count as u16;
324 }
325
326 n_bytes
327 }
328
329 pub fn iter(&self) -> PackedPointNumbersIter<'a> {
331 let (count, n_bytes) = self.count_and_count_bytes();
332 let mut cursor = self.data.cursor();
333 cursor.advance_by(n_bytes);
334 PackedPointNumbersIter::new(count, cursor)
335 }
336}
337
338#[derive(Clone, Debug)]
340pub struct PackedPointNumbersIter<'a> {
341 count: u16,
342 seen: u16,
343 last_val: u16,
344 current_run: PointRunIter<'a>,
345}
346
347impl<'a> PackedPointNumbersIter<'a> {
348 fn new(count: u16, cursor: Cursor<'a>) -> Self {
349 PackedPointNumbersIter {
350 count,
351 seen: 0,
352 last_val: 0,
353 current_run: PointRunIter {
354 remaining: 0,
355 two_bytes: false,
356 cursor,
357 },
358 }
359 }
360}
361
362#[derive(Clone, Debug)]
364struct PointRunIter<'a> {
365 remaining: u8,
366 two_bytes: bool,
367 cursor: Cursor<'a>,
368}
369
370impl Iterator for PointRunIter<'_> {
371 type Item = u16;
372
373 fn next(&mut self) -> Option<Self::Item> {
374 while self.remaining == 0 {
376 (self.remaining, self.two_bytes) = read_control_byte(&mut self.cursor)?;
377 }
378
379 self.remaining -= 1;
380 if self.two_bytes {
381 self.cursor.read().ok()
382 } else {
383 self.cursor.read::<u8>().ok().map(|v| v as u16)
384 }
385 }
386}
387
388fn read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)> {
390 let control: u8 = cursor.read().ok()?;
391 let two_bytes = (control & 0x80) != 0;
392 let count = (control & 0x7F) + 1;
393 Some((count, two_bytes))
394}
395
396impl Iterator for PackedPointNumbersIter<'_> {
397 type Item = u16;
398
399 fn next(&mut self) -> Option<Self::Item> {
400 if self.count == 0 {
402 let result = self.last_val;
403 self.last_val = self.last_val.checked_add(1)?;
404 return Some(result);
405 }
406
407 if self.count == self.seen {
408 return None;
409 }
410 self.seen += 1;
411 self.last_val = self.last_val.checked_add(self.current_run.next()?)?;
412 Some(self.last_val)
413 }
414
415 fn size_hint(&self) -> (usize, Option<usize>) {
416 (self.count as usize, Some(self.count as usize))
417 }
418}
419
420impl ExactSizeIterator for PackedPointNumbersIter<'_> {}
422
423#[derive(Clone, Debug)]
425pub struct PackedDeltas<'a> {
426 data: FontData<'a>,
427 count: Option<usize>,
429}
430
431impl<'a> PackedDeltas<'a> {
432 pub(crate) fn new(data: FontData<'a>, count: usize) -> Self {
433 Self {
434 data,
435 count: Some(count),
436 }
437 }
438
439 #[doc(hidden)] pub fn consume_all(data: FontData<'a>) -> Self {
442 Self { data, count: None }
443 }
444
445 pub fn count(&self) -> Option<usize> {
446 self.count
447 }
448
449 pub fn count_or_compute(&self) -> usize {
450 self.count.unwrap_or_else(|| count_all_deltas(self.data))
451 }
452
453 pub fn iter(&self) -> DeltaRunIter<'a> {
454 DeltaRunIter::new(self.data.cursor(), self.count)
455 }
456
457 pub fn fetcher(&self) -> PackedDeltaFetcher<'a> {
458 PackedDeltaFetcher::new(self.data.as_bytes(), self.count)
459 }
460
461 fn x_deltas(&self) -> DeltaRunIter<'a> {
462 let count = self.count_or_compute() / 2;
463 DeltaRunIter::new(self.data.cursor(), Some(count))
464 }
465
466 fn y_deltas(&self) -> DeltaRunIter<'a> {
467 let count = self.count_or_compute();
468 DeltaRunIter::new(self.data.cursor(), Some(count)).skip_fast(count / 2)
469 }
470}
471
472const DELTAS_ARE_ZERO: u8 = 0x80;
475const DELTAS_ARE_WORDS: u8 = 0x40;
477const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
479
480#[derive(Clone, Copy, Debug, PartialEq)]
485pub enum DeltaRunType {
486 Zero = 0,
487 I8 = 1,
488 I16 = 2,
489 I32 = 4,
490}
491
492impl DeltaRunType {
493 pub fn new(control: u8) -> Self {
495 let are_zero = (control & DELTAS_ARE_ZERO) != 0;
499 let are_words = (control & DELTAS_ARE_WORDS) != 0;
500 match (are_zero, are_words) {
501 (false, false) => Self::I8,
502 (false, true) => Self::I16,
503 (true, false) => Self::Zero,
504 (true, true) => Self::I32,
505 }
506 }
507}
508
509#[derive(Clone, Debug)]
511pub struct DeltaRunIter<'a> {
512 limit: Option<usize>, remaining_in_run: u8,
514 value_type: DeltaRunType,
515 cursor: Cursor<'a>,
516}
517
518pub struct PackedDeltaFetcher<'a> {
520 data: &'a [u8],
521 pos: usize,
522 end: usize,
523 run_count: usize,
524 value_type: DeltaRunType,
525 remaining_total: Option<usize>,
526}
527
528impl<'a> PackedDeltaFetcher<'a> {
529 fn new(data: &'a [u8], count: Option<usize>) -> Self {
530 Self {
531 data,
532 pos: 0,
533 end: data.len(),
534 run_count: 0,
535 value_type: DeltaRunType::I8,
536 remaining_total: count,
537 }
538 }
539
540 #[inline(always)]
541 fn ensure_run(&mut self) -> Result<(), ReadError> {
542 if self.run_count > 0 {
543 return Ok(());
544 }
545 if self.pos >= self.end {
546 return Err(ReadError::OutOfBounds);
547 }
548 let control = self.data[self.pos];
549 self.pos += 1;
550 self.run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
551 self.value_type = DeltaRunType::new(control);
552 let width = self.value_type as usize;
553 let needed = self.run_count * width;
554 if self.pos + needed > self.end {
555 return Err(ReadError::OutOfBounds);
556 }
557 Ok(())
558 }
559
560 pub fn skip(&mut self, mut n: usize) -> Result<(), ReadError> {
561 if let Some(remaining_total) = self.remaining_total {
562 if n > remaining_total {
563 return Err(ReadError::OutOfBounds);
564 }
565 self.remaining_total = Some(remaining_total - n);
566 }
567 while n > 0 {
568 self.ensure_run()?;
569 let take = n.min(self.run_count);
570 let width = self.value_type as usize;
571 self.pos += take * width;
572 self.run_count -= take;
573 n -= take;
574 }
575 Ok(())
576 }
577
578 pub fn add_to_f32_scaled(&mut self, out: &mut [f32], scale: f32) -> Result<(), ReadError> {
579 let mut remaining = out.len();
580 if let Some(remaining_total) = self.remaining_total {
581 if remaining > remaining_total {
582 return Err(ReadError::OutOfBounds);
583 }
584 self.remaining_total = Some(remaining_total - remaining);
585 }
586 let mut idx = 0usize;
587 while remaining > 0 {
588 self.ensure_run()?;
589 let take = remaining.min(self.run_count);
590 match self.value_type {
591 DeltaRunType::Zero => {
592 idx += take;
594 }
595 DeltaRunType::I8 => {
596 let bytes = &self.data[self.pos..self.pos + take];
597 for &b in bytes {
598 out[idx] += b as i8 as f32 * scale;
599 idx += 1;
600 }
601 self.pos += take;
602 }
603 DeltaRunType::I16 => {
604 let bytes = &self.data[self.pos..self.pos + take * 2];
605 for chunk in bytes.chunks_exact(2) {
606 let delta = i16::from_be_bytes([chunk[0], chunk[1]]) as f32;
607 out[idx] += delta * scale;
608 idx += 1;
609 }
610 self.pos += take * 2;
611 }
612 DeltaRunType::I32 => {
613 let bytes = &self.data[self.pos..self.pos + take * 4];
614 for chunk in bytes.chunks_exact(4) {
615 let delta =
616 i32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]) as f32;
617 out[idx] += delta * scale;
618 idx += 1;
619 }
620 self.pos += take * 4;
621 }
622 }
623 self.run_count -= take;
624 remaining -= take;
625 }
626 Ok(())
627 }
628}
629
630fn count_all_deltas(data: FontData) -> usize {
633 let mut count = 0;
634 let mut offset = 0;
635 while let Ok(control) = data.read_at::<u8>(offset) {
636 let run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
637 count += run_count;
638 offset += run_count * DeltaRunType::new(control) as usize + 1;
639 }
640 count
641}
642
643impl<'a> DeltaRunIter<'a> {
644 fn new(cursor: Cursor<'a>, limit: Option<usize>) -> Self {
645 DeltaRunIter {
646 limit,
647 remaining_in_run: 0,
648 value_type: DeltaRunType::I8,
649 cursor,
650 }
651 }
652
653 pub(crate) fn end(mut self) -> Cursor<'a> {
654 if let Some(limit) = self.limit {
655 return self.skip_fast(limit).cursor;
656 }
657 if self.remaining_in_run != 0 {
659 if self.value_type != DeltaRunType::Zero {
660 self.cursor
661 .advance_by(self.remaining_in_run as usize * self.value_type as usize);
662 }
663 self.remaining_in_run = 0;
664 }
665 while self.read_next_control().is_some() {
666 if self.value_type != DeltaRunType::Zero {
667 self.cursor
668 .advance_by(self.remaining_in_run as usize * self.value_type as usize);
669 }
670 self.remaining_in_run = 0;
671 }
672 self.cursor
673 }
674
675 #[inline(always)]
677 pub fn skip_fast(mut self, n: usize) -> Self {
678 let mut wanted = n;
679 let mut remaining = self.remaining_in_run as usize;
680 let mut value_type = self.value_type;
681 loop {
682 if wanted > remaining {
683 self.cursor.advance_by(remaining * value_type as usize);
685 wanted -= remaining;
686 if self.read_next_control().is_none() {
687 self.limit = Some(0);
688 break;
689 }
690 remaining = self.remaining_in_run as usize;
691 value_type = self.value_type;
692 continue;
693 }
694 let consumed = wanted;
695 self.remaining_in_run -= consumed as u8;
696 self.cursor.advance_by(consumed * value_type as usize);
697 if let Some(limit) = self.limit.as_mut() {
698 *limit = limit.saturating_sub(n);
699 }
700 break;
701 }
702 self
703 }
704
705 #[inline(always)]
706 fn read_next_control(&mut self) -> Option<()> {
707 self.remaining_in_run = 0;
708 let control: u8 = self.cursor.read().ok()?;
709 self.value_type = DeltaRunType::new(control);
710 self.remaining_in_run = (control & DELTA_RUN_COUNT_MASK) + 1;
711 Some(())
712 }
713}
714
715impl Iterator for DeltaRunIter<'_> {
716 type Item = i32;
717
718 #[inline(always)]
719 fn next(&mut self) -> Option<Self::Item> {
720 if let Some(limit) = self.limit {
721 if limit == 0 {
722 return None;
723 }
724 self.limit = Some(limit - 1);
725 }
726 if self.remaining_in_run == 0 {
727 self.read_next_control()?;
728 }
729 self.remaining_in_run -= 1;
730 match self.value_type {
731 DeltaRunType::Zero => Some(0),
732 DeltaRunType::I8 => self.cursor.read::<i8>().ok().map(|v| v as i32),
733 DeltaRunType::I16 => self.cursor.read::<i16>().ok().map(|v| v as i32),
734 DeltaRunType::I32 => self.cursor.read::<i32>().ok(),
735 }
736 }
737}
738
739pub struct TupleVariationHeaderIter<'a> {
741 data: FontData<'a>,
742 n_headers: usize,
743 current: usize,
744 axis_count: u16,
745}
746
747impl<'a> TupleVariationHeaderIter<'a> {
748 pub(crate) fn new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self {
749 Self {
750 data,
751 n_headers,
752 current: 0,
753 axis_count,
754 }
755 }
756}
757
758impl<'a> Iterator for TupleVariationHeaderIter<'a> {
759 type Item = Result<TupleVariationHeader<'a>, ReadError>;
760
761 #[inline(always)]
762 fn next(&mut self) -> Option<Self::Item> {
763 if self.current == self.n_headers {
764 return None;
765 }
766 self.current += 1;
767 let next = TupleVariationHeader::read(self.data, self.axis_count);
768
769 let next_len = next
770 .as_ref()
771 .map(|table| table.byte_len(self.axis_count))
772 .unwrap_or(0);
773 self.data = self.data.split_off(next_len)?;
774 Some(next)
775 }
776}
777
778#[derive(Clone)]
779pub struct TupleVariationData<'a, T> {
780 pub(crate) axis_count: u16,
781 pub(crate) shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
782 pub(crate) shared_point_numbers: Option<PackedPointNumbers<'a>>,
783 pub(crate) tuple_count: TupleVariationCount,
784 pub(crate) header_data: FontData<'a>,
786 pub(crate) serialized_data: FontData<'a>,
788 pub(crate) _marker: std::marker::PhantomData<fn() -> T>,
789}
790
791impl<'a, T> TupleVariationData<'a, T>
792where
793 T: TupleDelta,
794{
795 pub fn tuples(&self) -> TupleVariationIter<'a, T> {
796 TupleVariationIter {
797 current: 0,
798 parent: self.clone(),
799 header_iter: TupleVariationHeaderIter::new(
800 self.header_data,
801 self.tuple_count.count() as usize,
802 self.axis_count,
803 ),
804 serialized_data: self.serialized_data,
805 _marker: std::marker::PhantomData,
806 }
807 }
808
809 pub fn active_tuples_at<'b>(
813 &self,
814 coords: &'b [F2Dot14],
815 ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
816 where
817 'a: 'b,
818 {
819 ActiveTupleVariationIter {
820 coords,
821 parent: self.clone(),
822 header_iter: TupleVariationHeaderIter::new(
823 self.header_data,
824 self.tuple_count.count() as usize,
825 self.axis_count,
826 ),
827 serialized_data: self.serialized_data,
828 data_offset: 0,
829 _marker: std::marker::PhantomData,
830 }
831 }
832
833 pub(crate) fn tuple_count(&self) -> usize {
834 self.tuple_count.count() as usize
835 }
836}
837
838pub struct TupleVariationIter<'a, T> {
840 current: usize,
841 parent: TupleVariationData<'a, T>,
842 header_iter: TupleVariationHeaderIter<'a>,
843 serialized_data: FontData<'a>,
844 _marker: std::marker::PhantomData<fn() -> T>,
845}
846
847impl<'a, T> TupleVariationIter<'a, T>
848where
849 T: TupleDelta,
850{
851 #[inline(always)]
852 fn next_tuple(&mut self) -> Option<TupleVariation<'a, T>> {
853 if self.parent.tuple_count() == self.current {
854 return None;
855 }
856 self.current += 1;
857
858 let header = self.header_iter.next()?.ok()?;
860 let data_len = header.variation_data_size() as usize;
861 let var_data = self.serialized_data.take_up_to(data_len)?;
862
863 Some(TupleVariation {
864 axis_count: self.parent.axis_count,
865 header,
866 shared_tuples: self.parent.shared_tuples.clone(),
867 serialized_data: var_data,
868 shared_point_numbers: self.parent.shared_point_numbers.clone(),
869 _marker: std::marker::PhantomData,
870 })
871 }
872}
873
874impl<'a, T> Iterator for TupleVariationIter<'a, T>
875where
876 T: TupleDelta,
877{
878 type Item = TupleVariation<'a, T>;
879
880 #[inline(always)]
881 fn next(&mut self) -> Option<Self::Item> {
882 self.next_tuple()
883 }
884}
885
886struct ActiveTupleVariationIter<'a, 'b, T> {
889 coords: &'b [F2Dot14],
890 parent: TupleVariationData<'a, T>,
891 header_iter: TupleVariationHeaderIter<'a>,
892 serialized_data: FontData<'a>,
893 data_offset: usize,
894 _marker: std::marker::PhantomData<fn() -> T>,
895}
896
897impl<'a, T> Iterator for ActiveTupleVariationIter<'a, '_, T>
898where
899 T: TupleDelta,
900{
901 type Item = (TupleVariation<'a, T>, Fixed);
902
903 #[inline(always)]
904 fn next(&mut self) -> Option<Self::Item> {
905 loop {
906 let header = self.header_iter.next()?.ok()?;
907 let data_len = header.variation_data_size() as usize;
908 let data_start = self.data_offset;
909 let data_end = data_start.checked_add(data_len)?;
910 self.data_offset = data_end;
911 if let Some(scalar) = compute_scalar(
912 &header,
913 self.parent.axis_count as usize,
914 &self.parent.shared_tuples,
915 self.coords,
916 ) {
917 let var_data = self.serialized_data.slice(data_start..data_end)?;
918 return Some((
919 TupleVariation {
920 axis_count: self.parent.axis_count,
921 header,
922 shared_tuples: self.parent.shared_tuples.clone(),
923 serialized_data: var_data,
924 shared_point_numbers: self.parent.shared_point_numbers.clone(),
925 _marker: std::marker::PhantomData,
926 },
927 scalar,
928 ));
929 }
930 }
931 }
932}
933
934#[derive(Clone)]
936pub struct TupleVariation<'a, T> {
937 axis_count: u16,
938 header: TupleVariationHeader<'a>,
939 shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
940 serialized_data: FontData<'a>,
941 shared_point_numbers: Option<PackedPointNumbers<'a>>,
942 _marker: std::marker::PhantomData<fn() -> T>,
943}
944
945impl<'a, T> TupleVariation<'a, T>
946where
947 T: TupleDelta,
948{
949 pub fn has_deltas_for_all_points(&self) -> bool {
951 if self.header.tuple_index().private_point_numbers() {
952 PackedPointNumbers {
953 data: self.serialized_data,
954 }
955 .count()
956 == 0
957 } else if let Some(shared) = &self.shared_point_numbers {
958 shared.count() == 0
959 } else {
960 false
961 }
962 }
963
964 pub fn point_numbers(&self) -> PackedPointNumbersIter<'a> {
965 let (point_numbers, _) = self.point_numbers_and_packed_deltas();
966 point_numbers.iter()
967 }
968
969 pub fn peak(&self) -> Tuple<'a> {
971 self.header
972 .tuple_index()
973 .tuple_records_index()
974 .and_then(|idx| self.shared_tuples.as_ref()?.get(idx as usize).ok())
975 .or_else(|| self.header.peak_tuple())
976 .unwrap_or_default()
977 }
978
979 pub fn intermediate_start(&self) -> Option<Tuple<'a>> {
980 self.header.intermediate_start_tuple()
981 }
982
983 pub fn intermediate_end(&self) -> Option<Tuple<'a>> {
984 self.header.intermediate_end_tuple()
985 }
986
987 pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Option<Fixed> {
997 compute_scalar(
998 &self.header,
999 self.axis_count as usize,
1000 &self.shared_tuples,
1001 coords,
1002 )
1003 }
1004
1005 pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> Option<f32> {
1015 let mut scalar = 1.0;
1016 let peak = self.peak();
1017 let inter_start = self.header.intermediate_start_tuple();
1018 let inter_end = self.header.intermediate_end_tuple();
1019 if peak.len() != self.axis_count as usize {
1020 return None;
1021 }
1022 for i in 0..self.axis_count {
1023 let i = i as usize;
1024 let coord = coords.get(i).copied().unwrap_or_default().to_bits() as i32;
1025 let peak = peak.get(i).unwrap_or_default().to_bits() as i32;
1026 if peak == 0 || peak == coord {
1027 continue;
1028 }
1029 if coord == 0 {
1030 return None;
1031 }
1032 if let (Some(inter_start), Some(inter_end)) = (&inter_start, &inter_end) {
1033 let start = inter_start.get(i).unwrap_or_default().to_bits() as i32;
1034 let end = inter_end.get(i).unwrap_or_default().to_bits() as i32;
1035 if start > peak || peak > end || (start < 0 && end > 0 && peak != 0) {
1036 continue;
1037 }
1038 if coord < start || coord > end {
1039 return None;
1040 }
1041 if coord < peak {
1042 if peak != start {
1043 scalar *= (coord - start) as f32 / (peak - start) as f32;
1044 }
1045 } else if peak != end {
1046 scalar *= (end - coord) as f32 / (end - peak) as f32;
1047 }
1048 } else {
1049 if coord < peak.min(0) || coord > peak.max(0) {
1050 return None;
1051 }
1052 scalar *= coord as f32 / peak as f32;
1053 }
1054 }
1055 Some(scalar)
1056 }
1057
1058 pub fn deltas(&self) -> TupleDeltaIter<'a, T> {
1063 let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1064 let count = point_numbers.count() as usize;
1065 let packed_deltas = if count == 0 {
1066 PackedDeltas::consume_all(packed_deltas)
1067 } else {
1068 PackedDeltas::new(packed_deltas, if T::is_point() { count * 2 } else { count })
1069 };
1070 TupleDeltaIter::new(&point_numbers, packed_deltas)
1071 }
1072
1073 fn point_numbers_and_packed_deltas(&self) -> (PackedPointNumbers<'a>, FontData<'a>) {
1074 if self.header.tuple_index().private_point_numbers() {
1075 PackedPointNumbers::split_off_front(self.serialized_data)
1076 } else {
1077 (
1078 self.shared_point_numbers.clone().unwrap_or_default(),
1079 self.serialized_data,
1080 )
1081 }
1082 }
1083}
1084
1085impl TupleVariation<'_, GlyphDelta> {
1086 pub fn accumulate_dense_deltas<D: PointCoord>(
1103 &self,
1104 deltas: &mut [Point<D>],
1105 scalar: Fixed,
1106 ) -> Result<(), ReadError> {
1107 let (_, packed_deltas) = self.point_numbers_and_packed_deltas();
1108 let mut cursor = packed_deltas.cursor();
1109 if scalar == Fixed::ONE {
1110 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1113 delta.x += D::from_i32(new_delta);
1114 })?;
1115 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1116 delta.y += D::from_i32(new_delta);
1117 })?;
1118 } else {
1119 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1120 delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1121 })?;
1122 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1123 delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1124 })?;
1125 }
1126 Ok(())
1127 }
1128
1129 pub fn accumulate_sparse_deltas<D: PointCoord>(
1151 &self,
1152 deltas: &mut [Point<D>],
1153 flags: &mut [PointFlags],
1154 scalar: Fixed,
1155 ) -> Result<(), ReadError> {
1156 let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1157 let mut cursor = packed_deltas.cursor();
1158 let count = point_numbers.count() as usize;
1159 if scalar == Fixed::ONE {
1160 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1163 if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1164 delta.x += D::from_i32(new_delta);
1165 flag.set_marker(PointMarker::HAS_DELTA);
1166 }
1167 })?;
1168 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1169 if let Some(delta) = deltas.get_mut(ix) {
1170 delta.y += D::from_i32(new_delta);
1171 }
1172 })?;
1173 } else {
1174 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1175 if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1176 delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1177 flag.set_marker(PointMarker::HAS_DELTA);
1178 }
1179 })?;
1180 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1181 if let Some(delta) = deltas.get_mut(ix) {
1182 delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1183 }
1184 })?;
1185 }
1186 Ok(())
1187 }
1188}
1189
1190fn read_dense_deltas<T>(
1195 cursor: &mut Cursor,
1196 deltas: &mut [T],
1197 mut f: impl FnMut(&mut T, i32),
1198) -> Result<(), ReadError> {
1199 let count = deltas.len();
1200 let mut cur = 0;
1201 while cur < count {
1202 let control: u8 = cursor.read()?;
1203 let value_type = DeltaRunType::new(control);
1204 let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1205 let dest = deltas
1206 .get_mut(cur..cur + run_count)
1207 .ok_or(ReadError::OutOfBounds)?;
1208 match value_type {
1209 DeltaRunType::Zero => {}
1210 DeltaRunType::I8 => {
1211 let packed_deltas = cursor.read_array::<i8>(run_count)?;
1212 for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1213 f(delta, *new_delta as i32);
1214 }
1215 }
1216 DeltaRunType::I16 => {
1217 let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1218 for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1219 f(delta, new_delta.get() as i32);
1220 }
1221 }
1222 DeltaRunType::I32 => {
1223 let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1224 for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1225 f(delta, new_delta.get());
1226 }
1227 }
1228 }
1229 cur += run_count;
1230 }
1231 Ok(())
1232}
1233
1234fn read_sparse_deltas(
1236 cursor: &mut Cursor,
1237 point_numbers: &PackedPointNumbers,
1238 count: usize,
1239 mut f: impl FnMut(usize, i32),
1240) -> Result<(), ReadError> {
1241 let mut cur = 0;
1242 let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1243 while cur < count {
1244 let control: u8 = cursor.read()?;
1245 let value_type = DeltaRunType::new(control);
1246 let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1247 match value_type {
1248 DeltaRunType::Zero => {
1249 for _ in 0..run_count {
1250 let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1251 f(point_ix, 0);
1252 }
1253 }
1254 DeltaRunType::I8 => {
1255 let packed_deltas = cursor.read_array::<i8>(run_count)?;
1256 for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1257 f(point_ix, *new_delta as i32);
1258 }
1259 }
1260 DeltaRunType::I16 => {
1261 let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1262 for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1263 f(point_ix, new_delta.get() as i32);
1264 }
1265 }
1266 DeltaRunType::I32 => {
1267 let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1268 for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1269 f(point_ix, new_delta.get());
1270 }
1271 }
1272 }
1273 cur += run_count;
1274 }
1275 Ok(())
1276}
1277
1278#[inline(always)]
1288fn compute_scalar<'a>(
1289 header: &TupleVariationHeader,
1290 axis_count: usize,
1291 shared_tuples: &Option<ComputedArray<'a, Tuple<'a>>>,
1292 coords: &[F2Dot14],
1293) -> Option<Fixed> {
1294 let mut scalar = Fixed::ONE;
1295 let tuple_idx = header.tuple_index();
1296 let peak = if let Some(shared_index) = tuple_idx.tuple_records_index() {
1297 shared_tuples.as_ref()?.get(shared_index as usize).ok()?
1298 } else {
1299 header.peak_tuple()?
1300 };
1301 if peak.len() != axis_count {
1302 return None;
1303 }
1304 let intermediate = header.intermediate_tuples();
1305 for (i, peak) in peak
1306 .values
1307 .iter()
1308 .enumerate()
1309 .filter(|(_, peak)| peak.get() != F2Dot14::ZERO)
1310 {
1311 let coord = coords.get(i).copied().unwrap_or_default();
1312 if coord == F2Dot14::ZERO {
1313 return None;
1314 }
1315 let peak = peak.get();
1316 if peak == coord {
1317 continue;
1318 }
1319 if let Some((inter_start, inter_end)) = &intermediate {
1320 let start = inter_start.get(i).unwrap_or_default();
1321 let end = inter_end.get(i).unwrap_or_default();
1322 if coord <= start || coord >= end {
1323 return None;
1324 }
1325 let coord = coord.to_fixed();
1326 let peak = peak.to_fixed();
1327 if coord < peak {
1328 let start = start.to_fixed();
1329 scalar = scalar.mul_div(coord - start, peak - start);
1330 } else {
1331 let end = end.to_fixed();
1332 scalar = scalar.mul_div(end - coord, end - peak);
1333 }
1334 } else {
1335 if coord < peak.min(F2Dot14::ZERO) || coord > peak.max(F2Dot14::ZERO) {
1336 return None;
1337 }
1338 let coord = coord.to_fixed();
1339 let peak = peak.to_fixed();
1340 scalar = scalar.mul_div(coord, peak);
1341 }
1342 }
1343 (scalar != Fixed::ZERO).then_some(scalar)
1344}
1345
1346#[derive(Clone, Debug)]
1347enum TupleDeltaValues<'a> {
1348 Points(DeltaRunIter<'a>, DeltaRunIter<'a>),
1350 Scalars(DeltaRunIter<'a>),
1351}
1352
1353#[derive(Clone, Debug)]
1355pub struct TupleDeltaIter<'a, T> {
1356 pub cur: usize,
1357 points: Option<PackedPointNumbersIter<'a>>,
1359 next_point: usize,
1360 values: TupleDeltaValues<'a>,
1361 _marker: std::marker::PhantomData<fn() -> T>,
1362}
1363
1364impl<'a, T> TupleDeltaIter<'a, T>
1365where
1366 T: TupleDelta,
1367{
1368 fn new(points: &PackedPointNumbers<'a>, deltas: PackedDeltas<'a>) -> TupleDeltaIter<'a, T> {
1369 let mut points = points.iter();
1370 let next_point = points.next();
1371 let values = if T::is_point() {
1372 TupleDeltaValues::Points(deltas.x_deltas(), deltas.y_deltas())
1373 } else {
1374 TupleDeltaValues::Scalars(deltas.iter())
1375 };
1376 TupleDeltaIter {
1377 cur: 0,
1378 points: next_point.map(|_| points),
1379 next_point: next_point.unwrap_or_default() as usize,
1380 values,
1381 _marker: std::marker::PhantomData,
1382 }
1383 }
1384}
1385
1386pub trait TupleDelta: Sized + Copy + 'static {
1388 fn is_point() -> bool;
1391
1392 fn new(position: u16, x: i32, y: i32) -> Self;
1395}
1396
1397impl<T> Iterator for TupleDeltaIter<'_, T>
1398where
1399 T: TupleDelta,
1400{
1401 type Item = T;
1402
1403 fn next(&mut self) -> Option<Self::Item> {
1404 let (position, dx, dy) = loop {
1405 let position = if let Some(points) = &mut self.points {
1406 if self.cur > self.next_point {
1408 self.next_point = points.next()? as usize;
1409 }
1410 self.next_point
1411 } else {
1412 self.cur
1414 };
1415 if position == self.cur {
1416 let (dx, dy) = match &mut self.values {
1417 TupleDeltaValues::Points(x, y) => (x.next()?, y.next()?),
1418 TupleDeltaValues::Scalars(scalars) => (scalars.next()?, 0),
1419 };
1420 break (position, dx, dy);
1421 }
1422 self.cur += 1;
1423 };
1424 self.cur += 1;
1425 Some(T::new(position as u16, dx, dy))
1426 }
1427}
1428
1429impl EntryFormat {
1430 pub fn entry_size(self) -> u8 {
1431 ((self.bits() & Self::MAP_ENTRY_SIZE_MASK.bits()) >> 4) + 1
1432 }
1433
1434 pub fn bit_count(self) -> u8 {
1435 (self.bits() & Self::INNER_INDEX_BIT_COUNT_MASK.bits()) + 1
1436 }
1437
1438 pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
1440 self.entry_size() as usize * map_count.into() as usize
1441 }
1442}
1443
1444impl DeltaSetIndexMap<'_> {
1445 pub fn get(&self, index: u32) -> Result<DeltaSetIndex, ReadError> {
1447 let (entry_format, map_count, data) = match self {
1448 Self::Format0(fmt) => (fmt.entry_format(), fmt.map_count() as u32, fmt.map_data()),
1449 Self::Format1(fmt) => (fmt.entry_format(), fmt.map_count(), fmt.map_data()),
1450 };
1451 if map_count == 0 {
1452 return Ok(DeltaSetIndex {
1453 outer: (index >> 16) as u16,
1454 inner: index as u16,
1455 });
1456 }
1457 let entry_size = entry_format.entry_size();
1458 let data = FontData::new(data);
1459 let index = index.min(map_count.saturating_sub(1));
1464 let offset = index as usize * entry_size as usize;
1465 let entry = match entry_size {
1466 1 => data.read_at::<u8>(offset)? as u32,
1467 2 => data.read_at::<u16>(offset)? as u32,
1468 3 => data.read_at::<Uint24>(offset)?.into(),
1469 4 => data.read_at::<u32>(offset)?,
1470 _ => {
1471 return Err(ReadError::MalformedData(
1472 "invalid entry size in DeltaSetIndexMap",
1473 ))
1474 }
1475 };
1476 let bit_count = entry_format.bit_count();
1477 Ok(DeltaSetIndex {
1478 outer: (entry >> bit_count) as u16,
1479 inner: (entry & ((1 << bit_count) - 1)) as u16,
1480 })
1481 }
1482}
1483
1484impl ItemVariationStore<'_> {
1485 pub fn compute_delta(
1488 &self,
1489 index: DeltaSetIndex,
1490 coords: &[F2Dot14],
1491 ) -> Result<i32, ReadError> {
1492 if coords.is_empty() || index == DeltaSetIndex::NO_VARIATION_INDEX {
1493 return Ok(0);
1494 }
1495 let data = match self.item_variation_data().get(index.outer as usize) {
1496 Some(data) => data?,
1497 None => return Ok(0),
1498 };
1499 let regions = self.variation_region_list()?.variation_regions();
1500 let region_indices = data.region_indexes();
1501 let mut accum = 0i64;
1504 for (i, region_delta) in data.delta_set(index.inner).enumerate() {
1505 let region_index = region_indices
1506 .get(i)
1507 .ok_or(ReadError::MalformedData(
1508 "invalid delta sets in ItemVariationStore",
1509 ))?
1510 .get() as usize;
1511 let region = regions.get(region_index)?;
1512 let scalar = region.compute_scalar(coords);
1513 accum += region_delta as i64 * scalar.to_bits() as i64;
1514 }
1515 Ok(((accum + 0x8000) >> 16) as i32)
1516 }
1517
1518 pub fn compute_float_delta(
1521 &self,
1522 index: DeltaSetIndex,
1523 coords: &[F2Dot14],
1524 ) -> Result<FloatItemDelta, ReadError> {
1525 if coords.is_empty() {
1526 return Ok(FloatItemDelta::ZERO);
1527 }
1528 let data = match self.item_variation_data().get(index.outer as usize) {
1529 Some(data) => data?,
1530 None => return Ok(FloatItemDelta::ZERO),
1531 };
1532 let regions = self.variation_region_list()?.variation_regions();
1533 let region_indices = data.region_indexes();
1534 let mut accum = 0f64;
1536 for (i, region_delta) in data.delta_set(index.inner).enumerate() {
1537 let region_index = region_indices
1538 .get(i)
1539 .ok_or(ReadError::MalformedData(
1540 "invalid delta sets in ItemVariationStore",
1541 ))?
1542 .get() as usize;
1543 let region = regions.get(region_index)?;
1544 let scalar = region.compute_scalar_f32(coords);
1545 accum += region_delta as f64 * scalar as f64;
1546 }
1547 Ok(FloatItemDelta(accum))
1548 }
1549}
1550
1551#[derive(Copy, Clone, Default, Debug)]
1555pub struct FloatItemDelta(f64);
1556
1557impl FloatItemDelta {
1558 pub const ZERO: Self = Self(0.0);
1559
1560 pub fn to_f64(self) -> f64 {
1562 self.0
1563 }
1564}
1565
1566pub trait FloatItemDeltaTarget {
1568 fn apply_float_delta(&self, delta: FloatItemDelta) -> f32;
1569}
1570
1571impl FloatItemDeltaTarget for Fixed {
1572 fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1573 const FIXED_TO_FLOAT: f64 = 1.0 / 65536.0;
1574 self.to_f32() + (delta.0 * FIXED_TO_FLOAT) as f32
1575 }
1576}
1577
1578impl FloatItemDeltaTarget for FWord {
1579 fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1580 self.to_i16() as f32 + delta.0 as f32
1581 }
1582}
1583
1584impl FloatItemDeltaTarget for UfWord {
1585 fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1586 self.to_u16() as f32 + delta.0 as f32
1587 }
1588}
1589
1590impl FloatItemDeltaTarget for F2Dot14 {
1591 fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1592 const F2DOT14_TO_FLOAT: f64 = 1.0 / 16384.0;
1593 self.to_f32() + (delta.0 * F2DOT14_TO_FLOAT) as f32
1594 }
1595}
1596
1597impl<'a> VariationRegion<'a> {
1598 pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Fixed {
1601 const ZERO: Fixed = Fixed::ZERO;
1602 let mut scalar = Fixed::ONE;
1603 for (i, peak, axis_coords) in self.active_region_axes() {
1604 let peak = peak.to_fixed();
1605 let start = axis_coords.start_coord.get().to_fixed();
1606 let end = axis_coords.end_coord.get().to_fixed();
1607 if start > peak || peak > end || start < ZERO && end > ZERO {
1608 continue;
1609 }
1610 let coord = coords.get(i).map(|coord| coord.to_fixed()).unwrap_or(ZERO);
1611 if coord < start || coord > end {
1612 return ZERO;
1613 } else if coord == peak {
1614 continue;
1615 } else if coord < peak {
1616 scalar = scalar.mul_div(coord - start, peak - start);
1617 } else {
1618 scalar = scalar.mul_div(end - coord, end - peak);
1619 }
1620 }
1621 scalar
1622 }
1623
1624 pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> f32 {
1627 let mut scalar = 1.0;
1628 for (i, peak, axis_coords) in self.active_region_axes() {
1629 let peak = peak.to_f32();
1630 let start = axis_coords.start_coord.get().to_f32();
1631 let end = axis_coords.end_coord.get().to_f32();
1632 if start > peak || peak > end || start < 0.0 && end > 0.0 {
1633 continue;
1634 }
1635 let coord = coords.get(i).map(|coord| coord.to_f32()).unwrap_or(0.0);
1636 if coord < start || coord > end {
1637 return 0.0;
1638 } else if coord == peak {
1639 continue;
1640 } else if coord < peak {
1641 scalar = (scalar * (coord - start)) / (peak - start);
1642 } else {
1643 scalar = (scalar * (end - coord)) / (end - peak);
1644 }
1645 }
1646 scalar
1647 }
1648
1649 fn active_region_axes(
1650 &self,
1651 ) -> impl Iterator<Item = (usize, F2Dot14, &'a RegionAxisCoordinates)> {
1652 self.region_axes()
1653 .iter()
1654 .enumerate()
1655 .filter_map(|(i, axis_coords)| {
1656 let peak = axis_coords.peak_coord();
1657 if peak != F2Dot14::ZERO {
1658 Some((i, peak, axis_coords))
1659 } else {
1660 None
1661 }
1662 })
1663 }
1664}
1665
1666impl<'a> ItemVariationData<'a> {
1667 pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
1670 let word_delta_count = self.word_delta_count();
1671 let region_count = self.region_index_count();
1672 let bytes_per_row = Self::delta_row_len(word_delta_count, region_count);
1673 let long_words = word_delta_count & 0x8000 != 0;
1674 let word_delta_count = word_delta_count & 0x7FFF;
1675
1676 let offset = bytes_per_row * inner_index as usize;
1677 ItemDeltas {
1678 cursor: FontData::new(self.delta_sets())
1679 .slice(offset..)
1680 .unwrap_or_default()
1681 .cursor(),
1682 word_delta_count,
1683 long_words,
1684 len: region_count,
1685 pos: 0,
1686 }
1687 }
1688
1689 pub fn get_delta_row_len(&self) -> usize {
1690 let word_delta_count = self.word_delta_count();
1691 let region_count = self.region_index_count();
1692 Self::delta_row_len(word_delta_count, region_count)
1693 }
1694
1695 pub fn delta_row_len(word_delta_count: u16, region_index_count: u16) -> usize {
1697 let region_count = region_index_count as usize;
1698 let long_words = word_delta_count & 0x8000 != 0;
1699 let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
1700 let long_delta_count = (word_delta_count & 0x7FFF) as usize;
1701 let short_delta_count = region_count.saturating_sub(long_delta_count);
1702 long_delta_count * word_size + short_delta_count * small_size
1703 }
1704
1705 pub fn delta_sets_len(
1707 item_count: u16,
1708 word_delta_count: u16,
1709 region_index_count: u16,
1710 ) -> usize {
1711 let bytes_per_row = Self::delta_row_len(word_delta_count, region_index_count);
1712 bytes_per_row * item_count as usize
1713 }
1714}
1715
1716#[derive(Clone)]
1717struct ItemDeltas<'a> {
1718 cursor: Cursor<'a>,
1719 word_delta_count: u16,
1720 long_words: bool,
1721 len: u16,
1722 pos: u16,
1723}
1724
1725impl Iterator for ItemDeltas<'_> {
1726 type Item = i32;
1727
1728 fn next(&mut self) -> Option<Self::Item> {
1729 if self.pos >= self.len {
1730 return None;
1731 }
1732 let pos = self.pos;
1733 self.pos += 1;
1734 let value = match (pos >= self.word_delta_count, self.long_words) {
1735 (true, true) | (false, false) => self.cursor.read::<i16>().ok()? as i32,
1736 (true, false) => self.cursor.read::<i8>().ok()? as i32,
1737 (false, true) => self.cursor.read::<i32>().ok()?,
1738 };
1739 Some(value)
1740 }
1741}
1742
1743pub(crate) fn advance_delta(
1744 dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1745 ivs: Result<ItemVariationStore, ReadError>,
1746 glyph_id: GlyphId,
1747 coords: &[F2Dot14],
1748) -> Result<Fixed, ReadError> {
1749 if coords.is_empty() {
1750 return Ok(Fixed::ZERO);
1751 }
1752 let gid = glyph_id.to_u32();
1753 let ix = match dsim {
1754 Some(Ok(dsim)) => dsim.get(gid)?,
1755 _ => DeltaSetIndex {
1756 outer: 0,
1757 inner: gid as _,
1758 },
1759 };
1760 Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
1761}
1762
1763pub(crate) fn item_delta(
1764 dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1765 ivs: Result<ItemVariationStore, ReadError>,
1766 glyph_id: GlyphId,
1767 coords: &[F2Dot14],
1768) -> Result<Fixed, ReadError> {
1769 if coords.is_empty() {
1770 return Ok(Fixed::ZERO);
1771 }
1772 let gid = glyph_id.to_u32();
1773 let ix = match dsim {
1774 Some(Ok(dsim)) => dsim.get(gid)?,
1775 _ => return Err(ReadError::NullOffset),
1776 };
1777 Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
1778}
1779
1780#[cfg(test)]
1781mod tests {
1782 use font_test_data::bebuffer::BeBuffer;
1783
1784 use super::*;
1785 use crate::{FontRef, TableProvider};
1786
1787 #[test]
1788 fn ivs_regions() {
1789 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1790 let hvar = font.hvar().expect("missing HVAR table");
1791 let ivs = hvar
1792 .item_variation_store()
1793 .expect("missing item variation store in HVAR");
1794 let region_list = ivs.variation_region_list().expect("missing region list!");
1795 let regions = region_list.variation_regions();
1796 let expected = &[
1797 vec![[-1.0f32, -1.0, 0.0]],
1799 vec![[0.0, 1.0, 1.0]],
1800 ][..];
1801 let region_coords = regions
1802 .iter()
1803 .map(|region| {
1804 region
1805 .unwrap()
1806 .region_axes()
1807 .iter()
1808 .map(|coords| {
1809 [
1810 coords.start_coord().to_f32(),
1811 coords.peak_coord().to_f32(),
1812 coords.end_coord().to_f32(),
1813 ]
1814 })
1815 .collect::<Vec<_>>()
1816 })
1817 .collect::<Vec<_>>();
1818 assert_eq!(expected, ®ion_coords);
1819 }
1820
1821 #[test]
1823 fn packed_points() {
1824 fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
1825 let data = FontData::new(bytes);
1826 let packed = PackedPointNumbers { data };
1827 if packed.count() == 0 {
1828 None
1829 } else {
1830 Some(packed.iter().collect())
1831 }
1832 }
1833
1834 assert_eq!(decode_points(&[0]), None);
1835 assert_eq!(decode_points(&[0x80, 0]), None);
1837 assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
1839 assert_eq!(
1841 decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
1842 Some(vec![0xbeef, 0xcafe])
1843 );
1844 assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
1846 assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
1848 assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
1850 assert_eq!(
1852 decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
1853 Some(vec![7, 8, 263, 265])
1854 );
1855 }
1856
1857 #[test]
1858 fn packed_point_byte_len() {
1859 fn count_bytes(bytes: &[u8]) -> usize {
1860 let packed = PackedPointNumbers {
1861 data: FontData::new(bytes),
1862 };
1863 packed.total_len()
1864 }
1865
1866 static CASES: &[&[u8]] = &[
1867 &[0],
1868 &[0x80, 0],
1869 &[0x02, 0x01, 0x09, 0x06],
1870 &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
1871 &[0x01, 0, 0x07],
1872 &[0x01, 0x80, 0, 0x07],
1873 &[0x01, 0x80, 0xff, 0xff],
1874 &[0x04, 1, 7, 1, 1, 0xff, 2],
1875 ];
1876
1877 for case in CASES {
1878 assert_eq!(count_bytes(case), case.len(), "{case:?}");
1879 }
1880 }
1881
1882 #[test]
1884 fn packed_deltas() {
1885 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1886
1887 let deltas = PackedDeltas::consume_all(INPUT);
1888 assert_eq!(deltas.count_or_compute(), 7);
1889 assert_eq!(
1890 deltas.iter().collect::<Vec<_>>(),
1891 &[0, 0, 0, 0, 258, -127, -128]
1892 );
1893
1894 assert_eq!(
1895 PackedDeltas::consume_all(FontData::new(&[0x81]))
1896 .iter()
1897 .collect::<Vec<_>>(),
1898 &[0, 0,]
1899 );
1900 }
1901
1902 #[test]
1904 fn packed_deltas_spec() {
1905 static INPUT: FontData = FontData::new(&[
1906 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1907 ]);
1908 static EXPECTED: &[i32] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
1909
1910 let deltas = PackedDeltas::consume_all(INPUT);
1911 assert_eq!(deltas.count_or_compute(), EXPECTED.len());
1912 assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
1913 }
1914
1915 #[test]
1916 fn packed_delta_fetcher_skip_matches_iterator_suffix() {
1917 static INPUT: FontData = FontData::new(&[
1918 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1919 ]);
1920 let deltas = PackedDeltas::consume_all(INPUT);
1921 let expected = deltas.iter().collect::<Vec<_>>();
1922
1923 for skip in 0..=expected.len() {
1924 let mut fetcher = deltas.fetcher();
1925 fetcher.skip(skip).unwrap();
1926 let mut out = vec![0.0; expected.len() - skip];
1927 fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
1928 let got = out.into_iter().map(|v| v as i32).collect::<Vec<_>>();
1929 assert_eq!(&got[..], &expected[skip..], "skip={skip}");
1930 }
1931
1932 let mut fetcher = deltas.fetcher();
1933 assert!(matches!(
1934 fetcher.skip(expected.len() + 1),
1935 Err(ReadError::OutOfBounds)
1936 ));
1937 }
1938
1939 #[test]
1940 fn packed_delta_fetcher_scaled_add_and_exhaustion() {
1941 static INPUT: FontData = FontData::new(&[
1942 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1943 ]);
1944 let deltas = PackedDeltas::new(INPUT, 4);
1946 let mut fetcher = deltas.fetcher();
1947 let mut out = [1.0f32; 4];
1948 fetcher.add_to_f32_scaled(&mut out, 0.5).unwrap();
1949 assert_eq!(out, [6.0, -51.5, 1.0, -28.0]);
1950
1951 let mut extra = [0.0f32; 1];
1953 assert!(matches!(
1954 fetcher.add_to_f32_scaled(&mut extra, 1.0),
1955 Err(ReadError::OutOfBounds)
1956 ));
1957 }
1958
1959 #[test]
1960 fn packed_delta_fetcher_skip_then_add_bounded() {
1961 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1962 let deltas = PackedDeltas::new(INPUT, 7);
1964 let mut fetcher = deltas.fetcher();
1965 fetcher.skip(3).unwrap();
1966 let mut out = [0.0f32; 4];
1967 fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
1968 assert_eq!(out, [0.0, 258.0, -127.0, -128.0]);
1969 }
1970
1971 #[test]
1972 fn delta_run_iter_end_exhausts_unbounded_data() {
1973 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1974 let deltas = PackedDeltas::consume_all(INPUT);
1975 let end = deltas.iter().end();
1976 assert_eq!(end.remaining_bytes(), 0);
1977 }
1978
1979 #[test]
1980 fn delta_run_iter_end_respects_bounded_count() {
1981 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1982 let deltas = PackedDeltas::new(INPUT, 4);
1985 let end = deltas.iter().end();
1986 assert_eq!(end.remaining_bytes(), INPUT.len() - 1);
1987
1988 let end_via_skip = deltas.iter().skip_fast(4).cursor;
1989 assert_eq!(end_via_skip.remaining_bytes(), INPUT.len() - 1);
1990 }
1991
1992 #[test]
1993 fn delta_run_iter_end_matches_manual_iteration_for_bounded_data() {
1994 static INPUT: FontData = FontData::new(&[
1995 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1996 ]);
1997 let deltas = PackedDeltas::new(INPUT, 6);
1998
1999 let iter_collected = deltas.iter().collect::<Vec<_>>();
2000 assert_eq!(iter_collected.len(), 6);
2001
2002 let end = deltas.iter().end();
2003 let end_via_skip = deltas.iter().skip_fast(6).cursor;
2004 assert_eq!(end.remaining_bytes(), end_via_skip.remaining_bytes());
2005 }
2006
2007 fn lcg_next(state: &mut u32) -> u32 {
2008 *state = state.wrapping_mul(1664525).wrapping_add(1013904223);
2009 *state
2010 }
2011
2012 fn generated_delta_stream(seed: u32) -> (Vec<u8>, Vec<i32>) {
2013 let mut state = seed;
2014 let mut bytes = Vec::new();
2015 let mut expected = Vec::new();
2016 let run_count = (lcg_next(&mut state) % 6 + 1) as usize;
2017 for _ in 0..run_count {
2018 let run_type = (lcg_next(&mut state) % 4) as usize;
2019 let len = (lcg_next(&mut state) % 8 + 1) as usize;
2020 let control = match run_type {
2021 0 => (len - 1) as u8, 1 => 0x40 | (len - 1) as u8, 2 => 0x80 | (len - 1) as u8, _ => 0xC0 | (len - 1) as u8, };
2026 bytes.push(control);
2027 match run_type {
2028 0 => {
2029 for _ in 0..len {
2030 let v = ((lcg_next(&mut state) % 255) as i32 - 127) as i8;
2031 bytes.push(v as u8);
2032 expected.push(v as i32);
2033 }
2034 }
2035 1 => {
2036 for _ in 0..len {
2037 let v = ((lcg_next(&mut state) % 65535) as i32 - 32767) as i16;
2038 bytes.extend(v.to_be_bytes());
2039 expected.push(v as i32);
2040 }
2041 }
2042 2 => {
2043 expected.resize(expected.len() + len, 0);
2044 }
2045 _ => {
2046 for _ in 0..len {
2047 let v = (lcg_next(&mut state) % 2_000_001) as i32 - 1_000_000;
2048 bytes.extend(v.to_be_bytes());
2049 expected.push(v);
2050 }
2051 }
2052 }
2053 }
2054 (bytes, expected)
2055 }
2056
2057 #[test]
2058 fn generated_packed_deltas_iter_matches_expected() {
2059 for seed in 1..=64 {
2060 let (bytes, expected) = generated_delta_stream(seed);
2061 let data = FontData::new(&bytes);
2062 let deltas = PackedDeltas::consume_all(data);
2063 assert_eq!(deltas.count_or_compute(), expected.len(), "seed={seed}");
2064 assert_eq!(deltas.iter().collect::<Vec<_>>(), expected, "seed={seed}");
2065 }
2066 }
2067
2068 #[test]
2069 fn generated_fetcher_skip_scaled_matches_expected() {
2070 for seed in 1..=64 {
2071 let (bytes, expected) = generated_delta_stream(seed);
2072 let data = FontData::new(&bytes);
2073 let deltas = PackedDeltas::new(data, expected.len());
2074 let mut fetcher = deltas.fetcher();
2075 let skip = (seed as usize * 7) % (expected.len() + 1);
2076 fetcher.skip(skip).unwrap();
2077
2078 let scale = if seed % 2 == 0 { 0.25 } else { -0.5 };
2079 let mut out = vec![10.0f32; expected.len() - skip];
2080 fetcher.add_to_f32_scaled(&mut out, scale).unwrap();
2081 for (i, got) in out.iter().copied().enumerate() {
2082 let want = 10.0 + expected[skip + i] as f32 * scale;
2083 assert!(
2084 (got - want).abs() <= 1e-6,
2085 "seed={seed} i={i} got={got} want={want}"
2086 );
2087 }
2088
2089 let mut extra = [0.0f32; 1];
2091 assert!(matches!(
2092 fetcher.add_to_f32_scaled(&mut extra, 1.0),
2093 Err(ReadError::OutOfBounds)
2094 ));
2095 }
2096 }
2097
2098 #[test]
2099 fn packed_point_split() {
2100 static INPUT: FontData =
2101 FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
2102 let (points, data) = PackedPointNumbers::split_off_front(INPUT);
2103 assert_eq!(points.count(), 2);
2104 assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
2105 assert_eq!(points.total_len(), 4);
2106 assert_eq!(data.len(), INPUT.len() - 4);
2107 }
2108
2109 #[test]
2110 fn packed_points_dont_panic() {
2111 static ALL_POINTS: FontData = FontData::new(&[0]);
2113 let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
2114 assert_eq!(all_points.iter().count(), u16::MAX as usize);
2116 }
2117
2118 #[test]
2121 fn packed_delta_run_crosses_coord_boundary() {
2122 static INPUT: FontData = FontData::new(&[
2125 5,
2127 0,
2128 1,
2129 2,
2130 3,
2131 4,
2133 5,
2134 1 | DELTAS_ARE_WORDS,
2136 0,
2137 6,
2138 0,
2139 7,
2140 ]);
2141 let deltas = PackedDeltas::consume_all(INPUT);
2142 assert_eq!(deltas.count_or_compute(), 8);
2143 let x_deltas = deltas.x_deltas().collect::<Vec<_>>();
2144 let y_deltas = deltas.y_deltas().collect::<Vec<_>>();
2145 assert_eq!(x_deltas, [0, 1, 2, 3]);
2146 assert_eq!(y_deltas, [4, 5, 6, 7]);
2147 }
2148
2149 #[test]
2153 fn ivs_float_deltas_nearly_match_fixed_deltas() {
2154 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
2155 let axis_count = font.fvar().unwrap().axis_count() as usize;
2156 let colr = font.colr().unwrap();
2157 let ivs = colr.item_variation_store().unwrap().unwrap();
2158 for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
2160 let coords = vec![coord; axis_count];
2162 for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
2163 let outer_ix = outer_ix as u16;
2164 let Some(Ok(data)) = data else {
2165 continue;
2166 };
2167 for inner_ix in 0..data.item_count() {
2168 let delta_ix = DeltaSetIndex {
2169 outer: outer_ix,
2170 inner: inner_ix,
2171 };
2172 let orig_delta = ivs.compute_delta(delta_ix, &coords).unwrap();
2174 let float_delta = ivs.compute_float_delta(delta_ix, &coords).unwrap();
2175 assert!(
2179 orig_delta == float_delta.0.round() as i32
2180 || orig_delta == float_delta.0.trunc() as i32
2181 );
2182 const EPSILON: f32 = 1e12;
2184 let fixed_delta = Fixed::ZERO.apply_float_delta(float_delta);
2185 assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
2186 let f2dot14_delta = F2Dot14::ZERO.apply_float_delta(float_delta);
2187 assert!(
2188 (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
2189 < EPSILON
2190 );
2191 }
2192 }
2193 }
2194 }
2195
2196 #[test]
2197 fn ivs_data_len_short() {
2198 let data = BeBuffer::new()
2199 .push(2u16) .push(3u16) .push(5u16) .extend([0u16, 1, 2, 3, 4]) .extend([1u8; 128]); let ivs = ItemVariationData::read(data.data().into()).unwrap();
2206 let row_len = (3 * u16::RAW_BYTE_LEN) + (2 * u8::RAW_BYTE_LEN); let expected_len = 2 * row_len;
2208 assert_eq!(ivs.delta_sets().len(), expected_len);
2209 }
2210
2211 #[test]
2212 fn ivs_data_len_long() {
2213 let data = BeBuffer::new()
2214 .push(2u16) .push(2u16 | 0x8000) .push(4u16) .extend([0u16, 1, 2]) .extend([1u8; 128]); let ivs = ItemVariationData::read(data.data().into()).unwrap();
2221 let row_len = (2 * u32::RAW_BYTE_LEN) + (2 * u16::RAW_BYTE_LEN); let expected_len = 2 * row_len;
2223 assert_eq!(ivs.delta_sets().len(), expected_len);
2224 }
2225
2226 #[test]
2229 fn packed_point_numbers_avoid_overflow() {
2230 let buf = vec![0xFF; 0xFFFF];
2232 let iter = PackedPointNumbersIter::new(0xFFFF, FontData::new(&buf).cursor());
2233 let _ = iter.count();
2235 }
2236
2237 #[test]
2239 fn accumulate_dense() {
2240 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2241 let gvar = font.gvar().unwrap();
2242 let gvar_data = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
2243 let mut count = 0;
2244 for tuple in gvar_data.tuples() {
2245 if !tuple.has_deltas_for_all_points() {
2246 continue;
2247 }
2248 let iter_deltas = tuple
2249 .deltas()
2250 .map(|delta| (delta.x_delta, delta.y_delta))
2251 .collect::<Vec<_>>();
2252 let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); iter_deltas.len()];
2253 tuple
2254 .accumulate_dense_deltas(&mut delta_buf, Fixed::ONE)
2255 .unwrap();
2256 let accum_deltas = delta_buf
2257 .iter()
2258 .map(|delta| (delta.x.to_i32(), delta.y.to_i32()))
2259 .collect::<Vec<_>>();
2260 assert_eq!(iter_deltas, accum_deltas);
2261 count += iter_deltas.len();
2262 }
2263 assert!(count != 0);
2264 }
2265
2266 #[test]
2268 fn accumulate_sparse() {
2269 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2270 let gvar = font.gvar().unwrap();
2271 let gvar_data = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
2272 let mut count = 0;
2273 for tuple in gvar_data.tuples() {
2274 if tuple.has_deltas_for_all_points() {
2275 continue;
2276 }
2277 let iter_deltas = tuple.deltas().collect::<Vec<_>>();
2278 let max_modified_point = iter_deltas
2279 .iter()
2280 .max_by_key(|delta| delta.position)
2281 .unwrap()
2282 .position as usize;
2283 let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); max_modified_point + 1];
2284 let mut flags = vec![PointFlags::default(); delta_buf.len()];
2285 tuple
2286 .accumulate_sparse_deltas(&mut delta_buf, &mut flags, Fixed::ONE)
2287 .unwrap();
2288 let mut accum_deltas = vec![];
2289 for (i, (delta, flag)) in delta_buf.iter().zip(flags).enumerate() {
2290 if flag.has_marker(PointMarker::HAS_DELTA) {
2291 accum_deltas.push(GlyphDelta::new(
2292 i as u16,
2293 delta.x.to_i32(),
2294 delta.y.to_i32(),
2295 ));
2296 }
2297 }
2298 assert_eq!(iter_deltas, accum_deltas);
2299 count += iter_deltas.len();
2300 }
2301 assert!(count != 0);
2302 }
2303
2304 #[test]
2305 fn delta_set_index_map_empty_is_identity() {
2306 let data = BeBuffer::new()
2307 .push(0u8) .push(EntryFormat::empty())
2309 .push(0u16); let map = DeltaSetIndexMap::read(data.data().into()).unwrap();
2311 assert_eq!(
2312 map.get(0x0001_0002).unwrap(),
2313 DeltaSetIndex { outer: 1, inner: 2 }
2314 );
2315 }
2316}