read_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
8/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
9#[derive(Debug, Clone, Copy)]
10#[doc(hidden)]
11pub struct ScriptListMarker {
12    script_records_byte_len: usize,
13}
14
15impl ScriptListMarker {
16    pub fn script_count_byte_range(&self) -> Range<usize> {
17        let start = 0;
18        start..start + u16::RAW_BYTE_LEN
19    }
20
21    pub fn script_records_byte_range(&self) -> Range<usize> {
22        let start = self.script_count_byte_range().end;
23        start..start + self.script_records_byte_len
24    }
25}
26
27impl MinByteRange for ScriptListMarker {
28    fn min_byte_range(&self) -> Range<usize> {
29        0..self.script_records_byte_range().end
30    }
31}
32
33impl<'a> FontRead<'a> for ScriptList<'a> {
34    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
35        let mut cursor = data.cursor();
36        let script_count: u16 = cursor.read()?;
37        let script_records_byte_len = (script_count as usize)
38            .checked_mul(ScriptRecord::RAW_BYTE_LEN)
39            .ok_or(ReadError::OutOfBounds)?;
40        cursor.advance_by(script_records_byte_len);
41        cursor.finish(ScriptListMarker {
42            script_records_byte_len,
43        })
44    }
45}
46
47/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
48pub type ScriptList<'a> = TableRef<'a, ScriptListMarker>;
49
50#[allow(clippy::needless_lifetimes)]
51impl<'a> ScriptList<'a> {
52    /// Number of ScriptRecords
53    pub fn script_count(&self) -> u16 {
54        let range = self.shape.script_count_byte_range();
55        self.data.read_at(range.start).unwrap()
56    }
57
58    /// Array of ScriptRecords, listed alphabetically by script tag
59    pub fn script_records(&self) -> &'a [ScriptRecord] {
60        let range = self.shape.script_records_byte_range();
61        self.data.read_array(range).unwrap()
62    }
63}
64
65#[cfg(feature = "experimental_traverse")]
66impl<'a> SomeTable<'a> for ScriptList<'a> {
67    fn type_name(&self) -> &str {
68        "ScriptList"
69    }
70    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
71        match idx {
72            0usize => Some(Field::new("script_count", self.script_count())),
73            1usize => Some(Field::new(
74                "script_records",
75                traversal::FieldType::array_of_records(
76                    stringify!(ScriptRecord),
77                    self.script_records(),
78                    self.offset_data(),
79                ),
80            )),
81            _ => None,
82        }
83    }
84}
85
86#[cfg(feature = "experimental_traverse")]
87#[allow(clippy::needless_lifetimes)]
88impl<'a> std::fmt::Debug for ScriptList<'a> {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        (self as &dyn SomeTable<'a>).fmt(f)
91    }
92}
93
94/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
95#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
96#[repr(C)]
97#[repr(packed)]
98pub struct ScriptRecord {
99    /// 4-byte script tag identifier
100    pub script_tag: BigEndian<Tag>,
101    /// Offset to Script table, from beginning of ScriptList
102    pub script_offset: BigEndian<Offset16>,
103}
104
105impl ScriptRecord {
106    /// 4-byte script tag identifier
107    pub fn script_tag(&self) -> Tag {
108        self.script_tag.get()
109    }
110
111    /// Offset to Script table, from beginning of ScriptList
112    pub fn script_offset(&self) -> Offset16 {
113        self.script_offset.get()
114    }
115
116    /// Offset to Script table, from beginning of ScriptList
117    ///
118    /// The `data` argument should be retrieved from the parent table
119    /// By calling its `offset_data` method.
120    pub fn script<'a>(&self, data: FontData<'a>) -> Result<Script<'a>, ReadError> {
121        self.script_offset().resolve(data)
122    }
123}
124
125impl FixedSize for ScriptRecord {
126    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
127}
128
129#[cfg(feature = "experimental_traverse")]
130impl<'a> SomeRecord<'a> for ScriptRecord {
131    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
132        RecordResolver {
133            name: "ScriptRecord",
134            get_field: Box::new(move |idx, _data| match idx {
135                0usize => Some(Field::new("script_tag", self.script_tag())),
136                1usize => Some(Field::new(
137                    "script_offset",
138                    FieldType::offset(self.script_offset(), self.script(_data)),
139                )),
140                _ => None,
141            }),
142            data,
143        }
144    }
145}
146
147/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
148#[derive(Debug, Clone, Copy)]
149#[doc(hidden)]
150pub struct ScriptMarker {
151    lang_sys_records_byte_len: usize,
152}
153
154impl ScriptMarker {
155    pub fn default_lang_sys_offset_byte_range(&self) -> Range<usize> {
156        let start = 0;
157        start..start + Offset16::RAW_BYTE_LEN
158    }
159
160    pub fn lang_sys_count_byte_range(&self) -> Range<usize> {
161        let start = self.default_lang_sys_offset_byte_range().end;
162        start..start + u16::RAW_BYTE_LEN
163    }
164
165    pub fn lang_sys_records_byte_range(&self) -> Range<usize> {
166        let start = self.lang_sys_count_byte_range().end;
167        start..start + self.lang_sys_records_byte_len
168    }
169}
170
171impl MinByteRange for ScriptMarker {
172    fn min_byte_range(&self) -> Range<usize> {
173        0..self.lang_sys_records_byte_range().end
174    }
175}
176
177impl<'a> FontRead<'a> for Script<'a> {
178    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
179        let mut cursor = data.cursor();
180        cursor.advance::<Offset16>();
181        let lang_sys_count: u16 = cursor.read()?;
182        let lang_sys_records_byte_len = (lang_sys_count as usize)
183            .checked_mul(LangSysRecord::RAW_BYTE_LEN)
184            .ok_or(ReadError::OutOfBounds)?;
185        cursor.advance_by(lang_sys_records_byte_len);
186        cursor.finish(ScriptMarker {
187            lang_sys_records_byte_len,
188        })
189    }
190}
191
192/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
193pub type Script<'a> = TableRef<'a, ScriptMarker>;
194
195#[allow(clippy::needless_lifetimes)]
196impl<'a> Script<'a> {
197    /// Offset to default LangSys table, from beginning of Script table
198    /// — may be NULL
199    pub fn default_lang_sys_offset(&self) -> Nullable<Offset16> {
200        let range = self.shape.default_lang_sys_offset_byte_range();
201        self.data.read_at(range.start).unwrap()
202    }
203
204    /// Attempt to resolve [`default_lang_sys_offset`][Self::default_lang_sys_offset].
205    pub fn default_lang_sys(&self) -> Option<Result<LangSys<'a>, ReadError>> {
206        let data = self.data;
207        self.default_lang_sys_offset().resolve(data)
208    }
209
210    /// Number of LangSysRecords for this script — excluding the
211    /// default LangSys
212    pub fn lang_sys_count(&self) -> u16 {
213        let range = self.shape.lang_sys_count_byte_range();
214        self.data.read_at(range.start).unwrap()
215    }
216
217    /// Array of LangSysRecords, listed alphabetically by LangSys tag
218    pub fn lang_sys_records(&self) -> &'a [LangSysRecord] {
219        let range = self.shape.lang_sys_records_byte_range();
220        self.data.read_array(range).unwrap()
221    }
222}
223
224#[cfg(feature = "experimental_traverse")]
225impl<'a> SomeTable<'a> for Script<'a> {
226    fn type_name(&self) -> &str {
227        "Script"
228    }
229    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
230        match idx {
231            0usize => Some(Field::new(
232                "default_lang_sys_offset",
233                FieldType::offset(self.default_lang_sys_offset(), self.default_lang_sys()),
234            )),
235            1usize => Some(Field::new("lang_sys_count", self.lang_sys_count())),
236            2usize => Some(Field::new(
237                "lang_sys_records",
238                traversal::FieldType::array_of_records(
239                    stringify!(LangSysRecord),
240                    self.lang_sys_records(),
241                    self.offset_data(),
242                ),
243            )),
244            _ => None,
245        }
246    }
247}
248
249#[cfg(feature = "experimental_traverse")]
250#[allow(clippy::needless_lifetimes)]
251impl<'a> std::fmt::Debug for Script<'a> {
252    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253        (self as &dyn SomeTable<'a>).fmt(f)
254    }
255}
256
257#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
258#[repr(C)]
259#[repr(packed)]
260pub struct LangSysRecord {
261    /// 4-byte LangSysTag identifier
262    pub lang_sys_tag: BigEndian<Tag>,
263    /// Offset to LangSys table, from beginning of Script table
264    pub lang_sys_offset: BigEndian<Offset16>,
265}
266
267impl LangSysRecord {
268    /// 4-byte LangSysTag identifier
269    pub fn lang_sys_tag(&self) -> Tag {
270        self.lang_sys_tag.get()
271    }
272
273    /// Offset to LangSys table, from beginning of Script table
274    pub fn lang_sys_offset(&self) -> Offset16 {
275        self.lang_sys_offset.get()
276    }
277
278    /// Offset to LangSys table, from beginning of Script table
279    ///
280    /// The `data` argument should be retrieved from the parent table
281    /// By calling its `offset_data` method.
282    pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result<LangSys<'a>, ReadError> {
283        self.lang_sys_offset().resolve(data)
284    }
285}
286
287impl FixedSize for LangSysRecord {
288    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
289}
290
291#[cfg(feature = "experimental_traverse")]
292impl<'a> SomeRecord<'a> for LangSysRecord {
293    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
294        RecordResolver {
295            name: "LangSysRecord",
296            get_field: Box::new(move |idx, _data| match idx {
297                0usize => Some(Field::new("lang_sys_tag", self.lang_sys_tag())),
298                1usize => Some(Field::new(
299                    "lang_sys_offset",
300                    FieldType::offset(self.lang_sys_offset(), self.lang_sys(_data)),
301                )),
302                _ => None,
303            }),
304            data,
305        }
306    }
307}
308
309/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
310#[derive(Debug, Clone, Copy)]
311#[doc(hidden)]
312pub struct LangSysMarker {
313    feature_indices_byte_len: usize,
314}
315
316impl LangSysMarker {
317    pub fn lookup_order_offset_byte_range(&self) -> Range<usize> {
318        let start = 0;
319        start..start + u16::RAW_BYTE_LEN
320    }
321
322    pub fn required_feature_index_byte_range(&self) -> Range<usize> {
323        let start = self.lookup_order_offset_byte_range().end;
324        start..start + u16::RAW_BYTE_LEN
325    }
326
327    pub fn feature_index_count_byte_range(&self) -> Range<usize> {
328        let start = self.required_feature_index_byte_range().end;
329        start..start + u16::RAW_BYTE_LEN
330    }
331
332    pub fn feature_indices_byte_range(&self) -> Range<usize> {
333        let start = self.feature_index_count_byte_range().end;
334        start..start + self.feature_indices_byte_len
335    }
336}
337
338impl MinByteRange for LangSysMarker {
339    fn min_byte_range(&self) -> Range<usize> {
340        0..self.feature_indices_byte_range().end
341    }
342}
343
344impl<'a> FontRead<'a> for LangSys<'a> {
345    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
346        let mut cursor = data.cursor();
347        cursor.advance::<u16>();
348        cursor.advance::<u16>();
349        let feature_index_count: u16 = cursor.read()?;
350        let feature_indices_byte_len = (feature_index_count as usize)
351            .checked_mul(u16::RAW_BYTE_LEN)
352            .ok_or(ReadError::OutOfBounds)?;
353        cursor.advance_by(feature_indices_byte_len);
354        cursor.finish(LangSysMarker {
355            feature_indices_byte_len,
356        })
357    }
358}
359
360/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
361pub type LangSys<'a> = TableRef<'a, LangSysMarker>;
362
363#[allow(clippy::needless_lifetimes)]
364impl<'a> LangSys<'a> {
365    /// Index of a feature required for this language system; if no
366    /// required features = 0xFFFF
367    pub fn required_feature_index(&self) -> u16 {
368        let range = self.shape.required_feature_index_byte_range();
369        self.data.read_at(range.start).unwrap()
370    }
371
372    /// Number of feature index values for this language system —
373    /// excludes the required feature
374    pub fn feature_index_count(&self) -> u16 {
375        let range = self.shape.feature_index_count_byte_range();
376        self.data.read_at(range.start).unwrap()
377    }
378
379    /// Array of indices into the FeatureList, in arbitrary order
380    pub fn feature_indices(&self) -> &'a [BigEndian<u16>] {
381        let range = self.shape.feature_indices_byte_range();
382        self.data.read_array(range).unwrap()
383    }
384}
385
386#[cfg(feature = "experimental_traverse")]
387impl<'a> SomeTable<'a> for LangSys<'a> {
388    fn type_name(&self) -> &str {
389        "LangSys"
390    }
391    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
392        match idx {
393            0usize => Some(Field::new(
394                "required_feature_index",
395                self.required_feature_index(),
396            )),
397            1usize => Some(Field::new(
398                "feature_index_count",
399                self.feature_index_count(),
400            )),
401            2usize => Some(Field::new("feature_indices", self.feature_indices())),
402            _ => None,
403        }
404    }
405}
406
407#[cfg(feature = "experimental_traverse")]
408#[allow(clippy::needless_lifetimes)]
409impl<'a> std::fmt::Debug for LangSys<'a> {
410    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411        (self as &dyn SomeTable<'a>).fmt(f)
412    }
413}
414
415/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
416#[derive(Debug, Clone, Copy)]
417#[doc(hidden)]
418pub struct FeatureListMarker {
419    feature_records_byte_len: usize,
420}
421
422impl FeatureListMarker {
423    pub fn feature_count_byte_range(&self) -> Range<usize> {
424        let start = 0;
425        start..start + u16::RAW_BYTE_LEN
426    }
427
428    pub fn feature_records_byte_range(&self) -> Range<usize> {
429        let start = self.feature_count_byte_range().end;
430        start..start + self.feature_records_byte_len
431    }
432}
433
434impl MinByteRange for FeatureListMarker {
435    fn min_byte_range(&self) -> Range<usize> {
436        0..self.feature_records_byte_range().end
437    }
438}
439
440impl<'a> FontRead<'a> for FeatureList<'a> {
441    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
442        let mut cursor = data.cursor();
443        let feature_count: u16 = cursor.read()?;
444        let feature_records_byte_len = (feature_count as usize)
445            .checked_mul(FeatureRecord::RAW_BYTE_LEN)
446            .ok_or(ReadError::OutOfBounds)?;
447        cursor.advance_by(feature_records_byte_len);
448        cursor.finish(FeatureListMarker {
449            feature_records_byte_len,
450        })
451    }
452}
453
454/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
455pub type FeatureList<'a> = TableRef<'a, FeatureListMarker>;
456
457#[allow(clippy::needless_lifetimes)]
458impl<'a> FeatureList<'a> {
459    /// Number of FeatureRecords in this table
460    pub fn feature_count(&self) -> u16 {
461        let range = self.shape.feature_count_byte_range();
462        self.data.read_at(range.start).unwrap()
463    }
464
465    /// Array of FeatureRecords — zero-based (first feature has
466    /// FeatureIndex = 0), listed alphabetically by feature tag
467    pub fn feature_records(&self) -> &'a [FeatureRecord] {
468        let range = self.shape.feature_records_byte_range();
469        self.data.read_array(range).unwrap()
470    }
471}
472
473#[cfg(feature = "experimental_traverse")]
474impl<'a> SomeTable<'a> for FeatureList<'a> {
475    fn type_name(&self) -> &str {
476        "FeatureList"
477    }
478    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
479        match idx {
480            0usize => Some(Field::new("feature_count", self.feature_count())),
481            1usize => Some(Field::new(
482                "feature_records",
483                traversal::FieldType::array_of_records(
484                    stringify!(FeatureRecord),
485                    self.feature_records(),
486                    self.offset_data(),
487                ),
488            )),
489            _ => None,
490        }
491    }
492}
493
494#[cfg(feature = "experimental_traverse")]
495#[allow(clippy::needless_lifetimes)]
496impl<'a> std::fmt::Debug for FeatureList<'a> {
497    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
498        (self as &dyn SomeTable<'a>).fmt(f)
499    }
500}
501
502/// Part of [FeatureList]
503#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
504#[repr(C)]
505#[repr(packed)]
506pub struct FeatureRecord {
507    /// 4-byte feature identification tag
508    pub feature_tag: BigEndian<Tag>,
509    /// Offset to Feature table, from beginning of FeatureList
510    pub feature_offset: BigEndian<Offset16>,
511}
512
513impl FeatureRecord {
514    /// 4-byte feature identification tag
515    pub fn feature_tag(&self) -> Tag {
516        self.feature_tag.get()
517    }
518
519    /// Offset to Feature table, from beginning of FeatureList
520    pub fn feature_offset(&self) -> Offset16 {
521        self.feature_offset.get()
522    }
523
524    /// Offset to Feature table, from beginning of FeatureList
525    ///
526    /// The `data` argument should be retrieved from the parent table
527    /// By calling its `offset_data` method.
528    pub fn feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
529        let args = self.feature_tag();
530        self.feature_offset().resolve_with_args(data, &args)
531    }
532}
533
534impl FixedSize for FeatureRecord {
535    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
536}
537
538#[cfg(feature = "experimental_traverse")]
539impl<'a> SomeRecord<'a> for FeatureRecord {
540    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
541        RecordResolver {
542            name: "FeatureRecord",
543            get_field: Box::new(move |idx, _data| match idx {
544                0usize => Some(Field::new("feature_tag", self.feature_tag())),
545                1usize => Some(Field::new(
546                    "feature_offset",
547                    FieldType::offset(self.feature_offset(), self.feature(_data)),
548                )),
549                _ => None,
550            }),
551            data,
552        }
553    }
554}
555
556/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
557#[derive(Debug, Clone, Copy)]
558#[doc(hidden)]
559pub struct FeatureMarker {
560    feature_tag: Tag,
561    lookup_list_indices_byte_len: usize,
562}
563
564impl FeatureMarker {
565    pub fn feature_params_offset_byte_range(&self) -> Range<usize> {
566        let start = 0;
567        start..start + Offset16::RAW_BYTE_LEN
568    }
569
570    pub fn lookup_index_count_byte_range(&self) -> Range<usize> {
571        let start = self.feature_params_offset_byte_range().end;
572        start..start + u16::RAW_BYTE_LEN
573    }
574
575    pub fn lookup_list_indices_byte_range(&self) -> Range<usize> {
576        let start = self.lookup_index_count_byte_range().end;
577        start..start + self.lookup_list_indices_byte_len
578    }
579}
580
581impl MinByteRange for FeatureMarker {
582    fn min_byte_range(&self) -> Range<usize> {
583        0..self.lookup_list_indices_byte_range().end
584    }
585}
586
587impl ReadArgs for Feature<'_> {
588    type Args = Tag;
589}
590
591impl<'a> FontReadWithArgs<'a> for Feature<'a> {
592    fn read_with_args(data: FontData<'a>, args: &Tag) -> Result<Self, ReadError> {
593        let feature_tag = *args;
594        let mut cursor = data.cursor();
595        cursor.advance::<Offset16>();
596        let lookup_index_count: u16 = cursor.read()?;
597        let lookup_list_indices_byte_len = (lookup_index_count as usize)
598            .checked_mul(u16::RAW_BYTE_LEN)
599            .ok_or(ReadError::OutOfBounds)?;
600        cursor.advance_by(lookup_list_indices_byte_len);
601        cursor.finish(FeatureMarker {
602            feature_tag,
603            lookup_list_indices_byte_len,
604        })
605    }
606}
607
608impl<'a> Feature<'a> {
609    /// A constructor that requires additional arguments.
610    ///
611    /// This type requires some external state in order to be
612    /// parsed.
613    pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result<Self, ReadError> {
614        let args = feature_tag;
615        Self::read_with_args(data, &args)
616    }
617}
618
619/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
620pub type Feature<'a> = TableRef<'a, FeatureMarker>;
621
622#[allow(clippy::needless_lifetimes)]
623impl<'a> Feature<'a> {
624    /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
625    pub fn feature_params_offset(&self) -> Nullable<Offset16> {
626        let range = self.shape.feature_params_offset_byte_range();
627        self.data.read_at(range.start).unwrap()
628    }
629
630    /// Attempt to resolve [`feature_params_offset`][Self::feature_params_offset].
631    pub fn feature_params(&self) -> Option<Result<FeatureParams<'a>, ReadError>> {
632        let data = self.data;
633        let args = self.feature_tag();
634        self.feature_params_offset().resolve_with_args(data, &args)
635    }
636
637    /// Number of LookupList indices for this feature
638    pub fn lookup_index_count(&self) -> u16 {
639        let range = self.shape.lookup_index_count_byte_range();
640        self.data.read_at(range.start).unwrap()
641    }
642
643    /// Array of indices into the LookupList — zero-based (first
644    /// lookup is LookupListIndex = 0)
645    pub fn lookup_list_indices(&self) -> &'a [BigEndian<u16>] {
646        let range = self.shape.lookup_list_indices_byte_range();
647        self.data.read_array(range).unwrap()
648    }
649
650    pub(crate) fn feature_tag(&self) -> Tag {
651        self.shape.feature_tag
652    }
653}
654
655#[cfg(feature = "experimental_traverse")]
656impl<'a> SomeTable<'a> for Feature<'a> {
657    fn type_name(&self) -> &str {
658        "Feature"
659    }
660    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
661        match idx {
662            0usize => Some(Field::new(
663                "feature_params_offset",
664                FieldType::offset(self.feature_params_offset(), self.feature_params()),
665            )),
666            1usize => Some(Field::new("lookup_index_count", self.lookup_index_count())),
667            2usize => Some(Field::new(
668                "lookup_list_indices",
669                self.lookup_list_indices(),
670            )),
671            _ => None,
672        }
673    }
674}
675
676#[cfg(feature = "experimental_traverse")]
677#[allow(clippy::needless_lifetimes)]
678impl<'a> std::fmt::Debug for Feature<'a> {
679    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
680        (self as &dyn SomeTable<'a>).fmt(f)
681    }
682}
683
684/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
685#[derive(Debug)]
686#[doc(hidden)]
687pub struct LookupListMarker<T = ()> {
688    lookup_offsets_byte_len: usize,
689    offset_type: std::marker::PhantomData<*const T>,
690}
691
692impl<T> LookupListMarker<T> {
693    pub fn lookup_count_byte_range(&self) -> Range<usize> {
694        let start = 0;
695        start..start + u16::RAW_BYTE_LEN
696    }
697
698    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
699        let start = self.lookup_count_byte_range().end;
700        start..start + self.lookup_offsets_byte_len
701    }
702}
703
704impl MinByteRange for LookupListMarker {
705    fn min_byte_range(&self) -> Range<usize> {
706        0..self.lookup_offsets_byte_range().end
707    }
708}
709
710impl<T> Clone for LookupListMarker<T> {
711    fn clone(&self) -> Self {
712        *self
713    }
714}
715
716impl<T> Copy for LookupListMarker<T> {}
717
718impl<'a, T> FontRead<'a> for LookupList<'a, T> {
719    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
720        let mut cursor = data.cursor();
721        let lookup_count: u16 = cursor.read()?;
722        let lookup_offsets_byte_len = (lookup_count as usize)
723            .checked_mul(Offset16::RAW_BYTE_LEN)
724            .ok_or(ReadError::OutOfBounds)?;
725        cursor.advance_by(lookup_offsets_byte_len);
726        cursor.finish(LookupListMarker {
727            lookup_offsets_byte_len,
728            offset_type: std::marker::PhantomData,
729        })
730    }
731}
732
733impl<'a> LookupList<'a, ()> {
734    #[allow(dead_code)]
735    pub(crate) fn into_concrete<T>(self) -> LookupList<'a, T> {
736        let TableRef { data, shape } = self;
737        TableRef {
738            shape: LookupListMarker {
739                lookup_offsets_byte_len: shape.lookup_offsets_byte_len,
740                offset_type: std::marker::PhantomData,
741            },
742            data,
743        }
744    }
745}
746
747impl<'a, T> LookupList<'a, T> {
748    #[allow(dead_code)]
749    /// Replace the specific generic type on this implementation with `()`
750    pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> {
751        let TableRef { data, shape } = self;
752        TableRef {
753            shape: LookupListMarker {
754                lookup_offsets_byte_len: shape.lookup_offsets_byte_len,
755                offset_type: std::marker::PhantomData,
756            },
757            data: *data,
758        }
759    }
760}
761
762/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
763pub type LookupList<'a, T> = TableRef<'a, LookupListMarker<T>>;
764
765#[allow(clippy::needless_lifetimes)]
766impl<'a, T> LookupList<'a, T> {
767    /// Number of lookups in this table
768    pub fn lookup_count(&self) -> u16 {
769        let range = self.shape.lookup_count_byte_range();
770        self.data.read_at(range.start).unwrap()
771    }
772
773    /// Array of offsets to Lookup tables, from beginning of LookupList
774    /// — zero based (first lookup is Lookup index = 0)
775    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
776        let range = self.shape.lookup_offsets_byte_range();
777        self.data.read_array(range).unwrap()
778    }
779
780    /// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets].
781    pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16>
782    where
783        T: FontRead<'a>,
784    {
785        let data = self.data;
786        let offsets = self.lookup_offsets();
787        ArrayOfOffsets::new(offsets, data, ())
788    }
789}
790
791#[cfg(feature = "experimental_traverse")]
792impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for LookupList<'a, T> {
793    fn type_name(&self) -> &str {
794        "LookupList"
795    }
796    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
797        match idx {
798            0usize => Some(Field::new("lookup_count", self.lookup_count())),
799            1usize => Some({
800                let data = self.data;
801                Field::new(
802                    "lookup_offsets",
803                    FieldType::array_of_offsets(
804                        better_type_name::<T>(),
805                        self.lookup_offsets(),
806                        move |off| {
807                            let target = off.get().resolve::<T>(data);
808                            FieldType::offset(off.get(), target)
809                        },
810                    ),
811                )
812            }),
813            _ => None,
814        }
815    }
816}
817
818#[cfg(feature = "experimental_traverse")]
819#[allow(clippy::needless_lifetimes)]
820impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for LookupList<'a, T> {
821    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
822        (self as &dyn SomeTable<'a>).fmt(f)
823    }
824}
825
826/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
827#[derive(Debug)]
828#[doc(hidden)]
829pub struct LookupMarker<T = ()> {
830    subtable_offsets_byte_len: usize,
831    mark_filtering_set_byte_start: Option<usize>,
832    offset_type: std::marker::PhantomData<*const T>,
833}
834
835impl<T> LookupMarker<T> {
836    pub fn lookup_type_byte_range(&self) -> Range<usize> {
837        let start = 0;
838        start..start + u16::RAW_BYTE_LEN
839    }
840
841    pub fn lookup_flag_byte_range(&self) -> Range<usize> {
842        let start = self.lookup_type_byte_range().end;
843        start..start + LookupFlag::RAW_BYTE_LEN
844    }
845
846    pub fn sub_table_count_byte_range(&self) -> Range<usize> {
847        let start = self.lookup_flag_byte_range().end;
848        start..start + u16::RAW_BYTE_LEN
849    }
850
851    pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
852        let start = self.sub_table_count_byte_range().end;
853        start..start + self.subtable_offsets_byte_len
854    }
855
856    pub fn mark_filtering_set_byte_range(&self) -> Option<Range<usize>> {
857        let start = self.mark_filtering_set_byte_start?;
858        Some(start..start + u16::RAW_BYTE_LEN)
859    }
860}
861
862impl MinByteRange for LookupMarker {
863    fn min_byte_range(&self) -> Range<usize> {
864        0..self.subtable_offsets_byte_range().end
865    }
866}
867
868impl<T> Clone for LookupMarker<T> {
869    fn clone(&self) -> Self {
870        *self
871    }
872}
873
874impl<T> Copy for LookupMarker<T> {}
875
876impl<'a, T> FontRead<'a> for Lookup<'a, T> {
877    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
878        let mut cursor = data.cursor();
879        cursor.advance::<u16>();
880        let lookup_flag: LookupFlag = cursor.read()?;
881        let sub_table_count: u16 = cursor.read()?;
882        let subtable_offsets_byte_len = (sub_table_count as usize)
883            .checked_mul(Offset16::RAW_BYTE_LEN)
884            .ok_or(ReadError::OutOfBounds)?;
885        cursor.advance_by(subtable_offsets_byte_len);
886        let mark_filtering_set_byte_start = lookup_flag
887            .contains(LookupFlag::USE_MARK_FILTERING_SET)
888            .then(|| cursor.position())
889            .transpose()?;
890        lookup_flag
891            .contains(LookupFlag::USE_MARK_FILTERING_SET)
892            .then(|| cursor.advance::<u16>());
893        cursor.finish(LookupMarker {
894            subtable_offsets_byte_len,
895            mark_filtering_set_byte_start,
896            offset_type: std::marker::PhantomData,
897        })
898    }
899}
900
901impl<'a> Lookup<'a, ()> {
902    #[allow(dead_code)]
903    pub(crate) fn into_concrete<T>(self) -> Lookup<'a, T> {
904        let TableRef { data, shape } = self;
905        TableRef {
906            shape: LookupMarker {
907                subtable_offsets_byte_len: shape.subtable_offsets_byte_len,
908                mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start,
909                offset_type: std::marker::PhantomData,
910            },
911            data,
912        }
913    }
914}
915
916impl<'a, T> Lookup<'a, T> {
917    #[allow(dead_code)]
918    /// Replace the specific generic type on this implementation with `()`
919    pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
920        let TableRef { data, shape } = self;
921        TableRef {
922            shape: LookupMarker {
923                subtable_offsets_byte_len: shape.subtable_offsets_byte_len,
924                mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start,
925                offset_type: std::marker::PhantomData,
926            },
927            data: *data,
928        }
929    }
930}
931
932/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
933pub type Lookup<'a, T> = TableRef<'a, LookupMarker<T>>;
934
935#[allow(clippy::needless_lifetimes)]
936impl<'a, T> Lookup<'a, T> {
937    /// Different enumerations for GSUB and GPOS
938    pub fn lookup_type(&self) -> u16 {
939        let range = self.shape.lookup_type_byte_range();
940        self.data.read_at(range.start).unwrap()
941    }
942
943    /// Lookup qualifiers
944    pub fn lookup_flag(&self) -> LookupFlag {
945        let range = self.shape.lookup_flag_byte_range();
946        self.data.read_at(range.start).unwrap()
947    }
948
949    /// Number of subtables for this lookup
950    pub fn sub_table_count(&self) -> u16 {
951        let range = self.shape.sub_table_count_byte_range();
952        self.data.read_at(range.start).unwrap()
953    }
954
955    /// Array of offsets to lookup subtables, from beginning of Lookup
956    /// table
957    pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
958        let range = self.shape.subtable_offsets_byte_range();
959        self.data.read_array(range).unwrap()
960    }
961
962    /// A dynamically resolving wrapper for [`subtable_offsets`][Self::subtable_offsets].
963    pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16>
964    where
965        T: FontRead<'a>,
966    {
967        let data = self.data;
968        let offsets = self.subtable_offsets();
969        ArrayOfOffsets::new(offsets, data, ())
970    }
971
972    /// Index (base 0) into GDEF mark glyph sets structure. This field
973    /// is only present if the USE_MARK_FILTERING_SET lookup flag is
974    /// set.
975    pub fn mark_filtering_set(&self) -> Option<u16> {
976        let range = self.shape.mark_filtering_set_byte_range()?;
977        Some(self.data.read_at(range.start).unwrap())
978    }
979}
980
981#[cfg(feature = "experimental_traverse")]
982impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for Lookup<'a, T> {
983    fn type_name(&self) -> &str {
984        "Lookup"
985    }
986    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
987        let lookup_flag = self.lookup_flag();
988        match idx {
989            0usize => Some(Field::new("lookup_type", self.lookup_type())),
990            1usize => Some(Field::new("lookup_flag", self.traverse_lookup_flag())),
991            2usize => Some(Field::new("sub_table_count", self.sub_table_count())),
992            3usize => Some({
993                let data = self.data;
994                Field::new(
995                    "subtable_offsets",
996                    FieldType::array_of_offsets(
997                        better_type_name::<T>(),
998                        self.subtable_offsets(),
999                        move |off| {
1000                            let target = off.get().resolve::<T>(data);
1001                            FieldType::offset(off.get(), target)
1002                        },
1003                    ),
1004                )
1005            }),
1006            4usize if lookup_flag.contains(LookupFlag::USE_MARK_FILTERING_SET) => Some(Field::new(
1007                "mark_filtering_set",
1008                self.mark_filtering_set().unwrap(),
1009            )),
1010            _ => None,
1011        }
1012    }
1013}
1014
1015#[cfg(feature = "experimental_traverse")]
1016#[allow(clippy::needless_lifetimes)]
1017impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for Lookup<'a, T> {
1018    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1019        (self as &dyn SomeTable<'a>).fmt(f)
1020    }
1021}
1022
1023impl Format<u16> for CoverageFormat1Marker {
1024    const FORMAT: u16 = 1;
1025}
1026
1027/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
1028#[derive(Debug, Clone, Copy)]
1029#[doc(hidden)]
1030pub struct CoverageFormat1Marker {
1031    glyph_array_byte_len: usize,
1032}
1033
1034impl CoverageFormat1Marker {
1035    pub fn coverage_format_byte_range(&self) -> Range<usize> {
1036        let start = 0;
1037        start..start + u16::RAW_BYTE_LEN
1038    }
1039
1040    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1041        let start = self.coverage_format_byte_range().end;
1042        start..start + u16::RAW_BYTE_LEN
1043    }
1044
1045    pub fn glyph_array_byte_range(&self) -> Range<usize> {
1046        let start = self.glyph_count_byte_range().end;
1047        start..start + self.glyph_array_byte_len
1048    }
1049}
1050
1051impl MinByteRange for CoverageFormat1Marker {
1052    fn min_byte_range(&self) -> Range<usize> {
1053        0..self.glyph_array_byte_range().end
1054    }
1055}
1056
1057impl<'a> FontRead<'a> for CoverageFormat1<'a> {
1058    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1059        let mut cursor = data.cursor();
1060        cursor.advance::<u16>();
1061        let glyph_count: u16 = cursor.read()?;
1062        let glyph_array_byte_len = (glyph_count as usize)
1063            .checked_mul(GlyphId16::RAW_BYTE_LEN)
1064            .ok_or(ReadError::OutOfBounds)?;
1065        cursor.advance_by(glyph_array_byte_len);
1066        cursor.finish(CoverageFormat1Marker {
1067            glyph_array_byte_len,
1068        })
1069    }
1070}
1071
1072/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
1073pub type CoverageFormat1<'a> = TableRef<'a, CoverageFormat1Marker>;
1074
1075#[allow(clippy::needless_lifetimes)]
1076impl<'a> CoverageFormat1<'a> {
1077    /// Format identifier — format = 1
1078    pub fn coverage_format(&self) -> u16 {
1079        let range = self.shape.coverage_format_byte_range();
1080        self.data.read_at(range.start).unwrap()
1081    }
1082
1083    /// Number of glyphs in the glyph array
1084    pub fn glyph_count(&self) -> u16 {
1085        let range = self.shape.glyph_count_byte_range();
1086        self.data.read_at(range.start).unwrap()
1087    }
1088
1089    /// Array of glyph IDs — in numerical order
1090    pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1091        let range = self.shape.glyph_array_byte_range();
1092        self.data.read_array(range).unwrap()
1093    }
1094}
1095
1096#[cfg(feature = "experimental_traverse")]
1097impl<'a> SomeTable<'a> for CoverageFormat1<'a> {
1098    fn type_name(&self) -> &str {
1099        "CoverageFormat1"
1100    }
1101    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1102        match idx {
1103            0usize => Some(Field::new("coverage_format", self.coverage_format())),
1104            1usize => Some(Field::new("glyph_count", self.glyph_count())),
1105            2usize => Some(Field::new("glyph_array", self.glyph_array())),
1106            _ => None,
1107        }
1108    }
1109}
1110
1111#[cfg(feature = "experimental_traverse")]
1112#[allow(clippy::needless_lifetimes)]
1113impl<'a> std::fmt::Debug for CoverageFormat1<'a> {
1114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1115        (self as &dyn SomeTable<'a>).fmt(f)
1116    }
1117}
1118
1119impl Format<u16> for CoverageFormat2Marker {
1120    const FORMAT: u16 = 2;
1121}
1122
1123/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
1124#[derive(Debug, Clone, Copy)]
1125#[doc(hidden)]
1126pub struct CoverageFormat2Marker {
1127    range_records_byte_len: usize,
1128}
1129
1130impl CoverageFormat2Marker {
1131    pub fn coverage_format_byte_range(&self) -> Range<usize> {
1132        let start = 0;
1133        start..start + u16::RAW_BYTE_LEN
1134    }
1135
1136    pub fn range_count_byte_range(&self) -> Range<usize> {
1137        let start = self.coverage_format_byte_range().end;
1138        start..start + u16::RAW_BYTE_LEN
1139    }
1140
1141    pub fn range_records_byte_range(&self) -> Range<usize> {
1142        let start = self.range_count_byte_range().end;
1143        start..start + self.range_records_byte_len
1144    }
1145}
1146
1147impl MinByteRange for CoverageFormat2Marker {
1148    fn min_byte_range(&self) -> Range<usize> {
1149        0..self.range_records_byte_range().end
1150    }
1151}
1152
1153impl<'a> FontRead<'a> for CoverageFormat2<'a> {
1154    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1155        let mut cursor = data.cursor();
1156        cursor.advance::<u16>();
1157        let range_count: u16 = cursor.read()?;
1158        let range_records_byte_len = (range_count as usize)
1159            .checked_mul(RangeRecord::RAW_BYTE_LEN)
1160            .ok_or(ReadError::OutOfBounds)?;
1161        cursor.advance_by(range_records_byte_len);
1162        cursor.finish(CoverageFormat2Marker {
1163            range_records_byte_len,
1164        })
1165    }
1166}
1167
1168/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
1169pub type CoverageFormat2<'a> = TableRef<'a, CoverageFormat2Marker>;
1170
1171#[allow(clippy::needless_lifetimes)]
1172impl<'a> CoverageFormat2<'a> {
1173    /// Format identifier — format = 2
1174    pub fn coverage_format(&self) -> u16 {
1175        let range = self.shape.coverage_format_byte_range();
1176        self.data.read_at(range.start).unwrap()
1177    }
1178
1179    /// Number of RangeRecords
1180    pub fn range_count(&self) -> u16 {
1181        let range = self.shape.range_count_byte_range();
1182        self.data.read_at(range.start).unwrap()
1183    }
1184
1185    /// Array of glyph ranges — ordered by startGlyphID.
1186    pub fn range_records(&self) -> &'a [RangeRecord] {
1187        let range = self.shape.range_records_byte_range();
1188        self.data.read_array(range).unwrap()
1189    }
1190}
1191
1192#[cfg(feature = "experimental_traverse")]
1193impl<'a> SomeTable<'a> for CoverageFormat2<'a> {
1194    fn type_name(&self) -> &str {
1195        "CoverageFormat2"
1196    }
1197    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1198        match idx {
1199            0usize => Some(Field::new("coverage_format", self.coverage_format())),
1200            1usize => Some(Field::new("range_count", self.range_count())),
1201            2usize => Some(Field::new(
1202                "range_records",
1203                traversal::FieldType::array_of_records(
1204                    stringify!(RangeRecord),
1205                    self.range_records(),
1206                    self.offset_data(),
1207                ),
1208            )),
1209            _ => None,
1210        }
1211    }
1212}
1213
1214#[cfg(feature = "experimental_traverse")]
1215#[allow(clippy::needless_lifetimes)]
1216impl<'a> std::fmt::Debug for CoverageFormat2<'a> {
1217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1218        (self as &dyn SomeTable<'a>).fmt(f)
1219    }
1220}
1221
1222/// Used in [CoverageFormat2]
1223#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1224#[repr(C)]
1225#[repr(packed)]
1226pub struct RangeRecord {
1227    /// First glyph ID in the range
1228    pub start_glyph_id: BigEndian<GlyphId16>,
1229    /// Last glyph ID in the range
1230    pub end_glyph_id: BigEndian<GlyphId16>,
1231    /// Coverage Index of first glyph ID in range
1232    pub start_coverage_index: BigEndian<u16>,
1233}
1234
1235impl RangeRecord {
1236    /// First glyph ID in the range
1237    pub fn start_glyph_id(&self) -> GlyphId16 {
1238        self.start_glyph_id.get()
1239    }
1240
1241    /// Last glyph ID in the range
1242    pub fn end_glyph_id(&self) -> GlyphId16 {
1243        self.end_glyph_id.get()
1244    }
1245
1246    /// Coverage Index of first glyph ID in range
1247    pub fn start_coverage_index(&self) -> u16 {
1248        self.start_coverage_index.get()
1249    }
1250}
1251
1252impl FixedSize for RangeRecord {
1253    const RAW_BYTE_LEN: usize =
1254        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1255}
1256
1257#[cfg(feature = "experimental_traverse")]
1258impl<'a> SomeRecord<'a> for RangeRecord {
1259    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1260        RecordResolver {
1261            name: "RangeRecord",
1262            get_field: Box::new(move |idx, _data| match idx {
1263                0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1264                1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
1265                2usize => Some(Field::new(
1266                    "start_coverage_index",
1267                    self.start_coverage_index(),
1268                )),
1269                _ => None,
1270            }),
1271            data,
1272        }
1273    }
1274}
1275
1276/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
1277#[derive(Clone)]
1278pub enum CoverageTable<'a> {
1279    Format1(CoverageFormat1<'a>),
1280    Format2(CoverageFormat2<'a>),
1281}
1282
1283impl<'a> CoverageTable<'a> {
1284    ///Return the `FontData` used to resolve offsets for this table.
1285    pub fn offset_data(&self) -> FontData<'a> {
1286        match self {
1287            Self::Format1(item) => item.offset_data(),
1288            Self::Format2(item) => item.offset_data(),
1289        }
1290    }
1291
1292    /// Format identifier — format = 1
1293    pub fn coverage_format(&self) -> u16 {
1294        match self {
1295            Self::Format1(item) => item.coverage_format(),
1296            Self::Format2(item) => item.coverage_format(),
1297        }
1298    }
1299}
1300
1301impl<'a> FontRead<'a> for CoverageTable<'a> {
1302    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1303        let format: u16 = data.read_at(0usize)?;
1304        match format {
1305            CoverageFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1306            CoverageFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1307            other => Err(ReadError::InvalidFormat(other.into())),
1308        }
1309    }
1310}
1311
1312impl MinByteRange for CoverageTable<'_> {
1313    fn min_byte_range(&self) -> Range<usize> {
1314        match self {
1315            Self::Format1(item) => item.min_byte_range(),
1316            Self::Format2(item) => item.min_byte_range(),
1317        }
1318    }
1319}
1320
1321#[cfg(feature = "experimental_traverse")]
1322impl<'a> CoverageTable<'a> {
1323    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1324        match self {
1325            Self::Format1(table) => table,
1326            Self::Format2(table) => table,
1327        }
1328    }
1329}
1330
1331#[cfg(feature = "experimental_traverse")]
1332impl std::fmt::Debug for CoverageTable<'_> {
1333    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1334        self.dyn_inner().fmt(f)
1335    }
1336}
1337
1338#[cfg(feature = "experimental_traverse")]
1339impl<'a> SomeTable<'a> for CoverageTable<'a> {
1340    fn type_name(&self) -> &str {
1341        self.dyn_inner().type_name()
1342    }
1343    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1344        self.dyn_inner().get_field(idx)
1345    }
1346}
1347
1348impl Format<u16> for ClassDefFormat1Marker {
1349    const FORMAT: u16 = 1;
1350}
1351
1352/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
1353#[derive(Debug, Clone, Copy)]
1354#[doc(hidden)]
1355pub struct ClassDefFormat1Marker {
1356    class_value_array_byte_len: usize,
1357}
1358
1359impl ClassDefFormat1Marker {
1360    pub fn class_format_byte_range(&self) -> Range<usize> {
1361        let start = 0;
1362        start..start + u16::RAW_BYTE_LEN
1363    }
1364
1365    pub fn start_glyph_id_byte_range(&self) -> Range<usize> {
1366        let start = self.class_format_byte_range().end;
1367        start..start + GlyphId16::RAW_BYTE_LEN
1368    }
1369
1370    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1371        let start = self.start_glyph_id_byte_range().end;
1372        start..start + u16::RAW_BYTE_LEN
1373    }
1374
1375    pub fn class_value_array_byte_range(&self) -> Range<usize> {
1376        let start = self.glyph_count_byte_range().end;
1377        start..start + self.class_value_array_byte_len
1378    }
1379}
1380
1381impl MinByteRange for ClassDefFormat1Marker {
1382    fn min_byte_range(&self) -> Range<usize> {
1383        0..self.class_value_array_byte_range().end
1384    }
1385}
1386
1387impl<'a> FontRead<'a> for ClassDefFormat1<'a> {
1388    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1389        let mut cursor = data.cursor();
1390        cursor.advance::<u16>();
1391        cursor.advance::<GlyphId16>();
1392        let glyph_count: u16 = cursor.read()?;
1393        let class_value_array_byte_len = (glyph_count as usize)
1394            .checked_mul(u16::RAW_BYTE_LEN)
1395            .ok_or(ReadError::OutOfBounds)?;
1396        cursor.advance_by(class_value_array_byte_len);
1397        cursor.finish(ClassDefFormat1Marker {
1398            class_value_array_byte_len,
1399        })
1400    }
1401}
1402
1403/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
1404pub type ClassDefFormat1<'a> = TableRef<'a, ClassDefFormat1Marker>;
1405
1406#[allow(clippy::needless_lifetimes)]
1407impl<'a> ClassDefFormat1<'a> {
1408    /// Format identifier — format = 1
1409    pub fn class_format(&self) -> u16 {
1410        let range = self.shape.class_format_byte_range();
1411        self.data.read_at(range.start).unwrap()
1412    }
1413
1414    /// First glyph ID of the classValueArray
1415    pub fn start_glyph_id(&self) -> GlyphId16 {
1416        let range = self.shape.start_glyph_id_byte_range();
1417        self.data.read_at(range.start).unwrap()
1418    }
1419
1420    /// Size of the classValueArray
1421    pub fn glyph_count(&self) -> u16 {
1422        let range = self.shape.glyph_count_byte_range();
1423        self.data.read_at(range.start).unwrap()
1424    }
1425
1426    /// Array of Class Values — one per glyph ID
1427    pub fn class_value_array(&self) -> &'a [BigEndian<u16>] {
1428        let range = self.shape.class_value_array_byte_range();
1429        self.data.read_array(range).unwrap()
1430    }
1431}
1432
1433#[cfg(feature = "experimental_traverse")]
1434impl<'a> SomeTable<'a> for ClassDefFormat1<'a> {
1435    fn type_name(&self) -> &str {
1436        "ClassDefFormat1"
1437    }
1438    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1439        match idx {
1440            0usize => Some(Field::new("class_format", self.class_format())),
1441            1usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1442            2usize => Some(Field::new("glyph_count", self.glyph_count())),
1443            3usize => Some(Field::new("class_value_array", self.class_value_array())),
1444            _ => None,
1445        }
1446    }
1447}
1448
1449#[cfg(feature = "experimental_traverse")]
1450#[allow(clippy::needless_lifetimes)]
1451impl<'a> std::fmt::Debug for ClassDefFormat1<'a> {
1452    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1453        (self as &dyn SomeTable<'a>).fmt(f)
1454    }
1455}
1456
1457impl Format<u16> for ClassDefFormat2Marker {
1458    const FORMAT: u16 = 2;
1459}
1460
1461/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
1462#[derive(Debug, Clone, Copy)]
1463#[doc(hidden)]
1464pub struct ClassDefFormat2Marker {
1465    class_range_records_byte_len: usize,
1466}
1467
1468impl ClassDefFormat2Marker {
1469    pub fn class_format_byte_range(&self) -> Range<usize> {
1470        let start = 0;
1471        start..start + u16::RAW_BYTE_LEN
1472    }
1473
1474    pub fn class_range_count_byte_range(&self) -> Range<usize> {
1475        let start = self.class_format_byte_range().end;
1476        start..start + u16::RAW_BYTE_LEN
1477    }
1478
1479    pub fn class_range_records_byte_range(&self) -> Range<usize> {
1480        let start = self.class_range_count_byte_range().end;
1481        start..start + self.class_range_records_byte_len
1482    }
1483}
1484
1485impl MinByteRange for ClassDefFormat2Marker {
1486    fn min_byte_range(&self) -> Range<usize> {
1487        0..self.class_range_records_byte_range().end
1488    }
1489}
1490
1491impl<'a> FontRead<'a> for ClassDefFormat2<'a> {
1492    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1493        let mut cursor = data.cursor();
1494        cursor.advance::<u16>();
1495        let class_range_count: u16 = cursor.read()?;
1496        let class_range_records_byte_len = (class_range_count as usize)
1497            .checked_mul(ClassRangeRecord::RAW_BYTE_LEN)
1498            .ok_or(ReadError::OutOfBounds)?;
1499        cursor.advance_by(class_range_records_byte_len);
1500        cursor.finish(ClassDefFormat2Marker {
1501            class_range_records_byte_len,
1502        })
1503    }
1504}
1505
1506/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
1507pub type ClassDefFormat2<'a> = TableRef<'a, ClassDefFormat2Marker>;
1508
1509#[allow(clippy::needless_lifetimes)]
1510impl<'a> ClassDefFormat2<'a> {
1511    /// Format identifier — format = 2
1512    pub fn class_format(&self) -> u16 {
1513        let range = self.shape.class_format_byte_range();
1514        self.data.read_at(range.start).unwrap()
1515    }
1516
1517    /// Number of ClassRangeRecords
1518    pub fn class_range_count(&self) -> u16 {
1519        let range = self.shape.class_range_count_byte_range();
1520        self.data.read_at(range.start).unwrap()
1521    }
1522
1523    /// Array of ClassRangeRecords — ordered by startGlyphID
1524    pub fn class_range_records(&self) -> &'a [ClassRangeRecord] {
1525        let range = self.shape.class_range_records_byte_range();
1526        self.data.read_array(range).unwrap()
1527    }
1528}
1529
1530#[cfg(feature = "experimental_traverse")]
1531impl<'a> SomeTable<'a> for ClassDefFormat2<'a> {
1532    fn type_name(&self) -> &str {
1533        "ClassDefFormat2"
1534    }
1535    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1536        match idx {
1537            0usize => Some(Field::new("class_format", self.class_format())),
1538            1usize => Some(Field::new("class_range_count", self.class_range_count())),
1539            2usize => Some(Field::new(
1540                "class_range_records",
1541                traversal::FieldType::array_of_records(
1542                    stringify!(ClassRangeRecord),
1543                    self.class_range_records(),
1544                    self.offset_data(),
1545                ),
1546            )),
1547            _ => None,
1548        }
1549    }
1550}
1551
1552#[cfg(feature = "experimental_traverse")]
1553#[allow(clippy::needless_lifetimes)]
1554impl<'a> std::fmt::Debug for ClassDefFormat2<'a> {
1555    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1556        (self as &dyn SomeTable<'a>).fmt(f)
1557    }
1558}
1559
1560/// Used in [ClassDefFormat2]
1561#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1562#[repr(C)]
1563#[repr(packed)]
1564pub struct ClassRangeRecord {
1565    /// First glyph ID in the range
1566    pub start_glyph_id: BigEndian<GlyphId16>,
1567    /// Last glyph ID in the range
1568    pub end_glyph_id: BigEndian<GlyphId16>,
1569    /// Applied to all glyphs in the range
1570    pub class: BigEndian<u16>,
1571}
1572
1573impl ClassRangeRecord {
1574    /// First glyph ID in the range
1575    pub fn start_glyph_id(&self) -> GlyphId16 {
1576        self.start_glyph_id.get()
1577    }
1578
1579    /// Last glyph ID in the range
1580    pub fn end_glyph_id(&self) -> GlyphId16 {
1581        self.end_glyph_id.get()
1582    }
1583
1584    /// Applied to all glyphs in the range
1585    pub fn class(&self) -> u16 {
1586        self.class.get()
1587    }
1588}
1589
1590impl FixedSize for ClassRangeRecord {
1591    const RAW_BYTE_LEN: usize =
1592        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1593}
1594
1595#[cfg(feature = "experimental_traverse")]
1596impl<'a> SomeRecord<'a> for ClassRangeRecord {
1597    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1598        RecordResolver {
1599            name: "ClassRangeRecord",
1600            get_field: Box::new(move |idx, _data| match idx {
1601                0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1602                1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
1603                2usize => Some(Field::new("class", self.class())),
1604                _ => None,
1605            }),
1606            data,
1607        }
1608    }
1609}
1610
1611/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
1612#[derive(Clone)]
1613pub enum ClassDef<'a> {
1614    Format1(ClassDefFormat1<'a>),
1615    Format2(ClassDefFormat2<'a>),
1616}
1617
1618impl<'a> ClassDef<'a> {
1619    ///Return the `FontData` used to resolve offsets for this table.
1620    pub fn offset_data(&self) -> FontData<'a> {
1621        match self {
1622            Self::Format1(item) => item.offset_data(),
1623            Self::Format2(item) => item.offset_data(),
1624        }
1625    }
1626
1627    /// Format identifier — format = 1
1628    pub fn class_format(&self) -> u16 {
1629        match self {
1630            Self::Format1(item) => item.class_format(),
1631            Self::Format2(item) => item.class_format(),
1632        }
1633    }
1634}
1635
1636impl<'a> FontRead<'a> for ClassDef<'a> {
1637    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1638        let format: u16 = data.read_at(0usize)?;
1639        match format {
1640            ClassDefFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1641            ClassDefFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1642            other => Err(ReadError::InvalidFormat(other.into())),
1643        }
1644    }
1645}
1646
1647impl MinByteRange for ClassDef<'_> {
1648    fn min_byte_range(&self) -> Range<usize> {
1649        match self {
1650            Self::Format1(item) => item.min_byte_range(),
1651            Self::Format2(item) => item.min_byte_range(),
1652        }
1653    }
1654}
1655
1656#[cfg(feature = "experimental_traverse")]
1657impl<'a> ClassDef<'a> {
1658    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1659        match self {
1660            Self::Format1(table) => table,
1661            Self::Format2(table) => table,
1662        }
1663    }
1664}
1665
1666#[cfg(feature = "experimental_traverse")]
1667impl std::fmt::Debug for ClassDef<'_> {
1668    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1669        self.dyn_inner().fmt(f)
1670    }
1671}
1672
1673#[cfg(feature = "experimental_traverse")]
1674impl<'a> SomeTable<'a> for ClassDef<'a> {
1675    fn type_name(&self) -> &str {
1676        self.dyn_inner().type_name()
1677    }
1678    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1679        self.dyn_inner().get_field(idx)
1680    }
1681}
1682
1683/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
1684#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1685#[repr(C)]
1686#[repr(packed)]
1687pub struct SequenceLookupRecord {
1688    /// Index (zero-based) into the input glyph sequence
1689    pub sequence_index: BigEndian<u16>,
1690    /// Index (zero-based) into the LookupList
1691    pub lookup_list_index: BigEndian<u16>,
1692}
1693
1694impl SequenceLookupRecord {
1695    /// Index (zero-based) into the input glyph sequence
1696    pub fn sequence_index(&self) -> u16 {
1697        self.sequence_index.get()
1698    }
1699
1700    /// Index (zero-based) into the LookupList
1701    pub fn lookup_list_index(&self) -> u16 {
1702        self.lookup_list_index.get()
1703    }
1704}
1705
1706impl FixedSize for SequenceLookupRecord {
1707    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1708}
1709
1710#[cfg(feature = "experimental_traverse")]
1711impl<'a> SomeRecord<'a> for SequenceLookupRecord {
1712    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1713        RecordResolver {
1714            name: "SequenceLookupRecord",
1715            get_field: Box::new(move |idx, _data| match idx {
1716                0usize => Some(Field::new("sequence_index", self.sequence_index())),
1717                1usize => Some(Field::new("lookup_list_index", self.lookup_list_index())),
1718                _ => None,
1719            }),
1720            data,
1721        }
1722    }
1723}
1724
1725impl Format<u16> for SequenceContextFormat1Marker {
1726    const FORMAT: u16 = 1;
1727}
1728
1729/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
1730#[derive(Debug, Clone, Copy)]
1731#[doc(hidden)]
1732pub struct SequenceContextFormat1Marker {
1733    seq_rule_set_offsets_byte_len: usize,
1734}
1735
1736impl SequenceContextFormat1Marker {
1737    pub fn format_byte_range(&self) -> Range<usize> {
1738        let start = 0;
1739        start..start + u16::RAW_BYTE_LEN
1740    }
1741
1742    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1743        let start = self.format_byte_range().end;
1744        start..start + Offset16::RAW_BYTE_LEN
1745    }
1746
1747    pub fn seq_rule_set_count_byte_range(&self) -> Range<usize> {
1748        let start = self.coverage_offset_byte_range().end;
1749        start..start + u16::RAW_BYTE_LEN
1750    }
1751
1752    pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
1753        let start = self.seq_rule_set_count_byte_range().end;
1754        start..start + self.seq_rule_set_offsets_byte_len
1755    }
1756}
1757
1758impl MinByteRange for SequenceContextFormat1Marker {
1759    fn min_byte_range(&self) -> Range<usize> {
1760        0..self.seq_rule_set_offsets_byte_range().end
1761    }
1762}
1763
1764impl<'a> FontRead<'a> for SequenceContextFormat1<'a> {
1765    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1766        let mut cursor = data.cursor();
1767        cursor.advance::<u16>();
1768        cursor.advance::<Offset16>();
1769        let seq_rule_set_count: u16 = cursor.read()?;
1770        let seq_rule_set_offsets_byte_len = (seq_rule_set_count as usize)
1771            .checked_mul(Offset16::RAW_BYTE_LEN)
1772            .ok_or(ReadError::OutOfBounds)?;
1773        cursor.advance_by(seq_rule_set_offsets_byte_len);
1774        cursor.finish(SequenceContextFormat1Marker {
1775            seq_rule_set_offsets_byte_len,
1776        })
1777    }
1778}
1779
1780/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
1781pub type SequenceContextFormat1<'a> = TableRef<'a, SequenceContextFormat1Marker>;
1782
1783#[allow(clippy::needless_lifetimes)]
1784impl<'a> SequenceContextFormat1<'a> {
1785    /// Format identifier: format = 1
1786    pub fn format(&self) -> u16 {
1787        let range = self.shape.format_byte_range();
1788        self.data.read_at(range.start).unwrap()
1789    }
1790
1791    /// Offset to Coverage table, from beginning of
1792    /// SequenceContextFormat1 table
1793    pub fn coverage_offset(&self) -> Offset16 {
1794        let range = self.shape.coverage_offset_byte_range();
1795        self.data.read_at(range.start).unwrap()
1796    }
1797
1798    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1799    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1800        let data = self.data;
1801        self.coverage_offset().resolve(data)
1802    }
1803
1804    /// Number of SequenceRuleSet tables
1805    pub fn seq_rule_set_count(&self) -> u16 {
1806        let range = self.shape.seq_rule_set_count_byte_range();
1807        self.data.read_at(range.start).unwrap()
1808    }
1809
1810    /// Array of offsets to SequenceRuleSet tables, from beginning of
1811    /// SequenceContextFormat1 table (offsets may be NULL)
1812    pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
1813        let range = self.shape.seq_rule_set_offsets_byte_range();
1814        self.data.read_array(range).unwrap()
1815    }
1816
1817    /// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets].
1818    pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> {
1819        let data = self.data;
1820        let offsets = self.seq_rule_set_offsets();
1821        ArrayOfNullableOffsets::new(offsets, data, ())
1822    }
1823}
1824
1825#[cfg(feature = "experimental_traverse")]
1826impl<'a> SomeTable<'a> for SequenceContextFormat1<'a> {
1827    fn type_name(&self) -> &str {
1828        "SequenceContextFormat1"
1829    }
1830    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1831        match idx {
1832            0usize => Some(Field::new("format", self.format())),
1833            1usize => Some(Field::new(
1834                "coverage_offset",
1835                FieldType::offset(self.coverage_offset(), self.coverage()),
1836            )),
1837            2usize => Some(Field::new("seq_rule_set_count", self.seq_rule_set_count())),
1838            3usize => Some({
1839                let data = self.data;
1840                Field::new(
1841                    "seq_rule_set_offsets",
1842                    FieldType::array_of_offsets(
1843                        better_type_name::<SequenceRuleSet>(),
1844                        self.seq_rule_set_offsets(),
1845                        move |off| {
1846                            let target = off.get().resolve::<SequenceRuleSet>(data);
1847                            FieldType::offset(off.get(), target)
1848                        },
1849                    ),
1850                )
1851            }),
1852            _ => None,
1853        }
1854    }
1855}
1856
1857#[cfg(feature = "experimental_traverse")]
1858#[allow(clippy::needless_lifetimes)]
1859impl<'a> std::fmt::Debug for SequenceContextFormat1<'a> {
1860    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1861        (self as &dyn SomeTable<'a>).fmt(f)
1862    }
1863}
1864
1865/// Part of [SequenceContextFormat1]
1866#[derive(Debug, Clone, Copy)]
1867#[doc(hidden)]
1868pub struct SequenceRuleSetMarker {
1869    seq_rule_offsets_byte_len: usize,
1870}
1871
1872impl SequenceRuleSetMarker {
1873    pub fn seq_rule_count_byte_range(&self) -> Range<usize> {
1874        let start = 0;
1875        start..start + u16::RAW_BYTE_LEN
1876    }
1877
1878    pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
1879        let start = self.seq_rule_count_byte_range().end;
1880        start..start + self.seq_rule_offsets_byte_len
1881    }
1882}
1883
1884impl MinByteRange for SequenceRuleSetMarker {
1885    fn min_byte_range(&self) -> Range<usize> {
1886        0..self.seq_rule_offsets_byte_range().end
1887    }
1888}
1889
1890impl<'a> FontRead<'a> for SequenceRuleSet<'a> {
1891    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1892        let mut cursor = data.cursor();
1893        let seq_rule_count: u16 = cursor.read()?;
1894        let seq_rule_offsets_byte_len = (seq_rule_count as usize)
1895            .checked_mul(Offset16::RAW_BYTE_LEN)
1896            .ok_or(ReadError::OutOfBounds)?;
1897        cursor.advance_by(seq_rule_offsets_byte_len);
1898        cursor.finish(SequenceRuleSetMarker {
1899            seq_rule_offsets_byte_len,
1900        })
1901    }
1902}
1903
1904/// Part of [SequenceContextFormat1]
1905pub type SequenceRuleSet<'a> = TableRef<'a, SequenceRuleSetMarker>;
1906
1907#[allow(clippy::needless_lifetimes)]
1908impl<'a> SequenceRuleSet<'a> {
1909    /// Number of SequenceRule tables
1910    pub fn seq_rule_count(&self) -> u16 {
1911        let range = self.shape.seq_rule_count_byte_range();
1912        self.data.read_at(range.start).unwrap()
1913    }
1914
1915    /// Array of offsets to SequenceRule tables, from beginning of the
1916    /// SequenceRuleSet table
1917    pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
1918        let range = self.shape.seq_rule_offsets_byte_range();
1919        self.data.read_array(range).unwrap()
1920    }
1921
1922    /// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets].
1923    pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> {
1924        let data = self.data;
1925        let offsets = self.seq_rule_offsets();
1926        ArrayOfOffsets::new(offsets, data, ())
1927    }
1928}
1929
1930#[cfg(feature = "experimental_traverse")]
1931impl<'a> SomeTable<'a> for SequenceRuleSet<'a> {
1932    fn type_name(&self) -> &str {
1933        "SequenceRuleSet"
1934    }
1935    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1936        match idx {
1937            0usize => Some(Field::new("seq_rule_count", self.seq_rule_count())),
1938            1usize => Some({
1939                let data = self.data;
1940                Field::new(
1941                    "seq_rule_offsets",
1942                    FieldType::array_of_offsets(
1943                        better_type_name::<SequenceRule>(),
1944                        self.seq_rule_offsets(),
1945                        move |off| {
1946                            let target = off.get().resolve::<SequenceRule>(data);
1947                            FieldType::offset(off.get(), target)
1948                        },
1949                    ),
1950                )
1951            }),
1952            _ => None,
1953        }
1954    }
1955}
1956
1957#[cfg(feature = "experimental_traverse")]
1958#[allow(clippy::needless_lifetimes)]
1959impl<'a> std::fmt::Debug for SequenceRuleSet<'a> {
1960    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1961        (self as &dyn SomeTable<'a>).fmt(f)
1962    }
1963}
1964
1965/// Part of [SequenceContextFormat1]
1966#[derive(Debug, Clone, Copy)]
1967#[doc(hidden)]
1968pub struct SequenceRuleMarker {
1969    input_sequence_byte_len: usize,
1970    seq_lookup_records_byte_len: usize,
1971}
1972
1973impl SequenceRuleMarker {
1974    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1975        let start = 0;
1976        start..start + u16::RAW_BYTE_LEN
1977    }
1978
1979    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
1980        let start = self.glyph_count_byte_range().end;
1981        start..start + u16::RAW_BYTE_LEN
1982    }
1983
1984    pub fn input_sequence_byte_range(&self) -> Range<usize> {
1985        let start = self.seq_lookup_count_byte_range().end;
1986        start..start + self.input_sequence_byte_len
1987    }
1988
1989    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
1990        let start = self.input_sequence_byte_range().end;
1991        start..start + self.seq_lookup_records_byte_len
1992    }
1993}
1994
1995impl MinByteRange for SequenceRuleMarker {
1996    fn min_byte_range(&self) -> Range<usize> {
1997        0..self.seq_lookup_records_byte_range().end
1998    }
1999}
2000
2001impl<'a> FontRead<'a> for SequenceRule<'a> {
2002    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2003        let mut cursor = data.cursor();
2004        let glyph_count: u16 = cursor.read()?;
2005        let seq_lookup_count: u16 = cursor.read()?;
2006        let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize))
2007            .checked_mul(GlyphId16::RAW_BYTE_LEN)
2008            .ok_or(ReadError::OutOfBounds)?;
2009        cursor.advance_by(input_sequence_byte_len);
2010        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
2011            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2012            .ok_or(ReadError::OutOfBounds)?;
2013        cursor.advance_by(seq_lookup_records_byte_len);
2014        cursor.finish(SequenceRuleMarker {
2015            input_sequence_byte_len,
2016            seq_lookup_records_byte_len,
2017        })
2018    }
2019}
2020
2021/// Part of [SequenceContextFormat1]
2022pub type SequenceRule<'a> = TableRef<'a, SequenceRuleMarker>;
2023
2024#[allow(clippy::needless_lifetimes)]
2025impl<'a> SequenceRule<'a> {
2026    /// Number of glyphs in the input glyph sequence
2027    pub fn glyph_count(&self) -> u16 {
2028        let range = self.shape.glyph_count_byte_range();
2029        self.data.read_at(range.start).unwrap()
2030    }
2031
2032    /// Number of SequenceLookupRecords
2033    pub fn seq_lookup_count(&self) -> u16 {
2034        let range = self.shape.seq_lookup_count_byte_range();
2035        self.data.read_at(range.start).unwrap()
2036    }
2037
2038    /// Array of input glyph IDs—starting with the second glyph
2039    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2040        let range = self.shape.input_sequence_byte_range();
2041        self.data.read_array(range).unwrap()
2042    }
2043
2044    /// Array of Sequence lookup records
2045    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2046        let range = self.shape.seq_lookup_records_byte_range();
2047        self.data.read_array(range).unwrap()
2048    }
2049}
2050
2051#[cfg(feature = "experimental_traverse")]
2052impl<'a> SomeTable<'a> for SequenceRule<'a> {
2053    fn type_name(&self) -> &str {
2054        "SequenceRule"
2055    }
2056    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2057        match idx {
2058            0usize => Some(Field::new("glyph_count", self.glyph_count())),
2059            1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2060            2usize => Some(Field::new("input_sequence", self.input_sequence())),
2061            3usize => Some(Field::new(
2062                "seq_lookup_records",
2063                traversal::FieldType::array_of_records(
2064                    stringify!(SequenceLookupRecord),
2065                    self.seq_lookup_records(),
2066                    self.offset_data(),
2067                ),
2068            )),
2069            _ => None,
2070        }
2071    }
2072}
2073
2074#[cfg(feature = "experimental_traverse")]
2075#[allow(clippy::needless_lifetimes)]
2076impl<'a> std::fmt::Debug for SequenceRule<'a> {
2077    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2078        (self as &dyn SomeTable<'a>).fmt(f)
2079    }
2080}
2081
2082impl Format<u16> for SequenceContextFormat2Marker {
2083    const FORMAT: u16 = 2;
2084}
2085
2086/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
2087#[derive(Debug, Clone, Copy)]
2088#[doc(hidden)]
2089pub struct SequenceContextFormat2Marker {
2090    class_seq_rule_set_offsets_byte_len: usize,
2091}
2092
2093impl SequenceContextFormat2Marker {
2094    pub fn format_byte_range(&self) -> Range<usize> {
2095        let start = 0;
2096        start..start + u16::RAW_BYTE_LEN
2097    }
2098
2099    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2100        let start = self.format_byte_range().end;
2101        start..start + Offset16::RAW_BYTE_LEN
2102    }
2103
2104    pub fn class_def_offset_byte_range(&self) -> Range<usize> {
2105        let start = self.coverage_offset_byte_range().end;
2106        start..start + Offset16::RAW_BYTE_LEN
2107    }
2108
2109    pub fn class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2110        let start = self.class_def_offset_byte_range().end;
2111        start..start + u16::RAW_BYTE_LEN
2112    }
2113
2114    pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2115        let start = self.class_seq_rule_set_count_byte_range().end;
2116        start..start + self.class_seq_rule_set_offsets_byte_len
2117    }
2118}
2119
2120impl MinByteRange for SequenceContextFormat2Marker {
2121    fn min_byte_range(&self) -> Range<usize> {
2122        0..self.class_seq_rule_set_offsets_byte_range().end
2123    }
2124}
2125
2126impl<'a> FontRead<'a> for SequenceContextFormat2<'a> {
2127    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2128        let mut cursor = data.cursor();
2129        cursor.advance::<u16>();
2130        cursor.advance::<Offset16>();
2131        cursor.advance::<Offset16>();
2132        let class_seq_rule_set_count: u16 = cursor.read()?;
2133        let class_seq_rule_set_offsets_byte_len = (class_seq_rule_set_count as usize)
2134            .checked_mul(Offset16::RAW_BYTE_LEN)
2135            .ok_or(ReadError::OutOfBounds)?;
2136        cursor.advance_by(class_seq_rule_set_offsets_byte_len);
2137        cursor.finish(SequenceContextFormat2Marker {
2138            class_seq_rule_set_offsets_byte_len,
2139        })
2140    }
2141}
2142
2143/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
2144pub type SequenceContextFormat2<'a> = TableRef<'a, SequenceContextFormat2Marker>;
2145
2146#[allow(clippy::needless_lifetimes)]
2147impl<'a> SequenceContextFormat2<'a> {
2148    /// Format identifier: format = 2
2149    pub fn format(&self) -> u16 {
2150        let range = self.shape.format_byte_range();
2151        self.data.read_at(range.start).unwrap()
2152    }
2153
2154    /// Offset to Coverage table, from beginning of
2155    /// SequenceContextFormat2 table
2156    pub fn coverage_offset(&self) -> Offset16 {
2157        let range = self.shape.coverage_offset_byte_range();
2158        self.data.read_at(range.start).unwrap()
2159    }
2160
2161    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2162    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2163        let data = self.data;
2164        self.coverage_offset().resolve(data)
2165    }
2166
2167    /// Offset to ClassDef table, from beginning of
2168    /// SequenceContextFormat2 table
2169    pub fn class_def_offset(&self) -> Offset16 {
2170        let range = self.shape.class_def_offset_byte_range();
2171        self.data.read_at(range.start).unwrap()
2172    }
2173
2174    /// Attempt to resolve [`class_def_offset`][Self::class_def_offset].
2175    pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
2176        let data = self.data;
2177        self.class_def_offset().resolve(data)
2178    }
2179
2180    /// Number of ClassSequenceRuleSet tables
2181    pub fn class_seq_rule_set_count(&self) -> u16 {
2182        let range = self.shape.class_seq_rule_set_count_byte_range();
2183        self.data.read_at(range.start).unwrap()
2184    }
2185
2186    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
2187    /// of SequenceContextFormat2 table (may be NULL)
2188    pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2189        let range = self.shape.class_seq_rule_set_offsets_byte_range();
2190        self.data.read_array(range).unwrap()
2191    }
2192
2193    /// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets].
2194    pub fn class_seq_rule_sets(
2195        &self,
2196    ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> {
2197        let data = self.data;
2198        let offsets = self.class_seq_rule_set_offsets();
2199        ArrayOfNullableOffsets::new(offsets, data, ())
2200    }
2201}
2202
2203#[cfg(feature = "experimental_traverse")]
2204impl<'a> SomeTable<'a> for SequenceContextFormat2<'a> {
2205    fn type_name(&self) -> &str {
2206        "SequenceContextFormat2"
2207    }
2208    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2209        match idx {
2210            0usize => Some(Field::new("format", self.format())),
2211            1usize => Some(Field::new(
2212                "coverage_offset",
2213                FieldType::offset(self.coverage_offset(), self.coverage()),
2214            )),
2215            2usize => Some(Field::new(
2216                "class_def_offset",
2217                FieldType::offset(self.class_def_offset(), self.class_def()),
2218            )),
2219            3usize => Some(Field::new(
2220                "class_seq_rule_set_count",
2221                self.class_seq_rule_set_count(),
2222            )),
2223            4usize => Some({
2224                let data = self.data;
2225                Field::new(
2226                    "class_seq_rule_set_offsets",
2227                    FieldType::array_of_offsets(
2228                        better_type_name::<ClassSequenceRuleSet>(),
2229                        self.class_seq_rule_set_offsets(),
2230                        move |off| {
2231                            let target = off.get().resolve::<ClassSequenceRuleSet>(data);
2232                            FieldType::offset(off.get(), target)
2233                        },
2234                    ),
2235                )
2236            }),
2237            _ => None,
2238        }
2239    }
2240}
2241
2242#[cfg(feature = "experimental_traverse")]
2243#[allow(clippy::needless_lifetimes)]
2244impl<'a> std::fmt::Debug for SequenceContextFormat2<'a> {
2245    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2246        (self as &dyn SomeTable<'a>).fmt(f)
2247    }
2248}
2249
2250/// Part of [SequenceContextFormat2]
2251#[derive(Debug, Clone, Copy)]
2252#[doc(hidden)]
2253pub struct ClassSequenceRuleSetMarker {
2254    class_seq_rule_offsets_byte_len: usize,
2255}
2256
2257impl ClassSequenceRuleSetMarker {
2258    pub fn class_seq_rule_count_byte_range(&self) -> Range<usize> {
2259        let start = 0;
2260        start..start + u16::RAW_BYTE_LEN
2261    }
2262
2263    pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2264        let start = self.class_seq_rule_count_byte_range().end;
2265        start..start + self.class_seq_rule_offsets_byte_len
2266    }
2267}
2268
2269impl MinByteRange for ClassSequenceRuleSetMarker {
2270    fn min_byte_range(&self) -> Range<usize> {
2271        0..self.class_seq_rule_offsets_byte_range().end
2272    }
2273}
2274
2275impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> {
2276    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2277        let mut cursor = data.cursor();
2278        let class_seq_rule_count: u16 = cursor.read()?;
2279        let class_seq_rule_offsets_byte_len = (class_seq_rule_count as usize)
2280            .checked_mul(Offset16::RAW_BYTE_LEN)
2281            .ok_or(ReadError::OutOfBounds)?;
2282        cursor.advance_by(class_seq_rule_offsets_byte_len);
2283        cursor.finish(ClassSequenceRuleSetMarker {
2284            class_seq_rule_offsets_byte_len,
2285        })
2286    }
2287}
2288
2289/// Part of [SequenceContextFormat2]
2290pub type ClassSequenceRuleSet<'a> = TableRef<'a, ClassSequenceRuleSetMarker>;
2291
2292#[allow(clippy::needless_lifetimes)]
2293impl<'a> ClassSequenceRuleSet<'a> {
2294    /// Number of ClassSequenceRule tables
2295    pub fn class_seq_rule_count(&self) -> u16 {
2296        let range = self.shape.class_seq_rule_count_byte_range();
2297        self.data.read_at(range.start).unwrap()
2298    }
2299
2300    /// Array of offsets to ClassSequenceRule tables, from beginning of
2301    /// ClassSequenceRuleSet table
2302    pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2303        let range = self.shape.class_seq_rule_offsets_byte_range();
2304        self.data.read_array(range).unwrap()
2305    }
2306
2307    /// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets].
2308    pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> {
2309        let data = self.data;
2310        let offsets = self.class_seq_rule_offsets();
2311        ArrayOfOffsets::new(offsets, data, ())
2312    }
2313}
2314
2315#[cfg(feature = "experimental_traverse")]
2316impl<'a> SomeTable<'a> for ClassSequenceRuleSet<'a> {
2317    fn type_name(&self) -> &str {
2318        "ClassSequenceRuleSet"
2319    }
2320    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2321        match idx {
2322            0usize => Some(Field::new(
2323                "class_seq_rule_count",
2324                self.class_seq_rule_count(),
2325            )),
2326            1usize => Some({
2327                let data = self.data;
2328                Field::new(
2329                    "class_seq_rule_offsets",
2330                    FieldType::array_of_offsets(
2331                        better_type_name::<ClassSequenceRule>(),
2332                        self.class_seq_rule_offsets(),
2333                        move |off| {
2334                            let target = off.get().resolve::<ClassSequenceRule>(data);
2335                            FieldType::offset(off.get(), target)
2336                        },
2337                    ),
2338                )
2339            }),
2340            _ => None,
2341        }
2342    }
2343}
2344
2345#[cfg(feature = "experimental_traverse")]
2346#[allow(clippy::needless_lifetimes)]
2347impl<'a> std::fmt::Debug for ClassSequenceRuleSet<'a> {
2348    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2349        (self as &dyn SomeTable<'a>).fmt(f)
2350    }
2351}
2352
2353/// Part of [SequenceContextFormat2]
2354#[derive(Debug, Clone, Copy)]
2355#[doc(hidden)]
2356pub struct ClassSequenceRuleMarker {
2357    input_sequence_byte_len: usize,
2358    seq_lookup_records_byte_len: usize,
2359}
2360
2361impl ClassSequenceRuleMarker {
2362    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2363        let start = 0;
2364        start..start + u16::RAW_BYTE_LEN
2365    }
2366
2367    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2368        let start = self.glyph_count_byte_range().end;
2369        start..start + u16::RAW_BYTE_LEN
2370    }
2371
2372    pub fn input_sequence_byte_range(&self) -> Range<usize> {
2373        let start = self.seq_lookup_count_byte_range().end;
2374        start..start + self.input_sequence_byte_len
2375    }
2376
2377    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2378        let start = self.input_sequence_byte_range().end;
2379        start..start + self.seq_lookup_records_byte_len
2380    }
2381}
2382
2383impl MinByteRange for ClassSequenceRuleMarker {
2384    fn min_byte_range(&self) -> Range<usize> {
2385        0..self.seq_lookup_records_byte_range().end
2386    }
2387}
2388
2389impl<'a> FontRead<'a> for ClassSequenceRule<'a> {
2390    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2391        let mut cursor = data.cursor();
2392        let glyph_count: u16 = cursor.read()?;
2393        let seq_lookup_count: u16 = cursor.read()?;
2394        let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize))
2395            .checked_mul(u16::RAW_BYTE_LEN)
2396            .ok_or(ReadError::OutOfBounds)?;
2397        cursor.advance_by(input_sequence_byte_len);
2398        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
2399            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2400            .ok_or(ReadError::OutOfBounds)?;
2401        cursor.advance_by(seq_lookup_records_byte_len);
2402        cursor.finish(ClassSequenceRuleMarker {
2403            input_sequence_byte_len,
2404            seq_lookup_records_byte_len,
2405        })
2406    }
2407}
2408
2409/// Part of [SequenceContextFormat2]
2410pub type ClassSequenceRule<'a> = TableRef<'a, ClassSequenceRuleMarker>;
2411
2412#[allow(clippy::needless_lifetimes)]
2413impl<'a> ClassSequenceRule<'a> {
2414    /// Number of glyphs to be matched
2415    pub fn glyph_count(&self) -> u16 {
2416        let range = self.shape.glyph_count_byte_range();
2417        self.data.read_at(range.start).unwrap()
2418    }
2419
2420    /// Number of SequenceLookupRecords
2421    pub fn seq_lookup_count(&self) -> u16 {
2422        let range = self.shape.seq_lookup_count_byte_range();
2423        self.data.read_at(range.start).unwrap()
2424    }
2425
2426    /// Sequence of classes to be matched to the input glyph sequence,
2427    /// beginning with the second glyph position
2428    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
2429        let range = self.shape.input_sequence_byte_range();
2430        self.data.read_array(range).unwrap()
2431    }
2432
2433    /// Array of SequenceLookupRecords
2434    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2435        let range = self.shape.seq_lookup_records_byte_range();
2436        self.data.read_array(range).unwrap()
2437    }
2438}
2439
2440#[cfg(feature = "experimental_traverse")]
2441impl<'a> SomeTable<'a> for ClassSequenceRule<'a> {
2442    fn type_name(&self) -> &str {
2443        "ClassSequenceRule"
2444    }
2445    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2446        match idx {
2447            0usize => Some(Field::new("glyph_count", self.glyph_count())),
2448            1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2449            2usize => Some(Field::new("input_sequence", self.input_sequence())),
2450            3usize => Some(Field::new(
2451                "seq_lookup_records",
2452                traversal::FieldType::array_of_records(
2453                    stringify!(SequenceLookupRecord),
2454                    self.seq_lookup_records(),
2455                    self.offset_data(),
2456                ),
2457            )),
2458            _ => None,
2459        }
2460    }
2461}
2462
2463#[cfg(feature = "experimental_traverse")]
2464#[allow(clippy::needless_lifetimes)]
2465impl<'a> std::fmt::Debug for ClassSequenceRule<'a> {
2466    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2467        (self as &dyn SomeTable<'a>).fmt(f)
2468    }
2469}
2470
2471impl Format<u16> for SequenceContextFormat3Marker {
2472    const FORMAT: u16 = 3;
2473}
2474
2475/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
2476#[derive(Debug, Clone, Copy)]
2477#[doc(hidden)]
2478pub struct SequenceContextFormat3Marker {
2479    coverage_offsets_byte_len: usize,
2480    seq_lookup_records_byte_len: usize,
2481}
2482
2483impl SequenceContextFormat3Marker {
2484    pub fn format_byte_range(&self) -> Range<usize> {
2485        let start = 0;
2486        start..start + u16::RAW_BYTE_LEN
2487    }
2488
2489    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2490        let start = self.format_byte_range().end;
2491        start..start + u16::RAW_BYTE_LEN
2492    }
2493
2494    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2495        let start = self.glyph_count_byte_range().end;
2496        start..start + u16::RAW_BYTE_LEN
2497    }
2498
2499    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
2500        let start = self.seq_lookup_count_byte_range().end;
2501        start..start + self.coverage_offsets_byte_len
2502    }
2503
2504    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2505        let start = self.coverage_offsets_byte_range().end;
2506        start..start + self.seq_lookup_records_byte_len
2507    }
2508}
2509
2510impl MinByteRange for SequenceContextFormat3Marker {
2511    fn min_byte_range(&self) -> Range<usize> {
2512        0..self.seq_lookup_records_byte_range().end
2513    }
2514}
2515
2516impl<'a> FontRead<'a> for SequenceContextFormat3<'a> {
2517    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2518        let mut cursor = data.cursor();
2519        cursor.advance::<u16>();
2520        let glyph_count: u16 = cursor.read()?;
2521        let seq_lookup_count: u16 = cursor.read()?;
2522        let coverage_offsets_byte_len = (glyph_count as usize)
2523            .checked_mul(Offset16::RAW_BYTE_LEN)
2524            .ok_or(ReadError::OutOfBounds)?;
2525        cursor.advance_by(coverage_offsets_byte_len);
2526        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
2527            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2528            .ok_or(ReadError::OutOfBounds)?;
2529        cursor.advance_by(seq_lookup_records_byte_len);
2530        cursor.finish(SequenceContextFormat3Marker {
2531            coverage_offsets_byte_len,
2532            seq_lookup_records_byte_len,
2533        })
2534    }
2535}
2536
2537/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
2538pub type SequenceContextFormat3<'a> = TableRef<'a, SequenceContextFormat3Marker>;
2539
2540#[allow(clippy::needless_lifetimes)]
2541impl<'a> SequenceContextFormat3<'a> {
2542    /// Format identifier: format = 3
2543    pub fn format(&self) -> u16 {
2544        let range = self.shape.format_byte_range();
2545        self.data.read_at(range.start).unwrap()
2546    }
2547
2548    /// Number of glyphs in the input sequence
2549    pub fn glyph_count(&self) -> u16 {
2550        let range = self.shape.glyph_count_byte_range();
2551        self.data.read_at(range.start).unwrap()
2552    }
2553
2554    /// Number of SequenceLookupRecords
2555    pub fn seq_lookup_count(&self) -> u16 {
2556        let range = self.shape.seq_lookup_count_byte_range();
2557        self.data.read_at(range.start).unwrap()
2558    }
2559
2560    /// Array of offsets to Coverage tables, from beginning of
2561    /// SequenceContextFormat3 subtable
2562    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
2563        let range = self.shape.coverage_offsets_byte_range();
2564        self.data.read_array(range).unwrap()
2565    }
2566
2567    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
2568    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
2569        let data = self.data;
2570        let offsets = self.coverage_offsets();
2571        ArrayOfOffsets::new(offsets, data, ())
2572    }
2573
2574    /// Array of SequenceLookupRecords
2575    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2576        let range = self.shape.seq_lookup_records_byte_range();
2577        self.data.read_array(range).unwrap()
2578    }
2579}
2580
2581#[cfg(feature = "experimental_traverse")]
2582impl<'a> SomeTable<'a> for SequenceContextFormat3<'a> {
2583    fn type_name(&self) -> &str {
2584        "SequenceContextFormat3"
2585    }
2586    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2587        match idx {
2588            0usize => Some(Field::new("format", self.format())),
2589            1usize => Some(Field::new("glyph_count", self.glyph_count())),
2590            2usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2591            3usize => Some({
2592                let data = self.data;
2593                Field::new(
2594                    "coverage_offsets",
2595                    FieldType::array_of_offsets(
2596                        better_type_name::<CoverageTable>(),
2597                        self.coverage_offsets(),
2598                        move |off| {
2599                            let target = off.get().resolve::<CoverageTable>(data);
2600                            FieldType::offset(off.get(), target)
2601                        },
2602                    ),
2603                )
2604            }),
2605            4usize => Some(Field::new(
2606                "seq_lookup_records",
2607                traversal::FieldType::array_of_records(
2608                    stringify!(SequenceLookupRecord),
2609                    self.seq_lookup_records(),
2610                    self.offset_data(),
2611                ),
2612            )),
2613            _ => None,
2614        }
2615    }
2616}
2617
2618#[cfg(feature = "experimental_traverse")]
2619#[allow(clippy::needless_lifetimes)]
2620impl<'a> std::fmt::Debug for SequenceContextFormat3<'a> {
2621    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2622        (self as &dyn SomeTable<'a>).fmt(f)
2623    }
2624}
2625
2626#[derive(Clone)]
2627pub enum SequenceContext<'a> {
2628    Format1(SequenceContextFormat1<'a>),
2629    Format2(SequenceContextFormat2<'a>),
2630    Format3(SequenceContextFormat3<'a>),
2631}
2632
2633impl<'a> SequenceContext<'a> {
2634    ///Return the `FontData` used to resolve offsets for this table.
2635    pub fn offset_data(&self) -> FontData<'a> {
2636        match self {
2637            Self::Format1(item) => item.offset_data(),
2638            Self::Format2(item) => item.offset_data(),
2639            Self::Format3(item) => item.offset_data(),
2640        }
2641    }
2642
2643    /// Format identifier: format = 1
2644    pub fn format(&self) -> u16 {
2645        match self {
2646            Self::Format1(item) => item.format(),
2647            Self::Format2(item) => item.format(),
2648            Self::Format3(item) => item.format(),
2649        }
2650    }
2651}
2652
2653impl<'a> FontRead<'a> for SequenceContext<'a> {
2654    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2655        let format: u16 = data.read_at(0usize)?;
2656        match format {
2657            SequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
2658            SequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
2659            SequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
2660            other => Err(ReadError::InvalidFormat(other.into())),
2661        }
2662    }
2663}
2664
2665impl MinByteRange for SequenceContext<'_> {
2666    fn min_byte_range(&self) -> Range<usize> {
2667        match self {
2668            Self::Format1(item) => item.min_byte_range(),
2669            Self::Format2(item) => item.min_byte_range(),
2670            Self::Format3(item) => item.min_byte_range(),
2671        }
2672    }
2673}
2674
2675#[cfg(feature = "experimental_traverse")]
2676impl<'a> SequenceContext<'a> {
2677    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
2678        match self {
2679            Self::Format1(table) => table,
2680            Self::Format2(table) => table,
2681            Self::Format3(table) => table,
2682        }
2683    }
2684}
2685
2686#[cfg(feature = "experimental_traverse")]
2687impl std::fmt::Debug for SequenceContext<'_> {
2688    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2689        self.dyn_inner().fmt(f)
2690    }
2691}
2692
2693#[cfg(feature = "experimental_traverse")]
2694impl<'a> SomeTable<'a> for SequenceContext<'a> {
2695    fn type_name(&self) -> &str {
2696        self.dyn_inner().type_name()
2697    }
2698    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2699        self.dyn_inner().get_field(idx)
2700    }
2701}
2702
2703impl Format<u16> for ChainedSequenceContextFormat1Marker {
2704    const FORMAT: u16 = 1;
2705}
2706
2707/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
2708#[derive(Debug, Clone, Copy)]
2709#[doc(hidden)]
2710pub struct ChainedSequenceContextFormat1Marker {
2711    chained_seq_rule_set_offsets_byte_len: usize,
2712}
2713
2714impl ChainedSequenceContextFormat1Marker {
2715    pub fn format_byte_range(&self) -> Range<usize> {
2716        let start = 0;
2717        start..start + u16::RAW_BYTE_LEN
2718    }
2719
2720    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2721        let start = self.format_byte_range().end;
2722        start..start + Offset16::RAW_BYTE_LEN
2723    }
2724
2725    pub fn chained_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2726        let start = self.coverage_offset_byte_range().end;
2727        start..start + u16::RAW_BYTE_LEN
2728    }
2729
2730    pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2731        let start = self.chained_seq_rule_set_count_byte_range().end;
2732        start..start + self.chained_seq_rule_set_offsets_byte_len
2733    }
2734}
2735
2736impl MinByteRange for ChainedSequenceContextFormat1Marker {
2737    fn min_byte_range(&self) -> Range<usize> {
2738        0..self.chained_seq_rule_set_offsets_byte_range().end
2739    }
2740}
2741
2742impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> {
2743    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2744        let mut cursor = data.cursor();
2745        cursor.advance::<u16>();
2746        cursor.advance::<Offset16>();
2747        let chained_seq_rule_set_count: u16 = cursor.read()?;
2748        let chained_seq_rule_set_offsets_byte_len = (chained_seq_rule_set_count as usize)
2749            .checked_mul(Offset16::RAW_BYTE_LEN)
2750            .ok_or(ReadError::OutOfBounds)?;
2751        cursor.advance_by(chained_seq_rule_set_offsets_byte_len);
2752        cursor.finish(ChainedSequenceContextFormat1Marker {
2753            chained_seq_rule_set_offsets_byte_len,
2754        })
2755    }
2756}
2757
2758/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
2759pub type ChainedSequenceContextFormat1<'a> = TableRef<'a, ChainedSequenceContextFormat1Marker>;
2760
2761#[allow(clippy::needless_lifetimes)]
2762impl<'a> ChainedSequenceContextFormat1<'a> {
2763    /// Format identifier: format = 1
2764    pub fn format(&self) -> u16 {
2765        let range = self.shape.format_byte_range();
2766        self.data.read_at(range.start).unwrap()
2767    }
2768
2769    /// Offset to Coverage table, from beginning of
2770    /// ChainSequenceContextFormat1 table
2771    pub fn coverage_offset(&self) -> Offset16 {
2772        let range = self.shape.coverage_offset_byte_range();
2773        self.data.read_at(range.start).unwrap()
2774    }
2775
2776    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2777    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2778        let data = self.data;
2779        self.coverage_offset().resolve(data)
2780    }
2781
2782    /// Number of ChainedSequenceRuleSet tables
2783    pub fn chained_seq_rule_set_count(&self) -> u16 {
2784        let range = self.shape.chained_seq_rule_set_count_byte_range();
2785        self.data.read_at(range.start).unwrap()
2786    }
2787
2788    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
2789    /// ChainedSequenceContextFormat1 table (may be NULL)
2790    pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2791        let range = self.shape.chained_seq_rule_set_offsets_byte_range();
2792        self.data.read_array(range).unwrap()
2793    }
2794
2795    /// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets].
2796    pub fn chained_seq_rule_sets(
2797        &self,
2798    ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> {
2799        let data = self.data;
2800        let offsets = self.chained_seq_rule_set_offsets();
2801        ArrayOfNullableOffsets::new(offsets, data, ())
2802    }
2803}
2804
2805#[cfg(feature = "experimental_traverse")]
2806impl<'a> SomeTable<'a> for ChainedSequenceContextFormat1<'a> {
2807    fn type_name(&self) -> &str {
2808        "ChainedSequenceContextFormat1"
2809    }
2810    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2811        match idx {
2812            0usize => Some(Field::new("format", self.format())),
2813            1usize => Some(Field::new(
2814                "coverage_offset",
2815                FieldType::offset(self.coverage_offset(), self.coverage()),
2816            )),
2817            2usize => Some(Field::new(
2818                "chained_seq_rule_set_count",
2819                self.chained_seq_rule_set_count(),
2820            )),
2821            3usize => Some({
2822                let data = self.data;
2823                Field::new(
2824                    "chained_seq_rule_set_offsets",
2825                    FieldType::array_of_offsets(
2826                        better_type_name::<ChainedSequenceRuleSet>(),
2827                        self.chained_seq_rule_set_offsets(),
2828                        move |off| {
2829                            let target = off.get().resolve::<ChainedSequenceRuleSet>(data);
2830                            FieldType::offset(off.get(), target)
2831                        },
2832                    ),
2833                )
2834            }),
2835            _ => None,
2836        }
2837    }
2838}
2839
2840#[cfg(feature = "experimental_traverse")]
2841#[allow(clippy::needless_lifetimes)]
2842impl<'a> std::fmt::Debug for ChainedSequenceContextFormat1<'a> {
2843    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2844        (self as &dyn SomeTable<'a>).fmt(f)
2845    }
2846}
2847
2848/// Part of [ChainedSequenceContextFormat1]
2849#[derive(Debug, Clone, Copy)]
2850#[doc(hidden)]
2851pub struct ChainedSequenceRuleSetMarker {
2852    chained_seq_rule_offsets_byte_len: usize,
2853}
2854
2855impl ChainedSequenceRuleSetMarker {
2856    pub fn chained_seq_rule_count_byte_range(&self) -> Range<usize> {
2857        let start = 0;
2858        start..start + u16::RAW_BYTE_LEN
2859    }
2860
2861    pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2862        let start = self.chained_seq_rule_count_byte_range().end;
2863        start..start + self.chained_seq_rule_offsets_byte_len
2864    }
2865}
2866
2867impl MinByteRange for ChainedSequenceRuleSetMarker {
2868    fn min_byte_range(&self) -> Range<usize> {
2869        0..self.chained_seq_rule_offsets_byte_range().end
2870    }
2871}
2872
2873impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> {
2874    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2875        let mut cursor = data.cursor();
2876        let chained_seq_rule_count: u16 = cursor.read()?;
2877        let chained_seq_rule_offsets_byte_len = (chained_seq_rule_count as usize)
2878            .checked_mul(Offset16::RAW_BYTE_LEN)
2879            .ok_or(ReadError::OutOfBounds)?;
2880        cursor.advance_by(chained_seq_rule_offsets_byte_len);
2881        cursor.finish(ChainedSequenceRuleSetMarker {
2882            chained_seq_rule_offsets_byte_len,
2883        })
2884    }
2885}
2886
2887/// Part of [ChainedSequenceContextFormat1]
2888pub type ChainedSequenceRuleSet<'a> = TableRef<'a, ChainedSequenceRuleSetMarker>;
2889
2890#[allow(clippy::needless_lifetimes)]
2891impl<'a> ChainedSequenceRuleSet<'a> {
2892    /// Number of ChainedSequenceRule tables
2893    pub fn chained_seq_rule_count(&self) -> u16 {
2894        let range = self.shape.chained_seq_rule_count_byte_range();
2895        self.data.read_at(range.start).unwrap()
2896    }
2897
2898    /// Array of offsets to ChainedSequenceRule tables, from beginning
2899    /// of ChainedSequenceRuleSet table
2900    pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2901        let range = self.shape.chained_seq_rule_offsets_byte_range();
2902        self.data.read_array(range).unwrap()
2903    }
2904
2905    /// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets].
2906    pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> {
2907        let data = self.data;
2908        let offsets = self.chained_seq_rule_offsets();
2909        ArrayOfOffsets::new(offsets, data, ())
2910    }
2911}
2912
2913#[cfg(feature = "experimental_traverse")]
2914impl<'a> SomeTable<'a> for ChainedSequenceRuleSet<'a> {
2915    fn type_name(&self) -> &str {
2916        "ChainedSequenceRuleSet"
2917    }
2918    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2919        match idx {
2920            0usize => Some(Field::new(
2921                "chained_seq_rule_count",
2922                self.chained_seq_rule_count(),
2923            )),
2924            1usize => Some({
2925                let data = self.data;
2926                Field::new(
2927                    "chained_seq_rule_offsets",
2928                    FieldType::array_of_offsets(
2929                        better_type_name::<ChainedSequenceRule>(),
2930                        self.chained_seq_rule_offsets(),
2931                        move |off| {
2932                            let target = off.get().resolve::<ChainedSequenceRule>(data);
2933                            FieldType::offset(off.get(), target)
2934                        },
2935                    ),
2936                )
2937            }),
2938            _ => None,
2939        }
2940    }
2941}
2942
2943#[cfg(feature = "experimental_traverse")]
2944#[allow(clippy::needless_lifetimes)]
2945impl<'a> std::fmt::Debug for ChainedSequenceRuleSet<'a> {
2946    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2947        (self as &dyn SomeTable<'a>).fmt(f)
2948    }
2949}
2950
2951/// Part of [ChainedSequenceContextFormat1]
2952#[derive(Debug, Clone, Copy)]
2953#[doc(hidden)]
2954pub struct ChainedSequenceRuleMarker {
2955    backtrack_sequence_byte_len: usize,
2956    input_sequence_byte_len: usize,
2957    lookahead_sequence_byte_len: usize,
2958    seq_lookup_records_byte_len: usize,
2959}
2960
2961impl ChainedSequenceRuleMarker {
2962    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
2963        let start = 0;
2964        start..start + u16::RAW_BYTE_LEN
2965    }
2966
2967    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
2968        let start = self.backtrack_glyph_count_byte_range().end;
2969        start..start + self.backtrack_sequence_byte_len
2970    }
2971
2972    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
2973        let start = self.backtrack_sequence_byte_range().end;
2974        start..start + u16::RAW_BYTE_LEN
2975    }
2976
2977    pub fn input_sequence_byte_range(&self) -> Range<usize> {
2978        let start = self.input_glyph_count_byte_range().end;
2979        start..start + self.input_sequence_byte_len
2980    }
2981
2982    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
2983        let start = self.input_sequence_byte_range().end;
2984        start..start + u16::RAW_BYTE_LEN
2985    }
2986
2987    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
2988        let start = self.lookahead_glyph_count_byte_range().end;
2989        start..start + self.lookahead_sequence_byte_len
2990    }
2991
2992    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2993        let start = self.lookahead_sequence_byte_range().end;
2994        start..start + u16::RAW_BYTE_LEN
2995    }
2996
2997    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2998        let start = self.seq_lookup_count_byte_range().end;
2999        start..start + self.seq_lookup_records_byte_len
3000    }
3001}
3002
3003impl MinByteRange for ChainedSequenceRuleMarker {
3004    fn min_byte_range(&self) -> Range<usize> {
3005        0..self.seq_lookup_records_byte_range().end
3006    }
3007}
3008
3009impl<'a> FontRead<'a> for ChainedSequenceRule<'a> {
3010    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3011        let mut cursor = data.cursor();
3012        let backtrack_glyph_count: u16 = cursor.read()?;
3013        let backtrack_sequence_byte_len = (backtrack_glyph_count as usize)
3014            .checked_mul(GlyphId16::RAW_BYTE_LEN)
3015            .ok_or(ReadError::OutOfBounds)?;
3016        cursor.advance_by(backtrack_sequence_byte_len);
3017        let input_glyph_count: u16 = cursor.read()?;
3018        let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize))
3019            .checked_mul(GlyphId16::RAW_BYTE_LEN)
3020            .ok_or(ReadError::OutOfBounds)?;
3021        cursor.advance_by(input_sequence_byte_len);
3022        let lookahead_glyph_count: u16 = cursor.read()?;
3023        let lookahead_sequence_byte_len = (lookahead_glyph_count as usize)
3024            .checked_mul(GlyphId16::RAW_BYTE_LEN)
3025            .ok_or(ReadError::OutOfBounds)?;
3026        cursor.advance_by(lookahead_sequence_byte_len);
3027        let seq_lookup_count: u16 = cursor.read()?;
3028        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
3029            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3030            .ok_or(ReadError::OutOfBounds)?;
3031        cursor.advance_by(seq_lookup_records_byte_len);
3032        cursor.finish(ChainedSequenceRuleMarker {
3033            backtrack_sequence_byte_len,
3034            input_sequence_byte_len,
3035            lookahead_sequence_byte_len,
3036            seq_lookup_records_byte_len,
3037        })
3038    }
3039}
3040
3041/// Part of [ChainedSequenceContextFormat1]
3042pub type ChainedSequenceRule<'a> = TableRef<'a, ChainedSequenceRuleMarker>;
3043
3044#[allow(clippy::needless_lifetimes)]
3045impl<'a> ChainedSequenceRule<'a> {
3046    /// Number of glyphs in the backtrack sequence
3047    pub fn backtrack_glyph_count(&self) -> u16 {
3048        let range = self.shape.backtrack_glyph_count_byte_range();
3049        self.data.read_at(range.start).unwrap()
3050    }
3051
3052    /// Array of backtrack glyph IDs
3053    pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
3054        let range = self.shape.backtrack_sequence_byte_range();
3055        self.data.read_array(range).unwrap()
3056    }
3057
3058    /// Number of glyphs in the input sequence
3059    pub fn input_glyph_count(&self) -> u16 {
3060        let range = self.shape.input_glyph_count_byte_range();
3061        self.data.read_at(range.start).unwrap()
3062    }
3063
3064    /// Array of input glyph IDs—start with second glyph
3065    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
3066        let range = self.shape.input_sequence_byte_range();
3067        self.data.read_array(range).unwrap()
3068    }
3069
3070    /// Number of glyphs in the lookahead sequence
3071    pub fn lookahead_glyph_count(&self) -> u16 {
3072        let range = self.shape.lookahead_glyph_count_byte_range();
3073        self.data.read_at(range.start).unwrap()
3074    }
3075
3076    /// Array of lookahead glyph IDs
3077    pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
3078        let range = self.shape.lookahead_sequence_byte_range();
3079        self.data.read_array(range).unwrap()
3080    }
3081
3082    /// Number of SequenceLookupRecords
3083    pub fn seq_lookup_count(&self) -> u16 {
3084        let range = self.shape.seq_lookup_count_byte_range();
3085        self.data.read_at(range.start).unwrap()
3086    }
3087
3088    /// Array of SequenceLookupRecords
3089    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3090        let range = self.shape.seq_lookup_records_byte_range();
3091        self.data.read_array(range).unwrap()
3092    }
3093}
3094
3095#[cfg(feature = "experimental_traverse")]
3096impl<'a> SomeTable<'a> for ChainedSequenceRule<'a> {
3097    fn type_name(&self) -> &str {
3098        "ChainedSequenceRule"
3099    }
3100    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3101        match idx {
3102            0usize => Some(Field::new(
3103                "backtrack_glyph_count",
3104                self.backtrack_glyph_count(),
3105            )),
3106            1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
3107            2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3108            3usize => Some(Field::new("input_sequence", self.input_sequence())),
3109            4usize => Some(Field::new(
3110                "lookahead_glyph_count",
3111                self.lookahead_glyph_count(),
3112            )),
3113            5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
3114            6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3115            7usize => Some(Field::new(
3116                "seq_lookup_records",
3117                traversal::FieldType::array_of_records(
3118                    stringify!(SequenceLookupRecord),
3119                    self.seq_lookup_records(),
3120                    self.offset_data(),
3121                ),
3122            )),
3123            _ => None,
3124        }
3125    }
3126}
3127
3128#[cfg(feature = "experimental_traverse")]
3129#[allow(clippy::needless_lifetimes)]
3130impl<'a> std::fmt::Debug for ChainedSequenceRule<'a> {
3131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3132        (self as &dyn SomeTable<'a>).fmt(f)
3133    }
3134}
3135
3136impl Format<u16> for ChainedSequenceContextFormat2Marker {
3137    const FORMAT: u16 = 2;
3138}
3139
3140/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
3141#[derive(Debug, Clone, Copy)]
3142#[doc(hidden)]
3143pub struct ChainedSequenceContextFormat2Marker {
3144    chained_class_seq_rule_set_offsets_byte_len: usize,
3145}
3146
3147impl ChainedSequenceContextFormat2Marker {
3148    pub fn format_byte_range(&self) -> Range<usize> {
3149        let start = 0;
3150        start..start + u16::RAW_BYTE_LEN
3151    }
3152
3153    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
3154        let start = self.format_byte_range().end;
3155        start..start + Offset16::RAW_BYTE_LEN
3156    }
3157
3158    pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
3159        let start = self.coverage_offset_byte_range().end;
3160        start..start + Offset16::RAW_BYTE_LEN
3161    }
3162
3163    pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
3164        let start = self.backtrack_class_def_offset_byte_range().end;
3165        start..start + Offset16::RAW_BYTE_LEN
3166    }
3167
3168    pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
3169        let start = self.input_class_def_offset_byte_range().end;
3170        start..start + Offset16::RAW_BYTE_LEN
3171    }
3172
3173    pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
3174        let start = self.lookahead_class_def_offset_byte_range().end;
3175        start..start + u16::RAW_BYTE_LEN
3176    }
3177
3178    pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
3179        let start = self.chained_class_seq_rule_set_count_byte_range().end;
3180        start..start + self.chained_class_seq_rule_set_offsets_byte_len
3181    }
3182}
3183
3184impl MinByteRange for ChainedSequenceContextFormat2Marker {
3185    fn min_byte_range(&self) -> Range<usize> {
3186        0..self.chained_class_seq_rule_set_offsets_byte_range().end
3187    }
3188}
3189
3190impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> {
3191    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3192        let mut cursor = data.cursor();
3193        cursor.advance::<u16>();
3194        cursor.advance::<Offset16>();
3195        cursor.advance::<Offset16>();
3196        cursor.advance::<Offset16>();
3197        cursor.advance::<Offset16>();
3198        let chained_class_seq_rule_set_count: u16 = cursor.read()?;
3199        let chained_class_seq_rule_set_offsets_byte_len = (chained_class_seq_rule_set_count
3200            as usize)
3201            .checked_mul(Offset16::RAW_BYTE_LEN)
3202            .ok_or(ReadError::OutOfBounds)?;
3203        cursor.advance_by(chained_class_seq_rule_set_offsets_byte_len);
3204        cursor.finish(ChainedSequenceContextFormat2Marker {
3205            chained_class_seq_rule_set_offsets_byte_len,
3206        })
3207    }
3208}
3209
3210/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
3211pub type ChainedSequenceContextFormat2<'a> = TableRef<'a, ChainedSequenceContextFormat2Marker>;
3212
3213#[allow(clippy::needless_lifetimes)]
3214impl<'a> ChainedSequenceContextFormat2<'a> {
3215    /// Format identifier: format = 2
3216    pub fn format(&self) -> u16 {
3217        let range = self.shape.format_byte_range();
3218        self.data.read_at(range.start).unwrap()
3219    }
3220
3221    /// Offset to Coverage table, from beginning of
3222    /// ChainedSequenceContextFormat2 table
3223    pub fn coverage_offset(&self) -> Offset16 {
3224        let range = self.shape.coverage_offset_byte_range();
3225        self.data.read_at(range.start).unwrap()
3226    }
3227
3228    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
3229    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3230        let data = self.data;
3231        self.coverage_offset().resolve(data)
3232    }
3233
3234    /// Offset to ClassDef table containing backtrack sequence context,
3235    /// from beginning of ChainedSequenceContextFormat2 table
3236    pub fn backtrack_class_def_offset(&self) -> Offset16 {
3237        let range = self.shape.backtrack_class_def_offset_byte_range();
3238        self.data.read_at(range.start).unwrap()
3239    }
3240
3241    /// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset].
3242    pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3243        let data = self.data;
3244        self.backtrack_class_def_offset().resolve(data)
3245    }
3246
3247    /// Offset to ClassDef table containing input sequence context,
3248    /// from beginning of ChainedSequenceContextFormat2 table
3249    pub fn input_class_def_offset(&self) -> Offset16 {
3250        let range = self.shape.input_class_def_offset_byte_range();
3251        self.data.read_at(range.start).unwrap()
3252    }
3253
3254    /// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset].
3255    pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3256        let data = self.data;
3257        self.input_class_def_offset().resolve(data)
3258    }
3259
3260    /// Offset to ClassDef table containing lookahead sequence context,
3261    /// from beginning of ChainedSequenceContextFormat2 table
3262    pub fn lookahead_class_def_offset(&self) -> Offset16 {
3263        let range = self.shape.lookahead_class_def_offset_byte_range();
3264        self.data.read_at(range.start).unwrap()
3265    }
3266
3267    /// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset].
3268    pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3269        let data = self.data;
3270        self.lookahead_class_def_offset().resolve(data)
3271    }
3272
3273    /// Number of ChainedClassSequenceRuleSet tables
3274    pub fn chained_class_seq_rule_set_count(&self) -> u16 {
3275        let range = self.shape.chained_class_seq_rule_set_count_byte_range();
3276        self.data.read_at(range.start).unwrap()
3277    }
3278
3279    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
3280    /// beginning of ChainedSequenceContextFormat2 table (may be NULL)
3281    pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3282        let range = self.shape.chained_class_seq_rule_set_offsets_byte_range();
3283        self.data.read_array(range).unwrap()
3284    }
3285
3286    /// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets].
3287    pub fn chained_class_seq_rule_sets(
3288        &self,
3289    ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> {
3290        let data = self.data;
3291        let offsets = self.chained_class_seq_rule_set_offsets();
3292        ArrayOfNullableOffsets::new(offsets, data, ())
3293    }
3294}
3295
3296#[cfg(feature = "experimental_traverse")]
3297impl<'a> SomeTable<'a> for ChainedSequenceContextFormat2<'a> {
3298    fn type_name(&self) -> &str {
3299        "ChainedSequenceContextFormat2"
3300    }
3301    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3302        match idx {
3303            0usize => Some(Field::new("format", self.format())),
3304            1usize => Some(Field::new(
3305                "coverage_offset",
3306                FieldType::offset(self.coverage_offset(), self.coverage()),
3307            )),
3308            2usize => Some(Field::new(
3309                "backtrack_class_def_offset",
3310                FieldType::offset(
3311                    self.backtrack_class_def_offset(),
3312                    self.backtrack_class_def(),
3313                ),
3314            )),
3315            3usize => Some(Field::new(
3316                "input_class_def_offset",
3317                FieldType::offset(self.input_class_def_offset(), self.input_class_def()),
3318            )),
3319            4usize => Some(Field::new(
3320                "lookahead_class_def_offset",
3321                FieldType::offset(
3322                    self.lookahead_class_def_offset(),
3323                    self.lookahead_class_def(),
3324                ),
3325            )),
3326            5usize => Some(Field::new(
3327                "chained_class_seq_rule_set_count",
3328                self.chained_class_seq_rule_set_count(),
3329            )),
3330            6usize => Some({
3331                let data = self.data;
3332                Field::new(
3333                    "chained_class_seq_rule_set_offsets",
3334                    FieldType::array_of_offsets(
3335                        better_type_name::<ChainedClassSequenceRuleSet>(),
3336                        self.chained_class_seq_rule_set_offsets(),
3337                        move |off| {
3338                            let target = off.get().resolve::<ChainedClassSequenceRuleSet>(data);
3339                            FieldType::offset(off.get(), target)
3340                        },
3341                    ),
3342                )
3343            }),
3344            _ => None,
3345        }
3346    }
3347}
3348
3349#[cfg(feature = "experimental_traverse")]
3350#[allow(clippy::needless_lifetimes)]
3351impl<'a> std::fmt::Debug for ChainedSequenceContextFormat2<'a> {
3352    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3353        (self as &dyn SomeTable<'a>).fmt(f)
3354    }
3355}
3356
3357/// Part of [ChainedSequenceContextFormat2]
3358#[derive(Debug, Clone, Copy)]
3359#[doc(hidden)]
3360pub struct ChainedClassSequenceRuleSetMarker {
3361    chained_class_seq_rule_offsets_byte_len: usize,
3362}
3363
3364impl ChainedClassSequenceRuleSetMarker {
3365    pub fn chained_class_seq_rule_count_byte_range(&self) -> Range<usize> {
3366        let start = 0;
3367        start..start + u16::RAW_BYTE_LEN
3368    }
3369
3370    pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
3371        let start = self.chained_class_seq_rule_count_byte_range().end;
3372        start..start + self.chained_class_seq_rule_offsets_byte_len
3373    }
3374}
3375
3376impl MinByteRange for ChainedClassSequenceRuleSetMarker {
3377    fn min_byte_range(&self) -> Range<usize> {
3378        0..self.chained_class_seq_rule_offsets_byte_range().end
3379    }
3380}
3381
3382impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> {
3383    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3384        let mut cursor = data.cursor();
3385        let chained_class_seq_rule_count: u16 = cursor.read()?;
3386        let chained_class_seq_rule_offsets_byte_len = (chained_class_seq_rule_count as usize)
3387            .checked_mul(Offset16::RAW_BYTE_LEN)
3388            .ok_or(ReadError::OutOfBounds)?;
3389        cursor.advance_by(chained_class_seq_rule_offsets_byte_len);
3390        cursor.finish(ChainedClassSequenceRuleSetMarker {
3391            chained_class_seq_rule_offsets_byte_len,
3392        })
3393    }
3394}
3395
3396/// Part of [ChainedSequenceContextFormat2]
3397pub type ChainedClassSequenceRuleSet<'a> = TableRef<'a, ChainedClassSequenceRuleSetMarker>;
3398
3399#[allow(clippy::needless_lifetimes)]
3400impl<'a> ChainedClassSequenceRuleSet<'a> {
3401    /// Number of ChainedClassSequenceRule tables
3402    pub fn chained_class_seq_rule_count(&self) -> u16 {
3403        let range = self.shape.chained_class_seq_rule_count_byte_range();
3404        self.data.read_at(range.start).unwrap()
3405    }
3406
3407    /// Array of offsets to ChainedClassSequenceRule tables, from
3408    /// beginning of ChainedClassSequenceRuleSet
3409    pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
3410        let range = self.shape.chained_class_seq_rule_offsets_byte_range();
3411        self.data.read_array(range).unwrap()
3412    }
3413
3414    /// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets].
3415    pub fn chained_class_seq_rules(
3416        &self,
3417    ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> {
3418        let data = self.data;
3419        let offsets = self.chained_class_seq_rule_offsets();
3420        ArrayOfOffsets::new(offsets, data, ())
3421    }
3422}
3423
3424#[cfg(feature = "experimental_traverse")]
3425impl<'a> SomeTable<'a> for ChainedClassSequenceRuleSet<'a> {
3426    fn type_name(&self) -> &str {
3427        "ChainedClassSequenceRuleSet"
3428    }
3429    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3430        match idx {
3431            0usize => Some(Field::new(
3432                "chained_class_seq_rule_count",
3433                self.chained_class_seq_rule_count(),
3434            )),
3435            1usize => Some({
3436                let data = self.data;
3437                Field::new(
3438                    "chained_class_seq_rule_offsets",
3439                    FieldType::array_of_offsets(
3440                        better_type_name::<ChainedClassSequenceRule>(),
3441                        self.chained_class_seq_rule_offsets(),
3442                        move |off| {
3443                            let target = off.get().resolve::<ChainedClassSequenceRule>(data);
3444                            FieldType::offset(off.get(), target)
3445                        },
3446                    ),
3447                )
3448            }),
3449            _ => None,
3450        }
3451    }
3452}
3453
3454#[cfg(feature = "experimental_traverse")]
3455#[allow(clippy::needless_lifetimes)]
3456impl<'a> std::fmt::Debug for ChainedClassSequenceRuleSet<'a> {
3457    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3458        (self as &dyn SomeTable<'a>).fmt(f)
3459    }
3460}
3461
3462/// Part of [ChainedSequenceContextFormat2]
3463#[derive(Debug, Clone, Copy)]
3464#[doc(hidden)]
3465pub struct ChainedClassSequenceRuleMarker {
3466    backtrack_sequence_byte_len: usize,
3467    input_sequence_byte_len: usize,
3468    lookahead_sequence_byte_len: usize,
3469    seq_lookup_records_byte_len: usize,
3470}
3471
3472impl ChainedClassSequenceRuleMarker {
3473    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3474        let start = 0;
3475        start..start + u16::RAW_BYTE_LEN
3476    }
3477
3478    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
3479        let start = self.backtrack_glyph_count_byte_range().end;
3480        start..start + self.backtrack_sequence_byte_len
3481    }
3482
3483    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3484        let start = self.backtrack_sequence_byte_range().end;
3485        start..start + u16::RAW_BYTE_LEN
3486    }
3487
3488    pub fn input_sequence_byte_range(&self) -> Range<usize> {
3489        let start = self.input_glyph_count_byte_range().end;
3490        start..start + self.input_sequence_byte_len
3491    }
3492
3493    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3494        let start = self.input_sequence_byte_range().end;
3495        start..start + u16::RAW_BYTE_LEN
3496    }
3497
3498    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
3499        let start = self.lookahead_glyph_count_byte_range().end;
3500        start..start + self.lookahead_sequence_byte_len
3501    }
3502
3503    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3504        let start = self.lookahead_sequence_byte_range().end;
3505        start..start + u16::RAW_BYTE_LEN
3506    }
3507
3508    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3509        let start = self.seq_lookup_count_byte_range().end;
3510        start..start + self.seq_lookup_records_byte_len
3511    }
3512}
3513
3514impl MinByteRange for ChainedClassSequenceRuleMarker {
3515    fn min_byte_range(&self) -> Range<usize> {
3516        0..self.seq_lookup_records_byte_range().end
3517    }
3518}
3519
3520impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> {
3521    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3522        let mut cursor = data.cursor();
3523        let backtrack_glyph_count: u16 = cursor.read()?;
3524        let backtrack_sequence_byte_len = (backtrack_glyph_count as usize)
3525            .checked_mul(u16::RAW_BYTE_LEN)
3526            .ok_or(ReadError::OutOfBounds)?;
3527        cursor.advance_by(backtrack_sequence_byte_len);
3528        let input_glyph_count: u16 = cursor.read()?;
3529        let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize))
3530            .checked_mul(u16::RAW_BYTE_LEN)
3531            .ok_or(ReadError::OutOfBounds)?;
3532        cursor.advance_by(input_sequence_byte_len);
3533        let lookahead_glyph_count: u16 = cursor.read()?;
3534        let lookahead_sequence_byte_len = (lookahead_glyph_count as usize)
3535            .checked_mul(u16::RAW_BYTE_LEN)
3536            .ok_or(ReadError::OutOfBounds)?;
3537        cursor.advance_by(lookahead_sequence_byte_len);
3538        let seq_lookup_count: u16 = cursor.read()?;
3539        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
3540            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3541            .ok_or(ReadError::OutOfBounds)?;
3542        cursor.advance_by(seq_lookup_records_byte_len);
3543        cursor.finish(ChainedClassSequenceRuleMarker {
3544            backtrack_sequence_byte_len,
3545            input_sequence_byte_len,
3546            lookahead_sequence_byte_len,
3547            seq_lookup_records_byte_len,
3548        })
3549    }
3550}
3551
3552/// Part of [ChainedSequenceContextFormat2]
3553pub type ChainedClassSequenceRule<'a> = TableRef<'a, ChainedClassSequenceRuleMarker>;
3554
3555#[allow(clippy::needless_lifetimes)]
3556impl<'a> ChainedClassSequenceRule<'a> {
3557    /// Number of glyphs in the backtrack sequence
3558    pub fn backtrack_glyph_count(&self) -> u16 {
3559        let range = self.shape.backtrack_glyph_count_byte_range();
3560        self.data.read_at(range.start).unwrap()
3561    }
3562
3563    /// Array of backtrack-sequence classes
3564    pub fn backtrack_sequence(&self) -> &'a [BigEndian<u16>] {
3565        let range = self.shape.backtrack_sequence_byte_range();
3566        self.data.read_array(range).unwrap()
3567    }
3568
3569    /// Total number of glyphs in the input sequence
3570    pub fn input_glyph_count(&self) -> u16 {
3571        let range = self.shape.input_glyph_count_byte_range();
3572        self.data.read_at(range.start).unwrap()
3573    }
3574
3575    /// Array of input sequence classes, beginning with the second
3576    /// glyph position
3577    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
3578        let range = self.shape.input_sequence_byte_range();
3579        self.data.read_array(range).unwrap()
3580    }
3581
3582    /// Number of glyphs in the lookahead sequence
3583    pub fn lookahead_glyph_count(&self) -> u16 {
3584        let range = self.shape.lookahead_glyph_count_byte_range();
3585        self.data.read_at(range.start).unwrap()
3586    }
3587
3588    /// Array of lookahead-sequence classes
3589    pub fn lookahead_sequence(&self) -> &'a [BigEndian<u16>] {
3590        let range = self.shape.lookahead_sequence_byte_range();
3591        self.data.read_array(range).unwrap()
3592    }
3593
3594    /// Number of SequenceLookupRecords
3595    pub fn seq_lookup_count(&self) -> u16 {
3596        let range = self.shape.seq_lookup_count_byte_range();
3597        self.data.read_at(range.start).unwrap()
3598    }
3599
3600    /// Array of SequenceLookupRecords
3601    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3602        let range = self.shape.seq_lookup_records_byte_range();
3603        self.data.read_array(range).unwrap()
3604    }
3605}
3606
3607#[cfg(feature = "experimental_traverse")]
3608impl<'a> SomeTable<'a> for ChainedClassSequenceRule<'a> {
3609    fn type_name(&self) -> &str {
3610        "ChainedClassSequenceRule"
3611    }
3612    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3613        match idx {
3614            0usize => Some(Field::new(
3615                "backtrack_glyph_count",
3616                self.backtrack_glyph_count(),
3617            )),
3618            1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
3619            2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3620            3usize => Some(Field::new("input_sequence", self.input_sequence())),
3621            4usize => Some(Field::new(
3622                "lookahead_glyph_count",
3623                self.lookahead_glyph_count(),
3624            )),
3625            5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
3626            6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3627            7usize => Some(Field::new(
3628                "seq_lookup_records",
3629                traversal::FieldType::array_of_records(
3630                    stringify!(SequenceLookupRecord),
3631                    self.seq_lookup_records(),
3632                    self.offset_data(),
3633                ),
3634            )),
3635            _ => None,
3636        }
3637    }
3638}
3639
3640#[cfg(feature = "experimental_traverse")]
3641#[allow(clippy::needless_lifetimes)]
3642impl<'a> std::fmt::Debug for ChainedClassSequenceRule<'a> {
3643    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3644        (self as &dyn SomeTable<'a>).fmt(f)
3645    }
3646}
3647
3648impl Format<u16> for ChainedSequenceContextFormat3Marker {
3649    const FORMAT: u16 = 3;
3650}
3651
3652/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
3653#[derive(Debug, Clone, Copy)]
3654#[doc(hidden)]
3655pub struct ChainedSequenceContextFormat3Marker {
3656    backtrack_coverage_offsets_byte_len: usize,
3657    input_coverage_offsets_byte_len: usize,
3658    lookahead_coverage_offsets_byte_len: usize,
3659    seq_lookup_records_byte_len: usize,
3660}
3661
3662impl ChainedSequenceContextFormat3Marker {
3663    pub fn format_byte_range(&self) -> Range<usize> {
3664        let start = 0;
3665        start..start + u16::RAW_BYTE_LEN
3666    }
3667
3668    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3669        let start = self.format_byte_range().end;
3670        start..start + u16::RAW_BYTE_LEN
3671    }
3672
3673    pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
3674        let start = self.backtrack_glyph_count_byte_range().end;
3675        start..start + self.backtrack_coverage_offsets_byte_len
3676    }
3677
3678    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3679        let start = self.backtrack_coverage_offsets_byte_range().end;
3680        start..start + u16::RAW_BYTE_LEN
3681    }
3682
3683    pub fn input_coverage_offsets_byte_range(&self) -> Range<usize> {
3684        let start = self.input_glyph_count_byte_range().end;
3685        start..start + self.input_coverage_offsets_byte_len
3686    }
3687
3688    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3689        let start = self.input_coverage_offsets_byte_range().end;
3690        start..start + u16::RAW_BYTE_LEN
3691    }
3692
3693    pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
3694        let start = self.lookahead_glyph_count_byte_range().end;
3695        start..start + self.lookahead_coverage_offsets_byte_len
3696    }
3697
3698    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3699        let start = self.lookahead_coverage_offsets_byte_range().end;
3700        start..start + u16::RAW_BYTE_LEN
3701    }
3702
3703    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3704        let start = self.seq_lookup_count_byte_range().end;
3705        start..start + self.seq_lookup_records_byte_len
3706    }
3707}
3708
3709impl MinByteRange for ChainedSequenceContextFormat3Marker {
3710    fn min_byte_range(&self) -> Range<usize> {
3711        0..self.seq_lookup_records_byte_range().end
3712    }
3713}
3714
3715impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> {
3716    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3717        let mut cursor = data.cursor();
3718        cursor.advance::<u16>();
3719        let backtrack_glyph_count: u16 = cursor.read()?;
3720        let backtrack_coverage_offsets_byte_len = (backtrack_glyph_count as usize)
3721            .checked_mul(Offset16::RAW_BYTE_LEN)
3722            .ok_or(ReadError::OutOfBounds)?;
3723        cursor.advance_by(backtrack_coverage_offsets_byte_len);
3724        let input_glyph_count: u16 = cursor.read()?;
3725        let input_coverage_offsets_byte_len = (input_glyph_count as usize)
3726            .checked_mul(Offset16::RAW_BYTE_LEN)
3727            .ok_or(ReadError::OutOfBounds)?;
3728        cursor.advance_by(input_coverage_offsets_byte_len);
3729        let lookahead_glyph_count: u16 = cursor.read()?;
3730        let lookahead_coverage_offsets_byte_len = (lookahead_glyph_count as usize)
3731            .checked_mul(Offset16::RAW_BYTE_LEN)
3732            .ok_or(ReadError::OutOfBounds)?;
3733        cursor.advance_by(lookahead_coverage_offsets_byte_len);
3734        let seq_lookup_count: u16 = cursor.read()?;
3735        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
3736            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3737            .ok_or(ReadError::OutOfBounds)?;
3738        cursor.advance_by(seq_lookup_records_byte_len);
3739        cursor.finish(ChainedSequenceContextFormat3Marker {
3740            backtrack_coverage_offsets_byte_len,
3741            input_coverage_offsets_byte_len,
3742            lookahead_coverage_offsets_byte_len,
3743            seq_lookup_records_byte_len,
3744        })
3745    }
3746}
3747
3748/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
3749pub type ChainedSequenceContextFormat3<'a> = TableRef<'a, ChainedSequenceContextFormat3Marker>;
3750
3751#[allow(clippy::needless_lifetimes)]
3752impl<'a> ChainedSequenceContextFormat3<'a> {
3753    /// Format identifier: format = 3
3754    pub fn format(&self) -> u16 {
3755        let range = self.shape.format_byte_range();
3756        self.data.read_at(range.start).unwrap()
3757    }
3758
3759    /// Number of glyphs in the backtrack sequence
3760    pub fn backtrack_glyph_count(&self) -> u16 {
3761        let range = self.shape.backtrack_glyph_count_byte_range();
3762        self.data.read_at(range.start).unwrap()
3763    }
3764
3765    /// Array of offsets to coverage tables for the backtrack sequence
3766    pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3767        let range = self.shape.backtrack_coverage_offsets_byte_range();
3768        self.data.read_array(range).unwrap()
3769    }
3770
3771    /// A dynamically resolving wrapper for [`backtrack_coverage_offsets`][Self::backtrack_coverage_offsets].
3772    pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3773        let data = self.data;
3774        let offsets = self.backtrack_coverage_offsets();
3775        ArrayOfOffsets::new(offsets, data, ())
3776    }
3777
3778    /// Number of glyphs in the input sequence
3779    pub fn input_glyph_count(&self) -> u16 {
3780        let range = self.shape.input_glyph_count_byte_range();
3781        self.data.read_at(range.start).unwrap()
3782    }
3783
3784    /// Array of offsets to coverage tables for the input sequence
3785    pub fn input_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3786        let range = self.shape.input_coverage_offsets_byte_range();
3787        self.data.read_array(range).unwrap()
3788    }
3789
3790    /// A dynamically resolving wrapper for [`input_coverage_offsets`][Self::input_coverage_offsets].
3791    pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3792        let data = self.data;
3793        let offsets = self.input_coverage_offsets();
3794        ArrayOfOffsets::new(offsets, data, ())
3795    }
3796
3797    /// Number of glyphs in the lookahead sequence
3798    pub fn lookahead_glyph_count(&self) -> u16 {
3799        let range = self.shape.lookahead_glyph_count_byte_range();
3800        self.data.read_at(range.start).unwrap()
3801    }
3802
3803    /// Array of offsets to coverage tables for the lookahead sequence
3804    pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3805        let range = self.shape.lookahead_coverage_offsets_byte_range();
3806        self.data.read_array(range).unwrap()
3807    }
3808
3809    /// A dynamically resolving wrapper for [`lookahead_coverage_offsets`][Self::lookahead_coverage_offsets].
3810    pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3811        let data = self.data;
3812        let offsets = self.lookahead_coverage_offsets();
3813        ArrayOfOffsets::new(offsets, data, ())
3814    }
3815
3816    /// Number of SequenceLookupRecords
3817    pub fn seq_lookup_count(&self) -> u16 {
3818        let range = self.shape.seq_lookup_count_byte_range();
3819        self.data.read_at(range.start).unwrap()
3820    }
3821
3822    /// Array of SequenceLookupRecords
3823    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3824        let range = self.shape.seq_lookup_records_byte_range();
3825        self.data.read_array(range).unwrap()
3826    }
3827}
3828
3829#[cfg(feature = "experimental_traverse")]
3830impl<'a> SomeTable<'a> for ChainedSequenceContextFormat3<'a> {
3831    fn type_name(&self) -> &str {
3832        "ChainedSequenceContextFormat3"
3833    }
3834    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3835        match idx {
3836            0usize => Some(Field::new("format", self.format())),
3837            1usize => Some(Field::new(
3838                "backtrack_glyph_count",
3839                self.backtrack_glyph_count(),
3840            )),
3841            2usize => Some({
3842                let data = self.data;
3843                Field::new(
3844                    "backtrack_coverage_offsets",
3845                    FieldType::array_of_offsets(
3846                        better_type_name::<CoverageTable>(),
3847                        self.backtrack_coverage_offsets(),
3848                        move |off| {
3849                            let target = off.get().resolve::<CoverageTable>(data);
3850                            FieldType::offset(off.get(), target)
3851                        },
3852                    ),
3853                )
3854            }),
3855            3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3856            4usize => Some({
3857                let data = self.data;
3858                Field::new(
3859                    "input_coverage_offsets",
3860                    FieldType::array_of_offsets(
3861                        better_type_name::<CoverageTable>(),
3862                        self.input_coverage_offsets(),
3863                        move |off| {
3864                            let target = off.get().resolve::<CoverageTable>(data);
3865                            FieldType::offset(off.get(), target)
3866                        },
3867                    ),
3868                )
3869            }),
3870            5usize => Some(Field::new(
3871                "lookahead_glyph_count",
3872                self.lookahead_glyph_count(),
3873            )),
3874            6usize => Some({
3875                let data = self.data;
3876                Field::new(
3877                    "lookahead_coverage_offsets",
3878                    FieldType::array_of_offsets(
3879                        better_type_name::<CoverageTable>(),
3880                        self.lookahead_coverage_offsets(),
3881                        move |off| {
3882                            let target = off.get().resolve::<CoverageTable>(data);
3883                            FieldType::offset(off.get(), target)
3884                        },
3885                    ),
3886                )
3887            }),
3888            7usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3889            8usize => Some(Field::new(
3890                "seq_lookup_records",
3891                traversal::FieldType::array_of_records(
3892                    stringify!(SequenceLookupRecord),
3893                    self.seq_lookup_records(),
3894                    self.offset_data(),
3895                ),
3896            )),
3897            _ => None,
3898        }
3899    }
3900}
3901
3902#[cfg(feature = "experimental_traverse")]
3903#[allow(clippy::needless_lifetimes)]
3904impl<'a> std::fmt::Debug for ChainedSequenceContextFormat3<'a> {
3905    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3906        (self as &dyn SomeTable<'a>).fmt(f)
3907    }
3908}
3909
3910#[derive(Clone)]
3911pub enum ChainedSequenceContext<'a> {
3912    Format1(ChainedSequenceContextFormat1<'a>),
3913    Format2(ChainedSequenceContextFormat2<'a>),
3914    Format3(ChainedSequenceContextFormat3<'a>),
3915}
3916
3917impl<'a> ChainedSequenceContext<'a> {
3918    ///Return the `FontData` used to resolve offsets for this table.
3919    pub fn offset_data(&self) -> FontData<'a> {
3920        match self {
3921            Self::Format1(item) => item.offset_data(),
3922            Self::Format2(item) => item.offset_data(),
3923            Self::Format3(item) => item.offset_data(),
3924        }
3925    }
3926
3927    /// Format identifier: format = 1
3928    pub fn format(&self) -> u16 {
3929        match self {
3930            Self::Format1(item) => item.format(),
3931            Self::Format2(item) => item.format(),
3932            Self::Format3(item) => item.format(),
3933        }
3934    }
3935}
3936
3937impl<'a> FontRead<'a> for ChainedSequenceContext<'a> {
3938    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3939        let format: u16 = data.read_at(0usize)?;
3940        match format {
3941            ChainedSequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
3942            ChainedSequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
3943            ChainedSequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
3944            other => Err(ReadError::InvalidFormat(other.into())),
3945        }
3946    }
3947}
3948
3949impl MinByteRange for ChainedSequenceContext<'_> {
3950    fn min_byte_range(&self) -> Range<usize> {
3951        match self {
3952            Self::Format1(item) => item.min_byte_range(),
3953            Self::Format2(item) => item.min_byte_range(),
3954            Self::Format3(item) => item.min_byte_range(),
3955        }
3956    }
3957}
3958
3959#[cfg(feature = "experimental_traverse")]
3960impl<'a> ChainedSequenceContext<'a> {
3961    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
3962        match self {
3963            Self::Format1(table) => table,
3964            Self::Format2(table) => table,
3965            Self::Format3(table) => table,
3966        }
3967    }
3968}
3969
3970#[cfg(feature = "experimental_traverse")]
3971impl std::fmt::Debug for ChainedSequenceContext<'_> {
3972    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3973        self.dyn_inner().fmt(f)
3974    }
3975}
3976
3977#[cfg(feature = "experimental_traverse")]
3978impl<'a> SomeTable<'a> for ChainedSequenceContext<'a> {
3979    fn type_name(&self) -> &str {
3980        self.dyn_inner().type_name()
3981    }
3982    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3983        self.dyn_inner().get_field(idx)
3984    }
3985}
3986
3987/// [Device](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
3988/// delta formats
3989#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
3990#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3991#[repr(u16)]
3992#[allow(clippy::manual_non_exhaustive)]
3993pub enum DeltaFormat {
3994    /// Signed 2-bit value, 8 values per uint16
3995    #[default]
3996    Local2BitDeltas = 0x0001,
3997    /// Signed 4-bit value, 4 values per uint16
3998    Local4BitDeltas = 0x0002,
3999    /// Signed 8-bit value, 2 values per uint16
4000    Local8BitDeltas = 0x0003,
4001    /// VariationIndex table, contains a delta-set index pair.
4002    VariationIndex = 0x8000,
4003    #[doc(hidden)]
4004    /// If font data is malformed we will map unknown values to this variant
4005    Unknown,
4006}
4007
4008impl DeltaFormat {
4009    /// Create from a raw scalar.
4010    ///
4011    /// This will never fail; unknown values will be mapped to the `Unknown` variant
4012    pub fn new(raw: u16) -> Self {
4013        match raw {
4014            0x0001 => Self::Local2BitDeltas,
4015            0x0002 => Self::Local4BitDeltas,
4016            0x0003 => Self::Local8BitDeltas,
4017            0x8000 => Self::VariationIndex,
4018            _ => Self::Unknown,
4019        }
4020    }
4021}
4022
4023impl font_types::Scalar for DeltaFormat {
4024    type Raw = <u16 as font_types::Scalar>::Raw;
4025    fn to_raw(self) -> Self::Raw {
4026        (self as u16).to_raw()
4027    }
4028    fn from_raw(raw: Self::Raw) -> Self {
4029        let t = <u16>::from_raw(raw);
4030        Self::new(t)
4031    }
4032}
4033
4034#[cfg(feature = "experimental_traverse")]
4035impl<'a> From<DeltaFormat> for FieldType<'a> {
4036    fn from(src: DeltaFormat) -> FieldType<'a> {
4037        (src as u16).into()
4038    }
4039}
4040
4041/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
4042#[derive(Debug, Clone, Copy)]
4043#[doc(hidden)]
4044pub struct DeviceMarker {
4045    delta_value_byte_len: usize,
4046}
4047
4048impl DeviceMarker {
4049    pub fn start_size_byte_range(&self) -> Range<usize> {
4050        let start = 0;
4051        start..start + u16::RAW_BYTE_LEN
4052    }
4053
4054    pub fn end_size_byte_range(&self) -> Range<usize> {
4055        let start = self.start_size_byte_range().end;
4056        start..start + u16::RAW_BYTE_LEN
4057    }
4058
4059    pub fn delta_format_byte_range(&self) -> Range<usize> {
4060        let start = self.end_size_byte_range().end;
4061        start..start + DeltaFormat::RAW_BYTE_LEN
4062    }
4063
4064    pub fn delta_value_byte_range(&self) -> Range<usize> {
4065        let start = self.delta_format_byte_range().end;
4066        start..start + self.delta_value_byte_len
4067    }
4068}
4069
4070impl MinByteRange for DeviceMarker {
4071    fn min_byte_range(&self) -> Range<usize> {
4072        0..self.delta_value_byte_range().end
4073    }
4074}
4075
4076impl<'a> FontRead<'a> for Device<'a> {
4077    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4078        let mut cursor = data.cursor();
4079        let start_size: u16 = cursor.read()?;
4080        let end_size: u16 = cursor.read()?;
4081        let delta_format: DeltaFormat = cursor.read()?;
4082        let delta_value_byte_len = (DeltaFormat::value_count(delta_format, start_size, end_size))
4083            .checked_mul(u16::RAW_BYTE_LEN)
4084            .ok_or(ReadError::OutOfBounds)?;
4085        cursor.advance_by(delta_value_byte_len);
4086        cursor.finish(DeviceMarker {
4087            delta_value_byte_len,
4088        })
4089    }
4090}
4091
4092/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
4093pub type Device<'a> = TableRef<'a, DeviceMarker>;
4094
4095#[allow(clippy::needless_lifetimes)]
4096impl<'a> Device<'a> {
4097    /// Smallest size to correct, in ppem
4098    pub fn start_size(&self) -> u16 {
4099        let range = self.shape.start_size_byte_range();
4100        self.data.read_at(range.start).unwrap()
4101    }
4102
4103    /// Largest size to correct, in ppem
4104    pub fn end_size(&self) -> u16 {
4105        let range = self.shape.end_size_byte_range();
4106        self.data.read_at(range.start).unwrap()
4107    }
4108
4109    /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
4110    pub fn delta_format(&self) -> DeltaFormat {
4111        let range = self.shape.delta_format_byte_range();
4112        self.data.read_at(range.start).unwrap()
4113    }
4114
4115    /// Array of compressed data
4116    pub fn delta_value(&self) -> &'a [BigEndian<u16>] {
4117        let range = self.shape.delta_value_byte_range();
4118        self.data.read_array(range).unwrap()
4119    }
4120}
4121
4122#[cfg(feature = "experimental_traverse")]
4123impl<'a> SomeTable<'a> for Device<'a> {
4124    fn type_name(&self) -> &str {
4125        "Device"
4126    }
4127    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4128        match idx {
4129            0usize => Some(Field::new("start_size", self.start_size())),
4130            1usize => Some(Field::new("end_size", self.end_size())),
4131            2usize => Some(Field::new("delta_format", self.delta_format())),
4132            3usize => Some(Field::new("delta_value", self.delta_value())),
4133            _ => None,
4134        }
4135    }
4136}
4137
4138#[cfg(feature = "experimental_traverse")]
4139#[allow(clippy::needless_lifetimes)]
4140impl<'a> std::fmt::Debug for Device<'a> {
4141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4142        (self as &dyn SomeTable<'a>).fmt(f)
4143    }
4144}
4145
4146/// Variation index table
4147#[derive(Debug, Clone, Copy)]
4148#[doc(hidden)]
4149pub struct VariationIndexMarker {}
4150
4151impl VariationIndexMarker {
4152    pub fn delta_set_outer_index_byte_range(&self) -> Range<usize> {
4153        let start = 0;
4154        start..start + u16::RAW_BYTE_LEN
4155    }
4156
4157    pub fn delta_set_inner_index_byte_range(&self) -> Range<usize> {
4158        let start = self.delta_set_outer_index_byte_range().end;
4159        start..start + u16::RAW_BYTE_LEN
4160    }
4161
4162    pub fn delta_format_byte_range(&self) -> Range<usize> {
4163        let start = self.delta_set_inner_index_byte_range().end;
4164        start..start + DeltaFormat::RAW_BYTE_LEN
4165    }
4166}
4167
4168impl MinByteRange for VariationIndexMarker {
4169    fn min_byte_range(&self) -> Range<usize> {
4170        0..self.delta_format_byte_range().end
4171    }
4172}
4173
4174impl<'a> FontRead<'a> for VariationIndex<'a> {
4175    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4176        let mut cursor = data.cursor();
4177        cursor.advance::<u16>();
4178        cursor.advance::<u16>();
4179        cursor.advance::<DeltaFormat>();
4180        cursor.finish(VariationIndexMarker {})
4181    }
4182}
4183
4184/// Variation index table
4185pub type VariationIndex<'a> = TableRef<'a, VariationIndexMarker>;
4186
4187#[allow(clippy::needless_lifetimes)]
4188impl<'a> VariationIndex<'a> {
4189    /// A delta-set outer index — used to select an item variation
4190    /// data subtable within the item variation store.
4191    pub fn delta_set_outer_index(&self) -> u16 {
4192        let range = self.shape.delta_set_outer_index_byte_range();
4193        self.data.read_at(range.start).unwrap()
4194    }
4195
4196    /// A delta-set inner index — used to select a delta-set row
4197    /// within an item variation data subtable.
4198    pub fn delta_set_inner_index(&self) -> u16 {
4199        let range = self.shape.delta_set_inner_index_byte_range();
4200        self.data.read_at(range.start).unwrap()
4201    }
4202
4203    /// Format, = 0x8000
4204    pub fn delta_format(&self) -> DeltaFormat {
4205        let range = self.shape.delta_format_byte_range();
4206        self.data.read_at(range.start).unwrap()
4207    }
4208}
4209
4210#[cfg(feature = "experimental_traverse")]
4211impl<'a> SomeTable<'a> for VariationIndex<'a> {
4212    fn type_name(&self) -> &str {
4213        "VariationIndex"
4214    }
4215    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4216        match idx {
4217            0usize => Some(Field::new(
4218                "delta_set_outer_index",
4219                self.delta_set_outer_index(),
4220            )),
4221            1usize => Some(Field::new(
4222                "delta_set_inner_index",
4223                self.delta_set_inner_index(),
4224            )),
4225            2usize => Some(Field::new("delta_format", self.delta_format())),
4226            _ => None,
4227        }
4228    }
4229}
4230
4231#[cfg(feature = "experimental_traverse")]
4232#[allow(clippy::needless_lifetimes)]
4233impl<'a> std::fmt::Debug for VariationIndex<'a> {
4234    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4235        (self as &dyn SomeTable<'a>).fmt(f)
4236    }
4237}
4238
4239/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
4240#[derive(Clone)]
4241pub enum DeviceOrVariationIndex<'a> {
4242    Device(Device<'a>),
4243    VariationIndex(VariationIndex<'a>),
4244}
4245
4246impl<'a> DeviceOrVariationIndex<'a> {
4247    ///Return the `FontData` used to resolve offsets for this table.
4248    pub fn offset_data(&self) -> FontData<'a> {
4249        match self {
4250            Self::Device(item) => item.offset_data(),
4251            Self::VariationIndex(item) => item.offset_data(),
4252        }
4253    }
4254}
4255
4256impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> {
4257    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4258        let format: DeltaFormat = data.read_at(4usize)?;
4259
4260        #[allow(clippy::redundant_guards)]
4261        match format {
4262            format if format != DeltaFormat::VariationIndex => {
4263                Ok(Self::Device(FontRead::read(data)?))
4264            }
4265            format if format == DeltaFormat::VariationIndex => {
4266                Ok(Self::VariationIndex(FontRead::read(data)?))
4267            }
4268            other => Err(ReadError::InvalidFormat(other.into())),
4269        }
4270    }
4271}
4272
4273impl MinByteRange for DeviceOrVariationIndex<'_> {
4274    fn min_byte_range(&self) -> Range<usize> {
4275        match self {
4276            Self::Device(item) => item.min_byte_range(),
4277            Self::VariationIndex(item) => item.min_byte_range(),
4278        }
4279    }
4280}
4281
4282#[cfg(feature = "experimental_traverse")]
4283impl<'a> DeviceOrVariationIndex<'a> {
4284    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
4285        match self {
4286            Self::Device(table) => table,
4287            Self::VariationIndex(table) => table,
4288        }
4289    }
4290}
4291
4292#[cfg(feature = "experimental_traverse")]
4293impl std::fmt::Debug for DeviceOrVariationIndex<'_> {
4294    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4295        self.dyn_inner().fmt(f)
4296    }
4297}
4298
4299#[cfg(feature = "experimental_traverse")]
4300impl<'a> SomeTable<'a> for DeviceOrVariationIndex<'a> {
4301    fn type_name(&self) -> &str {
4302        self.dyn_inner().type_name()
4303    }
4304    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4305        self.dyn_inner().get_field(idx)
4306    }
4307}
4308
4309/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
4310#[derive(Debug, Clone, Copy)]
4311#[doc(hidden)]
4312pub struct FeatureVariationsMarker {
4313    feature_variation_records_byte_len: usize,
4314}
4315
4316impl FeatureVariationsMarker {
4317    pub fn version_byte_range(&self) -> Range<usize> {
4318        let start = 0;
4319        start..start + MajorMinor::RAW_BYTE_LEN
4320    }
4321
4322    pub fn feature_variation_record_count_byte_range(&self) -> Range<usize> {
4323        let start = self.version_byte_range().end;
4324        start..start + u32::RAW_BYTE_LEN
4325    }
4326
4327    pub fn feature_variation_records_byte_range(&self) -> Range<usize> {
4328        let start = self.feature_variation_record_count_byte_range().end;
4329        start..start + self.feature_variation_records_byte_len
4330    }
4331}
4332
4333impl MinByteRange for FeatureVariationsMarker {
4334    fn min_byte_range(&self) -> Range<usize> {
4335        0..self.feature_variation_records_byte_range().end
4336    }
4337}
4338
4339impl<'a> FontRead<'a> for FeatureVariations<'a> {
4340    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4341        let mut cursor = data.cursor();
4342        cursor.advance::<MajorMinor>();
4343        let feature_variation_record_count: u32 = cursor.read()?;
4344        let feature_variation_records_byte_len = (feature_variation_record_count as usize)
4345            .checked_mul(FeatureVariationRecord::RAW_BYTE_LEN)
4346            .ok_or(ReadError::OutOfBounds)?;
4347        cursor.advance_by(feature_variation_records_byte_len);
4348        cursor.finish(FeatureVariationsMarker {
4349            feature_variation_records_byte_len,
4350        })
4351    }
4352}
4353
4354/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
4355pub type FeatureVariations<'a> = TableRef<'a, FeatureVariationsMarker>;
4356
4357#[allow(clippy::needless_lifetimes)]
4358impl<'a> FeatureVariations<'a> {
4359    pub fn version(&self) -> MajorMinor {
4360        let range = self.shape.version_byte_range();
4361        self.data.read_at(range.start).unwrap()
4362    }
4363
4364    /// Number of feature variation records.
4365    pub fn feature_variation_record_count(&self) -> u32 {
4366        let range = self.shape.feature_variation_record_count_byte_range();
4367        self.data.read_at(range.start).unwrap()
4368    }
4369
4370    /// Array of feature variation records.
4371    pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] {
4372        let range = self.shape.feature_variation_records_byte_range();
4373        self.data.read_array(range).unwrap()
4374    }
4375}
4376
4377#[cfg(feature = "experimental_traverse")]
4378impl<'a> SomeTable<'a> for FeatureVariations<'a> {
4379    fn type_name(&self) -> &str {
4380        "FeatureVariations"
4381    }
4382    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4383        match idx {
4384            0usize => Some(Field::new("version", self.version())),
4385            1usize => Some(Field::new(
4386                "feature_variation_record_count",
4387                self.feature_variation_record_count(),
4388            )),
4389            2usize => Some(Field::new(
4390                "feature_variation_records",
4391                traversal::FieldType::array_of_records(
4392                    stringify!(FeatureVariationRecord),
4393                    self.feature_variation_records(),
4394                    self.offset_data(),
4395                ),
4396            )),
4397            _ => None,
4398        }
4399    }
4400}
4401
4402#[cfg(feature = "experimental_traverse")]
4403#[allow(clippy::needless_lifetimes)]
4404impl<'a> std::fmt::Debug for FeatureVariations<'a> {
4405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4406        (self as &dyn SomeTable<'a>).fmt(f)
4407    }
4408}
4409
4410/// Part of [FeatureVariations]
4411#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4412#[repr(C)]
4413#[repr(packed)]
4414pub struct FeatureVariationRecord {
4415    /// Offset to a condition set table, from beginning of
4416    /// FeatureVariations table.
4417    pub condition_set_offset: BigEndian<Nullable<Offset32>>,
4418    /// Offset to a feature table substitution table, from beginning of
4419    /// the FeatureVariations table.
4420    pub feature_table_substitution_offset: BigEndian<Nullable<Offset32>>,
4421}
4422
4423impl FeatureVariationRecord {
4424    /// Offset to a condition set table, from beginning of
4425    /// FeatureVariations table.
4426    pub fn condition_set_offset(&self) -> Nullable<Offset32> {
4427        self.condition_set_offset.get()
4428    }
4429
4430    /// Offset to a condition set table, from beginning of
4431    /// FeatureVariations table.
4432    ///
4433    /// The `data` argument should be retrieved from the parent table
4434    /// By calling its `offset_data` method.
4435    pub fn condition_set<'a>(
4436        &self,
4437        data: FontData<'a>,
4438    ) -> Option<Result<ConditionSet<'a>, ReadError>> {
4439        self.condition_set_offset().resolve(data)
4440    }
4441
4442    /// Offset to a feature table substitution table, from beginning of
4443    /// the FeatureVariations table.
4444    pub fn feature_table_substitution_offset(&self) -> Nullable<Offset32> {
4445        self.feature_table_substitution_offset.get()
4446    }
4447
4448    /// Offset to a feature table substitution table, from beginning of
4449    /// the FeatureVariations table.
4450    ///
4451    /// The `data` argument should be retrieved from the parent table
4452    /// By calling its `offset_data` method.
4453    pub fn feature_table_substitution<'a>(
4454        &self,
4455        data: FontData<'a>,
4456    ) -> Option<Result<FeatureTableSubstitution<'a>, ReadError>> {
4457        self.feature_table_substitution_offset().resolve(data)
4458    }
4459}
4460
4461impl FixedSize for FeatureVariationRecord {
4462    const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
4463}
4464
4465#[cfg(feature = "experimental_traverse")]
4466impl<'a> SomeRecord<'a> for FeatureVariationRecord {
4467    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
4468        RecordResolver {
4469            name: "FeatureVariationRecord",
4470            get_field: Box::new(move |idx, _data| match idx {
4471                0usize => Some(Field::new(
4472                    "condition_set_offset",
4473                    FieldType::offset(self.condition_set_offset(), self.condition_set(_data)),
4474                )),
4475                1usize => Some(Field::new(
4476                    "feature_table_substitution_offset",
4477                    FieldType::offset(
4478                        self.feature_table_substitution_offset(),
4479                        self.feature_table_substitution(_data),
4480                    ),
4481                )),
4482                _ => None,
4483            }),
4484            data,
4485        }
4486    }
4487}
4488
4489/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
4490#[derive(Debug, Clone, Copy)]
4491#[doc(hidden)]
4492pub struct ConditionSetMarker {
4493    condition_offsets_byte_len: usize,
4494}
4495
4496impl ConditionSetMarker {
4497    pub fn condition_count_byte_range(&self) -> Range<usize> {
4498        let start = 0;
4499        start..start + u16::RAW_BYTE_LEN
4500    }
4501
4502    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4503        let start = self.condition_count_byte_range().end;
4504        start..start + self.condition_offsets_byte_len
4505    }
4506}
4507
4508impl MinByteRange for ConditionSetMarker {
4509    fn min_byte_range(&self) -> Range<usize> {
4510        0..self.condition_offsets_byte_range().end
4511    }
4512}
4513
4514impl<'a> FontRead<'a> for ConditionSet<'a> {
4515    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4516        let mut cursor = data.cursor();
4517        let condition_count: u16 = cursor.read()?;
4518        let condition_offsets_byte_len = (condition_count as usize)
4519            .checked_mul(Offset32::RAW_BYTE_LEN)
4520            .ok_or(ReadError::OutOfBounds)?;
4521        cursor.advance_by(condition_offsets_byte_len);
4522        cursor.finish(ConditionSetMarker {
4523            condition_offsets_byte_len,
4524        })
4525    }
4526}
4527
4528/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
4529pub type ConditionSet<'a> = TableRef<'a, ConditionSetMarker>;
4530
4531#[allow(clippy::needless_lifetimes)]
4532impl<'a> ConditionSet<'a> {
4533    /// Number of conditions for this condition set.
4534    pub fn condition_count(&self) -> u16 {
4535        let range = self.shape.condition_count_byte_range();
4536        self.data.read_at(range.start).unwrap()
4537    }
4538
4539    /// Array of offsets to condition tables, from beginning of the
4540    /// ConditionSet table.
4541    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset32>] {
4542        let range = self.shape.condition_offsets_byte_range();
4543        self.data.read_array(range).unwrap()
4544    }
4545
4546    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
4547    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> {
4548        let data = self.data;
4549        let offsets = self.condition_offsets();
4550        ArrayOfOffsets::new(offsets, data, ())
4551    }
4552}
4553
4554#[cfg(feature = "experimental_traverse")]
4555impl<'a> SomeTable<'a> for ConditionSet<'a> {
4556    fn type_name(&self) -> &str {
4557        "ConditionSet"
4558    }
4559    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4560        match idx {
4561            0usize => Some(Field::new("condition_count", self.condition_count())),
4562            1usize => Some({
4563                let data = self.data;
4564                Field::new(
4565                    "condition_offsets",
4566                    FieldType::array_of_offsets(
4567                        better_type_name::<Condition>(),
4568                        self.condition_offsets(),
4569                        move |off| {
4570                            let target = off.get().resolve::<Condition>(data);
4571                            FieldType::offset(off.get(), target)
4572                        },
4573                    ),
4574                )
4575            }),
4576            _ => None,
4577        }
4578    }
4579}
4580
4581#[cfg(feature = "experimental_traverse")]
4582#[allow(clippy::needless_lifetimes)]
4583impl<'a> std::fmt::Debug for ConditionSet<'a> {
4584    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4585        (self as &dyn SomeTable<'a>).fmt(f)
4586    }
4587}
4588
4589/// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table)
4590///
4591/// Formats 2..5 are implementations of specification changes currently under debate at ISO for an OFF
4592/// update. For the time being the specification is <https://github.com/harfbuzz/boring-expansion-spec/blob/main/ConditionTree.md>.
4593#[derive(Clone)]
4594pub enum Condition<'a> {
4595    Format1AxisRange(ConditionFormat1<'a>),
4596    Format2VariableValue(ConditionFormat2<'a>),
4597    Format3And(ConditionFormat3<'a>),
4598    Format4Or(ConditionFormat4<'a>),
4599    Format5Negate(ConditionFormat5<'a>),
4600}
4601
4602impl<'a> Condition<'a> {
4603    ///Return the `FontData` used to resolve offsets for this table.
4604    pub fn offset_data(&self) -> FontData<'a> {
4605        match self {
4606            Self::Format1AxisRange(item) => item.offset_data(),
4607            Self::Format2VariableValue(item) => item.offset_data(),
4608            Self::Format3And(item) => item.offset_data(),
4609            Self::Format4Or(item) => item.offset_data(),
4610            Self::Format5Negate(item) => item.offset_data(),
4611        }
4612    }
4613
4614    /// Format, = 1
4615    pub fn format(&self) -> u16 {
4616        match self {
4617            Self::Format1AxisRange(item) => item.format(),
4618            Self::Format2VariableValue(item) => item.format(),
4619            Self::Format3And(item) => item.format(),
4620            Self::Format4Or(item) => item.format(),
4621            Self::Format5Negate(item) => item.format(),
4622        }
4623    }
4624}
4625
4626impl<'a> FontRead<'a> for Condition<'a> {
4627    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4628        let format: u16 = data.read_at(0usize)?;
4629        match format {
4630            ConditionFormat1Marker::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)),
4631            ConditionFormat2Marker::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)),
4632            ConditionFormat3Marker::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)),
4633            ConditionFormat4Marker::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)),
4634            ConditionFormat5Marker::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)),
4635            other => Err(ReadError::InvalidFormat(other.into())),
4636        }
4637    }
4638}
4639
4640impl MinByteRange for Condition<'_> {
4641    fn min_byte_range(&self) -> Range<usize> {
4642        match self {
4643            Self::Format1AxisRange(item) => item.min_byte_range(),
4644            Self::Format2VariableValue(item) => item.min_byte_range(),
4645            Self::Format3And(item) => item.min_byte_range(),
4646            Self::Format4Or(item) => item.min_byte_range(),
4647            Self::Format5Negate(item) => item.min_byte_range(),
4648        }
4649    }
4650}
4651
4652#[cfg(feature = "experimental_traverse")]
4653impl<'a> Condition<'a> {
4654    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
4655        match self {
4656            Self::Format1AxisRange(table) => table,
4657            Self::Format2VariableValue(table) => table,
4658            Self::Format3And(table) => table,
4659            Self::Format4Or(table) => table,
4660            Self::Format5Negate(table) => table,
4661        }
4662    }
4663}
4664
4665#[cfg(feature = "experimental_traverse")]
4666impl std::fmt::Debug for Condition<'_> {
4667    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4668        self.dyn_inner().fmt(f)
4669    }
4670}
4671
4672#[cfg(feature = "experimental_traverse")]
4673impl<'a> SomeTable<'a> for Condition<'a> {
4674    fn type_name(&self) -> &str {
4675        self.dyn_inner().type_name()
4676    }
4677    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4678        self.dyn_inner().get_field(idx)
4679    }
4680}
4681
4682impl Format<u16> for ConditionFormat1Marker {
4683    const FORMAT: u16 = 1;
4684}
4685
4686/// [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
4687#[derive(Debug, Clone, Copy)]
4688#[doc(hidden)]
4689pub struct ConditionFormat1Marker {}
4690
4691impl ConditionFormat1Marker {
4692    pub fn format_byte_range(&self) -> Range<usize> {
4693        let start = 0;
4694        start..start + u16::RAW_BYTE_LEN
4695    }
4696
4697    pub fn axis_index_byte_range(&self) -> Range<usize> {
4698        let start = self.format_byte_range().end;
4699        start..start + u16::RAW_BYTE_LEN
4700    }
4701
4702    pub fn filter_range_min_value_byte_range(&self) -> Range<usize> {
4703        let start = self.axis_index_byte_range().end;
4704        start..start + F2Dot14::RAW_BYTE_LEN
4705    }
4706
4707    pub fn filter_range_max_value_byte_range(&self) -> Range<usize> {
4708        let start = self.filter_range_min_value_byte_range().end;
4709        start..start + F2Dot14::RAW_BYTE_LEN
4710    }
4711}
4712
4713impl MinByteRange for ConditionFormat1Marker {
4714    fn min_byte_range(&self) -> Range<usize> {
4715        0..self.filter_range_max_value_byte_range().end
4716    }
4717}
4718
4719impl<'a> FontRead<'a> for ConditionFormat1<'a> {
4720    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4721        let mut cursor = data.cursor();
4722        cursor.advance::<u16>();
4723        cursor.advance::<u16>();
4724        cursor.advance::<F2Dot14>();
4725        cursor.advance::<F2Dot14>();
4726        cursor.finish(ConditionFormat1Marker {})
4727    }
4728}
4729
4730/// [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
4731pub type ConditionFormat1<'a> = TableRef<'a, ConditionFormat1Marker>;
4732
4733#[allow(clippy::needless_lifetimes)]
4734impl<'a> ConditionFormat1<'a> {
4735    /// Format, = 1
4736    pub fn format(&self) -> u16 {
4737        let range = self.shape.format_byte_range();
4738        self.data.read_at(range.start).unwrap()
4739    }
4740
4741    /// Index (zero-based) for the variation axis within the 'fvar'
4742    /// table.
4743    pub fn axis_index(&self) -> u16 {
4744        let range = self.shape.axis_index_byte_range();
4745        self.data.read_at(range.start).unwrap()
4746    }
4747
4748    /// Minimum value of the font variation instances that satisfy this
4749    /// condition.
4750    pub fn filter_range_min_value(&self) -> F2Dot14 {
4751        let range = self.shape.filter_range_min_value_byte_range();
4752        self.data.read_at(range.start).unwrap()
4753    }
4754
4755    /// Maximum value of the font variation instances that satisfy this
4756    /// condition.
4757    pub fn filter_range_max_value(&self) -> F2Dot14 {
4758        let range = self.shape.filter_range_max_value_byte_range();
4759        self.data.read_at(range.start).unwrap()
4760    }
4761}
4762
4763#[cfg(feature = "experimental_traverse")]
4764impl<'a> SomeTable<'a> for ConditionFormat1<'a> {
4765    fn type_name(&self) -> &str {
4766        "ConditionFormat1"
4767    }
4768    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4769        match idx {
4770            0usize => Some(Field::new("format", self.format())),
4771            1usize => Some(Field::new("axis_index", self.axis_index())),
4772            2usize => Some(Field::new(
4773                "filter_range_min_value",
4774                self.filter_range_min_value(),
4775            )),
4776            3usize => Some(Field::new(
4777                "filter_range_max_value",
4778                self.filter_range_max_value(),
4779            )),
4780            _ => None,
4781        }
4782    }
4783}
4784
4785#[cfg(feature = "experimental_traverse")]
4786#[allow(clippy::needless_lifetimes)]
4787impl<'a> std::fmt::Debug for ConditionFormat1<'a> {
4788    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4789        (self as &dyn SomeTable<'a>).fmt(f)
4790    }
4791}
4792
4793impl Format<u16> for ConditionFormat2Marker {
4794    const FORMAT: u16 = 2;
4795}
4796
4797/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
4798#[derive(Debug, Clone, Copy)]
4799#[doc(hidden)]
4800pub struct ConditionFormat2Marker {}
4801
4802impl ConditionFormat2Marker {
4803    pub fn format_byte_range(&self) -> Range<usize> {
4804        let start = 0;
4805        start..start + u16::RAW_BYTE_LEN
4806    }
4807
4808    pub fn default_value_byte_range(&self) -> Range<usize> {
4809        let start = self.format_byte_range().end;
4810        start..start + i16::RAW_BYTE_LEN
4811    }
4812
4813    pub fn var_index_byte_range(&self) -> Range<usize> {
4814        let start = self.default_value_byte_range().end;
4815        start..start + u32::RAW_BYTE_LEN
4816    }
4817}
4818
4819impl MinByteRange for ConditionFormat2Marker {
4820    fn min_byte_range(&self) -> Range<usize> {
4821        0..self.var_index_byte_range().end
4822    }
4823}
4824
4825impl<'a> FontRead<'a> for ConditionFormat2<'a> {
4826    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4827        let mut cursor = data.cursor();
4828        cursor.advance::<u16>();
4829        cursor.advance::<i16>();
4830        cursor.advance::<u32>();
4831        cursor.finish(ConditionFormat2Marker {})
4832    }
4833}
4834
4835/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
4836pub type ConditionFormat2<'a> = TableRef<'a, ConditionFormat2Marker>;
4837
4838#[allow(clippy::needless_lifetimes)]
4839impl<'a> ConditionFormat2<'a> {
4840    /// Format, = 2
4841    pub fn format(&self) -> u16 {
4842        let range = self.shape.format_byte_range();
4843        self.data.read_at(range.start).unwrap()
4844    }
4845
4846    /// Value at default instance.
4847    pub fn default_value(&self) -> i16 {
4848        let range = self.shape.default_value_byte_range();
4849        self.data.read_at(range.start).unwrap()
4850    }
4851
4852    /// Variation index to vary the value based on current designspace location.
4853    pub fn var_index(&self) -> u32 {
4854        let range = self.shape.var_index_byte_range();
4855        self.data.read_at(range.start).unwrap()
4856    }
4857}
4858
4859#[cfg(feature = "experimental_traverse")]
4860impl<'a> SomeTable<'a> for ConditionFormat2<'a> {
4861    fn type_name(&self) -> &str {
4862        "ConditionFormat2"
4863    }
4864    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4865        match idx {
4866            0usize => Some(Field::new("format", self.format())),
4867            1usize => Some(Field::new("default_value", self.default_value())),
4868            2usize => Some(Field::new("var_index", self.var_index())),
4869            _ => None,
4870        }
4871    }
4872}
4873
4874#[cfg(feature = "experimental_traverse")]
4875#[allow(clippy::needless_lifetimes)]
4876impl<'a> std::fmt::Debug for ConditionFormat2<'a> {
4877    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4878        (self as &dyn SomeTable<'a>).fmt(f)
4879    }
4880}
4881
4882impl Format<u16> for ConditionFormat3Marker {
4883    const FORMAT: u16 = 3;
4884}
4885
4886/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
4887#[derive(Debug, Clone, Copy)]
4888#[doc(hidden)]
4889pub struct ConditionFormat3Marker {
4890    condition_offsets_byte_len: usize,
4891}
4892
4893impl ConditionFormat3Marker {
4894    pub fn format_byte_range(&self) -> Range<usize> {
4895        let start = 0;
4896        start..start + u16::RAW_BYTE_LEN
4897    }
4898
4899    pub fn condition_count_byte_range(&self) -> Range<usize> {
4900        let start = self.format_byte_range().end;
4901        start..start + u8::RAW_BYTE_LEN
4902    }
4903
4904    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4905        let start = self.condition_count_byte_range().end;
4906        start..start + self.condition_offsets_byte_len
4907    }
4908}
4909
4910impl MinByteRange for ConditionFormat3Marker {
4911    fn min_byte_range(&self) -> Range<usize> {
4912        0..self.condition_offsets_byte_range().end
4913    }
4914}
4915
4916impl<'a> FontRead<'a> for ConditionFormat3<'a> {
4917    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4918        let mut cursor = data.cursor();
4919        cursor.advance::<u16>();
4920        let condition_count: u8 = cursor.read()?;
4921        let condition_offsets_byte_len = (condition_count as usize)
4922            .checked_mul(Offset24::RAW_BYTE_LEN)
4923            .ok_or(ReadError::OutOfBounds)?;
4924        cursor.advance_by(condition_offsets_byte_len);
4925        cursor.finish(ConditionFormat3Marker {
4926            condition_offsets_byte_len,
4927        })
4928    }
4929}
4930
4931/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
4932pub type ConditionFormat3<'a> = TableRef<'a, ConditionFormat3Marker>;
4933
4934#[allow(clippy::needless_lifetimes)]
4935impl<'a> ConditionFormat3<'a> {
4936    /// Format, = 3
4937    pub fn format(&self) -> u16 {
4938        let range = self.shape.format_byte_range();
4939        self.data.read_at(range.start).unwrap()
4940    }
4941
4942    /// Number of conditions.
4943    pub fn condition_count(&self) -> u8 {
4944        let range = self.shape.condition_count_byte_range();
4945        self.data.read_at(range.start).unwrap()
4946    }
4947
4948    /// Array of condition tables for this conjunction (AND) expression.
4949    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
4950        let range = self.shape.condition_offsets_byte_range();
4951        self.data.read_array(range).unwrap()
4952    }
4953
4954    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
4955    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
4956        let data = self.data;
4957        let offsets = self.condition_offsets();
4958        ArrayOfOffsets::new(offsets, data, ())
4959    }
4960}
4961
4962#[cfg(feature = "experimental_traverse")]
4963impl<'a> SomeTable<'a> for ConditionFormat3<'a> {
4964    fn type_name(&self) -> &str {
4965        "ConditionFormat3"
4966    }
4967    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4968        match idx {
4969            0usize => Some(Field::new("format", self.format())),
4970            1usize => Some(Field::new("condition_count", self.condition_count())),
4971            2usize => Some({
4972                let data = self.data;
4973                Field::new(
4974                    "condition_offsets",
4975                    FieldType::array_of_offsets(
4976                        better_type_name::<Condition>(),
4977                        self.condition_offsets(),
4978                        move |off| {
4979                            let target = off.get().resolve::<Condition>(data);
4980                            FieldType::offset(off.get(), target)
4981                        },
4982                    ),
4983                )
4984            }),
4985            _ => None,
4986        }
4987    }
4988}
4989
4990#[cfg(feature = "experimental_traverse")]
4991#[allow(clippy::needless_lifetimes)]
4992impl<'a> std::fmt::Debug for ConditionFormat3<'a> {
4993    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4994        (self as &dyn SomeTable<'a>).fmt(f)
4995    }
4996}
4997
4998impl Format<u16> for ConditionFormat4Marker {
4999    const FORMAT: u16 = 4;
5000}
5001
5002/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
5003#[derive(Debug, Clone, Copy)]
5004#[doc(hidden)]
5005pub struct ConditionFormat4Marker {
5006    condition_offsets_byte_len: usize,
5007}
5008
5009impl ConditionFormat4Marker {
5010    pub fn format_byte_range(&self) -> Range<usize> {
5011        let start = 0;
5012        start..start + u16::RAW_BYTE_LEN
5013    }
5014
5015    pub fn condition_count_byte_range(&self) -> Range<usize> {
5016        let start = self.format_byte_range().end;
5017        start..start + u8::RAW_BYTE_LEN
5018    }
5019
5020    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
5021        let start = self.condition_count_byte_range().end;
5022        start..start + self.condition_offsets_byte_len
5023    }
5024}
5025
5026impl MinByteRange for ConditionFormat4Marker {
5027    fn min_byte_range(&self) -> Range<usize> {
5028        0..self.condition_offsets_byte_range().end
5029    }
5030}
5031
5032impl<'a> FontRead<'a> for ConditionFormat4<'a> {
5033    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5034        let mut cursor = data.cursor();
5035        cursor.advance::<u16>();
5036        let condition_count: u8 = cursor.read()?;
5037        let condition_offsets_byte_len = (condition_count as usize)
5038            .checked_mul(Offset24::RAW_BYTE_LEN)
5039            .ok_or(ReadError::OutOfBounds)?;
5040        cursor.advance_by(condition_offsets_byte_len);
5041        cursor.finish(ConditionFormat4Marker {
5042            condition_offsets_byte_len,
5043        })
5044    }
5045}
5046
5047/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
5048pub type ConditionFormat4<'a> = TableRef<'a, ConditionFormat4Marker>;
5049
5050#[allow(clippy::needless_lifetimes)]
5051impl<'a> ConditionFormat4<'a> {
5052    /// Format, = 4
5053    pub fn format(&self) -> u16 {
5054        let range = self.shape.format_byte_range();
5055        self.data.read_at(range.start).unwrap()
5056    }
5057
5058    /// Number of conditions.
5059    pub fn condition_count(&self) -> u8 {
5060        let range = self.shape.condition_count_byte_range();
5061        self.data.read_at(range.start).unwrap()
5062    }
5063
5064    /// Array of condition tables for this disjunction (OR) expression.
5065    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
5066        let range = self.shape.condition_offsets_byte_range();
5067        self.data.read_array(range).unwrap()
5068    }
5069
5070    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
5071    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
5072        let data = self.data;
5073        let offsets = self.condition_offsets();
5074        ArrayOfOffsets::new(offsets, data, ())
5075    }
5076}
5077
5078#[cfg(feature = "experimental_traverse")]
5079impl<'a> SomeTable<'a> for ConditionFormat4<'a> {
5080    fn type_name(&self) -> &str {
5081        "ConditionFormat4"
5082    }
5083    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5084        match idx {
5085            0usize => Some(Field::new("format", self.format())),
5086            1usize => Some(Field::new("condition_count", self.condition_count())),
5087            2usize => Some({
5088                let data = self.data;
5089                Field::new(
5090                    "condition_offsets",
5091                    FieldType::array_of_offsets(
5092                        better_type_name::<Condition>(),
5093                        self.condition_offsets(),
5094                        move |off| {
5095                            let target = off.get().resolve::<Condition>(data);
5096                            FieldType::offset(off.get(), target)
5097                        },
5098                    ),
5099                )
5100            }),
5101            _ => None,
5102        }
5103    }
5104}
5105
5106#[cfg(feature = "experimental_traverse")]
5107#[allow(clippy::needless_lifetimes)]
5108impl<'a> std::fmt::Debug for ConditionFormat4<'a> {
5109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5110        (self as &dyn SomeTable<'a>).fmt(f)
5111    }
5112}
5113
5114impl Format<u16> for ConditionFormat5Marker {
5115    const FORMAT: u16 = 5;
5116}
5117
5118/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
5119#[derive(Debug, Clone, Copy)]
5120#[doc(hidden)]
5121pub struct ConditionFormat5Marker {}
5122
5123impl ConditionFormat5Marker {
5124    pub fn format_byte_range(&self) -> Range<usize> {
5125        let start = 0;
5126        start..start + u16::RAW_BYTE_LEN
5127    }
5128
5129    pub fn condition_offset_byte_range(&self) -> Range<usize> {
5130        let start = self.format_byte_range().end;
5131        start..start + Offset24::RAW_BYTE_LEN
5132    }
5133}
5134
5135impl MinByteRange for ConditionFormat5Marker {
5136    fn min_byte_range(&self) -> Range<usize> {
5137        0..self.condition_offset_byte_range().end
5138    }
5139}
5140
5141impl<'a> FontRead<'a> for ConditionFormat5<'a> {
5142    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5143        let mut cursor = data.cursor();
5144        cursor.advance::<u16>();
5145        cursor.advance::<Offset24>();
5146        cursor.finish(ConditionFormat5Marker {})
5147    }
5148}
5149
5150/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
5151pub type ConditionFormat5<'a> = TableRef<'a, ConditionFormat5Marker>;
5152
5153#[allow(clippy::needless_lifetimes)]
5154impl<'a> ConditionFormat5<'a> {
5155    /// Format, = 5
5156    pub fn format(&self) -> u16 {
5157        let range = self.shape.format_byte_range();
5158        self.data.read_at(range.start).unwrap()
5159    }
5160
5161    /// Condition to negate.
5162    pub fn condition_offset(&self) -> Offset24 {
5163        let range = self.shape.condition_offset_byte_range();
5164        self.data.read_at(range.start).unwrap()
5165    }
5166
5167    /// Attempt to resolve [`condition_offset`][Self::condition_offset].
5168    pub fn condition(&self) -> Result<Condition<'a>, ReadError> {
5169        let data = self.data;
5170        self.condition_offset().resolve(data)
5171    }
5172}
5173
5174#[cfg(feature = "experimental_traverse")]
5175impl<'a> SomeTable<'a> for ConditionFormat5<'a> {
5176    fn type_name(&self) -> &str {
5177        "ConditionFormat5"
5178    }
5179    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5180        match idx {
5181            0usize => Some(Field::new("format", self.format())),
5182            1usize => Some(Field::new(
5183                "condition_offset",
5184                FieldType::offset(self.condition_offset(), self.condition()),
5185            )),
5186            _ => None,
5187        }
5188    }
5189}
5190
5191#[cfg(feature = "experimental_traverse")]
5192#[allow(clippy::needless_lifetimes)]
5193impl<'a> std::fmt::Debug for ConditionFormat5<'a> {
5194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5195        (self as &dyn SomeTable<'a>).fmt(f)
5196    }
5197}
5198
5199/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
5200#[derive(Debug, Clone, Copy)]
5201#[doc(hidden)]
5202pub struct FeatureTableSubstitutionMarker {
5203    substitutions_byte_len: usize,
5204}
5205
5206impl FeatureTableSubstitutionMarker {
5207    pub fn version_byte_range(&self) -> Range<usize> {
5208        let start = 0;
5209        start..start + MajorMinor::RAW_BYTE_LEN
5210    }
5211
5212    pub fn substitution_count_byte_range(&self) -> Range<usize> {
5213        let start = self.version_byte_range().end;
5214        start..start + u16::RAW_BYTE_LEN
5215    }
5216
5217    pub fn substitutions_byte_range(&self) -> Range<usize> {
5218        let start = self.substitution_count_byte_range().end;
5219        start..start + self.substitutions_byte_len
5220    }
5221}
5222
5223impl MinByteRange for FeatureTableSubstitutionMarker {
5224    fn min_byte_range(&self) -> Range<usize> {
5225        0..self.substitutions_byte_range().end
5226    }
5227}
5228
5229impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> {
5230    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5231        let mut cursor = data.cursor();
5232        cursor.advance::<MajorMinor>();
5233        let substitution_count: u16 = cursor.read()?;
5234        let substitutions_byte_len = (substitution_count as usize)
5235            .checked_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN)
5236            .ok_or(ReadError::OutOfBounds)?;
5237        cursor.advance_by(substitutions_byte_len);
5238        cursor.finish(FeatureTableSubstitutionMarker {
5239            substitutions_byte_len,
5240        })
5241    }
5242}
5243
5244/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
5245pub type FeatureTableSubstitution<'a> = TableRef<'a, FeatureTableSubstitutionMarker>;
5246
5247#[allow(clippy::needless_lifetimes)]
5248impl<'a> FeatureTableSubstitution<'a> {
5249    /// Major & minor version of the table: (1, 0)
5250    pub fn version(&self) -> MajorMinor {
5251        let range = self.shape.version_byte_range();
5252        self.data.read_at(range.start).unwrap()
5253    }
5254
5255    /// Number of feature table substitution records.
5256    pub fn substitution_count(&self) -> u16 {
5257        let range = self.shape.substitution_count_byte_range();
5258        self.data.read_at(range.start).unwrap()
5259    }
5260
5261    /// Array of feature table substitution records.
5262    pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] {
5263        let range = self.shape.substitutions_byte_range();
5264        self.data.read_array(range).unwrap()
5265    }
5266}
5267
5268#[cfg(feature = "experimental_traverse")]
5269impl<'a> SomeTable<'a> for FeatureTableSubstitution<'a> {
5270    fn type_name(&self) -> &str {
5271        "FeatureTableSubstitution"
5272    }
5273    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5274        match idx {
5275            0usize => Some(Field::new("version", self.version())),
5276            1usize => Some(Field::new("substitution_count", self.substitution_count())),
5277            2usize => Some(Field::new(
5278                "substitutions",
5279                traversal::FieldType::array_of_records(
5280                    stringify!(FeatureTableSubstitutionRecord),
5281                    self.substitutions(),
5282                    self.offset_data(),
5283                ),
5284            )),
5285            _ => None,
5286        }
5287    }
5288}
5289
5290#[cfg(feature = "experimental_traverse")]
5291#[allow(clippy::needless_lifetimes)]
5292impl<'a> std::fmt::Debug for FeatureTableSubstitution<'a> {
5293    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5294        (self as &dyn SomeTable<'a>).fmt(f)
5295    }
5296}
5297
5298/// Used in [FeatureTableSubstitution]
5299#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
5300#[repr(C)]
5301#[repr(packed)]
5302pub struct FeatureTableSubstitutionRecord {
5303    /// The feature table index to match.
5304    pub feature_index: BigEndian<u16>,
5305    /// Offset to an alternate feature table, from start of the
5306    /// FeatureTableSubstitution table.
5307    pub alternate_feature_offset: BigEndian<Offset32>,
5308}
5309
5310impl FeatureTableSubstitutionRecord {
5311    /// The feature table index to match.
5312    pub fn feature_index(&self) -> u16 {
5313        self.feature_index.get()
5314    }
5315
5316    /// Offset to an alternate feature table, from start of the
5317    /// FeatureTableSubstitution table.
5318    pub fn alternate_feature_offset(&self) -> Offset32 {
5319        self.alternate_feature_offset.get()
5320    }
5321}
5322
5323impl FixedSize for FeatureTableSubstitutionRecord {
5324    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
5325}
5326
5327#[cfg(feature = "experimental_traverse")]
5328impl<'a> SomeRecord<'a> for FeatureTableSubstitutionRecord {
5329    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
5330        RecordResolver {
5331            name: "FeatureTableSubstitutionRecord",
5332            get_field: Box::new(move |idx, _data| match idx {
5333                0usize => Some(Field::new("feature_index", self.feature_index())),
5334                1usize => Some(Field::new(
5335                    "alternate_feature_offset",
5336                    FieldType::offset(
5337                        self.alternate_feature_offset(),
5338                        self.alternate_feature(_data),
5339                    ),
5340                )),
5341                _ => None,
5342            }),
5343            data,
5344        }
5345    }
5346}
5347
5348#[derive(Debug, Clone, Copy)]
5349#[doc(hidden)]
5350pub struct SizeParamsMarker {}
5351
5352impl SizeParamsMarker {
5353    pub fn design_size_byte_range(&self) -> Range<usize> {
5354        let start = 0;
5355        start..start + u16::RAW_BYTE_LEN
5356    }
5357
5358    pub fn identifier_byte_range(&self) -> Range<usize> {
5359        let start = self.design_size_byte_range().end;
5360        start..start + u16::RAW_BYTE_LEN
5361    }
5362
5363    pub fn name_entry_byte_range(&self) -> Range<usize> {
5364        let start = self.identifier_byte_range().end;
5365        start..start + u16::RAW_BYTE_LEN
5366    }
5367
5368    pub fn range_start_byte_range(&self) -> Range<usize> {
5369        let start = self.name_entry_byte_range().end;
5370        start..start + u16::RAW_BYTE_LEN
5371    }
5372
5373    pub fn range_end_byte_range(&self) -> Range<usize> {
5374        let start = self.range_start_byte_range().end;
5375        start..start + u16::RAW_BYTE_LEN
5376    }
5377}
5378
5379impl MinByteRange for SizeParamsMarker {
5380    fn min_byte_range(&self) -> Range<usize> {
5381        0..self.range_end_byte_range().end
5382    }
5383}
5384
5385impl<'a> FontRead<'a> for SizeParams<'a> {
5386    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5387        let mut cursor = data.cursor();
5388        cursor.advance::<u16>();
5389        cursor.advance::<u16>();
5390        cursor.advance::<u16>();
5391        cursor.advance::<u16>();
5392        cursor.advance::<u16>();
5393        cursor.finish(SizeParamsMarker {})
5394    }
5395}
5396
5397pub type SizeParams<'a> = TableRef<'a, SizeParamsMarker>;
5398
5399#[allow(clippy::needless_lifetimes)]
5400impl<'a> SizeParams<'a> {
5401    /// The first value represents the design size in 720/inch units (decipoints).
5402    ///
5403    /// The design size entry must be non-zero. When there is a design size but
5404    /// no recommended size range, the rest of the array will consist of zeros.
5405    pub fn design_size(&self) -> u16 {
5406        let range = self.shape.design_size_byte_range();
5407        self.data.read_at(range.start).unwrap()
5408    }
5409
5410    /// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily.
5411    ///
5412    /// All fonts which share a Typographic or Font Family name and which differ
5413    /// only by size range shall have the same subfamily value, and no fonts
5414    /// which differ in weight or style shall have the same subfamily value.
5415    /// If this value is zero, the remaining fields in the array will be ignored.
5416    pub fn identifier(&self) -> u16 {
5417        let range = self.shape.identifier_byte_range();
5418        self.data.read_at(range.start).unwrap()
5419    }
5420
5421    /// The third value enables applications to use a single name for the subfamily identified by the second value.
5422    ///
5423    /// If the preceding value is non-zero, this value must be set in the range
5424    /// 256 – 32767 (inclusive). It records the value of a field in the 'name'
5425    /// table, which must contain English-language strings encoded in Windows
5426    /// Unicode and Macintosh Roman, and may contain additional strings localized
5427    /// to other scripts and languages. Each of these strings is the name
5428    /// an application should use, in combination with the family name, to
5429    /// represent the subfamily in a menu. Applications will choose the
5430    /// appropriate version based on their selection criteria.
5431    pub fn name_entry(&self) -> u16 {
5432        let range = self.shape.name_entry_byte_range();
5433        self.data.read_at(range.start).unwrap()
5434    }
5435
5436    /// The fourth and fifth values represent the small end of the recommended
5437    /// usage range (exclusive) and the large end of the recommended usage range
5438    /// (inclusive), stored in 720/inch units (decipoints).
5439    ///
5440    /// Ranges must not overlap, and should generally be contiguous.
5441    pub fn range_start(&self) -> u16 {
5442        let range = self.shape.range_start_byte_range();
5443        self.data.read_at(range.start).unwrap()
5444    }
5445
5446    pub fn range_end(&self) -> u16 {
5447        let range = self.shape.range_end_byte_range();
5448        self.data.read_at(range.start).unwrap()
5449    }
5450}
5451
5452#[cfg(feature = "experimental_traverse")]
5453impl<'a> SomeTable<'a> for SizeParams<'a> {
5454    fn type_name(&self) -> &str {
5455        "SizeParams"
5456    }
5457    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5458        match idx {
5459            0usize => Some(Field::new("design_size", self.design_size())),
5460            1usize => Some(Field::new("identifier", self.identifier())),
5461            2usize => Some(Field::new("name_entry", self.name_entry())),
5462            3usize => Some(Field::new("range_start", self.range_start())),
5463            4usize => Some(Field::new("range_end", self.range_end())),
5464            _ => None,
5465        }
5466    }
5467}
5468
5469#[cfg(feature = "experimental_traverse")]
5470#[allow(clippy::needless_lifetimes)]
5471impl<'a> std::fmt::Debug for SizeParams<'a> {
5472    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5473        (self as &dyn SomeTable<'a>).fmt(f)
5474    }
5475}
5476
5477#[derive(Debug, Clone, Copy)]
5478#[doc(hidden)]
5479pub struct StylisticSetParamsMarker {}
5480
5481impl StylisticSetParamsMarker {
5482    pub fn version_byte_range(&self) -> Range<usize> {
5483        let start = 0;
5484        start..start + u16::RAW_BYTE_LEN
5485    }
5486
5487    pub fn ui_name_id_byte_range(&self) -> Range<usize> {
5488        let start = self.version_byte_range().end;
5489        start..start + NameId::RAW_BYTE_LEN
5490    }
5491}
5492
5493impl MinByteRange for StylisticSetParamsMarker {
5494    fn min_byte_range(&self) -> Range<usize> {
5495        0..self.ui_name_id_byte_range().end
5496    }
5497}
5498
5499impl<'a> FontRead<'a> for StylisticSetParams<'a> {
5500    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5501        let mut cursor = data.cursor();
5502        cursor.advance::<u16>();
5503        cursor.advance::<NameId>();
5504        cursor.finish(StylisticSetParamsMarker {})
5505    }
5506}
5507
5508pub type StylisticSetParams<'a> = TableRef<'a, StylisticSetParamsMarker>;
5509
5510#[allow(clippy::needless_lifetimes)]
5511impl<'a> StylisticSetParams<'a> {
5512    pub fn version(&self) -> u16 {
5513        let range = self.shape.version_byte_range();
5514        self.data.read_at(range.start).unwrap()
5515    }
5516
5517    /// The 'name' table name ID that specifies a string (or strings, for
5518    /// multiple languages) for a user-interface label for this feature.
5519    ///
5520    /// The value of uiLabelNameId is expected to be in the font-specific name
5521    /// ID range (256-32767), though that is not a requirement in this Feature
5522    /// Parameters specification. The user-interface label for the feature can
5523    /// be provided in multiple languages. An English string should be included
5524    /// as a fallback. The string should be kept to a minimal length to fit
5525    /// comfortably with different application interfaces.
5526    pub fn ui_name_id(&self) -> NameId {
5527        let range = self.shape.ui_name_id_byte_range();
5528        self.data.read_at(range.start).unwrap()
5529    }
5530}
5531
5532#[cfg(feature = "experimental_traverse")]
5533impl<'a> SomeTable<'a> for StylisticSetParams<'a> {
5534    fn type_name(&self) -> &str {
5535        "StylisticSetParams"
5536    }
5537    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5538        match idx {
5539            0usize => Some(Field::new("version", self.version())),
5540            1usize => Some(Field::new("ui_name_id", self.ui_name_id())),
5541            _ => None,
5542        }
5543    }
5544}
5545
5546#[cfg(feature = "experimental_traverse")]
5547#[allow(clippy::needless_lifetimes)]
5548impl<'a> std::fmt::Debug for StylisticSetParams<'a> {
5549    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5550        (self as &dyn SomeTable<'a>).fmt(f)
5551    }
5552}
5553
5554impl Format<u16> for CharacterVariantParamsMarker {
5555    const FORMAT: u16 = 0;
5556}
5557
5558/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
5559#[derive(Debug, Clone, Copy)]
5560#[doc(hidden)]
5561pub struct CharacterVariantParamsMarker {
5562    character_byte_len: usize,
5563}
5564
5565impl CharacterVariantParamsMarker {
5566    pub fn format_byte_range(&self) -> Range<usize> {
5567        let start = 0;
5568        start..start + u16::RAW_BYTE_LEN
5569    }
5570
5571    pub fn feat_ui_label_name_id_byte_range(&self) -> Range<usize> {
5572        let start = self.format_byte_range().end;
5573        start..start + NameId::RAW_BYTE_LEN
5574    }
5575
5576    pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range<usize> {
5577        let start = self.feat_ui_label_name_id_byte_range().end;
5578        start..start + NameId::RAW_BYTE_LEN
5579    }
5580
5581    pub fn sample_text_name_id_byte_range(&self) -> Range<usize> {
5582        let start = self.feat_ui_tooltip_text_name_id_byte_range().end;
5583        start..start + NameId::RAW_BYTE_LEN
5584    }
5585
5586    pub fn num_named_parameters_byte_range(&self) -> Range<usize> {
5587        let start = self.sample_text_name_id_byte_range().end;
5588        start..start + u16::RAW_BYTE_LEN
5589    }
5590
5591    pub fn first_param_ui_label_name_id_byte_range(&self) -> Range<usize> {
5592        let start = self.num_named_parameters_byte_range().end;
5593        start..start + NameId::RAW_BYTE_LEN
5594    }
5595
5596    pub fn char_count_byte_range(&self) -> Range<usize> {
5597        let start = self.first_param_ui_label_name_id_byte_range().end;
5598        start..start + u16::RAW_BYTE_LEN
5599    }
5600
5601    pub fn character_byte_range(&self) -> Range<usize> {
5602        let start = self.char_count_byte_range().end;
5603        start..start + self.character_byte_len
5604    }
5605}
5606
5607impl MinByteRange for CharacterVariantParamsMarker {
5608    fn min_byte_range(&self) -> Range<usize> {
5609        0..self.character_byte_range().end
5610    }
5611}
5612
5613impl<'a> FontRead<'a> for CharacterVariantParams<'a> {
5614    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5615        let mut cursor = data.cursor();
5616        cursor.advance::<u16>();
5617        cursor.advance::<NameId>();
5618        cursor.advance::<NameId>();
5619        cursor.advance::<NameId>();
5620        cursor.advance::<u16>();
5621        cursor.advance::<NameId>();
5622        let char_count: u16 = cursor.read()?;
5623        let character_byte_len = (char_count as usize)
5624            .checked_mul(Uint24::RAW_BYTE_LEN)
5625            .ok_or(ReadError::OutOfBounds)?;
5626        cursor.advance_by(character_byte_len);
5627        cursor.finish(CharacterVariantParamsMarker { character_byte_len })
5628    }
5629}
5630
5631/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
5632pub type CharacterVariantParams<'a> = TableRef<'a, CharacterVariantParamsMarker>;
5633
5634#[allow(clippy::needless_lifetimes)]
5635impl<'a> CharacterVariantParams<'a> {
5636    /// Format number is set to 0.
5637    pub fn format(&self) -> u16 {
5638        let range = self.shape.format_byte_range();
5639        self.data.read_at(range.start).unwrap()
5640    }
5641
5642    /// The 'name' table name ID that specifies a string (or strings,
5643    /// for multiple languages) for a user-interface label for this
5644    /// feature. (May be NULL.)
5645    pub fn feat_ui_label_name_id(&self) -> NameId {
5646        let range = self.shape.feat_ui_label_name_id_byte_range();
5647        self.data.read_at(range.start).unwrap()
5648    }
5649
5650    /// The 'name' table name ID that specifies a string (or strings,
5651    /// for multiple languages) that an application can use for tooltip
5652    /// text for this feature. (May be NULL.)
5653    pub fn feat_ui_tooltip_text_name_id(&self) -> NameId {
5654        let range = self.shape.feat_ui_tooltip_text_name_id_byte_range();
5655        self.data.read_at(range.start).unwrap()
5656    }
5657
5658    /// The 'name' table name ID that specifies sample text that
5659    /// illustrates the effect of this feature. (May be NULL.)
5660    pub fn sample_text_name_id(&self) -> NameId {
5661        let range = self.shape.sample_text_name_id_byte_range();
5662        self.data.read_at(range.start).unwrap()
5663    }
5664
5665    /// Number of named parameters. (May be zero.)
5666    pub fn num_named_parameters(&self) -> u16 {
5667        let range = self.shape.num_named_parameters_byte_range();
5668        self.data.read_at(range.start).unwrap()
5669    }
5670
5671    /// The first 'name' table name ID used to specify strings for
5672    /// user-interface labels for the feature parameters. (Must be zero
5673    /// if numParameters is zero.)
5674    pub fn first_param_ui_label_name_id(&self) -> NameId {
5675        let range = self.shape.first_param_ui_label_name_id_byte_range();
5676        self.data.read_at(range.start).unwrap()
5677    }
5678
5679    /// The count of characters for which this feature provides glyph
5680    /// variants. (May be zero.)
5681    pub fn char_count(&self) -> u16 {
5682        let range = self.shape.char_count_byte_range();
5683        self.data.read_at(range.start).unwrap()
5684    }
5685
5686    /// The Unicode Scalar Value of the characters for which this
5687    /// feature provides glyph variants.
5688    pub fn character(&self) -> &'a [BigEndian<Uint24>] {
5689        let range = self.shape.character_byte_range();
5690        self.data.read_array(range).unwrap()
5691    }
5692}
5693
5694#[cfg(feature = "experimental_traverse")]
5695impl<'a> SomeTable<'a> for CharacterVariantParams<'a> {
5696    fn type_name(&self) -> &str {
5697        "CharacterVariantParams"
5698    }
5699    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5700        match idx {
5701            0usize => Some(Field::new("format", self.format())),
5702            1usize => Some(Field::new(
5703                "feat_ui_label_name_id",
5704                self.feat_ui_label_name_id(),
5705            )),
5706            2usize => Some(Field::new(
5707                "feat_ui_tooltip_text_name_id",
5708                self.feat_ui_tooltip_text_name_id(),
5709            )),
5710            3usize => Some(Field::new(
5711                "sample_text_name_id",
5712                self.sample_text_name_id(),
5713            )),
5714            4usize => Some(Field::new(
5715                "num_named_parameters",
5716                self.num_named_parameters(),
5717            )),
5718            5usize => Some(Field::new(
5719                "first_param_ui_label_name_id",
5720                self.first_param_ui_label_name_id(),
5721            )),
5722            6usize => Some(Field::new("char_count", self.char_count())),
5723            7usize => Some(Field::new("character", self.character())),
5724            _ => None,
5725        }
5726    }
5727}
5728
5729#[cfg(feature = "experimental_traverse")]
5730#[allow(clippy::needless_lifetimes)]
5731impl<'a> std::fmt::Debug for CharacterVariantParams<'a> {
5732    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5733        (self as &dyn SomeTable<'a>).fmt(f)
5734    }
5735}