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