use crate::Engine;
use crate::codes::UNDEFINED_MATH_PARAM;
use crate::eqtb::{Loc, Val};
use crate::primitives_gen::assign_int as ip;
#[allow(missing_docs)]
pub mod mp {
pub const QUAD: u32 = 0;
pub const AXIS: u32 = 1;
pub const OPERATOR_SIZE: u32 = 2;
pub const OVERBAR_KERN: u32 = 3;
pub const OVERBAR_RULE: u32 = 4;
pub const OVERBAR_VGAP: u32 = 5;
pub const UNDERBAR_KERN: u32 = 6;
pub const UNDERBAR_RULE: u32 = 7;
pub const UNDERBAR_VGAP: u32 = 8;
pub const RADICAL_KERN: u32 = 9;
pub const RADICAL_RULE: u32 = 10;
pub const RADICAL_VGAP: u32 = 11;
pub const RADICAL_DEGREE_BEFORE: u32 = 12;
pub const RADICAL_DEGREE_AFTER: u32 = 13;
pub const RADICAL_DEGREE_RAISE: u32 = 14;
pub const STACK_VGAP: u32 = 15;
pub const STACK_NUM_UP: u32 = 16;
pub const STACK_DENOM_DOWN: u32 = 17;
pub const FRACTION_RULE: u32 = 18;
pub const FRACTION_NUM_VGAP: u32 = 19;
pub const FRACTION_NUM_UP: u32 = 20;
pub const FRACTION_DENOM_VGAP: u32 = 21;
pub const FRACTION_DENOM_DOWN: u32 = 22;
pub const FRACTION_DEL_SIZE: u32 = 23;
pub const SKEWED_FRACTION_HGAP: u32 = 24;
pub const SKEWED_FRACTION_VGAP: u32 = 25;
pub const LIMIT_ABOVE_VGAP: u32 = 26;
pub const LIMIT_ABOVE_BGAP: u32 = 27;
pub const LIMIT_ABOVE_KERN: u32 = 28;
pub const LIMIT_BELOW_VGAP: u32 = 29;
pub const LIMIT_BELOW_BGAP: u32 = 30;
pub const LIMIT_BELOW_KERN: u32 = 31;
pub const NOLIMIT_SUB_FACTOR: u32 = 32;
pub const NOLIMIT_SUP_FACTOR: u32 = 33;
pub const UNDER_DELIMITER_VGAP: u32 = 34;
pub const UNDER_DELIMITER_BGAP: u32 = 35;
pub const OVER_DELIMITER_VGAP: u32 = 36;
pub const OVER_DELIMITER_BGAP: u32 = 37;
pub const SUB_SHIFT_DROP: u32 = 38;
pub const SUP_SHIFT_DROP: u32 = 39;
pub const SUB_SHIFT_DOWN: u32 = 40;
pub const SUB_SUP_SHIFT_DOWN: u32 = 41;
pub const SUB_TOP_MAX: u32 = 42;
pub const SUP_SHIFT_UP: u32 = 43;
pub const SUP_BOTTOM_MIN: u32 = 44;
pub const SUP_SUB_BOTTOM_MAX: u32 = 45;
pub const SUB_SUP_VGAP: u32 = 46;
pub const SPACE_AFTER_SCRIPT: u32 = 47;
pub const CONNECTOR_OVERLAP_MIN: u32 = 48;
}
fn size_styles(size: u32) -> &'static [u32] {
match size {
0 => &[0, 1, 2, 3],
1 => &[4, 5],
_ => &[6, 7],
}
}
impl Engine {
pub fn define_math_param(&mut self, global: bool, p: u32, s: u32, v: i32) {
let ta = self.eqtb.int(ip::TRACINGASSIGNS);
let quiet = ta > 0 && ta < 2;
if quiet {
self.eqtb.int_par[ip::TRACINGASSIGNS as usize].val = 0;
}
self.define(global, Loc::MathParam(p * 8 + s), Val::Int(i64::from(v)));
if quiet {
self.eqtb.int_par[ip::TRACINGASSIGNS as usize].val = ta;
}
}
pub fn set_font_math_params(&mut self, global: bool, size: u32, fam: u32, f: u32) {
if self.set_opentype_math_params(global, size, f) {
return;
}
let params = self.font(f).params.clone();
let par = |n: usize| params.get(n).copied().unwrap_or(0);
let np = params.len().saturating_sub(1);
let styles = size_styles(size);
if fam == 2 && np >= 22 {
let xh = par(5);
let quad = par(6);
let deg = |n: i32| retex_arith::xn_over_d(quad, n, 18).map_or(0, |r| r.quotient);
for &s in styles {
let display = s < 2;
let cramped = s % 2 == 1;
let set = |e: &mut Engine, p: u32, v: i32| e.define_math_param(global, p, s, v);
set(self, mp::QUAD, quad);
set(self, mp::AXIS, par(22));
set(
self,
mp::FRACTION_DEL_SIZE,
if display { par(20) } else { par(21) },
);
set(
self,
mp::FRACTION_DENOM_DOWN,
if display { par(11) } else { par(12) },
);
set(
self,
mp::FRACTION_NUM_UP,
if display { par(8) } else { par(9) },
);
set(
self,
mp::STACK_NUM_UP,
if display { par(8) } else { par(10) },
);
set(
self,
mp::STACK_DENOM_DOWN,
if display { par(11) } else { par(12) },
);
set(self, mp::SKEWED_FRACTION_HGAP, 0);
set(self, mp::SKEWED_FRACTION_VGAP, 0);
set(self, mp::SUB_SHIFT_DOWN, par(16));
set(self, mp::SUB_SUP_SHIFT_DOWN, par(17));
set(self, mp::SUB_TOP_MAX, (xh * 4).abs() / 5);
set(self, mp::SUP_BOTTOM_MIN, (xh / 4).abs());
set(self, mp::SUP_SUB_BOTTOM_MAX, (xh * 4).abs() / 5);
let sup = if cramped {
par(15)
} else if display {
par(13)
} else {
par(14)
};
set(self, mp::SUP_SHIFT_UP, sup);
set(self, mp::RADICAL_DEGREE_BEFORE, deg(5));
set(self, mp::RADICAL_DEGREE_AFTER, -deg(10));
set(self, mp::RADICAL_DEGREE_RAISE, 60);
}
let drop_styles: &[u32] = match size {
1 => &[0, 1, 2, 3],
2 => &[4, 5, 6, 7],
_ => &[],
};
for &s in drop_styles {
self.define_math_param(global, mp::SUB_SHIFT_DROP, s, par(19));
self.define_math_param(global, mp::SUP_SHIFT_DROP, s, par(18));
}
} else if fam == 3 && np >= 13 {
let drt = par(8);
let f2 = self.fam_fnt(2, size);
let xh2 = self.font(f2).params.get(5).copied().unwrap_or(0);
for &s in styles {
let display = s < 2;
let set = |e: &mut Engine, p: u32, v: i32| e.define_math_param(global, p, s, v);
set(self, mp::OVERBAR_KERN, drt);
set(self, mp::OVERBAR_RULE, drt);
set(self, mp::OVERBAR_VGAP, 3 * drt);
set(self, mp::UNDERBAR_KERN, drt);
set(self, mp::UNDERBAR_RULE, drt);
set(self, mp::UNDERBAR_VGAP, 3 * drt);
set(self, mp::RADICAL_KERN, drt);
set(
self,
mp::RADICAL_VGAP,
if display {
drt + xh2.abs() / 4
} else {
drt + drt.abs() / 4
},
);
set(
self,
mp::STACK_VGAP,
if display { 7 * drt } else { 3 * drt },
);
set(self, mp::FRACTION_RULE, drt);
set(
self,
mp::FRACTION_NUM_VGAP,
if display { 3 * drt } else { drt },
);
set(
self,
mp::FRACTION_DENOM_VGAP,
if display { 3 * drt } else { drt },
);
set(self, mp::LIMIT_ABOVE_VGAP, par(9));
set(self, mp::LIMIT_ABOVE_BGAP, par(11));
set(self, mp::LIMIT_ABOVE_KERN, par(13));
set(self, mp::LIMIT_BELOW_VGAP, par(10));
set(self, mp::LIMIT_BELOW_BGAP, par(12));
set(self, mp::LIMIT_BELOW_KERN, par(13));
set(self, mp::UNDER_DELIMITER_VGAP, par(10));
set(self, mp::UNDER_DELIMITER_BGAP, par(12));
set(self, mp::OVER_DELIMITER_VGAP, par(9));
set(self, mp::OVER_DELIMITER_BGAP, par(11));
set(self, mp::SUB_SUP_VGAP, 4 * drt);
set(self, mp::CONNECTOR_OVERLAP_MIN, 0);
}
}
}
pub fn set_opentype_math_params(&mut self, global: bool, size: u32, f: u32) -> bool {
let Some(mc) = self.font(f).math_constants.clone() else {
return false;
};
let font_size = self.font(f).size;
const MAP: &[(u32, &str, &str)] = &[
(mp::AXIS, "AxisHeight", "AxisHeight"),
(mp::OPERATOR_SIZE, "DisplayOperatorMinHeight", ""),
(
mp::FRACTION_DEL_SIZE,
"FractionDelimiterDisplayStyleSize",
"FractionDelimiterSize",
),
(
mp::FRACTION_DENOM_DOWN,
"FractionDenominatorDisplayStyleShiftDown",
"FractionDenominatorShiftDown",
),
(
mp::FRACTION_DENOM_VGAP,
"FractionDenominatorDisplayStyleGapMin",
"FractionDenominatorGapMin",
),
(
mp::FRACTION_NUM_UP,
"FractionNumeratorDisplayStyleShiftUp",
"FractionNumeratorShiftUp",
),
(
mp::FRACTION_NUM_VGAP,
"FractionNumeratorDisplayStyleGapMin",
"FractionNumeratorGapMin",
),
(
mp::FRACTION_RULE,
"FractionRuleThickness",
"FractionRuleThickness",
),
(
mp::SKEWED_FRACTION_HGAP,
"SkewedFractionHorizontalGap",
"SkewedFractionHorizontalGap",
),
(
mp::SKEWED_FRACTION_VGAP,
"SkewedFractionVerticalGap",
"SkewedFractionVerticalGap",
),
(
mp::LIMIT_ABOVE_BGAP,
"UpperLimitBaselineRiseMin",
"UpperLimitBaselineRiseMin",
),
(mp::LIMIT_ABOVE_VGAP, "UpperLimitGapMin", "UpperLimitGapMin"),
(
mp::LIMIT_BELOW_BGAP,
"LowerLimitBaselineDropMin",
"LowerLimitBaselineDropMin",
),
(mp::LIMIT_BELOW_VGAP, "LowerLimitGapMin", "LowerLimitGapMin"),
(
mp::OVER_DELIMITER_VGAP,
"StretchStackGapBelowMin",
"StretchStackGapBelowMin",
),
(
mp::OVER_DELIMITER_BGAP,
"StretchStackTopShiftUp",
"StretchStackTopShiftUp",
),
(
mp::UNDER_DELIMITER_VGAP,
"StretchStackGapAboveMin",
"StretchStackGapAboveMin",
),
(
mp::UNDER_DELIMITER_BGAP,
"StretchStackBottomShiftDown",
"StretchStackBottomShiftDown",
),
(
mp::OVERBAR_KERN,
"OverbarExtraAscender",
"OverbarExtraAscender",
),
(
mp::OVERBAR_RULE,
"OverbarRuleThickness",
"OverbarRuleThickness",
),
(mp::OVERBAR_VGAP, "OverbarVerticalGap", "OverbarVerticalGap"),
(
mp::RADICAL_KERN,
"RadicalExtraAscender",
"RadicalExtraAscender",
),
(
mp::RADICAL_RULE,
"RadicalRuleThickness",
"RadicalRuleThickness",
),
(
mp::RADICAL_VGAP,
"RadicalDisplayStyleVerticalGap",
"RadicalVerticalGap",
),
(
mp::RADICAL_DEGREE_BEFORE,
"RadicalKernBeforeDegree",
"RadicalKernBeforeDegree",
),
(
mp::RADICAL_DEGREE_AFTER,
"RadicalKernAfterDegree",
"RadicalKernAfterDegree",
),
(
mp::RADICAL_DEGREE_RAISE,
"RadicalDegreeBottomRaisePercent",
"RadicalDegreeBottomRaisePercent",
),
(
mp::SPACE_AFTER_SCRIPT,
"SpaceAfterScript",
"SpaceAfterScript",
),
(
mp::STACK_DENOM_DOWN,
"StackBottomDisplayStyleShiftDown",
"StackBottomShiftDown",
),
(
mp::STACK_NUM_UP,
"StackTopDisplayStyleShiftUp",
"StackTopShiftUp",
),
(mp::STACK_VGAP, "StackDisplayStyleGapMin", "StackGapMin"),
(
mp::SUB_SHIFT_DOWN,
"SubscriptShiftDown",
"SubscriptShiftDown",
),
(
mp::SUB_SHIFT_DROP,
"SubscriptBaselineDropMin",
"SubscriptBaselineDropMin",
),
(
mp::SUB_SUP_SHIFT_DOWN,
"SubscriptShiftDownWithSuperscript",
"SubscriptShiftDownWithSuperscript",
),
(mp::SUB_TOP_MAX, "SubscriptTopMax", "SubscriptTopMax"),
(
mp::SUB_SUP_VGAP,
"SubSuperscriptGapMin",
"SubSuperscriptGapMin",
),
(
mp::SUP_BOTTOM_MIN,
"SuperscriptBottomMin",
"SuperscriptBottomMin",
),
(
mp::SUP_SHIFT_DROP,
"SuperscriptBaselineDropMax",
"SuperscriptBaselineDropMax",
),
(
mp::SUP_SUB_BOTTOM_MAX,
"SuperscriptBottomMaxWithSubscript",
"SuperscriptBottomMaxWithSubscript",
),
(
mp::UNDERBAR_KERN,
"UnderbarExtraDescender",
"UnderbarExtraDescender",
),
(
mp::UNDERBAR_RULE,
"UnderbarRuleThickness",
"UnderbarRuleThickness",
),
(
mp::UNDERBAR_VGAP,
"UnderbarVerticalGap",
"UnderbarVerticalGap",
),
(
mp::CONNECTOR_OVERLAP_MIN,
"MinConnectorOverlap",
"MinConnectorOverlap",
),
];
for &s in size_styles(size) {
let display = s < 2;
let cramped = s % 2 == 1;
for &(p, d, o) in MAP {
let key = if display { d } else { o };
if let Some(&v) = mc.get(key) {
self.define_math_param(global, p, s, v);
}
}
let sup = if cramped {
"SuperscriptShiftUpCramped"
} else {
"SuperscriptShiftUp"
};
if let Some(&v) = mc.get(sup) {
self.define_math_param(global, mp::SUP_SHIFT_UP, s, v);
}
if !mc.contains_key("SubscriptShiftDownWithSuperscript")
&& let Some(&v) = mc.get("SubscriptShiftDown")
{
self.define_math_param(global, mp::SUB_SUP_SHIFT_DOWN, s, v);
}
self.define_math_param(global, mp::QUAD, s, font_size);
self.define_math_param(global, mp::LIMIT_ABOVE_KERN, s, 0);
self.define_math_param(global, mp::LIMIT_BELOW_KERN, s, 0);
}
true
}
pub fn init_math_params_once(&mut self) {
if self.math_params_initialized {
return;
}
self.math_params_initialized = true;
let ss = self
.eqtb
.dimen(crate::primitives_gen::assign_dimen::SCRIPTSPACE);
for s in 0..8 {
if self.math_param_value(mp::SPACE_AFTER_SCRIPT, s) == UNDEFINED_MATH_PARAM {
let loc = Loc::MathParam(mp::SPACE_AFTER_SCRIPT * 8 + s);
self.eqtb
.set(loc, Val::Int(i64::from(ss)), crate::eqtb::LEVEL_ONE);
}
}
}
}