ttf_parser/tables/
math.rs

1//! A [Math Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math) implementation.
2
3use crate::gpos::Device;
4use crate::opentype_layout::Coverage;
5use crate::parser::{
6    FromData, FromSlice, LazyArray16, LazyOffsetArray16, Offset, Offset16, Stream,
7};
8use crate::GlyphId;
9
10/// A [Math Value](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord)
11/// with optional device corrections.
12#[derive(Clone, Copy, Debug)]
13pub struct MathValue<'a> {
14    /// The X or Y value in font design units.
15    pub value: i16,
16    /// Device corrections for this value.
17    pub device: Option<Device<'a>>,
18}
19
20impl<'a> MathValue<'a> {
21    fn parse(data: &'a [u8], parent: &'a [u8]) -> Option<Self> {
22        Some(MathValueRecord::parse(data)?.get(parent))
23    }
24}
25
26/// A math value record with unresolved offset.
27#[derive(Clone, Copy)]
28struct MathValueRecord {
29    value: i16,
30    device_offset: Option<Offset16>,
31}
32
33impl FromData for MathValueRecord {
34    const SIZE: usize = 4;
35
36    fn parse(data: &[u8]) -> Option<Self> {
37        let mut s = Stream::new(data);
38        let value = s.read::<i16>()?;
39        let device_offset = s.read::<Option<Offset16>>()?;
40        Some(MathValueRecord {
41            value,
42            device_offset,
43        })
44    }
45}
46
47impl MathValueRecord {
48    fn get(self, data: &[u8]) -> MathValue {
49        let device = self
50            .device_offset
51            .and_then(|offset| data.get(offset.to_usize()..))
52            .and_then(Device::parse);
53        MathValue {
54            value: self.value,
55            device,
56        }
57    }
58}
59
60/// A mapping from glyphs to
61/// [Math Values](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvaluerecord).
62#[derive(Clone, Copy)]
63pub struct MathValues<'a> {
64    data: &'a [u8],
65    coverage: Coverage<'a>,
66    records: LazyArray16<'a, MathValueRecord>,
67}
68
69impl<'a> FromSlice<'a> for MathValues<'a> {
70    fn parse(data: &'a [u8]) -> Option<Self> {
71        let mut s = Stream::new(data);
72        let coverage = s.parse_at_offset16::<Coverage>(data)?;
73        let count = s.read::<u16>()?;
74        let records = s.read_array16::<MathValueRecord>(count)?;
75        Some(MathValues {
76            data,
77            coverage,
78            records,
79        })
80    }
81}
82
83impl<'a> MathValues<'a> {
84    /// Returns the value for the glyph or `None` if it is not covered.
85    #[inline]
86    pub fn get(&self, glyph: GlyphId) -> Option<MathValue<'a>> {
87        let index = self.coverage.get(glyph)?;
88        Some(self.records.get(index)?.get(self.data))
89    }
90}
91
92impl core::fmt::Debug for MathValues<'_> {
93    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
94        write!(f, "MathValues {{ ... }}")
95    }
96}
97
98/// A [Math Constants Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table).
99#[derive(Clone, Copy)]
100pub struct Constants<'a> {
101    data: &'a [u8],
102}
103
104impl<'a> FromSlice<'a> for Constants<'a> {
105    fn parse(data: &'a [u8]) -> Option<Self> {
106        Some(Constants { data })
107    }
108}
109
110impl core::fmt::Debug for Constants<'_> {
111    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
112        write!(f, "Constants {{ ... }}")
113    }
114}
115
116const SCRIPT_PERCENT_SCALE_DOWN_OFFSET: usize = 0;
117const SCRIPT_SCRIPT_PERCENT_SCALE_DOWN_OFFSET: usize = 2;
118const DELIMITED_SUB_FORMULA_MIN_HEIGHT_OFFSET: usize = 4;
119const DISPLAY_OPERATOR_MIN_HEIGHT_OFFSET: usize = 6;
120const MATH_LEADING_OFFSET: usize = 8;
121const AXIS_HEIGHT_OFFSET: usize = 12;
122const ACCENT_BASE_HEIGHT_OFFSET: usize = 16;
123const FLATTENED_ACCENT_BASE_HEIGHT_OFFSET: usize = 20;
124const SUBSCRIPT_SHIFT_DOWN_OFFSET: usize = 24;
125const SUBSCRIPT_TOP_MAX_OFFSET: usize = 28;
126const SUBSCRIPT_BASELINE_DROP_MIN_OFFSET: usize = 32;
127const SUPERSCRIPT_SHIFT_UP_OFFSET: usize = 36;
128const SUPERSCRIPT_SHIFT_UP_CRAMPED_OFFSET: usize = 40;
129const SUPERSCRIPT_BOTTOM_MIN_OFFSET: usize = 44;
130const SUPERSCRIPT_BASELINE_DROP_MAX_OFFSET: usize = 48;
131const SUB_SUPERSCRIPT_GAP_MIN_OFFSET: usize = 52;
132const SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT_OFFSET: usize = 56;
133const SPACE_AFTER_SCRIPT_OFFSET: usize = 60;
134const UPPER_LIMIT_GAP_MIN_OFFSET: usize = 64;
135const UPPER_LIMIT_BASELINE_RISE_MIN_OFFSET: usize = 68;
136const LOWER_LIMIT_GAP_MIN_OFFSET: usize = 72;
137const LOWER_LIMIT_BASELINE_DROP_MIN_OFFSET: usize = 76;
138const STACK_TOP_SHIFT_UP_OFFSET: usize = 80;
139const STACK_TOP_DISPLAY_STYLE_SHIFT_UP_OFFSET: usize = 84;
140const STACK_BOTTOM_SHIFT_DOWN_OFFSET: usize = 88;
141const STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN_OFFSET: usize = 92;
142const STACK_GAP_MIN_OFFSET: usize = 96;
143const STACK_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 100;
144const STRETCH_STACK_TOP_SHIFT_UP_OFFSET: usize = 104;
145const STRETCH_STACK_BOTTOM_SHIFT_DOWN_OFFSET: usize = 108;
146const STRETCH_STACK_GAP_ABOVE_MIN_OFFSET: usize = 112;
147const STRETCH_STACK_GAP_BELOW_MIN_OFFSET: usize = 116;
148const FRACTION_NUMERATOR_SHIFT_UP_OFFSET: usize = 120;
149const FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP_OFFSET: usize = 124;
150const FRACTION_DENOMINATOR_SHIFT_DOWN_OFFSET: usize = 128;
151const FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN_OFFSET: usize = 132;
152const FRACTION_NUMERATOR_GAP_MIN_OFFSET: usize = 136;
153const FRACTION_NUM_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 140;
154const FRACTION_RULE_THICKNESS_OFFSET: usize = 144;
155const FRACTION_DENOMINATOR_GAP_MIN_OFFSET: usize = 148;
156const FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN_OFFSET: usize = 152;
157const SKEWED_FRACTION_HORIZONTAL_GAP_OFFSET: usize = 156;
158const SKEWED_FRACTION_VERTICAL_GAP_OFFSET: usize = 160;
159const OVERBAR_VERTICAL_GAP_OFFSET: usize = 164;
160const OVERBAR_RULE_THICKNESS_OFFSET: usize = 168;
161const OVERBAR_EXTRA_ASCENDER_OFFSET: usize = 172;
162const UNDERBAR_VERTICAL_GAP_OFFSET: usize = 176;
163const UNDERBAR_RULE_THICKNESS_OFFSET: usize = 180;
164const UNDERBAR_EXTRA_DESCENDER_OFFSET: usize = 184;
165const RADICAL_VERTICAL_GAP_OFFSET: usize = 188;
166const RADICAL_DISPLAY_STYLE_VERTICAL_GAP_OFFSET: usize = 192;
167const RADICAL_RULE_THICKNESS_OFFSET: usize = 196;
168const RADICAL_EXTRA_ASCENDER_OFFSET: usize = 200;
169const RADICAL_KERN_BEFORE_DEGREE_OFFSET: usize = 204;
170const RADICAL_KERN_AFTER_DEGREE_OFFSET: usize = 208;
171const RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET: usize = 212;
172
173impl<'a> Constants<'a> {
174    /// Percentage of scaling down for level 1 superscripts and subscripts.
175    #[inline]
176    pub fn script_percent_scale_down(&self) -> i16 {
177        self.read_i16(SCRIPT_PERCENT_SCALE_DOWN_OFFSET)
178    }
179
180    /// Percentage of scaling down for level 2 (scriptScript) superscripts and subscripts.
181    #[inline]
182    pub fn script_script_percent_scale_down(&self) -> i16 {
183        self.read_i16(SCRIPT_SCRIPT_PERCENT_SCALE_DOWN_OFFSET)
184    }
185
186    /// Minimum height required for a delimited expression (contained within parentheses, etc.) to
187    /// be treated as a sub-formula.
188    #[inline]
189    pub fn delimited_sub_formula_min_height(&self) -> u16 {
190        self.read_u16(DELIMITED_SUB_FORMULA_MIN_HEIGHT_OFFSET)
191    }
192
193    /// Minimum height of n-ary operators (such as integral and summation) for formulas in display
194    /// mode (that is, appearing as standalone page elements, not embedded inline within text).
195    #[inline]
196    pub fn display_operator_min_height(&self) -> u16 {
197        self.read_u16(DISPLAY_OPERATOR_MIN_HEIGHT_OFFSET)
198    }
199
200    /// White space to be left between math formulas to ensure proper line spacing.
201    #[inline]
202    pub fn math_leading(&self) -> MathValue<'a> {
203        self.read_record(MATH_LEADING_OFFSET)
204    }
205
206    /// Axis height of the font.
207    #[inline]
208    pub fn axis_height(&self) -> MathValue<'a> {
209        self.read_record(AXIS_HEIGHT_OFFSET)
210    }
211
212    /// Maximum (ink) height of accent base that does not require raising the accents.
213    #[inline]
214    pub fn accent_base_height(&self) -> MathValue<'a> {
215        self.read_record(ACCENT_BASE_HEIGHT_OFFSET)
216    }
217
218    /// Maximum (ink) height of accent base that does not require flattening the accents.
219    #[inline]
220    pub fn flattened_accent_base_height(&self) -> MathValue<'a> {
221        self.read_record(FLATTENED_ACCENT_BASE_HEIGHT_OFFSET)
222    }
223
224    /// The standard shift down applied to subscript elements.
225    #[inline]
226    pub fn subscript_shift_down(&self) -> MathValue<'a> {
227        self.read_record(SUBSCRIPT_SHIFT_DOWN_OFFSET)
228    }
229
230    /// Maximum allowed height of the (ink) top of subscripts that does not require moving
231    /// subscripts further down.
232    #[inline]
233    pub fn subscript_top_max(&self) -> MathValue<'a> {
234        self.read_record(SUBSCRIPT_TOP_MAX_OFFSET)
235    }
236
237    /// Minimum allowed drop of the baseline of subscripts relative to the (ink) bottom of the
238    /// base.
239    #[inline]
240    pub fn subscript_baseline_drop_min(&self) -> MathValue<'a> {
241        self.read_record(SUBSCRIPT_BASELINE_DROP_MIN_OFFSET)
242    }
243
244    /// Standard shift up applied to superscript elements.
245    #[inline]
246    pub fn superscript_shift_up(&self) -> MathValue<'a> {
247        self.read_record(SUPERSCRIPT_SHIFT_UP_OFFSET)
248    }
249
250    /// Standard shift of superscripts relative to the base, in cramped style.
251    #[inline]
252    pub fn superscript_shift_up_cramped(&self) -> MathValue<'a> {
253        self.read_record(SUPERSCRIPT_SHIFT_UP_CRAMPED_OFFSET)
254    }
255
256    /// Minimum allowed height of the (ink) bottom of superscripts that does not require moving
257    /// subscripts further up.
258    #[inline]
259    pub fn superscript_bottom_min(&self) -> MathValue<'a> {
260        self.read_record(SUPERSCRIPT_BOTTOM_MIN_OFFSET)
261    }
262
263    /// Maximum allowed drop of the baseline of superscripts relative to the (ink) top of the
264    /// base.
265    #[inline]
266    pub fn superscript_baseline_drop_max(&self) -> MathValue<'a> {
267        self.read_record(SUPERSCRIPT_BASELINE_DROP_MAX_OFFSET)
268    }
269
270    /// Minimum gap between the superscript and subscript ink.
271    #[inline]
272    pub fn sub_superscript_gap_min(&self) -> MathValue<'a> {
273        self.read_record(SUB_SUPERSCRIPT_GAP_MIN_OFFSET)
274    }
275
276    /// The maximum level to which the (ink) bottom of superscript can be pushed to increase the
277    /// gap between superscript and subscript, before subscript starts being moved down.
278    #[inline]
279    pub fn superscript_bottom_max_with_subscript(&self) -> MathValue<'a> {
280        self.read_record(SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT_OFFSET)
281    }
282
283    /// Extra white space to be added after each subscript and superscript.
284    #[inline]
285    pub fn space_after_script(&self) -> MathValue<'a> {
286        self.read_record(SPACE_AFTER_SCRIPT_OFFSET)
287    }
288
289    /// Minimum gap between the (ink) bottom of the upper limit, and the (ink) top of the base
290    /// operator.
291    #[inline]
292    pub fn upper_limit_gap_min(&self) -> MathValue<'a> {
293        self.read_record(UPPER_LIMIT_GAP_MIN_OFFSET)
294    }
295
296    /// Minimum distance between baseline of upper limit and (ink) top of the base operator.
297    #[inline]
298    pub fn upper_limit_baseline_rise_min(&self) -> MathValue<'a> {
299        self.read_record(UPPER_LIMIT_BASELINE_RISE_MIN_OFFSET)
300    }
301
302    /// Minimum gap between (ink) top of the lower limit, and (ink) bottom of the base operator.
303    #[inline]
304    pub fn lower_limit_gap_min(&self) -> MathValue<'a> {
305        self.read_record(LOWER_LIMIT_GAP_MIN_OFFSET)
306    }
307
308    /// Minimum distance between baseline of the lower limit and (ink) bottom of the base operator.
309    #[inline]
310    pub fn lower_limit_baseline_drop_min(&self) -> MathValue<'a> {
311        self.read_record(LOWER_LIMIT_BASELINE_DROP_MIN_OFFSET)
312    }
313
314    /// Standard shift up applied to the top element of a stack.
315    #[inline]
316    pub fn stack_top_shift_up(&self) -> MathValue<'a> {
317        self.read_record(STACK_TOP_SHIFT_UP_OFFSET)
318    }
319
320    /// Standard shift up applied to the top element of a stack in display style.
321    #[inline]
322    pub fn stack_top_display_style_shift_up(&self) -> MathValue<'a> {
323        self.read_record(STACK_TOP_DISPLAY_STYLE_SHIFT_UP_OFFSET)
324    }
325
326    /// Standard shift down applied to the bottom element of a stack.
327    #[inline]
328    pub fn stack_bottom_shift_down(&self) -> MathValue<'a> {
329        self.read_record(STACK_BOTTOM_SHIFT_DOWN_OFFSET)
330    }
331
332    /// Standard shift down applied to the bottom element of a stack in display style.
333    #[inline]
334    pub fn stack_bottom_display_style_shift_down(&self) -> MathValue<'a> {
335        self.read_record(STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN_OFFSET)
336    }
337
338    /// Minimum gap between (ink) bottom of the top element of a stack, and the (ink) top of the
339    /// bottom element.
340    #[inline]
341    pub fn stack_gap_min(&self) -> MathValue<'a> {
342        self.read_record(STACK_GAP_MIN_OFFSET)
343    }
344
345    /// Minimum gap between (ink) bottom of the top element of a stack, and the (ink) top of the
346    /// bottom element in display style.
347    #[inline]
348    pub fn stack_display_style_gap_min(&self) -> MathValue<'a> {
349        self.read_record(STACK_DISPLAY_STYLE_GAP_MIN_OFFSET)
350    }
351
352    /// Standard shift up applied to the top element of the stretch stack.
353    #[inline]
354    pub fn stretch_stack_top_shift_up(&self) -> MathValue<'a> {
355        self.read_record(STRETCH_STACK_TOP_SHIFT_UP_OFFSET)
356    }
357
358    /// Standard shift down applied to the bottom element of the stretch stack.
359    #[inline]
360    pub fn stretch_stack_bottom_shift_down(&self) -> MathValue<'a> {
361        self.read_record(STRETCH_STACK_BOTTOM_SHIFT_DOWN_OFFSET)
362    }
363
364    /// Minimum gap between the ink of the stretched element, and the (ink) bottom of the element above.
365    #[inline]
366    pub fn stretch_stack_gap_above_min(&self) -> MathValue<'a> {
367        self.read_record(STRETCH_STACK_GAP_ABOVE_MIN_OFFSET)
368    }
369
370    /// Minimum gap between the ink of the stretched element, and the (ink) top of the element below.
371    #[inline]
372    pub fn stretch_stack_gap_below_min(&self) -> MathValue<'a> {
373        self.read_record(STRETCH_STACK_GAP_BELOW_MIN_OFFSET)
374    }
375
376    /// Standard shift up applied to the numerator.
377    #[inline]
378    pub fn fraction_numerator_shift_up(&self) -> MathValue<'a> {
379        self.read_record(FRACTION_NUMERATOR_SHIFT_UP_OFFSET)
380    }
381
382    /// Standard shift up applied to the numerator in display style.
383    #[inline]
384    pub fn fraction_numerator_display_style_shift_up(&self) -> MathValue<'a> {
385        self.read_record(FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP_OFFSET)
386    }
387
388    /// Standard shift down applied to the denominator.
389    #[inline]
390    pub fn fraction_denominator_shift_down(&self) -> MathValue<'a> {
391        self.read_record(FRACTION_DENOMINATOR_SHIFT_DOWN_OFFSET)
392    }
393
394    /// Standard shift down applied to the denominator in display style.
395    #[inline]
396    pub fn fraction_denominator_display_style_shift_down(&self) -> MathValue<'a> {
397        self.read_record(FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN_OFFSET)
398    }
399
400    /// Minimum tolerated gap between the (ink) bottom of the numerator and the ink of the
401    /// fraction bar.
402    #[inline]
403    pub fn fraction_numerator_gap_min(&self) -> MathValue<'a> {
404        self.read_record(FRACTION_NUMERATOR_GAP_MIN_OFFSET)
405    }
406
407    /// Minimum tolerated gap between the (ink) bottom of the numerator and the ink of the
408    /// fraction bar in display style.
409    #[inline]
410    pub fn fraction_num_display_style_gap_min(&self) -> MathValue<'a> {
411        self.read_record(FRACTION_NUM_DISPLAY_STYLE_GAP_MIN_OFFSET)
412    }
413
414    /// Thickness of the fraction bar.
415    #[inline]
416    pub fn fraction_rule_thickness(&self) -> MathValue<'a> {
417        self.read_record(FRACTION_RULE_THICKNESS_OFFSET)
418    }
419
420    /// Minimum tolerated gap between the (ink) top of the denominator and the ink of the fraction bar.
421    #[inline]
422    pub fn fraction_denominator_gap_min(&self) -> MathValue<'a> {
423        self.read_record(FRACTION_DENOMINATOR_GAP_MIN_OFFSET)
424    }
425
426    /// Minimum tolerated gap between the (ink) top of the denominator and the ink of the fraction
427    /// bar in display style.
428    #[inline]
429    pub fn fraction_denom_display_style_gap_min(&self) -> MathValue<'a> {
430        self.read_record(FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN_OFFSET)
431    }
432
433    /// Horizontal distance between the top and bottom elements of a skewed fraction.
434    #[inline]
435    pub fn skewed_fraction_horizontal_gap(&self) -> MathValue<'a> {
436        self.read_record(SKEWED_FRACTION_HORIZONTAL_GAP_OFFSET)
437    }
438
439    /// Vertical distance between the ink of the top and bottom elements of a skewed fraction.
440    #[inline]
441    pub fn skewed_fraction_vertical_gap(&self) -> MathValue<'a> {
442        self.read_record(SKEWED_FRACTION_VERTICAL_GAP_OFFSET)
443    }
444
445    /// Distance between the overbar and the (ink) top of he base.
446    #[inline]
447    pub fn overbar_vertical_gap(&self) -> MathValue<'a> {
448        self.read_record(OVERBAR_VERTICAL_GAP_OFFSET)
449    }
450
451    /// Thickness of overbar.
452    #[inline]
453    pub fn overbar_rule_thickness(&self) -> MathValue<'a> {
454        self.read_record(OVERBAR_RULE_THICKNESS_OFFSET)
455    }
456
457    /// Extra white space reserved above the overbar.
458    #[inline]
459    pub fn overbar_extra_ascender(&self) -> MathValue<'a> {
460        self.read_record(OVERBAR_EXTRA_ASCENDER_OFFSET)
461    }
462
463    /// Distance between underbar and (ink) bottom of the base.
464    #[inline]
465    pub fn underbar_vertical_gap(&self) -> MathValue<'a> {
466        self.read_record(UNDERBAR_VERTICAL_GAP_OFFSET)
467    }
468
469    /// Thickness of underbar.
470    #[inline]
471    pub fn underbar_rule_thickness(&self) -> MathValue<'a> {
472        self.read_record(UNDERBAR_RULE_THICKNESS_OFFSET)
473    }
474
475    /// Extra white space reserved below the underbar.
476    #[inline]
477    pub fn underbar_extra_descender(&self) -> MathValue<'a> {
478        self.read_record(UNDERBAR_EXTRA_DESCENDER_OFFSET)
479    }
480
481    /// Space between the (ink) top of the expression and the bar over it.
482    #[inline]
483    pub fn radical_vertical_gap(&self) -> MathValue<'a> {
484        self.read_record(RADICAL_VERTICAL_GAP_OFFSET)
485    }
486
487    /// Space between the (ink) top of the expression and the bar over it.
488    #[inline]
489    pub fn radical_display_style_vertical_gap(&self) -> MathValue<'a> {
490        self.read_record(RADICAL_DISPLAY_STYLE_VERTICAL_GAP_OFFSET)
491    }
492
493    /// Thickness of the radical rule.
494    #[inline]
495    pub fn radical_rule_thickness(&self) -> MathValue<'a> {
496        self.read_record(RADICAL_RULE_THICKNESS_OFFSET)
497    }
498
499    /// Extra white space reserved above the radical.
500    #[inline]
501    pub fn radical_extra_ascender(&self) -> MathValue<'a> {
502        self.read_record(RADICAL_EXTRA_ASCENDER_OFFSET)
503    }
504
505    /// Extra horizontal kern before the degree of a radical, if such is present.
506    #[inline]
507    pub fn radical_kern_before_degree(&self) -> MathValue<'a> {
508        self.read_record(RADICAL_KERN_BEFORE_DEGREE_OFFSET)
509    }
510
511    /// Negative kern after the degree of a radical, if such is present.
512    #[inline]
513    pub fn radical_kern_after_degree(&self) -> MathValue<'a> {
514        self.read_record(RADICAL_KERN_AFTER_DEGREE_OFFSET)
515    }
516
517    /// Height of the bottom of the radical degree, if such is present, in proportion to the
518    /// ascender of the radical sign.
519    #[inline]
520    pub fn radical_degree_bottom_raise_percent(&self) -> i16 {
521        self.read_i16(RADICAL_DEGREE_BOTTOM_RAISE_PERCENT_OFFSET)
522    }
523
524    /// Read an `i16` at an offset into the table.
525    #[inline]
526    fn read_i16(&self, offset: usize) -> i16 {
527        Stream::read_at(self.data, offset).unwrap_or(0)
528    }
529
530    /// Read an `u16` at an offset into the table.
531    #[inline]
532    fn read_u16(&self, offset: usize) -> u16 {
533        Stream::read_at(self.data, offset).unwrap_or(0)
534    }
535
536    /// Read a `MathValueRecord` at an offset into the table.
537    #[inline]
538    fn read_record(&self, offset: usize) -> MathValue<'a> {
539        self.data
540            .get(offset..)
541            .and_then(|data| MathValue::parse(data, self.data))
542            .unwrap_or(MathValue {
543                value: 0,
544                device: None,
545            })
546    }
547}
548
549/// A [Math Kern Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkern-table).
550#[derive(Clone)]
551pub struct Kern<'a> {
552    data: &'a [u8],
553    heights: LazyArray16<'a, MathValueRecord>,
554    kerns: LazyArray16<'a, MathValueRecord>,
555}
556
557impl<'a> Kern<'a> {
558    /// Number of heights at which the kern value changes.
559    pub fn count(&self) -> u16 {
560        self.heights.len()
561    }
562
563    /// The correction height at the given index.
564    ///
565    /// The index must be smaller than `count()`.
566    pub fn height(&self, index: u16) -> Option<MathValue<'a>> {
567        Some(self.heights.get(index)?.get(self.data))
568    }
569
570    /// The kern value at the given index.
571    ///
572    /// The index must be smaller than or equal to `count()`.
573    pub fn kern(&self, index: u16) -> Option<MathValue<'a>> {
574        Some(self.kerns.get(index)?.get(self.data))
575    }
576}
577
578impl<'a> FromSlice<'a> for Kern<'a> {
579    fn parse(data: &'a [u8]) -> Option<Self> {
580        let mut s = Stream::new(data);
581        let count = s.read::<u16>()?;
582        let heights = s.read_array16::<MathValueRecord>(count)?;
583        let kerns = s.read_array16::<MathValueRecord>(count + 1)?;
584        Some(Kern {
585            data,
586            heights,
587            kerns,
588        })
589    }
590}
591
592impl core::fmt::Debug for Kern<'_> {
593    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
594        write!(f, "Kern {{ ... }}")
595    }
596}
597
598#[derive(Clone, Copy)]
599struct KernInfoRecord {
600    top_right: Option<Offset16>,
601    top_left: Option<Offset16>,
602    bottom_right: Option<Offset16>,
603    bottom_left: Option<Offset16>,
604}
605
606impl FromData for KernInfoRecord {
607    const SIZE: usize = 8;
608
609    fn parse(data: &[u8]) -> Option<Self> {
610        let mut s = Stream::new(data);
611        Some(KernInfoRecord {
612            top_right: s.read::<Option<Offset16>>()?,
613            top_left: s.read::<Option<Offset16>>()?,
614            bottom_right: s.read::<Option<Offset16>>()?,
615            bottom_left: s.read::<Option<Offset16>>()?,
616        })
617    }
618}
619
620impl KernInfoRecord {
621    fn get<'a>(&self, data: &'a [u8]) -> KernInfo<'a> {
622        let parse_field = |offset: Option<Offset16>| {
623            offset
624                .and_then(|offset| data.get(offset.to_usize()..))
625                .and_then(Kern::parse)
626        };
627        KernInfo {
628            top_right: parse_field(self.top_right),
629            top_left: parse_field(self.top_left),
630            bottom_right: parse_field(self.bottom_right),
631            bottom_left: parse_field(self.bottom_left),
632        }
633    }
634}
635
636/// An [entry in a Math Kern Info Table](
637/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathkerninforecord).
638#[derive(Clone, Debug)]
639pub struct KernInfo<'a> {
640    /// The kerning data for the top-right corner.
641    pub top_right: Option<Kern<'a>>,
642    /// The kerning data for the top-left corner.
643    pub top_left: Option<Kern<'a>>,
644    /// The kerning data for the bottom-right corner.
645    pub bottom_right: Option<Kern<'a>>,
646    /// The kerning data for the bottom-left corner.
647    pub bottom_left: Option<Kern<'a>>,
648}
649
650/// A [Math Kern Info Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathkerninfo-table).
651#[derive(Clone, Copy)]
652pub struct KernInfos<'a> {
653    data: &'a [u8],
654    coverage: Coverage<'a>,
655    records: LazyArray16<'a, KernInfoRecord>,
656}
657
658impl<'a> FromSlice<'a> for KernInfos<'a> {
659    fn parse(data: &'a [u8]) -> Option<Self> {
660        let mut s = Stream::new(data);
661        let coverage = s.parse_at_offset16::<Coverage>(data)?;
662        let count = s.read::<u16>()?;
663        let records = s.read_array16::<KernInfoRecord>(count)?;
664        Some(KernInfos {
665            data,
666            coverage,
667            records,
668        })
669    }
670}
671
672impl<'a> KernInfos<'a> {
673    /// Returns the kerning info for the glyph or `None` if it is not covered.
674    #[inline]
675    pub fn get(&self, glyph: GlyphId) -> Option<KernInfo<'a>> {
676        let index = self.coverage.get(glyph)?;
677        Some(self.records.get(index)?.get(self.data))
678    }
679}
680
681impl core::fmt::Debug for KernInfos<'_> {
682    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
683        write!(f, "KernInfos {{ ... }}")
684    }
685}
686
687/// A [Math Glyph Info Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphinfo-table).
688#[derive(Clone, Copy, Debug)]
689pub struct GlyphInfo<'a> {
690    /// Per-glyph italics correction values.
691    pub italic_corrections: Option<MathValues<'a>>,
692    /// Per-glyph horizontal positions for attaching mathematical accents.
693    pub top_accent_attachments: Option<MathValues<'a>>,
694    /// Glyphs which are _extended shapes_.
695    pub extended_shapes: Option<Coverage<'a>>,
696    /// Per-glyph information for mathematical kerning.
697    pub kern_infos: Option<KernInfos<'a>>,
698}
699
700impl<'a> FromSlice<'a> for GlyphInfo<'a> {
701    fn parse(data: &'a [u8]) -> Option<Self> {
702        let mut s = Stream::new(data);
703        Some(GlyphInfo {
704            italic_corrections: s.parse_at_offset16::<MathValues>(data),
705            top_accent_attachments: s.parse_at_offset16::<MathValues>(data),
706            extended_shapes: s.parse_at_offset16::<Coverage>(data),
707            kern_infos: s.parse_at_offset16::<KernInfos>(data),
708        })
709    }
710}
711
712/// Glyph part flags.
713#[derive(Clone, Copy, Debug)]
714pub struct PartFlags(pub u16);
715
716#[allow(missing_docs)]
717impl PartFlags {
718    #[inline]
719    pub fn extender(self) -> bool {
720        self.0 & 0x0001 != 0
721    }
722}
723
724impl FromData for PartFlags {
725    const SIZE: usize = 2;
726
727    fn parse(data: &[u8]) -> Option<Self> {
728        u16::parse(data).map(PartFlags)
729    }
730}
731
732/// Details for a glyph part in an assembly.
733#[derive(Clone, Copy, Debug)]
734pub struct GlyphPart {
735    /// Glyph ID for the part.
736    pub glyph_id: GlyphId,
737    /// Lengths of the connectors on the start of the glyph, in font design units.
738    pub start_connector_length: u16,
739    /// Lengths of the connectors on the end of the glyph, in font design units.
740    pub end_connector_length: u16,
741    /// The full advance of the part, in font design units.
742    pub full_advance: u16,
743    /// Part flags.
744    pub part_flags: PartFlags,
745}
746
747impl FromData for GlyphPart {
748    const SIZE: usize = 10;
749
750    fn parse(data: &[u8]) -> Option<Self> {
751        let mut s = Stream::new(data);
752        Some(GlyphPart {
753            glyph_id: s.read::<GlyphId>()?,
754            start_connector_length: s.read::<u16>()?,
755            end_connector_length: s.read::<u16>()?,
756            full_advance: s.read::<u16>()?,
757            part_flags: s.read::<PartFlags>()?,
758        })
759    }
760}
761
762/// A [Glyph Assembly Table](https://learn.microsoft.com/en-us/typography/opentype/spec/math#glyphassembly-table).
763#[derive(Clone, Copy, Debug)]
764pub struct GlyphAssembly<'a> {
765    /// The italics correction of the assembled glyph.
766    pub italics_correction: MathValue<'a>,
767    /// Parts the assembly is composed of.
768    pub parts: LazyArray16<'a, GlyphPart>,
769}
770
771impl<'a> FromSlice<'a> for GlyphAssembly<'a> {
772    fn parse(data: &'a [u8]) -> Option<Self> {
773        let mut s = Stream::new(data);
774        let italics_correction = s.read::<MathValueRecord>()?.get(data);
775        let count = s.read::<u16>()?;
776        let parts = s.read_array16::<GlyphPart>(count)?;
777        Some(GlyphAssembly {
778            italics_correction,
779            parts,
780        })
781    }
782}
783
784/// Description of math glyph variants.
785#[derive(Clone, Copy, Debug)]
786pub struct GlyphVariant {
787    /// The ID of the variant glyph.
788    pub variant_glyph: GlyphId,
789    /// Advance width/height, in design units, of the variant glyph.
790    pub advance_measurement: u16,
791}
792
793impl FromData for GlyphVariant {
794    const SIZE: usize = 4;
795
796    fn parse(data: &[u8]) -> Option<Self> {
797        let mut s = Stream::new(data);
798        Some(GlyphVariant {
799            variant_glyph: s.read::<GlyphId>()?,
800            advance_measurement: s.read::<u16>()?,
801        })
802    }
803}
804
805/// A [Math Glyph Construction Table](
806/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table).
807#[derive(Clone, Copy, Debug)]
808pub struct GlyphConstruction<'a> {
809    /// A general recipe on how to construct a variant with large advance width/height.
810    pub assembly: Option<GlyphAssembly<'a>>,
811    /// Prepared variants of the glyph with varying advances.
812    pub variants: LazyArray16<'a, GlyphVariant>,
813}
814
815impl<'a> FromSlice<'a> for GlyphConstruction<'a> {
816    fn parse(data: &'a [u8]) -> Option<Self> {
817        let mut s = Stream::new(data);
818        let assembly = s.parse_at_offset16::<GlyphAssembly>(data);
819        let variant_count = s.read::<u16>()?;
820        let variants = s.read_array16::<GlyphVariant>(variant_count)?;
821        Some(GlyphConstruction { assembly, variants })
822    }
823}
824
825/// A mapping from glyphs to
826/// [Math Glyph Construction Tables](
827/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathglyphconstruction-table).
828#[derive(Clone, Copy)]
829pub struct GlyphConstructions<'a> {
830    coverage: Coverage<'a>,
831    constructions: LazyOffsetArray16<'a, GlyphConstruction<'a>>,
832}
833
834impl<'a> GlyphConstructions<'a> {
835    fn new(
836        data: &'a [u8],
837        coverage: Option<Coverage<'a>>,
838        offsets: LazyArray16<'a, Option<Offset16>>,
839    ) -> Self {
840        GlyphConstructions {
841            coverage: coverage.unwrap_or(Coverage::Format1 {
842                glyphs: LazyArray16::new(&[]),
843            }),
844            constructions: LazyOffsetArray16::new(data, offsets),
845        }
846    }
847
848    /// Returns the construction for the glyph or `None` if it is not covered.
849    #[inline]
850    pub fn get(&self, glyph: GlyphId) -> Option<GlyphConstruction<'a>> {
851        let index = self.coverage.get(glyph)?;
852        self.constructions.get(index)
853    }
854}
855
856impl core::fmt::Debug for GlyphConstructions<'_> {
857    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
858        write!(f, "GlyphConstructions {{ ... }}")
859    }
860}
861
862/// A [Math Variants Table](
863/// https://learn.microsoft.com/en-us/typography/opentype/spec/math#mathvariants-table).
864#[derive(Clone, Copy, Debug)]
865pub struct Variants<'a> {
866    /// Minimum overlap of connecting glyphs during glyph construction, in design units.
867    pub min_connector_overlap: u16,
868    /// Constructions for shapes growing in the vertical direction.
869    pub vertical_constructions: GlyphConstructions<'a>,
870    /// Constructions for shapes growing in the horizontal direction.
871    pub horizontal_constructions: GlyphConstructions<'a>,
872}
873
874impl<'a> FromSlice<'a> for Variants<'a> {
875    fn parse(data: &'a [u8]) -> Option<Self> {
876        let mut s = Stream::new(data);
877        let min_connector_overlap = s.read::<u16>()?;
878        let vertical_coverage = s.parse_at_offset16::<Coverage>(data);
879        let horizontal_coverage = s.parse_at_offset16::<Coverage>(data);
880        let vertical_count = s.read::<u16>()?;
881        let horizontal_count = s.read::<u16>()?;
882        let vertical_offsets = s.read_array16::<Option<Offset16>>(vertical_count)?;
883        let horizontal_offsets = s.read_array16::<Option<Offset16>>(horizontal_count)?;
884        Some(Variants {
885            min_connector_overlap,
886            vertical_constructions: GlyphConstructions::new(
887                data,
888                vertical_coverage,
889                vertical_offsets,
890            ),
891            horizontal_constructions: GlyphConstructions::new(
892                data,
893                horizontal_coverage,
894                horizontal_offsets,
895            ),
896        })
897    }
898}
899
900/// A [Math Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math).
901#[derive(Clone, Copy, Debug)]
902pub struct Table<'a> {
903    /// Math positioning constants.
904    pub constants: Option<Constants<'a>>,
905    /// Per-glyph positioning information.
906    pub glyph_info: Option<GlyphInfo<'a>>,
907    /// Variants and assembly recipes for growable glyphs.
908    pub variants: Option<Variants<'a>>,
909}
910
911impl<'a> Table<'a> {
912    /// Parses a table from raw data.
913    pub fn parse(data: &'a [u8]) -> Option<Self> {
914        let mut s = Stream::new(data);
915        let major_version = s.read::<u16>()? as u8;
916        s.skip::<u16>(); // minor version
917        if major_version != 1 {
918            return None;
919        }
920
921        Some(Table {
922            constants: s.parse_at_offset16::<Constants>(data),
923            glyph_info: s.parse_at_offset16::<GlyphInfo>(data),
924            variants: s.parse_at_offset16::<Variants>(data),
925        })
926    }
927}
928
929trait StreamExt<'a> {
930    fn parse_at_offset16<T: FromSlice<'a>>(&mut self, data: &'a [u8]) -> Option<T>;
931}
932
933impl<'a> StreamExt<'a> for Stream<'a> {
934    fn parse_at_offset16<T: FromSlice<'a>>(&mut self, data: &'a [u8]) -> Option<T> {
935        let offset = self.read::<Option<Offset16>>()??.to_usize();
936        data.get(offset..).and_then(T::parse)
937    }
938}