Skip to main content

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