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