Coverage Report

Created: 2025-09-27 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/read-fonts/generated/generated_kern.rs
Line
Count
Source
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)]
6
use 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)]
11
pub struct OtKernMarker {
12
    subtable_data_byte_len: usize,
13
}
14
15
impl OtKernMarker {
16
0
    pub fn version_byte_range(&self) -> Range<usize> {
17
0
        let start = 0;
18
0
        start..start + u16::RAW_BYTE_LEN
19
0
    }
20
21
0
    pub fn n_tables_byte_range(&self) -> Range<usize> {
22
0
        let start = self.version_byte_range().end;
23
0
        start..start + u16::RAW_BYTE_LEN
24
0
    }
25
26
0
    pub fn subtable_data_byte_range(&self) -> Range<usize> {
27
0
        let start = self.n_tables_byte_range().end;
28
0
        start..start + self.subtable_data_byte_len
29
0
    }
30
}
31
32
impl MinByteRange for OtKernMarker {
33
0
    fn min_byte_range(&self) -> Range<usize> {
34
0
        0..self.subtable_data_byte_range().end
35
0
    }
36
}
37
38
impl<'a> FontRead<'a> for OtKern<'a> {
39
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
40
0
        let mut cursor = data.cursor();
41
0
        cursor.advance::<u16>();
42
0
        cursor.advance::<u16>();
43
0
        let subtable_data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
44
0
        cursor.advance_by(subtable_data_byte_len);
45
0
        cursor.finish(OtKernMarker {
46
0
            subtable_data_byte_len,
47
0
        })
48
0
    }
49
}
50
51
/// The OpenType [kerning](https://learn.microsoft.com/en-us/typography/opentype/spec/kern) table.
52
pub type OtKern<'a> = TableRef<'a, OtKernMarker>;
53
54
#[allow(clippy::needless_lifetimes)]
55
impl<'a> OtKern<'a> {
56
    /// Table version number—set to 0.
57
0
    pub fn version(&self) -> u16 {
58
0
        let range = self.shape.version_byte_range();
59
0
        self.data.read_at(range.start).unwrap()
60
0
    }
61
62
    /// Number of subtables in the kerning table.
63
0
    pub fn n_tables(&self) -> u16 {
64
0
        let range = self.shape.n_tables_byte_range();
65
0
        self.data.read_at(range.start).unwrap()
66
0
    }
67
68
    /// Data for subtables, immediately following the header.
69
0
    pub fn subtable_data(&self) -> &'a [u8] {
70
0
        let range = self.shape.subtable_data_byte_range();
71
0
        self.data.read_array(range).unwrap()
72
0
    }
73
}
74
75
#[cfg(feature = "experimental_traverse")]
76
impl<'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)]
92
impl<'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)]
101
pub struct AatKernMarker {
102
    subtable_data_byte_len: usize,
103
}
104
105
impl AatKernMarker {
106
0
    pub fn version_byte_range(&self) -> Range<usize> {
107
0
        let start = 0;
108
0
        start..start + MajorMinor::RAW_BYTE_LEN
109
0
    }
110
111
0
    pub fn n_tables_byte_range(&self) -> Range<usize> {
112
0
        let start = self.version_byte_range().end;
113
0
        start..start + u32::RAW_BYTE_LEN
114
0
    }
115
116
0
    pub fn subtable_data_byte_range(&self) -> Range<usize> {
117
0
        let start = self.n_tables_byte_range().end;
118
0
        start..start + self.subtable_data_byte_len
119
0
    }
120
}
121
122
impl MinByteRange for AatKernMarker {
123
0
    fn min_byte_range(&self) -> Range<usize> {
124
0
        0..self.subtable_data_byte_range().end
125
0
    }
126
}
127
128
impl<'a> FontRead<'a> for AatKern<'a> {
129
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
130
0
        let mut cursor = data.cursor();
131
0
        cursor.advance::<MajorMinor>();
132
0
        cursor.advance::<u32>();
133
0
        let subtable_data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
134
0
        cursor.advance_by(subtable_data_byte_len);
