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 + (glyph_count as usize).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 + (point_count as usize).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..start + (lig_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
571    }
572}
573
574const _: () = assert!(FontData::default_data_long_enough(LigCaretList::MIN_SIZE));
575
576impl Default for LigCaretList<'_> {
577    fn default() -> Self {
578        Self {
579            data: FontData::default_table_data(),
580        }
581    }
582}
583
584#[cfg(feature = "experimental_traverse")]
585impl<'a> SomeTable<'a> for LigCaretList<'a> {
586    fn type_name(&self) -> &str {
587        "LigCaretList"
588    }
589    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
590        match idx {
591            0usize => Some(Field::new(
592                "coverage_offset",
593                FieldType::offset(self.coverage_offset(), self.coverage()),
594            )),
595            1usize => Some(Field::new("lig_glyph_count", self.lig_glyph_count())),
596            2usize => Some(Field::new(
597                "lig_glyph_offsets",
598                FieldType::from(self.lig_glyphs()),
599            )),
600            _ => None,
601        }
602    }
603}
604
605#[cfg(feature = "experimental_traverse")]
606#[allow(clippy::needless_lifetimes)]
607impl<'a> std::fmt::Debug for LigCaretList<'a> {
608    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
609        (self as &dyn SomeTable<'a>).fmt(f)
610    }
611}
612
613impl<'a> MinByteRange<'a> for LigGlyph<'a> {
614    fn min_byte_range(&self) -> Range<usize> {
615        0..self.caret_value_offsets_byte_range().end
616    }
617    fn min_table_bytes(&self) -> &'a [u8] {
618        let range = self.min_byte_range();
619        self.data.as_bytes().get(range).unwrap_or_default()
620    }
621}
622
623impl<'a> FontRead<'a> for LigGlyph<'a> {
624    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
625        #[allow(clippy::absurd_extreme_comparisons)]
626        if data.len() < Self::MIN_SIZE {
627            return Err(ReadError::OutOfBounds);
628        }
629        Ok(Self { data })
630    }
631}
632
633/// [Ligature Glyph Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#ligature-glyph-table)
634#[derive(Clone)]
635pub struct LigGlyph<'a> {
636    data: FontData<'a>,
637}
638
639#[allow(clippy::needless_lifetimes)]
640impl<'a> LigGlyph<'a> {
641    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
642    basic_table_impls!(impl_the_methods);
643
644    /// Number of CaretValue tables for this ligature (components - 1)
645    pub fn caret_count(&self) -> u16 {
646        let range = self.caret_count_byte_range();
647        self.data.read_at(range.start).ok().unwrap()
648    }
649
650    /// Array of offsets to CaretValue tables, from beginning of
651    /// LigGlyph table — in increasing coordinate order
652    pub fn caret_value_offsets(&self) -> &'a [BigEndian<Offset16>] {
653        let range = self.caret_value_offsets_byte_range();
654        self.data.read_array(range).ok().unwrap_or_default()
655    }
656
657    /// A dynamically resolving wrapper for [`caret_value_offsets`][Self::caret_value_offsets].
658    pub fn caret_values(&self) -> ArrayOfOffsets<'a, CaretValue<'a>, Offset16> {
659        let data = self.data;
660        let offsets = self.caret_value_offsets();
661        ArrayOfOffsets::new(offsets, data, ())
662    }
663
664    pub fn caret_count_byte_range(&self) -> Range<usize> {
665        let start = 0;
666        start..start + u16::RAW_BYTE_LEN
667    }
668
669    pub fn caret_value_offsets_byte_range(&self) -> Range<usize> {
670        let caret_count = self.caret_count();
671        let start = self.caret_count_byte_range().end;
672        start..start + (caret_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
673    }
674}
675
676const _: () = assert!(FontData::default_data_long_enough(LigGlyph::MIN_SIZE));
677
678impl Default for LigGlyph<'_> {
679    fn default() -> Self {
680        Self {
681            data: FontData::default_table_data(),
682        }
683    }
684}
685
686#[cfg(feature = "experimental_traverse")]
687impl<'a> SomeTable<'a> for LigGlyph<'a> {
688    fn type_name(&self) -> &str {
689        "LigGlyph"
690    }
691    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
692        match idx {
693            0usize => Some(Field::new("caret_count", self.caret_count())),
694            1usize => Some(Field::new(
695                "caret_value_offsets",
696                FieldType::from(self.caret_values()),
697            )),
698            _ => None,
699        }
700    }
701}
702
703#[cfg(feature = "experimental_traverse")]
704#[allow(clippy::needless_lifetimes)]
705impl<'a> std::fmt::Debug for LigGlyph<'a> {
706    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
707        (self as &dyn SomeTable<'a>).fmt(f)
708    }
709}
710
711/// [Caret Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caret-value-tables)
712#[derive(Clone)]
713pub enum CaretValue<'a> {
714    Format1(CaretValueFormat1<'a>),
715    Format2(CaretValueFormat2<'a>),
716    Format3(CaretValueFormat3<'a>),
717}
718
719impl Default for CaretValue<'_> {
720    fn default() -> Self {
721        Self::Format1(Default::default())
722    }
723}
724
725impl<'a> CaretValue<'a> {
726    ///Return the `FontData` used to resolve offsets for this table.
727    pub fn offset_data(&self) -> FontData<'a> {
728        match self {
729            Self::Format1(item) => item.offset_data(),
730            Self::Format2(item) => item.offset_data(),
731            Self::Format3(item) => item.offset_data(),
732        }
733    }
734
735    /// Format identifier: format = 1
736    pub fn caret_value_format(&self) -> u16 {
737        match self {
738            Self::Format1(item) => item.caret_value_format(),
739            Self::Format2(item) => item.caret_value_format(),
740            Self::Format3(item) => item.caret_value_format(),
741        }
742    }
743}
744
745impl<'a> FontRead<'a> for CaretValue<'a> {
746    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
747        let format: u16 = data.read_at(0usize)?;
748        match format {
749            CaretValueFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
750            CaretValueFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
751            CaretValueFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
752            other => Err(ReadError::InvalidFormat(other.into())),
753        }
754    }
755}
756
757impl<'a> MinByteRange<'a> for CaretValue<'a> {
758    fn min_byte_range(&self) -> Range<usize> {
759        match self {
760            Self::Format1(item) => item.min_byte_range(),
761            Self::Format2(item) => item.min_byte_range(),
762            Self::Format3(item) => item.min_byte_range(),
763        }
764    }
765    fn min_table_bytes(&self) -> &'a [u8] {
766        match self {
767            Self::Format1(item) => item.min_table_bytes(),
768            Self::Format2(item) => item.min_table_bytes(),
769            Self::Format3(item) => item.min_table_bytes(),
770        }
771    }
772}
773
774#[cfg(feature = "experimental_traverse")]
775impl<'a> CaretValue<'a> {
776    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
777        match self {
778            Self::Format1(table) => table,
779            Self::Format2(table) => table,
780            Self::Format3(table) => table,
781        }
782    }
783}
784
785#[cfg(feature = "experimental_traverse")]
786impl std::fmt::Debug for CaretValue<'_> {
787    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
788        self.dyn_inner().fmt(f)
789    }
790}
791
792#[cfg(feature = "experimental_traverse")]
793impl<'a> SomeTable<'a> for CaretValue<'a> {
794    fn type_name(&self) -> &str {
795        self.dyn_inner().type_name()
796    }
797    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
798        self.dyn_inner().get_field(idx)
799    }
800}
801
802impl Format<u16> for CaretValueFormat1<'_> {
803    const FORMAT: u16 = 1;
804}
805
806impl<'a> MinByteRange<'a> for CaretValueFormat1<'a> {
807    fn min_byte_range(&self) -> Range<usize> {
808        0..self.coordinate_byte_range().end
809    }
810    fn min_table_bytes(&self) -> &'a [u8] {
811        let range = self.min_byte_range();
812        self.data.as_bytes().get(range).unwrap_or_default()
813    }
814}
815
816impl<'a> FontRead<'a> for CaretValueFormat1<'a> {
817    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
818        #[allow(clippy::absurd_extreme_comparisons)]
819        if data.len() < Self::MIN_SIZE {
820            return Err(ReadError::OutOfBounds);
821        }
822        Ok(Self { data })
823    }
824}
825
826/// [CaretValue Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-1)
827#[derive(Clone)]
828pub struct CaretValueFormat1<'a> {
829    data: FontData<'a>,
830}
831
832#[allow(clippy::needless_lifetimes)]
833impl<'a> CaretValueFormat1<'a> {
834    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
835    basic_table_impls!(impl_the_methods);
836
837    /// Format identifier: format = 1
838    pub fn caret_value_format(&self) -> u16 {
839        let range = self.caret_value_format_byte_range();
840        self.data.read_at(range.start).ok().unwrap()
841    }
842
843    /// X or Y value, in design units
844    pub fn coordinate(&self) -> i16 {
845        let range = self.coordinate_byte_range();
846        self.data.read_at(range.start).ok().unwrap()
847    }
848
849    pub fn caret_value_format_byte_range(&self) -> Range<usize> {
850        let start = 0;
851        start..start + u16::RAW_BYTE_LEN
852    }
853
854    pub fn coordinate_byte_range(&self) -> Range<usize> {
855        let start = self.caret_value_format_byte_range().end;
856        start..start + i16::RAW_BYTE_LEN
857    }
858}
859
860const _: () = assert!(FontData::default_data_long_enough(
861    CaretValueFormat1::MIN_SIZE
862));
863
864impl Default for CaretValueFormat1<'_> {
865    fn default() -> Self {
866        Self {
867            data: FontData::default_format_1_u16_table_data(),
868        }
869    }
870}
871
872#[cfg(feature = "experimental_traverse")]
873impl<'a> SomeTable<'a> for CaretValueFormat1<'a> {
874    fn type_name(&self) -> &str {
875        "CaretValueFormat1"
876    }
877    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
878        match idx {
879            0usize => Some(Field::new("caret_value_format", self.caret_value_format())),
880            1usize => Some(Field::new("coordinate", self.coordinate())),
881            _ => None,
882        }
883    }
884}
885
886#[cfg(feature = "experimental_traverse")]
887#[allow(clippy::needless_lifetimes)]
888impl<'a> std::fmt::Debug for CaretValueFormat1<'a> {
889    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
890        (self as &dyn SomeTable<'a>).fmt(f)
891    }
892}
893
894impl Format<u16> for CaretValueFormat2<'_> {
895    const FORMAT: u16 = 2;
896}
897
898impl<'a> MinByteRange<'a> for CaretValueFormat2<'a> {
899    fn min_byte_range(&self) -> Range<usize> {
900        0..self.caret_value_point_index_byte_range().end
901    }
902    fn min_table_bytes(&self) -> &'a [u8] {
903        let range = self.min_byte_range();
904        self.data.as_bytes().get(range).unwrap_or_default()
905    }
906}
907
908impl<'a> FontRead<'a> for CaretValueFormat2<'a> {
909    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
910        #[allow(clippy::absurd_extreme_comparisons)]
911        if data.len() < Self::MIN_SIZE {
912            return Err(ReadError::OutOfBounds);
913        }
914        Ok(Self { data })
915    }
916}
917
918/// [CaretValue Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-2)
919#[derive(Clone)]
920pub struct CaretValueFormat2<'a> {
921    data: FontData<'a>,
922}
923
924#[allow(clippy::needless_lifetimes)]
925impl<'a> CaretValueFormat2<'a> {
926    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
927    basic_table_impls!(impl_the_methods);
928
929    /// Format identifier: format = 2
930    pub fn caret_value_format(&self) -> u16 {
931        let range = self.caret_value_format_byte_range();
932        self.data.read_at(range.start).ok().unwrap()
933    }
934
935    /// Contour point index on glyph
936    pub fn caret_value_point_index(&self) -> u16 {
937        let range = self.caret_value_point_index_byte_range();
938        self.data.read_at(range.start).ok().unwrap()
939    }
940
941    pub fn caret_value_format_byte_range(&self) -> Range<usize> {
942        let start = 0;
943        start..start + u16::RAW_BYTE_LEN
944    }
945
946    pub fn caret_value_point_index_byte_range(&self) -> Range<usize> {
947        let start = self.caret_value_format_byte_range().end;
948        start..start + u16::RAW_BYTE_LEN
949    }
950}
951
952#[cfg(feature = "experimental_traverse")]
953impl<'a> SomeTable<'a> for CaretValueFormat2<'a> {
954    fn type_name(&self) -> &str {
955        "CaretValueFormat2"
956    }
957    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
958        match idx {
959            0usize => Some(Field::new("caret_value_format", self.caret_value_format())),
960            1usize => Some(Field::new(
961                "caret_value_point_index",
962                self.caret_value_point_index(),
963            )),
964            _ => None,
965        }
966    }
967}
968
969#[cfg(feature = "experimental_traverse")]
970#[allow(clippy::needless_lifetimes)]
971impl<'a> std::fmt::Debug for CaretValueFormat2<'a> {
972    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
973        (self as &dyn SomeTable<'a>).fmt(f)
974    }
975}
976
977impl Format<u16> for CaretValueFormat3<'_> {
978    const FORMAT: u16 = 3;
979}
980
981impl<'a> MinByteRange<'a> for CaretValueFormat3<'a> {
982    fn min_byte_range(&self) -> Range<usize> {
983        0..self.device_offset_byte_range().end
984    }
985    fn min_table_bytes(&self) -> &'a [u8] {
986        let range = self.min_byte_range();
987        self.data.as_bytes().get(range).unwrap_or_default()
988    }
989}
990
991impl<'a> FontRead<'a> for CaretValueFormat3<'a> {
992    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
993        #[allow(clippy::absurd_extreme_comparisons)]
994        if data.len() < Self::MIN_SIZE {
995            return Err(ReadError::OutOfBounds);
996        }
997        Ok(Self { data })
998    }
999}
1000
1001/// [CaretValue Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#caretvalue-format-3)
1002#[derive(Clone)]
1003pub struct CaretValueFormat3<'a> {
1004    data: FontData<'a>,
1005}
1006
1007#[allow(clippy::needless_lifetimes)]
1008impl<'a> CaretValueFormat3<'a> {
1009    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN);
1010    basic_table_impls!(impl_the_methods);
1011
1012    /// Format identifier-format = 3
1013    pub fn caret_value_format(&self) -> u16 {
1014        let range = self.caret_value_format_byte_range();
1015        self.data.read_at(range.start).ok().unwrap()
1016    }
1017
1018    /// X or Y value, in design units
1019    pub fn coordinate(&self) -> i16 {
1020        let range = self.coordinate_byte_range();
1021        self.data.read_at(range.start).ok().unwrap()
1022    }
1023
1024    /// Offset to Device table (non-variable font) / Variation Index
1025    /// table (variable font) for X or Y value-from beginning of
1026    /// CaretValue table
1027    pub fn device_offset(&self) -> Offset16 {
1028        let range = self.device_offset_byte_range();
1029        self.data.read_at(range.start).ok().unwrap()
1030    }
1031
1032    /// Attempt to resolve [`device_offset`][Self::device_offset].
1033    pub fn device(&self) -> Result<DeviceOrVariationIndex<'a>, ReadError> {
1034        let data = self.data;
1035        self.device_offset().resolve(data)
1036    }
1037
1038    pub fn caret_value_format_byte_range(&self) -> Range<usize> {
1039        let start = 0;
1040        start..start + u16::RAW_BYTE_LEN
1041    }
1042
1043    pub fn coordinate_byte_range(&self) -> Range<usize> {
1044        let start = self.caret_value_format_byte_range().end;
1045        start..start + i16::RAW_BYTE_LEN
1046    }
1047
1048    pub fn device_offset_byte_range(&self) -> Range<usize> {
1049        let start = self.coordinate_byte_range().end;
1050        start..start + Offset16::RAW_BYTE_LEN
1051    }
1052}
1053
1054#[cfg(feature = "experimental_traverse")]
1055impl<'a> SomeTable<'a> for CaretValueFormat3<'a> {
1056    fn type_name(&self) -> &str {
1057        "CaretValueFormat3"
1058    }
1059    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1060        match idx {
1061            0usize => Some(Field::new("caret_value_format", self.caret_value_format())),
1062            1usize => Some(Field::new("coordinate", self.coordinate())),
1063            2usize => Some(Field::new(
1064                "device_offset",
1065                FieldType::offset(self.device_offset(), self.device()),
1066            )),
1067            _ => None,
1068        }
1069    }
1070}
1071
1072#[cfg(feature = "experimental_traverse")]
1073#[allow(clippy::needless_lifetimes)]
1074impl<'a> std::fmt::Debug for CaretValueFormat3<'a> {
1075    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1076        (self as &dyn SomeTable<'a>).fmt(f)
1077    }
1078}
1079
1080impl Format<u16> for MarkGlyphSets<'_> {
1081    const FORMAT: u16 = 1;
1082}
1083
1084impl<'a> MinByteRange<'a> for MarkGlyphSets<'a> {
1085    fn min_byte_range(&self) -> Range<usize> {
1086        0..self.coverage_offsets_byte_range().end
1087    }
1088    fn min_table_bytes(&self) -> &'a [u8] {
1089        let range = self.min_byte_range();
1090        self.data.as_bytes().get(range).unwrap_or_default()
1091    }
1092}
1093
1094impl<'a> FontRead<'a> for MarkGlyphSets<'a> {
1095    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1096        #[allow(clippy::absurd_extreme_comparisons)]
1097        if data.len() < Self::MIN_SIZE {
1098            return Err(ReadError::OutOfBounds);
1099        }
1100        Ok(Self { data })
1101    }
1102}
1103
1104/// [Mark Glyph Sets Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef#mark-glyph-sets-table)
1105#[derive(Clone)]
1106pub struct MarkGlyphSets<'a> {
1107    data: FontData<'a>,
1108}
1109
1110#[allow(clippy::needless_lifetimes)]
1111impl<'a> MarkGlyphSets<'a> {
1112    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1113    basic_table_impls!(impl_the_methods);
1114
1115    /// Format identifier == 1
1116    pub fn format(&self) -> u16 {
1117        let range = self.format_byte_range();
1118        self.data.read_at(range.start).ok().unwrap()
1119    }
1120
1121    /// Number of mark glyph sets defined
1122    pub fn mark_glyph_set_count(&self) -> u16 {
1123        let range = self.mark_glyph_set_count_byte_range();
1124        self.data.read_at(range.start).ok().unwrap()
1125    }
1126
1127    /// Array of offsets to mark glyph set coverage tables, from the
1128    /// start of the MarkGlyphSets table.
1129    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset32>] {
1130        let range = self.coverage_offsets_byte_range();
1131        self.data.read_array(range).ok().unwrap_or_default()
1132    }
1133
1134    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
1135    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset32> {
1136        let data = self.data;
1137        let offsets = self.coverage_offsets();
1138        ArrayOfOffsets::new(offsets, data, ())
1139    }
1140
1141    pub fn format_byte_range(&self) -> Range<usize> {
1142        let start = 0;
1143        start..start + u16::RAW_BYTE_LEN
1144    }
1145
1146    pub fn mark_glyph_set_count_byte_range(&self) -> Range<usize> {
1147        let start = self.format_byte_range().end;
1148        start..start + u16::RAW_BYTE_LEN
1149    }
1150
1151    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
1152        let mark_glyph_set_count = self.mark_glyph_set_count();
1153        let start = self.mark_glyph_set_count_byte_range().end;
1154        start..start + (mark_glyph_set_count as usize).saturating_mul(Offset32::RAW_BYTE_LEN)
1155    }
1156}
1157
1158const _: () = assert!(FontData::default_data_long_enough(MarkGlyphSets::MIN_SIZE));
1159
1160impl Default for MarkGlyphSets<'_> {
1161    fn default() -> Self {
1162        Self {
1163            data: FontData::default_format_1_u16_table_data(),
1164        }
1165    }
1166}
1167
1168#[cfg(feature = "experimental_traverse")]
1169impl<'a> SomeTable<'a> for MarkGlyphSets<'a> {
1170    fn type_name(&self) -> &str {
1171        "MarkGlyphSets"
1172    }
1173    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1174        match idx {
1175            0usize => Some(Field::new("format", self.format())),
1176            1usize => Some(Field::new(
1177                "mark_glyph_set_count",
1178                self.mark_glyph_set_count(),
1179            )),
1180            2usize => Some(Field::new(
1181                "coverage_offsets",
1182                FieldType::from(self.coverages()),
1183            )),
1184            _ => None,
1185        }
1186    }
1187}
1188
1189#[cfg(feature = "experimental_traverse")]
1190#[allow(clippy::needless_lifetimes)]
1191impl<'a> std::fmt::Debug for MarkGlyphSets<'a> {
1192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1193        (self as &dyn SomeTable<'a>).fmt(f)
1194    }
1195}