Coverage Report

Created: 2026-10-24 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/read-fonts-0.46.0/generated/generated_aat.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
/// Lookup tables provide a way of looking up information about a glyph index.
9
/// The different cmap subtable formats.
10
#[derive(Clone)]
11
pub enum Lookup<'a> {
12
    Format0(Lookup0<'a>),
13
    Format2(Lookup2<'a>),
14
    Format4(Lookup4<'a>),
15
    Format6(Lookup6<'a>),
16
    Format8(Lookup8<'a>),
17
    Format10(Lookup10<'a>),
18
}
19
20
impl Default for Lookup<'_> {
21
0
    fn default() -> Self {
22
0
        Self::Format0(Default::default())
23
0
    }
24
}
25
26
impl<'a> Lookup<'a> {
27
    ///Return the `FontData` used to resolve offsets for this table.
28
0
    pub fn offset_data(&self) -> FontData<'a> {
29
0
        match self {
30
0
            Self::Format0(item) => item.offset_data(),
31
0
            Self::Format2(item) => item.offset_data(),
32
0
            Self::Format4(item) => item.offset_data(),
33
0
            Self::Format6(item) => item.offset_data(),
34
0
            Self::Format8(item) => item.offset_data(),
35
0
            Self::Format10(item) => item.offset_data(),
36
        }
37
0
    }
38
39
    /// Format number is set to 0.
40
0
    pub fn format(&self) -> u16 {
41
0
        match self {
42
0
            Self::Format0(item) => item.format(),
43
0
            Self::Format2(item) => item.format(),
44
0
            Self::Format4(item) => item.format(),
45
0
            Self::Format6(item) => item.format(),
46
0
            Self::Format8(item) => item.format(),
47
0
            Self::Format10(item) => item.format(),
48
        }
49
0
    }
50
}
51
52
impl ReadArgs for Lookup<'_> {
53
    type Args = ();
54
}
55
56
impl<'a> FontRead<'a> for Lookup<'a> {
57
    #[inline]
58
9.91M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
59
9.91M
        let format: u16 = data.read_at(0usize)?;
60
9.48M
        match format {
61
2.23M
            Lookup0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
62
1.29M
            Lookup2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
63
1.29M
            Lookup4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
64
1.72M
            Lookup6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
65
1.29M
            Lookup8::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
66
717k
            Lookup10::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
67
938k
            other => Err(ReadError::InvalidFormat(other.into())),
68
        }
69
9.91M
    }
70
}
71
72
impl<'a> MinByteRange<'a> for Lookup<'a> {
73
0
    fn min_byte_range(&self) -> Range<usize> {
74
0
        match self {
75
0
            Self::Format0(item) => item.min_byte_range(),
76
0
            Self::Format2(item) => item.min_byte_range(),
77
0
            Self::Format4(item) => item.min_byte_range(),
78
0
            Self::Format6(item) => item.min_byte_range(),
79
0
            Self::Format8(item) => item.min_byte_range(),
80
0
            Self::Format10(item) => item.min_byte_range(),
81
        }
82
0
    }
83
0
    fn min_table_bytes(&self) -> &'a [u8] {
84
0
        match self {
85
0
            Self::Format0(item) => item.min_table_bytes(),
86
0
            Self::Format2(item) => item.min_table_bytes(),
87
0
            Self::Format4(item) => item.min_table_bytes(),
88
0
            Self::Format6(item) => item.min_table_bytes(),
89
0
            Self::Format8(item) => item.min_table_bytes(),
90
0
            Self::Format10(item) => item.min_table_bytes(),
91
        }
92
0
    }
93
}
94
95
impl Format<u16> for Lookup0<'_> {
96
    const FORMAT: u16 = 0;
97
}
98
99
impl<'a> MinByteRange<'a> for Lookup0<'a> {
100
0
    fn min_byte_range(&self) -> Range<usize> {
101
0
        0..self.values_data_byte_range().end
102
0
    }
103
0
    fn min_table_bytes(&self) -> &'a [u8] {
104
0
        let range = self.min_byte_range();
105
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
106
0
    }
107
}
108
109
impl ReadArgs for Lookup0<'_> {
110
    type Args = ();
111
}
112
113
impl<'a> FontRead<'a> for Lookup0<'a> {
114
2.23M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
115
        #[allow(clippy::absurd_extreme_comparisons)]
116
2.23M
        if data.len() < Self::MIN_SIZE {
117
0
            return Err(ReadError::OutOfBounds);
118
2.23M
        }
119
2.23M
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
120
0
            return Err(ReadError::OutOfBounds);
121
        };
122
2.23M
        Ok(Self { data })
123
2.23M
    }
124
}
125
126
/// The fields at the start of the table, which are read directly.
127
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
128
#[repr(C, packed)]
129
#[doc(hidden)]
130
pub struct Lookup0FixedHeader {
131
    pub format: BigEndian<u16>,
132
}
133
134
#[allow(clippy::absurd_extreme_comparisons)]
135
const _: () = assert!(std::mem::size_of::<Lookup0FixedHeader>() <= Lookup0::MIN_SIZE);
136
137
/// Simple array format. The lookup data is an array of lookup values, indexed
138
/// by glyph index.
139
#[derive(Clone)]
140
pub struct Lookup0<'a> {
141
    data: TableDataRef<'a, Lookup0FixedHeader>,
142
}
143
144
#[allow(clippy::needless_lifetimes)]
145
impl<'a> Lookup0<'a> {
146
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
147
    basic_table_impls!(impl_the_methods);
148
149
    /// Format number is set to 0.
150
0
    pub fn format(&self) -> u16 {
151
0
        self.data.header().format.get()
152
0
    }
153
154
    /// Values, indexed by glyph index.
155
2.23M
    pub fn values_data(&self) -> &'a [u8] {
156
2.23M
        let range = self.values_data_byte_range();
157
2.23M
        self.offset_data()
158
2.23M
            .read_array(range)
159
2.23M
            .ok()
160
2.23M
            .unwrap_or_default()
161
2.23M
    }
162
163
2.23M
    pub fn format_byte_range(&self) -> Range<usize> {
164
2.23M
        let start = 0;
165
2.23M
        let end = start + u16::RAW_BYTE_LEN;
166
2.23M
        start..end
167
2.23M
    }
168
169
2.23M
    pub fn values_data_byte_range(&self) -> Range<usize> {
170
2.23M
        let start = self.format_byte_range().end;
171
2.23M
        let end = start
172
2.23M
            + self.offset_data().len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
173
2.23M
        start..end
174
2.23M
    }
175
}
176
177
const _: () = assert!(FontData::default_data_long_enough(Lookup0::MIN_SIZE));
178
179
impl Default for Lookup0<'_> {
180
0
    fn default() -> Self {
181
        Self {
182
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
183
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
184
        }
185
0
    }
186
}
187
188
impl Format<u16> for Lookup2<'_> {
189
    const FORMAT: u16 = 2;
190
}
191
192
impl<'a> MinByteRange<'a> for Lookup2<'a> {
193
0
    fn min_byte_range(&self) -> Range<usize> {
194
0
        0..self.segments_data_byte_range().end
195
0
    }
