Coverage Report

Created: 2026-08-11 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontations/read-fonts/generated/generated_kerx.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
impl<'a> MinByteRange<'a> for Kerx<'a> {
9
0
    fn min_byte_range(&self) -> Range<usize> {
10
0
        0..self.subtables_byte_range().end
11
0
    }
12
0
    fn min_table_bytes(&self) -> &'a [u8] {
13
0
        let range = self.min_byte_range();
14
0
        self.data.as_bytes().get(range).unwrap_or_default()
15
0
    }
16
}
17
18
impl TopLevelTable for Kerx<'_> {
19
    /// `kerx`
20
    const TAG: Tag = Tag::new(b"kerx");
21
}
22
23
impl ReadArgs for Kerx<'_> {
24
    type Args = ();
25
}
26
27
impl<'a> FontRead<'a> for Kerx<'a> {
28
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29
        #[allow(clippy::absurd_extreme_comparisons)]
30
0
        if data.len() < Self::MIN_SIZE {
31
0
            return Err(ReadError::OutOfBounds);
32
0
        }
33
0
        Ok(Self { data })
34
0
    }
35
}
36
37
/// The [kerx (Extended Kerning)](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html) table.
38
#[derive(Clone)]
39
pub struct Kerx<'a> {
40
    data: FontData<'a>,
41
}
42
43
#[allow(clippy::needless_lifetimes)]
44
impl<'a> Kerx<'a> {
45
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
46
    basic_table_impls!(impl_the_methods);
47
48
    /// The version number of the extended kerning table (currently 2, 3, or 4)
49
0
    pub fn version(&self) -> u16 {
50
0
        let range = self.version_byte_range();
51
0
        self.data.read_at(range.start).ok().unwrap()
52
0
    }
53
54
    /// The number of subtables included in the extended kerning table.
55
0
    pub fn n_tables(&self) -> u32 {
56
0
        let range = self.n_tables_byte_range();
57
0
        self.data.read_at(range.start).ok().unwrap()
58
0
    }
59
60
0
    pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
61
0
        let range = self.subtables_byte_range();
62
0
        self.data
63
0
            .split_off(range.start)
64
0
            .and_then(|d| VarLenArray::read(d).ok())
65
0
            .unwrap_or_default()
66
0
    }
67
68
0
    pub fn version_byte_range(&self) -> Range<usize> {
69
0
        let start = 0;
70
0
        let end = start + u16::RAW_BYTE_LEN;
71
0
        start..end
72
0
    }
73
74
0
    pub fn padding_byte_range(&self) -> Range<usize> {
75
0
        let start = self.version_byte_range().end;
76
0
        let end = start + u16::RAW_BYTE_LEN;
77
0
        start..end
78
0
    }
79
80
0
    pub fn n_tables_byte_range(&self) -> Range<usize> {
81
0
        let start = self.padding_byte_range().end;
82
0
        let end = start + u32::RAW_BYTE_LEN;
83
0
        start..end
84
0
    }
85
86
0
    pub fn subtables_byte_range(&self) -> Range<usize> {
87
0
        let n_tables = self.n_tables();
88
0
        let start = self.n_tables_byte_range().end;
89
0
        let end = start + {
90
0
            let data = self.data.split_off(start).unwrap_or_default();
91
0
            <Subtable as VarSize>::total_len_for_count(data, transforms::to_usize(n_tables))
92
0
                .unwrap_or(0)
93
0
        };
94
0
        start..end
95
0
    }
96
}
97
98
const _: () = assert!(FontData::default_data_long_enough(Kerx::MIN_SIZE));
99
100
impl Default for Kerx<'_> {
101
0
    fn default() -> Self {
102
0
        Self {
103
0
            data: FontData::default_table_data(),
104
0
        }
105
0
    }
106
}
107
108
#[cfg(feature = "experimental_traverse")]
109
impl<'a> SomeTable<'a> for Kerx<'a> {
110
    fn type_name(&self) -> &str {
111
        "Kerx"
112
    }
