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