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