read_fonts/generated/
generated_base.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
8/// The [BASE](https://learn.microsoft.com/en-us/typography/opentype/spec/base) (Baseline) table
9#[derive(Debug, Clone, Copy)]
10#[doc(hidden)]
11pub struct BaseMarker {
12    item_var_store_offset_byte_start: Option<usize>,
13}
14
15impl BaseMarker {
16    pub fn version_byte_range(&self) -> Range<usize> {
17        let start = 0;
18        start..start + MajorMinor::RAW_BYTE_LEN
19    }
20
21    pub fn horiz_axis_offset_byte_range(&self) -> Range<usize> {
22        let start = self.version_byte_range().end;
23        start..start + Offset16::RAW_BYTE_LEN
24    }
25
26    pub fn vert_axis_offset_byte_range(&self) -> Range<usize> {
27        let start = self.horiz_axis_offset_byte_range().end;
28        start..start + Offset16::RAW_BYTE_LEN
29    }
30
31    pub fn item_var_store_offset_byte_range(&self) -> Option<Range<usize>> {
32        let start = self.item_var_store_offset_byte_start?;
33        Some(start..start + Offset32::RAW_BYTE_LEN)
34    }
35}
36
37impl MinByteRange for BaseMarker {
38    fn min_byte_range(&self) -> Range<usize> {
39        0..self.vert_axis_offset_byte_range().end
40    }
41}
42
43impl TopLevelTable for Base<'_> {
44    /// `BASE`
45    const TAG: Tag = Tag::new(b"BASE");
46}
47
48impl<'a> FontRead<'a> for Base<'a> {
49    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
50        let mut cursor = data.cursor();
51        let version: MajorMinor = cursor.read()?;
52        cursor.advance::<Offset16>();
53        cursor.advance::<Offset16>();
54        let item_var_store_offset_byte_start = version
55            .compatible((1u16, 1u16))
56            .then(|| cursor.position())
57            .transpose()?;
58        version
59            .compatible((1u16, 1u16))
60            .then(|| cursor.advance::<Offset32>());
61        cursor.finish(BaseMarker {
62            item_var_store_offset_byte_start,
63        })
64    }
65}
66
67/// The [BASE](https://learn.microsoft.com/en-us/typography/opentype/spec/base) (Baseline) table
68pub type Base<'a> = TableRef<'a, BaseMarker>;
69
70#[allow(clippy::needless_lifetimes)]
71impl<'a> Base<'a> {
72    /// (major, minor) Version for the BASE table (1,0) or (1,1)
73    pub fn version(&self) -> MajorMinor {
74        let range = self.shape.version_byte_range();
75        self.data.read_at(range.start).unwrap()
76    }
77
78    /// Offset to horizontal Axis table, from beginning of BASE table (may be NULL)
79    pub fn horiz_axis_offset(&self) -> Nullable<Offset16> {
80        let range = self.shape.horiz_axis_offset_byte_range();
81        self.data.read_at(range.start).unwrap()
82    }
83
84    /// Attempt to resolve [`horiz_axis_offset`][Self::horiz_axis_offset].
85    pub fn horiz_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
86        let data = self.data;
87        self.horiz_axis_offset().resolve(data)
88    }
89
90    /// Offset to vertical Axis table, from beginning of BASE table (may be NULL)
91    pub fn vert_axis_offset(&self) -> Nullable<Offset16> {
92        let range = self.shape.vert_axis_offset_byte_range();
93        self.data.read_at(range.start).unwrap()
94    }
95
96    /// Attempt to resolve [`vert_axis_offset`][Self::vert_axis_offset].
97    pub fn vert_axis(&self) -> Option<Result<Axis<'a>, ReadError>> {
98        let data = self.data;
99        self.vert_axis_offset().resolve(data)
100    }
101
102    /// Offset to Item Variation Store table, from beginning of BASE table (may be null)
103    pub fn item_var_store_offset(&self) -> Option<Nullable<Offset32>> {
104        let range = self.shape.item_var_store_offset_byte_range()?;
105        Some(self.data.read_at(range.start).unwrap())
106    }
107
108    /// Attempt to resolve [`item_var_store_offset`][Self::item_var_store_offset].
109    pub fn item_var_store(&self) -> Option<Result<ItemVariationStore<'a>, ReadError>> {
110        let data = self.data;
111        self.item_var_store_offset().map(|x| x.resolve(data))?
112    }
113}
114
115#[cfg(feature = "experimental_traverse")]
116impl<'a> SomeTable<'a> for Base<'a> {
117    fn type_name(&self) -> &str {
118        "Base"
119    }
120    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
121        let version = self.version();
122        match idx {
123            0usize => Some(Field::new("version", self.version())),
124            1usize => Some(Field::new(
125                "horiz_axis_offset",
126                FieldType::offset(self.horiz_axis_offset(), self.horiz_axis()),
127            )),
128            2usize => Some(Field::new(
129                "vert_axis_offset",
130                FieldType::offset(self.vert_axis_offset(), self.vert_axis()),
131            )),
132            3usize if version.compatible((1u16, 1u16)) => Some(Field::new(
133                "item_var_store_offset",
134                FieldType::offset(self.item_var_store_offset().unwrap(), self.item_var_store()),
135            )),
136            _ => None,
137        }
138    }
139}
140
141#[cfg(feature = "experimental_traverse")]
142#[allow(clippy::needless_lifetimes)]
143impl<'a> std::fmt::Debug for Base<'a> {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        (self as &dyn SomeTable<'a>).fmt(f)
146    }
147}
148
149/// [Axis Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#axis-tables-horizaxis-and-vertaxis)
150#[derive(Debug, Clone, Copy)]
151#[doc(hidden)]
152pub struct AxisMarker {}
153
154impl AxisMarker {
155    pub fn base_tag_list_offset_byte_range(&self) -> Range<usize> {
156        let start = 0;
157        start..start + Offset16::RAW_BYTE_LEN
158    }
159
160    pub fn base_script_list_offset_byte_range(&self) -> Range<usize> {
161        let start = self.base_tag_list_offset_byte_range().end;
162        start..start + Offset16::RAW_BYTE_LEN
163    }
164}
165
166impl MinByteRange for AxisMarker {
167    fn min_byte_range(&self) -> Range<usize> {
168        0..self.base_script_list_offset_byte_range().end
169    }
170}
171
172impl<'a> FontRead<'a> for Axis<'a> {
173    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
174        let mut cursor = data.cursor();
175        cursor.advance::<Offset16>();
176        cursor.advance::<Offset16>();
177        cursor.finish(AxisMarker {})
178    }
179}
180
181/// [Axis Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#axis-tables-horizaxis-and-vertaxis)
182pub type Axis<'a> = TableRef<'a, AxisMarker>;
183
184#[allow(clippy::needless_lifetimes)]
185impl<'a> Axis<'a> {
186    /// Offset to BaseTagList table, from beginning of Axis table (may
187    /// be NULL)
188    pub fn base_tag_list_offset(&self) -> Nullable<Offset16> {
189        let range = self.shape.base_tag_list_offset_byte_range();
190        self.data.read_at(range.start).unwrap()
191    }
192
193    /// Attempt to resolve [`base_tag_list_offset`][Self::base_tag_list_offset].
194    pub fn base_tag_list(&self) -> Option<Result<BaseTagList<'a>, ReadError>> {
195        let data = self.data;
196        self.base_tag_list_offset().resolve(data)
197    }
198
199    /// Offset to BaseScriptList table, from beginning of Axis table
200    pub fn base_script_list_offset(&self) -> Offset16 {
201        let range = self.shape.base_script_list_offset_byte_range();
202        self.data.read_at(range.start).unwrap()
203    }
204
205    /// Attempt to resolve [`base_script_list_offset`][Self::base_script_list_offset].
206    pub fn base_script_list(&self) -> Result<BaseScriptList<'a>, ReadError> {
207        let data = self.data;
208        self.base_script_list_offset().resolve(data)
209    }
210}
211
212#[cfg(feature = "experimental_traverse")]
213impl<'a> SomeTable<'a> for Axis<'a> {
214    fn type_name(&self) -> &str {
215        "Axis"
216    }
217    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
218        match idx {
219            0usize => Some(Field::new(
220                "base_tag_list_offset",
221                FieldType::offset(self.base_tag_list_offset(), self.base_tag_list()),
222            )),
223            1usize => Some(Field::new(
224                "base_script_list_offset",
225                FieldType::offset(self.base_script_list_offset(), self.base_script_list()),
226            )),
227            _ => None,
228        }
229    }
230}
231
232#[cfg(feature = "experimental_traverse")]
233#[allow(clippy::needless_lifetimes)]
234impl<'a> std::fmt::Debug for Axis<'a> {
235    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236        (self as &dyn SomeTable<'a>).fmt(f)
237    }
238}
239
240/// [BaseTagList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basetaglist-table)
241#[derive(Debug, Clone, Copy)]
242#[doc(hidden)]
243pub struct BaseTagListMarker {
244    baseline_tags_byte_len: usize,
245}
246
247impl BaseTagListMarker {
248    pub fn base_tag_count_byte_range(&self) -> Range<usize> {
249        let start = 0;
250        start..start + u16::RAW_BYTE_LEN
251    }
252
253    pub fn baseline_tags_byte_range(&self) -> Range<usize> {
254        let start = self.base_tag_count_byte_range().end;
255        start..start + self.baseline_tags_byte_len
256    }
257}
258
259impl MinByteRange for BaseTagListMarker {
260    fn min_byte_range(&self) -> Range<usize> {
261        0..self.baseline_tags_byte_range().end
262    }
263}
264
265impl<'a> FontRead<'a> for BaseTagList<'a> {
266    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
267        let mut cursor = data.cursor();
268        let base_tag_count: u16 = cursor.read()?;
269        let baseline_tags_byte_len = (base_tag_count as usize)
270            .checked_mul(Tag::RAW_BYTE_LEN)
271            .ok_or(ReadError::OutOfBounds)?;
272        cursor.advance_by(baseline_tags_byte_len);
273        cursor.finish(BaseTagListMarker {
274            baseline_tags_byte_len,
275        })
276    }
277}
278
279/// [BaseTagList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basetaglist-table)
280pub type BaseTagList<'a> = TableRef<'a, BaseTagListMarker>;
281
282#[allow(clippy::needless_lifetimes)]
283impl<'a> BaseTagList<'a> {
284    /// Number of baseline identification tags in this text direction
285    /// — may be zero (0)
286    pub fn base_tag_count(&self) -> u16 {
287        let range = self.shape.base_tag_count_byte_range();
288        self.data.read_at(range.start).unwrap()
289    }
290
291    /// Array of 4-byte baseline identification tags — must be in
292    /// alphabetical order
293    pub fn baseline_tags(&self) -> &'a [BigEndian<Tag>] {
294        let range = self.shape.baseline_tags_byte_range();
295        self.data.read_array(range).unwrap()
296    }
297}
298
299#[cfg(feature = "experimental_traverse")]
300impl<'a> SomeTable<'a> for BaseTagList<'a> {
301    fn type_name(&self) -> &str {
302        "BaseTagList"
303    }
304    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
305        match idx {
306            0usize => Some(Field::new("base_tag_count", self.base_tag_count())),
307            1usize => Some(Field::new("baseline_tags", self.baseline_tags())),
308            _ => None,
309        }
310    }
311}
312
313#[cfg(feature = "experimental_traverse")]
314#[allow(clippy::needless_lifetimes)]
315impl<'a> std::fmt::Debug for BaseTagList<'a> {
316    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317        (self as &dyn SomeTable<'a>).fmt(f)
318    }
319}
320
321/// [BaseScriptList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table)
322#[derive(Debug, Clone, Copy)]
323#[doc(hidden)]
324pub struct BaseScriptListMarker {
325    base_script_records_byte_len: usize,
326}
327
328impl BaseScriptListMarker {
329    pub fn base_script_count_byte_range(&self) -> Range<usize> {
330        let start = 0;
331        start..start + u16::RAW_BYTE_LEN
332    }
333
334    pub fn base_script_records_byte_range(&self) -> Range<usize> {
335        let start = self.base_script_count_byte_range().end;
336        start..start + self.base_script_records_byte_len
337    }
338}
339
340impl MinByteRange for BaseScriptListMarker {
341    fn min_byte_range(&self) -> Range<usize> {
342        0..self.base_script_records_byte_range().end
343    }
344}
345
346impl<'a> FontRead<'a> for BaseScriptList<'a> {
347    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
348        let mut cursor = data.cursor();
349        let base_script_count: u16 = cursor.read()?;
350        let base_script_records_byte_len = (base_script_count as usize)
351            .checked_mul(BaseScriptRecord::RAW_BYTE_LEN)
352            .ok_or(ReadError::OutOfBounds)?;
353        cursor.advance_by(base_script_records_byte_len);
354        cursor.finish(BaseScriptListMarker {
355            base_script_records_byte_len,
356        })
357    }
358}
359
360/// [BaseScriptList Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptlist-table)
361pub type BaseScriptList<'a> = TableRef<'a, BaseScriptListMarker>;
362
363#[allow(clippy::needless_lifetimes)]
364impl<'a> BaseScriptList<'a> {
365    /// Number of BaseScriptRecords defined
366    pub fn base_script_count(&self) -> u16 {
367        let range = self.shape.base_script_count_byte_range();
368        self.data.read_at(range.start).unwrap()
369    }
370
371    /// Array of BaseScriptRecords, in alphabetical order by
372    /// baseScriptTag
373    pub fn base_script_records(&self) -> &'a [BaseScriptRecord] {
374        let range = self.shape.base_script_records_byte_range();
375        self.data.read_array(range).unwrap()
376    }
377}
378
379#[cfg(feature = "experimental_traverse")]
380impl<'a> SomeTable<'a> for BaseScriptList<'a> {
381    fn type_name(&self) -> &str {
382        "BaseScriptList"
383    }
384    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
385        match idx {
386            0usize => Some(Field::new("base_script_count", self.base_script_count())),
387            1usize => Some(Field::new(
388                "base_script_records",
389                traversal::FieldType::array_of_records(
390                    stringify!(BaseScriptRecord),
391                    self.base_script_records(),
392                    self.offset_data(),
393                ),
394            )),
395            _ => None,
396        }
397    }
398}
399
400#[cfg(feature = "experimental_traverse")]
401#[allow(clippy::needless_lifetimes)]
402impl<'a> std::fmt::Debug for BaseScriptList<'a> {
403    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404        (self as &dyn SomeTable<'a>).fmt(f)
405    }
406}
407
408/// [BaseScriptRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescriptrecord)
409#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
410#[repr(C)]
411#[repr(packed)]
412pub struct BaseScriptRecord {
413    /// 4-byte script identification tag
414    pub base_script_tag: BigEndian<Tag>,
415    /// Offset to BaseScript table, from beginning of BaseScriptList
416    pub base_script_offset: BigEndian<Offset16>,
417}
418
419impl BaseScriptRecord {
420    /// 4-byte script identification tag
421    pub fn base_script_tag(&self) -> Tag {
422        self.base_script_tag.get()
423    }
424
425    /// Offset to BaseScript table, from beginning of BaseScriptList
426    pub fn base_script_offset(&self) -> Offset16 {
427        self.base_script_offset.get()
428    }
429
430    /// Offset to BaseScript table, from beginning of BaseScriptList
431    ///
432    /// The `data` argument should be retrieved from the parent table
433    /// By calling its `offset_data` method.
434    pub fn base_script<'a>(&self, data: FontData<'a>) -> Result<BaseScript<'a>, ReadError> {
435        self.base_script_offset().resolve(data)
436    }
437}
438
439impl FixedSize for BaseScriptRecord {
440    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
441}
442
443#[cfg(feature = "experimental_traverse")]
444impl<'a> SomeRecord<'a> for BaseScriptRecord {
445    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
446        RecordResolver {
447            name: "BaseScriptRecord",
448            get_field: Box::new(move |idx, _data| match idx {
449                0usize => Some(Field::new("base_script_tag", self.base_script_tag())),
450                1usize => Some(Field::new(
451                    "base_script_offset",
452                    FieldType::offset(self.base_script_offset(), self.base_script(_data)),
453                )),
454                _ => None,
455            }),
456            data,
457        }
458    }
459}
460
461/// [BaseScript Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescript-table)
462#[derive(Debug, Clone, Copy)]
463#[doc(hidden)]
464pub struct BaseScriptMarker {
465    base_lang_sys_records_byte_len: usize,
466}
467
468impl BaseScriptMarker {
469    pub fn base_values_offset_byte_range(&self) -> Range<usize> {
470        let start = 0;
471        start..start + Offset16::RAW_BYTE_LEN
472    }
473
474    pub fn default_min_max_offset_byte_range(&self) -> Range<usize> {
475        let start = self.base_values_offset_byte_range().end;
476        start..start + Offset16::RAW_BYTE_LEN
477    }
478
479    pub fn base_lang_sys_count_byte_range(&self) -> Range<usize> {
480        let start = self.default_min_max_offset_byte_range().end;
481        start..start + u16::RAW_BYTE_LEN
482    }
483
484    pub fn base_lang_sys_records_byte_range(&self) -> Range<usize> {
485        let start = self.base_lang_sys_count_byte_range().end;
486        start..start + self.base_lang_sys_records_byte_len
487    }
488}
489
490impl MinByteRange for BaseScriptMarker {
491    fn min_byte_range(&self) -> Range<usize> {
492        0..self.base_lang_sys_records_byte_range().end
493    }
494}
495
496impl<'a> FontRead<'a> for BaseScript<'a> {
497    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
498        let mut cursor = data.cursor();
499        cursor.advance::<Offset16>();
500        cursor.advance::<Offset16>();
501        let base_lang_sys_count: u16 = cursor.read()?;
502        let base_lang_sys_records_byte_len = (base_lang_sys_count as usize)
503            .checked_mul(BaseLangSysRecord::RAW_BYTE_LEN)
504            .ok_or(ReadError::OutOfBounds)?;
505        cursor.advance_by(base_lang_sys_records_byte_len);
506        cursor.finish(BaseScriptMarker {
507            base_lang_sys_records_byte_len,
508        })
509    }
510}
511
512/// [BaseScript Table](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basescript-table)
513pub type BaseScript<'a> = TableRef<'a, BaseScriptMarker>;
514
515#[allow(clippy::needless_lifetimes)]
516impl<'a> BaseScript<'a> {
517    /// Offset to BaseValues table, from beginning of BaseScript table (may be NULL)
518    pub fn base_values_offset(&self) -> Nullable<Offset16> {
519        let range = self.shape.base_values_offset_byte_range();
520        self.data.read_at(range.start).unwrap()
521    }
522
523    /// Attempt to resolve [`base_values_offset`][Self::base_values_offset].
524    pub fn base_values(&self) -> Option<Result<BaseValues<'a>, ReadError>> {
525        let data = self.data;
526        self.base_values_offset().resolve(data)
527    }
528
529    /// Offset to MinMax table, from beginning of BaseScript table (may be NULL)
530    pub fn default_min_max_offset(&self) -> Nullable<Offset16> {
531        let range = self.shape.default_min_max_offset_byte_range();
532        self.data.read_at(range.start).unwrap()
533    }
534
535    /// Attempt to resolve [`default_min_max_offset`][Self::default_min_max_offset].
536    pub fn default_min_max(&self) -> Option<Result<MinMax<'a>, ReadError>> {
537        let data = self.data;
538        self.default_min_max_offset().resolve(data)
539    }
540
541    /// Number of BaseLangSysRecords defined — may be zero (0)
542    pub fn base_lang_sys_count(&self) -> u16 {
543        let range = self.shape.base_lang_sys_count_byte_range();
544        self.data.read_at(range.start).unwrap()
545    }
546
547    /// Array of BaseLangSysRecords, in alphabetical order by
548    /// BaseLangSysTag
549    pub fn base_lang_sys_records(&self) -> &'a [BaseLangSysRecord] {
550        let range = self.shape.base_lang_sys_records_byte_range();
551        self.data.read_array(range).unwrap()
552    }
553}
554
555#[cfg(feature = "experimental_traverse")]
556impl<'a> SomeTable<'a> for BaseScript<'a> {
557    fn type_name(&self) -> &str {
558        "BaseScript"
559    }
560    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
561        match idx {
562            0usize => Some(Field::new(
563                "base_values_offset",
564                FieldType::offset(self.base_values_offset(), self.base_values()),
565            )),
566            1usize => Some(Field::new(
567                "default_min_max_offset",
568                FieldType::offset(self.default_min_max_offset(), self.default_min_max()),
569            )),
570            2usize => Some(Field::new(
571                "base_lang_sys_count",
572                self.base_lang_sys_count(),
573            )),
574            3usize => Some(Field::new(
575                "base_lang_sys_records",
576                traversal::FieldType::array_of_records(
577                    stringify!(BaseLangSysRecord),
578                    self.base_lang_sys_records(),
579                    self.offset_data(),
580                ),
581            )),
582            _ => None,
583        }
584    }
585}
586
587#[cfg(feature = "experimental_traverse")]
588#[allow(clippy::needless_lifetimes)]
589impl<'a> std::fmt::Debug for BaseScript<'a> {
590    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
591        (self as &dyn SomeTable<'a>).fmt(f)
592    }
593}
594
595/// [BaseLangSysRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#baselangsysrecord)
596#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
597#[repr(C)]
598#[repr(packed)]
599pub struct BaseLangSysRecord {
600    /// 4-byte language system identification tag
601    pub base_lang_sys_tag: BigEndian<Tag>,
602    /// Offset to MinMax table, from beginning of BaseScript table
603    pub min_max_offset: BigEndian<Offset16>,
604}
605
606impl BaseLangSysRecord {
607    /// 4-byte language system identification tag
608    pub fn base_lang_sys_tag(&self) -> Tag {
609        self.base_lang_sys_tag.get()
610    }
611
612    /// Offset to MinMax table, from beginning of BaseScript table
613    pub fn min_max_offset(&self) -> Offset16 {
614        self.min_max_offset.get()
615    }
616
617    /// Offset to MinMax table, from beginning of BaseScript table
618    ///
619    /// The `data` argument should be retrieved from the parent table
620    /// By calling its `offset_data` method.
621    pub fn min_max<'a>(&self, data: FontData<'a>) -> Result<MinMax<'a>, ReadError> {
622        self.min_max_offset().resolve(data)
623    }
624}
625
626impl FixedSize for BaseLangSysRecord {
627    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
628}
629
630#[cfg(feature = "experimental_traverse")]
631impl<'a> SomeRecord<'a> for BaseLangSysRecord {
632    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
633        RecordResolver {
634            name: "BaseLangSysRecord",
635            get_field: Box::new(move |idx, _data| match idx {
636                0usize => Some(Field::new("base_lang_sys_tag", self.base_lang_sys_tag())),
637                1usize => Some(Field::new(
638                    "min_max_offset",
639                    FieldType::offset(self.min_max_offset(), self.min_max(_data)),
640                )),
641                _ => None,
642            }),
643            data,
644        }
645    }
646}
647
648/// [BaseValues](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basevalues-table) table
649#[derive(Debug, Clone, Copy)]
650#[doc(hidden)]
651pub struct BaseValuesMarker {
652    base_coord_offsets_byte_len: usize,
653}
654
655impl BaseValuesMarker {
656    pub fn default_baseline_index_byte_range(&self) -> Range<usize> {
657        let start = 0;
658        start..start + u16::RAW_BYTE_LEN
659    }
660
661    pub fn base_coord_count_byte_range(&self) -> Range<usize> {
662        let start = self.default_baseline_index_byte_range().end;
663        start..start + u16::RAW_BYTE_LEN
664    }
665
666    pub fn base_coord_offsets_byte_range(&self) -> Range<usize> {
667        let start = self.base_coord_count_byte_range().end;
668        start..start + self.base_coord_offsets_byte_len
669    }
670}
671
672impl MinByteRange for BaseValuesMarker {
673    fn min_byte_range(&self) -> Range<usize> {
674        0..self.base_coord_offsets_byte_range().end
675    }
676}
677
678impl<'a> FontRead<'a> for BaseValues<'a> {
679    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
680        let mut cursor = data.cursor();
681        cursor.advance::<u16>();
682        let base_coord_count: u16 = cursor.read()?;
683        let base_coord_offsets_byte_len = (base_coord_count as usize)
684            .checked_mul(Offset16::RAW_BYTE_LEN)
685            .ok_or(ReadError::OutOfBounds)?;
686        cursor.advance_by(base_coord_offsets_byte_len);
687        cursor.finish(BaseValuesMarker {
688            base_coord_offsets_byte_len,
689        })
690    }
691}
692
693/// [BaseValues](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basevalues-table) table
694pub type BaseValues<'a> = TableRef<'a, BaseValuesMarker>;
695
696#[allow(clippy::needless_lifetimes)]
697impl<'a> BaseValues<'a> {
698    /// Index number of default baseline for this script — equals
699    /// index position of baseline tag in baselineTags array of the
700    /// BaseTagList
701    pub fn default_baseline_index(&self) -> u16 {
702        let range = self.shape.default_baseline_index_byte_range();
703        self.data.read_at(range.start).unwrap()
704    }
705
706    /// Number of BaseCoord tables defined — should equal
707    /// baseTagCount in the BaseTagList
708    pub fn base_coord_count(&self) -> u16 {
709        let range = self.shape.base_coord_count_byte_range();
710        self.data.read_at(range.start).unwrap()
711    }
712
713    /// Array of offsets to BaseCoord tables, from beginning of
714    /// BaseValues table — order matches baselineTags array in the
715    /// BaseTagList
716    pub fn base_coord_offsets(&self) -> &'a [BigEndian<Offset16>] {
717        let range = self.shape.base_coord_offsets_byte_range();
718        self.data.read_array(range).unwrap()
719    }
720
721    /// A dynamically resolving wrapper for [`base_coord_offsets`][Self::base_coord_offsets].
722    pub fn base_coords(&self) -> ArrayOfOffsets<'a, BaseCoord<'a>, Offset16> {
723        let data = self.data;
724        let offsets = self.base_coord_offsets();
725        ArrayOfOffsets::new(offsets, data, ())
726    }
727}
728
729#[cfg(feature = "experimental_traverse")]
730impl<'a> SomeTable<'a> for BaseValues<'a> {
731    fn type_name(&self) -> &str {
732        "BaseValues"
733    }
734    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
735        match idx {
736            0usize => Some(Field::new(
737                "default_baseline_index",
738                self.default_baseline_index(),
739            )),
740            1usize => Some(Field::new("base_coord_count", self.base_coord_count())),
741            2usize => Some({
742                let data = self.data;
743                Field::new(
744                    "base_coord_offsets",
745                    FieldType::array_of_offsets(
746                        better_type_name::<BaseCoord>(),
747                        self.base_coord_offsets(),
748                        move |off| {
749                            let target = off.get().resolve::<BaseCoord>(data);
750                            FieldType::offset(off.get(), target)
751                        },
752                    ),
753                )
754            }),
755            _ => None,
756        }
757    }
758}
759
760#[cfg(feature = "experimental_traverse")]
761#[allow(clippy::needless_lifetimes)]
762impl<'a> std::fmt::Debug for BaseValues<'a> {
763    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
764        (self as &dyn SomeTable<'a>).fmt(f)
765    }
766}
767
768/// [MinMax](https://learn.microsoft.com/en-us/typography/opentype/spec/base#minmax-table) table
769#[derive(Debug, Clone, Copy)]
770#[doc(hidden)]
771pub struct MinMaxMarker {
772    feat_min_max_records_byte_len: usize,
773}
774
775impl MinMaxMarker {
776    pub fn min_coord_offset_byte_range(&self) -> Range<usize> {
777        let start = 0;
778        start..start + Offset16::RAW_BYTE_LEN
779    }
780
781    pub fn max_coord_offset_byte_range(&self) -> Range<usize> {
782        let start = self.min_coord_offset_byte_range().end;
783        start..start + Offset16::RAW_BYTE_LEN
784    }
785
786    pub fn feat_min_max_count_byte_range(&self) -> Range<usize> {
787        let start = self.max_coord_offset_byte_range().end;
788        start..start + u16::RAW_BYTE_LEN
789    }
790
791    pub fn feat_min_max_records_byte_range(&self) -> Range<usize> {
792        let start = self.feat_min_max_count_byte_range().end;
793        start..start + self.feat_min_max_records_byte_len
794    }
795}
796
797impl MinByteRange for MinMaxMarker {
798    fn min_byte_range(&self) -> Range<usize> {
799        0..self.feat_min_max_records_byte_range().end
800    }
801}
802
803impl<'a> FontRead<'a> for MinMax<'a> {
804    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
805        let mut cursor = data.cursor();
806        cursor.advance::<Offset16>();
807        cursor.advance::<Offset16>();
808        let feat_min_max_count: u16 = cursor.read()?;
809        let feat_min_max_records_byte_len = (feat_min_max_count as usize)
810            .checked_mul(FeatMinMaxRecord::RAW_BYTE_LEN)
811            .ok_or(ReadError::OutOfBounds)?;
812        cursor.advance_by(feat_min_max_records_byte_len);
813        cursor.finish(MinMaxMarker {
814            feat_min_max_records_byte_len,
815        })
816    }
817}
818
819/// [MinMax](https://learn.microsoft.com/en-us/typography/opentype/spec/base#minmax-table) table
820pub type MinMax<'a> = TableRef<'a, MinMaxMarker>;
821
822#[allow(clippy::needless_lifetimes)]
823impl<'a> MinMax<'a> {
824    /// Offset to BaseCoord table that defines the minimum extent
825    /// value, from the beginning of MinMax table (may be NULL)
826    pub fn min_coord_offset(&self) -> Nullable<Offset16> {
827        let range = self.shape.min_coord_offset_byte_range();
828        self.data.read_at(range.start).unwrap()
829    }
830
831    /// Attempt to resolve [`min_coord_offset`][Self::min_coord_offset].
832    pub fn min_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
833        let data = self.data;
834        self.min_coord_offset().resolve(data)
835    }
836
837    /// Offset to BaseCoord table that defines maximum extent value,
838    /// from the beginning of MinMax table (may be NULL)
839    pub fn max_coord_offset(&self) -> Nullable<Offset16> {
840        let range = self.shape.max_coord_offset_byte_range();
841        self.data.read_at(range.start).unwrap()
842    }
843
844    /// Attempt to resolve [`max_coord_offset`][Self::max_coord_offset].
845    pub fn max_coord(&self) -> Option<Result<BaseCoord<'a>, ReadError>> {
846        let data = self.data;
847        self.max_coord_offset().resolve(data)
848    }
849
850    /// Number of FeatMinMaxRecords — may be zero (0)
851    pub fn feat_min_max_count(&self) -> u16 {
852        let range = self.shape.feat_min_max_count_byte_range();
853        self.data.read_at(range.start).unwrap()
854    }
855
856    /// Array of FeatMinMaxRecords, in alphabetical order by
857    /// featureTableTag
858    pub fn feat_min_max_records(&self) -> &'a [FeatMinMaxRecord] {
859        let range = self.shape.feat_min_max_records_byte_range();
860        self.data.read_array(range).unwrap()
861    }
862}
863
864#[cfg(feature = "experimental_traverse")]
865impl<'a> SomeTable<'a> for MinMax<'a> {
866    fn type_name(&self) -> &str {
867        "MinMax"
868    }
869    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
870        match idx {
871            0usize => Some(Field::new(
872                "min_coord_offset",
873                FieldType::offset(self.min_coord_offset(), self.min_coord()),
874            )),
875            1usize => Some(Field::new(
876                "max_coord_offset",
877                FieldType::offset(self.max_coord_offset(), self.max_coord()),
878            )),
879            2usize => Some(Field::new("feat_min_max_count", self.feat_min_max_count())),
880            3usize => Some(Field::new(
881                "feat_min_max_records",
882                traversal::FieldType::array_of_records(
883                    stringify!(FeatMinMaxRecord),
884                    self.feat_min_max_records(),
885                    self.offset_data(),
886                ),
887            )),
888            _ => None,
889        }
890    }
891}
892
893#[cfg(feature = "experimental_traverse")]
894#[allow(clippy::needless_lifetimes)]
895impl<'a> std::fmt::Debug for MinMax<'a> {
896    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
897        (self as &dyn SomeTable<'a>).fmt(f)
898    }
899}
900
901/// [FeatMinMaxRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/base#baselangsysrecord)
902#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
903#[repr(C)]
904#[repr(packed)]
905pub struct FeatMinMaxRecord {
906    /// 4-byte feature identification tag — must match feature tag in
907    /// FeatureList
908    pub feature_table_tag: BigEndian<Tag>,
909    /// Offset to BaseCoord table that defines the minimum extent
910    /// value, from beginning of MinMax table (may be NULL)
911    pub min_coord_offset: BigEndian<Nullable<Offset16>>,
912    /// Offset to BaseCoord table that defines the maximum extent
913    /// value, from beginning of MinMax table (may be NULL)
914    pub max_coord_offset: BigEndian<Nullable<Offset16>>,
915}
916
917impl FeatMinMaxRecord {
918    /// 4-byte feature identification tag — must match feature tag in
919    /// FeatureList
920    pub fn feature_table_tag(&self) -> Tag {
921        self.feature_table_tag.get()
922    }
923
924    /// Offset to BaseCoord table that defines the minimum extent
925    /// value, from beginning of MinMax table (may be NULL)
926    pub fn min_coord_offset(&self) -> Nullable<Offset16> {
927        self.min_coord_offset.get()
928    }
929
930    /// Offset to BaseCoord table that defines the minimum extent
931    /// value, from beginning of MinMax table (may be NULL)
932    ///
933    /// The `data` argument should be retrieved from the parent table
934    /// By calling its `offset_data` method.
935    pub fn min_coord<'a>(&self, data: FontData<'a>) -> Option<Result<MinMax<'a>, ReadError>> {
936        self.min_coord_offset().resolve(data)
937    }
938
939    /// Offset to BaseCoord table that defines the maximum extent
940    /// value, from beginning of MinMax table (may be NULL)
941    pub fn max_coord_offset(&self) -> Nullable<Offset16> {
942        self.max_coord_offset.get()
943    }
944
945    /// Offset to BaseCoord table that defines the maximum extent
946    /// value, from beginning of MinMax table (may be NULL)
947    ///
948    /// The `data` argument should be retrieved from the parent table
949    /// By calling its `offset_data` method.
950    pub fn max_coord<'a>(&self, data: FontData<'a>) -> Option<Result<MinMax<'a>, ReadError>> {
951        self.max_coord_offset().resolve(data)
952    }
953}
954
955impl FixedSize for FeatMinMaxRecord {
956    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
957}
958
959#[cfg(feature = "experimental_traverse")]
960impl<'a> SomeRecord<'a> for FeatMinMaxRecord {
961    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
962        RecordResolver {
963            name: "FeatMinMaxRecord",
964            get_field: Box::new(move |idx, _data| match idx {
965                0usize => Some(Field::new("feature_table_tag", self.feature_table_tag())),
966                1usize => Some(Field::new(
967                    "min_coord_offset",
968                    FieldType::offset(self.min_coord_offset(), self.min_coord(_data)),
969                )),
970                2usize => Some(Field::new(
971                    "max_coord_offset",
972                    FieldType::offset(self.max_coord_offset(), self.max_coord(_data)),
973                )),
974                _ => None,
975            }),
976            data,
977        }
978    }
979}
980
981#[derive(Clone)]
982pub enum BaseCoord<'a> {
983    Format1(BaseCoordFormat1<'a>),
984    Format2(BaseCoordFormat2<'a>),
985    Format3(BaseCoordFormat3<'a>),
986}
987
988impl<'a> BaseCoord<'a> {
989    ///Return the `FontData` used to resolve offsets for this table.
990    pub fn offset_data(&self) -> FontData<'a> {
991        match self {
992            Self::Format1(item) => item.offset_data(),
993            Self::Format2(item) => item.offset_data(),
994            Self::Format3(item) => item.offset_data(),
995        }
996    }
997
998    /// Format identifier — format = 1
999    pub fn base_coord_format(&self) -> u16 {
1000        match self {
1001            Self::Format1(item) => item.base_coord_format(),
1002            Self::Format2(item) => item.base_coord_format(),
1003            Self::Format3(item) => item.base_coord_format(),
1004        }
1005    }
1006
1007    /// X or Y value, in design units
1008    pub fn coordinate(&self) -> i16 {
1009        match self {
1010            Self::Format1(item) => item.coordinate(),
1011            Self::Format2(item) => item.coordinate(),
1012            Self::Format3(item) => item.coordinate(),
1013        }
1014    }
1015}
1016
1017impl<'a> FontRead<'a> for BaseCoord<'a> {
1018    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1019        let format: u16 = data.read_at(0usize)?;
1020        match format {
1021            BaseCoordFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1022            BaseCoordFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1023            BaseCoordFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
1024            other => Err(ReadError::InvalidFormat(other.into())),
1025        }
1026    }
1027}
1028
1029impl MinByteRange for BaseCoord<'_> {
1030    fn min_byte_range(&self) -> Range<usize> {
1031        match self {
1032            Self::Format1(item) => item.min_byte_range(),
1033            Self::Format2(item) => item.min_byte_range(),
1034            Self::Format3(item) => item.min_byte_range(),
1035        }
1036    }
1037}
1038
1039#[cfg(feature = "experimental_traverse")]
1040impl<'a> BaseCoord<'a> {
1041    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1042        match self {
1043            Self::Format1(table) => table,
1044            Self::Format2(table) => table,
1045            Self::Format3(table) => table,
1046        }
1047    }
1048}
1049
1050#[cfg(feature = "experimental_traverse")]
1051impl std::fmt::Debug for BaseCoord<'_> {
1052    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1053        self.dyn_inner().fmt(f)
1054    }
1055}
1056
1057#[cfg(feature = "experimental_traverse")]
1058impl<'a> SomeTable<'a> for BaseCoord<'a> {
1059    fn type_name(&self) -> &str {
1060        self.dyn_inner().type_name()
1061    }
1062    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1063        self.dyn_inner().get_field(idx)
1064    }
1065}
1066
1067impl Format<u16> for BaseCoordFormat1Marker {
1068    const FORMAT: u16 = 1;
1069}
1070
1071/// [BaseCoordFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-1)
1072#[derive(Debug, Clone, Copy)]
1073#[doc(hidden)]
1074pub struct BaseCoordFormat1Marker {}
1075
1076impl BaseCoordFormat1Marker {
1077    pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1078        let start = 0;
1079        start..start + u16::RAW_BYTE_LEN
1080    }
1081
1082    pub fn coordinate_byte_range(&self) -> Range<usize> {
1083        let start = self.base_coord_format_byte_range().end;
1084        start..start + i16::RAW_BYTE_LEN
1085    }
1086}
1087
1088impl MinByteRange for BaseCoordFormat1Marker {
1089    fn min_byte_range(&self) -> Range<usize> {
1090        0..self.coordinate_byte_range().end
1091    }
1092}
1093
1094impl<'a> FontRead<'a> for BaseCoordFormat1<'a> {
1095    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1096        let mut cursor = data.cursor();
1097        cursor.advance::<u16>();
1098        cursor.advance::<i16>();
1099        cursor.finish(BaseCoordFormat1Marker {})
1100    }
1101}
1102
1103/// [BaseCoordFormat1](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-1)
1104pub type BaseCoordFormat1<'a> = TableRef<'a, BaseCoordFormat1Marker>;
1105
1106#[allow(clippy::needless_lifetimes)]
1107impl<'a> BaseCoordFormat1<'a> {
1108    /// Format identifier — format = 1
1109    pub fn base_coord_format(&self) -> u16 {
1110        let range = self.shape.base_coord_format_byte_range();
1111        self.data.read_at(range.start).unwrap()
1112    }
1113
1114    /// X or Y value, in design units
1115    pub fn coordinate(&self) -> i16 {
1116        let range = self.shape.coordinate_byte_range();
1117        self.data.read_at(range.start).unwrap()
1118    }
1119}
1120
1121#[cfg(feature = "experimental_traverse")]
1122impl<'a> SomeTable<'a> for BaseCoordFormat1<'a> {
1123    fn type_name(&self) -> &str {
1124        "BaseCoordFormat1"
1125    }
1126    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1127        match idx {
1128            0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1129            1usize => Some(Field::new("coordinate", self.coordinate())),
1130            _ => None,
1131        }
1132    }
1133}
1134
1135#[cfg(feature = "experimental_traverse")]
1136#[allow(clippy::needless_lifetimes)]
1137impl<'a> std::fmt::Debug for BaseCoordFormat1<'a> {
1138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1139        (self as &dyn SomeTable<'a>).fmt(f)
1140    }
1141}
1142
1143impl Format<u16> for BaseCoordFormat2Marker {
1144    const FORMAT: u16 = 2;
1145}
1146
1147/// [BaseCoordFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-2)
1148#[derive(Debug, Clone, Copy)]
1149#[doc(hidden)]
1150pub struct BaseCoordFormat2Marker {}
1151
1152impl BaseCoordFormat2Marker {
1153    pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1154        let start = 0;
1155        start..start + u16::RAW_BYTE_LEN
1156    }
1157
1158    pub fn coordinate_byte_range(&self) -> Range<usize> {
1159        let start = self.base_coord_format_byte_range().end;
1160        start..start + i16::RAW_BYTE_LEN
1161    }
1162
1163    pub fn reference_glyph_byte_range(&self) -> Range<usize> {
1164        let start = self.coordinate_byte_range().end;
1165        start..start + u16::RAW_BYTE_LEN
1166    }
1167
1168    pub fn base_coord_point_byte_range(&self) -> Range<usize> {
1169        let start = self.reference_glyph_byte_range().end;
1170        start..start + u16::RAW_BYTE_LEN
1171    }
1172}
1173
1174impl MinByteRange for BaseCoordFormat2Marker {
1175    fn min_byte_range(&self) -> Range<usize> {
1176        0..self.base_coord_point_byte_range().end
1177    }
1178}
1179
1180impl<'a> FontRead<'a> for BaseCoordFormat2<'a> {
1181    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1182        let mut cursor = data.cursor();
1183        cursor.advance::<u16>();
1184        cursor.advance::<i16>();
1185        cursor.advance::<u16>();
1186        cursor.advance::<u16>();
1187        cursor.finish(BaseCoordFormat2Marker {})
1188    }
1189}
1190
1191/// [BaseCoordFormat2](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-2)
1192pub type BaseCoordFormat2<'a> = TableRef<'a, BaseCoordFormat2Marker>;
1193
1194#[allow(clippy::needless_lifetimes)]
1195impl<'a> BaseCoordFormat2<'a> {
1196    /// Format identifier — format = 2
1197    pub fn base_coord_format(&self) -> u16 {
1198        let range = self.shape.base_coord_format_byte_range();
1199        self.data.read_at(range.start).unwrap()
1200    }
1201
1202    /// X or Y value, in design units
1203    pub fn coordinate(&self) -> i16 {
1204        let range = self.shape.coordinate_byte_range();
1205        self.data.read_at(range.start).unwrap()
1206    }
1207
1208    /// Glyph ID of control glyph
1209    pub fn reference_glyph(&self) -> u16 {
1210        let range = self.shape.reference_glyph_byte_range();
1211        self.data.read_at(range.start).unwrap()
1212    }
1213
1214    /// Index of contour point on the reference glyph
1215    pub fn base_coord_point(&self) -> u16 {
1216        let range = self.shape.base_coord_point_byte_range();
1217        self.data.read_at(range.start).unwrap()
1218    }
1219}
1220
1221#[cfg(feature = "experimental_traverse")]
1222impl<'a> SomeTable<'a> for BaseCoordFormat2<'a> {
1223    fn type_name(&self) -> &str {
1224        "BaseCoordFormat2"
1225    }
1226    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1227        match idx {
1228            0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1229            1usize => Some(Field::new("coordinate", self.coordinate())),
1230            2usize => Some(Field::new("reference_glyph", self.reference_glyph())),
1231            3usize => Some(Field::new("base_coord_point", self.base_coord_point())),
1232            _ => None,
1233        }
1234    }
1235}
1236
1237#[cfg(feature = "experimental_traverse")]
1238#[allow(clippy::needless_lifetimes)]
1239impl<'a> std::fmt::Debug for BaseCoordFormat2<'a> {
1240    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1241        (self as &dyn SomeTable<'a>).fmt(f)
1242    }
1243}
1244
1245impl Format<u16> for BaseCoordFormat3Marker {
1246    const FORMAT: u16 = 3;
1247}
1248
1249/// [BaseCoordFormat3](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-3)
1250#[derive(Debug, Clone, Copy)]
1251#[doc(hidden)]
1252pub struct BaseCoordFormat3Marker {}
1253
1254impl BaseCoordFormat3Marker {
1255    pub fn base_coord_format_byte_range(&self) -> Range<usize> {
1256        let start = 0;
1257        start..start + u16::RAW_BYTE_LEN
1258    }
1259
1260    pub fn coordinate_byte_range(&self) -> Range<usize> {
1261        let start = self.base_coord_format_byte_range().end;
1262        start..start + i16::RAW_BYTE_LEN
1263    }
1264
1265    pub fn device_offset_byte_range(&self) -> Range<usize> {
1266        let start = self.coordinate_byte_range().end;
1267        start..start + Offset16::RAW_BYTE_LEN
1268    }
1269}
1270
1271impl MinByteRange for BaseCoordFormat3Marker {
1272    fn min_byte_range(&self) -> Range<usize> {
1273        0..self.device_offset_byte_range().end
1274    }
1275}
1276
1277impl<'a> FontRead<'a> for BaseCoordFormat3<'a> {
1278    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1279        let mut cursor = data.cursor();
1280        cursor.advance::<u16>();
1281        cursor.advance::<i16>();
1282        cursor.advance::<Offset16>();
1283        cursor.finish(BaseCoordFormat3Marker {})
1284    }
1285}
1286
1287/// [BaseCoordFormat3](https://learn.microsoft.com/en-us/typography/opentype/spec/base#basecoord-format-3)
1288pub type BaseCoordFormat3<'a> = TableRef<'a, BaseCoordFormat3Marker>;
1289
1290#[allow(clippy::needless_lifetimes)]
1291impl<'a> BaseCoordFormat3<'a> {
1292    /// Format identifier — format = 3
1293    pub fn base_coord_format(&self) -> u16 {
1294        let range = self.shape.base_coord_format_byte_range();
1295        self.data.read_at(range.start).unwrap()
1296    }
1297
1298    /// X or Y value, in design units
1299    pub fn coordinate(&self) -> i16 {
1300        let range = self.shape.coordinate_byte_range();
1301        self.data.read_at(range.start).unwrap()
1302    }
1303
1304    /// Offset to Device table (non-variable font) / Variation Index
1305    /// table (variable font) for X or Y value, from beginning of
1306    /// BaseCoord table (may be NULL).
1307    pub fn device_offset(&self) -> Nullable<Offset16> {
1308        let range = self.shape.device_offset_byte_range();
1309        self.data.read_at(range.start).unwrap()
1310    }
1311
1312    /// Attempt to resolve [`device_offset`][Self::device_offset].
1313    pub fn device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1314        let data = self.data;
1315        self.device_offset().resolve(data)
1316    }
1317}
1318
1319#[cfg(feature = "experimental_traverse")]
1320impl<'a> SomeTable<'a> for BaseCoordFormat3<'a> {
1321    fn type_name(&self) -> &str {
1322        "BaseCoordFormat3"
1323    }
1324    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1325        match idx {
1326            0usize => Some(Field::new("base_coord_format", self.base_coord_format())),
1327            1usize => Some(Field::new("coordinate", self.coordinate())),
1328            2usize => Some(Field::new(
1329                "device_offset",
1330                FieldType::offset(self.device_offset(), self.device()),
1331            )),
1332            _ => None,
1333        }
1334    }
1335}
1336
1337#[cfg(feature = "experimental_traverse")]
1338#[allow(clippy::needless_lifetimes)]
1339impl<'a> std::fmt::Debug for BaseCoordFormat3<'a> {
1340    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1341        (self as &dyn SomeTable<'a>).fmt(f)
1342    }
1343}