113
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
114
        match idx {
115
            0usize => Some(Field::new("version", self.version())),
116
            1usize => Some(Field::new("n_tables", self.n_tables())),
117
            2usize => Some(Field::new(
118
                "subtables",
119
                traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
120
            )),
121
            _ => None,
122
        }
123
    }
124
}
125
126
#[cfg(feature = "experimental_traverse")]
127
#[allow(clippy::needless_lifetimes)]
128
impl<'a> std::fmt::Debug for Kerx<'a> {
129
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130
        (self as &dyn SomeTable<'a>).fmt(f)
131
    }
132
}
133
134
impl<'a> MinByteRange<'a> for Subtable<'a> {
135
0
    fn min_byte_range(&self) -> Range<usize> {
136
0
        0..self.data_byte_range().end
137
0
    }
138
0
    fn min_table_bytes(&self) -> &'a [u8] {
139
0
        let range = self.min_byte_range();
140
0
        self.data.as_bytes().get(range).unwrap_or_default()
141
0
    }
142
}
143
144
impl ReadArgs for Subtable<'_> {
145
    type Args = ();
146
}
147
148
impl<'a> FontRead<'a> for Subtable<'a> {
149
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
150
        #[allow(clippy::absurd_extreme_comparisons)]
151
0
        if data.len() < Self::MIN_SIZE {
152
0
            return Err(ReadError::OutOfBounds);
153
0
        }
154
0
        Ok(Self { data })
155
0
    }
156
}
157
158
/// A subtable in a `kerx` table.
159
#[derive(Clone)]
160
pub struct Subtable<'a> {
161
    data: FontData<'a>,
162
}
163
164
#[allow(clippy::needless_lifetimes)]
165
impl<'a> Subtable<'a> {
166
    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
167
    basic_table_impls!(impl_the_methods);
168
169
    /// The length of this subtable in bytes, including this header.
170
0
    pub fn length(&self) -> u32 {
171
0
        let range = self.length_byte_range();
172
0
        self.data.read_at(range.start).ok().unwrap()
173
0
    }
174
175
    /// Circumstances under which this table is used.
176
0
    pub fn coverage(&self) -> u32 {
177
0
        let range = self.coverage_byte_range();
178
0
        self.data.read_at(range.start).ok().unwrap()
179
0
    }
180
181
    /// The tuple count. This value is only used with variation fonts and should be 0 for all other fonts. The subtable's tupleCount will be ignored if the 'kerx' table version is less than 4.
182
0
    pub fn tuple_count(&self) -> u32 {
183
0
        let range = self.tuple_count_byte_range();
184
0
        self.data.read_at(range.start).ok().unwrap()
185
0
    }
186
187
    /// Subtable specific data.
188
0
    pub fn data(&self) -> &'a [u8] {
189
0
        let range = self.data_byte_range();
190
0
        self.data.read_array(range).ok().unwrap_or_default()
191
0
    }
192
193
0
    pub fn length_byte_range(&self) -> Range<usize> {
194
0
        let start = 0;
195
0
        let end = start + u32::RAW_BYTE_LEN;
196
0
        start..end
197
0
    }
198
199
0
    pub fn coverage_byte_range(&self) -> Range<usize> {
200
0
        let start = self.length_byte_range().end;
201
0
        let end = start + u32::RAW_BYTE_LEN;
202
0
        start..end
203
0
    }
204
205
0
    pub fn tuple_count_byte_range(&self) -> Range<usize> {
206
0
        let start = self.coverage_byte_range().end;
207
0
        let end = start + u32::RAW_BYTE_LEN;
208
0
        start..end
209
0
    }
210
211
0
    pub fn data_byte_range(&self) -> Range<usize> {
212
0
        let start = self.tuple_count_byte_range().end;
213
0
        let end =
214
0
            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
215
0
        start..end
216
0
    }
217
}
218
219
const _: () = assert!(FontData::default_data_long_enough(Subtable::MIN_SIZE));
220
221
impl Default for Subtable<'_> {
222
0
    fn default() -> Self {
223
0
        Self {
224
0
            data: FontData::default_table_data(),
225
0
        }
226
0
    }
