Skip to main content

write_fonts/generated/
generated_layout.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::layout::DeltaFormat;
9
10/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
11#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct ScriptList {
14    /// Array of ScriptRecords, listed alphabetically by script tag
15    pub script_records: Vec<ScriptRecord>,
16}
17
18impl ScriptList {
19    /// Construct a new `ScriptList`
20    pub fn new(script_records: Vec<ScriptRecord>) -> Self {
21        Self { script_records }
22    }
23}
24
25impl FontWrite for ScriptList {
26    #[allow(clippy::unnecessary_cast)]
27    fn write_into(&self, writer: &mut TableWriter) {
28        (u16::try_from(array_len(&self.script_records)).unwrap()).write_into(writer);
29        self.script_records.write_into(writer);
30    }
31    fn table_type(&self) -> TableType {
32        TableType::Named("ScriptList")
33    }
34}
35
36impl Validate for ScriptList {
37    fn validate_impl(&self, ctx: &mut ValidationCtx) {
38        ctx.in_table("ScriptList", |ctx| {
39            ctx.in_field("script_records", |ctx| {
40                if self.script_records.len() > to_usize(u16::MAX) {
41                    ctx.report("array exceeds max length");
42                }
43                self.script_records.validate_impl(ctx);
44            });
45        })
46    }
47}
48
49impl<'a> FromObjRef<read_fonts::tables::layout::ScriptList<'a>> for ScriptList {
50    fn from_obj_ref(obj: &read_fonts::tables::layout::ScriptList<'a>, _: FontData) -> Self {
51        let offset_data = obj.offset_data();
52        ScriptList {
53            script_records: obj.script_records().to_owned_obj(offset_data),
54        }
55    }
56}
57
58#[allow(clippy::needless_lifetimes)]
59impl<'a> FromTableRef<read_fonts::tables::layout::ScriptList<'a>> for ScriptList {}
60
61impl ReadArgs for ScriptList {
62    type Args = ();
63}
64
65impl<'a> FontRead<'a> for ScriptList {
66    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
67        <read_fonts::tables::layout::ScriptList as FontRead>::read(data).map(|x| x.to_owned_table())
68    }
69}
70
71/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
72#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74pub struct ScriptRecord {
75    /// 4-byte script tag identifier
76    pub script_tag: Tag,
77    /// Offset to Script table, from beginning of ScriptList
78    pub script: OffsetMarker<Script>,
79}
80
81impl ScriptRecord {
82    /// Construct a new `ScriptRecord`
83    pub fn new(script_tag: Tag, script: Script) -> Self {
84        Self {
85            script_tag,
86            script: script.into(),
87        }
88    }
89}
90
91impl FontWrite for ScriptRecord {
92    fn write_into(&self, writer: &mut TableWriter) {
93        self.script_tag.write_into(writer);
94        self.script.write_into(writer);
95    }
96    fn table_type(&self) -> TableType {
97        TableType::Named("ScriptRecord")
98    }
99}
100
101impl Validate for ScriptRecord {
102    fn validate_impl(&self, ctx: &mut ValidationCtx) {
103        ctx.in_table("ScriptRecord", |ctx| {
104            ctx.in_field("script", |ctx| {
105                self.script.validate_impl(ctx);
106            });
107        })
108    }
109}
110
111impl FromObjRef<read_fonts::tables::layout::ScriptRecord> for ScriptRecord {
112    fn from_obj_ref(obj: &read_fonts::tables::layout::ScriptRecord, offset_data: FontData) -> Self {
113        ScriptRecord {
114            script_tag: obj.script_tag(),
115            script: obj.script(offset_data).to_owned_table(),
116        }
117    }
118}
119
120/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
121#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
123pub struct Script {
124    /// Offset to default LangSys table, from beginning of Script table
125    /// — may be NULL
126    pub default_lang_sys: NullableOffsetMarker<LangSys>,
127    /// Array of LangSysRecords, listed alphabetically by LangSys tag
128    pub lang_sys_records: Vec<LangSysRecord>,
129}
130
131impl Script {
132    /// Construct a new `Script`
133    pub fn new(default_lang_sys: Option<LangSys>, lang_sys_records: Vec<LangSysRecord>) -> Self {
134        Self {
135            default_lang_sys: default_lang_sys.into(),
136            lang_sys_records,
137        }
138    }
139}
140
141impl FontWrite for Script {
142    #[allow(clippy::unnecessary_cast)]
143    fn write_into(&self, writer: &mut TableWriter) {
144        self.default_lang_sys.write_into(writer);
145        (u16::try_from(array_len(&self.lang_sys_records)).unwrap()).write_into(writer);
146        self.lang_sys_records.write_into(writer);
147    }
148    fn table_type(&self) -> TableType {
149        TableType::Named("Script")
150    }
151}
152
153impl Validate for Script {
154    fn validate_impl(&self, ctx: &mut ValidationCtx) {
155        ctx.in_table("Script", |ctx| {
156            ctx.in_field("default_lang_sys", |ctx| {
157                self.default_lang_sys.validate_impl(ctx);
158            });
159            ctx.in_field("lang_sys_records", |ctx| {
160                if self.lang_sys_records.len() > to_usize(u16::MAX) {
161                    ctx.report("array exceeds max length");
162                }
163                self.lang_sys_records.validate_impl(ctx);
164            });
165        })
166    }
167}
168
169impl<'a> FromObjRef<read_fonts::tables::layout::Script<'a>> for Script {
170    fn from_obj_ref(obj: &read_fonts::tables::layout::Script<'a>, _: FontData) -> Self {
171        let offset_data = obj.offset_data();
172        Script {
173            default_lang_sys: obj.default_lang_sys().to_owned_table(),
174            lang_sys_records: obj.lang_sys_records().to_owned_obj(offset_data),
175        }
176    }
177}
178
179#[allow(clippy::needless_lifetimes)]
180impl<'a> FromTableRef<read_fonts::tables::layout::Script<'a>> for Script {}
181
182impl ReadArgs for Script {
183    type Args = ();
184}
185
186impl<'a> FontRead<'a> for Script {
187    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
188        <read_fonts::tables::layout::Script as FontRead>::read(data).map(|x| x.to_owned_table())
189    }
190}
191
192#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
193#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
194pub struct LangSysRecord {
195    /// 4-byte LangSysTag identifier
196    pub lang_sys_tag: Tag,
197    /// Offset to LangSys table, from beginning of Script table
198    pub lang_sys: OffsetMarker<LangSys>,
199}
200
201impl LangSysRecord {
202    /// Construct a new `LangSysRecord`
203    pub fn new(lang_sys_tag: Tag, lang_sys: LangSys) -> Self {
204        Self {
205            lang_sys_tag,
206            lang_sys: lang_sys.into(),
207        }
208    }
209}
210
211impl FontWrite for LangSysRecord {
212    fn write_into(&self, writer: &mut TableWriter) {
213        self.lang_sys_tag.write_into(writer);
214        self.lang_sys.write_into(writer);
215    }
216    fn table_type(&self) -> TableType {
217        TableType::Named("LangSysRecord")
218    }
219}
220
221impl Validate for LangSysRecord {
222    fn validate_impl(&self, ctx: &mut ValidationCtx) {
223        ctx.in_table("LangSysRecord", |ctx| {
224            ctx.in_field("lang_sys", |ctx| {
225                self.lang_sys.validate_impl(ctx);
226            });
227        })
228    }
229}
230
231impl FromObjRef<read_fonts::tables::layout::LangSysRecord> for LangSysRecord {
232    fn from_obj_ref(
233        obj: &read_fonts::tables::layout::LangSysRecord,
234        offset_data: FontData,
235    ) -> Self {
236        LangSysRecord {
237            lang_sys_tag: obj.lang_sys_tag(),
238            lang_sys: obj.lang_sys(offset_data).to_owned_table(),
239        }
240    }
241}
242
243/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
244#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
246pub struct LangSys {
247    /// Index of a feature required for this language system; if no
248    /// required features = 0xFFFF
249    pub required_feature_index: u16,
250    /// Array of indices into the FeatureList, in arbitrary order
251    pub feature_indices: Vec<u16>,
252}
253
254impl Default for LangSys {
255    fn default() -> Self {
256        Self {
257            required_feature_index: 0xFFFF,
258            feature_indices: Default::default(),
259        }
260    }
261}
262
263impl LangSys {
264    /// Construct a new `LangSys`
265    pub fn new(feature_indices: Vec<u16>) -> Self {
266        Self {
267            feature_indices,
268            ..Default::default()
269        }
270    }
271}
272
273impl FontWrite for LangSys {
274    #[allow(clippy::unnecessary_cast)]
275    fn write_into(&self, writer: &mut TableWriter) {
276        (0 as u16).write_into(writer);
277        self.required_feature_index.write_into(writer);
278        (u16::try_from(array_len(&self.feature_indices)).unwrap()).write_into(writer);
279        self.feature_indices.write_into(writer);
280    }
281    fn table_type(&self) -> TableType {
282        TableType::Named("LangSys")
283    }
284}
285
286impl Validate for LangSys {
287    fn validate_impl(&self, ctx: &mut ValidationCtx) {
288        ctx.in_table("LangSys", |ctx| {
289            ctx.in_field("feature_indices", |ctx| {
290                if self.feature_indices.len() > to_usize(u16::MAX) {
291                    ctx.report("array exceeds max length");
292                }
293            });
294        })
295    }
296}
297
298impl<'a> FromObjRef<read_fonts::tables::layout::LangSys<'a>> for LangSys {
299    fn from_obj_ref(obj: &read_fonts::tables::layout::LangSys<'a>, _: FontData) -> Self {
300        let offset_data = obj.offset_data();
301        LangSys {
302            required_feature_index: obj.required_feature_index(),
303            feature_indices: obj.feature_indices().to_owned_obj(offset_data),
304        }
305    }
306}
307
308#[allow(clippy::needless_lifetimes)]
309impl<'a> FromTableRef<read_fonts::tables::layout::LangSys<'a>> for LangSys {}
310
311impl ReadArgs for LangSys {
312    type Args = ();
313}
314
315impl<'a> FontRead<'a> for LangSys {
316    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
317        <read_fonts::tables::layout::LangSys as FontRead>::read(data).map(|x| x.to_owned_table())
318    }
319}
320
321/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
322#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
323#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
324pub struct FeatureList {
325    /// Array of FeatureRecords — zero-based (first feature has
326    /// FeatureIndex = 0), listed alphabetically by feature tag
327    pub feature_records: Vec<FeatureRecord>,
328}
329
330impl FeatureList {
331    /// Construct a new `FeatureList`
332    pub fn new(feature_records: Vec<FeatureRecord>) -> Self {
333        Self { feature_records }
334    }
335}
336
337impl FontWrite for FeatureList {
338    #[allow(clippy::unnecessary_cast)]
339    fn write_into(&self, writer: &mut TableWriter) {
340        (u16::try_from(array_len(&self.feature_records)).unwrap()).write_into(writer);
341        self.feature_records.write_into(writer);
342    }
343    fn table_type(&self) -> TableType {
344        TableType::Named("FeatureList")
345    }
346}
347
348impl Validate for FeatureList {
349    fn validate_impl(&self, ctx: &mut ValidationCtx) {
350        ctx.in_table("FeatureList", |ctx| {
351            ctx.in_field("feature_records", |ctx| {
352                if self.feature_records.len() > to_usize(u16::MAX) {
353                    ctx.report("array exceeds max length");
354                }
355                self.feature_records.validate_impl(ctx);
356            });
357        })
358    }
359}
360
361impl<'a> FromObjRef<read_fonts::tables::layout::FeatureList<'a>> for FeatureList {
362    fn from_obj_ref(obj: &read_fonts::tables::layout::FeatureList<'a>, _: FontData) -> Self {
363        let offset_data = obj.offset_data();
364        FeatureList {
365            feature_records: obj.feature_records().to_owned_obj(offset_data),
366        }
367    }
368}
369
370#[allow(clippy::needless_lifetimes)]
371impl<'a> FromTableRef<read_fonts::tables::layout::FeatureList<'a>> for FeatureList {}
372
373impl ReadArgs for FeatureList {
374    type Args = ();
375}
376
377impl<'a> FontRead<'a> for FeatureList {
378    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
379        <read_fonts::tables::layout::FeatureList as FontRead>::read(data)
380            .map(|x| x.to_owned_table())
381    }
382}
383
384/// Part of [FeatureList]
385#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
386#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
387pub struct FeatureRecord {
388    /// 4-byte feature identification tag
389    pub feature_tag: Tag,
390    /// Offset to Feature table, from beginning of FeatureList
391    pub feature: OffsetMarker<Feature>,
392}
393
394impl FeatureRecord {
395    /// Construct a new `FeatureRecord`
396    pub fn new(feature_tag: Tag, feature: Feature) -> Self {
397        Self {
398            feature_tag,
399            feature: feature.into(),
400        }
401    }
402}
403
404impl FontWrite for FeatureRecord {
405    fn write_into(&self, writer: &mut TableWriter) {
406        self.feature_tag.write_into(writer);
407        self.feature.write_into(writer);
408    }
409    fn table_type(&self) -> TableType {
410        TableType::Named("FeatureRecord")
411    }
412}
413
414impl Validate for FeatureRecord {
415    fn validate_impl(&self, ctx: &mut ValidationCtx) {
416        ctx.in_table("FeatureRecord", |ctx| {
417            ctx.in_field("feature", |ctx| {
418                self.feature.validate_impl(ctx);
419            });
420        })
421    }
422}
423
424impl FromObjRef<read_fonts::tables::layout::FeatureRecord> for FeatureRecord {
425    fn from_obj_ref(
426        obj: &read_fonts::tables::layout::FeatureRecord,
427        offset_data: FontData,
428    ) -> Self {
429        FeatureRecord {
430            feature_tag: obj.feature_tag(),
431            feature: obj.feature(offset_data).to_owned_table(),
432        }
433    }
434}
435
436/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
437#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct Feature {
440    /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
441    pub feature_params: NullableOffsetMarker<FeatureParams>,
442    /// Array of indices into the LookupList — zero-based (first
443    /// lookup is LookupListIndex = 0)
444    pub lookup_list_indices: Vec<u16>,
445}
446
447impl Feature {
448    /// Construct a new `Feature`
449    pub fn new(feature_params: Option<FeatureParams>, lookup_list_indices: Vec<u16>) -> Self {
450        Self {
451            feature_params: feature_params.into(),
452            lookup_list_indices,
453        }
454    }
455}
456
457impl FontWrite for Feature {
458    #[allow(clippy::unnecessary_cast)]
459    fn write_into(&self, writer: &mut TableWriter) {
460        self.feature_params.write_into(writer);
461        (u16::try_from(array_len(&self.lookup_list_indices)).unwrap()).write_into(writer);
462        self.lookup_list_indices.write_into(writer);
463    }
464    fn table_type(&self) -> TableType {
465        TableType::Named("Feature")
466    }
467}
468
469impl Validate for Feature {
470    fn validate_impl(&self, ctx: &mut ValidationCtx) {
471        ctx.in_table("Feature", |ctx| {
472            ctx.in_field("feature_params", |ctx| {
473                self.feature_params.validate_impl(ctx);
474            });
475            ctx.in_field("lookup_list_indices", |ctx| {
476                if self.lookup_list_indices.len() > to_usize(u16::MAX) {
477                    ctx.report("array exceeds max length");
478                }
479            });
480        })
481    }
482}
483
484impl<'a> FromObjRef<read_fonts::tables::layout::Feature<'a>> for Feature {
485    fn from_obj_ref(obj: &read_fonts::tables::layout::Feature<'a>, _: FontData) -> Self {
486        let offset_data = obj.offset_data();
487        Feature {
488            feature_params: obj.feature_params().to_owned_table(),
489            lookup_list_indices: obj.lookup_list_indices().to_owned_obj(offset_data),
490        }
491    }
492}
493
494#[allow(clippy::needless_lifetimes)]
495impl<'a> FromTableRef<read_fonts::tables::layout::Feature<'a>> for Feature {}
496
497/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
498#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
499#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
500pub struct LookupList<T> {
501    /// Array of offsets to Lookup tables, from beginning of LookupList
502    /// — zero based (first lookup is Lookup index = 0)
503    pub lookups: Vec<OffsetMarker<T>>,
504}
505
506impl<T: Default> LookupList<T> {
507    /// Construct a new `LookupList`
508    pub fn new(lookups: Vec<T>) -> Self {
509        Self {
510            lookups: lookups.into_iter().map(Into::into).collect(),
511        }
512    }
513}
514
515impl<T: FontWrite> FontWrite for LookupList<T> {
516    #[allow(clippy::unnecessary_cast)]
517    fn write_into(&self, writer: &mut TableWriter) {
518        (u16::try_from(array_len(&self.lookups)).unwrap()).write_into(writer);
519        self.lookups.write_into(writer);
520    }
521    fn table_type(&self) -> TableType {
522        TableType::Named("LookupList")
523    }
524}
525
526impl<T: Validate> Validate for LookupList<T> {
527    fn validate_impl(&self, ctx: &mut ValidationCtx) {
528        ctx.in_table("LookupList", |ctx| {
529            ctx.in_field("lookups", |ctx| {
530                if self.lookups.len() > to_usize(u16::MAX) {
531                    ctx.report("array exceeds max length");
532                }
533                self.lookups.validate_impl(ctx);
534            });
535        })
536    }
537}
538
539impl<'a, T, U> FromObjRef<read_fonts::tables::layout::LookupList<'a, U>> for LookupList<T>
540where
541    U: FontRead<'a, Args = ()>,
542    T: FromTableRef<U> + Default + 'static,
543{
544    fn from_obj_ref(obj: &read_fonts::tables::layout::LookupList<'a, U>, _: FontData) -> Self {
545        LookupList {
546            lookups: obj.lookups().to_owned_table(),
547        }
548    }
549}
550
551#[allow(clippy::needless_lifetimes)]
552impl<'a, T, U> FromTableRef<read_fonts::tables::layout::LookupList<'a, U>> for LookupList<T>
553where
554    U: FontRead<'a, Args = ()>,
555    T: FromTableRef<U> + Default + 'static,
556{
557}
558
559/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
560#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
561#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
562pub struct Lookup<T> {
563    /// Lookup qualifiers
564    pub lookup_flag: LookupFlag,
565    /// Array of offsets to lookup subtables, from beginning of Lookup
566    /// table
567    pub subtables: Vec<OffsetMarker<T>>,
568    /// Index (base 0) into GDEF mark glyph sets structure. This field
569    /// is only present if the USE_MARK_FILTERING_SET lookup flag is
570    /// set.
571    pub mark_filtering_set: Option<u16>,
572}
573
574impl<T: Default> Lookup<T> {
575    /// Construct a new `Lookup`
576    pub fn new(lookup_flag: LookupFlag, subtables: Vec<T>) -> Self {
577        Self {
578            lookup_flag,
579            subtables: subtables.into_iter().map(Into::into).collect(),
580            ..Default::default()
581        }
582    }
583}
584
585impl<T: Validate> Validate for Lookup<T> {
586    fn validate_impl(&self, ctx: &mut ValidationCtx) {
587        ctx.in_table("Lookup", |ctx| {
588            ctx.in_field("subtables", |ctx| {
589                if self.subtables.len() > to_usize(u16::MAX) {
590                    ctx.report("array exceeds max length");
591                }
592                self.subtables.validate_impl(ctx);
593            });
594            ctx.in_field("mark_filtering_set", |ctx| {
595                if !(self
596                    .lookup_flag
597                    .contains(LookupFlag::USE_MARK_FILTERING_SET))
598                    && self.mark_filtering_set.is_some()
599                {
600                    ctx.report("'mark_filtering_set' is present but USE_MARK_FILTERING_SET not set")
601                }
602                if (self
603                    .lookup_flag
604                    .contains(LookupFlag::USE_MARK_FILTERING_SET))
605                    && self.mark_filtering_set.is_none()
606                {
607                    ctx.report("USE_MARK_FILTERING_SET is set but 'mark_filtering_set' is None")
608                }
609            });
610        })
611    }
612}
613
614impl<'a, T, U> FromObjRef<read_fonts::tables::layout::Lookup<'a, U>> for Lookup<T>
615where
616    U: FontRead<'a, Args = ()>,
617    T: FromTableRef<U> + Default + 'static,
618{
619    fn from_obj_ref(obj: &read_fonts::tables::layout::Lookup<'a, U>, _: FontData) -> Self {
620        Lookup {
621            lookup_flag: obj.lookup_flag(),
622            subtables: obj.subtables().to_owned_table(),
623            mark_filtering_set: obj.mark_filtering_set(),
624        }
625    }
626}
627
628#[allow(clippy::needless_lifetimes)]
629impl<'a, T, U> FromTableRef<read_fonts::tables::layout::Lookup<'a, U>> for Lookup<T>
630where
631    U: FontRead<'a, Args = ()>,
632    T: FromTableRef<U> + Default + 'static,
633{
634}
635
636/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
637#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
638#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
639pub struct CoverageFormat1 {
640    /// Array of glyph IDs — in numerical order
641    pub glyph_array: Vec<GlyphId16>,
642}
643
644impl CoverageFormat1 {
645    /// Construct a new `CoverageFormat1`
646    pub fn new(glyph_array: Vec<GlyphId16>) -> Self {
647        Self { glyph_array }
648    }
649}
650
651impl FontWrite for CoverageFormat1 {
652    #[allow(clippy::unnecessary_cast)]
653    fn write_into(&self, writer: &mut TableWriter) {
654        (1 as u16).write_into(writer);
655        (u16::try_from(array_len(&self.glyph_array)).unwrap()).write_into(writer);
656        self.glyph_array.write_into(writer);
657    }
658    fn table_type(&self) -> TableType {
659        TableType::Named("CoverageFormat1")
660    }
661}
662
663impl Validate for CoverageFormat1 {
664    fn validate_impl(&self, ctx: &mut ValidationCtx) {
665        ctx.in_table("CoverageFormat1", |ctx| {
666            ctx.in_field("glyph_array", |ctx| {
667                if self.glyph_array.len() > to_usize(u16::MAX) {
668                    ctx.report("array exceeds max length");
669                }
670            });
671        })
672    }
673}
674
675impl<'a> FromObjRef<read_fonts::tables::layout::CoverageFormat1<'a>> for CoverageFormat1 {
676    fn from_obj_ref(obj: &read_fonts::tables::layout::CoverageFormat1<'a>, _: FontData) -> Self {
677        let offset_data = obj.offset_data();
678        CoverageFormat1 {
679            glyph_array: obj.glyph_array().to_owned_obj(offset_data),
680        }
681    }
682}
683
684#[allow(clippy::needless_lifetimes)]
685impl<'a> FromTableRef<read_fonts::tables::layout::CoverageFormat1<'a>> for CoverageFormat1 {}
686
687impl ReadArgs for CoverageFormat1 {
688    type Args = ();
689}
690
691impl<'a> FontRead<'a> for CoverageFormat1 {
692    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
693        <read_fonts::tables::layout::CoverageFormat1 as FontRead>::read(data)
694            .map(|x| x.to_owned_table())
695    }
696}
697
698/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
699#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
700#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
701pub struct CoverageFormat2 {
702    /// Array of glyph ranges — ordered by startGlyphID.
703    pub range_records: Vec<RangeRecord>,
704}
705
706impl CoverageFormat2 {
707    /// Construct a new `CoverageFormat2`
708    pub fn new(range_records: Vec<RangeRecord>) -> Self {
709        Self { range_records }
710    }
711}
712
713impl FontWrite for CoverageFormat2 {
714    #[allow(clippy::unnecessary_cast)]
715    fn write_into(&self, writer: &mut TableWriter) {
716        (2 as u16).write_into(writer);
717        (u16::try_from(array_len(&self.range_records)).unwrap()).write_into(writer);
718        self.range_records.write_into(writer);
719    }
720    fn table_type(&self) -> TableType {
721        TableType::Named("CoverageFormat2")
722    }
723}
724
725impl Validate for CoverageFormat2 {
726    fn validate_impl(&self, ctx: &mut ValidationCtx) {
727        ctx.in_table("CoverageFormat2", |ctx| {
728            ctx.in_field("range_records", |ctx| {
729                if self.range_records.len() > to_usize(u16::MAX) {
730                    ctx.report("array exceeds max length");
731                }
732                self.range_records.validate_impl(ctx);
733            });
734        })
735    }
736}
737
738impl<'a> FromObjRef<read_fonts::tables::layout::CoverageFormat2<'a>> for CoverageFormat2 {
739    fn from_obj_ref(obj: &read_fonts::tables::layout::CoverageFormat2<'a>, _: FontData) -> Self {
740        let offset_data = obj.offset_data();
741        CoverageFormat2 {
742            range_records: obj.range_records().to_owned_obj(offset_data),
743        }
744    }
745}
746
747#[allow(clippy::needless_lifetimes)]
748impl<'a> FromTableRef<read_fonts::tables::layout::CoverageFormat2<'a>> for CoverageFormat2 {}
749
750impl ReadArgs for CoverageFormat2 {
751    type Args = ();
752}
753
754impl<'a> FontRead<'a> for CoverageFormat2 {
755    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
756        <read_fonts::tables::layout::CoverageFormat2 as FontRead>::read(data)
757            .map(|x| x.to_owned_table())
758    }
759}
760
761/// Used in [CoverageFormat2]
762#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
763#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
764pub struct RangeRecord {
765    /// First glyph ID in the range
766    pub start_glyph_id: GlyphId16,
767    /// Last glyph ID in the range
768    pub end_glyph_id: GlyphId16,
769    /// Coverage Index of first glyph ID in range
770    pub start_coverage_index: u16,
771}
772
773impl RangeRecord {
774    /// Construct a new `RangeRecord`
775    pub fn new(
776        start_glyph_id: GlyphId16,
777        end_glyph_id: GlyphId16,
778        start_coverage_index: u16,
779    ) -> Self {
780        Self {
781            start_glyph_id,
782            end_glyph_id,
783            start_coverage_index,
784        }
785    }
786}
787
788impl FontWrite for RangeRecord {
789    fn write_into(&self, writer: &mut TableWriter) {
790        self.start_glyph_id.write_into(writer);
791        self.end_glyph_id.write_into(writer);
792        self.start_coverage_index.write_into(writer);
793    }
794    fn table_type(&self) -> TableType {
795        TableType::Named("RangeRecord")
796    }
797}
798
799impl Validate for RangeRecord {
800    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
801}
802
803impl FromObjRef<read_fonts::tables::layout::RangeRecord> for RangeRecord {
804    fn from_obj_ref(obj: &read_fonts::tables::layout::RangeRecord, _: FontData) -> Self {
805        RangeRecord {
806            start_glyph_id: obj.start_glyph_id(),
807            end_glyph_id: obj.end_glyph_id(),
808            start_coverage_index: obj.start_coverage_index(),
809        }
810    }
811}
812
813/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
814#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
815#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
816pub enum CoverageTable {
817    Format1(CoverageFormat1),
818    Format2(CoverageFormat2),
819}
820
821impl CoverageTable {
822    /// Construct a new `CoverageFormat1` subtable
823    pub fn format_1(glyph_array: Vec<GlyphId16>) -> Self {
824        Self::Format1(CoverageFormat1::new(glyph_array))
825    }
826
827    /// Construct a new `CoverageFormat2` subtable
828    pub fn format_2(range_records: Vec<RangeRecord>) -> Self {
829        Self::Format2(CoverageFormat2::new(range_records))
830    }
831}
832
833impl Default for CoverageTable {
834    fn default() -> Self {
835        Self::Format1(Default::default())
836    }
837}
838
839impl FontWrite for CoverageTable {
840    fn write_into(&self, writer: &mut TableWriter) {
841        match self {
842            Self::Format1(item) => item.write_into(writer),
843            Self::Format2(item) => item.write_into(writer),
844        }
845    }
846    fn table_type(&self) -> TableType {
847        match self {
848            Self::Format1(item) => item.table_type(),
849            Self::Format2(item) => item.table_type(),
850        }
851    }
852}
853
854impl Validate for CoverageTable {
855    fn validate_impl(&self, ctx: &mut ValidationCtx) {
856        match self {
857            Self::Format1(item) => item.validate_impl(ctx),
858            Self::Format2(item) => item.validate_impl(ctx),
859        }
860    }
861}
862
863impl FromObjRef<read_fonts::tables::layout::CoverageTable<'_>> for CoverageTable {
864    fn from_obj_ref(obj: &read_fonts::tables::layout::CoverageTable, _: FontData) -> Self {
865        use read_fonts::tables::layout::CoverageTable as ObjRefType;
866        match obj {
867            ObjRefType::Format1(item) => CoverageTable::Format1(item.to_owned_table()),
868            ObjRefType::Format2(item) => CoverageTable::Format2(item.to_owned_table()),
869        }
870    }
871}
872
873impl FromTableRef<read_fonts::tables::layout::CoverageTable<'_>> for CoverageTable {}
874
875impl ReadArgs for CoverageTable {
876    type Args = ();
877}
878
879impl<'a> FontRead<'a> for CoverageTable {
880    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
881        <read_fonts::tables::layout::CoverageTable as FontRead>::read(data)
882            .map(|x| x.to_owned_table())
883    }
884}
885
886impl From<CoverageFormat1> for CoverageTable {
887    fn from(src: CoverageFormat1) -> CoverageTable {
888        CoverageTable::Format1(src)
889    }
890}
891
892impl From<CoverageFormat2> for CoverageTable {
893    fn from(src: CoverageFormat2) -> CoverageTable {
894        CoverageTable::Format2(src)
895    }
896}
897
898/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
899#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
900#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
901pub struct ClassDefFormat1 {
902    /// First glyph ID of the classValueArray
903    pub start_glyph_id: GlyphId16,
904    /// Array of Class Values — one per glyph ID
905    pub class_value_array: Vec<u16>,
906}
907
908impl ClassDefFormat1 {
909    /// Construct a new `ClassDefFormat1`
910    pub fn new(start_glyph_id: GlyphId16, class_value_array: Vec<u16>) -> Self {
911        Self {
912            start_glyph_id,
913            class_value_array,
914        }
915    }
916}
917
918impl FontWrite for ClassDefFormat1 {
919    #[allow(clippy::unnecessary_cast)]
920    fn write_into(&self, writer: &mut TableWriter) {
921        (1 as u16).write_into(writer);
922        self.start_glyph_id.write_into(writer);
923        (u16::try_from(array_len(&self.class_value_array)).unwrap()).write_into(writer);
924        self.class_value_array.write_into(writer);
925    }
926    fn table_type(&self) -> TableType {
927        TableType::Named("ClassDefFormat1")
928    }
929}
930
931impl Validate for ClassDefFormat1 {
932    fn validate_impl(&self, ctx: &mut ValidationCtx) {
933        ctx.in_table("ClassDefFormat1", |ctx| {
934            ctx.in_field("class_value_array", |ctx| {
935                if self.class_value_array.len() > to_usize(u16::MAX) {
936                    ctx.report("array exceeds max length");
937                }
938            });
939        })
940    }
941}
942
943impl<'a> FromObjRef<read_fonts::tables::layout::ClassDefFormat1<'a>> for ClassDefFormat1 {
944    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassDefFormat1<'a>, _: FontData) -> Self {
945        let offset_data = obj.offset_data();
946        ClassDefFormat1 {
947            start_glyph_id: obj.start_glyph_id(),
948            class_value_array: obj.class_value_array().to_owned_obj(offset_data),
949        }
950    }
951}
952
953#[allow(clippy::needless_lifetimes)]
954impl<'a> FromTableRef<read_fonts::tables::layout::ClassDefFormat1<'a>> for ClassDefFormat1 {}
955
956impl ReadArgs for ClassDefFormat1 {
957    type Args = ();
958}
959
960impl<'a> FontRead<'a> for ClassDefFormat1 {
961    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
962        <read_fonts::tables::layout::ClassDefFormat1 as FontRead>::read(data)
963            .map(|x| x.to_owned_table())
964    }
965}
966
967/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
968#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
969#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
970pub struct ClassDefFormat2 {
971    /// Array of ClassRangeRecords — ordered by startGlyphID
972    pub class_range_records: Vec<ClassRangeRecord>,
973}
974
975impl ClassDefFormat2 {
976    /// Construct a new `ClassDefFormat2`
977    pub fn new(class_range_records: Vec<ClassRangeRecord>) -> Self {
978        Self {
979            class_range_records,
980        }
981    }
982}
983
984impl FontWrite for ClassDefFormat2 {
985    #[allow(clippy::unnecessary_cast)]
986    fn write_into(&self, writer: &mut TableWriter) {
987        (2 as u16).write_into(writer);
988        (u16::try_from(array_len(&self.class_range_records)).unwrap()).write_into(writer);
989        self.class_range_records.write_into(writer);
990    }
991    fn table_type(&self) -> TableType {
992        TableType::Named("ClassDefFormat2")
993    }
994}
995
996impl Validate for ClassDefFormat2 {
997    fn validate_impl(&self, ctx: &mut ValidationCtx) {
998        ctx.in_table("ClassDefFormat2", |ctx| {
999            ctx.in_field("class_range_records", |ctx| {
1000                if self.class_range_records.len() > to_usize(u16::MAX) {
1001                    ctx.report("array exceeds max length");
1002                }
1003                self.class_range_records.validate_impl(ctx);
1004            });
1005        })
1006    }
1007}
1008
1009impl<'a> FromObjRef<read_fonts::tables::layout::ClassDefFormat2<'a>> for ClassDefFormat2 {
1010    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassDefFormat2<'a>, _: FontData) -> Self {
1011        let offset_data = obj.offset_data();
1012        ClassDefFormat2 {
1013            class_range_records: obj.class_range_records().to_owned_obj(offset_data),
1014        }
1015    }
1016}
1017
1018#[allow(clippy::needless_lifetimes)]
1019impl<'a> FromTableRef<read_fonts::tables::layout::ClassDefFormat2<'a>> for ClassDefFormat2 {}
1020
1021impl ReadArgs for ClassDefFormat2 {
1022    type Args = ();
1023}
1024
1025impl<'a> FontRead<'a> for ClassDefFormat2 {
1026    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1027        <read_fonts::tables::layout::ClassDefFormat2 as FontRead>::read(data)
1028            .map(|x| x.to_owned_table())
1029    }
1030}
1031
1032/// Used in [ClassDefFormat2]
1033#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1034#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1035pub struct ClassRangeRecord {
1036    /// First glyph ID in the range
1037    pub start_glyph_id: GlyphId16,
1038    /// Last glyph ID in the range
1039    pub end_glyph_id: GlyphId16,
1040    /// Applied to all glyphs in the range
1041    pub class: u16,
1042}
1043
1044impl ClassRangeRecord {
1045    /// Construct a new `ClassRangeRecord`
1046    pub fn new(start_glyph_id: GlyphId16, end_glyph_id: GlyphId16, class: u16) -> Self {
1047        Self {
1048            start_glyph_id,
1049            end_glyph_id,
1050            class,
1051        }
1052    }
1053}
1054
1055impl FontWrite for ClassRangeRecord {
1056    fn write_into(&self, writer: &mut TableWriter) {
1057        self.start_glyph_id.write_into(writer);
1058        self.end_glyph_id.write_into(writer);
1059        self.class.write_into(writer);
1060    }
1061    fn table_type(&self) -> TableType {
1062        TableType::Named("ClassRangeRecord")
1063    }
1064}
1065
1066impl Validate for ClassRangeRecord {
1067    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1068        ctx.in_table("ClassRangeRecord", |ctx| {
1069            ctx.in_field("start_glyph_id", |ctx| {
1070                self.validate_glyph_range(ctx);
1071            });
1072        })
1073    }
1074}
1075
1076impl FromObjRef<read_fonts::tables::layout::ClassRangeRecord> for ClassRangeRecord {
1077    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassRangeRecord, _: FontData) -> Self {
1078        ClassRangeRecord {
1079            start_glyph_id: obj.start_glyph_id(),
1080            end_glyph_id: obj.end_glyph_id(),
1081            class: obj.class(),
1082        }
1083    }
1084}
1085
1086/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
1087#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1088#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1089pub enum ClassDef {
1090    Format1(ClassDefFormat1),
1091    Format2(ClassDefFormat2),
1092}
1093
1094impl ClassDef {
1095    /// Construct a new `ClassDefFormat1` subtable
1096    pub fn format_1(start_glyph_id: GlyphId16, class_value_array: Vec<u16>) -> Self {
1097        Self::Format1(ClassDefFormat1::new(start_glyph_id, class_value_array))
1098    }
1099
1100    /// Construct a new `ClassDefFormat2` subtable
1101    pub fn format_2(class_range_records: Vec<ClassRangeRecord>) -> Self {
1102        Self::Format2(ClassDefFormat2::new(class_range_records))
1103    }
1104}
1105
1106impl Default for ClassDef {
1107    fn default() -> Self {
1108        Self::Format1(Default::default())
1109    }
1110}
1111
1112impl FontWrite for ClassDef {
1113    fn write_into(&self, writer: &mut TableWriter) {
1114        match self {
1115            Self::Format1(item) => item.write_into(writer),
1116            Self::Format2(item) => item.write_into(writer),
1117        }
1118    }
1119    fn table_type(&self) -> TableType {
1120        match self {
1121            Self::Format1(item) => item.table_type(),
1122            Self::Format2(item) => item.table_type(),
1123        }
1124    }
1125}
1126
1127impl Validate for ClassDef {
1128    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1129        match self {
1130            Self::Format1(item) => item.validate_impl(ctx),
1131            Self::Format2(item) => item.validate_impl(ctx),
1132        }
1133    }
1134}
1135
1136impl FromObjRef<read_fonts::tables::layout::ClassDef<'_>> for ClassDef {
1137    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassDef, _: FontData) -> Self {
1138        use read_fonts::tables::layout::ClassDef as ObjRefType;
1139        match obj {
1140            ObjRefType::Format1(item) => ClassDef::Format1(item.to_owned_table()),
1141            ObjRefType::Format2(item) => ClassDef::Format2(item.to_owned_table()),
1142        }
1143    }
1144}
1145
1146impl FromTableRef<read_fonts::tables::layout::ClassDef<'_>> for ClassDef {}
1147
1148impl ReadArgs for ClassDef {
1149    type Args = ();
1150}
1151
1152impl<'a> FontRead<'a> for ClassDef {
1153    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1154        <read_fonts::tables::layout::ClassDef as FontRead>::read(data).map(|x| x.to_owned_table())
1155    }
1156}
1157
1158impl From<ClassDefFormat1> for ClassDef {
1159    fn from(src: ClassDefFormat1) -> ClassDef {
1160        ClassDef::Format1(src)
1161    }
1162}
1163
1164impl From<ClassDefFormat2> for ClassDef {
1165    fn from(src: ClassDefFormat2) -> ClassDef {
1166        ClassDef::Format2(src)
1167    }
1168}
1169
1170/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
1171#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1173pub struct SequenceLookupRecord {
1174    /// Index (zero-based) into the input glyph sequence
1175    pub sequence_index: u16,
1176    /// Index (zero-based) into the LookupList
1177    pub lookup_list_index: u16,
1178}
1179
1180impl SequenceLookupRecord {
1181    /// Construct a new `SequenceLookupRecord`
1182    pub fn new(sequence_index: u16, lookup_list_index: u16) -> Self {
1183        Self {
1184            sequence_index,
1185            lookup_list_index,
1186        }
1187    }
1188}
1189
1190impl FontWrite for SequenceLookupRecord {
1191    fn write_into(&self, writer: &mut TableWriter) {
1192        self.sequence_index.write_into(writer);
1193        self.lookup_list_index.write_into(writer);
1194    }
1195    fn table_type(&self) -> TableType {
1196        TableType::Named("SequenceLookupRecord")
1197    }
1198}
1199
1200impl Validate for SequenceLookupRecord {
1201    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
1202}
1203
1204impl FromObjRef<read_fonts::tables::layout::SequenceLookupRecord> for SequenceLookupRecord {
1205    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceLookupRecord, _: FontData) -> Self {
1206        SequenceLookupRecord {
1207            sequence_index: obj.sequence_index(),
1208            lookup_list_index: obj.lookup_list_index(),
1209        }
1210    }
1211}
1212
1213/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
1214#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1215#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1216pub struct SequenceContextFormat1 {
1217    /// Offset to Coverage table, from beginning of
1218    /// SequenceContextFormat1 table
1219    pub coverage: OffsetMarker<CoverageTable>,
1220    /// Array of offsets to SequenceRuleSet tables, from beginning of
1221    /// SequenceContextFormat1 table (offsets may be NULL)
1222    pub seq_rule_sets: Vec<NullableOffsetMarker<SequenceRuleSet>>,
1223}
1224
1225impl SequenceContextFormat1 {
1226    /// Construct a new `SequenceContextFormat1`
1227    pub fn new(coverage: CoverageTable, seq_rule_sets: Vec<Option<SequenceRuleSet>>) -> Self {
1228        Self {
1229            coverage: coverage.into(),
1230            seq_rule_sets: seq_rule_sets.into_iter().map(Into::into).collect(),
1231        }
1232    }
1233}
1234
1235impl FontWrite for SequenceContextFormat1 {
1236    #[allow(clippy::unnecessary_cast)]
1237    fn write_into(&self, writer: &mut TableWriter) {
1238        (1 as u16).write_into(writer);
1239        self.coverage.write_into(writer);
1240        (u16::try_from(array_len(&self.seq_rule_sets)).unwrap()).write_into(writer);
1241        self.seq_rule_sets.write_into(writer);
1242    }
1243    fn table_type(&self) -> TableType {
1244        TableType::Named("SequenceContextFormat1")
1245    }
1246}
1247
1248impl Validate for SequenceContextFormat1 {
1249    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1250        ctx.in_table("SequenceContextFormat1", |ctx| {
1251            ctx.in_field("coverage", |ctx| {
1252                self.coverage.validate_impl(ctx);
1253            });
1254            ctx.in_field("seq_rule_sets", |ctx| {
1255                if self.seq_rule_sets.len() > to_usize(u16::MAX) {
1256                    ctx.report("array exceeds max length");
1257                }
1258                self.seq_rule_sets.validate_impl(ctx);
1259            });
1260        })
1261    }
1262}
1263
1264impl<'a> FromObjRef<read_fonts::tables::layout::SequenceContextFormat1<'a>>
1265    for SequenceContextFormat1
1266{
1267    fn from_obj_ref(
1268        obj: &read_fonts::tables::layout::SequenceContextFormat1<'a>,
1269        _: FontData,
1270    ) -> Self {
1271        SequenceContextFormat1 {
1272            coverage: obj.coverage().to_owned_table(),
1273            seq_rule_sets: obj.seq_rule_sets().to_owned_table(),
1274        }
1275    }
1276}
1277
1278#[allow(clippy::needless_lifetimes)]
1279impl<'a> FromTableRef<read_fonts::tables::layout::SequenceContextFormat1<'a>>
1280    for SequenceContextFormat1
1281{
1282}
1283
1284impl ReadArgs for SequenceContextFormat1 {
1285    type Args = ();
1286}
1287
1288impl<'a> FontRead<'a> for SequenceContextFormat1 {
1289    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1290        <read_fonts::tables::layout::SequenceContextFormat1 as FontRead>::read(data)
1291            .map(|x| x.to_owned_table())
1292    }
1293}
1294
1295/// Part of [SequenceContextFormat1]
1296#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1297#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1298pub struct SequenceRuleSet {
1299    /// Array of offsets to SequenceRule tables, from beginning of the
1300    /// SequenceRuleSet table
1301    pub seq_rules: Vec<OffsetMarker<SequenceRule>>,
1302}
1303
1304impl SequenceRuleSet {
1305    /// Construct a new `SequenceRuleSet`
1306    pub fn new(seq_rules: Vec<SequenceRule>) -> Self {
1307        Self {
1308            seq_rules: seq_rules.into_iter().map(Into::into).collect(),
1309        }
1310    }
1311}
1312
1313impl FontWrite for SequenceRuleSet {
1314    #[allow(clippy::unnecessary_cast)]
1315    fn write_into(&self, writer: &mut TableWriter) {
1316        (u16::try_from(array_len(&self.seq_rules)).unwrap()).write_into(writer);
1317        self.seq_rules.write_into(writer);
1318    }
1319    fn table_type(&self) -> TableType {
1320        TableType::Named("SequenceRuleSet")
1321    }
1322}
1323
1324impl Validate for SequenceRuleSet {
1325    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1326        ctx.in_table("SequenceRuleSet", |ctx| {
1327            ctx.in_field("seq_rules", |ctx| {
1328                if self.seq_rules.len() > to_usize(u16::MAX) {
1329                    ctx.report("array exceeds max length");
1330                }
1331                self.seq_rules.validate_impl(ctx);
1332            });
1333        })
1334    }
1335}
1336
1337impl<'a> FromObjRef<read_fonts::tables::layout::SequenceRuleSet<'a>> for SequenceRuleSet {
1338    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceRuleSet<'a>, _: FontData) -> Self {
1339        SequenceRuleSet {
1340            seq_rules: obj.seq_rules().to_owned_table(),
1341        }
1342    }
1343}
1344
1345#[allow(clippy::needless_lifetimes)]
1346impl<'a> FromTableRef<read_fonts::tables::layout::SequenceRuleSet<'a>> for SequenceRuleSet {}
1347
1348impl ReadArgs for SequenceRuleSet {
1349    type Args = ();
1350}
1351
1352impl<'a> FontRead<'a> for SequenceRuleSet {
1353    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1354        <read_fonts::tables::layout::SequenceRuleSet as FontRead>::read(data)
1355            .map(|x| x.to_owned_table())
1356    }
1357}
1358
1359/// Part of [SequenceContextFormat1]
1360#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1361#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1362pub struct SequenceRule {
1363    /// Array of input glyph IDs—starting with the second glyph
1364    pub input_sequence: Vec<GlyphId16>,
1365    /// Array of Sequence lookup records
1366    pub seq_lookup_records: Vec<SequenceLookupRecord>,
1367}
1368
1369impl SequenceRule {
1370    /// Construct a new `SequenceRule`
1371    pub fn new(
1372        input_sequence: Vec<GlyphId16>,
1373        seq_lookup_records: Vec<SequenceLookupRecord>,
1374    ) -> Self {
1375        Self {
1376            input_sequence,
1377            seq_lookup_records,
1378        }
1379    }
1380}
1381
1382impl FontWrite for SequenceRule {
1383    #[allow(clippy::unnecessary_cast)]
1384    fn write_into(&self, writer: &mut TableWriter) {
1385        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
1386        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
1387        self.input_sequence.write_into(writer);
1388        self.seq_lookup_records.write_into(writer);
1389    }
1390    fn table_type(&self) -> TableType {
1391        TableType::Named("SequenceRule")
1392    }
1393}
1394
1395impl Validate for SequenceRule {
1396    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1397        ctx.in_table("SequenceRule", |ctx| {
1398            ctx.in_field("seq_lookup_records", |ctx| {
1399                if self.seq_lookup_records.len() > to_usize(u16::MAX) {
1400                    ctx.report("array exceeds max length");
1401                }
1402                self.seq_lookup_records.validate_impl(ctx);
1403            });
1404        })
1405    }
1406}
1407
1408impl<'a> FromObjRef<read_fonts::tables::layout::SequenceRule<'a>> for SequenceRule {
1409    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceRule<'a>, _: FontData) -> Self {
1410        let offset_data = obj.offset_data();
1411        SequenceRule {
1412            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
1413            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
1414        }
1415    }
1416}
1417
1418#[allow(clippy::needless_lifetimes)]
1419impl<'a> FromTableRef<read_fonts::tables::layout::SequenceRule<'a>> for SequenceRule {}
1420
1421impl ReadArgs for SequenceRule {
1422    type Args = ();
1423}
1424
1425impl<'a> FontRead<'a> for SequenceRule {
1426    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1427        <read_fonts::tables::layout::SequenceRule as FontRead>::read(data)
1428            .map(|x| x.to_owned_table())
1429    }
1430}
1431
1432/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
1433#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1434#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1435pub struct SequenceContextFormat2 {
1436    /// Offset to Coverage table, from beginning of
1437    /// SequenceContextFormat2 table
1438    pub coverage: OffsetMarker<CoverageTable>,
1439    /// Offset to ClassDef table, from beginning of
1440    /// SequenceContextFormat2 table
1441    pub class_def: OffsetMarker<ClassDef>,
1442    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
1443    /// of SequenceContextFormat2 table (may be NULL)
1444    pub class_seq_rule_sets: Vec<NullableOffsetMarker<ClassSequenceRuleSet>>,
1445}
1446
1447impl SequenceContextFormat2 {
1448    /// Construct a new `SequenceContextFormat2`
1449    pub fn new(
1450        coverage: CoverageTable,
1451        class_def: ClassDef,
1452        class_seq_rule_sets: Vec<Option<ClassSequenceRuleSet>>,
1453    ) -> Self {
1454        Self {
1455            coverage: coverage.into(),
1456            class_def: class_def.into(),
1457            class_seq_rule_sets: class_seq_rule_sets.into_iter().map(Into::into).collect(),
1458        }
1459    }
1460}
1461
1462impl FontWrite for SequenceContextFormat2 {
1463    #[allow(clippy::unnecessary_cast)]
1464    fn write_into(&self, writer: &mut TableWriter) {
1465        (2 as u16).write_into(writer);
1466        self.coverage.write_into(writer);
1467        self.class_def.write_into(writer);
1468        (u16::try_from(array_len(&self.class_seq_rule_sets)).unwrap()).write_into(writer);
1469        self.class_seq_rule_sets.write_into(writer);
1470    }
1471    fn table_type(&self) -> TableType {
1472        TableType::Named("SequenceContextFormat2")
1473    }
1474}
1475
1476impl Validate for SequenceContextFormat2 {
1477    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1478        ctx.in_table("SequenceContextFormat2", |ctx| {
1479            ctx.in_field("coverage", |ctx| {
1480                self.coverage.validate_impl(ctx);
1481            });
1482            ctx.in_field("class_def", |ctx| {
1483                self.class_def.validate_impl(ctx);
1484            });
1485            ctx.in_field("class_seq_rule_sets", |ctx| {
1486                if self.class_seq_rule_sets.len() > to_usize(u16::MAX) {
1487                    ctx.report("array exceeds max length");
1488                }
1489                self.class_seq_rule_sets.validate_impl(ctx);
1490            });
1491        })
1492    }
1493}
1494
1495impl<'a> FromObjRef<read_fonts::tables::layout::SequenceContextFormat2<'a>>
1496    for SequenceContextFormat2
1497{
1498    fn from_obj_ref(
1499        obj: &read_fonts::tables::layout::SequenceContextFormat2<'a>,
1500        _: FontData,
1501    ) -> Self {
1502        SequenceContextFormat2 {
1503            coverage: obj.coverage().to_owned_table(),
1504            class_def: obj.class_def().to_owned_table(),
1505            class_seq_rule_sets: obj.class_seq_rule_sets().to_owned_table(),
1506        }
1507    }
1508}
1509
1510#[allow(clippy::needless_lifetimes)]
1511impl<'a> FromTableRef<read_fonts::tables::layout::SequenceContextFormat2<'a>>
1512    for SequenceContextFormat2
1513{
1514}
1515
1516impl ReadArgs for SequenceContextFormat2 {
1517    type Args = ();
1518}
1519
1520impl<'a> FontRead<'a> for SequenceContextFormat2 {
1521    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1522        <read_fonts::tables::layout::SequenceContextFormat2 as FontRead>::read(data)
1523            .map(|x| x.to_owned_table())
1524    }
1525}
1526
1527/// Part of [SequenceContextFormat2]
1528#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1529#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1530pub struct ClassSequenceRuleSet {
1531    /// Array of offsets to ClassSequenceRule tables, from beginning of
1532    /// ClassSequenceRuleSet table
1533    pub class_seq_rules: Vec<OffsetMarker<ClassSequenceRule>>,
1534}
1535
1536impl ClassSequenceRuleSet {
1537    /// Construct a new `ClassSequenceRuleSet`
1538    pub fn new(class_seq_rules: Vec<ClassSequenceRule>) -> Self {
1539        Self {
1540            class_seq_rules: class_seq_rules.into_iter().map(Into::into).collect(),
1541        }
1542    }
1543}
1544
1545impl FontWrite for ClassSequenceRuleSet {
1546    #[allow(clippy::unnecessary_cast)]
1547    fn write_into(&self, writer: &mut TableWriter) {
1548        (u16::try_from(array_len(&self.class_seq_rules)).unwrap()).write_into(writer);
1549        self.class_seq_rules.write_into(writer);
1550    }
1551    fn table_type(&self) -> TableType {
1552        TableType::Named("ClassSequenceRuleSet")
1553    }
1554}
1555
1556impl Validate for ClassSequenceRuleSet {
1557    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1558        ctx.in_table("ClassSequenceRuleSet", |ctx| {
1559            ctx.in_field("class_seq_rules", |ctx| {
1560                if self.class_seq_rules.len() > to_usize(u16::MAX) {
1561                    ctx.report("array exceeds max length");
1562                }
1563                self.class_seq_rules.validate_impl(ctx);
1564            });
1565        })
1566    }
1567}
1568
1569impl<'a> FromObjRef<read_fonts::tables::layout::ClassSequenceRuleSet<'a>> for ClassSequenceRuleSet {
1570    fn from_obj_ref(
1571        obj: &read_fonts::tables::layout::ClassSequenceRuleSet<'a>,
1572        _: FontData,
1573    ) -> Self {
1574        ClassSequenceRuleSet {
1575            class_seq_rules: obj.class_seq_rules().to_owned_table(),
1576        }
1577    }
1578}
1579
1580#[allow(clippy::needless_lifetimes)]
1581impl<'a> FromTableRef<read_fonts::tables::layout::ClassSequenceRuleSet<'a>>
1582    for ClassSequenceRuleSet
1583{
1584}
1585
1586impl ReadArgs for ClassSequenceRuleSet {
1587    type Args = ();
1588}
1589
1590impl<'a> FontRead<'a> for ClassSequenceRuleSet {
1591    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1592        <read_fonts::tables::layout::ClassSequenceRuleSet as FontRead>::read(data)
1593            .map(|x| x.to_owned_table())
1594    }
1595}
1596
1597/// Part of [SequenceContextFormat2]
1598#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1599#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1600pub struct ClassSequenceRule {
1601    /// Sequence of classes to be matched to the input glyph sequence,
1602    /// beginning with the second glyph position
1603    pub input_sequence: Vec<u16>,
1604    /// Array of SequenceLookupRecords
1605    pub seq_lookup_records: Vec<SequenceLookupRecord>,
1606}
1607
1608impl ClassSequenceRule {
1609    /// Construct a new `ClassSequenceRule`
1610    pub fn new(input_sequence: Vec<u16>, seq_lookup_records: Vec<SequenceLookupRecord>) -> Self {
1611        Self {
1612            input_sequence,
1613            seq_lookup_records,
1614        }
1615    }
1616}
1617
1618impl FontWrite for ClassSequenceRule {
1619    #[allow(clippy::unnecessary_cast)]
1620    fn write_into(&self, writer: &mut TableWriter) {
1621        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
1622        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
1623        self.input_sequence.write_into(writer);
1624        self.seq_lookup_records.write_into(writer);
1625    }
1626    fn table_type(&self) -> TableType {
1627        TableType::Named("ClassSequenceRule")
1628    }
1629}
1630
1631impl Validate for ClassSequenceRule {
1632    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1633        ctx.in_table("ClassSequenceRule", |ctx| {
1634            ctx.in_field("seq_lookup_records", |ctx| {
1635                if self.seq_lookup_records.len() > to_usize(u16::MAX) {
1636                    ctx.report("array exceeds max length");
1637                }
1638                self.seq_lookup_records.validate_impl(ctx);
1639            });
1640        })
1641    }
1642}
1643
1644impl<'a> FromObjRef<read_fonts::tables::layout::ClassSequenceRule<'a>> for ClassSequenceRule {
1645    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassSequenceRule<'a>, _: FontData) -> Self {
1646        let offset_data = obj.offset_data();
1647        ClassSequenceRule {
1648            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
1649            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
1650        }
1651    }
1652}
1653
1654#[allow(clippy::needless_lifetimes)]
1655impl<'a> FromTableRef<read_fonts::tables::layout::ClassSequenceRule<'a>> for ClassSequenceRule {}
1656
1657impl ReadArgs for ClassSequenceRule {
1658    type Args = ();
1659}
1660
1661impl<'a> FontRead<'a> for ClassSequenceRule {
1662    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1663        <read_fonts::tables::layout::ClassSequenceRule as FontRead>::read(data)
1664            .map(|x| x.to_owned_table())
1665    }
1666}
1667
1668/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
1669#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1670#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1671pub struct SequenceContextFormat3 {
1672    /// Array of offsets to Coverage tables, from beginning of
1673    /// SequenceContextFormat3 subtable
1674    pub coverages: Vec<OffsetMarker<CoverageTable>>,
1675    /// Array of SequenceLookupRecords
1676    pub seq_lookup_records: Vec<SequenceLookupRecord>,
1677}
1678
1679impl SequenceContextFormat3 {
1680    /// Construct a new `SequenceContextFormat3`
1681    pub fn new(
1682        coverages: Vec<CoverageTable>,
1683        seq_lookup_records: Vec<SequenceLookupRecord>,
1684    ) -> Self {
1685        Self {
1686            coverages: coverages.into_iter().map(Into::into).collect(),
1687            seq_lookup_records,
1688        }
1689    }
1690}
1691
1692impl FontWrite for SequenceContextFormat3 {
1693    #[allow(clippy::unnecessary_cast)]
1694    fn write_into(&self, writer: &mut TableWriter) {
1695        (3 as u16).write_into(writer);
1696        (u16::try_from(array_len(&self.coverages)).unwrap()).write_into(writer);
1697        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
1698        self.coverages.write_into(writer);
1699        self.seq_lookup_records.write_into(writer);
1700    }
1701    fn table_type(&self) -> TableType {
1702        TableType::Named("SequenceContextFormat3")
1703    }
1704}
1705
1706impl Validate for SequenceContextFormat3 {
1707    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1708        ctx.in_table("SequenceContextFormat3", |ctx| {
1709            ctx.in_field("coverages", |ctx| {
1710                if self.coverages.len() > to_usize(u16::MAX) {
1711                    ctx.report("array exceeds max length");
1712                }
1713                self.coverages.validate_impl(ctx);
1714            });
1715            ctx.in_field("seq_lookup_records", |ctx| {
1716                if self.seq_lookup_records.len() > to_usize(u16::MAX) {
1717                    ctx.report("array exceeds max length");
1718                }
1719                self.seq_lookup_records.validate_impl(ctx);
1720            });
1721        })
1722    }
1723}
1724
1725impl<'a> FromObjRef<read_fonts::tables::layout::SequenceContextFormat3<'a>>
1726    for SequenceContextFormat3
1727{
1728    fn from_obj_ref(
1729        obj: &read_fonts::tables::layout::SequenceContextFormat3<'a>,
1730        _: FontData,
1731    ) -> Self {
1732        let offset_data = obj.offset_data();
1733        SequenceContextFormat3 {
1734            coverages: obj.coverages().to_owned_table(),
1735            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
1736        }
1737    }
1738}
1739
1740#[allow(clippy::needless_lifetimes)]
1741impl<'a> FromTableRef<read_fonts::tables::layout::SequenceContextFormat3<'a>>
1742    for SequenceContextFormat3
1743{
1744}
1745
1746impl ReadArgs for SequenceContextFormat3 {
1747    type Args = ();
1748}
1749
1750impl<'a> FontRead<'a> for SequenceContextFormat3 {
1751    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1752        <read_fonts::tables::layout::SequenceContextFormat3 as FontRead>::read(data)
1753            .map(|x| x.to_owned_table())
1754    }
1755}
1756
1757#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1758#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1759pub enum SequenceContext {
1760    Format1(SequenceContextFormat1),
1761    Format2(SequenceContextFormat2),
1762    Format3(SequenceContextFormat3),
1763}
1764
1765impl SequenceContext {
1766    /// Construct a new `SequenceContextFormat1` subtable
1767    pub fn format_1(coverage: CoverageTable, seq_rule_sets: Vec<Option<SequenceRuleSet>>) -> Self {
1768        Self::Format1(SequenceContextFormat1::new(coverage, seq_rule_sets))
1769    }
1770
1771    /// Construct a new `SequenceContextFormat2` subtable
1772    pub fn format_2(
1773        coverage: CoverageTable,
1774        class_def: ClassDef,
1775        class_seq_rule_sets: Vec<Option<ClassSequenceRuleSet>>,
1776    ) -> Self {
1777        Self::Format2(SequenceContextFormat2::new(
1778            coverage,
1779            class_def,
1780            class_seq_rule_sets,
1781        ))
1782    }
1783
1784    /// Construct a new `SequenceContextFormat3` subtable
1785    pub fn format_3(
1786        coverages: Vec<CoverageTable>,
1787        seq_lookup_records: Vec<SequenceLookupRecord>,
1788    ) -> Self {
1789        Self::Format3(SequenceContextFormat3::new(coverages, seq_lookup_records))
1790    }
1791}
1792
1793impl Default for SequenceContext {
1794    fn default() -> Self {
1795        Self::Format1(Default::default())
1796    }
1797}
1798
1799impl FontWrite for SequenceContext {
1800    fn write_into(&self, writer: &mut TableWriter) {
1801        match self {
1802            Self::Format1(item) => item.write_into(writer),
1803            Self::Format2(item) => item.write_into(writer),
1804            Self::Format3(item) => item.write_into(writer),
1805        }
1806    }
1807    fn table_type(&self) -> TableType {
1808        match self {
1809            Self::Format1(item) => item.table_type(),
1810            Self::Format2(item) => item.table_type(),
1811            Self::Format3(item) => item.table_type(),
1812        }
1813    }
1814}
1815
1816impl Validate for SequenceContext {
1817    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1818        match self {
1819            Self::Format1(item) => item.validate_impl(ctx),
1820            Self::Format2(item) => item.validate_impl(ctx),
1821            Self::Format3(item) => item.validate_impl(ctx),
1822        }
1823    }
1824}
1825
1826impl FromObjRef<read_fonts::tables::layout::SequenceContext<'_>> for SequenceContext {
1827    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceContext, _: FontData) -> Self {
1828        use read_fonts::tables::layout::SequenceContext as ObjRefType;
1829        match obj {
1830            ObjRefType::Format1(item) => SequenceContext::Format1(item.to_owned_table()),
1831            ObjRefType::Format2(item) => SequenceContext::Format2(item.to_owned_table()),
1832            ObjRefType::Format3(item) => SequenceContext::Format3(item.to_owned_table()),
1833        }
1834    }
1835}
1836
1837impl FromTableRef<read_fonts::tables::layout::SequenceContext<'_>> for SequenceContext {}
1838
1839impl ReadArgs for SequenceContext {
1840    type Args = ();
1841}
1842
1843impl<'a> FontRead<'a> for SequenceContext {
1844    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1845        <read_fonts::tables::layout::SequenceContext as FontRead>::read(data)
1846            .map(|x| x.to_owned_table())
1847    }
1848}
1849
1850impl From<SequenceContextFormat1> for SequenceContext {
1851    fn from(src: SequenceContextFormat1) -> SequenceContext {
1852        SequenceContext::Format1(src)
1853    }
1854}
1855
1856impl From<SequenceContextFormat2> for SequenceContext {
1857    fn from(src: SequenceContextFormat2) -> SequenceContext {
1858        SequenceContext::Format2(src)
1859    }
1860}
1861
1862impl From<SequenceContextFormat3> for SequenceContext {
1863    fn from(src: SequenceContextFormat3) -> SequenceContext {
1864        SequenceContext::Format3(src)
1865    }
1866}
1867
1868/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
1869#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1870#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1871pub struct ChainedSequenceContextFormat1 {
1872    /// Offset to Coverage table, from beginning of
1873    /// ChainSequenceContextFormat1 table
1874    pub coverage: OffsetMarker<CoverageTable>,
1875    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
1876    /// ChainedSequenceContextFormat1 table (may be NULL)
1877    pub chained_seq_rule_sets: Vec<NullableOffsetMarker<ChainedSequenceRuleSet>>,
1878}
1879
1880impl ChainedSequenceContextFormat1 {
1881    /// Construct a new `ChainedSequenceContextFormat1`
1882    pub fn new(
1883        coverage: CoverageTable,
1884        chained_seq_rule_sets: Vec<Option<ChainedSequenceRuleSet>>,
1885    ) -> Self {
1886        Self {
1887            coverage: coverage.into(),
1888            chained_seq_rule_sets: chained_seq_rule_sets.into_iter().map(Into::into).collect(),
1889        }
1890    }
1891}
1892
1893impl FontWrite for ChainedSequenceContextFormat1 {
1894    #[allow(clippy::unnecessary_cast)]
1895    fn write_into(&self, writer: &mut TableWriter) {
1896        (1 as u16).write_into(writer);
1897        self.coverage.write_into(writer);
1898        (u16::try_from(array_len(&self.chained_seq_rule_sets)).unwrap()).write_into(writer);
1899        self.chained_seq_rule_sets.write_into(writer);
1900    }
1901    fn table_type(&self) -> TableType {
1902        TableType::Named("ChainedSequenceContextFormat1")
1903    }
1904}
1905
1906impl Validate for ChainedSequenceContextFormat1 {
1907    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1908        ctx.in_table("ChainedSequenceContextFormat1", |ctx| {
1909            ctx.in_field("coverage", |ctx| {
1910                self.coverage.validate_impl(ctx);
1911            });
1912            ctx.in_field("chained_seq_rule_sets", |ctx| {
1913                if self.chained_seq_rule_sets.len() > to_usize(u16::MAX) {
1914                    ctx.report("array exceeds max length");
1915                }
1916                self.chained_seq_rule_sets.validate_impl(ctx);
1917            });
1918        })
1919    }
1920}
1921
1922impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceContextFormat1<'a>>
1923    for ChainedSequenceContextFormat1
1924{
1925    fn from_obj_ref(
1926        obj: &read_fonts::tables::layout::ChainedSequenceContextFormat1<'a>,
1927        _: FontData,
1928    ) -> Self {
1929        ChainedSequenceContextFormat1 {
1930            coverage: obj.coverage().to_owned_table(),
1931            chained_seq_rule_sets: obj.chained_seq_rule_sets().to_owned_table(),
1932        }
1933    }
1934}
1935
1936#[allow(clippy::needless_lifetimes)]
1937impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceContextFormat1<'a>>
1938    for ChainedSequenceContextFormat1
1939{
1940}
1941
1942impl ReadArgs for ChainedSequenceContextFormat1 {
1943    type Args = ();
1944}
1945
1946impl<'a> FontRead<'a> for ChainedSequenceContextFormat1 {
1947    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1948        <read_fonts::tables::layout::ChainedSequenceContextFormat1 as FontRead>::read(data)
1949            .map(|x| x.to_owned_table())
1950    }
1951}
1952
1953/// Part of [ChainedSequenceContextFormat1]
1954#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1955#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1956pub struct ChainedSequenceRuleSet {
1957    /// Array of offsets to ChainedSequenceRule tables, from beginning
1958    /// of ChainedSequenceRuleSet table
1959    pub chained_seq_rules: Vec<OffsetMarker<ChainedSequenceRule>>,
1960}
1961
1962impl ChainedSequenceRuleSet {
1963    /// Construct a new `ChainedSequenceRuleSet`
1964    pub fn new(chained_seq_rules: Vec<ChainedSequenceRule>) -> Self {
1965        Self {
1966            chained_seq_rules: chained_seq_rules.into_iter().map(Into::into).collect(),
1967        }
1968    }
1969}
1970
1971impl FontWrite for ChainedSequenceRuleSet {
1972    #[allow(clippy::unnecessary_cast)]
1973    fn write_into(&self, writer: &mut TableWriter) {
1974        (u16::try_from(array_len(&self.chained_seq_rules)).unwrap()).write_into(writer);
1975        self.chained_seq_rules.write_into(writer);
1976    }
1977    fn table_type(&self) -> TableType {
1978        TableType::Named("ChainedSequenceRuleSet")
1979    }
1980}
1981
1982impl Validate for ChainedSequenceRuleSet {
1983    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1984        ctx.in_table("ChainedSequenceRuleSet", |ctx| {
1985            ctx.in_field("chained_seq_rules", |ctx| {
1986                if self.chained_seq_rules.len() > to_usize(u16::MAX) {
1987                    ctx.report("array exceeds max length");
1988                }
1989                self.chained_seq_rules.validate_impl(ctx);
1990            });
1991        })
1992    }
1993}
1994
1995impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceRuleSet<'a>>
1996    for ChainedSequenceRuleSet
1997{
1998    fn from_obj_ref(
1999        obj: &read_fonts::tables::layout::ChainedSequenceRuleSet<'a>,
2000        _: FontData,
2001    ) -> Self {
2002        ChainedSequenceRuleSet {
2003            chained_seq_rules: obj.chained_seq_rules().to_owned_table(),
2004        }
2005    }
2006}
2007
2008#[allow(clippy::needless_lifetimes)]
2009impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceRuleSet<'a>>
2010    for ChainedSequenceRuleSet
2011{
2012}
2013
2014impl ReadArgs for ChainedSequenceRuleSet {
2015    type Args = ();
2016}
2017
2018impl<'a> FontRead<'a> for ChainedSequenceRuleSet {
2019    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2020        <read_fonts::tables::layout::ChainedSequenceRuleSet as FontRead>::read(data)
2021            .map(|x| x.to_owned_table())
2022    }
2023}
2024
2025/// Part of [ChainedSequenceContextFormat1]
2026#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2027#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2028pub struct ChainedSequenceRule {
2029    /// Array of backtrack glyph IDs
2030    pub backtrack_sequence: Vec<GlyphId16>,
2031    /// Array of input glyph IDs—start with second glyph
2032    pub input_sequence: Vec<GlyphId16>,
2033    /// Array of lookahead glyph IDs
2034    pub lookahead_sequence: Vec<GlyphId16>,
2035    /// Array of SequenceLookupRecords
2036    pub seq_lookup_records: Vec<SequenceLookupRecord>,
2037}
2038
2039impl ChainedSequenceRule {
2040    /// Construct a new `ChainedSequenceRule`
2041    pub fn new(
2042        backtrack_sequence: Vec<GlyphId16>,
2043        input_sequence: Vec<GlyphId16>,
2044        lookahead_sequence: Vec<GlyphId16>,
2045        seq_lookup_records: Vec<SequenceLookupRecord>,
2046    ) -> Self {
2047        Self {
2048            backtrack_sequence,
2049            input_sequence,
2050            lookahead_sequence,
2051            seq_lookup_records,
2052        }
2053    }
2054}
2055
2056impl FontWrite for ChainedSequenceRule {
2057    #[allow(clippy::unnecessary_cast)]
2058    fn write_into(&self, writer: &mut TableWriter) {
2059        (u16::try_from(array_len(&self.backtrack_sequence)).unwrap()).write_into(writer);
2060        self.backtrack_sequence.write_into(writer);
2061        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
2062        self.input_sequence.write_into(writer);
2063        (u16::try_from(array_len(&self.lookahead_sequence)).unwrap()).write_into(writer);
2064        self.lookahead_sequence.write_into(writer);
2065        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
2066        self.seq_lookup_records.write_into(writer);
2067    }
2068    fn table_type(&self) -> TableType {
2069        TableType::Named("ChainedSequenceRule")
2070    }
2071}
2072
2073impl Validate for ChainedSequenceRule {
2074    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2075        ctx.in_table("ChainedSequenceRule", |ctx| {
2076            ctx.in_field("backtrack_sequence", |ctx| {
2077                if self.backtrack_sequence.len() > to_usize(u16::MAX) {
2078                    ctx.report("array exceeds max length");
2079                }
2080            });
2081            ctx.in_field("lookahead_sequence", |ctx| {
2082                if self.lookahead_sequence.len() > to_usize(u16::MAX) {
2083                    ctx.report("array exceeds max length");
2084                }
2085            });
2086            ctx.in_field("seq_lookup_records", |ctx| {
2087                if self.seq_lookup_records.len() > to_usize(u16::MAX) {
2088                    ctx.report("array exceeds max length");
2089                }
2090                self.seq_lookup_records.validate_impl(ctx);
2091            });
2092        })
2093    }
2094}
2095
2096impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceRule<'a>> for ChainedSequenceRule {
2097    fn from_obj_ref(
2098        obj: &read_fonts::tables::layout::ChainedSequenceRule<'a>,
2099        _: FontData,
2100    ) -> Self {
2101        let offset_data = obj.offset_data();
2102        ChainedSequenceRule {
2103            backtrack_sequence: obj.backtrack_sequence().to_owned_obj(offset_data),
2104            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
2105            lookahead_sequence: obj.lookahead_sequence().to_owned_obj(offset_data),
2106            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
2107        }
2108    }
2109}
2110
2111#[allow(clippy::needless_lifetimes)]
2112impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceRule<'a>> for ChainedSequenceRule {}
2113
2114impl ReadArgs for ChainedSequenceRule {
2115    type Args = ();
2116}
2117
2118impl<'a> FontRead<'a> for ChainedSequenceRule {
2119    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2120        <read_fonts::tables::layout::ChainedSequenceRule as FontRead>::read(data)
2121            .map(|x| x.to_owned_table())
2122    }
2123}
2124
2125/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
2126#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2127#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2128pub struct ChainedSequenceContextFormat2 {
2129    /// Offset to Coverage table, from beginning of
2130    /// ChainedSequenceContextFormat2 table
2131    pub coverage: OffsetMarker<CoverageTable>,
2132    /// Offset to ClassDef table containing backtrack sequence context,
2133    /// from beginning of ChainedSequenceContextFormat2 table
2134    pub backtrack_class_def: OffsetMarker<ClassDef>,
2135    /// Offset to ClassDef table containing input sequence context,
2136    /// from beginning of ChainedSequenceContextFormat2 table
2137    pub input_class_def: OffsetMarker<ClassDef>,
2138    /// Offset to ClassDef table containing lookahead sequence context,
2139    /// from beginning of ChainedSequenceContextFormat2 table
2140    pub lookahead_class_def: OffsetMarker<ClassDef>,
2141    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
2142    /// beginning of ChainedSequenceContextFormat2 table (may be NULL)
2143    pub chained_class_seq_rule_sets: Vec<NullableOffsetMarker<ChainedClassSequenceRuleSet>>,
2144}
2145
2146impl ChainedSequenceContextFormat2 {
2147    /// Construct a new `ChainedSequenceContextFormat2`
2148    pub fn new(
2149        coverage: CoverageTable,
2150        backtrack_class_def: ClassDef,
2151        input_class_def: ClassDef,
2152        lookahead_class_def: ClassDef,
2153        chained_class_seq_rule_sets: Vec<Option<ChainedClassSequenceRuleSet>>,
2154    ) -> Self {
2155        Self {
2156            coverage: coverage.into(),
2157            backtrack_class_def: backtrack_class_def.into(),
2158            input_class_def: input_class_def.into(),
2159            lookahead_class_def: lookahead_class_def.into(),
2160            chained_class_seq_rule_sets: chained_class_seq_rule_sets
2161                .into_iter()
2162                .map(Into::into)
2163                .collect(),
2164        }
2165    }
2166}
2167
2168impl FontWrite for ChainedSequenceContextFormat2 {
2169    #[allow(clippy::unnecessary_cast)]
2170    fn write_into(&self, writer: &mut TableWriter) {
2171        (2 as u16).write_into(writer);
2172        self.coverage.write_into(writer);
2173        self.backtrack_class_def.write_into(writer);
2174        self.input_class_def.write_into(writer);
2175        self.lookahead_class_def.write_into(writer);
2176        (u16::try_from(array_len(&self.chained_class_seq_rule_sets)).unwrap()).write_into(writer);
2177        self.chained_class_seq_rule_sets.write_into(writer);
2178    }
2179    fn table_type(&self) -> TableType {
2180        TableType::Named("ChainedSequenceContextFormat2")
2181    }
2182}
2183
2184impl Validate for ChainedSequenceContextFormat2 {
2185    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2186        ctx.in_table("ChainedSequenceContextFormat2", |ctx| {
2187            ctx.in_field("coverage", |ctx| {
2188                self.coverage.validate_impl(ctx);
2189            });
2190            ctx.in_field("backtrack_class_def", |ctx| {
2191                self.backtrack_class_def.validate_impl(ctx);
2192            });
2193            ctx.in_field("input_class_def", |ctx| {
2194                self.input_class_def.validate_impl(ctx);
2195            });
2196            ctx.in_field("lookahead_class_def", |ctx| {
2197                self.lookahead_class_def.validate_impl(ctx);
2198            });
2199            ctx.in_field("chained_class_seq_rule_sets", |ctx| {
2200                if self.chained_class_seq_rule_sets.len() > to_usize(u16::MAX) {
2201                    ctx.report("array exceeds max length");
2202                }
2203                self.chained_class_seq_rule_sets.validate_impl(ctx);
2204            });
2205        })
2206    }
2207}
2208
2209impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceContextFormat2<'a>>
2210    for ChainedSequenceContextFormat2
2211{
2212    fn from_obj_ref(
2213        obj: &read_fonts::tables::layout::ChainedSequenceContextFormat2<'a>,
2214        _: FontData,
2215    ) -> Self {
2216        ChainedSequenceContextFormat2 {
2217            coverage: obj.coverage().to_owned_table(),
2218            backtrack_class_def: obj.backtrack_class_def().to_owned_table(),
2219            input_class_def: obj.input_class_def().to_owned_table(),
2220            lookahead_class_def: obj.lookahead_class_def().to_owned_table(),
2221            chained_class_seq_rule_sets: obj.chained_class_seq_rule_sets().to_owned_table(),
2222        }
2223    }
2224}
2225
2226#[allow(clippy::needless_lifetimes)]
2227impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceContextFormat2<'a>>
2228    for ChainedSequenceContextFormat2
2229{
2230}
2231
2232impl ReadArgs for ChainedSequenceContextFormat2 {
2233    type Args = ();
2234}
2235
2236impl<'a> FontRead<'a> for ChainedSequenceContextFormat2 {
2237    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2238        <read_fonts::tables::layout::ChainedSequenceContextFormat2 as FontRead>::read(data)
2239            .map(|x| x.to_owned_table())
2240    }
2241}
2242
2243/// Part of [ChainedSequenceContextFormat2]
2244#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2246pub struct ChainedClassSequenceRuleSet {
2247    /// Array of offsets to ChainedClassSequenceRule tables, from
2248    /// beginning of ChainedClassSequenceRuleSet
2249    pub chained_class_seq_rules: Vec<OffsetMarker<ChainedClassSequenceRule>>,
2250}
2251
2252impl ChainedClassSequenceRuleSet {
2253    /// Construct a new `ChainedClassSequenceRuleSet`
2254    pub fn new(chained_class_seq_rules: Vec<ChainedClassSequenceRule>) -> Self {
2255        Self {
2256            chained_class_seq_rules: chained_class_seq_rules
2257                .into_iter()
2258                .map(Into::into)
2259                .collect(),
2260        }
2261    }
2262}
2263
2264impl FontWrite for ChainedClassSequenceRuleSet {
2265    #[allow(clippy::unnecessary_cast)]
2266    fn write_into(&self, writer: &mut TableWriter) {
2267        (u16::try_from(array_len(&self.chained_class_seq_rules)).unwrap()).write_into(writer);
2268        self.chained_class_seq_rules.write_into(writer);
2269    }
2270    fn table_type(&self) -> TableType {
2271        TableType::Named("ChainedClassSequenceRuleSet")
2272    }
2273}
2274
2275impl Validate for ChainedClassSequenceRuleSet {
2276    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2277        ctx.in_table("ChainedClassSequenceRuleSet", |ctx| {
2278            ctx.in_field("chained_class_seq_rules", |ctx| {
2279                if self.chained_class_seq_rules.len() > to_usize(u16::MAX) {
2280                    ctx.report("array exceeds max length");
2281                }
2282                self.chained_class_seq_rules.validate_impl(ctx);
2283            });
2284        })
2285    }
2286}
2287
2288impl<'a> FromObjRef<read_fonts::tables::layout::ChainedClassSequenceRuleSet<'a>>
2289    for ChainedClassSequenceRuleSet
2290{
2291    fn from_obj_ref(
2292        obj: &read_fonts::tables::layout::ChainedClassSequenceRuleSet<'a>,
2293        _: FontData,
2294    ) -> Self {
2295        ChainedClassSequenceRuleSet {
2296            chained_class_seq_rules: obj.chained_class_seq_rules().to_owned_table(),
2297        }
2298    }
2299}
2300
2301#[allow(clippy::needless_lifetimes)]
2302impl<'a> FromTableRef<read_fonts::tables::layout::ChainedClassSequenceRuleSet<'a>>
2303    for ChainedClassSequenceRuleSet
2304{
2305}
2306
2307impl ReadArgs for ChainedClassSequenceRuleSet {
2308    type Args = ();
2309}
2310
2311impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet {
2312    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2313        <read_fonts::tables::layout::ChainedClassSequenceRuleSet as FontRead>::read(data)
2314            .map(|x| x.to_owned_table())
2315    }
2316}
2317
2318/// Part of [ChainedSequenceContextFormat2]
2319#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2321pub struct ChainedClassSequenceRule {
2322    /// Array of backtrack-sequence classes
2323    pub backtrack_sequence: Vec<u16>,
2324    /// Array of input sequence classes, beginning with the second
2325    /// glyph position
2326    pub input_sequence: Vec<u16>,
2327    /// Array of lookahead-sequence classes
2328    pub lookahead_sequence: Vec<u16>,
2329    /// Array of SequenceLookupRecords
2330    pub seq_lookup_records: Vec<SequenceLookupRecord>,
2331}
2332
2333impl ChainedClassSequenceRule {
2334    /// Construct a new `ChainedClassSequenceRule`
2335    pub fn new(
2336        backtrack_sequence: Vec<u16>,
2337        input_sequence: Vec<u16>,
2338        lookahead_sequence: Vec<u16>,
2339        seq_lookup_records: Vec<SequenceLookupRecord>,
2340    ) -> Self {
2341        Self {
2342            backtrack_sequence,
2343            input_sequence,
2344            lookahead_sequence,
2345            seq_lookup_records,
2346        }
2347    }
2348}
2349
2350impl FontWrite for ChainedClassSequenceRule {
2351    #[allow(clippy::unnecessary_cast)]
2352    fn write_into(&self, writer: &mut TableWriter) {
2353        (u16::try_from(array_len(&self.backtrack_sequence)).unwrap()).write_into(writer);
2354        self.backtrack_sequence.write_into(writer);
2355        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
2356        self.input_sequence.write_into(writer);
2357        (u16::try_from(array_len(&self.lookahead_sequence)).unwrap()).write_into(writer);
2358        self.lookahead_sequence.write_into(writer);
2359        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
2360        self.seq_lookup_records.write_into(writer);
2361    }
2362    fn table_type(&self) -> TableType {
2363        TableType::Named("ChainedClassSequenceRule")
2364    }
2365}
2366
2367impl Validate for ChainedClassSequenceRule {
2368    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2369        ctx.in_table("ChainedClassSequenceRule", |ctx| {
2370            ctx.in_field("backtrack_sequence", |ctx| {
2371                if self.backtrack_sequence.len() > to_usize(u16::MAX) {
2372                    ctx.report("array exceeds max length");
2373                }
2374            });
2375            ctx.in_field("lookahead_sequence", |ctx| {
2376                if self.lookahead_sequence.len() > to_usize(u16::MAX) {
2377                    ctx.report("array exceeds max length");
2378                }
2379            });
2380            ctx.in_field("seq_lookup_records", |ctx| {
2381                if self.seq_lookup_records.len() > to_usize(u16::MAX) {
2382                    ctx.report("array exceeds max length");
2383                }
2384                self.seq_lookup_records.validate_impl(ctx);
2385            });
2386        })
2387    }
2388}
2389
2390impl<'a> FromObjRef<read_fonts::tables::layout::ChainedClassSequenceRule<'a>>
2391    for ChainedClassSequenceRule
2392{
2393    fn from_obj_ref(
2394        obj: &read_fonts::tables::layout::ChainedClassSequenceRule<'a>,
2395        _: FontData,
2396    ) -> Self {
2397        let offset_data = obj.offset_data();
2398        ChainedClassSequenceRule {
2399            backtrack_sequence: obj.backtrack_sequence().to_owned_obj(offset_data),
2400            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
2401            lookahead_sequence: obj.lookahead_sequence().to_owned_obj(offset_data),
2402            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
2403        }
2404    }
2405}
2406
2407#[allow(clippy::needless_lifetimes)]
2408impl<'a> FromTableRef<read_fonts::tables::layout::ChainedClassSequenceRule<'a>>
2409    for ChainedClassSequenceRule
2410{
2411}
2412
2413impl ReadArgs for ChainedClassSequenceRule {
2414    type Args = ();
2415}
2416
2417impl<'a> FontRead<'a> for ChainedClassSequenceRule {
2418    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2419        <read_fonts::tables::layout::ChainedClassSequenceRule as FontRead>::read(data)
2420            .map(|x| x.to_owned_table())
2421    }
2422}
2423
2424/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
2425#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2426#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2427pub struct ChainedSequenceContextFormat3 {
2428    /// Array of offsets to coverage tables for the backtrack sequence
2429    pub backtrack_coverages: Vec<OffsetMarker<CoverageTable>>,
2430    /// Array of offsets to coverage tables for the input sequence
2431    pub input_coverages: Vec<OffsetMarker<CoverageTable>>,
2432    /// Array of offsets to coverage tables for the lookahead sequence
2433    pub lookahead_coverages: Vec<OffsetMarker<CoverageTable>>,
2434    /// Array of SequenceLookupRecords
2435    pub seq_lookup_records: Vec<SequenceLookupRecord>,
2436}
2437
2438impl ChainedSequenceContextFormat3 {
2439    /// Construct a new `ChainedSequenceContextFormat3`
2440    pub fn new(
2441        backtrack_coverages: Vec<CoverageTable>,
2442        input_coverages: Vec<CoverageTable>,
2443        lookahead_coverages: Vec<CoverageTable>,
2444        seq_lookup_records: Vec<SequenceLookupRecord>,
2445    ) -> Self {
2446        Self {
2447            backtrack_coverages: backtrack_coverages.into_iter().map(Into::into).collect(),
2448            input_coverages: input_coverages.into_iter().map(Into::into).collect(),
2449            lookahead_coverages: lookahead_coverages.into_iter().map(Into::into).collect(),
2450            seq_lookup_records,
2451        }
2452    }
2453}
2454
2455impl FontWrite for ChainedSequenceContextFormat3 {
2456    #[allow(clippy::unnecessary_cast)]
2457    fn write_into(&self, writer: &mut TableWriter) {
2458        (3 as u16).write_into(writer);
2459        (u16::try_from(array_len(&self.backtrack_coverages)).unwrap()).write_into(writer);
2460        self.backtrack_coverages.write_into(writer);
2461        (u16::try_from(array_len(&self.input_coverages)).unwrap()).write_into(writer);
2462        self.input_coverages.write_into(writer);
2463        (u16::try_from(array_len(&self.lookahead_coverages)).unwrap()).write_into(writer);
2464        self.lookahead_coverages.write_into(writer);
2465        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
2466        self.seq_lookup_records.write_into(writer);
2467    }
2468    fn table_type(&self) -> TableType {
2469        TableType::Named("ChainedSequenceContextFormat3")
2470    }
2471}
2472
2473impl Validate for ChainedSequenceContextFormat3 {
2474    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2475        ctx.in_table("ChainedSequenceContextFormat3", |ctx| {
2476            ctx.in_field("backtrack_coverages", |ctx| {
2477                if self.backtrack_coverages.len() > to_usize(u16::MAX) {
2478                    ctx.report("array exceeds max length");
2479                }
2480                self.backtrack_coverages.validate_impl(ctx);
2481            });
2482            ctx.in_field("input_coverages", |ctx| {
2483                if self.input_coverages.len() > to_usize(u16::MAX) {
2484                    ctx.report("array exceeds max length");
2485                }
2486                self.input_coverages.validate_impl(ctx);
2487            });
2488            ctx.in_field("lookahead_coverages", |ctx| {
2489                if self.lookahead_coverages.len() > to_usize(u16::MAX) {
2490                    ctx.report("array exceeds max length");
2491                }
2492                self.lookahead_coverages.validate_impl(ctx);
2493            });
2494            ctx.in_field("seq_lookup_records", |ctx| {
2495                if self.seq_lookup_records.len() > to_usize(u16::MAX) {
2496                    ctx.report("array exceeds max length");
2497                }
2498                self.seq_lookup_records.validate_impl(ctx);
2499            });
2500        })
2501    }
2502}
2503
2504impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceContextFormat3<'a>>
2505    for ChainedSequenceContextFormat3
2506{
2507    fn from_obj_ref(
2508        obj: &read_fonts::tables::layout::ChainedSequenceContextFormat3<'a>,
2509        _: FontData,
2510    ) -> Self {
2511        let offset_data = obj.offset_data();
2512        ChainedSequenceContextFormat3 {
2513            backtrack_coverages: obj.backtrack_coverages().to_owned_table(),
2514            input_coverages: obj.input_coverages().to_owned_table(),
2515            lookahead_coverages: obj.lookahead_coverages().to_owned_table(),
2516            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
2517        }
2518    }
2519}
2520
2521#[allow(clippy::needless_lifetimes)]
2522impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceContextFormat3<'a>>
2523    for ChainedSequenceContextFormat3
2524{
2525}
2526
2527impl ReadArgs for ChainedSequenceContextFormat3 {
2528    type Args = ();
2529}
2530
2531impl<'a> FontRead<'a> for ChainedSequenceContextFormat3 {
2532    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2533        <read_fonts::tables::layout::ChainedSequenceContextFormat3 as FontRead>::read(data)
2534            .map(|x| x.to_owned_table())
2535    }
2536}
2537
2538#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2539#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2540pub enum ChainedSequenceContext {
2541    Format1(ChainedSequenceContextFormat1),
2542    Format2(ChainedSequenceContextFormat2),
2543    Format3(ChainedSequenceContextFormat3),
2544}
2545
2546impl ChainedSequenceContext {
2547    /// Construct a new `ChainedSequenceContextFormat1` subtable
2548    pub fn format_1(
2549        coverage: CoverageTable,
2550        chained_seq_rule_sets: Vec<Option<ChainedSequenceRuleSet>>,
2551    ) -> Self {
2552        Self::Format1(ChainedSequenceContextFormat1::new(
2553            coverage,
2554            chained_seq_rule_sets,
2555        ))
2556    }
2557
2558    /// Construct a new `ChainedSequenceContextFormat2` subtable
2559    pub fn format_2(
2560        coverage: CoverageTable,
2561        backtrack_class_def: ClassDef,
2562        input_class_def: ClassDef,
2563        lookahead_class_def: ClassDef,
2564        chained_class_seq_rule_sets: Vec<Option<ChainedClassSequenceRuleSet>>,
2565    ) -> Self {
2566        Self::Format2(ChainedSequenceContextFormat2::new(
2567            coverage,
2568            backtrack_class_def,
2569            input_class_def,
2570            lookahead_class_def,
2571            chained_class_seq_rule_sets,
2572        ))
2573    }
2574
2575    /// Construct a new `ChainedSequenceContextFormat3` subtable
2576    pub fn format_3(
2577        backtrack_coverages: Vec<CoverageTable>,
2578        input_coverages: Vec<CoverageTable>,
2579        lookahead_coverages: Vec<CoverageTable>,
2580        seq_lookup_records: Vec<SequenceLookupRecord>,
2581    ) -> Self {
2582        Self::Format3(ChainedSequenceContextFormat3::new(
2583            backtrack_coverages,
2584            input_coverages,
2585            lookahead_coverages,
2586            seq_lookup_records,
2587        ))
2588    }
2589}
2590
2591impl Default for ChainedSequenceContext {
2592    fn default() -> Self {
2593        Self::Format1(Default::default())
2594    }
2595}
2596
2597impl FontWrite for ChainedSequenceContext {
2598    fn write_into(&self, writer: &mut TableWriter) {
2599        match self {
2600            Self::Format1(item) => item.write_into(writer),
2601            Self::Format2(item) => item.write_into(writer),
2602            Self::Format3(item) => item.write_into(writer),
2603        }
2604    }
2605    fn table_type(&self) -> TableType {
2606        match self {
2607            Self::Format1(item) => item.table_type(),
2608            Self::Format2(item) => item.table_type(),
2609            Self::Format3(item) => item.table_type(),
2610        }
2611    }
2612}
2613
2614impl Validate for ChainedSequenceContext {
2615    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2616        match self {
2617            Self::Format1(item) => item.validate_impl(ctx),
2618            Self::Format2(item) => item.validate_impl(ctx),
2619            Self::Format3(item) => item.validate_impl(ctx),
2620        }
2621    }
2622}
2623
2624impl FromObjRef<read_fonts::tables::layout::ChainedSequenceContext<'_>> for ChainedSequenceContext {
2625    fn from_obj_ref(obj: &read_fonts::tables::layout::ChainedSequenceContext, _: FontData) -> Self {
2626        use read_fonts::tables::layout::ChainedSequenceContext as ObjRefType;
2627        match obj {
2628            ObjRefType::Format1(item) => ChainedSequenceContext::Format1(item.to_owned_table()),
2629            ObjRefType::Format2(item) => ChainedSequenceContext::Format2(item.to_owned_table()),
2630            ObjRefType::Format3(item) => ChainedSequenceContext::Format3(item.to_owned_table()),
2631        }
2632    }
2633}
2634
2635impl FromTableRef<read_fonts::tables::layout::ChainedSequenceContext<'_>>
2636    for ChainedSequenceContext
2637{
2638}
2639
2640impl ReadArgs for ChainedSequenceContext {
2641    type Args = ();
2642}
2643
2644impl<'a> FontRead<'a> for ChainedSequenceContext {
2645    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2646        <read_fonts::tables::layout::ChainedSequenceContext as FontRead>::read(data)
2647            .map(|x| x.to_owned_table())
2648    }
2649}
2650
2651impl From<ChainedSequenceContextFormat1> for ChainedSequenceContext {
2652    fn from(src: ChainedSequenceContextFormat1) -> ChainedSequenceContext {
2653        ChainedSequenceContext::Format1(src)
2654    }
2655}
2656
2657impl From<ChainedSequenceContextFormat2> for ChainedSequenceContext {
2658    fn from(src: ChainedSequenceContextFormat2) -> ChainedSequenceContext {
2659        ChainedSequenceContext::Format2(src)
2660    }
2661}
2662
2663impl From<ChainedSequenceContextFormat3> for ChainedSequenceContext {
2664    fn from(src: ChainedSequenceContextFormat3) -> ChainedSequenceContext {
2665        ChainedSequenceContext::Format3(src)
2666    }
2667}
2668
2669impl FontWrite for DeltaFormat {
2670    fn write_into(&self, writer: &mut TableWriter) {
2671        let val = *self as u16;
2672        writer.write_slice(&val.to_be_bytes())
2673    }
2674}
2675
2676/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
2677#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2678#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2679pub struct Device {
2680    /// Smallest size to correct, in ppem
2681    pub start_size: u16,
2682    /// Largest size to correct, in ppem
2683    pub end_size: u16,
2684    /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
2685    pub delta_format: DeltaFormat,
2686    /// Array of compressed data
2687    pub delta_value: Vec<u16>,
2688}
2689
2690impl FontWrite for Device {
2691    fn write_into(&self, writer: &mut TableWriter) {
2692        self.start_size.write_into(writer);
2693        self.end_size.write_into(writer);
2694        self.delta_format.write_into(writer);
2695        self.delta_value.write_into(writer);
2696    }
2697    fn table_type(&self) -> TableType {
2698        TableType::Named("Device")
2699    }
2700}
2701
2702impl Validate for Device {
2703    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
2704}
2705
2706impl<'a> FromObjRef<read_fonts::tables::layout::Device<'a>> for Device {
2707    fn from_obj_ref(obj: &read_fonts::tables::layout::Device<'a>, _: FontData) -> Self {
2708        let offset_data = obj.offset_data();
2709        Device {
2710            start_size: obj.start_size(),
2711            end_size: obj.end_size(),
2712            delta_format: obj.delta_format(),
2713            delta_value: obj.delta_value().to_owned_obj(offset_data),
2714        }
2715    }
2716}
2717
2718#[allow(clippy::needless_lifetimes)]
2719impl<'a> FromTableRef<read_fonts::tables::layout::Device<'a>> for Device {}
2720
2721impl ReadArgs for Device {
2722    type Args = ();
2723}
2724
2725impl<'a> FontRead<'a> for Device {
2726    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2727        <read_fonts::tables::layout::Device as FontRead>::read(data).map(|x| x.to_owned_table())
2728    }
2729}
2730
2731/// Variation index table
2732#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2733#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2734pub struct VariationIndex {
2735    /// A delta-set outer index — used to select an item variation
2736    /// data subtable within the item variation store.
2737    pub delta_set_outer_index: u16,
2738    /// A delta-set inner index — used to select a delta-set row
2739    /// within an item variation data subtable.
2740    pub delta_set_inner_index: u16,
2741}
2742
2743impl VariationIndex {
2744    /// Construct a new `VariationIndex`
2745    pub fn new(delta_set_outer_index: u16, delta_set_inner_index: u16) -> Self {
2746        Self {
2747            delta_set_outer_index,
2748            delta_set_inner_index,
2749        }
2750    }
2751}
2752
2753impl FontWrite for VariationIndex {
2754    #[allow(clippy::unnecessary_cast)]
2755    fn write_into(&self, writer: &mut TableWriter) {
2756        self.delta_set_outer_index.write_into(writer);
2757        self.delta_set_inner_index.write_into(writer);
2758        (DeltaFormat::VariationIndex as DeltaFormat).write_into(writer);
2759    }
2760    fn table_type(&self) -> TableType {
2761        TableType::Named("VariationIndex")
2762    }
2763}
2764
2765impl Validate for VariationIndex {
2766    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
2767}
2768
2769impl<'a> FromObjRef<read_fonts::tables::layout::VariationIndex<'a>> for VariationIndex {
2770    fn from_obj_ref(obj: &read_fonts::tables::layout::VariationIndex<'a>, _: FontData) -> Self {
2771        VariationIndex {
2772            delta_set_outer_index: obj.delta_set_outer_index(),
2773            delta_set_inner_index: obj.delta_set_inner_index(),
2774        }
2775    }
2776}
2777
2778#[allow(clippy::needless_lifetimes)]
2779impl<'a> FromTableRef<read_fonts::tables::layout::VariationIndex<'a>> for VariationIndex {}
2780
2781impl ReadArgs for VariationIndex {
2782    type Args = ();
2783}
2784
2785impl<'a> FontRead<'a> for VariationIndex {
2786    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2787        <read_fonts::tables::layout::VariationIndex as FontRead>::read(data)
2788            .map(|x| x.to_owned_table())
2789    }
2790}
2791
2792/// A type representing a temporary identifier for a set of variation deltas.
2793///
2794/// The final indices used in the VariationIndex table are not known until
2795/// all deltas have been collected. This variant is used to assign a
2796/// temporary identifier during compilation.
2797///
2798/// This type is not part of the spec and will never appear in an actual font file.
2799/// It is intended to serve as a sentinel value, and will panic when written,
2800/// ensuring that all VariationIndex tables have been correctly mapped before
2801/// the font is compiled.
2802#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2803#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2804pub struct PendingVariationIndex {
2805    /// A unique identifier for a given set of deltas.
2806    pub delta_set_id: u32,
2807}
2808
2809impl PendingVariationIndex {
2810    /// Construct a new `PendingVariationIndex`
2811    pub fn new(delta_set_id: u32) -> Self {
2812        Self { delta_set_id }
2813    }
2814}
2815
2816impl Validate for PendingVariationIndex {
2817    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
2818}
2819
2820/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
2821#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2822#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2823pub enum DeviceOrVariationIndex {
2824    Device(Device),
2825    VariationIndex(VariationIndex),
2826    PendingVariationIndex(PendingVariationIndex),
2827}
2828
2829impl DeviceOrVariationIndex {
2830    /// Construct a new `VariationIndex` subtable
2831    pub fn variation_index(delta_set_outer_index: u16, delta_set_inner_index: u16) -> Self {
2832        Self::VariationIndex(VariationIndex::new(
2833            delta_set_outer_index,
2834            delta_set_inner_index,
2835        ))
2836    }
2837
2838    /// Construct a new `PendingVariationIndex` subtable
2839    pub fn pending_variation_index(delta_set_id: u32) -> Self {
2840        Self::PendingVariationIndex(PendingVariationIndex::new(delta_set_id))
2841    }
2842}
2843
2844impl Default for DeviceOrVariationIndex {
2845    fn default() -> Self {
2846        Self::Device(Default::default())
2847    }
2848}
2849
2850impl FontWrite for DeviceOrVariationIndex {
2851    fn write_into(&self, writer: &mut TableWriter) {
2852        match self {
2853            Self::Device(item) => item.write_into(writer),
2854            Self::VariationIndex(item) => item.write_into(writer),
2855            Self::PendingVariationIndex(item) => item.write_into(writer),
2856        }
2857    }
2858    fn table_type(&self) -> TableType {
2859        match self {
2860            Self::Device(item) => item.table_type(),
2861            Self::VariationIndex(item) => item.table_type(),
2862            Self::PendingVariationIndex(item) => item.table_type(),
2863        }
2864    }
2865}
2866
2867impl Validate for DeviceOrVariationIndex {
2868    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2869        match self {
2870            Self::Device(item) => item.validate_impl(ctx),
2871            Self::VariationIndex(item) => item.validate_impl(ctx),
2872            Self::PendingVariationIndex(item) => item.validate_impl(ctx),
2873        }
2874    }
2875}
2876
2877impl FromObjRef<read_fonts::tables::layout::DeviceOrVariationIndex<'_>> for DeviceOrVariationIndex {
2878    fn from_obj_ref(obj: &read_fonts::tables::layout::DeviceOrVariationIndex, _: FontData) -> Self {
2879        use read_fonts::tables::layout::DeviceOrVariationIndex as ObjRefType;
2880        match obj {
2881            ObjRefType::Device(item) => DeviceOrVariationIndex::Device(item.to_owned_table()),
2882            ObjRefType::VariationIndex(item) => {
2883                DeviceOrVariationIndex::VariationIndex(item.to_owned_table())
2884            }
2885        }
2886    }
2887}
2888
2889impl FromTableRef<read_fonts::tables::layout::DeviceOrVariationIndex<'_>>
2890    for DeviceOrVariationIndex
2891{
2892}
2893
2894impl ReadArgs for DeviceOrVariationIndex {
2895    type Args = ();
2896}
2897
2898impl<'a> FontRead<'a> for DeviceOrVariationIndex {
2899    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2900        <read_fonts::tables::layout::DeviceOrVariationIndex as FontRead>::read(data)
2901            .map(|x| x.to_owned_table())
2902    }
2903}
2904
2905impl From<Device> for DeviceOrVariationIndex {
2906    fn from(src: Device) -> DeviceOrVariationIndex {
2907        DeviceOrVariationIndex::Device(src)
2908    }
2909}
2910
2911impl From<VariationIndex> for DeviceOrVariationIndex {
2912    fn from(src: VariationIndex) -> DeviceOrVariationIndex {
2913        DeviceOrVariationIndex::VariationIndex(src)
2914    }
2915}
2916
2917impl From<PendingVariationIndex> for DeviceOrVariationIndex {
2918    fn from(src: PendingVariationIndex) -> DeviceOrVariationIndex {
2919        DeviceOrVariationIndex::PendingVariationIndex(src)
2920    }
2921}
2922
2923/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
2924#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2925#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2926pub struct FeatureVariations {
2927    /// Array of feature variation records.
2928    pub feature_variation_records: Vec<FeatureVariationRecord>,
2929}
2930
2931impl FeatureVariations {
2932    /// Construct a new `FeatureVariations`
2933    pub fn new(feature_variation_records: Vec<FeatureVariationRecord>) -> Self {
2934        Self {
2935            feature_variation_records,
2936        }
2937    }
2938}
2939
2940impl FontWrite for FeatureVariations {
2941    #[allow(clippy::unnecessary_cast)]
2942    fn write_into(&self, writer: &mut TableWriter) {
2943        (MajorMinor::VERSION_1_0 as MajorMinor).write_into(writer);
2944        (u32::try_from(array_len(&self.feature_variation_records)).unwrap()).write_into(writer);
2945        self.feature_variation_records.write_into(writer);
2946    }
2947    fn table_type(&self) -> TableType {
2948        TableType::Named("FeatureVariations")
2949    }
2950}
2951
2952impl Validate for FeatureVariations {
2953    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2954        ctx.in_table("FeatureVariations", |ctx| {
2955            ctx.in_field("feature_variation_records", |ctx| {
2956                if self.feature_variation_records.len() > to_usize(u32::MAX) {
2957                    ctx.report("array exceeds max length");
2958                }
2959                self.feature_variation_records.validate_impl(ctx);
2960            });
2961        })
2962    }
2963}
2964
2965impl<'a> FromObjRef<read_fonts::tables::layout::FeatureVariations<'a>> for FeatureVariations {
2966    fn from_obj_ref(obj: &read_fonts::tables::layout::FeatureVariations<'a>, _: FontData) -> Self {
2967        let offset_data = obj.offset_data();
2968        FeatureVariations {
2969            feature_variation_records: obj.feature_variation_records().to_owned_obj(offset_data),
2970        }
2971    }
2972}
2973
2974#[allow(clippy::needless_lifetimes)]
2975impl<'a> FromTableRef<read_fonts::tables::layout::FeatureVariations<'a>> for FeatureVariations {}
2976
2977impl ReadArgs for FeatureVariations {
2978    type Args = ();
2979}
2980
2981impl<'a> FontRead<'a> for FeatureVariations {
2982    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2983        <read_fonts::tables::layout::FeatureVariations as FontRead>::read(data)
2984            .map(|x| x.to_owned_table())
2985    }
2986}
2987
2988/// Part of [FeatureVariations]
2989#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
2990#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2991pub struct FeatureVariationRecord {
2992    /// Offset to a condition set table, from beginning of
2993    /// FeatureVariations table.
2994    pub condition_set: NullableOffsetMarker<ConditionSet, WIDTH_32>,
2995    /// Offset to a feature table substitution table, from beginning of
2996    /// the FeatureVariations table.
2997    pub feature_table_substitution: NullableOffsetMarker<FeatureTableSubstitution, WIDTH_32>,
2998}
2999
3000impl FeatureVariationRecord {
3001    /// Construct a new `FeatureVariationRecord`
3002    pub fn new(
3003        condition_set: Option<ConditionSet>,
3004        feature_table_substitution: Option<FeatureTableSubstitution>,
3005    ) -> Self {
3006        Self {
3007            condition_set: condition_set.into(),
3008            feature_table_substitution: feature_table_substitution.into(),
3009        }
3010    }
3011}
3012
3013impl FontWrite for FeatureVariationRecord {
3014    fn write_into(&self, writer: &mut TableWriter) {
3015        self.condition_set.write_into(writer);
3016        self.feature_table_substitution.write_into(writer);
3017    }
3018    fn table_type(&self) -> TableType {
3019        TableType::Named("FeatureVariationRecord")
3020    }
3021}
3022
3023impl Validate for FeatureVariationRecord {
3024    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3025        ctx.in_table("FeatureVariationRecord", |ctx| {
3026            ctx.in_field("condition_set", |ctx| {
3027                self.condition_set.validate_impl(ctx);
3028            });
3029            ctx.in_field("feature_table_substitution", |ctx| {
3030                self.feature_table_substitution.validate_impl(ctx);
3031            });
3032        })
3033    }
3034}
3035
3036impl FromObjRef<read_fonts::tables::layout::FeatureVariationRecord> for FeatureVariationRecord {
3037    fn from_obj_ref(
3038        obj: &read_fonts::tables::layout::FeatureVariationRecord,
3039        offset_data: FontData,
3040    ) -> Self {
3041        FeatureVariationRecord {
3042            condition_set: obj.condition_set(offset_data).to_owned_table(),
3043            feature_table_substitution: obj
3044                .feature_table_substitution(offset_data)
3045                .to_owned_table(),
3046        }
3047    }
3048}
3049
3050/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
3051#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3052#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3053pub struct ConditionSet {
3054    /// Array of offsets to condition tables, from beginning of the
3055    /// ConditionSet table.
3056    pub conditions: Vec<OffsetMarker<Condition, WIDTH_32>>,
3057}
3058
3059impl ConditionSet {
3060    /// Construct a new `ConditionSet`
3061    pub fn new(conditions: Vec<Condition>) -> Self {
3062        Self {
3063            conditions: conditions.into_iter().map(Into::into).collect(),
3064        }
3065    }
3066}
3067
3068impl FontWrite for ConditionSet {
3069    #[allow(clippy::unnecessary_cast)]
3070    fn write_into(&self, writer: &mut TableWriter) {
3071        (u16::try_from(array_len(&self.conditions)).unwrap()).write_into(writer);
3072        self.conditions.write_into(writer);
3073    }
3074    fn table_type(&self) -> TableType {
3075        TableType::Named("ConditionSet")
3076    }
3077}
3078
3079impl Validate for ConditionSet {
3080    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3081        ctx.in_table("ConditionSet", |ctx| {
3082            ctx.in_field("conditions", |ctx| {
3083                if self.conditions.len() > to_usize(u16::MAX) {
3084                    ctx.report("array exceeds max length");
3085                }
3086                self.conditions.validate_impl(ctx);
3087            });
3088        })
3089    }
3090}
3091
3092impl<'a> FromObjRef<read_fonts::tables::layout::ConditionSet<'a>> for ConditionSet {
3093    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionSet<'a>, _: FontData) -> Self {
3094        ConditionSet {
3095            conditions: obj.conditions().to_owned_table(),
3096        }
3097    }
3098}
3099
3100#[allow(clippy::needless_lifetimes)]
3101impl<'a> FromTableRef<read_fonts::tables::layout::ConditionSet<'a>> for ConditionSet {}
3102
3103impl ReadArgs for ConditionSet {
3104    type Args = ();
3105}
3106
3107impl<'a> FontRead<'a> for ConditionSet {
3108    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3109        <read_fonts::tables::layout::ConditionSet as FontRead>::read(data)
3110            .map(|x| x.to_owned_table())
3111    }
3112}
3113
3114/// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table)
3115///
3116/// Formats 2..5 are implementations of specification changes currently under debate at ISO for an OFF
3117/// update. For the time being the specification is <https://github.com/harfbuzz/boring-expansion-spec/blob/main/ConditionTree.md>.
3118#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
3119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3120pub enum Condition {
3121    Format1AxisRange(ConditionFormat1),
3122    Format2VariableValue(ConditionFormat2),
3123    Format3And(ConditionFormat3),
3124    Format4Or(ConditionFormat4),
3125    Format5Negate(ConditionFormat5),
3126}
3127
3128impl Condition {
3129    /// Construct a new `ConditionFormat1` subtable
3130    pub fn format_1_axis_range(
3131        axis_index: u16,
3132        filter_range_min_value: F2Dot14,
3133        filter_range_max_value: F2Dot14,
3134    ) -> Self {
3135        Self::Format1AxisRange(ConditionFormat1::new(
3136            axis_index,
3137            filter_range_min_value,
3138            filter_range_max_value,
3139        ))
3140    }
3141
3142    /// Construct a new `ConditionFormat2` subtable
3143    pub fn format_2_variable_value(default_value: i16, var_index: u32) -> Self {
3144        Self::Format2VariableValue(ConditionFormat2::new(default_value, var_index))
3145    }
3146
3147    /// Construct a new `ConditionFormat3` subtable
3148    pub fn format_3_and(condition_count: u8, conditions: Vec<Condition>) -> Self {
3149        Self::Format3And(ConditionFormat3::new(condition_count, conditions))
3150    }
3151
3152    /// Construct a new `ConditionFormat4` subtable
3153    pub fn format_4_or(condition_count: u8, conditions: Vec<Condition>) -> Self {
3154        Self::Format4Or(ConditionFormat4::new(condition_count, conditions))
3155    }
3156
3157    /// Construct a new `ConditionFormat5` subtable
3158    pub fn format_5_negate(condition: Condition) -> Self {
3159        Self::Format5Negate(ConditionFormat5::new(condition))
3160    }
3161}
3162
3163impl Default for Condition {
3164    fn default() -> Self {
3165        Self::Format1AxisRange(Default::default())
3166    }
3167}
3168
3169impl FontWrite for Condition {
3170    fn write_into(&self, writer: &mut TableWriter) {
3171        match self {
3172            Self::Format1AxisRange(item) => item.write_into(writer),
3173            Self::Format2VariableValue(item) => item.write_into(writer),
3174            Self::Format3And(item) => item.write_into(writer),
3175            Self::Format4Or(item) => item.write_into(writer),
3176            Self::Format5Negate(item) => item.write_into(writer),
3177        }
3178    }
3179    fn table_type(&self) -> TableType {
3180        match self {
3181            Self::Format1AxisRange(item) => item.table_type(),
3182            Self::Format2VariableValue(item) => item.table_type(),
3183            Self::Format3And(item) => item.table_type(),
3184            Self::Format4Or(item) => item.table_type(),
3185            Self::Format5Negate(item) => item.table_type(),
3186        }
3187    }
3188}
3189
3190impl Validate for Condition {
3191    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3192        match self {
3193            Self::Format1AxisRange(item) => item.validate_impl(ctx),
3194            Self::Format2VariableValue(item) => item.validate_impl(ctx),
3195            Self::Format3And(item) => item.validate_impl(ctx),
3196            Self::Format4Or(item) => item.validate_impl(ctx),
3197            Self::Format5Negate(item) => item.validate_impl(ctx),
3198        }
3199    }
3200}
3201
3202impl FromObjRef<read_fonts::tables::layout::Condition<'_>> for Condition {
3203    fn from_obj_ref(obj: &read_fonts::tables::layout::Condition, _: FontData) -> Self {
3204        use read_fonts::tables::layout::Condition as ObjRefType;
3205        match obj {
3206            ObjRefType::Format1AxisRange(item) => {
3207                Condition::Format1AxisRange(item.to_owned_table())
3208            }
3209            ObjRefType::Format2VariableValue(item) => {
3210                Condition::Format2VariableValue(item.to_owned_table())
3211            }
3212            ObjRefType::Format3And(item) => Condition::Format3And(item.to_owned_table()),
3213            ObjRefType::Format4Or(item) => Condition::Format4Or(item.to_owned_table()),
3214            ObjRefType::Format5Negate(item) => Condition::Format5Negate(item.to_owned_table()),
3215        }
3216    }
3217}
3218
3219impl FromTableRef<read_fonts::tables::layout::Condition<'_>> for Condition {}
3220
3221impl ReadArgs for Condition {
3222    type Args = ();
3223}
3224
3225impl<'a> FontRead<'a> for Condition {
3226    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3227        <read_fonts::tables::layout::Condition as FontRead>::read(data).map(|x| x.to_owned_table())
3228    }
3229}
3230
3231impl From<ConditionFormat1> for Condition {
3232    fn from(src: ConditionFormat1) -> Condition {
3233        Condition::Format1AxisRange(src)
3234    }
3235}
3236
3237impl From<ConditionFormat2> for Condition {
3238    fn from(src: ConditionFormat2) -> Condition {
3239        Condition::Format2VariableValue(src)
3240    }
3241}
3242
3243impl From<ConditionFormat3> for Condition {
3244    fn from(src: ConditionFormat3) -> Condition {
3245        Condition::Format3And(src)
3246    }
3247}
3248
3249impl From<ConditionFormat4> for Condition {
3250    fn from(src: ConditionFormat4) -> Condition {
3251        Condition::Format4Or(src)
3252    }
3253}
3254
3255impl From<ConditionFormat5> for Condition {
3256    fn from(src: ConditionFormat5) -> Condition {
3257        Condition::Format5Negate(src)
3258    }
3259}
3260
3261/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
3262#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3263#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3264pub struct ConditionFormat1 {
3265    /// Index (zero-based) for the variation axis within the 'fvar'
3266    /// table.
3267    pub axis_index: u16,
3268    /// Minimum value of the font variation instances that satisfy this
3269    /// condition.
3270    pub filter_range_min_value: F2Dot14,
3271    /// Maximum value of the font variation instances that satisfy this
3272    /// condition.
3273    pub filter_range_max_value: F2Dot14,
3274}
3275
3276impl ConditionFormat1 {
3277    /// Construct a new `ConditionFormat1`
3278    pub fn new(
3279        axis_index: u16,
3280        filter_range_min_value: F2Dot14,
3281        filter_range_max_value: F2Dot14,
3282    ) -> Self {
3283        Self {
3284            axis_index,
3285            filter_range_min_value,
3286            filter_range_max_value,
3287        }
3288    }
3289}
3290
3291impl FontWrite for ConditionFormat1 {
3292    #[allow(clippy::unnecessary_cast)]
3293    fn write_into(&self, writer: &mut TableWriter) {
3294        (1 as u16).write_into(writer);
3295        self.axis_index.write_into(writer);
3296        self.filter_range_min_value.write_into(writer);
3297        self.filter_range_max_value.write_into(writer);
3298    }
3299    fn table_type(&self) -> TableType {
3300        TableType::Named("ConditionFormat1")
3301    }
3302}
3303
3304impl Validate for ConditionFormat1 {
3305    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
3306}
3307
3308impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat1<'a>> for ConditionFormat1 {
3309    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat1<'a>, _: FontData) -> Self {
3310        ConditionFormat1 {
3311            axis_index: obj.axis_index(),
3312            filter_range_min_value: obj.filter_range_min_value(),
3313            filter_range_max_value: obj.filter_range_max_value(),
3314        }
3315    }
3316}
3317
3318#[allow(clippy::needless_lifetimes)]
3319impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat1<'a>> for ConditionFormat1 {}
3320
3321impl ReadArgs for ConditionFormat1 {
3322    type Args = ();
3323}
3324
3325impl<'a> FontRead<'a> for ConditionFormat1 {
3326    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3327        <read_fonts::tables::layout::ConditionFormat1 as FontRead>::read(data)
3328            .map(|x| x.to_owned_table())
3329    }
3330}
3331
3332/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
3333#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3334#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3335pub struct ConditionFormat2 {
3336    /// Value at default instance.
3337    pub default_value: i16,
3338    /// Variation index to vary the value based on current designspace location.
3339    pub var_index: u32,
3340}
3341
3342impl ConditionFormat2 {
3343    /// Construct a new `ConditionFormat2`
3344    pub fn new(default_value: i16, var_index: u32) -> Self {
3345        Self {
3346            default_value,
3347            var_index,
3348        }
3349    }
3350}
3351
3352impl FontWrite for ConditionFormat2 {
3353    #[allow(clippy::unnecessary_cast)]
3354    fn write_into(&self, writer: &mut TableWriter) {
3355        (2 as u16).write_into(writer);
3356        self.default_value.write_into(writer);
3357        self.var_index.write_into(writer);
3358    }
3359    fn table_type(&self) -> TableType {
3360        TableType::Named("ConditionFormat2")
3361    }
3362}
3363
3364impl Validate for ConditionFormat2 {
3365    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
3366}
3367
3368impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat2<'a>> for ConditionFormat2 {
3369    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat2<'a>, _: FontData) -> Self {
3370        ConditionFormat2 {
3371            default_value: obj.default_value(),
3372            var_index: obj.var_index(),
3373        }
3374    }
3375}
3376
3377#[allow(clippy::needless_lifetimes)]
3378impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat2<'a>> for ConditionFormat2 {}
3379
3380impl ReadArgs for ConditionFormat2 {
3381    type Args = ();
3382}
3383
3384impl<'a> FontRead<'a> for ConditionFormat2 {
3385    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3386        <read_fonts::tables::layout::ConditionFormat2 as FontRead>::read(data)
3387            .map(|x| x.to_owned_table())
3388    }
3389}
3390
3391/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
3392#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3393#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3394pub struct ConditionFormat3 {
3395    /// Number of conditions.
3396    pub condition_count: u8,
3397    /// Array of condition tables for this conjunction (AND) expression.
3398    pub conditions: Vec<OffsetMarker<Condition, WIDTH_24>>,
3399}
3400
3401impl ConditionFormat3 {
3402    /// Construct a new `ConditionFormat3`
3403    pub fn new(condition_count: u8, conditions: Vec<Condition>) -> Self {
3404        Self {
3405            condition_count,
3406            conditions: conditions.into_iter().map(Into::into).collect(),
3407        }
3408    }
3409}
3410
3411impl FontWrite for ConditionFormat3 {
3412    #[allow(clippy::unnecessary_cast)]
3413    fn write_into(&self, writer: &mut TableWriter) {
3414        (3 as u16).write_into(writer);
3415        self.condition_count.write_into(writer);
3416        self.conditions.write_into(writer);
3417    }
3418    fn table_type(&self) -> TableType {
3419        TableType::Named("ConditionFormat3")
3420    }
3421}
3422
3423impl Validate for ConditionFormat3 {
3424    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3425        ctx.in_table("ConditionFormat3", |ctx| {
3426            ctx.in_field("conditions", |ctx| {
3427                if self.conditions.len() > to_usize(u8::MAX) {
3428                    ctx.report("array exceeds max length");
3429                }
3430                self.conditions.validate_impl(ctx);
3431            });
3432        })
3433    }
3434}
3435
3436impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat3<'a>> for ConditionFormat3 {
3437    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat3<'a>, _: FontData) -> Self {
3438        ConditionFormat3 {
3439            condition_count: obj.condition_count(),
3440            conditions: obj.conditions().to_owned_table(),
3441        }
3442    }
3443}
3444
3445#[allow(clippy::needless_lifetimes)]
3446impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat3<'a>> for ConditionFormat3 {}
3447
3448impl ReadArgs for ConditionFormat3 {
3449    type Args = ();
3450}
3451
3452impl<'a> FontRead<'a> for ConditionFormat3 {
3453    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3454        <read_fonts::tables::layout::ConditionFormat3 as FontRead>::read(data)
3455            .map(|x| x.to_owned_table())
3456    }
3457}
3458
3459/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
3460#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3461#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3462pub struct ConditionFormat4 {
3463    /// Number of conditions.
3464    pub condition_count: u8,
3465    /// Array of condition tables for this disjunction (OR) expression.
3466    pub conditions: Vec<OffsetMarker<Condition, WIDTH_24>>,
3467}
3468
3469impl ConditionFormat4 {
3470    /// Construct a new `ConditionFormat4`
3471    pub fn new(condition_count: u8, conditions: Vec<Condition>) -> Self {
3472        Self {
3473            condition_count,
3474            conditions: conditions.into_iter().map(Into::into).collect(),
3475        }
3476    }
3477}
3478
3479impl FontWrite for ConditionFormat4 {
3480    #[allow(clippy::unnecessary_cast)]
3481    fn write_into(&self, writer: &mut TableWriter) {
3482        (4 as u16).write_into(writer);
3483        self.condition_count.write_into(writer);
3484        self.conditions.write_into(writer);
3485    }
3486    fn table_type(&self) -> TableType {
3487        TableType::Named("ConditionFormat4")
3488    }
3489}
3490
3491impl Validate for ConditionFormat4 {
3492    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3493        ctx.in_table("ConditionFormat4", |ctx| {
3494            ctx.in_field("conditions", |ctx| {
3495                if self.conditions.len() > to_usize(u8::MAX) {
3496                    ctx.report("array exceeds max length");
3497                }
3498                self.conditions.validate_impl(ctx);
3499            });
3500        })
3501    }
3502}
3503
3504impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat4<'a>> for ConditionFormat4 {
3505    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat4<'a>, _: FontData) -> Self {
3506        ConditionFormat4 {
3507            condition_count: obj.condition_count(),
3508            conditions: obj.conditions().to_owned_table(),
3509        }
3510    }
3511}
3512
3513#[allow(clippy::needless_lifetimes)]
3514impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat4<'a>> for ConditionFormat4 {}
3515
3516impl ReadArgs for ConditionFormat4 {
3517    type Args = ();
3518}
3519
3520impl<'a> FontRead<'a> for ConditionFormat4 {
3521    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3522        <read_fonts::tables::layout::ConditionFormat4 as FontRead>::read(data)
3523            .map(|x| x.to_owned_table())
3524    }
3525}
3526
3527/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
3528#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3529#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3530pub struct ConditionFormat5 {
3531    /// Condition to negate.
3532    pub condition: OffsetMarker<Condition, WIDTH_24>,
3533}
3534
3535impl ConditionFormat5 {
3536    /// Construct a new `ConditionFormat5`
3537    pub fn new(condition: Condition) -> Self {
3538        Self {
3539            condition: condition.into(),
3540        }
3541    }
3542}
3543
3544impl FontWrite for ConditionFormat5 {
3545    #[allow(clippy::unnecessary_cast)]
3546    fn write_into(&self, writer: &mut TableWriter) {
3547        (5 as u16).write_into(writer);
3548        self.condition.write_into(writer);
3549    }
3550    fn table_type(&self) -> TableType {
3551        TableType::Named("ConditionFormat5")
3552    }
3553}
3554
3555impl Validate for ConditionFormat5 {
3556    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3557        ctx.in_table("ConditionFormat5", |ctx| {
3558            ctx.in_field("condition", |ctx| {
3559                self.condition.validate_impl(ctx);
3560            });
3561        })
3562    }
3563}
3564
3565impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat5<'a>> for ConditionFormat5 {
3566    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat5<'a>, _: FontData) -> Self {
3567        ConditionFormat5 {
3568            condition: obj.condition().to_owned_table(),
3569        }
3570    }
3571}
3572
3573#[allow(clippy::needless_lifetimes)]
3574impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat5<'a>> for ConditionFormat5 {}
3575
3576impl ReadArgs for ConditionFormat5 {
3577    type Args = ();
3578}
3579
3580impl<'a> FontRead<'a> for ConditionFormat5 {
3581    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3582        <read_fonts::tables::layout::ConditionFormat5 as FontRead>::read(data)
3583            .map(|x| x.to_owned_table())
3584    }
3585}
3586
3587/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
3588#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3589#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3590pub struct FeatureTableSubstitution {
3591    /// Array of feature table substitution records.
3592    pub substitutions: Vec<FeatureTableSubstitutionRecord>,
3593}
3594
3595impl FeatureTableSubstitution {
3596    /// Construct a new `FeatureTableSubstitution`
3597    pub fn new(substitutions: Vec<FeatureTableSubstitutionRecord>) -> Self {
3598        Self { substitutions }
3599    }
3600}
3601
3602impl FontWrite for FeatureTableSubstitution {
3603    #[allow(clippy::unnecessary_cast)]
3604    fn write_into(&self, writer: &mut TableWriter) {
3605        (MajorMinor::VERSION_1_0 as MajorMinor).write_into(writer);
3606        (u16::try_from(array_len(&self.substitutions)).unwrap()).write_into(writer);
3607        self.substitutions.write_into(writer);
3608    }
3609    fn table_type(&self) -> TableType {
3610        TableType::Named("FeatureTableSubstitution")
3611    }
3612}
3613
3614impl Validate for FeatureTableSubstitution {
3615    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3616        ctx.in_table("FeatureTableSubstitution", |ctx| {
3617            ctx.in_field("substitutions", |ctx| {
3618                if self.substitutions.len() > to_usize(u16::MAX) {
3619                    ctx.report("array exceeds max length");
3620                }
3621                self.substitutions.validate_impl(ctx);
3622            });
3623        })
3624    }
3625}
3626
3627impl<'a> FromObjRef<read_fonts::tables::layout::FeatureTableSubstitution<'a>>
3628    for FeatureTableSubstitution
3629{
3630    fn from_obj_ref(
3631        obj: &read_fonts::tables::layout::FeatureTableSubstitution<'a>,
3632        _: FontData,
3633    ) -> Self {
3634        let offset_data = obj.offset_data();
3635        FeatureTableSubstitution {
3636            substitutions: obj.substitutions().to_owned_obj(offset_data),
3637        }
3638    }
3639}
3640
3641#[allow(clippy::needless_lifetimes)]
3642impl<'a> FromTableRef<read_fonts::tables::layout::FeatureTableSubstitution<'a>>
3643    for FeatureTableSubstitution
3644{
3645}
3646
3647impl ReadArgs for FeatureTableSubstitution {
3648    type Args = ();
3649}
3650
3651impl<'a> FontRead<'a> for FeatureTableSubstitution {
3652    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3653        <read_fonts::tables::layout::FeatureTableSubstitution as FontRead>::read(data)
3654            .map(|x| x.to_owned_table())
3655    }
3656}
3657
3658/// Used in [FeatureTableSubstitution]
3659#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3660#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3661pub struct FeatureTableSubstitutionRecord {
3662    /// The feature table index to match.
3663    pub feature_index: u16,
3664    /// Offset to an alternate feature table, from start of the
3665    /// FeatureTableSubstitution table.
3666    pub alternate_feature: OffsetMarker<Feature, WIDTH_32>,
3667}
3668
3669impl FeatureTableSubstitutionRecord {
3670    /// Construct a new `FeatureTableSubstitutionRecord`
3671    pub fn new(feature_index: u16, alternate_feature: Feature) -> Self {
3672        Self {
3673            feature_index,
3674            alternate_feature: alternate_feature.into(),
3675        }
3676    }
3677}
3678
3679impl FontWrite for FeatureTableSubstitutionRecord {
3680    fn write_into(&self, writer: &mut TableWriter) {
3681        self.feature_index.write_into(writer);
3682        self.alternate_feature.write_into(writer);
3683    }
3684    fn table_type(&self) -> TableType {
3685        TableType::Named("FeatureTableSubstitutionRecord")
3686    }
3687}
3688
3689impl Validate for FeatureTableSubstitutionRecord {
3690    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3691        ctx.in_table("FeatureTableSubstitutionRecord", |ctx| {
3692            ctx.in_field("alternate_feature", |ctx| {
3693                self.alternate_feature.validate_impl(ctx);
3694            });
3695        })
3696    }
3697}
3698
3699impl FromObjRef<read_fonts::tables::layout::FeatureTableSubstitutionRecord>
3700    for FeatureTableSubstitutionRecord
3701{
3702    fn from_obj_ref(
3703        obj: &read_fonts::tables::layout::FeatureTableSubstitutionRecord,
3704        offset_data: FontData,
3705    ) -> Self {
3706        FeatureTableSubstitutionRecord {
3707            feature_index: obj.feature_index(),
3708            alternate_feature: obj.alternate_feature(offset_data).to_owned_table(),
3709        }
3710    }
3711}
3712
3713#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3714#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3715pub struct SizeParams {
3716    /// The first value represents the design size in 720/inch units (decipoints).
3717    ///
3718    /// The design size entry must be non-zero. When there is a design size but
3719    /// no recommended size range, the rest of the array will consist of zeros.
3720    pub design_size: u16,
3721    /// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily.
3722    ///
3723    /// All fonts which share a Typographic or Font Family name and which differ
3724    /// only by size range shall have the same subfamily value, and no fonts
3725    /// which differ in weight or style shall have the same subfamily value.
3726    /// If this value is zero, the remaining fields in the array will be ignored.
3727    pub identifier: u16,
3728    /// The third value enables applications to use a single name for the subfamily identified by the second value.
3729    ///
3730    /// If the preceding value is non-zero, this value must be set in the range
3731    /// 256 – 32767 (inclusive). It records the value of a field in the 'name'
3732    /// table, which must contain English-language strings encoded in Windows
3733    /// Unicode and Macintosh Roman, and may contain additional strings localized
3734    /// to other scripts and languages. Each of these strings is the name
3735    /// an application should use, in combination with the family name, to
3736    /// represent the subfamily in a menu. Applications will choose the
3737    /// appropriate version based on their selection criteria.
3738    pub name_entry: u16,
3739    /// The fourth and fifth values represent the small end of the recommended
3740    /// usage range (exclusive) and the large end of the recommended usage range
3741    /// (inclusive), stored in 720/inch units (decipoints).
3742    ///
3743    /// Ranges must not overlap, and should generally be contiguous.
3744    pub range_start: u16,
3745    pub range_end: u16,
3746}
3747
3748impl SizeParams {
3749    /// Construct a new `SizeParams`
3750    pub fn new(
3751        design_size: u16,
3752        identifier: u16,
3753        name_entry: u16,
3754        range_start: u16,
3755        range_end: u16,
3756    ) -> Self {
3757        Self {
3758            design_size,
3759            identifier,
3760            name_entry,
3761            range_start,
3762            range_end,
3763        }
3764    }
3765}
3766
3767impl FontWrite for SizeParams {
3768    fn write_into(&self, writer: &mut TableWriter) {
3769        self.design_size.write_into(writer);
3770        self.identifier.write_into(writer);
3771        self.name_entry.write_into(writer);
3772        self.range_start.write_into(writer);
3773        self.range_end.write_into(writer);
3774    }
3775    fn table_type(&self) -> TableType {
3776        TableType::Named("SizeParams")
3777    }
3778}
3779
3780impl Validate for SizeParams {
3781    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
3782}
3783
3784impl<'a> FromObjRef<read_fonts::tables::layout::SizeParams<'a>> for SizeParams {
3785    fn from_obj_ref(obj: &read_fonts::tables::layout::SizeParams<'a>, _: FontData) -> Self {
3786        SizeParams {
3787            design_size: obj.design_size(),
3788            identifier: obj.identifier(),
3789            name_entry: obj.name_entry(),
3790            range_start: obj.range_start(),
3791            range_end: obj.range_end(),
3792        }
3793    }
3794}
3795
3796#[allow(clippy::needless_lifetimes)]
3797impl<'a> FromTableRef<read_fonts::tables::layout::SizeParams<'a>> for SizeParams {}
3798
3799impl ReadArgs for SizeParams {
3800    type Args = ();
3801}
3802
3803impl<'a> FontRead<'a> for SizeParams {
3804    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3805        <read_fonts::tables::layout::SizeParams as FontRead>::read(data).map(|x| x.to_owned_table())
3806    }
3807}
3808
3809#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3810#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3811pub struct StylisticSetParams {
3812    /// The 'name' table name ID that specifies a string (or strings, for
3813    /// multiple languages) for a user-interface label for this feature.
3814    ///
3815    /// The value of uiLabelNameId is expected to be in the font-specific name
3816    /// ID range (256-32767), though that is not a requirement in this Feature
3817    /// Parameters specification. The user-interface label for the feature can
3818    /// be provided in multiple languages. An English string should be included
3819    /// as a fallback. The string should be kept to a minimal length to fit
3820    /// comfortably with different application interfaces.
3821    pub ui_name_id: NameId,
3822}
3823
3824impl StylisticSetParams {
3825    /// Construct a new `StylisticSetParams`
3826    pub fn new(ui_name_id: NameId) -> Self {
3827        Self { ui_name_id }
3828    }
3829}
3830
3831impl FontWrite for StylisticSetParams {
3832    #[allow(clippy::unnecessary_cast)]
3833    fn write_into(&self, writer: &mut TableWriter) {
3834        (0 as u16).write_into(writer);
3835        self.ui_name_id.write_into(writer);
3836    }
3837    fn table_type(&self) -> TableType {
3838        TableType::Named("StylisticSetParams")
3839    }
3840}
3841
3842impl Validate for StylisticSetParams {
3843    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
3844}
3845
3846impl<'a> FromObjRef<read_fonts::tables::layout::StylisticSetParams<'a>> for StylisticSetParams {
3847    fn from_obj_ref(obj: &read_fonts::tables::layout::StylisticSetParams<'a>, _: FontData) -> Self {
3848        StylisticSetParams {
3849            ui_name_id: obj.ui_name_id(),
3850        }
3851    }
3852}
3853
3854#[allow(clippy::needless_lifetimes)]
3855impl<'a> FromTableRef<read_fonts::tables::layout::StylisticSetParams<'a>> for StylisticSetParams {}
3856
3857impl ReadArgs for StylisticSetParams {
3858    type Args = ();
3859}
3860
3861impl<'a> FontRead<'a> for StylisticSetParams {
3862    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3863        <read_fonts::tables::layout::StylisticSetParams as FontRead>::read(data)
3864            .map(|x| x.to_owned_table())
3865    }
3866}
3867
3868/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
3869#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
3870#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3871pub struct CharacterVariantParams {
3872    /// The 'name' table name ID that specifies a string (or strings,
3873    /// for multiple languages) for a user-interface label for this
3874    /// feature. (May be NULL.)
3875    pub feat_ui_label_name_id: NameId,
3876    /// The 'name' table name ID that specifies a string (or strings,
3877    /// for multiple languages) that an application can use for tooltip
3878    /// text for this feature. (May be NULL.)
3879    pub feat_ui_tooltip_text_name_id: NameId,
3880    /// The 'name' table name ID that specifies sample text that
3881    /// illustrates the effect of this feature. (May be NULL.)
3882    pub sample_text_name_id: NameId,
3883    /// Number of named parameters. (May be zero.)
3884    pub num_named_parameters: u16,
3885    /// The first 'name' table name ID used to specify strings for
3886    /// user-interface labels for the feature parameters. (Must be zero
3887    /// if numParameters is zero.)
3888    pub first_param_ui_label_name_id: NameId,
3889    /// The Unicode Scalar Value of the characters for which this
3890    /// feature provides glyph variants.
3891    pub character: Vec<Uint24>,
3892}
3893
3894impl CharacterVariantParams {
3895    /// Construct a new `CharacterVariantParams`
3896    pub fn new(
3897        feat_ui_label_name_id: NameId,
3898        feat_ui_tooltip_text_name_id: NameId,
3899        sample_text_name_id: NameId,
3900        num_named_parameters: u16,
3901        first_param_ui_label_name_id: NameId,
3902        character: Vec<Uint24>,
3903    ) -> Self {
3904        Self {
3905            feat_ui_label_name_id,
3906            feat_ui_tooltip_text_name_id,
3907            sample_text_name_id,
3908            num_named_parameters,
3909            first_param_ui_label_name_id,
3910            character,
3911        }
3912    }
3913}
3914
3915impl FontWrite for CharacterVariantParams {
3916    #[allow(clippy::unnecessary_cast)]
3917    fn write_into(&self, writer: &mut TableWriter) {
3918        (0 as u16).write_into(writer);
3919        self.feat_ui_label_name_id.write_into(writer);
3920        self.feat_ui_tooltip_text_name_id.write_into(writer);
3921        self.sample_text_name_id.write_into(writer);
3922        self.num_named_parameters.write_into(writer);
3923        self.first_param_ui_label_name_id.write_into(writer);
3924        (u16::try_from(array_len(&self.character)).unwrap()).write_into(writer);
3925        self.character.write_into(writer);
3926    }
3927    fn table_type(&self) -> TableType {
3928        TableType::Named("CharacterVariantParams")
3929    }
3930}
3931
3932impl Validate for CharacterVariantParams {
3933    fn validate_impl(&self, ctx: &mut ValidationCtx) {
3934        ctx.in_table("CharacterVariantParams", |ctx| {
3935            ctx.in_field("character", |ctx| {
3936                if self.character.len() > to_usize(u16::MAX) {
3937                    ctx.report("array exceeds max length");
3938                }
3939            });
3940        })
3941    }
3942}
3943
3944impl<'a> FromObjRef<read_fonts::tables::layout::CharacterVariantParams<'a>>
3945    for CharacterVariantParams
3946{
3947    fn from_obj_ref(
3948        obj: &read_fonts::tables::layout::CharacterVariantParams<'a>,
3949        _: FontData,
3950    ) -> Self {
3951        let offset_data = obj.offset_data();
3952        CharacterVariantParams {
3953            feat_ui_label_name_id: obj.feat_ui_label_name_id(),
3954            feat_ui_tooltip_text_name_id: obj.feat_ui_tooltip_text_name_id(),
3955            sample_text_name_id: obj.sample_text_name_id(),
3956            num_named_parameters: obj.num_named_parameters(),
3957            first_param_ui_label_name_id: obj.first_param_ui_label_name_id(),
3958            character: obj.character().to_owned_obj(offset_data),
3959        }
3960    }
3961}
3962
3963#[allow(clippy::needless_lifetimes)]
3964impl<'a> FromTableRef<read_fonts::tables::layout::CharacterVariantParams<'a>>
3965    for CharacterVariantParams
3966{
3967}
3968
3969impl ReadArgs for CharacterVariantParams {
3970    type Args = ();
3971}
3972
3973impl<'a> FontRead<'a> for CharacterVariantParams {
3974    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3975        <read_fonts::tables::layout::CharacterVariantParams as FontRead>::read(data)
3976            .map(|x| x.to_owned_table())
3977    }
3978}