135
0
        cursor.finish(AatKernMarker {
136
0
            subtable_data_byte_len,
137
0
        })
138
0
    }
139
}
140
141
/// The Apple Advanced Typography [kerning](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html) table.
142
pub type AatKern<'a> = TableRef<'a, AatKernMarker>;
143
144
#[allow(clippy::needless_lifetimes)]
145
impl<'a> AatKern<'a> {
146
    /// The version number of the kerning table (0x00010000 for the current version).
147
0
    pub fn version(&self) -> MajorMinor {
148
0
        let range = self.shape.version_byte_range();
149
0
        self.data.read_at(range.start).unwrap()
150
0
    }
151
152
    /// The number of subtables included in the kerning table.
153
0
    pub fn n_tables(&self) -> u32 {
154
0
        let range = self.shape.n_tables_byte_range();
155
0
        self.data.read_at(range.start).unwrap()
156
0
    }
157
158
    /// Data for subtables, immediately following the header.    
159
0
    pub fn subtable_data(&self) -> &'a [u8] {
160
0
        let range = self.shape.subtable_data_byte_range();
161
0
        self.data.read_array(range).unwrap()
162
0
    }
163
}
164
165
#[cfg(feature = "experimental_traverse")]
166
impl<'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)]
182
impl<'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)]
191
pub struct OtSubtableMarker {
192
    data_byte_len: usize,
193
}
194
195
impl OtSubtableMarker {
196
0
    pub fn version_byte_range(&self) -> Range<usize> {
197
0
        let start = 0;
198
0
        start..start + u16::RAW_BYTE_LEN
199
0
    }
200
201
0
    pub fn length_byte_range(&self) -> Range<usize> {
202
0
        let start = self.version_byte_range().end;
203
0
        start..start + u16::RAW_BYTE_LEN
204
0
    }
205
206
0
    pub fn coverage_byte_range(&self) -> Range<usize> {
207
0
        let start = self.length_byte_range().end;
208
0
        start..start + u16::RAW_BYTE_LEN
209
0
    }
210
211
0
    pub fn data_byte_range(&self) -> Range<usize> {
212
0
        let start = self.coverage_byte_range().end;
213
0
        start..start + self.data_byte_len
214
0
    }
215
}
216
217
impl MinByteRange for OtSubtableMarker {
218
0
    fn min_byte_range(&self) -> Range<usize> {
219
0
        0..self.data_byte_range().end
220
0
    }
221
}
222
223
impl<'a> FontRead<'a> for OtSubtable<'a> {
224
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
225
0
        let mut cursor = data.cursor();
226
0
        cursor.advance::<u16>();
227
0
        cursor.advance::<u16>();
228
0
        cursor.advance::<u16>();
229
0
        let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
230
0
        cursor.advance_by(data_byte_len);
231
0
        cursor.finish(OtSubtableMarker { data_byte_len })
232
0
    }
233
}
234
235
/// A subtable in an OT `kern` table.
236
pub type OtSubtable<'a> = TableRef<'a, OtSubtableMarker>;
237
238
#[allow(clippy::needless_lifetimes)]
239
impl<'a> OtSubtable<'a> {
240
    /// Kern subtable version number-- set to 0.
241
0
    pub fn version(&self) -> u16 {
242
0
        let range = self.shape.version_byte_range();
243
0
        self.data.read_at(range.start).unwrap()
244
0
    }
245
246
    /// The length of this subtable in bytes, including this header.
247
0
    pub fn length(&self) -> u16 {
248
0
        let range = self.shape.length_byte_range();
249
0
        self.data.read_at(range.start).unwrap()
250
0
    }
251
252
    /// Circumstances under which this table is used.
253
0
    pub fn coverage(&self) -> u16 {
254
0
        let range = self.shape.coverage_byte_range();
255
0
        self.data.read_at(range.start).unwrap()
256
0
    }
257
258
    /// Subtable specific data.
259
0
    pub fn data(&self) -> &'a [u8] {
260
0
        let range = self.shape.data_byte_range();
261
0
        self.data.read_array(range).unwrap()
262
0
    }
