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