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