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_gdef.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 Gdef<'a> {
9
0
    fn min_byte_range(&self) -> Range<usize> {
10
0
        0..self.mark_attach_class_def_offset_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 TopLevelTable for Gdef<'_> {
19
    /// `GDEF`
20
    const TAG: Tag = Tag::new(b"GDEF");
21
}
22
23
impl ReadArgs for Gdef<'_> {
24
    type Args = ();
25
}
26
27
impl<'a> FontRead<'a> for Gdef<'a> {
28
296
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29
        #[allow(clippy::absurd_extreme_comparisons)]
30
296
        if data.len() < Self::MIN_SIZE {
31
4
            return Err(ReadError::OutOfBounds);
32
292
        }
33
292
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
34
0
            return Err(ReadError::OutOfBounds);
35
        };
36
292
        Ok(Self { data })
37
296
    }
38
}
39
40
/// The fields at the start of the table, which are read directly.
41
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
42
#[repr(C, packed)]
43
#[doc(hidden)]
44
pub struct GdefFixedHeader {
45
    pub version: BigEndian<MajorMinor>,
46
    pub glyph_class_def_offset: BigEndian<Nullable<Offset16>>,
47
    pub attach_list_offset: BigEndian<Nullable<Offset16>>,
48
    pub lig_caret_list_offset: BigEndian<Nullable<Offset16>>,
49
    pub mark_attach_class_def_offset: BigEndian<Nullable<Offset16>>,
50
}
51
52
#[allow(clippy::absurd_extreme_comparisons)]
53
const _: () = assert!(std::mem::size_of::<GdefFixedHeader>() <= Gdef::MIN_SIZE);
54
55
/// [GDEF](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#gdef-header) 1.0
56
#[derive(Clone)]
57
pub struct Gdef<'a> {
58
    data: TableDataRef<'a, GdefFixedHeader>,
59
}
60
61
#[allow(clippy::needless_lifetimes)]
62
impl<'a> Gdef<'a> {
63
    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
64
        + Offset16::RAW_BYTE_LEN
65
        + Offset16::RAW_BYTE_LEN
66
        + Offset16::RAW_BYTE_LEN
67
        + Offset16::RAW_BYTE_LEN);
68
    basic_table_impls!(impl_the_methods);
69
70
    /// The major/minor version of the GDEF table
71
6.42k
    pub fn version(&self) -> MajorMinor {
72
6.42k
        self.data.header().version.get()
73
6.42k
    }
74
75
    /// Offset to class definition table for glyph type, from beginning
76
    /// of GDEF header (may be NULL)
77
292
    pub fn glyph_class_def_offset(&self) -> Nullable<Offset16> {
78
292
        self.data.header().glyph_class_def_offset.get()
79
292
    }
80
81
    /// Offset to attachment point list table, from beginning of GDEF
82
    /// header (may be NULL)
83
0
    pub fn attach_list_offset(&self) -> Nullable<Offset16> {
84
0
        self.data.header().attach_list_offset.get()
85
0
    }
86
87
    /// Offset to ligature caret list table, from beginning of GDEF
88
    /// header (may be NULL)
89
0
    pub fn lig_caret_list_offset(&self) -> Nullable<Offset16> {
90
0
        self.data.header().lig_caret_list_offset.get()
91
0
    }
92
93
    /// Offset to class definition table for mark attachment type, from
94
    /// beginning of GDEF header (may be NULL)
95
292
    pub fn mark_attach_class_def_offset(&self) -> Nullable<Offset16> {
96
292
        self.data.header().mark_attach_class_def_offset.get()
97
292
    }
98
99
    /// Offset to the table of mark glyph set definitions, from
100
    /// beginning of GDEF header (may be NULL)
101
292
    pub fn mark_glyph_sets_def_offset(&self) -> Option<Nullable<Offset16>> {
102
292
        let range = self.mark_glyph_sets_def_offset_byte_range();
103
292
        (!range.is_empty())
104
292
            .then(|| self.offset_data().read_at(range.start).ok())
105
292
            .flatten()
106
292
    }
107
108
    /// Offset to the Item Variation Store table, from beginning of
109
    /// GDEF header (may be NULL)
110
292
    pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> {
111
292
        let range = self.item_var_store_offset_byte_range();
112
292
        (!range.is_empty())
113
292
            .then(|| self.offset_data().read_at(range.start).ok())
114
292
            .flatten()
115
292
    }
116
117
    /// Attempt to resolve [`item_var_store_offset`][Self::item_var_store_offset].
118
292
    pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
119
292
        let data = self.offset_data();
120
292
        self.item_var_store_offset().map(|x| x.resolve(data))?
121
292
    }
122
123
    /// 32-bit offset taking precedence over glyph_class_def_offset when nonzero.
124
292
    pub fn glyph_class_def2_offset(&self) -> Option<Nullable<Offset32>> {
125
292
        let range = self.glyph_class_def2_offset_byte_range();
126
292
        (!range.is_empty())
127
292
            .then(|| self.offset_data().read_at(range.start).ok())
128
292
            .flatten()
129
292
    }
130
131
    /// Attempt to resolve [`glyph_class_def2_offset`][Self::glyph_class_def2_offset].
132
0
    pub fn glyph_class_def2(&self) -> Option<Result<ClassDef<'a>, ReadError>> {
133
0
        let data = self.offset_data();
134
0
        self.glyph_class_def2_offset().map(|x| x.resolve(data))?
135
0
    }
136
137
    /// 32-bit offset taking precedence over attach_list_offset when nonzero.
138
0
    pub fn attach_list2_offset(&self) -> Option<Nullable<Offset32>> {
139
0
        let range = self.attach_list2_offset_byte_range();
140
0
        (!range.is_empty())
141
0
            .then(|| self.offset_data().read_at(range.start).ok())
142
0
            .flatten()
143
0
    }
144
145
    /// Attempt to resolve [`attach_list2_offset`][Self::attach_list2_offset].
146
0
    pub fn attach_list2(&self) -> Option<Result<AttachList<'a>, ReadError>> {
147
0
        let data = self.offset_data();
148
0
        self.attach_list2_offset().map(|x| x.resolve(data))?
149
0
    }
150
151
    /// 32-bit offset taking precedence over lig_caret_list_offset when nonzero.
152
0
    pub fn lig_caret_list2_offset(&self) -> Option<Nullable<Offset32>> {
153
0
        let range = self.lig_caret_list2_offset_byte_range();
154
0
        (!range.is_empty())
155
0
            .then(|| self.offset_data().read_at(range.start).ok())
156
0
            .flatten()
157
0
    }