196
0
    fn min_table_bytes(&self) -> &'a [u8] {
197
0
        let range = self.min_byte_range();
198
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
199
0
    }
200
}
201
202
impl ReadArgs for Lookup2<'_> {
203
    type Args = ();
204
}
205
206
impl<'a> FontRead<'a> for Lookup2<'a> {
207
1.29M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
208
        #[allow(clippy::absurd_extreme_comparisons)]
209
1.29M
        if data.len() < Self::MIN_SIZE {
210
286k
            return Err(ReadError::OutOfBounds);
211
1.00M
        }
212
1.00M
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
213
0
            return Err(ReadError::OutOfBounds);
214
        };
215
1.00M
        Ok(Self { data })
216
1.29M
    }
217
}
218
219
/// The fields at the start of the table, which are read directly.
220
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
221
#[repr(C, packed)]
222
#[doc(hidden)]
223
pub struct Lookup2FixedHeader {
224
    pub format: BigEndian<u16>,
225
    pub unit_size: BigEndian<u16>,
226
    pub n_units: BigEndian<u16>,
227
    pub search_range: BigEndian<u16>,
228
    pub entry_selector: BigEndian<u16>,
229
    pub range_shift: BigEndian<u16>,
230
}
231
232
#[allow(clippy::absurd_extreme_comparisons)]
233
const _: () = assert!(std::mem::size_of::<Lookup2FixedHeader>() <= Lookup2::MIN_SIZE);
234
235
/// Segment single format. Each non-overlapping segment has a single lookup
236
/// value that applies to all glyphs in the segment. A segment is defined as
237
/// a contiguous range of glyph indexes.
238
#[derive(Clone)]
239
pub struct Lookup2<'a> {
240
    data: TableDataRef<'a, Lookup2FixedHeader>,
241
}
242
243
#[allow(clippy::needless_lifetimes)]
244
impl<'a> Lookup2<'a> {
245
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
246
        + u16::RAW_BYTE_LEN
247
        + u16::RAW_BYTE_LEN
248
        + u16::RAW_BYTE_LEN
249
        + u16::RAW_BYTE_LEN
250
        + u16::RAW_BYTE_LEN);
251
    basic_table_impls!(impl_the_methods);
252
253
    /// Format number is set to 2.
254
0
    pub fn format(&self) -> u16 {
255
0
        self.data.header().format.get()
256
0
    }
257
258
    /// Size of a lookup unit for this search in bytes.
259
1.57M
    pub fn unit_size(&self) -> u16 {
260
1.57M
        self.data.header().unit_size.get()
261
1.57M
    }
262
263
    /// Number of units of the preceding size to be searched.
264
3.15M
    pub fn n_units(&self) -> u16 {
265
3.15M
        self.data.header().n_units.get()
266
3.15M
    }
267
268
    /// The value of unitSize times the largest power of 2 that is less than or equal to the value of nUnits.
269
0
    pub fn search_range(&self) -> u16 {
270
0
        self.data.header().search_range.get()
271
0
    }
272
273
    /// The log base 2 of the largest power of 2 less than or equal to the value of nUnits.
274
0
    pub fn entry_selector(&self) -> u16 {
275
0
        self.data.header().entry_selector.get()
276
0
    }
277
278
    /// The value of unitSize times the difference of the value of nUnits minus the largest power of 2 less than or equal to the value of nUnits.
279
0
    pub fn range_shift(&self) -> u16 {
280
0
        self.data.header().range_shift.get()
281
0
    }
282
283
    /// Segments.
284
1.57M
    pub fn segments_data(&self) -> &'a [u8] {
285
1.57M
        let range = self.segments_data_byte_range();
286
1.57M
        self.offset_data()
287
1.57M
            .read_array(range)
288
1.57M
            .ok()
289
1.57M
            .unwrap_or_default()
290
1.57M
    }
291
292
1.57M
    pub fn format_byte_range(&self) -> Range<usize> {
293
1.57M
        let start = 0;
294
1.57M
        let end = start + u16::RAW_BYTE_LEN;
295
1.57M
        start..end
296
1.57M
    }
297
298
1.57M
    pub fn unit_size_byte_range(&self) -> Range<usize> {
299
1.57M
        let start = self.format_byte_range().end;
300
1.57M
        let end = start + u16::RAW_BYTE_LEN;
301
1.57M
        start..end
302
1.57M
    }
303
304
1.57M
    pub fn n_units_byte_range(&self) -> Range<usize> {
305
1.57M
        let start = self.unit_size_byte_range().end;
306
1.57M
        let end = start + u16::RAW_BYTE_LEN;
307
1.57M
        start..end
308
1.57M
    }
309
310
1.57M
    pub fn search_range_byte_range(&self) -> Range<usize> {
311
1.57M
        let start = self.n_units_byte_range().end;
312
1.57M
        let end = start + u16::RAW_BYTE_LEN;
313
1.57M
        start..end
314
1.57M
    }
315
316
1.57M
    pub fn entry_selector_byte_range(&self) -> Range<usize> {
317
1.57M
        let start = self.search_range_byte_range().end;
318
1.57M
        let end = start + u16::RAW_BYTE_LEN;
319
1.57M
        start..end
320
1.57M
    }
321
322
1.57M
    pub fn range_shift_byte_range(&self) -> Range<usize> {
323
1.57M
        let start = self.entry_selector_byte_range().end;
324
1.57M
        let end = start + u16::RAW_BYTE_LEN;
325
1.57M
        start..end
326
1.57M
    }
327
328
1.57M
    pub fn segments_data_byte_range(&self) -> Range<usize> {
329
1.57M
        let unit_size = self.unit_size();
330
1.57M
        let n_units = self.n_units();
331
1.57M
        let start = self.range_shift_byte_range().end;
332
1.57M
        let end = start
333
1.57M
            + (transforms::add_multiply(unit_size, 0_usize, n_units))
334
1.57M
                .saturating_mul(u8::RAW_BYTE_LEN);
335
1.57M
        start..end
336
1.57M
    }
337
}
338
339
impl Format<u16> for Lookup4<'_> {
340
    const FORMAT: u16 = 4;
341
}
342
343
impl<'a> MinByteRange<'a> for Lookup4<'a> {
344
0
    fn min_byte_range(&self) -> Range<usize> {
345
0
        0..self.segments_byte_range().end
346
0
    }
347
0
    fn min_table_bytes(&self) -> &'a [u8] {
348
0
        let range = self.min_byte_range();
349
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
350
0
    }
351
}
352
353
impl ReadArgs for Lookup4<'_> {
354
    type Args = ();
355
}
356
357
impl<'a> FontRead<'a> for Lookup4<'a> {
358
1.29M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
359
        #[allow(clippy::absurd_extreme_comparisons)]
360
1.29M
        if data.len() < Self::MIN_SIZE {
361
573k
            return Err(ReadError::OutOfBounds);
362
718k
        }
363
718k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
364
0
            return Err(ReadError::OutOfBounds);
365
        };
366
718k
        Ok(Self { data })
367
1.29M
    }