263
}
264
265
#[cfg(feature = "experimental_traverse")]
266
impl<'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)]
283
impl<'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)]
292
pub struct AatSubtableMarker {
293
    data_byte_len: usize,
294
}
295
296
impl AatSubtableMarker {
297
0
    pub fn length_byte_range(&self) -> Range<usize> {
298
0
        let start = 0;
299
0
        start..start + u32::RAW_BYTE_LEN
300
0
    }
301
302
0
    pub fn coverage_byte_range(&self) -> Range<usize> {
303
0
        let start = self.length_byte_range().end;
304
0
        start..start + u16::RAW_BYTE_LEN
305
0
    }
306
307
0
    pub fn tuple_index_byte_range(&self) -> Range<usize> {
308
0
        let start = self.coverage_byte_range().end;
309
0
        start..start + u16::RAW_BYTE_LEN
310
0
    }
311
312
0
    pub fn data_byte_range(&self) -> Range<usize> {
313
0
        let start = self.tuple_index_byte_range().end;
314
0
        start..start + self.data_byte_len
315
0
    }
316
}
317
318
impl MinByteRange for AatSubtableMarker {
319
0
    fn min_byte_range(&self) -> Range<usize> {
320
0
        0..self.data_byte_range().end
321
0
    }
322
}
323
324
impl<'a> FontRead<'a> for AatSubtable<'a> {
325
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
326
0
        let mut cursor = data.cursor();
327
0
        cursor.advance::<u32>();
328
0
        cursor.advance::<u16>();
329
0
        cursor.advance::<u16>();
330
0
        let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
331
0
        cursor.advance_by(data_byte_len);
332
0
        cursor.finish(AatSubtableMarker { data_byte_len })
333
0
    }
334
}
335
336
/// A subtable in an AAT `kern` table.
337
pub type AatSubtable<'a> = TableRef<'a, AatSubtableMarker>;
338
339
#[allow(clippy::needless_lifetimes)]
340
impl<'a> AatSubtable<'a> {
341
    /// The length of this subtable in bytes, including this header.
342
0
    pub fn length(&self) -> u32 {
343
0
        let range = self.shape.length_byte_range();
344
0
        self.data.read_at(range.start).unwrap()
345
0
    }
346
347
    /// Circumstances under which this table is used.
348
0
    pub fn coverage(&self) -> u16 {
349
0
        let range = self.shape.coverage_byte_range();
350
0
        self.data.read_at(range.start).unwrap()
351
0
    }
352
353
    /// The tuple index (used for variations fonts). This value specifies which tuple this subtable covers.
354
0
    pub fn tuple_index(&self) -> u16 {
355
0
        let range = self.shape.tuple_index_byte_range();
356
0
        self.data.read_at(range.start).unwrap()
357
0
    }
358
359
    /// Subtable specific data.
360
0
    pub fn data(&self) -> &'a [u8] {
361
0
        let range = self.shape.data_byte_range();
362
0
        self.data.read_array(range).unwrap()
363
0
    }
364
}
365
366
#[cfg(feature = "experimental_traverse")]
367
impl<'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)]
384
impl<'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)]
393
pub struct Subtable0Marker {
394
    pairs_byte_len: usize,
395
}
396
397
impl Subtable0Marker {
398
0
    pub fn n_pairs_byte_range(&self) -> Range<usize> {
399
0
        let start = 0;
400
0
        start..start + u16::RAW_BYTE_LEN
401
0
    }
402
403
0
    pub fn search_range_byte_range(&self) -> Range<usize> {
404
0
        let start = self.n_pairs_byte_range().end;
405
0
        start..start + u16::RAW_BYTE_LEN
406
0
    }
407
408
0
    pub fn entry_selector_byte_range(&self) -> Range<usize> {
409
0
        let start = self.search_range_byte_range().end;
410
0
        start..start + u16::RAW_BYTE_LEN
411
0
    }
412
413
0
    pub fn range_shift_byte_range(&self) -> Range<usize> {
414
0
        let start = self.entry_selector_byte_range().end;
415
0
        start..start + u16::RAW_BYTE_LEN
416
0
    }
417
418
0
    pub fn pairs_byte_range(&self) -> Range<usize> {
419
0
        let start = self.range_shift_byte_range().end;
420
0
        start..start + self.pairs_byte_len
421
0
    }
422
}
423
424
impl MinByteRange for Subtable0Marker {
425
0
    fn min_byte_range(&self) -> Range<usize> {
426
0
        0..self.pairs_byte_range().end
427
0
    }
428
}
429
430
impl<'a> FontRead<'a> for Subtable0<'a> {
431
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
432
0
        let mut cursor = data.cursor();
