Skip to main content

read_fonts/generated/
generated_morx.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 Morx<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.chains_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 Morx<'_> {
19    /// `morx`
20    const TAG: Tag = Tag::new(b"morx");
21}
22
23impl ReadArgs for Morx<'_> {
24    type Args = ();
25}
26
27impl<'a> FontRead<'a> for Morx<'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 MorxFixedHeader {
45    pub version: BigEndian<u16>,
46    pub unused: BigEndian<u16>,
47    pub n_chains: BigEndian<u32>,
48}
49
50#[allow(clippy::absurd_extreme_comparisons)]
51const _: () = assert!(std::mem::size_of::<MorxFixedHeader>() <= Morx::MIN_SIZE);
52
53/// The [morx (Extended Glyph Metamorphosis)](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html) table.
54#[derive(Clone)]
55pub struct Morx<'a> {
56    data: TableDataRef<'a, MorxFixedHeader>,
57}
58
59#[allow(clippy::needless_lifetimes)]
60impl<'a> Morx<'a> {
61    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
62    basic_table_impls!(impl_the_methods);
63
64    /// Version number of the extended glyph metamorphosis table (either 2 or 3).
65    pub fn version(&self) -> u16 {
66        self.data.header().version.get()
67    }
68
69    /// Number of metamorphosis chains contained in this table.
70    pub fn n_chains(&self) -> u32 {
71        self.data.header().n_chains.get()
72    }
73
74    pub fn chains(&self) -> VarLenArray<'a, Chain<'a>> {
75        let range = self.chains_byte_range();
76        self.offset_data()
77            .split_off(range.start)
78            .and_then(|d| VarLenArray::read(d).ok())
79            .unwrap_or_default()
80    }
81
82    pub fn version_byte_range(&self) -> Range<usize> {
83        let start = 0;
84        let end = start + u16::RAW_BYTE_LEN;
85        start..end
86    }
87
88    pub fn unused_byte_range(&self) -> Range<usize> {
89        let start = self.version_byte_range().end;
90        let end = start + u16::RAW_BYTE_LEN;
91        start..end
92    }
93
94    pub fn n_chains_byte_range(&self) -> Range<usize> {
95        let start = self.unused_byte_range().end;
96        let end = start + u32::RAW_BYTE_LEN;
97        start..end
98    }
99
100    pub fn chains_byte_range(&self) -> Range<usize> {
101        let n_chains = self.n_chains();
102        let start = self.n_chains_byte_range().end;
103        let end = start + {
104            let data = self.offset_data().split_off(start).unwrap_or_default();
105            <Chain as VarSize>::total_len_for_count(data, transforms::to_usize(n_chains))
106                .unwrap_or(0)
107        };
108        start..end
109    }
110}
111
112const _: () = assert!(FontData::default_data_long_enough(Morx::MIN_SIZE));
113
114impl Default for Morx<'_> {
115    fn default() -> Self {
116        Self {
117            data: TableDataRef::new(FontData::default_table_data().as_bytes())
118                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
119        }
120    }
121}
122
123impl<'a> MinByteRange<'a> for Chain<'a> {
124    fn min_byte_range(&self) -> Range<usize> {
125        0..self.subtables_byte_range().end
126    }
127    fn min_table_bytes(&self) -> &'a [u8] {
128        let range = self.min_byte_range();
129        self.offset_data().as_bytes().get(range).unwrap_or_default()
130    }
131}
132
133impl ReadArgs for Chain<'_> {
134    type Args = ();
135}
136
137impl<'a> FontRead<'a> for Chain<'a> {
138    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
139        #[allow(clippy::absurd_extreme_comparisons)]
140        if data.len() < Self::MIN_SIZE {
141            return Err(ReadError::OutOfBounds);
142        }
143        let Some(data) = TableDataRef::new(data.as_bytes()) else {
144            return Err(ReadError::OutOfBounds);
145        };
146        Ok(Self { data })
147    }
148}
149
150/// The fields at the start of the table, which are read directly.
151#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
152#[repr(C, packed)]
153#[doc(hidden)]
154pub struct ChainFixedHeader {
155    pub default_flags: BigEndian<u32>,
156    pub chain_length: BigEndian<u32>,
157    pub n_feature_entries: BigEndian<u32>,
158    pub n_subtables: BigEndian<u32>,
159}
160
161#[allow(clippy::absurd_extreme_comparisons)]
162const _: () = assert!(std::mem::size_of::<ChainFixedHeader>() <= Chain::MIN_SIZE);
163
164/// A chain in a `morx` table.
165#[derive(Clone)]
166pub struct Chain<'a> {
167    data: TableDataRef<'a, ChainFixedHeader>,
168}
169
170#[allow(clippy::needless_lifetimes)]
171impl<'a> Chain<'a> {
172    pub const MIN_SIZE: usize =
173        (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
174    basic_table_impls!(impl_the_methods);
175
176    /// The default specification for subtables.
177    pub fn default_flags(&self) -> u32 {
178        self.data.header().default_flags.get()
179    }
180
181    /// Total byte count, including this header; must be a multiple of 4.
182    pub fn chain_length(&self) -> u32 {
183        self.data.header().chain_length.get()
184    }
185
186    /// Number of feature subtable entries.
187    pub fn n_feature_entries(&self) -> u32 {
188        self.data.header().n_feature_entries.get()
189    }
190
191    /// The number of subtables in the chain.
192    pub fn n_subtables(&self) -> u32 {
193        self.data.header().n_subtables.get()
194    }
195
196    /// Feature entries for this chain.
197    pub fn features(&self) -> &'a [Feature] {
198        let range = self.features_byte_range();
199        self.offset_data()
200            .read_array(range)
201            .ok()
202            .unwrap_or_default()
203    }
204
205    /// Array of chain subtables.
206    pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
207        let range = self.subtables_byte_range();
208        self.offset_data()
209            .split_off(range.start)
210            .and_then(|d| VarLenArray::read(d).ok())
211            .unwrap_or_default()
212    }
213
214    pub fn default_flags_byte_range(&self) -> Range<usize> {
215        let start = 0;
216        let end = start + u32::RAW_BYTE_LEN;
217        start..end
218    }
219
220    pub fn chain_length_byte_range(&self) -> Range<usize> {
221        let start = self.default_flags_byte_range().end;
222        let end = start + u32::RAW_BYTE_LEN;
223        start..end
224    }
225
226    pub fn n_feature_entries_byte_range(&self) -> Range<usize> {
227        let start = self.chain_length_byte_range().end;
228        let end = start + u32::RAW_BYTE_LEN;
229        start..end
230    }
231
232    pub fn n_subtables_byte_range(&self) -> Range<usize> {
233        let start = self.n_feature_entries_byte_range().end;
234        let end = start + u32::RAW_BYTE_LEN;
235        start..end
236    }
237
238    pub fn features_byte_range(&self) -> Range<usize> {
239        let n_feature_entries = self.n_feature_entries();
240        let start = self.n_subtables_byte_range().end;
241        let end =
242            start + (transforms::to_usize(n_feature_entries)).saturating_mul(Feature::RAW_BYTE_LEN);
243        start..end
244    }
245
246    pub fn subtables_byte_range(&self) -> Range<usize> {
247        let n_subtables = self.n_subtables();
248        let start = self.features_byte_range().end;
249        let end = start + {
250            let data = self.offset_data().split_off(start).unwrap_or_default();
251            <Subtable as VarSize>::total_len_for_count(data, transforms::to_usize(n_subtables))
252                .unwrap_or(0)
253        };
254        start..end
255    }
256}
257
258const _: () = assert!(FontData::default_data_long_enough(Chain::MIN_SIZE));
259
260impl Default for Chain<'_> {
261    fn default() -> Self {
262        Self {
263            data: TableDataRef::new(FontData::default_table_data().as_bytes())
264                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
265        }
266    }
267}
268
269/// Used to compute the sub-feature flags for a list of requested features and settings.
270#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
271#[repr(C)]
272#[repr(packed)]
273pub struct Feature {
274    /// The type of feature.
275    pub feature_type: BigEndian<u16>,
276    /// The feature's setting (aka selector).
277    pub feature_settings: BigEndian<u16>,
278    /// Flags for the settings that this feature and setting enables.
279    pub enable_flags: BigEndian<u32>,
280    /// Complement of flags for the settings that this feature and setting disable.
281    pub disable_flags: BigEndian<u32>,
282}
283
284impl Feature {
285    /// The type of feature.
286    pub fn feature_type(&self) -> u16 {
287        self.feature_type.get()
288    }
289
290    /// The feature's setting (aka selector).
291    pub fn feature_settings(&self) -> u16 {
292        self.feature_settings.get()
293    }
294
295    /// Flags for the settings that this feature and setting enables.
296    pub fn enable_flags(&self) -> u32 {
297        self.enable_flags.get()
298    }
299
300    /// Complement of flags for the settings that this feature and setting disable.
301    pub fn disable_flags(&self) -> u32 {
302        self.disable_flags.get()
303    }
304}
305
306impl FixedSize for Feature {
307    const RAW_BYTE_LEN: usize =
308        u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
309}
310
311impl<'a> MinByteRange<'a> for Subtable<'a> {
312    fn min_byte_range(&self) -> Range<usize> {
313        0..self.data_byte_range().end
314    }
315    fn min_table_bytes(&self) -> &'a [u8] {
316        let range = self.min_byte_range();
317        self.offset_data().as_bytes().get(range).unwrap_or_default()
318    }
319}
320
321impl ReadArgs for Subtable<'_> {
322    type Args = ();
323}
324
325impl<'a> FontRead<'a> for Subtable<'a> {
326    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
327        #[allow(clippy::absurd_extreme_comparisons)]
328        if data.len() < Self::MIN_SIZE {
329            return Err(ReadError::OutOfBounds);
330        }
331        let Some(data) = TableDataRef::new(data.as_bytes()) else {
332            return Err(ReadError::OutOfBounds);
333        };
334        Ok(Self { data })
335    }
336}
337
338/// The fields at the start of the table, which are read directly.
339#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
340#[repr(C, packed)]
341#[doc(hidden)]
342pub struct SubtableFixedHeader {
343    pub length: BigEndian<u32>,
344    pub coverage: BigEndian<u32>,
345    pub sub_feature_flags: BigEndian<u32>,
346}
347
348#[allow(clippy::absurd_extreme_comparisons)]
349const _: () = assert!(std::mem::size_of::<SubtableFixedHeader>() <= Subtable::MIN_SIZE);
350
351/// A subtable in a `morx` chain.
352#[derive(Clone)]
353pub struct Subtable<'a> {
354    data: TableDataRef<'a, SubtableFixedHeader>,
355}
356
357#[allow(clippy::needless_lifetimes)]
358impl<'a> Subtable<'a> {
359    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
360    basic_table_impls!(impl_the_methods);
361
362    /// Total subtable length, including this header.
363    pub fn length(&self) -> u32 {
364        self.data.header().length.get()
365    }
366
367    /// Coverage flags and subtable type.
368    pub fn coverage(&self) -> u32 {
369        self.data.header().coverage.get()
370    }
371
372    /// The 32-bit mask identifying which subtable this is (the subtable being executed if the AND of this value and the processed defaultFlags is nonzero).
373    pub fn sub_feature_flags(&self) -> u32 {
374        self.data.header().sub_feature_flags.get()
375    }
376
377    /// Data for specific subtable.
378    pub fn data(&self) -> &'a [u8] {
379        let range = self.data_byte_range();
380        self.offset_data()
381            .read_array(range)
382            .ok()
383            .unwrap_or_default()
384    }
385
386    pub fn length_byte_range(&self) -> Range<usize> {
387        let start = 0;
388        let end = start + u32::RAW_BYTE_LEN;
389        start..end
390    }
391
392    pub fn coverage_byte_range(&self) -> Range<usize> {
393        let start = self.length_byte_range().end;
394        let end = start + u32::RAW_BYTE_LEN;
395        start..end
396    }
397
398    pub fn sub_feature_flags_byte_range(&self) -> Range<usize> {
399        let start = self.coverage_byte_range().end;
400        let end = start + u32::RAW_BYTE_LEN;
401        start..end
402    }
403
404    pub fn data_byte_range(&self) -> Range<usize> {
405        let start = self.sub_feature_flags_byte_range().end;
406        let end = start
407            + self.offset_data().len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
408        start..end
409    }
410}
411
412const _: () = assert!(FontData::default_data_long_enough(Subtable::MIN_SIZE));
413
414impl Default for Subtable<'_> {
415    fn default() -> Self {
416        Self {
417            data: TableDataRef::new(FontData::default_table_data().as_bytes())
418                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
419        }
420    }
421}
422
423/// Entry payload in a contextual subtable state machine.
424#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
425#[repr(C)]
426#[repr(packed)]
427pub struct ContextualEntryData {
428    /// Index of the substitution table for the marked glyph (use 0xFFFF for
429    /// none).
430    pub mark_index: BigEndian<u16>,
431    /// Index of the substitution table for the current glyph (use 0xFFFF for
432    /// none)
433    pub current_index: BigEndian<u16>,
434}
435
436impl ContextualEntryData {
437    /// Index of the substitution table for the marked glyph (use 0xFFFF for
438    /// none).
439    pub fn mark_index(&self) -> u16 {
440        self.mark_index.get()
441    }
442
443    /// Index of the substitution table for the current glyph (use 0xFFFF for
444    /// none)
445    pub fn current_index(&self) -> u16 {
446        self.current_index.get()
447    }
448}
449
450impl FixedSize for ContextualEntryData {
451    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
452}
453
454/// Entry payload in an insertion subtable state machine.
455#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
456#[repr(C)]
457#[repr(packed)]
458pub struct InsertionEntryData {
459    /// Zero-based index into the insertion glyph table. The number of glyphs
460    /// to be inserted is contained in the currentInsertCount field in the
461    /// flags (see below). A value of 0xFFFF indicates no insertion is to be done.
462    pub current_insert_index: BigEndian<u16>,
463    /// Zero-based index into the insertion glyph table. The number of glyphs
464    /// to be inserted is contained in the markedInsertCount field in the
465    /// flags (see below). A value of 0xFFFF indicates no insertion is to be
466    /// done.
467    pub marked_insert_index: BigEndian<u16>,
468}
469
470impl InsertionEntryData {
471    /// Zero-based index into the insertion glyph table. The number of glyphs
472    /// to be inserted is contained in the currentInsertCount field in the
473    /// flags (see below). A value of 0xFFFF indicates no insertion is to be done.
474    pub fn current_insert_index(&self) -> u16 {
475        self.current_insert_index.get()
476    }
477
478    /// Zero-based index into the insertion glyph table. The number of glyphs
479    /// to be inserted is contained in the markedInsertCount field in the
480    /// flags (see below). A value of 0xFFFF indicates no insertion is to be
481    /// done.
482    pub fn marked_insert_index(&self) -> u16 {
483        self.marked_insert_index.get()
484    }
485}
486
487impl FixedSize for InsertionEntryData {
488    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
489}