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