1use crate::dim::Dim;
4use crate::error::Error;
5use crate::font::MathFont;
6use crate::layout::style::MathStyle;
7
8#[derive(Clone, Debug)]
21pub struct MathParams {
22 pub x_height: Dim,
24 pub quad: Dim,
26 pub axis_height: Dim,
28 pub accent_base_height: Dim,
30 pub flattened_accent_base_height: Dim,
32 pub fraction_rule_thickness: Dim,
34 pub fraction_numerator_shift_up: Dim,
36 pub fraction_numerator_display_style_shift_up: Dim,
38 pub fraction_denominator_shift_down: Dim,
40 pub fraction_denominator_display_style_shift_down: Dim,
42 pub fraction_numerator_gap_min: Dim,
44 pub fraction_num_display_style_gap_min: Dim,
46 pub fraction_denominator_gap_min: Dim,
48 pub fraction_denom_display_style_gap_min: Dim,
50 pub superscript_shift_up: Dim,
52 pub superscript_shift_up_cramped: Dim,
54 pub subscript_shift_down: Dim,
56 pub sub_superscript_gap_min: Dim,
58 pub space_after_script: Dim,
60 pub radical_vertical_gap: Dim,
62 pub radical_display_style_vertical_gap: Dim,
64 pub radical_rule_thickness: Dim,
66 pub radical_extra_ascender: Dim,
68 pub radical_kern_before_degree: Dim,
70 pub radical_kern_after_degree: Dim,
72 pub radical_degree_bottom_raise_percent: i16,
74 pub overbar_vertical_gap: Dim,
76 pub overbar_rule_thickness: Dim,
78 pub overbar_extra_ascender: Dim,
80 pub underbar_vertical_gap: Dim,
82 pub underbar_rule_thickness: Dim,
84 pub underbar_extra_descender: Dim,
86 pub upper_limit_gap_min: Dim,
88 pub upper_limit_baseline_rise_min: Dim,
90 pub lower_limit_gap_min: Dim,
92 pub lower_limit_baseline_drop_min: Dim,
94 pub display_operator_min_height: Dim,
96 pub script_percent_scale_down: i16,
98 pub script_script_percent_scale_down: i16,
100 pub units_per_em: u16,
102}
103
104impl MathParams {
105 pub fn from_font(font: &MathFont) -> Result<Self, Error> {
111 let face = font.face();
112 let math = face.tables().math.ok_or_else(|| Error::Unsupported {
113 what: "OpenType MATH table".into(),
114 })?;
115 let c = math.constants.ok_or_else(|| Error::Unsupported {
116 what: "MATH constants".into(),
117 })?;
118 let upem = font.units_per_em();
119 let fu = |v: i16| Dim::from_font_units(i64::from(v), upem);
120 let fu_u = |v: u16| Dim::from_font_units(i64::from(v), upem);
121 let xh = face.x_height().map(fu).unwrap_or_else(|| Dim::ratio(1, 2));
122 Ok(Self {
123 x_height: xh,
124 quad: Dim::one(),
125 axis_height: fu(c.axis_height().value),
126 accent_base_height: fu(c.accent_base_height().value),
127 flattened_accent_base_height: fu(c.flattened_accent_base_height().value),
128 fraction_rule_thickness: fu(c.fraction_rule_thickness().value),
129 fraction_numerator_shift_up: fu(c.fraction_numerator_shift_up().value),
130 fraction_numerator_display_style_shift_up: fu(c
131 .fraction_numerator_display_style_shift_up()
132 .value),
133 fraction_denominator_shift_down: fu(c.fraction_denominator_shift_down().value),
134 fraction_denominator_display_style_shift_down: fu(c
135 .fraction_denominator_display_style_shift_down()
136 .value),
137 fraction_numerator_gap_min: fu(c.fraction_numerator_gap_min().value),
138 fraction_num_display_style_gap_min: fu(c.fraction_num_display_style_gap_min().value),
139 fraction_denominator_gap_min: fu(c.fraction_denominator_gap_min().value),
140 fraction_denom_display_style_gap_min: fu(c
141 .fraction_denom_display_style_gap_min()
142 .value),
143 superscript_shift_up: fu(c.superscript_shift_up().value),
144 superscript_shift_up_cramped: fu(c.superscript_shift_up_cramped().value),
145 subscript_shift_down: fu(c.subscript_shift_down().value),
146 sub_superscript_gap_min: fu(c.sub_superscript_gap_min().value),
147 space_after_script: fu(c.space_after_script().value),
148 radical_vertical_gap: fu(c.radical_vertical_gap().value),
149 radical_display_style_vertical_gap: fu(c.radical_display_style_vertical_gap().value),
150 radical_rule_thickness: fu(c.radical_rule_thickness().value),
151 radical_extra_ascender: fu(c.radical_extra_ascender().value),
152 radical_kern_before_degree: fu(c.radical_kern_before_degree().value),
153 radical_kern_after_degree: fu(c.radical_kern_after_degree().value),
154 radical_degree_bottom_raise_percent: c.radical_degree_bottom_raise_percent(),
155 overbar_vertical_gap: fu(c.overbar_vertical_gap().value),
156 overbar_rule_thickness: fu(c.overbar_rule_thickness().value),
157 overbar_extra_ascender: fu(c.overbar_extra_ascender().value),
158 underbar_vertical_gap: fu(c.underbar_vertical_gap().value),
159 underbar_rule_thickness: fu(c.underbar_rule_thickness().value),
160 underbar_extra_descender: fu(c.underbar_extra_descender().value),
161 upper_limit_gap_min: fu(c.upper_limit_gap_min().value),
162 upper_limit_baseline_rise_min: fu(c.upper_limit_baseline_rise_min().value),
163 lower_limit_gap_min: fu(c.lower_limit_gap_min().value),
164 lower_limit_baseline_drop_min: fu(c.lower_limit_baseline_drop_min().value),
165 display_operator_min_height: fu_u(c.display_operator_min_height()),
166 script_percent_scale_down: c.script_percent_scale_down(),
167 script_script_percent_scale_down: c.script_script_percent_scale_down(),
168 units_per_em: upem,
169 })
170 }
171
172 #[must_use]
174 pub fn scale(&self, style: MathStyle) -> Dim {
175 match style.script_level() {
176 0 => Dim::one(),
177 1 => Dim::from_i64(i64::from(self.script_percent_scale_down)) / Dim::from_i64(100),
178 _ => {
179 Dim::from_i64(i64::from(self.script_script_percent_scale_down)) / Dim::from_i64(100)
180 }
181 }
182 }
183
184 #[must_use]
186 pub fn em(&self, style: MathStyle) -> Dim {
187 &self.quad * &self.scale(style)
188 }
189
190 #[must_use]
192 pub fn mu(&self, style: MathStyle) -> Dim {
193 self.em(style) / Dim::from_i64(18)
194 }
195}