use crate::dim::Dim;
use crate::error::Error;
use crate::font::MathFont;
use crate::layout::style::MathStyle;
#[derive(Clone, Debug)]
pub struct MathParams {
pub x_height: Dim,
pub quad: Dim,
pub axis_height: Dim,
pub accent_base_height: Dim,
pub flattened_accent_base_height: Dim,
pub fraction_rule_thickness: Dim,
pub fraction_numerator_shift_up: Dim,
pub fraction_numerator_display_style_shift_up: Dim,
pub fraction_denominator_shift_down: Dim,
pub fraction_denominator_display_style_shift_down: Dim,
pub fraction_numerator_gap_min: Dim,
pub fraction_num_display_style_gap_min: Dim,
pub fraction_denominator_gap_min: Dim,
pub fraction_denom_display_style_gap_min: Dim,
pub superscript_shift_up: Dim,
pub superscript_shift_up_cramped: Dim,
pub subscript_shift_down: Dim,
pub sub_superscript_gap_min: Dim,
pub space_after_script: Dim,
pub radical_vertical_gap: Dim,
pub radical_display_style_vertical_gap: Dim,
pub radical_rule_thickness: Dim,
pub radical_extra_ascender: Dim,
pub radical_kern_before_degree: Dim,
pub radical_kern_after_degree: Dim,
pub radical_degree_bottom_raise_percent: i16,
pub overbar_vertical_gap: Dim,
pub overbar_rule_thickness: Dim,
pub overbar_extra_ascender: Dim,
pub underbar_vertical_gap: Dim,
pub underbar_rule_thickness: Dim,
pub underbar_extra_descender: Dim,
pub upper_limit_gap_min: Dim,
pub upper_limit_baseline_rise_min: Dim,
pub lower_limit_gap_min: Dim,
pub lower_limit_baseline_drop_min: Dim,
pub display_operator_min_height: Dim,
pub script_percent_scale_down: i16,
pub script_script_percent_scale_down: i16,
pub units_per_em: u16,
}
impl MathParams {
pub fn from_font(font: &MathFont) -> Result<Self, Error> {
let face = font.face();
let math = face.tables().math.ok_or_else(|| Error::Unsupported {
what: "OpenType MATH table".into(),
})?;
let c = math.constants.ok_or_else(|| Error::Unsupported {
what: "MATH constants".into(),
})?;
let upem = font.units_per_em();
let fu = |v: i16| Dim::from_font_units(i64::from(v), upem);
let fu_u = |v: u16| Dim::from_font_units(i64::from(v), upem);
let xh = face.x_height().map(fu).unwrap_or_else(|| Dim::ratio(1, 2));
Ok(Self {
x_height: xh,
quad: Dim::one(),
axis_height: fu(c.axis_height().value),
accent_base_height: fu(c.accent_base_height().value),
flattened_accent_base_height: fu(c.flattened_accent_base_height().value),
fraction_rule_thickness: fu(c.fraction_rule_thickness().value),
fraction_numerator_shift_up: fu(c.fraction_numerator_shift_up().value),
fraction_numerator_display_style_shift_up: fu(c
.fraction_numerator_display_style_shift_up()
.value),
fraction_denominator_shift_down: fu(c.fraction_denominator_shift_down().value),
fraction_denominator_display_style_shift_down: fu(c
.fraction_denominator_display_style_shift_down()
.value),
fraction_numerator_gap_min: fu(c.fraction_numerator_gap_min().value),
fraction_num_display_style_gap_min: fu(c.fraction_num_display_style_gap_min().value),
fraction_denominator_gap_min: fu(c.fraction_denominator_gap_min().value),
fraction_denom_display_style_gap_min: fu(c
.fraction_denom_display_style_gap_min()
.value),
superscript_shift_up: fu(c.superscript_shift_up().value),
superscript_shift_up_cramped: fu(c.superscript_shift_up_cramped().value),
subscript_shift_down: fu(c.subscript_shift_down().value),
sub_superscript_gap_min: fu(c.sub_superscript_gap_min().value),
space_after_script: fu(c.space_after_script().value),
radical_vertical_gap: fu(c.radical_vertical_gap().value),
radical_display_style_vertical_gap: fu(c.radical_display_style_vertical_gap().value),
radical_rule_thickness: fu(c.radical_rule_thickness().value),
radical_extra_ascender: fu(c.radical_extra_ascender().value),
radical_kern_before_degree: fu(c.radical_kern_before_degree().value),
radical_kern_after_degree: fu(c.radical_kern_after_degree().value),
radical_degree_bottom_raise_percent: c.radical_degree_bottom_raise_percent(),
overbar_vertical_gap: fu(c.overbar_vertical_gap().value),
overbar_rule_thickness: fu(c.overbar_rule_thickness().value),
overbar_extra_ascender: fu(c.overbar_extra_ascender().value),
underbar_vertical_gap: fu(c.underbar_vertical_gap().value),
underbar_rule_thickness: fu(c.underbar_rule_thickness().value),
underbar_extra_descender: fu(c.underbar_extra_descender().value),
upper_limit_gap_min: fu(c.upper_limit_gap_min().value),
upper_limit_baseline_rise_min: fu(c.upper_limit_baseline_rise_min().value),
lower_limit_gap_min: fu(c.lower_limit_gap_min().value),
lower_limit_baseline_drop_min: fu(c.lower_limit_baseline_drop_min().value),
display_operator_min_height: fu_u(c.display_operator_min_height()),
script_percent_scale_down: c.script_percent_scale_down(),
script_script_percent_scale_down: c.script_script_percent_scale_down(),
units_per_em: upem,
})
}
#[must_use]
pub fn scale(&self, style: MathStyle) -> Dim {
match style.script_level() {
0 => Dim::one(),
1 => Dim::from_i64(i64::from(self.script_percent_scale_down)) / Dim::from_i64(100),
_ => {
Dim::from_i64(i64::from(self.script_script_percent_scale_down)) / Dim::from_i64(100)
}
}
}
#[must_use]
pub fn em(&self, style: MathStyle) -> Dim {
&self.quad * &self.scale(style)
}
#[must_use]
pub fn mu(&self, style: MathStyle) -> Dim {
self.em(style) / Dim::from_i64(18)
}
}