368
}
369
370
/// The fields at the start of the table, which are read directly.
371
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
372
#[repr(C, packed)]
373
#[doc(hidden)]
374
pub struct Lookup4FixedHeader {
375
    pub format: BigEndian<u16>,
376
    pub unit_size: BigEndian<u16>,
377
    pub n_units: BigEndian<u16>,
378
    pub search_range: BigEndian<u16>,
379
    pub entry_selector: BigEndian<u16>,
380
    pub range_shift: BigEndian<u16>,
381
}
382
383
#[allow(clippy::absurd_extreme_comparisons)]
384
const _: () = assert!(std::mem::size_of::<Lookup4FixedHeader>() <= Lookup4::MIN_SIZE);
385
386
/// Segment array format. A segment mapping is performed (as with Format 2),
387
/// but instead of a single lookup value for all the glyphs in the segment,
388
/// each glyph in the segment gets its own separate lookup value.
389
#[derive(Clone)]
390
pub struct Lookup4<'a> {
391
    data: TableDataRef<'a, Lookup4FixedHeader>,
392
}
393
394
#[allow(clippy::needless_lifetimes)]
395
impl<'a> Lookup4<'a> {
396
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
397
        + u16::RAW_BYTE_LEN
398
        + u16::RAW_BYTE_LEN
399
        + u16::RAW_BYTE_LEN
400
        + u16::RAW_BYTE_LEN
401
        + u16::RAW_BYTE_LEN);
402
    basic_table_impls!(impl_the_methods);
403
404
    /// Format number is set to 4.
405
0
    pub fn format(&self) -> u16 {
406
0
        self.data.header().format.get()
407
0
    }
408
409
    /// Size of a lookup unit for this search in bytes.
410
0
    pub fn unit_size(&self) -> u16 {
411
0
        self.data.header().unit_size.get()
412
0
    }
413
414
    /// Number of units of the preceding size to be searched.
415
729k
    pub fn n_units(&self) -> u16 {
416
729k
        self.data.header().n_units.get()
417
729k
    }
418
419
    /// The value of unitSize times the largest power of 2 that is less than or equal to the value of nUnits.
420
0
    pub fn search_range(&self) -> u16 {
421
0
        self.data.header().search_range.get()
422
0
    }
423
424
    /// The log base 2 of the largest power of 2 less than or equal to the value of nUnits.
425
0
    pub fn entry_selector(&self) -> u16 {
426
0
        self.data.header().entry_selector.get()
427
0
    }
428
429
    /// The value of unitSize times the difference of the value of nUnits minus the largest power of 2 less than or equal to the value of nUnits.
430
0
    pub fn range_shift(&self) -> u16 {
431
0
        self.data.header().range_shift.get()
432
0
    }
433
434
    /// Segments.
435
729k
    pub fn segments(&self) -> &'a [LookupSegment4] {
436
729k
        let range = self.segments_byte_range();
437
729k
        self.offset_data()
438
729k
            .read_array(range)
439
729k
            .ok()
440
729k
            .unwrap_or_default()
441
729k
    }
442
443
729k
    pub fn format_byte_range(&self) -> Range<usize> {
444
729k
        let start = 0;
445
729k
        let end = start + u16::RAW_BYTE_LEN;
446
729k
        start..end
447
729k
    }
448
449
729k
    pub fn unit_size_byte_range(&self) -> Range<usize> {
450
729k
        let start = self.format_byte_range().end;
451
729k
        let end = start + u16::RAW_BYTE_LEN;
452
729k
        start..end
453
729k
    }
454
455
729k
    pub fn n_units_byte_range(&self) -> Range<usize> {
456
729k
        let start = self.unit_size_byte_range().end;
457
729k
        let end = start + u16::RAW_BYTE_LEN;
458
729k
        start..end
459
729k
    }
460
461
729k
    pub fn search_range_byte_range(&self) -> Range<usize> {
462
729k
        let start = self.n_units_byte_range().end;
463
729k
        let end = start + u16::RAW_BYTE_LEN;
464
729k
        start..end
465
729k
    }
466
467
729k
    pub fn entry_selector_byte_range(&self) -> Range<usize> {
468
729k
        let start = self.search_range_byte_range().end;
469
729k
        let end = start + u16::RAW_BYTE_LEN;
470
729k
        start..end
471
729k
    }
472
473
729k
    pub fn range_shift_byte_range(&self) -> Range<usize> {
474
729k
        let start = self.entry_selector_byte_range().end;
475
729k
        let end = start + u16::RAW_BYTE_LEN;
476
729k
        start..end
477
729k
    }
478
479
729k
    pub fn segments_byte_range(&self) -> Range<usize> {
480
729k
        let n_units = self.n_units();
481
729k
        let start = self.range_shift_byte_range().end;
482
729k
        let end =
483
729k
            start + (transforms::to_usize(n_units)).saturating_mul(LookupSegment4::RAW_BYTE_LEN);
484
729k
        start..end
485
729k
    }
486
}
487
488
/// Lookup segment for format 4.
489
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
490
#[repr(C)]
491
#[repr(packed)]
492
pub struct LookupSegment4 {
493
    /// Last glyph index in this segment.
494
    pub last_glyph: BigEndian<u16>,
495
    /// First glyph index in this segment.
496
    pub first_glyph: BigEndian<u16>,
497
    /// A 16-bit offset from the start of the table to the data.
498
    pub value_offset: BigEndian<u16>,
499
}
500
501
impl LookupSegment4 {
502
    /// Last glyph index in this segment.
503
0
    pub fn last_glyph(&self) -> u16 {
504
0
        self.last_glyph.get()
505
0
    }
506
507
    /// First glyph index in this segment.
508
7.45k
    pub fn first_glyph(&self) -> u16 {
509
7.45k
        self.first_glyph.get()
510
7.45k
    }
511
512
    /// A 16-bit offset from the start of the table to the data.
513
9.58k
    pub fn value_offset(&self) -> u16 {
514
9.58k
        self.value_offset.get()
515
9.58k
    }
516
}
517
518
impl FixedSize for LookupSegment4 {
519
    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
520
}
521
522
impl Format<u16> for Lookup6<'_> {
523
    const FORMAT: u16 = 6;
524
}
525
526
impl<'a> MinByteRange<'a> for Lookup6<'a> {
527
0
    fn min_byte_range(&self) -> Range<usize> {
528
0
        0..self.entries_data_byte_range().end
529
0
    }
530
0
    fn min_table_bytes(&self) -> &'a [u8] {
531
0
        let range = self.min_byte_range();
532
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
533
0
    }
534
}
535
536
impl ReadArgs for Lookup6<'_> {
537
    type Args = ();
538
}
539
540
impl<'a> FontRead<'a> for Lookup6<'a> {
541
1.72M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
542
        #[allow(clippy::absurd_extreme_comparisons)]
543
1.72M
        if data.len() < Self::MIN_SIZE {
544
573k
            return Err(ReadError::OutOfBounds);
545
1.14M
        }
546
1.14M
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
547
0
            return Err(ReadError::OutOfBounds);
548
        };
549
1.14M
        Ok(Self { data })
550
1.72M
    }
