Skip to main content

read_fonts/generated/
generated_math.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 Math<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.math_variants_offset_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.offset_data().as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl TopLevelTable for Math<'_> {
19    /// `MATH`
20    const TAG: Tag = Tag::new(b"MATH");
21}
22
23impl ReadArgs for Math<'_> {
24    type Args = ();
25}
26
27impl<'a> FontRead<'a> for Math<'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 MathFixedHeader {
45    pub version: BigEndian<MajorMinor>,
46    pub math_constants_offset: BigEndian<Offset16>,
47    pub math_glyph_info_offset: BigEndian<Offset16>,
48    pub math_variants_offset: BigEndian<Offset16>,
49}
50
51#[allow(clippy::absurd_extreme_comparisons)]
52const _: () = assert!(std::mem::size_of::<MathFixedHeader>() <= Math::MIN_SIZE);
53
54/// The [MATH](https://learn.microsoft.com/en-us/typography/opentype/spec/math) table
55#[derive(Clone)]
56pub struct Math<'a> {
57    data: TableDataRef<'a, MathFixedHeader>,
58}
59
60#[allow(clippy::needless_lifetimes)]
61impl<'a> Math<'a> {
62    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
63        + Offset16::RAW_BYTE_LEN
64        + Offset16::RAW_BYTE_LEN
65        + Offset16::RAW_BYTE_LEN);
66    basic_table_impls!(impl_the_methods);
67
68    /// (major, minor) Version for the MATH table (1,0)
69    pub fn version(&self) -> MajorMinor {
70        self.data.header().version.get()
71    }
72
73    /// Offset to MathConstants table, from beginning of MATH table.
74    pub fn math_constants_offset(&self) -> Offset16 {
75        self.data.header().math_constants_offset.get()
76    }
77
78    /// Attempt to resolve [`math_constants_offset`][Self::math_constants_offset].
79    pub fn math_constants(&self) -> Result<MathConstants<'a>, ReadError> {
80        let data = self.offset_data();
81        self.math_constants_offset().resolve(data)
82    }
83
84    /// Offset to MathGlyphInfo table, from beginning of MATH table.
85    pub fn math_glyph_info_offset(&self) -> Offset16 {
86        self.data.header().math_glyph_info_offset.get()
87    }
88
89    /// Attempt to resolve [`math_glyph_info_offset`][Self::math_glyph_info_offset].
90    pub fn math_glyph_info(&self) -> Result<MathGlyphInfo<'a>, ReadError> {
91        let data = self.offset_data();
92        self.math_glyph_info_offset().resolve(data)
93    }
94
95    /// Offset to MathVariants table, from beginning of MATH table.
96    pub fn math_variants_offset(&self) -> Offset16 {
97        self.data.header().math_variants_offset.get()
98    }
99
100    /// Attempt to resolve [`math_variants_offset`][Self::math_variants_offset].
101    pub fn math_variants(&self) -> Result<MathVariants<'a>, ReadError> {
102        let data = self.offset_data();
103        self.math_variants_offset().resolve(data)
104    }
105
106    pub fn version_byte_range(&self) -> Range<usize> {
107        let start = 0;
108        let end = start + MajorMinor::RAW_BYTE_LEN;
109        start..end
110    }
111
112    pub fn math_constants_offset_byte_range(&self) -> Range<usize> {
113        let start = self.version_byte_range().end;
114        let end = start + Offset16::RAW_BYTE_LEN;
115        start..end
116    }
117
118    pub fn math_glyph_info_offset_byte_range(&self) -> Range<usize> {
119        let start = self.math_constants_offset_byte_range().end;
120        let end = start + Offset16::RAW_BYTE_LEN;
121        start..end
122    }
123
124    pub fn math_variants_offset_byte_range(&self) -> Range<usize> {
125        let start = self.math_glyph_info_offset_byte_range().end;
126        let end = start + Offset16::RAW_BYTE_LEN;
127        start..end
128    }
129}
130
131const _: () = assert!(FontData::default_data_long_enough(Math::MIN_SIZE));
132
133impl Default for Math<'_> {
134    fn default() -> Self {
135        Self {
136            data: TableDataRef::new(FontData::default_table_data().as_bytes())
137                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
138        }
139    }
140}
141
142/// [MathValueRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord)
143///
144/// The device offset is measured from the beginning of the table that contains
145/// the record, not from the record itself.
146#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
147#[repr(C)]
148#[repr(packed)]
149pub struct MathValueRecord {
150    /// The X or Y value in design units.
151    pub value: BigEndian<FWord>,
152    /// Offset to the Device table (non-variable font) / VariationIndex table
153    /// (variable font) for this value, from the beginning of the parent table.
154    /// May be NULL.
155    pub device_offset: BigEndian<Nullable<Offset16>>,
156}
157
158impl MathValueRecord {
159    /// The X or Y value in design units.
160    pub fn value(&self) -> FWord {
161        self.value.get()
162    }
163
164    /// Offset to the Device table (non-variable font) / VariationIndex table
165    /// (variable font) for this value, from the beginning of the parent table.
166    /// May be NULL.
167    pub fn device_offset(&self) -> Nullable<Offset16> {
168        self.device_offset.get()
169    }
170
171    /// Offset to the Device table (non-variable font) / VariationIndex table
172    /// (variable font) for this value, from the beginning of the parent table.
173    /// May be NULL.
174    ///
175    /// The `data` argument should be retrieved from the parent table
176    /// By calling its `offset_data` method.
177    pub fn device<'a>(
178        &self,
179        data: FontData<'a>,
180    ) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
181        self.device_offset().resolve(data)
182    }
183}
184
185impl FixedSize for MathValueRecord {
186    const RAW_BYTE_LEN: usize = FWord::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
187}
188
189impl<'a> MinByteRange<'a> for MathConstants<'a> {
190    fn min_byte_range(&self) -> Range<usize> {
191        0..self.radical_degree_bottom_raise_percent_byte_range().end
192    }
193    fn min_table_bytes(&self) -> &'a [u8] {
194        let range = self.min_byte_range();
195        self.offset_data().as_bytes().get(range).unwrap_or_default()
196    }
197}
198
199impl ReadArgs for MathConstants<'_> {
200    type Args = ();
201}
202
203impl<'a> FontRead<'a> for MathConstants<'a> {
204    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
205        #[allow(clippy::absurd_extreme_comparisons)]
206        if data.len() < Self::MIN_SIZE {
207            return Err(ReadError::OutOfBounds);
208        }
209        let Some(data) = TableDataRef::new(data.as_bytes()) else {
210            return Err(ReadError::OutOfBounds);
211        };
212        Ok(Self { data })
213    }
214}
215
216/// The fields at the start of the table, which are read directly.
217#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
218#[repr(C, packed)]
219#[doc(hidden)]
220pub struct MathConstantsFixedHeader {
221    pub script_percent_scale_down: BigEndian<i16>,
222    pub script_script_percent_scale_down: BigEndian<i16>,
223    pub delimited_sub_formula_min_height: BigEndian<UfWord>,
224    pub display_operator_min_height: BigEndian<UfWord>,
225    pub math_leading: MathValueRecord,
226    pub axis_height: MathValueRecord,
227    pub accent_base_height: MathValueRecord,
228    pub flattened_accent_base_height: MathValueRecord,
229    pub subscript_shift_down: MathValueRecord,
230    pub subscript_top_max: MathValueRecord,
231    pub subscript_baseline_drop_min: MathValueRecord,
232    pub superscript_shift_up: MathValueRecord,
233    pub superscript_shift_up_cramped: MathValueRecord,
234    pub superscript_bottom_min: MathValueRecord,
235    pub superscript_baseline_drop_max: MathValueRecord,
236    pub sub_superscript_gap_min: MathValueRecord,
237    pub superscript_bottom_max_with_subscript: MathValueRecord,
238    pub space_after_script: MathValueRecord,
239    pub upper_limit_gap_min: MathValueRecord,
240    pub upper_limit_baseline_rise_min: MathValueRecord,
241    pub lower_limit_gap_min: MathValueRecord,
242    pub lower_limit_baseline_drop_min: MathValueRecord,
243    pub stack_top_shift_up: MathValueRecord,
244    pub stack_top_display_style_shift_up: MathValueRecord,
245    pub stack_bottom_shift_down: MathValueRecord,
246    pub stack_bottom_display_style_shift_down: MathValueRecord,
247    pub stack_gap_min: MathValueRecord,
248    pub stack_display_style_gap_min: MathValueRecord,
249    pub stretch_stack_top_shift_up: MathValueRecord,
250    pub stretch_stack_bottom_shift_down: MathValueRecord,
251    pub stretch_stack_gap_above_min: MathValueRecord,
252    pub stretch_stack_gap_below_min: MathValueRecord,
253    pub fraction_numerator_shift_up: MathValueRecord,
254    pub fraction_numerator_display_style_shift_up: MathValueRecord,
255    pub fraction_denominator_shift_down: MathValueRecord,
256    pub fraction_denominator_display_style_shift_down: MathValueRecord,
257    pub fraction_numerator_gap_min: MathValueRecord,
258    pub fraction_num_display_style_gap_min: MathValueRecord,
259    pub fraction_rule_thickness: MathValueRecord,
260    pub fraction_denominator_gap_min: MathValueRecord,
261    pub fraction_denom_display_style_gap_min: MathValueRecord,
262    pub skewed_fraction_horizontal_gap: MathValueRecord,
263    pub skewed_fraction_vertical_gap: MathValueRecord,
264    pub overbar_vertical_gap: MathValueRecord,
265    pub overbar_rule_thickness: MathValueRecord,
266    pub overbar_extra_ascender: MathValueRecord,
267    pub underbar_vertical_gap: MathValueRecord,
268    pub underbar_rule_thickness: MathValueRecord,
269    pub underbar_extra_descender: MathValueRecord,
270    pub radical_vertical_gap: MathValueRecord,
271    pub radical_display_style_vertical_gap: MathValueRecord,
272    pub radical_rule_thickness: MathValueRecord,
273    pub radical_extra_ascender: MathValueRecord,
274    pub radical_kern_before_degree: MathValueRecord,
275    pub radical_kern_after_degree: MathValueRecord,
276    pub radical_degree_bottom_raise_percent: BigEndian<i16>,
277}
278
279#[allow(clippy::absurd_extreme_comparisons)]
280const _: () = assert!(std::mem::size_of::<MathConstantsFixedHeader>() <= MathConstants::MIN_SIZE);
281
282/// [MathConstants](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table)
283#[derive(Clone)]
284pub struct MathConstants<'a> {
285    data: TableDataRef<'a, MathConstantsFixedHeader>,
286}
287
288#[allow(clippy::needless_lifetimes)]
289impl<'a> MathConstants<'a> {
290    pub const MIN_SIZE: usize = (i16::RAW_BYTE_LEN
291        + i16::RAW_BYTE_LEN
292        + UfWord::RAW_BYTE_LEN
293        + UfWord::RAW_BYTE_LEN
294        + MathValueRecord::RAW_BYTE_LEN
295        + MathValueRecord::RAW_BYTE_LEN
296        + MathValueRecord::RAW_BYTE_LEN
297        + MathValueRecord::RAW_BYTE_LEN
298        + MathValueRecord::RAW_BYTE_LEN
299        + MathValueRecord::RAW_BYTE_LEN
300        + MathValueRecord::RAW_BYTE_LEN
301        + MathValueRecord::RAW_BYTE_LEN
302        + MathValueRecord::RAW_BYTE_LEN
303        + MathValueRecord::RAW_BYTE_LEN
304        + MathValueRecord::RAW_BYTE_LEN
305        + MathValueRecord::RAW_BYTE_LEN
306        + MathValueRecord::RAW_BYTE_LEN
307        + MathValueRecord::RAW_BYTE_LEN
308        + MathValueRecord::RAW_BYTE_LEN
309        + MathValueRecord::RAW_BYTE_LEN
310        + MathValueRecord::RAW_BYTE_LEN
311        + MathValueRecord::RAW_BYTE_LEN
312        + MathValueRecord::RAW_BYTE_LEN
313        + MathValueRecord::RAW_BYTE_LEN
314        + MathValueRecord::RAW_BYTE_LEN
315        + MathValueRecord::RAW_BYTE_LEN
316        + MathValueRecord::RAW_BYTE_LEN
317        + MathValueRecord::RAW_BYTE_LEN
318        + MathValueRecord::RAW_BYTE_LEN
319        + MathValueRecord::RAW_BYTE_LEN
320        + MathValueRecord::RAW_BYTE_LEN
321        + MathValueRecord::RAW_BYTE_LEN
322        + MathValueRecord::RAW_BYTE_LEN
323        + MathValueRecord::RAW_BYTE_LEN
324        + MathValueRecord::RAW_BYTE_LEN
325        + MathValueRecord::RAW_BYTE_LEN
326        + MathValueRecord::RAW_BYTE_LEN
327        + MathValueRecord::RAW_BYTE_LEN
328        + MathValueRecord::RAW_BYTE_LEN
329        + MathValueRecord::RAW_BYTE_LEN
330        + MathValueRecord::RAW_BYTE_LEN
331        + MathValueRecord::RAW_BYTE_LEN
332        + MathValueRecord::RAW_BYTE_LEN
333        + MathValueRecord::RAW_BYTE_LEN
334        + MathValueRecord::RAW_BYTE_LEN
335        + MathValueRecord::RAW_BYTE_LEN
336        + MathValueRecord::RAW_BYTE_LEN
337        + MathValueRecord::RAW_BYTE_LEN
338        + MathValueRecord::RAW_BYTE_LEN
339        + MathValueRecord::RAW_BYTE_LEN
340        + MathValueRecord::RAW_BYTE_LEN
341        + MathValueRecord::RAW_BYTE_LEN
342        + MathValueRecord::RAW_BYTE_LEN
343        + MathValueRecord::RAW_BYTE_LEN
344        + MathValueRecord::RAW_BYTE_LEN
345        + i16::RAW_BYTE_LEN);
346    basic_table_impls!(impl_the_methods);
347
348    /// Percentage of scaling down for level 1 superscripts and subscripts.
349    pub fn script_percent_scale_down(&self) -> i16 {
350        self.data.header().script_percent_scale_down.get()
351    }
352
353    /// Percentage of scaling down for level 2 (scriptScript) superscripts and
354    /// subscripts.
355    pub fn script_script_percent_scale_down(&self) -> i16 {
356        self.data.header().script_script_percent_scale_down.get()
357    }
358
359    /// Minimum height required for a delimited expression (contained within
360    /// parentheses, etc.) to be treated as a sub-formula.
361    pub fn delimited_sub_formula_min_height(&self) -> UfWord {
362        self.data.header().delimited_sub_formula_min_height.get()
363    }
364
365    /// Minimum height of n-ary operators (such as integral and summation) for
366    /// formulas in display mode (that is, appearing as standalone page
367    /// elements, not embedded inline within text).
368    pub fn display_operator_min_height(&self) -> UfWord {
369        self.data.header().display_operator_min_height.get()
370    }
371
372    /// White space to be left between math formulas to ensure proper line
373    /// spacing.
374    pub fn math_leading(&self) -> &'a MathValueRecord {
375        &self.data.header().math_leading
376    }
377
378    /// Axis height of the font.
379    pub fn axis_height(&self) -> &'a MathValueRecord {
380        &self.data.header().axis_height
381    }
382
383    /// Maximum (ink) height of accent base that does not require raising the
384    /// accents.
385    pub fn accent_base_height(&self) -> &'a MathValueRecord {
386        &self.data.header().accent_base_height
387    }
388
389    /// Maximum (ink) height of accent base that does not require flattening the
390    /// accents.
391    pub fn flattened_accent_base_height(&self) -> &'a MathValueRecord {
392        &self.data.header().flattened_accent_base_height
393    }
394
395    /// The standard shift down applied to subscript elements.
396    pub fn subscript_shift_down(&self) -> &'a MathValueRecord {
397        &self.data.header().subscript_shift_down
398    }
399
400    /// Maximum allowed height of the (ink) top of subscripts that does not
401    /// require moving subscripts further down.
402    pub fn subscript_top_max(&self) -> &'a MathValueRecord {
403        &self.data.header().subscript_top_max
404    }
405
406    /// Minimum allowed drop of the baseline of subscripts relative to the (ink)
407    /// bottom of the base.
408    pub fn subscript_baseline_drop_min(&self) -> &'a MathValueRecord {
409        &self.data.header().subscript_baseline_drop_min
410    }
411
412    /// Standard shift up applied to superscript elements.
413    pub fn superscript_shift_up(&self) -> &'a MathValueRecord {
414        &self.data.header().superscript_shift_up
415    }
416
417    /// Standard shift of superscripts relative to the base, in cramped style.
418    pub fn superscript_shift_up_cramped(&self) -> &'a MathValueRecord {
419        &self.data.header().superscript_shift_up_cramped
420    }
421
422    /// Minimum allowed height of the (ink) bottom of superscripts that does not
423    /// require moving subscripts further up.
424    pub fn superscript_bottom_min(&self) -> &'a MathValueRecord {
425        &self.data.header().superscript_bottom_min
426    }
427
428    /// Maximum allowed drop of the baseline of superscripts relative to the
429    /// (ink) top of the base.
430    pub fn superscript_baseline_drop_max(&self) -> &'a MathValueRecord {
431        &self.data.header().superscript_baseline_drop_max
432    }
433
434    /// Minimum gap between the superscript and subscript ink.
435    pub fn sub_superscript_gap_min(&self) -> &'a MathValueRecord {
436        &self.data.header().sub_superscript_gap_min
437    }
438
439    /// The maximum level to which the (ink) bottom of superscript can be
440    /// pushed to increase the gap between superscript and subscript, before
441    /// subscript starts being moved down.
442    pub fn superscript_bottom_max_with_subscript(&self) -> &'a MathValueRecord {
443        &self.data.header().superscript_bottom_max_with_subscript
444    }
445
446    /// Extra white space to be added after each subscript and superscript.
447    pub fn space_after_script(&self) -> &'a MathValueRecord {
448        &self.data.header().space_after_script
449    }
450
451    /// Minimum gap between the (ink) bottom of the upper limit, and the (ink)
452    /// top of the base operator.
453    pub fn upper_limit_gap_min(&self) -> &'a MathValueRecord {
454        &self.data.header().upper_limit_gap_min
455    }
456
457    /// Minimum distance between baseline of upper limit and (ink) top of the
458    /// base operator.
459    pub fn upper_limit_baseline_rise_min(&self) -> &'a MathValueRecord {
460        &self.data.header().upper_limit_baseline_rise_min
461    }
462
463    /// Minimum gap between (ink) top of the lower limit, and (ink) bottom of
464    /// the base operator.
465    pub fn lower_limit_gap_min(&self) -> &'a MathValueRecord {
466        &self.data.header().lower_limit_gap_min
467    }
468
469    /// Minimum distance between baseline of the lower limit and (ink) bottom of
470    /// the base operator.
471    pub fn lower_limit_baseline_drop_min(&self) -> &'a MathValueRecord {
472        &self.data.header().lower_limit_baseline_drop_min
473    }
474
475    /// Standard shift up applied to the top element of a stack.
476    pub fn stack_top_shift_up(&self) -> &'a MathValueRecord {
477        &self.data.header().stack_top_shift_up
478    }
479
480    /// Standard shift up applied to the top element of a stack in display
481    /// style.
482    pub fn stack_top_display_style_shift_up(&self) -> &'a MathValueRecord {
483        &self.data.header().stack_top_display_style_shift_up
484    }
485
486    /// Standard shift down applied to the bottom element of a stack.
487    pub fn stack_bottom_shift_down(&self) -> &'a MathValueRecord {
488        &self.data.header().stack_bottom_shift_down
489    }
490
491    /// Standard shift down applied to the bottom element of a stack in display
492    /// style.
493    pub fn stack_bottom_display_style_shift_down(&self) -> &'a MathValueRecord {
494        &self.data.header().stack_bottom_display_style_shift_down
495    }
496
497    /// Minimum gap between (ink) bottom of the top element of a stack, and the
498    /// (ink) top of the bottom element.
499    pub fn stack_gap_min(&self) -> &'a MathValueRecord {
500        &self.data.header().stack_gap_min
501    }
502
503    /// Minimum gap between (ink) bottom of the top element of a stack, and the
504    /// (ink) top of the bottom element in display style.
505    pub fn stack_display_style_gap_min(&self) -> &'a MathValueRecord {
506        &self.data.header().stack_display_style_gap_min
507    }
508
509    /// Standard shift up applied to the top element of the stretch stack.
510    pub fn stretch_stack_top_shift_up(&self) -> &'a MathValueRecord {
511        &self.data.header().stretch_stack_top_shift_up
512    }
513
514    /// Standard shift down applied to the bottom element of the stretch stack.
515    pub fn stretch_stack_bottom_shift_down(&self) -> &'a MathValueRecord {
516        &self.data.header().stretch_stack_bottom_shift_down
517    }
518
519    /// Minimum gap between the ink of the stretched element, and the (ink)
520    /// bottom of the element above.
521    pub fn stretch_stack_gap_above_min(&self) -> &'a MathValueRecord {
522        &self.data.header().stretch_stack_gap_above_min
523    }
524
525    /// Minimum gap between the ink of the stretched element, and the (ink) top
526    /// of the element below.
527    pub fn stretch_stack_gap_below_min(&self) -> &'a MathValueRecord {
528        &self.data.header().stretch_stack_gap_below_min
529    }
530
531    /// Standard shift up applied to the numerator.
532    pub fn fraction_numerator_shift_up(&self) -> &'a MathValueRecord {
533        &self.data.header().fraction_numerator_shift_up
534    }
535
536    /// Standard shift up applied to the numerator in display style.
537    pub fn fraction_numerator_display_style_shift_up(&self) -> &'a MathValueRecord {
538        &self.data.header().fraction_numerator_display_style_shift_up
539    }
540
541    /// Standard shift down applied to the denominator.
542    pub fn fraction_denominator_shift_down(&self) -> &'a MathValueRecord {
543        &self.data.header().fraction_denominator_shift_down
544    }
545
546    /// Standard shift down applied to the denominator in display style.
547    pub fn fraction_denominator_display_style_shift_down(&self) -> &'a MathValueRecord {
548        &self
549            .data
550            .header()
551            .fraction_denominator_display_style_shift_down
552    }
553
554    /// Minimum tolerated gap between the (ink) bottom of the numerator and the
555    /// ink of the fraction bar.
556    pub fn fraction_numerator_gap_min(&self) -> &'a MathValueRecord {
557        &self.data.header().fraction_numerator_gap_min
558    }
559
560    /// Minimum tolerated gap between the (ink) bottom of the numerator and the
561    /// ink of the fraction bar in display style.
562    pub fn fraction_num_display_style_gap_min(&self) -> &'a MathValueRecord {
563        &self.data.header().fraction_num_display_style_gap_min
564    }
565
566    /// Thickness of the fraction bar.
567    pub fn fraction_rule_thickness(&self) -> &'a MathValueRecord {
568        &self.data.header().fraction_rule_thickness
569    }
570
571    /// Minimum tolerated gap between the ink of the fraction bar and the (ink)
572    /// top of the denominator.
573    pub fn fraction_denominator_gap_min(&self) -> &'a MathValueRecord {
574        &self.data.header().fraction_denominator_gap_min
575    }
576
577    /// Minimum tolerated gap between the ink of the fraction bar and the (ink)
578    /// top of the denominator in display style.
579    pub fn fraction_denom_display_style_gap_min(&self) -> &'a MathValueRecord {
580        &self.data.header().fraction_denom_display_style_gap_min
581    }
582
583    /// Horizontal distance between the top and bottom elements of a skewed
584    /// fraction.
585    pub fn skewed_fraction_horizontal_gap(&self) -> &'a MathValueRecord {
586        &self.data.header().skewed_fraction_horizontal_gap
587    }
588
589    /// Vertical distance between the ink of the top and bottom elements of a
590    /// skewed fraction.
591    pub fn skewed_fraction_vertical_gap(&self) -> &'a MathValueRecord {
592        &self.data.header().skewed_fraction_vertical_gap
593    }
594
595    /// Distance between the overbar and the (ink) top of he base.
596    pub fn overbar_vertical_gap(&self) -> &'a MathValueRecord {
597        &self.data.header().overbar_vertical_gap
598    }
599
600    /// Thickness of overbar.
601    pub fn overbar_rule_thickness(&self) -> &'a MathValueRecord {
602        &self.data.header().overbar_rule_thickness
603    }
604
605    /// Extra white space reserved above the overbar.
606    pub fn overbar_extra_ascender(&self) -> &'a MathValueRecord {
607        &self.data.header().overbar_extra_ascender
608    }
609
610    /// Distance between underbar and (ink) bottom of the base.
611    pub fn underbar_vertical_gap(&self) -> &'a MathValueRecord {
612        &self.data.header().underbar_vertical_gap
613    }
614
615    /// Thickness of underbar.
616    pub fn underbar_rule_thickness(&self) -> &'a MathValueRecord {
617        &self.data.header().underbar_rule_thickness
618    }
619
620    /// Extra white space reserved below the underbar.
621    pub fn underbar_extra_descender(&self) -> &'a MathValueRecord {
622        &self.data.header().underbar_extra_descender
623    }
624
625    /// Space between the (ink) top of the expression and the bar over it.
626    pub fn radical_vertical_gap(&self) -> &'a MathValueRecord {
627        &self.data.header().radical_vertical_gap
628    }
629
630    /// Space between the (ink) top of the expression and the bar over it in
631    /// display style.
632    pub fn radical_display_style_vertical_gap(&self) -> &'a MathValueRecord {
633        &self.data.header().radical_display_style_vertical_gap
634    }
635
636    /// Thickness of the radical rule.
637    pub fn radical_rule_thickness(&self) -> &'a MathValueRecord {
638        &self.data.header().radical_rule_thickness
639    }
640
641    /// Extra white space reserved above the radical.
642    pub fn radical_extra_ascender(&self) -> &'a MathValueRecord {
643        &self.data.header().radical_extra_ascender
644    }
645
646    /// Extra horizontal kern before the degree of a radical, if such is
647    /// present.
648    pub fn radical_kern_before_degree(&self) -> &'a MathValueRecord {
649        &self.data.header().radical_kern_before_degree
650    }
651
652    /// Negative kern after the degree of a radical, if such is present.
653    pub fn radical_kern_after_degree(&self) -> &'a MathValueRecord {
654        &self.data.header().radical_kern_after_degree
655    }
656
657    /// Height of the bottom of the radical degree, if such is present, in
658    /// proportion to the ascender of the radical sign.
659    pub fn radical_degree_bottom_raise_percent(&self) -> i16 {
660        self.data.header().radical_degree_bottom_raise_percent.get()
661    }
662
663    pub fn script_percent_scale_down_byte_range(&self) -> Range<usize> {
664        let start = 0;
665        let end = start + i16::RAW_BYTE_LEN;
666        start..end
667    }
668
669    pub fn script_script_percent_scale_down_byte_range(&self) -> Range<usize> {
670        let start = self.script_percent_scale_down_byte_range().end;
671        let end = start + i16::RAW_BYTE_LEN;
672        start..end
673    }
674
675    pub fn delimited_sub_formula_min_height_byte_range(&self) -> Range<usize> {
676        let start = self.script_script_percent_scale_down_byte_range().end;
677        let end = start + UfWord::RAW_BYTE_LEN;
678        start..end
679    }
680
681    pub fn display_operator_min_height_byte_range(&self) -> Range<usize> {
682        let start = self.delimited_sub_formula_min_height_byte_range().end;
683        let end = start + UfWord::RAW_BYTE_LEN;
684        start..end
685    }
686
687    pub fn math_leading_byte_range(&self) -> Range<usize> {
688        let start = self.display_operator_min_height_byte_range().end;
689        let end = start + MathValueRecord::RAW_BYTE_LEN;
690        start..end
691    }
692
693    pub fn axis_height_byte_range(&self) -> Range<usize> {
694        let start = self.math_leading_byte_range().end;
695        let end = start + MathValueRecord::RAW_BYTE_LEN;
696        start..end
697    }
698
699    pub fn accent_base_height_byte_range(&self) -> Range<usize> {
700        let start = self.axis_height_byte_range().end;
701        let end = start + MathValueRecord::RAW_BYTE_LEN;
702        start..end
703    }
704
705    pub fn flattened_accent_base_height_byte_range(&self) -> Range<usize> {
706        let start = self.accent_base_height_byte_range().end;
707        let end = start + MathValueRecord::RAW_BYTE_LEN;
708        start..end
709    }
710
711    pub fn subscript_shift_down_byte_range(&self) -> Range<usize> {
712        let start = self.flattened_accent_base_height_byte_range().end;
713        let end = start + MathValueRecord::RAW_BYTE_LEN;
714        start..end
715    }
716
717    pub fn subscript_top_max_byte_range(&self) -> Range<usize> {
718        let start = self.subscript_shift_down_byte_range().end;
719        let end = start + MathValueRecord::RAW_BYTE_LEN;
720        start..end
721    }
722
723    pub fn subscript_baseline_drop_min_byte_range(&self) -> Range<usize> {
724        let start = self.subscript_top_max_byte_range().end;
725        let end = start + MathValueRecord::RAW_BYTE_LEN;
726        start..end
727    }
728
729    pub fn superscript_shift_up_byte_range(&self) -> Range<usize> {
730        let start = self.subscript_baseline_drop_min_byte_range().end;
731        let end = start + MathValueRecord::RAW_BYTE_LEN;
732        start..end
733    }
734
735    pub fn superscript_shift_up_cramped_byte_range(&self) -> Range<usize> {
736        let start = self.superscript_shift_up_byte_range().end;
737        let end = start + MathValueRecord::RAW_BYTE_LEN;
738        start..end
739    }
740
741    pub fn superscript_bottom_min_byte_range(&self) -> Range<usize> {
742        let start = self.superscript_shift_up_cramped_byte_range().end;
743        let end = start + MathValueRecord::RAW_BYTE_LEN;
744        start..end
745    }
746
747    pub fn superscript_baseline_drop_max_byte_range(&self) -> Range<usize> {
748        let start = self.superscript_bottom_min_byte_range().end;
749        let end = start + MathValueRecord::RAW_BYTE_LEN;
750        start..end
751    }
752
753    pub fn sub_superscript_gap_min_byte_range(&self) -> Range<usize> {
754        let start = self.superscript_baseline_drop_max_byte_range().end;
755        let end = start + MathValueRecord::RAW_BYTE_LEN;
756        start..end
757    }
758
759    pub fn superscript_bottom_max_with_subscript_byte_range(&self) -> Range<usize> {
760        let start = self.sub_superscript_gap_min_byte_range().end;
761        let end = start + MathValueRecord::RAW_BYTE_LEN;
762        start..end
763    }
764
765    pub fn space_after_script_byte_range(&self) -> Range<usize> {
766        let start = self.superscript_bottom_max_with_subscript_byte_range().end;
767        let end = start + MathValueRecord::RAW_BYTE_LEN;
768        start..end
769    }
770
771    pub fn upper_limit_gap_min_byte_range(&self) -> Range<usize> {
772        let start = self.space_after_script_byte_range().end;
773        let end = start + MathValueRecord::RAW_BYTE_LEN;
774        start..end
775    }
776
777    pub fn upper_limit_baseline_rise_min_byte_range(&self) -> Range<usize> {
778        let start = self.upper_limit_gap_min_byte_range().end;
779        let end = start + MathValueRecord::RAW_BYTE_LEN;
780        start..end
781    }
782
783    pub fn lower_limit_gap_min_byte_range(&self) -> Range<usize> {
784        let start = self.upper_limit_baseline_rise_min_byte_range().end;
785        let end = start + MathValueRecord::RAW_BYTE_LEN;
786        start..end
787    }
788
789    pub fn lower_limit_baseline_drop_min_byte_range(&self) -> Range<usize> {
790        let start = self.lower_limit_gap_min_byte_range().end;
791        let end = start + MathValueRecord::RAW_BYTE_LEN;
792        start..end
793    }
794
795    pub fn stack_top_shift_up_byte_range(&self) -> Range<usize> {
796        let start = self.lower_limit_baseline_drop_min_byte_range().end;
797        let end = start + MathValueRecord::RAW_BYTE_LEN;
798        start..end
799    }
800
801    pub fn stack_top_display_style_shift_up_byte_range(&self) -> Range<usize> {
802        let start = self.stack_top_shift_up_byte_range().end;
803        let end = start + MathValueRecord::RAW_BYTE_LEN;
804        start..end
805    }
806
807    pub fn stack_bottom_shift_down_byte_range(&self) -> Range<usize> {
808        let start = self.stack_top_display_style_shift_up_byte_range().end;
809        let end = start + MathValueRecord::RAW_BYTE_LEN;
810        start..end
811    }
812
813    pub fn stack_bottom_display_style_shift_down_byte_range(&self) -> Range<usize> {
814        let start = self.stack_bottom_shift_down_byte_range().end;
815        let end = start + MathValueRecord::RAW_BYTE_LEN;
816        start..end
817    }
818
819    pub fn stack_gap_min_byte_range(&self) -> Range<usize> {
820        let start = self.stack_bottom_display_style_shift_down_byte_range().end;
821        let end = start + MathValueRecord::RAW_BYTE_LEN;
822        start..end
823    }
824
825    pub fn stack_display_style_gap_min_byte_range(&self) -> Range<usize> {
826        let start = self.stack_gap_min_byte_range().end;
827        let end = start + MathValueRecord::RAW_BYTE_LEN;
828        start..end
829    }
830
831    pub fn stretch_stack_top_shift_up_byte_range(&self) -> Range<usize> {
832        let start = self.stack_display_style_gap_min_byte_range().end;
833        let end = start + MathValueRecord::RAW_BYTE_LEN;
834        start..end
835    }
836
837    pub fn stretch_stack_bottom_shift_down_byte_range(&self) -> Range<usize> {
838        let start = self.stretch_stack_top_shift_up_byte_range().end;
839        let end = start + MathValueRecord::RAW_BYTE_LEN;
840        start..end
841    }
842
843    pub fn stretch_stack_gap_above_min_byte_range(&self) -> Range<usize> {
844        let start = self.stretch_stack_bottom_shift_down_byte_range().end;
845        let end = start + MathValueRecord::RAW_BYTE_LEN;
846        start..end
847    }
848
849    pub fn stretch_stack_gap_below_min_byte_range(&self) -> Range<usize> {
850        let start = self.stretch_stack_gap_above_min_byte_range().end;
851        let end = start + MathValueRecord::RAW_BYTE_LEN;
852        start..end
853    }
854
855    pub fn fraction_numerator_shift_up_byte_range(&self) -> Range<usize> {
856        let start = self.stretch_stack_gap_below_min_byte_range().end;
857        let end = start + MathValueRecord::RAW_BYTE_LEN;
858        start..end
859    }
860
861    pub fn fraction_numerator_display_style_shift_up_byte_range(&self) -> Range<usize> {
862        let start = self.fraction_numerator_shift_up_byte_range().end;
863        let end = start + MathValueRecord::RAW_BYTE_LEN;
864        start..end
865    }
866
867    pub fn fraction_denominator_shift_down_byte_range(&self) -> Range<usize> {
868        let start = self
869            .fraction_numerator_display_style_shift_up_byte_range()
870            .end;
871        let end = start + MathValueRecord::RAW_BYTE_LEN;
872        start..end
873    }
874
875    pub fn fraction_denominator_display_style_shift_down_byte_range(&self) -> Range<usize> {
876        let start = self.fraction_denominator_shift_down_byte_range().end;
877        let end = start + MathValueRecord::RAW_BYTE_LEN;
878        start..end
879    }
880
881    pub fn fraction_numerator_gap_min_byte_range(&self) -> Range<usize> {
882        let start = self
883            .fraction_denominator_display_style_shift_down_byte_range()
884            .end;
885        let end = start + MathValueRecord::RAW_BYTE_LEN;
886        start..end
887    }
888
889    pub fn fraction_num_display_style_gap_min_byte_range(&self) -> Range<usize> {
890        let start = self.fraction_numerator_gap_min_byte_range().end;
891        let end = start + MathValueRecord::RAW_BYTE_LEN;
892        start..end
893    }
894
895    pub fn fraction_rule_thickness_byte_range(&self) -> Range<usize> {
896        let start = self.fraction_num_display_style_gap_min_byte_range().end;
897        let end = start + MathValueRecord::RAW_BYTE_LEN;
898        start..end
899    }
900
901    pub fn fraction_denominator_gap_min_byte_range(&self) -> Range<usize> {
902        let start = self.fraction_rule_thickness_byte_range().end;
903        let end = start + MathValueRecord::RAW_BYTE_LEN;
904        start..end
905    }
906
907    pub fn fraction_denom_display_style_gap_min_byte_range(&self) -> Range<usize> {
908        let start = self.fraction_denominator_gap_min_byte_range().end;
909        let end = start + MathValueRecord::RAW_BYTE_LEN;
910        start..end
911    }
912
913    pub fn skewed_fraction_horizontal_gap_byte_range(&self) -> Range<usize> {
914        let start = self.fraction_denom_display_style_gap_min_byte_range().end;
915        let end = start + MathValueRecord::RAW_BYTE_LEN;
916        start..end
917    }
918
919    pub fn skewed_fraction_vertical_gap_byte_range(&self) -> Range<usize> {
920        let start = self.skewed_fraction_horizontal_gap_byte_range().end;
921        let end = start + MathValueRecord::RAW_BYTE_LEN;
922        start..end
923    }
924
925    pub fn overbar_vertical_gap_byte_range(&self) -> Range<usize> {
926        let start = self.skewed_fraction_vertical_gap_byte_range().end;
927        let end = start + MathValueRecord::RAW_BYTE_LEN;
928        start..end
929    }
930
931    pub fn overbar_rule_thickness_byte_range(&self) -> Range<usize> {
932        let start = self.overbar_vertical_gap_byte_range().end;
933        let end = start + MathValueRecord::RAW_BYTE_LEN;
934        start..end
935    }
936
937    pub fn overbar_extra_ascender_byte_range(&self) -> Range<usize> {
938        let start = self.overbar_rule_thickness_byte_range().end;
939        let end = start + MathValueRecord::RAW_BYTE_LEN;
940        start..end
941    }
942
943    pub fn underbar_vertical_gap_byte_range(&self) -> Range<usize> {
944        let start = self.overbar_extra_ascender_byte_range().end;
945        let end = start + MathValueRecord::RAW_BYTE_LEN;
946        start..end
947    }
948
949    pub fn underbar_rule_thickness_byte_range(&self) -> Range<usize> {
950        let start = self.underbar_vertical_gap_byte_range().end;
951        let end = start + MathValueRecord::RAW_BYTE_LEN;
952        start..end
953    }
954
955    pub fn underbar_extra_descender_byte_range(&self) -> Range<usize> {
956        let start = self.underbar_rule_thickness_byte_range().end;
957        let end = start + MathValueRecord::RAW_BYTE_LEN;
958        start..end
959    }
960
961    pub fn radical_vertical_gap_byte_range(&self) -> Range<usize> {
962        let start = self.underbar_extra_descender_byte_range().end;
963        let end = start + MathValueRecord::RAW_BYTE_LEN;
964        start..end
965    }
966
967    pub fn radical_display_style_vertical_gap_byte_range(&self) -> Range<usize> {
968        let start = self.radical_vertical_gap_byte_range().end;
969        let end = start + MathValueRecord::RAW_BYTE_LEN;
970        start..end
971    }
972
973    pub fn radical_rule_thickness_byte_range(&self) -> Range<usize> {
974        let start = self.radical_display_style_vertical_gap_byte_range().end;
975        let end = start + MathValueRecord::RAW_BYTE_LEN;
976        start..end
977    }
978
979    pub fn radical_extra_ascender_byte_range(&self) -> Range<usize> {
980        let start = self.radical_rule_thickness_byte_range().end;
981        let end = start + MathValueRecord::RAW_BYTE_LEN;
982        start..end
983    }
984
985    pub fn radical_kern_before_degree_byte_range(&self) -> Range<usize> {
986        let start = self.radical_extra_ascender_byte_range().end;
987        let end = start + MathValueRecord::RAW_BYTE_LEN;
988        start..end
989    }
990
991    pub fn radical_kern_after_degree_byte_range(&self) -> Range<usize> {
992        let start = self.radical_kern_before_degree_byte_range().end;
993        let end = start + MathValueRecord::RAW_BYTE_LEN;
994        start..end
995    }
996
997    pub fn radical_degree_bottom_raise_percent_byte_range(&self) -> Range<usize> {
998        let start = self.radical_kern_after_degree_byte_range().end;
999        let end = start + i16::RAW_BYTE_LEN;
1000        start..end
1001    }
1002}
1003
1004const _: () = assert!(FontData::default_data_long_enough(MathConstants::MIN_SIZE));
1005
1006impl Default for MathConstants<'_> {
1007    fn default() -> Self {
1008        Self {
1009            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1010                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1011        }
1012    }
1013}
1014
1015impl<'a> MinByteRange<'a> for MathGlyphInfo<'a> {
1016    fn min_byte_range(&self) -> Range<usize> {
1017        0..self.math_kern_info_offset_byte_range().end
1018    }
1019    fn min_table_bytes(&self) -> &'a [u8] {
1020        let range = self.min_byte_range();
1021        self.offset_data().as_bytes().get(range).unwrap_or_default()
1022    }
1023}
1024
1025impl ReadArgs for MathGlyphInfo<'_> {
1026    type Args = ();
1027}
1028
1029impl<'a> FontRead<'a> for MathGlyphInfo<'a> {
1030    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1031        #[allow(clippy::absurd_extreme_comparisons)]
1032        if data.len() < Self::MIN_SIZE {
1033            return Err(ReadError::OutOfBounds);
1034        }
1035        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1036            return Err(ReadError::OutOfBounds);
1037        };
1038        Ok(Self { data })
1039    }
1040}
1041
1042/// The fields at the start of the table, which are read directly.
1043#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1044#[repr(C, packed)]
1045#[doc(hidden)]
1046pub struct MathGlyphInfoFixedHeader {
1047    pub math_italics_correction_info_offset: BigEndian<Nullable<Offset16>>,
1048    pub math_top_accent_attachment_offset: BigEndian<Nullable<Offset16>>,
1049    pub extended_shape_coverage_offset: BigEndian<Nullable<Offset16>>,
1050    pub math_kern_info_offset: BigEndian<Nullable<Offset16>>,
1051}
1052
1053#[allow(clippy::absurd_extreme_comparisons)]
1054const _: () = assert!(std::mem::size_of::<MathGlyphInfoFixedHeader>() <= MathGlyphInfo::MIN_SIZE);
1055
1056/// [MathGlyphInfo](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphinfo-table)
1057#[derive(Clone)]
1058pub struct MathGlyphInfo<'a> {
1059    data: TableDataRef<'a, MathGlyphInfoFixedHeader>,
1060}
1061
1062#[allow(clippy::needless_lifetimes)]
1063impl<'a> MathGlyphInfo<'a> {
1064    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN
1065        + Offset16::RAW_BYTE_LEN
1066        + Offset16::RAW_BYTE_LEN
1067        + Offset16::RAW_BYTE_LEN);
1068    basic_table_impls!(impl_the_methods);
1069
1070    /// Offset to MathItalicsCorrectionInfo table, from the beginning of the
1071    /// MathGlyphInfo table. May be NULL.
1072    pub fn math_italics_correction_info_offset(&self) -> Nullable<Offset16> {
1073        self.data.header().math_italics_correction_info_offset.get()
1074    }
1075
1076    /// Attempt to resolve [`math_italics_correction_info_offset`][Self::math_italics_correction_info_offset].
1077    pub fn math_italics_correction_info(
1078        &self,
1079    ) -> Option<Result<MathItalicsCorrectionInfo<'a>, ReadError>> {
1080        let data = self.offset_data();
1081        self.math_italics_correction_info_offset().resolve(data)
1082    }
1083
1084    /// Offset to MathTopAccentAttachment table, from the beginning of the
1085    /// MathGlyphInfo table. May be NULL.
1086    pub fn math_top_accent_attachment_offset(&self) -> Nullable<Offset16> {
1087        self.data.header().math_top_accent_attachment_offset.get()
1088    }
1089
1090    /// Attempt to resolve [`math_top_accent_attachment_offset`][Self::math_top_accent_attachment_offset].
1091    pub fn math_top_accent_attachment(
1092        &self,
1093    ) -> Option<Result<MathTopAccentAttachment<'a>, ReadError>> {
1094        let data = self.offset_data();
1095        self.math_top_accent_attachment_offset().resolve(data)
1096    }
1097
1098    /// Offset to the Coverage table for glyphs with extended shapes, from the
1099    /// beginning of the MathGlyphInfo table. May be NULL.
1100    pub fn extended_shape_coverage_offset(&self) -> Nullable<Offset16> {
1101        self.data.header().extended_shape_coverage_offset.get()
1102    }
1103
1104    /// Attempt to resolve [`extended_shape_coverage_offset`][Self::extended_shape_coverage_offset].
1105    pub fn extended_shape_coverage(&self) -> Option<Result<CoverageTable<'a>, ReadError>> {
1106        let data = self.offset_data();
1107        self.extended_shape_coverage_offset().resolve(data)
1108    }
1109
1110    /// Offset to the MathKernInfo table, from the beginning of the
1111    /// MathGlyphInfo table. May be NULL.
1112    pub fn math_kern_info_offset(&self) -> Nullable<Offset16> {
1113        self.data.header().math_kern_info_offset.get()
1114    }
1115
1116    /// Attempt to resolve [`math_kern_info_offset`][Self::math_kern_info_offset].
1117    pub fn math_kern_info(&self) -> Option<Result<MathKernInfo<'a>, ReadError>> {
1118        let data = self.offset_data();
1119        self.math_kern_info_offset().resolve(data)
1120    }
1121
1122    pub fn math_italics_correction_info_offset_byte_range(&self) -> Range<usize> {
1123        let start = 0;
1124        let end = start + Offset16::RAW_BYTE_LEN;
1125        start..end
1126    }
1127
1128    pub fn math_top_accent_attachment_offset_byte_range(&self) -> Range<usize> {
1129        let start = self.math_italics_correction_info_offset_byte_range().end;
1130        let end = start + Offset16::RAW_BYTE_LEN;
1131        start..end
1132    }
1133
1134    pub fn extended_shape_coverage_offset_byte_range(&self) -> Range<usize> {
1135        let start = self.math_top_accent_attachment_offset_byte_range().end;
1136        let end = start + Offset16::RAW_BYTE_LEN;
1137        start..end
1138    }
1139
1140    pub fn math_kern_info_offset_byte_range(&self) -> Range<usize> {
1141        let start = self.extended_shape_coverage_offset_byte_range().end;
1142        let end = start + Offset16::RAW_BYTE_LEN;
1143        start..end
1144    }
1145}
1146
1147const _: () = assert!(FontData::default_data_long_enough(MathGlyphInfo::MIN_SIZE));
1148
1149impl Default for MathGlyphInfo<'_> {
1150    fn default() -> Self {
1151        Self {
1152            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1153                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1154        }
1155    }
1156}
1157
1158impl<'a> MinByteRange<'a> for MathItalicsCorrectionInfo<'a> {
1159    fn min_byte_range(&self) -> Range<usize> {
1160        0..self.italics_correction_byte_range().end
1161    }
1162    fn min_table_bytes(&self) -> &'a [u8] {
1163        let range = self.min_byte_range();
1164        self.offset_data().as_bytes().get(range).unwrap_or_default()
1165    }
1166}
1167
1168impl ReadArgs for MathItalicsCorrectionInfo<'_> {
1169    type Args = ();
1170}
1171
1172impl<'a> FontRead<'a> for MathItalicsCorrectionInfo<'a> {
1173    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1174        #[allow(clippy::absurd_extreme_comparisons)]
1175        if data.len() < Self::MIN_SIZE {
1176            return Err(ReadError::OutOfBounds);
1177        }
1178        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1179            return Err(ReadError::OutOfBounds);
1180        };
1181        Ok(Self { data })
1182    }
1183}
1184
1185/// The fields at the start of the table, which are read directly.
1186#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1187#[repr(C, packed)]
1188#[doc(hidden)]
1189pub struct MathItalicsCorrectionInfoFixedHeader {
1190    pub coverage_offset: BigEndian<Offset16>,
1191    pub italics_correction_count: BigEndian<u16>,
1192}
1193
1194#[allow(clippy::absurd_extreme_comparisons)]
1195const _: () = assert!(
1196    std::mem::size_of::<MathItalicsCorrectionInfoFixedHeader>()
1197        <= MathItalicsCorrectionInfo::MIN_SIZE
1198);
1199
1200/// [MathItalicsCorrectionInfo](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathitalicscorrectioninfo-table)
1201#[derive(Clone)]
1202pub struct MathItalicsCorrectionInfo<'a> {
1203    data: TableDataRef<'a, MathItalicsCorrectionInfoFixedHeader>,
1204}
1205
1206#[allow(clippy::needless_lifetimes)]
1207impl<'a> MathItalicsCorrectionInfo<'a> {
1208    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1209    basic_table_impls!(impl_the_methods);
1210
1211    /// Offset to the Coverage table, from the beginning of the
1212    /// MathItalicsCorrectionInfo table.
1213    pub fn coverage_offset(&self) -> Offset16 {
1214        self.data.header().coverage_offset.get()
1215    }
1216
1217    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1218    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1219        let data = self.offset_data();
1220        self.coverage_offset().resolve(data)
1221    }
1222
1223    /// Number of italics correction values. Should coincide with the number of
1224    /// covered glyphs.
1225    pub fn italics_correction_count(&self) -> u16 {
1226        self.data.header().italics_correction_count.get()
1227    }
1228
1229    /// Array of MathValueRecords defining italics correction values for each
1230    /// covered glyph.
1231    pub fn italics_correction(&self) -> &'a [MathValueRecord] {
1232        let range = self.italics_correction_byte_range();
1233        self.offset_data()
1234            .read_array(range)
1235            .ok()
1236            .unwrap_or_default()
1237    }
1238
1239    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1240        let start = 0;
1241        let end = start + Offset16::RAW_BYTE_LEN;
1242        start..end
1243    }
1244
1245    pub fn italics_correction_count_byte_range(&self) -> Range<usize> {
1246        let start = self.coverage_offset_byte_range().end;
1247        let end = start + u16::RAW_BYTE_LEN;
1248        start..end
1249    }
1250
1251    pub fn italics_correction_byte_range(&self) -> Range<usize> {
1252        let italics_correction_count = self.italics_correction_count();
1253        let start = self.italics_correction_count_byte_range().end;
1254        let end = start
1255            + (transforms::to_usize(italics_correction_count))
1256                .saturating_mul(MathValueRecord::RAW_BYTE_LEN);
1257        start..end
1258    }
1259}
1260
1261const _: () = assert!(FontData::default_data_long_enough(
1262    MathItalicsCorrectionInfo::MIN_SIZE
1263));
1264
1265impl Default for MathItalicsCorrectionInfo<'_> {
1266    fn default() -> Self {
1267        Self {
1268            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1269                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1270        }
1271    }
1272}
1273
1274impl<'a> MinByteRange<'a> for MathTopAccentAttachment<'a> {
1275    fn min_byte_range(&self) -> Range<usize> {
1276        0..self.top_accent_attachment_byte_range().end
1277    }
1278    fn min_table_bytes(&self) -> &'a [u8] {
1279        let range = self.min_byte_range();
1280        self.offset_data().as_bytes().get(range).unwrap_or_default()
1281    }
1282}
1283
1284impl ReadArgs for MathTopAccentAttachment<'_> {
1285    type Args = ();
1286}
1287
1288impl<'a> FontRead<'a> for MathTopAccentAttachment<'a> {
1289    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1290        #[allow(clippy::absurd_extreme_comparisons)]
1291        if data.len() < Self::MIN_SIZE {
1292            return Err(ReadError::OutOfBounds);
1293        }
1294        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1295            return Err(ReadError::OutOfBounds);
1296        };
1297        Ok(Self { data })
1298    }
1299}
1300
1301/// The fields at the start of the table, which are read directly.
1302#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1303#[repr(C, packed)]
1304#[doc(hidden)]
1305pub struct MathTopAccentAttachmentFixedHeader {
1306    pub top_accent_coverage_offset: BigEndian<Offset16>,
1307    pub top_accent_attachment_count: BigEndian<u16>,
1308}
1309
1310#[allow(clippy::absurd_extreme_comparisons)]
1311const _: () = assert!(
1312    std::mem::size_of::<MathTopAccentAttachmentFixedHeader>() <= MathTopAccentAttachment::MIN_SIZE
1313);
1314
1315/// [MathTopAccentAttachment](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathtopaccentattachment-table)
1316#[derive(Clone)]
1317pub struct MathTopAccentAttachment<'a> {
1318    data: TableDataRef<'a, MathTopAccentAttachmentFixedHeader>,
1319}
1320
1321#[allow(clippy::needless_lifetimes)]
1322impl<'a> MathTopAccentAttachment<'a> {
1323    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1324    basic_table_impls!(impl_the_methods);
1325
1326    /// Offset to the Coverage table, from the beginning of the
1327    /// MathTopAccentAttachment table.
1328    pub fn top_accent_coverage_offset(&self) -> Offset16 {
1329        self.data.header().top_accent_coverage_offset.get()
1330    }
1331
1332    /// Attempt to resolve [`top_accent_coverage_offset`][Self::top_accent_coverage_offset].
1333    pub fn top_accent_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1334        let data = self.offset_data();
1335        self.top_accent_coverage_offset().resolve(data)
1336    }
1337
1338    /// Number of top accent attachment point values. Should coincide with the
1339    /// number of covered glyphs.
1340    pub fn top_accent_attachment_count(&self) -> u16 {
1341        self.data.header().top_accent_attachment_count.get()
1342    }
1343
1344    /// Array of MathValueRecords defining top accent attachment points for each
1345    /// covered glyph.
1346    pub fn top_accent_attachment(&self) -> &'a [MathValueRecord] {
1347        let range = self.top_accent_attachment_byte_range();
1348        self.offset_data()
1349            .read_array(range)
1350            .ok()
1351            .unwrap_or_default()
1352    }
1353
1354    pub fn top_accent_coverage_offset_byte_range(&self) -> Range<usize> {
1355        let start = 0;
1356        let end = start + Offset16::RAW_BYTE_LEN;
1357        start..end
1358    }
1359
1360    pub fn top_accent_attachment_count_byte_range(&self) -> Range<usize> {
1361        let start = self.top_accent_coverage_offset_byte_range().end;
1362        let end = start + u16::RAW_BYTE_LEN;
1363        start..end
1364    }
1365
1366    pub fn top_accent_attachment_byte_range(&self) -> Range<usize> {
1367        let top_accent_attachment_count = self.top_accent_attachment_count();
1368        let start = self.top_accent_attachment_count_byte_range().end;
1369        let end = start
1370            + (transforms::to_usize(top_accent_attachment_count))
1371                .saturating_mul(MathValueRecord::RAW_BYTE_LEN);
1372        start..end
1373    }
1374}
1375
1376const _: () = assert!(FontData::default_data_long_enough(
1377    MathTopAccentAttachment::MIN_SIZE
1378));
1379
1380impl Default for MathTopAccentAttachment<'_> {
1381    fn default() -> Self {
1382        Self {
1383            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1384                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1385        }
1386    }
1387}
1388
1389impl<'a> MinByteRange<'a> for MathKernInfo<'a> {
1390    fn min_byte_range(&self) -> Range<usize> {
1391        0..self.math_kern_info_records_byte_range().end
1392    }
1393    fn min_table_bytes(&self) -> &'a [u8] {
1394        let range = self.min_byte_range();
1395        self.offset_data().as_bytes().get(range).unwrap_or_default()
1396    }
1397}
1398
1399impl ReadArgs for MathKernInfo<'_> {
1400    type Args = ();
1401}
1402
1403impl<'a> FontRead<'a> for MathKernInfo<'a> {
1404    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1405        #[allow(clippy::absurd_extreme_comparisons)]
1406        if data.len() < Self::MIN_SIZE {
1407            return Err(ReadError::OutOfBounds);
1408        }
1409        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1410            return Err(ReadError::OutOfBounds);
1411        };
1412        Ok(Self { data })
1413    }
1414}
1415
1416/// The fields at the start of the table, which are read directly.
1417#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1418#[repr(C, packed)]
1419#[doc(hidden)]
1420pub struct MathKernInfoFixedHeader {
1421    pub math_kern_coverage_offset: BigEndian<Offset16>,
1422    pub math_kern_count: BigEndian<u16>,
1423}
1424
1425#[allow(clippy::absurd_extreme_comparisons)]
1426const _: () = assert!(std::mem::size_of::<MathKernInfoFixedHeader>() <= MathKernInfo::MIN_SIZE);
1427
1428/// [MathKernInfo](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkerninfo-table)
1429#[derive(Clone)]
1430pub struct MathKernInfo<'a> {
1431    data: TableDataRef<'a, MathKernInfoFixedHeader>,
1432}
1433
1434#[allow(clippy::needless_lifetimes)]
1435impl<'a> MathKernInfo<'a> {
1436    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1437    basic_table_impls!(impl_the_methods);
1438
1439    /// Offset to the Coverage table, from the beginning of the MathKernInfo
1440    /// table.
1441    pub fn math_kern_coverage_offset(&self) -> Offset16 {
1442        self.data.header().math_kern_coverage_offset.get()
1443    }
1444
1445    /// Attempt to resolve [`math_kern_coverage_offset`][Self::math_kern_coverage_offset].
1446    pub fn math_kern_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1447        let data = self.offset_data();
1448        self.math_kern_coverage_offset().resolve(data)
1449    }
1450
1451    /// Number of MathKernInfoRecords. Should coincide with the number of
1452    /// covered glyphs.
1453    pub fn math_kern_count(&self) -> u16 {
1454        self.data.header().math_kern_count.get()
1455    }
1456
1457    /// Array of MathKernInfoRecords, one for each covered glyph.
1458    pub fn math_kern_info_records(&self) -> &'a [MathKernInfoRecord] {
1459        let range = self.math_kern_info_records_byte_range();
1460        self.offset_data()
1461            .read_array(range)
1462            .ok()
1463            .unwrap_or_default()
1464    }
1465
1466    pub fn math_kern_coverage_offset_byte_range(&self) -> Range<usize> {
1467        let start = 0;
1468        let end = start + Offset16::RAW_BYTE_LEN;
1469        start..end
1470    }
1471
1472    pub fn math_kern_count_byte_range(&self) -> Range<usize> {
1473        let start = self.math_kern_coverage_offset_byte_range().end;
1474        let end = start + u16::RAW_BYTE_LEN;
1475        start..end
1476    }
1477
1478    pub fn math_kern_info_records_byte_range(&self) -> Range<usize> {
1479        let math_kern_count = self.math_kern_count();
1480        let start = self.math_kern_count_byte_range().end;
1481        let end = start
1482            + (transforms::to_usize(math_kern_count))
1483                .saturating_mul(MathKernInfoRecord::RAW_BYTE_LEN);
1484        start..end
1485    }
1486}
1487
1488const _: () = assert!(FontData::default_data_long_enough(MathKernInfo::MIN_SIZE));
1489
1490impl Default for MathKernInfo<'_> {
1491    fn default() -> Self {
1492        Self {
1493            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1494                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1495        }
1496    }
1497}
1498
1499/// [MathKernInfoRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkerninforecord)
1500///
1501/// The offsets are measured from the beginning of the MathKernInfo table.
1502#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1503#[repr(C)]
1504#[repr(packed)]
1505pub struct MathKernInfoRecord {
1506    /// Offset to the MathKern table for the top right corner, from the
1507    /// beginning of the MathKernInfo table. May be NULL.
1508    pub top_right_math_kern_offset: BigEndian<Nullable<Offset16>>,
1509    /// Offset to the MathKern table for the top left corner, from the beginning
1510    /// of the MathKernInfo table. May be NULL.
1511    pub top_left_math_kern_offset: BigEndian<Nullable<Offset16>>,
1512    /// Offset to the MathKern table for the bottom right corner, from the
1513    /// beginning of the MathKernInfo table. May be NULL.
1514    pub bottom_right_math_kern_offset: BigEndian<Nullable<Offset16>>,
1515    /// Offset to the MathKern table for the bottom left corner, from the
1516    /// beginning of the MathKernInfo table. May be NULL.
1517    pub bottom_left_math_kern_offset: BigEndian<Nullable<Offset16>>,
1518}
1519
1520impl MathKernInfoRecord {
1521    /// Offset to the MathKern table for the top right corner, from the
1522    /// beginning of the MathKernInfo table. May be NULL.
1523    pub fn top_right_math_kern_offset(&self) -> Nullable<Offset16> {
1524        self.top_right_math_kern_offset.get()
1525    }
1526
1527    /// Offset to the MathKern table for the top right corner, from the
1528    /// beginning of the MathKernInfo table. May be NULL.
1529    ///
1530    /// The `data` argument should be retrieved from the parent table
1531    /// By calling its `offset_data` method.
1532    pub fn top_right_math_kern<'a>(
1533        &self,
1534        data: FontData<'a>,
1535    ) -> Option<Result<MathKern<'a>, ReadError>> {
1536        self.top_right_math_kern_offset().resolve(data)
1537    }
1538
1539    /// Offset to the MathKern table for the top left corner, from the beginning
1540    /// of the MathKernInfo table. May be NULL.
1541    pub fn top_left_math_kern_offset(&self) -> Nullable<Offset16> {
1542        self.top_left_math_kern_offset.get()
1543    }
1544
1545    /// Offset to the MathKern table for the top left corner, from the beginning
1546    /// of the MathKernInfo table. May be NULL.
1547    ///
1548    /// The `data` argument should be retrieved from the parent table
1549    /// By calling its `offset_data` method.
1550    pub fn top_left_math_kern<'a>(
1551        &self,
1552        data: FontData<'a>,
1553    ) -> Option<Result<MathKern<'a>, ReadError>> {
1554        self.top_left_math_kern_offset().resolve(data)
1555    }
1556
1557    /// Offset to the MathKern table for the bottom right corner, from the
1558    /// beginning of the MathKernInfo table. May be NULL.
1559    pub fn bottom_right_math_kern_offset(&self) -> Nullable<Offset16> {
1560        self.bottom_right_math_kern_offset.get()
1561    }
1562
1563    /// Offset to the MathKern table for the bottom right corner, from the
1564    /// beginning of the MathKernInfo table. May be NULL.
1565    ///
1566    /// The `data` argument should be retrieved from the parent table
1567    /// By calling its `offset_data` method.
1568    pub fn bottom_right_math_kern<'a>(
1569        &self,
1570        data: FontData<'a>,
1571    ) -> Option<Result<MathKern<'a>, ReadError>> {
1572        self.bottom_right_math_kern_offset().resolve(data)
1573    }
1574
1575    /// Offset to the MathKern table for the bottom left corner, from the
1576    /// beginning of the MathKernInfo table. May be NULL.
1577    pub fn bottom_left_math_kern_offset(&self) -> Nullable<Offset16> {
1578        self.bottom_left_math_kern_offset.get()
1579    }
1580
1581    /// Offset to the MathKern table for the bottom left corner, from the
1582    /// beginning of the MathKernInfo table. May be NULL.
1583    ///
1584    /// The `data` argument should be retrieved from the parent table
1585    /// By calling its `offset_data` method.
1586    pub fn bottom_left_math_kern<'a>(
1587        &self,
1588        data: FontData<'a>,
1589    ) -> Option<Result<MathKern<'a>, ReadError>> {
1590        self.bottom_left_math_kern_offset().resolve(data)
1591    }
1592}
1593
1594impl FixedSize for MathKernInfoRecord {
1595    const RAW_BYTE_LEN: usize = Offset16::RAW_BYTE_LEN
1596        + Offset16::RAW_BYTE_LEN
1597        + Offset16::RAW_BYTE_LEN
1598        + Offset16::RAW_BYTE_LEN;
1599}
1600
1601impl<'a> MinByteRange<'a> for MathKern<'a> {
1602    fn min_byte_range(&self) -> Range<usize> {
1603        0..self.kern_values_byte_range().end
1604    }
1605    fn min_table_bytes(&self) -> &'a [u8] {
1606        let range = self.min_byte_range();
1607        self.offset_data().as_bytes().get(range).unwrap_or_default()
1608    }
1609}
1610
1611impl ReadArgs for MathKern<'_> {
1612    type Args = ();
1613}
1614
1615impl<'a> FontRead<'a> for MathKern<'a> {
1616    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1617        #[allow(clippy::absurd_extreme_comparisons)]
1618        if data.len() < Self::MIN_SIZE {
1619            return Err(ReadError::OutOfBounds);
1620        }
1621        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1622            return Err(ReadError::OutOfBounds);
1623        };
1624        Ok(Self { data })
1625    }
1626}
1627
1628/// The fields at the start of the table, which are read directly.
1629#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1630#[repr(C, packed)]
1631#[doc(hidden)]
1632pub struct MathKernFixedHeader {
1633    pub height_count: BigEndian<u16>,
1634}
1635
1636#[allow(clippy::absurd_extreme_comparisons)]
1637const _: () = assert!(std::mem::size_of::<MathKernFixedHeader>() <= MathKern::MIN_SIZE);
1638
1639/// [MathKern](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkern-table)
1640#[derive(Clone)]
1641pub struct MathKern<'a> {
1642    data: TableDataRef<'a, MathKernFixedHeader>,
1643}
1644
1645#[allow(clippy::needless_lifetimes)]
1646impl<'a> MathKern<'a> {
1647    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1648    basic_table_impls!(impl_the_methods);
1649
1650    /// Number of heights at which the kern value changes.
1651    pub fn height_count(&self) -> u16 {
1652        self.data.header().height_count.get()
1653    }
1654
1655    /// Array of correction heights, in design units, sorted from lowest to
1656    /// highest.
1657    pub fn correction_height(&self) -> &'a [MathValueRecord] {
1658        let range = self.correction_height_byte_range();
1659        self.offset_data()
1660            .read_array(range)
1661            .ok()
1662            .unwrap_or_default()
1663    }
1664
1665    /// Array of kerning values for different height ranges, in design units.
1666    ///
1667    /// There is one more of these than there are correction heights: the first
1668    /// applies below the first correction height, and the last above the last.
1669    pub fn kern_values(&self) -> &'a [MathValueRecord] {
1670        let range = self.kern_values_byte_range();
1671        self.offset_data()
1672            .read_array(range)
1673            .ok()
1674            .unwrap_or_default()
1675    }
1676
1677    pub fn height_count_byte_range(&self) -> Range<usize> {
1678        let start = 0;
1679        let end = start + u16::RAW_BYTE_LEN;
1680        start..end
1681    }
1682
1683    pub fn correction_height_byte_range(&self) -> Range<usize> {
1684        let height_count = self.height_count();
1685        let start = self.height_count_byte_range().end;
1686        let end = start
1687            + (transforms::to_usize(height_count)).saturating_mul(MathValueRecord::RAW_BYTE_LEN);
1688        start..end
1689    }
1690
1691    pub fn kern_values_byte_range(&self) -> Range<usize> {
1692        let height_count = self.height_count();
1693        let start = self.correction_height_byte_range().end;
1694        let end = start
1695            + (transforms::add(height_count, 1_usize))
1696                .saturating_mul(MathValueRecord::RAW_BYTE_LEN);
1697        start..end
1698    }
1699}
1700
1701const _: () = assert!(FontData::default_data_long_enough(MathKern::MIN_SIZE));
1702
1703impl Default for MathKern<'_> {
1704    fn default() -> Self {
1705        Self {
1706            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1707                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1708        }
1709    }
1710}
1711
1712impl<'a> MinByteRange<'a> for MathVariants<'a> {
1713    fn min_byte_range(&self) -> Range<usize> {
1714        0..self.horiz_glyph_construction_offsets_byte_range().end
1715    }
1716    fn min_table_bytes(&self) -> &'a [u8] {
1717        let range = self.min_byte_range();
1718        self.offset_data().as_bytes().get(range).unwrap_or_default()
1719    }
1720}
1721
1722impl ReadArgs for MathVariants<'_> {
1723    type Args = ();
1724}
1725
1726impl<'a> FontRead<'a> for MathVariants<'a> {
1727    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1728        #[allow(clippy::absurd_extreme_comparisons)]
1729        if data.len() < Self::MIN_SIZE {
1730            return Err(ReadError::OutOfBounds);
1731        }
1732        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1733            return Err(ReadError::OutOfBounds);
1734        };
1735        Ok(Self { data })
1736    }
1737}
1738
1739/// The fields at the start of the table, which are read directly.
1740#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1741#[repr(C, packed)]
1742#[doc(hidden)]
1743pub struct MathVariantsFixedHeader {
1744    pub min_connector_overlap: BigEndian<UfWord>,
1745    pub vert_glyph_coverage_offset: BigEndian<Nullable<Offset16>>,
1746    pub horiz_glyph_coverage_offset: BigEndian<Nullable<Offset16>>,
1747    pub vert_glyph_count: BigEndian<u16>,
1748    pub horiz_glyph_count: BigEndian<u16>,
1749}
1750
1751#[allow(clippy::absurd_extreme_comparisons)]
1752const _: () = assert!(std::mem::size_of::<MathVariantsFixedHeader>() <= MathVariants::MIN_SIZE);
1753
1754/// [MathVariants](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathvariants-table)
1755#[derive(Clone)]
1756pub struct MathVariants<'a> {
1757    data: TableDataRef<'a, MathVariantsFixedHeader>,
1758}
1759
1760#[allow(clippy::needless_lifetimes)]
1761impl<'a> MathVariants<'a> {
1762    pub const MIN_SIZE: usize = (UfWord::RAW_BYTE_LEN
1763        + Offset16::RAW_BYTE_LEN
1764        + Offset16::RAW_BYTE_LEN
1765        + u16::RAW_BYTE_LEN
1766        + u16::RAW_BYTE_LEN);
1767    basic_table_impls!(impl_the_methods);
1768
1769    /// Minimum overlap of connecting glyphs during glyph construction, in
1770    /// design units.
1771    pub fn min_connector_overlap(&self) -> UfWord {
1772        self.data.header().min_connector_overlap.get()
1773    }
1774
1775    /// Offset to the Coverage table for shapes growing in the vertical
1776    /// direction, from the beginning of the MathVariants table. May be NULL.
1777    pub fn vert_glyph_coverage_offset(&self) -> Nullable<Offset16> {
1778        self.data.header().vert_glyph_coverage_offset.get()
1779    }
1780
1781    /// Attempt to resolve [`vert_glyph_coverage_offset`][Self::vert_glyph_coverage_offset].
1782    pub fn vert_glyph_coverage(&self) -> Option<Result<CoverageTable<'a>, ReadError>> {
1783        let data = self.offset_data();
1784        self.vert_glyph_coverage_offset().resolve(data)
1785    }
1786
1787    /// Offset to the Coverage table for shapes growing in the horizontal
1788    /// direction, from the beginning of the MathVariants table. May be NULL.
1789    pub fn horiz_glyph_coverage_offset(&self) -> Nullable<Offset16> {
1790        self.data.header().horiz_glyph_coverage_offset.get()
1791    }
1792
1793    /// Attempt to resolve [`horiz_glyph_coverage_offset`][Self::horiz_glyph_coverage_offset].
1794    pub fn horiz_glyph_coverage(&self) -> Option<Result<CoverageTable<'a>, ReadError>> {
1795        let data = self.offset_data();
1796        self.horiz_glyph_coverage_offset().resolve(data)
1797    }
1798
1799    /// Number of glyphs for which information is provided for vertically
1800    /// growing variants. Must be the same as the number of glyph IDs referenced
1801    /// in the vertical Coverage table.
1802    pub fn vert_glyph_count(&self) -> u16 {
1803        self.data.header().vert_glyph_count.get()
1804    }
1805
1806    /// Number of glyphs for which information is provided for horizontally
1807    /// growing variants. Must be the same as the number of glyph IDs referenced
1808    /// in the horizontal Coverage table.
1809    pub fn horiz_glyph_count(&self) -> u16 {
1810        self.data.header().horiz_glyph_count.get()
1811    }
1812
1813    /// Array of offsets to MathGlyphConstruction tables, from the beginning of
1814    /// the MathVariants table, for shapes growing in the vertical direction.
1815    pub fn vert_glyph_construction_offsets(&self) -> &'a [BigEndian<Offset16>] {
1816        let range = self.vert_glyph_construction_offsets_byte_range();
1817        self.offset_data()
1818            .read_array(range)
1819            .ok()
1820            .unwrap_or_default()
1821    }
1822
1823    /// A dynamically resolving wrapper for [`vert_glyph_construction_offsets`][Self::vert_glyph_construction_offsets].
1824    pub fn vert_glyph_constructions(
1825        &self,
1826    ) -> ArrayOfOffsets<'a, MathGlyphConstruction<'a>, Offset16> {
1827        let data = self.offset_data();
1828        let offsets = self.vert_glyph_construction_offsets();
1829        ArrayOfOffsets::new(offsets, data, ())
1830    }
1831
1832    /// Array of offsets to MathGlyphConstruction tables, from the beginning of
1833    /// the MathVariants table, for shapes growing in the horizontal direction.
1834    pub fn horiz_glyph_construction_offsets(&self) -> &'a [BigEndian<Offset16>] {
1835        let range = self.horiz_glyph_construction_offsets_byte_range();
1836        self.offset_data()
1837            .read_array(range)
1838            .ok()
1839            .unwrap_or_default()
1840    }
1841
1842    /// A dynamically resolving wrapper for [`horiz_glyph_construction_offsets`][Self::horiz_glyph_construction_offsets].
1843    pub fn horiz_glyph_constructions(
1844        &self,
1845    ) -> ArrayOfOffsets<'a, MathGlyphConstruction<'a>, Offset16> {
1846        let data = self.offset_data();
1847        let offsets = self.horiz_glyph_construction_offsets();
1848        ArrayOfOffsets::new(offsets, data, ())
1849    }
1850
1851    pub fn min_connector_overlap_byte_range(&self) -> Range<usize> {
1852        let start = 0;
1853        let end = start + UfWord::RAW_BYTE_LEN;
1854        start..end
1855    }
1856
1857    pub fn vert_glyph_coverage_offset_byte_range(&self) -> Range<usize> {
1858        let start = self.min_connector_overlap_byte_range().end;
1859        let end = start + Offset16::RAW_BYTE_LEN;
1860        start..end
1861    }
1862
1863    pub fn horiz_glyph_coverage_offset_byte_range(&self) -> Range<usize> {
1864        let start = self.vert_glyph_coverage_offset_byte_range().end;
1865        let end = start + Offset16::RAW_BYTE_LEN;
1866        start..end
1867    }
1868
1869    pub fn vert_glyph_count_byte_range(&self) -> Range<usize> {
1870        let start = self.horiz_glyph_coverage_offset_byte_range().end;
1871        let end = start + u16::RAW_BYTE_LEN;
1872        start..end
1873    }
1874
1875    pub fn horiz_glyph_count_byte_range(&self) -> Range<usize> {
1876        let start = self.vert_glyph_count_byte_range().end;
1877        let end = start + u16::RAW_BYTE_LEN;
1878        start..end
1879    }
1880
1881    pub fn vert_glyph_construction_offsets_byte_range(&self) -> Range<usize> {
1882        let vert_glyph_count = self.vert_glyph_count();
1883        let start = self.horiz_glyph_count_byte_range().end;
1884        let end =
1885            start + (transforms::to_usize(vert_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1886        start..end
1887    }
1888
1889    pub fn horiz_glyph_construction_offsets_byte_range(&self) -> Range<usize> {
1890        let horiz_glyph_count = self.horiz_glyph_count();
1891        let start = self.vert_glyph_construction_offsets_byte_range().end;
1892        let end = start
1893            + (transforms::to_usize(horiz_glyph_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1894        start..end
1895    }
1896}
1897
1898const _: () = assert!(FontData::default_data_long_enough(MathVariants::MIN_SIZE));
1899
1900impl Default for MathVariants<'_> {
1901    fn default() -> Self {
1902        Self {
1903            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1904                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1905        }
1906    }
1907}
1908
1909impl<'a> MinByteRange<'a> for MathGlyphConstruction<'a> {
1910    fn min_byte_range(&self) -> Range<usize> {
1911        0..self.math_glyph_variant_records_byte_range().end
1912    }
1913    fn min_table_bytes(&self) -> &'a [u8] {
1914        let range = self.min_byte_range();
1915        self.offset_data().as_bytes().get(range).unwrap_or_default()
1916    }
1917}
1918
1919impl ReadArgs for MathGlyphConstruction<'_> {
1920    type Args = ();
1921}
1922
1923impl<'a> FontRead<'a> for MathGlyphConstruction<'a> {
1924    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1925        #[allow(clippy::absurd_extreme_comparisons)]
1926        if data.len() < Self::MIN_SIZE {
1927            return Err(ReadError::OutOfBounds);
1928        }
1929        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1930            return Err(ReadError::OutOfBounds);
1931        };
1932        Ok(Self { data })
1933    }
1934}
1935
1936/// The fields at the start of the table, which are read directly.
1937#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1938#[repr(C, packed)]
1939#[doc(hidden)]
1940pub struct MathGlyphConstructionFixedHeader {
1941    pub glyph_assembly_offset: BigEndian<Nullable<Offset16>>,
1942    pub variant_count: BigEndian<u16>,
1943}
1944
1945#[allow(clippy::absurd_extreme_comparisons)]
1946const _: () = assert!(
1947    std::mem::size_of::<MathGlyphConstructionFixedHeader>() <= MathGlyphConstruction::MIN_SIZE
1948);
1949
1950/// [MathGlyphConstruction](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table)
1951#[derive(Clone)]
1952pub struct MathGlyphConstruction<'a> {
1953    data: TableDataRef<'a, MathGlyphConstructionFixedHeader>,
1954}
1955
1956#[allow(clippy::needless_lifetimes)]
1957impl<'a> MathGlyphConstruction<'a> {
1958    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1959    basic_table_impls!(impl_the_methods);
1960
1961    /// Offset to the GlyphAssembly table for this shape, from the beginning of
1962    /// the MathGlyphConstruction table. May be NULL.
1963    pub fn glyph_assembly_offset(&self) -> Nullable<Offset16> {
1964        self.data.header().glyph_assembly_offset.get()
1965    }
1966
1967    /// Attempt to resolve [`glyph_assembly_offset`][Self::glyph_assembly_offset].
1968    pub fn glyph_assembly(&self) -> Option<Result<GlyphAssembly<'a>, ReadError>> {
1969        let data = self.offset_data();
1970        self.glyph_assembly_offset().resolve(data)
1971    }
1972
1973    /// Count of glyph growing variants for this glyph.
1974    pub fn variant_count(&self) -> u16 {
1975        self.data.header().variant_count.get()
1976    }
1977
1978    /// MathGlyphVariantRecords for alternative variants of the base glyph.
1979    pub fn math_glyph_variant_records(&self) -> &'a [MathGlyphVariantRecord] {
1980        let range = self.math_glyph_variant_records_byte_range();
1981        self.offset_data()
1982            .read_array(range)
1983            .ok()
1984            .unwrap_or_default()
1985    }
1986
1987    pub fn glyph_assembly_offset_byte_range(&self) -> Range<usize> {
1988        let start = 0;
1989        let end = start + Offset16::RAW_BYTE_LEN;
1990        start..end
1991    }
1992
1993    pub fn variant_count_byte_range(&self) -> Range<usize> {
1994        let start = self.glyph_assembly_offset_byte_range().end;
1995        let end = start + u16::RAW_BYTE_LEN;
1996        start..end
1997    }
1998
1999    pub fn math_glyph_variant_records_byte_range(&self) -> Range<usize> {
2000        let variant_count = self.variant_count();
2001        let start = self.variant_count_byte_range().end;
2002        let end = start
2003            + (transforms::to_usize(variant_count))
2004                .saturating_mul(MathGlyphVariantRecord::RAW_BYTE_LEN);
2005        start..end
2006    }
2007}
2008
2009const _: () = assert!(FontData::default_data_long_enough(
2010    MathGlyphConstruction::MIN_SIZE
2011));
2012
2013impl Default for MathGlyphConstruction<'_> {
2014    fn default() -> Self {
2015        Self {
2016            data: TableDataRef::new(FontData::default_table_data().as_bytes())
2017                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2018        }
2019    }
2020}
2021
2022/// [MathGlyphVariantRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphvariantrecord)
2023#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
2024#[repr(C)]
2025#[repr(packed)]
2026pub struct MathGlyphVariantRecord {
2027    /// Glyph ID for the variant.
2028    pub variant_glyph: BigEndian<GlyphId16>,
2029    /// Advance width/height, in design units, of the variant, in the direction
2030    /// of requested glyph extension.
2031    pub advance_measurement: BigEndian<UfWord>,
2032}
2033
2034impl MathGlyphVariantRecord {
2035    /// Glyph ID for the variant.
2036    pub fn variant_glyph(&self) -> GlyphId16 {
2037        self.variant_glyph.get()
2038    }
2039
2040    /// Advance width/height, in design units, of the variant, in the direction
2041    /// of requested glyph extension.
2042    pub fn advance_measurement(&self) -> UfWord {
2043        self.advance_measurement.get()
2044    }
2045}
2046
2047impl FixedSize for MathGlyphVariantRecord {
2048    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN + UfWord::RAW_BYTE_LEN;
2049}
2050
2051impl<'a> MinByteRange<'a> for GlyphAssembly<'a> {
2052    fn min_byte_range(&self) -> Range<usize> {
2053        0..self.part_records_byte_range().end
2054    }
2055    fn min_table_bytes(&self) -> &'a [u8] {
2056        let range = self.min_byte_range();
2057        self.offset_data().as_bytes().get(range).unwrap_or_default()
2058    }
2059}
2060
2061impl ReadArgs for GlyphAssembly<'_> {
2062    type Args = ();
2063}
2064
2065impl<'a> FontRead<'a> for GlyphAssembly<'a> {
2066    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2067        #[allow(clippy::absurd_extreme_comparisons)]
2068        if data.len() < Self::MIN_SIZE {
2069            return Err(ReadError::OutOfBounds);
2070        }
2071        let Some(data) = TableDataRef::new(data.as_bytes()) else {
2072            return Err(ReadError::OutOfBounds);
2073        };
2074        Ok(Self { data })
2075    }
2076}
2077
2078/// The fields at the start of the table, which are read directly.
2079#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
2080#[repr(C, packed)]
2081#[doc(hidden)]
2082pub struct GlyphAssemblyFixedHeader {
2083    pub italics_correction: MathValueRecord,
2084    pub part_count: BigEndian<u16>,
2085}
2086
2087#[allow(clippy::absurd_extreme_comparisons)]
2088const _: () = assert!(std::mem::size_of::<GlyphAssemblyFixedHeader>() <= GlyphAssembly::MIN_SIZE);
2089
2090/// [GlyphAssembly](https://learn.microsoft.com/en-us/typography/opentype/spec/math#glyphassembly-table)
2091#[derive(Clone)]
2092pub struct GlyphAssembly<'a> {
2093    data: TableDataRef<'a, GlyphAssemblyFixedHeader>,
2094}
2095
2096#[allow(clippy::needless_lifetimes)]
2097impl<'a> GlyphAssembly<'a> {
2098    pub const MIN_SIZE: usize = (MathValueRecord::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2099    basic_table_impls!(impl_the_methods);
2100
2101    /// Italics correction of this GlyphAssembly. Should not depend on the
2102    /// assembly size.
2103    pub fn italics_correction(&self) -> &'a MathValueRecord {
2104        &self.data.header().italics_correction
2105    }
2106
2107    /// Number of parts in this assembly.
2108    pub fn part_count(&self) -> u16 {
2109        self.data.header().part_count.get()
2110    }
2111
2112    /// Array of part records, from left to right (for assemblies that extend
2113    /// horizontally) or bottom to top (for assemblies that extend vertically).
2114    pub fn part_records(&self) -> &'a [GlyphPartRecord] {
2115        let range = self.part_records_byte_range();
2116        self.offset_data()
2117            .read_array(range)
2118            .ok()
2119            .unwrap_or_default()
2120    }
2121
2122    pub fn italics_correction_byte_range(&self) -> Range<usize> {
2123        let start = 0;
2124        let end = start + MathValueRecord::RAW_BYTE_LEN;
2125        start..end
2126    }
2127
2128    pub fn part_count_byte_range(&self) -> Range<usize> {
2129        let start = self.italics_correction_byte_range().end;
2130        let end = start + u16::RAW_BYTE_LEN;
2131        start..end
2132    }
2133
2134    pub fn part_records_byte_range(&self) -> Range<usize> {
2135        let part_count = self.part_count();
2136        let start = self.part_count_byte_range().end;
2137        let end = start
2138            + (transforms::to_usize(part_count)).saturating_mul(GlyphPartRecord::RAW_BYTE_LEN);
2139        start..end
2140    }
2141}
2142
2143const _: () = assert!(FontData::default_data_long_enough(GlyphAssembly::MIN_SIZE));
2144
2145impl Default for GlyphAssembly<'_> {
2146    fn default() -> Self {
2147        Self {
2148            data: TableDataRef::new(FontData::default_table_data().as_bytes())
2149                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
2150        }
2151    }
2152}
2153
2154/// [GlyphPartRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/math#glyphpartrecord)
2155#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
2156#[repr(C)]
2157#[repr(packed)]
2158pub struct GlyphPartRecord {
2159    /// Glyph ID for the part.
2160    pub glyph_id: BigEndian<GlyphId16>,
2161    /// Advance width/ height, in design units, of the straight bar connector
2162    /// material at the start of the glyph in the direction of the extension.
2163    pub start_connector_length: BigEndian<UfWord>,
2164    /// Advance width/ height, in design units, of the straight bar connector
2165    /// material at the end of the glyph in the direction of the extension.
2166    pub end_connector_length: BigEndian<UfWord>,
2167    /// Full advance width/height for this part in the direction of the
2168    /// extension, in design units.
2169    pub full_advance: BigEndian<UfWord>,
2170    /// Part qualifiers.
2171    pub part_flags: BigEndian<PartFlags>,
2172}
2173
2174impl GlyphPartRecord {
2175    /// Glyph ID for the part.
2176    pub fn glyph_id(&self) -> GlyphId16 {
2177        self.glyph_id.get()
2178    }
2179
2180    /// Advance width/ height, in design units, of the straight bar connector
2181    /// material at the start of the glyph in the direction of the extension.
2182    pub fn start_connector_length(&self) -> UfWord {
2183        self.start_connector_length.get()
2184    }
2185
2186    /// Advance width/ height, in design units, of the straight bar connector
2187    /// material at the end of the glyph in the direction of the extension.
2188    pub fn end_connector_length(&self) -> UfWord {
2189        self.end_connector_length.get()
2190    }
2191
2192    /// Full advance width/height for this part in the direction of the
2193    /// extension, in design units.
2194    pub fn full_advance(&self) -> UfWord {
2195        self.full_advance.get()
2196    }
2197
2198    /// Part qualifiers.
2199    pub fn part_flags(&self) -> PartFlags {
2200        self.part_flags.get()
2201    }
2202}
2203
2204impl FixedSize for GlyphPartRecord {
2205    const RAW_BYTE_LEN: usize = GlyphId16::RAW_BYTE_LEN
2206        + UfWord::RAW_BYTE_LEN
2207        + UfWord::RAW_BYTE_LEN
2208        + UfWord::RAW_BYTE_LEN
2209        + PartFlags::RAW_BYTE_LEN;
2210}
2211
2212/// Qualifiers for a [`GlyphPartRecord`].
2213#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
2214#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2215#[repr(transparent)]
2216pub struct PartFlags {
2217    bits: u16,
2218}
2219
2220impl PartFlags {
2221    /// If set, the part can be skipped or repeated.
2222    pub const EXTENDER_FLAG: Self = Self { bits: 0x0001 };
2223}
2224
2225impl PartFlags {
2226    ///  Returns an empty set of flags.
2227    #[inline]
2228    pub const fn empty() -> Self {
2229        Self { bits: 0 }
2230    }
2231
2232    /// Returns the set containing all flags.
2233    #[inline]
2234    pub const fn all() -> Self {
2235        Self {
2236            bits: Self::EXTENDER_FLAG.bits,
2237        }
2238    }
2239
2240    /// Returns the raw value of the flags currently stored.
2241    #[inline]
2242    pub const fn bits(&self) -> u16 {
2243        self.bits
2244    }
2245
2246    /// Convert from underlying bit representation, unless that
2247    /// representation contains bits that do not correspond to a flag.
2248    #[inline]
2249    pub const fn from_bits(bits: u16) -> Option<Self> {
2250        if (bits & !Self::all().bits()) == 0 {
2251            Some(Self { bits })
2252        } else {
2253            None
2254        }
2255    }
2256
2257    /// Convert from underlying bit representation, dropping any bits
2258    /// that do not correspond to flags.
2259    #[inline]
2260    pub const fn from_bits_truncate(bits: u16) -> Self {
2261        Self {
2262            bits: bits & Self::all().bits,
2263        }
2264    }
2265
2266    /// Returns `true` if no flags are currently stored.
2267    #[inline]
2268    pub const fn is_empty(&self) -> bool {
2269        self.bits() == Self::empty().bits()
2270    }
2271
2272    /// Returns `true` if there are flags common to both `self` and `other`.
2273    #[inline]
2274    pub const fn intersects(&self, other: Self) -> bool {
2275        !(Self {
2276            bits: self.bits & other.bits,
2277        })
2278        .is_empty()
2279    }
2280
2281    /// Returns `true` if all of the flags in `other` are contained within `self`.
2282    #[inline]
2283    pub const fn contains(&self, other: Self) -> bool {
2284        (self.bits & other.bits) == other.bits
2285    }
2286
2287    /// Inserts the specified flags in-place.
2288    #[inline]
2289    pub fn insert(&mut self, other: Self) {
2290        self.bits |= other.bits;
2291    }
2292
2293    /// Removes the specified flags in-place.
2294    #[inline]
2295    pub fn remove(&mut self, other: Self) {
2296        self.bits &= !other.bits;
2297    }
2298
2299    /// Toggles the specified flags in-place.
2300    #[inline]
2301    pub fn toggle(&mut self, other: Self) {
2302        self.bits ^= other.bits;
2303    }
2304
2305    /// Returns the intersection between the flags in `self` and
2306    /// `other`.
2307    ///
2308    /// Specifically, the returned set contains only the flags which are
2309    /// present in *both* `self` *and* `other`.
2310    ///
2311    /// This is equivalent to using the `&` operator (e.g.
2312    /// [`ops::BitAnd`]), as in `flags & other`.
2313    ///
2314    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
2315    #[inline]
2316    #[must_use]
2317    pub const fn intersection(self, other: Self) -> Self {
2318        Self {
2319            bits: self.bits & other.bits,
2320        }
2321    }
2322
2323    /// Returns the union of between the flags in `self` and `other`.
2324    ///
2325    /// Specifically, the returned set contains all flags which are
2326    /// present in *either* `self` *or* `other`, including any which are
2327    /// present in both.
2328    ///
2329    /// This is equivalent to using the `|` operator (e.g.
2330    /// [`ops::BitOr`]), as in `flags | other`.
2331    ///
2332    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
2333    #[inline]
2334    #[must_use]
2335    pub const fn union(self, other: Self) -> Self {
2336        Self {
2337            bits: self.bits | other.bits,
2338        }
2339    }
2340
2341    /// Returns the difference between the flags in `self` and `other`.
2342    ///
2343    /// Specifically, the returned set contains all flags present in
2344    /// `self`, except for the ones present in `other`.
2345    ///
2346    /// It is also conceptually equivalent to the "bit-clear" operation:
2347    /// `flags & !other` (and this syntax is also supported).
2348    ///
2349    /// This is equivalent to using the `-` operator (e.g.
2350    /// [`ops::Sub`]), as in `flags - other`.
2351    ///
2352    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
2353    #[inline]
2354    #[must_use]
2355    pub const fn difference(self, other: Self) -> Self {
2356        Self {
2357            bits: self.bits & !other.bits,
2358        }
2359    }
2360}
2361
2362impl std::ops::BitOr for PartFlags {
2363    type Output = Self;
2364
2365    /// Returns the union of the two sets of flags.
2366    #[inline]
2367    fn bitor(self, other: PartFlags) -> Self {
2368        Self {
2369            bits: self.bits | other.bits,
2370        }
2371    }
2372}
2373
2374impl std::ops::BitOrAssign for PartFlags {
2375    /// Adds the set of flags.
2376    #[inline]
2377    fn bitor_assign(&mut self, other: Self) {
2378        self.bits |= other.bits;
2379    }
2380}
2381
2382impl std::ops::BitXor for PartFlags {
2383    type Output = Self;
2384
2385    /// Returns the left flags, but with all the right flags toggled.
2386    #[inline]
2387    fn bitxor(self, other: Self) -> Self {
2388        Self {
2389            bits: self.bits ^ other.bits,
2390        }
2391    }
2392}
2393
2394impl std::ops::BitXorAssign for PartFlags {
2395    /// Toggles the set of flags.
2396    #[inline]
2397    fn bitxor_assign(&mut self, other: Self) {
2398        self.bits ^= other.bits;
2399    }
2400}
2401
2402impl std::ops::BitAnd for PartFlags {
2403    type Output = Self;
2404
2405    /// Returns the intersection between the two sets of flags.
2406    #[inline]
2407    fn bitand(self, other: Self) -> Self {
2408        Self {
2409            bits: self.bits & other.bits,
2410        }
2411    }
2412}
2413
2414impl std::ops::BitAndAssign for PartFlags {
2415    /// Disables all flags disabled in the set.
2416    #[inline]
2417    fn bitand_assign(&mut self, other: Self) {
2418        self.bits &= other.bits;
2419    }
2420}
2421
2422impl std::ops::Sub for PartFlags {
2423    type Output = Self;
2424
2425    /// Returns the set difference of the two sets of flags.
2426    #[inline]
2427    fn sub(self, other: Self) -> Self {
2428        Self {
2429            bits: self.bits & !other.bits,
2430        }
2431    }
2432}
2433
2434impl std::ops::SubAssign for PartFlags {
2435    /// Disables all flags enabled in the set.
2436    #[inline]
2437    fn sub_assign(&mut self, other: Self) {
2438        self.bits &= !other.bits;
2439    }
2440}
2441
2442impl std::ops::Not for PartFlags {
2443    type Output = Self;
2444
2445    /// Returns the complement of this set of flags.
2446    #[inline]
2447    fn not(self) -> Self {
2448        Self { bits: !self.bits } & Self::all()
2449    }
2450}
2451
2452impl std::fmt::Debug for PartFlags {
2453    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2454        let members: &[(&str, Self)] = &[("EXTENDER_FLAG", Self::EXTENDER_FLAG)];
2455        let mut first = true;
2456        for (name, value) in members {
2457            if self.contains(*value) {
2458                if !first {
2459                    f.write_str(" | ")?;
2460                }
2461                first = false;
2462                f.write_str(name)?;
2463            }
2464        }
2465        if first {
2466            f.write_str("(empty)")?;
2467        }
2468        Ok(())
2469    }
2470}
2471
2472impl std::fmt::Binary for PartFlags {
2473    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2474        std::fmt::Binary::fmt(&self.bits, f)
2475    }
2476}
2477
2478impl std::fmt::Octal for PartFlags {
2479    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2480        std::fmt::Octal::fmt(&self.bits, f)
2481    }
2482}
2483
2484impl std::fmt::LowerHex for PartFlags {
2485    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2486        std::fmt::LowerHex::fmt(&self.bits, f)
2487    }
2488}
2489
2490impl std::fmt::UpperHex for PartFlags {
2491    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2492        std::fmt::UpperHex::fmt(&self.bits, f)
2493    }
2494}
2495
2496impl font_types::Scalar for PartFlags {
2497    type Raw = <u16 as font_types::Scalar>::Raw;
2498    fn to_raw(self) -> Self::Raw {
2499        self.bits().to_raw()
2500    }
2501    fn from_raw(raw: Self::Raw) -> Self {
2502        let t = <u16>::from_raw(raw);
2503        Self::from_bits_truncate(t)
2504    }
2505}