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_layout.rs
Line
Count
Source
1
// THIS FILE IS AUTOGENERATED.
2
// Any changes to this file will be overwritten.
3
// For more information about how codegen works, see font-codegen/README.md
4
5
#[allow(unused_imports)]
6
use crate::codegen_prelude::*;
7
8
impl<'a> MinByteRange<'a> for ScriptList<'a> {
9
0
    fn min_byte_range(&self) -> Range<usize> {
10
0
        0..self.script_records_byte_range().end
11
0
    }
12
0
    fn min_table_bytes(&self) -> &'a [u8] {
13
0
        let range = self.min_byte_range();
14
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
15
0
    }
16
}
17
18
impl ReadArgs for ScriptList<'_> {
19
    type Args = ();
20
}
21
22
impl<'a> FontRead<'a> for ScriptList<'a> {
23
693k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
24
        #[allow(clippy::absurd_extreme_comparisons)]
25
693k
        if data.len() < Self::MIN_SIZE {
26
10
            return Err(ReadError::OutOfBounds);
27
692k
        }
28
692k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
29
0
            return Err(ReadError::OutOfBounds);
30
        };
31
692k
        Ok(Self { data })
32
693k
    }
33
}
34
35
/// The fields at the start of the table, which are read directly.
36
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
37
#[repr(C, packed)]
38
#[doc(hidden)]
39
pub struct ScriptListFixedHeader {
40
    pub script_count: BigEndian<u16>,
41
}
42
43
#[allow(clippy::absurd_extreme_comparisons)]
44
const _: () = assert!(std::mem::size_of::<ScriptListFixedHeader>() <= ScriptList::MIN_SIZE);
45
46
/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
47
#[derive(Clone)]
48
pub struct ScriptList<'a> {
49
    data: TableDataRef<'a, ScriptListFixedHeader>,
50
}
51
52
#[allow(clippy::needless_lifetimes)]
53
impl<'a> ScriptList<'a> {
54
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
55
    basic_table_impls!(impl_the_methods);
56
57
    /// Number of ScriptRecords
58
727k
    pub fn script_count(&self) -> u16 {
59
727k
        self.data.header().script_count.get()
60
727k
    }
61
62
    /// Array of ScriptRecords, listed alphabetically by script tag
63
727k
    pub fn script_records(&self) -> &'a [ScriptRecord] {
64
727k
        let range = self.script_records_byte_range();
65
727k
        self.offset_data()
66
727k
            .read_array(range)
67
727k
            .ok()
68
727k
            .unwrap_or_default()
69
727k
    }
70
71
727k
    pub fn script_count_byte_range(&self) -> Range<usize> {
72
727k
        let start = 0;
73
727k
        let end = start + u16::RAW_BYTE_LEN;
74
727k
        start..end
75
727k
    }
76
77
727k
    pub fn script_records_byte_range(&self) -> Range<usize> {
78
727k
        let script_count = self.script_count();
79
727k
        let start = self.script_count_byte_range().end;
80
727k
        let end =
81
727k
            start + (transforms::to_usize(script_count)).saturating_mul(ScriptRecord::RAW_BYTE_LEN);
82
727k
        start..end
83
727k
    }
84
}
85
86
const _: () = assert!(FontData::default_data_long_enough(ScriptList::MIN_SIZE));
87
88
impl Default for ScriptList<'_> {
89
0
    fn default() -> Self {
90
        Self {
91
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
92
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
93
        }
94
0
    }
95
}
96
97
/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
98
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
99
#[repr(C)]
100
#[repr(packed)]
101
pub struct ScriptRecord {
102
    /// 4-byte script tag identifier
103
    pub script_tag: BigEndian<Tag>,
104
    /// Offset to Script table, from beginning of ScriptList
105
    pub script_offset: BigEndian<Offset16>,
106
}
107
108
impl ScriptRecord {
109
    /// 4-byte script tag identifier
110
845k
    pub fn script_tag(&self) -> Tag {
111
845k
        self.script_tag.get()
112
845k
    }
113
114
    /// Offset to Script table, from beginning of ScriptList
115
668k
    pub fn script_offset(&self) -> Offset16 {
116
668k
        self.script_offset.get()
117
668k
    }
118
119
    /// Offset to Script table, from beginning of ScriptList
120
    ///
121
    /// The `data` argument should be retrieved from the parent table
122
    /// By calling its `offset_data` method.
123
668k
    pub fn script<'a>(&self, data: FontData<'a>) -> Result<Script<'a>, ReadError> {
124
668k
        self.script_offset().resolve(data)
125
668k
    }
126
}
127
128
impl FixedSize for ScriptRecord {
129
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
130
}
131
132
impl<'a> MinByteRange<'a> for Script<'a> {
133
0
    fn min_byte_range(&self) -> Range<usize> {
134
0
        0..self.lang_sys_records_byte_range().end
135
0
    }
136
0
    fn min_table_bytes(&self) -> &'a [u8] {
137
0
        let range = self.min_byte_range();
138
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
139
0
    }
140
}
141
142
impl ReadArgs for Script<'_> {
143
    type Args = ();
144
}
145
146
impl<'a> FontRead<'a> for Script<'a> {
147
665k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
148
        #[allow(clippy::absurd_extreme_comparisons)]
149
665k
        if data.len() < Self::MIN_SIZE {
150
348
            return Err(ReadError::OutOfBounds);
151
665k
        }
152
665k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
153
0
            return Err(ReadError::OutOfBounds);
154
        };
155
665k
        Ok(Self { data })
156
665k
    }
157
}
158
159
/// The fields at the start of the table, which are read directly.
160
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
161
#[repr(C, packed)]
162
#[doc(hidden)]
163
pub struct ScriptFixedHeader {
164
    pub default_lang_sys_offset: BigEndian<Nullable<Offset16>>,
165
    pub lang_sys_count: BigEndian<u16>,
166
}
167
168
#[allow(clippy::absurd_extreme_comparisons)]
169
const _: () = assert!(std::mem::size_of::<ScriptFixedHeader>() <= Script::MIN_SIZE);
170
171
/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
172
#[derive(Clone)]
173
pub struct Script<'a> {
174
    data: TableDataRef<'a, ScriptFixedHeader>,
175
}
176
177
#[allow(clippy::needless_lifetimes)]
178
impl<'a> Script<'a> {
179
    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
180
    basic_table_impls!(impl_the_methods);
181
182
    /// Offset to default LangSys table, from beginning of Script table
183
    /// — may be NULL
184
642k
    pub fn default_lang_sys_offset(&self) -> Nullable<Offset16> {
185
642k
        self.data.header().default_lang_sys_offset.get()
186
642k
    }
187
188
    /// Attempt to resolve [`default_lang_sys_offset`][Self::default_lang_sys_offset].
189
642k
    pub fn default_lang_sys(&self) -> Option<Result<LangSys<'a>, ReadError>> {
190
642k
        let data = self.offset_data();
191
642k
        self.default_lang_sys_offset().resolve(data)
192
642k
    }
193
194
    /// Number of LangSysRecords for this script — excluding the
195
    /// default LangSys
196
22.6k
    pub fn lang_sys_count(&self) -> u16 {
197
22.6k
        self.data.header().lang_sys_count.get()
198
22.6k
    }
199
200
    /// Array of LangSysRecords, listed alphabetically by LangSys tag
201
22.6k
    pub fn lang_sys_records(&self) -> &'a [LangSysRecord] {
202
22.6k
        let range = self.lang_sys_records_byte_range();
203
22.6k
        self.offset_data()
204
22.6k
            .read_array(range)
205
22.6k
            .ok()
206
22.6k
            .unwrap_or_default()
207
22.6k
    }
208
209
22.6k
    pub fn default_lang_sys_offset_byte_range(&self) -> Range<usize> {
210
22.6k
        let start = 0;
211
22.6k
        let end = start + Offset16::RAW_BYTE_LEN;
212
22.6k
        start..end
213
22.6k
    }
214
215
22.6k
    pub fn lang_sys_count_byte_range(&self) -> Range<usize> {
216
22.6k
        let start = self.default_lang_sys_offset_byte_range().end;
217
22.6k
        let end = start + u16::RAW_BYTE_LEN;
218
22.6k
        start..end
219
22.6k
    }
220
221
22.6k
    pub fn lang_sys_records_byte_range(&self) -> Range<usize> {
222
22.6k
        let lang_sys_count = self.lang_sys_count();
223
22.6k
        let start = self.lang_sys_count_byte_range().end;
224
22.6k
        let end = start
225
22.6k
            + (transforms::to_usize(lang_sys_count)).saturating_mul(LangSysRecord::RAW_BYTE_LEN);
226
22.6k
        start..end
227
22.6k
    }
228
}
229
230
const _: () = assert!(FontData::default_data_long_enough(Script::MIN_SIZE));
231
232
impl Default for Script<'_> {
233
0
    fn default() -> Self {
234
        Self {
235
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
236
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
237
        }
238
0
    }
239
}
240
241
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
242
#[repr(C)]
243
#[repr(packed)]
244
pub struct LangSysRecord {
245
    /// 4-byte LangSysTag identifier
246
    pub lang_sys_tag: BigEndian<Tag>,
247
    /// Offset to LangSys table, from beginning of Script table
248
    pub lang_sys_offset: BigEndian<Offset16>,
249
}
250
251
impl LangSysRecord {
252
    /// 4-byte LangSysTag identifier
253
3.92k
    pub fn lang_sys_tag(&self) -> Tag {
254
3.92k
        self.lang_sys_tag.get()
255
3.92k
    }
256
257
    /// Offset to LangSys table, from beginning of Script table
258
862
    pub fn lang_sys_offset(&self) -> Offset16 {
259
862
        self.lang_sys_offset.get()
260
862
    }
261
262
    /// Offset to LangSys table, from beginning of Script table
263
    ///
264
    /// The `data` argument should be retrieved from the parent table
265
    /// By calling its `offset_data` method.
266
862
    pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result<LangSys<'a>, ReadError> {
267
862
        self.lang_sys_offset().resolve(data)
268
862
    }
269
}
270
271
impl FixedSize for LangSysRecord {
272
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
273
}
274
275
impl<'a> MinByteRange<'a> for LangSys<'a> {
276
0
    fn min_byte_range(&self) -> Range<usize> {
277
0
        0..self.feature_indices_byte_range().end
278
0
    }
279
0
    fn min_table_bytes(&self) -> &'a [u8] {
280
0
        let range = self.min_byte_range();
281
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
282
0
    }
283
}
284
285
impl ReadArgs for LangSys<'_> {
286
    type Args = ();
287
}
288
289
impl<'a> FontRead<'a> for LangSys<'a> {
290
641k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
291
        #[allow(clippy::absurd_extreme_comparisons)]
292
641k
        if data.len() < Self::MIN_SIZE {
293
420
            return Err(ReadError::OutOfBounds);
294
640k
        }
295
640k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
296
0
            return Err(ReadError::OutOfBounds);
297
        };
298
640k
        Ok(Self { data })
299
641k
    }
300
}
301
302
/// The fields at the start of the table, which are read directly.
303
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
304
#[repr(C, packed)]
305
#[doc(hidden)]
306
pub struct LangSysFixedHeader {
307
    pub lookup_order_offset: BigEndian<u16>,
308
    pub required_feature_index: BigEndian<u16>,
309
    pub feature_index_count: BigEndian<u16>,
310
}
311
312
#[allow(clippy::absurd_extreme_comparisons)]
313
const _: () = assert!(std::mem::size_of::<LangSysFixedHeader>() <= LangSys::MIN_SIZE);
314
315
/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
316
#[derive(Clone)]
317
pub struct LangSys<'a> {
318
    data: TableDataRef<'a, LangSysFixedHeader>,
319
}
320
321
#[allow(clippy::needless_lifetimes)]
322
impl<'a> LangSys<'a> {
323
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
324
    basic_table_impls!(impl_the_methods);
325
326
    /// Index of a feature required for this language system; if no
327
    /// required features = 0xFFFF
328
21.6k
    pub fn required_feature_index(&self) -> u16 {
329
21.6k
        self.data.header().required_feature_index.get()
330
21.6k
    }
331
332
    /// Number of feature index values for this language system —
333
    /// excludes the required feature
334
617k
    pub fn feature_index_count(&self) -> u16 {
335
617k
        self.data.header().feature_index_count.get()
336
617k
    }
337
338
    /// Array of indices into the FeatureList, in arbitrary order
339
617k
    pub fn feature_indices(&self) -> &'a [BigEndian<u16>] {
340
617k
        let range = self.feature_indices_byte_range();
341
617k
        self.offset_data()
342
617k
            .read_array(range)
343
617k
            .ok()
344
617k
            .unwrap_or_default()
345
617k
    }
346
347
617k
    pub fn lookup_order_offset_byte_range(&self) -> Range<usize> {
348
617k
        let start = 0;
349
617k
        let end = start + u16::RAW_BYTE_LEN;
350
617k
        start..end
351
617k
    }
352
353
617k
    pub fn required_feature_index_byte_range(&self) -> Range<usize> {
354
617k
        let start = self.lookup_order_offset_byte_range().end;
355
617k
        let end = start + u16::RAW_BYTE_LEN;
356
617k
        start..end
357
617k
    }
358
359
617k
    pub fn feature_index_count_byte_range(&self) -> Range<usize> {
360
617k
        let start = self.required_feature_index_byte_range().end;
361
617k
        let end = start + u16::RAW_BYTE_LEN;
362
617k
        start..end
363
617k
    }
364
365
617k
    pub fn feature_indices_byte_range(&self) -> Range<usize> {
366
617k
        let feature_index_count = self.feature_index_count();
367
617k
        let start = self.feature_index_count_byte_range().end;
368
617k
        let end =
369
617k
            start + (transforms::to_usize(feature_index_count)).saturating_mul(u16::RAW_BYTE_LEN);
370
617k
        start..end
371
617k
    }
372
}
373
374
const _: () = assert!(FontData::default_data_long_enough(LangSys::MIN_SIZE));
375
376
impl Default for LangSys<'_> {
377
0
    fn default() -> Self {
378
        Self {
379
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
380
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
381
        }
382
0
    }
383
}
384
385
impl<'a> MinByteRange<'a> for FeatureList<'a> {
386
0
    fn min_byte_range(&self) -> Range<usize> {
387
0
        0..self.feature_records_byte_range().end
388
0
    }
389
0
    fn min_table_bytes(&self) -> &'a [u8] {
390
0
        let range = self.min_byte_range();
391
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
392
0
    }
393
}
394
395
impl ReadArgs for FeatureList<'_> {
396
    type Args = ();
397
}
398
399
impl<'a> FontRead<'a> for FeatureList<'a> {
400
664k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
401
        #[allow(clippy::absurd_extreme_comparisons)]
402
664k
        if data.len() < Self::MIN_SIZE {
403
169
            return Err(ReadError::OutOfBounds);
404
664k
        }
405
664k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
406
0
            return Err(ReadError::OutOfBounds);
407
        };
408
664k
        Ok(Self { data })
409
664k
    }
410
}
411
412
/// The fields at the start of the table, which are read directly.
413
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
414
#[repr(C, packed)]
415
#[doc(hidden)]
416
pub struct FeatureListFixedHeader {
417
    pub feature_count: BigEndian<u16>,
418
}
419
420
#[allow(clippy::absurd_extreme_comparisons)]
421
const _: () = assert!(std::mem::size_of::<FeatureListFixedHeader>() <= FeatureList::MIN_SIZE);
422
423
/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
424
#[derive(Clone)]
425
pub struct FeatureList<'a> {
426
    data: TableDataRef<'a, FeatureListFixedHeader>,
427
}
428
429
#[allow(clippy::needless_lifetimes)]
430
impl<'a> FeatureList<'a> {
431
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
432
    basic_table_impls!(impl_the_methods);
433
434
    /// Number of FeatureRecords in this table
435
664k
    pub fn feature_count(&self) -> u16 {
436
664k
        self.data.header().feature_count.get()
437
664k
    }
438
439
    /// Array of FeatureRecords — zero-based (first feature has
440
    /// FeatureIndex = 0), listed alphabetically by feature tag
441
664k
    pub fn feature_records(&self) -> &'a [FeatureRecord] {
442
664k
        let range = self.feature_records_byte_range();
443
664k
        self.offset_data()
444
664k
            .read_array(range)
445
664k
            .ok()
446
664k
            .unwrap_or_default()
447
664k
    }
448
449
664k
    pub fn feature_count_byte_range(&self) -> Range<usize> {
450
664k
        let start = 0;
451
664k
        let end = start + u16::RAW_BYTE_LEN;
452
664k
        start..end
453
664k
    }
454
455
664k
    pub fn feature_records_byte_range(&self) -> Range<usize> {
456
664k
        let feature_count = self.feature_count();
457
664k
        let start = self.feature_count_byte_range().end;
458
664k
        let end = start
459
664k
            + (transforms::to_usize(feature_count)).saturating_mul(FeatureRecord::RAW_BYTE_LEN);
460
664k
        start..end
461
664k
    }
462
}
463
464
const _: () = assert!(FontData::default_data_long_enough(FeatureList::MIN_SIZE));
465
466
impl Default for FeatureList<'_> {
467
0
    fn default() -> Self {
468
        Self {
469
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
470
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
471
        }
472
0
    }
473
}
474
475
/// Part of [FeatureList]
476
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
477
#[repr(C)]
478
#[repr(packed)]
479
pub struct FeatureRecord {
480
    /// 4-byte feature identification tag
481
    pub feature_tag: BigEndian<Tag>,
482
    /// Offset to Feature table, from beginning of FeatureList
483
    pub feature_offset: BigEndian<Offset16>,
484
}
485
486
impl FeatureRecord {
487
    /// 4-byte feature identification tag
488
19.9M
    pub fn feature_tag(&self) -> Tag {
489
19.9M
        self.feature_tag.get()
490
19.9M
    }
491
492
    /// Offset to Feature table, from beginning of FeatureList
493
46.2k
    pub fn feature_offset(&self) -> Offset16 {
494
46.2k
        self.feature_offset.get()
495
46.2k
    }
496
497
    /// Offset to Feature table, from beginning of FeatureList
498
    ///
499
    /// The `data` argument should be retrieved from the parent table
500
    /// By calling its `offset_data` method.
501
46.2k
    pub fn feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
502
46.2k
        let args = self.feature_tag();
503
46.2k
        self.feature_offset().resolve_with_args(data, args)
504
46.2k
    }
505
}
506
507
impl FixedSize for FeatureRecord {
508
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
509
}
510
511
impl<'a> MinByteRange<'a> for Feature<'a> {
512
0
    fn min_byte_range(&self) -> Range<usize> {
513
0
        0..self.lookup_list_indices_byte_range().end
514
0
    }
515
0
    fn min_table_bytes(&self) -> &'a [u8] {
516
0
        let range = self.min_byte_range();
517
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
518
0
    }
519
}
520
521
impl ReadArgs for Feature<'_> {
522
    type Args = Tag;
523
}
524
525
impl<'a> FontRead<'a> for Feature<'a> {
526
45.9k
    fn read_with_args(data: FontData<'a>, args: Tag) -> Result<Self, ReadError> {
527
45.9k
        let feature_tag = args;
528
529
        #[allow(clippy::absurd_extreme_comparisons)]
530
45.9k
        if data.len() < Self::MIN_SIZE {
531
13
            return Err(ReadError::OutOfBounds);
532
45.9k
        }
533
45.9k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
534
0
            return Err(ReadError::OutOfBounds);
535
        };
536
45.9k
        Ok(Self { data, feature_tag })
537
45.9k
    }
538
}
539
540
impl<'a> Feature<'a> {
541
    /// A constructor that requires additional arguments.
542
    ///
543
    /// This type requires some external state in order to be
544
    /// parsed.
545
0
    pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result<Self, ReadError> {
546
0
        let args = feature_tag;
547
0
        Self::read_with_args(data, args)
548
0
    }
549
}
550
551
/// The fields at the start of the table, which are read directly.
552
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
553
#[repr(C, packed)]
554
#[doc(hidden)]
555
pub struct FeatureFixedHeader {
556
    pub feature_params_offset: BigEndian<Nullable<Offset16>>,
557
    pub lookup_index_count: BigEndian<u16>,
558
}
559
560
#[allow(clippy::absurd_extreme_comparisons)]
561
const _: () = assert!(std::mem::size_of::<FeatureFixedHeader>() <= Feature::MIN_SIZE);
562
563
/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
564
#[derive(Clone)]
565
pub struct Feature<'a> {
566
    data: TableDataRef<'a, FeatureFixedHeader>,
567
    feature_tag: Tag,
568
}
569
570
#[allow(clippy::needless_lifetimes)]
571
impl<'a> Feature<'a> {
572
    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
573
    basic_table_impls!(impl_the_methods);
574
575
    /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
576
0
    pub fn feature_params_offset(&self) -> Nullable<Offset16> {
577
0
        self.data.header().feature_params_offset.get()
578
0
    }
579
580
    /// Attempt to resolve [`feature_params_offset`][Self::feature_params_offset].
581
0
    pub fn feature_params(&self) -> Option<Result<FeatureParams<'a>, ReadError>> {
582
0
        let data = self.offset_data();
583
0
        let args = self.feature_tag();
584
0
        self.feature_params_offset().resolve_with_args(data, args)
585
0
    }
586
587
    /// Number of LookupList indices for this feature
588
24.9k
    pub fn lookup_index_count(&self) -> u16 {
589
24.9k
        self.data.header().lookup_index_count.get()
590
24.9k
    }
591
592
    /// Array of indices into the LookupList — zero-based (first
593
    /// lookup is LookupListIndex = 0)
594
24.9k
    pub fn lookup_list_indices(&self) -> &'a [BigEndian<u16>] {
595
24.9k
        let range = self.lookup_list_indices_byte_range();
596
24.9k
        self.offset_data()
597
24.9k
            .read_array(range)
598
24.9k
            .ok()
599
24.9k
            .unwrap_or_default()
600
24.9k
    }
601
602
0
    pub(crate) fn feature_tag(&self) -> Tag {
603
0
        self.feature_tag
604
0
    }
605
606
24.9k
    pub fn feature_params_offset_byte_range(&self) -> Range<usize> {
607
24.9k
        let start = 0;
608
24.9k
        let end = start + Offset16::RAW_BYTE_LEN;
609
24.9k
        start..end
610
24.9k
    }
611
612
24.9k
    pub fn lookup_index_count_byte_range(&self) -> Range<usize> {
613
24.9k
        let start = self.feature_params_offset_byte_range().end;
614
24.9k
        let end = start + u16::RAW_BYTE_LEN;
615
24.9k
        start..end
616
24.9k
    }
617
618
24.9k
    pub fn lookup_list_indices_byte_range(&self) -> Range<usize> {
619
24.9k
        let lookup_index_count = self.lookup_index_count();
620
24.9k
        let start = self.lookup_index_count_byte_range().end;
621
24.9k
        let end =
622
24.9k
            start + (transforms::to_usize(lookup_index_count)).saturating_mul(u16::RAW_BYTE_LEN);
623
24.9k
        start..end
624
24.9k
    }
625
}
626
627
const _: () = assert!(FontData::default_data_long_enough(Feature::MIN_SIZE));
628
629
impl Default for Feature<'_> {
630
0
    fn default() -> Self {
631
        Self {
632
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
633
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
634
0
            feature_tag: Default::default(),
635
        }
636
0
    }
637
}
638
639
impl<'a, T> MinByteRange<'a> for LookupList<'a, T> {
640
0
    fn min_byte_range(&self) -> Range<usize> {
641
0
        0..self.lookup_offsets_byte_range().end
642
0
    }
643
0
    fn min_table_bytes(&self) -> &'a [u8] {
644
0
        let range = self.min_byte_range();
645
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
646
0
    }
647
}
648
649
impl<T> ReadArgs for LookupList<'_, T> {
650
    type Args = ();
651
}
652
653
impl<'a, T> FontRead<'a> for LookupList<'a, T> {
654
265k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
655
        #[allow(clippy::absurd_extreme_comparisons)]
656
265k
        if data.len() < Self::MIN_SIZE {
657
17
            return Err(ReadError::OutOfBounds);
658
265k
        }
659
265k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
660
0
            return Err(ReadError::OutOfBounds);
661
        };
662
265k
        Ok(Self {
663
265k
            data,
664
265k
            offset_type: std::marker::PhantomData,
665
265k
        })
666
265k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gpos::PositionLookup> as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
654
103k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
655
        #[allow(clippy::absurd_extreme_comparisons)]
656
103k
        if data.len() < Self::MIN_SIZE {
657
11
            return Err(ReadError::OutOfBounds);
658
103k
        }
659
103k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
660
0
            return Err(ReadError::OutOfBounds);
661
        };
662
103k
        Ok(Self {
663
103k
            data,
664
103k
            offset_type: std::marker::PhantomData,
665
103k
        })
666
103k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gsub::SubstitutionLookup> as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
654
162k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
655
        #[allow(clippy::absurd_extreme_comparisons)]
656
162k
        if data.len() < Self::MIN_SIZE {
657
6
            return Err(ReadError::OutOfBounds);
658
162k
        }
659
162k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
660
0
            return Err(ReadError::OutOfBounds);
661
        };
662
162k
        Ok(Self {
663
162k
            data,
664
162k
            offset_type: std::marker::PhantomData,
665
162k
        })
666
162k
    }
667
}
668
669
impl<'a, T> LookupList<'a, T> {
670
    #[allow(dead_code)]
671
    /// Replace the specific generic type on this implementation with `()`
672
0
    pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> {
673
0
        LookupList {
674
0
            data: self.data,
675
0
            offset_type: std::marker::PhantomData,
676
0
        }
677
0
    }
678
}
679
680
/// The fields at the start of the table, which are read directly.
681
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
682
#[repr(C, packed)]
683
#[doc(hidden)]
684
pub struct LookupListFixedHeader {
685
    pub lookup_count: BigEndian<u16>,
686
}
687
688
#[allow(clippy::absurd_extreme_comparisons)]
689
const _: () = assert!(std::mem::size_of::<LookupListFixedHeader>() <= LookupList::<()>::MIN_SIZE);
690
691
/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
692
#[derive(Clone)]
693
pub struct LookupList<'a, T = ()> {
694
    data: TableDataRef<'a, LookupListFixedHeader>,
695
    offset_type: std::marker::PhantomData<*const T>,
696
}
697
698
#[allow(clippy::needless_lifetimes)]
699
impl<'a, T> LookupList<'a, T> {
700
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
701
    basic_table_impls!(impl_the_methods);
702
703
    /// Number of lookups in this table
704
265k
    pub fn lookup_count(&self) -> u16 {
705
265k
        self.data.header().lookup_count.get()
706
265k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gpos::PositionLookup>>::lookup_count
Line
Count
Source
704
103k
    pub fn lookup_count(&self) -> u16 {
705
103k
        self.data.header().lookup_count.get()
706
103k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_count
Line
Count
Source
704
162k
    pub fn lookup_count(&self) -> u16 {
705
162k
        self.data.header().lookup_count.get()
706
162k
    }
707
708
    /// Array of offsets to Lookup tables, from beginning of LookupList
709
    /// — zero based (first lookup is Lookup index = 0)
710
227k
    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
711
227k
        let range = self.lookup_offsets_byte_range();
712
227k
        self.offset_data()
713
227k
            .read_array(range)
714
227k
            .ok()
715
227k
            .unwrap_or_default()
716
227k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gpos::PositionLookup>>::lookup_offsets
Line
Count
Source
710
89.1k
    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
711
89.1k
        let range = self.lookup_offsets_byte_range();
712
89.1k
        self.offset_data()
713
89.1k
            .read_array(range)
714
89.1k
            .ok()
715
89.1k
            .unwrap_or_default()
716
89.1k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_offsets
Line
Count
Source
710
138k
    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
711
138k
        let range = self.lookup_offsets_byte_range();
712
138k
        self.offset_data()
713
138k
            .read_array(range)
714
138k
            .ok()
715
138k
            .unwrap_or_default()
716
138k
    }
717
718
    /// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets].
719
0
    pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16>
720
0
    where
721
0
        T: FontRead<'a, Args = ()>,
722
    {
723
0
        let data = self.offset_data();
724
0
        let offsets = self.lookup_offsets();
725
0
        ArrayOfOffsets::new(offsets, data, ())
726
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::LookupList<read_fonts::tables::gpos::PositionLookup>>::lookups
Unexecuted instantiation: <read_fonts::tables::layout::LookupList<read_fonts::tables::gsub::SubstitutionLookup>>::lookups
727
728
227k
    pub fn lookup_count_byte_range(&self) -> Range<usize> {
729
227k
        let start = 0;
730
227k
        let end = start + u16::RAW_BYTE_LEN;
731
227k
        start..end
732
227k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gpos::PositionLookup>>::lookup_count_byte_range
Line
Count
Source
728
89.1k
    pub fn lookup_count_byte_range(&self) -> Range<usize> {
729
89.1k
        let start = 0;
730
89.1k
        let end = start + u16::RAW_BYTE_LEN;
731
89.1k
        start..end
732
89.1k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_count_byte_range
Line
Count
Source
728
138k
    pub fn lookup_count_byte_range(&self) -> Range<usize> {
729
138k
        let start = 0;
730
138k
        let end = start + u16::RAW_BYTE_LEN;
731
138k
        start..end
732
138k
    }
733
734
227k
    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
735
227k
        let lookup_count = self.lookup_count();
736
227k
        let start = self.lookup_count_byte_range().end;
737
227k
        let end =
738
227k
            start + (transforms::to_usize(lookup_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
739
227k
        start..end
740
227k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gpos::PositionLookup>>::lookup_offsets_byte_range
Line
Count
Source
734
89.1k
    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
735
89.1k
        let lookup_count = self.lookup_count();
736
89.1k
        let start = self.lookup_count_byte_range().end;
737
89.1k
        let end =
738
89.1k
            start + (transforms::to_usize(lookup_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
739
89.1k
        start..end
740
89.1k
    }
<read_fonts::tables::layout::LookupList<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_offsets_byte_range
Line
Count
Source
734
138k
    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
735
138k
        let lookup_count = self.lookup_count();
736
138k
        let start = self.lookup_count_byte_range().end;
737
138k
        let end =
738
138k
            start + (transforms::to_usize(lookup_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
739
138k
        start..end
740
138k
    }
741
}
742
743
const _: () = assert!(FontData::default_data_long_enough(
744
    LookupList::<()>::MIN_SIZE
745
));
746
747
impl<T> Default for LookupList<'_, T> {
748
0
    fn default() -> Self {
749
        Self {
750
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
751
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
752
0
            offset_type: std::marker::PhantomData,
753
        }
754
0
    }
755
}
756
757
impl Discriminant for Lookup<'_, ()> {
758
0
    fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
759
0
        data.read_at(0)
760
0
    }
761
}
762
763
impl<'a, T> MinByteRange<'a> for Lookup<'a, T> {
764
0
    fn min_byte_range(&self) -> Range<usize> {
765
0
        0..self.subtable_offsets_byte_range().end
766
0
    }
767
0
    fn min_table_bytes(&self) -> &'a [u8] {
768
0
        let range = self.min_byte_range();
769
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
770
0
    }
771
}
772
773
impl<T> ReadArgs for Lookup<'_, T> {
774
    type Args = ();
775
}
776
777
impl<'a, T> FontRead<'a> for Lookup<'a, T> {
778
142k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
779
        #[allow(clippy::absurd_extreme_comparisons)]
780
142k
        if data.len() < Self::MIN_SIZE {
781
101
            return Err(ReadError::OutOfBounds);
782
142k
        }
783
142k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
784
0
            return Err(ReadError::OutOfBounds);
785
        };
786
142k
        Ok(Self {
787
142k
            data,
788
142k
            offset_type: std::marker::PhantomData,
789
142k
        })
790
142k
    }
<read_fonts::tables::layout::Lookup as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
778
142k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
779
        #[allow(clippy::absurd_extreme_comparisons)]
780
142k
        if data.len() < Self::MIN_SIZE {
781
101
            return Err(ReadError::OutOfBounds);
782
142k
        }
783
142k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
784
0
            return Err(ReadError::OutOfBounds);
785
        };
786
142k
        Ok(Self {
787
142k
            data,
788
142k
            offset_type: std::marker::PhantomData,
789
142k
        })
790
142k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable> as read_fonts::read::FontRead>::read_with_args
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst> as read_fonts::read::FontRead>::read_with_args
791
}
792
793
impl<'a, T> Lookup<'a, T> {
794
    #[allow(dead_code)]
795
    /// Replace the specific generic type on this implementation with `()`
796
0
    pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
797
0
        Lookup {
798
0
            data: self.data,
799
0
            offset_type: std::marker::PhantomData,
800
0
        }
801
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::of_unit_type
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::of_unit_type
802
}
803
804
/// The fields at the start of the table, which are read directly.
805
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
806
#[repr(C, packed)]
807
#[doc(hidden)]
808
pub struct LookupFixedHeader {
809
    pub lookup_type: BigEndian<u16>,
810
    pub lookup_flag: BigEndian<LookupFlag>,
811
    pub sub_table_count: BigEndian<u16>,
812
}
813
814
#[allow(clippy::absurd_extreme_comparisons)]
815
const _: () = assert!(std::mem::size_of::<LookupFixedHeader>() <= Lookup::<()>::MIN_SIZE);
816
817
/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
818
#[derive(Clone)]
819
pub struct Lookup<'a, T = ()> {
820
    data: TableDataRef<'a, LookupFixedHeader>,
821
    offset_type: std::marker::PhantomData<*const T>,
822
}
823
824
#[allow(clippy::needless_lifetimes)]
825
impl<'a, T> Lookup<'a, T> {
826
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + LookupFlag::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
827
    basic_table_impls!(impl_the_methods);
828
829
    /// Different enumerations for GSUB and GPOS
830
167k
    pub fn lookup_type(&self) -> u16 {
831
167k
        self.data.header().lookup_type.get()
832
167k
    }
833
834
    /// Lookup qualifiers
835
120k
    pub fn lookup_flag(&self) -> LookupFlag {
836
120k
        self.data.header().lookup_flag.get()
837
120k
    }
838
839
    /// Number of subtables for this lookup
840
263k
    pub fn sub_table_count(&self) -> u16 {
841
263k
        self.data.header().sub_table_count.get()
842
263k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::sub_table_count
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::sub_table_count
<read_fonts::tables::layout::Lookup>::sub_table_count
Line
Count
Source
840
263k
    pub fn sub_table_count(&self) -> u16 {
841
263k
        self.data.header().sub_table_count.get()
842
263k
    }
843
844
    /// Array of offsets to lookup subtables, from beginning of Lookup
845
    /// table
846
103k
    pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
847
103k
        let range = self.subtable_offsets_byte_range();
848
103k
        self.offset_data()
849
103k
            .read_array(range)
850
103k
            .ok()
851
103k
            .unwrap_or_default()
852
103k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::subtable_offsets
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::subtable_offsets
<read_fonts::tables::layout::Lookup>::subtable_offsets
Line
Count
Source
846
103k
    pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
847
103k
        let range = self.subtable_offsets_byte_range();
848
103k
        self.offset_data()
849
103k
            .read_array(range)
850
103k
            .ok()
851
103k
            .unwrap_or_default()
852
103k
    }
853
854
    /// A dynamically resolving wrapper for [`subtable_offsets`][Self::subtable_offsets].
855
0
    pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16>
856
0
    where
857
0
        T: FontRead<'a, Args = ()>,
858
    {
859
0
        let data = self.offset_data();
860
0
        let offsets = self.subtable_offsets();
861
0
        ArrayOfOffsets::new(offsets, data, ())
862
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::subtables
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::subtables
863
864
    /// Index (base 0) into GDEF mark glyph sets structure. This field
865
    /// is only present if the USE_MARK_FILTERING_SET lookup flag is
866
    /// set.
867
17.4k
    pub fn mark_filtering_set(&self) -> Option<u16> {
868
17.4k
        let range = self.mark_filtering_set_byte_range();
869
17.4k
        (!range.is_empty())
870
17.4k
            .then(|| self.offset_data().read_at(range.start).ok())
871
17.4k
            .flatten()
872
17.4k
    }
873
874
120k
    pub fn lookup_type_byte_range(&self) -> Range<usize> {
875
120k
        let start = 0;
876
120k
        let end = start + u16::RAW_BYTE_LEN;
877
120k
        start..end
878
120k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::lookup_type_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::lookup_type_byte_range
<read_fonts::tables::layout::Lookup>::lookup_type_byte_range
Line
Count
Source
874
120k
    pub fn lookup_type_byte_range(&self) -> Range<usize> {
875
120k
        let start = 0;
876
120k
        let end = start + u16::RAW_BYTE_LEN;
877
120k
        start..end
878
120k
    }
879
880
120k
    pub fn lookup_flag_byte_range(&self) -> Range<usize> {
881
120k
        let start = self.lookup_type_byte_range().end;
882
120k
        let end = start + LookupFlag::RAW_BYTE_LEN;
883
120k
        start..end
884
120k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::lookup_flag_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::lookup_flag_byte_range
<read_fonts::tables::layout::Lookup>::lookup_flag_byte_range
Line
Count
Source
880
120k
    pub fn lookup_flag_byte_range(&self) -> Range<usize> {
881
120k
        let start = self.lookup_type_byte_range().end;
882
120k
        let end = start + LookupFlag::RAW_BYTE_LEN;
883
120k
        start..end
884
120k
    }
885
886
120k
    pub fn sub_table_count_byte_range(&self) -> Range<usize> {
887
120k
        let start = self.lookup_flag_byte_range().end;
888
120k
        let end = start + u16::RAW_BYTE_LEN;
889
120k
        start..end
890
120k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::sub_table_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::sub_table_count_byte_range
<read_fonts::tables::layout::Lookup>::sub_table_count_byte_range
Line
Count
Source
886
120k
    pub fn sub_table_count_byte_range(&self) -> Range<usize> {
887
120k
        let start = self.lookup_flag_byte_range().end;
888
120k
        let end = start + u16::RAW_BYTE_LEN;
889
120k
        start..end
890
120k
    }
891
892
120k
    pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
893
120k
        let sub_table_count = self.sub_table_count();
894
120k
        let start = self.sub_table_count_byte_range().end;
895
120k
        let end =
896
120k
            start + (transforms::to_usize(sub_table_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
897
120k
        start..end
898
120k
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::SequenceContext>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::layout::ChainedSequenceContext>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::CursivePos>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkLigPos>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkBasePos>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::MarkMarkPos>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::ExtensionSubtable>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::PairPos>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::LigatureSubst>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::MultipleSubst>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::AlternateSubst>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ExtensionSubtable>>::subtable_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::ReverseChainSingleSubst>>::subtable_offsets_byte_range
<read_fonts::tables::layout::Lookup>::subtable_offsets_byte_range
Line
Count
Source
892
120k
    pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
893
120k
        let sub_table_count = self.sub_table_count();
894
120k
        let start = self.sub_table_count_byte_range().end;
895
120k
        let end =
896
120k
            start + (transforms::to_usize(sub_table_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
897
120k
        start..end
898
120k
    }
899
900
17.4k
    pub fn mark_filtering_set_byte_range(&self) -> Range<usize> {
901
17.4k
        let start = self.subtable_offsets_byte_range().end;
902
17.4k
        let end = if self
903
17.4k
            .lookup_flag()
904
17.4k
            .contains(LookupFlag::USE_MARK_FILTERING_SET)
905
        {
906
17.4k
            start + u16::RAW_BYTE_LEN
907
        } else {
908
0
            start
909
        };
910
17.4k
        start..end
911
17.4k
    }
912
}
913
914
const _: () = assert!(FontData::default_data_long_enough(Lookup::<()>::MIN_SIZE));
915
916
impl<T> Default for Lookup<'_, T> {
917
0
    fn default() -> Self {
918
        Self {
919
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
920
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos> as core::default::Default>::default::{closure#0}
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst> as core::default::Default>::default::{closure#0}
921
0
            offset_type: std::marker::PhantomData,
922
        }
923
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gpos::SinglePos> as core::default::Default>::default
Unexecuted instantiation: <read_fonts::tables::layout::Lookup<read_fonts::tables::gsub::SingleSubst> as core::default::Default>::default
924
}
925
926
impl Format<u16> for CoverageFormat1<'_> {
927
    const FORMAT: u16 = 1;
928
}
929
930
impl<'a> MinByteRange<'a> for CoverageFormat1<'a> {
931
0
    fn min_byte_range(&self) -> Range<usize> {
932
0
        0..self.glyph_array_byte_range().end
933
0
    }
934
0
    fn min_table_bytes(&self) -> &'a [u8] {
935
0
        let range = self.min_byte_range();
936
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
937
0
    }
938
}
939
940
impl ReadArgs for CoverageFormat1<'_> {
941
    type Args = ();
942
}
943
944
impl<'a> FontRead<'a> for CoverageFormat1<'a> {
945
65.7k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
946
        #[allow(clippy::absurd_extreme_comparisons)]
947
65.7k
        if data.len() < Self::MIN_SIZE {
948
768
            return Err(ReadError::OutOfBounds);
949
64.9k
        }
950
64.9k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
951
0
            return Err(ReadError::OutOfBounds);
952
        };
953
64.9k
        Ok(Self { data })
954
65.7k
    }
955
}
956
957
/// The fields at the start of the table, which are read directly.
958
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
959
#[repr(C, packed)]
960
#[doc(hidden)]
961
pub struct CoverageFormat1FixedHeader {
962
    pub coverage_format: BigEndian<u16>,
963
    pub glyph_count: BigEndian<u16>,
964
}
965
966
#[allow(clippy::absurd_extreme_comparisons)]
967
const _: () =
968
    assert!(std::mem::size_of::<CoverageFormat1FixedHeader>() <= CoverageFormat1::MIN_SIZE);
969
970
/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
971
#[derive(Clone)]
972
pub struct CoverageFormat1<'a> {
973
    data: TableDataRef<'a, CoverageFormat1FixedHeader>,
974
}
975
976
#[allow(clippy::needless_lifetimes)]
977
impl<'a> CoverageFormat1<'a> {
978
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
979
    basic_table_impls!(impl_the_methods);
980
981
    /// Format identifier — format = 1
982
0
    pub fn coverage_format(&self) -> u16 {
983
0
        self.data.header().coverage_format.get()
984
0
    }
985
986
    /// Number of glyphs in the glyph array
987
65.0k
    pub fn glyph_count(&self) -> u16 {
988
65.0k
        self.data.header().glyph_count.get()
989
65.0k
    }
990
991
    /// Array of glyph IDs — in numerical order
992
65.0k
    pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
993
65.0k
        let range = self.glyph_array_byte_range();
994
65.0k
        self.offset_data()
995
65.0k
            .read_array(range)
996
65.0k
            .ok()
997
65.0k
            .unwrap_or_default()
998
65.0k
    }
999
1000
65.0k
    pub fn coverage_format_byte_range(&self) -> Range<usize> {
1001
65.0k
        let start = 0;
1002
65.0k
        let end = start + u16::RAW_BYTE_LEN;
1003
65.0k
        start..end
1004
65.0k
    }
1005
1006
65.0k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1007
65.0k
        let start = self.coverage_format_byte_range().end;
1008
65.0k
        let end = start + u16::RAW_BYTE_LEN;
1009
65.0k
        start..end
1010
65.0k
    }
1011
1012
65.0k
    pub fn glyph_array_byte_range(&self) -> Range<usize> {
1013
65.0k
        let glyph_count = self.glyph_count();
1014
65.0k
        let start = self.glyph_count_byte_range().end;
1015
65.0k
        let end =
1016
65.0k
            start + (transforms::to_usize(glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
1017
65.0k
        start..end
1018
65.0k
    }
1019
}
1020
1021
const _: () = assert!(FontData::default_data_long_enough(
1022
    CoverageFormat1::MIN_SIZE
1023
));
1024
1025
impl Default for CoverageFormat1<'_> {
1026
0
    fn default() -> Self {
1027
        Self {
1028
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1029
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1030
        }
1031
0
    }
1032
}
1033
1034
impl Format<u16> for CoverageFormat2<'_> {
1035
    const FORMAT: u16 = 2;
1036
}
1037
1038
impl<'a> MinByteRange<'a> for CoverageFormat2<'a> {
1039
0
    fn min_byte_range(&self) -> Range<usize> {
1040
0
        0..self.range_records_byte_range().end
1041
0
    }
1042
0
    fn min_table_bytes(&self) -> &'a [u8] {
1043
0
        let range = self.min_byte_range();
1044
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1045
0
    }
1046
}
1047
1048
impl ReadArgs for CoverageFormat2<'_> {
1049
    type Args = ();
1050
}
1051
1052
impl<'a> FontRead<'a> for CoverageFormat2<'a> {
1053
328k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1054
        #[allow(clippy::absurd_extreme_comparisons)]
1055
328k
        if data.len() < Self::MIN_SIZE {
1056
738
            return Err(ReadError::OutOfBounds);
1057
327k
        }
1058
327k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1059
0
            return Err(ReadError::OutOfBounds);
1060
        };
1061
327k
        Ok(Self { data })
1062
328k
    }
1063
}
1064
1065
/// The fields at the start of the table, which are read directly.
1066
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1067
#[repr(C, packed)]
1068
#[doc(hidden)]
1069
pub struct CoverageFormat2FixedHeader {
1070
    pub coverage_format: BigEndian<u16>,
1071
    pub range_count: BigEndian<u16>,
1072
}
1073
1074
#[allow(clippy::absurd_extreme_comparisons)]
1075
const _: () =
1076
    assert!(std::mem::size_of::<CoverageFormat2FixedHeader>() <= CoverageFormat2::MIN_SIZE);
1077
1078
/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
1079
#[derive(Clone)]
1080
pub struct CoverageFormat2<'a> {
1081
    data: TableDataRef<'a, CoverageFormat2FixedHeader>,
1082
}
1083
1084
#[allow(clippy::needless_lifetimes)]
1085
impl<'a> CoverageFormat2<'a> {
1086
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1087
    basic_table_impls!(impl_the_methods);
1088
1089
    /// Format identifier — format = 2
1090
0
    pub fn coverage_format(&self) -> u16 {
1091
0
        self.data.header().coverage_format.get()
1092
0
    }
1093
1094
    /// Number of RangeRecords
1095
328k
    pub fn range_count(&self) -> u16 {
1096
328k
        self.data.header().range_count.get()
1097
328k
    }
1098
1099
    /// Array of glyph ranges — ordered by startGlyphID.
1100
328k
    pub fn range_records(&self) -> &'a [RangeRecord] {
1101
328k
        let range = self.range_records_byte_range();
1102
328k
        self.offset_data()
1103
328k
            .read_array(range)
1104
328k
            .ok()
1105
328k
            .unwrap_or_default()
1106
328k
    }
1107
1108
328k
    pub fn coverage_format_byte_range(&self) -> Range<usize> {
1109
328k
        let start = 0;
1110
328k
        let end = start + u16::RAW_BYTE_LEN;
1111
328k
        start..end
1112
328k
    }
1113
1114
328k
    pub fn range_count_byte_range(&self) -> Range<usize> {
1115
328k
        let start = self.coverage_format_byte_range().end;
1116
328k
        let end = start + u16::RAW_BYTE_LEN;
1117
328k
        start..end
1118
328k
    }
1119
1120
328k
    pub fn range_records_byte_range(&self) -> Range<usize> {
1121
328k
        let range_count = self.range_count();
1122
328k
        let start = self.range_count_byte_range().end;
1123
328k
        let end =
1124
328k
            start + (transforms::to_usize(range_count)).saturating_mul(RangeRecord::RAW_BYTE_LEN);
1125
328k
        start..end
1126
328k
    }
1127
}
1128
1129
/// Used in [CoverageFormat2]
1130
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1131
#[repr(C)]
1132
#[repr(packed)]
1133
pub struct RangeRecord {
1134
    /// First glyph ID in the range
1135
    pub start_glyph_id: BigEndian<GlyphId16>,
1136
    /// Last glyph ID in the range
1137
    pub end_glyph_id: BigEndian<GlyphId16>,
1138
    /// Coverage Index of first glyph ID in range
1139
    pub start_coverage_index: BigEndian<u16>,
1140
}
1141
1142
impl RangeRecord {
1143
    /// First glyph ID in the range
1144
236M
    pub fn start_glyph_id(&self) -> GlyphId16 {
1145
236M
        self.start_glyph_id.get()
1146
236M
    }
1147
1148
    /// Last glyph ID in the range
1149
214M
    pub fn end_glyph_id(&self) -> GlyphId16 {
1150
214M
        self.end_glyph_id.get()
1151
214M
    }
1152
1153
    /// Coverage Index of first glyph ID in range
1154
21.7M
    pub fn start_coverage_index(&self) -> u16 {
1155
21.7M
        self.start_coverage_index.get()
1156
21.7M
    }
1157
}
1158
1159
impl FixedSize for RangeRecord {
1160
    const RAW_BYTE_LEN: usize =
1161
        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1162
}
1163
1164
/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
1165
#[derive(Clone)]
1166
pub enum CoverageTable<'a> {
1167
    Format1(CoverageFormat1<'a>),
1168
    Format2(CoverageFormat2<'a>),
1169
    Format3(CoverageFormat3<'a>),
1170
    Format4(CoverageFormat4<'a>),
1171
}
1172
1173
impl Default for CoverageTable<'_> {
1174
0
    fn default() -> Self {
1175
0
        Self::Format1(Default::default())
1176
0
    }
1177
}
1178
1179
impl<'a> CoverageTable<'a> {
1180
    ///Return the `FontData` used to resolve offsets for this table.
1181
0
    pub fn offset_data(&self) -> FontData<'a> {
1182
0
        match self {
1183
0
            Self::Format1(item) => item.offset_data(),
1184
0
            Self::Format2(item) => item.offset_data(),
1185
0
            Self::Format3(item) => item.offset_data(),
1186
0
            Self::Format4(item) => item.offset_data(),
1187
        }
1188
0
    }
1189
1190
    /// Format identifier — format = 1
1191
0
    pub fn coverage_format(&self) -> u16 {
1192
0
        match self {
1193
0
            Self::Format1(item) => item.coverage_format(),
1194
0
            Self::Format2(item) => item.coverage_format(),
1195
0
            Self::Format3(item) => item.coverage_format(),
1196
0
            Self::Format4(item) => item.coverage_format(),
1197
        }
1198
0
    }
1199
}
1200
1201
impl ReadArgs for CoverageTable<'_> {
1202
    type Args = ();
1203
}
1204
1205
impl<'a> FontRead<'a> for CoverageTable<'a> {
1206
    #[inline]
1207
844k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1208
844k
        let format: u16 = data.read_at(0usize)?;
1209
842k
        match format {
1210
65.7k
            CoverageFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1211
328k
            CoverageFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1212
8.95k
            CoverageFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1213
12.5k
            CoverageFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
1214
426k
            other => Err(ReadError::InvalidFormat(other.into())),
1215
        }
1216
844k
    }
<read_fonts::tables::layout::CoverageTable as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
1207
456k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1208
456k
        let format: u16 = data.read_at(0usize)?;
1209
456k
        match format {
1210
9.07k
            CoverageFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1211
224k
            CoverageFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1212
1.62k
            CoverageFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1213
1.77k
            CoverageFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
1214
218k
            other => Err(ReadError::InvalidFormat(other.into())),
1215
        }
1216
456k
    }
<read_fonts::tables::layout::CoverageTable as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
1207
387k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1208
387k
        let format: u16 = data.read_at(0usize)?;
1209
386k
        match format {
1210
56.6k
            CoverageFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1211
103k
            CoverageFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1212
7.32k
            CoverageFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1213
10.7k
            CoverageFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
1214
207k
            other => Err(ReadError::InvalidFormat(other.into())),
1215
        }
1216
387k
    }
1217
}
1218
1219
impl<'a> MinByteRange<'a> for CoverageTable<'a> {
1220
0
    fn min_byte_range(&self) -> Range<usize> {
1221
0
        match self {
1222
0
            Self::Format1(item) => item.min_byte_range(),
1223
0
            Self::Format2(item) => item.min_byte_range(),
1224
0
            Self::Format3(item) => item.min_byte_range(),
1225
0
            Self::Format4(item) => item.min_byte_range(),
1226
        }
1227
0
    }
1228
0
    fn min_table_bytes(&self) -> &'a [u8] {
1229
0
        match self {
1230
0
            Self::Format1(item) => item.min_table_bytes(),
1231
0
            Self::Format2(item) => item.min_table_bytes(),
1232
0
            Self::Format3(item) => item.min_table_bytes(),
1233
0
            Self::Format4(item) => item.min_table_bytes(),
1234
        }
1235
0
    }
1236
}
1237
1238
impl Format<u16> for ClassDefFormat1<'_> {
1239
    const FORMAT: u16 = 1;
1240
}
1241
1242
impl<'a> MinByteRange<'a> for ClassDefFormat1<'a> {
1243
0
    fn min_byte_range(&self) -> Range<usize> {
1244
0
        0..self.class_value_array_byte_range().end
1245
0
    }
1246
0
    fn min_table_bytes(&self) -> &'a [u8] {
1247
0
        let range = self.min_byte_range();
1248
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1249
0
    }
1250
}
1251
1252
impl ReadArgs for ClassDefFormat1<'_> {
1253
    type Args = ();
1254
}
1255
1256
impl<'a> FontRead<'a> for ClassDefFormat1<'a> {
1257
33.1k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1258
        #[allow(clippy::absurd_extreme_comparisons)]
1259
33.1k
        if data.len() < Self::MIN_SIZE {
1260
1.27k
            return Err(ReadError::OutOfBounds);
1261
31.9k
        }
1262
31.9k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1263
0
            return Err(ReadError::OutOfBounds);
1264
        };
1265
31.9k
        Ok(Self { data })
1266
33.1k
    }
1267
}
1268
1269
/// The fields at the start of the table, which are read directly.
1270
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1271
#[repr(C, packed)]
1272
#[doc(hidden)]
1273
pub struct ClassDefFormat1FixedHeader {
1274
    pub class_format: BigEndian<u16>,
1275
    pub start_glyph_id: BigEndian<GlyphId16>,
1276
    pub glyph_count: BigEndian<u16>,
1277
}
1278
1279
#[allow(clippy::absurd_extreme_comparisons)]
1280
const _: () =
1281
    assert!(std::mem::size_of::<ClassDefFormat1FixedHeader>() <= ClassDefFormat1::MIN_SIZE);
1282
1283
/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
1284
#[derive(Clone)]
1285
pub struct ClassDefFormat1<'a> {
1286
    data: TableDataRef<'a, ClassDefFormat1FixedHeader>,
1287
}
1288
1289
#[allow(clippy::needless_lifetimes)]
1290
impl<'a> ClassDefFormat1<'a> {
1291
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1292
    basic_table_impls!(impl_the_methods);
1293
1294
    /// Format identifier — format = 1
1295
0
    pub fn class_format(&self) -> u16 {
1296
0
        self.data.header().class_format.get()
1297
0
    }
1298
1299
    /// First glyph ID of the classValueArray
1300
31.9k
    pub fn start_glyph_id(&self) -> GlyphId16 {
1301
31.9k
        self.data.header().start_glyph_id.get()
1302
31.9k
    }
1303
1304
    /// Size of the classValueArray
1305
31.9k
    pub fn glyph_count(&self) -> u16 {
1306
31.9k
        self.data.header().glyph_count.get()
1307
31.9k
    }
1308
1309
    /// Array of Class Values — one per glyph ID
1310
31.9k
    pub fn class_value_array(&self) -> &'a [BigEndian<u16>] {
1311
31.9k
        let range = self.class_value_array_byte_range();
1312
31.9k
        self.offset_data()
1313
31.9k
            .read_array(range)
1314
31.9k
            .ok()
1315
31.9k
            .unwrap_or_default()
1316
31.9k
    }
1317
1318
31.9k
    pub fn class_format_byte_range(&self) -> Range<usize> {
1319
31.9k
        let start = 0;
1320
31.9k
        let end = start + u16::RAW_BYTE_LEN;
1321
31.9k
        start..end
1322
31.9k
    }
1323
1324
31.9k
    pub fn start_glyph_id_byte_range(&self) -> Range<usize> {
1325
31.9k
        let start = self.class_format_byte_range().end;
1326
31.9k
        let end = start + GlyphId16::RAW_BYTE_LEN;
1327
31.9k
        start..end
1328
31.9k
    }
1329
1330
31.9k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1331
31.9k
        let start = self.start_glyph_id_byte_range().end;
1332
31.9k
        let end = start + u16::RAW_BYTE_LEN;
1333
31.9k
        start..end
1334
31.9k
    }
1335
1336
31.9k
    pub fn class_value_array_byte_range(&self) -> Range<usize> {
1337
31.9k
        let glyph_count = self.glyph_count();
1338
31.9k
        let start = self.glyph_count_byte_range().end;
1339
31.9k
        let end = start + (transforms::to_usize(glyph_count)).saturating_mul(u16::RAW_BYTE_LEN);
1340
31.9k
        start..end
1341
31.9k
    }
1342
}
1343
1344
const _: () = assert!(FontData::default_data_long_enough(
1345
    ClassDefFormat1::MIN_SIZE
1346
));
1347
1348
impl Default for ClassDefFormat1<'_> {
1349
0
    fn default() -> Self {
1350
        Self {
1351
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1352
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1353
        }
1354
0
    }
1355
}
1356
1357
impl Format<u16> for ClassDefFormat2<'_> {
1358
    const FORMAT: u16 = 2;
1359
}
1360
1361
impl<'a> MinByteRange<'a> for ClassDefFormat2<'a> {
1362
0
    fn min_byte_range(&self) -> Range<usize> {
1363
0
        0..self.class_range_records_byte_range().end
1364
0
    }
1365
0
    fn min_table_bytes(&self) -> &'a [u8] {
1366
0
        let range = self.min_byte_range();
1367
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1368
0
    }
1369
}
1370
1371
impl ReadArgs for ClassDefFormat2<'_> {
1372
    type Args = ();
1373
}
1374
1375
impl<'a> FontRead<'a> for ClassDefFormat2<'a> {
1376
25.4k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1377
        #[allow(clippy::absurd_extreme_comparisons)]
1378
25.4k
        if data.len() < Self::MIN_SIZE {
1379
1.38k
            return Err(ReadError::OutOfBounds);
1380
24.0k
        }
1381
24.0k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1382
0
            return Err(ReadError::OutOfBounds);
1383
        };
1384
24.0k
        Ok(Self { data })
1385
25.4k
    }
1386
}
1387
1388
/// The fields at the start of the table, which are read directly.
1389
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1390
#[repr(C, packed)]
1391
#[doc(hidden)]
1392
pub struct ClassDefFormat2FixedHeader {
1393
    pub class_format: BigEndian<u16>,
1394
    pub class_range_count: BigEndian<u16>,
1395
}
1396
1397
#[allow(clippy::absurd_extreme_comparisons)]
1398
const _: () =
1399
    assert!(std::mem::size_of::<ClassDefFormat2FixedHeader>() <= ClassDefFormat2::MIN_SIZE);
1400
1401
/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
1402
#[derive(Clone)]
1403
pub struct ClassDefFormat2<'a> {
1404
    data: TableDataRef<'a, ClassDefFormat2FixedHeader>,
1405
}
1406
1407
#[allow(clippy::needless_lifetimes)]
1408
impl<'a> ClassDefFormat2<'a> {
1409
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1410
    basic_table_impls!(impl_the_methods);
1411
1412
    /// Format identifier — format = 2
1413
0
    pub fn class_format(&self) -> u16 {
1414
0
        self.data.header().class_format.get()
1415
0
    }
1416
1417
    /// Number of ClassRangeRecords
1418
24.0k
    pub fn class_range_count(&self) -> u16 {
1419
24.0k
        self.data.header().class_range_count.get()
1420
24.0k
    }
1421
1422
    /// Array of ClassRangeRecords — ordered by startGlyphID
1423
24.0k
    pub fn class_range_records(&self) -> &'a [ClassRangeRecord] {
1424
24.0k
        let range = self.class_range_records_byte_range();
1425
24.0k
        self.offset_data()
1426
24.0k
            .read_array(range)
1427
24.0k
            .ok()
1428
24.0k
            .unwrap_or_default()
1429
24.0k
    }
1430
1431
24.0k
    pub fn class_format_byte_range(&self) -> Range<usize> {
1432
24.0k
        let start = 0;
1433
24.0k
        let end = start + u16::RAW_BYTE_LEN;
1434
24.0k
        start..end
1435
24.0k
    }
1436
1437
24.0k
    pub fn class_range_count_byte_range(&self) -> Range<usize> {
1438
24.0k
        let start = self.class_format_byte_range().end;
1439
24.0k
        let end = start + u16::RAW_BYTE_LEN;
1440
24.0k
        start..end
1441
24.0k
    }
1442
1443
24.0k
    pub fn class_range_records_byte_range(&self) -> Range<usize> {
1444
24.0k
        let class_range_count = self.class_range_count();
1445
24.0k
        let start = self.class_range_count_byte_range().end;
1446
24.0k
        let end = start
1447
24.0k
            + (transforms::to_usize(class_range_count))
1448
24.0k
                .saturating_mul(ClassRangeRecord::RAW_BYTE_LEN);
1449
24.0k
        start..end
1450
24.0k
    }
1451
}
1452
1453
/// Used in [ClassDefFormat2]
1454
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1455
#[repr(C)]
1456
#[repr(packed)]
1457
pub struct ClassRangeRecord {
1458
    /// First glyph ID in the range
1459
    pub start_glyph_id: BigEndian<GlyphId16>,
1460
    /// Last glyph ID in the range
1461
    pub end_glyph_id: BigEndian<GlyphId16>,
1462
    /// Applied to all glyphs in the range
1463
    pub class: BigEndian<u16>,
1464
}
1465
1466
impl ClassRangeRecord {
1467
    /// First glyph ID in the range
1468
2.37M
    pub fn start_glyph_id(&self) -> GlyphId16 {
1469
2.37M
        self.start_glyph_id.get()
1470
2.37M
    }
1471
1472
    /// Last glyph ID in the range
1473
2.37M
    pub fn end_glyph_id(&self) -> GlyphId16 {
1474
2.37M
        self.end_glyph_id.get()
1475
2.37M
    }
1476
1477
    /// Applied to all glyphs in the range
1478
447k
    pub fn class(&self) -> u16 {
1479
447k
        self.class.get()
1480
447k
    }
1481
}
1482
1483
impl FixedSize for ClassRangeRecord {
1484
    const RAW_BYTE_LEN: usize =
1485
        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1486
}
1487
1488
/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
1489
#[derive(Clone)]
1490
pub enum ClassDef<'a> {
1491
    Format1(ClassDefFormat1<'a>),
1492
    Format2(ClassDefFormat2<'a>),
1493
    Format3(ClassDefFormat3<'a>),
1494
    Format4(ClassDefFormat4<'a>),
1495
}
1496
1497
impl Default for ClassDef<'_> {
1498
0
    fn default() -> Self {
1499
0
        Self::Format1(Default::default())
1500
0
    }
1501
}
1502
1503
impl<'a> ClassDef<'a> {
1504
    ///Return the `FontData` used to resolve offsets for this table.
1505
0
    pub fn offset_data(&self) -> FontData<'a> {
1506
0
        match self {
1507
0
            Self::Format1(item) => item.offset_data(),
1508
0
            Self::Format2(item) => item.offset_data(),
1509
0
            Self::Format3(item) => item.offset_data(),
1510
0
            Self::Format4(item) => item.offset_data(),
1511
        }
1512
0
    }
1513
1514
    /// Format identifier — format = 1
1515
0
    pub fn class_format(&self) -> u16 {
1516
0
        match self {
1517
0
            Self::Format1(item) => item.class_format(),
1518
0
            Self::Format2(item) => item.class_format(),
1519
0
            Self::Format3(item) => item.class_format(),
1520
0
            Self::Format4(item) => item.class_format(),
1521
        }
1522
0
    }
1523
}
1524
1525
impl ReadArgs for ClassDef<'_> {
1526
    type Args = ();
1527
}
1528
1529
impl<'a> FontRead<'a> for ClassDef<'a> {
1530
    #[inline]
1531
379k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1532
379k
        let format: u16 = data.read_at(0usize)?;
1533
374k
        match format {
1534
33.1k
            ClassDefFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1535
25.4k
            ClassDefFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1536
7.68k
            ClassDefFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1537
7.45k
            ClassDefFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
1538
300k
            other => Err(ReadError::InvalidFormat(other.into())),
1539
        }
1540
379k
    }
1541
}
1542
1543
impl<'a> MinByteRange<'a> for ClassDef<'a> {
1544
0
    fn min_byte_range(&self) -> Range<usize> {
1545
0
        match self {
1546
0
            Self::Format1(item) => item.min_byte_range(),
1547
0
            Self::Format2(item) => item.min_byte_range(),
1548
0
            Self::Format3(item) => item.min_byte_range(),
1549
0
            Self::Format4(item) => item.min_byte_range(),
1550
        }
1551
0
    }
1552
0
    fn min_table_bytes(&self) -> &'a [u8] {
1553
0
        match self {
1554
0
            Self::Format1(item) => item.min_table_bytes(),
1555
0
            Self::Format2(item) => item.min_table_bytes(),
1556
0
            Self::Format3(item) => item.min_table_bytes(),
1557
0
            Self::Format4(item) => item.min_table_bytes(),
1558
        }
1559
0
    }
1560
}
1561
1562
/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
1563
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1564
#[repr(C)]
1565
#[repr(packed)]
1566
pub struct SequenceLookupRecord {
1567
    /// Index (zero-based) into the input glyph sequence
1568
    pub sequence_index: BigEndian<u16>,
1569
    /// Index (zero-based) into the LookupList
1570
    pub lookup_list_index: BigEndian<u16>,
1571
}
1572
1573
impl SequenceLookupRecord {
1574
    /// Index (zero-based) into the input glyph sequence
1575
0
    pub fn sequence_index(&self) -> u16 {
1576
0
        self.sequence_index.get()
1577
0
    }
1578
1579
    /// Index (zero-based) into the LookupList
1580
0
    pub fn lookup_list_index(&self) -> u16 {
1581
0
        self.lookup_list_index.get()
1582
0
    }
1583
}
1584
1585
impl FixedSize for SequenceLookupRecord {
1586
    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1587
}
1588
1589
impl Format<u16> for SequenceContextFormat1<'_> {
1590
    const FORMAT: u16 = 1;
1591
}
1592
1593
impl<'a> MinByteRange<'a> for SequenceContextFormat1<'a> {
1594
0
    fn min_byte_range(&self) -> Range<usize> {
1595
0
        0..self.seq_rule_set_offsets_byte_range().end
1596
0
    }
1597
0
    fn min_table_bytes(&self) -> &'a [u8] {
1598
0
        let range = self.min_byte_range();
1599
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1600
0
    }
1601
}
1602
1603
impl ReadArgs for SequenceContextFormat1<'_> {
1604
    type Args = ();
1605
}
1606
1607
impl<'a> FontRead<'a> for SequenceContextFormat1<'a> {
1608
26.6k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1609
        #[allow(clippy::absurd_extreme_comparisons)]
1610
26.6k
        if data.len() < Self::MIN_SIZE {
1611
365
            return Err(ReadError::OutOfBounds);
1612
26.2k
        }
1613
26.2k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1614
0
            return Err(ReadError::OutOfBounds);
1615
        };
1616
26.2k
        Ok(Self { data })
1617
26.6k
    }
1618
}
1619
1620
/// The fields at the start of the table, which are read directly.
1621
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1622
#[repr(C, packed)]
1623
#[doc(hidden)]
1624
pub struct SequenceContextFormat1FixedHeader {
1625
    pub format: BigEndian<u16>,
1626
    pub coverage_offset: BigEndian<Offset16>,
1627
    pub seq_rule_set_count: BigEndian<u16>,
1628
}
1629
1630
#[allow(clippy::absurd_extreme_comparisons)]
1631
const _: () = assert!(
1632
    std::mem::size_of::<SequenceContextFormat1FixedHeader>() <= SequenceContextFormat1::MIN_SIZE
1633
);
1634
1635
/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
1636
#[derive(Clone)]
1637
pub struct SequenceContextFormat1<'a> {
1638
    data: TableDataRef<'a, SequenceContextFormat1FixedHeader>,
1639
}
1640
1641
#[allow(clippy::needless_lifetimes)]
1642
impl<'a> SequenceContextFormat1<'a> {
1643
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1644
    basic_table_impls!(impl_the_methods);
1645
1646
    /// Format identifier: format = 1
1647
0
    pub fn format(&self) -> u16 {
1648
0
        self.data.header().format.get()
1649
0
    }
1650
1651
    /// Offset to Coverage table, from beginning of
1652
    /// SequenceContextFormat1 table
1653
26.2k
    pub fn coverage_offset(&self) -> Offset16 {
1654
26.2k
        self.data.header().coverage_offset.get()
1655
26.2k
    }
1656
1657
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1658
26.2k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1659
26.2k
        let data = self.offset_data();
1660
26.2k
        self.coverage_offset().resolve(data)
1661
26.2k
    }
1662
1663
    /// Number of SequenceRuleSet tables
1664
26.2k
    pub fn seq_rule_set_count(&self) -> u16 {
1665
26.2k
        self.data.header().seq_rule_set_count.get()
1666
26.2k
    }
1667
1668
    /// Array of offsets to SequenceRuleSet tables, from beginning of
1669
    /// SequenceContextFormat1 table (offsets may be NULL)
1670
0
    pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
1671
0
        let range = self.seq_rule_set_offsets_byte_range();
1672
0
        self.offset_data()
1673
0
            .read_array(range)
1674
0
            .ok()
1675
0
            .unwrap_or_default()
1676
0
    }
1677
1678
    /// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets].
1679
0
    pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> {
1680
0
        let data = self.offset_data();
1681
0
        let offsets = self.seq_rule_set_offsets();
1682
0
        ArrayOfNullableOffsets::new(offsets, data, ())
1683
0
    }
1684
1685
26.2k
    pub fn format_byte_range(&self) -> Range<usize> {
1686
26.2k
        let start = 0;
1687
26.2k
        let end = start + u16::RAW_BYTE_LEN;
1688
26.2k
        start..end
1689
26.2k
    }
1690
1691
26.2k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1692
26.2k
        let start = self.format_byte_range().end;
1693
26.2k
        let end = start + Offset16::RAW_BYTE_LEN;
1694
26.2k
        start..end
1695
26.2k
    }
1696
1697
26.2k
    pub fn seq_rule_set_count_byte_range(&self) -> Range<usize> {
1698
26.2k
        let start = self.coverage_offset_byte_range().end;
1699
26.2k
        let end = start + u16::RAW_BYTE_LEN;
1700
26.2k
        start..end
1701
26.2k
    }
1702
1703
26.2k
    pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
1704
26.2k
        let seq_rule_set_count = self.seq_rule_set_count();
1705
26.2k
        let start = self.seq_rule_set_count_byte_range().end;
1706
26.2k
        let end = start
1707
26.2k
            + (transforms::to_usize(seq_rule_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1708
26.2k
        start..end
1709
26.2k
    }
1710
}
1711
1712
const _: () = assert!(FontData::default_data_long_enough(
1713
    SequenceContextFormat1::MIN_SIZE
1714
));
1715
1716
impl Default for SequenceContextFormat1<'_> {
1717
0
    fn default() -> Self {
1718
        Self {
1719
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1720
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1721
        }
1722
0
    }
1723
}
1724
1725
impl<'a> MinByteRange<'a> for SequenceRuleSet<'a> {
1726
0
    fn min_byte_range(&self) -> Range<usize> {
1727
0
        0..self.seq_rule_offsets_byte_range().end
1728
0
    }
1729
0
    fn min_table_bytes(&self) -> &'a [u8] {
1730
0
        let range = self.min_byte_range();
1731
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1732
0
    }
1733
}
1734
1735
impl ReadArgs for SequenceRuleSet<'_> {
1736
    type Args = ();
1737
}
1738
1739
impl<'a> FontRead<'a> for SequenceRuleSet<'a> {
1740
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1741
        #[allow(clippy::absurd_extreme_comparisons)]
1742
0
        if data.len() < Self::MIN_SIZE {
1743
0
            return Err(ReadError::OutOfBounds);
1744
0
        }
1745
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1746
0
            return Err(ReadError::OutOfBounds);
1747
        };
1748
0
        Ok(Self { data })
1749
0
    }
1750
}
1751
1752
/// The fields at the start of the table, which are read directly.
1753
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1754
#[repr(C, packed)]
1755
#[doc(hidden)]
1756
pub struct SequenceRuleSetFixedHeader {
1757
    pub seq_rule_count: BigEndian<u16>,
1758
}
1759
1760
#[allow(clippy::absurd_extreme_comparisons)]
1761
const _: () =
1762
    assert!(std::mem::size_of::<SequenceRuleSetFixedHeader>() <= SequenceRuleSet::MIN_SIZE);
1763
1764
/// Part of [SequenceContextFormat1]
1765
#[derive(Clone)]
1766
pub struct SequenceRuleSet<'a> {
1767
    data: TableDataRef<'a, SequenceRuleSetFixedHeader>,
1768
}
1769
1770
#[allow(clippy::needless_lifetimes)]
1771
impl<'a> SequenceRuleSet<'a> {
1772
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1773
    basic_table_impls!(impl_the_methods);
1774
1775
    /// Number of SequenceRule tables
1776
0
    pub fn seq_rule_count(&self) -> u16 {
1777
0
        self.data.header().seq_rule_count.get()
1778
0
    }
1779
1780
    /// Array of offsets to SequenceRule tables, from beginning of the
1781
    /// SequenceRuleSet table
1782
0
    pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
1783
0
        let range = self.seq_rule_offsets_byte_range();
1784
0
        self.offset_data()
1785
0
            .read_array(range)
1786
0
            .ok()
1787
0
            .unwrap_or_default()
1788
0
    }
1789
1790
    /// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets].
1791
0
    pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> {
1792
0
        let data = self.offset_data();
1793
0
        let offsets = self.seq_rule_offsets();
1794
0
        ArrayOfOffsets::new(offsets, data, ())
1795
0
    }
1796
1797
0
    pub fn seq_rule_count_byte_range(&self) -> Range<usize> {
1798
0
        let start = 0;
1799
0
        let end = start + u16::RAW_BYTE_LEN;
1800
0
        start..end
1801
0
    }
1802
1803
0
    pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
1804
0
        let seq_rule_count = self.seq_rule_count();
1805
0
        let start = self.seq_rule_count_byte_range().end;
1806
0
        let end =
1807
0
            start + (transforms::to_usize(seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1808
0
        start..end
1809
0
    }
1810
}
1811
1812
const _: () = assert!(FontData::default_data_long_enough(
1813
    SequenceRuleSet::MIN_SIZE
1814
));
1815
1816
impl Default for SequenceRuleSet<'_> {
1817
0
    fn default() -> Self {
1818
        Self {
1819
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1820
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1821
        }
1822
0
    }
1823
}
1824
1825
impl<'a> MinByteRange<'a> for SequenceRule<'a> {
1826
0
    fn min_byte_range(&self) -> Range<usize> {
1827
0
        0..self.seq_lookup_records_byte_range().end
1828
0
    }
1829
0
    fn min_table_bytes(&self) -> &'a [u8] {
1830
0
        let range = self.min_byte_range();
1831
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1832
0
    }
1833
}
1834
1835
impl ReadArgs for SequenceRule<'_> {
1836
    type Args = ();
1837
}
1838
1839
impl<'a> FontRead<'a> for SequenceRule<'a> {
1840
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1841
        #[allow(clippy::absurd_extreme_comparisons)]
1842
0
        if data.len() < Self::MIN_SIZE {
1843
0
            return Err(ReadError::OutOfBounds);
1844
0
        }
1845
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1846
0
            return Err(ReadError::OutOfBounds);
1847
        };
1848
0
        Ok(Self { data })
1849
0
    }
1850
}
1851
1852
/// The fields at the start of the table, which are read directly.
1853
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1854
#[repr(C, packed)]
1855
#[doc(hidden)]
1856
pub struct SequenceRuleFixedHeader {
1857
    pub glyph_count: BigEndian<u16>,
1858
    pub seq_lookup_count: BigEndian<u16>,
1859
}
1860
1861
#[allow(clippy::absurd_extreme_comparisons)]
1862
const _: () = assert!(std::mem::size_of::<SequenceRuleFixedHeader>() <= SequenceRule::MIN_SIZE);
1863
1864
/// Part of [SequenceContextFormat1]
1865
#[derive(Clone)]
1866
pub struct SequenceRule<'a> {
1867
    data: TableDataRef<'a, SequenceRuleFixedHeader>,
1868
}
1869
1870
#[allow(clippy::needless_lifetimes)]
1871
impl<'a> SequenceRule<'a> {
1872
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1873
    basic_table_impls!(impl_the_methods);
1874
1875
    /// Number of glyphs in the input glyph sequence
1876
0
    pub fn glyph_count(&self) -> u16 {
1877
0
        self.data.header().glyph_count.get()
1878
0
    }
1879
1880
    /// Number of SequenceLookupRecords
1881
0
    pub fn seq_lookup_count(&self) -> u16 {
1882
0
        self.data.header().seq_lookup_count.get()
1883
0
    }
1884
1885
    /// Array of input glyph IDs—starting with the second glyph
1886
0
    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
1887
0
        let range = self.input_sequence_byte_range();
1888
0
        self.offset_data()
1889
0
            .read_array(range)
1890
0
            .ok()
1891
0
            .unwrap_or_default()
1892
0
    }
1893
1894
    /// Array of Sequence lookup records
1895
0
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
1896
0
        let range = self.seq_lookup_records_byte_range();
1897
0
        self.offset_data()
1898
0
            .read_array(range)
1899
0
            .ok()
1900
0
            .unwrap_or_default()
1901
0
    }
1902
1903
0
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1904
0
        let start = 0;
1905
0
        let end = start + u16::RAW_BYTE_LEN;
1906
0
        start..end
1907
0
    }
1908
1909
0
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
1910
0
        let start = self.glyph_count_byte_range().end;
1911
0
        let end = start + u16::RAW_BYTE_LEN;
1912
0
        start..end
1913
0
    }
1914
1915
0
    pub fn input_sequence_byte_range(&self) -> Range<usize> {
1916
0
        let glyph_count = self.glyph_count();
1917
0
        let start = self.seq_lookup_count_byte_range().end;
1918
0
        let end = start
1919
0
            + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
1920
0
        start..end
1921
0
    }
1922
1923
0
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
1924
0
        let seq_lookup_count = self.seq_lookup_count();
1925
0
        let start = self.input_sequence_byte_range().end;
1926
0
        let end = start
1927
0
            + (transforms::to_usize(seq_lookup_count))
1928
0
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
1929
0
        start..end
1930
0
    }
1931
}
1932
1933
const _: () = assert!(FontData::default_data_long_enough(SequenceRule::MIN_SIZE));
1934
1935
impl Default for SequenceRule<'_> {
1936
0
    fn default() -> Self {
1937
        Self {
1938
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1939
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1940
        }
1941
0
    }
1942
}
1943
1944
impl Format<u16> for SequenceContextFormat2<'_> {
1945
    const FORMAT: u16 = 2;
1946
}
1947
1948
impl<'a> MinByteRange<'a> for SequenceContextFormat2<'a> {
1949
0
    fn min_byte_range(&self) -> Range<usize> {
1950
0
        0..self.class_seq_rule_set_offsets_byte_range().end
1951
0
    }
1952
0
    fn min_table_bytes(&self) -> &'a [u8] {
1953
0
        let range = self.min_byte_range();
1954
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1955
0
    }
1956
}
1957
1958
impl ReadArgs for SequenceContextFormat2<'_> {
1959
    type Args = ();
1960
}
1961
1962
impl<'a> FontRead<'a> for SequenceContextFormat2<'a> {
1963
30.1k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1964
        #[allow(clippy::absurd_extreme_comparisons)]
1965
30.1k
        if data.len() < Self::MIN_SIZE {
1966
278
            return Err(ReadError::OutOfBounds);
1967
29.8k
        }
1968
29.8k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1969
0
            return Err(ReadError::OutOfBounds);
1970
        };
1971
29.8k
        Ok(Self { data })
1972
30.1k
    }
1973
}
1974
1975
/// The fields at the start of the table, which are read directly.
1976
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1977
#[repr(C, packed)]
1978
#[doc(hidden)]
1979
pub struct SequenceContextFormat2FixedHeader {
1980
    pub format: BigEndian<u16>,
1981
    pub coverage_offset: BigEndian<Offset16>,
1982
    pub class_def_offset: BigEndian<Offset16>,
1983
    pub class_seq_rule_set_count: BigEndian<u16>,
1984
}
1985
1986
#[allow(clippy::absurd_extreme_comparisons)]
1987
const _: () = assert!(
1988
    std::mem::size_of::<SequenceContextFormat2FixedHeader>() <= SequenceContextFormat2::MIN_SIZE
1989
);
1990
1991
/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
1992
#[derive(Clone)]
1993
pub struct SequenceContextFormat2<'a> {
1994
    data: TableDataRef<'a, SequenceContextFormat2FixedHeader>,
1995
}
1996
1997
#[allow(clippy::needless_lifetimes)]
1998
impl<'a> SequenceContextFormat2<'a> {
1999
    pub const MIN_SIZE: usize =
2000
        (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2001
    basic_table_impls!(impl_the_methods);
2002
2003
    /// Format identifier: format = 2
2004
0
    pub fn format(&self) -> u16 {
2005
0
        self.data.header().format.get()
2006
0
    }
2007
2008
    /// Offset to Coverage table, from beginning of
2009
    /// SequenceContextFormat2 table
2010
29.8k
    pub fn coverage_offset(&self) -> Offset16 {
2011
29.8k
        self.data.header().coverage_offset.get()
2012
29.8k
    }
2013
2014
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2015
29.8k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2016
29.8k
        let data = self.offset_data();
2017
29.8k
        self.coverage_offset().resolve(data)
2018
29.8k
    }
2019
2020
    /// Offset to ClassDef table, from beginning of
2021
    /// SequenceContextFormat2 table
2022
29.8k
    pub fn class_def_offset(&self) -> Offset16 {
2023
29.8k
        self.data.header().class_def_offset.get()
2024
29.8k
    }
2025
2026
    /// Attempt to resolve [`class_def_offset`][Self::class_def_offset].
2027
29.8k
    pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
2028
29.8k
        let data = self.offset_data();
2029
29.8k
        self.class_def_offset().resolve(data)
2030
29.8k
    }
2031
2032
    /// Number of ClassSequenceRuleSet tables
2033
29.8k
    pub fn class_seq_rule_set_count(&self) -> u16 {
2034
29.8k
        self.data.header().class_seq_rule_set_count.get()
2035
29.8k
    }
2036
2037
    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
2038
    /// of SequenceContextFormat2 table (may be NULL)
2039
0
    pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2040
0
        let range = self.class_seq_rule_set_offsets_byte_range();
2041
0
        self.offset_data()
2042
0
            .read_array(range)
2043
0
            .ok()
2044
0
            .unwrap_or_default()
2045
0
    }
2046
2047
    /// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets].
2048
0
    pub fn class_seq_rule_sets(
2049
0
        &self,
2050
0
    ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> {
2051
0
        let data = self.offset_data();
2052
0
        let offsets = self.class_seq_rule_set_offsets();
2053
0
        ArrayOfNullableOffsets::new(offsets, data, ())
2054
0
    }
2055
2056
29.8k
    pub fn format_byte_range(&self) -> Range<usize> {
2057
29.8k
        let start = 0;
2058
29.8k
        let end = start + u16::RAW_BYTE_LEN;
2059
29.8k
        start..end
2060
29.8k
    }
2061
2062
29.8k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2063
29.8k
        let start = self.format_byte_range().end;
2064
29.8k
        let end = start + Offset16::RAW_BYTE_LEN;
2065
29.8k
        start..end
2066
29.8k
    }
2067
2068
29.8k
    pub fn class_def_offset_byte_range(&self) -> Range<usize> {
2069
29.8k
        let start = self.coverage_offset_byte_range().end;
2070
29.8k
        let end = start + Offset16::RAW_BYTE_LEN;
2071
29.8k
        start..end
2072
29.8k
    }
2073
2074
29.8k
    pub fn class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2075
29.8k
        let start = self.class_def_offset_byte_range().end;
2076
29.8k
        let end = start + u16::RAW_BYTE_LEN;
2077
29.8k
        start..end
2078
29.8k
    }
2079
2080
29.8k
    pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2081
29.8k
        let class_seq_rule_set_count = self.class_seq_rule_set_count();
2082
29.8k
        let start = self.class_seq_rule_set_count_byte_range().end;
2083
29.8k
        let end = start
2084
29.8k
            + (transforms::to_usize(class_seq_rule_set_count))
2085
29.8k
                .saturating_mul(Offset16::RAW_BYTE_LEN);
2086
29.8k
        start..end
2087
29.8k
    }
2088
}
2089
2090
impl<'a> MinByteRange<'a> for ClassSequenceRuleSet<'a> {
2091
0
    fn min_byte_range(&self) -> Range<usize> {
2092
0
        0..self.class_seq_rule_offsets_byte_range().end
2093
0
    }
2094
0
    fn min_table_bytes(&self) -> &'a [u8] {
2095
0
        let range = self.min_byte_range();
2096
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2097
0
    }
2098
}
2099
2100
impl ReadArgs for ClassSequenceRuleSet<'_> {
2101
    type Args = ();
2102
}
2103
2104
impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> {
2105
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2106
        #[allow(clippy::absurd_extreme_comparisons)]
2107
0
        if data.len() < Self::MIN_SIZE {
2108
0
            return Err(ReadError::OutOfBounds);
2109
0
        }
2110
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2111
0
            return Err(ReadError::OutOfBounds);
2112
        };
2113
0
        Ok(Self { data })
2114
0
    }
2115
}
2116
2117
/// The fields at the start of the table, which are read directly.
2118
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2119
#[repr(C, packed)]
2120
#[doc(hidden)]
2121
pub struct ClassSequenceRuleSetFixedHeader {
2122
    pub class_seq_rule_count: BigEndian<u16>,
2123
}
2124
2125
#[allow(clippy::absurd_extreme_comparisons)]
2126
const _: () = assert!(
2127
    std::mem::size_of::<ClassSequenceRuleSetFixedHeader>() <= ClassSequenceRuleSet::MIN_SIZE
2128
);
2129
2130
/// Part of [SequenceContextFormat2]
2131
#[derive(Clone)]
2132
pub struct ClassSequenceRuleSet<'a> {
2133
    data: TableDataRef<'a, ClassSequenceRuleSetFixedHeader>,
2134
}
2135
2136
#[allow(clippy::needless_lifetimes)]
2137
impl<'a> ClassSequenceRuleSet<'a> {
2138
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2139
    basic_table_impls!(impl_the_methods);
2140
2141
    /// Number of ClassSequenceRule tables
2142
0
    pub fn class_seq_rule_count(&self) -> u16 {
2143
0
        self.data.header().class_seq_rule_count.get()
2144
0
    }
2145
2146
    /// Array of offsets to ClassSequenceRule tables, from beginning of
2147
    /// ClassSequenceRuleSet table
2148
0
    pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2149
0
        let range = self.class_seq_rule_offsets_byte_range();
2150
0
        self.offset_data()
2151
0
            .read_array(range)
2152
0
            .ok()
2153
0
            .unwrap_or_default()
2154
0
    }
2155
2156
    /// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets].
2157
0
    pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> {
2158
0
        let data = self.offset_data();
2159
0
        let offsets = self.class_seq_rule_offsets();
2160
0
        ArrayOfOffsets::new(offsets, data, ())
2161
0
    }
2162
2163
0
    pub fn class_seq_rule_count_byte_range(&self) -> Range<usize> {
2164
0
        let start = 0;
2165
0
        let end = start + u16::RAW_BYTE_LEN;
2166
0
        start..end
2167
0
    }
2168
2169
0
    pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2170
0
        let class_seq_rule_count = self.class_seq_rule_count();
2171
0
        let start = self.class_seq_rule_count_byte_range().end;
2172
0
        let end = start
2173
0
            + (transforms::to_usize(class_seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
2174
0
        start..end
2175
0
    }
2176
}
2177
2178
const _: () = assert!(FontData::default_data_long_enough(
2179
    ClassSequenceRuleSet::MIN_SIZE
2180
));
2181
2182
impl Default for ClassSequenceRuleSet<'_> {
2183
0
    fn default() -> Self {
2184
        Self {
2185
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
2186
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2187
        }
2188
0
    }
2189
}
2190
2191
impl<'a> MinByteRange<'a> for ClassSequenceRule<'a> {
2192
0
    fn min_byte_range(&self) -> Range<usize> {
2193
0
        0..self.seq_lookup_records_byte_range().end
2194
0
    }
2195
0
    fn min_table_bytes(&self) -> &'a [u8] {
2196
0
        let range = self.min_byte_range();
2197
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2198
0
    }
2199
}
2200
2201
impl ReadArgs for ClassSequenceRule<'_> {
2202
    type Args = ();
2203
}
2204
2205
impl<'a> FontRead<'a> for ClassSequenceRule<'a> {
2206
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2207
        #[allow(clippy::absurd_extreme_comparisons)]
2208
0
        if data.len() < Self::MIN_SIZE {
2209
0
            return Err(ReadError::OutOfBounds);
2210
0
        }
2211
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2212
0
            return Err(ReadError::OutOfBounds);
2213
        };
2214
0
        Ok(Self { data })
2215
0
    }
2216
}
2217
2218
/// The fields at the start of the table, which are read directly.
2219
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2220
#[repr(C, packed)]
2221
#[doc(hidden)]
2222
pub struct ClassSequenceRuleFixedHeader {
2223
    pub glyph_count: BigEndian<u16>,
2224
    pub seq_lookup_count: BigEndian<u16>,
2225
}
2226
2227
#[allow(clippy::absurd_extreme_comparisons)]
2228
const _: () =
2229
    assert!(std::mem::size_of::<ClassSequenceRuleFixedHeader>() <= ClassSequenceRule::MIN_SIZE);
2230
2231
/// Part of [SequenceContextFormat2]
2232
#[derive(Clone)]
2233
pub struct ClassSequenceRule<'a> {
2234
    data: TableDataRef<'a, ClassSequenceRuleFixedHeader>,
2235
}
2236
2237
#[allow(clippy::needless_lifetimes)]
2238
impl<'a> ClassSequenceRule<'a> {
2239
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2240
    basic_table_impls!(impl_the_methods);
2241
2242
    /// Number of glyphs to be matched
2243
0
    pub fn glyph_count(&self) -> u16 {
2244
0
        self.data.header().glyph_count.get()
2245
0
    }
2246
2247
    /// Number of SequenceLookupRecords
2248
0
    pub fn seq_lookup_count(&self) -> u16 {
2249
0
        self.data.header().seq_lookup_count.get()
2250
0
    }
2251
2252
    /// Sequence of classes to be matched to the input glyph sequence,
2253
    /// beginning with the second glyph position
2254
0
    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
2255
0
        let range = self.input_sequence_byte_range();
2256
0
        self.offset_data()
2257
0
            .read_array(range)
2258
0
            .ok()
2259
0
            .unwrap_or_default()
2260
0
    }
2261
2262
    /// Array of SequenceLookupRecords
2263
0
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2264
0
        let range = self.seq_lookup_records_byte_range();
2265
0
        self.offset_data()
2266
0
            .read_array(range)
2267
0
            .ok()
2268
0
            .unwrap_or_default()
2269
0
    }
2270
2271
0
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2272
0
        let start = 0;
2273
0
        let end = start + u16::RAW_BYTE_LEN;
2274
0
        start..end
2275
0
    }
2276
2277
0
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2278
0
        let start = self.glyph_count_byte_range().end;
2279
0
        let end = start + u16::RAW_BYTE_LEN;
2280
0
        start..end
2281
0
    }
2282
2283
0
    pub fn input_sequence_byte_range(&self) -> Range<usize> {
2284
0
        let glyph_count = self.glyph_count();
2285
0
        let start = self.seq_lookup_count_byte_range().end;
2286
0
        let end =
2287
0
            start + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(u16::RAW_BYTE_LEN);
2288
0
        start..end
2289
0
    }
2290
2291
0
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2292
0
        let seq_lookup_count = self.seq_lookup_count();
2293
0
        let start = self.input_sequence_byte_range().end;
2294
0
        let end = start
2295
0
            + (transforms::to_usize(seq_lookup_count))
2296
0
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
2297
0
        start..end
2298
0
    }
2299
}
2300
2301
const _: () = assert!(FontData::default_data_long_enough(
2302
    ClassSequenceRule::MIN_SIZE
2303
));
2304
2305
impl Default for ClassSequenceRule<'_> {
2306
0
    fn default() -> Self {
2307
        Self {
2308
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
2309
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2310
        }
2311
0
    }
2312
}
2313
2314
impl Format<u16> for SequenceContextFormat3<'_> {
2315
    const FORMAT: u16 = 3;
2316
}
2317
2318
impl<'a> MinByteRange<'a> for SequenceContextFormat3<'a> {
2319
0
    fn min_byte_range(&self) -> Range<usize> {
2320
0
        0..self.seq_lookup_records_byte_range().end
2321
0
    }
2322
0
    fn min_table_bytes(&self) -> &'a [u8] {
2323
0
        let range = self.min_byte_range();
2324
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2325
0
    }
2326
}
2327
2328
impl ReadArgs for SequenceContextFormat3<'_> {
2329
    type Args = ();
2330
}
2331
2332
impl<'a> FontRead<'a> for SequenceContextFormat3<'a> {
2333
11.2k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2334
        #[allow(clippy::absurd_extreme_comparisons)]
2335
11.2k
        if data.len() < Self::MIN_SIZE {
2336
287
            return Err(ReadError::OutOfBounds);
2337
10.9k
        }
2338
10.9k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2339
0
            return Err(ReadError::OutOfBounds);
2340
        };
2341
10.9k
        Ok(Self { data })
2342
11.2k
    }
2343
}
2344
2345
/// The fields at the start of the table, which are read directly.
2346
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2347
#[repr(C, packed)]
2348
#[doc(hidden)]
2349
pub struct SequenceContextFormat3FixedHeader {
2350
    pub format: BigEndian<u16>,
2351
    pub glyph_count: BigEndian<u16>,
2352
    pub seq_lookup_count: BigEndian<u16>,
2353
}
2354
2355
#[allow(clippy::absurd_extreme_comparisons)]
2356
const _: () = assert!(
2357
    std::mem::size_of::<SequenceContextFormat3FixedHeader>() <= SequenceContextFormat3::MIN_SIZE
2358
);
2359
2360
/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
2361
#[derive(Clone)]
2362
pub struct SequenceContextFormat3<'a> {
2363
    data: TableDataRef<'a, SequenceContextFormat3FixedHeader>,
2364
}
2365
2366
#[allow(clippy::needless_lifetimes)]
2367
impl<'a> SequenceContextFormat3<'a> {
2368
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2369
    basic_table_impls!(impl_the_methods);
2370
2371
    /// Format identifier: format = 3
2372
0
    pub fn format(&self) -> u16 {
2373
0
        self.data.header().format.get()
2374
0
    }
2375
2376
    /// Number of glyphs in the input sequence
2377
32.9k
    pub fn glyph_count(&self) -> u16 {
2378
32.9k
        self.data.header().glyph_count.get()
2379
32.9k
    }
2380
2381
    /// Number of SequenceLookupRecords
2382
10.9k
    pub fn seq_lookup_count(&self) -> u16 {
2383
10.9k
        self.data.header().seq_lookup_count.get()
2384
10.9k
    }
2385
2386
    /// Array of offsets to Coverage tables, from beginning of
2387
    /// SequenceContextFormat3 subtable
2388
10.9k
    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
2389
10.9k
        let range = self.coverage_offsets_byte_range();
2390
10.9k
        self.offset_data()
2391
10.9k
            .read_array(range)
2392
10.9k
            .ok()
2393
10.9k
            .unwrap_or_default()
2394
10.9k
    }
2395
2396
    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
2397
10.9k
    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
2398
10.9k
        let data = self.offset_data();
2399
10.9k
        let offsets = self.coverage_offsets();
2400
10.9k
        ArrayOfOffsets::new(offsets, data, ())
2401
10.9k
    }
2402
2403
    /// Array of SequenceLookupRecords
2404
10.9k
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2405
10.9k
        let range = self.seq_lookup_records_byte_range();
2406
10.9k
        self.offset_data()
2407
10.9k
            .read_array(range)
2408
10.9k
            .ok()
2409
10.9k
            .unwrap_or_default()
2410
10.9k
    }
2411
2412
32.9k
    pub fn format_byte_range(&self) -> Range<usize> {
2413
32.9k
        let start = 0;
2414
32.9k
        let end = start + u16::RAW_BYTE_LEN;
2415
32.9k
        start..end
2416
32.9k
    }
2417
2418
32.9k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2419
32.9k
        let start = self.format_byte_range().end;
2420
32.9k
        let end = start + u16::RAW_BYTE_LEN;
2421
32.9k
        start..end
2422
32.9k
    }
2423
2424
32.9k
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2425
32.9k
        let start = self.glyph_count_byte_range().end;
2426
32.9k
        let end = start + u16::RAW_BYTE_LEN;
2427
32.9k
        start..end
2428
32.9k
    }
2429
2430
32.9k
    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
2431
32.9k
        let glyph_count = self.glyph_count();
2432
32.9k
        let start = self.seq_lookup_count_byte_range().end;
2433
32.9k
        let end =
2434
32.9k
            start + (transforms::to_usize(glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
2435
32.9k
        start..end
2436
32.9k
    }
2437
2438
10.9k
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2439
10.9k
        let seq_lookup_count = self.seq_lookup_count();
2440
10.9k
        let start = self.coverage_offsets_byte_range().end;
2441
10.9k
        let end = start
2442
10.9k
            + (transforms::to_usize(seq_lookup_count))
2443
10.9k
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
2444
10.9k
        start..end
2445
10.9k
    }
2446
}
2447
2448
#[derive(Clone)]
2449
pub enum SequenceContext<'a> {
2450
    Format1(SequenceContextFormat1<'a>),
2451
    Format2(SequenceContextFormat2<'a>),
2452
    Format3(SequenceContextFormat3<'a>),
2453
    Format4(SequenceContextFormat4<'a>),
2454
    Format5(SequenceContextFormat5<'a>),
2455
    Format6(SequenceContextFormat6<'a>),
2456
}
2457
2458
impl Default for SequenceContext<'_> {
2459
0
    fn default() -> Self {
2460
0
        Self::Format1(Default::default())
2461
0
    }
2462
}
2463
2464
impl<'a> SequenceContext<'a> {
2465
    ///Return the `FontData` used to resolve offsets for this table.
2466
0
    pub fn offset_data(&self) -> FontData<'a> {
2467
0
        match self {
2468
0
            Self::Format1(item) => item.offset_data(),
2469
0
            Self::Format2(item) => item.offset_data(),
2470
0
            Self::Format3(item) => item.offset_data(),
2471
0
            Self::Format4(item) => item.offset_data(),
2472
0
            Self::Format5(item) => item.offset_data(),
2473
0
            Self::Format6(item) => item.offset_data(),
2474
        }
2475
0
    }
2476
2477
    /// Format identifier: format = 1
2478
0
    pub fn format(&self) -> u16 {
2479
0
        match self {
2480
0
            Self::Format1(item) => item.format(),
2481
0
            Self::Format2(item) => item.format(),
2482
0
            Self::Format3(item) => item.format(),
2483
0
            Self::Format4(item) => item.format(),
2484
0
            Self::Format5(item) => item.format(),
2485
0
            Self::Format6(item) => item.format(),
2486
        }
2487
0
    }
2488
}
2489
2490
impl ReadArgs for SequenceContext<'_> {
2491
    type Args = ();
2492
}
2493
2494
impl<'a> FontRead<'a> for SequenceContext<'a> {
2495
    #[inline]
2496
964k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2497
964k
        let format: u16 = data.read_at(0usize)?;
2498
963k
        match format {
2499
26.6k
            SequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
2500
30.1k
            SequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
2501
11.2k
            SequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
2502
3.63k
            SequenceContextFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
2503
158k
            SequenceContextFormat5::FORMAT => Ok(Self::Format5(FontRead::read(data)?)),
2504
6.53k
            SequenceContextFormat6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
2505
727k
            other => Err(ReadError::InvalidFormat(other.into())),
2506
        }
2507
964k
    }
<read_fonts::tables::layout::SequenceContext as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
2496
964k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2497
964k
        let format: u16 = data.read_at(0usize)?;
2498
963k
        match format {
2499
26.6k
            SequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
2500
30.1k
            SequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
2501
11.2k
            SequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
2502
3.63k
            SequenceContextFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
2503
158k
            SequenceContextFormat5::FORMAT => Ok(Self::Format5(FontRead::read(data)?)),
2504
6.53k
            SequenceContextFormat6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
2505
727k
            other => Err(ReadError::InvalidFormat(other.into())),
2506
        }
2507
964k
    }
Unexecuted instantiation: <read_fonts::tables::layout::SequenceContext as read_fonts::read::FontRead>::read_with_args
2508
}
2509
2510
impl<'a> MinByteRange<'a> for SequenceContext<'a> {
2511
0
    fn min_byte_range(&self) -> Range<usize> {
2512
0
        match self {
2513
0
            Self::Format1(item) => item.min_byte_range(),
2514
0
            Self::Format2(item) => item.min_byte_range(),
2515
0
            Self::Format3(item) => item.min_byte_range(),
2516
0
            Self::Format4(item) => item.min_byte_range(),
2517
0
            Self::Format5(item) => item.min_byte_range(),
2518
0
            Self::Format6(item) => item.min_byte_range(),
2519
        }
2520
0
    }
2521
0
    fn min_table_bytes(&self) -> &'a [u8] {
2522
0
        match self {
2523
0
            Self::Format1(item) => item.min_table_bytes(),
2524
0
            Self::Format2(item) => item.min_table_bytes(),
2525
0
            Self::Format3(item) => item.min_table_bytes(),
2526
0
            Self::Format4(item) => item.min_table_bytes(),
2527
0
            Self::Format5(item) => item.min_table_bytes(),
2528
0
            Self::Format6(item) => item.min_table_bytes(),
2529
        }
2530
0
    }
2531
}
2532
2533
impl Format<u16> for ChainedSequenceContextFormat1<'_> {
2534
    const FORMAT: u16 = 1;
2535
}
2536
2537
impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat1<'a> {
2538
0
    fn min_byte_range(&self) -> Range<usize> {
2539
0
        0..self.chained_seq_rule_set_offsets_byte_range().end
2540
0
    }
2541
0
    fn min_table_bytes(&self) -> &'a [u8] {
2542
0
        let range = self.min_byte_range();
2543
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2544
0
    }
2545
}
2546
2547
impl ReadArgs for ChainedSequenceContextFormat1<'_> {
2548
    type Args = ();
2549
}
2550
2551
impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> {
2552
32.5k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2553
        #[allow(clippy::absurd_extreme_comparisons)]
2554
32.5k
        if data.len() < Self::MIN_SIZE {
2555
232
            return Err(ReadError::OutOfBounds);
2556
32.3k
        }
2557
32.3k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2558
0
            return Err(ReadError::OutOfBounds);
2559
        };
2560
32.3k
        Ok(Self { data })
2561
32.5k
    }
2562
}
2563
2564
/// The fields at the start of the table, which are read directly.
2565
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2566
#[repr(C, packed)]
2567
#[doc(hidden)]
2568
pub struct ChainedSequenceContextFormat1FixedHeader {
2569
    pub format: BigEndian<u16>,
2570
    pub coverage_offset: BigEndian<Offset16>,
2571
    pub chained_seq_rule_set_count: BigEndian<u16>,
2572
}
2573
2574
#[allow(clippy::absurd_extreme_comparisons)]
2575
const _: () = assert!(
2576
    std::mem::size_of::<ChainedSequenceContextFormat1FixedHeader>()
2577
        <= ChainedSequenceContextFormat1::MIN_SIZE
2578
);
2579
2580
/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
2581
#[derive(Clone)]
2582
pub struct ChainedSequenceContextFormat1<'a> {
2583
    data: TableDataRef<'a, ChainedSequenceContextFormat1FixedHeader>,
2584
}
2585
2586
#[allow(clippy::needless_lifetimes)]
2587
impl<'a> ChainedSequenceContextFormat1<'a> {
2588
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2589
    basic_table_impls!(impl_the_methods);
2590
2591
    /// Format identifier: format = 1
2592
0
    pub fn format(&self) -> u16 {
2593
0
        self.data.header().format.get()
2594
0
    }
2595
2596
    /// Offset to Coverage table, from beginning of
2597
    /// ChainSequenceContextFormat1 table
2598
32.3k
    pub fn coverage_offset(&self) -> Offset16 {
2599
32.3k
        self.data.header().coverage_offset.get()
2600
32.3k
    }
2601
2602
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2603
32.3k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2604
32.3k
        let data = self.offset_data();
2605
32.3k
        self.coverage_offset().resolve(data)
2606
32.3k
    }
2607
2608
    /// Number of ChainedSequenceRuleSet tables
2609
32.3k
    pub fn chained_seq_rule_set_count(&self) -> u16 {
2610
32.3k
        self.data.header().chained_seq_rule_set_count.get()
2611
32.3k
    }
2612
2613
    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
2614
    /// ChainedSequenceContextFormat1 table (may be NULL)
2615
0
    pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2616
0
        let range = self.chained_seq_rule_set_offsets_byte_range();
2617
0
        self.offset_data()
2618
0
            .read_array(range)
2619
0
            .ok()
2620
0
            .unwrap_or_default()
2621
0
    }
2622
2623
    /// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets].
2624
0
    pub fn chained_seq_rule_sets(
2625
0
        &self,
2626
0
    ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> {
2627
0
        let data = self.offset_data();
2628
0
        let offsets = self.chained_seq_rule_set_offsets();
2629
0
        ArrayOfNullableOffsets::new(offsets, data, ())
2630
0
    }
2631
2632
32.3k
    pub fn format_byte_range(&self) -> Range<usize> {
2633
32.3k
        let start = 0;
2634
32.3k
        let end = start + u16::RAW_BYTE_LEN;
2635
32.3k
        start..end
2636
32.3k
    }
2637
2638
32.3k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2639
32.3k
        let start = self.format_byte_range().end;
2640
32.3k
        let end = start + Offset16::RAW_BYTE_LEN;
2641
32.3k
        start..end
2642
32.3k
    }
2643
2644
32.3k
    pub fn chained_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2645
32.3k
        let start = self.coverage_offset_byte_range().end;
2646
32.3k
        let end = start + u16::RAW_BYTE_LEN;
2647
32.3k
        start..end
2648
32.3k
    }
2649
2650
32.3k
    pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2651
32.3k
        let chained_seq_rule_set_count = self.chained_seq_rule_set_count();
2652
32.3k
        let start = self.chained_seq_rule_set_count_byte_range().end;
2653
32.3k
        let end = start
2654
32.3k
            + (transforms::to_usize(chained_seq_rule_set_count))
2655
32.3k
                .saturating_mul(Offset16::RAW_BYTE_LEN);
2656
32.3k
        start..end
2657
32.3k
    }
2658
}
2659
2660
const _: () = assert!(FontData::default_data_long_enough(
2661
    ChainedSequenceContextFormat1::MIN_SIZE
2662
));
2663
2664
impl Default for ChainedSequenceContextFormat1<'_> {
2665
0
    fn default() -> Self {
2666
        Self {
2667
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
2668
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2669
        }
2670
0
    }
2671
}
2672
2673
impl<'a> MinByteRange<'a> for ChainedSequenceRuleSet<'a> {
2674
0
    fn min_byte_range(&self) -> Range<usize> {
2675
0
        0..self.chained_seq_rule_offsets_byte_range().end
2676
0
    }
2677
0
    fn min_table_bytes(&self) -> &'a [u8] {
2678
0
        let range = self.min_byte_range();
2679
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2680
0
    }
2681
}
2682
2683
impl ReadArgs for ChainedSequenceRuleSet<'_> {
2684
    type Args = ();
2685
}
2686
2687
impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> {
2688
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2689
        #[allow(clippy::absurd_extreme_comparisons)]
2690
0
        if data.len() < Self::MIN_SIZE {
2691
0
            return Err(ReadError::OutOfBounds);
2692
0
        }
2693
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2694
0
            return Err(ReadError::OutOfBounds);
2695
        };
2696
0
        Ok(Self { data })
2697
0
    }
2698
}
2699
2700
/// The fields at the start of the table, which are read directly.
2701
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2702
#[repr(C, packed)]
2703
#[doc(hidden)]
2704
pub struct ChainedSequenceRuleSetFixedHeader {
2705
    pub chained_seq_rule_count: BigEndian<u16>,
2706
}
2707
2708
#[allow(clippy::absurd_extreme_comparisons)]
2709
const _: () = assert!(
2710
    std::mem::size_of::<ChainedSequenceRuleSetFixedHeader>() <= ChainedSequenceRuleSet::MIN_SIZE
2711
);
2712
2713
/// Part of [ChainedSequenceContextFormat1]
2714
#[derive(Clone)]
2715
pub struct ChainedSequenceRuleSet<'a> {
2716
    data: TableDataRef<'a, ChainedSequenceRuleSetFixedHeader>,
2717
}
2718
2719
#[allow(clippy::needless_lifetimes)]
2720
impl<'a> ChainedSequenceRuleSet<'a> {
2721
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2722
    basic_table_impls!(impl_the_methods);
2723
2724
    /// Number of ChainedSequenceRule tables
2725
0
    pub fn chained_seq_rule_count(&self) -> u16 {
2726
0
        self.data.header().chained_seq_rule_count.get()
2727
0
    }
2728
2729
    /// Array of offsets to ChainedSequenceRule tables, from beginning
2730
    /// of ChainedSequenceRuleSet table
2731
0
    pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2732
0
        let range = self.chained_seq_rule_offsets_byte_range();
2733
0
        self.offset_data()
2734
0
            .read_array(range)
2735
0
            .ok()
2736
0
            .unwrap_or_default()
2737
0
    }
2738
2739
    /// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets].
2740
0
    pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> {
2741
0
        let data = self.offset_data();
2742
0
        let offsets = self.chained_seq_rule_offsets();
2743
0
        ArrayOfOffsets::new(offsets, data, ())
2744
0
    }
2745
2746
0
    pub fn chained_seq_rule_count_byte_range(&self) -> Range<usize> {
2747
0
        let start = 0;
2748
0
        let end = start + u16::RAW_BYTE_LEN;
2749
0
        start..end
2750
0
    }
2751
2752
0
    pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2753
0
        let chained_seq_rule_count = self.chained_seq_rule_count();
2754
0
        let start = self.chained_seq_rule_count_byte_range().end;
2755
0
        let end = start
2756
0
            + (transforms::to_usize(chained_seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
2757
0
        start..end
2758
0
    }
2759
}
2760
2761
const _: () = assert!(FontData::default_data_long_enough(
2762
    ChainedSequenceRuleSet::MIN_SIZE
2763
));
2764
2765
impl Default for ChainedSequenceRuleSet<'_> {
2766
0
    fn default() -> Self {
2767
        Self {
2768
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
2769
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2770
        }
2771
0
    }
2772
}
2773
2774
impl<'a> MinByteRange<'a> for ChainedSequenceRule<'a> {
2775
0
    fn min_byte_range(&self) -> Range<usize> {
2776
0
        0..self.seq_lookup_records_byte_range().end
2777
0
    }
2778
0
    fn min_table_bytes(&self) -> &'a [u8] {
2779
0
        let range = self.min_byte_range();
2780
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2781
0
    }
2782
}
2783
2784
impl ReadArgs for ChainedSequenceRule<'_> {
2785
    type Args = ();
2786
}
2787
2788
impl<'a> FontRead<'a> for ChainedSequenceRule<'a> {
2789
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2790
        #[allow(clippy::absurd_extreme_comparisons)]
2791
0
        if data.len() < Self::MIN_SIZE {
2792
0
            return Err(ReadError::OutOfBounds);
2793
0
        }
2794
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2795
0
            return Err(ReadError::OutOfBounds);
2796
        };
2797
0
        Ok(Self { data })
2798
0
    }
2799
}
2800
2801
/// The fields at the start of the table, which are read directly.
2802
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2803
#[repr(C, packed)]
2804
#[doc(hidden)]
2805
pub struct ChainedSequenceRuleFixedHeader {
2806
    pub backtrack_glyph_count: BigEndian<u16>,
2807
}
2808
2809
#[allow(clippy::absurd_extreme_comparisons)]
2810
const _: () =
2811
    assert!(std::mem::size_of::<ChainedSequenceRuleFixedHeader>() <= ChainedSequenceRule::MIN_SIZE);
2812
2813
/// Part of [ChainedSequenceContextFormat1]
2814
#[derive(Clone)]
2815
pub struct ChainedSequenceRule<'a> {
2816
    data: TableDataRef<'a, ChainedSequenceRuleFixedHeader>,
2817
}
2818
2819
#[allow(clippy::needless_lifetimes)]
2820
impl<'a> ChainedSequenceRule<'a> {
2821
    pub const MIN_SIZE: usize =
2822
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2823
    basic_table_impls!(impl_the_methods);
2824
2825
    /// Number of glyphs in the backtrack sequence
2826
0
    pub fn backtrack_glyph_count(&self) -> u16 {
2827
0
        self.data.header().backtrack_glyph_count.get()
2828
0
    }
2829
2830
    /// Array of backtrack glyph IDs
2831
0
    pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2832
0
        let range = self.backtrack_sequence_byte_range();
2833
0
        self.offset_data()
2834
0
            .read_array(range)
2835
0
            .ok()
2836
0
            .unwrap_or_default()
2837
0
    }
2838
2839
    /// Number of glyphs in the input sequence
2840
0
    pub fn input_glyph_count(&self) -> u16 {
2841
0
        let range = self.input_glyph_count_byte_range();
2842
0
        self.offset_data()
2843
0
            .read_at(range.start)
2844
0
            .ok()
2845
0
            .unwrap_or_default()
2846
0
    }
2847
2848
    /// Array of input glyph IDs—start with second glyph
2849
0
    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2850
0
        let range = self.input_sequence_byte_range();
2851
0
        self.offset_data()
2852
0
            .read_array(range)
2853
0
            .ok()
2854
0
            .unwrap_or_default()
2855
0
    }
2856
2857
    /// Number of glyphs in the lookahead sequence
2858
0
    pub fn lookahead_glyph_count(&self) -> u16 {
2859
0
        let range = self.lookahead_glyph_count_byte_range();
2860
0
        self.offset_data()
2861
0
            .read_at(range.start)
2862
0
            .ok()
2863
0
            .unwrap_or_default()
2864
0
    }
2865
2866
    /// Array of lookahead glyph IDs
2867
0
    pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2868
0
        let range = self.lookahead_sequence_byte_range();
2869
0
        self.offset_data()
2870
0
            .read_array(range)
2871
0
            .ok()
2872
0
            .unwrap_or_default()
2873
0
    }
2874
2875
    /// Number of SequenceLookupRecords
2876
0
    pub fn seq_lookup_count(&self) -> u16 {
2877
0
        let range = self.seq_lookup_count_byte_range();
2878
0
        self.offset_data()
2879
0
            .read_at(range.start)
2880
0
            .ok()
2881
0
            .unwrap_or_default()
2882
0
    }
2883
2884
    /// Array of SequenceLookupRecords
2885
0
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2886
0
        let range = self.seq_lookup_records_byte_range();
2887
0
        self.offset_data()
2888
0
            .read_array(range)
2889
0
            .ok()
2890
0
            .unwrap_or_default()
2891
0
    }
2892
2893
0
    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
2894
0
        let start = 0;
2895
0
        let end = start + u16::RAW_BYTE_LEN;
2896
0
        start..end
2897
0
    }
2898
2899
0
    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
2900
0
        let backtrack_glyph_count = self.backtrack_glyph_count();
2901
0
        let start = self.backtrack_glyph_count_byte_range().end;
2902
0
        let end = start
2903
0
            + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
2904
0
        start..end
2905
0
    }
2906
2907
0
    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
2908
0
        let start = self.backtrack_sequence_byte_range().end;
2909
0
        let end = start + u16::RAW_BYTE_LEN;
2910
0
        start..end
2911
0
    }
2912
2913
0
    pub fn input_sequence_byte_range(&self) -> Range<usize> {
2914
0
        let input_glyph_count = self.input_glyph_count();
2915
0
        let start = self.input_glyph_count_byte_range().end;
2916
0
        let end = start
2917
0
            + (transforms::subtract(input_glyph_count, 1_usize))
2918
0
                .saturating_mul(GlyphId16::RAW_BYTE_LEN);
2919
0
        start..end
2920
0
    }
2921
2922
0
    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
2923
0
        let start = self.input_sequence_byte_range().end;
2924
0
        let end = start + u16::RAW_BYTE_LEN;
2925
0
        start..end
2926
0
    }
2927
2928
0
    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
2929
0
        let lookahead_glyph_count = self.lookahead_glyph_count();
2930
0
        let start = self.lookahead_glyph_count_byte_range().end;
2931
0
        let end = start
2932
0
            + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(GlyphId16::RAW_BYTE_LEN);
2933
0
        start..end
2934
0
    }
2935
2936
0
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2937
0
        let start = self.lookahead_sequence_byte_range().end;
2938
0
        let end = start + u16::RAW_BYTE_LEN;
2939
0
        start..end
2940
0
    }
2941
2942
0
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2943
0
        let seq_lookup_count = self.seq_lookup_count();
2944
0
        let start = self.seq_lookup_count_byte_range().end;
2945
0
        let end = start
2946
0
            + (transforms::to_usize(seq_lookup_count))
2947
0
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
2948
0
        start..end
2949
0
    }
2950
}
2951
2952
const _: () = assert!(FontData::default_data_long_enough(
2953
    ChainedSequenceRule::MIN_SIZE
2954
));
2955
2956
impl Default for ChainedSequenceRule<'_> {
2957
0
    fn default() -> Self {
2958
        Self {
2959
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
2960
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2961
        }
2962
0
    }
2963
}
2964
2965
impl Format<u16> for ChainedSequenceContextFormat2<'_> {
2966
    const FORMAT: u16 = 2;
2967
}
2968
2969
impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat2<'a> {
2970
0
    fn min_byte_range(&self) -> Range<usize> {
2971
0
        0..self.chained_class_seq_rule_set_offsets_byte_range().end
2972
0
    }
2973
0
    fn min_table_bytes(&self) -> &'a [u8] {
2974
0
        let range = self.min_byte_range();
2975
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
2976
0
    }
2977
}
2978
2979
impl ReadArgs for ChainedSequenceContextFormat2<'_> {
2980
    type Args = ();
2981
}
2982
2983
impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> {
2984
44.9k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2985
        #[allow(clippy::absurd_extreme_comparisons)]
2986
44.9k
        if data.len() < Self::MIN_SIZE {
2987
480
            return Err(ReadError::OutOfBounds);
2988
44.4k
        }
2989
44.4k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2990
0
            return Err(ReadError::OutOfBounds);
2991
        };
2992
44.4k
        Ok(Self { data })
2993
44.9k
    }
2994
}
2995
2996
/// The fields at the start of the table, which are read directly.
2997
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2998
#[repr(C, packed)]
2999
#[doc(hidden)]
3000
pub struct ChainedSequenceContextFormat2FixedHeader {
3001
    pub format: BigEndian<u16>,
3002
    pub coverage_offset: BigEndian<Offset16>,
3003
    pub backtrack_class_def_offset: BigEndian<Offset16>,
3004
    pub input_class_def_offset: BigEndian<Offset16>,
3005
    pub lookahead_class_def_offset: BigEndian<Offset16>,
3006
    pub chained_class_seq_rule_set_count: BigEndian<u16>,
3007
}
3008
3009
#[allow(clippy::absurd_extreme_comparisons)]
3010
const _: () = assert!(
3011
    std::mem::size_of::<ChainedSequenceContextFormat2FixedHeader>()
3012
        <= ChainedSequenceContextFormat2::MIN_SIZE
3013
);
3014
3015
/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
3016
#[derive(Clone)]
3017
pub struct ChainedSequenceContextFormat2<'a> {
3018
    data: TableDataRef<'a, ChainedSequenceContextFormat2FixedHeader>,
3019
}
3020
3021
#[allow(clippy::needless_lifetimes)]
3022
impl<'a> ChainedSequenceContextFormat2<'a> {
3023
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3024
        + Offset16::RAW_BYTE_LEN
3025
        + Offset16::RAW_BYTE_LEN
3026
        + Offset16::RAW_BYTE_LEN
3027
        + Offset16::RAW_BYTE_LEN
3028
        + u16::RAW_BYTE_LEN);
3029
    basic_table_impls!(impl_the_methods);
3030
3031
    /// Format identifier: format = 2
3032
0
    pub fn format(&self) -> u16 {
3033
0
        self.data.header().format.get()
3034
0
    }
3035
3036
    /// Offset to Coverage table, from beginning of
3037
    /// ChainedSequenceContextFormat2 table
3038
44.4k
    pub fn coverage_offset(&self) -> Offset16 {
3039
44.4k
        self.data.header().coverage_offset.get()
3040
44.4k
    }
3041
3042
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
3043
44.4k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3044
44.4k
        let data = self.offset_data();
3045
44.4k
        self.coverage_offset().resolve(data)
3046
44.4k
    }
3047
3048
    /// Offset to ClassDef table containing backtrack sequence context,
3049
    /// from beginning of ChainedSequenceContextFormat2 table
3050
44.4k
    pub fn backtrack_class_def_offset(&self) -> Offset16 {
3051
44.4k
        self.data.header().backtrack_class_def_offset.get()
3052
44.4k
    }
3053
3054
    /// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset].
3055
44.4k
    pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3056
44.4k
        let data = self.offset_data();
3057
44.4k
        self.backtrack_class_def_offset().resolve(data)
3058
44.4k
    }
3059
3060
    /// Offset to ClassDef table containing input sequence context,
3061
    /// from beginning of ChainedSequenceContextFormat2 table
3062
44.4k
    pub fn input_class_def_offset(&self) -> Offset16 {
3063
44.4k
        self.data.header().input_class_def_offset.get()
3064
44.4k
    }
3065
3066
    /// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset].
3067
44.4k
    pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3068
44.4k
        let data = self.offset_data();
3069
44.4k
        self.input_class_def_offset().resolve(data)
3070
44.4k
    }
3071
3072
    /// Offset to ClassDef table containing lookahead sequence context,
3073
    /// from beginning of ChainedSequenceContextFormat2 table
3074
44.4k
    pub fn lookahead_class_def_offset(&self) -> Offset16 {
3075
44.4k
        self.data.header().lookahead_class_def_offset.get()
3076
44.4k
    }
3077
3078
    /// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset].
3079
44.4k
    pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3080
44.4k
        let data = self.offset_data();
3081
44.4k
        self.lookahead_class_def_offset().resolve(data)
3082
44.4k
    }
3083
3084
    /// Number of ChainedClassSequenceRuleSet tables
3085
44.4k
    pub fn chained_class_seq_rule_set_count(&self) -> u16 {
3086
44.4k
        self.data.header().chained_class_seq_rule_set_count.get()
3087
44.4k
    }
3088
3089
    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
3090
    /// beginning of ChainedSequenceContextFormat2 table (may be NULL)
3091
0
    pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3092
0
        let range = self.chained_class_seq_rule_set_offsets_byte_range();
3093
0
        self.offset_data()
3094
0
            .read_array(range)
3095
0
            .ok()
3096
0
            .unwrap_or_default()
3097
0
    }
3098
3099
    /// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets].
3100
0
    pub fn chained_class_seq_rule_sets(
3101
0
        &self,
3102
0
    ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> {
3103
0
        let data = self.offset_data();
3104
0
        let offsets = self.chained_class_seq_rule_set_offsets();
3105
0
        ArrayOfNullableOffsets::new(offsets, data, ())
3106
0
    }
3107
3108
44.4k
    pub fn format_byte_range(&self) -> Range<usize> {
3109
44.4k
        let start = 0;
3110
44.4k
        let end = start + u16::RAW_BYTE_LEN;
3111
44.4k
        start..end
3112
44.4k
    }
3113
3114
44.4k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
3115
44.4k
        let start = self.format_byte_range().end;
3116
44.4k
        let end = start + Offset16::RAW_BYTE_LEN;
3117
44.4k
        start..end
3118
44.4k
    }
3119
3120
44.4k
    pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
3121
44.4k
        let start = self.coverage_offset_byte_range().end;
3122
44.4k
        let end = start + Offset16::RAW_BYTE_LEN;
3123
44.4k
        start..end
3124
44.4k
    }
3125
3126
44.4k
    pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
3127
44.4k
        let start = self.backtrack_class_def_offset_byte_range().end;
3128
44.4k
        let end = start + Offset16::RAW_BYTE_LEN;
3129
44.4k
        start..end
3130
44.4k
    }
3131
3132
44.4k
    pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
3133
44.4k
        let start = self.input_class_def_offset_byte_range().end;
3134
44.4k
        let end = start + Offset16::RAW_BYTE_LEN;
3135
44.4k
        start..end
3136
44.4k
    }
3137
3138
44.4k
    pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
3139
44.4k
        let start = self.lookahead_class_def_offset_byte_range().end;
3140
44.4k
        let end = start + u16::RAW_BYTE_LEN;
3141
44.4k
        start..end
3142
44.4k
    }
3143
3144
44.4k
    pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
3145
44.4k
        let chained_class_seq_rule_set_count = self.chained_class_seq_rule_set_count();
3146
44.4k
        let start = self.chained_class_seq_rule_set_count_byte_range().end;
3147
44.4k
        let end = start
3148
44.4k
            + (transforms::to_usize(chained_class_seq_rule_set_count))
3149
44.4k
                .saturating_mul(Offset16::RAW_BYTE_LEN);
3150
44.4k
        start..end
3151
44.4k
    }
3152
}
3153
3154
impl<'a> MinByteRange<'a> for ChainedClassSequenceRuleSet<'a> {
3155
0
    fn min_byte_range(&self) -> Range<usize> {
3156
0
        0..self.chained_class_seq_rule_offsets_byte_range().end
3157
0
    }
3158
0
    fn min_table_bytes(&self) -> &'a [u8] {
3159
0
        let range = self.min_byte_range();
3160
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
3161
0
    }
3162
}
3163
3164
impl ReadArgs for ChainedClassSequenceRuleSet<'_> {
3165
    type Args = ();
3166
}
3167
3168
impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> {
3169
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3170
        #[allow(clippy::absurd_extreme_comparisons)]
3171
0
        if data.len() < Self::MIN_SIZE {
3172
0
            return Err(ReadError::OutOfBounds);
3173
0
        }
3174
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
3175
0
            return Err(ReadError::OutOfBounds);
3176
        };
3177
0
        Ok(Self { data })
3178
0
    }
3179
}
3180
3181
/// The fields at the start of the table, which are read directly.
3182
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3183
#[repr(C, packed)]
3184
#[doc(hidden)]
3185
pub struct ChainedClassSequenceRuleSetFixedHeader {
3186
    pub chained_class_seq_rule_count: BigEndian<u16>,
3187
}
3188
3189
#[allow(clippy::absurd_extreme_comparisons)]
3190
const _: () = assert!(
3191
    std::mem::size_of::<ChainedClassSequenceRuleSetFixedHeader>()
3192
        <= ChainedClassSequenceRuleSet::MIN_SIZE
3193
);
3194
3195
/// Part of [ChainedSequenceContextFormat2]
3196
#[derive(Clone)]
3197
pub struct ChainedClassSequenceRuleSet<'a> {
3198
    data: TableDataRef<'a, ChainedClassSequenceRuleSetFixedHeader>,
3199
}
3200
3201
#[allow(clippy::needless_lifetimes)]
3202
impl<'a> ChainedClassSequenceRuleSet<'a> {
3203
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3204
    basic_table_impls!(impl_the_methods);
3205
3206
    /// Number of ChainedClassSequenceRule tables
3207
0
    pub fn chained_class_seq_rule_count(&self) -> u16 {
3208
0
        self.data.header().chained_class_seq_rule_count.get()
3209
0
    }
3210
3211
    /// Array of offsets to ChainedClassSequenceRule tables, from
3212
    /// beginning of ChainedClassSequenceRuleSet
3213
0
    pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
3214
0
        let range = self.chained_class_seq_rule_offsets_byte_range();
3215
0
        self.offset_data()
3216
0
            .read_array(range)
3217
0
            .ok()
3218
0
            .unwrap_or_default()
3219
0
    }
3220
3221
    /// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets].
3222
0
    pub fn chained_class_seq_rules(
3223
0
        &self,
3224
0
    ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> {
3225
0
        let data = self.offset_data();
3226
0
        let offsets = self.chained_class_seq_rule_offsets();
3227
0
        ArrayOfOffsets::new(offsets, data, ())
3228
0
    }
3229
3230
0
    pub fn chained_class_seq_rule_count_byte_range(&self) -> Range<usize> {
3231
0
        let start = 0;
3232
0
        let end = start + u16::RAW_BYTE_LEN;
3233
0
        start..end
3234
0
    }
3235
3236
0
    pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
3237
0
        let chained_class_seq_rule_count = self.chained_class_seq_rule_count();
3238
0
        let start = self.chained_class_seq_rule_count_byte_range().end;
3239
0
        let end = start
3240
0
            + (transforms::to_usize(chained_class_seq_rule_count))
3241
0
                .saturating_mul(Offset16::RAW_BYTE_LEN);
3242
0
        start..end
3243
0
    }
3244
}
3245
3246
const _: () = assert!(FontData::default_data_long_enough(
3247
    ChainedClassSequenceRuleSet::MIN_SIZE
3248
));
3249
3250
impl Default for ChainedClassSequenceRuleSet<'_> {
3251
0
    fn default() -> Self {
3252
        Self {
3253
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
3254
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3255
        }
3256
0
    }
3257
}
3258
3259
impl<'a> MinByteRange<'a> for ChainedClassSequenceRule<'a> {
3260
0
    fn min_byte_range(&self) -> Range<usize> {
3261
0
        0..self.seq_lookup_records_byte_range().end
3262
0
    }
3263
0
    fn min_table_bytes(&self) -> &'a [u8] {
3264
0
        let range = self.min_byte_range();
3265
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
3266
0
    }
3267
}
3268
3269
impl ReadArgs for ChainedClassSequenceRule<'_> {
3270
    type Args = ();
3271
}
3272
3273
impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> {
3274
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3275
        #[allow(clippy::absurd_extreme_comparisons)]
3276
0
        if data.len() < Self::MIN_SIZE {
3277
0
            return Err(ReadError::OutOfBounds);
3278
0
        }
3279
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
3280
0
            return Err(ReadError::OutOfBounds);
3281
        };
3282
0
        Ok(Self { data })
3283
0
    }
3284
}
3285
3286
/// The fields at the start of the table, which are read directly.
3287
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3288
#[repr(C, packed)]
3289
#[doc(hidden)]
3290
pub struct ChainedClassSequenceRuleFixedHeader {
3291
    pub backtrack_glyph_count: BigEndian<u16>,
3292
}
3293
3294
#[allow(clippy::absurd_extreme_comparisons)]
3295
const _: () = assert!(
3296
    std::mem::size_of::<ChainedClassSequenceRuleFixedHeader>()
3297
        <= ChainedClassSequenceRule::MIN_SIZE
3298
);
3299
3300
/// Part of [ChainedSequenceContextFormat2]
3301
#[derive(Clone)]
3302
pub struct ChainedClassSequenceRule<'a> {
3303
    data: TableDataRef<'a, ChainedClassSequenceRuleFixedHeader>,
3304
}
3305
3306
#[allow(clippy::needless_lifetimes)]
3307
impl<'a> ChainedClassSequenceRule<'a> {
3308
    pub const MIN_SIZE: usize =
3309
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
3310
    basic_table_impls!(impl_the_methods);
3311
3312
    /// Number of glyphs in the backtrack sequence
3313
0
    pub fn backtrack_glyph_count(&self) -> u16 {
3314
0
        self.data.header().backtrack_glyph_count.get()
3315
0
    }
3316
3317
    /// Array of backtrack-sequence classes
3318
0
    pub fn backtrack_sequence(&self) -> &'a [BigEndian<u16>] {
3319
0
        let range = self.backtrack_sequence_byte_range();
3320
0
        self.offset_data()
3321
0
            .read_array(range)
3322
0
            .ok()
3323
0
            .unwrap_or_default()
3324
0
    }
3325
3326
    /// Total number of glyphs in the input sequence
3327
0
    pub fn input_glyph_count(&self) -> u16 {
3328
0
        let range = self.input_glyph_count_byte_range();
3329
0
        self.offset_data()
3330
0
            .read_at(range.start)
3331
0
            .ok()
3332
0
            .unwrap_or_default()
3333
0
    }
3334
3335
    /// Array of input sequence classes, beginning with the second
3336
    /// glyph position
3337
0
    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
3338
0
        let range = self.input_sequence_byte_range();
3339
0
        self.offset_data()
3340
0
            .read_array(range)
3341
0
            .ok()
3342
0
            .unwrap_or_default()
3343
0
    }
3344
3345
    /// Number of glyphs in the lookahead sequence
3346
0
    pub fn lookahead_glyph_count(&self) -> u16 {
3347
0
        let range = self.lookahead_glyph_count_byte_range();
3348
0
        self.offset_data()
3349
0
            .read_at(range.start)
3350
0
            .ok()
3351
0
            .unwrap_or_default()
3352
0
    }
3353
3354
    /// Array of lookahead-sequence classes
3355
0
    pub fn lookahead_sequence(&self) -> &'a [BigEndian<u16>] {
3356
0
        let range = self.lookahead_sequence_byte_range();
3357
0
        self.offset_data()
3358
0
            .read_array(range)
3359
0
            .ok()
3360
0
            .unwrap_or_default()
3361
0
    }
3362
3363
    /// Number of SequenceLookupRecords
3364
0
    pub fn seq_lookup_count(&self) -> u16 {
3365
0
        let range = self.seq_lookup_count_byte_range();
3366
0
        self.offset_data()
3367
0
            .read_at(range.start)
3368
0
            .ok()
3369
0
            .unwrap_or_default()
3370
0
    }
3371
3372
    /// Array of SequenceLookupRecords
3373
0
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3374
0
        let range = self.seq_lookup_records_byte_range();
3375
0
        self.offset_data()
3376
0
            .read_array(range)
3377
0
            .ok()
3378
0
            .unwrap_or_default()
3379
0
    }
3380
3381
0
    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3382
0
        let start = 0;
3383
0
        let end = start + u16::RAW_BYTE_LEN;
3384
0
        start..end
3385
0
    }
3386
3387
0
    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
3388
0
        let backtrack_glyph_count = self.backtrack_glyph_count();
3389
0
        let start = self.backtrack_glyph_count_byte_range().end;
3390
0
        let end =
3391
0
            start + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(u16::RAW_BYTE_LEN);
3392
0
        start..end
3393
0
    }
3394
3395
0
    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3396
0
        let start = self.backtrack_sequence_byte_range().end;
3397
0
        let end = start + u16::RAW_BYTE_LEN;
3398
0
        start..end
3399
0
    }
3400
3401
0
    pub fn input_sequence_byte_range(&self) -> Range<usize> {
3402
0
        let input_glyph_count = self.input_glyph_count();
3403
0
        let start = self.input_glyph_count_byte_range().end;
3404
0
        let end = start
3405
0
            + (transforms::subtract(input_glyph_count, 1_usize)).saturating_mul(u16::RAW_BYTE_LEN);
3406
0
        start..end
3407
0
    }
3408
3409
0
    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3410
0
        let start = self.input_sequence_byte_range().end;
3411
0
        let end = start + u16::RAW_BYTE_LEN;
3412
0
        start..end
3413
0
    }
3414
3415
0
    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
3416
0
        let lookahead_glyph_count = self.lookahead_glyph_count();
3417
0
        let start = self.lookahead_glyph_count_byte_range().end;
3418
0
        let end =
3419
0
            start + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(u16::RAW_BYTE_LEN);
3420
0
        start..end
3421
0
    }
3422
3423
0
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3424
0
        let start = self.lookahead_sequence_byte_range().end;
3425
0
        let end = start + u16::RAW_BYTE_LEN;
3426
0
        start..end
3427
0
    }
3428
3429
0
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3430
0
        let seq_lookup_count = self.seq_lookup_count();
3431
0
        let start = self.seq_lookup_count_byte_range().end;
3432
0
        let end = start
3433
0
            + (transforms::to_usize(seq_lookup_count))
3434
0
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
3435
0
        start..end
3436
0
    }
3437
}
3438
3439
const _: () = assert!(FontData::default_data_long_enough(
3440
    ChainedClassSequenceRule::MIN_SIZE
3441
));
3442
3443
impl Default for ChainedClassSequenceRule<'_> {
3444
0
    fn default() -> Self {
3445
        Self {
3446
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
3447
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3448
        }
3449
0
    }
3450
}
3451
3452
impl Format<u16> for ChainedSequenceContextFormat3<'_> {
3453
    const FORMAT: u16 = 3;
3454
}
3455
3456
impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat3<'a> {
3457
0
    fn min_byte_range(&self) -> Range<usize> {
3458
0
        0..self.seq_lookup_records_byte_range().end
3459
0
    }
3460
0
    fn min_table_bytes(&self) -> &'a [u8] {
3461
0
        let range = self.min_byte_range();
3462
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
3463
0
    }
3464
}
3465
3466
impl ReadArgs for ChainedSequenceContextFormat3<'_> {
3467
    type Args = ();
3468
}
3469
3470
impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> {
3471
17.6k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3472
        #[allow(clippy::absurd_extreme_comparisons)]
3473
17.6k
        if data.len() < Self::MIN_SIZE {
3474
355
            return Err(ReadError::OutOfBounds);
3475
17.2k
        }
3476
17.2k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
3477
0
            return Err(ReadError::OutOfBounds);
3478
        };
3479
17.2k
        Ok(Self { data })
3480
17.6k
    }
3481
}
3482
3483
/// The fields at the start of the table, which are read directly.
3484
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3485
#[repr(C, packed)]
3486
#[doc(hidden)]
3487
pub struct ChainedSequenceContextFormat3FixedHeader {
3488
    pub format: BigEndian<u16>,
3489
    pub backtrack_glyph_count: BigEndian<u16>,
3490
}
3491
3492
#[allow(clippy::absurd_extreme_comparisons)]
3493
const _: () = assert!(
3494
    std::mem::size_of::<ChainedSequenceContextFormat3FixedHeader>()
3495
        <= ChainedSequenceContextFormat3::MIN_SIZE
3496
);
3497
3498
/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
3499
#[derive(Clone)]
3500
pub struct ChainedSequenceContextFormat3<'a> {
3501
    data: TableDataRef<'a, ChainedSequenceContextFormat3FixedHeader>,
3502
}
3503
3504
#[allow(clippy::needless_lifetimes)]
3505
impl<'a> ChainedSequenceContextFormat3<'a> {
3506
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3507
        + u16::RAW_BYTE_LEN
3508
        + u16::RAW_BYTE_LEN
3509
        + u16::RAW_BYTE_LEN
3510
        + u16::RAW_BYTE_LEN);
3511
    basic_table_impls!(impl_the_methods);
3512
3513
    /// Format identifier: format = 3
3514
0
    pub fn format(&self) -> u16 {
3515
0
        self.data.header().format.get()
3516
0
    }
3517
3518
    /// Number of glyphs in the backtrack sequence
3519
293k
    pub fn backtrack_glyph_count(&self) -> u16 {
3520
293k
        self.data.header().backtrack_glyph_count.get()
3521
293k
    }
3522
3523
    /// Array of offsets to coverage tables for the backtrack sequence
3524
0
    pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3525
0
        let range = self.backtrack_coverage_offsets_byte_range();
3526
0
        self.offset_data()
3527
0
            .read_array(range)
3528
0
            .ok()
3529
0
            .unwrap_or_default()
3530
0
    }
3531
3532
    /// A dynamically resolving wrapper for [`backtrack_coverage_offsets`][Self::backtrack_coverage_offsets].
3533
0
    pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3534
0
        let data = self.offset_data();
3535
0
        let offsets = self.backtrack_coverage_offsets();
3536
0
        ArrayOfOffsets::new(offsets, data, ())
3537
0
    }
3538
3539
    /// Number of glyphs in the input sequence
3540
138k
    pub fn input_glyph_count(&self) -> u16 {
3541
138k
        let range = self.input_glyph_count_byte_range();
3542
138k
        self.offset_data()
3543
138k
            .read_at(range.start)
3544
138k
            .ok()
3545
138k
            .unwrap_or_default()
3546
138k
    }
3547
3548
    /// Array of offsets to coverage tables for the input sequence
3549
17.2k
    pub fn input_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3550
17.2k
        let range = self.input_coverage_offsets_byte_range();
3551
17.2k
        self.offset_data()
3552
17.2k
            .read_array(range)
3553
17.2k
            .ok()
3554
17.2k
            .unwrap_or_default()
3555
17.2k
    }
3556
3557
    /// A dynamically resolving wrapper for [`input_coverage_offsets`][Self::input_coverage_offsets].
3558
17.2k
    pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3559
17.2k
        let data = self.offset_data();
3560
17.2k
        let offsets = self.input_coverage_offsets();
3561
17.2k
        ArrayOfOffsets::new(offsets, data, ())
3562
17.2k
    }
3563
3564
    /// Number of glyphs in the lookahead sequence
3565
51.8k
    pub fn lookahead_glyph_count(&self) -> u16 {
3566
51.8k
        let range = self.lookahead_glyph_count_byte_range();
3567
51.8k
        self.offset_data()
3568
51.8k
            .read_at(range.start)
3569
51.8k
            .ok()
3570
51.8k
            .unwrap_or_default()
3571
51.8k
    }
3572
3573
    /// Array of offsets to coverage tables for the lookahead sequence
3574
0
    pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3575
0
        let range = self.lookahead_coverage_offsets_byte_range();
3576
0
        self.offset_data()
3577
0
            .read_array(range)
3578
0
            .ok()
3579
0
            .unwrap_or_default()
3580
0
    }
3581
3582
    /// A dynamically resolving wrapper for [`lookahead_coverage_offsets`][Self::lookahead_coverage_offsets].
3583
0
    pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3584
0
        let data = self.offset_data();
3585
0
        let offsets = self.lookahead_coverage_offsets();
3586
0
        ArrayOfOffsets::new(offsets, data, ())
3587
0
    }
3588
3589
    /// Number of SequenceLookupRecords
3590
17.2k
    pub fn seq_lookup_count(&self) -> u16 {
3591
17.2k
        let range = self.seq_lookup_count_byte_range();
3592
17.2k
        self.offset_data()
3593
17.2k
            .read_at(range.start)
3594
17.2k
            .ok()
3595
17.2k
            .unwrap_or_default()
3596
17.2k
    }
3597
3598
    /// Array of SequenceLookupRecords
3599
17.2k
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3600
17.2k
        let range = self.seq_lookup_records_byte_range();
3601
17.2k
        self.offset_data()
3602
17.2k
            .read_array(range)
3603
17.2k
            .ok()
3604
17.2k
            .unwrap_or_default()
3605
17.2k
    }
3606
3607
293k
    pub fn format_byte_range(&self) -> Range<usize> {
3608
293k
        let start = 0;
3609
293k
        let end = start + u16::RAW_BYTE_LEN;
3610
293k
        start..end
3611
293k
    }
3612
3613
293k
    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3614
293k
        let start = self.format_byte_range().end;
3615
293k
        let end = start + u16::RAW_BYTE_LEN;
3616
293k
        start..end
3617
293k
    }
3618
3619
293k
    pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
3620
293k
        let backtrack_glyph_count = self.backtrack_glyph_count();
3621
293k
        let start = self.backtrack_glyph_count_byte_range().end;
3622
293k
        let end = start
3623
293k
            + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
3624
293k
        start..end
3625
293k
    }
3626
3627
276k
    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3628
276k
        let start = self.backtrack_coverage_offsets_byte_range().end;
3629
276k
        let end = start + u16::RAW_BYTE_LEN;
3630
276k
        start..end
3631
276k
    }
3632
3633
138k
    pub fn input_coverage_offsets_byte_range(&self) -> Range<usize> {
3634
138k
        let input_glyph_count = self.input_glyph_count();
3635
138k
        let start = self.input_glyph_count_byte_range().end;
3636
138k
        let end = start
3637
138k
            + (transforms::to_usize(input_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
3638
138k
        start..end
3639
138k
    }
3640
3641
103k
    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3642
103k
        let start = self.input_coverage_offsets_byte_range().end;
3643
103k
        let end = start + u16::RAW_BYTE_LEN;
3644
103k
        start..end
3645
103k
    }
3646
3647
51.8k
    pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
3648
51.8k
        let lookahead_glyph_count = self.lookahead_glyph_count();
3649
51.8k
        let start = self.lookahead_glyph_count_byte_range().end;
3650
51.8k
        let end = start
3651
51.8k
            + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
3652
51.8k
        start..end
3653
51.8k
    }
3654
3655
34.5k
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3656
34.5k
        let start = self.lookahead_coverage_offsets_byte_range().end;
3657
34.5k
        let end = start + u16::RAW_BYTE_LEN;
3658
34.5k
        start..end
3659
34.5k
    }
3660
3661
17.2k
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3662
17.2k
        let seq_lookup_count = self.seq_lookup_count();
3663
17.2k
        let start = self.seq_lookup_count_byte_range().end;
3664
17.2k
        let end = start
3665
17.2k
            + (transforms::to_usize(seq_lookup_count))
3666
17.2k
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
3667
17.2k
        start..end
3668
17.2k
    }
3669
}
3670
3671
#[derive(Clone)]
3672
pub enum ChainedSequenceContext<'a> {
3673
    Format1(ChainedSequenceContextFormat1<'a>),
3674
    Format2(ChainedSequenceContextFormat2<'a>),
3675
    Format3(ChainedSequenceContextFormat3<'a>),
3676
    Format4(ChainedSequenceContextFormat4<'a>),
3677
    Format5(ChainedSequenceContextFormat5<'a>),
3678
}
3679
3680
impl Default for ChainedSequenceContext<'_> {
3681
0
    fn default() -> Self {
3682
0
        Self::Format1(Default::default())
3683
0
    }
3684
}
3685
3686
impl<'a> ChainedSequenceContext<'a> {
3687
    ///Return the `FontData` used to resolve offsets for this table.
3688
0
    pub fn offset_data(&self) -> FontData<'a> {
3689
0
        match self {
3690
0
            Self::Format1(item) => item.offset_data(),
3691
0
            Self::Format2(item) => item.offset_data(),
3692
0
            Self::Format3(item) => item.offset_data(),
3693
0
            Self::Format4(item) => item.offset_data(),
3694
0
            Self::Format5(item) => item.offset_data(),
3695
        }
3696
0
    }
3697
3698
    /// Format identifier: format = 1
3699
0
    pub fn format(&self) -> u16 {
3700
0
        match self {
3701
0
            Self::Format1(item) => item.format(),
3702
0
            Self::Format2(item) => item.format(),
3703
0
            Self::Format3(item) => item.format(),
3704
0
            Self::Format4(item) => item.format(),
3705
0
            Self::Format5(item) => item.format(),
3706
        }
3707
0
    }
3708
}
3709
3710
impl ReadArgs for ChainedSequenceContext<'_> {
3711
    type Args = ();
3712
}
3713
3714
impl<'a> FontRead<'a> for ChainedSequenceContext<'a> {
3715
    #[inline]
3716
1.23M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3717
1.23M
        let format: u16 = data.read_at(0usize)?;
3718
1.23M
        match format {
3719
32.5k
            ChainedSequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
3720
44.9k
            ChainedSequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
3721
17.6k
            ChainedSequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
3722
5.31k
            ChainedSequenceContextFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
3723
5.53k
            ChainedSequenceContextFormat5::FORMAT => Ok(Self::Format5(FontRead::read(data)?)),
3724
1.12M
            other => Err(ReadError::InvalidFormat(other.into())),
3725
        }
3726
1.23M
    }
<read_fonts::tables::layout::ChainedSequenceContext as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
3716
1.23M
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3717
1.23M
        let format: u16 = data.read_at(0usize)?;
3718
1.23M
        match format {
3719
32.5k
            ChainedSequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
3720
44.9k
            ChainedSequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
3721
17.6k
            ChainedSequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
3722
5.31k
            ChainedSequenceContextFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
3723
5.53k
            ChainedSequenceContextFormat5::FORMAT => Ok(Self::Format5(FontRead::read(data)?)),
3724
1.12M
            other => Err(ReadError::InvalidFormat(other.into())),
3725
        }
3726
1.23M
    }
Unexecuted instantiation: <read_fonts::tables::layout::ChainedSequenceContext as read_fonts::read::FontRead>::read_with_args
3727
}
3728
3729
impl<'a> MinByteRange<'a> for ChainedSequenceContext<'a> {
3730
0
    fn min_byte_range(&self) -> Range<usize> {
3731
0
        match self {
3732
0
            Self::Format1(item) => item.min_byte_range(),
3733
0
            Self::Format2(item) => item.min_byte_range(),
3734
0
            Self::Format3(item) => item.min_byte_range(),
3735
0
            Self::Format4(item) => item.min_byte_range(),
3736
0
            Self::Format5(item) => item.min_byte_range(),
3737
        }
3738
0
    }
3739
0
    fn min_table_bytes(&self) -> &'a [u8] {
3740
0
        match self {
3741
0
            Self::Format1(item) => item.min_table_bytes(),
3742
0
            Self::Format2(item) => item.min_table_bytes(),
3743
0
            Self::Format3(item) => item.min_table_bytes(),
3744
0
            Self::Format4(item) => item.min_table_bytes(),
3745
0
            Self::Format5(item) => item.min_table_bytes(),
3746
        }
3747
0
    }
3748
}
3749
3750
/// [Device](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
3751
/// delta formats
3752
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
3753
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3754
#[repr(u16)]
3755
#[allow(clippy::manual_non_exhaustive)]
3756
pub enum DeltaFormat {
3757
    /// Signed 2-bit value, 8 values per uint16
3758
    #[default]
3759
    Local2BitDeltas = 0x0001,
3760
    /// Signed 4-bit value, 4 values per uint16
3761
    Local4BitDeltas = 0x0002,
3762
    /// Signed 8-bit value, 2 values per uint16
3763
    Local8BitDeltas = 0x0003,
3764
    /// VariationIndex table, contains a delta-set index pair.
3765
    VariationIndex = 0x8000,
3766
    #[doc(hidden)]
3767
    /// If font data is malformed we will map unknown values to this variant
3768
    Unknown,
3769
}
3770
3771
impl DeltaFormat {
3772
    /// Create from a raw scalar.
3773
    ///
3774
    /// This will never fail; unknown values will be mapped to the `Unknown` variant
3775
0
    pub fn new(raw: u16) -> Self {
3776
0
        match raw {
3777
0
            0x0001 => Self::Local2BitDeltas,
3778
0
            0x0002 => Self::Local4BitDeltas,
3779
0
            0x0003 => Self::Local8BitDeltas,
3780
0
            0x8000 => Self::VariationIndex,
3781
0
            _ => Self::Unknown,
3782
        }
3783
0
    }
3784
}
3785
3786
impl font_types::Scalar for DeltaFormat {
3787
    type Raw = <u16 as font_types::Scalar>::Raw;
3788
0
    fn to_raw(self) -> Self::Raw {
3789
0
        (self as u16).to_raw()
3790
0
    }
3791
0
    fn from_raw(raw: Self::Raw) -> Self {
3792
0
        let t = <u16>::from_raw(raw);
3793
0
        Self::new(t)
3794
0
    }
3795
}
3796
3797
impl<'a> MinByteRange<'a> for Device<'a> {
3798
0
    fn min_byte_range(&self) -> Range<usize> {
3799
0
        0..self.delta_value_byte_range().end
3800
0
    }
3801
0
    fn min_table_bytes(&self) -> &'a [u8] {
3802
0
        let range = self.min_byte_range();
3803
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
3804
0
    }
3805
}
3806
3807
impl ReadArgs for Device<'_> {
3808
    type Args = ();
3809
}
3810
3811
impl<'a> FontRead<'a> for Device<'a> {
3812
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3813
        #[allow(clippy::absurd_extreme_comparisons)]
3814
0
        if data.len() < Self::MIN_SIZE {
3815
0
            return Err(ReadError::OutOfBounds);
3816
0
        }
3817
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
3818
0
            return Err(ReadError::OutOfBounds);
3819
        };
3820
0
        Ok(Self { data })
3821
0
    }
3822
}
3823
3824
/// The fields at the start of the table, which are read directly.
3825
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3826
#[repr(C, packed)]
3827
#[doc(hidden)]
3828
pub struct DeviceFixedHeader {
3829
    pub start_size: BigEndian<u16>,
3830
    pub end_size: BigEndian<u16>,
3831
    pub delta_format: BigEndian<DeltaFormat>,
3832
}
3833
3834
#[allow(clippy::absurd_extreme_comparisons)]
3835
const _: () = assert!(std::mem::size_of::<DeviceFixedHeader>() <= Device::MIN_SIZE);
3836
3837
/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
3838
#[derive(Clone)]
3839
pub struct Device<'a> {
3840
    data: TableDataRef<'a, DeviceFixedHeader>,
3841
}
3842
3843
#[allow(clippy::needless_lifetimes)]
3844
impl<'a> Device<'a> {
3845
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN);
3846
    basic_table_impls!(impl_the_methods);
3847
3848
    /// Smallest size to correct, in ppem
3849
0
    pub fn start_size(&self) -> u16 {
3850
0
        self.data.header().start_size.get()
3851
0
    }
3852
3853
    /// Largest size to correct, in ppem
3854
0
    pub fn end_size(&self) -> u16 {
3855
0
        self.data.header().end_size.get()
3856
0
    }
3857
3858
    /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
3859
0
    pub fn delta_format(&self) -> DeltaFormat {
3860
0
        self.data.header().delta_format.get()
3861
0
    }
3862
3863
    /// Array of compressed data
3864
0
    pub fn delta_value(&self) -> &'a [BigEndian<u16>] {
3865
0
        let range = self.delta_value_byte_range();
3866
0
        self.offset_data()
3867
0
            .read_array(range)
3868
0
            .ok()
3869
0
            .unwrap_or_default()
3870
0
    }
3871
3872
0
    pub fn start_size_byte_range(&self) -> Range<usize> {
3873
0
        let start = 0;
3874
0
        let end = start + u16::RAW_BYTE_LEN;
3875
0
        start..end
3876
0
    }
3877
3878
0
    pub fn end_size_byte_range(&self) -> Range<usize> {
3879
0
        let start = self.start_size_byte_range().end;
3880
0
        let end = start + u16::RAW_BYTE_LEN;
3881
0
        start..end
3882
0
    }
3883
3884
0
    pub fn delta_format_byte_range(&self) -> Range<usize> {
3885
0
        let start = self.end_size_byte_range().end;
3886
0
        let end = start + DeltaFormat::RAW_BYTE_LEN;
3887
0
        start..end
3888
0
    }
3889
3890
0
    pub fn delta_value_byte_range(&self) -> Range<usize> {
3891
0
        let delta_format = self.delta_format();
3892
0
        let start_size = self.start_size();
3893
0
        let end_size = self.end_size();
3894
0
        let start = self.delta_format_byte_range().end;
3895
0
        let end = start
3896
0
            + (DeltaFormat::value_count(delta_format, start_size, end_size))
3897
0
                .saturating_mul(u16::RAW_BYTE_LEN);
3898
0
        start..end
3899
0
    }
3900
}
3901
3902
const _: () = assert!(FontData::default_data_long_enough(Device::MIN_SIZE));
3903
3904
impl Default for Device<'_> {
3905
0
    fn default() -> Self {
3906
        Self {
3907
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
3908
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
3909
        }
3910
0
    }
3911
}
3912
3913
impl<'a> MinByteRange<'a> for VariationIndex<'a> {
3914
0
    fn min_byte_range(&self) -> Range<usize> {
3915
0
        0..self.delta_format_byte_range().end
3916
0
    }
3917
0
    fn min_table_bytes(&self) -> &'a [u8] {
3918
0
        let range = self.min_byte_range();
3919
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
3920
0
    }
3921
}
3922
3923
impl ReadArgs for VariationIndex<'_> {
3924
    type Args = ();
3925
}
3926
3927
impl<'a> FontRead<'a> for VariationIndex<'a> {
3928
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3929
        #[allow(clippy::absurd_extreme_comparisons)]
3930
0
        if data.len() < Self::MIN_SIZE {
3931
0
            return Err(ReadError::OutOfBounds);
3932
0
        }
3933
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
3934
0
            return Err(ReadError::OutOfBounds);
3935
        };
3936
0
        Ok(Self { data })
3937
0
    }
3938
}
3939
3940
/// The fields at the start of the table, which are read directly.
3941
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
3942
#[repr(C, packed)]
3943
#[doc(hidden)]
3944
pub struct VariationIndexFixedHeader {
3945
    pub delta_set_outer_index: BigEndian<u16>,
3946
    pub delta_set_inner_index: BigEndian<u16>,
3947
    pub delta_format: BigEndian<DeltaFormat>,
3948
}
3949
3950
#[allow(clippy::absurd_extreme_comparisons)]
3951
const _: () = assert!(std::mem::size_of::<VariationIndexFixedHeader>() <= VariationIndex::MIN_SIZE);
3952
3953
/// Variation index table
3954
#[derive(Clone)]
3955
pub struct VariationIndex<'a> {
3956
    data: TableDataRef<'a, VariationIndexFixedHeader>,
3957
}
3958
3959
#[allow(clippy::needless_lifetimes)]
3960
impl<'a> VariationIndex<'a> {
3961
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN);
3962
    basic_table_impls!(impl_the_methods);
3963
3964
    /// A delta-set outer index — used to select an item variation
3965
    /// data subtable within the item variation store.
3966
0
    pub fn delta_set_outer_index(&self) -> u16 {
3967
0
        self.data.header().delta_set_outer_index.get()
3968
0
    }
3969
3970
    /// A delta-set inner index — used to select a delta-set row
3971
    /// within an item variation data subtable.
3972
0
    pub fn delta_set_inner_index(&self) -> u16 {
3973
0
        self.data.header().delta_set_inner_index.get()
3974
0
    }
3975
3976
    /// Format, = 0x8000
3977
0
    pub fn delta_format(&self) -> DeltaFormat {
3978
0
        self.data.header().delta_format.get()
3979
0
    }
3980
3981
0
    pub fn delta_set_outer_index_byte_range(&self) -> Range<usize> {
3982
0
        let start = 0;
3983
0
        let end = start + u16::RAW_BYTE_LEN;
3984
0
        start..end
3985
0
    }
3986
3987
0
    pub fn delta_set_inner_index_byte_range(&self) -> Range<usize> {
3988
0
        let start = self.delta_set_outer_index_byte_range().end;
3989
0
        let end = start + u16::RAW_BYTE_LEN;
3990
0
        start..end
3991
0
    }
3992
3993
0
    pub fn delta_format_byte_range(&self) -> Range<usize> {
3994
0
        let start = self.delta_set_inner_index_byte_range().end;
3995
0
        let end = start + DeltaFormat::RAW_BYTE_LEN;
3996
0
        start..end
3997
0
    }
3998
}
3999
4000
const _: () = assert!(FontData::default_data_long_enough(VariationIndex::MIN_SIZE));
4001
4002
impl Default for VariationIndex<'_> {
4003
0
    fn default() -> Self {
4004
        Self {
4005
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
4006
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
4007
        }
4008
0
    }
4009
}
4010
4011
/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
4012
#[derive(Clone)]
4013
pub enum DeviceOrVariationIndex<'a> {
4014
    Device(Device<'a>),
4015
    VariationIndex(VariationIndex<'a>),
4016
}
4017
4018
impl Default for DeviceOrVariationIndex<'_> {
4019
0
    fn default() -> Self {
4020
0
        Self::Device(Default::default())
4021
0
    }
4022
}
4023
4024
impl<'a> DeviceOrVariationIndex<'a> {
4025
    ///Return the `FontData` used to resolve offsets for this table.
4026
0
    pub fn offset_data(&self) -> FontData<'a> {
4027
0
        match self {
4028
0
            Self::Device(item) => item.offset_data(),
4029
0
            Self::VariationIndex(item) => item.offset_data(),
4030
        }
4031
0
    }
4032
}
4033
4034
impl ReadArgs for DeviceOrVariationIndex<'_> {
4035
    type Args = ();
4036
}
4037
4038
impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> {
4039
    #[inline]
4040
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4041
0
        let format: DeltaFormat = data.read_at(4usize)?;
4042
4043
        #[allow(clippy::redundant_guards)]
4044
0
        match format {
4045
0
            format if format != DeltaFormat::VariationIndex => {
4046
0
                Ok(Self::Device(FontRead::read(data)?))
4047
            }
4048
0
            format if format == DeltaFormat::VariationIndex => {
4049
0
                Ok(Self::VariationIndex(FontRead::read(data)?))
4050
            }
4051
0
            other => Err(ReadError::InvalidFormat(other.into())),
4052
        }
4053
0
    }
4054
}
4055
4056
impl<'a> MinByteRange<'a> for DeviceOrVariationIndex<'a> {
4057
0
    fn min_byte_range(&self) -> Range<usize> {
4058
0
        match self {
4059
0
            Self::Device(item) => item.min_byte_range(),
4060
0
            Self::VariationIndex(item) => item.min_byte_range(),
4061
        }
4062
0
    }
4063
0
    fn min_table_bytes(&self) -> &'a [u8] {
4064
0
        match self {
4065
0
            Self::Device(item) => item.min_table_bytes(),
4066
0
            Self::VariationIndex(item) => item.min_table_bytes(),
4067
        }
4068
0
    }
4069
}
4070
4071
impl<'a> MinByteRange<'a> for FeatureVariations<'a> {
4072
0
    fn min_byte_range(&self) -> Range<usize> {
4073
0
        0..self.feature_variation_records_byte_range().end
4074
0
    }
4075
0
    fn min_table_bytes(&self) -> &'a [u8] {
4076
0
        let range = self.min_byte_range();
4077
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
4078
0
    }
4079
}
4080
4081
impl ReadArgs for FeatureVariations<'_> {
4082
    type Args = ();
4083
}
4084
4085
impl<'a> FontRead<'a> for FeatureVariations<'a> {
4086
30
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4087
        #[allow(clippy::absurd_extreme_comparisons)]
4088
30
        if data.len() < Self::MIN_SIZE {
4089
0
            return Err(ReadError::OutOfBounds);
4090
30
        }
4091
30
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
4092
0
            return Err(ReadError::OutOfBounds);
4093
        };
4094
30
        Ok(Self { data })
4095
30
    }
4096
}
4097
4098
/// The fields at the start of the table, which are read directly.
4099
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4100
#[repr(C, packed)]
4101
#[doc(hidden)]
4102
pub struct FeatureVariationsFixedHeader {
4103
    pub version: BigEndian<MajorMinor>,
4104
    pub feature_variation_record_count: BigEndian<u32>,
4105
}
4106
4107
#[allow(clippy::absurd_extreme_comparisons)]
4108
const _: () =
4109
    assert!(std::mem::size_of::<FeatureVariationsFixedHeader>() <= FeatureVariations::MIN_SIZE);
4110
4111
/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
4112
/// Version 1.1 is defined in ISO/IEC 14496-22:2026, 6.2.11.
4113
#[derive(Clone)]
4114
pub struct FeatureVariations<'a> {
4115
    data: TableDataRef<'a, FeatureVariationsFixedHeader>,
4116
}
4117
4118
#[allow(clippy::needless_lifetimes)]
4119
impl<'a> FeatureVariations<'a> {
4120
    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4121
    basic_table_impls!(impl_the_methods);
4122
4123
75
    pub fn version(&self) -> MajorMinor {
4124
75
        self.data.header().version.get()
4125
75
    }
4126
4127
    /// Number of feature variation records.
4128
49
    pub fn feature_variation_record_count(&self) -> u32 {
4129
49
        self.data.header().feature_variation_record_count.get()
4130
49
    }
4131
4132
    /// Array of feature variation records.
4133
15
    pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] {
4134
15
        let range = self.feature_variation_records_byte_range();
4135
15
        self.offset_data()
4136
15
            .read_array(range)
4137
15
            .ok()
4138
15
            .unwrap_or_default()
4139
15
    }
4140
4141
    /// Number of lookup variation records.
4142
9
    pub fn lookup_variation_record_count(&self) -> Option<u32> {
4143
9
        let range = self.lookup_variation_record_count_byte_range();
4144
9
        (!range.is_empty())
4145
9
            .then(|| self.offset_data().read_at(range.start).ok())
4146
9
            .flatten()
4147
9
    }
4148
4149
33
    pub fn version_byte_range(&self) -> Range<usize> {
4150
33
        let start = 0;
4151
33
        let end = start + MajorMinor::RAW_BYTE_LEN;
4152
33
        start..end
4153
33
    }
4154
4155
33
    pub fn feature_variation_record_count_byte_range(&self) -> Range<usize> {
4156
33
        let start = self.version_byte_range().end;
4157
33
        let end = start + u32::RAW_BYTE_LEN;
4158
33
        start..end
4159
33
    }
4160
4161
33
    pub fn feature_variation_records_byte_range(&self) -> Range<usize> {
4162
33
        let feature_variation_record_count = self.feature_variation_record_count();
4163
33
        let start = self.feature_variation_record_count_byte_range().end;
4164
33
        let end = start
4165
33
            + (transforms::to_usize(feature_variation_record_count))
4166
33
                .saturating_mul(FeatureVariationRecord::RAW_BYTE_LEN);
4167
33
        start..end
4168
33
    }
4169
4170
18
    pub fn lookup_variation_record_count_byte_range(&self) -> Range<usize> {
4171
18
        let start = self.feature_variation_records_byte_range().end;
4172
18
        let end = if self.version().compatible((1u16, 1u16)) {
4173
18
            start + u32::RAW_BYTE_LEN
4174
        } else {
4175
0
            start
4176
        };
4177
18
        start..end
4178
18
    }
4179
4180
0
    pub fn lookup_variation_records_byte_range(&self) -> Range<usize> {
4181
0
        let lookup_variation_record_count =
4182
0
            self.lookup_variation_record_count().unwrap_or_default();
4183
0
        let start = self.lookup_variation_record_count_byte_range().end;
4184
0
        let end = if self.version().compatible((1u16, 1u16)) {
4185
0
            start
4186
0
                + (transforms::to_usize(lookup_variation_record_count))
4187
0
                    .saturating_mul(LookupVariationRecord::RAW_BYTE_LEN)
4188
        } else {
4189
0
            start
4190
        };
4191
0
        start..end
4192
0
    }
4193
}
4194
4195
const _: () = assert!(FontData::default_data_long_enough(
4196
    FeatureVariations::MIN_SIZE
4197
));
4198
4199
impl Default for FeatureVariations<'_> {
4200
0
    fn default() -> Self {
4201
        Self {
4202
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
4203
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
4204
        }
4205
0
    }
4206
}
4207
4208
/// Part of [FeatureVariations]
4209
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4210
#[repr(C)]
4211
#[repr(packed)]
4212
pub struct FeatureVariationRecord {
4213
    /// Offset to a condition set table, from beginning of
4214
    /// FeatureVariations table.
4215
    pub condition_set_offset: BigEndian<Nullable<Offset32>>,
4216
    /// Offset to a feature table substitution table, from beginning of
4217
    /// the FeatureVariations table.
4218
    pub feature_table_substitution_offset: BigEndian<Nullable<Offset32>>,
4219
}
4220
4221
impl FeatureVariationRecord {
4222
    /// Offset to a condition set table, from beginning of
4223
    /// FeatureVariations table.
4224
0
    pub fn condition_set_offset(&self) -> Nullable<Offset32> {
4225
0
        self.condition_set_offset.get()
4226
0
    }
4227
4228
    /// Offset to a condition set table, from beginning of
4229
    /// FeatureVariations table.
4230
    ///
4231
    /// The `data` argument should be retrieved from the parent table
4232
    /// By calling its `offset_data` method.
4233
0
    pub fn condition_set<'a>(
4234
0
        &self,
4235
0
        data: FontData<'a>,
4236
0
    ) -> Option<Result<ConditionSet<'a>, ReadError>> {
4237
0
        self.condition_set_offset().resolve(data)
4238
0
    }
4239
4240
    /// Offset to a feature table substitution table, from beginning of
4241
    /// the FeatureVariations table.
4242
0
    pub fn feature_table_substitution_offset(&self) -> Nullable<Offset32> {
4243
0
        self.feature_table_substitution_offset.get()
4244
0
    }
4245
4246
    /// Offset to a feature table substitution table, from beginning of
4247
    /// the FeatureVariations table.
4248
    ///
4249
    /// The `data` argument should be retrieved from the parent table
4250
    /// By calling its `offset_data` method.
4251
0
    pub fn feature_table_substitution<'a>(
4252
0
        &self,
4253
0
        data: FontData<'a>,
4254
0
    ) -> Option<Result<FeatureTableSubstitution<'a>, ReadError>> {
4255
0
        self.feature_table_substitution_offset().resolve(data)
4256
0
    }
4257
}
4258
4259
impl FixedSize for FeatureVariationRecord {
4260
    const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
4261
}
4262
4263
/// Lookup variations for one feature (ISO/IEC 14496-22:2026, 6.2.11).
4264
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4265
#[repr(C)]
4266
#[repr(packed)]
4267
pub struct LookupVariationRecord {
4268
    pub feature_index: BigEndian<u16>,
4269
    /// Offset from the beginning of FeatureVariations.
4270
    pub feature_lookups_offset: BigEndian<Offset32>,
4271
}
4272
4273
impl LookupVariationRecord {
4274
12
    pub fn feature_index(&self) -> u16 {
4275
12
        self.feature_index.get()
4276
12
    }
4277
4278
    /// Offset from the beginning of FeatureVariations.
4279
0
    pub fn feature_lookups_offset(&self) -> Offset32 {
4280
0
        self.feature_lookups_offset.get()
4281
0
    }
4282
4283
    /// Offset from the beginning of FeatureVariations.
4284
    ///
4285
    /// The `data` argument should be retrieved from the parent table
4286
    /// By calling its `offset_data` method.
4287
0
    pub fn feature_lookups<'a>(&self, data: FontData<'a>) -> Result<FeatureLookups<'a>, ReadError> {
4288
0
        self.feature_lookups_offset().resolve(data)
4289
0
    }
4290
}
4291
4292
impl FixedSize for LookupVariationRecord {
4293
    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
4294
}
4295
4296
impl<'a> MinByteRange<'a> for FeatureLookups<'a> {
4297
0
    fn min_byte_range(&self) -> Range<usize> {
4298
0
        0..self.lookup_condition_records_byte_range().end
4299
0
    }
4300
0
    fn min_table_bytes(&self) -> &'a [u8] {
4301
0
        let range = self.min_byte_range();
4302
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
4303
0
    }
4304
}
4305
4306
impl ReadArgs for FeatureLookups<'_> {
4307
    type Args = ();
4308
}
4309
4310
impl<'a> FontRead<'a> for FeatureLookups<'a> {
4311
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4312
        #[allow(clippy::absurd_extreme_comparisons)]
4313
0
        if data.len() < Self::MIN_SIZE {
4314
0
            return Err(ReadError::OutOfBounds);
4315
0
        }
4316
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
4317
0
            return Err(ReadError::OutOfBounds);
4318
        };
4319
0
        Ok(Self { data })
4320
0
    }
4321
}
4322
4323
/// The fields at the start of the table, which are read directly.
4324
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4325
#[repr(C, packed)]
4326
#[doc(hidden)]
4327
pub struct FeatureLookupsFixedHeader {
4328
    pub version: BigEndian<MajorMinor>,
4329
    pub flags: BigEndian<FeatureLookupsFlags>,
4330
    pub lookup_condition_count: BigEndian<u32>,
4331
}
4332
4333
#[allow(clippy::absurd_extreme_comparisons)]
4334
const _: () = assert!(std::mem::size_of::<FeatureLookupsFixedHeader>() <= FeatureLookups::MIN_SIZE);
4335
4336
/// Conditional lookup sets for one feature (ISO/IEC 14496-22:2026, 6.2.11).
4337
#[derive(Clone)]
4338
pub struct FeatureLookups<'a> {
4339
    data: TableDataRef<'a, FeatureLookupsFixedHeader>,
4340
}
4341
4342
#[allow(clippy::needless_lifetimes)]
4343
impl<'a> FeatureLookups<'a> {
4344
    pub const MIN_SIZE: usize =
4345
        (MajorMinor::RAW_BYTE_LEN + FeatureLookupsFlags::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4346
    basic_table_impls!(impl_the_methods);
4347
4348
0
    pub fn version(&self) -> MajorMinor {
4349
0
        self.data.header().version.get()
4350
0
    }
4351
4352
0
    pub fn flags(&self) -> FeatureLookupsFlags {
4353
0
        self.data.header().flags.get()
4354
0
    }
4355
4356
0
    pub fn lookup_condition_count(&self) -> u32 {
4357
0
        self.data.header().lookup_condition_count.get()
4358
0
    }
4359
4360
0
    pub fn lookup_condition_records(&self) -> &'a [LookupConditionRecord] {
4361
0
        let range = self.lookup_condition_records_byte_range();
4362
0
        self.offset_data()
4363
0
            .read_array(range)
4364
0
            .ok()
4365
0
            .unwrap_or_default()
4366
0
    }
4367
4368
0
    pub fn version_byte_range(&self) -> Range<usize> {
4369
0
        let start = 0;
4370
0
        let end = start + MajorMinor::RAW_BYTE_LEN;
4371
0
        start..end
4372
0
    }
4373
4374
0
    pub fn flags_byte_range(&self) -> Range<usize> {
4375
0
        let start = self.version_byte_range().end;
4376
0
        let end = start + FeatureLookupsFlags::RAW_BYTE_LEN;
4377
0
        start..end
4378
0
    }
4379
4380
0
    pub fn lookup_condition_count_byte_range(&self) -> Range<usize> {
4381
0
        let start = self.flags_byte_range().end;
4382
0
        let end = start + u32::RAW_BYTE_LEN;
4383
0
        start..end
4384
0
    }
4385
4386
0
    pub fn lookup_condition_records_byte_range(&self) -> Range<usize> {
4387
0
        let lookup_condition_count = self.lookup_condition_count();
4388
0
        let start = self.lookup_condition_count_byte_range().end;
4389
0
        let end = start
4390
0
            + (transforms::to_usize(lookup_condition_count))
4391
0
                .saturating_mul(LookupConditionRecord::RAW_BYTE_LEN);
4392
0
        start..end
4393
0
    }
4394
}
4395
4396
const _: () = assert!(FontData::default_data_long_enough(FeatureLookups::MIN_SIZE));
4397
4398
impl Default for FeatureLookups<'_> {
4399
0
    fn default() -> Self {
4400
        Self {
4401
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
4402
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
4403
        }
4404
0
    }
4405
}
4406
4407
/// Qualifiers for [FeatureLookups].
4408
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
4409
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4410
#[repr(transparent)]
4411
pub struct FeatureLookupsFlags {
4412
    bits: u16,
4413
}
4414
4415
impl FeatureLookupsFlags {
4416
    /// Include the current feature's lookups as well as conditional lookups.
4417
    pub const ADD_DEFAULT_LOOKUPS: Self = Self { bits: 0x0001 };
4418
}
4419
4420
impl FeatureLookupsFlags {
4421
    ///  Returns an empty set of flags.
4422
    #[inline]
4423
0
    pub const fn empty() -> Self {
4424
0
        Self { bits: 0 }
4425
0
    }
4426
4427
    /// Returns the set containing all flags.
4428
    #[inline]
4429
0
    pub const fn all() -> Self {
4430
0
        Self {
4431
0
            bits: Self::ADD_DEFAULT_LOOKUPS.bits,
4432
0
        }
4433
0
    }
4434
4435
    /// Returns the raw value of the flags currently stored.
4436
    #[inline]
4437
0
    pub const fn bits(&self) -> u16 {
4438
0
        self.bits
4439
0
    }
4440
4441
    /// Convert from underlying bit representation, unless that
4442
    /// representation contains bits that do not correspond to a flag.
4443
    #[inline]
4444
0
    pub const fn from_bits(bits: u16) -> Option<Self> {
4445
0
        if (bits & !Self::all().bits()) == 0 {
4446
0
            Some(Self { bits })
4447
        } else {
4448
0
            None
4449
        }
4450
0
    }
4451
4452
    /// Convert from underlying bit representation, dropping any bits
4453
    /// that do not correspond to flags.
4454
    #[inline]
4455
0
    pub const fn from_bits_truncate(bits: u16) -> Self {
4456
0
        Self {
4457
0
            bits: bits & Self::all().bits,
4458
0
        }
4459
0
    }
4460
4461
    /// Returns `true` if no flags are currently stored.
4462
    #[inline]
4463
0
    pub const fn is_empty(&self) -> bool {
4464
0
        self.bits() == Self::empty().bits()
4465
0
    }
4466
4467
    /// Returns `true` if there are flags common to both `self` and `other`.
4468
    #[inline]
4469
0
    pub const fn intersects(&self, other: Self) -> bool {
4470
0
        !(Self {
4471
0
            bits: self.bits & other.bits,
4472
0
        })
4473
0
        .is_empty()
4474
0
    }
4475
4476
    /// Returns `true` if all of the flags in `other` are contained within `self`.
4477
    #[inline]
4478
0
    pub const fn contains(&self, other: Self) -> bool {
4479
0
        (self.bits & other.bits) == other.bits
4480
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::FeatureLookupsFlags>::contains
Unexecuted instantiation: <read_fonts::tables::layout::FeatureLookupsFlags>::contains
4481
4482
    /// Inserts the specified flags in-place.
4483
    #[inline]
4484
0
    pub fn insert(&mut self, other: Self) {
4485
0
        self.bits |= other.bits;
4486
0
    }
4487
4488
    /// Removes the specified flags in-place.
4489
    #[inline]
4490
0
    pub fn remove(&mut self, other: Self) {
4491
0
        self.bits &= !other.bits;
4492
0
    }
4493
4494
    /// Toggles the specified flags in-place.
4495
    #[inline]
4496
0
    pub fn toggle(&mut self, other: Self) {
4497
0
        self.bits ^= other.bits;
4498
0
    }
4499
4500
    /// Returns the intersection between the flags in `self` and
4501
    /// `other`.
4502
    ///
4503
    /// Specifically, the returned set contains only the flags which are
4504
    /// present in *both* `self` *and* `other`.
4505
    ///
4506
    /// This is equivalent to using the `&` operator (e.g.
4507
    /// [`ops::BitAnd`]), as in `flags & other`.
4508
    ///
4509
    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
4510
    #[inline]
4511
    #[must_use]
4512
0
    pub const fn intersection(self, other: Self) -> Self {
4513
0
        Self {
4514
0
            bits: self.bits & other.bits,
4515
0
        }
4516
0
    }
4517
4518
    /// Returns the union of between the flags in `self` and `other`.
4519
    ///
4520
    /// Specifically, the returned set contains all flags which are
4521
    /// present in *either* `self` *or* `other`, including any which are
4522
    /// present in both.
4523
    ///
4524
    /// This is equivalent to using the `|` operator (e.g.
4525
    /// [`ops::BitOr`]), as in `flags | other`.
4526
    ///
4527
    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
4528
    #[inline]
4529
    #[must_use]
4530
0
    pub const fn union(self, other: Self) -> Self {
4531
0
        Self {
4532
0
            bits: self.bits | other.bits,
4533
0
        }
4534
0
    }
4535
4536
    /// Returns the difference between the flags in `self` and `other`.
4537
    ///
4538
    /// Specifically, the returned set contains all flags present in
4539
    /// `self`, except for the ones present in `other`.
4540
    ///
4541
    /// It is also conceptually equivalent to the "bit-clear" operation:
4542
    /// `flags & !other` (and this syntax is also supported).
4543
    ///
4544
    /// This is equivalent to using the `-` operator (e.g.
4545
    /// [`ops::Sub`]), as in `flags - other`.
4546
    ///
4547
    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
4548
    #[inline]
4549
    #[must_use]
4550
0
    pub const fn difference(self, other: Self) -> Self {
4551
0
        Self {
4552
0
            bits: self.bits & !other.bits,
4553
0
        }
4554
0
    }
4555
}
4556
4557
impl std::ops::BitOr for FeatureLookupsFlags {
4558
    type Output = Self;
4559
4560
    /// Returns the union of the two sets of flags.
4561
    #[inline]
4562
0
    fn bitor(self, other: FeatureLookupsFlags) -> Self {
4563
0
        Self {
4564
0
            bits: self.bits | other.bits,
4565
0
        }
4566
0
    }
4567
}
4568
4569
impl std::ops::BitOrAssign for FeatureLookupsFlags {
4570
    /// Adds the set of flags.
4571
    #[inline]
4572
0
    fn bitor_assign(&mut self, other: Self) {
4573
0
        self.bits |= other.bits;
4574
0
    }
4575
}
4576
4577
impl std::ops::BitXor for FeatureLookupsFlags {
4578
    type Output = Self;
4579
4580
    /// Returns the left flags, but with all the right flags toggled.
4581
    #[inline]
4582
0
    fn bitxor(self, other: Self) -> Self {
4583
0
        Self {
4584
0
            bits: self.bits ^ other.bits,
4585
0
        }
4586
0
    }
4587
}
4588
4589
impl std::ops::BitXorAssign for FeatureLookupsFlags {
4590
    /// Toggles the set of flags.
4591
    #[inline]
4592
0
    fn bitxor_assign(&mut self, other: Self) {
4593
0
        self.bits ^= other.bits;
4594
0
    }
4595
}
4596
4597
impl std::ops::BitAnd for FeatureLookupsFlags {
4598
    type Output = Self;
4599
4600
    /// Returns the intersection between the two sets of flags.
4601
    #[inline]
4602
0
    fn bitand(self, other: Self) -> Self {
4603
0
        Self {
4604
0
            bits: self.bits & other.bits,
4605
0
        }
4606
0
    }
4607
}
4608
4609
impl std::ops::BitAndAssign for FeatureLookupsFlags {
4610
    /// Disables all flags disabled in the set.
4611
    #[inline]
4612
0
    fn bitand_assign(&mut self, other: Self) {
4613
0
        self.bits &= other.bits;
4614
0
    }
4615
}
4616
4617
impl std::ops::Sub for FeatureLookupsFlags {
4618
    type Output = Self;
4619
4620
    /// Returns the set difference of the two sets of flags.
4621
    #[inline]
4622
0
    fn sub(self, other: Self) -> Self {
4623
0
        Self {
4624
0
            bits: self.bits & !other.bits,
4625
0
        }
4626
0
    }
4627
}
4628
4629
impl std::ops::SubAssign for FeatureLookupsFlags {
4630
    /// Disables all flags enabled in the set.
4631
    #[inline]
4632
0
    fn sub_assign(&mut self, other: Self) {
4633
0
        self.bits &= !other.bits;
4634
0
    }
4635
}
4636
4637
impl std::ops::Not for FeatureLookupsFlags {
4638
    type Output = Self;
4639
4640
    /// Returns the complement of this set of flags.
4641
    #[inline]
4642
0
    fn not(self) -> Self {
4643
0
        Self { bits: !self.bits } & Self::all()
4644
0
    }
4645
}
4646
4647
impl std::fmt::Debug for FeatureLookupsFlags {
4648
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4649
0
        let members: &[(&str, Self)] = &[("ADD_DEFAULT_LOOKUPS", Self::ADD_DEFAULT_LOOKUPS)];
4650
0
        let mut first = true;
4651
0
        for (name, value) in members {
4652
0
            if self.contains(*value) {
4653
0
                if !first {
4654
0
                    f.write_str(" | ")?;
4655
0
                }
4656
0
                first = false;
4657
0
                f.write_str(name)?;
4658
0
            }
4659
        }
4660
0
        if first {
4661
0
            f.write_str("(empty)")?;
4662
0
        }
4663
0
        Ok(())
4664
0
    }
4665
}
4666
4667
impl std::fmt::Binary for FeatureLookupsFlags {
4668
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4669
0
        std::fmt::Binary::fmt(&self.bits, f)
4670
0
    }
4671
}
4672
4673
impl std::fmt::Octal for FeatureLookupsFlags {
4674
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4675
0
        std::fmt::Octal::fmt(&self.bits, f)
4676
0
    }
4677
}
4678
4679
impl std::fmt::LowerHex for FeatureLookupsFlags {
4680
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4681
0
        std::fmt::LowerHex::fmt(&self.bits, f)
4682
0
    }
4683
}
4684
4685
impl std::fmt::UpperHex for FeatureLookupsFlags {
4686
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4687
0
        std::fmt::UpperHex::fmt(&self.bits, f)
4688
0
    }
4689
}
4690
4691
impl font_types::Scalar for FeatureLookupsFlags {
4692
    type Raw = <u16 as font_types::Scalar>::Raw;
4693
0
    fn to_raw(self) -> Self::Raw {
4694
0
        self.bits().to_raw()
4695
0
    }
4696
0
    fn from_raw(raw: Self::Raw) -> Self {
4697
0
        let t = <u16>::from_raw(raw);
4698
0
        Self::from_bits_truncate(t)
4699
0
    }
4700
}
4701
4702
/// Lookups to include when a condition is true.
4703
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4704
#[repr(C)]
4705
#[repr(packed)]
4706
pub struct LookupConditionRecord {
4707
    /// Offset from the beginning of FeatureLookups; null means true.
4708
    pub condition_offset: BigEndian<Nullable<Offset32>>,
4709
    /// Offset from the beginning of FeatureLookups.
4710
    pub lookup_index_list_offset: BigEndian<Offset32>,
4711
}
4712
4713
impl LookupConditionRecord {
4714
    /// Offset from the beginning of FeatureLookups; null means true.
4715
0
    pub fn condition_offset(&self) -> Nullable<Offset32> {
4716
0
        self.condition_offset.get()
4717
0
    }
4718
4719
    /// Offset from the beginning of FeatureLookups; null means true.
4720
    ///
4721
    /// The `data` argument should be retrieved from the parent table
4722
    /// By calling its `offset_data` method.
4723
0
    pub fn condition<'a>(&self, data: FontData<'a>) -> Option<Result<Condition<'a>, ReadError>> {
4724
0
        self.condition_offset().resolve(data)
4725
0
    }
4726
4727
    /// Offset from the beginning of FeatureLookups.
4728
0
    pub fn lookup_index_list_offset(&self) -> Offset32 {
4729
0
        self.lookup_index_list_offset.get()
4730
0
    }
4731
4732
    /// Offset from the beginning of FeatureLookups.
4733
    ///
4734
    /// The `data` argument should be retrieved from the parent table
4735
    /// By calling its `offset_data` method.
4736
0
    pub fn lookup_index_list<'a>(
4737
0
        &self,
4738
0
        data: FontData<'a>,
4739
0
    ) -> Result<LookupIndexList<'a>, ReadError> {
4740
0
        self.lookup_index_list_offset().resolve(data)
4741
0
    }
4742
}
4743
4744
impl FixedSize for LookupConditionRecord {
4745
    const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
4746
}
4747
4748
impl<'a> MinByteRange<'a> for LookupIndexList<'a> {
4749
0
    fn min_byte_range(&self) -> Range<usize> {
4750
0
        0..self.lookup_indices_byte_range().end
4751
0
    }
4752
0
    fn min_table_bytes(&self) -> &'a [u8] {
4753
0
        let range = self.min_byte_range();
4754
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
4755
0
    }
4756
}
4757
4758
impl ReadArgs for LookupIndexList<'_> {
4759
    type Args = ();
4760
}
4761
4762
impl<'a> FontRead<'a> for LookupIndexList<'a> {
4763
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4764
        #[allow(clippy::absurd_extreme_comparisons)]
4765
0
        if data.len() < Self::MIN_SIZE {
4766
0
            return Err(ReadError::OutOfBounds);
4767
0
        }
4768
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
4769
0
            return Err(ReadError::OutOfBounds);
4770
        };
4771
0
        Ok(Self { data })
4772
0
    }
4773
}
4774
4775
/// The fields at the start of the table, which are read directly.
4776
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4777
#[repr(C, packed)]
4778
#[doc(hidden)]
4779
pub struct LookupIndexListFixedHeader {
4780
    pub lookup_index_count: BigEndian<u16>,
4781
}
4782
4783
#[allow(clippy::absurd_extreme_comparisons)]
4784
const _: () =
4785
    assert!(std::mem::size_of::<LookupIndexListFixedHeader>() <= LookupIndexList::MIN_SIZE);
4786
4787
/// Indices into the GSUB or GPOS LookupList.
4788
#[derive(Clone)]
4789
pub struct LookupIndexList<'a> {
4790
    data: TableDataRef<'a, LookupIndexListFixedHeader>,
4791
}
4792
4793
#[allow(clippy::needless_lifetimes)]
4794
impl<'a> LookupIndexList<'a> {
4795
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
4796
    basic_table_impls!(impl_the_methods);
4797
4798
0
    pub fn lookup_index_count(&self) -> u16 {
4799
0
        self.data.header().lookup_index_count.get()
4800
0
    }
4801
4802
0
    pub fn lookup_indices(&self) -> &'a [BigEndian<u16>] {
4803
0
        let range = self.lookup_indices_byte_range();
4804
0
        self.offset_data()
4805
0
            .read_array(range)
4806
0
            .ok()
4807
0
            .unwrap_or_default()
4808
0
    }
4809
4810
0
    pub fn lookup_index_count_byte_range(&self) -> Range<usize> {
4811
0
        let start = 0;
4812
0
        let end = start + u16::RAW_BYTE_LEN;
4813
0
        start..end
4814
0
    }
4815
4816
0
    pub fn lookup_indices_byte_range(&self) -> Range<usize> {
4817
0
        let lookup_index_count = self.lookup_index_count();
4818
0
        let start = self.lookup_index_count_byte_range().end;
4819
0
        let end =
4820
0
            start + (transforms::to_usize(lookup_index_count)).saturating_mul(u16::RAW_BYTE_LEN);
4821
0
        start..end
4822
0
    }
4823
}
4824
4825
const _: () = assert!(FontData::default_data_long_enough(
4826
    LookupIndexList::MIN_SIZE
4827
));
4828
4829
impl Default for LookupIndexList<'_> {
4830
0
    fn default() -> Self {
4831
        Self {
4832
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
4833
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
4834
        }
4835
0
    }
4836
}
4837
4838
impl<'a> MinByteRange<'a> for ConditionSet<'a> {
4839
0
    fn min_byte_range(&self) -> Range<usize> {
4840
0
        0..self.condition_offsets_byte_range().end
4841
0
    }
4842
0
    fn min_table_bytes(&self) -> &'a [u8] {
4843
0
        let range = self.min_byte_range();
4844
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
4845
0
    }
4846
}
4847
4848
impl ReadArgs for ConditionSet<'_> {
4849
    type Args = ();
4850
}
4851
4852
impl<'a> FontRead<'a> for ConditionSet<'a> {
4853
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4854
        #[allow(clippy::absurd_extreme_comparisons)]
4855
0
        if data.len() < Self::MIN_SIZE {
4856
0
            return Err(ReadError::OutOfBounds);
4857
0
        }
4858
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
4859
0
            return Err(ReadError::OutOfBounds);
4860
        };
4861
0
        Ok(Self { data })
4862
0
    }
4863
}
4864
4865
/// The fields at the start of the table, which are read directly.
4866
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
4867
#[repr(C, packed)]
4868
#[doc(hidden)]
4869
pub struct ConditionSetFixedHeader {
4870
    pub condition_count: BigEndian<u16>,
4871
}
4872
4873
#[allow(clippy::absurd_extreme_comparisons)]
4874
const _: () = assert!(std::mem::size_of::<ConditionSetFixedHeader>() <= ConditionSet::MIN_SIZE);
4875
4876
/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
4877
#[derive(Clone)]
4878
pub struct ConditionSet<'a> {
4879
    data: TableDataRef<'a, ConditionSetFixedHeader>,
4880
}
4881
4882
#[allow(clippy::needless_lifetimes)]
4883
impl<'a> ConditionSet<'a> {
4884
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
4885
    basic_table_impls!(impl_the_methods);
4886
4887
    /// Number of conditions for this condition set.
4888
0
    pub fn condition_count(&self) -> u16 {
4889
0
        self.data.header().condition_count.get()
4890
0
    }
4891
4892
    /// Array of offsets to condition tables, from beginning of the
4893
    /// ConditionSet table.
4894
0
    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset32>] {
4895
0
        let range = self.condition_offsets_byte_range();
4896
0
        self.offset_data()
4897
0
            .read_array(range)
4898
0
            .ok()
4899
0
            .unwrap_or_default()
4900
0
    }
4901
4902
    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
4903
0
    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> {
4904
0
        let data = self.offset_data();
4905
0
        let offsets = self.condition_offsets();
4906
0
        ArrayOfOffsets::new(offsets, data, ())
4907
0
    }
4908
4909
0
    pub fn condition_count_byte_range(&self) -> Range<usize> {
4910
0
        let start = 0;
4911
0
        let end = start + u16::RAW_BYTE_LEN;
4912
0
        start..end
4913
0
    }
4914
4915
0
    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4916
0
        let condition_count = self.condition_count();
4917
0
        let start = self.condition_count_byte_range().end;
4918
0
        let end =
4919
0
            start + (transforms::to_usize(condition_count)).saturating_mul(Offset32::RAW_BYTE_LEN);
4920
0
        start..end
4921
0
    }
4922
}
4923
4924
const _: () = assert!(FontData::default_data_long_enough(ConditionSet::MIN_SIZE));
4925
4926
impl Default for ConditionSet<'_> {
4927
0
    fn default() -> Self {
4928
        Self {
4929
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
4930
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
4931
        }
4932
0
    }
4933
}
4934
4935
/// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table)
4936
///
4937
/// Formats 2..5 are defined in ISO/IEC 14496-22:2026, 6.2.10.
4938
#[derive(Clone)]
4939
pub enum Condition<'a> {
4940
    Format1AxisRange(ConditionFormat1<'a>),
4941
    Format2VariableValue(ConditionFormat2<'a>),
4942
    Format3And(ConditionFormat3<'a>),
4943
    Format4Or(ConditionFormat4<'a>),
4944
    Format5Negate(ConditionFormat5<'a>),
4945
}
4946
4947
impl Default for Condition<'_> {
4948
0
    fn default() -> Self {
4949
0
        Self::Format1AxisRange(Default::default())
4950
0
    }
4951
}
4952
4953
impl<'a> Condition<'a> {
4954
    ///Return the `FontData` used to resolve offsets for this table.
4955
0
    pub fn offset_data(&self) -> FontData<'a> {
4956
0
        match self {
4957
0
            Self::Format1AxisRange(item) => item.offset_data(),
4958
0
            Self::Format2VariableValue(item) => item.offset_data(),
4959
0
            Self::Format3And(item) => item.offset_data(),
4960
0
            Self::Format4Or(item) => item.offset_data(),
4961
0
            Self::Format5Negate(item) => item.offset_data(),
4962
        }
4963
0
    }
4964
4965
    /// Format, = 1
4966
0
    pub fn format(&self) -> u16 {
4967
0
        match self {
4968
0
            Self::Format1AxisRange(item) => item.format(),
4969
0
            Self::Format2VariableValue(item) => item.format(),
4970
0
            Self::Format3And(item) => item.format(),
4971
0
            Self::Format4Or(item) => item.format(),
4972
0
            Self::Format5Negate(item) => item.format(),
4973
        }
4974
0
    }
4975
}
4976
4977
impl ReadArgs for Condition<'_> {
4978
    type Args = ();
4979
}
4980
4981
impl<'a> FontRead<'a> for Condition<'a> {
4982
    #[inline]
4983
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4984
0
        let format: u16 = data.read_at(0usize)?;
4985
0
        match format {
4986
0
            ConditionFormat1::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)),
4987
0
            ConditionFormat2::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)),
4988
0
            ConditionFormat3::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)),
4989
0
            ConditionFormat4::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)),
4990
0
            ConditionFormat5::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)),
4991
0
            other => Err(ReadError::InvalidFormat(other.into())),
4992
        }
4993
0
    }
4994
}
4995
4996
impl<'a> MinByteRange<'a> for Condition<'a> {
4997
0
    fn min_byte_range(&self) -> Range<usize> {
4998
0
        match self {
4999
0
            Self::Format1AxisRange(item) => item.min_byte_range(),
5000
0
            Self::Format2VariableValue(item) => item.min_byte_range(),
5001
0
            Self::Format3And(item) => item.min_byte_range(),
5002
0
            Self::Format4Or(item) => item.min_byte_range(),
5003
0
            Self::Format5Negate(item) => item.min_byte_range(),
5004
        }
5005
0
    }
5006
0
    fn min_table_bytes(&self) -> &'a [u8] {
5007
0
        match self {
5008
0
            Self::Format1AxisRange(item) => item.min_table_bytes(),
5009
0
            Self::Format2VariableValue(item) => item.min_table_bytes(),
5010
0
            Self::Format3And(item) => item.min_table_bytes(),
5011
0
            Self::Format4Or(item) => item.min_table_bytes(),
5012
0
            Self::Format5Negate(item) => item.min_table_bytes(),
5013
        }
5014
0
    }
5015
}
5016
5017
impl Format<u16> for ConditionFormat1<'_> {
5018
    const FORMAT: u16 = 1;
5019
}
5020
5021
impl<'a> MinByteRange<'a> for ConditionFormat1<'a> {
5022
0
    fn min_byte_range(&self) -> Range<usize> {
5023
0
        0..self.filter_range_max_value_byte_range().end
5024
0
    }
5025
0
    fn min_table_bytes(&self) -> &'a [u8] {
5026
0
        let range = self.min_byte_range();
5027
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5028
0
    }
5029
}
5030
5031
impl ReadArgs for ConditionFormat1<'_> {
5032
    type Args = ();
5033
}
5034
5035
impl<'a> FontRead<'a> for ConditionFormat1<'a> {
5036
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5037
        #[allow(clippy::absurd_extreme_comparisons)]
5038
0
        if data.len() < Self::MIN_SIZE {
5039
0
            return Err(ReadError::OutOfBounds);
5040
0
        }
5041
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5042
0
            return Err(ReadError::OutOfBounds);
5043
        };
5044
0
        Ok(Self { data })
5045
0
    }
5046
}
5047
5048
/// The fields at the start of the table, which are read directly.
5049
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5050
#[repr(C, packed)]
5051
#[doc(hidden)]
5052
pub struct ConditionFormat1FixedHeader {
5053
    pub format: BigEndian<u16>,
5054
    pub axis_index: BigEndian<u16>,
5055
    pub filter_range_min_value: BigEndian<F2Dot14>,
5056
    pub filter_range_max_value: BigEndian<F2Dot14>,
5057
}
5058
5059
#[allow(clippy::absurd_extreme_comparisons)]
5060
const _: () =
5061
    assert!(std::mem::size_of::<ConditionFormat1FixedHeader>() <= ConditionFormat1::MIN_SIZE);
5062
5063
/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
5064
#[derive(Clone)]
5065
pub struct ConditionFormat1<'a> {
5066
    data: TableDataRef<'a, ConditionFormat1FixedHeader>,
5067
}
5068
5069
#[allow(clippy::needless_lifetimes)]
5070
impl<'a> ConditionFormat1<'a> {
5071
    pub const MIN_SIZE: usize =
5072
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
5073
    basic_table_impls!(impl_the_methods);
5074
5075
    /// Format, = 1
5076
0
    pub fn format(&self) -> u16 {
5077
0
        self.data.header().format.get()
5078
0
    }
5079
5080
    /// Index (zero-based) for the variation axis within the 'fvar'
5081
    /// table.
5082
0
    pub fn axis_index(&self) -> u16 {
5083
0
        self.data.header().axis_index.get()
5084
0
    }
5085
5086
    /// Minimum value of the font variation instances that satisfy this
5087
    /// condition.
5088
0
    pub fn filter_range_min_value(&self) -> F2Dot14 {
5089
0
        self.data.header().filter_range_min_value.get()
5090
0
    }
5091
5092
    /// Maximum value of the font variation instances that satisfy this
5093
    /// condition.
5094
0
    pub fn filter_range_max_value(&self) -> F2Dot14 {
5095
0
        self.data.header().filter_range_max_value.get()
5096
0
    }
5097
5098
0
    pub fn format_byte_range(&self) -> Range<usize> {
5099
0
        let start = 0;
5100
0
        let end = start + u16::RAW_BYTE_LEN;
5101
0
        start..end
5102
0
    }
5103
5104
0
    pub fn axis_index_byte_range(&self) -> Range<usize> {
5105
0
        let start = self.format_byte_range().end;
5106
0
        let end = start + u16::RAW_BYTE_LEN;
5107
0
        start..end
5108
0
    }
5109
5110
0
    pub fn filter_range_min_value_byte_range(&self) -> Range<usize> {
5111
0
        let start = self.axis_index_byte_range().end;
5112
0
        let end = start + F2Dot14::RAW_BYTE_LEN;
5113
0
        start..end
5114
0
    }
5115
5116
0
    pub fn filter_range_max_value_byte_range(&self) -> Range<usize> {
5117
0
        let start = self.filter_range_min_value_byte_range().end;
5118
0
        let end = start + F2Dot14::RAW_BYTE_LEN;
5119
0
        start..end
5120
0
    }
5121
}
5122
5123
const _: () = assert!(FontData::default_data_long_enough(
5124
    ConditionFormat1::MIN_SIZE
5125
));
5126
5127
impl Default for ConditionFormat1<'_> {
5128
0
    fn default() -> Self {
5129
        Self {
5130
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
5131
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5132
        }
5133
0
    }
5134
}
5135
5136
impl Format<u16> for ConditionFormat2<'_> {
5137
    const FORMAT: u16 = 2;
5138
}
5139
5140
impl<'a> MinByteRange<'a> for ConditionFormat2<'a> {
5141
0
    fn min_byte_range(&self) -> Range<usize> {
5142
0
        0..self.var_index_byte_range().end
5143
0
    }
5144
0
    fn min_table_bytes(&self) -> &'a [u8] {
5145
0
        let range = self.min_byte_range();
5146
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5147
0
    }
5148
}
5149
5150
impl ReadArgs for ConditionFormat2<'_> {
5151
    type Args = ();
5152
}
5153
5154
impl<'a> FontRead<'a> for ConditionFormat2<'a> {
5155
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5156
        #[allow(clippy::absurd_extreme_comparisons)]
5157
0
        if data.len() < Self::MIN_SIZE {
5158
0
            return Err(ReadError::OutOfBounds);
5159
0
        }
5160
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5161
0
            return Err(ReadError::OutOfBounds);
5162
        };
5163
0
        Ok(Self { data })
5164
0
    }
5165
}
5166
5167
/// The fields at the start of the table, which are read directly.
5168
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5169
#[repr(C, packed)]
5170
#[doc(hidden)]
5171
pub struct ConditionFormat2FixedHeader {
5172
    pub format: BigEndian<u16>,
5173
    pub default_value: BigEndian<i16>,
5174
    pub var_index: BigEndian<u32>,
5175
}
5176
5177
#[allow(clippy::absurd_extreme_comparisons)]
5178
const _: () =
5179
    assert!(std::mem::size_of::<ConditionFormat2FixedHeader>() <= ConditionFormat2::MIN_SIZE);
5180
5181
/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
5182
#[derive(Clone)]
5183
pub struct ConditionFormat2<'a> {
5184
    data: TableDataRef<'a, ConditionFormat2FixedHeader>,
5185
}
5186
5187
#[allow(clippy::needless_lifetimes)]
5188
impl<'a> ConditionFormat2<'a> {
5189
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
5190
    basic_table_impls!(impl_the_methods);
5191
5192
    /// Format, = 2
5193
0
    pub fn format(&self) -> u16 {
5194
0
        self.data.header().format.get()
5195
0
    }
5196
5197
    /// Value at default instance.
5198
0
    pub fn default_value(&self) -> i16 {
5199
0
        self.data.header().default_value.get()
5200
0
    }
5201
5202
    /// Variation index to vary the value based on current designspace location.
5203
0
    pub fn var_index(&self) -> u32 {
5204
0
        self.data.header().var_index.get()
5205
0
    }
5206
5207
0
    pub fn format_byte_range(&self) -> Range<usize> {
5208
0
        let start = 0;
5209
0
        let end = start + u16::RAW_BYTE_LEN;
5210
0
        start..end
5211
0
    }
5212
5213
0
    pub fn default_value_byte_range(&self) -> Range<usize> {
5214
0
        let start = self.format_byte_range().end;
5215
0
        let end = start + i16::RAW_BYTE_LEN;
5216
0
        start..end
5217
0
    }
5218
5219
0
    pub fn var_index_byte_range(&self) -> Range<usize> {
5220
0
        let start = self.default_value_byte_range().end;
5221
0
        let end = start + u32::RAW_BYTE_LEN;
5222
0
        start..end
5223
0
    }
5224
}
5225
5226
impl Format<u16> for ConditionFormat3<'_> {
5227
    const FORMAT: u16 = 3;
5228
}
5229
5230
impl<'a> MinByteRange<'a> for ConditionFormat3<'a> {
5231
0
    fn min_byte_range(&self) -> Range<usize> {
5232
0
        0..self.condition_offsets_byte_range().end
5233
0
    }
5234
0
    fn min_table_bytes(&self) -> &'a [u8] {
5235
0
        let range = self.min_byte_range();
5236
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5237
0
    }
5238
}
5239
5240
impl ReadArgs for ConditionFormat3<'_> {
5241
    type Args = ();
5242
}
5243
5244
impl<'a> FontRead<'a> for ConditionFormat3<'a> {
5245
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5246
        #[allow(clippy::absurd_extreme_comparisons)]
5247
0
        if data.len() < Self::MIN_SIZE {
5248
0
            return Err(ReadError::OutOfBounds);
5249
0
        }
5250
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5251
0
            return Err(ReadError::OutOfBounds);
5252
        };
5253
0
        Ok(Self { data })
5254
0
    }
5255
}
5256
5257
/// The fields at the start of the table, which are read directly.
5258
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5259
#[repr(C, packed)]
5260
#[doc(hidden)]
5261
pub struct ConditionFormat3FixedHeader {
5262
    pub format: BigEndian<u16>,
5263
    pub condition_count: u8,
5264
}
5265
5266
#[allow(clippy::absurd_extreme_comparisons)]
5267
const _: () =
5268
    assert!(std::mem::size_of::<ConditionFormat3FixedHeader>() <= ConditionFormat3::MIN_SIZE);
5269
5270
/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
5271
#[derive(Clone)]
5272
pub struct ConditionFormat3<'a> {
5273
    data: TableDataRef<'a, ConditionFormat3FixedHeader>,
5274
}
5275
5276
#[allow(clippy::needless_lifetimes)]
5277
impl<'a> ConditionFormat3<'a> {
5278
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
5279
    basic_table_impls!(impl_the_methods);
5280
5281
    /// Format, = 3
5282
0
    pub fn format(&self) -> u16 {
5283
0
        self.data.header().format.get()
5284
0
    }
5285
5286
    /// Number of conditions.
5287
0
    pub fn condition_count(&self) -> u8 {
5288
0
        self.data.header().condition_count
5289
0
    }
5290
5291
    /// Array of condition tables for this conjunction (AND) expression.
5292
0
    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
5293
0
        let range = self.condition_offsets_byte_range();
5294
0
        self.offset_data()
5295
0
            .read_array(range)
5296
0
            .ok()
5297
0
            .unwrap_or_default()
5298
0
    }
5299
5300
    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
5301
0
    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
5302
0
        let data = self.offset_data();
5303
0
        let offsets = self.condition_offsets();
5304
0
        ArrayOfOffsets::new(offsets, data, ())
5305
0
    }
5306
5307
0
    pub fn format_byte_range(&self) -> Range<usize> {
5308
0
        let start = 0;
5309
0
        let end = start + u16::RAW_BYTE_LEN;
5310
0
        start..end
5311
0
    }
5312
5313
0
    pub fn condition_count_byte_range(&self) -> Range<usize> {
5314
0
        let start = self.format_byte_range().end;
5315
0
        let end = start + u8::RAW_BYTE_LEN;
5316
0
        start..end
5317
0
    }
5318
5319
0
    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
5320
0
        let condition_count = self.condition_count();
5321
0
        let start = self.condition_count_byte_range().end;
5322
0
        let end =
5323
0
            start + (transforms::to_usize(condition_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
5324
0
        start..end
5325
0
    }
5326
}
5327
5328
impl Format<u16> for ConditionFormat4<'_> {
5329
    const FORMAT: u16 = 4;
5330
}
5331
5332
impl<'a> MinByteRange<'a> for ConditionFormat4<'a> {
5333
0
    fn min_byte_range(&self) -> Range<usize> {
5334
0
        0..self.condition_offsets_byte_range().end
5335
0
    }
5336
0
    fn min_table_bytes(&self) -> &'a [u8] {
5337
0
        let range = self.min_byte_range();
5338
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5339
0
    }
5340
}
5341
5342
impl ReadArgs for ConditionFormat4<'_> {
5343
    type Args = ();
5344
}
5345
5346
impl<'a> FontRead<'a> for ConditionFormat4<'a> {
5347
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5348
        #[allow(clippy::absurd_extreme_comparisons)]
5349
0
        if data.len() < Self::MIN_SIZE {
5350
0
            return Err(ReadError::OutOfBounds);
5351
0
        }
5352
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5353
0
            return Err(ReadError::OutOfBounds);
5354
        };
5355
0
        Ok(Self { data })
5356
0
    }
5357
}
5358
5359
/// The fields at the start of the table, which are read directly.
5360
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5361
#[repr(C, packed)]
5362
#[doc(hidden)]
5363
pub struct ConditionFormat4FixedHeader {
5364
    pub format: BigEndian<u16>,
5365
    pub condition_count: u8,
5366
}
5367
5368
#[allow(clippy::absurd_extreme_comparisons)]
5369
const _: () =
5370
    assert!(std::mem::size_of::<ConditionFormat4FixedHeader>() <= ConditionFormat4::MIN_SIZE);
5371
5372
/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
5373
#[derive(Clone)]
5374
pub struct ConditionFormat4<'a> {
5375
    data: TableDataRef<'a, ConditionFormat4FixedHeader>,
5376
}
5377
5378
#[allow(clippy::needless_lifetimes)]
5379
impl<'a> ConditionFormat4<'a> {
5380
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
5381
    basic_table_impls!(impl_the_methods);
5382
5383
    /// Format, = 4
5384
0
    pub fn format(&self) -> u16 {
5385
0
        self.data.header().format.get()
5386
0
    }
5387
5388
    /// Number of conditions.
5389
0
    pub fn condition_count(&self) -> u8 {
5390
0
        self.data.header().condition_count
5391
0
    }
5392
5393
    /// Array of condition tables for this disjunction (OR) expression.
5394
0
    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
5395
0
        let range = self.condition_offsets_byte_range();
5396
0
        self.offset_data()
5397
0
            .read_array(range)
5398
0
            .ok()
5399
0
            .unwrap_or_default()
5400
0
    }
5401
5402
    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
5403
0
    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
5404
0
        let data = self.offset_data();
5405
0
        let offsets = self.condition_offsets();
5406
0
        ArrayOfOffsets::new(offsets, data, ())
5407
0
    }
5408
5409
0
    pub fn format_byte_range(&self) -> Range<usize> {
5410
0
        let start = 0;
5411
0
        let end = start + u16::RAW_BYTE_LEN;
5412
0
        start..end
5413
0
    }
5414
5415
0
    pub fn condition_count_byte_range(&self) -> Range<usize> {
5416
0
        let start = self.format_byte_range().end;
5417
0
        let end = start + u8::RAW_BYTE_LEN;
5418
0
        start..end
5419
0
    }
5420
5421
0
    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
5422
0
        let condition_count = self.condition_count();
5423
0
        let start = self.condition_count_byte_range().end;
5424
0
        let end =
5425
0
            start + (transforms::to_usize(condition_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
5426
0
        start..end
5427
0
    }
5428
}
5429
5430
impl Format<u16> for ConditionFormat5<'_> {
5431
    const FORMAT: u16 = 5;
5432
}
5433
5434
impl<'a> MinByteRange<'a> for ConditionFormat5<'a> {
5435
0
    fn min_byte_range(&self) -> Range<usize> {
5436
0
        0..self.condition_offset_byte_range().end
5437
0
    }
5438
0
    fn min_table_bytes(&self) -> &'a [u8] {
5439
0
        let range = self.min_byte_range();
5440
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5441
0
    }
5442
}
5443
5444
impl ReadArgs for ConditionFormat5<'_> {
5445
    type Args = ();
5446
}
5447
5448
impl<'a> FontRead<'a> for ConditionFormat5<'a> {
5449
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5450
        #[allow(clippy::absurd_extreme_comparisons)]
5451
0
        if data.len() < Self::MIN_SIZE {
5452
0
            return Err(ReadError::OutOfBounds);
5453
0
        }
5454
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5455
0
            return Err(ReadError::OutOfBounds);
5456
        };
5457
0
        Ok(Self { data })
5458
0
    }
5459
}
5460
5461
/// The fields at the start of the table, which are read directly.
5462
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5463
#[repr(C, packed)]
5464
#[doc(hidden)]
5465
pub struct ConditionFormat5FixedHeader {
5466
    pub format: BigEndian<u16>,
5467
    pub condition_offset: BigEndian<Offset24>,
5468
}
5469
5470
#[allow(clippy::absurd_extreme_comparisons)]
5471
const _: () =
5472
    assert!(std::mem::size_of::<ConditionFormat5FixedHeader>() <= ConditionFormat5::MIN_SIZE);
5473
5474
/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
5475
#[derive(Clone)]
5476
pub struct ConditionFormat5<'a> {
5477
    data: TableDataRef<'a, ConditionFormat5FixedHeader>,
5478
}
5479
5480
#[allow(clippy::needless_lifetimes)]
5481
impl<'a> ConditionFormat5<'a> {
5482
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN);
5483
    basic_table_impls!(impl_the_methods);
5484
5485
    /// Format, = 5
5486
0
    pub fn format(&self) -> u16 {
5487
0
        self.data.header().format.get()
5488
0
    }
5489
5490
    /// Condition to negate.
5491
0
    pub fn condition_offset(&self) -> Offset24 {
5492
0
        self.data.header().condition_offset.get()
5493
0
    }
5494
5495
    /// Attempt to resolve [`condition_offset`][Self::condition_offset].
5496
0
    pub fn condition(&self) -> Result<Condition<'a>, ReadError> {
5497
0
        let data = self.offset_data();
5498
0
        self.condition_offset().resolve(data)
5499
0
    }
5500
5501
0
    pub fn format_byte_range(&self) -> Range<usize> {
5502
0
        let start = 0;
5503
0
        let end = start + u16::RAW_BYTE_LEN;
5504
0
        start..end
5505
0
    }
5506
5507
0
    pub fn condition_offset_byte_range(&self) -> Range<usize> {
5508
0
        let start = self.format_byte_range().end;
5509
0
        let end = start + Offset24::RAW_BYTE_LEN;
5510
0
        start..end
5511
0
    }
5512
}
5513
5514
impl<'a> MinByteRange<'a> for FeatureTableSubstitution<'a> {
5515
0
    fn min_byte_range(&self) -> Range<usize> {
5516
0
        0..self.substitutions_byte_range().end
5517
0
    }
5518
0
    fn min_table_bytes(&self) -> &'a [u8] {
5519
0
        let range = self.min_byte_range();
5520
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5521
0
    }
5522
}
5523
5524
impl ReadArgs for FeatureTableSubstitution<'_> {
5525
    type Args = ();
5526
}
5527
5528
impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> {
5529
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5530
        #[allow(clippy::absurd_extreme_comparisons)]
5531
0
        if data.len() < Self::MIN_SIZE {
5532
0
            return Err(ReadError::OutOfBounds);
5533
0
        }
5534
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5535
0
            return Err(ReadError::OutOfBounds);
5536
        };
5537
0
        Ok(Self { data })
5538
0
    }
5539
}
5540
5541
/// The fields at the start of the table, which are read directly.
5542
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5543
#[repr(C, packed)]
5544
#[doc(hidden)]
5545
pub struct FeatureTableSubstitutionFixedHeader {
5546
    pub version: BigEndian<MajorMinor>,
5547
    pub substitution_count: BigEndian<u16>,
5548
}
5549
5550
#[allow(clippy::absurd_extreme_comparisons)]
5551
const _: () = assert!(
5552
    std::mem::size_of::<FeatureTableSubstitutionFixedHeader>()
5553
        <= FeatureTableSubstitution::MIN_SIZE
5554
);
5555
5556
/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
5557
#[derive(Clone)]
5558
pub struct FeatureTableSubstitution<'a> {
5559
    data: TableDataRef<'a, FeatureTableSubstitutionFixedHeader>,
5560
}
5561
5562
#[allow(clippy::needless_lifetimes)]
5563
impl<'a> FeatureTableSubstitution<'a> {
5564
    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
5565
    basic_table_impls!(impl_the_methods);
5566
5567
    /// Major & minor version of the table: (1, 0)
5568
0
    pub fn version(&self) -> MajorMinor {
5569
0
        self.data.header().version.get()
5570
0
    }
5571
5572
    /// Number of feature table substitution records.
5573
0
    pub fn substitution_count(&self) -> u16 {
5574
0
        self.data.header().substitution_count.get()
5575
0
    }
5576
5577
    /// Array of feature table substitution records.
5578
0
    pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] {
5579
0
        let range = self.substitutions_byte_range();
5580
0
        self.offset_data()
5581
0
            .read_array(range)
5582
0
            .ok()
5583
0
            .unwrap_or_default()
5584
0
    }
5585
5586
0
    pub fn version_byte_range(&self) -> Range<usize> {
5587
0
        let start = 0;
5588
0
        let end = start + MajorMinor::RAW_BYTE_LEN;
5589
0
        start..end
5590
0
    }
5591
5592
0
    pub fn substitution_count_byte_range(&self) -> Range<usize> {
5593
0
        let start = self.version_byte_range().end;
5594
0
        let end = start + u16::RAW_BYTE_LEN;
5595
0
        start..end
5596
0
    }
5597
5598
0
    pub fn substitutions_byte_range(&self) -> Range<usize> {
5599
0
        let substitution_count = self.substitution_count();
5600
0
        let start = self.substitution_count_byte_range().end;
5601
0
        let end = start
5602
0
            + (transforms::to_usize(substitution_count))
5603
0
                .saturating_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN);
5604
0
        start..end
5605
0
    }
5606
}
5607
5608
const _: () = assert!(FontData::default_data_long_enough(
5609
    FeatureTableSubstitution::MIN_SIZE
5610
));
5611
5612
impl Default for FeatureTableSubstitution<'_> {
5613
0
    fn default() -> Self {
5614
        Self {
5615
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
5616
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5617
        }
5618
0
    }
5619
}
5620
5621
/// Used in [FeatureTableSubstitution]
5622
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
5623
#[repr(C)]
5624
#[repr(packed)]
5625
pub struct FeatureTableSubstitutionRecord {
5626
    /// The feature table index to match.
5627
    pub feature_index: BigEndian<u16>,
5628
    /// Offset to an alternate feature table, from start of the
5629
    /// FeatureTableSubstitution table.
5630
    pub alternate_feature_offset: BigEndian<Offset32>,
5631
}
5632
5633
impl FeatureTableSubstitutionRecord {
5634
    /// The feature table index to match.
5635
0
    pub fn feature_index(&self) -> u16 {
5636
0
        self.feature_index.get()
5637
0
    }
5638
5639
    /// Offset to an alternate feature table, from start of the
5640
    /// FeatureTableSubstitution table.
5641
0
    pub fn alternate_feature_offset(&self) -> Offset32 {
5642
0
        self.alternate_feature_offset.get()
5643
0
    }
5644
}
5645
5646
impl FixedSize for FeatureTableSubstitutionRecord {
5647
    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
5648
}
5649
5650
impl<'a> MinByteRange<'a> for SizeParams<'a> {
5651
0
    fn min_byte_range(&self) -> Range<usize> {
5652
0
        0..self.range_end_byte_range().end
5653
0
    }
5654
0
    fn min_table_bytes(&self) -> &'a [u8] {
5655
0
        let range = self.min_byte_range();
5656
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5657
0
    }
5658
}
5659
5660
impl ReadArgs for SizeParams<'_> {
5661
    type Args = ();
5662
}
5663
5664
impl<'a> FontRead<'a> for SizeParams<'a> {
5665
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5666
        #[allow(clippy::absurd_extreme_comparisons)]
5667
0
        if data.len() < Self::MIN_SIZE {
5668
0
            return Err(ReadError::OutOfBounds);
5669
0
        }
5670
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5671
0
            return Err(ReadError::OutOfBounds);
5672
        };
5673
0
        Ok(Self { data })
5674
0
    }
5675
}
5676
5677
/// The fields at the start of the table, which are read directly.
5678
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5679
#[repr(C, packed)]
5680
#[doc(hidden)]
5681
pub struct SizeParamsFixedHeader {
5682
    pub design_size: BigEndian<u16>,
5683
    pub identifier: BigEndian<u16>,
5684
    pub name_entry: BigEndian<u16>,
5685
    pub range_start: BigEndian<u16>,
5686
    pub range_end: BigEndian<u16>,
5687
}
5688
5689
#[allow(clippy::absurd_extreme_comparisons)]
5690
const _: () = assert!(std::mem::size_of::<SizeParamsFixedHeader>() <= SizeParams::MIN_SIZE);
5691
5692
#[derive(Clone)]
5693
pub struct SizeParams<'a> {
5694
    data: TableDataRef<'a, SizeParamsFixedHeader>,
5695
}
5696
5697
#[allow(clippy::needless_lifetimes)]
5698
impl<'a> SizeParams<'a> {
5699
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5700
        + u16::RAW_BYTE_LEN
5701
        + u16::RAW_BYTE_LEN
5702
        + u16::RAW_BYTE_LEN
5703
        + u16::RAW_BYTE_LEN);
5704
    basic_table_impls!(impl_the_methods);
5705
5706
    /// The first value represents the design size in 720/inch units (decipoints).
5707
    ///
5708
    /// The design size entry must be non-zero. When there is a design size but
5709
    /// no recommended size range, the rest of the array will consist of zeros.
5710
0
    pub fn design_size(&self) -> u16 {
5711
0
        self.data.header().design_size.get()
5712
0
    }
5713
5714
    /// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily.
5715
    ///
5716
    /// All fonts which share a Typographic or Font Family name and which differ
5717
    /// only by size range shall have the same subfamily value, and no fonts
5718
    /// which differ in weight or style shall have the same subfamily value.
5719
    /// If this value is zero, the remaining fields in the array will be ignored.
5720
0
    pub fn identifier(&self) -> u16 {
5721
0
        self.data.header().identifier.get()
5722
0
    }
5723
5724
    /// The third value enables applications to use a single name for the subfamily identified by the second value.
5725
    ///
5726
    /// If the preceding value is non-zero, this value must be set in the range
5727
    /// 256 – 32767 (inclusive). It records the value of a field in the 'name'
5728
    /// table, which must contain English-language strings encoded in Windows
5729
    /// Unicode and Macintosh Roman, and may contain additional strings localized
5730
    /// to other scripts and languages. Each of these strings is the name
5731
    /// an application should use, in combination with the family name, to
5732
    /// represent the subfamily in a menu. Applications will choose the
5733
    /// appropriate version based on their selection criteria.
5734
0
    pub fn name_entry(&self) -> u16 {
5735
0
        self.data.header().name_entry.get()
5736
0
    }
5737
5738
    /// The fourth and fifth values represent the small end of the recommended
5739
    /// usage range (exclusive) and the large end of the recommended usage range
5740
    /// (inclusive), stored in 720/inch units (decipoints).
5741
    ///
5742
    /// Ranges must not overlap, and should generally be contiguous.
5743
0
    pub fn range_start(&self) -> u16 {
5744
0
        self.data.header().range_start.get()
5745
0
    }
5746
5747
0
    pub fn range_end(&self) -> u16 {
5748
0
        self.data.header().range_end.get()
5749
0
    }
5750
5751
0
    pub fn design_size_byte_range(&self) -> Range<usize> {
5752
0
        let start = 0;
5753
0
        let end = start + u16::RAW_BYTE_LEN;
5754
0
        start..end
5755
0
    }
5756
5757
0
    pub fn identifier_byte_range(&self) -> Range<usize> {
5758
0
        let start = self.design_size_byte_range().end;
5759
0
        let end = start + u16::RAW_BYTE_LEN;
5760
0
        start..end
5761
0
    }
5762
5763
0
    pub fn name_entry_byte_range(&self) -> Range<usize> {
5764
0
        let start = self.identifier_byte_range().end;
5765
0
        let end = start + u16::RAW_BYTE_LEN;
5766
0
        start..end
5767
0
    }
5768
5769
0
    pub fn range_start_byte_range(&self) -> Range<usize> {
5770
0
        let start = self.name_entry_byte_range().end;
5771
0
        let end = start + u16::RAW_BYTE_LEN;
5772
0
        start..end
5773
0
    }
5774
5775
0
    pub fn range_end_byte_range(&self) -> Range<usize> {
5776
0
        let start = self.range_start_byte_range().end;
5777
0
        let end = start + u16::RAW_BYTE_LEN;
5778
0
        start..end
5779
0
    }
5780
}
5781
5782
const _: () = assert!(FontData::default_data_long_enough(SizeParams::MIN_SIZE));
5783
5784
impl Default for SizeParams<'_> {
5785
0
    fn default() -> Self {
5786
        Self {
5787
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
5788
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5789
        }
5790
0
    }
5791
}
5792
5793
impl<'a> MinByteRange<'a> for StylisticSetParams<'a> {
5794
0
    fn min_byte_range(&self) -> Range<usize> {
5795
0
        0..self.ui_name_id_byte_range().end
5796
0
    }
5797
0
    fn min_table_bytes(&self) -> &'a [u8] {
5798
0
        let range = self.min_byte_range();
5799
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5800
0
    }
5801
}
5802
5803
impl ReadArgs for StylisticSetParams<'_> {
5804
    type Args = ();
5805
}
5806
5807
impl<'a> FontRead<'a> for StylisticSetParams<'a> {
5808
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5809
        #[allow(clippy::absurd_extreme_comparisons)]
5810
0
        if data.len() < Self::MIN_SIZE {
5811
0
            return Err(ReadError::OutOfBounds);
5812
0
        }
5813
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5814
0
            return Err(ReadError::OutOfBounds);
5815
        };
5816
0
        Ok(Self { data })
5817
0
    }
5818
}
5819
5820
/// The fields at the start of the table, which are read directly.
5821
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5822
#[repr(C, packed)]
5823
#[doc(hidden)]
5824
pub struct StylisticSetParamsFixedHeader {
5825
    pub version: BigEndian<u16>,
5826
    pub ui_name_id: BigEndian<NameId>,
5827
}
5828
5829
#[allow(clippy::absurd_extreme_comparisons)]
5830
const _: () =
5831
    assert!(std::mem::size_of::<StylisticSetParamsFixedHeader>() <= StylisticSetParams::MIN_SIZE);
5832
5833
#[derive(Clone)]
5834
pub struct StylisticSetParams<'a> {
5835
    data: TableDataRef<'a, StylisticSetParamsFixedHeader>,
5836
}
5837
5838
#[allow(clippy::needless_lifetimes)]
5839
impl<'a> StylisticSetParams<'a> {
5840
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN);
5841
    basic_table_impls!(impl_the_methods);
5842
5843
0
    pub fn version(&self) -> u16 {
5844
0
        self.data.header().version.get()
5845
0
    }
5846
5847
    /// The 'name' table name ID that specifies a string (or strings, for
5848
    /// multiple languages) for a user-interface label for this feature.
5849
    ///
5850
    /// The value of uiLabelNameId is expected to be in the font-specific name
5851
    /// ID range (256-32767), though that is not a requirement in this Feature
5852
    /// Parameters specification. The user-interface label for the feature can
5853
    /// be provided in multiple languages. An English string should be included
5854
    /// as a fallback. The string should be kept to a minimal length to fit
5855
    /// comfortably with different application interfaces.
5856
0
    pub fn ui_name_id(&self) -> NameId {
5857
0
        self.data.header().ui_name_id.get()
5858
0
    }
5859
5860
0
    pub fn version_byte_range(&self) -> Range<usize> {
5861
0
        let start = 0;
5862
0
        let end = start + u16::RAW_BYTE_LEN;
5863
0
        start..end
5864
0
    }
5865
5866
0
    pub fn ui_name_id_byte_range(&self) -> Range<usize> {
5867
0
        let start = self.version_byte_range().end;
5868
0
        let end = start + NameId::RAW_BYTE_LEN;
5869
0
        start..end
5870
0
    }
5871
}
5872
5873
const _: () = assert!(FontData::default_data_long_enough(
5874
    StylisticSetParams::MIN_SIZE
5875
));
5876
5877
impl Default for StylisticSetParams<'_> {
5878
0
    fn default() -> Self {
5879
        Self {
5880
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
5881
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
5882
        }
5883
0
    }
5884
}
5885
5886
impl Format<u16> for CharacterVariantParams<'_> {
5887
    const FORMAT: u16 = 0;
5888
}
5889
5890
impl<'a> MinByteRange<'a> for CharacterVariantParams<'a> {
5891
0
    fn min_byte_range(&self) -> Range<usize> {
5892
0
        0..self.character_byte_range().end
5893
0
    }
5894
0
    fn min_table_bytes(&self) -> &'a [u8] {
5895
0
        let range = self.min_byte_range();
5896
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
5897
0
    }
5898
}
5899
5900
impl ReadArgs for CharacterVariantParams<'_> {
5901
    type Args = ();
5902
}
5903
5904
impl<'a> FontRead<'a> for CharacterVariantParams<'a> {
5905
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
5906
        #[allow(clippy::absurd_extreme_comparisons)]
5907
0
        if data.len() < Self::MIN_SIZE {
5908
0
            return Err(ReadError::OutOfBounds);
5909
0
        }
5910
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
5911
0
            return Err(ReadError::OutOfBounds);
5912
        };
5913
0
        Ok(Self { data })
5914
0
    }
5915
}
5916
5917
/// The fields at the start of the table, which are read directly.
5918
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
5919
#[repr(C, packed)]
5920
#[doc(hidden)]
5921
pub struct CharacterVariantParamsFixedHeader {
5922
    pub format: BigEndian<u16>,
5923
    pub feat_ui_label_name_id: BigEndian<NameId>,
5924
    pub feat_ui_tooltip_text_name_id: BigEndian<NameId>,
5925
    pub sample_text_name_id: BigEndian<NameId>,
5926
    pub num_named_parameters: BigEndian<u16>,
5927
    pub first_param_ui_label_name_id: BigEndian<NameId>,
5928
    pub char_count: BigEndian<u16>,
5929
}
5930
5931
#[allow(clippy::absurd_extreme_comparisons)]
5932
const _: () = assert!(
5933
    std::mem::size_of::<CharacterVariantParamsFixedHeader>() <= CharacterVariantParams::MIN_SIZE
5934
);
5935
5936
/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
5937
#[derive(Clone)]
5938
pub struct CharacterVariantParams<'a> {
5939
    data: TableDataRef<'a, CharacterVariantParamsFixedHeader>,
5940
}
5941
5942
#[allow(clippy::needless_lifetimes)]
5943
impl<'a> CharacterVariantParams<'a> {
5944
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5945
        + NameId::RAW_BYTE_LEN
5946
        + NameId::RAW_BYTE_LEN
5947
        + NameId::RAW_BYTE_LEN
5948
        + u16::RAW_BYTE_LEN
5949
        + NameId::RAW_BYTE_LEN
5950
        + u16::RAW_BYTE_LEN);
5951
    basic_table_impls!(impl_the_methods);
5952
5953
    /// Format number is set to 0.
5954
0
    pub fn format(&self) -> u16 {
5955
0
        self.data.header().format.get()
5956
0
    }
5957
5958
    /// The 'name' table name ID that specifies a string (or strings,
5959
    /// for multiple languages) for a user-interface label for this
5960
    /// feature. (May be NULL.)
5961
0
    pub fn feat_ui_label_name_id(&self) -> NameId {
5962
0
        self.data.header().feat_ui_label_name_id.get()
5963
0
    }
5964
5965
    /// The 'name' table name ID that specifies a string (or strings,
5966
    /// for multiple languages) that an application can use for tooltip
5967
    /// text for this feature. (May be NULL.)
5968
0
    pub fn feat_ui_tooltip_text_name_id(&self) -> NameId {
5969
0
        self.data.header().feat_ui_tooltip_text_name_id.get()
5970
0
    }
5971
5972
    /// The 'name' table name ID that specifies sample text that
5973
    /// illustrates the effect of this feature. (May be NULL.)
5974
0
    pub fn sample_text_name_id(&self) -> NameId {
5975
0
        self.data.header().sample_text_name_id.get()
5976
0
    }
5977
5978
    /// Number of named parameters. (May be zero.)
5979
0
    pub fn num_named_parameters(&self) -> u16 {
5980
0
        self.data.header().num_named_parameters.get()
5981
0
    }
5982
5983
    /// The first 'name' table name ID used to specify strings for
5984
    /// user-interface labels for the feature parameters. (Must be zero
5985
    /// if numParameters is zero.)
5986
0
    pub fn first_param_ui_label_name_id(&self) -> NameId {
5987
0
        self.data.header().first_param_ui_label_name_id.get()
5988
0
    }
5989
5990
    /// The count of characters for which this feature provides glyph
5991
    /// variants. (May be zero.)
5992
0
    pub fn char_count(&self) -> u16 {
5993
0
        self.data.header().char_count.get()
5994
0
    }
5995
5996
    /// The Unicode Scalar Value of the characters for which this
5997
    /// feature provides glyph variants.
5998
0
    pub fn character(&self) -> &'a [BigEndian<Uint24>] {
5999
0
        let range = self.character_byte_range();
6000
0
        self.offset_data()
6001
0
            .read_array(range)
6002
0
            .ok()
6003
0
            .unwrap_or_default()
6004
0
    }
6005
6006
0
    pub fn format_byte_range(&self) -> Range<usize> {
6007
0
        let start = 0;
6008
0
        let end = start + u16::RAW_BYTE_LEN;
6009
0
        start..end
6010
0
    }
6011
6012
0
    pub fn feat_ui_label_name_id_byte_range(&self) -> Range<usize> {
6013
0
        let start = self.format_byte_range().end;
6014
0
        let end = start + NameId::RAW_BYTE_LEN;
6015
0
        start..end
6016
0
    }
6017
6018
0
    pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range<usize> {
6019
0
        let start = self.feat_ui_label_name_id_byte_range().end;
6020
0
        let end = start + NameId::RAW_BYTE_LEN;
6021
0
        start..end
6022
0
    }
6023
6024
0
    pub fn sample_text_name_id_byte_range(&self) -> Range<usize> {
6025
0
        let start = self.feat_ui_tooltip_text_name_id_byte_range().end;
6026
0
        let end = start + NameId::RAW_BYTE_LEN;
6027
0
        start..end
6028
0
    }
6029
6030
0
    pub fn num_named_parameters_byte_range(&self) -> Range<usize> {
6031
0
        let start = self.sample_text_name_id_byte_range().end;
6032
0
        let end = start + u16::RAW_BYTE_LEN;
6033
0
        start..end
6034
0
    }
6035
6036
0
    pub fn first_param_ui_label_name_id_byte_range(&self) -> Range<usize> {
6037
0
        let start = self.num_named_parameters_byte_range().end;
6038
0
        let end = start + NameId::RAW_BYTE_LEN;
6039
0
        start..end
6040
0
    }
6041
6042
0
    pub fn char_count_byte_range(&self) -> Range<usize> {
6043
0
        let start = self.first_param_ui_label_name_id_byte_range().end;
6044
0
        let end = start + u16::RAW_BYTE_LEN;
6045
0
        start..end
6046
0
    }
6047
6048
0
    pub fn character_byte_range(&self) -> Range<usize> {
6049
0
        let char_count = self.char_count();
6050
0
        let start = self.char_count_byte_range().end;
6051
0
        let end = start + (transforms::to_usize(char_count)).saturating_mul(Uint24::RAW_BYTE_LEN);
6052
0
        start..end
6053
0
    }
6054
}
6055
6056
const _: () = assert!(FontData::default_data_long_enough(
6057
    CharacterVariantParams::MIN_SIZE
6058
));
6059
6060
impl Default for CharacterVariantParams<'_> {
6061
0
    fn default() -> Self {
6062
        Self {
6063
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
6064
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
6065
        }
6066
0
    }
6067
}
6068
6069
impl Format<u16> for CoverageFormat3<'_> {
6070
    const FORMAT: u16 = 3;
6071
}
6072
6073
impl<'a> MinByteRange<'a> for CoverageFormat3<'a> {
6074
0
    fn min_byte_range(&self) -> Range<usize> {
6075
0
        0..self.glyph_array_byte_range().end
6076
0
    }
6077
0
    fn min_table_bytes(&self) -> &'a [u8] {
6078
0
        let range = self.min_byte_range();
6079
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6080
0
    }
6081
}
6082
6083
impl ReadArgs for CoverageFormat3<'_> {
6084
    type Args = ();
6085
}
6086
6087
impl<'a> FontRead<'a> for CoverageFormat3<'a> {
6088
8.95k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6089
        #[allow(clippy::absurd_extreme_comparisons)]
6090
8.95k
        if data.len() < Self::MIN_SIZE {
6091
710
            return Err(ReadError::OutOfBounds);
6092
8.24k
        }
6093
8.24k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6094
0
            return Err(ReadError::OutOfBounds);
6095
        };
6096
8.24k
        Ok(Self { data })
6097
8.95k
    }
6098
}
6099
6100
/// The fields at the start of the table, which are read directly.
6101
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6102
#[repr(C, packed)]
6103
#[doc(hidden)]
6104
pub struct CoverageFormat3FixedHeader {
6105
    pub coverage_format: BigEndian<u16>,
6106
    pub glyph_count: BigEndian<Uint24>,
6107
}
6108
6109
#[allow(clippy::absurd_extreme_comparisons)]
6110
const _: () =
6111
    assert!(std::mem::size_of::<CoverageFormat3FixedHeader>() <= CoverageFormat3::MIN_SIZE);
6112
6113
/// CoverageFormat3 (ISO/IEC 14496-22:2026).
6114
#[derive(Clone)]
6115
pub struct CoverageFormat3<'a> {
6116
    data: TableDataRef<'a, CoverageFormat3FixedHeader>,
6117
}
6118
6119
#[allow(clippy::needless_lifetimes)]
6120
impl<'a> CoverageFormat3<'a> {
6121
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
6122
    basic_table_impls!(impl_the_methods);
6123
6124
    /// Format identifier — format = 3
6125
0
    pub fn coverage_format(&self) -> u16 {
6126
0
        self.data.header().coverage_format.get()
6127
0
    }
6128
6129
    /// Number of glyphs in the glyph array
6130
8.25k
    pub fn glyph_count(&self) -> Uint24 {
6131
8.25k
        self.data.header().glyph_count.get()
6132
8.25k
    }
6133
6134
    /// Array of glyph IDs — in numerical order
6135
8.25k
    pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId24>] {
6136
8.25k
        let range = self.glyph_array_byte_range();
6137
8.25k
        self.offset_data()
6138
8.25k
            .read_array(range)
6139
8.25k
            .ok()
6140
8.25k
            .unwrap_or_default()
6141
8.25k
    }
6142
6143
8.25k
    pub fn coverage_format_byte_range(&self) -> Range<usize> {
6144
8.25k
        let start = 0;
6145
8.25k
        let end = start + u16::RAW_BYTE_LEN;
6146
8.25k
        start..end
6147
8.25k
    }
6148
6149
8.25k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
6150
8.25k
        let start = self.coverage_format_byte_range().end;
6151
8.25k
        let end = start + Uint24::RAW_BYTE_LEN;
6152
8.25k
        start..end
6153
8.25k
    }
6154
6155
8.25k
    pub fn glyph_array_byte_range(&self) -> Range<usize> {
6156
8.25k
        let glyph_count = self.glyph_count();
6157
8.25k
        let start = self.glyph_count_byte_range().end;
6158
8.25k
        let end =
6159
8.25k
            start + (transforms::to_usize(glyph_count)).saturating_mul(GlyphId24::RAW_BYTE_LEN);
6160
8.25k
        start..end
6161
8.25k
    }
6162
}
6163
6164
impl Format<u16> for CoverageFormat4<'_> {
6165
    const FORMAT: u16 = 4;
6166
}
6167
6168
impl<'a> MinByteRange<'a> for CoverageFormat4<'a> {
6169
0
    fn min_byte_range(&self) -> Range<usize> {
6170
0
        0..self.range_records_byte_range().end
6171
0
    }
6172
0
    fn min_table_bytes(&self) -> &'a [u8] {
6173
0
        let range = self.min_byte_range();
6174
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6175
0
    }
6176
}
6177
6178
impl ReadArgs for CoverageFormat4<'_> {
6179
    type Args = ();
6180
}
6181
6182
impl<'a> FontRead<'a> for CoverageFormat4<'a> {
6183
12.5k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6184
        #[allow(clippy::absurd_extreme_comparisons)]
6185
12.5k
        if data.len() < Self::MIN_SIZE {
6186
1.03k
            return Err(ReadError::OutOfBounds);
6187
11.4k
        }
6188
11.4k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6189
0
            return Err(ReadError::OutOfBounds);
6190
        };
6191
11.4k
        Ok(Self { data })
6192
12.5k
    }
6193
}
6194
6195
/// The fields at the start of the table, which are read directly.
6196
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6197
#[repr(C, packed)]
6198
#[doc(hidden)]
6199
pub struct CoverageFormat4FixedHeader {
6200
    pub coverage_format: BigEndian<u16>,
6201
    pub range_count: BigEndian<Uint24>,
6202
}
6203
6204
#[allow(clippy::absurd_extreme_comparisons)]
6205
const _: () =
6206
    assert!(std::mem::size_of::<CoverageFormat4FixedHeader>() <= CoverageFormat4::MIN_SIZE);
6207
6208
/// CoverageFormat4 (ISO/IEC 14496-22:2026).
6209
#[derive(Clone)]
6210
pub struct CoverageFormat4<'a> {
6211
    data: TableDataRef<'a, CoverageFormat4FixedHeader>,
6212
}
6213
6214
#[allow(clippy::needless_lifetimes)]
6215
impl<'a> CoverageFormat4<'a> {
6216
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
6217
    basic_table_impls!(impl_the_methods);
6218
6219
    /// Format identifier — format = 4
6220
0
    pub fn coverage_format(&self) -> u16 {
6221
0
        self.data.header().coverage_format.get()
6222
0
    }
6223
6224
    /// Number of RangeRecords
6225
11.4k
    pub fn range_count(&self) -> Uint24 {
6226
11.4k
        self.data.header().range_count.get()
6227
11.4k
    }
6228
6229
    /// Array of glyph ranges — ordered by startGlyphID.
6230
11.4k
    pub fn range_records(&self) -> &'a [RangeRecord2] {
6231
11.4k
        let range = self.range_records_byte_range();
6232
11.4k
        self.offset_data()
6233
11.4k
            .read_array(range)
6234
11.4k
            .ok()
6235
11.4k
            .unwrap_or_default()
6236
11.4k
    }
6237
6238
11.4k
    pub fn coverage_format_byte_range(&self) -> Range<usize> {
6239
11.4k
        let start = 0;
6240
11.4k
        let end = start + u16::RAW_BYTE_LEN;
6241
11.4k
        start..end
6242
11.4k
    }
6243
6244
11.4k
    pub fn range_count_byte_range(&self) -> Range<usize> {
6245
11.4k
        let start = self.coverage_format_byte_range().end;
6246
11.4k
        let end = start + Uint24::RAW_BYTE_LEN;
6247
11.4k
        start..end
6248
11.4k
    }
6249
6250
11.4k
    pub fn range_records_byte_range(&self) -> Range<usize> {
6251
11.4k
        let range_count = self.range_count();
6252
11.4k
        let start = self.range_count_byte_range().end;
6253
11.4k
        let end =
6254
11.4k
            start + (transforms::to_usize(range_count)).saturating_mul(RangeRecord2::RAW_BYTE_LEN);
6255
11.4k
        start..end
6256
11.4k
    }
6257
}
6258
6259
/// RangeRecord2 (ISO/IEC 14496-22:2026).
6260
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
6261
#[repr(C)]
6262
#[repr(packed)]
6263
pub struct RangeRecord2 {
6264
    /// First glyph ID in the range
6265
    pub start_glyph_id: BigEndian<GlyphId24>,
6266
    /// Last glyph ID in the range
6267
    pub end_glyph_id: BigEndian<GlyphId24>,
6268
    /// Coverage Index of first glyph ID in range
6269
    pub start_coverage_index: BigEndian<Uint24>,
6270
}
6271
6272
impl RangeRecord2 {
6273
    /// First glyph ID in the range
6274
709k
    pub fn start_glyph_id(&self) -> GlyphId24 {
6275
709k
        self.start_glyph_id.get()
6276
709k
    }
6277
6278
    /// Last glyph ID in the range
6279
626k
    pub fn end_glyph_id(&self) -> GlyphId24 {
6280
626k
        self.end_glyph_id.get()
6281
626k
    }
6282
6283
    /// Coverage Index of first glyph ID in range
6284
83.4k
    pub fn start_coverage_index(&self) -> Uint24 {
6285
83.4k
        self.start_coverage_index.get()
6286
83.4k
    }
6287
}
6288
6289
impl FixedSize for RangeRecord2 {
6290
    const RAW_BYTE_LEN: usize =
6291
        GlyphId24::RAW_BYTE_LEN + GlyphId24::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN;
6292
}
6293
6294
impl Format<u16> for ClassDefFormat3<'_> {
6295
    const FORMAT: u16 = 3;
6296
}
6297
6298
impl<'a> MinByteRange<'a> for ClassDefFormat3<'a> {
6299
0
    fn min_byte_range(&self) -> Range<usize> {
6300
0
        0..self.class_value_array_byte_range().end
6301
0
    }
6302
0
    fn min_table_bytes(&self) -> &'a [u8] {
6303
0
        let range = self.min_byte_range();
6304
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6305
0
    }
6306
}
6307
6308
impl ReadArgs for ClassDefFormat3<'_> {
6309
    type Args = ();
6310
}
6311
6312
impl<'a> FontRead<'a> for ClassDefFormat3<'a> {
6313
7.68k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6314
        #[allow(clippy::absurd_extreme_comparisons)]
6315
7.68k
        if data.len() < Self::MIN_SIZE {
6316
1.33k
            return Err(ReadError::OutOfBounds);
6317
6.34k
        }
6318
6.34k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6319
0
            return Err(ReadError::OutOfBounds);
6320
        };
6321
6.34k
        Ok(Self { data })
6322
7.68k
    }
6323
}
6324
6325
/// The fields at the start of the table, which are read directly.
6326
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6327
#[repr(C, packed)]
6328
#[doc(hidden)]
6329
pub struct ClassDefFormat3FixedHeader {
6330
    pub class_format: BigEndian<u16>,
6331
    pub start_glyph_id: BigEndian<GlyphId24>,
6332
    pub glyph_count: BigEndian<Uint24>,
6333
}
6334
6335
#[allow(clippy::absurd_extreme_comparisons)]
6336
const _: () =
6337
    assert!(std::mem::size_of::<ClassDefFormat3FixedHeader>() <= ClassDefFormat3::MIN_SIZE);
6338
6339
/// ClassDefFormat3 (ISO/IEC 14496-22:2026).
6340
#[derive(Clone)]
6341
pub struct ClassDefFormat3<'a> {
6342
    data: TableDataRef<'a, ClassDefFormat3FixedHeader>,
6343
}
6344
6345
#[allow(clippy::needless_lifetimes)]
6346
impl<'a> ClassDefFormat3<'a> {
6347
    pub const MIN_SIZE: usize =
6348
        (u16::RAW_BYTE_LEN + GlyphId24::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
6349
    basic_table_impls!(impl_the_methods);
6350
6351
    /// Format identifier — format = 3
6352
0
    pub fn class_format(&self) -> u16 {
6353
0
        self.data.header().class_format.get()
6354
0
    }
6355
6356
    /// First glyph ID of the classValueArray
6357
6.34k
    pub fn start_glyph_id(&self) -> GlyphId24 {
6358
6.34k
        self.data.header().start_glyph_id.get()
6359
6.34k
    }
6360
6361
    /// Size of the classValueArray
6362
6.34k
    pub fn glyph_count(&self) -> Uint24 {
6363
6.34k
        self.data.header().glyph_count.get()
6364
6.34k
    }
6365
6366
    /// Array of Class Values — one per glyph ID
6367
6.34k
    pub fn class_value_array(&self) -> &'a [BigEndian<Uint24>] {
6368
6.34k
        let range = self.class_value_array_byte_range();
6369
6.34k
        self.offset_data()
6370
6.34k
            .read_array(range)
6371
6.34k
            .ok()
6372
6.34k
            .unwrap_or_default()
6373
6.34k
    }
6374
6375
6.34k
    pub fn class_format_byte_range(&self) -> Range<usize> {
6376
6.34k
        let start = 0;
6377
6.34k
        let end = start + u16::RAW_BYTE_LEN;
6378
6.34k
        start..end
6379
6.34k
    }
6380
6381
6.34k
    pub fn start_glyph_id_byte_range(&self) -> Range<usize> {
6382
6.34k
        let start = self.class_format_byte_range().end;
6383
6.34k
        let end = start + GlyphId24::RAW_BYTE_LEN;
6384
6.34k
        start..end
6385
6.34k
    }
6386
6387
6.34k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
6388
6.34k
        let start = self.start_glyph_id_byte_range().end;
6389
6.34k
        let end = start + Uint24::RAW_BYTE_LEN;
6390
6.34k
        start..end
6391
6.34k
    }
6392
6393
6.34k
    pub fn class_value_array_byte_range(&self) -> Range<usize> {
6394
6.34k
        let glyph_count = self.glyph_count();
6395
6.34k
        let start = self.glyph_count_byte_range().end;
6396
6.34k
        let end = start + (transforms::to_usize(glyph_count)).saturating_mul(Uint24::RAW_BYTE_LEN);
6397
6.34k
        start..end
6398
6.34k
    }
6399
}
6400
6401
impl Format<u16> for ClassDefFormat4<'_> {
6402
    const FORMAT: u16 = 4;
6403
}
6404
6405
impl<'a> MinByteRange<'a> for ClassDefFormat4<'a> {
6406
0
    fn min_byte_range(&self) -> Range<usize> {
6407
0
        0..self.class_range_records_byte_range().end
6408
0
    }
6409
0
    fn min_table_bytes(&self) -> &'a [u8] {
6410
0
        let range = self.min_byte_range();
6411
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6412
0
    }
6413
}
6414
6415
impl ReadArgs for ClassDefFormat4<'_> {
6416
    type Args = ();
6417
}
6418
6419
impl<'a> FontRead<'a> for ClassDefFormat4<'a> {
6420
7.45k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6421
        #[allow(clippy::absurd_extreme_comparisons)]
6422
7.45k
        if data.len() < Self::MIN_SIZE {
6423
1.00k
            return Err(ReadError::OutOfBounds);
6424
6.44k
        }
6425
6.44k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6426
0
            return Err(ReadError::OutOfBounds);
6427
        };
6428
6.44k
        Ok(Self { data })
6429
7.45k
    }
6430
}
6431
6432
/// The fields at the start of the table, which are read directly.
6433
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6434
#[repr(C, packed)]
6435
#[doc(hidden)]
6436
pub struct ClassDefFormat4FixedHeader {
6437
    pub class_format: BigEndian<u16>,
6438
    pub class_range_count: BigEndian<Uint24>,
6439
}
6440
6441
#[allow(clippy::absurd_extreme_comparisons)]
6442
const _: () =
6443
    assert!(std::mem::size_of::<ClassDefFormat4FixedHeader>() <= ClassDefFormat4::MIN_SIZE);
6444
6445
/// ClassDefFormat4 (ISO/IEC 14496-22:2026).
6446
#[derive(Clone)]
6447
pub struct ClassDefFormat4<'a> {
6448
    data: TableDataRef<'a, ClassDefFormat4FixedHeader>,
6449
}
6450
6451
#[allow(clippy::needless_lifetimes)]
6452
impl<'a> ClassDefFormat4<'a> {
6453
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
6454
    basic_table_impls!(impl_the_methods);
6455
6456
    /// Format identifier — format = 4
6457
0
    pub fn class_format(&self) -> u16 {
6458
0
        self.data.header().class_format.get()
6459
0
    }
6460
6461
    /// Number of ClassRangeRecords
6462
6.44k
    pub fn class_range_count(&self) -> Uint24 {
6463
6.44k
        self.data.header().class_range_count.get()
6464
6.44k
    }
6465
6466
    /// Array of ClassRangeRecords — ordered by startGlyphID
6467
6.44k
    pub fn class_range_records(&self) -> &'a [ClassRangeRecord2] {
6468
6.44k
        let range = self.class_range_records_byte_range();
6469
6.44k
        self.offset_data()
6470
6.44k
            .read_array(range)
6471
6.44k
            .ok()
6472
6.44k
            .unwrap_or_default()
6473
6.44k
    }
6474
6475
6.44k
    pub fn class_format_byte_range(&self) -> Range<usize> {
6476
6.44k
        let start = 0;
6477
6.44k
        let end = start + u16::RAW_BYTE_LEN;
6478
6.44k
        start..end
6479
6.44k
    }
6480
6481
6.44k
    pub fn class_range_count_byte_range(&self) -> Range<usize> {
6482
6.44k
        let start = self.class_format_byte_range().end;
6483
6.44k
        let end = start + Uint24::RAW_BYTE_LEN;
6484
6.44k
        start..end
6485
6.44k
    }
6486
6487
6.44k
    pub fn class_range_records_byte_range(&self) -> Range<usize> {
6488
6.44k
        let class_range_count = self.class_range_count();
6489
6.44k
        let start = self.class_range_count_byte_range().end;
6490
6.44k
        let end = start
6491
6.44k
            + (transforms::to_usize(class_range_count))
6492
6.44k
                .saturating_mul(ClassRangeRecord2::RAW_BYTE_LEN);
6493
6.44k
        start..end
6494
6.44k
    }
6495
}
6496
6497
/// ClassRangeRecord2 (ISO/IEC 14496-22:2026).
6498
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
6499
#[repr(C)]
6500
#[repr(packed)]
6501
pub struct ClassRangeRecord2 {
6502
    /// First glyph ID in the range
6503
    pub start_glyph_id: BigEndian<GlyphId24>,
6504
    /// Last glyph ID in the range
6505
    pub end_glyph_id: BigEndian<GlyphId24>,
6506
    /// Applied to all glyphs in the range
6507
    pub class: BigEndian<u16>,
6508
}
6509
6510
impl ClassRangeRecord2 {
6511
    /// First glyph ID in the range
6512
117k
    pub fn start_glyph_id(&self) -> GlyphId24 {
6513
117k
        self.start_glyph_id.get()
6514
117k
    }
6515
6516
    /// Last glyph ID in the range
6517
117k
    pub fn end_glyph_id(&self) -> GlyphId24 {
6518
117k
        self.end_glyph_id.get()
6519
117k
    }
6520
6521
    /// Applied to all glyphs in the range
6522
27.5k
    pub fn class(&self) -> u16 {
6523
27.5k
        self.class.get()
6524
27.5k
    }
6525
}
6526
6527
impl FixedSize for ClassRangeRecord2 {
6528
    const RAW_BYTE_LEN: usize =
6529
        GlyphId24::RAW_BYTE_LEN + GlyphId24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
6530
}
6531
6532
impl Format<u16> for SequenceContextFormat4<'_> {
6533
    const FORMAT: u16 = 4;
6534
}
6535
6536
impl<'a> MinByteRange<'a> for SequenceContextFormat4<'a> {
6537
0
    fn min_byte_range(&self) -> Range<usize> {
6538
0
        0..self.seq_rule_set_offsets_byte_range().end
6539
0
    }
6540
0
    fn min_table_bytes(&self) -> &'a [u8] {
6541
0
        let range = self.min_byte_range();
6542
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6543
0
    }
6544
}
6545
6546
impl ReadArgs for SequenceContextFormat4<'_> {
6547
    type Args = ();
6548
}
6549
6550
impl<'a> FontRead<'a> for SequenceContextFormat4<'a> {
6551
3.63k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6552
        #[allow(clippy::absurd_extreme_comparisons)]
6553
3.63k
        if data.len() < Self::MIN_SIZE {
6554
264
            return Err(ReadError::OutOfBounds);
6555
3.36k
        }
6556
3.36k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6557
0
            return Err(ReadError::OutOfBounds);
6558
        };
6559
3.36k
        Ok(Self { data })
6560
3.63k
    }
6561
}
6562
6563
/// The fields at the start of the table, which are read directly.
6564
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6565
#[repr(C, packed)]
6566
#[doc(hidden)]
6567
pub struct SequenceContextFormat4FixedHeader {
6568
    pub format: BigEndian<u16>,
6569
    pub coverage_offset: BigEndian<Offset32>,
6570
    pub seq_rule_set_count: BigEndian<Uint24>,
6571
}
6572
6573
#[allow(clippy::absurd_extreme_comparisons)]
6574
const _: () = assert!(
6575
    std::mem::size_of::<SequenceContextFormat4FixedHeader>() <= SequenceContextFormat4::MIN_SIZE
6576
);
6577
6578
/// SequenceContextFormat4 (ISO/IEC 14496-22:2026).
6579
#[derive(Clone)]
6580
pub struct SequenceContextFormat4<'a> {
6581
    data: TableDataRef<'a, SequenceContextFormat4FixedHeader>,
6582
}
6583
6584
#[allow(clippy::needless_lifetimes)]
6585
impl<'a> SequenceContextFormat4<'a> {
6586
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
6587
    basic_table_impls!(impl_the_methods);
6588
6589
    /// Format identifier: format = 4
6590
0
    pub fn format(&self) -> u16 {
6591
0
        self.data.header().format.get()
6592
0
    }
6593
6594
    /// Offset to Coverage table, from beginning of
6595
    /// SequenceContextFormat4 table
6596
3.36k
    pub fn coverage_offset(&self) -> Offset32 {
6597
3.36k
        self.data.header().coverage_offset.get()
6598
3.36k
    }
6599
6600
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
6601
3.36k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
6602
3.36k
        let data = self.offset_data();
6603
3.36k
        self.coverage_offset().resolve(data)
6604
3.36k
    }
6605
6606
    /// Number of SequenceRuleSet tables
6607
3.36k
    pub fn seq_rule_set_count(&self) -> Uint24 {
6608
3.36k
        self.data.header().seq_rule_set_count.get()
6609
3.36k
    }
6610
6611
    /// Array of offsets to SequenceRuleSet tables, from beginning of
6612
    /// SequenceContextFormat4 table (offsets may be NULL)
6613
0
    pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
6614
0
        let range = self.seq_rule_set_offsets_byte_range();
6615
0
        self.offset_data()
6616
0
            .read_array(range)
6617
0
            .ok()
6618
0
            .unwrap_or_default()
6619
0
    }
6620
6621
    /// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets].
6622
0
    pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet2<'a>, Offset24> {
6623
0
        let data = self.offset_data();
6624
0
        let offsets = self.seq_rule_set_offsets();
6625
0
        ArrayOfNullableOffsets::new(offsets, data, ())
6626
0
    }
6627
6628
3.36k
    pub fn format_byte_range(&self) -> Range<usize> {
6629
3.36k
        let start = 0;
6630
3.36k
        let end = start + u16::RAW_BYTE_LEN;
6631
3.36k
        start..end
6632
3.36k
    }
6633
6634
3.36k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
6635
3.36k
        let start = self.format_byte_range().end;
6636
3.36k
        let end = start + Offset32::RAW_BYTE_LEN;
6637
3.36k
        start..end
6638
3.36k
    }
6639
6640
3.36k
    pub fn seq_rule_set_count_byte_range(&self) -> Range<usize> {
6641
3.36k
        let start = self.coverage_offset_byte_range().end;
6642
3.36k
        let end = start + Uint24::RAW_BYTE_LEN;
6643
3.36k
        start..end
6644
3.36k
    }
6645
6646
3.36k
    pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
6647
3.36k
        let seq_rule_set_count = self.seq_rule_set_count();
6648
3.36k
        let start = self.seq_rule_set_count_byte_range().end;
6649
3.36k
        let end = start
6650
3.36k
            + (transforms::to_usize(seq_rule_set_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
6651
3.36k
        start..end
6652
3.36k
    }
6653
}
6654
6655
impl<'a> MinByteRange<'a> for SequenceRuleSet2<'a> {
6656
0
    fn min_byte_range(&self) -> Range<usize> {
6657
0
        0..self.seq_rule_offsets_byte_range().end
6658
0
    }
6659
0
    fn min_table_bytes(&self) -> &'a [u8] {
6660
0
        let range = self.min_byte_range();
6661
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6662
0
    }
6663
}
6664
6665
impl ReadArgs for SequenceRuleSet2<'_> {
6666
    type Args = ();
6667
}
6668
6669
impl<'a> FontRead<'a> for SequenceRuleSet2<'a> {
6670
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6671
        #[allow(clippy::absurd_extreme_comparisons)]
6672
0
        if data.len() < Self::MIN_SIZE {
6673
0
            return Err(ReadError::OutOfBounds);
6674
0
        }
6675
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6676
0
            return Err(ReadError::OutOfBounds);
6677
        };
6678
0
        Ok(Self { data })
6679
0
    }
6680
}
6681
6682
/// The fields at the start of the table, which are read directly.
6683
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6684
#[repr(C, packed)]
6685
#[doc(hidden)]
6686
pub struct SequenceRuleSet2FixedHeader {
6687
    pub seq_rule_count: BigEndian<u16>,
6688
}
6689
6690
#[allow(clippy::absurd_extreme_comparisons)]
6691
const _: () =
6692
    assert!(std::mem::size_of::<SequenceRuleSet2FixedHeader>() <= SequenceRuleSet2::MIN_SIZE);
6693
6694
/// SequenceRuleSet2 (ISO/IEC 14496-22:2026).
6695
#[derive(Clone)]
6696
pub struct SequenceRuleSet2<'a> {
6697
    data: TableDataRef<'a, SequenceRuleSet2FixedHeader>,
6698
}
6699
6700
#[allow(clippy::needless_lifetimes)]
6701
impl<'a> SequenceRuleSet2<'a> {
6702
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
6703
    basic_table_impls!(impl_the_methods);
6704
6705
    /// Number of SequenceRule tables
6706
0
    pub fn seq_rule_count(&self) -> u16 {
6707
0
        self.data.header().seq_rule_count.get()
6708
0
    }
6709
6710
    /// Array of offsets to SequenceRule tables, from beginning of the
6711
    /// SequenceRuleSet2 table
6712
0
    pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
6713
0
        let range = self.seq_rule_offsets_byte_range();
6714
0
        self.offset_data()
6715
0
            .read_array(range)
6716
0
            .ok()
6717
0
            .unwrap_or_default()
6718
0
    }
6719
6720
    /// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets].
6721
0
    pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule2<'a>, Offset16> {
6722
0
        let data = self.offset_data();
6723
0
        let offsets = self.seq_rule_offsets();
6724
0
        ArrayOfOffsets::new(offsets, data, ())
6725
0
    }
6726
6727
0
    pub fn seq_rule_count_byte_range(&self) -> Range<usize> {
6728
0
        let start = 0;
6729
0
        let end = start + u16::RAW_BYTE_LEN;
6730
0
        start..end
6731
0
    }
6732
6733
0
    pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
6734
0
        let seq_rule_count = self.seq_rule_count();
6735
0
        let start = self.seq_rule_count_byte_range().end;
6736
0
        let end =
6737
0
            start + (transforms::to_usize(seq_rule_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
6738
0
        start..end
6739
0
    }
6740
}
6741
6742
const _: () = assert!(FontData::default_data_long_enough(
6743
    SequenceRuleSet2::MIN_SIZE
6744
));
6745
6746
impl Default for SequenceRuleSet2<'_> {
6747
0
    fn default() -> Self {
6748
        Self {
6749
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
6750
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
6751
        }
6752
0
    }
6753
}
6754
6755
impl<'a> MinByteRange<'a> for SequenceRule2<'a> {
6756
0
    fn min_byte_range(&self) -> Range<usize> {
6757
0
        0..self.seq_lookup_records_byte_range().end
6758
0
    }
6759
0
    fn min_table_bytes(&self) -> &'a [u8] {
6760
0
        let range = self.min_byte_range();
6761
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6762
0
    }
6763
}
6764
6765
impl ReadArgs for SequenceRule2<'_> {
6766
    type Args = ();
6767
}
6768
6769
impl<'a> FontRead<'a> for SequenceRule2<'a> {
6770
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6771
        #[allow(clippy::absurd_extreme_comparisons)]
6772
0
        if data.len() < Self::MIN_SIZE {
6773
0
            return Err(ReadError::OutOfBounds);
6774
0
        }
6775
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6776
0
            return Err(ReadError::OutOfBounds);
6777
        };
6778
0
        Ok(Self { data })
6779
0
    }
6780
}
6781
6782
/// The fields at the start of the table, which are read directly.
6783
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6784
#[repr(C, packed)]
6785
#[doc(hidden)]
6786
pub struct SequenceRule2FixedHeader {
6787
    pub glyph_count: BigEndian<u16>,
6788
    pub seq_lookup_count: BigEndian<u16>,
6789
}
6790
6791
#[allow(clippy::absurd_extreme_comparisons)]
6792
const _: () = assert!(std::mem::size_of::<SequenceRule2FixedHeader>() <= SequenceRule2::MIN_SIZE);
6793
6794
/// SequenceRule2 (ISO/IEC 14496-22:2026).
6795
#[derive(Clone)]
6796
pub struct SequenceRule2<'a> {
6797
    data: TableDataRef<'a, SequenceRule2FixedHeader>,
6798
}
6799
6800
#[allow(clippy::needless_lifetimes)]
6801
impl<'a> SequenceRule2<'a> {
6802
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
6803
    basic_table_impls!(impl_the_methods);
6804
6805
    /// Number of glyphs in the input glyph sequence
6806
0
    pub fn glyph_count(&self) -> u16 {
6807
0
        self.data.header().glyph_count.get()
6808
0
    }
6809
6810
    /// Number of SequenceLookupRecords
6811
0
    pub fn seq_lookup_count(&self) -> u16 {
6812
0
        self.data.header().seq_lookup_count.get()
6813
0
    }
6814
6815
    /// Array of input glyph IDs—starting with the second glyph
6816
0
    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId24>] {
6817
0
        let range = self.input_sequence_byte_range();
6818
0
        self.offset_data()
6819
0
            .read_array(range)
6820
0
            .ok()
6821
0
            .unwrap_or_default()
6822
0
    }
6823
6824
    /// Array of Sequence lookup records
6825
0
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
6826
0
        let range = self.seq_lookup_records_byte_range();
6827
0
        self.offset_data()
6828
0
            .read_array(range)
6829
0
            .ok()
6830
0
            .unwrap_or_default()
6831
0
    }
6832
6833
0
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
6834
0
        let start = 0;
6835
0
        let end = start + u16::RAW_BYTE_LEN;
6836
0
        start..end
6837
0
    }
6838
6839
0
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
6840
0
        let start = self.glyph_count_byte_range().end;
6841
0
        let end = start + u16::RAW_BYTE_LEN;
6842
0
        start..end
6843
0
    }
6844
6845
0
    pub fn input_sequence_byte_range(&self) -> Range<usize> {
6846
0
        let glyph_count = self.glyph_count();
6847
0
        let start = self.seq_lookup_count_byte_range().end;
6848
0
        let end = start
6849
0
            + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(GlyphId24::RAW_BYTE_LEN);
6850
0
        start..end
6851
0
    }
6852
6853
0
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
6854
0
        let seq_lookup_count = self.seq_lookup_count();
6855
0
        let start = self.input_sequence_byte_range().end;
6856
0
        let end = start
6857
0
            + (transforms::to_usize(seq_lookup_count))
6858
0
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
6859
0
        start..end
6860
0
    }
6861
}
6862
6863
const _: () = assert!(FontData::default_data_long_enough(SequenceRule2::MIN_SIZE));
6864
6865
impl Default for SequenceRule2<'_> {
6866
0
    fn default() -> Self {
6867
        Self {
6868
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
6869
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
6870
        }
6871
0
    }
6872
}
6873
6874
impl Format<u16> for SequenceContextFormat5<'_> {
6875
    const FORMAT: u16 = 5;
6876
}
6877
6878
impl<'a> MinByteRange<'a> for SequenceContextFormat5<'a> {
6879
0
    fn min_byte_range(&self) -> Range<usize> {
6880
0
        0..self.class_seq_rule_set_offsets_byte_range().end
6881
0
    }
6882
0
    fn min_table_bytes(&self) -> &'a [u8] {
6883
0
        let range = self.min_byte_range();
6884
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
6885
0
    }
6886
}
6887
6888
impl ReadArgs for SequenceContextFormat5<'_> {
6889
    type Args = ();
6890
}
6891
6892
impl<'a> FontRead<'a> for SequenceContextFormat5<'a> {
6893
158k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
6894
        #[allow(clippy::absurd_extreme_comparisons)]
6895
158k
        if data.len() < Self::MIN_SIZE {
6896
231
            return Err(ReadError::OutOfBounds);
6897
157k
        }
6898
157k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
6899
0
            return Err(ReadError::OutOfBounds);
6900
        };
6901
157k
        Ok(Self { data })
6902
158k
    }
6903
}
6904
6905
/// The fields at the start of the table, which are read directly.
6906
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
6907
#[repr(C, packed)]
6908
#[doc(hidden)]
6909
pub struct SequenceContextFormat5FixedHeader {
6910
    pub format: BigEndian<u16>,
6911
    pub coverage_offset: BigEndian<Offset32>,
6912
    pub class_def_offset: BigEndian<Offset32>,
6913
    pub class_seq_rule_set_count: BigEndian<Uint24>,
6914
}
6915
6916
#[allow(clippy::absurd_extreme_comparisons)]
6917
const _: () = assert!(
6918
    std::mem::size_of::<SequenceContextFormat5FixedHeader>() <= SequenceContextFormat5::MIN_SIZE
6919
);
6920
6921
/// SequenceContextFormat5 (ISO/IEC 14496-22:2026).
6922
#[derive(Clone)]
6923
pub struct SequenceContextFormat5<'a> {
6924
    data: TableDataRef<'a, SequenceContextFormat5FixedHeader>,
6925
}
6926
6927
#[allow(clippy::needless_lifetimes)]
6928
impl<'a> SequenceContextFormat5<'a> {
6929
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
6930
        + Offset32::RAW_BYTE_LEN
6931
        + Offset32::RAW_BYTE_LEN
6932
        + Uint24::RAW_BYTE_LEN);
6933
    basic_table_impls!(impl_the_methods);
6934
6935
    /// Format identifier: format = 5
6936
0
    pub fn format(&self) -> u16 {
6937
0
        self.data.header().format.get()
6938
0
    }
6939
6940
    /// Offset to Coverage table, from beginning of
6941
    /// SequenceContextFormat5 table
6942
157k
    pub fn coverage_offset(&self) -> Offset32 {
6943
157k
        self.data.header().coverage_offset.get()
6944
157k
    }
6945
6946
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
6947
157k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
6948
157k
        let data = self.offset_data();
6949
157k
        self.coverage_offset().resolve(data)
6950
157k
    }
6951
6952
    /// Offset to ClassDef table, from beginning of
6953
    /// SequenceContextFormat5 table
6954
157k
    pub fn class_def_offset(&self) -> Offset32 {
6955
157k
        self.data.header().class_def_offset.get()
6956
157k
    }
6957
6958
    /// Attempt to resolve [`class_def_offset`][Self::class_def_offset].
6959
157k
    pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
6960
157k
        let data = self.offset_data();
6961
157k
        self.class_def_offset().resolve(data)
6962
157k
    }
6963
6964
    /// Number of ClassSequenceRuleSet tables
6965
157k
    pub fn class_seq_rule_set_count(&self) -> Uint24 {
6966
157k
        self.data.header().class_seq_rule_set_count.get()
6967
157k
    }
6968
6969
    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
6970
    /// of SequenceContextFormat5 table (may be NULL)
6971
0
    pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
6972
0
        let range = self.class_seq_rule_set_offsets_byte_range();
6973
0
        self.offset_data()
6974
0
            .read_array(range)
6975
0
            .ok()
6976
0
            .unwrap_or_default()
6977
0
    }
6978
6979
    /// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets].
6980
0
    pub fn class_seq_rule_sets(
6981
0
        &self,
6982
0
    ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet2<'a>, Offset24> {
6983
0
        let data = self.offset_data();
6984
0
        let offsets = self.class_seq_rule_set_offsets();
6985
0
        ArrayOfNullableOffsets::new(offsets, data, ())
6986
0
    }
6987
6988
157k
    pub fn format_byte_range(&self) -> Range<usize> {
6989
157k
        let start = 0;
6990
157k
        let end = start + u16::RAW_BYTE_LEN;
6991
157k
        start..end
6992
157k
    }
6993
6994
157k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
6995
157k
        let start = self.format_byte_range().end;
6996
157k
        let end = start + Offset32::RAW_BYTE_LEN;
6997
157k
        start..end
6998
157k
    }
6999
7000
157k
    pub fn class_def_offset_byte_range(&self) -> Range<usize> {
7001
157k
        let start = self.coverage_offset_byte_range().end;
7002
157k
        let end = start + Offset32::RAW_BYTE_LEN;
7003
157k
        start..end
7004
157k
    }
7005
7006
157k
    pub fn class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
7007
157k
        let start = self.class_def_offset_byte_range().end;
7008
157k
        let end = start + Uint24::RAW_BYTE_LEN;
7009
157k
        start..end
7010
157k
    }
7011
7012
157k
    pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
7013
157k
        let class_seq_rule_set_count = self.class_seq_rule_set_count();
7014
157k
        let start = self.class_seq_rule_set_count_byte_range().end;
7015
157k
        let end = start
7016
157k
            + (transforms::to_usize(class_seq_rule_set_count))
7017
157k
                .saturating_mul(Offset24::RAW_BYTE_LEN);
7018
157k
        start..end
7019
157k
    }
7020
}
7021
7022
impl<'a> MinByteRange<'a> for ClassSequenceRuleSet2<'a> {
7023
0
    fn min_byte_range(&self) -> Range<usize> {
7024
0
        0..self.class_seq_rule_offsets_byte_range().end
7025
0
    }
7026
0
    fn min_table_bytes(&self) -> &'a [u8] {
7027
0
        let range = self.min_byte_range();
7028
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7029
0
    }
7030
}
7031
7032
impl ReadArgs for ClassSequenceRuleSet2<'_> {
7033
    type Args = ();
7034
}
7035
7036
impl<'a> FontRead<'a> for ClassSequenceRuleSet2<'a> {
7037
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7038
        #[allow(clippy::absurd_extreme_comparisons)]
7039
0
        if data.len() < Self::MIN_SIZE {
7040
0
            return Err(ReadError::OutOfBounds);
7041
0
        }
7042
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7043
0
            return Err(ReadError::OutOfBounds);
7044
        };
7045
0
        Ok(Self { data })
7046
0
    }
7047
}
7048
7049
/// The fields at the start of the table, which are read directly.
7050
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7051
#[repr(C, packed)]
7052
#[doc(hidden)]
7053
pub struct ClassSequenceRuleSet2FixedHeader {
7054
    pub class_seq_rule_count: BigEndian<u16>,
7055
}
7056
7057
#[allow(clippy::absurd_extreme_comparisons)]
7058
const _: () = assert!(
7059
    std::mem::size_of::<ClassSequenceRuleSet2FixedHeader>() <= ClassSequenceRuleSet2::MIN_SIZE
7060
);
7061
7062
/// ClassSequenceRuleSet2 (ISO/IEC 14496-22:2026).
7063
#[derive(Clone)]
7064
pub struct ClassSequenceRuleSet2<'a> {
7065
    data: TableDataRef<'a, ClassSequenceRuleSet2FixedHeader>,
7066
}
7067
7068
#[allow(clippy::needless_lifetimes)]
7069
impl<'a> ClassSequenceRuleSet2<'a> {
7070
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
7071
    basic_table_impls!(impl_the_methods);
7072
7073
    /// Number of ClassSequenceRule tables
7074
0
    pub fn class_seq_rule_count(&self) -> u16 {
7075
0
        self.data.header().class_seq_rule_count.get()
7076
0
    }
7077
7078
    /// Array of offsets to ClassSequenceRule tables, from beginning of
7079
    /// ClassSequenceRuleSet2 table
7080
0
    pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset24>] {
7081
0
        let range = self.class_seq_rule_offsets_byte_range();
7082
0
        self.offset_data()
7083
0
            .read_array(range)
7084
0
            .ok()
7085
0
            .unwrap_or_default()
7086
0
    }
7087
7088
    /// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets].
7089
0
    pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset24> {
7090
0
        let data = self.offset_data();
7091
0
        let offsets = self.class_seq_rule_offsets();
7092
0
        ArrayOfOffsets::new(offsets, data, ())
7093
0
    }
7094
7095
0
    pub fn class_seq_rule_count_byte_range(&self) -> Range<usize> {
7096
0
        let start = 0;
7097
0
        let end = start + u16::RAW_BYTE_LEN;
7098
0
        start..end
7099
0
    }
7100
7101
0
    pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
7102
0
        let class_seq_rule_count = self.class_seq_rule_count();
7103
0
        let start = self.class_seq_rule_count_byte_range().end;
7104
0
        let end = start
7105
0
            + (transforms::to_usize(class_seq_rule_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
7106
0
        start..end
7107
0
    }
7108
}
7109
7110
const _: () = assert!(FontData::default_data_long_enough(
7111
    ClassSequenceRuleSet2::MIN_SIZE
7112
));
7113
7114
impl Default for ClassSequenceRuleSet2<'_> {
7115
0
    fn default() -> Self {
7116
        Self {
7117
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
7118
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
7119
        }
7120
0
    }
7121
}
7122
7123
impl Format<u16> for SequenceContextFormat6<'_> {
7124
    const FORMAT: u16 = 6;
7125
}
7126
7127
impl<'a> MinByteRange<'a> for SequenceContextFormat6<'a> {
7128
0
    fn min_byte_range(&self) -> Range<usize> {
7129
0
        0..self.seq_lookup_records_byte_range().end
7130
0
    }
7131
0
    fn min_table_bytes(&self) -> &'a [u8] {
7132
0
        let range = self.min_byte_range();
7133
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7134
0
    }
7135
}
7136
7137
impl ReadArgs for SequenceContextFormat6<'_> {
7138
    type Args = ();
7139
}
7140
7141
impl<'a> FontRead<'a> for SequenceContextFormat6<'a> {
7142
6.53k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7143
        #[allow(clippy::absurd_extreme_comparisons)]
7144
6.53k
        if data.len() < Self::MIN_SIZE {
7145
121
            return Err(ReadError::OutOfBounds);
7146
6.41k
        }
7147
6.41k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7148
0
            return Err(ReadError::OutOfBounds);
7149
        };
7150
6.41k
        Ok(Self { data })
7151
6.53k
    }
7152
}
7153
7154
/// The fields at the start of the table, which are read directly.
7155
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7156
#[repr(C, packed)]
7157
#[doc(hidden)]
7158
pub struct SequenceContextFormat6FixedHeader {
7159
    pub format: BigEndian<u16>,
7160
    pub glyph_count: BigEndian<u16>,
7161
    pub seq_lookup_count: BigEndian<u16>,
7162
}
7163
7164
#[allow(clippy::absurd_extreme_comparisons)]
7165
const _: () = assert!(
7166
    std::mem::size_of::<SequenceContextFormat6FixedHeader>() <= SequenceContextFormat6::MIN_SIZE
7167
);
7168
7169
/// SequenceContextFormat6 (ISO/IEC 14496-22:2026).
7170
#[derive(Clone)]
7171
pub struct SequenceContextFormat6<'a> {
7172
    data: TableDataRef<'a, SequenceContextFormat6FixedHeader>,
7173
}
7174
7175
#[allow(clippy::needless_lifetimes)]
7176
impl<'a> SequenceContextFormat6<'a> {
7177
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
7178
    basic_table_impls!(impl_the_methods);
7179
7180
    /// Format identifier: format = 6
7181
0
    pub fn format(&self) -> u16 {
7182
0
        self.data.header().format.get()
7183
0
    }
7184
7185
    /// Number of glyphs in the input sequence
7186
19.2k
    pub fn glyph_count(&self) -> u16 {
7187
19.2k
        self.data.header().glyph_count.get()
7188
19.2k
    }
7189
7190
    /// Number of SequenceLookupRecords
7191
6.41k
    pub fn seq_lookup_count(&self) -> u16 {
7192
6.41k
        self.data.header().seq_lookup_count.get()
7193
6.41k
    }
7194
7195
    /// Array of offsets to Coverage tables, from beginning of
7196
    /// SequenceContextFormat6 subtable
7197
6.41k
    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset24>] {
7198
6.41k
        let range = self.coverage_offsets_byte_range();
7199
6.41k
        self.offset_data()
7200
6.41k
            .read_array(range)
7201
6.41k
            .ok()
7202
6.41k
            .unwrap_or_default()
7203
6.41k
    }
7204
7205
    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
7206
6.41k
    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset24> {
7207
6.41k
        let data = self.offset_data();
7208
6.41k
        let offsets = self.coverage_offsets();
7209
6.41k
        ArrayOfOffsets::new(offsets, data, ())
7210
6.41k
    }
7211
7212
    /// Array of SequenceLookupRecords
7213
6.41k
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
7214
6.41k
        let range = self.seq_lookup_records_byte_range();
7215
6.41k
        self.offset_data()
7216
6.41k
            .read_array(range)
7217
6.41k
            .ok()
7218
6.41k
            .unwrap_or_default()
7219
6.41k
    }
7220
7221
19.2k
    pub fn format_byte_range(&self) -> Range<usize> {
7222
19.2k
        let start = 0;
7223
19.2k
        let end = start + u16::RAW_BYTE_LEN;
7224
19.2k
        start..end
7225
19.2k
    }
7226
7227
19.2k
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
7228
19.2k
        let start = self.format_byte_range().end;
7229
19.2k
        let end = start + u16::RAW_BYTE_LEN;
7230
19.2k
        start..end
7231
19.2k
    }
7232
7233
19.2k
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
7234
19.2k
        let start = self.glyph_count_byte_range().end;
7235
19.2k
        let end = start + u16::RAW_BYTE_LEN;
7236
19.2k
        start..end
7237
19.2k
    }
7238
7239
19.2k
    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
7240
19.2k
        let glyph_count = self.glyph_count();
7241
19.2k
        let start = self.seq_lookup_count_byte_range().end;
7242
19.2k
        let end =
7243
19.2k
            start + (transforms::to_usize(glyph_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
7244
19.2k
        start..end
7245
19.2k
    }
7246
7247
6.41k
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
7248
6.41k
        let seq_lookup_count = self.seq_lookup_count();
7249
6.41k
        let start = self.coverage_offsets_byte_range().end;
7250
6.41k
        let end = start
7251
6.41k
            + (transforms::to_usize(seq_lookup_count))
7252
6.41k
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
7253
6.41k
        start..end
7254
6.41k
    }
7255
}
7256
7257
impl Format<u16> for ChainedSequenceContextFormat4<'_> {
7258
    const FORMAT: u16 = 4;
7259
}
7260
7261
impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat4<'a> {
7262
0
    fn min_byte_range(&self) -> Range<usize> {
7263
0
        0..self.chained_seq_rule_set_offsets_byte_range().end
7264
0
    }
7265
0
    fn min_table_bytes(&self) -> &'a [u8] {
7266
0
        let range = self.min_byte_range();
7267
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7268
0
    }
7269
}
7270
7271
impl ReadArgs for ChainedSequenceContextFormat4<'_> {
7272
    type Args = ();
7273
}
7274
7275
impl<'a> FontRead<'a> for ChainedSequenceContextFormat4<'a> {
7276
5.31k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7277
        #[allow(clippy::absurd_extreme_comparisons)]
7278
5.31k
        if data.len() < Self::MIN_SIZE {
7279
240
            return Err(ReadError::OutOfBounds);
7280
5.07k
        }
7281
5.07k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7282
0
            return Err(ReadError::OutOfBounds);
7283
        };
7284
5.07k
        Ok(Self { data })
7285
5.31k
    }
7286
}
7287
7288
/// The fields at the start of the table, which are read directly.
7289
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7290
#[repr(C, packed)]
7291
#[doc(hidden)]
7292
pub struct ChainedSequenceContextFormat4FixedHeader {
7293
    pub format: BigEndian<u16>,
7294
    pub coverage_offset: BigEndian<Offset32>,
7295
    pub chained_seq_rule_set_count: BigEndian<Uint24>,
7296
}
7297
7298
#[allow(clippy::absurd_extreme_comparisons)]
7299
const _: () = assert!(
7300
    std::mem::size_of::<ChainedSequenceContextFormat4FixedHeader>()
7301
        <= ChainedSequenceContextFormat4::MIN_SIZE
7302
);
7303
7304
/// ChainedSequenceContextFormat4 (ISO/IEC 14496-22:2026).
7305
#[derive(Clone)]
7306
pub struct ChainedSequenceContextFormat4<'a> {
7307
    data: TableDataRef<'a, ChainedSequenceContextFormat4FixedHeader>,
7308
}
7309
7310
#[allow(clippy::needless_lifetimes)]
7311
impl<'a> ChainedSequenceContextFormat4<'a> {
7312
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
7313
    basic_table_impls!(impl_the_methods);
7314
7315
    /// Format identifier: format = 4
7316
0
    pub fn format(&self) -> u16 {
7317
0
        self.data.header().format.get()
7318
0
    }
7319
7320
    /// Offset to Coverage table, from beginning of
7321
    /// ChainedSequenceContextFormat4 table
7322
5.07k
    pub fn coverage_offset(&self) -> Offset32 {
7323
5.07k
        self.data.header().coverage_offset.get()
7324
5.07k
    }
7325
7326
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
7327
5.07k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
7328
5.07k
        let data = self.offset_data();
7329
5.07k
        self.coverage_offset().resolve(data)
7330
5.07k
    }
7331
7332
    /// Number of ChainedSequenceRuleSet tables
7333
5.07k
    pub fn chained_seq_rule_set_count(&self) -> Uint24 {
7334
5.07k
        self.data.header().chained_seq_rule_set_count.get()
7335
5.07k
    }
7336
7337
    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
7338
    /// ChainedSequenceContextFormat4 table (may be NULL)
7339
0
    pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
7340
0
        let range = self.chained_seq_rule_set_offsets_byte_range();
7341
0
        self.offset_data()
7342
0
            .read_array(range)
7343
0
            .ok()
7344
0
            .unwrap_or_default()
7345
0
    }
7346
7347
    /// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets].
7348
0
    pub fn chained_seq_rule_sets(
7349
0
        &self,
7350
0
    ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet2<'a>, Offset24> {
7351
0
        let data = self.offset_data();
7352
0
        let offsets = self.chained_seq_rule_set_offsets();
7353
0
        ArrayOfNullableOffsets::new(offsets, data, ())
7354
0
    }
7355
7356
5.07k
    pub fn format_byte_range(&self) -> Range<usize> {
7357
5.07k
        let start = 0;
7358
5.07k
        let end = start + u16::RAW_BYTE_LEN;
7359
5.07k
        start..end
7360
5.07k
    }
7361
7362
5.07k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
7363
5.07k
        let start = self.format_byte_range().end;
7364
5.07k
        let end = start + Offset32::RAW_BYTE_LEN;
7365
5.07k
        start..end
7366
5.07k
    }
7367
7368
5.07k
    pub fn chained_seq_rule_set_count_byte_range(&self) -> Range<usize> {
7369
5.07k
        let start = self.coverage_offset_byte_range().end;
7370
5.07k
        let end = start + Uint24::RAW_BYTE_LEN;
7371
5.07k
        start..end
7372
5.07k
    }
7373
7374
5.07k
    pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
7375
5.07k
        let chained_seq_rule_set_count = self.chained_seq_rule_set_count();
7376
5.07k
        let start = self.chained_seq_rule_set_count_byte_range().end;
7377
5.07k
        let end = start
7378
5.07k
            + (transforms::to_usize(chained_seq_rule_set_count))
7379
5.07k
                .saturating_mul(Offset24::RAW_BYTE_LEN);
7380
5.07k
        start..end
7381
5.07k
    }
7382
}
7383
7384
impl<'a> MinByteRange<'a> for ChainedSequenceRuleSet2<'a> {
7385
0
    fn min_byte_range(&self) -> Range<usize> {
7386
0
        0..self.chained_seq_rule_offsets_byte_range().end
7387
0
    }
7388
0
    fn min_table_bytes(&self) -> &'a [u8] {
7389
0
        let range = self.min_byte_range();
7390
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7391
0
    }
7392
}
7393
7394
impl ReadArgs for ChainedSequenceRuleSet2<'_> {
7395
    type Args = ();
7396
}
7397
7398
impl<'a> FontRead<'a> for ChainedSequenceRuleSet2<'a> {
7399
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7400
        #[allow(clippy::absurd_extreme_comparisons)]
7401
0
        if data.len() < Self::MIN_SIZE {
7402
0
            return Err(ReadError::OutOfBounds);
7403
0
        }
7404
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7405
0
            return Err(ReadError::OutOfBounds);
7406
        };
7407
0
        Ok(Self { data })
7408
0
    }
7409
}
7410
7411
/// The fields at the start of the table, which are read directly.
7412
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7413
#[repr(C, packed)]
7414
#[doc(hidden)]
7415
pub struct ChainedSequenceRuleSet2FixedHeader {
7416
    pub chained_seq_rule_count: BigEndian<u16>,
7417
}
7418
7419
#[allow(clippy::absurd_extreme_comparisons)]
7420
const _: () = assert!(
7421
    std::mem::size_of::<ChainedSequenceRuleSet2FixedHeader>() <= ChainedSequenceRuleSet2::MIN_SIZE
7422
);
7423
7424
/// ChainedSequenceRuleSet2 (ISO/IEC 14496-22:2026).
7425
#[derive(Clone)]
7426
pub struct ChainedSequenceRuleSet2<'a> {
7427
    data: TableDataRef<'a, ChainedSequenceRuleSet2FixedHeader>,
7428
}
7429
7430
#[allow(clippy::needless_lifetimes)]
7431
impl<'a> ChainedSequenceRuleSet2<'a> {
7432
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
7433
    basic_table_impls!(impl_the_methods);
7434
7435
    /// Number of ChainedSequenceRule tables
7436
0
    pub fn chained_seq_rule_count(&self) -> u16 {
7437
0
        self.data.header().chained_seq_rule_count.get()
7438
0
    }
7439
7440
    /// Array of offsets to ChainedSequenceRule tables, from beginning
7441
    /// of ChainedSequenceRuleSet2 table
7442
0
    pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset24>] {
7443
0
        let range = self.chained_seq_rule_offsets_byte_range();
7444
0
        self.offset_data()
7445
0
            .read_array(range)
7446
0
            .ok()
7447
0
            .unwrap_or_default()
7448
0
    }
7449
7450
    /// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets].
7451
0
    pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule2<'a>, Offset24> {
7452
0
        let data = self.offset_data();
7453
0
        let offsets = self.chained_seq_rule_offsets();
7454
0
        ArrayOfOffsets::new(offsets, data, ())
7455
0
    }
7456
7457
0
    pub fn chained_seq_rule_count_byte_range(&self) -> Range<usize> {
7458
0
        let start = 0;
7459
0
        let end = start + u16::RAW_BYTE_LEN;
7460
0
        start..end
7461
0
    }
7462
7463
0
    pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
7464
0
        let chained_seq_rule_count = self.chained_seq_rule_count();
7465
0
        let start = self.chained_seq_rule_count_byte_range().end;
7466
0
        let end = start
7467
0
            + (transforms::to_usize(chained_seq_rule_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
7468
0
        start..end
7469
0
    }
7470
}
7471
7472
const _: () = assert!(FontData::default_data_long_enough(
7473
    ChainedSequenceRuleSet2::MIN_SIZE
7474
));
7475
7476
impl Default for ChainedSequenceRuleSet2<'_> {
7477
0
    fn default() -> Self {
7478
        Self {
7479
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
7480
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
7481
        }
7482
0
    }
7483
}
7484
7485
impl<'a> MinByteRange<'a> for ChainedSequenceRule2<'a> {
7486
0
    fn min_byte_range(&self) -> Range<usize> {
7487
0
        0..self.seq_lookup_records_byte_range().end
7488
0
    }
7489
0
    fn min_table_bytes(&self) -> &'a [u8] {
7490
0
        let range = self.min_byte_range();
7491
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7492
0
    }
7493
}
7494
7495
impl ReadArgs for ChainedSequenceRule2<'_> {
7496
    type Args = ();
7497
}
7498
7499
impl<'a> FontRead<'a> for ChainedSequenceRule2<'a> {
7500
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7501
        #[allow(clippy::absurd_extreme_comparisons)]
7502
0
        if data.len() < Self::MIN_SIZE {
7503
0
            return Err(ReadError::OutOfBounds);
7504
0
        }
7505
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7506
0
            return Err(ReadError::OutOfBounds);
7507
        };
7508
0
        Ok(Self { data })
7509
0
    }
7510
}
7511
7512
/// The fields at the start of the table, which are read directly.
7513
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7514
#[repr(C, packed)]
7515
#[doc(hidden)]
7516
pub struct ChainedSequenceRule2FixedHeader {
7517
    pub backtrack_glyph_count: BigEndian<u16>,
7518
}
7519
7520
#[allow(clippy::absurd_extreme_comparisons)]
7521
const _: () = assert!(
7522
    std::mem::size_of::<ChainedSequenceRule2FixedHeader>() <= ChainedSequenceRule2::MIN_SIZE
7523
);
7524
7525
/// ChainedSequenceRule2 (ISO/IEC 14496-22:2026).
7526
#[derive(Clone)]
7527
pub struct ChainedSequenceRule2<'a> {
7528
    data: TableDataRef<'a, ChainedSequenceRule2FixedHeader>,
7529
}
7530
7531
#[allow(clippy::needless_lifetimes)]
7532
impl<'a> ChainedSequenceRule2<'a> {
7533
    pub const MIN_SIZE: usize =
7534
        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
7535
    basic_table_impls!(impl_the_methods);
7536
7537
    /// Number of glyphs in the backtrack sequence
7538
0
    pub fn backtrack_glyph_count(&self) -> u16 {
7539
0
        self.data.header().backtrack_glyph_count.get()
7540
0
    }
7541
7542
    /// Array of backtrack glyph IDs
7543
0
    pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId24>] {
7544
0
        let range = self.backtrack_sequence_byte_range();
7545
0
        self.offset_data()
7546
0
            .read_array(range)
7547
0
            .ok()
7548
0
            .unwrap_or_default()
7549
0
    }
7550
7551
    /// Number of glyphs in the input sequence
7552
0
    pub fn input_glyph_count(&self) -> u16 {
7553
0
        let range = self.input_glyph_count_byte_range();
7554
0
        self.offset_data()
7555
0
            .read_at(range.start)
7556
0
            .ok()
7557
0
            .unwrap_or_default()
7558
0
    }
7559
7560
    /// Array of input glyph IDs—start with second glyph
7561
0
    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId24>] {
7562
0
        let range = self.input_sequence_byte_range();
7563
0
        self.offset_data()
7564
0
            .read_array(range)
7565
0
            .ok()
7566
0
            .unwrap_or_default()
7567
0
    }
7568
7569
    /// Number of glyphs in the lookahead sequence
7570
0
    pub fn lookahead_glyph_count(&self) -> u16 {
7571
0
        let range = self.lookahead_glyph_count_byte_range();
7572
0
        self.offset_data()
7573
0
            .read_at(range.start)
7574
0
            .ok()
7575
0
            .unwrap_or_default()
7576
0
    }
7577
7578
    /// Array of lookahead glyph IDs
7579
0
    pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId24>] {
7580
0
        let range = self.lookahead_sequence_byte_range();
7581
0
        self.offset_data()
7582
0
            .read_array(range)
7583
0
            .ok()
7584
0
            .unwrap_or_default()
7585
0
    }
7586
7587
    /// Number of SequenceLookupRecords
7588
0
    pub fn seq_lookup_count(&self) -> u16 {
7589
0
        let range = self.seq_lookup_count_byte_range();
7590
0
        self.offset_data()
7591
0
            .read_at(range.start)
7592
0
            .ok()
7593
0
            .unwrap_or_default()
7594
0
    }
7595
7596
    /// Array of SequenceLookupRecords
7597
0
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
7598
0
        let range = self.seq_lookup_records_byte_range();
7599
0
        self.offset_data()
7600
0
            .read_array(range)
7601
0
            .ok()
7602
0
            .unwrap_or_default()
7603
0
    }
7604
7605
0
    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
7606
0
        let start = 0;
7607
0
        let end = start + u16::RAW_BYTE_LEN;
7608
0
        start..end
7609
0
    }
7610
7611
0
    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
7612
0
        let backtrack_glyph_count = self.backtrack_glyph_count();
7613
0
        let start = self.backtrack_glyph_count_byte_range().end;
7614
0
        let end = start
7615
0
            + (transforms::to_usize(backtrack_glyph_count)).saturating_mul(GlyphId24::RAW_BYTE_LEN);
7616
0
        start..end
7617
0
    }
7618
7619
0
    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
7620
0
        let start = self.backtrack_sequence_byte_range().end;
7621
0
        let end = start + u16::RAW_BYTE_LEN;
7622
0
        start..end
7623
0
    }
7624
7625
0
    pub fn input_sequence_byte_range(&self) -> Range<usize> {
7626
0
        let input_glyph_count = self.input_glyph_count();
7627
0
        let start = self.input_glyph_count_byte_range().end;
7628
0
        let end = start
7629
0
            + (transforms::subtract(input_glyph_count, 1_usize))
7630
0
                .saturating_mul(GlyphId24::RAW_BYTE_LEN);
7631
0
        start..end
7632
0
    }
7633
7634
0
    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
7635
0
        let start = self.input_sequence_byte_range().end;
7636
0
        let end = start + u16::RAW_BYTE_LEN;
7637
0
        start..end
7638
0
    }
7639
7640
0
    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
7641
0
        let lookahead_glyph_count = self.lookahead_glyph_count();
7642
0
        let start = self.lookahead_glyph_count_byte_range().end;
7643
0
        let end = start
7644
0
            + (transforms::to_usize(lookahead_glyph_count)).saturating_mul(GlyphId24::RAW_BYTE_LEN);
7645
0
        start..end
7646
0
    }
7647
7648
0
    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
7649
0
        let start = self.lookahead_sequence_byte_range().end;
7650
0
        let end = start + u16::RAW_BYTE_LEN;
7651
0
        start..end
7652
0
    }
7653
7654
0
    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
7655
0
        let seq_lookup_count = self.seq_lookup_count();
7656
0
        let start = self.seq_lookup_count_byte_range().end;
7657
0
        let end = start
7658
0
            + (transforms::to_usize(seq_lookup_count))
7659
0
                .saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN);
7660
0
        start..end
7661
0
    }
7662
}
7663
7664
const _: () = assert!(FontData::default_data_long_enough(
7665
    ChainedSequenceRule2::MIN_SIZE
7666
));
7667
7668
impl Default for ChainedSequenceRule2<'_> {
7669
0
    fn default() -> Self {
7670
        Self {
7671
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
7672
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
7673
        }
7674
0
    }
7675
}
7676
7677
impl Format<u16> for ChainedSequenceContextFormat5<'_> {
7678
    const FORMAT: u16 = 5;
7679
}
7680
7681
impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat5<'a> {
7682
0
    fn min_byte_range(&self) -> Range<usize> {
7683
0
        0..self.chained_class_seq_rule_set_offsets_byte_range().end
7684
0
    }
7685
0
    fn min_table_bytes(&self) -> &'a [u8] {
7686
0
        let range = self.min_byte_range();
7687
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7688
0
    }
7689
}
7690
7691
impl ReadArgs for ChainedSequenceContextFormat5<'_> {
7692
    type Args = ();
7693
}
7694
7695
impl<'a> FontRead<'a> for ChainedSequenceContextFormat5<'a> {
7696
5.53k
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7697
        #[allow(clippy::absurd_extreme_comparisons)]
7698
5.53k
        if data.len() < Self::MIN_SIZE {
7699
310
            return Err(ReadError::OutOfBounds);
7700
5.22k
        }
7701
5.22k
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7702
0
            return Err(ReadError::OutOfBounds);
7703
        };
7704
5.22k
        Ok(Self { data })
7705
5.53k
    }
7706
}
7707
7708
/// The fields at the start of the table, which are read directly.
7709
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7710
#[repr(C, packed)]
7711
#[doc(hidden)]
7712
pub struct ChainedSequenceContextFormat5FixedHeader {
7713
    pub format: BigEndian<u16>,
7714
    pub coverage_offset: BigEndian<Offset32>,
7715
    pub backtrack_class_def_offset: BigEndian<Offset32>,
7716
    pub input_class_def_offset: BigEndian<Offset32>,
7717
    pub lookahead_class_def_offset: BigEndian<Offset32>,
7718
    pub chained_class_seq_rule_set_count: BigEndian<u16>,
7719
}
7720
7721
#[allow(clippy::absurd_extreme_comparisons)]
7722
const _: () = assert!(
7723
    std::mem::size_of::<ChainedSequenceContextFormat5FixedHeader>()
7724
        <= ChainedSequenceContextFormat5::MIN_SIZE
7725
);
7726
7727
/// ChainedSequenceContextFormat5 (ISO/IEC 14496-22:2026).
7728
#[derive(Clone)]
7729
pub struct ChainedSequenceContextFormat5<'a> {
7730
    data: TableDataRef<'a, ChainedSequenceContextFormat5FixedHeader>,
7731
}
7732
7733
#[allow(clippy::needless_lifetimes)]
7734
impl<'a> ChainedSequenceContextFormat5<'a> {
7735
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
7736
        + Offset32::RAW_BYTE_LEN
7737
        + Offset32::RAW_BYTE_LEN
7738
        + Offset32::RAW_BYTE_LEN
7739
        + Offset32::RAW_BYTE_LEN
7740
        + u16::RAW_BYTE_LEN);
7741
    basic_table_impls!(impl_the_methods);
7742
7743
    /// Format identifier: format = 5
7744
0
    pub fn format(&self) -> u16 {
7745
0
        self.data.header().format.get()
7746
0
    }
7747
7748
    /// Offset to Coverage table, from beginning of
7749
    /// ChainedSequenceContextFormat5 table
7750
5.22k
    pub fn coverage_offset(&self) -> Offset32 {
7751
5.22k
        self.data.header().coverage_offset.get()
7752
5.22k
    }
7753
7754
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
7755
5.22k
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
7756
5.22k
        let data = self.offset_data();
7757
5.22k
        self.coverage_offset().resolve(data)
7758
5.22k
    }
7759
7760
    /// Offset to ClassDef table containing backtrack sequence context,
7761
    /// from beginning of ChainedSequenceContextFormat5 table
7762
5.22k
    pub fn backtrack_class_def_offset(&self) -> Offset32 {
7763
5.22k
        self.data.header().backtrack_class_def_offset.get()
7764
5.22k
    }
7765
7766
    /// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset].
7767
5.22k
    pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
7768
5.22k
        let data = self.offset_data();
7769
5.22k
        self.backtrack_class_def_offset().resolve(data)
7770
5.22k
    }
7771
7772
    /// Offset to ClassDef table containing input sequence context,
7773
    /// from beginning of ChainedSequenceContextFormat5 table
7774
5.22k
    pub fn input_class_def_offset(&self) -> Offset32 {
7775
5.22k
        self.data.header().input_class_def_offset.get()
7776
5.22k
    }
7777
7778
    /// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset].
7779
5.22k
    pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
7780
5.22k
        let data = self.offset_data();
7781
5.22k
        self.input_class_def_offset().resolve(data)
7782
5.22k
    }
7783
7784
    /// Offset to ClassDef table containing lookahead sequence context,
7785
    /// from beginning of ChainedSequenceContextFormat5 table
7786
5.22k
    pub fn lookahead_class_def_offset(&self) -> Offset32 {
7787
5.22k
        self.data.header().lookahead_class_def_offset.get()
7788
5.22k
    }
7789
7790
    /// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset].
7791
5.22k
    pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
7792
5.22k
        let data = self.offset_data();
7793
5.22k
        self.lookahead_class_def_offset().resolve(data)
7794
5.22k
    }
7795
7796
    /// Number of ChainedClassSequenceRuleSet tables
7797
5.22k
    pub fn chained_class_seq_rule_set_count(&self) -> u16 {
7798
5.22k
        self.data.header().chained_class_seq_rule_set_count.get()
7799
5.22k
    }
7800
7801
    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
7802
    /// beginning of ChainedSequenceContextFormat5 table (may be NULL)
7803
0
    pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset24>>] {
7804
0
        let range = self.chained_class_seq_rule_set_offsets_byte_range();
7805
0
        self.offset_data()
7806
0
            .read_array(range)
7807
0
            .ok()
7808
0
            .unwrap_or_default()
7809
0
    }
7810
7811
    /// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets].
7812
0
    pub fn chained_class_seq_rule_sets(
7813
0
        &self,
7814
0
    ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet2<'a>, Offset24> {
7815
0
        let data = self.offset_data();
7816
0
        let offsets = self.chained_class_seq_rule_set_offsets();
7817
0
        ArrayOfNullableOffsets::new(offsets, data, ())
7818
0
    }
7819
7820
5.22k
    pub fn format_byte_range(&self) -> Range<usize> {
7821
5.22k
        let start = 0;
7822
5.22k
        let end = start + u16::RAW_BYTE_LEN;
7823
5.22k
        start..end
7824
5.22k
    }
7825
7826
5.22k
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
7827
5.22k
        let start = self.format_byte_range().end;
7828
5.22k
        let end = start + Offset32::RAW_BYTE_LEN;
7829
5.22k
        start..end
7830
5.22k
    }
7831
7832
5.22k
    pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
7833
5.22k
        let start = self.coverage_offset_byte_range().end;
7834
5.22k
        let end = start + Offset32::RAW_BYTE_LEN;
7835
5.22k
        start..end
7836
5.22k
    }
7837
7838
5.22k
    pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
7839
5.22k
        let start = self.backtrack_class_def_offset_byte_range().end;
7840
5.22k
        let end = start + Offset32::RAW_BYTE_LEN;
7841
5.22k
        start..end
7842
5.22k
    }
7843
7844
5.22k
    pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
7845
5.22k
        let start = self.input_class_def_offset_byte_range().end;
7846
5.22k
        let end = start + Offset32::RAW_BYTE_LEN;
7847
5.22k
        start..end
7848
5.22k
    }
7849
7850
5.22k
    pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
7851
5.22k
        let start = self.lookahead_class_def_offset_byte_range().end;
7852
5.22k
        let end = start + u16::RAW_BYTE_LEN;
7853
5.22k
        start..end
7854
5.22k
    }
7855
7856
5.22k
    pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
7857
5.22k
        let chained_class_seq_rule_set_count = self.chained_class_seq_rule_set_count();
7858
5.22k
        let start = self.chained_class_seq_rule_set_count_byte_range().end;
7859
5.22k
        let end = start
7860
5.22k
            + (transforms::to_usize(chained_class_seq_rule_set_count))
7861
5.22k
                .saturating_mul(Offset24::RAW_BYTE_LEN);
7862
5.22k
        start..end
7863
5.22k
    }
7864
}
7865
7866
impl<'a> MinByteRange<'a> for ChainedClassSequenceRuleSet2<'a> {
7867
0
    fn min_byte_range(&self) -> Range<usize> {
7868
0
        0..self.chained_class_seq_rule_offsets_byte_range().end
7869
0
    }
7870
0
    fn min_table_bytes(&self) -> &'a [u8] {
7871
0
        let range = self.min_byte_range();
7872
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7873
0
    }
7874
}
7875
7876
impl ReadArgs for ChainedClassSequenceRuleSet2<'_> {
7877
    type Args = ();
7878
}
7879
7880
impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet2<'a> {
7881
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7882
        #[allow(clippy::absurd_extreme_comparisons)]
7883
0
        if data.len() < Self::MIN_SIZE {
7884
0
            return Err(ReadError::OutOfBounds);
7885
0
        }
7886
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7887
0
            return Err(ReadError::OutOfBounds);
7888
        };
7889
0
        Ok(Self { data })
7890
0
    }
7891
}
7892
7893
/// The fields at the start of the table, which are read directly.
7894
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
7895
#[repr(C, packed)]
7896
#[doc(hidden)]
7897
pub struct ChainedClassSequenceRuleSet2FixedHeader {
7898
    pub chained_class_seq_rule_count: BigEndian<u16>,
7899
}
7900
7901
#[allow(clippy::absurd_extreme_comparisons)]
7902
const _: () = assert!(
7903
    std::mem::size_of::<ChainedClassSequenceRuleSet2FixedHeader>()
7904
        <= ChainedClassSequenceRuleSet2::MIN_SIZE
7905
);
7906
7907
/// ChainedClassSequenceRuleSet2 (ISO/IEC 14496-22:2026).
7908
#[derive(Clone)]
7909
pub struct ChainedClassSequenceRuleSet2<'a> {
7910
    data: TableDataRef<'a, ChainedClassSequenceRuleSet2FixedHeader>,
7911
}
7912
7913
#[allow(clippy::needless_lifetimes)]
7914
impl<'a> ChainedClassSequenceRuleSet2<'a> {
7915
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
7916
    basic_table_impls!(impl_the_methods);
7917
7918
    /// Number of ChainedClassSequenceRule tables
7919
0
    pub fn chained_class_seq_rule_count(&self) -> u16 {
7920
0
        self.data.header().chained_class_seq_rule_count.get()
7921
0
    }
7922
7923
    /// Array of offsets to ChainedClassSequenceRule tables, from
7924
    /// beginning of ChainedClassSequenceRuleSet2
7925
0
    pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset24>] {
7926
0
        let range = self.chained_class_seq_rule_offsets_byte_range();
7927
0
        self.offset_data()
7928
0
            .read_array(range)
7929
0
            .ok()
7930
0
            .unwrap_or_default()
7931
0
    }
7932
7933
    /// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets].
7934
0
    pub fn chained_class_seq_rules(
7935
0
        &self,
7936
0
    ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset24> {
7937
0
        let data = self.offset_data();
7938
0
        let offsets = self.chained_class_seq_rule_offsets();
7939
0
        ArrayOfOffsets::new(offsets, data, ())
7940
0
    }
7941
7942
0
    pub fn chained_class_seq_rule_count_byte_range(&self) -> Range<usize> {
7943
0
        let start = 0;
7944
0
        let end = start + u16::RAW_BYTE_LEN;
7945
0
        start..end
7946
0
    }
7947
7948
0
    pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
7949
0
        let chained_class_seq_rule_count = self.chained_class_seq_rule_count();
7950
0
        let start = self.chained_class_seq_rule_count_byte_range().end;
7951
0
        let end = start
7952
0
            + (transforms::to_usize(chained_class_seq_rule_count))
7953
0
                .saturating_mul(Offset24::RAW_BYTE_LEN);
7954
0
        start..end
7955
0
    }
7956
}
7957
7958
const _: () = assert!(FontData::default_data_long_enough(
7959
    ChainedClassSequenceRuleSet2::MIN_SIZE
7960
));
7961
7962
impl Default for ChainedClassSequenceRuleSet2<'_> {
7963
0
    fn default() -> Self {
7964
        Self {
7965
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
7966
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
7967
        }
7968
0
    }
7969
}
7970
7971
impl<'a, T> MinByteRange<'a> for LookupList2<'a, T> {
7972
0
    fn min_byte_range(&self) -> Range<usize> {
7973
0
        0..self.lookup_offsets_byte_range().end
7974
0
    }
7975
0
    fn min_table_bytes(&self) -> &'a [u8] {
7976
0
        let range = self.min_byte_range();
7977
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
7978
0
    }
7979
}
7980
7981
impl<T> ReadArgs for LookupList2<'_, T> {
7982
    type Args = ();
7983
}
7984
7985
impl<'a, T> FontRead<'a> for LookupList2<'a, T> {
7986
7
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7987
        #[allow(clippy::absurd_extreme_comparisons)]
7988
7
        if data.len() < Self::MIN_SIZE {
7989
1
            return Err(ReadError::OutOfBounds);
7990
6
        }
7991
6
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7992
0
            return Err(ReadError::OutOfBounds);
7993
        };
7994
6
        Ok(Self {
7995
6
            data,
7996
6
            offset_type: std::marker::PhantomData,
7997
6
        })
7998
7
    }
<read_fonts::tables::layout::LookupList2<read_fonts::tables::gpos::PositionLookup> as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
7986
5
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7987
        #[allow(clippy::absurd_extreme_comparisons)]
7988
5
        if data.len() < Self::MIN_SIZE {
7989
0
            return Err(ReadError::OutOfBounds);
7990
5
        }
7991
5
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7992
0
            return Err(ReadError::OutOfBounds);
7993
        };
7994
5
        Ok(Self {
7995
5
            data,
7996
5
            offset_type: std::marker::PhantomData,
7997
5
        })
7998
5
    }
<read_fonts::tables::layout::LookupList2<read_fonts::tables::gsub::SubstitutionLookup> as read_fonts::read::FontRead>::read_with_args
Line
Count
Source
7986
2
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
7987
        #[allow(clippy::absurd_extreme_comparisons)]
7988
2
        if data.len() < Self::MIN_SIZE {
7989
1
            return Err(ReadError::OutOfBounds);
7990
1
        }
7991
1
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
7992
0
            return Err(ReadError::OutOfBounds);
7993
        };
7994
1
        Ok(Self {
7995
1
            data,
7996
1
            offset_type: std::marker::PhantomData,
7997
1
        })
7998
2
    }
7999
}
8000
8001
impl<'a, T> LookupList2<'a, T> {
8002
    #[allow(dead_code)]
8003
    /// Replace the specific generic type on this implementation with `()`
8004
0
    pub(crate) fn of_unit_type(&self) -> LookupList2<'a, ()> {
8005
0
        LookupList2 {
8006
0
            data: self.data,
8007
0
            offset_type: std::marker::PhantomData,
8008
0
        }
8009
0
    }
8010
}
8011
8012
/// The fields at the start of the table, which are read directly.
8013
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
8014
#[repr(C, packed)]
8015
#[doc(hidden)]
8016
pub struct LookupList2FixedHeader {
8017
    pub lookup_count: BigEndian<u16>,
8018
}
8019
8020
#[allow(clippy::absurd_extreme_comparisons)]
8021
const _: () = assert!(std::mem::size_of::<LookupList2FixedHeader>() <= LookupList2::<()>::MIN_SIZE);
8022
8023
/// LookupList2 (ISO/IEC 14496-22:2026).
8024
#[derive(Clone)]
8025
pub struct LookupList2<'a, T = ()> {
8026
    data: TableDataRef<'a, LookupList2FixedHeader>,
8027
    offset_type: std::marker::PhantomData<*const T>,
8028
}
8029
8030
#[allow(clippy::needless_lifetimes)]
8031
impl<'a, T> LookupList2<'a, T> {
8032
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
8033
    basic_table_impls!(impl_the_methods);
8034
8035
    /// Number of lookups in this table
8036
6
    pub fn lookup_count(&self) -> u16 {
8037
6
        self.data.header().lookup_count.get()
8038
6
    }
<read_fonts::tables::layout::LookupList2<read_fonts::tables::gpos::PositionLookup>>::lookup_count
Line
Count
Source
8036
5
    pub fn lookup_count(&self) -> u16 {
8037
5
        self.data.header().lookup_count.get()
8038
5
    }
<read_fonts::tables::layout::LookupList2<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_count
Line
Count
Source
8036
1
    pub fn lookup_count(&self) -> u16 {
8037
1
        self.data.header().lookup_count.get()
8038
1
    }
8039
8040
    /// Array of offsets to Lookup tables, from beginning of LookupList2
8041
    /// — zero based (first lookup is Lookup index = 0)
8042
0
    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset32>] {
8043
0
        let range = self.lookup_offsets_byte_range();
8044
0
        self.offset_data()
8045
0
            .read_array(range)
8046
0
            .ok()
8047
0
            .unwrap_or_default()
8048
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gpos::PositionLookup>>::lookup_offsets
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_offsets
8049
8050
    /// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets].
8051
0
    pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset32>
8052
0
    where
8053
0
        T: FontRead<'a, Args = ()>,
8054
    {
8055
0
        let data = self.offset_data();
8056
0
        let offsets = self.lookup_offsets();
8057
0
        ArrayOfOffsets::new(offsets, data, ())
8058
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gpos::PositionLookup>>::lookups
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gsub::SubstitutionLookup>>::lookups
8059
8060
0
    pub fn lookup_count_byte_range(&self) -> Range<usize> {
8061
0
        let start = 0;
8062
0
        let end = start + u16::RAW_BYTE_LEN;
8063
0
        start..end
8064
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gpos::PositionLookup>>::lookup_count_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_count_byte_range
8065
8066
0
    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
8067
0
        let lookup_count = self.lookup_count();
8068
0
        let start = self.lookup_count_byte_range().end;
8069
0
        let end =
8070
0
            start + (transforms::to_usize(lookup_count)).saturating_mul(Offset32::RAW_BYTE_LEN);
8071
0
        start..end
8072
0
    }
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gpos::PositionLookup>>::lookup_offsets_byte_range
Unexecuted instantiation: <read_fonts::tables::layout::LookupList2<read_fonts::tables::gsub::SubstitutionLookup>>::lookup_offsets_byte_range
8073
}
8074
8075
const _: () = assert!(FontData::default_data_long_enough(
8076
    LookupList2::<()>::MIN_SIZE
8077
));
8078
8079
impl<T> Default for LookupList2<'_, T> {
8080
0
    fn default() -> Self {
8081
        Self {
8082
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
8083
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
8084
0
            offset_type: std::marker::PhantomData,
8085
        }
8086
0
    }
8087
}