Skip to main content

read_fonts/generated/
generated_gdef.rs

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