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