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.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        Ok(Self { data })
34    }
35}
36
37/// The [morx (Extended Glyph Metamorphosis)](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html) table.
38#[derive(Clone)]
39pub struct Morx<'a> {
40    data: FontData<'a>,
41}
42
43#[allow(clippy::needless_lifetimes)]
44impl<'a> Morx<'a> {
45    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
46    basic_table_impls!(impl_the_methods);
47
48    /// Version number of the extended glyph metamorphosis table (either 2 or 3).
49    pub fn version(&self) -> u16 {
50        let range = self.version_byte_range();
51        self.data.read_at(range.start).ok().unwrap()
52    }
53
54    /// Number of metamorphosis chains contained in this table.
55    pub fn n_chains(&self) -> u32 {
56        let range = self.n_chains_byte_range();
57        self.data.read_at(range.start).ok().unwrap()
58    }
59
60    pub fn chains(&self) -> VarLenArray<'a, Chain<'a>> {
61        let range = self.chains_byte_range();
62        self.data
63            .split_off(range.start)
64            .and_then(|d| VarLenArray::read(d).ok())
65            .unwrap_or_default()
66    }
67
68    pub fn version_byte_range(&self) -> Range<usize> {
69        let start = 0;
70        let end = start + u16::RAW_BYTE_LEN;
71        start..end
72    }
73
74    pub fn unused_byte_range(&self) -> Range<usize> {
75        let start = self.version_byte_range().end;
76        let end = start + u16::RAW_BYTE_LEN;
77        start..end
78    }
79
80    pub fn n_chains_byte_range(&self) -> Range<usize> {
81        let start = self.unused_byte_range().end;
82        let end = start + u32::RAW_BYTE_LEN;
83        start..end
84    }
85
86    pub fn chains_byte_range(&self) -> Range<usize> {
87        let n_chains = self.n_chains();
88        let start = self.n_chains_byte_range().end;
89        let end = start + {
90            let data = self.data.split_off(start).unwrap_or_default();
91            <Chain as VarSize>::total_len_for_count(data, transforms::to_usize(n_chains))
92                .unwrap_or(0)
93        };
94        start..end
95    }
96}
97
98const _: () = assert!(FontData::default_data_long_enough(Morx::MIN_SIZE));
99
100impl Default for Morx<'_> {
101    fn default() -> Self {
102        Self {
103            data: FontData::default_table_data(),
104        }
105    }
106}
107
108#[cfg(feature = "experimental_traverse")]
109impl<'a> SomeTable<'a> for Morx<'a> {
110    fn type_name(&self) -> &str {
111        "Morx"
112    }
113    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
114        match idx {
115            0usize => Some(Field::new("version", self.version())),
116            1usize => Some(Field::new("n_chains", self.n_chains())),
117            2usize => Some(Field::new(
118                "chains",
119                traversal::FieldType::var_array("Chain", self.chains(), self.offset_data()),
120            )),
121            _ => None,
122        }
123    }
124}
125
126#[cfg(feature = "experimental_traverse")]
127#[allow(clippy::needless_lifetimes)]
128impl<'a> std::fmt::Debug for Morx<'a> {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        (self as &dyn SomeTable<'a>).fmt(f)
131    }
132}
133
134impl<'a> MinByteRange<'a> for Chain<'a> {
135    fn min_byte_range(&self) -> Range<usize> {
136        0..self.subtables_byte_range().end
137    }
138    fn min_table_bytes(&self) -> &'a [u8] {
139        let range = self.min_byte_range();
140        self.data.as_bytes().get(range).unwrap_or_default()
141    }
142}
143
144impl ReadArgs for Chain<'_> {
145    type Args = ();
146}
147
148impl<'a> FontRead<'a> for Chain<'a> {
149    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
150        #[allow(clippy::absurd_extreme_comparisons)]
151        if data.len() < Self::MIN_SIZE {
152            return Err(ReadError::OutOfBounds);
153        }
154        Ok(Self { data })
155    }
156}
157
158/// A chain in a `morx` table.
159#[derive(Clone)]
160pub struct Chain<'a> {
161    data: FontData<'a>,
162}
163
164#[allow(clippy::needless_lifetimes)]
165impl<'a> Chain<'a> {
166    pub const MIN_SIZE: usize =
167        (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
168    basic_table_impls!(impl_the_methods);
169
170    /// The default specification for subtables.
171    pub fn default_flags(&self) -> u32 {
172        let range = self.default_flags_byte_range();
173        self.data.read_at(range.start).ok().unwrap()
174    }
175
176    /// Total byte count, including this header; must be a multiple of 4.
177    pub fn chain_length(&self) -> u32 {
178        let range = self.chain_length_byte_range();
179        self.data.read_at(range.start).ok().unwrap()
180    }
181
182    /// Number of feature subtable entries.
183    pub fn n_feature_entries(&self) -> u32 {
184        let range = self.n_feature_entries_byte_range();
185        self.data.read_at(range.start).ok().unwrap()
186    }
187
188    /// The number of subtables in the chain.
189    pub fn n_subtables(&self) -> u32 {
190        let range = self.n_subtables_byte_range();
191        self.data.read_at(range.start).ok().unwrap()
192    }
193
194    /// Feature entries for this chain.
195    pub fn features(&self) -> &'a [Feature] {
196        let range = self.features_byte_range();
197        self.data.read_array(range).ok().unwrap_or_default()
198    }
199
200    /// Array of chain subtables.
201    pub fn subtables(&self) -> VarLenArray<'a, Subtable<'a>> {
202        let range = self.subtables_byte_range();
203        self.data
204            .split_off(range.start)
205            .and_then(|d| VarLenArray::read(d).ok())
206            .unwrap_or_default()
207    }
208
209    pub fn default_flags_byte_range(&self) -> Range<usize> {
210        let start = 0;
211        let end = start + u32::RAW_BYTE_LEN;
212        start..end
213    }
214
215    pub fn chain_length_byte_range(&self) -> Range<usize> {
216        let start = self.default_flags_byte_range().end;
217        let end = start + u32::RAW_BYTE_LEN;
218        start..end
219    }
220
221    pub fn n_feature_entries_byte_range(&self) -> Range<usize> {
222        let start = self.chain_length_byte_range().end;
223        let end = start + u32::RAW_BYTE_LEN;
224        start..end
225    }
226
227    pub fn n_subtables_byte_range(&self) -> Range<usize> {
228        let start = self.n_feature_entries_byte_range().end;
229        let end = start + u32::RAW_BYTE_LEN;
230        start..end
231    }
232
233    pub fn features_byte_range(&self) -> Range<usize> {
234        let n_feature_entries = self.n_feature_entries();
235        let start = self.n_subtables_byte_range().end;
236        let end =
237            start + (transforms::to_usize(n_feature_entries)).saturating_mul(Feature::RAW_BYTE_LEN);
238        start..end
239    }
240
241    pub fn subtables_byte_range(&self) -> Range<usize> {
242        let n_subtables = self.n_subtables();
243        let start = self.features_byte_range().end;
244        let end = start + {
245            let data = self.data.split_off(start).unwrap_or_default();
246            <Subtable as VarSize>::total_len_for_count(data, transforms::to_usize(n_subtables))
247                .unwrap_or(0)
248        };
249        start..end
250    }
251}
252
253const _: () = assert!(FontData::default_data_long_enough(Chain::MIN_SIZE));
254
255impl Default for Chain<'_> {
256    fn default() -> Self {
257        Self {
258            data: FontData::default_table_data(),
259        }
260    }
261}
262
263#[cfg(feature = "experimental_traverse")]
264impl<'a> SomeTable<'a> for Chain<'a> {
265    fn type_name(&self) -> &str {
266        "Chain"
267    }
268    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
269        match idx {
270            0usize => Some(Field::new("default_flags", self.default_flags())),
271            1usize => Some(Field::new("chain_length", self.chain_length())),
272            2usize => Some(Field::new("n_feature_entries", self.n_feature_entries())),
273            3usize => Some(Field::new("n_subtables", self.n_subtables())),
274            4usize => Some(Field::new(
275                "features",
276                traversal::FieldType::array_of_records(
277                    stringify!(Feature),
278                    self.features(),
279                    self.offset_data(),
280                ),
281            )),
282            5usize => Some(Field::new(
283                "subtables",
284                traversal::FieldType::var_array("Subtable", self.subtables(), self.offset_data()),
285            )),
286            _ => None,
287        }
288    }
289}
290
291#[cfg(feature = "experimental_traverse")]
292#[allow(clippy::needless_lifetimes)]
293impl<'a> std::fmt::Debug for Chain<'a> {
294    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295        (self as &dyn SomeTable<'a>).fmt(f)
296    }
297}
298
299/// Used to compute the sub-feature flags for a list of requested features and settings.
300#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
301#[repr(C)]
302#[repr(packed)]
303pub struct Feature {
304    /// The type of feature.
305    pub feature_type: BigEndian<u16>,
306    /// The feature's setting (aka selector).
307    pub feature_settings: BigEndian<u16>,
308    /// Flags for the settings that this feature and setting enables.
309    pub enable_flags: BigEndian<u32>,
310    /// Complement of flags for the settings that this feature and setting disable.
311    pub disable_flags: BigEndian<u32>,
312}
313
314impl Feature {
315    /// The type of feature.
316    pub fn feature_type(&self) -> u16 {
317        self.feature_type.get()
318    }
319
320    /// The feature's setting (aka selector).
321    pub fn feature_settings(&self) -> u16 {
322        self.feature_settings.get()
323    }
324
325    /// Flags for the settings that this feature and setting enables.
326    pub fn enable_flags(&self) -> u32 {
327        self.enable_flags.get()
328    }
329
330    /// Complement of flags for the settings that this feature and setting disable.
331    pub fn disable_flags(&self) -> u32 {
332        self.disable_flags.get()
333    }
334}
335
336impl FixedSize for Feature {
337    const RAW_BYTE_LEN: usize =
338        u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
339}
340
341#[cfg(feature = "experimental_traverse")]
342impl<'a> SomeRecord<'a> for Feature {
343    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
344        RecordResolver {
345            name: "Feature",
346            get_field: Box::new(move |idx, _data| match idx {
347                0usize => Some(Field::new("feature_type", self.feature_type())),
348                1usize => Some(Field::new("feature_settings", self.feature_settings())),
349                2usize => Some(Field::new("enable_flags", self.enable_flags())),
350                3usize => Some(Field::new("disable_flags", self.disable_flags())),
351                _ => None,
352            }),
353            data,
354        }
355    }
356}
357
358impl<'a> MinByteRange<'a> for Subtable<'a> {
359    fn min_byte_range(&self) -> Range<usize> {
360        0..self.data_byte_range().end
361    }
362    fn min_table_bytes(&self) -> &'a [u8] {
363        let range = self.min_byte_range();
364        self.data.as_bytes().get(range).unwrap_or_default()
365    }
366}
367
368impl ReadArgs for Subtable<'_> {
369    type Args = ();
370}
371
372impl<'a> FontRead<'a> for Subtable<'a> {
373    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
374        #[allow(clippy::absurd_extreme_comparisons)]
375        if data.len() < Self::MIN_SIZE {
376            return Err(ReadError::OutOfBounds);
377        }
378        Ok(Self { data })
379    }
380}
381
382/// A subtable in a `morx` chain.
383#[derive(Clone)]
384pub struct Subtable<'a> {
385    data: FontData<'a>,
386}
387
388#[allow(clippy::needless_lifetimes)]
389impl<'a> Subtable<'a> {
390    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
391    basic_table_impls!(impl_the_methods);
392
393    /// Total subtable length, including this header.
394    pub fn length(&self) -> u32 {
395        let range = self.length_byte_range();
396        self.data.read_at(range.start).ok().unwrap()
397    }
398
399    /// Coverage flags and subtable type.
400    pub fn coverage(&self) -> u32 {
401        let range = self.coverage_byte_range();
402        self.data.read_at(range.start).ok().unwrap()
403    }
404
405    /// 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).
406    pub fn sub_feature_flags(&self) -> u32 {
407        let range = self.sub_feature_flags_byte_range();
408        self.data.read_at(range.start).ok().unwrap()
409    }
410
411    /// Data for specific subtable.
412    pub fn data(&self) -> &'a [u8] {
413        let range = self.data_byte_range();
414        self.data.read_array(range).ok().unwrap_or_default()
415    }
416
417    pub fn length_byte_range(&self) -> Range<usize> {
418        let start = 0;
419        let end = start + u32::RAW_BYTE_LEN;
420        start..end
421    }
422
423    pub fn coverage_byte_range(&self) -> Range<usize> {
424        let start = self.length_byte_range().end;
425        let end = start + u32::RAW_BYTE_LEN;
426        start..end
427    }
428
429    pub fn sub_feature_flags_byte_range(&self) -> Range<usize> {
430        let start = self.coverage_byte_range().end;
431        let end = start + u32::RAW_BYTE_LEN;
432        start..end
433    }
434
435    pub fn data_byte_range(&self) -> Range<usize> {
436        let start = self.sub_feature_flags_byte_range().end;
437        let end =
438            start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
439        start..end
440    }
441}
442
443const _: () = assert!(FontData::default_data_long_enough(Subtable::MIN_SIZE));
444
445impl Default for Subtable<'_> {
446    fn default() -> Self {
447        Self {
448            data: FontData::default_table_data(),
449        }
450    }
451}
452
453#[cfg(feature = "experimental_traverse")]
454impl<'a> SomeTable<'a> for Subtable<'a> {
455    fn type_name(&self) -> &str {
456        "Subtable"
457    }
458    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
459        match idx {
460            0usize => Some(Field::new("length", self.length())),
461            1usize => Some(Field::new("coverage", self.coverage())),
462            2usize => Some(Field::new("sub_feature_flags", self.sub_feature_flags())),
463            3usize => Some(Field::new("data", self.data())),
464            _ => None,
465        }
466    }
467}
468
469#[cfg(feature = "experimental_traverse")]
470#[allow(clippy::needless_lifetimes)]
471impl<'a> std::fmt::Debug for Subtable<'a> {
472    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
473        (self as &dyn SomeTable<'a>).fmt(f)
474    }
475}
476
477/// Entry payload in a contextual subtable state machine.
478#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
479#[repr(C)]
480#[repr(packed)]
481pub struct ContextualEntryData {
482    /// Index of the substitution table for the marked glyph (use 0xFFFF for
483    /// none).
484    pub mark_index: BigEndian<u16>,
485    /// Index of the substitution table for the current glyph (use 0xFFFF for
486    /// none)
487    pub current_index: BigEndian<u16>,
488}
489
490impl ContextualEntryData {
491    /// Index of the substitution table for the marked glyph (use 0xFFFF for
492    /// none).
493    pub fn mark_index(&self) -> u16 {
494        self.mark_index.get()
495    }
496
497    /// Index of the substitution table for the current glyph (use 0xFFFF for
498    /// none)
499    pub fn current_index(&self) -> u16 {
500        self.current_index.get()
501    }
502}
503
504impl FixedSize for ContextualEntryData {
505    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
506}
507
508#[cfg(feature = "experimental_traverse")]
509impl<'a> SomeRecord<'a> for ContextualEntryData {
510    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
511        RecordResolver {
512            name: "ContextualEntryData",
513            get_field: Box::new(move |idx, _data| match idx {
514                0usize => Some(Field::new("mark_index", self.mark_index())),
515                1usize => Some(Field::new("current_index", self.current_index())),
516                _ => None,
517            }),
518            data,
519        }
520    }
521}
522
523/// Entry payload in an insertion subtable state machine.
524#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
525#[repr(C)]
526#[repr(packed)]
527pub struct InsertionEntryData {
528    /// Zero-based index into the insertion glyph table. The number of glyphs
529    /// to be inserted is contained in the currentInsertCount field in the
530    /// flags (see below). A value of 0xFFFF indicates no insertion is to be done.
531    pub current_insert_index: BigEndian<u16>,
532    /// Zero-based index into the insertion glyph table. The number of glyphs
533    /// to be inserted is contained in the markedInsertCount field in the
534    /// flags (see below). A value of 0xFFFF indicates no insertion is to be
535    /// done.
536    pub marked_insert_index: BigEndian<u16>,
537}
538
539impl InsertionEntryData {
540    /// Zero-based index into the insertion glyph table. The number of glyphs
541    /// to be inserted is contained in the currentInsertCount field in the
542    /// flags (see below). A value of 0xFFFF indicates no insertion is to be done.
543    pub fn current_insert_index(&self) -> u16 {
544        self.current_insert_index.get()
545    }
546
547    /// Zero-based index into the insertion glyph table. The number of glyphs
548    /// to be inserted is contained in the markedInsertCount field in the
549    /// flags (see below). A value of 0xFFFF indicates no insertion is to be
550    /// done.
551    pub fn marked_insert_index(&self) -> u16 {
552        self.marked_insert_index.get()
553    }
554}
555
556impl FixedSize for InsertionEntryData {
557    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
558}
559
560#[cfg(feature = "experimental_traverse")]
561impl<'a> SomeRecord<'a> for InsertionEntryData {
562    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
563        RecordResolver {
564            name: "InsertionEntryData",
565            get_field: Box::new(move |idx, _data| match idx {
566                0usize => Some(Field::new(
567                    "current_insert_index",
568                    self.current_insert_index(),
569                )),
570                1usize => Some(Field::new(
571                    "marked_insert_index",
572                    self.marked_insert_index(),
573                )),
574                _ => None,
575            }),
576            data,
577        }
578    }
579}