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