551
}
552
553
/// The fields at the start of the table, which are read directly.
554
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
555
#[repr(C, packed)]
556
#[doc(hidden)]
557
pub struct Lookup6FixedHeader {
558
    pub format: BigEndian<u16>,
559
    pub unit_size: BigEndian<u16>,
560
    pub n_units: BigEndian<u16>,
561
    pub search_range: BigEndian<u16>,
562
    pub entry_selector: BigEndian<u16>,
563
    pub range_shift: BigEndian<u16>,
564
}
565
566
#[allow(clippy::absurd_extreme_comparisons)]
567
const _: () = assert!(std::mem::size_of::<Lookup6FixedHeader>() <= Lookup6::MIN_SIZE);
568
569
/// Single table format. The lookup data is a sorted list of
570
/// <glyph index,lookup value> pairs.
571
#[derive(Clone)]
572
pub struct Lookup6<'a> {
573
    data: TableDataRef<'a, Lookup6FixedHeader>,
574
}
575
576
#[allow(clippy::needless_lifetimes)]
577
impl<'a> Lookup6<'a> {
578
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
579
        + u16::RAW_BYTE_LEN
580
        + u16::RAW_BYTE_LEN
581
        + u16::RAW_BYTE_LEN
582
        + u16::RAW_BYTE_LEN
583
        + u16::RAW_BYTE_LEN);
584
    basic_table_impls!(impl_the_methods);
585
586
    /// Format number is set to 6.
587
0
    pub fn format(&self) -> u16 {
588
0
        self.data.header().format.get()
589
0
    }
590
591
    /// Size of a lookup unit for this search in bytes.
592
1.14M
    pub fn unit_size(&self) -> u16 {
593
1.14M
        self.data.header().unit_size.get()
594
1.14M
    }
595
596
    /// Number of units of the preceding size to be searched.
597
2.29M
    pub fn n_units(&self) -> u16 {
598
2.29M
        self.data.header().n_units.get()
599
2.29M
    }
600
601
    /// The value of unitSize times the largest power of 2 that is less than or equal to the value of nUnits.
602
0
    pub fn search_range(&self) -> u16 {
603
0
        self.data.header().search_range.get()
604
0
    }
605
606
    /// The log base 2 of the largest power of 2 less than or equal to the value of nUnits.
607
0
    pub fn entry_selector(&self) -> u16 {
608
0
        self.data.header().entry_selector.get()
609
0
    }
610
611
    /// The value of unitSize times the difference of the value of nUnits minus the largest power of 2 less than or equal to the value of nUnits.
612
0
    pub fn range_shift(&self) -> u16 {
613
0
        self.data.header().range_shift.get()
614
0
    }
615
616
    /// Values, indexed by glyph index.
617
1.14M
    pub fn entries_data(&self) -> &'a [u8] {
618
1.14M
        let range = self.entries_data_byte_range();
619
1.14M
        self.offset_data()
620
1.14M
            .read_array(range)
621
1.14M
            .ok()
622
1.14M
            .unwrap_or_default()
623
1.14M
    }
624
625
1.14M
    pub fn format_byte_range(&self) -> Range<usize> {
626
1.14M
        let start = 0;
627
1.14M
        let end = start + u16::RAW_BYTE_LEN;
628
1.14M
        start..end
629
1.14M
    }
630
631
1.14M
    pub fn unit_size_byte_range(&self) -> Range<usize> {
632
1.14M
        let start = self.format_byte_range().end;
633
1.14M
        let end = start + u16::RAW_BYTE_LEN;
634
1.14M
        start..end
635
1.14M
    }
636
637
1.14M
    pub fn n_units_byte_range(&self) -> Range<usize> {
638
1.14M
        let start = self.unit_size_byte_range().end;
639
1.14M
        let end = start + u16::RAW_BYTE_LEN;
640
1.14M
        start..end
641
1.14M
    }
642
643
1.14M
    pub fn search_range_byte_range(&self) -> Range<usize> {
644
1.14M
        let start = self.n_units_byte_range().end;
645
1.14M
        let end = start + u16::RAW_BYTE_LEN;
646
1.14M
        start..end
647
1.14M
    }
648
649
1.14M
    pub fn entry_selector_byte_range(&self) -> Range<usize> {
650
1.14M
        let start = self.search_range_byte_range().end;
651
1.14M
        let end = start + u16::RAW_BYTE_LEN;
652
1.14M
        start..end
653
1.14M
    }
654
655
1.14M
    pub fn range_shift_byte_range(&self) -> Range<usize> {
656
1.14M
        let start = self.entry_selector_byte_range().end;
657
1.14M
        let end = start + u16::RAW_BYTE_LEN;
658
1.14M
        start..end
659
1.14M
    }
660
661
1.14M
    pub fn entries_data_byte_range(&self) -> Range<usize> {
662
1.14M
        let unit_size = self.unit_size();
663
1.14M
        let n_units = self.n_units();
664
1.14M
        let start = self.range_shift_byte_range().end;
665
1.14M
        let end = start
666
1.14M
            + (transforms::add_multiply(unit_size, 0_usize, n_units))
667
1.14M
                .saturating_mul(u8::RAW_BYTE_LEN);
668
1.14M
        start..end
669
1.14M
    }
670
}
671
672
impl Format<u16> for Lookup8<'_> {
673
    const FORMAT: u16 = 8;
674
}
675
676
impl<'a> MinByteRange<'a> for Lookup8<'a> {
677
0
    fn min_byte_range(&self) -> Range<usize> {
678
0
        0..self.value_array_byte_range().end
679
0
    }
680
0
    fn min_table_bytes(&self) -> &'a [u8] {
681
0
        let range = self.min_byte_range();
682
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
683
0
    }
684
}
685
686
impl ReadArgs for Lookup8<'_> {
687
    type Args = ();
688
}
689
690
impl<'a> FontRead<'a> for Lookup8<'a> {
691
1.29M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
692
        #[allow(clippy::absurd_extreme_comparisons)]
693
1.29M
        if data.len() < Self::MIN_SIZE {
694
573k
            return Err(ReadError::OutOfBounds);
695
718k
        }
696
718k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
697
0
            return Err(ReadError::OutOfBounds);
698
        };
699
718k
        Ok(Self { data })
700
1.29M
    }
701
}
702
703
/// The fields at the start of the table, which are read directly.
704
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
705
#[repr(C, packed)]
706
#[doc(hidden)]
707
pub struct Lookup8FixedHeader {
708
    pub format: BigEndian<u16>,
709
    pub first_glyph: BigEndian<u16>,
710
    pub glyph_count: BigEndian<u16>,
711
}
712
713
#[allow(clippy::absurd_extreme_comparisons)]
714
const _: () = assert!(std::mem::size_of::<Lookup8FixedHeader>() <= Lookup8::MIN_SIZE);
715
716
/// Trimmed array format. The lookup data is a simple trimmed array
717
/// indexed by glyph index.
718
#[derive(Clone)]
719
pub struct Lookup8<'a> {
720
    data: TableDataRef<'a, Lookup8FixedHeader>,