158
159
    /// Attempt to resolve [`lig_caret_list2_offset`][Self::lig_caret_list2_offset].
160
0
    pub fn lig_caret_list2(&self) -> Option<Result<LigCaretList2<'a>, ReadError>> {
161
0
        let data = self.offset_data();
162
0
        self.lig_caret_list2_offset().map(|x| x.resolve(data))?
163
0
    }
164
165
    /// 32-bit offset taking precedence over mark_attach_class_def_offset when nonzero.
166
292
    pub fn mark_attach_class_def2_offset(&self) -> Option<Nullable<Offset32>> {
167
292
        let range = self.mark_attach_class_def2_offset_byte_range();
168
292
        (!range.is_empty())
169
292
            .then(|| self.offset_data().read_at(range.start).ok())
170
292
            .flatten()
171
292
    }
172
173
    /// Attempt to resolve [`mark_attach_class_def2_offset`][Self::mark_attach_class_def2_offset].
174
0
    pub fn mark_attach_class_def2(&self) -> Option<Result<ClassDef<'a>, ReadError>> {
175
0
        let data = self.offset_data();
176
0
        self.mark_attach_class_def2_offset()
177
0
            .map(|x| x.resolve(data))?
178
0
    }
179
180
    /// 32-bit offset taking precedence over mark_glyph_sets_def_offset when nonzero.
181
292
    pub fn mark_glyph_sets_def2_offset(&self) -> Option<Nullable<Offset32>> {
182
292
        let range = self.mark_glyph_sets_def2_offset_byte_range();
183
292
        (!range.is_empty())
184
292
            .then(|| self.offset_data().read_at(range.start).ok())
185
292
            .flatten()
186
292
    }
187
188
    /// Attempt to resolve [`mark_glyph_sets_def2_offset`][Self::mark_glyph_sets_def2_offset].
189
0
    pub fn mark_glyph_sets_def2(&self) -> Option<Result<MarkGlyphSets<'a>, ReadError>> {
190
0
        let data = self.offset_data();
191
0
        self.mark_glyph_sets_def2_offset()
192
0
            .map(|x| x.resolve(data))?
193
0
    }
194
195
1.46k
    pub fn version_byte_range(&self) -> Range<usize> {
196
1.46k
        let start = 0;
197
1.46k
        let end = start + MajorMinor::RAW_BYTE_LEN;
198
1.46k
        start..end
199
1.46k
    }
200
201
1.46k
    pub fn glyph_class_def_offset_byte_range(&self) -> Range<usize> {
202
1.46k
        let start = self.version_byte_range().end;
203
1.46k
        let end = start + Offset16::RAW_BYTE_LEN;
204
1.46k
        start..end
205
1.46k
    }
206
207
1.46k
    pub fn attach_list_offset_byte_range(&self) -> Range<usize> {
208
1.46k
        let start = self.glyph_class_def_offset_byte_range().end;
209
1.46k
        let end = start + Offset16::RAW_BYTE_LEN;
210
1.46k
        start..end
211
1.46k
    }
212
213
1.46k
    pub fn lig_caret_list_offset_byte_range(&self) -> Range<usize> {
214
1.46k
        let start = self.attach_list_offset_byte_range().end;
215
1.46k
        let end = start + Offset16::RAW_BYTE_LEN;
216
1.46k
        start..end
217
1.46k
    }
218
219
1.46k
    pub fn mark_attach_class_def_offset_byte_range(&self) -> Range<usize> {
220
1.46k
        let start = self.lig_caret_list_offset_byte_range().end;
221
1.46k
        let end = start + Offset16::RAW_BYTE_LEN;
222
1.46k
        start..end
223
1.46k
    }
224
225
1.46k
    pub fn mark_glyph_sets_def_offset_byte_range(&self) -> Range<usize> {
226
1.46k
        let start = self.mark_attach_class_def_offset_byte_range().end;
227
1.46k
        let end = if self.version().compatible((1u16, 2u16)) {
228
805
            start + Offset16::RAW_BYTE_LEN
229
        } else {
230
655
            start
231
        };
232
1.46k
        start..end
233
1.46k
    }
234
235
1.16k
    pub fn item_var_store_offset_byte_range(&self) -> Range<usize> {
236
1.16k
        let start = self.mark_glyph_sets_def_offset_byte_range().end;
237
1.16k
        let end = if self.version().compatible((1u16, 3u16)) {
238
640
            start + Offset32::RAW_BYTE_LEN
239
        } else {
240
528
            start
241
        };
242
1.16k
        start..end
243
1.16k
    }
244
245
876
    pub fn glyph_class_def2_offset_byte_range(&self) -> Range<usize> {
246
876
        let start = self.item_var_store_offset_byte_range().end;
247
876
        let end = if self.version().compatible((1u16, 4u16)) {
248
480
            start + Offset32::RAW_BYTE_LEN
249
        } else {
250
396
            start
251
        };
252
876
        start..end
253
876
    }
254
255
584
    pub fn attach_list2_offset_byte_range(&self) -> Range<usize> {
256
584
        let start = self.glyph_class_def2_offset_byte_range().end;
257
584
        let end = if self.version().compatible((1u16, 4u16)) {
258
320
            start + Offset32::RAW_BYTE_LEN
259
        } else {
260
264
            start
261
        };
262
584
        start..end
263
584
    }
264
265
584
    pub fn lig_caret_list2_offset_byte_range(&self) -> Range<usize> {
266
584
        let start = self.attach_list2_offset_byte_range().end;
267
584
        let end = if self.version().compatible((1u16, 4u16)) {
268
320
            start + Offset32::RAW_BYTE_LEN
269
        } else {
270
264
            start
271
        };
272
584
        start..end
273
584
    }
274
275
584
    pub fn mark_attach_class_def2_offset_byte_range(&self) -> Range<usize> {
276
584
        let start = self.lig_caret_list2_offset_byte_range().end;
277
584
        let end = if self.version().compatible((1u16, 4u16)) {
278
320
            start + Offset32::RAW_BYTE_LEN
279
        } else {
280
264
            start
281
        };
282
584
        start..end
283
584
    }
284
285
292
    pub fn mark_glyph_sets_def2_offset_byte_range(&self) -> Range<usize> {
286
292
        let start = self.mark_attach_class_def2_offset_byte_range().end;
287
292
        let end = if self.version().compatible((1u16, 4u16)) {
288
160
            start + Offset32::RAW_BYTE_LEN
289
        } else {
290
132
            start
291
        };
292
292
        start..end
293
292
    }
