Skip to main content

read_fonts/generated/
generated_kern.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
8impl<'a> MinByteRange<'a> for OtKern<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.subtable_data_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.data.as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl ReadArgs for OtKern<'_> {
19    type Args = ();
20}
21
22impl<'a> FontRead<'a> for OtKern<'a> {
23    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
24        #[allow(clippy::absurd_extreme_comparisons)]
25        if data.len() < Self::MIN_SIZE {
26            return Err(ReadError::OutOfBounds);
27        }
28        Ok(Self { data })
29    }
30}
31
32/// The OpenType [kerning](https://learn.microsoft.com/en-us/typography/opentype/spec/kern) table.
33#[derive(Clone)]
34pub struct OtKern<'a> {
35    data: FontData<'a>,
36}
37
38#[allow(clippy::needless_lifetimes)]
39impl<'a> OtKern<'a> {
40    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
41    basic_table_impls!(impl_the_methods);
42
43    /// Table version number—set to 0.
44    pub fn version(&self) -> u16 {
45        let range = self.version_byte_range();
46        self.data.read_at(range.start).ok().unwrap()
47    }
48
49    /// Number of subtables in the kerning table.
50    pub fn n_tables(&self) -> u16 {
51        let range = self.n_tables_byte_range();
52        self.data.read_at(range.start).ok().unwrap()
53    }
54
55    /// Data for subtables, immediately following the header.
56    pub fn subtable_data(&self) -> &'a [u8] {
57        let range = self.subtable_data_byte_range();
58        self.data.read_array(range).ok().unwrap_or_default()
59    }
60
61    pub fn version_byte_range(&self) -> Range<usize> {
62        let start = 0;
63        let end = start + u16::RAW_BYTE_LEN;
64        start..end
65    }
66
67    pub fn n_tables_byte_range(&self) -> Range<usize> {
68        let start = self.version_byte_range().end;
69        let end = start + u16::RAW_BYTE_LEN;
70        start..end
71    }
72
73    pub fn subtable_data_byte_range(&self) -> Range<usize> {
74        let start = self.n_tables_byte_range().end;
75        let end =
76            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
77        start..end
78    }
79}
80
81const _: () = assert!(FontData::default_data_long_enough(OtKern::MIN_SIZE));
82
83impl Default for OtKern<'_> {
84    fn default() -> Self {
85        Self {
86            data: FontData::default_table_data(),
87        }
88    }
89}
90
91#[cfg(feature = "experimental_traverse")]
92impl<'a> SomeTable<'a> for OtKern<'a> {
93    fn type_name(&self) -> &str {
94        "OtKern"
95    }
96    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
97        match idx {
98            0usize => Some(Field::new("version", self.version())),
99            1usize => Some(Field::new("n_tables", self.n_tables())),
100            2usize => Some(Field::new("subtable_data", self.subtable_data())),
101            _ => None,
102        }
103    }
104}
105
106#[cfg(feature = "experimental_traverse")]
107#[allow(clippy::needless_lifetimes)]
108impl<'a> std::fmt::Debug for OtKern<'a> {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        (self as &dyn SomeTable<'a>).fmt(f)
111    }
112}
113
114impl<'a> MinByteRange<'a> for AatKern<'a> {
115    fn min_byte_range(&self) -> Range<usize> {
116        0..self.subtable_data_byte_range().end
117    }
118    fn min_table_bytes(&self) -> &'a [u8] {
119        let range = self.min_byte_range();
120        self.data.as_bytes().get(range).unwrap_or_default()
121    }
122}
123
124impl ReadArgs for AatKern<'_> {
125    type Args = ();
126}
127
128impl<'a> FontRead<'a> for AatKern<'a> {
129    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
130        #[allow(clippy::absurd_extreme_comparisons)]
131        if data.len() < Self::MIN_SIZE {
132            return Err(ReadError::OutOfBounds);
133        }
134        Ok(Self { data })
135    }
136}
137
138/// The Apple Advanced Typography [kerning](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html) table.
139#[derive(Clone)]
140pub struct AatKern<'a> {
141    data: FontData<'a>,
142}
143
144#[allow(clippy::needless_lifetimes)]
145impl<'a> AatKern<'a> {
146    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
147    basic_table_impls!(impl_the_methods);
148
149    /// The version number of the kerning table (0x00010000 for the current version).
150    pub fn version(&self) -> MajorMinor {
151        let range = self.version_byte_range();
152        self.data.read_at(range.start).ok().unwrap()
153    }
154
155    /// The number of subtables included in the kerning table.
156    pub fn n_tables(&self) -> u32 {
157        let range = self.n_tables_byte_range();
158        self.data.read_at(range.start).ok().unwrap()
159    }
160
161    /// Data for subtables, immediately following the header.    
162    pub fn subtable_data(&self) -> &'a [u8] {
163        let range = self.subtable_data_byte_range();
164        self.data.read_array(range).ok().unwrap_or_default()
165    }
166
167    pub fn version_byte_range(&self) -> Range<usize> {
168        let start = 0;
169        let end = start + MajorMinor::RAW_BYTE_LEN;
170        start..end
171    }
172
173    pub fn n_tables_byte_range(&self) -> Range<usize> {
174        let start = self.version_byte_range().end;
175        let end = start + u32::RAW_BYTE_LEN;
176        start..end
177    }
178
179    pub fn subtable_data_byte_range(&self) -> Range<usize> {
180        let start = self.n_tables_byte_range().end;
181        let end =
182            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
183        start..end
184    }
185}
186
187const _: () = assert!(FontData::default_data_long_enough(AatKern::MIN_SIZE));
188
189impl Default for AatKern<'_> {
190    fn default() -> Self {
191        Self {
192            data: FontData::default_table_data(),
193        }
194    }
195}
196
197#[cfg(feature = "experimental_traverse")]
198impl<'a> SomeTable<'a> for AatKern<'a> {
199    fn type_name(&self) -> &str {
200        "AatKern"
201    }
202    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
203        match idx {
204            0usize => Some(Field::new("version", self.version())),
205            1usize => Some(Field::new("n_tables", self.n_tables())),
206            2usize => Some(Field::new("subtable_data", self.subtable_data())),
207            _ => None,
208        }
209    }
210}
211
212#[cfg(feature = "experimental_traverse")]
213#[allow(clippy::needless_lifetimes)]
214impl<'a> std::fmt::Debug for AatKern<'a> {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        (self as &dyn SomeTable<'a>).fmt(f)
217    }
218}
219
220impl<'a> MinByteRange<'a> for OtSubtable<'a> {
221    fn min_byte_range(&self) -> Range<usize> {
222        0..self.data_byte_range().end
223    }
224    fn min_table_bytes(&self) -> &'a [u8] {
225        let range = self.min_byte_range();
226        self.data.as_bytes().get(range).unwrap_or_default()
227    }
228}
229
230impl ReadArgs for OtSubtable<'_> {
231    type Args = ();
232}
233
234impl<'a> FontRead<'a> for OtSubtable<'a> {
235    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
236        #[allow(clippy::absurd_extreme_comparisons)]
237        if data.len() < Self::MIN_SIZE {
238            return Err(ReadError::OutOfBounds);
239        }
240        Ok(Self { data })
241    }
242}
243
244/// A subtable in an OT `kern` table.
245#[derive(Clone)]
246pub struct OtSubtable<'a> {
247    data: FontData<'a>,
248}
249
250#[allow(clippy::needless_lifetimes)]
251impl<'a> OtSubtable<'a> {
252    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
253    basic_table_impls!(impl_the_methods);
254
255    /// Kern subtable version number-- set to 0.
256    pub fn version(&self) -> u16 {
257        let range = self.version_byte_range();
258        self.data.read_at(range.start).ok().unwrap()
259    }
260
261    /// The length of this subtable in bytes, including this header.
262    pub fn length(&self) -> u16 {
263        let range = self.length_byte_range();
264        self.data.read_at(range.start).ok().unwrap()
265    }
266
267    /// Circumstances under which this table is used.
268    pub fn coverage(&self) -> u16 {
269        let range = self.coverage_byte_range();
270        self.data.read_at(range.start).ok().unwrap()
271    }
272
273    /// Subtable specific data.
274    pub fn data(&self) -> &'a [u8] {
275        let range = self.data_byte_range();
276        self.data.read_array(range).ok().unwrap_or_default()
277    }
278
279    pub fn version_byte_range(&self) -> Range<usize> {
280        let start = 0;
281        let end = start + u16::RAW_BYTE_LEN;
282        start..end
283    }
284
285    pub fn length_byte_range(&self) -> Range<usize> {
286        let start = self.version_byte_range().end;
287        let end = start + u16::RAW_BYTE_LEN;
288        start..end
289    }
290
291    pub fn coverage_byte_range(&self) -> Range<usize> {
292        let start = self.length_byte_range().end;
293        let end = start + u16::RAW_BYTE_LEN;
294        start..end
295    }
296
297    pub fn data_byte_range(&self) -> Range<usize> {
298        let start = self.coverage_byte_range().end;
299        let end =
300            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
301        start..end
302    }
303}
304
305const _: () = assert!(FontData::default_data_long_enough(OtSubtable::MIN_SIZE));
306
307impl Default for OtSubtable<'_> {
308    fn default() -> Self {
309        Self {
310            data: FontData::default_table_data(),
311        }
312    }
313}
314
315#[cfg(feature = "experimental_traverse")]
316impl<'a> SomeTable<'a> for OtSubtable<'a> {
317    fn type_name(&self) -> &str {
318        "OtSubtable"
319    }
320    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
321        match idx {
322            0usize => Some(Field::new("version", self.version())),
323            1usize => Some(Field::new("length", self.length())),
324            2usize => Some(Field::new("coverage", self.coverage())),
325            3usize => Some(Field::new("data", self.data())),
326            _ => None,
327        }
328    }
329}
330
331#[cfg(feature = "experimental_traverse")]
332#[allow(clippy::needless_lifetimes)]
333impl<'a> std::fmt::Debug for OtSubtable<'a> {
334    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335        (self as &dyn SomeTable<'a>).fmt(f)
336    }
337}
338
339impl<'a> MinByteRange<'a> for AatSubtable<'a> {
340    fn min_byte_range(&self) -> Range<usize> {
341        0..self.data_byte_range().end
342    }
343    fn min_table_bytes(&self) -> &'a [u8] {
344        let range = self.min_byte_range();
345        self.data.as_bytes().get(range).unwrap_or_default()
346    }
347}
348
349impl ReadArgs for AatSubtable<'_> {
350    type Args = ();
351}
352
353impl<'a> FontRead<'a> for AatSubtable<'a> {
354    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
355        #[allow(clippy::absurd_extreme_comparisons)]
356        if data.len() < Self::MIN_SIZE {
357            return Err(ReadError::OutOfBounds);
358        }
359        Ok(Self { data })
360    }
361}
362
363/// A subtable in an AAT `kern` table.
364#[derive(Clone)]
365pub struct AatSubtable<'a> {
366    data: FontData<'a>,
367}
368
369#[allow(clippy::needless_lifetimes)]
370impl<'a> AatSubtable<'a> {
371    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
372    basic_table_impls!(impl_the_methods);
373
374    /// The length of this subtable in bytes, including this header.
375    pub fn length(&self) -> u32 {
376        let range = self.length_byte_range();
377        self.data.read_at(range.start).ok().unwrap()
378    }
379
380    /// Circumstances under which this table is used.
381    pub fn coverage(&self) -> u16 {
382        let range = self.coverage_byte_range();
383        self.data.read_at(range.start).ok().unwrap()
384    }
385
386    /// The tuple index (used for variations fonts). This value specifies which tuple this subtable covers.
387    pub fn tuple_index(&self) -> u16 {
388        let range = self.tuple_index_byte_range();
389        self.data.read_at(range.start).ok().unwrap()
390    }
391
392    /// Subtable specific data.
393    pub fn data(&self) -> &'a [u8] {
394        let range = self.data_byte_range();
395        self.data.read_array(range).ok().unwrap_or_default()
396    }
397
398    pub fn length_byte_range(&self) -> Range<usize> {
399        let start = 0;
400        let end = start + u32::RAW_BYTE_LEN;
401        start..end
402    }
403
404    pub fn coverage_byte_range(&self) -> Range<usize> {
405        let start = self.length_byte_range().end;
406        let end = start + u16::RAW_BYTE_LEN;
407        start..end
408    }
409
410    pub fn tuple_index_byte_range(&self) -> Range<usize> {
411        let start = self.coverage_byte_range().end;
412        let end = start + u16::RAW_BYTE_LEN;
413        start..end
414    }
415
416    pub fn data_byte_range(&self) -> Range<usize> {
417        let start = self.tuple_index_byte_range().end;
418        let end =
419            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
420        start..end
421    }
422}
423
424const _: () = assert!(FontData::default_data_long_enough(AatSubtable::MIN_SIZE));
425
426impl Default for AatSubtable<'_> {
427    fn default() -> Self {
428        Self {
429            data: FontData::default_table_data(),
430        }
431    }
432}
433
434#[cfg(feature = "experimental_traverse")]
435impl<'a> SomeTable<'a> for AatSubtable<'a> {
436    fn type_name(&self) -> &str {
437        "AatSubtable"
438    }
439    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
440        match idx {
441            0usize => Some(Field::new("length", self.length())),
442            1usize => Some(Field::new("coverage", self.coverage())),
443            2usize => Some(Field::new("tuple_index", self.tuple_index())),
444            3usize => Some(Field::new("data", self.data())),
445            _ => None,
446        }
447    }
448}
449
450#[cfg(feature = "experimental_traverse")]
451#[allow(clippy::needless_lifetimes)]
452impl<'a> std::fmt::Debug for AatSubtable<'a> {
453    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
454        (self as &dyn SomeTable<'a>).fmt(f)
455    }
456}
457
458impl<'a> MinByteRange<'a> for Subtable0<'a> {
459    fn min_byte_range(&self) -> Range<usize> {
460        0..self.pairs_byte_range().end
461    }
462    fn min_table_bytes(&self) -> &'a [u8] {
463        let range = self.min_byte_range();
464        self.data.as_bytes().get(range).unwrap_or_default()
465    }
466}
467
468impl ReadArgs for Subtable0<'_> {
469    type Args = ();
470}
471
472impl<'a> FontRead<'a> for Subtable0<'a> {
473    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
474        #[allow(clippy::absurd_extreme_comparisons)]
475        if data.len() < Self::MIN_SIZE {
476            return Err(ReadError::OutOfBounds);
477        }
478        Ok(Self { data })
479    }
480}
481
482/// The type 0 `kern` subtable.
483#[derive(Clone)]
484pub struct Subtable0<'a> {
485    data: FontData<'a>,
486}
487
488#[allow(clippy::needless_lifetimes)]
489impl<'a> Subtable0<'a> {
490    pub const MIN_SIZE: usize =
491        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
492    basic_table_impls!(impl_the_methods);
493
494    /// The number of kerning pairs in this subtable.
495    pub fn n_pairs(&self) -> u16 {
496        let range = self.n_pairs_byte_range();
497        self.data.read_at(range.start).ok().unwrap()
498    }
499
500    /// The largest power of two less than or equal to the value of nPairs, multiplied by the size in bytes of an entry in the subtable.
501    pub fn search_range(&self) -> u16 {
502        let range = self.search_range_byte_range();
503        self.data.read_at(range.start).ok().unwrap()
504    }
505
506    /// This is calculated as log2 of the largest power of two less than or equal to the value of nPairs. This value indicates how many iterations of the search loop have to be made. For example, in a list of eight items, there would be three iterations of the loop.
507    pub fn entry_selector(&self) -> u16 {
508        let range = self.entry_selector_byte_range();
509        self.data.read_at(range.start).ok().unwrap()
510    }
511
512    /// The value of nPairs minus the largest power of two less than or equal to nPairs. This is multiplied by the size in bytes of an entry in the table.
513    pub fn range_shift(&self) -> u16 {
514        let range = self.range_shift_byte_range();
515        self.data.read_at(range.start).ok().unwrap()
516    }
517
518    /// Kerning records.
519    pub fn pairs(&self) -> &'a [Subtable0Pair] {
520        let range = self.pairs_byte_range();
521        self.data.read_array(range).ok().unwrap_or_default()
522    }
523
524    pub fn n_pairs_byte_range(&self) -> Range<usize> {
525        let start = 0;
526        let end = start + u16::RAW_BYTE_LEN;
527        start..end
528    }
529
530    pub fn search_range_byte_range(&self) -> Range<usize> {
531        let start = self.n_pairs_byte_range().end;
532        let end = start + u16::RAW_BYTE_LEN;
533        start..end
534    }
535
536    pub fn entry_selector_byte_range(&self) -> Range<usize> {
537        let start = self.search_range_byte_range().end;
538        let end = start + u16::RAW_BYTE_LEN;
539        start..end
540    }
541
542    pub fn range_shift_byte_range(&self) -> Range<usize> {
543        let start = self.entry_selector_byte_range().end;
544        let end = start + u16::RAW_BYTE_LEN;
545        start..end
546    }
547
548    pub fn pairs_byte_range(&self) -> Range<usize> {
549        let n_pairs = self.n_pairs();
550        let start = self.range_shift_byte_range().end;
551        let end =
552            start + (transforms::to_usize(n_pairs)).saturating_mul(Subtable0Pair::RAW_BYTE_LEN);
553        start..end
554    }
555}
556
557const _: () = assert!(FontData::default_data_long_enough(Subtable0::MIN_SIZE));
558
559impl Default for Subtable0<'_> {
560    fn default() -> Self {
561        Self {
562            data: FontData::default_table_data(),
563        }
564    }
565}
566
567#[cfg(feature = "experimental_traverse")]
568impl<'a> SomeTable<'a> for Subtable0<'a> {
569    fn type_name(&self) -> &str {
570        "Subtable0"
571    }
572    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
573        match idx {
574            0usize => Some(Field::new("n_pairs", self.n_pairs())),
575            1usize => Some(Field::new("search_range", self.search_range())),
576            2usize => Some(Field::new("entry_selector", self.entry_selector())),
577            3usize => Some(Field::new("range_shift", self.range_shift())),
578            4usize => Some(Field::new(
579                "pairs",
580                traversal::FieldType::array_of_records(
581                    stringify!(Subtable0Pair),
582                    self.pairs(),
583                    self.offset_data(),
584                ),
585            )),
586            _ => None,
587        }
588    }
589}
590
591#[cfg(feature = "experimental_traverse")]
592#[allow(clippy::needless_lifetimes)]
593impl<'a> std::fmt::Debug for Subtable0<'a> {
594    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
595        (self as &dyn SomeTable<'a>).fmt(f)
596    }
597}
598
599impl<'a> MinByteRange<'a> for Subtable2ClassTable<'a> {
600    fn min_byte_range(&self) -> Range<usize> {
601        0..self.offsets_byte_range().end
602    }
603    fn min_table_bytes(&self) -> &'a [u8] {
604        let range = self.min_byte_range();
605        self.data.as_bytes().get(range).unwrap_or_default()
606    }
607}
608
609impl ReadArgs for Subtable2ClassTable<'_> {
610    type Args = ();
611}
612
613impl<'a> FontRead<'a> for Subtable2ClassTable<'a> {
614    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
615        #[allow(clippy::absurd_extreme_comparisons)]
616        if data.len() < Self::MIN_SIZE {
617            return Err(ReadError::OutOfBounds);
618        }
619        Ok(Self { data })
620    }
621}
622
623/// Class table for the type 2 `kern` subtable.
624#[derive(Clone)]
625pub struct Subtable2ClassTable<'a> {
626    data: FontData<'a>,
627}
628
629#[allow(clippy::needless_lifetimes)]
630impl<'a> Subtable2ClassTable<'a> {
631    pub const MIN_SIZE: usize = (GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
632    basic_table_impls!(impl_the_methods);
633
634    /// First glyph in class range.
635    pub fn first_glyph(&self) -> GlyphId16 {
636        let range = self.first_glyph_byte_range();
637        self.data.read_at(range.start).ok().unwrap()
638    }
639
640    /// Number of glyph in class range.
641    pub fn n_glyphs(&self) -> u16 {
642        let range = self.n_glyphs_byte_range();
643        self.data.read_at(range.start).ok().unwrap()
644    }
645
646    /// The offsets array for all of the glyphs in the range.
647    pub fn offsets(&self) -> &'a [BigEndian<u16>] {
648        let range = self.offsets_byte_range();
649        self.data.read_array(range).ok().unwrap_or_default()
650    }
651
652    pub fn first_glyph_byte_range(&self) -> Range<usize> {
653        let start = 0;
654        let end = start + GlyphId16::RAW_BYTE_LEN;
655        start..end
656    }
657
658    pub fn n_glyphs_byte_range(&self) -> Range<usize> {
659        let start = self.first_glyph_byte_range().end;
660        let end = start + u16::RAW_BYTE_LEN;
661        start..end
662    }
663
664    pub fn offsets_byte_range(&self) -> Range<usize> {
665        let n_glyphs = self.n_glyphs();
666        let start = self.n_glyphs_byte_range().end;
667        let end = start + (transforms::to_usize(n_glyphs)).saturating_mul(u16::RAW_BYTE_LEN);
668        start..end
669    }
670}
671
672const _: () = assert!(FontData::default_data_long_enough(
673    Subtable2ClassTable::MIN_SIZE
674));
675
676impl Default for Subtable2ClassTable<'_> {
677    fn default() -> Self {
678        Self {
679            data: FontData::default_table_data(),
680        }
681    }
682}
683
684#[cfg(feature = "experimental_traverse")]
685impl<'a> SomeTable<'a> for Subtable2ClassTable<'a> {
686    fn type_name(&self) -> &str {
687        "Subtable2ClassTable"
688    }
689    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
690        match idx {
691            0usize => Some(Field::new("first_glyph", self.first_glyph())),
692            1usize => Some(Field::new("n_glyphs", self.n_glyphs())),
693            2usize => Some(Field::new("offsets", self.offsets())),
694            _ => None,
695        }
696    }
697}
698
699#[cfg(feature = "experimental_traverse")]
700#[allow(clippy::needless_lifetimes)]
701impl<'a> std::fmt::Debug for Subtable2ClassTable<'a> {
702    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
703        (self as &dyn SomeTable<'a>).fmt(f)
704    }
705}
706
707impl<'a> MinByteRange<'a> for Subtable3<'a> {
708    fn min_byte_range(&self) -> Range<usize> {
709        0..self.kern_index_byte_range().end
710    }
711    fn min_table_bytes(&self) -> &'a [u8] {
712        let range = self.min_byte_range();
713        self.data.as_bytes().get(range).unwrap_or_default()
714    }
715}
716
717impl ReadArgs for Subtable3<'_> {
718    type Args = ();
719}
720
721impl<'a> FontRead<'a> for Subtable3<'a> {
722    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
723        #[allow(clippy::absurd_extreme_comparisons)]
724        if data.len() < Self::MIN_SIZE {
725            return Err(ReadError::OutOfBounds);
726        }
727        Ok(Self { data })
728    }
729}
730
731/// The type 3 'kern' subtable.
732#[derive(Clone)]
733pub struct Subtable3<'a> {
734    data: FontData<'a>,
735}
736
737#[allow(clippy::needless_lifetimes)]
738impl<'a> Subtable3<'a> {
739    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
740        + u8::RAW_BYTE_LEN
741        + u8::RAW_BYTE_LEN
742        + u8::RAW_BYTE_LEN
743        + u8::RAW_BYTE_LEN);
744    basic_table_impls!(impl_the_methods);
745
746    /// The number of glyphs in this font.
747    pub fn glyph_count(&self) -> u16 {
748        let range = self.glyph_count_byte_range();
749        self.data.read_at(range.start).ok().unwrap()
750    }
751
752    /// The number of kerning values.
753    pub fn kern_value_count(&self) -> u8 {
754        let range = self.kern_value_count_byte_range();
755        self.data.read_at(range.start).ok().unwrap()
756    }
757
758    /// The number of left-hand classes.
759    pub fn left_class_count(&self) -> u8 {
760        let range = self.left_class_count_byte_range();
761        self.data.read_at(range.start).ok().unwrap()
762    }
763
764    /// The number of right-hand classes.
765    pub fn right_class_count(&self) -> u8 {
766        let range = self.right_class_count_byte_range();
767        self.data.read_at(range.start).ok().unwrap()
768    }
769
770    /// Set to zero (reserved for future use).
771    pub fn flags(&self) -> u8 {
772        let range = self.flags_byte_range();
773        self.data.read_at(range.start).ok().unwrap()
774    }
775
776    /// The kerning values.
777    pub fn kern_value(&self) -> &'a [BigEndian<i16>] {
778        let range = self.kern_value_byte_range();
779        self.data.read_array(range).ok().unwrap_or_default()
780    }
781
782    /// The left-hand classes.
783    pub fn left_class(&self) -> &'a [u8] {
784        let range = self.left_class_byte_range();
785        self.data.read_array(range).ok().unwrap_or_default()
786    }
787
788    /// The right-hand classes.
789    pub fn right_class(&self) -> &'a [u8] {
790        let range = self.right_class_byte_range();
791        self.data.read_array(range).ok().unwrap_or_default()
792    }
793
794    /// The indices into the kernValue array.
795    pub fn kern_index(&self) -> &'a [u8] {
796        let range = self.kern_index_byte_range();
797        self.data.read_array(range).ok().unwrap_or_default()
798    }
799
800    pub fn glyph_count_byte_range(&self) -> Range<usize> {
801        let start = 0;
802        let end = start + u16::RAW_BYTE_LEN;
803        start..end
804    }
805
806    pub fn kern_value_count_byte_range(&self) -> Range<usize> {
807        let start = self.glyph_count_byte_range().end;
808        let end = start + u8::RAW_BYTE_LEN;
809        start..end
810    }
811
812    pub fn left_class_count_byte_range(&self) -> Range<usize> {
813        let start = self.kern_value_count_byte_range().end;
814        let end = start + u8::RAW_BYTE_LEN;
815        start..end
816    }
817
818    pub fn right_class_count_byte_range(&self) -> Range<usize> {
819        let start = self.left_class_count_byte_range().end;
820        let end = start + u8::RAW_BYTE_LEN;
821        start..end
822    }
823
824    pub fn flags_byte_range(&self) -> Range<usize> {
825        let start = self.right_class_count_byte_range().end;
826        let end = start + u8::RAW_BYTE_LEN;
827        start..end
828    }
829
830    pub fn kern_value_byte_range(&self) -> Range<usize> {
831        let kern_value_count = self.kern_value_count();
832        let start = self.flags_byte_range().end;
833        let end =
834            start + (transforms::to_usize(kern_value_count)).saturating_mul(i16::RAW_BYTE_LEN);
835        start..end
836    }
837
838    pub fn left_class_byte_range(&self) -> Range<usize> {
839        let glyph_count = self.glyph_count();
840        let start = self.kern_value_byte_range().end;
841        let end = start + (transforms::to_usize(glyph_count)).saturating_mul(u8::RAW_BYTE_LEN);
842        start..end
843    }
844
845    pub fn right_class_byte_range(&self) -> Range<usize> {
846        let glyph_count = self.glyph_count();
847        let start = self.left_class_byte_range().end;
848        let end = start + (transforms::to_usize(glyph_count)).saturating_mul(u8::RAW_BYTE_LEN);
849        start..end
850    }
851
852    pub fn kern_index_byte_range(&self) -> Range<usize> {
853        let left_class_count = self.left_class_count();
854        let right_class_count = self.right_class_count();
855        let start = self.right_class_byte_range().end;
856        let end = start
857            + (transforms::add_multiply(left_class_count, 0_usize, right_class_count))
858                .saturating_mul(u8::RAW_BYTE_LEN);
859        start..end
860    }
861}
862
863const _: () = assert!(FontData::default_data_long_enough(Subtable3::MIN_SIZE));
864
865impl Default for Subtable3<'_> {
866    fn default() -> Self {
867        Self {
868            data: FontData::default_table_data(),
869        }
870    }
871}
872
873#[cfg(feature = "experimental_traverse")]
874impl<'a> SomeTable<'a> for Subtable3<'a> {
875    fn type_name(&self) -> &str {
876        "Subtable3"
877    }
878    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
879        match idx {
880            0usize => Some(Field::new("glyph_count", self.glyph_count())),
881            1usize => Some(Field::new("kern_value_count", self.kern_value_count())),
882            2usize => Some(Field::new("left_class_count", self.left_class_count())),
883            3usize => Some(Field::new("right_class_count", self.right_class_count())),
884            4usize => Some(Field::new("flags", self.flags())),
885            5usize => Some(Field::new("kern_value", self.kern_value())),
886            6usize => Some(Field::new("left_class", self.left_class())),
887            7usize => Some(Field::new("right_class", self.right_class())),
888            8usize => Some(Field::new("kern_index", self.kern_index())),
889            _ => None,
890        }
891    }
892}
893
894#[cfg(feature = "experimental_traverse")]
895#[allow(clippy::needless_lifetimes)]
896impl<'a> std::fmt::Debug for Subtable3<'a> {
897    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
898        (self as &dyn SomeTable<'a>).fmt(f)
899    }
900}