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 #[inline(always)]
161 pub fn peak_tuple(&self) -> Option<Tuple<'a>> {
162 self.tuple_index().embedded_peak_tuple().then(|| {
163 let range = self.peak_tuple_byte_range();
164 Tuple {
165 values: self.offset_data().read_array(range).unwrap(),
166 }
167 })
168 }
169
170 #[inline(always)]
173 pub fn intermediate_start_tuple(&self) -> Option<Tuple<'a>> {
174 self.tuple_index().intermediate_region().then(|| {
175 let range = self.intermediate_start_tuple_byte_range();
176 Tuple {
177 values: self.offset_data().read_array(range).unwrap(),
178 }
179 })
180 }
181
182 #[inline(always)]
185 pub fn intermediate_end_tuple(&self) -> Option<Tuple<'a>> {
186 self.tuple_index().intermediate_region().then(|| {
187 let range = self.intermediate_end_tuple_byte_range();
188 Tuple {
189 values: self.offset_data().read_array(range).unwrap(),
190 }
191 })
192 }
193
194 #[inline(always)]
197 pub fn intermediate_tuples(&self) -> Option<(Tuple<'a>, Tuple<'a>)> {
198 self.tuple_index().intermediate_region().then(|| {
199 let start_range = self.intermediate_start_tuple_byte_range();
200 let end_range = self.intermediate_end_tuple_byte_range();
201 (
202 Tuple {
203 values: self.offset_data().read_array(start_range).unwrap(),
204 },
205 Tuple {
206 values: self.offset_data().read_array(end_range).unwrap(),
207 },
208 )
209 })
210 }
211
212 #[inline(always)]
214 fn byte_len(&self, axis_count: u16) -> usize {
215 const FIXED_LEN: usize = u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN;
216 let tuple_byte_len = F2Dot14::RAW_BYTE_LEN * axis_count as usize;
217 let index = self.tuple_index();
218 FIXED_LEN
219 + if index.embedded_peak_tuple() {
220 tuple_byte_len
221 } else {
222 Default::default()
223 }
224 + if index.intermediate_region() {
225 tuple_byte_len * 2
226 } else {
227 Default::default()
228 }
229 }
230}
231
232impl Tuple<'_> {
233 pub fn len(&self) -> usize {
234 self.values().len()
235 }
236
237 pub fn is_empty(&self) -> bool {
238 self.values.is_empty()
239 }
240
241 #[inline(always)]
242 pub fn get(&self, idx: usize) -> Option<F2Dot14> {
243 self.values.get(idx).map(BigEndian::get)
244 }
245}
246
247#[allow(clippy::derivable_impls)]
249impl Default for Tuple<'_> {
250 fn default() -> Self {
251 Self {
252 values: Default::default(),
253 }
254 }
255}
256
257#[derive(Clone, Default, Debug)]
259pub struct PackedPointNumbers<'a> {
260 data: FontData<'a>,
261}
262
263impl<'a> PackedPointNumbers<'a> {
264 pub fn split_off_front(data: FontData<'a>) -> (Self, FontData<'a>) {
266 let this = PackedPointNumbers { data };
267 let total_len = this.total_len();
268 let remainder = data.split_off(total_len).unwrap_or_default();
269 (this, remainder)
270 }
271
272 pub fn count(&self) -> u16 {
274 self.count_and_count_bytes().0
275 }
276
277 fn count_and_count_bytes(&self) -> (u16, usize) {
279 match self.data.read_at::<u8>(0).unwrap_or(0) {
280 0 => (0, 1),
281 count @ 1..=127 => (count as u16, 1),
282 _ => {
283 let count = self.data.read_at::<u16>(0).unwrap_or_default() & 0x7FFF;
288 if count == 0 {
291 (0, 2)
292 } else {
293 (count & 0x7FFF, 2)
294 }
295 }
296 }
297 }
298
299 #[inline(never)]
301 fn total_len(&self) -> usize {
302 let (n_points, mut n_bytes) = self.count_and_count_bytes();
303 if n_points == 0 {
304 return n_bytes;
305 }
306 let mut cursor = self.data.cursor();
307 cursor.advance_by(n_bytes);
308
309 let mut n_seen = 0;
310 while n_seen < n_points {
311 let Some((count, two_bytes)) = read_control_byte(&mut cursor) else {
312 return n_bytes;
313 };
314 let word_size = 1 + usize::from(two_bytes);
315 let run_size = word_size * count as usize;
316 n_bytes += run_size + 1; cursor.advance_by(run_size);
318 n_seen += count as u16;
319 }
320
321 n_bytes
322 }
323
324 pub fn iter(&self) -> PackedPointNumbersIter<'a> {
326 let (count, n_bytes) = self.count_and_count_bytes();
327 let mut cursor = self.data.cursor();
328 cursor.advance_by(n_bytes);
329 PackedPointNumbersIter::new(count, cursor)
330 }
331}
332
333#[derive(Clone, Debug)]
335pub struct PackedPointNumbersIter<'a> {
336 count: u16,
337 seen: u16,
338 last_val: u16,
339 current_run: PointRunIter<'a>,
340}
341
342impl<'a> PackedPointNumbersIter<'a> {
343 fn new(count: u16, cursor: Cursor<'a>) -> Self {
344 PackedPointNumbersIter {
345 count,
346 seen: 0,
347 last_val: 0,
348 current_run: PointRunIter {
349 remaining: 0,
350 two_bytes: false,
351 cursor,
352 },
353 }
354 }
355}
356
357#[derive(Clone, Debug)]
359struct PointRunIter<'a> {
360 remaining: u8,
361 two_bytes: bool,
362 cursor: Cursor<'a>,
363}
364
365impl Iterator for PointRunIter<'_> {
366 type Item = u16;
367
368 fn next(&mut self) -> Option<Self::Item> {
369 while self.remaining == 0 {
371 (self.remaining, self.two_bytes) = read_control_byte(&mut self.cursor)?;
372 }
373
374 self.remaining -= 1;
375 if self.two_bytes {
376 self.cursor.read().ok()
377 } else {
378 self.cursor.read::<u8>().ok().map(|v| v as u16)
379 }
380 }
381}
382
383fn read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)> {
385 let control: u8 = cursor.read().ok()?;
386 let two_bytes = (control & 0x80) != 0;
387 let count = (control & 0x7F) + 1;
388 Some((count, two_bytes))
389}
390
391impl Iterator for PackedPointNumbersIter<'_> {
392 type Item = u16;
393
394 fn next(&mut self) -> Option<Self::Item> {
395 if self.count == 0 {
397 let result = self.last_val;
398 self.last_val = self.last_val.checked_add(1)?;
399 return Some(result);
400 }
401
402 if self.count == self.seen {
403 return None;
404 }
405 self.seen += 1;
406 self.last_val = self.last_val.checked_add(self.current_run.next()?)?;
407 Some(self.last_val)
408 }
409
410 fn size_hint(&self) -> (usize, Option<usize>) {
411 (self.count as usize, Some(self.count as usize))
412 }
413}
414
415impl ExactSizeIterator for PackedPointNumbersIter<'_> {}
417
418#[derive(Clone, Debug)]
420pub struct PackedDeltas<'a> {
421 data: FontData<'a>,
422 count: Option<usize>,
424}
425
426impl<'a> PackedDeltas<'a> {
427 pub(crate) fn new(data: FontData<'a>, count: usize) -> Self {
428 Self {
429 data,
430 count: Some(count),
431 }
432 }
433
434 #[doc(hidden)] pub fn consume_all(data: FontData<'a>) -> Self {
437 Self { data, count: None }
438 }
439
440 pub fn count(&self) -> Option<usize> {
441 self.count
442 }
443
444 pub fn count_or_compute(&self) -> usize {
445 self.count.unwrap_or_else(|| count_all_deltas(self.data))
446 }
447
448 pub fn iter(&self) -> DeltaRunIter<'a> {
449 DeltaRunIter::new(self.data.cursor(), self.count)
450 }
451
452 pub fn fetcher(&self) -> PackedDeltaFetcher<'a> {
453 PackedDeltaFetcher::new(self.data.as_bytes(), self.count)
454 }
455
456 fn x_deltas(&self) -> DeltaRunIter<'a> {
457 let count = self.count_or_compute() / 2;
458 DeltaRunIter::new(self.data.cursor(), Some(count))
459 }
460
461 fn y_deltas(&self) -> DeltaRunIter<'a> {
462 let count = self.count_or_compute();
463 DeltaRunIter::new(self.data.cursor(), Some(count)).skip_fast(count / 2)
464 }
465}
466
467const DELTAS_ARE_ZERO: u8 = 0x80;
470const DELTAS_ARE_WORDS: u8 = 0x40;
472const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
474
475#[derive(Clone, Copy, Debug, PartialEq)]
480pub enum DeltaRunType {
481 Zero = 0,
482 I8 = 1,
483 I16 = 2,
484 I32 = 4,
485}
486
487impl DeltaRunType {
488 pub fn new(control: u8) -> Self {
490 let are_zero = (control & DELTAS_ARE_ZERO) != 0;
494 let are_words = (control & DELTAS_ARE_WORDS) != 0;
495 match (are_zero, are_words) {
496 (false, false) => Self::I8,
497 (false, true) => Self::I16,
498 (true, false) => Self::Zero,
499 (true, true) => Self::I32,
500 }
501 }
502}
503
504#[derive(Clone, Debug)]
506pub struct DeltaRunIter<'a> {
507 limit: Option<usize>, remaining_in_run: u8,
509 value_type: DeltaRunType,
510 cursor: Cursor<'a>,
511}
512
513pub struct PackedDeltaFetcher<'a> {
515 data: &'a [u8],
516 pos: usize,
517 end: usize,
518 run_count: usize,
519 value_type: DeltaRunType,
520 remaining_total: Option<usize>,
521}
522
523impl<'a> PackedDeltaFetcher<'a> {
524 fn new(data: &'a [u8], count: Option<usize>) -> Self {
525 Self {
526 data,
527 pos: 0,
528 end: data.len(),
529 run_count: 0,
530 value_type: DeltaRunType::I8,
531 remaining_total: count,
532 }
533 }
534
535 #[inline(always)]
536 fn ensure_run(&mut self) -> Result<(), ReadError> {
537 if self.run_count > 0 {
538 return Ok(());
539 }
540 if self.pos >= self.end {
541 return Err(ReadError::OutOfBounds);
542 }
543 let control = self.data[self.pos];
544 self.pos += 1;
545 self.run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
546 self.value_type = DeltaRunType::new(control);
547 let width = self.value_type as usize;
548 let needed = self.run_count * width;
549 if self.pos + needed > self.end {
550 return Err(ReadError::OutOfBounds);
551 }
552 Ok(())
553 }
554
555 pub fn skip(&mut self, mut n: usize) -> Result<(), ReadError> {
556 if let Some(remaining_total) = self.remaining_total {
557 if n > remaining_total {
558 return Err(ReadError::OutOfBounds);
559 }
560 self.remaining_total = Some(remaining_total - n);
561 }
562 while n > 0 {
563 self.ensure_run()?;
564 let take = n.min(self.run_count);
565 let width = self.value_type as usize;
566 self.pos += take * width;
567 self.run_count -= take;
568 n -= take;
569 }
570 Ok(())
571 }
572
573 pub fn add_to_f32_scaled(&mut self, out: &mut [f32], scale: f32) -> Result<(), ReadError> {
574 self.add_to_scaled(out, scale, |delta| delta as f32)
575 }
576
577 pub fn add_to_f64_scaled(&mut self, out: &mut [f64], scale: f64) -> Result<(), ReadError> {
579 self.add_to_scaled(out, scale, |delta| delta as f64)
580 }
581
582 fn add_to_scaled<T>(
583 &mut self,
584 out: &mut [T],
585 scale: T,
586 convert: impl Fn(i32) -> T,
587 ) -> Result<(), ReadError>
588 where
589 T: Copy + core::ops::AddAssign + core::ops::Mul<Output = T>,
590 {
591 let mut remaining = out.len();
592 if let Some(remaining_total) = self.remaining_total {
593 if remaining > remaining_total {
594 return Err(ReadError::OutOfBounds);
595 }
596 self.remaining_total = Some(remaining_total - remaining);
597 }
598 let mut idx = 0usize;
599 while remaining > 0 {
600 self.ensure_run()?;
601 let take = remaining.min(self.run_count);
602 match self.value_type {
603 DeltaRunType::Zero => {
604 idx += take;
606 }
607 DeltaRunType::I8 => {
608 let bytes = &self.data[self.pos..self.pos + take];
609 for &b in bytes {
610 out[idx] += convert(b as i8 as i32) * scale;
611 idx += 1;
612 }
613 self.pos += take;
614 }
615 DeltaRunType::I16 => {
616 let bytes = &self.data[self.pos..self.pos + take * 2];
617 for chunk in bytes.chunks_exact(2) {
618 let delta = i16::from_be_bytes([chunk[0], chunk[1]]) as i32;
619 out[idx] += convert(delta) * scale;
620 idx += 1;
621 }
622 self.pos += take * 2;
623 }
624 DeltaRunType::I32 => {
625 let bytes = &self.data[self.pos..self.pos + take * 4];
626 for chunk in bytes.chunks_exact(4) {
627 let delta = i32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
628 out[idx] += convert(delta) * scale;
629 idx += 1;
630 }
631 self.pos += take * 4;
632 }
633 }
634 self.run_count -= take;
635 remaining -= take;
636 }
637 Ok(())
638 }
639}
640
641fn count_all_deltas(data: FontData) -> usize {
644 let mut count = 0;
645 let mut offset = 0;
646 while let Ok(control) = data.read_at::<u8>(offset) {
647 let run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
648 count += run_count;
649 offset += run_count * DeltaRunType::new(control) as usize + 1;
650 }
651 count
652}
653
654impl<'a> DeltaRunIter<'a> {
655 fn new(cursor: Cursor<'a>, limit: Option<usize>) -> Self {
656 DeltaRunIter {
657 limit,
658 remaining_in_run: 0,
659 value_type: DeltaRunType::I8,
660 cursor,
661 }
662 }
663
664 pub(crate) fn end(mut self) -> Cursor<'a> {
665 if let Some(limit) = self.limit {
666 return self.skip_fast(limit).cursor;
667 }
668 if self.remaining_in_run != 0 {
670 if self.value_type != DeltaRunType::Zero {
671 self.cursor
672 .advance_by(self.remaining_in_run as usize * self.value_type as usize);
673 }
674 self.remaining_in_run = 0;
675 }
676 while self.read_next_control().is_some() {
677 if self.value_type != DeltaRunType::Zero {
678 self.cursor
679 .advance_by(self.remaining_in_run as usize * self.value_type as usize);
680 }
681 self.remaining_in_run = 0;
682 }
683 self.cursor
684 }
685
686 #[inline(always)]
688 pub fn skip_fast(mut self, n: usize) -> Self {
689 let mut wanted = n;
690 let mut remaining = self.remaining_in_run as usize;
691 let mut value_type = self.value_type;
692 loop {
693 if wanted > remaining {
694 self.cursor.advance_by(remaining * value_type as usize);
696 wanted -= remaining;
697 if self.read_next_control().is_none() {
698 self.limit = Some(0);
699 break;
700 }
701 remaining = self.remaining_in_run as usize;
702 value_type = self.value_type;
703 continue;
704 }
705 let consumed = wanted;
706 self.remaining_in_run -= consumed as u8;
707 self.cursor.advance_by(consumed * value_type as usize);
708 if let Some(limit) = self.limit.as_mut() {
709 *limit = limit.saturating_sub(n);
710 }
711 break;
712 }
713 self
714 }
715
716 #[inline(always)]
717 fn read_next_control(&mut self) -> Option<()> {
718 self.remaining_in_run = 0;
719 let control: u8 = self.cursor.read().ok()?;
720 self.value_type = DeltaRunType::new(control);
721 self.remaining_in_run = (control & DELTA_RUN_COUNT_MASK) + 1;
722 Some(())
723 }
724}
725
726impl Iterator for DeltaRunIter<'_> {
727 type Item = i32;
728
729 #[inline(always)]
730 fn next(&mut self) -> Option<Self::Item> {
731 if let Some(limit) = self.limit {
732 if limit == 0 {
733 return None;
734 }
735 self.limit = Some(limit - 1);
736 }
737 if self.remaining_in_run == 0 {
738 self.read_next_control()?;
739 }
740 self.remaining_in_run -= 1;
741 match self.value_type {
742 DeltaRunType::Zero => Some(0),
743 DeltaRunType::I8 => self.cursor.read::<i8>().ok().map(|v| v as i32),
744 DeltaRunType::I16 => self.cursor.read::<i16>().ok().map(|v| v as i32),
745 DeltaRunType::I32 => self.cursor.read::<i32>().ok(),
746 }
747 }
748}
749
750pub struct TupleVariationHeaderIter<'a> {
752 data: FontData<'a>,
753 n_headers: usize,
754 current: usize,
755 axis_count: u16,
756}
757
758impl<'a> TupleVariationHeaderIter<'a> {
759 pub(crate) fn new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self {
760 Self {
761 data,
762 n_headers,
763 current: 0,
764 axis_count,
765 }
766 }
767}
768
769impl<'a> Iterator for TupleVariationHeaderIter<'a> {
770 type Item = Result<TupleVariationHeader<'a>, ReadError>;
771
772 #[inline(always)]
773 fn next(&mut self) -> Option<Self::Item> {
774 if self.current == self.n_headers {
775 return None;
776 }
777 self.current += 1;
778 let next = TupleVariationHeader::read(self.data, self.axis_count);
779
780 let next_len = next
781 .as_ref()
782 .map(|table| table.byte_len(self.axis_count))
783 .unwrap_or(0);
784 self.data = self.data.split_off(next_len)?;
785 Some(next)
786 }
787}
788
789#[derive(Clone)]
790pub struct TupleVariationData<'a, T> {
791 pub(crate) axis_count: u16,
792 pub(crate) shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
793 pub(crate) shared_point_numbers: Option<PackedPointNumbers<'a>>,
794 pub(crate) tuple_count: TupleVariationCount,
795 pub(crate) header_data: FontData<'a>,
797 pub(crate) serialized_data: FontData<'a>,
799 pub(crate) _marker: std::marker::PhantomData<fn() -> T>,
800}
801
802impl<'a, T> TupleVariationData<'a, T>
803where
804 T: TupleDelta,
805{
806 pub fn tuples(&self) -> TupleVariationIter<'a, T> {
807 TupleVariationIter {
808 current: 0,
809 parent: self.clone(),
810 header_iter: TupleVariationHeaderIter::new(
811 self.header_data,
812 self.tuple_count.count() as usize,
813 self.axis_count,
814 ),
815 serialized_data: self.serialized_data,
816 _marker: std::marker::PhantomData,
817 }
818 }
819
820 pub fn active_tuples_at<'b>(
824 &self,
825 coords: &'b [F2Dot14],
826 ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
827 where
828 'a: 'b,
829 {
830 self.active_tuples_at_with_scalars(coords, &[])
831 }
832
833 pub fn active_tuples_at_with_scalars<'b>(
844 &self,
845 coords: &'b [F2Dot14],
846 scalars: &'b [Fixed],
847 ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
848 where
849 'a: 'b,
850 {
851 ActiveTupleVariationIter {
852 coords,
853 scalars,
854 parent: self.clone(),
855 header_iter: TupleVariationHeaderIter::new(
856 self.header_data,
857 self.tuple_count.count() as usize,
858 self.axis_count,
859 ),
860 serialized_data: self.serialized_data,
861 data_offset: 0,
862 _marker: std::marker::PhantomData,
863 }
864 }
865
866 pub(crate) fn tuple_count(&self) -> usize {
867 self.tuple_count.count() as usize
868 }
869}
870
871pub struct TupleVariationIter<'a, T> {
873 current: usize,
874 parent: TupleVariationData<'a, T>,
875 header_iter: TupleVariationHeaderIter<'a>,
876 serialized_data: FontData<'a>,
877 _marker: std::marker::PhantomData<fn() -> T>,
878}
879
880impl<'a, T> TupleVariationIter<'a, T>
881where
882 T: TupleDelta,
883{
884 #[inline(always)]
885 fn next_tuple(&mut self) -> Option<TupleVariation<'a, T>> {
886 if self.parent.tuple_count() == self.current {
887 return None;
888 }
889 self.current += 1;
890
891 let header = self.header_iter.next()?.ok()?;
893 let data_len = header.variation_data_size() as usize;
894 let var_data = self.serialized_data.take_up_to(data_len)?;
895
896 Some(TupleVariation {
897 axis_count: self.parent.axis_count,
898 header,
899 shared_tuples: self.parent.shared_tuples.clone(),
900 serialized_data: var_data,
901 shared_point_numbers: self.parent.shared_point_numbers.clone(),
902 _marker: std::marker::PhantomData,
903 })
904 }
905}
906
907impl<'a, T> Iterator for TupleVariationIter<'a, T>
908where
909 T: TupleDelta,
910{
911 type Item = TupleVariation<'a, T>;
912
913 #[inline(always)]
914 fn next(&mut self) -> Option<Self::Item> {
915 self.next_tuple()
916 }
917}
918
919struct ActiveTupleVariationIter<'a, 'b, T> {
922 coords: &'b [F2Dot14],
923 scalars: &'b [Fixed],
924 parent: TupleVariationData<'a, T>,
925 header_iter: TupleVariationHeaderIter<'a>,
926 serialized_data: FontData<'a>,
927 data_offset: usize,
928 _marker: std::marker::PhantomData<fn() -> T>,
929}
930
931impl<'a, T> Iterator for ActiveTupleVariationIter<'a, '_, T>
932where
933 T: TupleDelta,
934{
935 type Item = (TupleVariation<'a, T>, Fixed);
936
937 #[inline(always)]
938 fn next(&mut self) -> Option<Self::Item> {
939 loop {
940 let header = self.header_iter.next()?.ok()?;
941 let data_len = header.variation_data_size() as usize;
942 let data_start = self.data_offset;
943 let data_end = data_start.checked_add(data_len)?;
944 self.data_offset = data_end;
945 if let Some(scalar) = compute_scalar(
946 &header,
947 self.parent.axis_count as usize,
948 &self.parent.shared_tuples,
949 self.coords,
950 self.scalars,
951 ) {
952 let var_data = self.serialized_data.slice(data_start..data_end)?;
953 return Some((
954 TupleVariation {
955 axis_count: self.parent.axis_count,
956 header,
957 shared_tuples: self.parent.shared_tuples.clone(),
958 serialized_data: var_data,
959 shared_point_numbers: self.parent.shared_point_numbers.clone(),
960 _marker: std::marker::PhantomData,
961 },
962 scalar,
963 ));
964 }
965 }
966 }
967}
968
969pub const NOT_COMPUTED: Fixed = Fixed::MAX;
978
979#[derive(Clone)]
981pub struct TupleVariation<'a, T> {
982 axis_count: u16,
983 header: TupleVariationHeader<'a>,
984 shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
985 serialized_data: FontData<'a>,
986 shared_point_numbers: Option<PackedPointNumbers<'a>>,
987 _marker: std::marker::PhantomData<fn() -> T>,
988}
989
990impl<'a, T> TupleVariation<'a, T>
991where
992 T: TupleDelta,
993{
994 pub fn has_deltas_for_all_points(&self) -> bool {
996 if self.header.tuple_index().private_point_numbers() {
997 PackedPointNumbers {
998 data: self.serialized_data,
999 }
1000 .count()
1001 == 0
1002 } else if let Some(shared) = &self.shared_point_numbers {
1003 shared.count() == 0
1004 } else {
1005 false
1006 }
1007 }
1008
1009 pub fn point_numbers(&self) -> PackedPointNumbersIter<'a> {
1010 let (point_numbers, _) = self.point_numbers_and_packed_deltas();
1011 point_numbers.iter()
1012 }
1013
1014 pub fn peak(&self) -> Tuple<'a> {
1016 self.header
1017 .tuple_index()
1018 .tuple_records_index()
1019 .and_then(|idx| self.shared_tuples.as_ref()?.get(idx as usize).ok())
1020 .or_else(|| self.header.peak_tuple())
1021 .unwrap_or_default()
1022 }
1023
1024 pub fn intermediate_start(&self) -> Option<Tuple<'a>> {
1025 self.header.intermediate_start_tuple()
1026 }
1027
1028 pub fn intermediate_end(&self) -> Option<Tuple<'a>> {
1029 self.header.intermediate_end_tuple()
1030 }
1031
1032 pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Option<Fixed> {
1042 compute_scalar(
1043 &self.header,
1044 self.axis_count as usize,
1045 &self.shared_tuples,
1046 coords,
1047 &[],
1048 )
1049 }
1050
1051 pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> Option<f32> {
1061 let mut scalar = 1.0;
1062 let peak = self.peak();
1063 let inter_start = self.header.intermediate_start_tuple();
1064 let inter_end = self.header.intermediate_end_tuple();
1065 if peak.len() != self.axis_count as usize {
1066 return None;
1067 }
1068 for i in 0..self.axis_count {
1069 let i = i as usize;
1070 let coord = coords.get(i).copied().unwrap_or_default().to_bits() as i32;
1071 let peak = peak.get(i).unwrap_or_default().to_bits() as i32;
1072 if peak == 0 || peak == coord {
1073 continue;
1074 }
1075 if coord == 0 {
1076 return None;
1077 }
1078 if let (Some(inter_start), Some(inter_end)) = (&inter_start, &inter_end) {
1079 let start = inter_start.get(i).unwrap_or_default().to_bits() as i32;
1080 let end = inter_end.get(i).unwrap_or_default().to_bits() as i32;
1081 if start > peak || peak > end || (start < 0 && end > 0 && peak != 0) {
1082 continue;
1083 }
1084 if coord < start || coord > end {
1085 return None;
1086 }
1087 if coord < peak {
1088 if peak != start {
1089 scalar *= (coord - start) as f32 / (peak - start) as f32;
1090 }
1091 } else if peak != end {
1092 scalar *= (end - coord) as f32 / (end - peak) as f32;
1093 }
1094 } else {
1095 if coord < peak.min(0) || coord > peak.max(0) {
1096 return None;
1097 }
1098 scalar *= coord as f32 / peak as f32;
1099 }
1100 }
1101 Some(scalar)
1102 }
1103
1104 pub fn deltas(&self) -> TupleDeltaIter<'a, T> {
1109 let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1110 let count = point_numbers.count() as usize;
1111 let packed_deltas = if count == 0 {
1112 PackedDeltas::consume_all(packed_deltas)
1113 } else {
1114 PackedDeltas::new(packed_deltas, if T::is_point() { count * 2 } else { count })
1115 };
1116 TupleDeltaIter::new(&point_numbers, packed_deltas)
1117 }
1118
1119 fn point_numbers_and_packed_deltas(&self) -> (PackedPointNumbers<'a>, FontData<'a>) {
1120 if self.header.tuple_index().private_point_numbers() {
1121 PackedPointNumbers::split_off_front(self.serialized_data)
1122 } else {
1123 (
1124 self.shared_point_numbers.clone().unwrap_or_default(),
1125 self.serialized_data,
1126 )
1127 }
1128 }
1129}
1130
1131impl TupleVariation<'_, GlyphDelta> {
1132 pub fn accumulate_dense_deltas<D: PointCoord>(
1149 &self,
1150 deltas: &mut [Point<D>],
1151 scalar: Fixed,
1152 ) -> Result<(), ReadError> {
1153 let (_, packed_deltas) = self.point_numbers_and_packed_deltas();
1154 let mut cursor = packed_deltas.cursor();
1155 if scalar == Fixed::ONE {
1156 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1159 delta.x += D::from_i32(new_delta);
1160 })?;
1161 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1162 delta.y += D::from_i32(new_delta);
1163 })?;
1164 } else {
1165 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1166 delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1167 })?;
1168 read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1169 delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1170 })?;
1171 }
1172 Ok(())
1173 }
1174
1175 pub fn accumulate_sparse_deltas<D: PointCoord>(
1197 &self,
1198 deltas: &mut [Point<D>],
1199 flags: &mut [PointFlags],
1200 scalar: Fixed,
1201 ) -> Result<(), ReadError> {
1202 let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1203 let mut cursor = packed_deltas.cursor();
1204 let count = point_numbers.count() as usize;
1205 if scalar == Fixed::ONE {
1206 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1209 if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1210 delta.x += D::from_i32(new_delta);
1211 flag.set_marker(PointMarker::HAS_DELTA);
1212 }
1213 })?;
1214 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1215 if let Some(delta) = deltas.get_mut(ix) {
1216 delta.y += D::from_i32(new_delta);
1217 }
1218 })?;
1219 } else {
1220 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1221 if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1222 delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1223 flag.set_marker(PointMarker::HAS_DELTA);
1224 }
1225 })?;
1226 read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1227 if let Some(delta) = deltas.get_mut(ix) {
1228 delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1229 }
1230 })?;
1231 }
1232 Ok(())
1233 }
1234}
1235
1236fn read_dense_deltas<T>(
1241 cursor: &mut Cursor,
1242 deltas: &mut [T],
1243 mut f: impl FnMut(&mut T, i32),
1244) -> Result<(), ReadError> {
1245 let count = deltas.len();
1246 let mut cur = 0;
1247 while cur < count {
1248 let control: u8 = cursor.read()?;
1249 let value_type = DeltaRunType::new(control);
1250 let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1251 let dest = deltas
1252 .get_mut(cur..cur + run_count)
1253 .ok_or(ReadError::OutOfBounds)?;
1254 match value_type {
1255 DeltaRunType::Zero => {}
1256 DeltaRunType::I8 => {
1257 let packed_deltas = cursor.read_array::<i8>(run_count)?;
1258 for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1259 f(delta, *new_delta as i32);
1260 }
1261 }
1262 DeltaRunType::I16 => {
1263 let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1264 for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1265 f(delta, new_delta.get() as i32);
1266 }
1267 }
1268 DeltaRunType::I32 => {
1269 let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1270 for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1271 f(delta, new_delta.get());
1272 }
1273 }
1274 }
1275 cur += run_count;
1276 }
1277 Ok(())
1278}
1279
1280fn read_sparse_deltas(
1282 cursor: &mut Cursor,
1283 point_numbers: &PackedPointNumbers,
1284 count: usize,
1285 mut f: impl FnMut(usize, i32),
1286) -> Result<(), ReadError> {
1287 let mut cur = 0;
1288 let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1289 while cur < count {
1290 let control: u8 = cursor.read()?;
1291 let value_type = DeltaRunType::new(control);
1292 let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1293 match value_type {
1294 DeltaRunType::Zero => {
1295 for _ in 0..run_count {
1296 let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1297 f(point_ix, 0);
1298 }
1299 }
1300 DeltaRunType::I8 => {
1301 let packed_deltas = cursor.read_array::<i8>(run_count)?;
1302 for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1303 f(point_ix, *new_delta as i32);
1304 }
1305 }
1306 DeltaRunType::I16 => {
1307 let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1308 for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1309 f(point_ix, new_delta.get() as i32);
1310 }
1311 }
1312 DeltaRunType::I32 => {
1313 let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1314 for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1315 f(point_ix, new_delta.get());
1316 }
1317 }
1318 }
1319 cur += run_count;
1320 }
1321 Ok(())
1322}
1323
1324#[inline(always)]
1334fn compute_scalar<'a>(
1335 header: &TupleVariationHeader,
1336 axis_count: usize,
1337 shared_tuples: &Option<ComputedArray<'a, Tuple<'a>>>,
1338 coords: &[F2Dot14],
1339 scalars: &[Fixed],
1340) -> Option<Fixed> {
1341 let tuple_idx = header.tuple_index();
1342 let intermediate = header.intermediate_tuples();
1343 let peak = if let Some(shared_index) = tuple_idx.tuple_records_index() {
1344 if intermediate.is_none() {
1347 match scalars.get(shared_index as usize) {
1348 Some(scalar) if *scalar != NOT_COMPUTED => {
1349 return (*scalar != Fixed::ZERO).then_some(*scalar);
1350 }
1351 _ => {}
1352 }
1353 }
1354 shared_tuples.as_ref()?.get(shared_index as usize).ok()?
1355 } else {
1356 header.peak_tuple()?
1357 };
1358 if peak.len() != axis_count {
1359 return None;
1360 }
1361 scalar_for(&peak, intermediate, coords)
1362}
1363
1364pub(crate) fn scalar_for(
1370 peak: &Tuple,
1371 intermediate: Option<(Tuple, Tuple)>,
1372 coords: &[F2Dot14],
1373) -> Option<Fixed> {
1374 let mut scalar = Fixed::ONE;
1375 for (i, peak) in peak
1376 .values
1377 .iter()
1378 .enumerate()
1379 .filter(|(_, peak)| peak.get() != F2Dot14::ZERO)
1380 {
1381 let coord = coords.get(i).copied().unwrap_or_default();
1382 if coord == F2Dot14::ZERO {
1383 return None;
1384 }
1385 let peak = peak.get();
1386 if peak == coord {
1387 continue;
1388 }
1389 if let Some((inter_start, inter_end)) = &intermediate {
1390 let start = inter_start.get(i).unwrap_or_default();
1391 let end = inter_end.get(i).unwrap_or_default();
1392 if start > peak || peak > end || (start < F2Dot14::ZERO && end > F2Dot14::ZERO) {
1399 continue;
1400 }
1401 if coord <= start || coord >= end {
1402 return None;
1403 }
1404 let coord = coord.to_fixed();
1405 let peak = peak.to_fixed();
1406 if coord < peak {
1407 let start = start.to_fixed();
1408 scalar = scalar.mul_div(coord - start, peak - start);
1409 } else {
1410 let end = end.to_fixed();
1411 scalar = scalar.mul_div(end - coord, end - peak);
1412 }
1413 } else {
1414 if coord < peak.min(F2Dot14::ZERO) || coord > peak.max(F2Dot14::ZERO) {
1415 return None;
1416 }
1417 let coord = coord.to_fixed();
1418 let peak = peak.to_fixed();
1419 scalar = scalar.mul_div(coord, peak);
1420 }
1421 }
1422 (scalar != Fixed::ZERO).then_some(scalar)
1423}
1424
1425#[derive(Clone, Debug)]
1426enum TupleDeltaValues<'a> {
1427 Points(DeltaRunIter<'a>, DeltaRunIter<'a>),
1429 Scalars(DeltaRunIter<'a>),
1430}
1431
1432#[derive(Clone, Debug)]
1434pub struct TupleDeltaIter<'a, T> {
1435 pub cur: usize,
1436 points: Option<PackedPointNumbersIter<'a>>,
1438 next_point: usize,
1439 values: TupleDeltaValues<'a>,
1440 _marker: std::marker::PhantomData<fn() -> T>,
1441}
1442
1443impl<'a, T> TupleDeltaIter<'a, T>
1444where
1445 T: TupleDelta,
1446{
1447 fn new(points: &PackedPointNumbers<'a>, deltas: PackedDeltas<'a>) -> TupleDeltaIter<'a, T> {
1448 let mut points = points.iter();
1449 let next_point = points.next();
1450 let values = if T::is_point() {
1451 TupleDeltaValues::Points(deltas.x_deltas(), deltas.y_deltas())
1452 } else {
1453 TupleDeltaValues::Scalars(deltas.iter())
1454 };
1455 TupleDeltaIter {
1456 cur: 0,
1457 points: next_point.map(|_| points),
1458 next_point: next_point.unwrap_or_default() as usize,
1459 values,
1460 _marker: std::marker::PhantomData,
1461 }
1462 }
1463}
1464
1465pub trait TupleDelta: Sized + Copy + 'static {
1467 fn is_point() -> bool;
1470
1471 fn new(position: u16, x: i32, y: i32) -> Self;
1474}
1475
1476impl<T> Iterator for TupleDeltaIter<'_, T>
1477where
1478 T: TupleDelta,
1479{
1480 type Item = T;
1481
1482 fn next(&mut self) -> Option<Self::Item> {
1483 let (position, dx, dy) = loop {
1484 let position = if let Some(points) = &mut self.points {
1485 if self.cur > self.next_point {
1487 self.next_point = points.next()? as usize;
1488 }
1489 self.next_point
1490 } else {
1491 self.cur
1493 };
1494 if position == self.cur {
1495 let (dx, dy) = match &mut self.values {
1496 TupleDeltaValues::Points(x, y) => (x.next()?, y.next()?),
1497 TupleDeltaValues::Scalars(scalars) => (scalars.next()?, 0),
1498 };
1499 break (position, dx, dy);
1500 }
1501 self.cur += 1;
1502 };
1503 self.cur += 1;
1504 Some(T::new(position as u16, dx, dy))
1505 }
1506}
1507
1508impl EntryFormat {
1509 pub fn entry_size(self) -> u8 {
1510 ((self.bits() & Self::MAP_ENTRY_SIZE_MASK.bits()) >> 4) + 1
1511 }
1512
1513 pub fn bit_count(self) -> u8 {
1514 (self.bits() & Self::INNER_INDEX_BIT_COUNT_MASK.bits()) + 1
1515 }
1516
1517 pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
1519 self.entry_size() as usize * map_count.into() as usize
1520 }
1521}
1522
1523impl DeltaSetIndexMap<'_> {
1524 pub fn get(&self, index: u32) -> Result<DeltaSetIndex, ReadError> {
1526 let (entry_format, map_count, data) = match self {
1527 Self::Format0(fmt) => (fmt.entry_format(), fmt.map_count() as u32, fmt.map_data()),
1528 Self::Format1(fmt) => (fmt.entry_format(), fmt.map_count(), fmt.map_data()),
1529 };
1530 if map_count == 0 {
1531 return Ok(DeltaSetIndex {
1532 outer: (index >> 16) as u16,
1533 inner: index as u16,
1534 });
1535 }
1536 let entry_size = entry_format.entry_size();
1537 let data = FontData::new(data);
1538 let index = index.min(map_count.saturating_sub(1));
1543 let offset = index as usize * entry_size as usize;
1544 let entry = match entry_size {
1545 1 => data.read_at::<u8>(offset)? as u32,
1546 2 => data.read_at::<u16>(offset)? as u32,
1547 3 => data.read_at::<Uint24>(offset)?.into(),
1548 4 => data.read_at::<u32>(offset)?,
1549 _ => {
1550 return Err(ReadError::MalformedData(
1551 "invalid entry size in DeltaSetIndexMap",
1552 ))
1553 }
1554 };
1555 let bit_count = entry_format.bit_count();
1556 Ok(DeltaSetIndex {
1557 outer: (entry >> bit_count) as u16,
1558 inner: (entry & ((1 << bit_count) - 1)) as u16,
1559 })
1560 }
1561}
1562
1563impl ItemVariationStore<'_> {
1564 pub fn compute_delta(&self, index: DeltaSetIndex, coords: &[F2Dot14]) -> Option<F48Dot16> {
1573 self.compute_delta_with_scalars(index, coords, &[])
1574 }
1575
1576 pub fn compute_delta_with_scalars(
1582 &self,
1583 index: DeltaSetIndex,
1584 coords: &[F2Dot14],
1585 scalars: &[Fixed],
1586 ) -> Option<F48Dot16> {
1587 if coords.is_empty() || index == DeltaSetIndex::NO_VARIATION_INDEX {
1588 return Some(F48Dot16::ZERO);
1589 }
1590 let data = match self.item_variation_data().get(index.outer as usize) {
1591 Some(data) => data.ok()?,
1592 None => return Some(F48Dot16::ZERO),
1593 };
1594 let region_indices = data.region_indexes();
1595 let mut regions = None;
1598 let mut accum = F48Dot16::ZERO;
1601 for (region_index, region_delta) in region_indices.iter().zip(data.delta_set(index.inner)) {
1604 let region_index = region_index.get() as usize;
1605 let scalar = match scalars.get(region_index) {
1606 Some(scalar) => *scalar,
1607 None => {
1608 let regions = match ®ions {
1609 Some(regions) => regions,
1610 None => {
1611 regions.insert(self.variation_region_list().ok()?.variation_regions())
1612 }
1613 };
1614 let region = regions.get(region_index).ok()?;
1615 if region_delta == 0 {
1618 continue;
1619 }
1620 region.compute_scalar(coords)
1621 }
1622 };
1623 accum += scalar.mul_i32(region_delta);
1628 }
1629 Some(accum)
1630 }
1631
1632 pub fn compute_scalars(&self, coords: &[F2Dot14], out: &mut [Fixed]) -> usize {
1646 let Ok(list) = self.variation_region_list() else {
1647 return 0;
1648 };
1649 let regions = list.variation_regions();
1650 let count = out.len().min(regions.len());
1651 for (i, out) in out[..count].iter_mut().enumerate() {
1652 let Ok(region) = regions.get(i) else {
1655 return i;
1656 };
1657 *out = region.compute_scalar(coords);
1658 }
1659 count
1660 }
1661}
1662
1663impl<'a> VariationRegion<'a> {
1664 pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Fixed {
1667 const ZERO: Fixed = Fixed::ZERO;
1668 let mut scalar = Fixed::ONE;
1669 for (i, peak, axis_coords) in self.active_region_axes() {
1670 let raw_coord = coords.get(i).copied().unwrap_or_default();
1677 if raw_coord == peak {
1678 continue;
1679 }
1680 let peak = peak.to_fixed();
1681 let start = axis_coords.start_coord.get().to_fixed();
1682 let end = axis_coords.end_coord.get().to_fixed();
1683 if start > peak || peak > end || start < ZERO && end > ZERO {
1684 continue;
1685 }
1686 let coord = raw_coord.to_fixed();
1687 if coord < start || coord > end {
1688 return ZERO;
1689 } else if coord < peak {
1690 scalar = scalar.mul_div(coord - start, peak - start);
1691 } else {
1692 scalar = scalar.mul_div(end - coord, end - peak);
1693 }
1694 }
1695 scalar
1696 }
1697
1698 fn active_region_axes(
1699 &self,
1700 ) -> impl Iterator<Item = (usize, F2Dot14, &'a RegionAxisCoordinates)> {
1701 self.region_axes()
1702 .iter()
1703 .enumerate()
1704 .filter_map(|(i, axis_coords)| {
1705 let peak = axis_coords.peak_coord();
1706 if peak != F2Dot14::ZERO {
1707 Some((i, peak, axis_coords))
1708 } else {
1709 None
1710 }
1711 })
1712 }
1713}
1714
1715impl<'a> ItemVariationData<'a> {
1716 pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
1719 let word_delta_count = self.word_delta_count();
1720 let region_count = self.region_index_count();
1721 let bytes_per_row = Self::delta_row_len(word_delta_count, region_count);
1722 let long_words = word_delta_count & 0x8000 != 0;
1723 let word_delta_count = word_delta_count & 0x7FFF;
1724
1725 let offset = bytes_per_row * inner_index as usize;
1726 ItemDeltas {
1727 bytes: self.delta_sets().get(offset..).unwrap_or_default().iter(),
1728 word_delta_count,
1729 long_words,
1730 len: region_count,
1731 pos: 0,
1732 }
1733 }
1734
1735 pub fn get_delta_row_len(&self) -> usize {
1736 let word_delta_count = self.word_delta_count();
1737 let region_count = self.region_index_count();
1738 Self::delta_row_len(word_delta_count, region_count)
1739 }
1740
1741 pub fn delta_row_len(word_delta_count: u16, region_index_count: u16) -> usize {
1743 let region_count = region_index_count as usize;
1744 let long_words = word_delta_count & 0x8000 != 0;
1745 let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
1746 let long_delta_count = (word_delta_count & 0x7FFF) as usize;
1747 let short_delta_count = region_count.saturating_sub(long_delta_count);
1748 long_delta_count * word_size + short_delta_count * small_size
1749 }
1750
1751 pub fn delta_sets_len(
1753 item_count: u16,
1754 word_delta_count: u16,
1755 region_index_count: u16,
1756 ) -> usize {
1757 let bytes_per_row = Self::delta_row_len(word_delta_count, region_index_count);
1758 bytes_per_row * item_count as usize
1759 }
1760}
1761
1762#[derive(Clone)]
1763struct ItemDeltas<'a> {
1764 bytes: core::slice::Iter<'a, u8>,
1765 word_delta_count: u16,
1766 long_words: bool,
1767 len: u16,
1768 pos: u16,
1769}
1770
1771impl Iterator for ItemDeltas<'_> {
1772 type Item = i32;
1773
1774 fn next(&mut self) -> Option<Self::Item> {
1775 if self.pos >= self.len {
1776 return None;
1777 }
1778 let pos = self.pos;
1779 self.pos += 1;
1780 let mut byte = || self.bytes.next().copied();
1781 let value = match (pos >= self.word_delta_count, self.long_words) {
1782 (true, true) | (false, false) => i16::from_be_bytes([byte()?, byte()?]) as i32,
1783 (true, false) => byte()? as i8 as i32,
1784 (false, true) => i32::from_be_bytes([byte()?, byte()?, byte()?, byte()?]),
1785 };
1786 Some(value)
1787 }
1788}
1789
1790pub(crate) fn advance_delta_with_scalars(
1795 dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1796 ivs: Result<ItemVariationStore, ReadError>,
1797 glyph_id: GlyphId,
1798 coords: &[F2Dot14],
1799 scalars: &[Fixed],
1800) -> Option<F48Dot16> {
1801 if coords.is_empty() {
1802 return Some(F48Dot16::ZERO);
1803 }
1804 let gid = glyph_id.to_u32();
1805 let ix = match dsim {
1806 Some(Ok(dsim)) => dsim.get(gid).ok()?,
1807 _ if gid > u16::MAX as u32 => return Some(F48Dot16::ZERO),
1810 _ => DeltaSetIndex {
1811 outer: 0,
1812 inner: gid as _,
1813 },
1814 };
1815 ivs.ok()?.compute_delta_with_scalars(ix, coords, scalars)
1816}
1817
1818pub(crate) fn item_delta_with_scalars(
1823 dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1824 ivs: Result<ItemVariationStore, ReadError>,
1825 glyph_id: GlyphId,
1826 coords: &[F2Dot14],
1827 scalars: &[Fixed],
1828) -> Option<F48Dot16> {
1829 if coords.is_empty() {
1830 return Some(F48Dot16::ZERO);
1831 }
1832 let gid = glyph_id.to_u32();
1833 let ix = match dsim {
1834 Some(Ok(dsim)) => dsim.get(gid).ok()?,
1835 _ => return None,
1836 };
1837 ivs.ok()?.compute_delta_with_scalars(ix, coords, scalars)
1838}
1839
1840#[cfg(test)]
1841mod tests {
1842 use font_test_data::bebuffer::BeBuffer;
1843
1844 use super::*;
1845 use crate::{FontRef, TableProvider};
1846
1847 #[test]
1848 fn zero_deltas_still_validate_their_regions() {
1849 let store_bytes = |indices: [u16; 2]| {
1850 BeBuffer::new()
1851 .push(1u16) .push(12u32) .push(1u16) .push(28u32) .push(1u16) .push(2u16) .extend([F2Dot14::ZERO, F2Dot14::ONE, F2Dot14::ONE])
1858 .extend([F2Dot14::NEG_ONE, F2Dot14::NEG_ONE, F2Dot14::ZERO])
1859 .push(2u16) .push(2u16) .push(2u16) .extend(indices)
1863 .extend([0i16, 120, -40, 0])
1864 };
1865 let bytes = store_bytes([0, 1]);
1866 let store = ItemVariationStore::read(FontData::new(&bytes)).unwrap();
1867 for coord in [-1.0, -0.25, 0.0, 0.25, 1.0] {
1868 let coords = [F2Dot14::from_f32(coord)];
1869 let mut scalars = [Fixed::ZERO; 2];
1870 assert_eq!(store.compute_scalars(&coords, &mut scalars), 2);
1871 for (inner, expected) in [120.0 * (-coord).max(0.0), -40.0 * coord.max(0.0)]
1872 .into_iter()
1873 .enumerate()
1874 {
1875 let index = DeltaSetIndex {
1876 outer: 0,
1877 inner: inner as u16,
1878 };
1879 let expected = Some(F48Dot16::from_f64(expected as f64));
1880 assert_eq!(store.compute_delta(index, &coords), expected);
1881 for count in 0..=2 {
1882 assert_eq!(
1883 store.compute_delta_with_scalars(index, &coords, &scalars[..count]),
1884 expected
1885 );
1886 }
1887 }
1888 }
1889 for (indices, inner) in [([2, 1], 0), ([0, 2], 1)] {
1891 let bytes = store_bytes(indices);
1892 let store = ItemVariationStore::read(FontData::new(&bytes)).unwrap();
1893 assert_eq!(
1894 store.compute_delta(DeltaSetIndex { outer: 0, inner }, &[F2Dot14::ONE]),
1895 None
1896 );
1897 }
1898 }
1899
1900 #[test]
1901 fn implicit_advance_indices_do_not_truncate_glyph_ids() {
1902 let bytes = BeBuffer::new()
1903 .push(1u16) .push(12u32) .push(1u16) .push(22u32) .push(1u16) .push(1u16) .extend([F2Dot14::ZERO, F2Dot14::ONE, F2Dot14::ONE])
1910 .push(2u16) .push(1u16) .push(1u16) .push(0u16) .extend([10i16, 100i16]);
1915 let store = ItemVariationStore::read(FontData::new(&bytes)).unwrap();
1916 let mapping = DeltaSetIndexMap::read(FontData::new(&[0, 0, 0, 1, 0])).unwrap();
1917 let coords = [F2Dot14::from_f32(0.75)];
1918 let mut scalars = [Fixed::ZERO; 32];
1919 let scalar_count = store.compute_scalars(&coords, &mut scalars);
1920 for scalars in [&[][..], &scalars[..scalar_count]] {
1921 let delta = advance_delta_with_scalars(
1922 None,
1923 Ok(store.clone()),
1924 GlyphId::new(1),
1925 &coords,
1926 scalars,
1927 );
1928 assert!(delta.is_some_and(|delta| delta != F48Dot16::ZERO));
1929 for gid in [0xFFFF, 0x10000, 0x10001, 0xFFFF0001] {
1930 assert_eq!(
1931 advance_delta_with_scalars(
1932 None,
1933 Ok(store.clone()),
1934 GlyphId::new(gid),
1935 &coords,
1936 scalars,
1937 ),
1938 Some(F48Dot16::ZERO),
1939 "implicit advance mapping wrapped glyph ID {gid}"
1940 );
1941 }
1942 for gid in [0x10000, 0x10001] {
1944 assert_eq!(
1945 advance_delta_with_scalars(
1946 Some(Ok(mapping.clone())),
1947 Ok(store.clone()),
1948 GlyphId::new(gid),
1949 &coords,
1950 scalars,
1951 ),
1952 Some(F48Dot16::from_f64(7.5))
1953 );
1954 }
1955 }
1956 }
1957
1958 #[test]
1959 fn ivs_regions() {
1960 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1961 let hvar = font.hvar().expect("missing HVAR table");
1962 let ivs = hvar
1963 .item_variation_store()
1964 .expect("missing item variation store in HVAR");
1965 let region_list = ivs.variation_region_list().expect("missing region list!");
1966 let regions = region_list.variation_regions();
1967 let expected = &[
1968 vec![[-1.0f32, -1.0, 0.0]],
1970 vec![[0.0, 1.0, 1.0]],
1971 ][..];
1972 let region_coords = regions
1973 .iter()
1974 .map(|region| {
1975 region
1976 .unwrap()
1977 .region_axes()
1978 .iter()
1979 .map(|coords| {
1980 [
1981 coords.start_coord().to_f32(),
1982 coords.peak_coord().to_f32(),
1983 coords.end_coord().to_f32(),
1984 ]
1985 })
1986 .collect::<Vec<_>>()
1987 })
1988 .collect::<Vec<_>>();
1989 assert_eq!(expected, ®ion_coords);
1990 }
1991
1992 #[test]
1998 fn scalar_for_ignores_invalid_intermediate_region() {
1999 fn tuple(values: &[BigEndian<F2Dot14>]) -> Tuple<'_> {
2000 Tuple { values }
2001 }
2002 let f = F2Dot14::from_f32;
2003
2004 let peak: [BigEndian<F2Dot14>; 1] = [f(0.5).into()];
2008 let start: [BigEndian<F2Dot14>; 1] = [f(0.8).into()];
2009 let end: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2010 let coords = [f(0.9)];
2011 assert_eq!(
2012 scalar_for(&tuple(&peak), Some((tuple(&start), tuple(&end))), &coords),
2013 Some(Fixed::ONE)
2014 );
2015
2016 let peak2: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2018 let start2: [BigEndian<F2Dot14>; 1] = [f(0.0).into()];
2019 let end2: [BigEndian<F2Dot14>; 1] = [f(0.5).into()];
2020 let coords2 = [f(0.25)];
2021 assert_eq!(
2022 scalar_for(
2023 &tuple(&peak2),
2024 Some((tuple(&start2), tuple(&end2))),
2025 &coords2
2026 ),
2027 Some(Fixed::ONE)
2028 );
2029
2030 let start3: [BigEndian<F2Dot14>; 1] = [f(-0.5).into()];
2032 let end3: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2033 let coords3 = [f(0.25)];
2034 assert_eq!(
2035 scalar_for(
2036 &tuple(&peak),
2037 Some((tuple(&start3), tuple(&end3))),
2038 &coords3
2039 ),
2040 Some(Fixed::ONE)
2041 );
2042
2043 let start4: [BigEndian<F2Dot14>; 1] = [f(0.0).into()];
2045 let end4: [BigEndian<F2Dot14>; 1] = [f(1.0).into()];
2046 let coords4 = [f(0.25)];
2047 let scalar = scalar_for(
2048 &tuple(&peak),
2049 Some((tuple(&start4), tuple(&end4))),
2050 &coords4,
2051 )
2052 .unwrap();
2053 assert!((scalar.to_f32() - 0.5).abs() < 1e-4);
2054 }
2055
2056 #[test]
2058 fn packed_points() {
2059 fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
2060 let data = FontData::new(bytes);
2061 let packed = PackedPointNumbers { data };
2062 if packed.count() == 0 {
2063 None
2064 } else {
2065 Some(packed.iter().collect())
2066 }
2067 }
2068
2069 assert_eq!(decode_points(&[0]), None);
2070 assert_eq!(decode_points(&[0x80, 0]), None);
2072 assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
2074 assert_eq!(
2076 decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
2077 Some(vec![0xbeef, 0xcafe])
2078 );
2079 assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
2081 assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
2083 assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
2085 assert_eq!(
2087 decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
2088 Some(vec![7, 8, 263, 265])
2089 );
2090 }
2091
2092 #[test]
2093 fn packed_point_byte_len() {
2094 fn count_bytes(bytes: &[u8]) -> usize {
2095 let packed = PackedPointNumbers {
2096 data: FontData::new(bytes),
2097 };
2098 packed.total_len()
2099 }
2100
2101 static CASES: &[&[u8]] = &[
2102 &[0],
2103 &[0x80, 0],
2104 &[0x02, 0x01, 0x09, 0x06],
2105 &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
2106 &[0x01, 0, 0x07],
2107 &[0x01, 0x80, 0, 0x07],
2108 &[0x01, 0x80, 0xff, 0xff],
2109 &[0x04, 1, 7, 1, 1, 0xff, 2],
2110 ];
2111
2112 for case in CASES {
2113 assert_eq!(count_bytes(case), case.len(), "{case:?}");
2114 }
2115 }
2116
2117 #[test]
2119 fn packed_deltas() {
2120 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2121
2122 let deltas = PackedDeltas::consume_all(INPUT);
2123 assert_eq!(deltas.count_or_compute(), 7);
2124 assert_eq!(
2125 deltas.iter().collect::<Vec<_>>(),
2126 &[0, 0, 0, 0, 258, -127, -128]
2127 );
2128
2129 assert_eq!(
2130 PackedDeltas::consume_all(FontData::new(&[0x81]))
2131 .iter()
2132 .collect::<Vec<_>>(),
2133 &[0, 0,]
2134 );
2135 }
2136
2137 #[test]
2139 fn packed_deltas_spec() {
2140 static INPUT: FontData = FontData::new(&[
2141 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2142 ]);
2143 static EXPECTED: &[i32] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
2144
2145 let deltas = PackedDeltas::consume_all(INPUT);
2146 assert_eq!(deltas.count_or_compute(), EXPECTED.len());
2147 assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
2148 }
2149
2150 #[test]
2151 fn packed_delta_fetcher_skip_matches_iterator_suffix() {
2152 static INPUT: FontData = FontData::new(&[
2153 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2154 ]);
2155 let deltas = PackedDeltas::consume_all(INPUT);
2156 let expected = deltas.iter().collect::<Vec<_>>();
2157
2158 for skip in 0..=expected.len() {
2159 let mut fetcher = deltas.fetcher();
2160 fetcher.skip(skip).unwrap();
2161 let mut out = vec![0.0; expected.len() - skip];
2162 fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
2163 let got = out.into_iter().map(|v| v as i32).collect::<Vec<_>>();
2164 assert_eq!(&got[..], &expected[skip..], "skip={skip}");
2165 }
2166
2167 let mut fetcher = deltas.fetcher();
2168 assert!(matches!(
2169 fetcher.skip(expected.len() + 1),
2170 Err(ReadError::OutOfBounds)
2171 ));
2172 }
2173
2174 #[test]
2175 fn packed_delta_fetcher_scaled_add_and_exhaustion() {
2176 static INPUT: FontData = FontData::new(&[
2177 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2178 ]);
2179 let deltas = PackedDeltas::new(INPUT, 4);
2181 let mut fetcher = deltas.fetcher();
2182 let mut out = [1.0f32; 4];
2183 fetcher.add_to_f32_scaled(&mut out, 0.5).unwrap();
2184 assert_eq!(out, [6.0, -51.5, 1.0, -28.0]);
2185
2186 let mut extra = [0.0f32; 1];
2188 assert!(matches!(
2189 fetcher.add_to_f32_scaled(&mut extra, 1.0),
2190 Err(ReadError::OutOfBounds)
2191 ));
2192 }
2193
2194 #[test]
2195 fn packed_delta_fetcher_f64_preserves_i32_residuals() {
2196 static INPUT: FontData =
2197 FontData::new(&[0xC1, 0x01, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00]);
2198 let mut fetcher = PackedDeltas::new(INPUT, 2).fetcher();
2199 let mut out = [0.0f64];
2200 fetcher.add_to_f64_scaled(&mut out, 0.5).unwrap();
2201 fetcher.add_to_f64_scaled(&mut out, 0.5).unwrap();
2202 assert_eq!(out, [0.5]);
2203 assert!(matches!(
2204 fetcher.add_to_f64_scaled(&mut out, 1.0),
2205 Err(ReadError::OutOfBounds)
2206 ));
2207 }
2208
2209 #[test]
2210 fn packed_delta_fetcher_skip_then_add_bounded() {
2211 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2212 let deltas = PackedDeltas::new(INPUT, 7);
2214 let mut fetcher = deltas.fetcher();
2215 fetcher.skip(3).unwrap();
2216 let mut out = [0.0f32; 4];
2217 fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
2218 assert_eq!(out, [0.0, 258.0, -127.0, -128.0]);
2219 }
2220
2221 #[test]
2222 fn delta_run_iter_end_exhausts_unbounded_data() {
2223 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2224 let deltas = PackedDeltas::consume_all(INPUT);
2225 let end = deltas.iter().end();
2226 assert_eq!(end.remaining_bytes(), 0);
2227 }
2228
2229 #[test]
2230 fn delta_run_iter_end_respects_bounded_count() {
2231 static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
2232 let deltas = PackedDeltas::new(INPUT, 4);
2235 let end = deltas.iter().end();
2236 assert_eq!(end.remaining_bytes(), INPUT.len() - 1);
2237
2238 let end_via_skip = deltas.iter().skip_fast(4).cursor;
2239 assert_eq!(end_via_skip.remaining_bytes(), INPUT.len() - 1);
2240 }
2241
2242 #[test]
2243 fn delta_run_iter_end_matches_manual_iteration_for_bounded_data() {
2244 static INPUT: FontData = FontData::new(&[
2245 0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
2246 ]);
2247 let deltas = PackedDeltas::new(INPUT, 6);
2248
2249 let iter_collected = deltas.iter().collect::<Vec<_>>();
2250 assert_eq!(iter_collected.len(), 6);
2251
2252 let end = deltas.iter().end();
2253 let end_via_skip = deltas.iter().skip_fast(6).cursor;
2254 assert_eq!(end.remaining_bytes(), end_via_skip.remaining_bytes());
2255 }
2256
2257 fn lcg_next(state: &mut u32) -> u32 {
2258 *state = state.wrapping_mul(1664525).wrapping_add(1013904223);
2259 *state
2260 }
2261
2262 fn generated_delta_stream(seed: u32) -> (Vec<u8>, Vec<i32>) {
2263 let mut state = seed;
2264 let mut bytes = Vec::new();
2265 let mut expected = Vec::new();
2266 let run_count = (lcg_next(&mut state) % 6 + 1) as usize;
2267 for _ in 0..run_count {
2268 let run_type = (lcg_next(&mut state) % 4) as usize;
2269 let len = (lcg_next(&mut state) % 8 + 1) as usize;
2270 let control = match run_type {
2271 0 => (len - 1) as u8, 1 => 0x40 | (len - 1) as u8, 2 => 0x80 | (len - 1) as u8, _ => 0xC0 | (len - 1) as u8, };
2276 bytes.push(control);
2277 match run_type {
2278 0 => {
2279 for _ in 0..len {
2280 let v = ((lcg_next(&mut state) % 255) as i32 - 127) as i8;
2281 bytes.push(v as u8);
2282 expected.push(v as i32);
2283 }
2284 }
2285 1 => {
2286 for _ in 0..len {
2287 let v = ((lcg_next(&mut state) % 65535) as i32 - 32767) as i16;
2288 bytes.extend(v.to_be_bytes());
2289 expected.push(v as i32);
2290 }
2291 }
2292 2 => {
2293 expected.resize(expected.len() + len, 0);
2294 }
2295 _ => {
2296 for _ in 0..len {
2297 let v = (lcg_next(&mut state) % 2_000_001) as i32 - 1_000_000;
2298 bytes.extend(v.to_be_bytes());
2299 expected.push(v);
2300 }
2301 }
2302 }
2303 }
2304 (bytes, expected)
2305 }
2306
2307 #[test]
2308 fn generated_packed_deltas_iter_matches_expected() {
2309 for seed in 1..=64 {
2310 let (bytes, expected) = generated_delta_stream(seed);
2311 let data = FontData::new(&bytes);
2312 let deltas = PackedDeltas::consume_all(data);
2313 assert_eq!(deltas.count_or_compute(), expected.len(), "seed={seed}");
2314 assert_eq!(deltas.iter().collect::<Vec<_>>(), expected, "seed={seed}");
2315 }
2316 }
2317
2318 #[test]
2319 fn generated_fetcher_skip_scaled_matches_expected() {
2320 for seed in 1..=64 {
2321 let (bytes, expected) = generated_delta_stream(seed);
2322 let data = FontData::new(&bytes);
2323 let deltas = PackedDeltas::new(data, expected.len());
2324 let mut fetcher = deltas.fetcher();
2325 let skip = (seed as usize * 7) % (expected.len() + 1);
2326 fetcher.skip(skip).unwrap();
2327
2328 let scale = if seed % 2 == 0 { 0.25 } else { -0.5 };
2329 let mut out = vec![10.0f32; expected.len() - skip];
2330 fetcher.add_to_f32_scaled(&mut out, scale).unwrap();
2331 for (i, got) in out.iter().copied().enumerate() {
2332 let want = 10.0 + expected[skip + i] as f32 * scale;
2333 assert!(
2334 (got - want).abs() <= 1e-6,
2335 "seed={seed} i={i} got={got} want={want}"
2336 );
2337 }
2338
2339 let mut extra = [0.0f32; 1];
2341 assert!(matches!(
2342 fetcher.add_to_f32_scaled(&mut extra, 1.0),
2343 Err(ReadError::OutOfBounds)
2344 ));
2345 }
2346 }
2347
2348 #[test]
2349 fn packed_point_split() {
2350 static INPUT: FontData =
2351 FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
2352 let (points, data) = PackedPointNumbers::split_off_front(INPUT);
2353 assert_eq!(points.count(), 2);
2354 assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
2355 assert_eq!(points.total_len(), 4);
2356 assert_eq!(data.len(), INPUT.len() - 4);
2357 }
2358
2359 #[test]
2360 fn packed_points_dont_panic() {
2361 static ALL_POINTS: FontData = FontData::new(&[0]);
2363 let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
2364 assert_eq!(all_points.iter().count(), u16::MAX as usize);
2366 }
2367
2368 #[test]
2371 fn packed_delta_run_crosses_coord_boundary() {
2372 static INPUT: FontData = FontData::new(&[
2375 5,
2377 0,
2378 1,
2379 2,
2380 3,
2381 4,
2383 5,
2384 1 | DELTAS_ARE_WORDS,
2386 0,
2387 6,
2388 0,
2389 7,
2390 ]);
2391 let deltas = PackedDeltas::consume_all(INPUT);
2392 assert_eq!(deltas.count_or_compute(), 8);
2393 let x_deltas = deltas.x_deltas().collect::<Vec<_>>();
2394 let y_deltas = deltas.y_deltas().collect::<Vec<_>>();
2395 assert_eq!(x_deltas, [0, 1, 2, 3]);
2396 assert_eq!(y_deltas, [4, 5, 6, 7]);
2397 }
2398
2399 #[test]
2403 fn ivs_float_deltas_nearly_match_fixed_deltas() {
2404 let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
2405 let axis_count = font.fvar().unwrap().axis_count() as usize;
2406 let colr = font.colr().unwrap();
2407 let ivs = colr.item_variation_store().unwrap().unwrap();
2408 for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
2410 let coords = vec![coord; axis_count];
2412 for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
2413 let outer_ix = outer_ix as u16;
2414 let Some(Ok(data)) = data else {
2415 continue;
2416 };
2417 for inner_ix in 0..data.item_count() {
2418 let delta_ix = DeltaSetIndex {
2419 outer: outer_ix,
2420 inner: inner_ix,
2421 };
2422 let delta = ivs.compute_delta(delta_ix, &coords).unwrap();
2424 let orig_delta = delta.to_i32();
2425 let float_delta = delta.to_f64();
2426
2427 assert!(
2431 orig_delta == float_delta.round() as i32
2432 || orig_delta == float_delta.trunc() as i32
2433 );
2434 const EPSILON: f32 = 1e12;
2436 let fixed_delta = Fixed::ZERO.apply_delta(delta);
2437 assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
2438 let f2dot14_delta = F2Dot14::ZERO.apply_delta(delta);
2439 assert!(
2440 (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
2441 < EPSILON
2442 );
2443 }
2444 }
2445 }
2446 }
2447
2448 #[test]
2449 fn ivs_data_len_short() {
2450 let data = BeBuffer::new()
2451 .push(2u16) .push(3u16) .push(5u16) .extend([0u16, 1, 2, 3, 4]) .extend([1u8; 128]); let ivs = ItemVariationData::read(data.data().into()).unwrap();
2458 let row_len = (3 * u16::RAW_BYTE_LEN) + (2 * u8::RAW_BYTE_LEN); let expected_len = 2 * row_len;
2460 assert_eq!(ivs.delta_sets().len(), expected_len);
2461 }
2462
2463 #[test]
2464 fn ivs_data_len_long() {
2465 let data = BeBuffer::new()
2466 .push(2u16) .push(2u16 | 0x8000) .push(4u16) .extend([0u16, 1, 2]) .extend([1u8; 128]); let ivs = ItemVariationData::read(data.data().into()).unwrap();
2473 let row_len = (2 * u32::RAW_BYTE_LEN) + (2 * u16::RAW_BYTE_LEN); let expected_len = 2 * row_len;
2475 assert_eq!(ivs.delta_sets().len(), expected_len);
2476 }
2477
2478 #[test]
2481 fn packed_point_numbers_avoid_overflow() {
2482 let buf = vec![0xFF; 0xFFFF];
2484 let iter = PackedPointNumbersIter::new(0xFFFF, FontData::new(&buf).cursor());
2485 let _ = iter.count();
2487 }
2488
2489 #[test]
2491 fn accumulate_dense() {
2492 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2493 let gvar = font.gvar().unwrap();
2494 let gvar_data = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
2495 let mut count = 0;
2496 for tuple in gvar_data.tuples() {
2497 if !tuple.has_deltas_for_all_points() {
2498 continue;
2499 }
2500 let iter_deltas = tuple
2501 .deltas()
2502 .map(|delta| (delta.x_delta, delta.y_delta))
2503 .collect::<Vec<_>>();
2504 let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); iter_deltas.len()];
2505 tuple
2506 .accumulate_dense_deltas(&mut delta_buf, Fixed::ONE)
2507 .unwrap();
2508 let accum_deltas = delta_buf
2509 .iter()
2510 .map(|delta| (delta.x.to_i32(), delta.y.to_i32()))
2511 .collect::<Vec<_>>();
2512 assert_eq!(iter_deltas, accum_deltas);
2513 count += iter_deltas.len();
2514 }
2515 assert!(count != 0);
2516 }
2517
2518 #[test]
2520 fn accumulate_sparse() {
2521 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2522 let gvar = font.gvar().unwrap();
2523 let gvar_data = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
2524 let mut count = 0;
2525 for tuple in gvar_data.tuples() {
2526 if tuple.has_deltas_for_all_points() {
2527 continue;
2528 }
2529 let iter_deltas = tuple.deltas().collect::<Vec<_>>();
2530 let max_modified_point = iter_deltas
2531 .iter()
2532 .max_by_key(|delta| delta.position)
2533 .unwrap()
2534 .position as usize;
2535 let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); max_modified_point + 1];
2536 let mut flags = vec![PointFlags::default(); delta_buf.len()];
2537 tuple
2538 .accumulate_sparse_deltas(&mut delta_buf, &mut flags, Fixed::ONE)
2539 .unwrap();
2540 let mut accum_deltas = vec![];
2541 for (i, (delta, flag)) in delta_buf.iter().zip(flags).enumerate() {
2542 if flag.has_marker(PointMarker::HAS_DELTA) {
2543 accum_deltas.push(GlyphDelta::new(
2544 i as u16,
2545 delta.x.to_i32(),
2546 delta.y.to_i32(),
2547 ));
2548 }
2549 }
2550 assert_eq!(iter_deltas, accum_deltas);
2551 count += iter_deltas.len();
2552 }
2553 assert!(count != 0);
2554 }
2555
2556 #[test]
2557 fn delta_set_index_map_empty_is_identity() {
2558 let data = BeBuffer::new()
2559 .push(0u8) .push(EntryFormat::empty())
2561 .push(0u16); let map = DeltaSetIndexMap::read(data.data().into()).unwrap();
2563 assert_eq!(
2564 map.get(0x0001_0002).unwrap(),
2565 DeltaSetIndex { outer: 1, inner: 2 }
2566 );
2567 }
2568}