294
}
295
296
const _: () = assert!(FontData::default_data_long_enough(Gdef::MIN_SIZE));
297
298
impl Default for Gdef<'_> {
299
0
    fn default() -> Self {
300
        Self {
301
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
302
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
303
        }
304
0
    }
305
}
306
307
/// Used in the [Glyph Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#glyph-class-definition-table)
308
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
309
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
310
#[repr(u16)]
311
#[allow(clippy::manual_non_exhaustive)]
312
pub enum GlyphClassDef {
313
    #[default]
314
    Base = 1,
315
    Ligature = 2,
316
    Mark = 3,
317
    Component = 4,
318
    #[doc(hidden)]
319
    /// If font data is malformed we will map unknown values to this variant
320
    Unknown,
321
}
322
323
impl GlyphClassDef {
324
    /// Create from a raw scalar.
325
    ///
326
    /// This will never fail; unknown values will be mapped to the `Unknown` variant
327
0
    pub fn new(raw: u16) -> Self {
328
0
        match raw {
329
0
            1 => Self::Base,
330
0
            2 => Self::Ligature,
331
0
            3 => Self::Mark,
332
0
            4 => Self::Component,
333
0
            _ => Self::Unknown,
334
        }
335
0
    }
336
}
337
338
impl font_types::Scalar for GlyphClassDef {
339
    type Raw = <u16 as font_types::Scalar>::Raw;
340
0
    fn to_raw(self) -> Self::Raw {
341
0
        (self as u16).to_raw()
342
0
    }
343
0
    fn from_raw(raw: Self::Raw) -> Self {
344
0
        let t = <u16>::from_raw(raw);
345
0
        Self::new(t)
346
0
    }
347
}
348
349
impl<'a> MinByteRange<'a> for AttachList<'a> {
350
0
    fn min_byte_range(&self) -> Range<usize> {
351
0
        0..self.attach_point_offsets_byte_range().end
352
0
    }
353
0
    fn min_table_bytes(&self) -> &'a [u8] {
354
0
        let range = self.min_byte_range();
355
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
356
0
    }
357
}
358
359
impl ReadArgs for AttachList<'_> {
360
    type Args = ();
361
}
362
363
impl<'a> FontRead<'a> for AttachList<'a> {
364
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
365
        #[allow(clippy::absurd_extreme_comparisons)]
366
0
        if data.len() < Self::MIN_SIZE {
367
0
            return Err(ReadError::OutOfBounds);
368
0
        }
369
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
370
0
            return Err(ReadError::OutOfBounds);
371
        };
372
0
        Ok(Self { data })
373
0
    }
374
}
375
376
/// The fields at the start of the table, which are read directly.
377
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
378
#[repr(C, packed)]
379
#[doc(hidden)]
380
pub struct AttachListFixedHeader {
381
    pub coverage_offset: BigEndian<Offset16>,
382
    pub glyph_count: BigEndian<u16>,
383
}
384
385
#[allow(clippy::absurd_extreme_comparisons)]
386
const _: () = assert!(std::mem::size_of::<AttachListFixedHeader>() <= AttachList::MIN_SIZE);
387
388
/// [Attachment Point List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#attachment-point-list-table)
389
#[derive(Clone)]
390
pub struct AttachList<'a> {
391
    data: TableDataRef<'a, AttachListFixedHeader>,
392
}
393
394
#[allow(clippy::needless_lifetimes)]
395
impl<'a> AttachList<'a> {
396
    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
397
    basic_table_impls!(impl_the_methods);
398
399
    /// Offset to Coverage table - from beginning of AttachList table
400
0
    pub fn coverage_offset(&self) -> Offset16 {
401
0
        self.data.header().coverage_offset.get()
402
0
    }
403
404
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
405
0
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
406
0
        let data = self.offset_data();
407
0
        self.coverage_offset().resolve(data)
408
0
    }
409
410
    /// Number of glyphs with attachment points
411
0
    pub fn glyph_count(&self) -> u16 {
412
0
        self.data.header().glyph_count.get()
413
0
    }
414
415
    /// Array of offsets to AttachPoint tables-from beginning of
416
    /// AttachList table-in Coverage Index order
417
0
    pub fn attach_point_offsets(&self) -> &'a [BigEndian<Offset16>] {
418
0
        let range = self.attach_point_offsets_byte_range();
419
0
        self.offset_data()
420
0
            .read_array(range)
421
0
            .ok()
422
0
            .unwrap_or_default()
423
0
    }
424
425
    /// A dynamically resolving wrapper for [`attach_point_offsets`][Self::attach_point_offsets].
426
0
    pub fn attach_points(&self) -> ArrayOfOffsets<'a, AttachPoint<'a>, Offset16> {
427
0
        let data = self.offset_data();
428
0
        let offsets = self.attach_point_offsets();
429
0
        ArrayOfOffsets::new(offsets, data, ())
430
0
    }
431
432
0
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
433
0
        let start = 0;
434
0
        let end = start + Offset16::RAW_BYTE_LEN;
435
0
        start..end
436
0
    }
437
438
0
    pub fn glyph_count_byte_range(&self) -> Range<usize> {
439
0
        let start = self.coverage_offset_byte_range().end;
440
0
        let end = start + u16::RAW_BYTE_LEN;
441
0
        start..end
442
0
    }
443
444
0
    pub fn attach_point_offsets_byte_range(&self) -> Range<usize> {
445
0
        let glyph_count = self.glyph_count();
446
0
        let start = self.glyph_count_byte_range().end;
447
0
        let end =
448
0
            start + (transforms::to_usize(glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
449
0
        start..end
450
0
    }
451
}
452
453
const _: () = assert!(FontData::default_data_long_enough(AttachList::MIN_SIZE));
454
455
impl Default for AttachList<'_> {
456
0
    fn default() -> Self {
457
        Self {
458
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
459
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
460
        }
461
0
    }
462
}
463
464
impl<'a> MinByteRange<'a> for AttachPoint<'a> {
465
0
    fn min_byte_range(&self) -> Range<usize> {
466
0
        0..self.point_indices_byte_range().end
467
0
    }
468
0
    fn min_table_bytes(&self) -> &'a [u8] {
469
0
        let range = self.min_byte_range();
470
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
471
0
    }
472
}
473
474
impl ReadArgs for AttachPoint<'_> {
475
    type Args = ();