721
}
722
723
#[allow(clippy::needless_lifetimes)]
724
impl<'a> Lookup8<'a> {
725
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
726
    basic_table_impls!(impl_the_methods);
727
728
    /// Format number is set to 8.
729
0
    pub fn format(&self) -> u16 {
730
0
        self.data.header().format.get()
731
0
    }
732
733
    /// First glyph index included in the trimmed array.
734
737k
    pub fn first_glyph(&self) -> u16 {
735
737k
        self.data.header().first_glyph.get()
736
737k
    }
737
738
    /// Total number of glyphs (equivalent to the last glyph minus the value
739
    /// of firstGlyph plus 1).
740
20.2k
    pub fn glyph_count(&self) -> u16 {
741
20.2k
        self.data.header().glyph_count.get()
742
20.2k
    }
743
744
    /// The lookup values (indexed by the glyph index minus the value of
745
    /// firstGlyph). Entries in the value array must be two bytes.
746
20.2k
    pub fn value_array(&self) -> &'a [BigEndian<u16>] {
747
20.2k
        let range = self.value_array_byte_range();
748
20.2k
        self.offset_data()
749
20.2k
            .read_array(range)
750
20.2k
            .ok()
751
20.2k
            .unwrap_or_default()
752
20.2k
    }
753
754
20.2k
    pub fn format_byte_range(&self) -> Range<usize> {
755
20.2k
        let start = 0;
756
20.2k
        let end = start + u16::RAW_BYTE_LEN;
757
20.2k
        start..end
758
20.2k
    }
759
760
20.2k
    pub fn first_glyph_byte_range(&self) -> Range<usize> {
761
20.2k
        let start = self.format_byte_range().end;
762
20.2k
        let end = start + u16::RAW_BYTE_LEN;
763
20.2k
        start..end
764
20.2k
    }
765
766
20.2k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
767
20.2k
        let start = self.first_glyph_byte_range().end;
768
20.2k
        let end = start + u16::RAW_BYTE_LEN;
769
20.2k
        start..end
770
20.2k
    }
771
772
20.2k
    pub fn value_array_byte_range(&self) -> Range<usize> {
773
20.2k
        let glyph_count = self.glyph_count();
774
20.2k
        let start = self.glyph_count_byte_range().end;
775
20.2k
        let end = start + (transforms::to_usize(glyph_count)).saturating_mul(u16::RAW_BYTE_LEN);
776
20.2k
        start..end
777
20.2k
    }
778
}
779
780
impl Format<u16> for Lookup10<'_> {
781
    const FORMAT: u16 = 10;
782
}
783
784
impl<'a> MinByteRange<'a> for Lookup10<'a> {
785
0
    fn min_byte_range(&self) -> Range<usize> {
786
0
        0..self.values_data_byte_range().end
787
0
    }
788
0
    fn min_table_bytes(&self) -> &'a [u8] {
789
0
        let range = self.min_byte_range();
790
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
791
0
    }
792
}
793
794
impl ReadArgs for Lookup10<'_> {
795
    type Args = ();
796
}
797
798
impl<'a> FontRead<'a> for Lookup10<'a> {
799
717k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
800
        #[allow(clippy::absurd_extreme_comparisons)]
801
717k
        if data.len() < Self::MIN_SIZE {
802
573k
            return Err(ReadError::OutOfBounds);
803
143k
        }
804
143k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
805
0
            return Err(ReadError::OutOfBounds);
806
        };
807
143k
        Ok(Self { data })
808
717k
    }
809
}
810
811
/// The fields at the start of the table, which are read directly.
812
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
813
#[repr(C, packed)]
814
#[doc(hidden)]
815
pub struct Lookup10FixedHeader {
816
    pub format: BigEndian<u16>,
817
    pub unit_size: BigEndian<u16>,
818
    pub first_glyph: BigEndian<u16>,
819
    pub glyph_count: BigEndian<u16>,
820
}
821
822
#[allow(clippy::absurd_extreme_comparisons)]
823
const _: () = assert!(std::mem::size_of::<Lookup10FixedHeader>() <= Lookup10::MIN_SIZE);
824
825
/// Trimmed array format. The lookup data is a simple trimmed array
826
/// indexed by glyph index.
827
#[derive(Clone)]
828
pub struct Lookup10<'a> {
829
    data: TableDataRef<'a, Lookup10FixedHeader>,
830
}
831
832
#[allow(clippy::needless_lifetimes)]
833
impl<'a> Lookup10<'a> {
834
    pub const MIN_SIZE: usize =
835
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
836
    basic_table_impls!(impl_the_methods);
837
838
    /// Format number is set to 10.
839
0
    pub fn format(&self) -> u16 {
840
0
        self.data.header().format.get()
841
0
    }
842
843
    /// Size of a lookup unit for this lookup table in bytes. Allowed values
844
    /// are 1, 2, 4, and 8.
845
1.80M
    pub fn unit_size(&self) -> u16 {
846
1.80M
        self.data.header().unit_size.get()
847
1.80M
    }
848
849
    /// First glyph index included in the trimmed array.
850
1.28M
    pub fn first_glyph(&self) -> u16 {
851
1.28M
        self.data.header().first_glyph.get()
852
1.28M
    }
853
854
    /// Total number of glyphs (equivalent to the last glyph minus the value
855
    /// of firstGlyph plus 1).
856
901k
    pub fn glyph_count(&self) -> u16 {
857
901k
        self.data.header().glyph_count.get()
858
901k
    }
859
860
    /// The lookup values (indexed by the glyph index minus the value of
861
    /// firstGlyph).
862
900k
    pub fn values_data(&self) -> &'a [u8] {
863
900k
        let range = self.values_data_byte_range();
864
900k
        self.offset_data()
865
900k
            .read_array(range)
866
900k
            .ok()
867
900k
            .unwrap_or_default()
868
900k
    }
869
870
900k
    pub fn format_byte_range(&self) -> Range<usize> {
871
900k
        let start = 0;
872
900k
        let end = start + u16::RAW_BYTE_LEN;
873
900k
        start..end
874
900k
    }
875
876
900k
    pub fn unit_size_byte_range(&self) -> Range<usize> {
877
900k
        let start = self.format_byte_range().end;
878
900k
        let end = start + u16::RAW_BYTE_LEN;
879
900k
        start..end
880
900k
    }
881
882
900k
    pub fn first_glyph_byte_range(&self) -> Range<usize> {
883
900k
        let start = self.unit_size_byte_range().end;
884
900k
        let end = start + u16::RAW_BYTE_LEN;
885
900k
        start..end
886
900k
    }
887
888
900k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
889
900k
        let start = self.first_glyph_byte_range().end;
890
900k
        let end = start + u16::RAW_BYTE_LEN;
891
900k
        start..end
892
900k
    }
893
894
900k
    pub fn values_data_byte_range(&self) -> Range<usize> {
895
900k
        let glyph_count = self.glyph_count();
896
900k
        let unit_size = self.unit_size();
897
900k
        let start = self.glyph_count_byte_range().end;
898
900k
        let end = start
899
900k
            + (transforms::add_multiply(glyph_count, 0_usize, unit_size))
900
900k
                .saturating_mul(u8::RAW_BYTE_LEN);
901
900k
        start..end
902
900k
    }
