Coverage Report

Created: 2026-07-25 07:50

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