476
}
477
478
impl<'a> FontRead<'a> for AttachPoint<'a> {
479
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
480
        #[allow(clippy::absurd_extreme_comparisons)]
481
0
        if data.len() < Self::MIN_SIZE {
482
0
            return Err(ReadError::OutOfBounds);
483
0
        }
484
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
485
0
            return Err(ReadError::OutOfBounds);
486
        };
487
0
        Ok(Self { data })
488
0
    }
489
}
490
491
/// The fields at the start of the table, which are read directly.
492
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
493
#[repr(C, packed)]
494
#[doc(hidden)]
495
pub struct AttachPointFixedHeader {
496
    pub point_count: BigEndian<u16>,
497
}
498
499
#[allow(clippy::absurd_extreme_comparisons)]
500
const _: () = assert!(std::mem::size_of::<AttachPointFixedHeader>() <= AttachPoint::MIN_SIZE);
501
502
/// Part of [AttachList]
503
#[derive(Clone)]
504
pub struct AttachPoint<'a> {
505
    data: TableDataRef<'a, AttachPointFixedHeader>,
506
}
507
508
#[allow(clippy::needless_lifetimes)]
509
impl<'a> AttachPoint<'a> {
510
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
511
    basic_table_impls!(impl_the_methods);
512
513
    /// Number of attachment points on this glyph
514
0
    pub fn point_count(&self) -> u16 {
515
0
        self.data.header().point_count.get()
516
0
    }
517
518
    /// Array of contour point indices -in increasing numerical order
519
0
    pub fn point_indices(&self) -> &'a [BigEndian<u16>] {
520
0
        let range = self.point_indices_byte_range();
521
0
        self.offset_data()
522
0
            .read_array(range)
523
0
            .ok()
524
0
            .unwrap_or_default()
525
0
    }
526
527
0
    pub fn point_count_byte_range(&self) -> Range<usize> {
528
0
        let start = 0;
529
0
        let end = start + u16::RAW_BYTE_LEN;
530
0
        start..end
531
0
    }
532
533
0
    pub fn point_indices_byte_range(&self) -> Range<usize> {
534
0
        let point_count = self.point_count();
535
0
        let start = self.point_count_byte_range().end;
536
0
        let end = start + (transforms::to_usize(point_count)).saturating_mul(u16::RAW_BYTE_LEN);
537
0
        start..end
538
0
    }
539
}
540
541
const _: () = assert!(FontData::default_data_long_enough(AttachPoint::MIN_SIZE));
542
543
impl Default for AttachPoint<'_> {
544
0
    fn default() -> Self {
545
        Self {
546
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
547
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
548
        }
549
0
    }
550
}
551
552
impl<'a> MinByteRange<'a> for LigCaretList<'a> {
553
0
    fn min_byte_range(&self) -> Range<usize> {
554
0
        0..self.lig_glyph_offsets_byte_range().end
555
0
    }
556
0
    fn min_table_bytes(&self) -> &'a [u8] {
557
0
        let range = self.min_byte_range();
558
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
559
0
    }
560
}
561
562
impl ReadArgs for LigCaretList<'_> {
563
    type Args = ();
564
}
565
566
impl<'a> FontRead<'a> for LigCaretList<'a> {
567
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
568
        #[allow(clippy::absurd_extreme_comparisons)]
569
0
        if data.len() < Self::MIN_SIZE {
570
0
            return Err(ReadError::OutOfBounds);
571
0
        }
572
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
573
0
            return Err(ReadError::OutOfBounds);
574
        };
575
0
        Ok(Self { data })
576
0
    }
577
}
578
579
/// The fields at the start of the table, which are read directly.
580
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
581
#[repr(C, packed)]
582
#[doc(hidden)]
583
pub struct LigCaretListFixedHeader {
584
    pub coverage_offset: BigEndian<Offset16>,
585
    pub lig_glyph_count: BigEndian<u16>,
586
}
587
588
#[allow(clippy::absurd_extreme_comparisons)]
589
const _: () = assert!(std::mem::size_of::<LigCaretListFixedHeader>() <= LigCaretList::MIN_SIZE);
590
591
/// [Ligature Caret List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#ligature-caret-list-table)
592
#[derive(Clone)]
593
pub struct LigCaretList<'a> {
594
    data: TableDataRef<'a, LigCaretListFixedHeader>,
595
}
596
597
#[allow(clippy::needless_lifetimes)]
598
impl<'a> LigCaretList<'a> {
599
    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
600
    basic_table_impls!(impl_the_methods);
601
602
    /// Offset to Coverage table - from beginning of LigCaretList table
603
0
    pub fn coverage_offset(&self) -> Offset16 {
604
0
        self.data.header().coverage_offset.get()
605
0
    }
606
607
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
608
0
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
609
0
        let data = self.offset_data();
610
0
        self.coverage_offset().resolve(data)
611
0
    }
612
613
    /// Number of ligature glyphs
614
0
    pub fn lig_glyph_count(&self) -> u16 {
615
0
        self.data.header().lig_glyph_count.get()
616
0
    }
617
618
    /// Array of offsets to LigGlyph tables, from beginning of
619
    /// LigCaretList table —in Coverage Index order
620
0
    pub fn lig_glyph_offsets(&self) -> &'a [BigEndian<Offset16>] {
621
0
        let range = self.lig_glyph_offsets_byte_range();
622
0
        self.offset_data()
623
0
            .read_array(range)
624
0
            .ok()
625
0
            .unwrap_or_default()
626
0
    }
627
628
    /// A dynamically resolving wrapper for [`lig_glyph_offsets`][Self::lig_glyph_offsets].
629
0
    pub fn lig_glyphs(&self) -> ArrayOfOffsets<'a, LigGlyph<'a>, Offset16> {
630
0
        let data = self.offset_data();
631
0
        let offsets = self.lig_glyph_offsets();
632
0
        ArrayOfOffsets::new(offsets, data, ())
633
0
    }
634
635
0
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
636
0
        let start = 0;
637
0
        let end = start + Offset16::RAW_BYTE_LEN;
638
0
        start..end
639
0
    }
640
641
0
    pub fn lig_glyph_count_byte_range(&self) -> Range<usize> {
642
0
        let start = self.coverage_offset_byte_range().end;
643
0
        let end = start + u16::RAW_BYTE_LEN;
644
0
        start..end
645
0
    }
