Skip to main content

read_fonts/generated/
generated_gpos.rs

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