903
}
904
905
impl<'a> MinByteRange<'a> for StateHeader<'a> {
906
0
    fn min_byte_range(&self) -> Range<usize> {
907
0
        0..self.entry_table_offset_byte_range().end
908
0
    }
909
0
    fn min_table_bytes(&self) -> &'a [u8] {
910
0
        let range = self.min_byte_range();
911
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
912
0
    }
913
}
914
915
impl ReadArgs for StateHeader<'_> {
916
    type Args = ();
917
}
918
919
impl<'a> FontRead<'a> for StateHeader<'a> {
920
9.31k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
921
        #[allow(clippy::absurd_extreme_comparisons)]
922
9.31k
        if data.len() < Self::MIN_SIZE {
923
93
            return Err(ReadError::OutOfBounds);
924
9.22k
        }
925
9.22k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
926
0
            return Err(ReadError::OutOfBounds);
927
        };
928
9.22k
        Ok(Self { data })
929
9.31k
    }
930
}
931
932
/// The fields at the start of the table, which are read directly.
933
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
934
#[repr(C, packed)]
935
#[doc(hidden)]
936
pub struct StateHeaderFixedHeader {
937
    pub state_size: BigEndian<u16>,
938
    pub class_table_offset: BigEndian<Offset16>,
939
    pub state_array_offset: BigEndian<Offset16>,
940
    pub entry_table_offset: BigEndian<Offset16>,
941
}
942
943
#[allow(clippy::absurd_extreme_comparisons)]
944
const _: () = assert!(std::mem::size_of::<StateHeaderFixedHeader>() <= StateHeader::MIN_SIZE);
945
946
/// Header for a state table.
947
#[derive(Clone)]
948
pub struct StateHeader<'a> {
949
    data: TableDataRef<'a, StateHeaderFixedHeader>,
950
}
951
952
#[allow(clippy::needless_lifetimes)]
953
impl<'a> StateHeader<'a> {
954
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
955
        + Offset16::RAW_BYTE_LEN
956
        + Offset16::RAW_BYTE_LEN
957
        + Offset16::RAW_BYTE_LEN);
958
    basic_table_impls!(impl_the_methods);
959
960
    /// Size of a state, in bytes. The size is limited to 8 bits, although the
961
    /// field is 16 bits for alignment.
962
12.7k
    pub fn state_size(&self) -> u16 {
963
12.7k
        self.data.header().state_size.get()
964
12.7k
    }
965
966
    /// Byte offset from the beginning of the state table to the class subtable.
967
8.45k
    pub fn class_table_offset(&self) -> Offset16 {
968
8.45k
        self.data.header().class_table_offset.get()
969
8.45k
    }
970
971
    /// Attempt to resolve [`class_table_offset`][Self::class_table_offset].
972
8.45k
    pub fn class_table(&self) -> Result<ClassSubtable<'a>, ReadError> {
973
8.45k
        let data = self.offset_data();
974
8.45k
        self.class_table_offset().resolve(data)
975
8.45k
    }
976
977
    /// Byte offset from the beginning of the state table to the state array.
978
18.3M
    pub fn state_array_offset(&self) -> Offset16 {
979
18.3M
        self.data.header().state_array_offset.get()
980
18.3M
    }
981
982
    /// Attempt to resolve [`state_array_offset`][Self::state_array_offset].
983
8.83k
    pub fn state_array(&self) -> Result<RawBytes<'a>, ReadError> {
984
8.83k
        let data = self.offset_data();
985
8.83k
        self.state_array_offset().resolve(data)
986
8.83k
    }
987
988
    /// Byte offset from the beginning of the state table to the entry subtable.
989
4.42k
    pub fn entry_table_offset(&self) -> Offset16 {
990
4.42k
        self.data.header().entry_table_offset.get()
991
4.42k
    }
992
993
    /// Attempt to resolve [`entry_table_offset`][Self::entry_table_offset].
994
4.42k
    pub fn entry_table(&self) -> Result<RawBytes<'a>, ReadError> {
995
4.42k
        let data = self.offset_data();
996
4.42k
        self.entry_table_offset().resolve(data)
997
4.42k
    }
998
999
0
    pub fn state_size_byte_range(&self) -> Range<usize> {
1000
0
        let start = 0;
1001
0
        let end = start + u16::RAW_BYTE_LEN;
1002
0
        start..end
1003
0
    }
1004
1005
0
    pub fn class_table_offset_byte_range(&self) -> Range<usize> {
1006
0
        let start = self.state_size_byte_range().end;
1007
0
        let end = start + Offset16::RAW_BYTE_LEN;
1008
0
        start..end
1009
0
    }
1010
1011
0
    pub fn state_array_offset_byte_range(&self) -> Range<usize> {
1012
0
        let start = self.class_table_offset_byte_range().end;
1013
0
        let end = start + Offset16::RAW_BYTE_LEN;
1014
0
        start..end
1015
0
    }
1016
1017
0
    pub fn entry_table_offset_byte_range(&self) -> Range<usize> {
1018
0
        let start = self.state_array_offset_byte_range().end;
1019
0
        let end = start + Offset16::RAW_BYTE_LEN;
1020
0
        start..end
1021
0
    }
1022
}
1023
1024
const _: () = assert!(FontData::default_data_long_enough(StateHeader::MIN_SIZE));
1025
1026
impl Default for StateHeader<'_> {
1027
0
    fn default() -> Self {
1028
        Self {
1029
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1030
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1031
        }
1032
0
    }
1033
}
1034
1035
impl<'a> MinByteRange<'a> for ClassSubtable<'a> {
1036
0
    fn min_byte_range(&self) -> Range<usize> {
1037
0
        0..self.class_array_byte_range().end
1038
0
    }
1039
0
    fn min_table_bytes(&self) -> &'a [u8] {
1040
0
        let range = self.min_byte_range();
1041
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1042
0
    }
1043
}
1044
1045
impl ReadArgs for ClassSubtable<'_> {
1046
    type Args = ();
1047
}
1048
1049
impl<'a> FontRead<'a> for ClassSubtable<'a> {
1050
8.14k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1051
        #[allow(clippy::absurd_extreme_comparisons)]
1052
8.14k
        if data.len() < Self::MIN_SIZE {
1053
29
            return Err(ReadError::OutOfBounds);
1054
8.12k
        }
1055
8.12k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1056
0
            return Err(ReadError::OutOfBounds);
1057
        };
1058
8.12k
        Ok(Self { data })
1059
8.14k
    }
1060
}
1061
1062
/// The fields at the start of the table, which are read directly.
1063
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1064
#[repr(C, packed)]
1065
#[doc(hidden)]
1066
pub struct ClassSubtableFixedHeader {
1067
    pub first_glyph: BigEndian<u16>,
1068
    pub n_glyphs: BigEndian<u16>,
1069
}
1070
1071
#[allow(clippy::absurd_extreme_comparisons)]
1072
const _: () = assert!(std::mem::size_of::<ClassSubtableFixedHeader>() <= ClassSubtable::MIN_SIZE);
1073
1074
/// Maps the glyph indexes of your font into classes.
1075
#[derive(Clone)]
1076
pub struct ClassSubtable<'a> {
1077
    data: TableDataRef<'a, ClassSubtableFixedHeader>,