433
0
        let n_pairs: u16 = cursor.read()?;
434
0
        cursor.advance::<u16>();
435
0
        cursor.advance::<u16>();
436
0
        cursor.advance::<u16>();
437
0
        let pairs_byte_len = (n_pairs as usize)
438
0
            .checked_mul(Subtable0Pair::RAW_BYTE_LEN)
439
0
            .ok_or(ReadError::OutOfBounds)?;
440
0
        cursor.advance_by(pairs_byte_len);
441
0
        cursor.finish(Subtable0Marker { pairs_byte_len })
442
0
    }
443
}
444
445
/// The type 0 `kern` subtable.
446
pub type Subtable0<'a> = TableRef<'a, Subtable0Marker>;
447
448
#[allow(clippy::needless_lifetimes)]
449
impl<'a> Subtable0<'a> {
450
    /// The number of kerning pairs in this subtable.
451
0
    pub fn n_pairs(&self) -> u16 {
452
0
        let range = self.shape.n_pairs_byte_range();
453
0
        self.data.read_at(range.start).unwrap()
454
0
    }
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
0
    pub fn search_range(&self) -> u16 {
458
0
        let range = self.shape.search_range_byte_range();
459
0
        self.data.read_at(range.start).unwrap()
460
0
    }
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
0
    pub fn entry_selector(&self) -> u16 {
464
0
        let range = self.shape.entry_selector_byte_range();
465
0
        self.data.read_at(range.start).unwrap()
466
0
    }
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
0
    pub fn range_shift(&self) -> u16 {
470
0
        let range = self.shape.range_shift_byte_range();
471
0
        self.data.read_at(range.start).unwrap()
472
0
    }
473
474
    /// Kerning records.
475
0
    pub fn pairs(&self) -> &'a [Subtable0Pair] {
476
0
        let range = self.shape.pairs_byte_range();
477
0
        self.data.read_array(range).unwrap()
478
0
    }
479
}
480
481
#[cfg(feature = "experimental_traverse")]
482
impl<'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)]
507
impl<'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)]
516
pub struct Subtable2ClassTableMarker {
517
    offsets_byte_len: usize,
518
}
519
520
impl Subtable2ClassTableMarker {
521
0
    pub fn first_glyph_byte_range(&self) -> Range<usize> {
522
0
        let start = 0;
523
0
        start..start + GlyphId16::RAW_BYTE_LEN
524
0
    }
525
526
0
    pub fn n_glyphs_byte_range(&self) -> Range<usize> {
527
0
        let start = self.first_glyph_byte_range().end;
528
0
        start..start + u16::RAW_BYTE_LEN
529
0
    }
530
531
0
    pub fn offsets_byte_range(&self) -> Range<usize> {
532
0
        let start = self.n_glyphs_byte_range().end;
533
0
        start..start + self.offsets_byte_len
534
0
    }
535
}
536
537
impl MinByteRange for Subtable2ClassTableMarker {
538
0
    fn min_byte_range(&self) -> Range<usize> {
539
0
        0..self.offsets_byte_range().end
540
0
    }
541
}
542
543
impl<'a> FontRead<'a> for Subtable2ClassTable<'a> {
544
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
545
0
        let mut cursor = data.cursor();
546
0
        cursor.advance::<GlyphId16>();
547
0
        let n_glyphs: u16 = cursor.read()?;
