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