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