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