1use crate::Engine;
28use crate::codes::UNDEFINED_MATH_PARAM;
29use crate::eqtb::{Loc, Val};
30use crate::primitives_gen::assign_int as ip;
31
32#[allow(missing_docs)]
34pub mod mp {
35 pub const QUAD: u32 = 0;
36 pub const AXIS: u32 = 1;
37 pub const OPERATOR_SIZE: u32 = 2;
38 pub const OVERBAR_KERN: u32 = 3;
39 pub const OVERBAR_RULE: u32 = 4;
40 pub const OVERBAR_VGAP: u32 = 5;
41 pub const UNDERBAR_KERN: u32 = 6;
42 pub const UNDERBAR_RULE: u32 = 7;
43 pub const UNDERBAR_VGAP: u32 = 8;
44 pub const RADICAL_KERN: u32 = 9;
45 pub const RADICAL_RULE: u32 = 10;
46 pub const RADICAL_VGAP: u32 = 11;
47 pub const RADICAL_DEGREE_BEFORE: u32 = 12;
48 pub const RADICAL_DEGREE_AFTER: u32 = 13;
49 pub const RADICAL_DEGREE_RAISE: u32 = 14;
50 pub const STACK_VGAP: u32 = 15;
51 pub const STACK_NUM_UP: u32 = 16;
52 pub const STACK_DENOM_DOWN: u32 = 17;
53 pub const FRACTION_RULE: u32 = 18;
54 pub const FRACTION_NUM_VGAP: u32 = 19;
55 pub const FRACTION_NUM_UP: u32 = 20;
56 pub const FRACTION_DENOM_VGAP: u32 = 21;
57 pub const FRACTION_DENOM_DOWN: u32 = 22;
58 pub const FRACTION_DEL_SIZE: u32 = 23;
59 pub const SKEWED_FRACTION_HGAP: u32 = 24;
60 pub const SKEWED_FRACTION_VGAP: u32 = 25;
61 pub const LIMIT_ABOVE_VGAP: u32 = 26;
62 pub const LIMIT_ABOVE_BGAP: u32 = 27;
63 pub const LIMIT_ABOVE_KERN: u32 = 28;
64 pub const LIMIT_BELOW_VGAP: u32 = 29;
65 pub const LIMIT_BELOW_BGAP: u32 = 30;
66 pub const LIMIT_BELOW_KERN: u32 = 31;
67 pub const NOLIMIT_SUB_FACTOR: u32 = 32;
68 pub const NOLIMIT_SUP_FACTOR: u32 = 33;
69 pub const UNDER_DELIMITER_VGAP: u32 = 34;
70 pub const UNDER_DELIMITER_BGAP: u32 = 35;
71 pub const OVER_DELIMITER_VGAP: u32 = 36;
72 pub const OVER_DELIMITER_BGAP: u32 = 37;
73 pub const SUB_SHIFT_DROP: u32 = 38;
74 pub const SUP_SHIFT_DROP: u32 = 39;
75 pub const SUB_SHIFT_DOWN: u32 = 40;
76 pub const SUB_SUP_SHIFT_DOWN: u32 = 41;
77 pub const SUB_TOP_MAX: u32 = 42;
78 pub const SUP_SHIFT_UP: u32 = 43;
79 pub const SUP_BOTTOM_MIN: u32 = 44;
80 pub const SUP_SUB_BOTTOM_MAX: u32 = 45;
81 pub const SUB_SUP_VGAP: u32 = 46;
82 pub const SPACE_AFTER_SCRIPT: u32 = 47;
83 pub const CONNECTOR_OVERLAP_MIN: u32 = 48;
84}
85
86fn size_styles(size: u32) -> &'static [u32] {
88 match size {
89 0 => &[0, 1, 2, 3],
90 1 => &[4, 5],
91 _ => &[6, 7],
92 }
93}
94
95impl Engine {
96 pub fn define_math_param(&mut self, global: bool, p: u32, s: u32, v: i32) {
100 let ta = self.eqtb.int(ip::TRACINGASSIGNS);
101 let quiet = ta > 0 && ta < 2;
102 if quiet {
103 self.eqtb.int_par[ip::TRACINGASSIGNS as usize].val = 0;
104 }
105 self.define(global, Loc::MathParam(p * 8 + s), Val::Int(i64::from(v)));
106 if quiet {
107 self.eqtb.int_par[ip::TRACINGASSIGNS as usize].val = ta;
108 }
109 }
110
111 pub fn set_font_math_params(&mut self, global: bool, size: u32, fam: u32, f: u32) {
114 if self.set_opentype_math_params(global, size, f) {
115 return;
116 }
117 let params = self.font(f).params.clone();
118 let par = |n: usize| params.get(n).copied().unwrap_or(0);
119 let np = params.len().saturating_sub(1);
120 let styles = size_styles(size);
121 if fam == 2 && np >= 22 {
122 let xh = par(5);
123 let quad = par(6);
124 let deg = |n: i32| retex_arith::xn_over_d(quad, n, 18).map_or(0, |r| r.quotient);
125 for &s in styles {
126 let display = s < 2;
127 let cramped = s % 2 == 1;
128 let set = |e: &mut Engine, p: u32, v: i32| e.define_math_param(global, p, s, v);
129 set(self, mp::QUAD, quad);
130 set(self, mp::AXIS, par(22));
131 set(
132 self,
133 mp::FRACTION_DEL_SIZE,
134 if display { par(20) } else { par(21) },
135 );
136 set(
137 self,
138 mp::FRACTION_DENOM_DOWN,
139 if display { par(11) } else { par(12) },
140 );
141 set(
142 self,
143 mp::FRACTION_NUM_UP,
144 if display { par(8) } else { par(9) },
145 );
146 set(
147 self,
148 mp::STACK_NUM_UP,
149 if display { par(8) } else { par(10) },
150 );
151 set(
152 self,
153 mp::STACK_DENOM_DOWN,
154 if display { par(11) } else { par(12) },
155 );
156 set(self, mp::SKEWED_FRACTION_HGAP, 0);
157 set(self, mp::SKEWED_FRACTION_VGAP, 0);
158 set(self, mp::SUB_SHIFT_DOWN, par(16));
159 set(self, mp::SUB_SUP_SHIFT_DOWN, par(17));
160 set(self, mp::SUB_TOP_MAX, (xh * 4).abs() / 5);
161 set(self, mp::SUP_BOTTOM_MIN, (xh / 4).abs());
162 set(self, mp::SUP_SUB_BOTTOM_MAX, (xh * 4).abs() / 5);
163 let sup = if cramped {
164 par(15)
165 } else if display {
166 par(13)
167 } else {
168 par(14)
169 };
170 set(self, mp::SUP_SHIFT_UP, sup);
171 set(self, mp::RADICAL_DEGREE_BEFORE, deg(5));
172 set(self, mp::RADICAL_DEGREE_AFTER, -deg(10));
173 set(self, mp::RADICAL_DEGREE_RAISE, 60);
174 }
175 let drop_styles: &[u32] = match size {
177 1 => &[0, 1, 2, 3],
178 2 => &[4, 5, 6, 7],
179 _ => &[],
180 };
181 for &s in drop_styles {
182 self.define_math_param(global, mp::SUB_SHIFT_DROP, s, par(19));
183 self.define_math_param(global, mp::SUP_SHIFT_DROP, s, par(18));
184 }
185 } else if fam == 3 && np >= 13 {
186 let drt = par(8);
187 let f2 = self.fam_fnt(2, size);
188 let xh2 = self.font(f2).params.get(5).copied().unwrap_or(0);
189 for &s in styles {
190 let display = s < 2;
191 let set = |e: &mut Engine, p: u32, v: i32| e.define_math_param(global, p, s, v);
192 set(self, mp::OVERBAR_KERN, drt);
193 set(self, mp::OVERBAR_RULE, drt);
194 set(self, mp::OVERBAR_VGAP, 3 * drt);
195 set(self, mp::UNDERBAR_KERN, drt);
196 set(self, mp::UNDERBAR_RULE, drt);
197 set(self, mp::UNDERBAR_VGAP, 3 * drt);
198 set(self, mp::RADICAL_KERN, drt);
199 set(
200 self,
201 mp::RADICAL_VGAP,
202 if display {
203 drt + xh2.abs() / 4
204 } else {
205 drt + drt.abs() / 4
206 },
207 );
208 set(
209 self,
210 mp::STACK_VGAP,
211 if display { 7 * drt } else { 3 * drt },
212 );
213 set(self, mp::FRACTION_RULE, drt);
214 set(
215 self,
216 mp::FRACTION_NUM_VGAP,
217 if display { 3 * drt } else { drt },
218 );
219 set(
220 self,
221 mp::FRACTION_DENOM_VGAP,
222 if display { 3 * drt } else { drt },
223 );
224 set(self, mp::LIMIT_ABOVE_VGAP, par(9));
225 set(self, mp::LIMIT_ABOVE_BGAP, par(11));
226 set(self, mp::LIMIT_ABOVE_KERN, par(13));
227 set(self, mp::LIMIT_BELOW_VGAP, par(10));
228 set(self, mp::LIMIT_BELOW_BGAP, par(12));
229 set(self, mp::LIMIT_BELOW_KERN, par(13));
230 set(self, mp::UNDER_DELIMITER_VGAP, par(10));
231 set(self, mp::UNDER_DELIMITER_BGAP, par(12));
232 set(self, mp::OVER_DELIMITER_VGAP, par(9));
233 set(self, mp::OVER_DELIMITER_BGAP, par(11));
234 set(self, mp::SUB_SUP_VGAP, 4 * drt);
235 set(self, mp::CONNECTOR_OVERLAP_MIN, 0);
236 }
237 }
238 }
239
240 pub fn set_opentype_math_params(&mut self, global: bool, size: u32, f: u32) -> bool {
243 let Some(mc) = self.font(f).math_constants.clone() else {
244 return false;
245 };
246 let font_size = self.font(f).size;
247 const MAP: &[(u32, &str, &str)] = &[
251 (mp::AXIS, "AxisHeight", "AxisHeight"),
252 (mp::OPERATOR_SIZE, "DisplayOperatorMinHeight", ""),
253 (
254 mp::FRACTION_DEL_SIZE,
255 "FractionDelimiterDisplayStyleSize",
256 "FractionDelimiterSize",
257 ),
258 (
259 mp::FRACTION_DENOM_DOWN,
260 "FractionDenominatorDisplayStyleShiftDown",
261 "FractionDenominatorShiftDown",
262 ),
263 (
264 mp::FRACTION_DENOM_VGAP,
265 "FractionDenominatorDisplayStyleGapMin",
266 "FractionDenominatorGapMin",
267 ),
268 (
269 mp::FRACTION_NUM_UP,
270 "FractionNumeratorDisplayStyleShiftUp",
271 "FractionNumeratorShiftUp",
272 ),
273 (
274 mp::FRACTION_NUM_VGAP,
275 "FractionNumeratorDisplayStyleGapMin",
276 "FractionNumeratorGapMin",
277 ),
278 (
279 mp::FRACTION_RULE,
280 "FractionRuleThickness",
281 "FractionRuleThickness",
282 ),
283 (
284 mp::SKEWED_FRACTION_HGAP,
285 "SkewedFractionHorizontalGap",
286 "SkewedFractionHorizontalGap",
287 ),
288 (
289 mp::SKEWED_FRACTION_VGAP,
290 "SkewedFractionVerticalGap",
291 "SkewedFractionVerticalGap",
292 ),
293 (
294 mp::LIMIT_ABOVE_BGAP,
295 "UpperLimitBaselineRiseMin",
296 "UpperLimitBaselineRiseMin",
297 ),
298 (mp::LIMIT_ABOVE_VGAP, "UpperLimitGapMin", "UpperLimitGapMin"),
299 (
300 mp::LIMIT_BELOW_BGAP,
301 "LowerLimitBaselineDropMin",
302 "LowerLimitBaselineDropMin",
303 ),
304 (mp::LIMIT_BELOW_VGAP, "LowerLimitGapMin", "LowerLimitGapMin"),
305 (
306 mp::OVER_DELIMITER_VGAP,
307 "StretchStackGapBelowMin",
308 "StretchStackGapBelowMin",
309 ),
310 (
311 mp::OVER_DELIMITER_BGAP,
312 "StretchStackTopShiftUp",
313 "StretchStackTopShiftUp",
314 ),
315 (
316 mp::UNDER_DELIMITER_VGAP,
317 "StretchStackGapAboveMin",
318 "StretchStackGapAboveMin",
319 ),
320 (
321 mp::UNDER_DELIMITER_BGAP,
322 "StretchStackBottomShiftDown",
323 "StretchStackBottomShiftDown",
324 ),
325 (
326 mp::OVERBAR_KERN,
327 "OverbarExtraAscender",
328 "OverbarExtraAscender",
329 ),
330 (
331 mp::OVERBAR_RULE,
332 "OverbarRuleThickness",
333 "OverbarRuleThickness",
334 ),
335 (mp::OVERBAR_VGAP, "OverbarVerticalGap", "OverbarVerticalGap"),
336 (
337 mp::RADICAL_KERN,
338 "RadicalExtraAscender",
339 "RadicalExtraAscender",
340 ),
341 (
342 mp::RADICAL_RULE,
343 "RadicalRuleThickness",
344 "RadicalRuleThickness",
345 ),
346 (
347 mp::RADICAL_VGAP,
348 "RadicalDisplayStyleVerticalGap",
349 "RadicalVerticalGap",
350 ),
351 (
352 mp::RADICAL_DEGREE_BEFORE,
353 "RadicalKernBeforeDegree",
354 "RadicalKernBeforeDegree",
355 ),
356 (
357 mp::RADICAL_DEGREE_AFTER,
358 "RadicalKernAfterDegree",
359 "RadicalKernAfterDegree",
360 ),
361 (
362 mp::RADICAL_DEGREE_RAISE,
363 "RadicalDegreeBottomRaisePercent",
364 "RadicalDegreeBottomRaisePercent",
365 ),
366 (
367 mp::SPACE_AFTER_SCRIPT,
368 "SpaceAfterScript",
369 "SpaceAfterScript",
370 ),
371 (
372 mp::STACK_DENOM_DOWN,
373 "StackBottomDisplayStyleShiftDown",
374 "StackBottomShiftDown",
375 ),
376 (
377 mp::STACK_NUM_UP,
378 "StackTopDisplayStyleShiftUp",
379 "StackTopShiftUp",
380 ),
381 (mp::STACK_VGAP, "StackDisplayStyleGapMin", "StackGapMin"),
382 (
383 mp::SUB_SHIFT_DOWN,
384 "SubscriptShiftDown",
385 "SubscriptShiftDown",
386 ),
387 (
388 mp::SUB_SHIFT_DROP,
389 "SubscriptBaselineDropMin",
390 "SubscriptBaselineDropMin",
391 ),
392 (
393 mp::SUB_SUP_SHIFT_DOWN,
394 "SubscriptShiftDownWithSuperscript",
395 "SubscriptShiftDownWithSuperscript",
396 ),
397 (mp::SUB_TOP_MAX, "SubscriptTopMax", "SubscriptTopMax"),
398 (
399 mp::SUB_SUP_VGAP,
400 "SubSuperscriptGapMin",
401 "SubSuperscriptGapMin",
402 ),
403 (
404 mp::SUP_BOTTOM_MIN,
405 "SuperscriptBottomMin",
406 "SuperscriptBottomMin",
407 ),
408 (
409 mp::SUP_SHIFT_DROP,
410 "SuperscriptBaselineDropMax",
411 "SuperscriptBaselineDropMax",
412 ),
413 (
414 mp::SUP_SUB_BOTTOM_MAX,
415 "SuperscriptBottomMaxWithSubscript",
416 "SuperscriptBottomMaxWithSubscript",
417 ),
418 (
419 mp::UNDERBAR_KERN,
420 "UnderbarExtraDescender",
421 "UnderbarExtraDescender",
422 ),
423 (
424 mp::UNDERBAR_RULE,
425 "UnderbarRuleThickness",
426 "UnderbarRuleThickness",
427 ),
428 (
429 mp::UNDERBAR_VGAP,
430 "UnderbarVerticalGap",
431 "UnderbarVerticalGap",
432 ),
433 (
434 mp::CONNECTOR_OVERLAP_MIN,
435 "MinConnectorOverlap",
436 "MinConnectorOverlap",
437 ),
438 ];
439 for &s in size_styles(size) {
440 let display = s < 2;
441 let cramped = s % 2 == 1;
442 for &(p, d, o) in MAP {
443 let key = if display { d } else { o };
444 if let Some(&v) = mc.get(key) {
445 self.define_math_param(global, p, s, v);
446 }
447 }
448 let sup = if cramped {
449 "SuperscriptShiftUpCramped"
450 } else {
451 "SuperscriptShiftUp"
452 };
453 if let Some(&v) = mc.get(sup) {
454 self.define_math_param(global, mp::SUP_SHIFT_UP, s, v);
455 }
456 if !mc.contains_key("SubscriptShiftDownWithSuperscript")
459 && let Some(&v) = mc.get("SubscriptShiftDown")
460 {
461 self.define_math_param(global, mp::SUB_SUP_SHIFT_DOWN, s, v);
462 }
463 self.define_math_param(global, mp::QUAD, s, font_size);
465 self.define_math_param(global, mp::LIMIT_ABOVE_KERN, s, 0);
466 self.define_math_param(global, mp::LIMIT_BELOW_KERN, s, 0);
467 }
468 true
469 }
470
471 pub fn init_math_params_once(&mut self) {
474 if self.math_params_initialized {
475 return;
476 }
477 self.math_params_initialized = true;
478 let ss = self
479 .eqtb
480 .dimen(crate::primitives_gen::assign_dimen::SCRIPTSPACE);
481 for s in 0..8 {
482 if self.math_param_value(mp::SPACE_AFTER_SCRIPT, s) == UNDEFINED_MATH_PARAM {
483 let loc = Loc::MathParam(mp::SPACE_AFTER_SCRIPT * 8 + s);
484 self.eqtb
485 .set(loc, Val::Int(i64::from(ss)), crate::eqtb::LEVEL_ONE);
486 }
487 }
488 }
489}