1078
}
1079
1080
#[allow(clippy::needless_lifetimes)]
1081
impl<'a> ClassSubtable<'a> {
1082
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1083
    basic_table_impls!(impl_the_methods);
1084
1085
    /// Glyph index of the first glyph in the class table.
1086
8.12k
    pub fn first_glyph(&self) -> u16 {
1087
8.12k
        self.data.header().first_glyph.get()
1088
8.12k
    }
1089
1090
    /// Number of glyphs in class table.
1091
8.12k
    pub fn n_glyphs(&self) -> u16 {
1092
8.12k
        self.data.header().n_glyphs.get()
1093
8.12k
    }
1094
1095
    /// The class codes (indexed by glyph index minus firstGlyph). Class codes
1096
    /// range from 0 to the value of stateSize minus 1.
1097
8.12k
    pub fn class_array(&self) -> &'a [u8] {
1098
8.12k
        let range = self.class_array_byte_range();
1099
8.12k
        self.offset_data()
1100
8.12k
            .read_array(range)
1101
8.12k
            .ok()
1102
8.12k
            .unwrap_or_default()
1103
8.12k
    }
1104
1105
8.12k
    pub fn first_glyph_byte_range(&self) -> Range<usize> {
1106
8.12k
        let start = 0;
1107
8.12k
        let end = start + u16::RAW_BYTE_LEN;
1108
8.12k
        start..end
1109
8.12k
    }
1110
1111
8.12k
    pub fn n_glyphs_byte_range(&self) -> Range<usize> {
1112
8.12k
        let start = self.first_glyph_byte_range().end;
1113
8.12k
        let end = start + u16::RAW_BYTE_LEN;
1114
8.12k
        start..end
1115
8.12k
    }
1116
1117
8.12k
    pub fn class_array_byte_range(&self) -> Range<usize> {
1118
8.12k
        let n_glyphs = self.n_glyphs();
1119
8.12k
        let start = self.n_glyphs_byte_range().end;
1120
8.12k
        let end = start + (transforms::to_usize(n_glyphs)).saturating_mul(u8::RAW_BYTE_LEN);
1121
8.12k
        start..end
1122
8.12k
    }
1123
}
1124
1125
const _: () = assert!(FontData::default_data_long_enough(ClassSubtable::MIN_SIZE));
1126
1127
impl Default for ClassSubtable<'_> {
1128
0
    fn default() -> Self {
1129
        Self {
1130
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1131
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1132
        }
1133
0
    }
1134
}
1135
1136
impl<'a> MinByteRange<'a> for RawBytes<'a> {
1137
0
    fn min_byte_range(&self) -> Range<usize> {
1138
0
        0..self.data_byte_range().end
1139
0
    }
1140
0
    fn min_table_bytes(&self) -> &'a [u8] {
1141
0
        let range = self.min_byte_range();
1142
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1143
0
    }
1144
}
1145
1146
impl ReadArgs for RawBytes<'_> {
1147
    type Args = ();
1148
}
1149
1150
impl<'a> FontRead<'a> for RawBytes<'a> {
1151
15.4k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1152
        #[allow(clippy::absurd_extreme_comparisons)]
1153
15.4k
        if data.len() < Self::MIN_SIZE {
1154
0
            return Err(ReadError::OutOfBounds);
1155
15.4k
        }
1156
15.4k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1157
0
            return Err(ReadError::OutOfBounds);
1158
        };
1159
15.4k
        Ok(Self { data })
1160
15.4k
    }
1161
}
1162
1163
/// The fields at the start of the table, which are read directly.
1164
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1165
#[repr(C, packed)]
1166
#[doc(hidden)]
1167
pub struct RawBytesFixedHeader {}
1168
1169
#[allow(clippy::absurd_extreme_comparisons)]
1170
const _: () = assert!(std::mem::size_of::<RawBytesFixedHeader>() <= RawBytes::MIN_SIZE);
1171
1172
/// Used for the `state_array` and `entry_table` fields in [`StateHeader`].
1173
#[derive(Clone)]
1174
pub struct RawBytes<'a> {
1175
    data: TableDataRef<'a, RawBytesFixedHeader>,
1176
}
1177
1178
#[allow(clippy::needless_lifetimes)]
1179
impl<'a> RawBytes<'a> {
1180
    pub const MIN_SIZE: usize = 0;
1181
    basic_table_impls!(impl_the_methods);
1182
1183
15.4k
    pub fn data(&self) -> &'a [u8] {
1184
15.4k
        let range = self.data_byte_range();
1185
15.4k
        self.offset_data()
1186
15.4k
            .read_array(range)
1187
15.4k
            .ok()
1188
15.4k
            .unwrap_or_default()
1189
15.4k
    }
1190
1191
15.4k
    pub fn data_byte_range(&self) -> Range<usize> {
1192
15.4k
        let start = 0;
1193
15.4k
        let end = start
1194
15.4k
            + self.offset_data().len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
1195
15.4k
        start..end
1196
15.4k
    }
1197
}
1198
1199
#[allow(clippy::absurd_extreme_comparisons)]
1200
const _: () = assert!(FontData::default_data_long_enough(RawBytes::MIN_SIZE));
1201
1202
impl Default for RawBytes<'_> {
1203
0
    fn default() -> Self {
1204
        Self {
1205
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1206
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1207
        }
1208
0
    }
1209
}
1210
1211
impl<'a> MinByteRange<'a> for StxHeader<'a> {
1212
0
    fn min_byte_range(&self) -> Range<usize> {
1213
0
        0..self.entry_table_offset_byte_range().end
1214
0
    }
1215
0
    fn min_table_bytes(&self) -> &'a [u8] {
1216
0
        let range = self.min_byte_range();
1217
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1218
0
    }
1219
}
1220
1221
impl ReadArgs for StxHeader<'_> {
1222
    type Args = ();
1223
}
1224
1225
impl<'a> FontRead<'a> for StxHeader<'a> {
1226
5.41k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1227
        #[allow(clippy::absurd_extreme_comparisons)]
1228
5.41k
        if data.len() < Self::MIN_SIZE {
1229
48
            return Err(ReadError::OutOfBounds);
1230
5.36k
        }
1231
5.36k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1232
0
            return Err(ReadError::OutOfBounds);
1233
        };
1234
5.36k
        Ok(Self { data })
1235
5.41k
    }
1236
}
1237
1238
/// The fields at the start of the table, which are read directly.
1239
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1240
#[repr(C, packed)]
1241
#[doc(hidden)]
1242
pub struct StxHeaderFixedHeader {
1243
    pub n_classes: BigEndian<u32>,
1244
    pub class_table_offset: BigEndian<Offset32>,
1245
    pub state_array_offset: BigEndian<Offset32>,
1246
    pub entry_table_offset: BigEndian<Offset32>,
1247
}
1248
1249
#[allow(clippy::absurd_extreme_comparisons)]
1250
const _: () = assert!(std::mem::size_of::<StxHeaderFixedHeader>() <= StxHeader::MIN_SIZE);
1251
1252
/// Header for an extended state table.
1253
#[derive(Clone)]
1254
pub struct StxHeader<'a> {
1255
    data: TableDataRef<'a, StxHeaderFixedHeader>,
