1 //! OpenType font variations common tables.
2 
3 include!("../../generated/generated_variations.rs");
4 
5 /// Outer and inner indices for reading from an [ItemVariationStore].
6 #[derive(Copy, Clone, Debug)]
7 pub struct DeltaSetIndex {
8     /// Outer delta set index.
9     pub outer: u16,
10     /// Inner delta set index.
11     pub inner: u16,
12 }
13 
14 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
15 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16 pub struct TupleIndex(u16);
17 
18 impl TupleIndex {
19     /// Flag indicating that this tuple variation header includes an embedded
20     /// peak tuple record, immediately after the tupleIndex field.
21     ///
22     /// If set, the low 12 bits of the tupleIndex value are ignored.
23     ///
24     /// Note that this must always be set within the 'cvar' table.
25     pub const EMBEDDED_PEAK_TUPLE: u16 = 0x8000;
26 
27     /// Flag indicating that this tuple variation table applies to an
28     /// intermediate region within the variation space.
29     ///
30     /// If set, the header includes the two intermediate-region, start and end
31     /// tuple records, immediately after the peak tuple record (if present).
32     pub const INTERMEDIATE_REGION: u16 = 0x4000;
33     /// Flag indicating that the serialized data for this tuple variation table
34     /// includes packed “point” number data.
35     ///
36     /// If set, this tuple variation table uses that number data; if clear,
37     /// this tuple variation table uses shared number data found at the start
38     /// of the serialized data for this glyph variation data or 'cvar' table.
39     pub const PRIVATE_POINT_NUMBERS: u16 = 0x2000;
40     //0x1000	Reserved	Reserved for future use — set to 0.
41     //
42     /// Mask for the low 12 bits to give the shared tuple records index.
43     pub const TUPLE_INDEX_MASK: u16 = 0x0FFF;
44 
tuple_len(self, axis_count: u16, flag: usize) -> usize45     fn tuple_len(self, axis_count: u16, flag: usize) -> usize {
46         match flag {
47             0 => self.embedded_peak_tuple(),
48             1 => self.intermediate_region(),
49             _ => panic!("only 0 or 1 allowed here"),
50         }
51         .then_some(axis_count as usize)
52         .unwrap_or_default()
53     }
54 
bits(self) -> u1655     pub fn bits(self) -> u16 {
56         self.0
57     }
58 
from_bits(bits: u16) -> Self59     pub fn from_bits(bits: u16) -> Self {
60         TupleIndex(bits)
61     }
62 
63     /// `true` if the header includes an embedded peak tuple.
embedded_peak_tuple(self) -> bool64     pub fn embedded_peak_tuple(self) -> bool {
65         (self.0 & Self::EMBEDDED_PEAK_TUPLE) != 0
66     }
67 
68     /// `true` if the header includes the two intermediate region tuple records.
intermediate_region(self) -> bool69     pub fn intermediate_region(self) -> bool {
70         (self.0 & Self::INTERMEDIATE_REGION) != 0
71     }
72 
73     /// `true` if the data for this table includes packed point number data.
private_point_numbers(self) -> bool74     pub fn private_point_numbers(self) -> bool {
75         (self.0 & Self::PRIVATE_POINT_NUMBERS) != 0
76     }
77 
tuple_records_index(self) -> Option<u16>78     pub fn tuple_records_index(self) -> Option<u16> {
79         (!self.embedded_peak_tuple()).then_some(self.0 & Self::TUPLE_INDEX_MASK)
80     }
81 }
82 
83 impl types::Scalar for TupleIndex {
84     type Raw = <u16 as types::Scalar>::Raw;
to_raw(self) -> Self::Raw85     fn to_raw(self) -> Self::Raw {
86         self.0.to_raw()
87     }
from_raw(raw: Self::Raw) -> Self88     fn from_raw(raw: Self::Raw) -> Self {
89         let t = <u16>::from_raw(raw);
90         Self(t)
91     }
92 }
93 
94 /// The 'tupleVariationCount' field of the [Tuple Variation Store Header][header]
95 ///
96 /// The high 4 bits are flags, and the low 12 bits are the number of tuple
97 /// variation tables for this glyph. The count can be any number between 1 and 4095.
98 ///
99 /// [header]: https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-variation-store-header
100 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
101 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
102 pub struct TupleVariationCount(u16);
103 
104 impl TupleVariationCount {
105     /// Flag indicating that some or all tuple variation tables reference a
106     /// shared set of “point” numbers.
107     ///
108     /// These shared numbers are represented as packed point number data at the
109     /// start of the serialized data.
110     pub const SHARED_POINT_NUMBERS: u16 = 0x8000;
111 
112     /// Mask for the low 12 bits to give the shared tuple records index.
113     pub const COUNT_MASK: u16 = 0x0FFF;
114 
bits(self) -> u16115     pub fn bits(self) -> u16 {
116         self.0
117     }
118 
from_bits(bits: u16) -> Self119     pub fn from_bits(bits: u16) -> Self {
120         Self(bits)
121     }
122 
123     /// `true` if any tables reference a shared set of point numbers
shared_point_numbers(self) -> bool124     pub fn shared_point_numbers(self) -> bool {
125         (self.0 & Self::SHARED_POINT_NUMBERS) != 0
126     }
127 
count(self) -> u16128     pub fn count(self) -> u16 {
129         self.0 & Self::COUNT_MASK
130     }
131 }
132 
133 impl types::Scalar for TupleVariationCount {
134     type Raw = <u16 as types::Scalar>::Raw;
to_raw(self) -> Self::Raw135     fn to_raw(self) -> Self::Raw {
136         self.0.to_raw()
137     }
from_raw(raw: Self::Raw) -> Self138     fn from_raw(raw: Self::Raw) -> Self {
139         let t = <u16>::from_raw(raw);
140         Self(t)
141     }
142 }
143 
144 impl<'a> TupleVariationHeader<'a> {
145     #[cfg(feature = "traversal")]
traverse_tuple_index(&self) -> traversal::FieldType<'a>146     fn traverse_tuple_index(&self) -> traversal::FieldType<'a> {
147         self.tuple_index().0.into()
148     }
149 
150     /// Peak tuple record for this tuple variation table — optional,
151     /// determined by flags in the tupleIndex value.  Note that this
152     /// must always be included in the 'cvar' table.
peak_tuple(&self) -> Option<Tuple<'a>>153     pub fn peak_tuple(&self) -> Option<Tuple<'a>> {
154         self.tuple_index().embedded_peak_tuple().then(|| {
155             let range = self.shape.peak_tuple_byte_range();
156             Tuple {
157                 values: self.data.read_array(range).unwrap(),
158             }
159         })
160     }
161 
162     /// Intermediate start tuple record for this tuple variation table
163     /// — optional, determined by flags in the tupleIndex value.
intermediate_start_tuple(&self) -> Option<Tuple<'a>>164     pub fn intermediate_start_tuple(&self) -> Option<Tuple<'a>> {
165         self.tuple_index().intermediate_region().then(|| {
166             let range = self.shape.intermediate_start_tuple_byte_range();
167             Tuple {
168                 values: self.data.read_array(range).unwrap(),
169             }
170         })
171     }
172 
173     /// Intermediate end tuple record for this tuple variation table
174     /// — optional, determined by flags in the tupleIndex value.
intermediate_end_tuple(&self) -> Option<Tuple<'a>>175     pub fn intermediate_end_tuple(&self) -> Option<Tuple<'a>> {
176         self.tuple_index().intermediate_region().then(|| {
177             let range = self.shape.intermediate_end_tuple_byte_range();
178             Tuple {
179                 values: self.data.read_array(range).unwrap(),
180             }
181         })
182     }
183 
184     /// Compute the actual length of this table in bytes
byte_len(&self, axis_count: u16) -> usize185     fn byte_len(&self, axis_count: u16) -> usize {
186         const FIXED_LEN: usize = u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN;
187         let tuple_byte_len = F2Dot14::RAW_BYTE_LEN * axis_count as usize;
188         let index = self.tuple_index();
189         FIXED_LEN
190             + index
191                 .embedded_peak_tuple()
192                 .then_some(tuple_byte_len)
193                 .unwrap_or_default()
194             + index
195                 .intermediate_region()
196                 .then_some(tuple_byte_len * 2)
197                 .unwrap_or_default()
198     }
199 }
200 
201 impl<'a> Tuple<'a> {
len(&self) -> usize202     pub fn len(&self) -> usize {
203         self.values().len()
204     }
205 
is_empty(&self) -> bool206     pub fn is_empty(&self) -> bool {
207         self.values.is_empty()
208     }
209 
get(&self, idx: usize) -> Option<F2Dot14>210     pub fn get(&self, idx: usize) -> Option<F2Dot14> {
211         self.values.get(idx).map(BigEndian::get)
212     }
213 }
214 
215 //FIXME: add an #[extra_traits(..)] attribute!
216 #[allow(clippy::derivable_impls)]
217 impl Default for Tuple<'_> {
default() -> Self218     fn default() -> Self {
219         Self {
220             values: Default::default(),
221         }
222     }
223 }
224 
225 /// [Packed "Point" Numbers](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-point-numbers)
226 #[derive(Clone, Debug)]
227 pub struct PackedPointNumbers<'a> {
228     data: FontData<'a>,
229 }
230 
231 impl<'a> PackedPointNumbers<'a> {
232     /// read point numbers off the front of this data, returning the remaining data
split_off_front(data: FontData<'a>) -> (Self, FontData<'a>)233     pub fn split_off_front(data: FontData<'a>) -> (Self, FontData<'a>) {
234         let this = PackedPointNumbers { data };
235         let total_len = this.total_len();
236         let remainder = data.split_off(total_len).unwrap_or_default();
237         (this, remainder)
238     }
239 
240     /// The number of points in this set
count(&self) -> u16241     pub fn count(&self) -> u16 {
242         self.count_and_count_bytes().0
243     }
244 
245     /// compute the count, and the number of bytes used to store it
count_and_count_bytes(&self) -> (u16, usize)246     fn count_and_count_bytes(&self) -> (u16, usize) {
247         match self.data.read_at::<u8>(0).unwrap_or(0) {
248             0 => (0, 1),
249             count @ 1..=127 => (count as u16, 1),
250             _ => {
251                 // "If the high bit of the first byte is set, then a second byte is used.
252                 // The count is read from interpreting the two bytes as a big-endian
253                 // uint16 value with the high-order bit masked out."
254 
255                 let count = self.data.read_at::<u16>(0).unwrap_or_default() & 0x7FFF;
256                 // a weird case where I'm following fonttools: if the 'use words' bit
257                 // is set, but the total count is still 0, treat it like 0 first byte
258                 if count == 0 {
259                     (0, 2)
260                 } else {
261                     (count & 0x7FFF, 2)
262                 }
263             }
264         }
265     }
266 
267     /// the number of bytes to encode the packed point numbers
total_len(&self) -> usize268     fn total_len(&self) -> usize {
269         let (n_points, mut n_bytes) = self.count_and_count_bytes();
270         if n_points == 0 {
271             return n_bytes;
272         }
273         let mut cursor = self.data.cursor();
274         cursor.advance_by(n_bytes);
275 
276         let mut n_seen = 0;
277         while n_seen < n_points {
278             let Some((count, two_bytes)) = read_control_byte(&mut cursor) else {
279                 return n_bytes;
280             };
281             let word_size = 1 + usize::from(two_bytes);
282             let run_size = word_size * count as usize;
283             n_bytes += run_size + 1; // plus the control byte;
284             cursor.advance_by(run_size);
285             n_seen += count as u16;
286         }
287 
288         n_bytes
289     }
290 
291     /// Iterate over the packed points
iter(&self) -> PackedPointNumbersIter<'a>292     pub fn iter(&self) -> PackedPointNumbersIter<'a> {
293         let (count, n_bytes) = self.count_and_count_bytes();
294         let mut cursor = self.data.cursor();
295         cursor.advance_by(n_bytes);
296         PackedPointNumbersIter::new(count, cursor)
297     }
298 }
299 
300 /// An iterator over the packed point numbers data.
301 #[derive(Clone, Debug)]
302 pub struct PackedPointNumbersIter<'a> {
303     count: u16,
304     seen: u16,
305     last_val: u16,
306     current_run: PointRunIter<'a>,
307 }
308 
309 impl<'a> PackedPointNumbersIter<'a> {
new(count: u16, cursor: Cursor<'a>) -> Self310     fn new(count: u16, cursor: Cursor<'a>) -> Self {
311         PackedPointNumbersIter {
312             count,
313             seen: 0,
314             last_val: 0,
315             current_run: PointRunIter {
316                 remaining: 0,
317                 two_bytes: false,
318                 cursor,
319             },
320         }
321     }
322 }
323 
324 /// Implements the logic for iterating over the individual runs
325 #[derive(Clone, Debug)]
326 struct PointRunIter<'a> {
327     remaining: u8,
328     two_bytes: bool,
329     cursor: Cursor<'a>,
330 }
331 
332 impl Iterator for PointRunIter<'_> {
333     type Item = u16;
334 
next(&mut self) -> Option<Self::Item>335     fn next(&mut self) -> Option<Self::Item> {
336         // if no items remain in this run, start the next one.
337         while self.remaining == 0 {
338             (self.remaining, self.two_bytes) = read_control_byte(&mut self.cursor)?;
339         }
340 
341         self.remaining -= 1;
342         if self.two_bytes {
343             self.cursor.read().ok()
344         } else {
345             self.cursor.read::<u8>().ok().map(|v| v as u16)
346         }
347     }
348 }
349 
350 /// returns the count and the 'uses_two_bytes' flag from the control byte
read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)>351 fn read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)> {
352     let control: u8 = cursor.read().ok()?;
353     let two_bytes = (control & 0x80) != 0;
354     let count = (control & 0x7F) + 1;
355     Some((count, two_bytes))
356 }
357 
358 impl Iterator for PackedPointNumbersIter<'_> {
359     type Item = u16;
360 
next(&mut self) -> Option<Self::Item>361     fn next(&mut self) -> Option<Self::Item> {
362         // if our count is zero, we keep incrementing forever
363         if self.count == 0 {
364             let result = self.last_val;
365             self.last_val = self.last_val.checked_add(1)?;
366             return Some(result);
367         }
368 
369         if self.count == self.seen {
370             return None;
371         }
372         self.seen += 1;
373         self.last_val += self.current_run.next()?;
374         Some(self.last_val)
375     }
376 
size_hint(&self) -> (usize, Option<usize>)377     fn size_hint(&self) -> (usize, Option<usize>) {
378         (self.count as usize, Some(self.count as usize))
379     }
380 }
381 
382 // completely unnecessary?
383 impl<'a> ExactSizeIterator for PackedPointNumbersIter<'a> {}
384 
385 /// [Packed Deltas](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas)
386 #[derive(Clone, Debug)]
387 pub struct PackedDeltas<'a> {
388     data: FontData<'a>,
389     count: usize,
390 }
391 
392 impl<'a> PackedDeltas<'a> {
393     /// NOTE: this is unbounded, and assumes all of data is deltas.
394     #[doc(hidden)] // used by tests in write-fonts
new(data: FontData<'a>) -> Self395     pub fn new(data: FontData<'a>) -> Self {
396         let count = DeltaRunIter::new(data.cursor()).count();
397         Self { data, count }
398     }
399 
count(&self) -> usize400     pub(crate) fn count(&self) -> usize {
401         self.count
402     }
403 
404     #[doc(hidden)] // used by tests in write-fonts
iter(&self) -> DeltaRunIter<'a>405     pub fn iter(&self) -> DeltaRunIter<'a> {
406         DeltaRunIter::new(self.data.cursor())
407     }
408 }
409 
410 /// Implements the logic for iterating over the individual runs
411 #[derive(Clone, Debug)]
412 pub struct DeltaRunIter<'a> {
413     remaining: u8,
414     two_bytes: bool,
415     are_zero: bool,
416     cursor: Cursor<'a>,
417 }
418 
419 impl<'a> DeltaRunIter<'a> {
new(cursor: Cursor<'a>) -> Self420     fn new(cursor: Cursor<'a>) -> Self {
421         DeltaRunIter {
422             remaining: 0,
423             two_bytes: false,
424             are_zero: false,
425             cursor,
426         }
427     }
428 }
429 
430 impl Iterator for DeltaRunIter<'_> {
431     type Item = i16;
432 
next(&mut self) -> Option<Self::Item>433     fn next(&mut self) -> Option<Self::Item> {
434         /// Flag indicating that this run contains no data,
435         /// and that the deltas for this run are all zero.
436         const DELTAS_ARE_ZERO: u8 = 0x80;
437         /// Flag indicating the data type for delta values in the run.
438         const DELTAS_ARE_WORDS: u8 = 0x40;
439         /// Mask for the low 6 bits to provide the number of delta values in the run, minus one.
440         const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
441 
442         // if no items remain in this run, start the next one.
443         // NOTE: we use `while` so we can sanely handle the case where some
444         // run in the middle of the data has an explicit zero length
445         //TODO: create a font with data of this shape and go crash some font parsers
446         while self.remaining == 0 {
447             let control: u8 = self.cursor.read().ok()?;
448             self.are_zero = (control & DELTAS_ARE_ZERO) != 0;
449             self.two_bytes = (control & DELTAS_ARE_WORDS) != 0;
450             self.remaining = (control & DELTA_RUN_COUNT_MASK) + 1;
451         }
452 
453         self.remaining -= 1;
454         if self.are_zero {
455             Some(0)
456         } else if self.two_bytes {
457             self.cursor.read().ok()
458         } else {
459             self.cursor.read::<i8>().ok().map(|v| v as i16)
460         }
461     }
462 }
463 
464 /// A helper type for iterating over [`TupleVariationHeader`]s.
465 pub struct TupleVariationHeaderIter<'a> {
466     data: FontData<'a>,
467     n_headers: usize,
468     current: usize,
469     axis_count: u16,
470 }
471 
472 impl<'a> TupleVariationHeaderIter<'a> {
new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self473     pub(crate) fn new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self {
474         Self {
475             data,
476             n_headers,
477             current: 0,
478             axis_count,
479         }
480     }
481 }
482 
483 impl<'a> Iterator for TupleVariationHeaderIter<'a> {
484     type Item = Result<TupleVariationHeader<'a>, ReadError>;
485 
next(&mut self) -> Option<Self::Item>486     fn next(&mut self) -> Option<Self::Item> {
487         if self.current == self.n_headers {
488             return None;
489         }
490         self.current += 1;
491         let next = TupleVariationHeader::read(self.data, self.axis_count);
492         let next_len = next
493             .as_ref()
494             .map(|table| table.byte_len(self.axis_count))
495             .unwrap_or(0);
496         self.data = self.data.split_off(next_len)?;
497         Some(next)
498     }
499 }
500 
501 impl EntryFormat {
entry_size(self) -> u8502     pub fn entry_size(self) -> u8 {
503         ((self.bits() & Self::MAP_ENTRY_SIZE_MASK.bits()) >> 4) + 1
504     }
505 
bit_count(self) -> u8506     pub fn bit_count(self) -> u8 {
507         (self.bits() & Self::INNER_INDEX_BIT_COUNT_MASK.bits()) + 1
508     }
509 
510     // called from codegen
map_size(self, map_count: impl Into<u32>) -> usize511     pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
512         self.entry_size() as usize * map_count.into() as usize
513     }
514 }
515 
516 impl<'a> DeltaSetIndexMap<'a> {
517     /// Returns the delta set index for the specified value.
get(&self, index: u32) -> Result<DeltaSetIndex, ReadError>518     pub fn get(&self, index: u32) -> Result<DeltaSetIndex, ReadError> {
519         let (entry_format, map_count, data) = match self {
520             Self::Format0(fmt) => (fmt.entry_format(), fmt.map_count() as u32, fmt.map_data()),
521             Self::Format1(fmt) => (fmt.entry_format(), fmt.map_count(), fmt.map_data()),
522         };
523         let entry_size = entry_format.entry_size();
524         let data = FontData::new(data);
525         // "if an index into the mapping array is used that is greater than or equal to
526         // mapCount, then the last logical entry of the mapping array is used."
527         // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats
528         // #associating-target-items-to-variation-data
529         let index = index.min(map_count.saturating_sub(1));
530         let offset = index as usize * entry_size as usize;
531         let entry = match entry_size {
532             1 => data.read_at::<u8>(offset)? as u32,
533             2 => data.read_at::<u16>(offset)? as u32,
534             3 => data.read_at::<Uint24>(offset)?.into(),
535             4 => data.read_at::<u32>(offset)?,
536             _ => {
537                 return Err(ReadError::MalformedData(
538                     "invalid entry size in DeltaSetIndexMap",
539                 ))
540             }
541         };
542         let bit_count = entry_format.bit_count();
543         Ok(DeltaSetIndex {
544             outer: (entry >> bit_count) as u16,
545             inner: (entry & ((1 << bit_count) - 1)) as u16,
546         })
547     }
548 }
549 
550 impl<'a> ItemVariationStore<'a> {
551     /// Computes the delta value for the specified index and set of normalized
552     /// variation coordinates.
compute_delta( &self, index: DeltaSetIndex, coords: &[F2Dot14], ) -> Result<i32, ReadError>553     pub fn compute_delta(
554         &self,
555         index: DeltaSetIndex,
556         coords: &[F2Dot14],
557     ) -> Result<i32, ReadError> {
558         let data = match self.item_variation_data().get(index.outer as usize) {
559             Some(data) => data?,
560             None => return Ok(0),
561         };
562         let regions = self.variation_region_list()?.variation_regions();
563         let region_indices = data.region_indexes();
564         // Compute deltas with 64-bit precision.
565         // See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/7ab541a2/src/truetype/ttgxvar.c#L1094>
566         let mut accum = 0i64;
567         for (i, region_delta) in data.delta_set(index.inner).enumerate() {
568             let region_index = region_indices
569                 .get(i)
570                 .ok_or(ReadError::MalformedData(
571                     "invalid delta sets in ItemVariationStore",
572                 ))?
573                 .get() as usize;
574             let region = regions.get(region_index)?;
575             let scalar = region.compute_scalar(coords);
576             accum += region_delta as i64 * scalar.to_bits() as i64;
577         }
578         Ok(((accum + 0x8000) >> 16) as i32)
579     }
580 
581     /// Computes the delta value in floating point for the specified index and set
582     /// of normalized variation coordinates.
compute_float_delta( &self, index: DeltaSetIndex, coords: &[F2Dot14], ) -> Result<FloatItemDelta, ReadError>583     pub fn compute_float_delta(
584         &self,
585         index: DeltaSetIndex,
586         coords: &[F2Dot14],
587     ) -> Result<FloatItemDelta, ReadError> {
588         let data = match self.item_variation_data().get(index.outer as usize) {
589             Some(data) => data?,
590             None => return Ok(FloatItemDelta::ZERO),
591         };
592         let regions = self.variation_region_list()?.variation_regions();
593         let region_indices = data.region_indexes();
594         // Compute deltas in 64-bit floating point.
595         let mut accum = 0f64;
596         for (i, region_delta) in data.delta_set(index.inner).enumerate() {
597             let region_index = region_indices
598                 .get(i)
599                 .ok_or(ReadError::MalformedData(
600                     "invalid delta sets in ItemVariationStore",
601                 ))?
602                 .get() as usize;
603             let region = regions.get(region_index)?;
604             let scalar = region.compute_scalar_f32(coords);
605             accum += region_delta as f64 * scalar as f64;
606         }
607         Ok(FloatItemDelta(accum))
608     }
609 }
610 
611 /// Floating point item delta computed by an item variation store.
612 ///
613 /// These can be applied to types that implement [`FloatItemDeltaTarget`].
614 #[derive(Copy, Clone, Default, Debug)]
615 pub struct FloatItemDelta(f64);
616 
617 impl FloatItemDelta {
618     pub const ZERO: Self = Self(0.0);
619 }
620 
621 /// Trait for applying floating point item deltas to target values.
622 pub trait FloatItemDeltaTarget {
apply_float_delta(&self, delta: FloatItemDelta) -> f32623     fn apply_float_delta(&self, delta: FloatItemDelta) -> f32;
624 }
625 
626 impl FloatItemDeltaTarget for Fixed {
apply_float_delta(&self, delta: FloatItemDelta) -> f32627     fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
628         const FIXED_TO_FLOAT: f64 = 1.0 / 65536.0;
629         self.to_f32() + (delta.0 * FIXED_TO_FLOAT) as f32
630     }
631 }
632 
633 impl FloatItemDeltaTarget for FWord {
apply_float_delta(&self, delta: FloatItemDelta) -> f32634     fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
635         self.to_i16() as f32 + delta.0 as f32
636     }
637 }
638 
639 impl FloatItemDeltaTarget for UfWord {
apply_float_delta(&self, delta: FloatItemDelta) -> f32640     fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
641         self.to_u16() as f32 + delta.0 as f32
642     }
643 }
644 
645 impl FloatItemDeltaTarget for F2Dot14 {
apply_float_delta(&self, delta: FloatItemDelta) -> f32646     fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
647         const F2DOT14_TO_FLOAT: f64 = 1.0 / 16384.0;
648         self.to_f32() + (delta.0 * F2DOT14_TO_FLOAT) as f32
649     }
650 }
651 
652 impl<'a> VariationRegion<'a> {
653     /// Computes a scalar value for this region and the specified
654     /// normalized variation coordinates.
compute_scalar(&self, coords: &[F2Dot14]) -> Fixed655     pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Fixed {
656         const ZERO: Fixed = Fixed::ZERO;
657         let mut scalar = Fixed::ONE;
658         for (i, axis_coords) in self.region_axes().iter().enumerate() {
659             let coord = coords.get(i).map(|coord| coord.to_fixed()).unwrap_or(ZERO);
660             let start = axis_coords.start_coord.get().to_fixed();
661             let end = axis_coords.end_coord.get().to_fixed();
662             let peak = axis_coords.peak_coord.get().to_fixed();
663             if start > peak || peak > end || peak == ZERO || start < ZERO && end > ZERO {
664                 continue;
665             } else if coord < start || coord > end {
666                 return ZERO;
667             } else if coord == peak {
668                 continue;
669             } else if coord < peak {
670                 scalar = scalar.mul_div(coord - start, peak - start);
671             } else {
672                 scalar = scalar.mul_div(end - coord, end - peak);
673             }
674         }
675         scalar
676     }
677 
678     /// Computes a floating point scalar value for this region and the
679     /// specified normalized variation coordinates.
compute_scalar_f32(&self, coords: &[F2Dot14]) -> f32680     pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> f32 {
681         let mut scalar = 1.0;
682         for (i, axis_coords) in self.region_axes().iter().enumerate() {
683             let coord = coords.get(i).map(|coord| coord.to_f32()).unwrap_or(0.0);
684             let start = axis_coords.start_coord.get().to_f32();
685             let end = axis_coords.end_coord.get().to_f32();
686             let peak = axis_coords.peak_coord.get().to_f32();
687             if start > peak || peak > end || peak == 0.0 || start < 0.0 && end > 0.0 {
688                 continue;
689             } else if coord < start || coord > end {
690                 return 0.0;
691             } else if coord == peak {
692                 continue;
693             } else if coord < peak {
694                 scalar = (scalar * (coord - start)) / (peak - start);
695             } else {
696                 scalar = (scalar * (end - coord)) / (end - peak);
697             }
698         }
699         scalar
700     }
701 }
702 
703 impl<'a> ItemVariationData<'a> {
704     /// Returns an iterator over the per-region delta values for the specified
705     /// inner index.
delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone706     pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
707         let word_delta_count = self.word_delta_count();
708         let long_words = word_delta_count & 0x8000 != 0;
709         let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
710         let word_delta_count = word_delta_count & 0x7FFF;
711         let region_count = self.region_index_count() as usize;
712         let row_size = word_delta_count as usize * word_size
713             + region_count.saturating_sub(word_delta_count as usize) * small_size;
714         let offset = row_size * inner_index as usize;
715         ItemDeltas {
716             cursor: FontData::new(self.delta_sets())
717                 .slice(offset..)
718                 .unwrap_or_default()
719                 .cursor(),
720             word_delta_count,
721             long_words,
722             len: region_count as u16,
723             pos: 0,
724         }
725     }
726 }
727 
728 #[derive(Clone)]
729 struct ItemDeltas<'a> {
730     cursor: Cursor<'a>,
731     word_delta_count: u16,
732     long_words: bool,
733     len: u16,
734     pos: u16,
735 }
736 
737 impl<'a> Iterator for ItemDeltas<'a> {
738     type Item = i32;
739 
next(&mut self) -> Option<Self::Item>740     fn next(&mut self) -> Option<Self::Item> {
741         if self.pos >= self.len {
742             return None;
743         }
744         let pos = self.pos;
745         self.pos += 1;
746         let value = match (pos >= self.word_delta_count, self.long_words) {
747             (true, true) | (false, false) => self.cursor.read::<i16>().ok()? as i32,
748             (true, false) => self.cursor.read::<i8>().ok()? as i32,
749             (false, true) => self.cursor.read::<i32>().ok()?,
750         };
751         Some(value)
752     }
753 }
754 
advance_delta( dsim: Option<Result<DeltaSetIndexMap, ReadError>>, ivs: Result<ItemVariationStore, ReadError>, glyph_id: GlyphId, coords: &[F2Dot14], ) -> Result<Fixed, ReadError>755 pub(crate) fn advance_delta(
756     dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
757     ivs: Result<ItemVariationStore, ReadError>,
758     glyph_id: GlyphId,
759     coords: &[F2Dot14],
760 ) -> Result<Fixed, ReadError> {
761     let gid = glyph_id.to_u16();
762     let ix = match dsim {
763         Some(Ok(dsim)) => dsim.get(gid as u32)?,
764         _ => DeltaSetIndex {
765             outer: 0,
766             inner: gid,
767         },
768     };
769     Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
770 }
771 
item_delta( dsim: Option<Result<DeltaSetIndexMap, ReadError>>, ivs: Result<ItemVariationStore, ReadError>, glyph_id: GlyphId, coords: &[F2Dot14], ) -> Result<Fixed, ReadError>772 pub(crate) fn item_delta(
773     dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
774     ivs: Result<ItemVariationStore, ReadError>,
775     glyph_id: GlyphId,
776     coords: &[F2Dot14],
777 ) -> Result<Fixed, ReadError> {
778     let gid = glyph_id.to_u16();
779     let ix = match dsim {
780         Some(Ok(dsim)) => dsim.get(gid as u32)?,
781         _ => return Err(ReadError::NullOffset),
782     };
783     Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
784 }
785 
786 #[cfg(test)]
787 mod tests {
788     use super::*;
789     use crate::{FontRef, TableProvider};
790 
791     #[test]
ivs_regions()792     fn ivs_regions() {
793         let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
794         let hvar = font.hvar().expect("missing HVAR table");
795         let ivs = hvar
796             .item_variation_store()
797             .expect("missing item variation store in HVAR");
798         let region_list = ivs.variation_region_list().expect("missing region list!");
799         let regions = region_list.variation_regions();
800         let expected = &[
801             // start_coord, peak_coord, end_coord
802             vec![[-1.0f32, -1.0, 0.0]],
803             vec![[0.0, 1.0, 1.0]],
804         ][..];
805         let region_coords = regions
806             .iter()
807             .map(|region| {
808                 region
809                     .unwrap()
810                     .region_axes()
811                     .iter()
812                     .map(|coords| {
813                         [
814                             coords.start_coord().to_f32(),
815                             coords.peak_coord().to_f32(),
816                             coords.end_coord().to_f32(),
817                         ]
818                     })
819                     .collect::<Vec<_>>()
820             })
821             .collect::<Vec<_>>();
822         assert_eq!(expected, &region_coords);
823     }
824 
825     // adapted from https://github.com/fonttools/fonttools/blob/f73220816264fc383b8a75f2146e8d69e455d398/Tests/ttLib/tables/TupleVariation_test.py#L492
826     #[test]
packed_points()827     fn packed_points() {
828         fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
829             let data = FontData::new(bytes);
830             let packed = PackedPointNumbers { data };
831             if packed.count() == 0 {
832                 None
833             } else {
834                 Some(packed.iter().collect())
835             }
836         }
837 
838         assert_eq!(decode_points(&[0]), None);
839         // all points in glyph (in overly verbose encoding, not explicitly prohibited by spec)
840         assert_eq!(decode_points(&[0x80, 0]), None);
841         // 2 points; first run: [9, 9+6]
842         assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
843         // 2 points; first run: [0xBEEF, 0xCAFE]. (0x0C0F = 0xCAFE - 0xBEEF)
844         assert_eq!(
845             decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
846             Some(vec![0xbeef, 0xcafe])
847         );
848         // 1 point; first run: [7]
849         assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
850         // 1 point; first run: [7] in overly verbose encoding
851         assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
852         // 1 point; first run: [65535]; requires words to be treated as unsigned numbers
853         assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
854         // 4 points; first run: [7, 8]; second run: [255, 257]. 257 is stored in delta-encoded bytes (0xFF + 2).
855         assert_eq!(
856             decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
857             Some(vec![7, 8, 263, 265])
858         );
859     }
860 
861     #[test]
packed_point_byte_len()862     fn packed_point_byte_len() {
863         fn count_bytes(bytes: &[u8]) -> usize {
864             let packed = PackedPointNumbers {
865                 data: FontData::new(bytes),
866             };
867             packed.total_len()
868         }
869 
870         static CASES: &[&[u8]] = &[
871             &[0],
872             &[0x80, 0],
873             &[0x02, 0x01, 0x09, 0x06],
874             &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
875             &[0x01, 0, 0x07],
876             &[0x01, 0x80, 0, 0x07],
877             &[0x01, 0x80, 0xff, 0xff],
878             &[0x04, 1, 7, 1, 1, 0xff, 2],
879         ];
880 
881         for case in CASES {
882             assert_eq!(count_bytes(case), case.len(), "{case:?}");
883         }
884     }
885 
886     // https://github.com/fonttools/fonttools/blob/c30a6355ffdf7f09d31e7719975b4b59bac410af/Tests/ttLib/tables/TupleVariation_test.py#L670
887     #[test]
packed_deltas()888     fn packed_deltas() {
889         static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
890 
891         let deltas = PackedDeltas::new(INPUT);
892         assert_eq!(deltas.count, 7);
893         assert_eq!(
894             deltas.iter().collect::<Vec<_>>(),
895             &[0, 0, 0, 0, 258, -127, -128]
896         );
897 
898         assert_eq!(
899             PackedDeltas::new(FontData::new(&[0x81]))
900                 .iter()
901                 .collect::<Vec<_>>(),
902             &[0, 0,]
903         );
904     }
905 
906     // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas
907     #[test]
packed_deltas_spec()908     fn packed_deltas_spec() {
909         static INPUT: FontData = FontData::new(&[
910             0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
911         ]);
912         static EXPECTED: &[i16] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
913 
914         let deltas = PackedDeltas::new(INPUT);
915         assert_eq!(deltas.count, EXPECTED.len());
916         assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
917     }
918 
919     #[test]
packed_point_split()920     fn packed_point_split() {
921         static INPUT: FontData =
922             FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
923         let (points, data) = PackedPointNumbers::split_off_front(INPUT);
924         assert_eq!(points.count(), 2);
925         assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
926         assert_eq!(points.total_len(), 4);
927         assert_eq!(data.len(), INPUT.len() - 4);
928     }
929 
930     #[test]
packed_points_dont_panic()931     fn packed_points_dont_panic() {
932         // a single '0' byte means that there are deltas for all points
933         static ALL_POINTS: FontData = FontData::new(&[0]);
934         let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
935         // in which case the iterator just keeps incrementing until u16::MAX
936         assert_eq!(all_points.iter().count(), u16::MAX as _);
937     }
938 
939     /// We don't have a reference for our float delta computation, so this is
940     /// a sanity test to ensure that floating point deltas are within a
941     /// reasonable margin of the same in fixed point.
942     #[test]
ivs_float_deltas_nearly_match_fixed_deltas()943     fn ivs_float_deltas_nearly_match_fixed_deltas() {
944         let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
945         let axis_count = font.fvar().unwrap().axis_count() as usize;
946         let colr = font.colr().unwrap();
947         let ivs = colr.item_variation_store().unwrap().unwrap();
948         // Generate a set of coords from -1 to 1 in 0.1 increments
949         for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
950             // For testing purposes, just splat the coord to all axes
951             let coords = vec![coord; axis_count];
952             for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
953                 let outer_ix = outer_ix as u16;
954                 let Some(Ok(data)) = data else {
955                     continue;
956                 };
957                 for inner_ix in 0..data.item_count() {
958                     let delta_ix = DeltaSetIndex {
959                         outer: outer_ix,
960                         inner: inner_ix,
961                     };
962                     // Check the deltas against all possible target values
963                     let orig_delta = ivs.compute_delta(delta_ix, &coords).unwrap();
964                     let float_delta = ivs.compute_float_delta(delta_ix, &coords).unwrap();
965                     // For font unit types, we need to accept both rounding and
966                     // truncation to account for the additional accumulation of
967                     // fractional bits in floating point
968                     assert!(
969                         orig_delta == float_delta.0.round() as i32
970                             || orig_delta == float_delta.0.trunc() as i32
971                     );
972                     // For the fixed point types, check with an epsilon
973                     const EPSILON: f32 = 1e12;
974                     let fixed_delta = Fixed::ZERO.apply_float_delta(float_delta);
975                     assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
976                     let f2dot14_delta = F2Dot14::ZERO.apply_float_delta(float_delta);
977                     assert!(
978                         (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
979                             < EPSILON
980                     );
981                 }
982             }
983         }
984     }
985 }
986