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