646
647
0
    pub fn lig_glyph_offsets_byte_range(&self) -> Range<usize> {
648
0
        let lig_glyph_count = self.lig_glyph_count();
649
0
        let start = self.lig_glyph_count_byte_range().end;
650
0
        let end =
651
0
            start + (transforms::to_usize(lig_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
652
0
        start..end
653
0
    }
654
}
655
656
const _: () = assert!(FontData::default_data_long_enough(LigCaretList::MIN_SIZE));
657
658
impl Default for LigCaretList<'_> {
659
0
    fn default() -> Self {
660
        Self {
661
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
662
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
663
        }
664
0
    }
665
}
666
667
impl<'a> MinByteRange<'a> for LigGlyph<'a> {
668
0
    fn min_byte_range(&self) -> Range<usize> {
669
0
        0..self.caret_value_offsets_byte_range().end
670
0
    }
671
0
    fn min_table_bytes(&self) -> &'a [u8] {
672
0
        let range = self.min_byte_range();
673
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
674
0
    }
675
}
676
677
impl ReadArgs for LigGlyph<'_> {
678
    type Args = ();
679
}
680
681
impl<'a> FontRead<'a> for LigGlyph<'a> {
682
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
683
        #[allow(clippy::absurd_extreme_comparisons)]
684
0
        if data.len() < Self::MIN_SIZE {
685
0
            return Err(ReadError::OutOfBounds);
686
0
        }
687
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
688
0
            return Err(ReadError::OutOfBounds);
689
        };
690
0
        Ok(Self { data })
691
0
    }
692
}
693
694
/// The fields at the start of the table, which are read directly.
695
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
696
#[repr(C, packed)]
697
#[doc(hidden)]
698
pub struct LigGlyphFixedHeader {
699
    pub caret_count: BigEndian<u16>,
700
}
701
702
#[allow(clippy::absurd_extreme_comparisons)]
703
const _: () = assert!(std::mem::size_of::<LigGlyphFixedHeader>() <= LigGlyph::MIN_SIZE);
704
705
/// [Ligature Glyph Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#ligature-glyph-table)
706
#[derive(Clone)]
707
pub struct LigGlyph<'a> {
708
    data: TableDataRef<'a, LigGlyphFixedHeader>,
709
}
710
711
#[allow(clippy::needless_lifetimes)]
712
impl<'a> LigGlyph<'a> {
713
    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
714
    basic_table_impls!(impl_the_methods);
715
716
    /// Number of CaretValue tables for this ligature (components - 1)
717
0
    pub fn caret_count(&self) -> u16 {
718
0
        self.data.header().caret_count.get()
719
0
    }
720
721
    /// Array of offsets to CaretValue tables, from beginning of
722
    /// LigGlyph table — in increasing coordinate order
723
0
    pub fn caret_value_offsets(&self) -> &'a [BigEndian<Offset16>] {
724
0
        let range = self.caret_value_offsets_byte_range();
725
0
        self.offset_data()
726
0
            .read_array(range)
727
0
            .ok()
728
0
            .unwrap_or_default()
729
0
    }
730
731
    /// A dynamically resolving wrapper for [`caret_value_offsets`][Self::caret_value_offsets].
732
0
    pub fn caret_values(&self) -> ArrayOfOffsets<'a, CaretValue<'a>, Offset16> {
733
0
        let data = self.offset_data();
734
0
        let offsets = self.caret_value_offsets();
735
0
        ArrayOfOffsets::new(offsets, data, ())
736
0
    }
737
738
0
    pub fn caret_count_byte_range(&self) -> Range<usize> {
739
0
        let start = 0;
740
0
        let end = start + u16::RAW_BYTE_LEN;
741
0
        start..end
742
0
    }
743
744
0
    pub fn caret_value_offsets_byte_range(&self) -> Range<usize> {
745
0
        let caret_count = self.caret_count();
746
0
        let start = self.caret_count_byte_range().end;
747
0
        let end =
748
0
            start + (transforms::to_usize(caret_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
749
0
        start..end
750
0
    }
751
}
752
753
const _: () = assert!(FontData::default_data_long_enough(LigGlyph::MIN_SIZE));
754
755
impl Default for LigGlyph<'_> {
756
0
    fn default() -> Self {
757
        Self {
758
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
759
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
760
        }
761
0
    }
762
}
763
764
/// [Caret Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caret-value-tables)
765
#[derive(Clone)]
766
pub enum CaretValue<'a> {
767
    Format1(CaretValueFormat1<'a>),
768
    Format2(CaretValueFormat2<'a>),
769
    Format3(CaretValueFormat3<'a>),
770
}
771
772
impl Default for CaretValue<'_> {
773
0
    fn default() -> Self {
774
0
        Self::Format1(Default::default())
775
0
    }
776
}
777
778
impl<'a> CaretValue<'a> {
779
    ///Return the `FontData` used to resolve offsets for this table.
780
0
    pub fn offset_data(&self) -> FontData<'a> {
781
0
        match self {
782
0
            Self::Format1(item) => item.offset_data(),
783
0
            Self::Format2(item) => item.offset_data(),
784
0
            Self::Format3(item) => item.offset_data(),
785
        }
786
0
    }
787
788
    /// Format identifier: format = 1
789
0
    pub fn caret_value_format(&self) -> u16 {
790
0
        match self {
791
0
            Self::Format1(item) => item.caret_value_format(),
792
0
            Self::Format2(item) => item.caret_value_format(),
793
0
            Self::Format3(item) => item.caret_value_format(),
794
        }
795
0
    }
796
}
797
798
impl ReadArgs for CaretValue<'_> {
799
    type Args = ();
800
}
801
802
impl<'a> FontRead<'a> for CaretValue<'a> {
803
    #[inline]
804
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
805
0
        let format: u16 = data.read_at(0usize)?;
806
0
        match format {
807
0
            CaretValueFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
808
0
            CaretValueFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
809
0
            CaretValueFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
810
0
            other => Err(ReadError::InvalidFormat(other.into())),
811
        }
812
0
    }
813
}
814
815
impl<'a> MinByteRange<'a> for CaretValue<'a> {
816
0
    fn min_byte_range(&self) -> Range<usize> {
817
0
        match self {
818
0
            Self::Format1(item) => item.min_byte_range(),
819
0
            Self::Format2(item) => item.min_byte_range(),
820
0
            Self::Format3(item) => item.min_byte_range(),
821
        }
822
0
    }
823
0
    fn min_table_bytes(&self) -> &'a [u8] {
824
0
        match self {
825
0
            Self::Format1(item) => item.min_table_bytes(),
826
0
            Self::Format2(item) => item.min_table_bytes(),
827
0
            Self::Format3(item) => item.min_table_bytes(),
828
        }
