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