Skip to main content

write_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
8pub use read_fonts::tables::gpos::ValueFormat;
9
10/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
11/// [GPOS Version 1.0](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#gpos-header)
12#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Gpos {
15    /// Offset to ScriptList table, from beginning of GPOS table
16    pub script_list: OffsetMarker<ScriptList>,
17    /// Offset to FeatureList table, from beginning of GPOS table
18    pub feature_list: OffsetMarker<FeatureList>,
19    /// Offset to LookupList table, from beginning of GPOS table
20    pub lookup_list: OffsetMarker<PositionLookupList>,
21    pub feature_variations: NullableOffsetMarker<FeatureVariations, WIDTH_32>,
22}
23
24impl Gpos {
25    /// Construct a new `Gpos`
26    pub fn new(
27        script_list: ScriptList,
28        feature_list: FeatureList,
29        lookup_list: PositionLookupList,
30    ) -> Self {
31        Self {
32            script_list: script_list.into(),
33            feature_list: feature_list.into(),
34            lookup_list: lookup_list.into(),
35            ..Default::default()
36        }
37    }
38}
39
40impl FontWrite for Gpos {
41    #[allow(clippy::unnecessary_cast)]
42    fn write_into(&self, writer: &mut TableWriter) {
43        let version = self.compute_version() as MajorMinor;
44        version.write_into(writer);
45        self.script_list.write_into(writer);
46        self.feature_list.write_into(writer);
47        self.lookup_list.write_into(writer);
48        version
49            .compatible((1u16, 1u16))
50            .then(|| self.feature_variations.write_into(writer));
51    }
52    fn table_type(&self) -> TableType {
53        TableType::TopLevel(Gpos::TAG)
54    }
55}
56
57impl Validate for Gpos {
58    fn validate_impl(&self, ctx: &mut ValidationCtx) {
59        ctx.in_table("Gpos", |ctx| {
60            ctx.in_field("script_list", |ctx| {
61                self.script_list.validate_impl(ctx);
62            });
63            ctx.in_field("feature_list", |ctx| {
64                self.feature_list.validate_impl(ctx);
65            });
66            ctx.in_field("lookup_list", |ctx| {
67                self.lookup_list.validate_impl(ctx);
68            });
69            ctx.in_field("feature_variations", |ctx| {
70                self.feature_variations.validate_impl(ctx);
71            });
72        })
73    }
74}
75
76impl TopLevelTable for Gpos {
77    const TAG: Tag = Tag::new(b"GPOS");
78}
79
80impl<'a> FromObjRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {
81    fn from_obj_ref(obj: &read_fonts::tables::gpos::Gpos<'a>, _: FontData) -> Self {
82        Gpos {
83            script_list: obj.script_list().to_owned_table(),
84            feature_list: obj.feature_list().to_owned_table(),
85            lookup_list: obj.lookup_list().to_owned_table(),
86            feature_variations: obj.feature_variations().to_owned_table(),
87        }
88    }
89}
90
91#[allow(clippy::needless_lifetimes)]
92impl<'a> FromTableRef<read_fonts::tables::gpos::Gpos<'a>> for Gpos {}
93
94impl ReadArgs for Gpos {
95    type Args = ();
96}
97
98impl<'a> FontRead<'a> for Gpos {
99    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
100        <read_fonts::tables::gpos::Gpos as FontRead>::read(data).map(|x| x.to_owned_table())
101    }
102}
103
104/// A [GPOS Lookup](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#gsubLookupTypeEnum) subtable.
105#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub enum PositionLookup {
108    Single(Lookup<SinglePos>),
109    Pair(Lookup<PairPos>),
110    Cursive(Lookup<CursivePosFormat1>),
111    MarkToBase(Lookup<MarkBasePosFormat1>),
112    MarkToLig(Lookup<MarkLigPosFormat1>),
113    MarkToMark(Lookup<MarkMarkPosFormat1>),
114    Contextual(Lookup<PositionSequenceContext>),
115    ChainContextual(Lookup<PositionChainContext>),
116    Extension(Lookup<ExtensionSubtable>),
117}
118
119impl Default for PositionLookup {
120    fn default() -> Self {
121        Self::Single(Default::default())
122    }
123}
124
125impl FontWrite for PositionLookup {
126    fn write_into(&self, writer: &mut TableWriter) {
127        match self {
128            Self::Single(table) => table.write_into(writer),
129            Self::Pair(table) => table.write_into(writer),
130            Self::Cursive(table) => table.write_into(writer),
131            Self::MarkToBase(table) => table.write_into(writer),
132            Self::MarkToLig(table) => table.write_into(writer),
133            Self::MarkToMark(table) => table.write_into(writer),
134            Self::Contextual(table) => table.write_into(writer),
135            Self::ChainContextual(table) => table.write_into(writer),
136            Self::Extension(table) => table.write_into(writer),
137        }
138    }
139    fn table_type(&self) -> TableType {
140        match self {
141            Self::Single(table) => table.table_type(),
142            Self::Pair(table) => table.table_type(),
143            Self::Cursive(table) => table.table_type(),
144            Self::MarkToBase(table) => table.table_type(),
145            Self::MarkToLig(table) => table.table_type(),
146            Self::MarkToMark(table) => table.table_type(),
147            Self::Contextual(table) => table.table_type(),
148            Self::ChainContextual(table) => table.table_type(),
149            Self::Extension(table) => table.table_type(),
150        }
151    }
152}
153
154impl Validate for PositionLookup {
155    fn validate_impl(&self, ctx: &mut ValidationCtx) {
156        match self {
157            Self::Single(table) => table.validate_impl(ctx),
158            Self::Pair(table) => table.validate_impl(ctx),
159            Self::Cursive(table) => table.validate_impl(ctx),
160            Self::MarkToBase(table) => table.validate_impl(ctx),
161            Self::MarkToLig(table) => table.validate_impl(ctx),
162            Self::MarkToMark(table) => table.validate_impl(ctx),
163            Self::Contextual(table) => table.validate_impl(ctx),
164            Self::ChainContextual(table) => table.validate_impl(ctx),
165            Self::Extension(table) => table.validate_impl(ctx),
166        }
167    }
168}
169
170impl FromObjRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {
171    fn from_obj_ref(from: &read_fonts::tables::gpos::PositionLookup<'_>, data: FontData) -> Self {
172        match from {
173            read_fonts::tables::gpos::PositionLookup::Single(table) => {
174                Self::Single(table.to_owned_obj(data))
175            }
176            read_fonts::tables::gpos::PositionLookup::Pair(table) => {
177                Self::Pair(table.to_owned_obj(data))
178            }
179            read_fonts::tables::gpos::PositionLookup::Cursive(table) => {
180                Self::Cursive(table.to_owned_obj(data))
181            }
182            read_fonts::tables::gpos::PositionLookup::MarkToBase(table) => {
183                Self::MarkToBase(table.to_owned_obj(data))
184            }
185            read_fonts::tables::gpos::PositionLookup::MarkToLig(table) => {
186                Self::MarkToLig(table.to_owned_obj(data))
187            }
188            read_fonts::tables::gpos::PositionLookup::MarkToMark(table) => {
189                Self::MarkToMark(table.to_owned_obj(data))
190            }
191            read_fonts::tables::gpos::PositionLookup::Contextual(table) => {
192                Self::Contextual(table.to_owned_obj(data))
193            }
194            read_fonts::tables::gpos::PositionLookup::ChainContextual(table) => {
195                Self::ChainContextual(table.to_owned_obj(data))
196            }
197            read_fonts::tables::gpos::PositionLookup::Extension(table) => {
198                Self::Extension(table.to_owned_obj(data))
199            }
200        }
201    }
202}
203
204impl FromTableRef<read_fonts::tables::gpos::PositionLookup<'_>> for PositionLookup {}
205
206impl From<Lookup<SinglePos>> for PositionLookup {
207    fn from(src: Lookup<SinglePos>) -> PositionLookup {
208        PositionLookup::Single(src)
209    }
210}
211
212impl From<Lookup<PairPos>> for PositionLookup {
213    fn from(src: Lookup<PairPos>) -> PositionLookup {
214        PositionLookup::Pair(src)
215    }
216}
217
218impl From<Lookup<CursivePosFormat1>> for PositionLookup {
219    fn from(src: Lookup<CursivePosFormat1>) -> PositionLookup {
220        PositionLookup::Cursive(src)
221    }
222}
223
224impl From<Lookup<MarkBasePosFormat1>> for PositionLookup {
225    fn from(src: Lookup<MarkBasePosFormat1>) -> PositionLookup {
226        PositionLookup::MarkToBase(src)
227    }
228}
229
230impl From<Lookup<MarkLigPosFormat1>> for PositionLookup {
231    fn from(src: Lookup<MarkLigPosFormat1>) -> PositionLookup {
232        PositionLookup::MarkToLig(src)
233    }
234}
235
236impl From<Lookup<MarkMarkPosFormat1>> for PositionLookup {
237    fn from(src: Lookup<MarkMarkPosFormat1>) -> PositionLookup {
238        PositionLookup::MarkToMark(src)
239    }
240}
241
242impl From<Lookup<PositionSequenceContext>> for PositionLookup {
243    fn from(src: Lookup<PositionSequenceContext>) -> PositionLookup {
244        PositionLookup::Contextual(src)
245    }
246}
247
248impl From<Lookup<PositionChainContext>> for PositionLookup {
249    fn from(src: Lookup<PositionChainContext>) -> PositionLookup {
250        PositionLookup::ChainContextual(src)
251    }
252}
253
254impl From<Lookup<ExtensionSubtable>> for PositionLookup {
255    fn from(src: Lookup<ExtensionSubtable>) -> PositionLookup {
256        PositionLookup::Extension(src)
257    }
258}
259
260impl FontWrite for ValueFormat {
261    fn write_into(&self, writer: &mut TableWriter) {
262        writer.write_slice(&self.bits().to_be_bytes())
263    }
264}
265
266/// [Anchor Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-tables)
267/// position one glyph with respect to another.
268#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
269#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
270pub enum AnchorTable {
271    Format1(AnchorFormat1),
272    Format2(AnchorFormat2),
273    Format3(AnchorFormat3),
274}
275
276impl AnchorTable {
277    /// Construct a new `AnchorFormat1` subtable
278    pub fn format_1(x_coordinate: i16, y_coordinate: i16) -> Self {
279        Self::Format1(AnchorFormat1::new(x_coordinate, y_coordinate))
280    }
281
282    /// Construct a new `AnchorFormat2` subtable
283    pub fn format_2(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self {
284        Self::Format2(AnchorFormat2::new(x_coordinate, y_coordinate, anchor_point))
285    }
286
287    /// Construct a new `AnchorFormat3` subtable
288    pub fn format_3(
289        x_coordinate: i16,
290        y_coordinate: i16,
291        x_device: Option<DeviceOrVariationIndex>,
292        y_device: Option<DeviceOrVariationIndex>,
293    ) -> Self {
294        Self::Format3(AnchorFormat3::new(
295            x_coordinate,
296            y_coordinate,
297            x_device,
298            y_device,
299        ))
300    }
301}
302
303impl Default for AnchorTable {
304    fn default() -> Self {
305        Self::Format1(Default::default())
306    }
307}
308
309impl FontWrite for AnchorTable {
310    fn write_into(&self, writer: &mut TableWriter) {
311        match self {
312            Self::Format1(item) => item.write_into(writer),
313            Self::Format2(item) => item.write_into(writer),
314            Self::Format3(item) => item.write_into(writer),
315        }
316    }
317    fn table_type(&self) -> TableType {
318        match self {
319            Self::Format1(item) => item.table_type(),
320            Self::Format2(item) => item.table_type(),
321            Self::Format3(item) => item.table_type(),
322        }
323    }
324}
325
326impl Validate for AnchorTable {
327    fn validate_impl(&self, ctx: &mut ValidationCtx) {
328        match self {
329            Self::Format1(item) => item.validate_impl(ctx),
330            Self::Format2(item) => item.validate_impl(ctx),
331            Self::Format3(item) => item.validate_impl(ctx),
332        }
333    }
334}
335
336impl FromObjRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {
337    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorTable, _: FontData) -> Self {
338        use read_fonts::tables::gpos::AnchorTable as ObjRefType;
339        match obj {
340            ObjRefType::Format1(item) => AnchorTable::Format1(item.to_owned_table()),
341            ObjRefType::Format2(item) => AnchorTable::Format2(item.to_owned_table()),
342            ObjRefType::Format3(item) => AnchorTable::Format3(item.to_owned_table()),
343        }
344    }
345}
346
347impl FromTableRef<read_fonts::tables::gpos::AnchorTable<'_>> for AnchorTable {}
348
349impl ReadArgs for AnchorTable {
350    type Args = ();
351}
352
353impl<'a> FontRead<'a> for AnchorTable {
354    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
355        <read_fonts::tables::gpos::AnchorTable as FontRead>::read(data).map(|x| x.to_owned_table())
356    }
357}
358
359impl From<AnchorFormat1> for AnchorTable {
360    fn from(src: AnchorFormat1) -> AnchorTable {
361        AnchorTable::Format1(src)
362    }
363}
364
365impl From<AnchorFormat2> for AnchorTable {
366    fn from(src: AnchorFormat2) -> AnchorTable {
367        AnchorTable::Format2(src)
368    }
369}
370
371impl From<AnchorFormat3> for AnchorTable {
372    fn from(src: AnchorFormat3) -> AnchorTable {
373        AnchorTable::Format3(src)
374    }
375}
376
377/// [Anchor Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#anchor-table-format-1-design-units): Design Units
378#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
379#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
380pub struct AnchorFormat1 {
381    /// Horizontal value, in design units
382    pub x_coordinate: i16,
383    /// Vertical value, in design units
384    pub y_coordinate: i16,
385}
386
387impl AnchorFormat1 {
388    /// Construct a new `AnchorFormat1`
389    pub fn new(x_coordinate: i16, y_coordinate: i16) -> Self {
390        Self {
391            x_coordinate,
392            y_coordinate,
393        }
394    }
395}
396
397impl FontWrite for AnchorFormat1 {
398    #[allow(clippy::unnecessary_cast)]
399    fn write_into(&self, writer: &mut TableWriter) {
400        (1 as u16).write_into(writer);
401        self.x_coordinate.write_into(writer);
402        self.y_coordinate.write_into(writer);
403    }
404    fn table_type(&self) -> TableType {
405        TableType::Named("AnchorFormat1")
406    }
407}
408
409impl Validate for AnchorFormat1 {
410    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
411}
412
413impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {
414    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat1<'a>, _: FontData) -> Self {
415        AnchorFormat1 {
416            x_coordinate: obj.x_coordinate(),
417            y_coordinate: obj.y_coordinate(),
418        }
419    }
420}
421
422#[allow(clippy::needless_lifetimes)]
423impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat1<'a>> for AnchorFormat1 {}
424
425impl ReadArgs for AnchorFormat1 {
426    type Args = ();
427}
428
429impl<'a> FontRead<'a> for AnchorFormat1 {
430    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
431        <read_fonts::tables::gpos::AnchorFormat1 as FontRead>::read(data)
432            .map(|x| x.to_owned_table())
433    }
434}
435
436/// [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
437#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct AnchorFormat2 {
440    /// Horizontal value, in design units
441    pub x_coordinate: i16,
442    /// Vertical value, in design units
443    pub y_coordinate: i16,
444    /// Index to glyph contour point
445    pub anchor_point: u16,
446}
447
448impl AnchorFormat2 {
449    /// Construct a new `AnchorFormat2`
450    pub fn new(x_coordinate: i16, y_coordinate: i16, anchor_point: u16) -> Self {
451        Self {
452            x_coordinate,
453            y_coordinate,
454            anchor_point,
455        }
456    }
457}
458
459impl FontWrite for AnchorFormat2 {
460    #[allow(clippy::unnecessary_cast)]
461    fn write_into(&self, writer: &mut TableWriter) {
462        (2 as u16).write_into(writer);
463        self.x_coordinate.write_into(writer);
464        self.y_coordinate.write_into(writer);
465        self.anchor_point.write_into(writer);
466    }
467    fn table_type(&self) -> TableType {
468        TableType::Named("AnchorFormat2")
469    }
470}
471
472impl Validate for AnchorFormat2 {
473    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
474}
475
476impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {
477    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat2<'a>, _: FontData) -> Self {
478        AnchorFormat2 {
479            x_coordinate: obj.x_coordinate(),
480            y_coordinate: obj.y_coordinate(),
481            anchor_point: obj.anchor_point(),
482        }
483    }
484}
485
486#[allow(clippy::needless_lifetimes)]
487impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat2<'a>> for AnchorFormat2 {}
488
489impl ReadArgs for AnchorFormat2 {
490    type Args = ();
491}
492
493impl<'a> FontRead<'a> for AnchorFormat2 {
494    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
495        <read_fonts::tables::gpos::AnchorFormat2 as FontRead>::read(data)
496            .map(|x| x.to_owned_table())
497    }
498}
499
500/// [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
501#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
502#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
503pub struct AnchorFormat3 {
504    /// Horizontal value, in design units
505    pub x_coordinate: i16,
506    /// Vertical value, in design units
507    pub y_coordinate: i16,
508    /// Offset to Device table (non-variable font) / VariationIndex
509    /// table (variable font) for X coordinate, from beginning of
510    /// Anchor table (may be NULL)
511    pub x_device: NullableOffsetMarker<DeviceOrVariationIndex>,
512    /// Offset to Device table (non-variable font) / VariationIndex
513    /// table (variable font) for Y coordinate, from beginning of
514    /// Anchor table (may be NULL)
515    pub y_device: NullableOffsetMarker<DeviceOrVariationIndex>,
516}
517
518impl AnchorFormat3 {
519    /// Construct a new `AnchorFormat3`
520    pub fn new(
521        x_coordinate: i16,
522        y_coordinate: i16,
523        x_device: Option<DeviceOrVariationIndex>,
524        y_device: Option<DeviceOrVariationIndex>,
525    ) -> Self {
526        Self {
527            x_coordinate,
528            y_coordinate,
529            x_device: x_device.into(),
530            y_device: y_device.into(),
531        }
532    }
533}
534
535impl FontWrite for AnchorFormat3 {
536    #[allow(clippy::unnecessary_cast)]
537    fn write_into(&self, writer: &mut TableWriter) {
538        (3 as u16).write_into(writer);
539        self.x_coordinate.write_into(writer);
540        self.y_coordinate.write_into(writer);
541        self.x_device.write_into(writer);
542        self.y_device.write_into(writer);
543    }
544    fn table_type(&self) -> TableType {
545        TableType::Named("AnchorFormat3")
546    }
547}
548
549impl Validate for AnchorFormat3 {
550    fn validate_impl(&self, ctx: &mut ValidationCtx) {
551        ctx.in_table("AnchorFormat3", |ctx| {
552            ctx.in_field("x_device", |ctx| {
553                self.x_device.validate_impl(ctx);
554            });
555            ctx.in_field("y_device", |ctx| {
556                self.y_device.validate_impl(ctx);
557            });
558        })
559    }
560}
561
562impl<'a> FromObjRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {
563    fn from_obj_ref(obj: &read_fonts::tables::gpos::AnchorFormat3<'a>, _: FontData) -> Self {
564        AnchorFormat3 {
565            x_coordinate: obj.x_coordinate(),
566            y_coordinate: obj.y_coordinate(),
567            x_device: obj.x_device().to_owned_table(),
568            y_device: obj.y_device().to_owned_table(),
569        }
570    }
571}
572
573#[allow(clippy::needless_lifetimes)]
574impl<'a> FromTableRef<read_fonts::tables::gpos::AnchorFormat3<'a>> for AnchorFormat3 {}
575
576impl ReadArgs for AnchorFormat3 {
577    type Args = ();
578}
579
580impl<'a> FontRead<'a> for AnchorFormat3 {
581    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
582        <read_fonts::tables::gpos::AnchorFormat3 as FontRead>::read(data)
583            .map(|x| x.to_owned_table())
584    }
585}
586
587/// [Mark Array Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#mark-array-table)
588#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
589#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
590pub struct MarkArray {
591    /// Array of MarkRecords, ordered by corresponding glyphs in the
592    /// associated mark Coverage table.
593    pub mark_records: Vec<MarkRecord>,
594}
595
596impl MarkArray {
597    /// Construct a new `MarkArray`
598    pub fn new(mark_records: Vec<MarkRecord>) -> Self {
599        Self { mark_records }
600    }
601}
602
603impl FontWrite for MarkArray {
604    #[allow(clippy::unnecessary_cast)]
605    fn write_into(&self, writer: &mut TableWriter) {
606        (u16::try_from(array_len(&self.mark_records)).unwrap()).write_into(writer);
607        self.mark_records.write_into(writer);
608    }
609    fn table_type(&self) -> TableType {
610        TableType::Named("MarkArray")
611    }
612}
613
614impl Validate for MarkArray {
615    fn validate_impl(&self, ctx: &mut ValidationCtx) {
616        ctx.in_table("MarkArray", |ctx| {
617            ctx.in_field("mark_records", |ctx| {
618                if self.mark_records.len() > to_usize(u16::MAX) {
619                    ctx.report("array exceeds max length");
620                }
621                self.mark_records.validate_impl(ctx);
622            });
623        })
624    }
625}
626
627impl<'a> FromObjRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {
628    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkArray<'a>, _: FontData) -> Self {
629        let offset_data = obj.offset_data();
630        MarkArray {
631            mark_records: obj.mark_records().to_owned_obj(offset_data),
632        }
633    }
634}
635
636#[allow(clippy::needless_lifetimes)]
637impl<'a> FromTableRef<read_fonts::tables::gpos::MarkArray<'a>> for MarkArray {}
638
639impl ReadArgs for MarkArray {
640    type Args = ();
641}
642
643impl<'a> FontRead<'a> for MarkArray {
644    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
645        <read_fonts::tables::gpos::MarkArray as FontRead>::read(data).map(|x| x.to_owned_table())
646    }
647}
648
649/// Part of [MarkArray]
650#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
651#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
652pub struct MarkRecord {
653    /// Class defined for the associated mark.
654    pub mark_class: u16,
655    /// Offset to Anchor table, from beginning of MarkArray table.
656    pub mark_anchor: OffsetMarker<AnchorTable>,
657}
658
659impl MarkRecord {
660    /// Construct a new `MarkRecord`
661    pub fn new(mark_class: u16, mark_anchor: AnchorTable) -> Self {
662        Self {
663            mark_class,
664            mark_anchor: mark_anchor.into(),
665        }
666    }
667}
668
669impl FontWrite for MarkRecord {
670    fn write_into(&self, writer: &mut TableWriter) {
671        self.mark_class.write_into(writer);
672        self.mark_anchor.write_into(writer);
673    }
674    fn table_type(&self) -> TableType {
675        TableType::Named("MarkRecord")
676    }
677}
678
679impl Validate for MarkRecord {
680    fn validate_impl(&self, ctx: &mut ValidationCtx) {
681        ctx.in_table("MarkRecord", |ctx| {
682            ctx.in_field("mark_anchor", |ctx| {
683                self.mark_anchor.validate_impl(ctx);
684            });
685        })
686    }
687}
688
689impl FromObjRef<read_fonts::tables::gpos::MarkRecord> for MarkRecord {
690    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkRecord, offset_data: FontData) -> Self {
691        MarkRecord {
692            mark_class: obj.mark_class(),
693            mark_anchor: obj.mark_anchor(offset_data).to_owned_table(),
694        }
695    }
696}
697
698/// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable
699#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
700#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
701pub enum SinglePos {
702    Format1(SinglePosFormat1),
703    Format2(SinglePosFormat2),
704}
705
706impl SinglePos {
707    /// Construct a new `SinglePosFormat1` subtable
708    pub fn format_1(coverage: CoverageTable, value_record: ValueRecord) -> Self {
709        Self::Format1(SinglePosFormat1::new(coverage, value_record))
710    }
711
712    /// Construct a new `SinglePosFormat2` subtable
713    pub fn format_2(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self {
714        Self::Format2(SinglePosFormat2::new(coverage, value_records))
715    }
716}
717
718impl Default for SinglePos {
719    fn default() -> Self {
720        Self::Format1(Default::default())
721    }
722}
723
724impl FontWrite for SinglePos {
725    fn write_into(&self, writer: &mut TableWriter) {
726        match self {
727            Self::Format1(item) => item.write_into(writer),
728            Self::Format2(item) => item.write_into(writer),
729        }
730    }
731    fn table_type(&self) -> TableType {
732        match self {
733            Self::Format1(item) => item.table_type(),
734            Self::Format2(item) => item.table_type(),
735        }
736    }
737}
738
739impl Validate for SinglePos {
740    fn validate_impl(&self, ctx: &mut ValidationCtx) {
741        match self {
742            Self::Format1(item) => item.validate_impl(ctx),
743            Self::Format2(item) => item.validate_impl(ctx),
744        }
745    }
746}
747
748impl FromObjRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {
749    fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePos, _: FontData) -> Self {
750        use read_fonts::tables::gpos::SinglePos as ObjRefType;
751        match obj {
752            ObjRefType::Format1(item) => SinglePos::Format1(item.to_owned_table()),
753            ObjRefType::Format2(item) => SinglePos::Format2(item.to_owned_table()),
754        }
755    }
756}
757
758impl FromTableRef<read_fonts::tables::gpos::SinglePos<'_>> for SinglePos {}
759
760impl ReadArgs for SinglePos {
761    type Args = ();
762}
763
764impl<'a> FontRead<'a> for SinglePos {
765    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
766        <read_fonts::tables::gpos::SinglePos as FontRead>::read(data).map(|x| x.to_owned_table())
767    }
768}
769
770impl From<SinglePosFormat1> for SinglePos {
771    fn from(src: SinglePosFormat1) -> SinglePos {
772        SinglePos::Format1(src)
773    }
774}
775
776impl From<SinglePosFormat2> for SinglePos {
777    fn from(src: SinglePosFormat2) -> SinglePos {
778        SinglePos::Format2(src)
779    }
780}
781
782/// [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
783#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
784#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
785pub struct SinglePosFormat1 {
786    /// Offset to Coverage table, from beginning of SinglePos subtable.
787    pub coverage: OffsetMarker<CoverageTable>,
788    /// Defines positioning value(s) — applied to all glyphs in the
789    /// Coverage table.
790    pub value_record: ValueRecord,
791}
792
793impl SinglePosFormat1 {
794    /// Construct a new `SinglePosFormat1`
795    pub fn new(coverage: CoverageTable, value_record: ValueRecord) -> Self {
796        Self {
797            coverage: coverage.into(),
798            value_record,
799        }
800    }
801}
802
803impl FontWrite for SinglePosFormat1 {
804    #[allow(clippy::unnecessary_cast)]
805    fn write_into(&self, writer: &mut TableWriter) {
806        (1 as u16).write_into(writer);
807        self.coverage.write_into(writer);
808        (self.compute_value_format() as ValueFormat).write_into(writer);
809        self.value_record.write_into(writer);
810    }
811    fn table_type(&self) -> TableType {
812        TableType::Named("SinglePosFormat1")
813    }
814}
815
816impl Validate for SinglePosFormat1 {
817    fn validate_impl(&self, ctx: &mut ValidationCtx) {
818        ctx.in_table("SinglePosFormat1", |ctx| {
819            ctx.in_field("coverage", |ctx| {
820                self.coverage.validate_impl(ctx);
821            });
822        })
823    }
824}
825
826impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {
827    fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat1<'a>, _: FontData) -> Self {
828        let offset_data = obj.offset_data();
829        SinglePosFormat1 {
830            coverage: obj.coverage().to_owned_table(),
831            value_record: obj.value_record().to_owned_obj(offset_data),
832        }
833    }
834}
835
836#[allow(clippy::needless_lifetimes)]
837impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat1<'a>> for SinglePosFormat1 {}
838
839impl ReadArgs for SinglePosFormat1 {
840    type Args = ();
841}
842
843impl<'a> FontRead<'a> for SinglePosFormat1 {
844    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
845        <read_fonts::tables::gpos::SinglePosFormat1 as FontRead>::read(data)
846            .map(|x| x.to_owned_table())
847    }
848}
849
850/// [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
851#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
852#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
853pub struct SinglePosFormat2 {
854    /// Offset to Coverage table, from beginning of SinglePos subtable.
855    pub coverage: OffsetMarker<CoverageTable>,
856    /// Array of ValueRecords — positioning values applied to glyphs.
857    pub value_records: Vec<ValueRecord>,
858}
859
860impl SinglePosFormat2 {
861    /// Construct a new `SinglePosFormat2`
862    pub fn new(coverage: CoverageTable, value_records: Vec<ValueRecord>) -> Self {
863        Self {
864            coverage: coverage.into(),
865            value_records,
866        }
867    }
868}
869
870impl FontWrite for SinglePosFormat2 {
871    #[allow(clippy::unnecessary_cast)]
872    fn write_into(&self, writer: &mut TableWriter) {
873        (2 as u16).write_into(writer);
874        self.coverage.write_into(writer);
875        (self.compute_value_format() as ValueFormat).write_into(writer);
876        (u16::try_from(array_len(&self.value_records)).unwrap()).write_into(writer);
877        self.value_records.write_into(writer);
878    }
879    fn table_type(&self) -> TableType {
880        TableType::Named("SinglePosFormat2")
881    }
882}
883
884impl Validate for SinglePosFormat2 {
885    fn validate_impl(&self, ctx: &mut ValidationCtx) {
886        ctx.in_table("SinglePosFormat2", |ctx| {
887            ctx.in_field("coverage", |ctx| {
888                self.coverage.validate_impl(ctx);
889            });
890            ctx.in_field("value_records", |ctx| {
891                if self.value_records.len() > to_usize(u16::MAX) {
892                    ctx.report("array exceeds max length");
893                }
894                self.value_records.validate_impl(ctx);
895            });
896        })
897    }
898}
899
900impl<'a> FromObjRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {
901    fn from_obj_ref(obj: &read_fonts::tables::gpos::SinglePosFormat2<'a>, _: FontData) -> Self {
902        let offset_data = obj.offset_data();
903        SinglePosFormat2 {
904            coverage: obj.coverage().to_owned_table(),
905            value_records: obj
906                .value_records()
907                .iter()
908                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
909                .collect(),
910        }
911    }
912}
913
914#[allow(clippy::needless_lifetimes)]
915impl<'a> FromTableRef<read_fonts::tables::gpos::SinglePosFormat2<'a>> for SinglePosFormat2 {}
916
917impl ReadArgs for SinglePosFormat2 {
918    type Args = ();
919}
920
921impl<'a> FontRead<'a> for SinglePosFormat2 {
922    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
923        <read_fonts::tables::gpos::SinglePosFormat2 as FontRead>::read(data)
924            .map(|x| x.to_owned_table())
925    }
926}
927
928/// [Lookup Type 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable): Single Adjustment Positioning Subtable
929#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
930#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
931pub enum PairPos {
932    Format1(PairPosFormat1),
933    Format2(PairPosFormat2),
934}
935
936impl PairPos {
937    /// Construct a new `PairPosFormat1` subtable
938    pub fn format_1(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self {
939        Self::Format1(PairPosFormat1::new(coverage, pair_sets))
940    }
941
942    /// Construct a new `PairPosFormat2` subtable
943    pub fn format_2(
944        coverage: CoverageTable,
945        class_def1: ClassDef,
946        class_def2: ClassDef,
947        class1_records: Vec<Class1Record>,
948    ) -> Self {
949        Self::Format2(PairPosFormat2::new(
950            coverage,
951            class_def1,
952            class_def2,
953            class1_records,
954        ))
955    }
956}
957
958impl Default for PairPos {
959    fn default() -> Self {
960        Self::Format1(Default::default())
961    }
962}
963
964impl FontWrite for PairPos {
965    fn write_into(&self, writer: &mut TableWriter) {
966        match self {
967            Self::Format1(item) => item.write_into(writer),
968            Self::Format2(item) => item.write_into(writer),
969        }
970    }
971    fn table_type(&self) -> TableType {
972        match self {
973            Self::Format1(item) => item.table_type(),
974            Self::Format2(item) => item.table_type(),
975        }
976    }
977}
978
979impl Validate for PairPos {
980    fn validate_impl(&self, ctx: &mut ValidationCtx) {
981        match self {
982            Self::Format1(item) => item.validate_impl(ctx),
983            Self::Format2(item) => item.validate_impl(ctx),
984        }
985    }
986}
987
988impl FromObjRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {
989    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPos, _: FontData) -> Self {
990        use read_fonts::tables::gpos::PairPos as ObjRefType;
991        match obj {
992            ObjRefType::Format1(item) => PairPos::Format1(item.to_owned_table()),
993            ObjRefType::Format2(item) => PairPos::Format2(item.to_owned_table()),
994        }
995    }
996}
997
998impl FromTableRef<read_fonts::tables::gpos::PairPos<'_>> for PairPos {}
999
1000impl ReadArgs for PairPos {
1001    type Args = ();
1002}
1003
1004impl<'a> FontRead<'a> for PairPos {
1005    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1006        <read_fonts::tables::gpos::PairPos as FontRead>::read(data).map(|x| x.to_owned_table())
1007    }
1008}
1009
1010impl From<PairPosFormat1> for PairPos {
1011    fn from(src: PairPosFormat1) -> PairPos {
1012        PairPos::Format1(src)
1013    }
1014}
1015
1016impl From<PairPosFormat2> for PairPos {
1017    fn from(src: PairPosFormat2) -> PairPos {
1018        PairPos::Format2(src)
1019    }
1020}
1021
1022/// [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
1023#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1024#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1025pub struct PairPosFormat1 {
1026    /// Offset to Coverage table, from beginning of PairPos subtable.
1027    pub coverage: OffsetMarker<CoverageTable>,
1028    /// Array of offsets to PairSet tables. Offsets are from beginning
1029    /// of PairPos subtable, ordered by Coverage Index.
1030    pub pair_sets: Vec<OffsetMarker<PairSet>>,
1031}
1032
1033impl PairPosFormat1 {
1034    /// Construct a new `PairPosFormat1`
1035    pub fn new(coverage: CoverageTable, pair_sets: Vec<PairSet>) -> Self {
1036        Self {
1037            coverage: coverage.into(),
1038            pair_sets: pair_sets.into_iter().map(Into::into).collect(),
1039        }
1040    }
1041}
1042
1043impl FontWrite for PairPosFormat1 {
1044    #[allow(clippy::unnecessary_cast)]
1045    fn write_into(&self, writer: &mut TableWriter) {
1046        (1 as u16).write_into(writer);
1047        self.coverage.write_into(writer);
1048        (self.compute_value_format1() as ValueFormat).write_into(writer);
1049        (self.compute_value_format2() as ValueFormat).write_into(writer);
1050        (u16::try_from(array_len(&self.pair_sets)).unwrap()).write_into(writer);
1051        self.pair_sets.write_into(writer);
1052    }
1053    fn table_type(&self) -> TableType {
1054        TableType::Named("PairPosFormat1")
1055    }
1056}
1057
1058impl Validate for PairPosFormat1 {
1059    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1060        ctx.in_table("PairPosFormat1", |ctx| {
1061            ctx.in_field("coverage", |ctx| {
1062                self.coverage.validate_impl(ctx);
1063            });
1064            ctx.in_field("pair_sets", |ctx| {
1065                if self.pair_sets.len() > to_usize(u16::MAX) {
1066                    ctx.report("array exceeds max length");
1067                }
1068                self.check_format_consistency(ctx);
1069            });
1070        })
1071    }
1072}
1073
1074impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {
1075    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat1<'a>, _: FontData) -> Self {
1076        PairPosFormat1 {
1077            coverage: obj.coverage().to_owned_table(),
1078            pair_sets: obj.pair_sets().to_owned_table(),
1079        }
1080    }
1081}
1082
1083#[allow(clippy::needless_lifetimes)]
1084impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat1<'a>> for PairPosFormat1 {}
1085
1086impl ReadArgs for PairPosFormat1 {
1087    type Args = ();
1088}
1089
1090impl<'a> FontRead<'a> for PairPosFormat1 {
1091    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1092        <read_fonts::tables::gpos::PairPosFormat1 as FontRead>::read(data)
1093            .map(|x| x.to_owned_table())
1094    }
1095}
1096
1097/// Part of [PairPosFormat1]
1098#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1099#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1100pub struct PairSet {
1101    /// Array of PairValueRecords, ordered by glyph ID of the second
1102    /// glyph.
1103    pub pair_value_records: Vec<PairValueRecord>,
1104}
1105
1106impl PairSet {
1107    /// Construct a new `PairSet`
1108    pub fn new(pair_value_records: Vec<PairValueRecord>) -> Self {
1109        Self { pair_value_records }
1110    }
1111}
1112
1113impl FontWrite for PairSet {
1114    #[allow(clippy::unnecessary_cast)]
1115    fn write_into(&self, writer: &mut TableWriter) {
1116        (u16::try_from(array_len(&self.pair_value_records)).unwrap()).write_into(writer);
1117        self.pair_value_records.write_into(writer);
1118    }
1119    fn table_type(&self) -> TableType {
1120        TableType::Named("PairSet")
1121    }
1122}
1123
1124impl Validate for PairSet {
1125    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1126        ctx.in_table("PairSet", |ctx| {
1127            ctx.in_field("pair_value_records", |ctx| {
1128                if self.pair_value_records.len() > to_usize(u16::MAX) {
1129                    ctx.report("array exceeds max length");
1130                }
1131                self.pair_value_records.validate_impl(ctx);
1132            });
1133        })
1134    }
1135}
1136
1137impl<'a> FromObjRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {
1138    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairSet<'a>, _: FontData) -> Self {
1139        let offset_data = obj.offset_data();
1140        PairSet {
1141            pair_value_records: obj
1142                .pair_value_records()
1143                .iter()
1144                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1145                .collect(),
1146        }
1147    }
1148}
1149
1150#[allow(clippy::needless_lifetimes)]
1151impl<'a> FromTableRef<read_fonts::tables::gpos::PairSet<'a>> for PairSet {}
1152
1153/// Part of [PairSet]
1154#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1155#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1156pub struct PairValueRecord {
1157    /// Glyph ID of second glyph in the pair (first glyph is listed in
1158    /// the Coverage table).
1159    pub second_glyph: GlyphId16,
1160    /// Positioning data for the first glyph in the pair.
1161    pub value_record1: ValueRecord,
1162    /// Positioning data for the second glyph in the pair.
1163    pub value_record2: ValueRecord,
1164}
1165
1166impl PairValueRecord {
1167    /// Construct a new `PairValueRecord`
1168    pub fn new(
1169        second_glyph: GlyphId16,
1170        value_record1: ValueRecord,
1171        value_record2: ValueRecord,
1172    ) -> Self {
1173        Self {
1174            second_glyph,
1175            value_record1,
1176            value_record2,
1177        }
1178    }
1179}
1180
1181impl FontWrite for PairValueRecord {
1182    fn write_into(&self, writer: &mut TableWriter) {
1183        self.second_glyph.write_into(writer);
1184        self.value_record1.write_into(writer);
1185        self.value_record2.write_into(writer);
1186    }
1187    fn table_type(&self) -> TableType {
1188        TableType::Named("PairValueRecord")
1189    }
1190}
1191
1192impl Validate for PairValueRecord {
1193    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1194}
1195
1196impl FromObjRef<read_fonts::tables::gpos::PairValueRecord> for PairValueRecord {
1197    fn from_obj_ref(
1198        obj: &read_fonts::tables::gpos::PairValueRecord,
1199        offset_data: FontData,
1200    ) -> Self {
1201        PairValueRecord {
1202            second_glyph: obj.second_glyph(),
1203            value_record1: obj.value_record1().to_owned_obj(offset_data),
1204            value_record2: obj.value_record2().to_owned_obj(offset_data),
1205        }
1206    }
1207}
1208
1209/// [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
1210#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1211#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1212pub struct PairPosFormat2 {
1213    /// Offset to Coverage table, from beginning of PairPos subtable.
1214    pub coverage: OffsetMarker<CoverageTable>,
1215    /// Offset to ClassDef table, from beginning of PairPos subtable
1216    /// — for the first glyph of the pair.
1217    pub class_def1: OffsetMarker<ClassDef>,
1218    /// Offset to ClassDef table, from beginning of PairPos subtable
1219    /// — for the second glyph of the pair.
1220    pub class_def2: OffsetMarker<ClassDef>,
1221    /// Array of Class1 records, ordered by classes in classDef1.
1222    pub class1_records: Vec<Class1Record>,
1223}
1224
1225impl PairPosFormat2 {
1226    /// Construct a new `PairPosFormat2`
1227    pub fn new(
1228        coverage: CoverageTable,
1229        class_def1: ClassDef,
1230        class_def2: ClassDef,
1231        class1_records: Vec<Class1Record>,
1232    ) -> Self {
1233        Self {
1234            coverage: coverage.into(),
1235            class_def1: class_def1.into(),
1236            class_def2: class_def2.into(),
1237            class1_records,
1238        }
1239    }
1240}
1241
1242impl FontWrite for PairPosFormat2 {
1243    #[allow(clippy::unnecessary_cast)]
1244    fn write_into(&self, writer: &mut TableWriter) {
1245        (2 as u16).write_into(writer);
1246        self.coverage.write_into(writer);
1247        (self.compute_value_format1() as ValueFormat).write_into(writer);
1248        (self.compute_value_format2() as ValueFormat).write_into(writer);
1249        self.class_def1.write_into(writer);
1250        self.class_def2.write_into(writer);
1251        (self.compute_class1_count() as u16).write_into(writer);
1252        (self.compute_class2_count() as u16).write_into(writer);
1253        self.class1_records.write_into(writer);
1254    }
1255    fn table_type(&self) -> TableType {
1256        TableType::Named("PairPosFormat2")
1257    }
1258}
1259
1260impl Validate for PairPosFormat2 {
1261    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1262        ctx.in_table("PairPosFormat2", |ctx| {
1263            ctx.in_field("coverage", |ctx| {
1264                self.coverage.validate_impl(ctx);
1265            });
1266            ctx.in_field("class_def1", |ctx| {
1267                self.class_def1.validate_impl(ctx);
1268            });
1269            ctx.in_field("class_def2", |ctx| {
1270                self.class_def2.validate_impl(ctx);
1271            });
1272            ctx.in_field("class1_records", |ctx| {
1273                if self.class1_records.len() > to_usize(u16::MAX) {
1274                    ctx.report("array exceeds max length");
1275                }
1276                self.class1_records.validate_impl(ctx);
1277            });
1278            self.check_length_and_format_conformance(ctx);
1279        })
1280    }
1281}
1282
1283impl<'a> FromObjRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {
1284    fn from_obj_ref(obj: &read_fonts::tables::gpos::PairPosFormat2<'a>, _: FontData) -> Self {
1285        let offset_data = obj.offset_data();
1286        PairPosFormat2 {
1287            coverage: obj.coverage().to_owned_table(),
1288            class_def1: obj.class_def1().to_owned_table(),
1289            class_def2: obj.class_def2().to_owned_table(),
1290            class1_records: obj
1291                .class1_records()
1292                .iter()
1293                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1294                .collect(),
1295        }
1296    }
1297}
1298
1299#[allow(clippy::needless_lifetimes)]
1300impl<'a> FromTableRef<read_fonts::tables::gpos::PairPosFormat2<'a>> for PairPosFormat2 {}
1301
1302impl ReadArgs for PairPosFormat2 {
1303    type Args = ();
1304}
1305
1306impl<'a> FontRead<'a> for PairPosFormat2 {
1307    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1308        <read_fonts::tables::gpos::PairPosFormat2 as FontRead>::read(data)
1309            .map(|x| x.to_owned_table())
1310    }
1311}
1312
1313/// Part of [PairPosFormat2]
1314#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1315#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1316pub struct Class1Record {
1317    /// Array of Class2 records, ordered by classes in classDef2.
1318    pub class2_records: Vec<Class2Record>,
1319}
1320
1321impl Class1Record {
1322    /// Construct a new `Class1Record`
1323    pub fn new(class2_records: Vec<Class2Record>) -> Self {
1324        Self { class2_records }
1325    }
1326}
1327
1328impl FontWrite for Class1Record {
1329    fn write_into(&self, writer: &mut TableWriter) {
1330        self.class2_records.write_into(writer);
1331    }
1332    fn table_type(&self) -> TableType {
1333        TableType::Named("Class1Record")
1334    }
1335}
1336
1337impl Validate for Class1Record {
1338    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1339        ctx.in_table("Class1Record", |ctx| {
1340            ctx.in_field("class2_records", |ctx| {
1341                if self.class2_records.len() > to_usize(u16::MAX) {
1342                    ctx.report("array exceeds max length");
1343                }
1344                self.class2_records.validate_impl(ctx);
1345            });
1346        })
1347    }
1348}
1349
1350impl FromObjRef<read_fonts::tables::gpos::Class1Record<'_>> for Class1Record {
1351    fn from_obj_ref(obj: &read_fonts::tables::gpos::Class1Record, offset_data: FontData) -> Self {
1352        Class1Record {
1353            class2_records: obj
1354                .class2_records()
1355                .iter()
1356                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1357                .collect(),
1358        }
1359    }
1360}
1361
1362/// Part of [PairPosFormat2]
1363#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1364#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1365pub struct Class2Record {
1366    /// Positioning for first glyph — empty if valueFormat1 = 0.
1367    pub value_record1: ValueRecord,
1368    /// Positioning for second glyph — empty if valueFormat2 = 0.
1369    pub value_record2: ValueRecord,
1370}
1371
1372impl Class2Record {
1373    /// Construct a new `Class2Record`
1374    pub fn new(value_record1: ValueRecord, value_record2: ValueRecord) -> Self {
1375        Self {
1376            value_record1,
1377            value_record2,
1378        }
1379    }
1380}
1381
1382impl FontWrite for Class2Record {
1383    fn write_into(&self, writer: &mut TableWriter) {
1384        self.value_record1.write_into(writer);
1385        self.value_record2.write_into(writer);
1386    }
1387    fn table_type(&self) -> TableType {
1388        TableType::Named("Class2Record")
1389    }
1390}
1391
1392impl Validate for Class2Record {
1393    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1394}
1395
1396impl FromObjRef<read_fonts::tables::gpos::Class2Record> for Class2Record {
1397    fn from_obj_ref(obj: &read_fonts::tables::gpos::Class2Record, offset_data: FontData) -> Self {
1398        Class2Record {
1399            value_record1: obj.value_record1().to_owned_obj(offset_data),
1400            value_record2: obj.value_record2().to_owned_obj(offset_data),
1401        }
1402    }
1403}
1404
1405/// [Cursive Attachment Positioning Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#cursive-attachment-positioning-format1-cursive-attachment): Cursvie attachment
1406#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1407#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1408pub struct CursivePosFormat1 {
1409    /// Offset to Coverage table, from beginning of CursivePos subtable.
1410    pub coverage: OffsetMarker<CoverageTable>,
1411    /// Array of EntryExit records, in Coverage index order.
1412    pub entry_exit_record: Vec<EntryExitRecord>,
1413}
1414
1415impl CursivePosFormat1 {
1416    /// Construct a new `CursivePosFormat1`
1417    pub fn new(coverage: CoverageTable, entry_exit_record: Vec<EntryExitRecord>) -> Self {
1418        Self {
1419            coverage: coverage.into(),
1420            entry_exit_record,
1421        }
1422    }
1423}
1424
1425impl FontWrite for CursivePosFormat1 {
1426    #[allow(clippy::unnecessary_cast)]
1427    fn write_into(&self, writer: &mut TableWriter) {
1428        (1 as u16).write_into(writer);
1429        self.coverage.write_into(writer);
1430        (u16::try_from(array_len(&self.entry_exit_record)).unwrap()).write_into(writer);
1431        self.entry_exit_record.write_into(writer);
1432    }
1433    fn table_type(&self) -> TableType {
1434        TableType::Named("CursivePosFormat1")
1435    }
1436}
1437
1438impl Validate for CursivePosFormat1 {
1439    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1440        ctx.in_table("CursivePosFormat1", |ctx| {
1441            ctx.in_field("coverage", |ctx| {
1442                self.coverage.validate_impl(ctx);
1443            });
1444            ctx.in_field("entry_exit_record", |ctx| {
1445                if self.entry_exit_record.len() > to_usize(u16::MAX) {
1446                    ctx.report("array exceeds max length");
1447                }
1448                self.entry_exit_record.validate_impl(ctx);
1449            });
1450        })
1451    }
1452}
1453
1454impl<'a> FromObjRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {
1455    fn from_obj_ref(obj: &read_fonts::tables::gpos::CursivePosFormat1<'a>, _: FontData) -> Self {
1456        let offset_data = obj.offset_data();
1457        CursivePosFormat1 {
1458            coverage: obj.coverage().to_owned_table(),
1459            entry_exit_record: obj.entry_exit_record().to_owned_obj(offset_data),
1460        }
1461    }
1462}
1463
1464#[allow(clippy::needless_lifetimes)]
1465impl<'a> FromTableRef<read_fonts::tables::gpos::CursivePosFormat1<'a>> for CursivePosFormat1 {}
1466
1467impl ReadArgs for CursivePosFormat1 {
1468    type Args = ();
1469}
1470
1471impl<'a> FontRead<'a> for CursivePosFormat1 {
1472    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1473        <read_fonts::tables::gpos::CursivePosFormat1 as FontRead>::read(data)
1474            .map(|x| x.to_owned_table())
1475    }
1476}
1477
1478/// Part of [CursivePosFormat1]
1479#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1480#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1481pub struct EntryExitRecord {
1482    /// Offset to entryAnchor table, from beginning of CursivePos
1483    /// subtable (may be NULL).
1484    pub entry_anchor: NullableOffsetMarker<AnchorTable>,
1485    /// Offset to exitAnchor table, from beginning of CursivePos
1486    /// subtable (may be NULL).
1487    pub exit_anchor: NullableOffsetMarker<AnchorTable>,
1488}
1489
1490impl EntryExitRecord {
1491    /// Construct a new `EntryExitRecord`
1492    pub fn new(entry_anchor: Option<AnchorTable>, exit_anchor: Option<AnchorTable>) -> Self {
1493        Self {
1494            entry_anchor: entry_anchor.into(),
1495            exit_anchor: exit_anchor.into(),
1496        }
1497    }
1498}
1499
1500impl FontWrite for EntryExitRecord {
1501    fn write_into(&self, writer: &mut TableWriter) {
1502        self.entry_anchor.write_into(writer);
1503        self.exit_anchor.write_into(writer);
1504    }
1505    fn table_type(&self) -> TableType {
1506        TableType::Named("EntryExitRecord")
1507    }
1508}
1509
1510impl Validate for EntryExitRecord {
1511    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1512        ctx.in_table("EntryExitRecord", |ctx| {
1513            ctx.in_field("entry_anchor", |ctx| {
1514                self.entry_anchor.validate_impl(ctx);
1515            });
1516            ctx.in_field("exit_anchor", |ctx| {
1517                self.exit_anchor.validate_impl(ctx);
1518            });
1519        })
1520    }
1521}
1522
1523impl FromObjRef<read_fonts::tables::gpos::EntryExitRecord> for EntryExitRecord {
1524    fn from_obj_ref(
1525        obj: &read_fonts::tables::gpos::EntryExitRecord,
1526        offset_data: FontData,
1527    ) -> Self {
1528        EntryExitRecord {
1529            entry_anchor: obj.entry_anchor(offset_data).to_owned_table(),
1530            exit_anchor: obj.exit_anchor(offset_data).to_owned_table(),
1531        }
1532    }
1533}
1534
1535/// [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
1536#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1537#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1538pub struct MarkBasePosFormat1 {
1539    /// Offset to markCoverage table, from beginning of MarkBasePos
1540    /// subtable.
1541    pub mark_coverage: OffsetMarker<CoverageTable>,
1542    /// Offset to baseCoverage table, from beginning of MarkBasePos
1543    /// subtable.
1544    pub base_coverage: OffsetMarker<CoverageTable>,
1545    /// Offset to MarkArray table, from beginning of MarkBasePos
1546    /// subtable.
1547    pub mark_array: OffsetMarker<MarkArray>,
1548    /// Offset to BaseArray table, from beginning of MarkBasePos
1549    /// subtable.
1550    pub base_array: OffsetMarker<BaseArray>,
1551}
1552
1553impl MarkBasePosFormat1 {
1554    /// Construct a new `MarkBasePosFormat1`
1555    pub fn new(
1556        mark_coverage: CoverageTable,
1557        base_coverage: CoverageTable,
1558        mark_array: MarkArray,
1559        base_array: BaseArray,
1560    ) -> Self {
1561        Self {
1562            mark_coverage: mark_coverage.into(),
1563            base_coverage: base_coverage.into(),
1564            mark_array: mark_array.into(),
1565            base_array: base_array.into(),
1566        }
1567    }
1568}
1569
1570impl FontWrite for MarkBasePosFormat1 {
1571    #[allow(clippy::unnecessary_cast)]
1572    fn write_into(&self, writer: &mut TableWriter) {
1573        (1 as u16).write_into(writer);
1574        self.mark_coverage.write_into(writer);
1575        self.base_coverage.write_into(writer);
1576        (self.compute_mark_class_count() as u16).write_into(writer);
1577        self.mark_array.write_into(writer);
1578        self.base_array.write_into(writer);
1579    }
1580    fn table_type(&self) -> TableType {
1581        TableType::Named("MarkBasePosFormat1")
1582    }
1583}
1584
1585impl Validate for MarkBasePosFormat1 {
1586    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1587        ctx.in_table("MarkBasePosFormat1", |ctx| {
1588            ctx.in_field("mark_coverage", |ctx| {
1589                self.mark_coverage.validate_impl(ctx);
1590            });
1591            ctx.in_field("base_coverage", |ctx| {
1592                self.base_coverage.validate_impl(ctx);
1593            });
1594            ctx.in_field("mark_array", |ctx| {
1595                self.mark_array.validate_impl(ctx);
1596            });
1597            ctx.in_field("base_array", |ctx| {
1598                self.base_array.validate_impl(ctx);
1599            });
1600        })
1601    }
1602}
1603
1604impl<'a> FromObjRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {
1605    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkBasePosFormat1<'a>, _: FontData) -> Self {
1606        MarkBasePosFormat1 {
1607            mark_coverage: obj.mark_coverage().to_owned_table(),
1608            base_coverage: obj.base_coverage().to_owned_table(),
1609            mark_array: obj.mark_array().to_owned_table(),
1610            base_array: obj.base_array().to_owned_table(),
1611        }
1612    }
1613}
1614
1615#[allow(clippy::needless_lifetimes)]
1616impl<'a> FromTableRef<read_fonts::tables::gpos::MarkBasePosFormat1<'a>> for MarkBasePosFormat1 {}
1617
1618impl ReadArgs for MarkBasePosFormat1 {
1619    type Args = ();
1620}
1621
1622impl<'a> FontRead<'a> for MarkBasePosFormat1 {
1623    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1624        <read_fonts::tables::gpos::MarkBasePosFormat1 as FontRead>::read(data)
1625            .map(|x| x.to_owned_table())
1626    }
1627}
1628
1629/// Part of [MarkBasePosFormat1]
1630#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1631#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1632pub struct BaseArray {
1633    /// Array of BaseRecords, in order of baseCoverage Index.
1634    pub base_records: Vec<BaseRecord>,
1635}
1636
1637impl BaseArray {
1638    /// Construct a new `BaseArray`
1639    pub fn new(base_records: Vec<BaseRecord>) -> Self {
1640        Self { base_records }
1641    }
1642}
1643
1644impl FontWrite for BaseArray {
1645    #[allow(clippy::unnecessary_cast)]
1646    fn write_into(&self, writer: &mut TableWriter) {
1647        (u16::try_from(array_len(&self.base_records)).unwrap()).write_into(writer);
1648        self.base_records.write_into(writer);
1649    }
1650    fn table_type(&self) -> TableType {
1651        TableType::Named("BaseArray")
1652    }
1653}
1654
1655impl Validate for BaseArray {
1656    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1657        ctx.in_table("BaseArray", |ctx| {
1658            ctx.in_field("base_records", |ctx| {
1659                if self.base_records.len() > to_usize(u16::MAX) {
1660                    ctx.report("array exceeds max length");
1661                }
1662                self.base_records.validate_impl(ctx);
1663            });
1664        })
1665    }
1666}
1667
1668impl<'a> FromObjRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {
1669    fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseArray<'a>, _: FontData) -> Self {
1670        let offset_data = obj.offset_data();
1671        BaseArray {
1672            base_records: obj
1673                .base_records()
1674                .iter()
1675                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1676                .collect(),
1677        }
1678    }
1679}
1680
1681#[allow(clippy::needless_lifetimes)]
1682impl<'a> FromTableRef<read_fonts::tables::gpos::BaseArray<'a>> for BaseArray {}
1683
1684/// Part of [BaseArray]
1685#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1686#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1687pub struct BaseRecord {
1688    /// Array of offsets (one per mark class) to Anchor tables. Offsets
1689    /// are from beginning of BaseArray table, ordered by class
1690    /// (offsets may be NULL).
1691    pub base_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
1692}
1693
1694impl BaseRecord {
1695    /// Construct a new `BaseRecord`
1696    pub fn new(base_anchors: Vec<Option<AnchorTable>>) -> Self {
1697        Self {
1698            base_anchors: base_anchors.into_iter().map(Into::into).collect(),
1699        }
1700    }
1701}
1702
1703impl FontWrite for BaseRecord {
1704    fn write_into(&self, writer: &mut TableWriter) {
1705        self.base_anchors.write_into(writer);
1706    }
1707    fn table_type(&self) -> TableType {
1708        TableType::Named("BaseRecord")
1709    }
1710}
1711
1712impl Validate for BaseRecord {
1713    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1714        ctx.in_table("BaseRecord", |ctx| {
1715            ctx.in_field("base_anchors", |ctx| {
1716                if self.base_anchors.len() > to_usize(u16::MAX) {
1717                    ctx.report("array exceeds max length");
1718                }
1719                self.base_anchors.validate_impl(ctx);
1720            });
1721        })
1722    }
1723}
1724
1725impl FromObjRef<read_fonts::tables::gpos::BaseRecord<'_>> for BaseRecord {
1726    fn from_obj_ref(obj: &read_fonts::tables::gpos::BaseRecord, offset_data: FontData) -> Self {
1727        BaseRecord {
1728            base_anchors: obj.base_anchors(offset_data).to_owned_table(),
1729        }
1730    }
1731}
1732
1733/// [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
1734#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1735#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1736pub struct MarkLigPosFormat1 {
1737    /// Offset to markCoverage table, from beginning of MarkLigPos
1738    /// subtable.
1739    pub mark_coverage: OffsetMarker<CoverageTable>,
1740    /// Offset to ligatureCoverage table, from beginning of MarkLigPos
1741    /// subtable.
1742    pub ligature_coverage: OffsetMarker<CoverageTable>,
1743    /// Offset to MarkArray table, from beginning of MarkLigPos
1744    /// subtable.
1745    pub mark_array: OffsetMarker<MarkArray>,
1746    /// Offset to LigatureArray table, from beginning of MarkLigPos
1747    /// subtable.
1748    pub ligature_array: OffsetMarker<LigatureArray>,
1749}
1750
1751impl MarkLigPosFormat1 {
1752    /// Construct a new `MarkLigPosFormat1`
1753    pub fn new(
1754        mark_coverage: CoverageTable,
1755        ligature_coverage: CoverageTable,
1756        mark_array: MarkArray,
1757        ligature_array: LigatureArray,
1758    ) -> Self {
1759        Self {
1760            mark_coverage: mark_coverage.into(),
1761            ligature_coverage: ligature_coverage.into(),
1762            mark_array: mark_array.into(),
1763            ligature_array: ligature_array.into(),
1764        }
1765    }
1766}
1767
1768impl FontWrite for MarkLigPosFormat1 {
1769    #[allow(clippy::unnecessary_cast)]
1770    fn write_into(&self, writer: &mut TableWriter) {
1771        (1 as u16).write_into(writer);
1772        self.mark_coverage.write_into(writer);
1773        self.ligature_coverage.write_into(writer);
1774        (self.compute_mark_class_count() as u16).write_into(writer);
1775        self.mark_array.write_into(writer);
1776        self.ligature_array.write_into(writer);
1777    }
1778    fn table_type(&self) -> TableType {
1779        TableType::Named("MarkLigPosFormat1")
1780    }
1781}
1782
1783impl Validate for MarkLigPosFormat1 {
1784    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1785        ctx.in_table("MarkLigPosFormat1", |ctx| {
1786            ctx.in_field("mark_coverage", |ctx| {
1787                self.mark_coverage.validate_impl(ctx);
1788            });
1789            ctx.in_field("ligature_coverage", |ctx| {
1790                self.ligature_coverage.validate_impl(ctx);
1791            });
1792            ctx.in_field("mark_array", |ctx| {
1793                self.mark_array.validate_impl(ctx);
1794            });
1795            ctx.in_field("ligature_array", |ctx| {
1796                self.ligature_array.validate_impl(ctx);
1797            });
1798        })
1799    }
1800}
1801
1802impl<'a> FromObjRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {
1803    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkLigPosFormat1<'a>, _: FontData) -> Self {
1804        MarkLigPosFormat1 {
1805            mark_coverage: obj.mark_coverage().to_owned_table(),
1806            ligature_coverage: obj.ligature_coverage().to_owned_table(),
1807            mark_array: obj.mark_array().to_owned_table(),
1808            ligature_array: obj.ligature_array().to_owned_table(),
1809        }
1810    }
1811}
1812
1813#[allow(clippy::needless_lifetimes)]
1814impl<'a> FromTableRef<read_fonts::tables::gpos::MarkLigPosFormat1<'a>> for MarkLigPosFormat1 {}
1815
1816impl ReadArgs for MarkLigPosFormat1 {
1817    type Args = ();
1818}
1819
1820impl<'a> FontRead<'a> for MarkLigPosFormat1 {
1821    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1822        <read_fonts::tables::gpos::MarkLigPosFormat1 as FontRead>::read(data)
1823            .map(|x| x.to_owned_table())
1824    }
1825}
1826
1827/// Part of [MarkLigPosFormat1]
1828#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1829#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1830pub struct LigatureArray {
1831    /// Array of offsets to LigatureAttach tables. Offsets are from
1832    /// beginning of LigatureArray table, ordered by ligatureCoverage
1833    /// index.
1834    pub ligature_attaches: Vec<OffsetMarker<LigatureAttach>>,
1835}
1836
1837impl LigatureArray {
1838    /// Construct a new `LigatureArray`
1839    pub fn new(ligature_attaches: Vec<LigatureAttach>) -> Self {
1840        Self {
1841            ligature_attaches: ligature_attaches.into_iter().map(Into::into).collect(),
1842        }
1843    }
1844}
1845
1846impl FontWrite for LigatureArray {
1847    #[allow(clippy::unnecessary_cast)]
1848    fn write_into(&self, writer: &mut TableWriter) {
1849        (u16::try_from(array_len(&self.ligature_attaches)).unwrap()).write_into(writer);
1850        self.ligature_attaches.write_into(writer);
1851    }
1852    fn table_type(&self) -> TableType {
1853        TableType::Named("LigatureArray")
1854    }
1855}
1856
1857impl Validate for LigatureArray {
1858    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1859        ctx.in_table("LigatureArray", |ctx| {
1860            ctx.in_field("ligature_attaches", |ctx| {
1861                if self.ligature_attaches.len() > to_usize(u16::MAX) {
1862                    ctx.report("array exceeds max length");
1863                }
1864                self.ligature_attaches.validate_impl(ctx);
1865            });
1866        })
1867    }
1868}
1869
1870impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {
1871    fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureArray<'a>, _: FontData) -> Self {
1872        LigatureArray {
1873            ligature_attaches: obj.ligature_attaches().to_owned_table(),
1874        }
1875    }
1876}
1877
1878#[allow(clippy::needless_lifetimes)]
1879impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureArray<'a>> for LigatureArray {}
1880
1881/// Part of [MarkLigPosFormat1]
1882#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1883#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1884pub struct LigatureAttach {
1885    /// Array of Component records, ordered in writing direction.
1886    pub component_records: Vec<ComponentRecord>,
1887}
1888
1889impl LigatureAttach {
1890    /// Construct a new `LigatureAttach`
1891    pub fn new(component_records: Vec<ComponentRecord>) -> Self {
1892        Self { component_records }
1893    }
1894}
1895
1896impl FontWrite for LigatureAttach {
1897    #[allow(clippy::unnecessary_cast)]
1898    fn write_into(&self, writer: &mut TableWriter) {
1899        (u16::try_from(array_len(&self.component_records)).unwrap()).write_into(writer);
1900        self.component_records.write_into(writer);
1901    }
1902    fn table_type(&self) -> TableType {
1903        TableType::Named("LigatureAttach")
1904    }
1905}
1906
1907impl Validate for LigatureAttach {
1908    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1909        ctx.in_table("LigatureAttach", |ctx| {
1910            ctx.in_field("component_records", |ctx| {
1911                if self.component_records.len() > to_usize(u16::MAX) {
1912                    ctx.report("array exceeds max length");
1913                }
1914                self.component_records.validate_impl(ctx);
1915            });
1916        })
1917    }
1918}
1919
1920impl<'a> FromObjRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {
1921    fn from_obj_ref(obj: &read_fonts::tables::gpos::LigatureAttach<'a>, _: FontData) -> Self {
1922        let offset_data = obj.offset_data();
1923        LigatureAttach {
1924            component_records: obj
1925                .component_records()
1926                .iter()
1927                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
1928                .collect(),
1929        }
1930    }
1931}
1932
1933#[allow(clippy::needless_lifetimes)]
1934impl<'a> FromTableRef<read_fonts::tables::gpos::LigatureAttach<'a>> for LigatureAttach {}
1935
1936/// Part of [MarkLigPosFormat1]
1937#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1938#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1939pub struct ComponentRecord {
1940    /// Array of offsets (one per class) to Anchor tables. Offsets are
1941    /// from beginning of LigatureAttach table, ordered by class
1942    /// (offsets may be NULL).
1943    pub ligature_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
1944}
1945
1946impl ComponentRecord {
1947    /// Construct a new `ComponentRecord`
1948    pub fn new(ligature_anchors: Vec<Option<AnchorTable>>) -> Self {
1949        Self {
1950            ligature_anchors: ligature_anchors.into_iter().map(Into::into).collect(),
1951        }
1952    }
1953}
1954
1955impl FontWrite for ComponentRecord {
1956    fn write_into(&self, writer: &mut TableWriter) {
1957        self.ligature_anchors.write_into(writer);
1958    }
1959    fn table_type(&self) -> TableType {
1960        TableType::Named("ComponentRecord")
1961    }
1962}
1963
1964impl Validate for ComponentRecord {
1965    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1966        ctx.in_table("ComponentRecord", |ctx| {
1967            ctx.in_field("ligature_anchors", |ctx| {
1968                if self.ligature_anchors.len() > to_usize(u16::MAX) {
1969                    ctx.report("array exceeds max length");
1970                }
1971                self.ligature_anchors.validate_impl(ctx);
1972            });
1973        })
1974    }
1975}
1976
1977impl FromObjRef<read_fonts::tables::gpos::ComponentRecord<'_>> for ComponentRecord {
1978    fn from_obj_ref(
1979        obj: &read_fonts::tables::gpos::ComponentRecord,
1980        offset_data: FontData,
1981    ) -> Self {
1982        ComponentRecord {
1983            ligature_anchors: obj.ligature_anchors(offset_data).to_owned_table(),
1984        }
1985    }
1986}
1987
1988/// [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
1989#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1990#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1991pub struct MarkMarkPosFormat1 {
1992    /// Offset to Combining Mark Coverage table, from beginning of
1993    /// MarkMarkPos subtable.
1994    pub mark1_coverage: OffsetMarker<CoverageTable>,
1995    /// Offset to Base Mark Coverage table, from beginning of
1996    /// MarkMarkPos subtable.
1997    pub mark2_coverage: OffsetMarker<CoverageTable>,
1998    /// Offset to MarkArray table for mark1, from beginning of
1999    /// MarkMarkPos subtable.
2000    pub mark1_array: OffsetMarker<MarkArray>,
2001    /// Offset to Mark2Array table for mark2, from beginning of
2002    /// MarkMarkPos subtable.
2003    pub mark2_array: OffsetMarker<Mark2Array>,
2004}
2005
2006impl MarkMarkPosFormat1 {
2007    /// Construct a new `MarkMarkPosFormat1`
2008    pub fn new(
2009        mark1_coverage: CoverageTable,
2010        mark2_coverage: CoverageTable,
2011        mark1_array: MarkArray,
2012        mark2_array: Mark2Array,
2013    ) -> Self {
2014        Self {
2015            mark1_coverage: mark1_coverage.into(),
2016            mark2_coverage: mark2_coverage.into(),
2017            mark1_array: mark1_array.into(),
2018            mark2_array: mark2_array.into(),
2019        }
2020    }
2021}
2022
2023impl FontWrite for MarkMarkPosFormat1 {
2024    #[allow(clippy::unnecessary_cast)]
2025    fn write_into(&self, writer: &mut TableWriter) {
2026        (1 as u16).write_into(writer);
2027        self.mark1_coverage.write_into(writer);
2028        self.mark2_coverage.write_into(writer);
2029        (self.compute_mark_class_count() as u16).write_into(writer);
2030        self.mark1_array.write_into(writer);
2031        self.mark2_array.write_into(writer);
2032    }
2033    fn table_type(&self) -> TableType {
2034        TableType::Named("MarkMarkPosFormat1")
2035    }
2036}
2037
2038impl Validate for MarkMarkPosFormat1 {
2039    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2040        ctx.in_table("MarkMarkPosFormat1", |ctx| {
2041            ctx.in_field("mark1_coverage", |ctx| {
2042                self.mark1_coverage.validate_impl(ctx);
2043            });
2044            ctx.in_field("mark2_coverage", |ctx| {
2045                self.mark2_coverage.validate_impl(ctx);
2046            });
2047            ctx.in_field("mark1_array", |ctx| {
2048                self.mark1_array.validate_impl(ctx);
2049            });
2050            ctx.in_field("mark2_array", |ctx| {
2051                self.mark2_array.validate_impl(ctx);
2052            });
2053        })
2054    }
2055}
2056
2057impl<'a> FromObjRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {
2058    fn from_obj_ref(obj: &read_fonts::tables::gpos::MarkMarkPosFormat1<'a>, _: FontData) -> Self {
2059        MarkMarkPosFormat1 {
2060            mark1_coverage: obj.mark1_coverage().to_owned_table(),
2061            mark2_coverage: obj.mark2_coverage().to_owned_table(),
2062            mark1_array: obj.mark1_array().to_owned_table(),
2063            mark2_array: obj.mark2_array().to_owned_table(),
2064        }
2065    }
2066}
2067
2068#[allow(clippy::needless_lifetimes)]
2069impl<'a> FromTableRef<read_fonts::tables::gpos::MarkMarkPosFormat1<'a>> for MarkMarkPosFormat1 {}
2070
2071impl ReadArgs for MarkMarkPosFormat1 {
2072    type Args = ();
2073}
2074
2075impl<'a> FontRead<'a> for MarkMarkPosFormat1 {
2076    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2077        <read_fonts::tables::gpos::MarkMarkPosFormat1 as FontRead>::read(data)
2078            .map(|x| x.to_owned_table())
2079    }
2080}
2081
2082/// Part of [MarkMarkPosFormat1]Class2Record
2083#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2084#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2085pub struct Mark2Array {
2086    /// Array of Mark2Records, in Coverage order.
2087    pub mark2_records: Vec<Mark2Record>,
2088}
2089
2090impl Mark2Array {
2091    /// Construct a new `Mark2Array`
2092    pub fn new(mark2_records: Vec<Mark2Record>) -> Self {
2093        Self { mark2_records }
2094    }
2095}
2096
2097impl FontWrite for Mark2Array {
2098    #[allow(clippy::unnecessary_cast)]
2099    fn write_into(&self, writer: &mut TableWriter) {
2100        (u16::try_from(array_len(&self.mark2_records)).unwrap()).write_into(writer);
2101        self.mark2_records.write_into(writer);
2102    }
2103    fn table_type(&self) -> TableType {
2104        TableType::Named("Mark2Array")
2105    }
2106}
2107
2108impl Validate for Mark2Array {
2109    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2110        ctx.in_table("Mark2Array", |ctx| {
2111            ctx.in_field("mark2_records", |ctx| {
2112                if self.mark2_records.len() > to_usize(u16::MAX) {
2113                    ctx.report("array exceeds max length");
2114                }
2115                self.mark2_records.validate_impl(ctx);
2116            });
2117        })
2118    }
2119}
2120
2121impl<'a> FromObjRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {
2122    fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Array<'a>, _: FontData) -> Self {
2123        let offset_data = obj.offset_data();
2124        Mark2Array {
2125            mark2_records: obj
2126                .mark2_records()
2127                .iter()
2128                .filter_map(|x| x.map(|x| FromObjRef::from_obj_ref(&x, offset_data)).ok())
2129                .collect(),
2130        }
2131    }
2132}
2133
2134#[allow(clippy::needless_lifetimes)]
2135impl<'a> FromTableRef<read_fonts::tables::gpos::Mark2Array<'a>> for Mark2Array {}
2136
2137/// Part of [MarkMarkPosFormat1]
2138#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2140pub struct Mark2Record {
2141    /// Array of offsets (one per class) to Anchor tables. Offsets are
2142    /// from beginning of Mark2Array table, in class order (offsets may
2143    /// be NULL).
2144    pub mark2_anchors: Vec<NullableOffsetMarker<AnchorTable>>,
2145}
2146
2147impl Mark2Record {
2148    /// Construct a new `Mark2Record`
2149    pub fn new(mark2_anchors: Vec<Option<AnchorTable>>) -> Self {
2150        Self {
2151            mark2_anchors: mark2_anchors.into_iter().map(Into::into).collect(),
2152        }
2153    }
2154}
2155
2156impl FontWrite for Mark2Record {
2157    fn write_into(&self, writer: &mut TableWriter) {
2158        self.mark2_anchors.write_into(writer);
2159    }
2160    fn table_type(&self) -> TableType {
2161        TableType::Named("Mark2Record")
2162    }
2163}
2164
2165impl Validate for Mark2Record {
2166    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2167        ctx.in_table("Mark2Record", |ctx| {
2168            ctx.in_field("mark2_anchors", |ctx| {
2169                if self.mark2_anchors.len() > to_usize(u16::MAX) {
2170                    ctx.report("array exceeds max length");
2171                }
2172                self.mark2_anchors.validate_impl(ctx);
2173            });
2174        })
2175    }
2176}
2177
2178impl FromObjRef<read_fonts::tables::gpos::Mark2Record<'_>> for Mark2Record {
2179    fn from_obj_ref(obj: &read_fonts::tables::gpos::Mark2Record, offset_data: FontData) -> Self {
2180        Mark2Record {
2181            mark2_anchors: obj.mark2_anchors(offset_data).to_owned_table(),
2182        }
2183    }
2184}
2185
2186/// [Extension Positioning Subtable Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#extension-positioning-subtable-format-1)
2187#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2189pub struct ExtensionPosFormat1<T> {
2190    /// Lookup type of subtable referenced by extensionOffset (i.e. the
2191    /// extension subtable).
2192    pub extension_lookup_type: u16,
2193    /// Offset to the extension subtable, of lookup type
2194    /// extensionLookupType, relative to the start of the
2195    /// ExtensionPosFormat1 subtable.
2196    pub extension: OffsetMarker<T, WIDTH_32>,
2197}
2198
2199impl<T: Default> ExtensionPosFormat1<T> {
2200    /// Construct a new `ExtensionPosFormat1`
2201    pub fn new(extension_lookup_type: u16, extension: T) -> Self {
2202        Self {
2203            extension_lookup_type,
2204            extension: extension.into(),
2205        }
2206    }
2207}
2208
2209impl<T: Validate> Validate for ExtensionPosFormat1<T> {
2210    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2211        ctx.in_table("ExtensionPosFormat1", |ctx| {
2212            ctx.in_field("extension", |ctx| {
2213                self.extension.validate_impl(ctx);
2214            });
2215        })
2216    }
2217}
2218
2219impl<'a, T, U> FromObjRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>>
2220    for ExtensionPosFormat1<T>
2221where
2222    U: FontRead<'a, Args = ()>,
2223    T: FromTableRef<U> + Default + 'static,
2224{
2225    fn from_obj_ref(
2226        obj: &read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>,
2227        _: FontData,
2228    ) -> Self {
2229        ExtensionPosFormat1 {
2230            extension_lookup_type: obj.extension_lookup_type(),
2231            extension: obj.extension().to_owned_table(),
2232        }
2233    }
2234}
2235
2236#[allow(clippy::needless_lifetimes)]
2237impl<'a, T, U> FromTableRef<read_fonts::tables::gpos::ExtensionPosFormat1<'a, U>>
2238    for ExtensionPosFormat1<T>
2239where
2240    U: FontRead<'a, Args = ()>,
2241    T: FromTableRef<U> + Default + 'static,
2242{
2243}
2244
2245/// A [GPOS Extension Positioning](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#lookuptype-9-extension-positioning) subtable
2246#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2248pub enum ExtensionSubtable {
2249    Single(ExtensionPosFormat1<SinglePos>),
2250    Pair(ExtensionPosFormat1<PairPos>),
2251    Cursive(ExtensionPosFormat1<CursivePosFormat1>),
2252    MarkToBase(ExtensionPosFormat1<MarkBasePosFormat1>),
2253    MarkToLig(ExtensionPosFormat1<MarkLigPosFormat1>),
2254    MarkToMark(ExtensionPosFormat1<MarkMarkPosFormat1>),
2255    Contextual(ExtensionPosFormat1<PositionSequenceContext>),
2256    ChainContextual(ExtensionPosFormat1<PositionChainContext>),
2257}
2258
2259impl Default for ExtensionSubtable {
2260    fn default() -> Self {
2261        Self::Single(Default::default())
2262    }
2263}
2264
2265impl FontWrite for ExtensionSubtable {
2266    fn write_into(&self, writer: &mut TableWriter) {
2267        match self {
2268            Self::Single(table) => table.write_into(writer),
2269            Self::Pair(table) => table.write_into(writer),
2270            Self::Cursive(table) => table.write_into(writer),
2271            Self::MarkToBase(table) => table.write_into(writer),
2272            Self::MarkToLig(table) => table.write_into(writer),
2273            Self::MarkToMark(table) => table.write_into(writer),
2274            Self::Contextual(table) => table.write_into(writer),
2275            Self::ChainContextual(table) => table.write_into(writer),
2276        }
2277    }
2278    fn table_type(&self) -> TableType {
2279        match self {
2280            Self::Single(table) => table.table_type(),
2281            Self::Pair(table) => table.table_type(),
2282            Self::Cursive(table) => table.table_type(),
2283            Self::MarkToBase(table) => table.table_type(),
2284            Self::MarkToLig(table) => table.table_type(),
2285            Self::MarkToMark(table) => table.table_type(),
2286            Self::Contextual(table) => table.table_type(),
2287            Self::ChainContextual(table) => table.table_type(),
2288        }
2289    }
2290}
2291
2292impl Validate for ExtensionSubtable {
2293    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2294        match self {
2295            Self::Single(table) => table.validate_impl(ctx),
2296            Self::Pair(table) => table.validate_impl(ctx),
2297            Self::Cursive(table) => table.validate_impl(ctx),
2298            Self::MarkToBase(table) => table.validate_impl(ctx),
2299            Self::MarkToLig(table) => table.validate_impl(ctx),
2300            Self::MarkToMark(table) => table.validate_impl(ctx),
2301            Self::Contextual(table) => table.validate_impl(ctx),
2302            Self::ChainContextual(table) => table.validate_impl(ctx),
2303        }
2304    }
2305}
2306
2307impl FromObjRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {
2308    fn from_obj_ref(
2309        from: &read_fonts::tables::gpos::ExtensionSubtable<'_>,
2310        data: FontData,
2311    ) -> Self {
2312        match from {
2313            read_fonts::tables::gpos::ExtensionSubtable::Single(table) => {
2314                Self::Single(table.to_owned_obj(data))
2315            }
2316            read_fonts::tables::gpos::ExtensionSubtable::Pair(table) => {
2317                Self::Pair(table.to_owned_obj(data))
2318            }
2319            read_fonts::tables::gpos::ExtensionSubtable::Cursive(table) => {
2320                Self::Cursive(table.to_owned_obj(data))
2321            }
2322            read_fonts::tables::gpos::ExtensionSubtable::MarkToBase(table) => {
2323                Self::MarkToBase(table.to_owned_obj(data))
2324            }
2325            read_fonts::tables::gpos::ExtensionSubtable::MarkToLig(table) => {
2326                Self::MarkToLig(table.to_owned_obj(data))
2327            }
2328            read_fonts::tables::gpos::ExtensionSubtable::MarkToMark(table) => {
2329                Self::MarkToMark(table.to_owned_obj(data))
2330            }
2331            read_fonts::tables::gpos::ExtensionSubtable::Contextual(table) => {
2332                Self::Contextual(table.to_owned_obj(data))
2333            }
2334            read_fonts::tables::gpos::ExtensionSubtable::ChainContextual(table) => {
2335                Self::ChainContextual(table.to_owned_obj(data))
2336            }
2337        }
2338    }
2339}
2340
2341impl FromTableRef<read_fonts::tables::gpos::ExtensionSubtable<'_>> for ExtensionSubtable {}
2342
2343impl From<ExtensionPosFormat1<SinglePos>> for ExtensionSubtable {
2344    fn from(src: ExtensionPosFormat1<SinglePos>) -> ExtensionSubtable {
2345        ExtensionSubtable::Single(src)
2346    }
2347}
2348
2349impl From<ExtensionPosFormat1<PairPos>> for ExtensionSubtable {
2350    fn from(src: ExtensionPosFormat1<PairPos>) -> ExtensionSubtable {
2351        ExtensionSubtable::Pair(src)
2352    }
2353}
2354
2355impl From<ExtensionPosFormat1<CursivePosFormat1>> for ExtensionSubtable {
2356    fn from(src: ExtensionPosFormat1<CursivePosFormat1>) -> ExtensionSubtable {
2357        ExtensionSubtable::Cursive(src)
2358    }
2359}
2360
2361impl From<ExtensionPosFormat1<MarkBasePosFormat1>> for ExtensionSubtable {
2362    fn from(src: ExtensionPosFormat1<MarkBasePosFormat1>) -> ExtensionSubtable {
2363        ExtensionSubtable::MarkToBase(src)
2364    }
2365}
2366
2367impl From<ExtensionPosFormat1<MarkLigPosFormat1>> for ExtensionSubtable {
2368    fn from(src: ExtensionPosFormat1<MarkLigPosFormat1>) -> ExtensionSubtable {
2369        ExtensionSubtable::MarkToLig(src)
2370    }
2371}
2372
2373impl From<ExtensionPosFormat1<MarkMarkPosFormat1>> for ExtensionSubtable {
2374    fn from(src: ExtensionPosFormat1<MarkMarkPosFormat1>) -> ExtensionSubtable {
2375        ExtensionSubtable::MarkToMark(src)
2376    }
2377}
2378
2379impl From<ExtensionPosFormat1<PositionSequenceContext>> for ExtensionSubtable {
2380    fn from(src: ExtensionPosFormat1<PositionSequenceContext>) -> ExtensionSubtable {
2381        ExtensionSubtable::Contextual(src)
2382    }
2383}
2384
2385impl From<ExtensionPosFormat1<PositionChainContext>> for ExtensionSubtable {
2386    fn from(src: ExtensionPosFormat1<PositionChainContext>) -> ExtensionSubtable {
2387        ExtensionSubtable::ChainContextual(src)
2388    }
2389}