829
0
    }
830
}
831
832
impl Format<u16> for CaretValueFormat1<'_> {
833
    const FORMAT: u16 = 1;
834
}
835
836
impl<'a> MinByteRange<'a> for CaretValueFormat1<'a> {
837
0
    fn min_byte_range(&self) -> Range<usize> {
838
0
        0..self.coordinate_byte_range().end
839
0
    }
840
0
    fn min_table_bytes(&self) -> &'a [u8] {
841
0
        let range = self.min_byte_range();
842
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
843
0
    }
844
}
845
846
impl ReadArgs for CaretValueFormat1<'_> {
847
    type Args = ();
848
}
849
850
impl<'a> FontRead<'a> for CaretValueFormat1<'a> {
851
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
852
        #[allow(clippy::absurd_extreme_comparisons)]
853
0
        if data.len() < Self::MIN_SIZE {
854
0
            return Err(ReadError::OutOfBounds);
855
0
        }
856
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
857
0
            return Err(ReadError::OutOfBounds);
858
        };
859
0
        Ok(Self { data })
860
0
    }
861
}
862
863
/// The fields at the start of the table, which are read directly.
864
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
865
#[repr(C, packed)]
866
#[doc(hidden)]
867
pub struct CaretValueFormat1FixedHeader {
868
    pub caret_value_format: BigEndian<u16>,
869
    pub coordinate: BigEndian<i16>,
870
}
871
872
#[allow(clippy::absurd_extreme_comparisons)]
873
const _: () =
874
    assert!(std::mem::size_of::<CaretValueFormat1FixedHeader>() <= CaretValueFormat1::MIN_SIZE);
875
876
/// [CaretValue Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-1)
877
#[derive(Clone)]
878
pub struct CaretValueFormat1<'a> {
879
    data: TableDataRef<'a, CaretValueFormat1FixedHeader>,
880
}
881
882
#[allow(clippy::needless_lifetimes)]
883
impl<'a> CaretValueFormat1<'a> {
884
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
885
    basic_table_impls!(impl_the_methods);
886
887
    /// Format identifier: format = 1
888
0
    pub fn caret_value_format(&self) -> u16 {
889
0
        self.data.header().caret_value_format.get()
890
0
    }
891
892
    /// X or Y value, in design units
893
0
    pub fn coordinate(&self) -> i16 {
894
0
        self.data.header().coordinate.get()
895
0
    }
896
897
0
    pub fn caret_value_format_byte_range(&self) -> Range<usize> {
898
0
        let start = 0;
899
0
        let end = start + u16::RAW_BYTE_LEN;
900
0
        start..end
901
0
    }
902
903
0
    pub fn coordinate_byte_range(&self) -> Range<usize> {
904
0
        let start = self.caret_value_format_byte_range().end;
905
0
        let end = start + i16::RAW_BYTE_LEN;
906
0
        start..end
907
0
    }
908
}
909
910
const _: () = assert!(FontData::default_data_long_enough(
911
    CaretValueFormat1::MIN_SIZE
912
));
913
914
impl Default for CaretValueFormat1<'_> {
915
0
    fn default() -> Self {
916
        Self {
917
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
918
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
919
        }
920
0
    }
921
}
922
923
impl Format<u16> for CaretValueFormat2<'_> {
924
    const FORMAT: u16 = 2;
925
}
926
927
impl<'a> MinByteRange<'a> for CaretValueFormat2<'a> {
928
0
    fn min_byte_range(&self) -> Range<usize> {
929
0
        0..self.caret_value_point_index_byte_range().end
930
0
    }
931
0
    fn min_table_bytes(&self) -> &'a [u8] {
932
0
        let range = self.min_byte_range();
933
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
934
0
    }
935
}
936
937
impl ReadArgs for CaretValueFormat2<'_> {
938
    type Args = ();
939
}
940
941
impl<'a> FontRead<'a> for CaretValueFormat2<'a> {
942
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
943
        #[allow(clippy::absurd_extreme_comparisons)]
944
0
        if data.len() < Self::MIN_SIZE {
945
0
            return Err(ReadError::OutOfBounds);
946
0
        }
947
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
948
0
            return Err(ReadError::OutOfBounds);
949
        };
950
0
        Ok(Self { data })
951
0
    }
952
}
953
954
/// The fields at the start of the table, which are read directly.
955
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
956
#[repr(C, packed)]
957
#[doc(hidden)]
958
pub struct CaretValueFormat2FixedHeader {
959
    pub caret_value_format: BigEndian<u16>,
960
    pub caret_value_point_index: BigEndian<u16>,
961
}
962
963
#[allow(clippy::absurd_extreme_comparisons)]
964
const _: () =
965
    assert!(std::mem::size_of::<CaretValueFormat2FixedHeader>() <= CaretValueFormat2::MIN_SIZE);
966
967
/// [CaretValue Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-2)
968
#[derive(Clone)]
969
pub struct CaretValueFormat2<'a> {
970
    data: TableDataRef<'a, CaretValueFormat2FixedHeader>,
971
}
972
973
#[allow(clippy::needless_lifetimes)]
974
impl<'a> CaretValueFormat2<'a> {
975
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
976
    basic_table_impls!(impl_the_methods);
977
978
    /// Format identifier: format = 2
979
0
    pub fn caret_value_format(&self) -> u16 {
980
0
        self.data.header().caret_value_format.get()
981
0
    }
982
983
    /// Contour point index on glyph
984
0
    pub fn caret_value_point_index(&self) -> u16 {
985
0
        self.data.header().caret_value_point_index.get()
986
0
    }
987
988
0
    pub fn caret_value_format_byte_range(&self) -> Range<usize> {
989
0
        let start = 0;
990
0
        let end = start + u16::RAW_BYTE_LEN;
991
0
        start..end
992
0
    }
993
994
0
    pub fn caret_value_point_index_byte_range(&self) -> Range<usize> {
995
0
        let start = self.caret_value_format_byte_range().end;
996
0
        let end = start + u16::RAW_BYTE_LEN;
997
0
        start..end
998
0
    }
999
}
1000
1001
impl Format<u16> for CaretValueFormat3<'_> {
1002
    const FORMAT: u16 = 3;
1003
}
1004
1005
impl<'a> MinByteRange<'a> for CaretValueFormat3<'a> {
1006
0
    fn min_byte_range(&self) -> Range<usize> {
1007
0
        0..self.device_offset_byte_range().end
1008
0
    }
1009
0
    fn min_table_bytes(&self) -> &'a [u8] {
