Skip to main content

read_fonts/generated/
generated_variations.rs

1// THIS FILE IS AUTOGENERATED.
2// Any changes to this file will be overwritten.
3// For more information about how codegen works, see font-codegen/README.md
4
5#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for TupleVariationHeader<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.intermediate_end_tuple_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.data.as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl ReadArgs for TupleVariationHeader<'_> {
19    type Args = u16;
20}
21
22impl<'a> FontReadWithArgs<'a> for TupleVariationHeader<'a> {
23    fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
24        let axis_count = *args;
25
26        #[allow(clippy::absurd_extreme_comparisons)]
27        if data.len() < Self::MIN_SIZE {
28            return Err(ReadError::OutOfBounds);
29        }
30        Ok(Self { data, axis_count })
31    }
32}
33
34impl<'a> TupleVariationHeader<'a> {
35    /// A constructor that requires additional arguments.
36    ///
37    /// This type requires some external state in order to be
38    /// parsed.
39    pub fn read(data: FontData<'a>, axis_count: u16) -> Result<Self, ReadError> {
40        let args = axis_count;
41        Self::read_with_args(data, &args)
42    }
43}
44
45/// [TupleVariationHeader](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader)
46#[derive(Clone)]
47pub struct TupleVariationHeader<'a> {
48    data: FontData<'a>,
49    axis_count: u16,
50}
51
52#[allow(clippy::needless_lifetimes)]
53impl<'a> TupleVariationHeader<'a> {
54    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN);
55    basic_table_impls!(impl_the_methods);
56
57    /// The size in bytes of the serialized data for this tuple
58    /// variation table.
59    pub fn variation_data_size(&self) -> u16 {
60        let range = self.variation_data_size_byte_range();
61        self.data.read_at(range.start).ok().unwrap()
62    }
63
64    /// A packed field. The high 4 bits are flags (see below). The low
65    /// 12 bits are an index into a shared tuple records array.
66    pub fn tuple_index(&self) -> TupleIndex {
67        let range = self.tuple_index_byte_range();
68        self.data.read_at(range.start).ok().unwrap()
69    }
70
71    pub(crate) fn axis_count(&self) -> u16 {
72        self.axis_count
73    }
74
75    pub fn variation_data_size_byte_range(&self) -> Range<usize> {
76        let start = 0;
77        let end = start + u16::RAW_BYTE_LEN;
78        start..end
79    }
80
81    pub fn tuple_index_byte_range(&self) -> Range<usize> {
82        let start = self.variation_data_size_byte_range().end;
83        let end = start + TupleIndex::RAW_BYTE_LEN;
84        start..end
85    }
86
87    pub fn peak_tuple_byte_range(&self) -> Range<usize> {
88        let tuple_index = self.tuple_index();
89        let axis_count = self.axis_count();
90        let start = self.tuple_index_byte_range().end;
91        let end = start
92            + (TupleIndex::tuple_len(tuple_index, axis_count, 0_usize))
93                .saturating_mul(F2Dot14::RAW_BYTE_LEN);
94        start..end
95    }
96
97    pub fn intermediate_start_tuple_byte_range(&self) -> Range<usize> {
98        let tuple_index = self.tuple_index();
99        let axis_count = self.axis_count();
100        let start = self.peak_tuple_byte_range().end;
101        let end = start
102            + (TupleIndex::tuple_len(tuple_index, axis_count, 1_usize))
103                .saturating_mul(F2Dot14::RAW_BYTE_LEN);
104        start..end
105    }
106
107    pub fn intermediate_end_tuple_byte_range(&self) -> Range<usize> {
108        let tuple_index = self.tuple_index();
109        let axis_count = self.axis_count();
110        let start = self.intermediate_start_tuple_byte_range().end;
111        let end = start
112            + (TupleIndex::tuple_len(tuple_index, axis_count, 1_usize))
113                .saturating_mul(F2Dot14::RAW_BYTE_LEN);
114        start..end
115    }
116}
117
118const _: () = assert!(FontData::default_data_long_enough(
119    TupleVariationHeader::MIN_SIZE
120));
121
122impl Default for TupleVariationHeader<'_> {
123    fn default() -> Self {
124        Self {
125            data: FontData::default_table_data(),
126            axis_count: Default::default(),
127        }
128    }
129}
130
131#[cfg(feature = "experimental_traverse")]
132impl<'a> SomeTable<'a> for TupleVariationHeader<'a> {
133    fn type_name(&self) -> &str {
134        "TupleVariationHeader"
135    }
136    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
137        match idx {
138            0usize => Some(Field::new(
139                "variation_data_size",
140                self.variation_data_size(),
141            )),
142            1usize => Some(Field::new("tuple_index", self.traverse_tuple_index())),
143            _ => None,
144        }
145    }
146}
147
148#[cfg(feature = "experimental_traverse")]
149#[allow(clippy::needless_lifetimes)]
150impl<'a> std::fmt::Debug for TupleVariationHeader<'a> {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        (self as &dyn SomeTable<'a>).fmt(f)
153    }
154}
155
156/// A [Tuple Record](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-records)
157///
158/// The tuple variation store formats reference regions within the font’s
159/// variation space using tuple records. A tuple record identifies a position
160/// in terms of normalized coordinates, which use F2DOT14 values.
161#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
162pub struct Tuple<'a> {
163    /// Coordinate array specifying a position within the font’s variation space.
164    ///
165    /// The number of elements must match the axisCount specified in the
166    /// 'fvar' table.
167    pub values: &'a [BigEndian<F2Dot14>],
168}
169
170impl<'a> Tuple<'a> {
171    /// Coordinate array specifying a position within the font’s variation space.
172    ///
173    /// The number of elements must match the axisCount specified in the
174    /// 'fvar' table.
175    pub fn values(&self) -> &'a [BigEndian<F2Dot14>] {
176        self.values
177    }
178}
179
180impl ReadArgs for Tuple<'_> {
181    type Args = u16;
182}
183
184impl ComputeSize for Tuple<'_> {
185    #[allow(clippy::needless_question_mark)]
186    fn compute_size(args: &u16) -> Result<usize, ReadError> {
187        let axis_count = *args;
188        Ok((transforms::to_usize(axis_count)).saturating_mul(F2Dot14::RAW_BYTE_LEN))
189    }
190}
191
192impl<'a> FontReadWithArgs<'a> for Tuple<'a> {
193    fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
194        let mut cursor = data.cursor();
195        let axis_count = *args;
196        Ok(Self {
197            values: cursor.read_array(transforms::to_usize(axis_count))?,
198        })
199    }
200}
201
202#[allow(clippy::needless_lifetimes)]
203impl<'a> Tuple<'a> {
204    /// A constructor that requires additional arguments.
205    ///
206    /// This type requires some external state in order to be
207    /// parsed.
208    pub fn read(data: FontData<'a>, axis_count: u16) -> Result<Self, ReadError> {
209        let args = axis_count;
210        Self::read_with_args(data, &args)
211    }
212}
213
214#[cfg(feature = "experimental_traverse")]
215impl<'a> SomeRecord<'a> for Tuple<'a> {
216    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
217        RecordResolver {
218            name: "Tuple",
219            get_field: Box::new(move |idx, _data| match idx {
220                0usize => Some(Field::new("values", self.values())),
221                _ => None,
222            }),
223            data,
224        }
225    }
226}
227
228impl Format<u8> for DeltaSetIndexMapFormat0<'_> {
229    const FORMAT: u8 = 0;
230}
231
232impl<'a> MinByteRange<'a> for DeltaSetIndexMapFormat0<'a> {
233    fn min_byte_range(&self) -> Range<usize> {
234        0..self.map_data_byte_range().end
235    }
236    fn min_table_bytes(&self) -> &'a [u8] {
237        let range = self.min_byte_range();
238        self.data.as_bytes().get(range).unwrap_or_default()
239    }
240}
241
242impl<'a> FontRead<'a> for DeltaSetIndexMapFormat0<'a> {
243    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
244        #[allow(clippy::absurd_extreme_comparisons)]
245        if data.len() < Self::MIN_SIZE {
246            return Err(ReadError::OutOfBounds);
247        }
248        Ok(Self { data })
249    }
250}
251
252/// The [DeltaSetIndexMap](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data) table format 0
253#[derive(Clone)]
254pub struct DeltaSetIndexMapFormat0<'a> {
255    data: FontData<'a>,
256}
257
258#[allow(clippy::needless_lifetimes)]
259impl<'a> DeltaSetIndexMapFormat0<'a> {
260    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + EntryFormat::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
261    basic_table_impls!(impl_the_methods);
262
263    /// DeltaSetIndexMap format: set to 0.
264    pub fn format(&self) -> u8 {
265        let range = self.format_byte_range();
266        self.data.read_at(range.start).ok().unwrap()
267    }
268
269    /// A packed field that describes the compressed representation of
270    /// delta-set indices. See details below.
271    pub fn entry_format(&self) -> EntryFormat {
272        let range = self.entry_format_byte_range();
273        self.data.read_at(range.start).ok().unwrap()
274    }
275
276    /// The number of mapping entries.
277    pub fn map_count(&self) -> u16 {
278        let range = self.map_count_byte_range();
279        self.data.read_at(range.start).ok().unwrap()
280    }
281
282    /// The delta-set index mapping data. See details below.
283    pub fn map_data(&self) -> &'a [u8] {
284        let range = self.map_data_byte_range();
285        self.data.read_array(range).ok().unwrap_or_default()
286    }
287
288    pub fn format_byte_range(&self) -> Range<usize> {
289        let start = 0;
290        let end = start + u8::RAW_BYTE_LEN;
291        start..end
292    }
293
294    pub fn entry_format_byte_range(&self) -> Range<usize> {
295        let start = self.format_byte_range().end;
296        let end = start + EntryFormat::RAW_BYTE_LEN;
297        start..end
298    }
299
300    pub fn map_count_byte_range(&self) -> Range<usize> {
301        let start = self.entry_format_byte_range().end;
302        let end = start + u16::RAW_BYTE_LEN;
303        start..end
304    }
305
306    pub fn map_data_byte_range(&self) -> Range<usize> {
307        let entry_format = self.entry_format();
308        let map_count = self.map_count();
309        let start = self.map_count_byte_range().end;
310        let end = start
311            + (EntryFormat::map_size(entry_format, map_count)).saturating_mul(u8::RAW_BYTE_LEN);
312        start..end
313    }
314}
315
316const _: () = assert!(FontData::default_data_long_enough(
317    DeltaSetIndexMapFormat0::MIN_SIZE
318));
319
320impl Default for DeltaSetIndexMapFormat0<'_> {
321    fn default() -> Self {
322        Self {
323            data: FontData::default_table_data(),
324        }
325    }
326}
327
328#[cfg(feature = "experimental_traverse")]
329impl<'a> SomeTable<'a> for DeltaSetIndexMapFormat0<'a> {
330    fn type_name(&self) -> &str {
331        "DeltaSetIndexMapFormat0"
332    }
333    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
334        match idx {
335            0usize => Some(Field::new("format", self.format())),
336            1usize => Some(Field::new("entry_format", self.entry_format())),
337            2usize => Some(Field::new("map_count", self.map_count())),
338            3usize => Some(Field::new("map_data", self.map_data())),
339            _ => None,
340        }
341    }
342}
343
344#[cfg(feature = "experimental_traverse")]
345#[allow(clippy::needless_lifetimes)]
346impl<'a> std::fmt::Debug for DeltaSetIndexMapFormat0<'a> {
347    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348        (self as &dyn SomeTable<'a>).fmt(f)
349    }
350}
351
352impl Format<u8> for DeltaSetIndexMapFormat1<'_> {
353    const FORMAT: u8 = 1;
354}
355
356impl<'a> MinByteRange<'a> for DeltaSetIndexMapFormat1<'a> {
357    fn min_byte_range(&self) -> Range<usize> {
358        0..self.map_data_byte_range().end
359    }
360    fn min_table_bytes(&self) -> &'a [u8] {
361        let range = self.min_byte_range();
362        self.data.as_bytes().get(range).unwrap_or_default()
363    }
364}
365
366impl<'a> FontRead<'a> for DeltaSetIndexMapFormat1<'a> {
367    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
368        #[allow(clippy::absurd_extreme_comparisons)]
369        if data.len() < Self::MIN_SIZE {
370            return Err(ReadError::OutOfBounds);
371        }
372        Ok(Self { data })
373    }
374}
375
376/// The [DeltaSetIndexMap](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data) table format 1
377#[derive(Clone)]
378pub struct DeltaSetIndexMapFormat1<'a> {
379    data: FontData<'a>,
380}
381
382#[allow(clippy::needless_lifetimes)]
383impl<'a> DeltaSetIndexMapFormat1<'a> {
384    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + EntryFormat::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
385    basic_table_impls!(impl_the_methods);
386
387    /// DeltaSetIndexMap format: set to 1.
388    pub fn format(&self) -> u8 {
389        let range = self.format_byte_range();
390        self.data.read_at(range.start).ok().unwrap()
391    }
392
393    /// A packed field that describes the compressed representation of
394    /// delta-set indices. See details below.
395    pub fn entry_format(&self) -> EntryFormat {
396        let range = self.entry_format_byte_range();
397        self.data.read_at(range.start).ok().unwrap()
398    }
399
400    /// The number of mapping entries.
401    pub fn map_count(&self) -> u32 {
402        let range = self.map_count_byte_range();
403        self.data.read_at(range.start).ok().unwrap()
404    }
405
406    /// The delta-set index mapping data. See details below.
407    pub fn map_data(&self) -> &'a [u8] {
408        let range = self.map_data_byte_range();
409        self.data.read_array(range).ok().unwrap_or_default()
410    }
411
412    pub fn format_byte_range(&self) -> Range<usize> {
413        let start = 0;
414        let end = start + u8::RAW_BYTE_LEN;
415        start..end
416    }
417
418    pub fn entry_format_byte_range(&self) -> Range<usize> {
419        let start = self.format_byte_range().end;
420        let end = start + EntryFormat::RAW_BYTE_LEN;
421        start..end
422    }
423
424    pub fn map_count_byte_range(&self) -> Range<usize> {
425        let start = self.entry_format_byte_range().end;
426        let end = start + u32::RAW_BYTE_LEN;
427        start..end
428    }
429
430    pub fn map_data_byte_range(&self) -> Range<usize> {
431        let entry_format = self.entry_format();
432        let map_count = self.map_count();
433        let start = self.map_count_byte_range().end;
434        let end = start
435            + (EntryFormat::map_size(entry_format, map_count)).saturating_mul(u8::RAW_BYTE_LEN);
436        start..end
437    }
438}
439
440const _: () = assert!(FontData::default_data_long_enough(
441    DeltaSetIndexMapFormat1::MIN_SIZE
442));
443
444impl Default for DeltaSetIndexMapFormat1<'_> {
445    fn default() -> Self {
446        Self {
447            data: FontData::default_format_1_u8_table_data(),
448        }
449    }
450}
451
452#[cfg(feature = "experimental_traverse")]
453impl<'a> SomeTable<'a> for DeltaSetIndexMapFormat1<'a> {
454    fn type_name(&self) -> &str {
455        "DeltaSetIndexMapFormat1"
456    }
457    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
458        match idx {
459            0usize => Some(Field::new("format", self.format())),
460            1usize => Some(Field::new("entry_format", self.entry_format())),
461            2usize => Some(Field::new("map_count", self.map_count())),
462            3usize => Some(Field::new("map_data", self.map_data())),
463            _ => None,
464        }
465    }
466}
467
468#[cfg(feature = "experimental_traverse")]
469#[allow(clippy::needless_lifetimes)]
470impl<'a> std::fmt::Debug for DeltaSetIndexMapFormat1<'a> {
471    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472        (self as &dyn SomeTable<'a>).fmt(f)
473    }
474}
475
476/// The [DeltaSetIndexMap](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data) table
477#[derive(Clone)]
478pub enum DeltaSetIndexMap<'a> {
479    Format0(DeltaSetIndexMapFormat0<'a>),
480    Format1(DeltaSetIndexMapFormat1<'a>),
481}
482
483impl Default for DeltaSetIndexMap<'_> {
484    fn default() -> Self {
485        Self::Format0(Default::default())
486    }
487}
488
489impl<'a> DeltaSetIndexMap<'a> {
490    ///Return the `FontData` used to resolve offsets for this table.
491    pub fn offset_data(&self) -> FontData<'a> {
492        match self {
493            Self::Format0(item) => item.offset_data(),
494            Self::Format1(item) => item.offset_data(),
495        }
496    }
497
498    /// DeltaSetIndexMap format: set to 0.
499    pub fn format(&self) -> u8 {
500        match self {
501            Self::Format0(item) => item.format(),
502            Self::Format1(item) => item.format(),
503        }
504    }
505
506    /// A packed field that describes the compressed representation of
507    /// delta-set indices. See details below.
508    pub fn entry_format(&self) -> EntryFormat {
509        match self {
510            Self::Format0(item) => item.entry_format(),
511            Self::Format1(item) => item.entry_format(),
512        }
513    }
514
515    /// The delta-set index mapping data. See details below.
516    pub fn map_data(&self) -> &'a [u8] {
517        match self {
518            Self::Format0(item) => item.map_data(),
519            Self::Format1(item) => item.map_data(),
520        }
521    }
522}
523
524impl<'a> FontRead<'a> for DeltaSetIndexMap<'a> {
525    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
526        let format: u8 = data.read_at(0usize)?;
527        match format {
528            DeltaSetIndexMapFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
529            DeltaSetIndexMapFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
530            other => Err(ReadError::InvalidFormat(other.into())),
531        }
532    }
533}
534
535impl<'a> MinByteRange<'a> for DeltaSetIndexMap<'a> {
536    fn min_byte_range(&self) -> Range<usize> {
537        match self {
538            Self::Format0(item) => item.min_byte_range(),
539            Self::Format1(item) => item.min_byte_range(),
540        }
541    }
542    fn min_table_bytes(&self) -> &'a [u8] {
543        match self {
544            Self::Format0(item) => item.min_table_bytes(),
545            Self::Format1(item) => item.min_table_bytes(),
546        }
547    }
548}
549
550#[cfg(feature = "experimental_traverse")]
551impl<'a> DeltaSetIndexMap<'a> {
552    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
553        match self {
554            Self::Format0(table) => table,
555            Self::Format1(table) => table,
556        }
557    }
558}
559
560#[cfg(feature = "experimental_traverse")]
561impl std::fmt::Debug for DeltaSetIndexMap<'_> {
562    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
563        self.dyn_inner().fmt(f)
564    }
565}
566
567#[cfg(feature = "experimental_traverse")]
568impl<'a> SomeTable<'a> for DeltaSetIndexMap<'a> {
569    fn type_name(&self) -> &str {
570        self.dyn_inner().type_name()
571    }
572    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
573        self.dyn_inner().get_field(idx)
574    }
575}
576
577/// Entry format for a [DeltaSetIndexMap].
578#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
579#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
580#[repr(transparent)]
581pub struct EntryFormat {
582    bits: u8,
583}
584
585impl EntryFormat {
586    /// Mask for the low 4 bits, which give the count of bits minus one that are used in each entry for the inner-level index.
587    pub const INNER_INDEX_BIT_COUNT_MASK: Self = Self { bits: 0x0F };
588
589    /// Mask for bits that indicate the size in bytes minus one of each entry.
590    pub const MAP_ENTRY_SIZE_MASK: Self = Self { bits: 0x30 };
591}
592
593impl EntryFormat {
594    ///  Returns an empty set of flags.
595    #[inline]
596    pub const fn empty() -> Self {
597        Self { bits: 0 }
598    }
599
600    /// Returns the set containing all flags.
601    #[inline]
602    pub const fn all() -> Self {
603        Self {
604            bits: Self::INNER_INDEX_BIT_COUNT_MASK.bits | Self::MAP_ENTRY_SIZE_MASK.bits,
605        }
606    }
607
608    /// Returns the raw value of the flags currently stored.
609    #[inline]
610    pub const fn bits(&self) -> u8 {
611        self.bits
612    }
613
614    /// Convert from underlying bit representation, unless that
615    /// representation contains bits that do not correspond to a flag.
616    #[inline]
617    pub const fn from_bits(bits: u8) -> Option<Self> {
618        if (bits & !Self::all().bits()) == 0 {
619            Some(Self { bits })
620        } else {
621            None
622        }
623    }
624
625    /// Convert from underlying bit representation, dropping any bits
626    /// that do not correspond to flags.
627    #[inline]
628    pub const fn from_bits_truncate(bits: u8) -> Self {
629        Self {
630            bits: bits & Self::all().bits,
631        }
632    }
633
634    /// Returns `true` if no flags are currently stored.
635    #[inline]
636    pub const fn is_empty(&self) -> bool {
637        self.bits() == Self::empty().bits()
638    }
639
640    /// Returns `true` if there are flags common to both `self` and `other`.
641    #[inline]
642    pub const fn intersects(&self, other: Self) -> bool {
643        !(Self {
644            bits: self.bits & other.bits,
645        })
646        .is_empty()
647    }
648
649    /// Returns `true` if all of the flags in `other` are contained within `self`.
650    #[inline]
651    pub const fn contains(&self, other: Self) -> bool {
652        (self.bits & other.bits) == other.bits
653    }
654
655    /// Inserts the specified flags in-place.
656    #[inline]
657    pub fn insert(&mut self, other: Self) {
658        self.bits |= other.bits;
659    }
660
661    /// Removes the specified flags in-place.
662    #[inline]
663    pub fn remove(&mut self, other: Self) {
664        self.bits &= !other.bits;
665    }
666
667    /// Toggles the specified flags in-place.
668    #[inline]
669    pub fn toggle(&mut self, other: Self) {
670        self.bits ^= other.bits;
671    }
672
673    /// Returns the intersection between the flags in `self` and
674    /// `other`.
675    ///
676    /// Specifically, the returned set contains only the flags which are
677    /// present in *both* `self` *and* `other`.
678    ///
679    /// This is equivalent to using the `&` operator (e.g.
680    /// [`ops::BitAnd`]), as in `flags & other`.
681    ///
682    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
683    #[inline]
684    #[must_use]
685    pub const fn intersection(self, other: Self) -> Self {
686        Self {
687            bits: self.bits & other.bits,
688        }
689    }
690
691    /// Returns the union of between the flags in `self` and `other`.
692    ///
693    /// Specifically, the returned set contains all flags which are
694    /// present in *either* `self` *or* `other`, including any which are
695    /// present in both.
696    ///
697    /// This is equivalent to using the `|` operator (e.g.
698    /// [`ops::BitOr`]), as in `flags | other`.
699    ///
700    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
701    #[inline]
702    #[must_use]
703    pub const fn union(self, other: Self) -> Self {
704        Self {
705            bits: self.bits | other.bits,
706        }
707    }
708
709    /// Returns the difference between the flags in `self` and `other`.
710    ///
711    /// Specifically, the returned set contains all flags present in
712    /// `self`, except for the ones present in `other`.
713    ///
714    /// It is also conceptually equivalent to the "bit-clear" operation:
715    /// `flags & !other` (and this syntax is also supported).
716    ///
717    /// This is equivalent to using the `-` operator (e.g.
718    /// [`ops::Sub`]), as in `flags - other`.
719    ///
720    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
721    #[inline]
722    #[must_use]
723    pub const fn difference(self, other: Self) -> Self {
724        Self {
725            bits: self.bits & !other.bits,
726        }
727    }
728}
729
730impl std::ops::BitOr for EntryFormat {
731    type Output = Self;
732
733    /// Returns the union of the two sets of flags.
734    #[inline]
735    fn bitor(self, other: EntryFormat) -> Self {
736        Self {
737            bits: self.bits | other.bits,
738        }
739    }
740}
741
742impl std::ops::BitOrAssign for EntryFormat {
743    /// Adds the set of flags.
744    #[inline]
745    fn bitor_assign(&mut self, other: Self) {
746        self.bits |= other.bits;
747    }
748}
749
750impl std::ops::BitXor for EntryFormat {
751    type Output = Self;
752
753    /// Returns the left flags, but with all the right flags toggled.
754    #[inline]
755    fn bitxor(self, other: Self) -> Self {
756        Self {
757            bits: self.bits ^ other.bits,
758        }
759    }
760}
761
762impl std::ops::BitXorAssign for EntryFormat {
763    /// Toggles the set of flags.
764    #[inline]
765    fn bitxor_assign(&mut self, other: Self) {
766        self.bits ^= other.bits;
767    }
768}
769
770impl std::ops::BitAnd for EntryFormat {
771    type Output = Self;
772
773    /// Returns the intersection between the two sets of flags.
774    #[inline]
775    fn bitand(self, other: Self) -> Self {
776        Self {
777            bits: self.bits & other.bits,
778        }
779    }
780}
781
782impl std::ops::BitAndAssign for EntryFormat {
783    /// Disables all flags disabled in the set.
784    #[inline]
785    fn bitand_assign(&mut self, other: Self) {
786        self.bits &= other.bits;
787    }
788}
789
790impl std::ops::Sub for EntryFormat {
791    type Output = Self;
792
793    /// Returns the set difference of the two sets of flags.
794    #[inline]
795    fn sub(self, other: Self) -> Self {
796        Self {
797            bits: self.bits & !other.bits,
798        }
799    }
800}
801
802impl std::ops::SubAssign for EntryFormat {
803    /// Disables all flags enabled in the set.
804    #[inline]
805    fn sub_assign(&mut self, other: Self) {
806        self.bits &= !other.bits;
807    }
808}
809
810impl std::ops::Not for EntryFormat {
811    type Output = Self;
812
813    /// Returns the complement of this set of flags.
814    #[inline]
815    fn not(self) -> Self {
816        Self { bits: !self.bits } & Self::all()
817    }
818}
819
820impl std::fmt::Debug for EntryFormat {
821    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
822        let members: &[(&str, Self)] = &[
823            (
824                "INNER_INDEX_BIT_COUNT_MASK",
825                Self::INNER_INDEX_BIT_COUNT_MASK,
826            ),
827            ("MAP_ENTRY_SIZE_MASK", Self::MAP_ENTRY_SIZE_MASK),
828        ];
829        let mut first = true;
830        for (name, value) in members {
831            if self.contains(*value) {
832                if !first {
833                    f.write_str(" | ")?;
834                }
835                first = false;
836                f.write_str(name)?;
837            }
838        }
839        if first {
840            f.write_str("(empty)")?;
841        }
842        Ok(())
843    }
844}
845
846impl std::fmt::Binary for EntryFormat {
847    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
848        std::fmt::Binary::fmt(&self.bits, f)
849    }
850}
851
852impl std::fmt::Octal for EntryFormat {
853    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
854        std::fmt::Octal::fmt(&self.bits, f)
855    }
856}
857
858impl std::fmt::LowerHex for EntryFormat {
859    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
860        std::fmt::LowerHex::fmt(&self.bits, f)
861    }
862}
863
864impl std::fmt::UpperHex for EntryFormat {
865    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
866        std::fmt::UpperHex::fmt(&self.bits, f)
867    }
868}
869
870impl font_types::Scalar for EntryFormat {
871    type Raw = <u8 as font_types::Scalar>::Raw;
872    fn to_raw(self) -> Self::Raw {
873        self.bits().to_raw()
874    }
875    fn from_raw(raw: Self::Raw) -> Self {
876        let t = <u8>::from_raw(raw);
877        Self::from_bits_truncate(t)
878    }
879}
880
881#[cfg(feature = "experimental_traverse")]
882impl<'a> From<EntryFormat> for FieldType<'a> {
883    fn from(src: EntryFormat) -> FieldType<'a> {
884        src.bits().into()
885    }
886}
887
888impl<'a> MinByteRange<'a> for VariationRegionList<'a> {
889    fn min_byte_range(&self) -> Range<usize> {
890        0..self.variation_regions_byte_range().end
891    }
892    fn min_table_bytes(&self) -> &'a [u8] {
893        let range = self.min_byte_range();
894        self.data.as_bytes().get(range).unwrap_or_default()
895    }
896}
897
898impl<'a> FontRead<'a> for VariationRegionList<'a> {
899    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
900        #[allow(clippy::absurd_extreme_comparisons)]
901        if data.len() < Self::MIN_SIZE {
902            return Err(ReadError::OutOfBounds);
903        }
904        Ok(Self { data })
905    }
906}
907
908/// The [VariationRegionList](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-regions) table
909#[derive(Clone)]
910pub struct VariationRegionList<'a> {
911    data: FontData<'a>,
912}
913
914#[allow(clippy::needless_lifetimes)]
915impl<'a> VariationRegionList<'a> {
916    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
917    basic_table_impls!(impl_the_methods);
918
919    /// The number of variation axes for this font. This must be the
920    /// same number as axisCount in the 'fvar' table.
921    pub fn axis_count(&self) -> u16 {
922        let range = self.axis_count_byte_range();
923        self.data.read_at(range.start).ok().unwrap()
924    }
925
926    /// The number of variation region tables in the variation region
927    /// list. Must be less than 32,768.
928    pub fn region_count(&self) -> u16 {
929        let range = self.region_count_byte_range();
930        self.data.read_at(range.start).ok().unwrap()
931    }
932
933    /// Array of variation regions.
934    pub fn variation_regions(&self) -> ComputedArray<'a, VariationRegion<'a>> {
935        let range = self.variation_regions_byte_range();
936        self.data
937            .read_with_args(range, &self.axis_count())
938            .unwrap_or_default()
939    }
940
941    pub fn axis_count_byte_range(&self) -> Range<usize> {
942        let start = 0;
943        let end = start + u16::RAW_BYTE_LEN;
944        start..end
945    }
946
947    pub fn region_count_byte_range(&self) -> Range<usize> {
948        let start = self.axis_count_byte_range().end;
949        let end = start + u16::RAW_BYTE_LEN;
950        start..end
951    }
952
953    pub fn variation_regions_byte_range(&self) -> Range<usize> {
954        let region_count = self.region_count();
955        let start = self.region_count_byte_range().end;
956        let end = start
957            + (transforms::to_usize(region_count)).saturating_mul(
958                <VariationRegion as ComputeSize>::compute_size(&self.axis_count()).unwrap_or(0),
959            );
960        start..end
961    }
962}
963
964const _: () = assert!(FontData::default_data_long_enough(
965    VariationRegionList::MIN_SIZE
966));
967
968impl Default for VariationRegionList<'_> {
969    fn default() -> Self {
970        Self {
971            data: FontData::default_table_data(),
972        }
973    }
974}
975
976#[cfg(feature = "experimental_traverse")]
977impl<'a> SomeTable<'a> for VariationRegionList<'a> {
978    fn type_name(&self) -> &str {
979        "VariationRegionList"
980    }
981    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
982        match idx {
983            0usize => Some(Field::new("axis_count", self.axis_count())),
984            1usize => Some(Field::new("region_count", self.region_count())),
985            2usize => Some(Field::new(
986                "variation_regions",
987                traversal::FieldType::computed_array(
988                    "VariationRegion",
989                    self.variation_regions(),
990                    self.offset_data(),
991                ),
992            )),
993            _ => None,
994        }
995    }
996}
997
998#[cfg(feature = "experimental_traverse")]
999#[allow(clippy::needless_lifetimes)]
1000impl<'a> std::fmt::Debug for VariationRegionList<'a> {
1001    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1002        (self as &dyn SomeTable<'a>).fmt(f)
1003    }
1004}
1005
1006/// The [VariationRegion](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-regions) record
1007#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1008pub struct VariationRegion<'a> {
1009    /// Array of region axis coordinates records, in the order of axes
1010    /// given in the 'fvar' table.
1011    pub region_axes: &'a [RegionAxisCoordinates],
1012}
1013
1014impl<'a> VariationRegion<'a> {
1015    /// Array of region axis coordinates records, in the order of axes
1016    /// given in the 'fvar' table.
1017    pub fn region_axes(&self) -> &'a [RegionAxisCoordinates] {
1018        self.region_axes
1019    }
1020}
1021
1022impl ReadArgs for VariationRegion<'_> {
1023    type Args = u16;
1024}
1025
1026impl ComputeSize for VariationRegion<'_> {
1027    #[allow(clippy::needless_question_mark)]
1028    fn compute_size(args: &u16) -> Result<usize, ReadError> {
1029        let axis_count = *args;
1030        Ok((transforms::to_usize(axis_count)).saturating_mul(RegionAxisCoordinates::RAW_BYTE_LEN))
1031    }
1032}
1033
1034impl<'a> FontReadWithArgs<'a> for VariationRegion<'a> {
1035    fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
1036        let mut cursor = data.cursor();
1037        let axis_count = *args;
1038        Ok(Self {
1039            region_axes: cursor.read_array(transforms::to_usize(axis_count))?,
1040        })
1041    }
1042}
1043
1044#[allow(clippy::needless_lifetimes)]
1045impl<'a> VariationRegion<'a> {
1046    /// A constructor that requires additional arguments.
1047    ///
1048    /// This type requires some external state in order to be
1049    /// parsed.
1050    pub fn read(data: FontData<'a>, axis_count: u16) -> Result<Self, ReadError> {
1051        let args = axis_count;
1052        Self::read_with_args(data, &args)
1053    }
1054}
1055
1056#[cfg(feature = "experimental_traverse")]
1057impl<'a> SomeRecord<'a> for VariationRegion<'a> {
1058    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1059        RecordResolver {
1060            name: "VariationRegion",
1061            get_field: Box::new(move |idx, _data| match idx {
1062                0usize => Some(Field::new(
1063                    "region_axes",
1064                    traversal::FieldType::array_of_records(
1065                        stringify!(RegionAxisCoordinates),
1066                        self.region_axes(),
1067                        _data,
1068                    ),
1069                )),
1070                _ => None,
1071            }),
1072            data,
1073        }
1074    }
1075}
1076
1077/// The [RegionAxisCoordinates](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-regions) record
1078#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1079#[repr(C)]
1080#[repr(packed)]
1081pub struct RegionAxisCoordinates {
1082    /// The region start coordinate value for the current axis.
1083    pub start_coord: BigEndian<F2Dot14>,
1084    /// The region peak coordinate value for the current axis.
1085    pub peak_coord: BigEndian<F2Dot14>,
1086    /// The region end coordinate value for the current axis.
1087    pub end_coord: BigEndian<F2Dot14>,
1088}
1089
1090impl RegionAxisCoordinates {
1091    /// The region start coordinate value for the current axis.
1092    pub fn start_coord(&self) -> F2Dot14 {
1093        self.start_coord.get()
1094    }
1095
1096    /// The region peak coordinate value for the current axis.
1097    pub fn peak_coord(&self) -> F2Dot14 {
1098        self.peak_coord.get()
1099    }
1100
1101    /// The region end coordinate value for the current axis.
1102    pub fn end_coord(&self) -> F2Dot14 {
1103        self.end_coord.get()
1104    }
1105}
1106
1107impl FixedSize for RegionAxisCoordinates {
1108    const RAW_BYTE_LEN: usize =
1109        F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN;
1110}
1111
1112#[cfg(feature = "experimental_traverse")]
1113impl<'a> SomeRecord<'a> for RegionAxisCoordinates {
1114    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1115        RecordResolver {
1116            name: "RegionAxisCoordinates",
1117            get_field: Box::new(move |idx, _data| match idx {
1118                0usize => Some(Field::new("start_coord", self.start_coord())),
1119                1usize => Some(Field::new("peak_coord", self.peak_coord())),
1120                2usize => Some(Field::new("end_coord", self.end_coord())),
1121                _ => None,
1122            }),
1123            data,
1124        }
1125    }
1126}
1127
1128impl<'a> MinByteRange<'a> for ItemVariationStore<'a> {
1129    fn min_byte_range(&self) -> Range<usize> {
1130        0..self.item_variation_data_offsets_byte_range().end
1131    }
1132    fn min_table_bytes(&self) -> &'a [u8] {
1133        let range = self.min_byte_range();
1134        self.data.as_bytes().get(range).unwrap_or_default()
1135    }
1136}
1137
1138impl<'a> FontRead<'a> for ItemVariationStore<'a> {
1139    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1140        #[allow(clippy::absurd_extreme_comparisons)]
1141        if data.len() < Self::MIN_SIZE {
1142            return Err(ReadError::OutOfBounds);
1143        }
1144        Ok(Self { data })
1145    }
1146}
1147
1148/// The [ItemVariationStore](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables) table
1149#[derive(Clone)]
1150pub struct ItemVariationStore<'a> {
1151    data: FontData<'a>,
1152}
1153
1154#[allow(clippy::needless_lifetimes)]
1155impl<'a> ItemVariationStore<'a> {
1156    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1157    basic_table_impls!(impl_the_methods);
1158
1159    /// Format— set to 1
1160    pub fn format(&self) -> u16 {
1161        let range = self.format_byte_range();
1162        self.data.read_at(range.start).ok().unwrap()
1163    }
1164
1165    /// Offset in bytes from the start of the item variation store to
1166    /// the variation region list.
1167    pub fn variation_region_list_offset(&self) -> Offset32 {
1168        let range = self.variation_region_list_offset_byte_range();
1169        self.data.read_at(range.start).ok().unwrap()
1170    }
1171
1172    /// Attempt to resolve [`variation_region_list_offset`][Self::variation_region_list_offset].
1173    pub fn variation_region_list(&self) -> Result<VariationRegionList<'a>, ReadError> {
1174        let data = self.data;
1175        self.variation_region_list_offset().resolve(data)
1176    }
1177
1178    /// The number of item variation data subtables.
1179    pub fn item_variation_data_count(&self) -> u16 {
1180        let range = self.item_variation_data_count_byte_range();
1181        self.data.read_at(range.start).ok().unwrap()
1182    }
1183
1184    /// Offsets in bytes from the start of the item variation store to
1185    /// each item variation data subtable.
1186    pub fn item_variation_data_offsets(&self) -> &'a [BigEndian<Nullable<Offset32>>] {
1187        let range = self.item_variation_data_offsets_byte_range();
1188        self.data.read_array(range).ok().unwrap_or_default()
1189    }
1190
1191    /// A dynamically resolving wrapper for [`item_variation_data_offsets`][Self::item_variation_data_offsets].
1192    pub fn item_variation_data(
1193        &self,
1194    ) -> ArrayOfNullableOffsets<'a, ItemVariationData<'a>, Offset32> {
1195        let data = self.data;
1196        let offsets = self.item_variation_data_offsets();
1197        ArrayOfNullableOffsets::new(offsets, data, ())
1198    }
1199
1200    pub fn format_byte_range(&self) -> Range<usize> {
1201        let start = 0;
1202        let end = start + u16::RAW_BYTE_LEN;
1203        start..end
1204    }
1205
1206    pub fn variation_region_list_offset_byte_range(&self) -> Range<usize> {
1207        let start = self.format_byte_range().end;
1208        let end = start + Offset32::RAW_BYTE_LEN;
1209        start..end
1210    }
1211
1212    pub fn item_variation_data_count_byte_range(&self) -> Range<usize> {
1213        let start = self.variation_region_list_offset_byte_range().end;
1214        let end = start + u16::RAW_BYTE_LEN;
1215        start..end
1216    }
1217
1218    pub fn item_variation_data_offsets_byte_range(&self) -> Range<usize> {
1219        let item_variation_data_count = self.item_variation_data_count();
1220        let start = self.item_variation_data_count_byte_range().end;
1221        let end = start
1222            + (transforms::to_usize(item_variation_data_count))
1223                .saturating_mul(Offset32::RAW_BYTE_LEN);
1224        start..end
1225    }
1226}
1227
1228const _: () = assert!(FontData::default_data_long_enough(
1229    ItemVariationStore::MIN_SIZE
1230));
1231
1232impl Default for ItemVariationStore<'_> {
1233    fn default() -> Self {
1234        Self {
1235            data: FontData::default_table_data(),
1236        }
1237    }
1238}
1239
1240#[cfg(feature = "experimental_traverse")]
1241impl<'a> SomeTable<'a> for ItemVariationStore<'a> {
1242    fn type_name(&self) -> &str {
1243        "ItemVariationStore"
1244    }
1245    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1246        match idx {
1247            0usize => Some(Field::new("format", self.format())),
1248            1usize => Some(Field::new(
1249                "variation_region_list_offset",
1250                FieldType::offset(
1251                    self.variation_region_list_offset(),
1252                    self.variation_region_list(),
1253                ),
1254            )),
1255            2usize => Some(Field::new(
1256                "item_variation_data_count",
1257                self.item_variation_data_count(),
1258            )),
1259            3usize => Some(Field::new(
1260                "item_variation_data_offsets",
1261                FieldType::from(self.item_variation_data()),
1262            )),
1263            _ => None,
1264        }
1265    }
1266}
1267
1268#[cfg(feature = "experimental_traverse")]
1269#[allow(clippy::needless_lifetimes)]
1270impl<'a> std::fmt::Debug for ItemVariationStore<'a> {
1271    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1272        (self as &dyn SomeTable<'a>).fmt(f)
1273    }
1274}
1275
1276impl<'a> MinByteRange<'a> for ItemVariationData<'a> {
1277    fn min_byte_range(&self) -> Range<usize> {
1278        0..self.delta_sets_byte_range().end
1279    }
1280    fn min_table_bytes(&self) -> &'a [u8] {
1281        let range = self.min_byte_range();
1282        self.data.as_bytes().get(range).unwrap_or_default()
1283    }
1284}
1285
1286impl<'a> FontRead<'a> for ItemVariationData<'a> {
1287    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1288        #[allow(clippy::absurd_extreme_comparisons)]
1289        if data.len() < Self::MIN_SIZE {
1290            return Err(ReadError::OutOfBounds);
1291        }
1292        Ok(Self { data })
1293    }
1294}
1295
1296/// The [ItemVariationData](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables) subtable
1297#[derive(Clone)]
1298pub struct ItemVariationData<'a> {
1299    data: FontData<'a>,
1300}
1301
1302#[allow(clippy::needless_lifetimes)]
1303impl<'a> ItemVariationData<'a> {
1304    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1305    basic_table_impls!(impl_the_methods);
1306
1307    /// The number of delta sets for distinct items.
1308    pub fn item_count(&self) -> u16 {
1309        let range = self.item_count_byte_range();
1310        self.data.read_at(range.start).ok().unwrap()
1311    }
1312
1313    /// A packed field: the high bit is a flag—see details below.
1314    pub fn word_delta_count(&self) -> u16 {
1315        let range = self.word_delta_count_byte_range();
1316        self.data.read_at(range.start).ok().unwrap()
1317    }
1318
1319    /// The number of variation regions referenced.
1320    pub fn region_index_count(&self) -> u16 {
1321        let range = self.region_index_count_byte_range();
1322        self.data.read_at(range.start).ok().unwrap()
1323    }
1324
1325    /// Array of indices into the variation region list for the regions
1326    /// referenced by this item variation data table.
1327    pub fn region_indexes(&self) -> &'a [BigEndian<u16>] {
1328        let range = self.region_indexes_byte_range();
1329        self.data.read_array(range).ok().unwrap_or_default()
1330    }
1331
1332    /// Delta-set rows.
1333    pub fn delta_sets(&self) -> &'a [u8] {
1334        let range = self.delta_sets_byte_range();
1335        self.data.read_array(range).ok().unwrap_or_default()
1336    }
1337
1338    pub fn item_count_byte_range(&self) -> Range<usize> {
1339        let start = 0;
1340        let end = start + u16::RAW_BYTE_LEN;
1341        start..end
1342    }
1343
1344    pub fn word_delta_count_byte_range(&self) -> Range<usize> {
1345        let start = self.item_count_byte_range().end;
1346        let end = start + u16::RAW_BYTE_LEN;
1347        start..end
1348    }
1349
1350    pub fn region_index_count_byte_range(&self) -> Range<usize> {
1351        let start = self.word_delta_count_byte_range().end;
1352        let end = start + u16::RAW_BYTE_LEN;
1353        start..end
1354    }
1355
1356    pub fn region_indexes_byte_range(&self) -> Range<usize> {
1357        let region_index_count = self.region_index_count();
1358        let start = self.region_index_count_byte_range().end;
1359        let end =
1360            start + (transforms::to_usize(region_index_count)).saturating_mul(u16::RAW_BYTE_LEN);
1361        start..end
1362    }
1363
1364    pub fn delta_sets_byte_range(&self) -> Range<usize> {
1365        let item_count = self.item_count();
1366        let word_delta_count = self.word_delta_count();
1367        let region_index_count = self.region_index_count();
1368        let start = self.region_indexes_byte_range().end;
1369        let end = start
1370            + (ItemVariationData::delta_sets_len(item_count, word_delta_count, region_index_count))
1371                .saturating_mul(u8::RAW_BYTE_LEN);
1372        start..end
1373    }
1374}
1375
1376const _: () = assert!(FontData::default_data_long_enough(
1377    ItemVariationData::MIN_SIZE
1378));
1379
1380impl Default for ItemVariationData<'_> {
1381    fn default() -> Self {
1382        Self {
1383            data: FontData::default_table_data(),
1384        }
1385    }
1386}
1387
1388#[cfg(feature = "experimental_traverse")]
1389impl<'a> SomeTable<'a> for ItemVariationData<'a> {
1390    fn type_name(&self) -> &str {
1391        "ItemVariationData"
1392    }
1393    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1394        match idx {
1395            0usize => Some(Field::new("item_count", self.item_count())),
1396            1usize => Some(Field::new("word_delta_count", self.word_delta_count())),
1397            2usize => Some(Field::new("region_index_count", self.region_index_count())),
1398            3usize => Some(Field::new("region_indexes", self.region_indexes())),
1399            4usize => Some(Field::new("delta_sets", self.delta_sets())),
1400            _ => None,
1401        }
1402    }
1403}
1404
1405#[cfg(feature = "experimental_traverse")]
1406#[allow(clippy::needless_lifetimes)]
1407impl<'a> std::fmt::Debug for ItemVariationData<'a> {
1408    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1409        (self as &dyn SomeTable<'a>).fmt(f)
1410    }
1411}