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