1256
}
1257
1258
#[allow(clippy::needless_lifetimes)]
1259
impl<'a> StxHeader<'a> {
1260
    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN
1261
        + Offset32::RAW_BYTE_LEN
1262
        + Offset32::RAW_BYTE_LEN
1263
        + Offset32::RAW_BYTE_LEN);
1264
    basic_table_impls!(impl_the_methods);
1265
1266
    /// Number of classes, which is the number of 16-bit entry indices in a single line in the state array.
1267
5.36k
    pub fn n_classes(&self) -> u32 {
1268
5.36k
        self.data.header().n_classes.get()
1269
5.36k
    }
1270
1271
    /// Byte offset from the beginning of the state table to the class subtable.
1272
5.36k
    pub fn class_table_offset(&self) -> Offset32 {
1273
5.36k
        self.data.header().class_table_offset.get()
1274
5.36k
    }
1275
1276
    /// Attempt to resolve [`class_table_offset`][Self::class_table_offset].
1277
2.96k
    pub fn class_table(&self) -> Result<LookupU16<'a>, ReadError> {
1278
2.96k
        let data = self.offset_data();
1279
2.96k
        self.class_table_offset().resolve(data)
1280
2.96k
    }
1281
1282
    /// Byte offset from the beginning of the state table to the state array.
1283
5.15k
    pub fn state_array_offset(&self) -> Offset32 {
1284
5.15k
        self.data.header().state_array_offset.get()
1285
5.15k
    }
1286
1287
    /// Attempt to resolve [`state_array_offset`][Self::state_array_offset].
1288
2.75k
    pub fn state_array(&self) -> Result<RawWords<'a>, ReadError> {
1289
2.75k
        let data = self.offset_data();
1290
2.75k
        self.state_array_offset().resolve(data)
1291
2.75k
    }
1292
1293
    /// Byte offset from the beginning of the state table to the entry subtable.
1294
5.02k
    pub fn entry_table_offset(&self) -> Offset32 {
1295
5.02k
        self.data.header().entry_table_offset.get()
1296
5.02k
    }
1297
1298
    /// Attempt to resolve [`entry_table_offset`][Self::entry_table_offset].
1299
2.62k
    pub fn entry_table(&self) -> Result<RawBytes<'a>, ReadError> {
1300
2.62k
        let data = self.offset_data();
1301
2.62k
        self.entry_table_offset().resolve(data)
1302
2.62k
    }
1303
1304
0
    pub fn n_classes_byte_range(&self) -> Range<usize> {
1305
0
        let start = 0;
1306
0
        let end = start + u32::RAW_BYTE_LEN;
1307
0
        start..end
1308
0
    }
1309
1310
0
    pub fn class_table_offset_byte_range(&self) -> Range<usize> {
1311
0
        let start = self.n_classes_byte_range().end;
1312
0
        let end = start + Offset32::RAW_BYTE_LEN;
1313
0
        start..end
1314
0
    }
1315
1316
0
    pub fn state_array_offset_byte_range(&self) -> Range<usize> {
1317
0
        let start = self.class_table_offset_byte_range().end;
1318
0
        let end = start + Offset32::RAW_BYTE_LEN;
1319
0
        start..end
1320
0
    }
1321
1322
0
    pub fn entry_table_offset_byte_range(&self) -> Range<usize> {
1323
0
        let start = self.state_array_offset_byte_range().end;
1324
0
        let end = start + Offset32::RAW_BYTE_LEN;
1325
0
        start..end
1326
0
    }
1327
}
1328
1329
const _: () = assert!(FontData::default_data_long_enough(StxHeader::MIN_SIZE));
1330
1331
impl Default for StxHeader<'_> {
1332
0
    fn default() -> Self {
1333
        Self {
1334
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1335
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1336
        }
1337
0
    }
1338
}
1339
1340
impl<'a> MinByteRange<'a> for RawWords<'a> {
1341
0
    fn min_byte_range(&self) -> Range<usize> {
1342
0
        0..self.data_byte_range().end
1343
0
    }
1344
0
    fn min_table_bytes(&self) -> &'a [u8] {
1345
0
        let range = self.min_byte_range();
1346
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1347
0
    }
1348
}
1349
1350
impl ReadArgs for RawWords<'_> {
1351
    type Args = ();
1352
}
1353
1354
impl<'a> FontRead<'a> for RawWords<'a> {
1355
2.62k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1356
        #[allow(clippy::absurd_extreme_comparisons)]
1357
2.62k
        if data.len() < Self::MIN_SIZE {
1358
0
            return Err(ReadError::OutOfBounds);
1359
2.62k
        }
1360
2.62k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1361
0
            return Err(ReadError::OutOfBounds);
1362
        };
1363
2.62k
        Ok(Self { data })
1364
2.62k
    }
1365
}
1366
1367
/// The fields at the start of the table, which are read directly.
1368
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1369
#[repr(C, packed)]
1370
#[doc(hidden)]
1371
pub struct RawWordsFixedHeader {}
1372
1373
#[allow(clippy::absurd_extreme_comparisons)]
1374
const _: () = assert!(std::mem::size_of::<RawWordsFixedHeader>() <= RawWords::MIN_SIZE);
1375
1376
/// Used for the `state_array` in [`StxHeader`].
1377
#[derive(Clone)]
1378
pub struct RawWords<'a> {
1379
    data: TableDataRef<'a, RawWordsFixedHeader>,
1380
}
1381
1382
#[allow(clippy::needless_lifetimes)]
1383
impl<'a> RawWords<'a> {
1384
    pub const MIN_SIZE: usize = 0;
1385
    basic_table_impls!(impl_the_methods);
1386
1387
2.62k
    pub fn data(&self) -> &'a [BigEndian<u16>] {
1388
2.62k
        let range = self.data_byte_range();
1389
2.62k
        self.offset_data()
1390
2.62k
            .read_array(range)
1391
2.62k
            .ok()
1392
2.62k
            .unwrap_or_default()
1393
2.62k
    }
1394
1395
2.62k
    pub fn data_byte_range(&self) -> Range<usize> {
1396
2.62k
        let start = 0;
1397
2.62k
        let end = start
1398
2.62k
            + self.offset_data().len().saturating_sub(start) / u16::RAW_BYTE_LEN
1399
2.62k
                * u16::RAW_BYTE_LEN;
1400
2.62k
        start..end
1401
2.62k
    }
1402
}
1403
1404
#[allow(clippy::absurd_extreme_comparisons)]
1405
const _: () = assert!(FontData::default_data_long_enough(RawWords::MIN_SIZE));
1406
1407
impl Default for RawWords<'_> {
1408
0
    fn default() -> Self {
1409
        Self {
1410
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1411
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1412
        }
1413
0
    }
1414
}