548
0
        let offsets_byte_len = (n_glyphs as usize)
549
0
            .checked_mul(u16::RAW_BYTE_LEN)
550
0
            .ok_or(ReadError::OutOfBounds)?;
551
0
        cursor.advance_by(offsets_byte_len);
552
0
        cursor.finish(Subtable2ClassTableMarker { offsets_byte_len })
553
0
    }
554
}
555
556
/// Class table for the type 2 `kern` subtable.
557
pub type Subtable2ClassTable<'a> = TableRef<'a, Subtable2ClassTableMarker>;
558
559
#[allow(clippy::needless_lifetimes)]
560
impl<'a> Subtable2ClassTable<'a> {
561
    /// First glyph in class range.
562
0
    pub fn first_glyph(&self) -> GlyphId16 {
563
0
        let range = self.shape.first_glyph_byte_range();
564
0
        self.data.read_at(range.start).unwrap()
565
0
    }
566
567
    /// Number of glyph in class range.
568
0
    pub fn n_glyphs(&self) -> u16 {
569
0
        let range = self.shape.n_glyphs_byte_range();
570
0
        self.data.read_at(range.start).unwrap()
571
0
    }
572
573
    /// The offsets array for all of the glyphs in the range.
574
0
    pub fn offsets(&self) -> &'a [BigEndian<u16>] {
575
0
        let range = self.shape.offsets_byte_range();
576
0
        self.data.read_array(range).unwrap()
577
0
    }
578
}
579
580
#[cfg(feature = "experimental_traverse")]
581
impl<'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)]
597
impl<'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)]
606
pub 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
613
impl Subtable3Marker {
614
0
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
615
0
        let start = 0;
616
0
        start..start + u16::RAW_BYTE_LEN
617
0
    }
618
619
0
    pub fn kern_value_count_byte_range(&self) -> Range<usize> {
620
0
        let start = self.glyph_count_byte_range().end;
621
0
        start..start + u8::RAW_BYTE_LEN
622
0
    }
623
624
0
    pub fn left_class_count_byte_range(&self) -> Range<usize> {
625
0
        let start = self.kern_value_count_byte_range().end;
626
0
        start..start + u8::RAW_BYTE_LEN
627
0
    }
628
629
0
    pub fn right_class_count_byte_range(&self) -> Range<usize> {
630
0
        let start = self.left_class_count_byte_range().end;
631
0
        start..start + u8::RAW_BYTE_LEN
632
0
    }
633
634
0
    pub fn flags_byte_range(&self) -> Range<usize> {
635
0
        let start = self.right_class_count_byte_range().end;
636
0
        start..start + u8::RAW_BYTE_LEN
637
0
    }
638
639
0
    pub fn kern_value_byte_range(&self) -> Range<usize> {
640
0
        let start = self.flags_byte_range().end;
641
0
        start..start + self.kern_value_byte_len
642
0
    }
643
644
0
    pub fn left_class_byte_range(&self) -> Range<usize> {
645
0
        let start = self.kern_value_byte_range().end;
646
0
        start..start + self.left_class_byte_len
647
0
    }
648
649
0
    pub fn right_class_byte_range(&self) -> Range<usize> {
650
0
        let start = self.left_class_byte_range().end;
651
0
        start..start + self.right_class_byte_len
652
0
    }
653
654
0
    pub fn kern_index_byte_range(&self) -> Range<usize> {
655
0
        let start = self.right_class_byte_range().end;
656
0
        start..start + self.kern_index_byte_len
657
0
    }
658
}
659
660
impl MinByteRange for Subtable3Marker {
661
0
    fn min_byte_range(&self) -> Range<usize> {
662
0
        0..self.kern_index_byte_range().end
663
0
    }
664
}
665
666
impl<'a> FontRead<'a> for Subtable3<'a> {
667
0
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
668
0
        let mut cursor = data.cursor();
669
0
        let glyph_count: u16 = cursor.read()?;
670
0
        let kern_value_count: u8 = cursor.read()?;
671
0
        let left_class_count: u8 = cursor.read()?;
