Skip to main content

read_fonts/generated/
generated_gpos.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 Gpos<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.lookup_list_offset_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 TopLevelTable for Gpos<'_> {
19    /// `GPOS`
20    const TAG: Tag = Tag::new(b"GPOS");
21}
22
23impl ReadArgs for Gpos<'_> {
24    type Args = ();
25}
26
27impl<'a> FontRead<'a> for Gpos<'a> {
28    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29        #[allow(clippy::absurd_extreme_comparisons)]
30        if data.len() < Self::MIN_SIZE {
31            return Err(ReadError::OutOfBounds);
32        }
33        Ok(Self { data })
34    }
35}
36
37/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
38/// [GPOS Version 1.0](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#gpos-header)
39#[derive(Clone)]
40pub struct Gpos<'a> {
41    data: FontData<'a>,
42}
43
44#[allow(clippy::needless_lifetimes)]
45impl<'a> Gpos<'a> {
46    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
47        + Offset16::RAW_BYTE_LEN
48        + Offset16::RAW_BYTE_LEN
49        + Offset16::RAW_BYTE_LEN);
50    basic_table_impls!(impl_the_methods);
51
52    /// The major and minor version of the GPOS table, as a tuple (u16, u16)
53    pub fn version(&self) -> MajorMinor {
54        let range = self.version_byte_range();
55        self.data.read_at(range.start).ok().unwrap()
56    }
57
58    /// Offset to ScriptList table, from beginning of GPOS table
59    pub fn script_list_offset(&self) -> Offset16 {
60        let range = self.script_list_offset_byte_range();
61        self.data.read_at(range.start).ok().unwrap()
62    }
63
64    /// Attempt to resolve [`script_list_offset`][Self::script_list_offset].
65    pub fn script_list(&self) -> Result<ScriptList<'a>, ReadError> {
66        let data = self.data;
67        self.script_list_offset().resolve(data)
68    }
69
70    /// Offset to FeatureList table, from beginning of GPOS table
71    pub fn feature_list_offset(&self) -> Offset16 {
72        let range = self.feature_list_offset_byte_range();
73        self.data.read_at(range.start).ok().unwrap()
74    }
75
76    /// Attempt to resolve [`feature_list_offset`][Self::feature_list_offset].
77    pub fn feature_list(&self) -> Result<FeatureList<'a>, ReadError> {
78        let data = self.data;
79        self.feature_list_offset().resolve(data)
80    }
81
82    /// Offset to LookupList table, from beginning of GPOS table
83    pub fn lookup_list_offset(&self) -> Offset16 {
84        let range = self.lookup_list_offset_byte_range();
85        self.data.read_at(range.start).ok().unwrap()
86    }
87
88    /// Attempt to resolve [`lookup_list_offset`][Self::lookup_list_offset].
89    pub fn lookup_list(&self) -> Result<PositionLookupList<'a>, ReadError> {
90        let data = self.data;
91        self.lookup_list_offset().resolve(data)
92    }
93
94    pub fn feature_variations_offset(&self) -> Option<Nullable<Offset32>> {
95        let range = self.feature_variations_offset_byte_range();
96        (!range.is_empty())
97            .then(|| self.data.read_at(range.start).ok())
98            .flatten()
99    }
100
101    /// Attempt to resolve [`feature_variations_offset`][Self::feature_variations_offset].
102    pub fn feature_variations(&self) -> Option<Result<FeatureVariations<'a>, ReadError>> {
103        let data = self.data;
104        self.feature_variations_offset().map(|x| x.resolve(data))?
105    }
106
107    pub fn version_byte_range(&self) -> Range<usize> {
108        let start = 0;
109        let end = start + MajorMinor::RAW_BYTE_LEN;
110        start..end
111    }
112
113    pub fn script_list_offset_byte_range(&self) -> Range<usize> {
114        let start = self.version_byte_range().end;
115        let end = start + Offset16::RAW_BYTE_LEN;
116        start..end
117    }
118
119    pub fn feature_list_offset_byte_range(&self) -> Range<usize> {
120        let start = self.script_list_offset_byte_range().end;
121        let end = start + Offset16::RAW_BYTE_LEN;
122        start..end
123    }
124
125    pub fn lookup_list_offset_byte_range(&self) -> Range<usize> {
126        let start = self.feature_list_offset_byte_range().end;
127        let end = start + Offset16::RAW_BYTE_LEN;
128        start..end
129    }
130
131    pub fn feature_variations_offset_byte_range(&self) -> Range<usize> {
132        let start = self.lookup_list_offset_byte_range().end;
133        let end = if self.version().compatible((1u16, 1u16)) {
134            start + Offset32::RAW_BYTE_LEN
135        } else {
136            start
137        };
138        start..end
139    }
140}
141
142const _: () = assert!(FontData::default_data_long_enough(Gpos::MIN_SIZE));
143
144impl Default for Gpos<'_> {
145    fn default() -> Self {
146        Self {
147            data: FontData::default_table_data(),
148        }
149    }
150}
151
152#[cfg(feature = "experimental_traverse")]
153impl<'a> SomeTable<'a> for Gpos<'a> {
154    fn type_name(&self) -> &str {
155        "Gpos"
156    }
157    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
158        match idx {
159            0usize => Some(Field::new("version", self.version())),
160            1usize => Some(Field::new(
161                "script_list_offset",
162                FieldType::offset(self.script_list_offset(), self.script_list()),
163            )),
164            2usize => Some(Field::new(
165                "feature_list_offset",
166                FieldType::offset(self.feature_list_offset(), self.feature_list()),
167            )),
168            3usize => Some(Field::new(
169                "lookup_list_offset",
170                FieldType::offset(self.lookup_list_offset(), self.lookup_list()),
171            )),
172            4usize if self.version().compatible((1u16, 1u16)) => Some(Field::new(
173                "feature_variations_offset",
174                FieldType::offset(
175                    self.feature_variations_offset().unwrap(),
176                    self.feature_variations(),
177                ),
178            )),
179            _ => None,
180        }
181    }
182}
183
184#[cfg(feature = "experimental_traverse")]
185#[allow(clippy::needless_lifetimes)]
186impl<'a> std::fmt::Debug for Gpos<'a> {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        (self as &dyn SomeTable<'a>).fmt(f)
189    }
190}
191
192/// A [GPOS Lookup](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#gsubLookupTypeEnum) subtable.
193pub enum PositionLookup<'a> {
194    Single(Lookup<'a, SinglePos<'a>>),
195    Pair(Lookup<'a, PairPos<'a>>),
196    Cursive(Lookup<'a, CursivePosFormat1<'a>>),
197    MarkToBase(Lookup<'a, MarkBasePosFormat1<'a>>),
198    MarkToLig(Lookup<'a, MarkLigPosFormat1<'a>>),
199    MarkToMark(Lookup<'a, MarkMarkPosFormat1<'a>>),
200    Contextual(Lookup<'a, PositionSequenceContext<'a>>),
201    ChainContextual(Lookup<'a, PositionChainContext<'a>>),
202    Extension(Lookup<'a, ExtensionSubtable<'a>>),
203}
204
205impl Default for PositionLookup<'_> {
206    fn default() -> Self {
207        Self::Single(Default::default())
208    }
209}
210
211impl ReadArgs for PositionLookup<'_> {
212    type Args = ();
213}
214
215impl<'a> FontRead<'a> for PositionLookup<'a> {
216    fn read_with_args(bytes: FontData<'a>, _: ()) -> Result<Self, ReadError> {
217        let discriminant = Lookup::read_discriminant(bytes)?;
218        match discriminant {
219            1 => Ok(PositionLookup::Single(FontRead::read(bytes)?)),
220            2 => Ok(PositionLookup::Pair(FontRead::read(bytes)?)),
221            3 => Ok(PositionLookup::Cursive(FontRead::read(bytes)?)),
222            4 => Ok(PositionLookup::MarkToBase(FontRead::read(bytes)?)),
223            5 => Ok(PositionLookup::MarkToLig(FontRead::read(bytes)?)),
224            6 => Ok(PositionLookup::MarkToMark(FontRead::read(bytes)?)),
225            7 => Ok(PositionLookup::Contextual(FontRead::read(bytes)?)),
226            8 => Ok(PositionLookup::ChainContextual(FontRead::read(bytes)?)),
227            9 => Ok(PositionLookup::Extension(FontRead::read(bytes)?)),
228            other => Err(ReadError::InvalidFormat(other.into())),
229        }
230    }
231}
232
233impl<'a> PositionLookup<'a> {
234    #[allow(dead_code)]
235    /// Return the inner table, removing the specific generics.
236    ///
237    /// This lets us return a single concrete type we can call methods on.
238    pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
239        match self {
240            PositionLookup::Single(inner) => inner.of_unit_type(),
241            PositionLookup::Pair(inner) => inner.of_unit_type(),
242            PositionLookup::Cursive(inner) => inner.of_unit_type(),
243            PositionLookup::MarkToBase(inner) => inner.of_unit_type(),
244            PositionLookup::MarkToLig(inner) => inner.of_unit_type(),
245            PositionLookup::MarkToMark(inner) => inner.of_unit_type(),
246            PositionLookup::Contextual(inner) => inner.of_unit_type(),
247            PositionLookup::ChainContextual(inner) => inner.of_unit_type(),
248            PositionLookup::Extension(inner) => inner.of_unit_type(),
249        }
250    }
251}
252
253#[cfg(feature = "experimental_traverse")]
254impl<'a> PositionLookup<'a> {
255    fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
256        match self {
257            PositionLookup::Single(table) => table,
258            PositionLookup::Pair(table) => table,
259            PositionLookup::Cursive(table) => table,
260            PositionLookup::MarkToBase(table) => table,
261            PositionLookup::MarkToLig(table) => table,
262            PositionLookup::MarkToMark(table) => table,
263            PositionLookup::Contextual(table) => table,
264            PositionLookup::ChainContextual(table) => table,
265            PositionLookup::Extension(table) => table,
266        }
267    }
268}
269
270#[cfg(feature = "experimental_traverse")]
271impl<'a> SomeTable<'a> for PositionLookup<'a> {
272    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
273        self.dyn_inner().get_field(idx)
274    }
275    fn type_name(&self) -> &str {
276        self.dyn_inner().type_name()
277    }
278}
279
280#[cfg(feature = "experimental_traverse")]
281impl std::fmt::Debug for PositionLookup<'_> {
282    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283        self.dyn_inner().fmt(f)
284    }
285}
286
287/// See [ValueRecord]
288#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
289#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
290#[repr(transparent)]
291pub struct ValueFormat {
292    bits: u16,
293}
294
295impl ValueFormat {
296    /// Includes horizontal adjustment for placement
297    pub const X_PLACEMENT: Self = Self { bits: 0x0001 };
298
299    /// Includes vertical adjustment for placement
300    pub const Y_PLACEMENT: Self = Self { bits: 0x0002 };
301
302    /// Includes horizontal adjustment for advance
303    pub const X_ADVANCE: Self = Self { bits: 0x0004 };
304
305    /// Includes vertical adjustment for advance
306    pub const Y_ADVANCE: Self = Self { bits: 0x0008 };
307
308    /// Includes Device table (non-variable font) / VariationIndex
309    /// table (variable font) for horizontal placement
310    pub const X_PLACEMENT_DEVICE: Self = Self { bits: 0x0010 };
311
312    /// Includes Device table (non-variable font) / VariationIndex
313    /// table (variable font) for vertical placement
314    pub const Y_PLACEMENT_DEVICE: Self = Self { bits: 0x0020 };
315
316    /// Includes Device table (non-variable font) / VariationIndex
317    /// table (variable font) for horizontal advance
318    pub const X_ADVANCE_DEVICE: Self = Self { bits: 0x0040 };
319
320    /// Includes Device table (non-variable font) / VariationIndex
321    /// table (variable font) for vertical advance
322    pub const Y_ADVANCE_DEVICE: Self = Self { bits: 0x0080 };
323}
324
325impl ValueFormat {
326    ///  Returns an empty set of flags.
327    #[inline]
328    pub const fn empty() -> Self {
329        Self { bits: 0 }
330    }
331
332    /// Returns the set containing all flags.
333    #[inline]
334    pub const fn all() -> Self {
335        Self {
336            bits: Self::X_PLACEMENT.bits
337                | Self::Y_PLACEMENT.bits
338                | Self::X_ADVANCE.bits
339                | Self::Y_ADVANCE.bits
340                | Self::X_PLACEMENT_DEVICE.bits
341                | Self::Y_PLACEMENT_DEVICE.bits
342                | Self::X_ADVANCE_DEVICE.bits
343                | Self::Y_ADVANCE_DEVICE.bits,
344        }
345    }
346
347    /// Returns the raw value of the flags currently stored.
348    #[inline]
349    pub const fn bits(&self) -> u16 {
350        self.bits
351    }
352
353    /// Convert from underlying bit representation, unless that
354    /// representation contains bits that do not correspond to a flag.
355    #[inline]
356    pub const fn from_bits(bits: u16) -> Option<Self> {
357        if (bits & !Self::all().bits()) == 0 {
358            Some(Self { bits })
359        } else {
360            None
361        }
362    }
363
364    /// Convert from underlying bit representation, dropping any bits
365    /// that do not correspond to flags.
366    #[inline]
367    pub const fn from_bits_truncate(bits: u16) -> Self {
368        Self {
369            bits: bits & Self::all().bits,
370        }
371    }
372
373    /// Returns `true` if no flags are currently stored.
374    #[inline]
375    pub const fn is_empty(&self) -> bool {
376        self.bits() == Self::empty().bits()
377    }
378
379    /// Returns `true` if there are flags common to both `self` and `other`.
380    #[inline]
381    pub const fn intersects(&self, other: Self) -> bool {
382        !(Self {
383            bits: self.bits & other.bits,
384        })
385        .is_empty()
386    }
387
388    /// Returns `true` if all of the flags in `other` are contained within `self`.
389    #[inline]
390    pub const fn contains(&self, other: Self) -> bool {
391        (self.bits & other.bits) == other.bits
392    }
393
394    /// Inserts the specified flags in-place.
395    #[inline]
396    pub fn insert(&mut self, other: Self) {
397        self.bits |= other.bits;
398    }
399
400    /// Removes the specified flags in-place.
401    #[inline]
402    pub fn remove(&mut self, other: Self) {
403        self.bits &= !other.bits;
404    }
405
406    /// Toggles the specified flags in-place.
407    #[inline]
408    pub fn toggle(&mut self, other: Self) {
409        self.bits ^= other.bits;
410    }
411
412    /// Returns the intersection between the flags in `self` and
413    /// `other`.
414    ///
415    /// Specifically, the returned set contains only the flags which are
416    /// present in *both* `self` *and* `other`.
417    ///
418    /// This is equivalent to using the `&` operator (e.g.
419    /// [`ops::BitAnd`]), as in `flags & other`.
420    ///
421    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
422    #[inline]
423    #[must_use]
424    pub const fn intersection(self, other: Self) -> Self {
425        Self {
426            bits: self.bits & other.bits,
427        }
428    }
429
430    /// Returns the union of between the flags in `self` and `other`.
431    ///
432    /// Specifically, the returned set contains all flags which are
433    /// present in *either* `self` *or* `other`, including any which are
434    /// present in both.
435    ///
436    /// This is equivalent to using the `|` operator (e.g.
437    /// [`ops::BitOr`]), as in `flags | other`.
438    ///
439    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
440    #[inline]
441    #[must_use]
442    pub const fn union(self, other: Self) -> Self {
443        Self {
444            bits: self.bits | other.bits,
445        }
446    }
447
448    /// Returns the difference between the flags in `self` and `other`.
449    ///
450    /// Specifically, the returned set contains all flags present in
451    /// `self`, except for the ones present in `other`.
452    ///
453    /// It is also conceptually equivalent to the "bit-clear" operation:
454    /// `flags & !other` (and this syntax is also supported).
455    ///
456    /// This is equivalent to using the `-` operator (e.g.
457    /// [`ops::Sub`]), as in `flags - other`.
458    ///
459    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
460    #[inline]
461    #[must_use]
462    pub const fn difference(self, other: Self) -> Self {
463        Self {
464            bits: self.bits & !other.bits,
465        }
466    }
467}
468
469impl std::ops::BitOr for ValueFormat {
470    type Output = Self;
471
472    /// Returns the union of the two sets of flags.
473    #[inline]
474    fn bitor(self, other: ValueFormat) -> Self {
475        Self {
476            bits: self.bits | other.bits,
477        }
478    }
479}
480
481impl std::ops::BitOrAssign for ValueFormat {
482    /// Adds the set of flags.
483    #[inline]
484    fn bitor_assign(&mut self, other: Self) {
485        self.bits |= other.bits;
486    }
487}
488
489impl std::ops::BitXor for ValueFormat {
490    type Output = Self;
491
492    /// Returns the left flags, but with all the right flags toggled.
493    #[inline]
494    fn bitxor(self, other: Self) -> Self {
495        Self {
496            bits: self.bits ^ other.bits,
497        }
498    }
499}
500
501impl std::ops::BitXorAssign for ValueFormat {
502    /// Toggles the set of flags.
503    #[inline]
504    fn bitxor_assign(&mut self, other: Self) {
505        self.bits ^= other.bits;
506    }
507}
508
509impl std::ops::BitAnd for ValueFormat {
510    type Output = Self;
511
512    /// Returns the intersection between the two sets of flags.
513    #[inline]
514    fn bitand(self, other: Self) -> Self {
515        Self {
516            bits: self.bits & other.bits,
517        }
518    }
519}
520
521impl std::ops::BitAndAssign for ValueFormat {
522    /// Disables all flags disabled in the set.
523    #[inline]
524    fn bitand_assign(&mut self, other: Self) {
525        self.bits &= other.bits;
526    }
527}
528
529impl std::ops::Sub for ValueFormat {
530    type Output = Self;
531
532    /// Returns the set difference of the two sets of flags.
533    #[inline]
534    fn sub(self, other: Self) -> Self {
535        Self {
536            bits: self.bits & !other.bits,
537        }
538    }
539}
540
541impl std::ops::SubAssign for ValueFormat {
542    /// Disables all flags enabled in the set.
543    #[inline]
544    fn sub_assign(&mut self, other: Self) {
545        self.bits &= !other.bits;
546    }
547}
548
549impl std::ops::Not for ValueFormat {
550    type Output = Self;
551
552    /// Returns the complement of this set of flags.
553    #[inline]
554    fn not(self) -> Self {
555        Self { bits: !self.bits } & Self::all()
556    }
557}
558
559impl std::fmt::Debug for ValueFormat {
560    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
561        let members: &[(&str, Self)] = &[
562            ("X_PLACEMENT", Self::X_PLACEMENT),
563            ("Y_PLACEMENT", Self::Y_PLACEMENT),
564            ("X_ADVANCE", Self::X_ADVANCE),
565            ("Y_ADVANCE", Self::Y_ADVANCE),
566            ("X_PLACEMENT_DEVICE", Self::X_PLACEMENT_DEVICE),
567            ("Y_PLACEMENT_DEVICE", Self::Y_PLACEMENT_DEVICE),
568            ("X_ADVANCE_DEVICE", Self::X_ADVANCE_DEVICE),
569            ("Y_ADVANCE_DEVICE", Self::Y_ADVANCE_DEVICE),
570        ];
571        let mut first = true;
572        for (name, value) in members {
573            if self.contains(*value) {
574                if !first {
575                    f.write_str(" | ")?;
576                }
577                first = false;
578                f.write_str(name)?;
579            }
580        }
581        if first {
582            f.write_str("(empty)")?;
583        }
584        Ok(())
585    }
586}
587
588impl std::fmt::Binary for ValueFormat {
589    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
590        std::fmt::Binary::fmt(&self.bits, f)
591    }
592}
593
594impl std::fmt::Octal for ValueFormat {
595    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
596        std::fmt::Octal::fmt(&self.bits, f)
597    }
598}
599
600impl std::fmt::LowerHex for ValueFormat {
601    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
602        std::fmt::LowerHex::fmt(&self.bits, f)
603    }
604}
605
606impl std::fmt::UpperHex for ValueFormat {
607    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
608        std::fmt::UpperHex::fmt(&self.bits, f)
609    }
610}
611
612impl font_types::Scalar for ValueFormat {
613    type Raw = <u16 as font_types::Scalar>::Raw;
614    fn to_raw(self) -> Self::Raw {
615        self.bits().to_raw()
616    }
617    fn from_raw(raw: Self::Raw) -> Self {
618        let t = <u16>::from_raw(raw);
619        Self::from_bits_truncate(t)
620    }
621}
622
623#[cfg(feature = "experimental_traverse")]
624impl<'a> From<ValueFormat> for FieldType<'a> {
625    fn from(src: ValueFormat) -> FieldType<'a> {
626        src.bits().into()
627    }
628}
629
630/// [Anchor Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-tables)
631/// position one glyph with respect to another.
632#[derive(Clone)]
633pub enum AnchorTable<'a> {
634    Format1(AnchorFormat1<'a>),
635    Format2(AnchorFormat2<'a>),
636    Format3(AnchorFormat3<'a>),
637}
638
639impl Default for AnchorTable<'_> {
640    fn default() -> Self {
641        Self::Format1(Default::default())
642    }
643}
644
645impl<'a> AnchorTable<'a> {
646    ///Return the `FontData` used to resolve offsets for this table.
647    pub fn offset_data(&self) -> FontData<'a> {
648        match self {
649            Self::Format1(item) => item.offset_data(),
650            Self::Format2(item) => item.offset_data(),
651            Self::Format3(item) => item.offset_data(),
652        }
653    }
654
655    /// Format identifier, = 1
656    pub fn anchor_format(&self) -> u16 {
657        match self {
658            Self::Format1(item) => item.anchor_format(),
659            Self::Format2(item) => item.anchor_format(),
660            Self::Format3(item) => item.anchor_format(),
661        }
662    }
663
664    /// Horizontal value, in design units
665    pub fn x_coordinate(&self) -> i16 {
666        match self {
667            Self::Format1(item) => item.x_coordinate(),
668            Self::Format2(item) => item.x_coordinate(),
669            Self::Format3(item) => item.x_coordinate(),
670        }
671    }
672
673    /// Vertical value, in design units
674    pub fn y_coordinate(&self) -> i16 {
675        match self {
676            Self::Format1(item) => item.y_coordinate(),
677            Self::Format2(item) => item.y_coordinate(),
678            Self::Format3(item) => item.y_coordinate(),
679        }
680    }
681}
682
683impl ReadArgs for AnchorTable<'_> {
684    type Args = ();
685}
686
687impl<'a> FontRead<'a> for AnchorTable<'a> {
688    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
689        let format: u16 = data.read_at(0usize)?;
690        match format {
691            AnchorFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
692            AnchorFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
693            AnchorFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
694            other => Err(ReadError::InvalidFormat(other.into())),
695        }
696    }
697}
698
699impl<'a> MinByteRange<'a> for AnchorTable<'a> {
700    fn min_byte_range(&self) -> Range<usize> {
701        match self {
702            Self::Format1(item) => item.min_byte_range(),
703            Self::Format2(item) => item.min_byte_range(),
704            Self::Format3(item) => item.min_byte_range(),
705        }
706    }
707    fn min_table_bytes(&self) -> &'a [u8] {
708        match self {
709            Self::Format1(item) => item.min_table_bytes(),
710            Self::Format2(item) => item.min_table_bytes(),
711            Self::Format3(item) => item.min_table_bytes(),
712        }
713    }
714}
715
716#[cfg(feature = "experimental_traverse")]
717impl<'a> AnchorTable<'a> {
718    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
719        match self {
720            Self::Format1(table) => table,
721            Self::Format2(table) => table,
722            Self::Format3(table) => table,
723        }
724    }
725}
726
727#[cfg(feature = "experimental_traverse")]
728impl std::fmt::Debug for AnchorTable<'_> {
729    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
730        self.dyn_inner().fmt(f)
731    }
732}
733
734#[cfg(feature = "experimental_traverse")]
735impl<'a> SomeTable<'a> for AnchorTable<'a> {
736    fn type_name(&self) -> &str {
737        self.dyn_inner().type_name()
738    }
739    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
740        self.dyn_inner().get_field(idx)
741    }
742}
743
744impl Format<u16> for AnchorFormat1<'_> {
745    const FORMAT: u16 = 1;
746}
747
748impl<'a> MinByteRange<'a> for AnchorFormat1<'a> {
749    fn min_byte_range(&self) -> Range<usize> {
750        0..self.y_coordinate_byte_range().end
751    }
752    fn min_table_bytes(&self) -> &'a [u8] {
753        let range = self.min_byte_range();
754        self.data.as_bytes().get(range).unwrap_or_default()
755    }
756}
757
758impl ReadArgs for AnchorFormat1<'_> {
759    type Args = ();
760}
761
762impl<'a> FontRead<'a> for AnchorFormat1<'a> {
763    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
764        #[allow(clippy::absurd_extreme_comparisons)]
765        if data.len() < Self::MIN_SIZE {
766            return Err(ReadError::OutOfBounds);
767        }
768        Ok(Self { data })
769    }
770}
771
772/// [Anchor Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-1-design-units): Design Units
773#[derive(Clone)]
774pub struct AnchorFormat1<'a> {
775    data: FontData<'a>,
776}
777
778#[allow(clippy::needless_lifetimes)]
779impl<'a> AnchorFormat1<'a> {
780    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
781    basic_table_impls!(impl_the_methods);
782
783    /// Format identifier, = 1
784    pub fn anchor_format(&self) -> u16 {
785        let range = self.anchor_format_byte_range();
786        self.data.read_at(range.start).ok().unwrap()
787    }
788
789    /// Horizontal value, in design units
790    pub fn x_coordinate(&self) -> i16 {
791        let range = self.x_coordinate_byte_range();
792        self.data.read_at(range.start).ok().unwrap()
793    }
794
795    /// Vertical value, in design units
796    pub fn y_coordinate(&self) -> i16 {
797        let range = self.y_coordinate_byte_range();
798        self.data.read_at(range.start).ok().unwrap()
799    }
800
801    pub fn anchor_format_byte_range(&self) -> Range<usize> {
802        let start = 0;
803        let end = start + u16::RAW_BYTE_LEN;
804        start..end
805    }
806
807    pub fn x_coordinate_byte_range(&self) -> Range<usize> {
808        let start = self.anchor_format_byte_range().end;
809        let end = start + i16::RAW_BYTE_LEN;
810        start..end
811    }
812
813    pub fn y_coordinate_byte_range(&self) -> Range<usize> {
814        let start = self.x_coordinate_byte_range().end;
815        let end = start + i16::RAW_BYTE_LEN;
816        start..end
817    }
818}
819
820const _: () = assert!(FontData::default_data_long_enough(AnchorFormat1::MIN_SIZE));
821
822impl Default for AnchorFormat1<'_> {
823    fn default() -> Self {
824        Self {
825            data: FontData::default_format_1_u16_table_data(),
826        }
827    }
828}
829
830#[cfg(feature = "experimental_traverse")]
831impl<'a> SomeTable<'a> for AnchorFormat1<'a> {
832    fn type_name(&self) -> &str {
833        "AnchorFormat1"
834    }
835    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
836        match idx {
837            0usize => Some(Field::new("anchor_format", self.anchor_format())),
838            1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
839            2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
840            _ => None,
841        }
842    }
843}
844
845#[cfg(feature = "experimental_traverse")]
846#[allow(clippy::needless_lifetimes)]
847impl<'a> std::fmt::Debug for AnchorFormat1<'a> {
848    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
849        (self as &dyn SomeTable<'a>).fmt(f)
850    }
851}
852
853impl Format<u16> for AnchorFormat2<'_> {
854    const FORMAT: u16 = 2;
855}
856
857impl<'a> MinByteRange<'a> for AnchorFormat2<'a> {
858    fn min_byte_range(&self) -> Range<usize> {
859        0..self.anchor_point_byte_range().end
860    }
861    fn min_table_bytes(&self) -> &'a [u8] {
862        let range = self.min_byte_range();
863        self.data.as_bytes().get(range).unwrap_or_default()
864    }
865}
866
867impl ReadArgs for AnchorFormat2<'_> {
868    type Args = ();
869}
870
871impl<'a> FontRead<'a> for AnchorFormat2<'a> {
872    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
873        #[allow(clippy::absurd_extreme_comparisons)]
874        if data.len() < Self::MIN_SIZE {
875            return Err(ReadError::OutOfBounds);
876        }
877        Ok(Self { data })
878    }
879}
880
881/// [Anchor Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-2-design-units-plus-contour-point): Design Units Plus Contour Point
882#[derive(Clone)]
883pub struct AnchorFormat2<'a> {
884    data: FontData<'a>,
885}
886
887#[allow(clippy::needless_lifetimes)]
888impl<'a> AnchorFormat2<'a> {
889    pub const MIN_SIZE: usize =
890        (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
891    basic_table_impls!(impl_the_methods);
892
893    /// Format identifier, = 2
894    pub fn anchor_format(&self) -> u16 {
895        let range = self.anchor_format_byte_range();
896        self.data.read_at(range.start).ok().unwrap()
897    }
898
899    /// Horizontal value, in design units
900    pub fn x_coordinate(&self) -> i16 {
901        let range = self.x_coordinate_byte_range();
902        self.data.read_at(range.start).ok().unwrap()
903    }
904
905    /// Vertical value, in design units
906    pub fn y_coordinate(&self) -> i16 {
907        let range = self.y_coordinate_byte_range();
908        self.data.read_at(range.start).ok().unwrap()
909    }
910
911    /// Index to glyph contour point
912    pub fn anchor_point(&self) -> u16 {
913        let range = self.anchor_point_byte_range();
914        self.data.read_at(range.start).ok().unwrap()
915    }
916
917    pub fn anchor_format_byte_range(&self) -> Range<usize> {
918        let start = 0;
919        let end = start + u16::RAW_BYTE_LEN;
920        start..end
921    }
922
923    pub fn x_coordinate_byte_range(&self) -> Range<usize> {
924        let start = self.anchor_format_byte_range().end;
925        let end = start + i16::RAW_BYTE_LEN;
926        start..end
927    }
928
929    pub fn y_coordinate_byte_range(&self) -> Range<usize> {
930        let start = self.x_coordinate_byte_range().end;
931        let end = start + i16::RAW_BYTE_LEN;
932        start..end
933    }
934
935    pub fn anchor_point_byte_range(&self) -> Range<usize> {
936        let start = self.y_coordinate_byte_range().end;
937        let end = start + u16::RAW_BYTE_LEN;
938        start..end
939    }
940}
941
942#[cfg(feature = "experimental_traverse")]
943impl<'a> SomeTable<'a> for AnchorFormat2<'a> {
944    fn type_name(&self) -> &str {
945        "AnchorFormat2"
946    }
947    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
948        match idx {
949            0usize => Some(Field::new("anchor_format", self.anchor_format())),
950            1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
951            2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
952            3usize => Some(Field::new("anchor_point", self.anchor_point())),
953            _ => None,
954        }
955    }
956}
957
958#[cfg(feature = "experimental_traverse")]
959#[allow(clippy::needless_lifetimes)]
960impl<'a> std::fmt::Debug for AnchorFormat2<'a> {
961    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
962        (self as &dyn SomeTable<'a>).fmt(f)
963    }
964}
965
966impl Format<u16> for AnchorFormat3<'_> {
967    const FORMAT: u16 = 3;
968}
969
970impl<'a> MinByteRange<'a> for AnchorFormat3<'a> {
971    fn min_byte_range(&self) -> Range<usize> {
972        0..self.y_device_offset_byte_range().end
973    }
974    fn min_table_bytes(&self) -> &'a [u8] {
975        let range = self.min_byte_range();
976        self.data.as_bytes().get(range).unwrap_or_default()
977    }
978}
979
980impl ReadArgs for AnchorFormat3<'_> {
981    type Args = ();
982}
983
984impl<'a> FontRead<'a> for AnchorFormat3<'a> {
985    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
986        #[allow(clippy::absurd_extreme_comparisons)]
987        if data.len() < Self::MIN_SIZE {
988            return Err(ReadError::OutOfBounds);
989        }
990        Ok(Self { data })
991    }
992}
993
994/// [Anchor Table Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-3-design-units-plus-device-or-variationindex-tables): Design Units Plus Device or VariationIndex Tables
995#[derive(Clone)]
996pub struct AnchorFormat3<'a> {
997    data: FontData<'a>,
998}
999
1000#[allow(clippy::needless_lifetimes)]
1001impl<'a> AnchorFormat3<'a> {
1002    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1003        + i16::RAW_BYTE_LEN
1004        + i16::RAW_BYTE_LEN
1005        + Offset16::RAW_BYTE_LEN
1006        + Offset16::RAW_BYTE_LEN);
1007    basic_table_impls!(impl_the_methods);
1008
1009    /// Format identifier, = 3
1010    pub fn anchor_format(&self) -> u16 {
1011        let range = self.anchor_format_byte_range();
1012        self.data.read_at(range.start).ok().unwrap()
1013    }
1014
1015    /// Horizontal value, in design units
1016    pub fn x_coordinate(&self) -> i16 {
1017        let range = self.x_coordinate_byte_range();
1018        self.data.read_at(range.start).ok().unwrap()
1019    }
1020
1021    /// Vertical value, in design units
1022    pub fn y_coordinate(&self) -> i16 {
1023        let range = self.y_coordinate_byte_range();
1024        self.data.read_at(range.start).ok().unwrap()
1025    }
1026
1027    /// Offset to Device table (non-variable font) / VariationIndex
1028    /// table (variable font) for X coordinate, from beginning of
1029    /// Anchor table (may be NULL)
1030    pub fn x_device_offset(&self) -> Nullable<Offset16> {
1031        let range = self.x_device_offset_byte_range();
1032        self.data.read_at(range.start).ok().unwrap()
1033    }
1034
1035    /// Attempt to resolve [`x_device_offset`][Self::x_device_offset].
1036    pub fn x_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1037        let data = self.data;
1038        self.x_device_offset().resolve(data)
1039    }
1040
1041    /// Offset to Device table (non-variable font) / VariationIndex
1042    /// table (variable font) for Y coordinate, from beginning of
1043    /// Anchor table (may be NULL)
1044    pub fn y_device_offset(&self) -> Nullable<Offset16> {
1045        let range = self.y_device_offset_byte_range();
1046        self.data.read_at(range.start).ok().unwrap()
1047    }
1048
1049    /// Attempt to resolve [`y_device_offset`][Self::y_device_offset].
1050    pub fn y_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1051        let data = self.data;
1052        self.y_device_offset().resolve(data)
1053    }
1054
1055    pub fn anchor_format_byte_range(&self) -> Range<usize> {
1056        let start = 0;
1057        let end = start + u16::RAW_BYTE_LEN;
1058        start..end
1059    }
1060
1061    pub fn x_coordinate_byte_range(&self) -> Range<usize> {
1062        let start = self.anchor_format_byte_range().end;
1063        let end = start + i16::RAW_BYTE_LEN;
1064        start..end
1065    }
1066
1067    pub fn y_coordinate_byte_range(&self) -> Range<usize> {
1068        let start = self.x_coordinate_byte_range().end;
1069        let end = start + i16::RAW_BYTE_LEN;
1070        start..end
1071    }
1072
1073    pub fn x_device_offset_byte_range(&self) -> Range<usize> {
1074        let start = self.y_coordinate_byte_range().end;
1075        let end = start + Offset16::RAW_BYTE_LEN;
1076        start..end
1077    }
1078
1079    pub fn y_device_offset_byte_range(&self) -> Range<usize> {
1080        let start = self.x_device_offset_byte_range().end;
1081        let end = start + Offset16::RAW_BYTE_LEN;
1082        start..end
1083    }
1084}
1085
1086#[cfg(feature = "experimental_traverse")]
1087impl<'a> SomeTable<'a> for AnchorFormat3<'a> {
1088    fn type_name(&self) -> &str {
1089        "AnchorFormat3"
1090    }
1091    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1092        match idx {
1093            0usize => Some(Field::new("anchor_format", self.anchor_format())),
1094            1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
1095            2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
1096            3usize => Some(Field::new(
1097                "x_device_offset",
1098                FieldType::offset(self.x_device_offset(), self.x_device()),
1099            )),
1100            4usize => Some(Field::new(
1101                "y_device_offset",
1102                FieldType::offset(self.y_device_offset(), self.y_device()),
1103            )),
1104            _ => None,
1105        }
1106    }
1107}
1108
1109#[cfg(feature = "experimental_traverse")]
1110#[allow(clippy::needless_lifetimes)]
1111impl<'a> std::fmt::Debug for AnchorFormat3<'a> {
1112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1113        (self as &dyn SomeTable<'a>).fmt(f)
1114    }
1115}
1116
1117impl<'a> MinByteRange<'a> for MarkArray<'a> {
1118    fn min_byte_range(&self) -> Range<usize> {
1119        0..self.mark_records_byte_range().end
1120    }
1121    fn min_table_bytes(&self) -> &'a [u8] {
1122        let range = self.min_byte_range();
1123        self.data.as_bytes().get(range).unwrap_or_default()
1124    }
1125}
1126
1127impl ReadArgs for MarkArray<'_> {
1128    type Args = ();
1129}
1130
1131impl<'a> FontRead<'a> for MarkArray<'a> {
1132    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1133        #[allow(clippy::absurd_extreme_comparisons)]
1134        if data.len() < Self::MIN_SIZE {
1135            return Err(ReadError::OutOfBounds);
1136        }
1137        Ok(Self { data })
1138    }
1139}
1140
1141/// [Mark Array Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-array-table)
1142#[derive(Clone)]
1143pub struct MarkArray<'a> {
1144    data: FontData<'a>,
1145}
1146
1147#[allow(clippy::needless_lifetimes)]
1148impl<'a> MarkArray<'a> {
1149    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1150    basic_table_impls!(impl_the_methods);
1151
1152    /// Number of MarkRecords
1153    pub fn mark_count(&self) -> u16 {
1154        let range = self.mark_count_byte_range();
1155        self.data.read_at(range.start).ok().unwrap()
1156    }
1157
1158    /// Array of MarkRecords, ordered by corresponding glyphs in the
1159    /// associated mark Coverage table.
1160    pub fn mark_records(&self) -> &'a [MarkRecord] {
1161        let range = self.mark_records_byte_range();
1162        self.data.read_array(range).ok().unwrap_or_default()
1163    }
1164
1165    pub fn mark_count_byte_range(&self) -> Range<usize> {
1166        let start = 0;
1167        let end = start + u16::RAW_BYTE_LEN;
1168        start..end
1169    }
1170
1171    pub fn mark_records_byte_range(&self) -> Range<usize> {
1172        let mark_count = self.mark_count();
1173        let start = self.mark_count_byte_range().end;
1174        let end =
1175            start + (transforms::to_usize(mark_count)).saturating_mul(MarkRecord::RAW_BYTE_LEN);
1176        start..end
1177    }
1178}
1179
1180const _: () = assert!(FontData::default_data_long_enough(MarkArray::MIN_SIZE));
1181
1182impl Default for MarkArray<'_> {
1183    fn default() -> Self {
1184        Self {
1185            data: FontData::default_table_data(),
1186        }
1187    }
1188}
1189
1190#[cfg(feature = "experimental_traverse")]
1191impl<'a> SomeTable<'a> for MarkArray<'a> {
1192    fn type_name(&self) -> &str {
1193        "MarkArray"
1194    }
1195    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1196        match idx {
1197            0usize => Some(Field::new("mark_count", self.mark_count())),
1198            1usize => Some(Field::new(
1199                "mark_records",
1200                traversal::FieldType::array_of_records(
1201                    stringify!(MarkRecord),
1202                    self.mark_records(),
1203                    self.offset_data(),
1204                ),
1205            )),
1206            _ => None,
1207        }
1208    }
1209}
1210
1211#[cfg(feature = "experimental_traverse")]
1212#[allow(clippy::needless_lifetimes)]
1213impl<'a> std::fmt::Debug for MarkArray<'a> {
1214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1215        (self as &dyn SomeTable<'a>).fmt(f)
1216    }
1217}
1218
1219/// Part of [MarkArray]
1220#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1221#[repr(C)]
1222#[repr(packed)]
1223pub struct MarkRecord {
1224    /// Class defined for the associated mark.
1225    pub mark_class: BigEndian<u16>,
1226    /// Offset to Anchor table, from beginning of MarkArray table.
1227    pub mark_anchor_offset: BigEndian<Offset16>,
1228}
1229
1230impl MarkRecord {
1231    /// Class defined for the associated mark.
1232    pub fn mark_class(&self) -> u16 {
1233        self.mark_class.get()
1234    }
1235
1236    /// Offset to Anchor table, from beginning of MarkArray table.
1237    pub fn mark_anchor_offset(&self) -> Offset16 {
1238        self.mark_anchor_offset.get()
1239    }
1240
1241    /// Offset to Anchor table, from beginning of MarkArray table.
1242    ///
1243    /// The `data` argument should be retrieved from the parent table
1244    /// By calling its `offset_data` method.
1245    pub fn mark_anchor<'a>(&self, data: FontData<'a>) -> Result<AnchorTable<'a>, ReadError> {
1246        self.mark_anchor_offset().resolve(data)
1247    }
1248}
1249
1250impl FixedSize for MarkRecord {
1251    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
1252}
1253
1254#[cfg(feature = "experimental_traverse")]
1255impl<'a> SomeRecord<'a> for MarkRecord {
1256    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1257        RecordResolver {
1258            name: "MarkRecord",
1259            get_field: Box::new(move |idx, _data| match idx {
1260                0usize => Some(Field::new("mark_class", self.mark_class())),
1261                1usize => Some(Field::new(
1262                    "mark_anchor_offset",
1263                    FieldType::offset(self.mark_anchor_offset(), self.mark_anchor(_data)),
1264                )),
1265                _ => None,
1266            }),
1267            data,
1268        }
1269    }
1270}
1271
1272/// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable
1273#[derive(Clone)]
1274pub enum SinglePos<'a> {
1275    Format1(SinglePosFormat1<'a>),
1276    Format2(SinglePosFormat2<'a>),
1277}
1278
1279impl Default for SinglePos<'_> {
1280    fn default() -> Self {
1281        Self::Format1(Default::default())
1282    }
1283}
1284
1285impl<'a> SinglePos<'a> {
1286    ///Return the `FontData` used to resolve offsets for this table.
1287    pub fn offset_data(&self) -> FontData<'a> {
1288        match self {
1289            Self::Format1(item) => item.offset_data(),
1290            Self::Format2(item) => item.offset_data(),
1291        }
1292    }
1293
1294    /// Format identifier: format = 1
1295    pub fn pos_format(&self) -> u16 {
1296        match self {
1297            Self::Format1(item) => item.pos_format(),
1298            Self::Format2(item) => item.pos_format(),
1299        }
1300    }
1301
1302    /// Offset to Coverage table, from beginning of SinglePos subtable.
1303    pub fn coverage_offset(&self) -> Offset16 {
1304        match self {
1305            Self::Format1(item) => item.coverage_offset(),
1306            Self::Format2(item) => item.coverage_offset(),
1307        }
1308    }
1309
1310    /// Defines the types of data in the ValueRecord.
1311    pub fn value_format(&self) -> ValueFormat {
1312        match self {
1313            Self::Format1(item) => item.value_format(),
1314            Self::Format2(item) => item.value_format(),
1315        }
1316    }
1317}
1318
1319impl ReadArgs for SinglePos<'_> {
1320    type Args = ();
1321}
1322
1323impl<'a> FontRead<'a> for SinglePos<'a> {
1324    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1325        let format: u16 = data.read_at(0usize)?;
1326        match format {
1327            SinglePosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1328            SinglePosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1329            other => Err(ReadError::InvalidFormat(other.into())),
1330        }
1331    }
1332}
1333
1334impl<'a> MinByteRange<'a> for SinglePos<'a> {
1335    fn min_byte_range(&self) -> Range<usize> {
1336        match self {
1337            Self::Format1(item) => item.min_byte_range(),
1338            Self::Format2(item) => item.min_byte_range(),
1339        }
1340    }
1341    fn min_table_bytes(&self) -> &'a [u8] {
1342        match self {
1343            Self::Format1(item) => item.min_table_bytes(),
1344            Self::Format2(item) => item.min_table_bytes(),
1345        }
1346    }
1347}
1348
1349#[cfg(feature = "experimental_traverse")]
1350impl<'a> SinglePos<'a> {
1351    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1352        match self {
1353            Self::Format1(table) => table,
1354            Self::Format2(table) => table,
1355        }
1356    }
1357}
1358
1359#[cfg(feature = "experimental_traverse")]
1360impl std::fmt::Debug for SinglePos<'_> {
1361    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1362        self.dyn_inner().fmt(f)
1363    }
1364}
1365
1366#[cfg(feature = "experimental_traverse")]
1367impl<'a> SomeTable<'a> for SinglePos<'a> {
1368    fn type_name(&self) -> &str {
1369        self.dyn_inner().type_name()
1370    }
1371    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1372        self.dyn_inner().get_field(idx)
1373    }
1374}
1375
1376impl Format<u16> for SinglePosFormat1<'_> {
1377    const FORMAT: u16 = 1;
1378}
1379
1380impl<'a> MinByteRange<'a> for SinglePosFormat1<'a> {
1381    fn min_byte_range(&self) -> Range<usize> {
1382        0..self.value_record_byte_range().end
1383    }
1384    fn min_table_bytes(&self) -> &'a [u8] {
1385        let range = self.min_byte_range();
1386        self.data.as_bytes().get(range).unwrap_or_default()
1387    }
1388}
1389
1390impl ReadArgs for SinglePosFormat1<'_> {
1391    type Args = ();
1392}
1393
1394impl<'a> FontRead<'a> for SinglePosFormat1<'a> {
1395    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1396        #[allow(clippy::absurd_extreme_comparisons)]
1397        if data.len() < Self::MIN_SIZE {
1398            return Err(ReadError::OutOfBounds);
1399        }
1400        Ok(Self { data })
1401    }
1402}
1403
1404/// [Single Adjustment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#single-adjustment-positioning-format-1-single-positioning-value): Single Positioning Value
1405#[derive(Clone)]
1406pub struct SinglePosFormat1<'a> {
1407    data: FontData<'a>,
1408}
1409
1410#[allow(clippy::needless_lifetimes)]
1411impl<'a> SinglePosFormat1<'a> {
1412    pub const MIN_SIZE: usize =
1413        (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + ValueFormat::RAW_BYTE_LEN);
1414    basic_table_impls!(impl_the_methods);
1415
1416    /// Format identifier: format = 1
1417    pub fn pos_format(&self) -> u16 {
1418        let range = self.pos_format_byte_range();
1419        self.data.read_at(range.start).ok().unwrap()
1420    }
1421
1422    /// Offset to Coverage table, from beginning of SinglePos subtable.
1423    pub fn coverage_offset(&self) -> Offset16 {
1424        let range = self.coverage_offset_byte_range();
1425        self.data.read_at(range.start).ok().unwrap()
1426    }
1427
1428    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1429    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1430        let data = self.data;
1431        self.coverage_offset().resolve(data)
1432    }
1433
1434    /// Defines the types of data in the ValueRecord.
1435    pub fn value_format(&self) -> ValueFormat {
1436        let range = self.value_format_byte_range();
1437        self.data.read_at(range.start).ok().unwrap()
1438    }
1439
1440    /// Defines positioning value(s) — applied to all glyphs in the
1441    /// Coverage table.
1442    pub fn value_record(&self) -> ValueRecord {
1443        let range = self.value_record_byte_range();
1444        self.data
1445            .read_with_args(range, self.value_format())
1446            .unwrap_or_default()
1447    }
1448
1449    pub fn pos_format_byte_range(&self) -> Range<usize> {
1450        let start = 0;
1451        let end = start + u16::RAW_BYTE_LEN;
1452        start..end
1453    }
1454
1455    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1456        let start = self.pos_format_byte_range().end;
1457        let end = start + Offset16::RAW_BYTE_LEN;
1458        start..end
1459    }
1460
1461    pub fn value_format_byte_range(&self) -> Range<usize> {
1462        let start = self.coverage_offset_byte_range().end;
1463        let end = start + ValueFormat::RAW_BYTE_LEN;
1464        start..end
1465    }
1466
1467    pub fn value_record_byte_range(&self) -> Range<usize> {
1468        let start = self.value_format_byte_range().end;
1469        let end =
1470            start + <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0);
1471        start..end
1472    }
1473}
1474
1475const _: () = assert!(FontData::default_data_long_enough(
1476    SinglePosFormat1::MIN_SIZE
1477));
1478
1479impl Default for SinglePosFormat1<'_> {
1480    fn default() -> Self {
1481        Self {
1482            data: FontData::default_format_1_u16_table_data(),
1483        }
1484    }
1485}
1486
1487#[cfg(feature = "experimental_traverse")]
1488impl<'a> SomeTable<'a> for SinglePosFormat1<'a> {
1489    fn type_name(&self) -> &str {
1490        "SinglePosFormat1"
1491    }
1492    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1493        match idx {
1494            0usize => Some(Field::new("pos_format", self.pos_format())),
1495            1usize => Some(Field::new(
1496                "coverage_offset",
1497                FieldType::offset(self.coverage_offset(), self.coverage()),
1498            )),
1499            2usize => Some(Field::new("value_format", self.value_format())),
1500            3usize => Some(Field::new(
1501                "value_record",
1502                self.value_record().traversal_type(self.offset_data()),
1503            )),
1504            _ => None,
1505        }
1506    }
1507}
1508
1509#[cfg(feature = "experimental_traverse")]
1510#[allow(clippy::needless_lifetimes)]
1511impl<'a> std::fmt::Debug for SinglePosFormat1<'a> {
1512    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1513        (self as &dyn SomeTable<'a>).fmt(f)
1514    }
1515}
1516
1517impl Format<u16> for SinglePosFormat2<'_> {
1518    const FORMAT: u16 = 2;
1519}
1520
1521impl<'a> MinByteRange<'a> for SinglePosFormat2<'a> {
1522    fn min_byte_range(&self) -> Range<usize> {
1523        0..self.value_records_byte_range().end
1524    }
1525    fn min_table_bytes(&self) -> &'a [u8] {
1526        let range = self.min_byte_range();
1527        self.data.as_bytes().get(range).unwrap_or_default()
1528    }
1529}
1530
1531impl ReadArgs for SinglePosFormat2<'_> {
1532    type Args = ();
1533}
1534
1535impl<'a> FontRead<'a> for SinglePosFormat2<'a> {
1536    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1537        #[allow(clippy::absurd_extreme_comparisons)]
1538        if data.len() < Self::MIN_SIZE {
1539            return Err(ReadError::OutOfBounds);
1540        }
1541        Ok(Self { data })
1542    }
1543}
1544
1545/// [Single Adjustment Positioning Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#single-adjustment-positioning-format-2-array-of-positioning-values): Array of Positioning Values
1546#[derive(Clone)]
1547pub struct SinglePosFormat2<'a> {
1548    data: FontData<'a>,
1549}
1550
1551#[allow(clippy::needless_lifetimes)]
1552impl<'a> SinglePosFormat2<'a> {
1553    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1554        + Offset16::RAW_BYTE_LEN
1555        + ValueFormat::RAW_BYTE_LEN
1556        + u16::RAW_BYTE_LEN);
1557    basic_table_impls!(impl_the_methods);
1558
1559    /// Format identifier: format = 2
1560    pub fn pos_format(&self) -> u16 {
1561        let range = self.pos_format_byte_range();
1562        self.data.read_at(range.start).ok().unwrap()
1563    }
1564
1565    /// Offset to Coverage table, from beginning of SinglePos subtable.
1566    pub fn coverage_offset(&self) -> Offset16 {
1567        let range = self.coverage_offset_byte_range();
1568        self.data.read_at(range.start).ok().unwrap()
1569    }
1570
1571    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1572    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1573        let data = self.data;
1574        self.coverage_offset().resolve(data)
1575    }
1576
1577    /// Defines the types of data in the ValueRecords.
1578    pub fn value_format(&self) -> ValueFormat {
1579        let range = self.value_format_byte_range();
1580        self.data.read_at(range.start).ok().unwrap()
1581    }
1582
1583    /// Number of ValueRecords — must equal glyphCount in the
1584    /// Coverage table.
1585    pub fn value_count(&self) -> u16 {
1586        let range = self.value_count_byte_range();
1587        self.data.read_at(range.start).ok().unwrap()
1588    }
1589
1590    /// Array of ValueRecords — positioning values applied to glyphs.
1591    pub fn value_records(&self) -> ComputedArray<'a, ValueRecord> {
1592        let range = self.value_records_byte_range();
1593        self.data
1594            .read_with_args(range, self.value_format())
1595            .unwrap_or_default()
1596    }
1597
1598    pub fn pos_format_byte_range(&self) -> Range<usize> {
1599        let start = 0;
1600        let end = start + u16::RAW_BYTE_LEN;
1601        start..end
1602    }
1603
1604    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1605        let start = self.pos_format_byte_range().end;
1606        let end = start + Offset16::RAW_BYTE_LEN;
1607        start..end
1608    }
1609
1610    pub fn value_format_byte_range(&self) -> Range<usize> {
1611        let start = self.coverage_offset_byte_range().end;
1612        let end = start + ValueFormat::RAW_BYTE_LEN;
1613        start..end
1614    }
1615
1616    pub fn value_count_byte_range(&self) -> Range<usize> {
1617        let start = self.value_format_byte_range().end;
1618        let end = start + u16::RAW_BYTE_LEN;
1619        start..end
1620    }
1621
1622    pub fn value_records_byte_range(&self) -> Range<usize> {
1623        let value_count = self.value_count();
1624        let start = self.value_count_byte_range().end;
1625        let end = start
1626            + (transforms::to_usize(value_count)).saturating_mul(
1627                <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0),
1628            );
1629        start..end
1630    }
1631}
1632
1633#[cfg(feature = "experimental_traverse")]
1634impl<'a> SomeTable<'a> for SinglePosFormat2<'a> {
1635    fn type_name(&self) -> &str {
1636        "SinglePosFormat2"
1637    }
1638    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1639        match idx {
1640            0usize => Some(Field::new("pos_format", self.pos_format())),
1641            1usize => Some(Field::new(
1642                "coverage_offset",
1643                FieldType::offset(self.coverage_offset(), self.coverage()),
1644            )),
1645            2usize => Some(Field::new("value_format", self.value_format())),
1646            3usize => Some(Field::new("value_count", self.value_count())),
1647            4usize => Some(Field::new(
1648                "value_records",
1649                traversal::FieldType::computed_array(
1650                    "ValueRecord",
1651                    self.value_records(),
1652                    self.offset_data(),
1653                ),
1654            )),
1655            _ => None,
1656        }
1657    }
1658}
1659
1660#[cfg(feature = "experimental_traverse")]
1661#[allow(clippy::needless_lifetimes)]
1662impl<'a> std::fmt::Debug for SinglePosFormat2<'a> {
1663    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1664        (self as &dyn SomeTable<'a>).fmt(f)
1665    }
1666}
1667
1668/// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable
1669#[derive(Clone)]
1670pub enum PairPos<'a> {
1671    Format1(PairPosFormat1<'a>),
1672    Format2(PairPosFormat2<'a>),
1673}
1674
1675impl Default for PairPos<'_> {
1676    fn default() -> Self {
1677        Self::Format1(Default::default())
1678    }
1679}
1680
1681impl<'a> PairPos<'a> {
1682    ///Return the `FontData` used to resolve offsets for this table.
1683    pub fn offset_data(&self) -> FontData<'a> {
1684        match self {
1685            Self::Format1(item) => item.offset_data(),
1686            Self::Format2(item) => item.offset_data(),
1687        }
1688    }
1689
1690    /// Format identifier: format = 1
1691    pub fn pos_format(&self) -> u16 {
1692        match self {
1693            Self::Format1(item) => item.pos_format(),
1694            Self::Format2(item) => item.pos_format(),
1695        }
1696    }
1697
1698    /// Offset to Coverage table, from beginning of PairPos subtable.
1699    pub fn coverage_offset(&self) -> Offset16 {
1700        match self {
1701            Self::Format1(item) => item.coverage_offset(),
1702            Self::Format2(item) => item.coverage_offset(),
1703        }
1704    }
1705
1706    /// Defines the types of data in valueRecord1 — for the first
1707    /// glyph in the pair (may be zero).
1708    pub fn value_format1(&self) -> ValueFormat {
1709        match self {
1710            Self::Format1(item) => item.value_format1(),
1711            Self::Format2(item) => item.value_format1(),
1712        }
1713    }
1714
1715    /// Defines the types of data in valueRecord2 — for the second
1716    /// glyph in the pair (may be zero).
1717    pub fn value_format2(&self) -> ValueFormat {
1718        match self {
1719            Self::Format1(item) => item.value_format2(),
1720            Self::Format2(item) => item.value_format2(),
1721        }
1722    }
1723}
1724
1725impl ReadArgs for PairPos<'_> {
1726    type Args = ();
1727}
1728
1729impl<'a> FontRead<'a> for PairPos<'a> {
1730    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1731        let format: u16 = data.read_at(0usize)?;
1732        match format {
1733            PairPosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1734            PairPosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1735            other => Err(ReadError::InvalidFormat(other.into())),
1736        }
1737    }
1738}
1739
1740impl<'a> MinByteRange<'a> for PairPos<'a> {
1741    fn min_byte_range(&self) -> Range<usize> {
1742        match self {
1743            Self::Format1(item) => item.min_byte_range(),
1744            Self::Format2(item) => item.min_byte_range(),
1745        }
1746    }
1747    fn min_table_bytes(&self) -> &'a [u8] {
1748        match self {
1749            Self::Format1(item) => item.min_table_bytes(),
1750            Self::Format2(item) => item.min_table_bytes(),
1751        }
1752    }
1753}
1754
1755#[cfg(feature = "experimental_traverse")]
1756impl<'a> PairPos<'a> {
1757    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1758        match self {
1759            Self::Format1(table) => table,
1760            Self::Format2(table) => table,
1761        }
1762    }
1763}
1764
1765#[cfg(feature = "experimental_traverse")]
1766impl std::fmt::Debug for PairPos<'_> {
1767    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1768        self.dyn_inner().fmt(f)
1769    }
1770}
1771
1772#[cfg(feature = "experimental_traverse")]
1773impl<'a> SomeTable<'a> for PairPos<'a> {
1774    fn type_name(&self) -> &str {
1775        self.dyn_inner().type_name()
1776    }
1777    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1778        self.dyn_inner().get_field(idx)
1779    }
1780}
1781
1782impl Format<u16> for PairPosFormat1<'_> {
1783    const FORMAT: u16 = 1;
1784}
1785
1786impl<'a> MinByteRange<'a> for PairPosFormat1<'a> {
1787    fn min_byte_range(&self) -> Range<usize> {
1788        0..self.pair_set_offsets_byte_range().end
1789    }
1790    fn min_table_bytes(&self) -> &'a [u8] {
1791        let range = self.min_byte_range();
1792        self.data.as_bytes().get(range).unwrap_or_default()
1793    }
1794}
1795
1796impl ReadArgs for PairPosFormat1<'_> {
1797    type Args = ();
1798}
1799
1800impl<'a> FontRead<'a> for PairPosFormat1<'a> {
1801    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1802        #[allow(clippy::absurd_extreme_comparisons)]
1803        if data.len() < Self::MIN_SIZE {
1804            return Err(ReadError::OutOfBounds);
1805        }
1806        Ok(Self { data })
1807    }
1808}
1809
1810/// [Pair Adjustment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#pair-adjustment-positioning-format-1-adjustments-for-glyph-pairs): Adjustments for Glyph Pairs
1811#[derive(Clone)]
1812pub struct PairPosFormat1<'a> {
1813    data: FontData<'a>,
1814}
1815
1816#[allow(clippy::needless_lifetimes)]
1817impl<'a> PairPosFormat1<'a> {
1818    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1819        + Offset16::RAW_BYTE_LEN
1820        + ValueFormat::RAW_BYTE_LEN
1821        + ValueFormat::RAW_BYTE_LEN
1822        + u16::RAW_BYTE_LEN);
1823    basic_table_impls!(impl_the_methods);
1824
1825    /// Format identifier: format = 1
1826    pub fn pos_format(&self) -> u16 {
1827        let range = self.pos_format_byte_range();
1828        self.data.read_at(range.start).ok().unwrap()
1829    }
1830
1831    /// Offset to Coverage table, from beginning of PairPos subtable.
1832    pub fn coverage_offset(&self) -> Offset16 {
1833        let range = self.coverage_offset_byte_range();
1834        self.data.read_at(range.start).ok().unwrap()
1835    }
1836
1837    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1838    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1839        let data = self.data;
1840        self.coverage_offset().resolve(data)
1841    }
1842
1843    /// Defines the types of data in valueRecord1 — for the first
1844    /// glyph in the pair (may be zero).
1845    pub fn value_format1(&self) -> ValueFormat {
1846        let range = self.value_format1_byte_range();
1847        self.data.read_at(range.start).ok().unwrap()
1848    }
1849
1850    /// Defines the types of data in valueRecord2 — for the second
1851    /// glyph in the pair (may be zero).
1852    pub fn value_format2(&self) -> ValueFormat {
1853        let range = self.value_format2_byte_range();
1854        self.data.read_at(range.start).ok().unwrap()
1855    }
1856
1857    /// Number of PairSet tables
1858    pub fn pair_set_count(&self) -> u16 {
1859        let range = self.pair_set_count_byte_range();
1860        self.data.read_at(range.start).ok().unwrap()
1861    }
1862
1863    /// Array of offsets to PairSet tables. Offsets are from beginning
1864    /// of PairPos subtable, ordered by Coverage Index.
1865    pub fn pair_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
1866        let range = self.pair_set_offsets_byte_range();
1867        self.data.read_array(range).ok().unwrap_or_default()
1868    }
1869
1870    /// A dynamically resolving wrapper for [`pair_set_offsets`][Self::pair_set_offsets].
1871    pub fn pair_sets(&self) -> ArrayOfOffsets<'a, PairSet<'a>, Offset16> {
1872        let data = self.data;
1873        let offsets = self.pair_set_offsets();
1874        let args = (self.value_format1(), self.value_format2());
1875        ArrayOfOffsets::new(offsets, data, args)
1876    }
1877
1878    pub fn pos_format_byte_range(&self) -> Range<usize> {
1879        let start = 0;
1880        let end = start + u16::RAW_BYTE_LEN;
1881        start..end
1882    }
1883
1884    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1885        let start = self.pos_format_byte_range().end;
1886        let end = start + Offset16::RAW_BYTE_LEN;
1887        start..end
1888    }
1889
1890    pub fn value_format1_byte_range(&self) -> Range<usize> {
1891        let start = self.coverage_offset_byte_range().end;
1892        let end = start + ValueFormat::RAW_BYTE_LEN;
1893        start..end
1894    }
1895
1896    pub fn value_format2_byte_range(&self) -> Range<usize> {
1897        let start = self.value_format1_byte_range().end;
1898        let end = start + ValueFormat::RAW_BYTE_LEN;
1899        start..end
1900    }
1901
1902    pub fn pair_set_count_byte_range(&self) -> Range<usize> {
1903        let start = self.value_format2_byte_range().end;
1904        let end = start + u16::RAW_BYTE_LEN;
1905        start..end
1906    }
1907
1908    pub fn pair_set_offsets_byte_range(&self) -> Range<usize> {
1909        let pair_set_count = self.pair_set_count();
1910        let start = self.pair_set_count_byte_range().end;
1911        let end =
1912            start + (transforms::to_usize(pair_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1913        start..end
1914    }
1915}
1916
1917const _: () = assert!(FontData::default_data_long_enough(PairPosFormat1::MIN_SIZE));
1918
1919impl Default for PairPosFormat1<'_> {
1920    fn default() -> Self {
1921        Self {
1922            data: FontData::default_format_1_u16_table_data(),
1923        }
1924    }
1925}
1926
1927#[cfg(feature = "experimental_traverse")]
1928impl<'a> SomeTable<'a> for PairPosFormat1<'a> {
1929    fn type_name(&self) -> &str {
1930        "PairPosFormat1"
1931    }
1932    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1933        match idx {
1934            0usize => Some(Field::new("pos_format", self.pos_format())),
1935            1usize => Some(Field::new(
1936                "coverage_offset",
1937                FieldType::offset(self.coverage_offset(), self.coverage()),
1938            )),
1939            2usize => Some(Field::new("value_format1", self.value_format1())),
1940            3usize => Some(Field::new("value_format2", self.value_format2())),
1941            4usize => Some(Field::new("pair_set_count", self.pair_set_count())),
1942            5usize => Some(Field::new(
1943                "pair_set_offsets",
1944                FieldType::from(self.pair_sets()),
1945            )),
1946            _ => None,
1947        }
1948    }
1949}
1950
1951#[cfg(feature = "experimental_traverse")]
1952#[allow(clippy::needless_lifetimes)]
1953impl<'a> std::fmt::Debug for PairPosFormat1<'a> {
1954    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1955        (self as &dyn SomeTable<'a>).fmt(f)
1956    }
1957}
1958
1959impl<'a> MinByteRange<'a> for PairSet<'a> {
1960    fn min_byte_range(&self) -> Range<usize> {
1961        0..self.pair_value_records_byte_range().end
1962    }
1963    fn min_table_bytes(&self) -> &'a [u8] {
1964        let range = self.min_byte_range();
1965        self.data.as_bytes().get(range).unwrap_or_default()
1966    }
1967}
1968
1969impl ReadArgs for PairSet<'_> {
1970    type Args = (ValueFormat, ValueFormat);
1971}
1972
1973impl<'a> FontRead<'a> for PairSet<'a> {
1974    fn read_with_args(
1975        data: FontData<'a>,
1976        args: (ValueFormat, ValueFormat),
1977    ) -> Result<Self, ReadError> {
1978        let (value_format1, value_format2) = args;
1979
1980        #[allow(clippy::absurd_extreme_comparisons)]
1981        if data.len() < Self::MIN_SIZE {
1982            return Err(ReadError::OutOfBounds);
1983        }
1984        Ok(Self {
1985            data,
1986            value_format1,
1987            value_format2,
1988        })
1989    }
1990}
1991
1992impl<'a> PairSet<'a> {
1993    /// A constructor that requires additional arguments.
1994    ///
1995    /// This type requires some external state in order to be
1996    /// parsed.
1997    pub fn read(
1998        data: FontData<'a>,
1999        value_format1: ValueFormat,
2000        value_format2: ValueFormat,
2001    ) -> Result<Self, ReadError> {
2002        let args = (value_format1, value_format2);
2003        Self::read_with_args(data, args)
2004    }
2005}
2006
2007/// Part of [PairPosFormat1]
2008#[derive(Clone)]
2009pub struct PairSet<'a> {
2010    data: FontData<'a>,
2011    value_format1: ValueFormat,
2012    value_format2: ValueFormat,
2013}
2014
2015#[allow(clippy::needless_lifetimes)]
2016impl<'a> PairSet<'a> {
2017    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2018    basic_table_impls!(impl_the_methods);
2019
2020    /// Number of PairValueRecords
2021    pub fn pair_value_count(&self) -> u16 {
2022        let range = self.pair_value_count_byte_range();
2023        self.data.read_at(range.start).ok().unwrap()
2024    }
2025
2026    /// Array of PairValueRecords, ordered by glyph ID of the second
2027    /// glyph.
2028    pub fn pair_value_records(&self) -> ComputedArray<'a, PairValueRecord> {
2029        let range = self.pair_value_records_byte_range();
2030        self.data
2031            .read_with_args(range, (self.value_format1(), self.value_format2()))
2032            .unwrap_or_default()
2033    }
2034
2035    pub(crate) fn value_format1(&self) -> ValueFormat {
2036        self.value_format1
2037    }
2038
2039    pub(crate) fn value_format2(&self) -> ValueFormat {
2040        self.value_format2
2041    }
2042
2043    pub fn pair_value_count_byte_range(&self) -> Range<usize> {
2044        let start = 0;
2045        let end = start + u16::RAW_BYTE_LEN;
2046        start..end
2047    }
2048
2049    pub fn pair_value_records_byte_range(&self) -> Range<usize> {
2050        let pair_value_count = self.pair_value_count();
2051        let start = self.pair_value_count_byte_range().end;
2052        let end = start
2053            + (transforms::to_usize(pair_value_count)).saturating_mul(
2054                <PairValueRecord as ComputeSize>::compute_size((
2055                    self.value_format1(),
2056                    self.value_format2(),
2057                ))
2058                .unwrap_or(0),
2059            );
2060        start..end
2061    }
2062}
2063
2064const _: () = assert!(FontData::default_data_long_enough(PairSet::MIN_SIZE));
2065
2066impl Default for PairSet<'_> {
2067    fn default() -> Self {
2068        Self {
2069            data: FontData::default_table_data(),
2070            value_format1: Default::default(),
2071            value_format2: Default::default(),
2072        }
2073    }
2074}
2075
2076#[cfg(feature = "experimental_traverse")]
2077impl<'a> SomeTable<'a> for PairSet<'a> {
2078    fn type_name(&self) -> &str {
2079        "PairSet"
2080    }
2081    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2082        match idx {
2083            0usize => Some(Field::new("pair_value_count", self.pair_value_count())),
2084            1usize => Some(Field::new(
2085                "pair_value_records",
2086                traversal::FieldType::computed_array(
2087                    "PairValueRecord",
2088                    self.pair_value_records(),
2089                    self.offset_data(),
2090                ),
2091            )),
2092            _ => None,
2093        }
2094    }
2095}
2096
2097#[cfg(feature = "experimental_traverse")]
2098#[allow(clippy::needless_lifetimes)]
2099impl<'a> std::fmt::Debug for PairSet<'a> {
2100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2101        (self as &dyn SomeTable<'a>).fmt(f)
2102    }
2103}
2104
2105/// Part of [PairSet]
2106#[derive(Clone, Debug)]
2107pub struct PairValueRecord {
2108    /// Glyph ID of second glyph in the pair (first glyph is listed in
2109    /// the Coverage table).
2110    pub second_glyph: BigEndian<GlyphId16>,
2111    /// Positioning data for the first glyph in the pair.
2112    pub value_record1: ValueRecord,
2113    /// Positioning data for the second glyph in the pair.
2114    pub value_record2: ValueRecord,
2115}
2116
2117impl PairValueRecord {
2118    /// Glyph ID of second glyph in the pair (first glyph is listed in
2119    /// the Coverage table).
2120    pub fn second_glyph(&self) -> GlyphId16 {
2121        self.second_glyph.get()
2122    }
2123
2124    /// Positioning data for the first glyph in the pair.
2125    pub fn value_record1(&self) -> &ValueRecord {
2126        &self.value_record1
2127    }
2128
2129    /// Positioning data for the second glyph in the pair.
2130    pub fn value_record2(&self) -> &ValueRecord {
2131        &self.value_record2
2132    }
2133}
2134
2135impl ReadArgs for PairValueRecord {
2136    type Args = (ValueFormat, ValueFormat);
2137}
2138
2139impl ComputeSize for PairValueRecord {
2140    #[allow(clippy::needless_question_mark)]
2141    fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2142        let (value_format1, value_format2) = args;
2143        let mut result = 0usize;
2144        result = result
2145            .checked_add(GlyphId16::RAW_BYTE_LEN)
2146            .ok_or(ReadError::OutOfBounds)?;
2147        result = result
2148            .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
2149            .ok_or(ReadError::OutOfBounds)?;
2150        result = result
2151            .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
2152            .ok_or(ReadError::OutOfBounds)?;
2153        Ok(result)
2154    }
2155}
2156
2157impl<'a> FontRead<'a> for PairValueRecord {
2158    fn read_with_args(
2159        data: FontData<'a>,
2160        args: (ValueFormat, ValueFormat),
2161    ) -> Result<Self, ReadError> {
2162        let mut cursor = data.cursor();
2163        let (value_format1, value_format2) = args;
2164        Ok(Self {
2165            second_glyph: cursor.read_be()?,
2166            value_record1: cursor.read_with_args(value_format1)?,
2167            value_record2: cursor.read_with_args(value_format2)?,
2168        })
2169    }
2170}
2171
2172#[allow(clippy::needless_lifetimes)]
2173impl<'a> PairValueRecord {
2174    /// A constructor that requires additional arguments.
2175    ///
2176    /// This type requires some external state in order to be
2177    /// parsed.
2178    pub fn read(
2179        data: FontData<'a>,
2180        value_format1: ValueFormat,
2181        value_format2: ValueFormat,
2182    ) -> Result<Self, ReadError> {
2183        let args = (value_format1, value_format2);
2184        Self::read_with_args(data, args)
2185    }
2186}
2187
2188#[cfg(feature = "experimental_traverse")]
2189impl<'a> SomeRecord<'a> for PairValueRecord {
2190    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2191        RecordResolver {
2192            name: "PairValueRecord",
2193            get_field: Box::new(move |idx, _data| match idx {
2194                0usize => Some(Field::new("second_glyph", self.second_glyph())),
2195                1usize => Some(Field::new(
2196                    "value_record1",
2197                    self.value_record1().traversal_type(_data),
2198                )),
2199                2usize => Some(Field::new(
2200                    "value_record2",
2201                    self.value_record2().traversal_type(_data),
2202                )),
2203                _ => None,
2204            }),
2205            data,
2206        }
2207    }
2208}
2209
2210impl Format<u16> for PairPosFormat2<'_> {
2211    const FORMAT: u16 = 2;
2212}
2213
2214impl<'a> MinByteRange<'a> for PairPosFormat2<'a> {
2215    fn min_byte_range(&self) -> Range<usize> {
2216        0..self.class1_records_byte_range().end
2217    }
2218    fn min_table_bytes(&self) -> &'a [u8] {
2219        let range = self.min_byte_range();
2220        self.data.as_bytes().get(range).unwrap_or_default()
2221    }
2222}
2223
2224impl ReadArgs for PairPosFormat2<'_> {
2225    type Args = ();
2226}
2227
2228impl<'a> FontRead<'a> for PairPosFormat2<'a> {
2229    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2230        #[allow(clippy::absurd_extreme_comparisons)]
2231        if data.len() < Self::MIN_SIZE {
2232            return Err(ReadError::OutOfBounds);
2233        }
2234        Ok(Self { data })
2235    }
2236}
2237
2238/// [Pair Adjustment Positioning Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#pair-adjustment-positioning-format-2-class-pair-adjustment): Class Pair Adjustment
2239#[derive(Clone)]
2240pub struct PairPosFormat2<'a> {
2241    data: FontData<'a>,
2242}
2243
2244#[allow(clippy::needless_lifetimes)]
2245impl<'a> PairPosFormat2<'a> {
2246    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2247        + Offset16::RAW_BYTE_LEN
2248        + ValueFormat::RAW_BYTE_LEN
2249        + ValueFormat::RAW_BYTE_LEN
2250        + Offset16::RAW_BYTE_LEN
2251        + Offset16::RAW_BYTE_LEN
2252        + u16::RAW_BYTE_LEN
2253        + u16::RAW_BYTE_LEN);
2254    basic_table_impls!(impl_the_methods);
2255
2256    /// Format identifier: format = 2
2257    pub fn pos_format(&self) -> u16 {
2258        let range = self.pos_format_byte_range();
2259        self.data.read_at(range.start).ok().unwrap()
2260    }
2261
2262    /// Offset to Coverage table, from beginning of PairPos subtable.
2263    pub fn coverage_offset(&self) -> Offset16 {
2264        let range = self.coverage_offset_byte_range();
2265        self.data.read_at(range.start).ok().unwrap()
2266    }
2267
2268    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2269    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2270        let data = self.data;
2271        self.coverage_offset().resolve(data)
2272    }
2273
2274    /// ValueRecord definition — for the first glyph of the pair (may
2275    /// be zero).
2276    pub fn value_format1(&self) -> ValueFormat {
2277        let range = self.value_format1_byte_range();
2278        self.data.read_at(range.start).ok().unwrap()
2279    }
2280
2281    /// ValueRecord definition — for the second glyph of the pair
2282    /// (may be zero).
2283    pub fn value_format2(&self) -> ValueFormat {
2284        let range = self.value_format2_byte_range();
2285        self.data.read_at(range.start).ok().unwrap()
2286    }
2287
2288    /// Offset to ClassDef table, from beginning of PairPos subtable
2289    /// — for the first glyph of the pair.
2290    pub fn class_def1_offset(&self) -> Offset16 {
2291        let range = self.class_def1_offset_byte_range();
2292        self.data.read_at(range.start).ok().unwrap()
2293    }
2294
2295    /// Attempt to resolve [`class_def1_offset`][Self::class_def1_offset].
2296    pub fn class_def1(&self) -> Result<ClassDef<'a>, ReadError> {
2297        let data = self.data;
2298        self.class_def1_offset().resolve(data)
2299    }
2300
2301    /// Offset to ClassDef table, from beginning of PairPos subtable
2302    /// — for the second glyph of the pair.
2303    pub fn class_def2_offset(&self) -> Offset16 {
2304        let range = self.class_def2_offset_byte_range();
2305        self.data.read_at(range.start).ok().unwrap()
2306    }
2307
2308    /// Attempt to resolve [`class_def2_offset`][Self::class_def2_offset].
2309    pub fn class_def2(&self) -> Result<ClassDef<'a>, ReadError> {
2310        let data = self.data;
2311        self.class_def2_offset().resolve(data)
2312    }
2313
2314    /// Number of classes in classDef1 table — includes Class 0.
2315    pub fn class1_count(&self) -> u16 {
2316        let range = self.class1_count_byte_range();
2317        self.data.read_at(range.start).ok().unwrap()
2318    }
2319
2320    /// Number of classes in classDef2 table — includes Class 0.
2321    pub fn class2_count(&self) -> u16 {
2322        let range = self.class2_count_byte_range();
2323        self.data.read_at(range.start).ok().unwrap()
2324    }
2325
2326    /// Array of Class1 records, ordered by classes in classDef1.
2327    pub fn class1_records(&self) -> ComputedArray<'a, Class1Record<'a>> {
2328        let range = self.class1_records_byte_range();
2329        self.data
2330            .read_with_args(
2331                range,
2332                (
2333                    self.class2_count(),
2334                    self.value_format1(),
2335                    self.value_format2(),
2336                ),
2337            )
2338            .unwrap_or_default()
2339    }
2340
2341    pub fn pos_format_byte_range(&self) -> Range<usize> {
2342        let start = 0;
2343        let end = start + u16::RAW_BYTE_LEN;
2344        start..end
2345    }
2346
2347    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2348        let start = self.pos_format_byte_range().end;
2349        let end = start + Offset16::RAW_BYTE_LEN;
2350        start..end
2351    }
2352
2353    pub fn value_format1_byte_range(&self) -> Range<usize> {
2354        let start = self.coverage_offset_byte_range().end;
2355        let end = start + ValueFormat::RAW_BYTE_LEN;
2356        start..end
2357    }
2358
2359    pub fn value_format2_byte_range(&self) -> Range<usize> {
2360        let start = self.value_format1_byte_range().end;
2361        let end = start + ValueFormat::RAW_BYTE_LEN;
2362        start..end
2363    }
2364
2365    pub fn class_def1_offset_byte_range(&self) -> Range<usize> {
2366        let start = self.value_format2_byte_range().end;
2367        let end = start + Offset16::RAW_BYTE_LEN;
2368        start..end
2369    }
2370
2371    pub fn class_def2_offset_byte_range(&self) -> Range<usize> {
2372        let start = self.class_def1_offset_byte_range().end;
2373        let end = start + Offset16::RAW_BYTE_LEN;
2374        start..end
2375    }
2376
2377    pub fn class1_count_byte_range(&self) -> Range<usize> {
2378        let start = self.class_def2_offset_byte_range().end;
2379        let end = start + u16::RAW_BYTE_LEN;
2380        start..end
2381    }
2382
2383    pub fn class2_count_byte_range(&self) -> Range<usize> {
2384        let start = self.class1_count_byte_range().end;
2385        let end = start + u16::RAW_BYTE_LEN;
2386        start..end
2387    }
2388
2389    pub fn class1_records_byte_range(&self) -> Range<usize> {
2390        let class1_count = self.class1_count();
2391        let start = self.class2_count_byte_range().end;
2392        let end = start
2393            + (transforms::to_usize(class1_count)).saturating_mul(
2394                <Class1Record as ComputeSize>::compute_size((
2395                    self.class2_count(),
2396                    self.value_format1(),
2397                    self.value_format2(),
2398                ))
2399                .unwrap_or(0),
2400            );
2401        start..end
2402    }
2403}
2404
2405#[cfg(feature = "experimental_traverse")]
2406impl<'a> SomeTable<'a> for PairPosFormat2<'a> {
2407    fn type_name(&self) -> &str {
2408        "PairPosFormat2"
2409    }
2410    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2411        match idx {
2412            0usize => Some(Field::new("pos_format", self.pos_format())),
2413            1usize => Some(Field::new(
2414                "coverage_offset",
2415                FieldType::offset(self.coverage_offset(), self.coverage()),
2416            )),
2417            2usize => Some(Field::new("value_format1", self.value_format1())),
2418            3usize => Some(Field::new("value_format2", self.value_format2())),
2419            4usize => Some(Field::new(
2420                "class_def1_offset",
2421                FieldType::offset(self.class_def1_offset(), self.class_def1()),
2422            )),
2423            5usize => Some(Field::new(
2424                "class_def2_offset",
2425                FieldType::offset(self.class_def2_offset(), self.class_def2()),
2426            )),
2427            6usize => Some(Field::new("class1_count", self.class1_count())),
2428            7usize => Some(Field::new("class2_count", self.class2_count())),
2429            8usize => Some(Field::new(
2430                "class1_records",
2431                traversal::FieldType::computed_array(
2432                    "Class1Record",
2433                    self.class1_records(),
2434                    self.offset_data(),
2435                ),
2436            )),
2437            _ => None,
2438        }
2439    }
2440}
2441
2442#[cfg(feature = "experimental_traverse")]
2443#[allow(clippy::needless_lifetimes)]
2444impl<'a> std::fmt::Debug for PairPosFormat2<'a> {
2445    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2446        (self as &dyn SomeTable<'a>).fmt(f)
2447    }
2448}
2449
2450/// Part of [PairPosFormat2]
2451#[derive(Clone, Debug)]
2452pub struct Class1Record<'a> {
2453    /// Array of Class2 records, ordered by classes in classDef2.
2454    pub class2_records: ComputedArray<'a, Class2Record>,
2455}
2456
2457impl<'a> Class1Record<'a> {
2458    /// Array of Class2 records, ordered by classes in classDef2.
2459    pub fn class2_records(&self) -> &ComputedArray<'a, Class2Record> {
2460        &self.class2_records
2461    }
2462}
2463
2464impl ReadArgs for Class1Record<'_> {
2465    type Args = (u16, ValueFormat, ValueFormat);
2466}
2467
2468impl ComputeSize for Class1Record<'_> {
2469    #[allow(clippy::needless_question_mark)]
2470    fn compute_size(args: (u16, ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2471        let (class2_count, value_format1, value_format2) = args;
2472        Ok((transforms::to_usize(class2_count)).saturating_mul(
2473            <Class2Record as ComputeSize>::compute_size((value_format1, value_format2))
2474                .unwrap_or(0),
2475        ))
2476    }
2477}
2478
2479impl<'a> FontRead<'a> for Class1Record<'a> {
2480    fn read_with_args(
2481        data: FontData<'a>,
2482        args: (u16, ValueFormat, ValueFormat),
2483    ) -> Result<Self, ReadError> {
2484        let mut cursor = data.cursor();
2485        let (class2_count, value_format1, value_format2) = args;
2486        Ok(Self {
2487            class2_records: cursor.read_computed_array(
2488                transforms::to_usize(class2_count),
2489                (value_format1, value_format2),
2490            )?,
2491        })
2492    }
2493}
2494
2495#[allow(clippy::needless_lifetimes)]
2496impl<'a> Class1Record<'a> {
2497    /// A constructor that requires additional arguments.
2498    ///
2499    /// This type requires some external state in order to be
2500    /// parsed.
2501    pub fn read(
2502        data: FontData<'a>,
2503        class2_count: u16,
2504        value_format1: ValueFormat,
2505        value_format2: ValueFormat,
2506    ) -> Result<Self, ReadError> {
2507        let args = (class2_count, value_format1, value_format2);
2508        Self::read_with_args(data, args)
2509    }
2510}
2511
2512#[cfg(feature = "experimental_traverse")]
2513impl<'a> SomeRecord<'a> for Class1Record<'a> {
2514    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2515        RecordResolver {
2516            name: "Class1Record",
2517            get_field: Box::new(move |idx, _data| match idx {
2518                0usize => Some(Field::new(
2519                    "class2_records",
2520                    traversal::FieldType::computed_array(
2521                        "Class2Record",
2522                        self.class2_records().clone(),
2523                        FontData::new(&[]),
2524                    ),
2525                )),
2526                _ => None,
2527            }),
2528            data,
2529        }
2530    }
2531}
2532
2533/// Part of [PairPosFormat2]
2534#[derive(Clone, Debug)]
2535pub struct Class2Record {
2536    /// Positioning for first glyph — empty if valueFormat1 = 0.
2537    pub value_record1: ValueRecord,
2538    /// Positioning for second glyph — empty if valueFormat2 = 0.
2539    pub value_record2: ValueRecord,
2540}
2541
2542impl Class2Record {
2543    /// Positioning for first glyph — empty if valueFormat1 = 0.
2544    pub fn value_record1(&self) -> &ValueRecord {
2545        &self.value_record1
2546    }
2547
2548    /// Positioning for second glyph — empty if valueFormat2 = 0.
2549    pub fn value_record2(&self) -> &ValueRecord {
2550        &self.value_record2
2551    }
2552}
2553
2554impl ReadArgs for Class2Record {
2555    type Args = (ValueFormat, ValueFormat);
2556}
2557
2558impl ComputeSize for Class2Record {
2559    #[allow(clippy::needless_question_mark)]
2560    fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2561        let (value_format1, value_format2) = args;
2562        let mut result = 0usize;
2563        result = result
2564            .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
2565            .ok_or(ReadError::OutOfBounds)?;
2566        result = result
2567            .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
2568            .ok_or(ReadError::OutOfBounds)?;
2569        Ok(result)
2570    }
2571}
2572
2573impl<'a> FontRead<'a> for Class2Record {
2574    fn read_with_args(
2575        data: FontData<'a>,
2576        args: (ValueFormat, ValueFormat),
2577    ) -> Result<Self, ReadError> {
2578        let mut cursor = data.cursor();
2579        let (value_format1, value_format2) = args;
2580        Ok(Self {
2581            value_record1: cursor.read_with_args(value_format1)?,
2582            value_record2: cursor.read_with_args(value_format2)?,
2583        })
2584    }
2585}
2586
2587#[allow(clippy::needless_lifetimes)]
2588impl<'a> Class2Record {
2589    /// A constructor that requires additional arguments.
2590    ///
2591    /// This type requires some external state in order to be
2592    /// parsed.
2593    pub fn read(
2594        data: FontData<'a>,
2595        value_format1: ValueFormat,
2596        value_format2: ValueFormat,
2597    ) -> Result<Self, ReadError> {
2598        let args = (value_format1, value_format2);
2599        Self::read_with_args(data, args)
2600    }
2601}
2602
2603#[cfg(feature = "experimental_traverse")]
2604impl<'a> SomeRecord<'a> for Class2Record {
2605    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2606        RecordResolver {
2607            name: "Class2Record",
2608            get_field: Box::new(move |idx, _data| match idx {
2609                0usize => Some(Field::new(
2610                    "value_record1",
2611                    self.value_record1().traversal_type(_data),
2612                )),
2613                1usize => Some(Field::new(
2614                    "value_record2",
2615                    self.value_record2().traversal_type(_data),
2616                )),
2617                _ => None,
2618            }),
2619            data,
2620        }
2621    }
2622}
2623
2624impl Format<u16> for CursivePosFormat1<'_> {
2625    const FORMAT: u16 = 1;
2626}
2627
2628impl<'a> MinByteRange<'a> for CursivePosFormat1<'a> {
2629    fn min_byte_range(&self) -> Range<usize> {
2630        0..self.entry_exit_record_byte_range().end
2631    }
2632    fn min_table_bytes(&self) -> &'a [u8] {
2633        let range = self.min_byte_range();
2634        self.data.as_bytes().get(range).unwrap_or_default()
2635    }
2636}
2637
2638impl ReadArgs for CursivePosFormat1<'_> {
2639    type Args = ();
2640}
2641
2642impl<'a> FontRead<'a> for CursivePosFormat1<'a> {
2643    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2644        #[allow(clippy::absurd_extreme_comparisons)]
2645        if data.len() < Self::MIN_SIZE {
2646            return Err(ReadError::OutOfBounds);
2647        }
2648        Ok(Self { data })
2649    }
2650}
2651
2652/// [Cursive Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#cursive-attachment-positioning-format1-cursive-attachment): Cursvie attachment
2653#[derive(Clone)]
2654pub struct CursivePosFormat1<'a> {
2655    data: FontData<'a>,
2656}
2657
2658#[allow(clippy::needless_lifetimes)]
2659impl<'a> CursivePosFormat1<'a> {
2660    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2661    basic_table_impls!(impl_the_methods);
2662
2663    /// Format identifier: format = 1
2664    pub fn pos_format(&self) -> u16 {
2665        let range = self.pos_format_byte_range();
2666        self.data.read_at(range.start).ok().unwrap()
2667    }
2668
2669    /// Offset to Coverage table, from beginning of CursivePos subtable.
2670    pub fn coverage_offset(&self) -> Offset16 {
2671        let range = self.coverage_offset_byte_range();
2672        self.data.read_at(range.start).ok().unwrap()
2673    }
2674
2675    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2676    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2677        let data = self.data;
2678        self.coverage_offset().resolve(data)
2679    }
2680
2681    /// Number of EntryExit records
2682    pub fn entry_exit_count(&self) -> u16 {
2683        let range = self.entry_exit_count_byte_range();
2684        self.data.read_at(range.start).ok().unwrap()
2685    }
2686
2687    /// Array of EntryExit records, in Coverage index order.
2688    pub fn entry_exit_record(&self) -> &'a [EntryExitRecord] {
2689        let range = self.entry_exit_record_byte_range();
2690        self.data.read_array(range).ok().unwrap_or_default()
2691    }
2692
2693    pub fn pos_format_byte_range(&self) -> Range<usize> {
2694        let start = 0;
2695        let end = start + u16::RAW_BYTE_LEN;
2696        start..end
2697    }
2698
2699    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2700        let start = self.pos_format_byte_range().end;
2701        let end = start + Offset16::RAW_BYTE_LEN;
2702        start..end
2703    }
2704
2705    pub fn entry_exit_count_byte_range(&self) -> Range<usize> {
2706        let start = self.coverage_offset_byte_range().end;
2707        let end = start + u16::RAW_BYTE_LEN;
2708        start..end
2709    }
2710
2711    pub fn entry_exit_record_byte_range(&self) -> Range<usize> {
2712        let entry_exit_count = self.entry_exit_count();
2713        let start = self.entry_exit_count_byte_range().end;
2714        let end = start
2715            + (transforms::to_usize(entry_exit_count))
2716                .saturating_mul(EntryExitRecord::RAW_BYTE_LEN);
2717        start..end
2718    }
2719}
2720
2721const _: () = assert!(FontData::default_data_long_enough(
2722    CursivePosFormat1::MIN_SIZE
2723));
2724
2725impl Default for CursivePosFormat1<'_> {
2726    fn default() -> Self {
2727        Self {
2728            data: FontData::default_format_1_u16_table_data(),
2729        }
2730    }
2731}
2732
2733#[cfg(feature = "experimental_traverse")]
2734impl<'a> SomeTable<'a> for CursivePosFormat1<'a> {
2735    fn type_name(&self) -> &str {
2736        "CursivePosFormat1"
2737    }
2738    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2739        match idx {
2740            0usize => Some(Field::new("pos_format", self.pos_format())),
2741            1usize => Some(Field::new(
2742                "coverage_offset",
2743                FieldType::offset(self.coverage_offset(), self.coverage()),
2744            )),
2745            2usize => Some(Field::new("entry_exit_count", self.entry_exit_count())),
2746            3usize => Some(Field::new(
2747                "entry_exit_record",
2748                traversal::FieldType::array_of_records(
2749                    stringify!(EntryExitRecord),
2750                    self.entry_exit_record(),
2751                    self.offset_data(),
2752                ),
2753            )),
2754            _ => None,
2755        }
2756    }
2757}
2758
2759#[cfg(feature = "experimental_traverse")]
2760#[allow(clippy::needless_lifetimes)]
2761impl<'a> std::fmt::Debug for CursivePosFormat1<'a> {
2762    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2763        (self as &dyn SomeTable<'a>).fmt(f)
2764    }
2765}
2766
2767/// Part of [CursivePosFormat1]
2768#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
2769#[repr(C)]
2770#[repr(packed)]
2771pub struct EntryExitRecord {
2772    /// Offset to entryAnchor table, from beginning of CursivePos
2773    /// subtable (may be NULL).
2774    pub entry_anchor_offset: BigEndian<Nullable<Offset16>>,
2775    /// Offset to exitAnchor table, from beginning of CursivePos
2776    /// subtable (may be NULL).
2777    pub exit_anchor_offset: BigEndian<Nullable<Offset16>>,
2778}
2779
2780impl EntryExitRecord {
2781    /// Offset to entryAnchor table, from beginning of CursivePos
2782    /// subtable (may be NULL).
2783    pub fn entry_anchor_offset(&self) -> Nullable<Offset16> {
2784        self.entry_anchor_offset.get()
2785    }
2786
2787    /// Offset to entryAnchor table, from beginning of CursivePos
2788    /// subtable (may be NULL).
2789    ///
2790    /// The `data` argument should be retrieved from the parent table
2791    /// By calling its `offset_data` method.
2792    pub fn entry_anchor<'a>(
2793        &self,
2794        data: FontData<'a>,
2795    ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2796        self.entry_anchor_offset().resolve(data)
2797    }
2798
2799    /// Offset to exitAnchor table, from beginning of CursivePos
2800    /// subtable (may be NULL).
2801    pub fn exit_anchor_offset(&self) -> Nullable<Offset16> {
2802        self.exit_anchor_offset.get()
2803    }
2804
2805    /// Offset to exitAnchor table, from beginning of CursivePos
2806    /// subtable (may be NULL).
2807    ///
2808    /// The `data` argument should be retrieved from the parent table
2809    /// By calling its `offset_data` method.
2810    pub fn exit_anchor<'a>(
2811        &self,
2812        data: FontData<'a>,
2813    ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2814        self.exit_anchor_offset().resolve(data)
2815    }
2816}
2817
2818impl FixedSize for EntryExitRecord {
2819    const RAW_BYTE_LEN: usize = Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
2820}
2821
2822#[cfg(feature = "experimental_traverse")]
2823impl<'a> SomeRecord<'a> for EntryExitRecord {
2824    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2825        RecordResolver {
2826            name: "EntryExitRecord",
2827            get_field: Box::new(move |idx, _data| match idx {
2828                0usize => Some(Field::new(
2829                    "entry_anchor_offset",
2830                    FieldType::offset(self.entry_anchor_offset(), self.entry_anchor(_data)),
2831                )),
2832                1usize => Some(Field::new(
2833                    "exit_anchor_offset",
2834                    FieldType::offset(self.exit_anchor_offset(), self.exit_anchor(_data)),
2835                )),
2836                _ => None,
2837            }),
2838            data,
2839        }
2840    }
2841}
2842
2843impl Format<u16> for MarkBasePosFormat1<'_> {
2844    const FORMAT: u16 = 1;
2845}
2846
2847impl<'a> MinByteRange<'a> for MarkBasePosFormat1<'a> {
2848    fn min_byte_range(&self) -> Range<usize> {
2849        0..self.base_array_offset_byte_range().end
2850    }
2851    fn min_table_bytes(&self) -> &'a [u8] {
2852        let range = self.min_byte_range();
2853        self.data.as_bytes().get(range).unwrap_or_default()
2854    }
2855}
2856
2857impl ReadArgs for MarkBasePosFormat1<'_> {
2858    type Args = ();
2859}
2860
2861impl<'a> FontRead<'a> for MarkBasePosFormat1<'a> {
2862    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2863        #[allow(clippy::absurd_extreme_comparisons)]
2864        if data.len() < Self::MIN_SIZE {
2865            return Err(ReadError::OutOfBounds);
2866        }
2867        Ok(Self { data })
2868    }
2869}
2870
2871/// [Mark-to-Base Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-base-attachment-positioning-format-1-mark-to-base-attachment-point): Mark-to-base Attachment Point
2872#[derive(Clone)]
2873pub struct MarkBasePosFormat1<'a> {
2874    data: FontData<'a>,
2875}
2876
2877#[allow(clippy::needless_lifetimes)]
2878impl<'a> MarkBasePosFormat1<'a> {
2879    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2880        + Offset16::RAW_BYTE_LEN
2881        + Offset16::RAW_BYTE_LEN
2882        + u16::RAW_BYTE_LEN
2883        + Offset16::RAW_BYTE_LEN
2884        + Offset16::RAW_BYTE_LEN);
2885    basic_table_impls!(impl_the_methods);
2886
2887    /// Format identifier: format = 1
2888    pub fn pos_format(&self) -> u16 {
2889        let range = self.pos_format_byte_range();
2890        self.data.read_at(range.start).ok().unwrap()
2891    }
2892
2893    /// Offset to markCoverage table, from beginning of MarkBasePos
2894    /// subtable.
2895    pub fn mark_coverage_offset(&self) -> Offset16 {
2896        let range = self.mark_coverage_offset_byte_range();
2897        self.data.read_at(range.start).ok().unwrap()
2898    }
2899
2900    /// Attempt to resolve [`mark_coverage_offset`][Self::mark_coverage_offset].
2901    pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2902        let data = self.data;
2903        self.mark_coverage_offset().resolve(data)
2904    }
2905
2906    /// Offset to baseCoverage table, from beginning of MarkBasePos
2907    /// subtable.
2908    pub fn base_coverage_offset(&self) -> Offset16 {
2909        let range = self.base_coverage_offset_byte_range();
2910        self.data.read_at(range.start).ok().unwrap()
2911    }
2912
2913    /// Attempt to resolve [`base_coverage_offset`][Self::base_coverage_offset].
2914    pub fn base_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2915        let data = self.data;
2916        self.base_coverage_offset().resolve(data)
2917    }
2918
2919    /// Number of classes defined for marks
2920    pub fn mark_class_count(&self) -> u16 {
2921        let range = self.mark_class_count_byte_range();
2922        self.data.read_at(range.start).ok().unwrap()
2923    }
2924
2925    /// Offset to MarkArray table, from beginning of MarkBasePos
2926    /// subtable.
2927    pub fn mark_array_offset(&self) -> Offset16 {
2928        let range = self.mark_array_offset_byte_range();
2929        self.data.read_at(range.start).ok().unwrap()
2930    }
2931
2932    /// Attempt to resolve [`mark_array_offset`][Self::mark_array_offset].
2933    pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
2934        let data = self.data;
2935        self.mark_array_offset().resolve(data)
2936    }
2937
2938    /// Offset to BaseArray table, from beginning of MarkBasePos
2939    /// subtable.
2940    pub fn base_array_offset(&self) -> Offset16 {
2941        let range = self.base_array_offset_byte_range();
2942        self.data.read_at(range.start).ok().unwrap()
2943    }
2944
2945    /// Attempt to resolve [`base_array_offset`][Self::base_array_offset].
2946    pub fn base_array(&self) -> Result<BaseArray<'a>, ReadError> {
2947        let data = self.data;
2948        let args = self.mark_class_count();
2949        self.base_array_offset().resolve_with_args(data, args)
2950    }
2951
2952    pub fn pos_format_byte_range(&self) -> Range<usize> {
2953        let start = 0;
2954        let end = start + u16::RAW_BYTE_LEN;
2955        start..end
2956    }
2957
2958    pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
2959        let start = self.pos_format_byte_range().end;
2960        let end = start + Offset16::RAW_BYTE_LEN;
2961        start..end
2962    }
2963
2964    pub fn base_coverage_offset_byte_range(&self) -> Range<usize> {
2965        let start = self.mark_coverage_offset_byte_range().end;
2966        let end = start + Offset16::RAW_BYTE_LEN;
2967        start..end
2968    }
2969
2970    pub fn mark_class_count_byte_range(&self) -> Range<usize> {
2971        let start = self.base_coverage_offset_byte_range().end;
2972        let end = start + u16::RAW_BYTE_LEN;
2973        start..end
2974    }
2975
2976    pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
2977        let start = self.mark_class_count_byte_range().end;
2978        let end = start + Offset16::RAW_BYTE_LEN;
2979        start..end
2980    }
2981
2982    pub fn base_array_offset_byte_range(&self) -> Range<usize> {
2983        let start = self.mark_array_offset_byte_range().end;
2984        let end = start + Offset16::RAW_BYTE_LEN;
2985        start..end
2986    }
2987}
2988
2989const _: () = assert!(FontData::default_data_long_enough(
2990    MarkBasePosFormat1::MIN_SIZE
2991));
2992
2993impl Default for MarkBasePosFormat1<'_> {
2994    fn default() -> Self {
2995        Self {
2996            data: FontData::default_format_1_u16_table_data(),
2997        }
2998    }
2999}
3000
3001#[cfg(feature = "experimental_traverse")]
3002impl<'a> SomeTable<'a> for MarkBasePosFormat1<'a> {
3003    fn type_name(&self) -> &str {
3004        "MarkBasePosFormat1"
3005    }
3006    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3007        match idx {
3008            0usize => Some(Field::new("pos_format", self.pos_format())),
3009            1usize => Some(Field::new(
3010                "mark_coverage_offset",
3011                FieldType::offset(self.mark_coverage_offset(), self.mark_coverage()),
3012            )),
3013            2usize => Some(Field::new(
3014                "base_coverage_offset",
3015                FieldType::offset(self.base_coverage_offset(), self.base_coverage()),
3016            )),
3017            3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3018            4usize => Some(Field::new(
3019                "mark_array_offset",
3020                FieldType::offset(self.mark_array_offset(), self.mark_array()),
3021            )),
3022            5usize => Some(Field::new(
3023                "base_array_offset",
3024                FieldType::offset(self.base_array_offset(), self.base_array()),
3025            )),
3026            _ => None,
3027        }
3028    }
3029}
3030
3031#[cfg(feature = "experimental_traverse")]
3032#[allow(clippy::needless_lifetimes)]
3033impl<'a> std::fmt::Debug for MarkBasePosFormat1<'a> {
3034    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3035        (self as &dyn SomeTable<'a>).fmt(f)
3036    }
3037}
3038
3039impl<'a> MinByteRange<'a> for BaseArray<'a> {
3040    fn min_byte_range(&self) -> Range<usize> {
3041        0..self.base_records_byte_range().end
3042    }
3043    fn min_table_bytes(&self) -> &'a [u8] {
3044        let range = self.min_byte_range();
3045        self.data.as_bytes().get(range).unwrap_or_default()
3046    }
3047}
3048
3049impl ReadArgs for BaseArray<'_> {
3050    type Args = u16;
3051}
3052
3053impl<'a> FontRead<'a> for BaseArray<'a> {
3054    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3055        let mark_class_count = args;
3056
3057        #[allow(clippy::absurd_extreme_comparisons)]
3058        if data.len() < Self::MIN_SIZE {
3059            return Err(ReadError::OutOfBounds);
3060        }
3061        Ok(Self {
3062            data,
3063            mark_class_count,
3064        })
3065    }
3066}
3067
3068impl<'a> BaseArray<'a> {
3069    /// A constructor that requires additional arguments.
3070    ///
3071    /// This type requires some external state in order to be
3072    /// parsed.
3073    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3074        let args = mark_class_count;
3075        Self::read_with_args(data, args)
3076    }
3077}
3078
3079/// Part of [MarkBasePosFormat1]
3080#[derive(Clone)]
3081pub struct BaseArray<'a> {
3082    data: FontData<'a>,
3083    mark_class_count: u16,
3084}
3085
3086#[allow(clippy::needless_lifetimes)]
3087impl<'a> BaseArray<'a> {
3088    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3089    basic_table_impls!(impl_the_methods);
3090
3091    /// Number of BaseRecords
3092    pub fn base_count(&self) -> u16 {
3093        let range = self.base_count_byte_range();
3094        self.data.read_at(range.start).ok().unwrap()
3095    }
3096
3097    /// Array of BaseRecords, in order of baseCoverage Index.
3098    pub fn base_records(&self) -> ComputedArray<'a, BaseRecord<'a>> {
3099        let range = self.base_records_byte_range();
3100        self.data
3101            .read_with_args(range, self.mark_class_count())
3102            .unwrap_or_default()
3103    }
3104
3105    pub(crate) fn mark_class_count(&self) -> u16 {
3106        self.mark_class_count
3107    }
3108
3109    pub fn base_count_byte_range(&self) -> Range<usize> {
3110        let start = 0;
3111        let end = start + u16::RAW_BYTE_LEN;
3112        start..end
3113    }
3114
3115    pub fn base_records_byte_range(&self) -> Range<usize> {
3116        let base_count = self.base_count();
3117        let start = self.base_count_byte_range().end;
3118        let end = start
3119            + (transforms::to_usize(base_count)).saturating_mul(
3120                <BaseRecord as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
3121            );
3122        start..end
3123    }
3124}
3125
3126const _: () = assert!(FontData::default_data_long_enough(BaseArray::MIN_SIZE));
3127
3128impl Default for BaseArray<'_> {
3129    fn default() -> Self {
3130        Self {
3131            data: FontData::default_table_data(),
3132            mark_class_count: Default::default(),
3133        }
3134    }
3135}
3136
3137#[cfg(feature = "experimental_traverse")]
3138impl<'a> SomeTable<'a> for BaseArray<'a> {
3139    fn type_name(&self) -> &str {
3140        "BaseArray"
3141    }
3142    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3143        match idx {
3144            0usize => Some(Field::new("base_count", self.base_count())),
3145            1usize => Some(Field::new(
3146                "base_records",
3147                traversal::FieldType::computed_array(
3148                    "BaseRecord",
3149                    self.base_records(),
3150                    self.offset_data(),
3151                ),
3152            )),
3153            _ => None,
3154        }
3155    }
3156}
3157
3158#[cfg(feature = "experimental_traverse")]
3159#[allow(clippy::needless_lifetimes)]
3160impl<'a> std::fmt::Debug for BaseArray<'a> {
3161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3162        (self as &dyn SomeTable<'a>).fmt(f)
3163    }
3164}
3165
3166/// Part of [BaseArray]
3167#[derive(Clone, Debug)]
3168pub struct BaseRecord<'a> {
3169    /// Array of offsets (one per mark class) to Anchor tables. Offsets
3170    /// are from beginning of BaseArray table, ordered by class
3171    /// (offsets may be NULL).
3172    pub base_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3173}
3174
3175impl<'a> BaseRecord<'a> {
3176    /// Array of offsets (one per mark class) to Anchor tables. Offsets
3177    /// are from beginning of BaseArray table, ordered by class
3178    /// (offsets may be NULL).
3179    pub fn base_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3180        self.base_anchor_offsets
3181    }
3182
3183    /// Array of offsets (one per mark class) to Anchor tables. Offsets
3184    /// are from beginning of BaseArray table, ordered by class
3185    /// (offsets may be NULL).
3186    ///
3187    /// The `data` argument should be retrieved from the parent table
3188    /// By calling its `offset_data` method.
3189    pub fn base_anchors(
3190        &self,
3191        data: FontData<'a>,
3192    ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3193        let offsets = self.base_anchor_offsets();
3194        ArrayOfNullableOffsets::new(offsets, data, ())
3195    }
3196}
3197
3198impl ReadArgs for BaseRecord<'_> {
3199    type Args = u16;
3200}
3201
3202impl ComputeSize for BaseRecord<'_> {
3203    #[allow(clippy::needless_question_mark)]
3204    fn compute_size(args: u16) -> Result<usize, ReadError> {
3205        let mark_class_count = args;
3206        Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
3207    }
3208}
3209
3210impl<'a> FontRead<'a> for BaseRecord<'a> {
3211    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3212        let mut cursor = data.cursor();
3213        let mark_class_count = args;
3214        Ok(Self {
3215            base_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
3216        })
3217    }
3218}
3219
3220#[allow(clippy::needless_lifetimes)]
3221impl<'a> BaseRecord<'a> {
3222    /// A constructor that requires additional arguments.
3223    ///
3224    /// This type requires some external state in order to be
3225    /// parsed.
3226    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3227        let args = mark_class_count;
3228        Self::read_with_args(data, args)
3229    }
3230}
3231
3232#[cfg(feature = "experimental_traverse")]
3233impl<'a> SomeRecord<'a> for BaseRecord<'a> {
3234    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
3235        RecordResolver {
3236            name: "BaseRecord",
3237            get_field: Box::new(move |idx, _data| match idx {
3238                0usize => Some(Field::new(
3239                    "base_anchor_offsets",
3240                    FieldType::from(self.base_anchors(_data)),
3241                )),
3242                _ => None,
3243            }),
3244            data,
3245        }
3246    }
3247}
3248
3249impl Format<u16> for MarkLigPosFormat1<'_> {
3250    const FORMAT: u16 = 1;
3251}
3252
3253impl<'a> MinByteRange<'a> for MarkLigPosFormat1<'a> {
3254    fn min_byte_range(&self) -> Range<usize> {
3255        0..self.ligature_array_offset_byte_range().end
3256    }
3257    fn min_table_bytes(&self) -> &'a [u8] {
3258        let range = self.min_byte_range();
3259        self.data.as_bytes().get(range).unwrap_or_default()
3260    }
3261}
3262
3263impl ReadArgs for MarkLigPosFormat1<'_> {
3264    type Args = ();
3265}
3266
3267impl<'a> FontRead<'a> for MarkLigPosFormat1<'a> {
3268    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3269        #[allow(clippy::absurd_extreme_comparisons)]
3270        if data.len() < Self::MIN_SIZE {
3271            return Err(ReadError::OutOfBounds);
3272        }
3273        Ok(Self { data })
3274    }
3275}
3276
3277/// [Mark-to-Ligature Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-ligature-attachment-positioning-format-1-mark-to-ligature-attachment): Mark-to-Ligature Attachment
3278#[derive(Clone)]
3279pub struct MarkLigPosFormat1<'a> {
3280    data: FontData<'a>,
3281}
3282
3283#[allow(clippy::needless_lifetimes)]
3284impl<'a> MarkLigPosFormat1<'a> {
3285    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3286        + Offset16::RAW_BYTE_LEN
3287        + Offset16::RAW_BYTE_LEN
3288        + u16::RAW_BYTE_LEN
3289        + Offset16::RAW_BYTE_LEN
3290        + Offset16::RAW_BYTE_LEN);
3291    basic_table_impls!(impl_the_methods);
3292
3293    /// Format identifier: format = 1
3294    pub fn pos_format(&self) -> u16 {
3295        let range = self.pos_format_byte_range();
3296        self.data.read_at(range.start).ok().unwrap()
3297    }
3298
3299    /// Offset to markCoverage table, from beginning of MarkLigPos
3300    /// subtable.
3301    pub fn mark_coverage_offset(&self) -> Offset16 {
3302        let range = self.mark_coverage_offset_byte_range();
3303        self.data.read_at(range.start).ok().unwrap()
3304    }
3305
3306    /// Attempt to resolve [`mark_coverage_offset`][Self::mark_coverage_offset].
3307    pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3308        let data = self.data;
3309        self.mark_coverage_offset().resolve(data)
3310    }
3311
3312    /// Offset to ligatureCoverage table, from beginning of MarkLigPos
3313    /// subtable.
3314    pub fn ligature_coverage_offset(&self) -> Offset16 {
3315        let range = self.ligature_coverage_offset_byte_range();
3316        self.data.read_at(range.start).ok().unwrap()
3317    }
3318
3319    /// Attempt to resolve [`ligature_coverage_offset`][Self::ligature_coverage_offset].
3320    pub fn ligature_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3321        let data = self.data;
3322        self.ligature_coverage_offset().resolve(data)
3323    }
3324
3325    /// Number of defined mark classes
3326    pub fn mark_class_count(&self) -> u16 {
3327        let range = self.mark_class_count_byte_range();
3328        self.data.read_at(range.start).ok().unwrap()
3329    }
3330
3331    /// Offset to MarkArray table, from beginning of MarkLigPos
3332    /// subtable.
3333    pub fn mark_array_offset(&self) -> Offset16 {
3334        let range = self.mark_array_offset_byte_range();
3335        self.data.read_at(range.start).ok().unwrap()
3336    }
3337
3338    /// Attempt to resolve [`mark_array_offset`][Self::mark_array_offset].
3339    pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
3340        let data = self.data;
3341        self.mark_array_offset().resolve(data)
3342    }
3343
3344    /// Offset to LigatureArray table, from beginning of MarkLigPos
3345    /// subtable.
3346    pub fn ligature_array_offset(&self) -> Offset16 {
3347        let range = self.ligature_array_offset_byte_range();
3348        self.data.read_at(range.start).ok().unwrap()
3349    }
3350
3351    /// Attempt to resolve [`ligature_array_offset`][Self::ligature_array_offset].
3352    pub fn ligature_array(&self) -> Result<LigatureArray<'a>, ReadError> {
3353        let data = self.data;
3354        let args = self.mark_class_count();
3355        self.ligature_array_offset().resolve_with_args(data, args)
3356    }
3357
3358    pub fn pos_format_byte_range(&self) -> Range<usize> {
3359        let start = 0;
3360        let end = start + u16::RAW_BYTE_LEN;
3361        start..end
3362    }
3363
3364    pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
3365        let start = self.pos_format_byte_range().end;
3366        let end = start + Offset16::RAW_BYTE_LEN;
3367        start..end
3368    }
3369
3370    pub fn ligature_coverage_offset_byte_range(&self) -> Range<usize> {
3371        let start = self.mark_coverage_offset_byte_range().end;
3372        let end = start + Offset16::RAW_BYTE_LEN;
3373        start..end
3374    }
3375
3376    pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3377        let start = self.ligature_coverage_offset_byte_range().end;
3378        let end = start + u16::RAW_BYTE_LEN;
3379        start..end
3380    }
3381
3382    pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
3383        let start = self.mark_class_count_byte_range().end;
3384        let end = start + Offset16::RAW_BYTE_LEN;
3385        start..end
3386    }
3387
3388    pub fn ligature_array_offset_byte_range(&self) -> Range<usize> {
3389        let start = self.mark_array_offset_byte_range().end;
3390        let end = start + Offset16::RAW_BYTE_LEN;
3391        start..end
3392    }
3393}
3394
3395const _: () = assert!(FontData::default_data_long_enough(
3396    MarkLigPosFormat1::MIN_SIZE
3397));
3398
3399impl Default for MarkLigPosFormat1<'_> {
3400    fn default() -> Self {
3401        Self {
3402            data: FontData::default_format_1_u16_table_data(),
3403        }
3404    }
3405}
3406
3407#[cfg(feature = "experimental_traverse")]
3408impl<'a> SomeTable<'a> for MarkLigPosFormat1<'a> {
3409    fn type_name(&self) -> &str {
3410        "MarkLigPosFormat1"
3411    }
3412    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3413        match idx {
3414            0usize => Some(Field::new("pos_format", self.pos_format())),
3415            1usize => Some(Field::new(
3416                "mark_coverage_offset",
3417                FieldType::offset(self.mark_coverage_offset(), self.mark_coverage()),
3418            )),
3419            2usize => Some(Field::new(
3420                "ligature_coverage_offset",
3421                FieldType::offset(self.ligature_coverage_offset(), self.ligature_coverage()),
3422            )),
3423            3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3424            4usize => Some(Field::new(
3425                "mark_array_offset",
3426                FieldType::offset(self.mark_array_offset(), self.mark_array()),
3427            )),
3428            5usize => Some(Field::new(
3429                "ligature_array_offset",
3430                FieldType::offset(self.ligature_array_offset(), self.ligature_array()),
3431            )),
3432            _ => None,
3433        }
3434    }
3435}
3436
3437#[cfg(feature = "experimental_traverse")]
3438#[allow(clippy::needless_lifetimes)]
3439impl<'a> std::fmt::Debug for MarkLigPosFormat1<'a> {
3440    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3441        (self as &dyn SomeTable<'a>).fmt(f)
3442    }
3443}
3444
3445impl<'a> MinByteRange<'a> for LigatureArray<'a> {
3446    fn min_byte_range(&self) -> Range<usize> {
3447        0..self.ligature_attach_offsets_byte_range().end
3448    }
3449    fn min_table_bytes(&self) -> &'a [u8] {
3450        let range = self.min_byte_range();
3451        self.data.as_bytes().get(range).unwrap_or_default()
3452    }
3453}
3454
3455impl ReadArgs for LigatureArray<'_> {
3456    type Args = u16;
3457}
3458
3459impl<'a> FontRead<'a> for LigatureArray<'a> {
3460    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3461        let mark_class_count = args;
3462
3463        #[allow(clippy::absurd_extreme_comparisons)]
3464        if data.len() < Self::MIN_SIZE {
3465            return Err(ReadError::OutOfBounds);
3466        }
3467        Ok(Self {
3468            data,
3469            mark_class_count,
3470        })
3471    }
3472}
3473
3474impl<'a> LigatureArray<'a> {
3475    /// A constructor that requires additional arguments.
3476    ///
3477    /// This type requires some external state in order to be
3478    /// parsed.
3479    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3480        let args = mark_class_count;
3481        Self::read_with_args(data, args)
3482    }
3483}
3484
3485/// Part of [MarkLigPosFormat1]
3486#[derive(Clone)]
3487pub struct LigatureArray<'a> {
3488    data: FontData<'a>,
3489    mark_class_count: u16,
3490}
3491
3492#[allow(clippy::needless_lifetimes)]
3493impl<'a> LigatureArray<'a> {
3494    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3495    basic_table_impls!(impl_the_methods);
3496
3497    /// Number of LigatureAttach table offsets
3498    pub fn ligature_count(&self) -> u16 {
3499        let range = self.ligature_count_byte_range();
3500        self.data.read_at(range.start).ok().unwrap()
3501    }
3502
3503    /// Array of offsets to LigatureAttach tables. Offsets are from
3504    /// beginning of LigatureArray table, ordered by ligatureCoverage
3505    /// index.
3506    pub fn ligature_attach_offsets(&self) -> &'a [BigEndian<Offset16>] {
3507        let range = self.ligature_attach_offsets_byte_range();
3508        self.data.read_array(range).ok().unwrap_or_default()
3509    }
3510
3511    /// A dynamically resolving wrapper for [`ligature_attach_offsets`][Self::ligature_attach_offsets].
3512    pub fn ligature_attaches(&self) -> ArrayOfOffsets<'a, LigatureAttach<'a>, Offset16> {
3513        let data = self.data;
3514        let offsets = self.ligature_attach_offsets();
3515        let args = self.mark_class_count();
3516        ArrayOfOffsets::new(offsets, data, args)
3517    }
3518
3519    pub(crate) fn mark_class_count(&self) -> u16 {
3520        self.mark_class_count
3521    }
3522
3523    pub fn ligature_count_byte_range(&self) -> Range<usize> {
3524        let start = 0;
3525        let end = start + u16::RAW_BYTE_LEN;
3526        start..end
3527    }
3528
3529    pub fn ligature_attach_offsets_byte_range(&self) -> Range<usize> {
3530        let ligature_count = self.ligature_count();
3531        let start = self.ligature_count_byte_range().end;
3532        let end =
3533            start + (transforms::to_usize(ligature_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
3534        start..end
3535    }
3536}
3537
3538const _: () = assert!(FontData::default_data_long_enough(LigatureArray::MIN_SIZE));
3539
3540impl Default for LigatureArray<'_> {
3541    fn default() -> Self {
3542        Self {
3543            data: FontData::default_table_data(),
3544            mark_class_count: Default::default(),
3545        }
3546    }
3547}
3548
3549#[cfg(feature = "experimental_traverse")]
3550impl<'a> SomeTable<'a> for LigatureArray<'a> {
3551    fn type_name(&self) -> &str {
3552        "LigatureArray"
3553    }
3554    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3555        match idx {
3556            0usize => Some(Field::new("ligature_count", self.ligature_count())),
3557            1usize => Some(Field::new(
3558                "ligature_attach_offsets",
3559                FieldType::from(self.ligature_attaches()),
3560            )),
3561            _ => None,
3562        }
3563    }
3564}
3565
3566#[cfg(feature = "experimental_traverse")]
3567#[allow(clippy::needless_lifetimes)]
3568impl<'a> std::fmt::Debug for LigatureArray<'a> {
3569    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3570        (self as &dyn SomeTable<'a>).fmt(f)
3571    }
3572}
3573
3574impl<'a> MinByteRange<'a> for LigatureAttach<'a> {
3575    fn min_byte_range(&self) -> Range<usize> {
3576        0..self.component_records_byte_range().end
3577    }
3578    fn min_table_bytes(&self) -> &'a [u8] {
3579        let range = self.min_byte_range();
3580        self.data.as_bytes().get(range).unwrap_or_default()
3581    }
3582}
3583
3584impl ReadArgs for LigatureAttach<'_> {
3585    type Args = u16;
3586}
3587
3588impl<'a> FontRead<'a> for LigatureAttach<'a> {
3589    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3590        let mark_class_count = args;
3591
3592        #[allow(clippy::absurd_extreme_comparisons)]
3593        if data.len() < Self::MIN_SIZE {
3594            return Err(ReadError::OutOfBounds);
3595        }
3596        Ok(Self {
3597            data,
3598            mark_class_count,
3599        })
3600    }
3601}
3602
3603impl<'a> LigatureAttach<'a> {
3604    /// A constructor that requires additional arguments.
3605    ///
3606    /// This type requires some external state in order to be
3607    /// parsed.
3608    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3609        let args = mark_class_count;
3610        Self::read_with_args(data, args)
3611    }
3612}
3613
3614/// Part of [MarkLigPosFormat1]
3615#[derive(Clone)]
3616pub struct LigatureAttach<'a> {
3617    data: FontData<'a>,
3618    mark_class_count: u16,
3619}
3620
3621#[allow(clippy::needless_lifetimes)]
3622impl<'a> LigatureAttach<'a> {
3623    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3624    basic_table_impls!(impl_the_methods);
3625
3626    /// Number of ComponentRecords in this ligature
3627    pub fn component_count(&self) -> u16 {
3628        let range = self.component_count_byte_range();
3629        self.data.read_at(range.start).ok().unwrap()
3630    }
3631
3632    /// Array of Component records, ordered in writing direction.
3633    pub fn component_records(&self) -> ComputedArray<'a, ComponentRecord<'a>> {
3634        let range = self.component_records_byte_range();
3635        self.data
3636            .read_with_args(range, self.mark_class_count())
3637            .unwrap_or_default()
3638    }
3639
3640    pub(crate) fn mark_class_count(&self) -> u16 {
3641        self.mark_class_count
3642    }
3643
3644    pub fn component_count_byte_range(&self) -> Range<usize> {
3645        let start = 0;
3646        let end = start + u16::RAW_BYTE_LEN;
3647        start..end
3648    }
3649
3650    pub fn component_records_byte_range(&self) -> Range<usize> {
3651        let component_count = self.component_count();
3652        let start = self.component_count_byte_range().end;
3653        let end = start
3654            + (transforms::to_usize(component_count)).saturating_mul(
3655                <ComponentRecord as ComputeSize>::compute_size(self.mark_class_count())
3656                    .unwrap_or(0),
3657            );
3658        start..end
3659    }
3660}
3661
3662const _: () = assert!(FontData::default_data_long_enough(LigatureAttach::MIN_SIZE));
3663
3664impl Default for LigatureAttach<'_> {
3665    fn default() -> Self {
3666        Self {
3667            data: FontData::default_table_data(),
3668            mark_class_count: Default::default(),
3669        }
3670    }
3671}
3672
3673#[cfg(feature = "experimental_traverse")]
3674impl<'a> SomeTable<'a> for LigatureAttach<'a> {
3675    fn type_name(&self) -> &str {
3676        "LigatureAttach"
3677    }
3678    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3679        match idx {
3680            0usize => Some(Field::new("component_count", self.component_count())),
3681            1usize => Some(Field::new(
3682                "component_records",
3683                traversal::FieldType::computed_array(
3684                    "ComponentRecord",
3685                    self.component_records(),
3686                    self.offset_data(),
3687                ),
3688            )),
3689            _ => None,
3690        }
3691    }
3692}
3693
3694#[cfg(feature = "experimental_traverse")]
3695#[allow(clippy::needless_lifetimes)]
3696impl<'a> std::fmt::Debug for LigatureAttach<'a> {
3697    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3698        (self as &dyn SomeTable<'a>).fmt(f)
3699    }
3700}
3701
3702/// Part of [MarkLigPosFormat1]
3703#[derive(Clone, Debug)]
3704pub struct ComponentRecord<'a> {
3705    /// Array of offsets (one per class) to Anchor tables. Offsets are
3706    /// from beginning of LigatureAttach table, ordered by class
3707    /// (offsets may be NULL).
3708    pub ligature_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3709}
3710
3711impl<'a> ComponentRecord<'a> {
3712    /// Array of offsets (one per class) to Anchor tables. Offsets are
3713    /// from beginning of LigatureAttach table, ordered by class
3714    /// (offsets may be NULL).
3715    pub fn ligature_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3716        self.ligature_anchor_offsets
3717    }
3718
3719    /// Array of offsets (one per class) to Anchor tables. Offsets are
3720    /// from beginning of LigatureAttach table, ordered by class
3721    /// (offsets may be NULL).
3722    ///
3723    /// The `data` argument should be retrieved from the parent table
3724    /// By calling its `offset_data` method.
3725    pub fn ligature_anchors(
3726        &self,
3727        data: FontData<'a>,
3728    ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3729        let offsets = self.ligature_anchor_offsets();
3730        ArrayOfNullableOffsets::new(offsets, data, ())
3731    }
3732}
3733
3734impl ReadArgs for ComponentRecord<'_> {
3735    type Args = u16;
3736}
3737
3738impl ComputeSize for ComponentRecord<'_> {
3739    #[allow(clippy::needless_question_mark)]
3740    fn compute_size(args: u16) -> Result<usize, ReadError> {
3741        let mark_class_count = args;
3742        Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
3743    }
3744}
3745
3746impl<'a> FontRead<'a> for ComponentRecord<'a> {
3747    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3748        let mut cursor = data.cursor();
3749        let mark_class_count = args;
3750        Ok(Self {
3751            ligature_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
3752        })
3753    }
3754}
3755
3756#[allow(clippy::needless_lifetimes)]
3757impl<'a> ComponentRecord<'a> {
3758    /// A constructor that requires additional arguments.
3759    ///
3760    /// This type requires some external state in order to be
3761    /// parsed.
3762    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3763        let args = mark_class_count;
3764        Self::read_with_args(data, args)
3765    }
3766}
3767
3768#[cfg(feature = "experimental_traverse")]
3769impl<'a> SomeRecord<'a> for ComponentRecord<'a> {
3770    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
3771        RecordResolver {
3772            name: "ComponentRecord",
3773            get_field: Box::new(move |idx, _data| match idx {
3774                0usize => Some(Field::new(
3775                    "ligature_anchor_offsets",
3776                    FieldType::from(self.ligature_anchors(_data)),
3777                )),
3778                _ => None,
3779            }),
3780            data,
3781        }
3782    }
3783}
3784
3785impl Format<u16> for MarkMarkPosFormat1<'_> {
3786    const FORMAT: u16 = 1;
3787}
3788
3789impl<'a> MinByteRange<'a> for MarkMarkPosFormat1<'a> {
3790    fn min_byte_range(&self) -> Range<usize> {
3791        0..self.mark2_array_offset_byte_range().end
3792    }
3793    fn min_table_bytes(&self) -> &'a [u8] {
3794        let range = self.min_byte_range();
3795        self.data.as_bytes().get(range).unwrap_or_default()
3796    }
3797}
3798
3799impl ReadArgs for MarkMarkPosFormat1<'_> {
3800    type Args = ();
3801}
3802
3803impl<'a> FontRead<'a> for MarkMarkPosFormat1<'a> {
3804    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3805        #[allow(clippy::absurd_extreme_comparisons)]
3806        if data.len() < Self::MIN_SIZE {
3807            return Err(ReadError::OutOfBounds);
3808        }
3809        Ok(Self { data })
3810    }
3811}
3812
3813/// [Mark-to-Mark Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-to-mark-attachment-positioning-format-1-mark-to-mark-attachment): Mark-to-Mark Attachment
3814#[derive(Clone)]
3815pub struct MarkMarkPosFormat1<'a> {
3816    data: FontData<'a>,
3817}
3818
3819#[allow(clippy::needless_lifetimes)]
3820impl<'a> MarkMarkPosFormat1<'a> {
3821    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3822        + Offset16::RAW_BYTE_LEN
3823        + Offset16::RAW_BYTE_LEN
3824        + u16::RAW_BYTE_LEN
3825        + Offset16::RAW_BYTE_LEN
3826        + Offset16::RAW_BYTE_LEN);
3827    basic_table_impls!(impl_the_methods);
3828
3829    /// Format identifier: format = 1
3830    pub fn pos_format(&self) -> u16 {
3831        let range = self.pos_format_byte_range();
3832        self.data.read_at(range.start).ok().unwrap()
3833    }
3834
3835    /// Offset to Combining Mark Coverage table, from beginning of
3836    /// MarkMarkPos subtable.
3837    pub fn mark1_coverage_offset(&self) -> Offset16 {
3838        let range = self.mark1_coverage_offset_byte_range();
3839        self.data.read_at(range.start).ok().unwrap()
3840    }
3841
3842    /// Attempt to resolve [`mark1_coverage_offset`][Self::mark1_coverage_offset].
3843    pub fn mark1_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3844        let data = self.data;
3845        self.mark1_coverage_offset().resolve(data)
3846    }
3847
3848    /// Offset to Base Mark Coverage table, from beginning of
3849    /// MarkMarkPos subtable.
3850    pub fn mark2_coverage_offset(&self) -> Offset16 {
3851        let range = self.mark2_coverage_offset_byte_range();
3852        self.data.read_at(range.start).ok().unwrap()
3853    }
3854
3855    /// Attempt to resolve [`mark2_coverage_offset`][Self::mark2_coverage_offset].
3856    pub fn mark2_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3857        let data = self.data;
3858        self.mark2_coverage_offset().resolve(data)
3859    }
3860
3861    /// Number of Combining Mark classes defined
3862    pub fn mark_class_count(&self) -> u16 {
3863        let range = self.mark_class_count_byte_range();
3864        self.data.read_at(range.start).ok().unwrap()
3865    }
3866
3867    /// Offset to MarkArray table for mark1, from beginning of
3868    /// MarkMarkPos subtable.
3869    pub fn mark1_array_offset(&self) -> Offset16 {
3870        let range = self.mark1_array_offset_byte_range();
3871        self.data.read_at(range.start).ok().unwrap()
3872    }
3873
3874    /// Attempt to resolve [`mark1_array_offset`][Self::mark1_array_offset].
3875    pub fn mark1_array(&self) -> Result<MarkArray<'a>, ReadError> {
3876        let data = self.data;
3877        self.mark1_array_offset().resolve(data)
3878    }
3879
3880    /// Offset to Mark2Array table for mark2, from beginning of
3881    /// MarkMarkPos subtable.
3882    pub fn mark2_array_offset(&self) -> Offset16 {
3883        let range = self.mark2_array_offset_byte_range();
3884        self.data.read_at(range.start).ok().unwrap()
3885    }
3886
3887    /// Attempt to resolve [`mark2_array_offset`][Self::mark2_array_offset].
3888    pub fn mark2_array(&self) -> Result<Mark2Array<'a>, ReadError> {
3889        let data = self.data;
3890        let args = self.mark_class_count();
3891        self.mark2_array_offset().resolve_with_args(data, args)
3892    }
3893
3894    pub fn pos_format_byte_range(&self) -> Range<usize> {
3895        let start = 0;
3896        let end = start + u16::RAW_BYTE_LEN;
3897        start..end
3898    }
3899
3900    pub fn mark1_coverage_offset_byte_range(&self) -> Range<usize> {
3901        let start = self.pos_format_byte_range().end;
3902        let end = start + Offset16::RAW_BYTE_LEN;
3903        start..end
3904    }
3905
3906    pub fn mark2_coverage_offset_byte_range(&self) -> Range<usize> {
3907        let start = self.mark1_coverage_offset_byte_range().end;
3908        let end = start + Offset16::RAW_BYTE_LEN;
3909        start..end
3910    }
3911
3912    pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3913        let start = self.mark2_coverage_offset_byte_range().end;
3914        let end = start + u16::RAW_BYTE_LEN;
3915        start..end
3916    }
3917
3918    pub fn mark1_array_offset_byte_range(&self) -> Range<usize> {
3919        let start = self.mark_class_count_byte_range().end;
3920        let end = start + Offset16::RAW_BYTE_LEN;
3921        start..end
3922    }
3923
3924    pub fn mark2_array_offset_byte_range(&self) -> Range<usize> {
3925        let start = self.mark1_array_offset_byte_range().end;
3926        let end = start + Offset16::RAW_BYTE_LEN;
3927        start..end
3928    }
3929}
3930
3931const _: () = assert!(FontData::default_data_long_enough(
3932    MarkMarkPosFormat1::MIN_SIZE
3933));
3934
3935impl Default for MarkMarkPosFormat1<'_> {
3936    fn default() -> Self {
3937        Self {
3938            data: FontData::default_format_1_u16_table_data(),
3939        }
3940    }
3941}
3942
3943#[cfg(feature = "experimental_traverse")]
3944impl<'a> SomeTable<'a> for MarkMarkPosFormat1<'a> {
3945    fn type_name(&self) -> &str {
3946        "MarkMarkPosFormat1"
3947    }
3948    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3949        match idx {
3950            0usize => Some(Field::new("pos_format", self.pos_format())),
3951            1usize => Some(Field::new(
3952                "mark1_coverage_offset",
3953                FieldType::offset(self.mark1_coverage_offset(), self.mark1_coverage()),
3954            )),
3955            2usize => Some(Field::new(
3956                "mark2_coverage_offset",
3957                FieldType::offset(self.mark2_coverage_offset(), self.mark2_coverage()),
3958            )),
3959            3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3960            4usize => Some(Field::new(
3961                "mark1_array_offset",
3962                FieldType::offset(self.mark1_array_offset(), self.mark1_array()),
3963            )),
3964            5usize => Some(Field::new(
3965                "mark2_array_offset",
3966                FieldType::offset(self.mark2_array_offset(), self.mark2_array()),
3967            )),
3968            _ => None,
3969        }
3970    }
3971}
3972
3973#[cfg(feature = "experimental_traverse")]
3974#[allow(clippy::needless_lifetimes)]
3975impl<'a> std::fmt::Debug for MarkMarkPosFormat1<'a> {
3976    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3977        (self as &dyn SomeTable<'a>).fmt(f)
3978    }
3979}
3980
3981impl<'a> MinByteRange<'a> for Mark2Array<'a> {
3982    fn min_byte_range(&self) -> Range<usize> {
3983        0..self.mark2_records_byte_range().end
3984    }
3985    fn min_table_bytes(&self) -> &'a [u8] {
3986        let range = self.min_byte_range();
3987        self.data.as_bytes().get(range).unwrap_or_default()
3988    }
3989}
3990
3991impl ReadArgs for Mark2Array<'_> {
3992    type Args = u16;
3993}
3994
3995impl<'a> FontRead<'a> for Mark2Array<'a> {
3996    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3997        let mark_class_count = args;
3998
3999        #[allow(clippy::absurd_extreme_comparisons)]
4000        if data.len() < Self::MIN_SIZE {
4001            return Err(ReadError::OutOfBounds);
4002        }
4003        Ok(Self {
4004            data,
4005            mark_class_count,
4006        })
4007    }
4008}
4009
4010impl<'a> Mark2Array<'a> {
4011    /// A constructor that requires additional arguments.
4012    ///
4013    /// This type requires some external state in order to be
4014    /// parsed.
4015    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
4016        let args = mark_class_count;
4017        Self::read_with_args(data, args)
4018    }
4019}
4020
4021/// Part of [MarkMarkPosFormat1]Class2Record
4022#[derive(Clone)]
4023pub struct Mark2Array<'a> {
4024    data: FontData<'a>,
4025    mark_class_count: u16,
4026}
4027
4028#[allow(clippy::needless_lifetimes)]
4029impl<'a> Mark2Array<'a> {
4030    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
4031    basic_table_impls!(impl_the_methods);
4032
4033    /// Number of Mark2 records
4034    pub fn mark2_count(&self) -> u16 {
4035        let range = self.mark2_count_byte_range();
4036        self.data.read_at(range.start).ok().unwrap()
4037    }
4038
4039    /// Array of Mark2Records, in Coverage order.
4040    pub fn mark2_records(&self) -> ComputedArray<'a, Mark2Record<'a>> {
4041        let range = self.mark2_records_byte_range();
4042        self.data
4043            .read_with_args(range, self.mark_class_count())
4044            .unwrap_or_default()
4045    }
4046
4047    pub(crate) fn mark_class_count(&self) -> u16 {
4048        self.mark_class_count
4049    }
4050
4051    pub fn mark2_count_byte_range(&self) -> Range<usize> {
4052        let start = 0;
4053        let end = start + u16::RAW_BYTE_LEN;
4054        start..end
4055    }
4056
4057    pub fn mark2_records_byte_range(&self) -> Range<usize> {
4058        let mark2_count = self.mark2_count();
4059        let start = self.mark2_count_byte_range().end;
4060        let end = start
4061            + (transforms::to_usize(mark2_count)).saturating_mul(
4062                <Mark2Record as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
4063            );
4064        start..end
4065    }
4066}
4067
4068const _: () = assert!(FontData::default_data_long_enough(Mark2Array::MIN_SIZE));
4069
4070impl Default for Mark2Array<'_> {
4071    fn default() -> Self {
4072        Self {
4073            data: FontData::default_table_data(),
4074            mark_class_count: Default::default(),
4075        }
4076    }
4077}
4078
4079#[cfg(feature = "experimental_traverse")]
4080impl<'a> SomeTable<'a> for Mark2Array<'a> {
4081    fn type_name(&self) -> &str {
4082        "Mark2Array"
4083    }
4084    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4085        match idx {
4086            0usize => Some(Field::new("mark2_count", self.mark2_count())),
4087            1usize => Some(Field::new(
4088                "mark2_records",
4089                traversal::FieldType::computed_array(
4090                    "Mark2Record",
4091                    self.mark2_records(),
4092                    self.offset_data(),
4093                ),
4094            )),
4095            _ => None,
4096        }
4097    }
4098}
4099
4100#[cfg(feature = "experimental_traverse")]
4101#[allow(clippy::needless_lifetimes)]
4102impl<'a> std::fmt::Debug for Mark2Array<'a> {
4103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4104        (self as &dyn SomeTable<'a>).fmt(f)
4105    }
4106}
4107
4108/// Part of [MarkMarkPosFormat1]
4109#[derive(Clone, Debug)]
4110pub struct Mark2Record<'a> {
4111    /// Array of offsets (one per class) to Anchor tables. Offsets are
4112    /// from beginning of Mark2Array table, in class order (offsets may
4113    /// be NULL).
4114    pub mark2_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
4115}
4116
4117impl<'a> Mark2Record<'a> {
4118    /// Array of offsets (one per class) to Anchor tables. Offsets are
4119    /// from beginning of Mark2Array table, in class order (offsets may
4120    /// be NULL).
4121    pub fn mark2_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
4122        self.mark2_anchor_offsets
4123    }
4124
4125    /// Array of offsets (one per class) to Anchor tables. Offsets are
4126    /// from beginning of Mark2Array table, in class order (offsets may
4127    /// be NULL).
4128    ///
4129    /// The `data` argument should be retrieved from the parent table
4130    /// By calling its `offset_data` method.
4131    pub fn mark2_anchors(
4132        &self,
4133        data: FontData<'a>,
4134    ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
4135        let offsets = self.mark2_anchor_offsets();
4136        ArrayOfNullableOffsets::new(offsets, data, ())
4137    }
4138}
4139
4140impl ReadArgs for Mark2Record<'_> {
4141    type Args = u16;
4142}
4143
4144impl ComputeSize for Mark2Record<'_> {
4145    #[allow(clippy::needless_question_mark)]
4146    fn compute_size(args: u16) -> Result<usize, ReadError> {
4147        let mark_class_count = args;
4148        Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
4149    }
4150}
4151
4152impl<'a> FontRead<'a> for Mark2Record<'a> {
4153    fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
4154        let mut cursor = data.cursor();
4155        let mark_class_count = args;
4156        Ok(Self {
4157            mark2_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
4158        })
4159    }
4160}
4161
4162#[allow(clippy::needless_lifetimes)]
4163impl<'a> Mark2Record<'a> {
4164    /// A constructor that requires additional arguments.
4165    ///
4166    /// This type requires some external state in order to be
4167    /// parsed.
4168    pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
4169        let args = mark_class_count;
4170        Self::read_with_args(data, args)
4171    }
4172}
4173
4174#[cfg(feature = "experimental_traverse")]
4175impl<'a> SomeRecord<'a> for Mark2Record<'a> {
4176    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
4177        RecordResolver {
4178            name: "Mark2Record",
4179            get_field: Box::new(move |idx, _data| match idx {
4180                0usize => Some(Field::new(
4181                    "mark2_anchor_offsets",
4182                    FieldType::from(self.mark2_anchors(_data)),
4183                )),
4184                _ => None,
4185            }),
4186            data,
4187        }
4188    }
4189}
4190
4191impl Format<u16> for ExtensionPosFormat1<'_> {
4192    const FORMAT: u16 = 1;
4193}
4194
4195impl Discriminant for ExtensionPosFormat1<'_, ()> {
4196    fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
4197        data.read_at(u16::RAW_BYTE_LEN)
4198    }
4199}
4200
4201impl<'a, T> MinByteRange<'a> for ExtensionPosFormat1<'a, T> {
4202    fn min_byte_range(&self) -> Range<usize> {
4203        0..self.extension_offset_byte_range().end
4204    }
4205    fn min_table_bytes(&self) -> &'a [u8] {
4206        let range = self.min_byte_range();
4207        self.data.as_bytes().get(range).unwrap_or_default()
4208    }
4209}
4210
4211impl<T> ReadArgs for ExtensionPosFormat1<'_, T> {
4212    type Args = ();
4213}
4214
4215impl<'a, T> FontRead<'a> for ExtensionPosFormat1<'a, T> {
4216    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4217        #[allow(clippy::absurd_extreme_comparisons)]
4218        if data.len() < Self::MIN_SIZE {
4219            return Err(ReadError::OutOfBounds);
4220        }
4221        Ok(Self {
4222            data,
4223            offset_type: std::marker::PhantomData,
4224        })
4225    }
4226}
4227
4228impl<'a, T> ExtensionPosFormat1<'a, T> {
4229    #[allow(dead_code)]
4230    /// Replace the specific generic type on this implementation with `()`
4231    pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
4232        ExtensionPosFormat1 {
4233            data: self.data,
4234            offset_type: std::marker::PhantomData,
4235        }
4236    }
4237}
4238
4239/// [Extension Positioning Subtable Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#extension-positioning-subtable-format-1)
4240#[derive(Clone)]
4241pub struct ExtensionPosFormat1<'a, T = ()> {
4242    data: FontData<'a>,
4243    offset_type: std::marker::PhantomData<*const T>,
4244}
4245
4246#[allow(clippy::needless_lifetimes)]
4247impl<'a, T> ExtensionPosFormat1<'a, T> {
4248    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN);
4249    basic_table_impls!(impl_the_methods);
4250
4251    /// Format identifier: format = 1
4252    pub fn pos_format(&self) -> u16 {
4253        let range = self.pos_format_byte_range();
4254        self.data.read_at(range.start).ok().unwrap()
4255    }
4256
4257    /// Lookup type of subtable referenced by extensionOffset (i.e. the
4258    /// extension subtable).
4259    pub fn extension_lookup_type(&self) -> u16 {
4260        let range = self.extension_lookup_type_byte_range();
4261        self.data.read_at(range.start).ok().unwrap()
4262    }
4263
4264    /// Offset to the extension subtable, of lookup type
4265    /// extensionLookupType, relative to the start of the
4266    /// ExtensionPosFormat1 subtable.
4267    pub fn extension_offset(&self) -> Offset32 {
4268        let range = self.extension_offset_byte_range();
4269        self.data.read_at(range.start).ok().unwrap()
4270    }
4271
4272    /// Attempt to resolve [`extension_offset`][Self::extension_offset].
4273    pub fn extension(&self) -> Result<T, ReadError>
4274    where
4275        T: FontRead<'a, Args = ()>,
4276    {
4277        let data = self.data;
4278        self.extension_offset().resolve(data)
4279    }
4280
4281    pub fn pos_format_byte_range(&self) -> Range<usize> {
4282        let start = 0;
4283        let end = start + u16::RAW_BYTE_LEN;
4284        start..end
4285    }
4286
4287    pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
4288        let start = self.pos_format_byte_range().end;
4289        let end = start + u16::RAW_BYTE_LEN;
4290        start..end
4291    }
4292
4293    pub fn extension_offset_byte_range(&self) -> Range<usize> {
4294        let start = self.extension_lookup_type_byte_range().end;
4295        let end = start + Offset32::RAW_BYTE_LEN;
4296        start..end
4297    }
4298}
4299
4300const _: () = assert!(FontData::default_data_long_enough(
4301    ExtensionPosFormat1::<()>::MIN_SIZE
4302));
4303
4304impl<T> Default for ExtensionPosFormat1<'_, T> {
4305    fn default() -> Self {
4306        Self {
4307            data: FontData::default_format_1_u16_table_data(),
4308            offset_type: std::marker::PhantomData,
4309        }
4310    }
4311}
4312
4313#[cfg(feature = "experimental_traverse")]
4314impl<'a, T: FontRead<'a, Args = ()> + SomeTable<'a> + 'a> SomeTable<'a>
4315    for ExtensionPosFormat1<'a, T>
4316{
4317    fn type_name(&self) -> &str {
4318        "ExtensionPosFormat1"
4319    }
4320    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4321        match idx {
4322            0usize => Some(Field::new("pos_format", self.pos_format())),
4323            1usize => Some(Field::new(
4324                "extension_lookup_type",
4325                self.extension_lookup_type(),
4326            )),
4327            2usize => Some(Field::new(
4328                "extension_offset",
4329                FieldType::offset(self.extension_offset(), self.extension()),
4330            )),
4331            _ => None,
4332        }
4333    }
4334}
4335
4336#[cfg(feature = "experimental_traverse")]
4337#[allow(clippy::needless_lifetimes)]
4338impl<'a, T: FontRead<'a, Args = ()> + SomeTable<'a> + 'a> std::fmt::Debug
4339    for ExtensionPosFormat1<'a, T>
4340{
4341    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4342        (self as &dyn SomeTable<'a>).fmt(f)
4343    }
4344}
4345
4346/// A [GPOS Extension Positioning](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#lookuptype-9-extension-positioning) subtable
4347pub enum ExtensionSubtable<'a> {
4348    Single(ExtensionPosFormat1<'a, SinglePos<'a>>),
4349    Pair(ExtensionPosFormat1<'a, PairPos<'a>>),
4350    Cursive(ExtensionPosFormat1<'a, CursivePosFormat1<'a>>),
4351    MarkToBase(ExtensionPosFormat1<'a, MarkBasePosFormat1<'a>>),
4352    MarkToLig(ExtensionPosFormat1<'a, MarkLigPosFormat1<'a>>),
4353    MarkToMark(ExtensionPosFormat1<'a, MarkMarkPosFormat1<'a>>),
4354    Contextual(ExtensionPosFormat1<'a, PositionSequenceContext<'a>>),
4355    ChainContextual(ExtensionPosFormat1<'a, PositionChainContext<'a>>),
4356}
4357
4358impl Default for ExtensionSubtable<'_> {
4359    fn default() -> Self {
4360        Self::Single(Default::default())
4361    }
4362}
4363
4364impl ReadArgs for ExtensionSubtable<'_> {
4365    type Args = ();
4366}
4367
4368impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
4369    fn read_with_args(bytes: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4370        let discriminant = ExtensionPosFormat1::read_discriminant(bytes)?;
4371        match discriminant {
4372            1 => Ok(ExtensionSubtable::Single(FontRead::read(bytes)?)),
4373            2 => Ok(ExtensionSubtable::Pair(FontRead::read(bytes)?)),
4374            3 => Ok(ExtensionSubtable::Cursive(FontRead::read(bytes)?)),
4375            4 => Ok(ExtensionSubtable::MarkToBase(FontRead::read(bytes)?)),
4376            5 => Ok(ExtensionSubtable::MarkToLig(FontRead::read(bytes)?)),
4377            6 => Ok(ExtensionSubtable::MarkToMark(FontRead::read(bytes)?)),
4378            7 => Ok(ExtensionSubtable::Contextual(FontRead::read(bytes)?)),
4379            8 => Ok(ExtensionSubtable::ChainContextual(FontRead::read(bytes)?)),
4380            other => Err(ReadError::InvalidFormat(other.into())),
4381        }
4382    }
4383}
4384
4385impl<'a> ExtensionSubtable<'a> {
4386    #[allow(dead_code)]
4387    /// Return the inner table, removing the specific generics.
4388    ///
4389    /// This lets us return a single concrete type we can call methods on.
4390    pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
4391        match self {
4392            ExtensionSubtable::Single(inner) => inner.of_unit_type(),
4393            ExtensionSubtable::Pair(inner) => inner.of_unit_type(),
4394            ExtensionSubtable::Cursive(inner) => inner.of_unit_type(),
4395            ExtensionSubtable::MarkToBase(inner) => inner.of_unit_type(),
4396            ExtensionSubtable::MarkToLig(inner) => inner.of_unit_type(),
4397            ExtensionSubtable::MarkToMark(inner) => inner.of_unit_type(),
4398            ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
4399            ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
4400        }
4401    }
4402}
4403
4404#[cfg(feature = "experimental_traverse")]
4405impl<'a> ExtensionSubtable<'a> {
4406    fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
4407        match self {
4408            ExtensionSubtable::Single(table) => table,
4409            ExtensionSubtable::Pair(table) => table,
4410            ExtensionSubtable::Cursive(table) => table,
4411            ExtensionSubtable::MarkToBase(table) => table,
4412            ExtensionSubtable::MarkToLig(table) => table,
4413            ExtensionSubtable::MarkToMark(table) => table,
4414            ExtensionSubtable::Contextual(table) => table,
4415            ExtensionSubtable::ChainContextual(table) => table,
4416        }
4417    }
4418}
4419
4420#[cfg(feature = "experimental_traverse")]
4421impl<'a> SomeTable<'a> for ExtensionSubtable<'a> {
4422    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4423        self.dyn_inner().get_field(idx)
4424    }
4425    fn type_name(&self) -> &str {
4426        self.dyn_inner().type_name()
4427    }
4428}
4429
4430#[cfg(feature = "experimental_traverse")]
4431impl std::fmt::Debug for ExtensionSubtable<'_> {
4432    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4433        self.dyn_inner().fmt(f)
4434    }
4435}