227
}
228
229
#[cfg(feature = "experimental_traverse")]
230
impl<'a> SomeTable<'a> for Subtable<'a> {
231
    fn type_name(&self) -> &str {
232
        "Subtable"
233
    }
234
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
235
        match idx {
236
            0usize => Some(Field::new("length", self.length())),
237
            1usize => Some(Field::new("coverage", self.coverage())),
238
            2usize => Some(Field::new("tuple_count", self.tuple_count())),
239
            3usize => Some(Field::new("data", self.data())),
240
            _ => None,
241
        }
242
    }
243
}
244
245
#[cfg(feature = "experimental_traverse")]
246
#[allow(clippy::needless_lifetimes)]
247
impl<'a> std::fmt::Debug for Subtable<'a> {
248
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249
        (self as &dyn SomeTable<'a>).fmt(f)
250
    }
251
}
252
253
impl<'a> MinByteRange<'a> for Subtable0<'a> {
254
0
    fn min_byte_range(&self) -> Range<usize> {
255
0
        0..self.pairs_byte_range().end
256
0
    }
257
0
    fn min_table_bytes(&self) -> &'a [u8] {
258
0
        let range = self.min_byte_range();
259
0
        self.data.as_bytes().get(range).unwrap_or_default()
260
0
    }
261
}
262
263
impl ReadArgs for Subtable0<'_> {
264
    type Args = ();
265
}
266
267
impl<'a> FontRead<'a> for Subtable0<'a> {
268
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
269
        #[allow(clippy::absurd_extreme_comparisons)]
270
0
        if data.len() < Self::MIN_SIZE {
271
0
            return Err(ReadError::OutOfBounds);
272
0
        }
273
0
        Ok(Self { data })
274
0
    }
275
}
276
277
/// The type 0 `kerx` subtable.
278
#[derive(Clone)]
279
pub struct Subtable0<'a> {
280
    data: FontData<'a>,
281
}
282
283
#[allow(clippy::needless_lifetimes)]
284
impl<'a> Subtable0<'a> {
285
    pub const MIN_SIZE: usize =
286
        (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
287
    basic_table_impls!(impl_the_methods);
288
289
    /// The number of kerning pairs in this subtable.
290
0
    pub fn n_pairs(&self) -> u32 {
291
0
        let range = self.n_pairs_byte_range();
292
0
        self.data.read_at(range.start).ok().unwrap()
293
0
    }
294
295
    /// 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.
296
0
    pub fn search_range(&self) -> u32 {
297
0
        let range = self.search_range_byte_range();
298
0
        self.data.read_at(range.start).ok().unwrap()
299
0
    }
300
301
    /// 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.
302
0
    pub fn entry_selector(&self) -> u32 {
303
0
        let range = self.entry_selector_byte_range();
304
0
        self.data.read_at(range.start).ok().unwrap()
305
0
    }
306
307
    /// 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.
308
0
    pub fn range_shift(&self) -> u32 {
309
0
        let range = self.range_shift_byte_range();
310
0
        self.data.read_at(range.start).ok().unwrap()
311
0
    }
312
313
    /// Kerning records.
314
0
    pub fn pairs(&self) -> &'a [Subtable0Pair] {
315
0
        let range = self.pairs_byte_range();
316
0
        self.data.read_array(range).ok().unwrap_or_default()
317
0
    }
318
319
0
    pub fn n_pairs_byte_range(&self) -> Range<usize> {
320
0
        let start = 0;
321
0
        let end = start + u32::RAW_BYTE_LEN;
322
0
        start..end
323
0
    }
324
325
0
    pub fn search_range_byte_range(&self) -> Range<usize> {
326
0
        let start = self.n_pairs_byte_range().end;
327
0
        let end = start + u32::RAW_BYTE_LEN;
328
0
        start..end
329
0
    }
330
331
0
    pub fn entry_selector_byte_range(&self) -> Range<usize> {
332
0
        let start = self.search_range_byte_range().end;
333
0
        let end = start + u32::RAW_BYTE_LEN;
334
0
        start..end
335
0
    }
336
337
0
    pub fn range_shift_byte_range(&self) -> Range<usize> {
338
0
        let start = self.entry_selector_byte_range().end;
339
0
        let end = start + u32::RAW_BYTE_LEN;
340
0
        start..end
341
0
    }
342
343
0
    pub fn pairs_byte_range(&self) -> Range<usize> {
344
0
        let n_pairs = self.n_pairs();
345
0
        let start = self.range_shift_byte_range().end;
346
0
        let end =
347
0
            start + (transforms::to_usize(n_pairs)).saturating_mul(Subtable0Pair::RAW_BYTE_LEN);
348
0
        start..end
349
0
    }
350
}
351
352
const _: () = assert!(FontData::default_data_long_enough(Subtable0::MIN_SIZE));
353
354
impl Default for Subtable0<'_> {
355
0
    fn default() -> Self {
356
0
        Self {
357
0
            data: FontData::default_table_data(),
358
0
        }
359
0
    }