672
0
        let right_class_count: u8 = cursor.read()?;
673
0
        cursor.advance::<u8>();
674
0
        let kern_value_byte_len = (kern_value_count as usize)
675
0
            .checked_mul(i16::RAW_BYTE_LEN)
676
0
            .ok_or(ReadError::OutOfBounds)?;
677
0
        cursor.advance_by(kern_value_byte_len);
678
0
        let left_class_byte_len = (glyph_count as usize)
679
0
            .checked_mul(u8::RAW_BYTE_LEN)
680
0
            .ok_or(ReadError::OutOfBounds)?;
681
0
        cursor.advance_by(left_class_byte_len);
682
0
        let right_class_byte_len = (glyph_count as usize)
683
0
            .checked_mul(u8::RAW_BYTE_LEN)
684
0
            .ok_or(ReadError::OutOfBounds)?;
685
0
        cursor.advance_by(right_class_byte_len);
686
0
        let kern_index_byte_len =
687
0
            (transforms::add_multiply(left_class_count, 0_usize, right_class_count))
688
0
                .checked_mul(u8::RAW_BYTE_LEN)
689
0
                .ok_or(ReadError::OutOfBounds)?;
690
0
        cursor.advance_by(kern_index_byte_len);
691
0
        cursor.finish(Subtable3Marker {
692
0
            kern_value_byte_len,
693
0
            left_class_byte_len,
694
0
            right_class_byte_len,
695
0
            kern_index_byte_len,
696
0
        })
697
0
    }
698
}
699
700
/// The type 3 'kern' subtable.
701
pub type Subtable3<'a> = TableRef<'a, Subtable3Marker>;
702
703
#[allow(clippy::needless_lifetimes)]
704
impl<'a> Subtable3<'a> {
705
    /// The number of glyphs in this font.
706
0
    pub fn glyph_count(&self) -> u16 {
707
0
        let range = self.shape.glyph_count_byte_range();
708
0
        self.data.read_at(range.start).unwrap()
709
0
    }
710
711
    /// The number of kerning values.
712
0
    pub fn kern_value_count(&self) -> u8 {
713
0
        let range = self.shape.kern_value_count_byte_range();
714
0
        self.data.read_at(range.start).unwrap()
715
0
    }
716
717
    /// The number of left-hand classes.
718
0
    pub fn left_class_count(&self) -> u8 {
719
0
        let range = self.shape.left_class_count_byte_range();
720
0
        self.data.read_at(range.start).unwrap()
721
0
    }
722
723
    /// The number of right-hand classes.
724
0
    pub fn right_class_count(&self) -> u8 {
725
0
        let range = self.shape.right_class_count_byte_range();
726
0
        self.data.read_at(range.start).unwrap()
727
0
    }
728
729
    /// Set to zero (reserved for future use).
730
0
    pub fn flags(&self) -> u8 {
731
0
        let range = self.shape.flags_byte_range();
732
0
        self.data.read_at(range.start).unwrap()
733
0
    }
734
735
    /// The kerning values.
736
0
    pub fn kern_value(&self) -> &'a [BigEndian<i16>] {
737
0
        let range = self.shape.kern_value_byte_range();
738
0
        self.data.read_array(range).unwrap()
739
0
    }
740
741
    /// The left-hand classes.
742
0
    pub fn left_class(&self) -> &'a [u8] {
743
0
        let range = self.shape.left_class_byte_range();
744
0
        self.data.read_array(range).unwrap()
745
0
    }
746
747
    /// The right-hand classes.
748
0
    pub fn right_class(&self) -> &'a [u8] {
749
0
        let range = self.shape.right_class_byte_range();
750
0
        self.data.read_array(range).unwrap()
751
0
    }
752
753
    /// The indices into the kernValue array.
754
0
    pub fn kern_index(&self) -> &'a [u8] {
755
0
        let range = self.shape.kern_index_byte_range();
756
0
        self.data.read_array(range).unwrap()
757
0
    }
758
}
759
760
#[cfg(feature = "experimental_traverse")]
761
impl<'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)]
783
impl<'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
}