1010
0
        let range = self.min_byte_range();
1011
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1012
0
    }
1013
}
1014
1015
impl ReadArgs for CaretValueFormat3<'_> {
1016
    type Args = ();
1017
}
1018
1019
impl<'a> FontRead<'a> for CaretValueFormat3<'a> {
1020
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1021
        #[allow(clippy::absurd_extreme_comparisons)]
1022
0
        if data.len() < Self::MIN_SIZE {
1023
0
            return Err(ReadError::OutOfBounds);
1024
0
        }
1025
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1026
0
            return Err(ReadError::OutOfBounds);
1027
        };
1028
0
        Ok(Self { data })
1029
0
    }
1030
}
1031
1032
/// The fields at the start of the table, which are read directly.
1033
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1034
#[repr(C, packed)]
1035
#[doc(hidden)]
1036
pub struct CaretValueFormat3FixedHeader {
1037
    pub caret_value_format: BigEndian<u16>,
1038
    pub coordinate: BigEndian<i16>,
1039
    pub device_offset: BigEndian<Offset16>,
1040
}
1041
1042
#[allow(clippy::absurd_extreme_comparisons)]
1043
const _: () =
1044
    assert!(std::mem::size_of::<CaretValueFormat3FixedHeader>() <= CaretValueFormat3::MIN_SIZE);
1045
1046
/// [CaretValue Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-3)
1047
#[derive(Clone)]
1048
pub struct CaretValueFormat3<'a> {
1049
    data: TableDataRef<'a, CaretValueFormat3FixedHeader>,
1050
}
1051
1052
#[allow(clippy::needless_lifetimes)]
1053
impl<'a> CaretValueFormat3<'a> {
1054
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1055
    basic_table_impls!(impl_the_methods);
1056
1057
    /// Format identifier-format = 3
1058
0
    pub fn caret_value_format(&self) -> u16 {
1059
0
        self.data.header().caret_value_format.get()
1060
0
    }
1061
1062
    /// X or Y value, in design units
1063
0
    pub fn coordinate(&self) -> i16 {
1064
0
        self.data.header().coordinate.get()
1065
0
    }
1066
1067
    /// Offset to Device table (non-variable font) / Variation Index
1068
    /// table (variable font) for X or Y value-from beginning of
1069
    /// CaretValue table
1070
0
    pub fn device_offset(&self) -> Offset16 {
1071
0
        self.data.header().device_offset.get()
1072
0
    }
1073
1074
    /// Attempt to resolve [`device_offset`][Self::device_offset].
1075
0
    pub fn device(&self) -> Result<DeviceOrVariationIndex<'a>, ReadError> {
1076
0
        let data = self.offset_data();
1077
0
        self.device_offset().resolve(data)
1078
0
    }
1079
1080
0
    pub fn caret_value_format_byte_range(&self) -> Range<usize> {
1081
0
        let start = 0;
1082
0
        let end = start + u16::RAW_BYTE_LEN;
1083
0
        start..end
1084
0
    }
1085
1086
0
    pub fn coordinate_byte_range(&self) -> Range<usize> {
1087
0
        let start = self.caret_value_format_byte_range().end;
1088
0
        let end = start + i16::RAW_BYTE_LEN;
1089
0
        start..end
1090
0
    }
1091
1092
0
    pub fn device_offset_byte_range(&self) -> Range<usize> {
1093
0
        let start = self.coordinate_byte_range().end;
1094
0
        let end = start + Offset16::RAW_BYTE_LEN;
1095
0
        start..end
1096
0
    }
1097
}
1098
1099
impl Format<u16> for MarkGlyphSets<'_> {
1100
    const FORMAT: u16 = 1;
1101
}
1102
1103
impl<'a> MinByteRange<'a> for MarkGlyphSets<'a> {
1104
0
    fn min_byte_range(&self) -> Range<usize> {
1105
0
        0..self.coverage_offsets_byte_range().end
1106
0
    }
1107
0
    fn min_table_bytes(&self) -> &'a [u8] {
1108
0
        let range = self.min_byte_range();
1109
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1110
0
    }
1111
}
1112
1113
impl ReadArgs for MarkGlyphSets<'_> {
1114
    type Args = ();
1115
}
1116
1117
impl<'a> FontRead<'a> for MarkGlyphSets<'a> {
1118
72
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1119
        #[allow(clippy::absurd_extreme_comparisons)]
1120
72
        if data.len() < Self::MIN_SIZE {
1121
0
            return Err(ReadError::OutOfBounds);
1122
72
        }
1123
72
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1124
0
            return Err(ReadError::OutOfBounds);
1125
        };
1126
72
        Ok(Self { data })
1127
72
    }
1128
}
1129
1130
/// The fields at the start of the table, which are read directly.
1131
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1132
#[repr(C, packed)]
1133
#[doc(hidden)]
1134
pub struct MarkGlyphSetsFixedHeader {
1135
    pub format: BigEndian<u16>,
1136
    pub mark_glyph_set_count: BigEndian<u16>,
1137
}
1138
1139
#[allow(clippy::absurd_extreme_comparisons)]
1140
const _: () = assert!(std::mem::size_of::<MarkGlyphSetsFixedHeader>() <= MarkGlyphSets::MIN_SIZE);
1141
1142
/// [Mark Glyph Sets Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#mark-glyph-sets-table)
1143
#[derive(Clone)]
1144
pub struct MarkGlyphSets<'a> {
1145
    data: TableDataRef<'a, MarkGlyphSetsFixedHeader>,
1146
}
1147
1148
#[allow(clippy::needless_lifetimes)]
1149
impl<'a> MarkGlyphSets<'a> {
1150
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1151
    basic_table_impls!(impl_the_methods);
1152
1153
    /// Format identifier == 1
1154
0
    pub fn format(&self) -> u16 {
1155
0
        self.data.header().format.get()
1156
0
    }
1157
1158
    /// Number of mark glyph sets defined
1159
72
    pub fn mark_glyph_set_count(&self) -> u16 {
1160
72
        self.data.header().mark_glyph_set_count.get()
1161
72
    }
1162
1163
    /// Array of offsets to mark glyph set coverage tables, from the
1164
    /// start of the MarkGlyphSets table.
1165
72
    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset32>] {
1166
72
        let range = self.coverage_offsets_byte_range();
1167
72
        self.offset_data()
1168
72
            .read_array(range)
1169
72
            .ok()
1170
72
            .unwrap_or_default()
1171
72
    }
1172
1173
    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
