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