360
}
361
362
#[cfg(feature = "experimental_traverse")]
363
impl<'a> SomeTable<'a> for Subtable0<'a> {
364
    fn type_name(&self) -> &str {
365
        "Subtable0"
366
    }
367
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
368
        match idx {
369
            0usize => Some(Field::new("n_pairs", self.n_pairs())),
370
            1usize => Some(Field::new("search_range", self.search_range())),
371
            2usize => Some(Field::new("entry_selector", self.entry_selector())),
372
            3usize => Some(Field::new("range_shift", self.range_shift())),
373
            4usize => Some(Field::new(
374
                "pairs",
375
                traversal::FieldType::array_of_records(
376
                    stringify!(Subtable0Pair),
377
                    self.pairs(),
378
                    self.offset_data(),
379
                ),
380
            )),
381
            _ => None,
382
        }
383
    }
384
}
385
386
#[cfg(feature = "experimental_traverse")]
387
#[allow(clippy::needless_lifetimes)]
388
impl<'a> std::fmt::Debug for Subtable0<'a> {
389
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
390
        (self as &dyn SomeTable<'a>).fmt(f)
391
    }
392
}
393
394
/// The type 0 `kerx` subtable kerning record.
395
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
396
#[repr(C)]
397
#[repr(packed)]
398
pub struct Subtable0Pair {
399
    /// The glyph index for the lefthand glyph in the kerning pair.
400
    pub left: BigEndian<GlyphId16>,
401
    /// The glyph index for the righthand glyph in the kerning pair.
402
    pub right: BigEndian<GlyphId16>,
403
    /// Kerning value.
404
    pub value: BigEndian<i16>,
405
}
406
407
impl Subtable0Pair {
408
    /// The glyph index for the lefthand glyph in the kerning pair.
409
0
    pub fn left(&self) -> GlyphId16 {
410
0
        self.left.get()
411
0
    }
412
413
    /// The glyph index for the righthand glyph in the kerning pair.
414
0
    pub fn right(&self) -> GlyphId16 {
415
0
        self.right.get()
416
0
    }
417
418
    /// Kerning value.
419
0
    pub fn value(&self) -> i16 {
420
0
        self.value.get()
421
0
    }
422
}
423
424
impl FixedSize for Subtable0Pair {
425
    const RAW_BYTE_LEN: usize =
426
        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN;
427
}
428
429
#[cfg(feature = "experimental_traverse")]
430
impl<'a> SomeRecord<'a> for Subtable0Pair {
431
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
432
        RecordResolver {
433
            name: "Subtable0Pair",
434
            get_field: Box::new(move |idx, _data| match idx {
435
                0usize => Some(Field::new("left", self.left())),
436
                1usize => Some(Field::new("right", self.right())),
437
                2usize => Some(Field::new("value", self.value())),
438
                _ => None,
439
            }),
440
            data,
441
        }
442
    }
443
}