1174
72
    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset32> {
1175
72
        let data = self.offset_data();
1176
72
        let offsets = self.coverage_offsets();
1177
72
        ArrayOfOffsets::new(offsets, data, ())
1178
72
    }
1179
1180
72
    pub fn format_byte_range(&self) -> Range<usize> {
1181
72
        let start = 0;
1182
72
        let end = start + u16::RAW_BYTE_LEN;
1183
72
        start..end
1184
72
    }
1185
1186
72
    pub fn mark_glyph_set_count_byte_range(&self) -> Range<usize> {
1187
72
        let start = self.format_byte_range().end;
1188
72
        let end = start + u16::RAW_BYTE_LEN;
1189
72
        start..end
1190
72
    }
1191
1192
72
    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
1193
72
        let mark_glyph_set_count = self.mark_glyph_set_count();
1194
72
        let start = self.mark_glyph_set_count_byte_range().end;
1195
72
        let end = start
1196
72
            + (transforms::to_usize(mark_glyph_set_count)).saturating_mul(Offset32::RAW_BYTE_LEN);
1197
72
        start..end
1198
72
    }
1199
}
1200
1201
const _: () = assert!(FontData::default_data_long_enough(MarkGlyphSets::MIN_SIZE));
1202
1203
impl Default for MarkGlyphSets<'_> {
1204
0
    fn default() -> Self {
1205
        Self {
1206
0
            data: TableDataRef::new(FontData::default_format_1_u16_table_data().as_bytes())
1207
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1208
        }
1209
0
    }
1210
}
1211
1212
impl<'a> MinByteRange<'a> for LigCaretList2<'a> {
1213
0
    fn min_byte_range(&self) -> Range<usize> {
1214
0
        0..self.lig_glyph_offsets_byte_range().end
1215
0
    }
1216
0
    fn min_table_bytes(&self) -> &'a [u8] {
1217
0
        let range = self.min_byte_range();
1218
0
        self.offset_data().as_bytes().get(range).unwrap_or_default()
1219
0
    }
1220
}
1221
1222
impl ReadArgs for LigCaretList2<'_> {
1223
    type Args = ();
1224
}
1225
1226
impl<'a> FontRead<'a> for LigCaretList2<'a> {
1227
0
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1228
        #[allow(clippy::absurd_extreme_comparisons)]
1229
0
        if data.len() < Self::MIN_SIZE {
1230
0
            return Err(ReadError::OutOfBounds);
1231
0
        }
1232
0
        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1233
0
            return Err(ReadError::OutOfBounds);
1234
        };
1235
0
        Ok(Self { data })
1236
0
    }
1237
}
1238
1239
/// The fields at the start of the table, which are read directly.
1240
#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1241
#[repr(C, packed)]
1242
#[doc(hidden)]
1243
pub struct LigCaretList2FixedHeader {
1244
    pub coverage_offset: BigEndian<Offset32>,
1245
    pub lig_glyph_count: BigEndian<Uint24>,
1246
}
1247
1248
#[allow(clippy::absurd_extreme_comparisons)]
1249
const _: () = assert!(std::mem::size_of::<LigCaretList2FixedHeader>() <= LigCaretList2::MIN_SIZE);
1250
1251
/// LigCaretList2 (ISO/IEC 14496-22:2026).
1252
#[derive(Clone)]
1253
pub struct LigCaretList2<'a> {
1254
    data: TableDataRef<'a, LigCaretList2FixedHeader>,
1255
}
1256
1257
#[allow(clippy::needless_lifetimes)]
1258
impl<'a> LigCaretList2<'a> {
1259
    pub const MIN_SIZE: usize = (Offset32::RAW_BYTE_LEN + Uint24::RAW_BYTE_LEN);
1260
    basic_table_impls!(impl_the_methods);
1261
1262
    /// Offset to Coverage table - from beginning of LigCaretList2 table
1263
0
    pub fn coverage_offset(&self) -> Offset32 {
1264
0
        self.data.header().coverage_offset.get()
1265
0
    }
1266
1267
    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1268
0
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1269
0
        let data = self.offset_data();
1270
0
        self.coverage_offset().resolve(data)
1271
0
    }
1272
1273
    /// Number of ligature glyphs
1274
0
    pub fn lig_glyph_count(&self) -> Uint24 {
1275
0
        self.data.header().lig_glyph_count.get()
1276
0
    }
1277
1278
    /// Array of offsets to LigGlyph tables, from beginning of
1279
    /// LigCaretList2 table —in Coverage Index order
1280
0
    pub fn lig_glyph_offsets(&self) -> &'a [BigEndian<Offset24>] {
1281
0
        let range = self.lig_glyph_offsets_byte_range();
1282
0
        self.offset_data()
1283
0
            .read_array(range)
1284
0
            .ok()
1285
0
            .unwrap_or_default()
1286
0
    }
1287
1288
    /// A dynamically resolving wrapper for [`lig_glyph_offsets`][Self::lig_glyph_offsets].
1289
0
    pub fn lig_glyphs(&self) -> ArrayOfOffsets<'a, LigGlyph<'a>, Offset24> {
1290
0
        let data = self.offset_data();
1291
0
        let offsets = self.lig_glyph_offsets();
1292
0
        ArrayOfOffsets::new(offsets, data, ())
1293
0
    }
1294
1295
0
    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1296
0
        let start = 0;
1297
0
        let end = start + Offset32::RAW_BYTE_LEN;
1298
0
        start..end
1299
0
    }
1300
1301
0
    pub fn lig_glyph_count_byte_range(&self) -> Range<usize> {
1302
0
        let start = self.coverage_offset_byte_range().end;
1303
0
        let end = start + Uint24::RAW_BYTE_LEN;
1304
0
        start..end
1305
0
    }
1306
1307
0
    pub fn lig_glyph_offsets_byte_range(&self) -> Range<usize> {
1308
0
        let lig_glyph_count = self.lig_glyph_count();
1309
0
        let start = self.lig_glyph_count_byte_range().end;
1310
0
        let end =
1311
0
            start + (transforms::to_usize(lig_glyph_count)).saturating_mul(Offset24::RAW_BYTE_LEN);
1312
0
        start..end
1313
0
    }
1314
}
1315
1316
const _: () = assert!(FontData::default_data_long_enough(LigCaretList2::MIN_SIZE));
1317
1318
impl Default for LigCaretList2<'_> {
1319
0
    fn default() -> Self {
1320
        Self {
1321
0
            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1322
0
                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1323
        }
1324
0
    }
1325
}