w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

mlist.c
Go to the documentation of this file.
1 /*
2 
3 Copyright 2006-2010 Taco Hoekwater <taco@luatex.org>
4 
5 This file is part of LuaTeX.
6 
7 LuaTeX is free software; you can redistribute it and/or modify it under the terms
8 of the GNU General Public License as published by the Free Software Foundation;
9 either version 2 of the License, or (at your option) any later version.
10 
11 LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along with
16 LuaTeX; if not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 /*tex
21 
22  In traditional \TeX\ the italic correction is added to the width of the
23  glyph. This is part of the engine design and related font design. In opentype
24  math this is different. There the italic correction had more explicit usage.
25  The 1.7 spec says:
26 
27  \startitemize
28 
29  \startitem
30  {\em italic correction:} When a run of slanted characters is followed by
31  a straight character (such as an operator or a delimiter), the italics
32  correction of the last glyph is added to its advance width.
33 
34  When positioning limits on an N-ary operator (e.g., integral sign), the
35  horizontal position of the upper limit is moved to the right by ½ of the
36  italics correction, while the position of the lower limit is moved to the
37  left by the same distance.
38 
39  When positioning superscripts and subscripts, their default horizontal
40  positions are also different by the amount of the italics correction of
41  the preceding glyph.
42  \stopitem
43 
44  \startitem
45  {\em math kerning:} Set the default horizontal position for the
46  superscript as shifted relative to the position of the subscript by the
47  italics correction of the base glyph.
48  \stopitem
49 
50  \stopitemize
51 
52  Before this was specified we had to gamble a bit and assume that cambria was
53  the font benchmark and trust our eyes (and msword) for the logic. I must
54  admit that I have been fighting these italics in fonts (and the heuristics
55  that Lua\TeX\ provided) right from the start (e.g. using Lua based
56  postprocessing) but by now we know more and have more fonts to test with.
57  More fonts are handy because not all fonts are alike when it comes to
58  italics. Axis are another area of concern, as it looks like opentype math
59  fonts often already apply that shift.
60 
61 */
62 
63 #define is_new_mathfont(A) ((font_math_params(A) >0) && (math_old_par == 0))
64 #define is_old_mathfont(A,B) ((font_math_params(A)==0) && (font_params(A)>=(B)))
65 #define do_new_math(A) ((font_math_params(A) >0) && (font_oldmath(A) == 0) && (math_old_par == 0))
66 #define protect_glyph(A) subtype(A)=256
67 
68 #include "ptexlib.h"
69 #include "lua/luatex-api.h"
70 
71 #define reset_attributes(p,newatt) do { \
72  delete_attribute_ref(node_attr(p)); \
73  node_attr(p) = newatt; \
74  if (newatt!=null) { \
75  add_node_attr_ref(node_attr(p)); \
76  } \
77  } while (0)
78 
79 #define DEFINE_MATH_PARAMETERS(A,B,C,D) do { \
80  if (B==text_size) { \
81  def_math_param(A, text_style, (C),D); \
82  def_math_param(A, cramped_text_style, (C),D); \
83  } else if (B==script_size) { \
84  def_math_param(A, script_style, (C),D); \
85  def_math_param(A, cramped_script_style, (C),D); \
86  } else if (B==script_script_size) { \
87  def_math_param(A, script_script_style, (C),D); \
88  def_math_param(A, cramped_script_script_style, (C),D); \
89  } \
90  } while (0)
91 
92 #define DEFINE_DMATH_PARAMETERS(A,B,C,D) do { \
93  if (B==text_size) { \
94  def_math_param(A, display_style,(C),D); \
95  def_math_param(A, cramped_display_style,(C),D); \
96  } \
97  } while (0)
98 
99 #define font_MATH_par(a,b) \
100  (font_math_params(a)>=b ? font_math_param(a,b) : undefined_math_parameter)
101 
102 /*tex
103 
104  Here are the math parameters that are font-dependant.
105 
106  Before an mlist is converted to an hlist, \TeX\ makes sure that the fonts in
107  family~2 have enough parameters to be math-symbol fonts, and that the fonts
108  in family~3 have enough parameters to be math-extension fonts. The
109  math-symbol parameters are referred to by using the following macros, which
110  take a size code as their parameter; for example, |num1(cur_size)| gives the
111  value of the |num1| parameter for the current size.
112 
113 */
114 
115 #define total_mathsy_params 22
116 #define total_mathex_params 13
117 
118 #define mathsy(A,B) font_param(fam_fnt(2,A),B)
119 
120 /*tex height of `\.x' */
121 
122 #define math_x_height(A) mathsy(A,5)
123 
124 /*tex \.{18mu} */
125 
126 #define math_quad(A) mathsy(A,6)
127 
128 /*tex numerator shift-up in display styles */
129 
130 #define num1(A) mathsy(A,8)
131 
132 /*tex numerator shift-up in non-display, non-\.{\\atop} */
133 
134 #define num2(A) mathsy(A,9)
135 
136 /*tex numerator shift-up in non-display \.{\\atop} */
137 
138 #define num3(A) mathsy(A,10)
139 
140 /*tex denominator shift-down in display styles */
141 
142 #define denom1(A) mathsy(A,11)
143 
144 /*tex denominator shift-down in non-display styles */
145 
146 #define denom2(A) mathsy(A,12)
147 
148 /*tex superscript shift-up in uncramped display style */
149 
150 #define sup1(A) mathsy(A,13)
151 
152 /*tex superscript shift-up in uncramped non-display */
153 
154 #define sup2(A) mathsy(A,14)
155 
156 /*tex superscript shift-up in cramped styles */
157 
158 #define sup3(A) mathsy(A,15)
159 
160 /*tex subscript shift-down if superscript is absent */
161 
162 #define sub1(A) mathsy(A,16)
163 
164 /*tex subscript shift-down if superscript is present */
165 
166 #define sub2(A) mathsy(A,17)
167 
168 /*tex superscript baseline below top of large box */
169 
170 #define sup_drop(A) mathsy(A,18)
171 
172 /*tex subscript baseline below bottom of large box */
173 
174 #define sub_drop(A) mathsy(A,19)
175 
176 /*tex size of \.{\\atopwithdelims} delimiters in display styles */
177 
178 #define delim1(A) mathsy(A,20)
179 
180 /*tex size of \.{\\atopwithdelims} delimiters in non-displays */
181 
182 #define delim2(A) mathsy(A,21)
183 
184 /*tex height of fraction lines above the baseline */
185 
186 #define axis_height(A) mathsy(A,22)
187 
188 /*tex
189 
190  The math-extension parameters have similar macros, but the size code is
191  omitted (since it is always |cur_size| when we refer to such parameters).
192 
193 */
194 
195 #define mathex(A,B) font_param(fam_fnt(3,A),B)
196 
197 /*tex thickness of \.{\\over} bars */
198 
199 #define default_rule_thickness(A) mathex(A,8)
200 
201 /*tex minimum clearance above a displayed op */
202 
203 #define big_op_spacing1(A) mathex(A,9)
204 
205 /*tex minimum clearance below a displayed op */
206 
207 #define big_op_spacing2(A) mathex(A,10)
208 
209 /*tex minimum baselineskip above displayed op */
210 
211 #define big_op_spacing3(A) mathex(A,11)
212 
213 /*tex minimum baselineskip below displayed op */
214 
215 #define big_op_spacing4(A) mathex(A,12)
216 
217 /*tex padding above and below displayed limits */
218 
219 #define big_op_spacing5(A) mathex(A,13)
220 
221 /*tex
222 
223  \LUATEX makes a bunch of extensions cf. the |MATH| table in \OPENTYPE, but
224  some of the |MathConstants| values have no matching usage in \LUATEX\ right
225  now.
226 
227  \startitemize
228 
229  \startitem
230  |ScriptPercentScaleDown| |ScriptScriptPercentScaleDown|: These should
231  be handled by the macro package, on the engine side there are three
232  separate fonts.
233  \stopitem
234 
235  \startitem
236  |DelimitedSubFormulaMinHeight|: This is perhaps related to word's
237  natural math input? We have no idea what to do about it.
238  \stopitem
239 
240  \startitem
241  |MathLeading|: \LUATEX does not currently handle multi-line displays,
242  and the parameter does not seem to make much sense elsewhere.
243  \stopitem
244 
245  \startitem
246  |FlattenedAccentBaseHeight|: This is based on the |flac| |GSUB|
247  feature. It would not be hard to support that, but proper math accent
248  placements cf.\ |MATH| needs support for |MathTopAccentAttachment|
249  table to be implemented first.
250  \stopitem
251 
252  \stopitemize
253 
254 */
255 
256 static void math_param_error(const char *param, int style)
257 {
258  char s[256];
259  const char *hlp[] = {
260  "Sorry, but I can't typeset math unless various parameters have",
261  "been set. This is normally done by loading special math fonts",
262  "into the math family slots. Your font set is lacking at least",
263  "the parameter mentioned earlier.",
264  NULL
265  };
266  snprintf(s, 256, "Math error: parameter \\Umath%s\\%sstyle is not set", param, math_style_names[style]);
267  tex_error(s, hlp);
268  return;
269 }
270 
272 {
273  scaled a;
274  if (do_new_math(f)) {
277  a = x_height(f);
278  } else {
279  a = x_height(f);
280  }
281  return a;
282 }
283 
284 /*tex
285 
286  The non-staticness of this function is for the benefit of |texmath.w|.
287  Watch out, this one uses the style! The style and size numbers don't
288  match because we have cramped styles.
289 
290 */
291 
293 {
295  if (a == undefined_math_parameter) {
296  math_param_error("quad", var);
297  return 0;
298  } else {
299  return a;
300  }
301 }
302 
303 /*tex
304 
305  For this reason the next one is different because it is called with a size
306  specifier instead of a style specifier.
307 
308 */
309 
311 {
312  scaled a;
313  int var;
314  if (b == script_size)
315  var = script_style;
316  else if (b == script_script_size)
318  else
319  var = text_style;
321  if (a == undefined_math_parameter) {
322  math_param_error("axis", var);
323  return 0;
324  } else {
325  return a;
326  }
327 }
328 
330 {
331  int var;
332  if (b == script_size)
333  var = script_style;
334  else if (b == script_script_size)
336  else
337  var = text_style;
339 }
340 
342 {
344  return a;
345 }
346 
347 /*tex
348 
349  Old-style fonts do not define the |radical_rule|. This allows |make_radical|
350  to select the backward compatibility code, and it means that we can't raise
351  an error here.
352 
353 */
354 
356 {
358  return a;
359 }
360 
361 /*tex
362 
363  Now follow all the trivial math parameters.
364 
365 */
366 
367 #define get_math_param_or_error(a,b) do_get_math_param_or_error(a, math_param_##b, #b)
368 #define get_math_param_or_zero(a,b) do_get_math_param_or_zero(a, math_param_##b, #b)
369 
370 static scaled do_get_math_param_or_error(int var, int param, const char *name)
371 {
373  if (a == undefined_math_parameter) {
375  a = 0;
376  }
377  return a;
378 }
379 
380 static scaled do_get_math_param_or_zero(int var, int param, const char *name)
381 {
383  if (a == undefined_math_parameter) {
384  a = 0;
385  }
386  return a;
387 }
388 
389 /*tex
390 
391  A variant on a suggestion on the list based on analysis by UV.
392 
393 */
394 
395 static scaled get_delimiter_height(scaled max_d, scaled max_h, boolean axis) {
396  scaled delta, delta1, delta2;
397  if (axis) {
398  delta2 = max_d + math_axis_size(cur_size);
399  } else {
400  delta2 = max_d;
401  }
402  delta1 = max_h + max_d - delta2;
403  if (delta2 > delta1) {
404  /*tex |delta1| is max distance from axis */
405  delta1 = delta2;
406  }
407  delta = (delta1 / 500) * delimiter_factor_par;
408  delta2 = delta1 + delta1 - delimiter_shortfall_par;
409  if (delta < delta2) {
410  return delta2;
411  } else {
412  return delta;
413  }
414 }
415 
416 #define radical_degree_before(a) get_math_param_or_error(a, radical_degree_before)
417 #define radical_degree_after(a) get_math_param_or_error(a, radical_degree_after)
418 #define radical_degree_raise(a) get_math_param_or_error(a, radical_degree_raise)
419 
420 #define connector_overlap_min(a) get_math_param_or_error(a, connector_overlap_min)
421 
422 #define overbar_rule(a) get_math_param_or_error(a, overbar_rule)
423 #define overbar_kern(a) get_math_param_or_error(a, overbar_kern)
424 #define overbar_vgap(a) get_math_param_or_error(a, overbar_vgap)
425 
426 #define underbar_rule(a) get_math_param_or_error(a, underbar_rule)
427 #define underbar_kern(a) get_math_param_or_error(a, underbar_kern)
428 #define underbar_vgap(a) get_math_param_or_error(a, underbar_vgap)
429 
430 #define under_delimiter_vgap(a) get_math_param_or_error(a, under_delimiter_vgap)
431 #define under_delimiter_bgap(a) get_math_param_or_error(a, under_delimiter_bgap)
432 
433 #define over_delimiter_vgap(a) get_math_param_or_error(a, over_delimiter_vgap)
434 #define over_delimiter_bgap(a) get_math_param_or_error(a, over_delimiter_bgap)
435 
436 #define radical_vgap(a) get_math_param_or_error(a, radical_vgap)
437 #define radical_kern(a) get_math_param_or_error(a, radical_kern)
438 
439 #define stack_vgap(a) get_math_param_or_error(a, stack_vgap)
440 #define stack_num_up(a) get_math_param_or_error(a, stack_num_up)
441 #define stack_denom_down(a) get_math_param_or_error(a, stack_denom_down)
442 
443 #define fraction_rule(a) get_math_param_or_error(a, fraction_rule)
444 #define fraction_num_vgap(a) get_math_param_or_error(a, fraction_num_vgap)
445 #define fraction_denom_vgap(a) get_math_param_or_error(a, fraction_denom_vgap)
446 #define fraction_num_up(a) get_math_param_or_error(a, fraction_num_up)
447 #define fraction_denom_down(a) get_math_param_or_error(a, fraction_denom_down)
448 #define fraction_del_size_new(a) get_math_param_or_error(a, fraction_del_size)
449 /* fraction_del_size_old(a) get_math_param (a, math_param_fraction_del_size) */
450 #define fraction_del_size_old(a) get_math_param_or_error(a, fraction_del_size)
451 
452 #define skewed_fraction_hgap(a) get_math_param_or_error(a, skewed_fraction_hgap)
453 #define skewed_fraction_vgap(a) get_math_param_or_error(a, skewed_fraction_vgap)
454 
455 #define limit_above_vgap(a) get_math_param_or_error(a, limit_above_vgap)
456 #define limit_above_bgap(a) get_math_param_or_error(a, limit_above_bgap)
457 #define limit_above_kern(a) get_math_param_or_error(a, limit_above_kern)
458 
459 #define limit_below_vgap(a) get_math_param_or_error(a, limit_below_vgap)
460 #define limit_below_bgap(a) get_math_param_or_error(a, limit_below_bgap)
461 #define limit_below_kern(a) get_math_param_or_error(a, limit_below_kern)
462 
463 #define nolimit_sub_factor(a) get_math_param_or_zero(a, nolimit_sub_factor)
464 #define nolimit_sup_factor(a) get_math_param_or_zero(a, nolimit_sup_factor)
465 
466 #define sub_shift_drop(a) get_math_param_or_error(a, sub_shift_drop)
467 #define sup_shift_drop(a) get_math_param_or_error(a, sup_shift_drop)
468 #define sub_shift_down(a) get_math_param_or_error(a, sub_shift_down)
469 #define sub_sup_shift_down(a) get_math_param_or_error(a, sub_sup_shift_down)
470 #define sup_shift_up(a) get_math_param_or_error(a, sup_shift_up)
471 #define sub_top_max(a) get_math_param_or_error(a, sub_top_max)
472 #define sup_bottom_min(a) get_math_param_or_error(a, sup_bottom_min)
473 #define sup_sub_bottom_max(a) get_math_param_or_error(a, sup_sub_bottom_max)
474 #define subsup_vgap(a) get_math_param_or_error(a, subsup_vgap)
475 
476 #define space_after_script(a) get_math_param_or_error(a, space_after_script)
477 
478 void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
479 {
480  if (is_new_mathfont(f)) {
481 
482  /*tex Fix all known parameters. */
483 
485  font_size(f), lvl);
487  font_size(f), lvl);
489  font_MATH_par(f, AxisHeight), lvl);
491  font_MATH_par(f, AxisHeight), lvl);
516 
525 
534 
544  font_MATH_par(f, StackGapMin), lvl);
547 
552 
555 
576 
577  if (size_id == text_size) {
586  } else if (size_id == script_size) {
591  } else if (size_id == script_script_size) {
596  }
597 
610 
616  } else {
621  }
622 
639 
649  0, lvl);
651  0, lvl);
661  0, lvl);
663  0, lvl);
665  font_MATH_par(f, NoLimitSubFactor), lvl); /* bonus */
667  font_MATH_par(f, NoLimitSubFactor), lvl); /* bonus */
669  font_MATH_par(f, NoLimitSupFactor), lvl); /* bonus */
671  font_MATH_par(f, NoLimitSupFactor), lvl); /* bonus */
672 
693 
698 
707 
712 
717 
718  } else if (fam_id == 2 && is_old_mathfont(f, total_mathsy_params)) {
719 
720  /*tex Fix old-style |sy| parameters. */
721 
723  math_quad(size_id), lvl);
725  math_quad(size_id), lvl);
727  axis_height(size_id), lvl);
729  axis_height(size_id), lvl);
731  num3(size_id), lvl);
733  num1(size_id), lvl);
735  denom2(size_id), lvl);
737  denom1(size_id), lvl);
739  num2(size_id), lvl);
741  num1(size_id), lvl);
743  denom2(size_id), lvl);
745  denom1(size_id), lvl);
747  delim2(size_id), lvl);
749  delim1(size_id), lvl);
750 
752  0, lvl);
754  0, lvl);
756  0, lvl);
758  0, lvl);
759 
760  if (size_id == text_size) {
762  sup1(size_id), lvl);
764  sup3(size_id), lvl);
766  sup2(size_id), lvl);
768  sup3(size_id), lvl);
769  } else if (size_id == script_size) {
771  sub_drop(size_id), lvl);
773  sub_drop(size_id), lvl);
775  sub_drop(size_id), lvl);
777  sub_drop(size_id), lvl);
779  sup_drop(size_id), lvl);
781  sup_drop(size_id), lvl);
783  sup_drop(size_id), lvl);
785  sup_drop(size_id), lvl);
787  sup2(size_id), lvl);
789  sup3(size_id), lvl);
790  } else if (size_id == script_script_size) {
792  sub_drop(size_id), lvl);
794  sub_drop(size_id), lvl);
796  sub_drop(size_id), lvl);
798  cramped_script_script_style, sub_drop(size_id), lvl);
800  sup_drop(size_id), lvl);
802  sup_drop(size_id), lvl);
804  sup_drop(size_id), lvl);
806  cramped_script_script_style, sup_drop(size_id), lvl);
808  sup2(size_id), lvl);
810  sup3(size_id), lvl);
811  }
812 
814  sub1(size_id), lvl);
816  sub1(size_id), lvl);
818  sub2(size_id), lvl);
820  sub2(size_id), lvl);
822  (abs(math_x_height(size_id) * 4) / 5), lvl);
824  (abs(math_x_height(size_id) * 4) / 5), lvl);
826  (abs(math_x_height(size_id)) / 4), lvl);
828  (abs(math_x_height(size_id)) / 4), lvl);
830  (abs(math_x_height(size_id) * 4) / 5), lvl);
832  (abs(math_x_height(size_id) * 4) / 5), lvl);
833 
834  /*tex
835 
836  The display-size |radical_vgap| is done twice because it needs values
837  from both the sy and the ex font.
838 
839  */
840 
842  (default_rule_thickness(size_id) + (abs(math_x_height(size_id)) / 4)), lvl);
844  60, lvl);
846  60, lvl);
848  xn_over_d(get_math_quad_size(size_id), 5, 18), lvl);
850  xn_over_d(get_math_quad_size(size_id), 5, 18), lvl);
852  (-xn_over_d (get_math_quad_size(size_id), 10, 18)), lvl);
854  (-xn_over_d (get_math_quad_size(size_id), 10, 18)), lvl);
855 
856  } else if (fam_id == 3 && is_old_mathfont(f, total_mathex_params)) {
857 
858  /*tex Fix old-style |ex| parameters. */
859 
861  default_rule_thickness(size_id), lvl);
863  default_rule_thickness(size_id), lvl);
865  3 * default_rule_thickness(size_id), lvl);
867  default_rule_thickness(size_id), lvl);
869  default_rule_thickness(size_id), lvl);
871  3 * default_rule_thickness(size_id), lvl);
873  default_rule_thickness(size_id), lvl);
875  default_rule_thickness(size_id), lvl);
877  3 * default_rule_thickness(size_id), lvl);
879  default_rule_thickness(size_id), lvl);
881  default_rule_thickness(size_id), lvl);
883  3 * default_rule_thickness(size_id), lvl);
885  default_rule_thickness(size_id), lvl);
887  default_rule_thickness(size_id), lvl);
889  (default_rule_thickness(size_id) + (abs(default_rule_thickness(size_id)) / 4)), lvl);
891  3 * default_rule_thickness(size_id), lvl);
893  7 * default_rule_thickness(size_id), lvl);
895  default_rule_thickness(size_id), lvl);
897  default_rule_thickness(size_id), lvl);
899  default_rule_thickness(size_id), lvl);
901  3 * default_rule_thickness(size_id), lvl);
903  default_rule_thickness(size_id), lvl);
905  3 * default_rule_thickness(size_id), lvl);
907  big_op_spacing1(size_id), lvl);
909  big_op_spacing1(size_id), lvl);
911  big_op_spacing3(size_id), lvl);
913  big_op_spacing3(size_id), lvl);
915  big_op_spacing5(size_id), lvl);
917  big_op_spacing5(size_id), lvl);
919  big_op_spacing2(size_id), lvl);
921  big_op_spacing2(size_id), lvl);
923  big_op_spacing4(size_id), lvl);
925  big_op_spacing4(size_id), lvl);
927  big_op_spacing5(size_id), lvl);
929  big_op_spacing5(size_id), lvl);
931  font_MATH_par(f, NoLimitSubFactor), lvl); /* bonus */
933  font_MATH_par(f, NoLimitSubFactor), lvl); /* bonus */
935  font_MATH_par(f, NoLimitSupFactor), lvl); /* bonus */
937  font_MATH_par(f, NoLimitSupFactor), lvl); /* bonus */
939  4 * default_rule_thickness(size_id), lvl);
941  4 * default_rule_thickness(size_id), lvl);
942 
943  /*tex
944 
945  All of the |space_after_script|s are done in
946  |finalize_math_parameters| because the \.{\\scriptspace} may have
947  been altered by the user.
948 
949  */
950 
952  0, lvl);
954  0, lvl);
955 
957  big_op_spacing2(size_id), lvl);
959  big_op_spacing2(size_id), lvl);
961  big_op_spacing4(size_id), lvl);
963  big_op_spacing4(size_id), lvl);
965  big_op_spacing1(size_id), lvl);
967  big_op_spacing1(size_id), lvl);
969  big_op_spacing3(size_id), lvl);
971  big_op_spacing3(size_id), lvl);
972 
973  /*tex
974 
975  The display-size |radical_vgap| is done twice because it needs values
976  from both the sy and the ex font.
977 
978  */
979 
981  (default_rule_thickness(size_id) + (abs(math_x_height(size_id)) / 4)), lvl);
982 
983  }
984 }
985 
986 /*tex
987 
988  This needs to be called just at the start of |mlist_to_hlist|, for backward
989  compatibility with \.{\\scriptspace}.
990 
991 */
992 
993 static void finalize_math_parameters(void)
994 {
995  int saved_trace = tracing_assigns_par;
1014  }
1015  tracing_assigns_par = saved_trace;
1016 }
1017 
1018 /*tex
1019 
1020  In order to convert mlists to hlists, i.e., noads to nodes, we need several
1021  subroutines that are conveniently dealt with now.
1022 
1023  Let us first introduce the macros that make it easy to get at the parameters
1024  and other font information. A size code, which is a multiple of 256, is added
1025  to a family number to get an index into the table of internal font numbers
1026  for each combination of family and size. (Be alert: Size codes get larger as
1027  the type gets smaller.)
1028 
1029 */
1030 
1031 static const char *math_size_string(int s)
1032 {
1033  if (s == text_size)
1034  return "textfont";
1035  else if (s == script_size)
1036  return "scriptfont";
1037  else
1038  return "scriptscriptfont";
1039 }
1040 
1041 /*tex
1042 
1043  When the style changes, the following piece of program computes associated
1044  information:
1045 
1046 */
1047 
1048 #define setup_cur_size(a) do { \
1049  if (a==script_style || a==cramped_script_style) \
1050  cur_size = script_size; \
1051  else if (a==script_script_style || a==cramped_script_script_style) \
1052  cur_size = script_script_size; \
1053  else \
1054  cur_size = text_size; \
1055 } while (0)
1056 
1057 
1058 /*tex
1059 
1060  A simple routine that creates a flat copy of a nucleus.
1061 
1062 */
1063 
1065 {
1066  pointer x;
1067  if (q == null)
1068  return null;
1069  x = new_node(type(q), 0);
1071  if (type(q) == math_char_node) {
1072  math_fam(x) = math_fam(q);
1074  } else {
1075  math_list(x) = math_list(q);
1076  }
1077  return x;
1078 }
1079 
1080 /*tex
1081 
1082  Here is a function that returns a pointer to a rule node having a given
1083  thickness |t|. The rule will extend horizontally to the boundary of the vlist
1084  that eventually contains it.
1085 
1086 */
1087 
1089 {
1090  pointer p;
1091  if (math_rules_mode_par) {
1092  p = new_rule(some_rule);
1095  } else {
1096  p = new_rule(normal_rule);
1097  }
1099  height(p) = t;
1100  depth(p) = 0;
1101  reset_attributes(p, att);
1102  return p;
1103 }
1104 
1105 /*tex
1106 
1107  The |overbar| function returns a pointer to a vlist box that consists of a
1108  given box |b|, above which has been placed a kern of height |k| under a
1109  fraction rule of thickness |t| under additional space of height |ht|.
1110 
1111 */
1112 
1114 {
1115  pointer p, q;
1116  p = new_kern(k);
1117  reset_attributes(p, att);
1118  couple_nodes(p,b);
1120  couple_nodes(q,p);
1121  p = new_kern(ht);
1122  reset_attributes(p, att);
1123  couple_nodes(p,q);
1125  reset_attributes(q, att);
1126  return q;
1127 }
1128 
1129 /*tex
1130 
1131  Here is a subroutine that creates a new box, whose list contains a single
1132  character, and whose width includes the italic correction for that character.
1133  The height or depth of the box will be negative, if the height or depth of
1134  the character is negative; thus, this routine may deliver a slightly
1135  different result than |hpack| would produce.
1136 
1137 */
1138 
1140 {
1141  /*tex The new box and its character node. */
1142  pointer b, p;
1143  b = new_null_box();
1144  if (do_new_math(f))
1145  width(b) = char_width(f, c);
1146  else
1147  width(b) = char_width(f, c) + char_italic(f, c);
1148  height(b) = char_height(f, c);
1149  depth(b) = char_depth(f, c);
1150  subtype(b) = math_char_list ;
1151  reset_attributes(b, bb);
1152  p = new_glyph(f, c);
1153  protect_glyph(p);
1154  reset_attributes(p, bb);
1155  list_ptr(b) = p;
1156  return b;
1157 }
1158 
1159 /*tex
1160 
1161  Another handy subroutine computes the height plus depth of a given character:
1162 
1163 */
1164 
1166 {
1167  return (char_height(f, c) + char_depth(f, c));
1168 }
1169 
1170 /*tex
1171 
1172  When we build an extensible character, it's handy to have the following
1173  subroutine, which puts a given character on top of the characters already in
1174  box |b|:
1175 
1176 */
1177 
1179 {
1180  /*tex New node placed into |b|: */
1181  pointer p, q;
1182  /*tex Italic gets added to width. */
1183  p = char_box(f, c, node_attr(b));
1184  if (type(b) == vlist_node) {
1186  list_ptr(b) = p;
1187  height(b) = height(p);
1188  if (width(b) < width(p))
1189  width(b) = width(p);
1190  return height_plus_depth(f, c);
1191  } else {
1192  q = list_ptr(b);
1193  if (q == null) {
1194  list_ptr(b) = p;
1195  } else {
1196  while (vlink(q) != null)
1197  q = vlink(q);
1198  couple_nodes(q,p);
1199  }
1200  if (height(b) < height(p))
1201  height(b) = height(p);
1202  if (depth(b) < depth(p))
1203  depth(b) = depth(p);
1204  return char_width(f, c);
1205  }
1206 }
1207 
1210  width(p) = min;
1211  stretch(p) = max - min;
1212  if (node_attr(b) != null) {
1214  }
1215  if (type(b) == vlist_node) {
1217  list_ptr(b) = p;
1218  } else {
1219  halfword q = list_ptr(b);
1220  if (q == null) {
1221  list_ptr(b) = p;
1222  } else {
1223  while (vlink(q) != null) {
1224  q = vlink(q);
1225  }
1226  couple_nodes(q,p);
1227  }
1228  }
1229 }
1230 
1231 /*tex
1232 
1233  \TeX's most important routine for dealing with formulas is called
1234  |mlist_to_hlist|. After a formula has been scanned and represented as an
1235  mlist, this routine converts it to an hlist that can be placed into a box or
1236  incorporated into the text of a paragraph. The explicit parameter |cur_mlist|
1237  points to the first node or noad in the given mlist (and it might be |null|);
1238  the parameter |penalties| is |true| if penalty nodes for potential line
1239  breaks are to be inserted into the resulting hlist, the parameter |cur_style|
1240  is a style code. After |mlist_to_hlist| has acted, |vlink(temp_head)| points
1241  to the translated hlist.
1242 
1243  Since mlists can be inside mlists, the procedure is recursive. And since this
1244  is not part of \TeX's inner loop, the program has been written in a manner
1245  that stresses compactness over efficiency.
1246 
1247 */
1248 
1249 /*tex Size code corresponding to |cur_style|: */
1250 
1251 int cur_size = 0;
1252 
1253 static pointer get_delim_box(internal_font_number fnt, halfword chr, scaled v, scaled min_overlap, int horizontal, halfword att)
1254 {
1255  int callback_id = callback_defined(make_extensible_callback);
1256  if (callback_id > 0) {
1257  /*tex
1258  This call is not optimized as it hardly makes sense to use it ... special
1259  and a it of feature creep too.
1260  */
1261  halfword b = null;
1262  run_callback(callback_id, "ddddbN->N",fnt,chr,v,min_overlap,horizontal,att,&b);
1263  if (b == null) {
1264  /*tex
1265  We see this as a signal to do it the \TEX\ way.
1266  */
1267  } else if (type(b) == hlist_node || type(b) == vlist_node) {
1268  return b;
1269  } else {
1270  formatted_error("fonts","invalid extensible character %i created for font %i, [h|v]list expected",chr,fnt);
1271  }
1272  }
1273  return make_extensible(fnt, chr, v, min_overlap, horizontal, att);
1274 }
1275 
1277 {
1278  /*tex new box */
1279  pointer b;
1280  /*tex natural (maximum) size of the stack */
1281  scaled b_max;
1282  /*tex amount of possible shrink in the stack */
1283  scaled s_max;
1284  extinfo *cur;
1285  extinfo *ext;
1286  scaled prev_overlap;
1287  /*tex a temporary counter number of extensible pieces */
1288  int i;
1289  /*tex number of times to repeat each repeatable item in |ext| */
1290  int with_extenders;
1291  int num_extenders, num_normal;
1292  scaled a, c, d;
1293  b = new_null_box();
1294  with_extenders = -1;
1295  num_extenders = 0;
1296  num_normal = 0;
1297  if (min_overlap < 0) {
1298  min_overlap = 0;
1299  }
1300  if (horizontal) {
1303  } else {
1306  }
1307  if (att != null) {
1308  reset_attributes(b,att);
1309  }
1310  cur = ext;
1311  while (cur != NULL) {
1312  if (!char_exists(fnt, cur->glyph)) {
1313  const char *hlp[] = {
1314  "Each glyph part in an extensible item should exist in the font.",
1315  "I will give up trying to find a suitable size for now. Fix your font!",
1316  NULL
1317  };
1318  tex_error("Variant part doesn't exist.", hlp);
1320  return b;
1321  }
1322  if (cur->extender > 0)
1323  num_extenders++;
1324  else
1325  num_normal++;
1326  /*tex No negative overlaps or advances are allowed. */
1327  if (cur->start_overlap < 0 || cur->end_overlap < 0 || cur->advance < 0) {
1328  const char *hlp[] = {
1329  "All measurements in extensible items should be positive.",
1330  "To get around this problem, I have changed the font metrics.",
1331  "Fix your font!",
1332  NULL
1333  };
1334  tex_error("Extensible recipe has negative fields.", hlp);
1335  if (cur->start_overlap < 0)
1336  cur->start_overlap = 0;
1337  if (cur->end_overlap < 0)
1338  cur->end_overlap = 0;
1339  if (cur->advance < 0)
1340  cur->advance = 0;
1341  }
1342  cur = cur->next;
1343  }
1344  if (num_normal == 0) {
1345  const char *hlp[] = {
1346  "Each extensible recipe should have at least one non-repeatable part.",
1347  "To get around this problem, I have changed the first part to be",
1348  "non-repeatable. Fix your font!",
1349  NULL
1350  };
1351  tex_error("Extensible recipe has no fixed parts.", hlp);
1352  ext->extender = 0;
1353  num_normal = 1;
1354  num_extenders--;
1355  }
1356  /*tex
1357 
1358  |ext| holds a linked list of numerous items that may or may not be
1359  repeatable. For the total height, we have to figure out how many items
1360  are needed to create a stack of at least |v|.
1361 
1362  The next |while| loop does that. It has two goals: it finds out the
1363  natural height |b_max| of the all the parts needed to reach at least |v|,
1364  and it sets |with_extenders| to the number of times each of the
1365  repeatable items in |ext| has to be repeated to reach that height.
1366 
1367  */
1368  cur = ext;
1369  b_max = 0;
1370  while (b_max < v && num_extenders > 0) {
1371  b_max = 0;
1372  prev_overlap = 0;
1373  with_extenders++;
1374  for (cur = ext; cur != NULL; cur = cur->next) {
1375  if (cur->extender == 0) {
1376  c = cur->start_overlap;
1377  if (min_overlap < c)
1378  c = min_overlap;
1379  if (prev_overlap < c)
1380  c = prev_overlap;
1381  a = cur->advance;
1382  if (a == 0) {
1383  /*tex for tfm fonts */
1384  if (horizontal) {
1385  a = char_width(fnt, cur->glyph);
1386  } else {
1387  a = height_plus_depth(fnt, cur->glyph);
1388  }
1389  if (a < 0) {
1390  formatted_error("fonts","bad extensible character %i in font %i",chr,fnt);
1391  }
1392  }
1393  b_max += a - c;
1394  prev_overlap = cur->end_overlap;
1395  } else {
1396  i = with_extenders;
1397  while (i > 0) {
1398  c = cur->start_overlap;
1399  if (min_overlap < c)
1400  c = min_overlap;
1401  if (prev_overlap < c)
1402  c = prev_overlap;
1403  a = cur->advance;
1404  if (a == 0) {
1405  /*tex for tfm fonts */
1406  if (horizontal) {
1407  a = char_width(fnt, cur->glyph);
1408  } else {
1409  a = height_plus_depth(fnt, cur->glyph);
1410  }
1411  if (a < 0) {
1412  formatted_error("fonts","bad extensible character %i in font %i",chr,fnt);
1413  }
1414  }
1415  b_max += a - c;
1416  prev_overlap = cur->end_overlap;
1417  i--;
1418  }
1419  }
1420  }
1421  }
1422  /*tex
1423 
1424  Assemble box using |with_extenders| copies of each extender, with
1425  appropriate glue wherever an overlap occurs.
1426 
1427  */
1428  prev_overlap = 0;
1429  b_max = 0;
1430  s_max = 0;
1431  for (cur = ext; cur != NULL; cur = cur->next) {
1432  if (cur->extender == 0) {
1433  c = cur->start_overlap;
1434  if (prev_overlap < c)
1435  c = prev_overlap;
1436  d = c;
1437  if (min_overlap < c)
1438  c = min_overlap;
1439  if (d > 0) {
1440  stack_glue_into_box(b, -d, -c);
1441  s_max += (-c) - (-d);
1442  b_max -= d;
1443  }
1444  b_max += stack_into_box(b, fnt, cur->glyph);
1445  prev_overlap = cur->end_overlap;
1446  i--;
1447  } else {
1448  i = with_extenders;
1449  while (i > 0) {
1450  c = cur->start_overlap;
1451  if (prev_overlap < c)
1452  c = prev_overlap;
1453  d = c;
1454  if (min_overlap < c)
1455  c = min_overlap;
1456  if (d > 0) {
1457  stack_glue_into_box(b, -d, -c);
1458  s_max += (-c) - (-d);
1459  b_max -= d;
1460  }
1461  b_max += stack_into_box(b, fnt, cur->glyph);
1462  prev_overlap = cur->end_overlap;
1463  i--;
1464  }
1465  }
1466  }
1467  /*tex Set glue so as to stretch the connections if needed. */
1468  d = 0;
1469  if (v > b_max && s_max > 0) {
1470  d = v-b_max;
1471  /*tex Don't stretch more than |s_max|. */
1472  if (d > s_max)
1473  d = s_max;
1474  glue_order(b) = normal;
1475  glue_sign(b) = stretching;
1476  glue_set(b) = unfloat(d/(float) s_max);
1477  b_max += d;
1478  }
1479  if (horizontal) {
1480  width(b) = b_max;
1482  } else {
1483  height(b) = b_max;
1485  }
1486  return b;
1487 }
1488 
1489 /*tex
1490 
1491  The |var_delimiter| function, which finds or constructs a sufficiently large
1492  delimiter, is the most interesting of the auxiliary functions that currently
1493  concern us. Given a pointer |d| to a delimiter field in some noad, together
1494  with a size code |s| and a vertical distance |v|, this function returns a
1495  pointer to a box that contains the smallest variant of |d| whose height plus
1496  depth is |v| or more. (And if no variant is large enough, it returns the
1497  largest available variant.) In particular, this routine will construct
1498  arbitrarily large delimiters from extensible components, if |d| leads to such
1499  characters.
1500 
1501  The value returned is a box whose |shift_amount| has been set so that the box
1502  is vertically centered with respect to the axis in the given size. If a
1503  built-up symbol is returned, the height of the box before shifting will be
1504  the height of its topmost component.
1505 
1506 */
1507 
1509 {
1510  char s[256];
1511  const char *hlp[] = {
1512  "You managed to create a seemingly endless charlist chain in the current",
1513  "font. I have counted until 10000 already and still have not escaped, so"
1514  "I will jump out of the loop all by myself now. Fix your font!",
1515  NULL
1516  };
1517  snprintf(s, 256, "Math error: endless loop in charlist (U+%04x in %s)", (int) y, font_name(g));
1518  tex_error(s, hlp);
1519 }
1520 
1521 static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat, int cur_style, boolean shift, boolean *stack, scaled *delta, int *same)
1522 {
1523  /*tex the box that will be constructed */
1524  pointer b;
1525  /*tex best-so-far and tentative font codes */
1527  /*tex best-so-far and tentative character codes */
1528  int c, i, x, y;
1529  /*tex height-plus-depth of a tentative character */
1530  scaled u;
1531  /*tex largest height-plus-depth so far */
1532  scaled w = 0;
1533  /*tex runs through font family members */
1534  int z;
1535  /*tex are we trying the ``large'' variant? */
1536  boolean large_attempt = false;
1537  /*tex to save the current attribute list */
1538  pointer att = null;
1539  int emas = 0 ;
1540  boolean do_parts = false;
1541  boolean parts_done = false;
1542  extinfo *ext;
1543 
1544  if (d && ! small_fam(d) && ! large_fam(d) && ! small_char(d) && ! large_char(d)) {
1545  halfword b = new_null_box();
1547  if (! flat)
1549  node_attr(b) = node_attr(d);
1550  node_attr(d) = null;
1551  flush_node(d);
1552  return b;
1553  }
1554 
1555  f = null_font;
1556  c = 0;
1557  if (d == null) {
1558  goto FOUND;
1559  }
1560  z = small_fam(d);
1561  x = small_char(d);
1562  i = 0;
1563  if (same != NULL) {
1564  emas = *same ;
1565  same = 0;
1566  }
1567  while (true) {
1568  /*tex
1569 
1570  The search process is complicated slightly by the facts that some of
1571  the characters might not be present in some of the fonts, and they
1572  might not be probed in increasing order of height.
1573 
1574  */
1575  if ((z != 0) || (x != 0)) {
1576  g = fam_fnt(z, s);
1577  if (g != null_font) {
1578  y = x;
1579  CONTINUE:
1580  i++;
1581  if (char_exists(g, y)) {
1582  if (flat)
1583  u = char_width(g, y);
1584  else
1585  u = height_plus_depth(g, y);
1586  if (u > w) {
1587  f = g;
1588  c = y;
1589  w = u;
1590  if (u >= v)
1591  goto FOUND;
1592  }
1593  if (char_tag(g, y) == ext_tag) {
1594  f = g;
1595  c = y;
1596  do_parts = true;
1597  goto FOUND;
1598  }
1599  if (i > 10000) {
1601  goto FOUND;
1602  }
1603  if (char_tag(g, y) == list_tag) {
1604  y = char_remainder(g, y);
1605  goto CONTINUE;
1606  }
1607  }
1608  }
1609  }
1610  if (large_attempt) {
1611  /*tex There were none large enough. */
1612  goto FOUND;
1613  }
1614  large_attempt = true;
1615  z = large_fam(d);
1616  x = large_char(d);
1617  }
1618  FOUND:
1619  if (d != null) {
1620  att = node_attr(d);
1621  node_attr(d) = null;
1622  flush_node(d);
1623  }
1624  if (f != null_font) {
1625  /*tex
1626 
1627  When the following code is executed, |do_parts| will be true if a
1628  built-up symbol is supposed to be returned.
1629 
1630  */
1631  ext = NULL;
1632  if ((do_parts) && ((!flat && (ext = get_charinfo_vert_variants(char_info(f,c))) != NULL)
1633  || ( flat && (ext = get_charinfo_hor_variants (char_info(f,c))) != NULL))) {
1634  parts_done = true;
1635  if (flat) {
1637  } else {
1639  }
1640  if (delta != NULL) {
1641  if (do_new_math(f)) {
1642  *delta = char_vert_italic(f,x);
1643  } else {
1644  *delta = char_italic(f,x);
1645  }
1646  }
1647  if (stack != NULL)
1648  *stack = true ;
1649  } else {
1650  parts_done = false;
1651  if (same != NULL && x == c) {
1652  *same = emas;
1653  }
1654  /*tex
1655  Here italic is added to width in traditional fonts which makes the delimiter get
1656  the real width. An \OPENTYPE\ font already has the right width.
1657  */
1658  b = char_box(f, c, att);
1659  /*tex
1660  There is one case where |delta| (ic) gets subtracted but only for a traditional
1661  font. In that case the traditional width (which is fake width + italic) becomes
1662  less and the delta is added. See (**). (On the mailing list font |ntxexx| was
1663  mentioned as test case by MK.)
1664  */
1665  if (delta != NULL) {
1666  *delta = char_italic(f, c);
1667  }
1668  if (stack != NULL)
1669  *stack = false ;
1670  }
1671  } else {
1672  b = new_null_box();
1673  reset_attributes(b, att);
1674  if (flat) {
1675  width(b) = 0;
1677  } else {
1678  /*tex Use this width if no delimiter was found. */
1681  }
1682  if (delta != NULL) {
1683  *delta = 0;
1684  }
1685  if (stack != NULL)
1686  *stack = false ;
1687  }
1688  if (!flat) {
1689  /*tex when emas ~= 0 then we have a non scaled character */
1690  if (emas != 0 && delimitermodesamenos) {
1691  /*tex same character and no shift when same forced */
1692  goto DONE;
1693  }
1694  if (! parts_done && delimitermodecharnos) {
1695  /*tex same character and no shift when same forced */
1696  goto DONE;
1697  }
1698  if (delimitermodenoshift) {
1699  /*tex no shift forced */
1700  goto DONE;
1701  }
1702  /*tex vertical variant */
1703  shift_amount(b) = half(height(b) - depth(b));
1704  if (shift) {
1706  }
1707  }
1708  DONE:
1709  delete_attribute_ref(att);
1710  return b;
1711 }
1712 
1713 /*tex
1714 
1715  The next subroutine is much simpler; it is used for numerators and
1716  denominators of fractions as well as for displayed operators and their limits
1717  above and below. It takes a given box~|b| and changes it so that the new box
1718  is centered in a box of width~|w|. The centering is done by putting \.{\\hss}
1719  glue at the left and right of the list inside |b|, then packaging the new
1720  box; thus, the actual box might not really be centered, if it already
1721  contains infinite glue.
1722 
1723  The given box might contain a single character whose italic correction has
1724  been added to the width of the box; in this case a compensating kern is
1725  inserted.
1726 
1727 */
1728 
1730 {
1731  /*tex temporary registers for list manipulation */
1732  pointer p, q, r, att;
1733  /*tex font in a one-character box */
1735  /*tex width of a character without italic correction */
1736  scaled v;
1737  if ((width(b) != w) && (list_ptr(b) != null)) {
1738  if (type(b) == vlist_node) {
1739  p = hpack(b, 0, additional, -1);
1741  b = p;
1742  }
1743  p = list_ptr(b);
1744  att = node_attr(b);
1745  add_node_attr_ref(att);
1746  if ((is_char_node(p)) && (vlink(p) == null)) {
1747  f = font(p);
1748  v = char_width(f, character(p));
1749  if (v != width(b)) {
1750  q = new_kern(width(b) - v);
1751  reset_attributes(q, att);
1752  couple_nodes(p,q);
1753  }
1754  }
1755  list_ptr(b) = null;
1756  flush_node(b);
1757  b = new_glue(ss_glue);
1758  reset_attributes(b, att);
1759  couple_nodes(b,p);
1760  while (vlink(p) != null)
1761  p = vlink(p);
1762  q = new_glue(ss_glue);
1763  reset_attributes(q, att);
1764  couple_nodes(p,q);
1765  r = hpack(b, w, exactly, -1);
1766  reset_attributes(r, att);
1767  delete_attribute_ref(att);
1768  return r;
1769  } else {
1770  width(b) = w;
1771  return b;
1772  }
1773 }
1774 
1775 /*tex
1776 
1777  Here is a subroutine that creates a new glue specification from another one
1778  that is expressed in `\.{mu}', given the value of the math unit.
1779 
1780 */
1781 
1782 #define mu_mult(A) mult_and_add(n,(A),xn_over_d((A),f,unity),max_dimen)
1783 
1785 {
1786  /*tex integer part of |m| */
1787  int n = x_over_n(m, unity);
1788  /*tex fraction part of |m| */
1790  /*tex the new glue specification */
1791  pointer p;
1792  if (f < 0) {
1793  decr(n);
1794  f = f + unity;
1795  }
1796  p = new_node(glue_node, 0);
1797  /* convert \.{mu} to \.{pt} */
1798  width(p) = mu_mult(width(g));
1800  if (stretch_order(p) == normal)
1801  stretch(p) = mu_mult(stretch(g));
1802  else
1803  stretch(p) = stretch(g);
1805  if (shrink_order(p) == normal)
1806  shrink(p) = mu_mult(shrink(g));
1807  else
1808  shrink(p) = shrink(g);
1809  return p;
1810 }
1811 
1813 {
1814  /*tex integer part of |m| */
1815  int n = x_over_n(m, unity);
1816  /*tex fraction part of |m| */
1818  if (f < 0) {
1819  decr(n);
1820  f = f + unity;
1821  }
1822  /* convert \.{mu} to \.{pt} */
1823  width(p) = mu_mult(width(p));
1824  if (stretch_order(p) == normal)
1825  stretch(p) = mu_mult(stretch(p));
1826  if (shrink_order(p) == normal)
1827  shrink(p) = mu_mult(shrink(p));
1828  subtype(p) = normal;
1829 }
1830 
1831 /*tex
1832 
1833  The |math_kern| subroutine removes |mu_glue| from a kern node, given the
1834  value of the math unit.
1835 
1836 */
1837 static void math_kern(pointer p, scaled m)
1838 {
1839  /*tex integer part of |m| */
1840  int n;
1841  /*tex fraction part of |m| */
1842  scaled f;
1843  if (subtype(p) == mu_glue) {
1844  n = x_over_n(m, unity);
1845  f = tex_remainder;
1846  if (f < 0) {
1847  decr(n);
1848  f = f + unity;
1849  }
1850  width(p) = mu_mult(width(p));
1851  /* this is weird, it's not a italic but explicit_kern */
1852  subtype(p) = italic_kern;
1853  }
1854 }
1855 
1856 void run_mlist_to_hlist(halfword p, boolean penalties, int mstyle)
1857 {
1858  int callback_id;
1859  int a, sfix, i;
1860  if (p == null) {
1861  vlink(temp_head) = null;
1862  return;
1863  }
1866  if (callback_id > 0) {
1867  sfix = lua_gettop(Luas);
1868  if (!get_callback(Luas, callback_id)) {
1869  lua_settop(Luas, sfix);
1870  return;
1871  }
1872  alink(p) = null ;
1874  lua_push_math_style_name(Luas, mstyle);
1875  lua_pushboolean(Luas, penalties);
1876  if ((i=lua_pcall(Luas, 3, 1, 0)) != 0) {
1877  formatted_warning("mlist to hlist","error: %s",lua_tostring(Luas, -1));
1878  lua_settop(Luas, sfix);
1879  luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
1880  return;
1881  }
1882  a = nodelist_from_lua(Luas,-1);
1883  /* alink(vlink(a)) = null; */
1884  vlink(temp_head) = a;
1885  lua_settop(Luas, sfix);
1886  } else if (callback_id == 0) {
1887  mlist_to_hlist(p, penalties, mstyle);
1888  } else {
1889  vlink(temp_head) = null;
1890  }
1891 }
1892 
1893 /*tex
1894 
1895  The recursion in |mlist_to_hlist| is due primarily to a subroutine called
1896  |clean_box| that puts a given noad field into a box using a given math style;
1897  |mlist_to_hlist| can call |clean_box|, which can call |mlist_to_hlist|.
1898 
1899  The box returned by |clean_box| is ``clean'' in the sense that its
1900  |shift_amount| is zero.
1901 
1902 */
1903 
1905 {
1906  /*tex beginning of a list to be boxed */
1907  pointer q;
1908  /*tex box to be returned */
1909  pointer x;
1910  /*tex temporary pointer */
1911  pointer r;
1912  /*tex beginning of mlist to be translated */
1913  pointer mlist = null;
1914  switch (type(p)) {
1915  case math_char_node:
1916  mlist = new_noad();
1917  r = math_clone(p);
1918  nucleus(mlist) = r;
1919  break;
1920  case sub_box_node:
1921  q = math_list(p);
1922  goto FOUND;
1923  break;
1924  case sub_mlist_node:
1925  mlist = math_list(p);
1926  break;
1927  default:
1928  q = new_null_box();
1930  goto FOUND;
1931  }
1932  mlist_to_hlist(mlist, false, s);
1933  /*tex recursive call */
1934  q = vlink(temp_head);
1936  FOUND:
1937  if (is_char_node(q) || (q == null))
1938  x = hpack(q, 0, additional, -1);
1939  else if ((vlink(q) == null) && (type(q) <= vlist_node) && (shift_amount(q) == 0))
1940  /*tex It's already clean. */
1941  x = q;
1942  else
1943  x = hpack(q, 0, additional, -1);
1944  if (x != q && q != null)
1946  subtype(x) = st;
1947  /*tex Here we save memory space in a common case. */
1948  q = list_ptr(x);
1949  if (is_char_node(q)) {
1950  r = vlink(q);
1951  if (r != null) {
1952  if (vlink(r) == null) {
1953  if (!is_char_node(r)) {
1954  if (type(r) == kern_node) {
1955  /*tex Unneeded italic correction. */
1956  flush_node(r);
1957  vlink(q) = null;
1958  }
1959  }
1960  }
1961  }
1962  }
1963  return x;
1964 }
1965 
1966 /*tex
1967 
1968  It is convenient to have a procedure that converts a |math_char| field to an
1969  ``unpacked'' form. The |fetch| routine sets |cur_f| and |cur_c| to the font
1970  code and character code of a given noad field. It also takes care of issuing
1971  error messages for nonexistent characters; in such cases,
1972  |char_exists(cur_f,cur_c)| will be |false| after |fetch| has acted, and the
1973  field will also have been reset to |null|.
1974 
1975  The outputs of |fetch| are placed in global variables.
1976 
1977 */
1978 
1979 /*tex the |font| field of a |math_char| */
1980 
1982 
1983 /*tex the |character| field of a |math_char| */
1984 
1985 int cur_c;
1986 
1987 /*tex Here we unpack the |math_char| field |a|. */
1988 
1989 static void fetch(pointer a)
1990 {
1991  cur_c = math_character(a);
1993  if (cur_f == null_font) {
1994  char *msg;
1995  const char *hlp[] = {
1996  "Somewhere in the math formula just ended, you used the",
1997  "stated character from an undefined font family. For example,",
1998  "plain TeX doesn't allow \\it or \\sl in subscripts. Proceed,",
1999  "and I'll try to forget that I needed that character.",
2000  NULL
2001  };
2002  msg = xmalloc(256);
2003  snprintf(msg, 255, "\\%s%d is undefined (character %d)",
2004  math_size_string(cur_size), (int) math_fam(a), (int) cur_c);
2005  tex_error(msg, hlp);
2006  free(msg);
2007  } else if (!(char_exists(cur_f, cur_c))) {
2009  }
2010 }
2011 
2012 /*tex
2013 
2014  We need to do a lot of different things, so |mlist_to_hlist| makes two passes
2015  over the given mlist.
2016 
2017  The first pass does most of the processing: It removes ``mu'' spacing from
2018  glue, it recursively evaluates all subsidiary mlists so that only the
2019  top-level mlist remains to be handled, it puts fractions and square roots and
2020  such things into boxes, it attaches subscripts and superscripts, and it
2021  computes the overall height and depth of the top-level mlist so that the size
2022  of delimiters for a |fence_noad| will be known. The hlist resulting from each
2023  noad is recorded in that noad's |new_hlist| field, an integer field that
2024  replaces the |nucleus| or |thickness|.
2025 
2026  The second pass eliminates all noads and inserts the correct glue and
2027  penalties between nodes.
2028 
2029 */
2030 
2032 {
2033  switch (type(q)) {
2034  case fraction_noad:
2035  math_list(numerator(q)) = null;
2037  numerator(q) = null;
2038  math_list(denominator(q)) = null;
2040  denominator(q) = null;
2041  break;
2042  case radical_noad:
2043  case simple_noad:
2044  case accent_noad:
2045  if (nucleus(q) != null) {
2046  math_list(nucleus(q)) = null;
2047  flush_node(nucleus(q));
2048  nucleus(q) = null;
2049  }
2050  break;
2051  }
2052  new_hlist(q) = r;
2053 }
2054 
2055 #define choose_mlist(A) do { p=A(q); A(q)=null; } while (0)
2056 
2057 /*tex
2058 
2059  Most of the actual construction work of |mlist_to_hlist| is done by
2060  procedures with names like |make_fraction|, |make_radical|, etc. To
2061  illustrate the general setup of such procedures, let's begin with a couple of
2062  simple ones.
2063 
2064 */
2065 
2066 static void make_over(pointer q, int cur_style, int cur_size, int cur_fam)
2067 {
2068  /*tex
2069 
2070  No rule adaption yet, maybe never as overbars should be proper
2071  extensibles.
2072 
2073  */
2074  pointer p;
2075  scaled f, t;
2076  scaled used_thickness = overbar_rule(cur_style);
2077  scaled used_fam = cur_fam;
2078  if (math_rule_thickness_mode_par > 0) {
2079  f = noad_fam(q);
2080  if (f >= 0) {
2081  t = fam_fnt(f,cur_size);
2082  if (do_new_math(t)) {
2084  if (t != undefined_math_parameter) {
2085  used_thickness = t;
2086  used_fam = f;
2087  }
2088  }
2089  }
2090  }
2092  overbar_vgap(cur_style), used_thickness, overbar_kern(cur_style),
2093  node_attr(nucleus(q)), math_over_rule, cur_size, used_fam);
2095  math_list(nucleus(q)) = p;
2096  type(nucleus(q)) = sub_box_node;
2097 }
2098 
2099 static void make_under(pointer q, int cur_style, int cur_size, int cur_fam)
2100 {
2101  /*tex
2102 
2103  No rule adaption yet, maybe never as underbars should be proper
2104  extensibles.
2105 
2106  */
2107  /*tex temporary registers for box construction */
2108  pointer p, x, y, r;
2109  /*tex overall height plus depth */
2110  scaled delta;
2111  scaled f, t;
2112  scaled used_thickness = underbar_rule(cur_style);
2113  scaled used_fam = cur_fam;
2117  couple_nodes(x,p);
2118  if (math_rule_thickness_mode_par > 0) {
2119  f = noad_fam(q);
2120  if (f >= 0) {
2121  t = fam_fnt(f,cur_size);
2122  if (do_new_math(t)) {
2124  if (t != undefined_math_parameter) {
2125  used_thickness = t;
2126  used_fam = f;
2127  }
2128  }
2129  }
2130  }
2131  r = do_fraction_rule(used_thickness, node_attr(q), math_under_rule, cur_size, used_fam);
2132  couple_nodes(p,r);
2137  height(y) = height(x);
2138  depth(y) = delta - height(y);
2139  math_list(nucleus(q)) = y;
2140  type(nucleus(q)) = sub_box_node;
2141 }
2142 
2143 static void make_vcenter(pointer q)
2144 {
2145  /*tex the box that should be centered vertically */
2146  pointer v;
2147  /*tex its height plus depth */
2148  scaled delta;
2149  v = math_list(nucleus(q));
2150  if (type(v) != vlist_node)
2151  confusion("vcenter");
2152  delta = height(v) + depth(v);
2154  depth(v) = delta - height(v);
2155 }
2156 
2157 /*tex
2158 
2159  According to the rules in the \.{DVI} file specifications, we ensure
2160  alignment between a square root sign and the rule above its nucleus by
2161  assuming that the baseline of the square-root symbol is the same as the
2162  bottom of the rule. The height of the square-root symbol will be the
2163  thickness of the rule, and the depth of the square-root symbol should exceed
2164  or equal the height-plus-depth of the nucleus plus a certain minimum
2165  clearance~|psi|. The symbol will be placed so that the actual clearance is
2166  |psi| plus half the excess.
2167 
2168 */
2169 
2171 {
2172  pointer e, p;
2173  halfword w;
2174  boolean stack = false;
2176  w = width(e);
2177  if (!stack&& (radicalwidth(q) != 0) && (radicalwidth(q) != width(e))) {
2178  if (radicalmiddle(q)) {
2179  p = new_kern(half(radicalwidth(q)-w));
2181  couple_nodes(p,e);
2182  e = p;
2183  w = radicalwidth(q);
2184  } else if (radicalexact(q)) {
2185  w = radicalwidth(q);
2186  }
2187  }
2188  e = hpack(e, 0, additional, -1);
2189  width(e) = w ;
2191  math_list(nucleus(q)) = e;
2192  left_delimiter(q) = null;
2193 }
2194 
2195 static void make_radical(pointer q, int cur_style)
2196 {
2197  /*tex temporary registers for box construction */
2198  pointer x, y, p, l1, l2;
2199  /*tex dimensions involved in the calculation */
2200  scaled delta, clr, theta, h, f;
2201  scaled t, used_fam ;
2203  clr = radical_vgap(cur_style);
2204  theta = radical_rule_par(cur_style);
2205  used_fam = small_fam(left_delimiter(q));
2206  /*tex
2207 
2208  We can take the rule width from the fam/style of the delimiter or use the
2209  most recent math parameters value.
2210 
2211  */
2212  if (math_rule_thickness_mode_par > 0) {
2214  if (f >= 0) {
2215  t = fam_fnt(f,cur_size);
2216  if (do_new_math(t)) {
2218  if (t != undefined_math_parameter) {
2219  theta = t;
2220  used_fam = f;
2221  }
2222  }
2223  }
2224  }
2225  if (theta == undefined_math_parameter) {
2226  /*tex a real radical */
2227  theta = fraction_rule(cur_style);
2228  y = do_delimiter(q, left_delimiter(q), cur_size, height(x) + depth(x) + clr + theta, false, cur_style, true, NULL, NULL, NULL);
2229  /*tex
2230 
2231  If |y| is a composite then set |theta| to the height of its top
2232  character, else set it to the height of |y|.
2233 
2234  */
2235  l1 = list_ptr(y);
2236  if ((l1 != null) && (type(l1) == hlist_node)) {
2237  /*tex possible composite */
2238  l2 = list_ptr(l1);
2239  if ((l2 != null) && (type(l2) == glyph_node)) {
2240  /*tex top character */
2241  theta = char_height(font(l2), character(l2));
2242  } else {
2243  theta = height(y);
2244  }
2245  } else {
2246  theta = height(y);
2247  }
2248  } else {
2249  /*tex
2250 
2251  Not really a radical but we use its node, historical sharing (like in
2252  mathml).
2253 
2254  */
2255  y = do_delimiter(q, left_delimiter(q), cur_size, height(x) + depth(x) + clr + theta, false, cur_style, true, NULL, NULL, NULL);
2256  }
2257  /*tex
2258 
2259  Weird hack, in overbar we use small_fam(left_delimiter(q)) so actually
2260  small_fam(0).
2261 
2262  */
2263  left_delimiter(q) = null;
2264  delta = (depth(y) + height(y) - theta) - (height(x) + depth(x) + clr);
2265  if (delta > 0) {
2266  /*tex increase the actual clearance */
2267  clr = clr + half(delta);
2268  }
2269  shift_amount(y) = (height(y) - theta) - (height(x) + clr);
2270  h = depth(y) + height(y);
2271  p = overbar(x, clr, theta, radical_kern(cur_style), node_attr(y), math_radical_rule, cur_size, used_fam);
2273  couple_nodes(y,p);
2274  if (degree(q) != null) {
2275  scaled wr, br, ar;
2278  wr = width(r);
2279  if (wr == 0) {
2280  flush_node(r);
2281  } else {
2284  if (-ar > (wr + br))
2285  ar = -(wr + br);
2286  x = new_kern(ar);
2288  couple_nodes(x,y);
2289  shift_amount(r) =
2291  depth(y) - shift_amount(y));
2292  couple_nodes(r,x);
2293  x = new_kern(br);
2295  couple_nodes(x,r);
2296  y = x;
2297  }
2298  /*tex for \.{\\Uroot ..{<list>}{}} : */
2299  math_list(degree(q)) = null;
2300  flush_node(degree(q));
2301  }
2302  p = hpack(y, 0, additional, -1);
2304  math_list(nucleus(q)) = p;
2305  type(nucleus(q)) = sub_box_node;
2306 }
2307 
2308 /*tex Construct a vlist box: */
2309 
2311 {
2312  pointer p;
2313  pointer v = new_null_box();
2314  type(v) = vlist_node;
2315  subtype(v) = st;
2316  height(v) = shift_up + height(x);
2317  depth(v) = depth(y) + shift_down;
2319  p = new_kern((shift_up - depth(x)) - (height(y) - shift_down));
2321  couple_nodes(p,y);
2322  couple_nodes(x,p);
2323  list_ptr(v) = x;
2324  return v;
2325 }
2326 
2327 /*tex When |exact| use radicalwidth (|y| is delimiter). */
2328 
2329 #define fixup_widths(q,x,y) do { \
2330  if (width(y) >= width(x)) { \
2331  if (radicalwidth(q) != 0) { \
2332  shift_amount(x) += half(width(y)-width(x)) ; \
2333  } \
2334  width(x) = width(y); \
2335  } else { \
2336  if (radicalwidth(q) != 0) { \
2337  shift_amount(y) += half(width(x)-width(y)) ; \
2338  } \
2339  width(y) = width(x); \
2340  } \
2341 } while (0)
2342 
2343 
2344 #define check_radical(q,stack,r,t) do { \
2345  if (!stack && (width(r) >= width(t)) && (radicalwidth(q) != 0) && (radicalwidth(q) != width(r))) { \
2346  if (radicalleft(q)) { \
2347  halfword p = new_kern(radicalwidth(q)-width(r)); \
2348  reset_attributes(p, node_attr(q)); \
2349  couple_nodes(p,r); \
2350  r = hpack(p, 0, additional, -1); \
2351  width(r) = radicalwidth(q); \
2352  reset_attributes(r, node_attr(q)); \
2353  } else if (radicalmiddle(q)) { \
2354  halfword p = new_kern(half(radicalwidth(q)-width(r))); \
2355  reset_attributes(p, node_attr(q)); \
2356  couple_nodes(p,r); \
2357  r = hpack(p, 0, additional, -1); \
2358  width(r) = radicalwidth(q); \
2359  reset_attributes(r, node_attr(q)); \
2360  } else if (radicalright(q)) { \
2361  /*tex also kind of exact compared to vertical */ \
2362  r = hpack(r, 0, additional, -1); \
2363  width(r) = radicalwidth(q); \
2364  reset_attributes(r, node_attr(q)); \
2365  } \
2366  } \
2367 } while (0)
2368 
2369 #define check_widths(q,p) do { \
2370  if (radicalwidth(q) != 0) { \
2371  wd = radicalwidth(q); \
2372  } else { \
2373  wd = width(p); \
2374  } \
2375 } while (0)
2376 
2377 /*tex
2378 
2379  This has the |nucleus| box |x| as a limit above an extensible delimiter |y|.
2380 
2381 */
2382 
2384 {
2385  pointer x, y, v;
2386  scaled shift_up, shift_down, clr, delta, wd;
2387  boolean stack;
2389  check_widths(q,x);
2390  y = do_delimiter(q, left_delimiter(q), cur_size, wd, true, cur_style, true, &stack, NULL, NULL);
2391  left_delimiter(q) = null;
2392  check_radical(q,stack,y,x);
2393  fixup_widths(q, x, y);
2394  shift_up = over_delimiter_bgap(cur_style);
2395  shift_down = 0;
2397  delta = clr - ((shift_up - depth(x)) - (height(y) - shift_down));
2398  if (delta > 0) {
2399  shift_up = shift_up + delta;
2400  }
2401  v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down, math_over_delimiter_list);
2402  /*tex This also equals |width(y)|: */
2403  width(v) = width(x);
2404  math_list(nucleus(q)) = v;
2405  type(nucleus(q)) = sub_box_node;
2406 }
2407 
2408 /*tex
2409 
2410  This has the extensible delimiter |x| as a limit below |nucleus| box |y|.
2411 
2412 */
2413 
2415 {
2416  pointer x, y, v;
2417  scaled shift_up, shift_down, clr, delta, wd;
2418  boolean stack;
2420  check_widths(q,y);
2421  x = do_delimiter(q, left_delimiter(q), cur_size, wd, true, cur_style, true, &stack, NULL, NULL);
2422  left_delimiter(q) = null;
2423  check_radical(q,stack,x,y);
2424  fixup_widths(q, x, y);
2425  shift_up = 0;
2426  shift_down = under_delimiter_bgap(cur_style);
2428  delta = clr - ((shift_up - depth(x)) - (height(y) - shift_down));
2429  if (delta > 0) {
2430  shift_down = shift_down + delta;
2431  }
2432  v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down, math_under_delimiter_list);
2433  /*tex This also equals |width(y)|: */
2434  width(v) = width(y);
2435  math_list(nucleus(q)) = v;
2436  type(nucleus(q)) = sub_box_node;
2437 }
2438 
2439 /*tex
2440 
2441  This has the extensible delimiter |x| as a limit above |nucleus| box |y|.
2442 
2443 */
2444 
2446 {
2447  pointer x, y, v;
2448  scaled shift_up, shift_down, clr, actual, wd;
2449  boolean stack;
2451  check_widths(q,y);
2452  x = do_delimiter(q, left_delimiter(q), cur_size + (cur_size == script_script_size ? 0 : 1), wd, true, cur_style, true, &stack, NULL, NULL);
2453  left_delimiter(q) = null;
2454  check_radical(q,stack,x,y);
2455  fixup_widths(q, x, y);
2456  shift_up = over_delimiter_bgap(cur_style)-height(x)-depth(x);
2457  shift_down = 0;
2459  actual = shift_up - height(y);
2460  if (actual < clr) {
2461  shift_up = shift_up + (clr-actual);
2462  }
2463  v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down, math_over_delimiter_list);
2464  /*tex This also equals |width(y)|: */
2465  width(v) = width(x);
2466  math_list(nucleus(q)) = v;
2467  type(nucleus(q)) = sub_box_node;
2468 }
2469 
2470 /*tex
2471 
2472  This has the extensible delimiter |y| as a limit below a |nucleus| box |x|.
2473 
2474 */
2475 
2477 {
2478  pointer x, y, v;
2479  scaled shift_up, shift_down, clr, actual, wd;
2480  boolean stack;
2482  check_widths(q,x);
2483  y = do_delimiter(q, left_delimiter(q), cur_size + (cur_size == script_script_size ? 0 : 1), wd, true, cur_style, true, &stack, NULL, NULL);
2484  left_delimiter(q) = null;
2485  check_radical(q,stack,y,x);
2486  fixup_widths(q, x, y);
2487  shift_up = 0;
2488  shift_down = under_delimiter_bgap(cur_style) - height(y)-depth(y);
2490  actual = shift_down - depth(x);
2491  if (actual<clr) {
2492  shift_down += (clr-actual);
2493  }
2494  v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down, math_under_delimiter_list);
2495  /*tex This also equals |width(y)|: */
2496  width(v) = width(y);
2497  math_list(nucleus(q)) = v;
2498  type(nucleus(q)) = sub_box_node;
2499 }
2500 
2501 /*tex
2502 
2503  Slants are not considered when placing accents in math mode. The accenter is
2504  centered over the accentee, and the accent width is treated as zero with
2505  respect to the size of the final box.
2506 
2507 */
2508 
2509 #define TOP_CODE 1
2510 #define BOT_CODE 2
2511 #define OVERLAY_CODE 4
2512 #define STRETCH_ACCENT_CODE 8
2513 
2514 static boolean compute_accent_skew(pointer q, int flags, scaled *s)
2515 {
2516  /*tex temporary register for box construction */
2517  pointer p;
2518  /*tex will be true if a top-accent is placed in |s| */
2519  boolean s_is_absolute = false;
2520  if (type(nucleus(q)) == math_char_node) {
2521  fetch(nucleus(q));
2522  if (do_new_math(cur_f)) {
2523  /*tex
2524  There is no bot_accent so let's assume similarity
2525 
2526  \starttyping
2527  if (flags & (TOP_CODE | OVERLAY_CODE)) {
2528  *s = char_top_accent(cur_f, cur_c);
2529  if (*s != INT_MIN) {
2530  s_is_absolute = true;
2531  }
2532  } else {
2533  *s = char_bot_accent(cur_f, cur_c);
2534  if (*s != INT_MIN) {
2535  s_is_absolute = true;
2536  }
2537  }
2538  \stoptyping
2539  */
2541  if (*s != INT_MIN) {
2542  s_is_absolute = true;
2543  }
2544  } else {
2545  if (flags & TOP_CODE) {
2547  } else {
2548  *s = 0;
2549  }
2550  }
2551  } else if (type(nucleus(q)) == sub_mlist_node) {
2552  /*tex
2553  If |nucleus(q)| is a |sub_mlist_node| composed of an |accent_noad| we:
2554 
2555  \startitemize
2556  \startitem
2557  use the positioning of the nucleus of that noad, recursing until
2558  \stopitem
2559  \startitem
2560  the inner most |accent_noad|. This way multiple stacked accents
2561  are
2562  \stopitem
2563  \startitem
2564  aligned to the inner most one.
2565  \stopitem
2566  \stoptitemize
2567 
2568  The vlink test was added in version 1.06, so that we only consider a
2569  lone noad:
2570 
2571  $
2572  \Umathaccent bottom 0 0 "023DF { \Umathaccent fixed 0 0 "00302 { m } r } \quad
2573  \Umathaccent bottom 0 0 "023DF { l \Umathaccent fixed 0 0 "00302 { m } r } \quad
2574  \Umathaccent bottom 0 0 "023DF { l \Umathaccent fixed 0 0 "00302 { m } } \quad
2575  \Umathaccent bottom 0 0 "023DF { \Umathaccent fixed 0 0 "00302 { m } } \quad
2576  \Umathaccent bottom 0 0 "023DF { l r }
2577  $
2578 
2579  */
2580  p = math_list(nucleus(q));
2581  if (type(p) == accent_noad && vlink(p) == null) {
2582  s_is_absolute = compute_accent_skew(p, flags, s);
2583  }
2584  } else {
2585  }
2586 
2587  return s_is_absolute;
2588 }
2589 
2591 {
2592  /*tex temporary registers for box construction */
2593  pointer p, r, x, y;
2594  /*tex amount to skew the accent to the right */
2595  scaled s;
2596  /*tex height of character being accented */
2597  scaled h;
2598  /*tex space to remove between accent and accentee */
2599  scaled delta;
2600  /*tex width of the accentee, not including sub/superscripts */
2601  scaled w;
2602  /*tex will be true if a top-accent is placed in |s| */
2603  boolean s_is_absolute;
2604  scaled fraction ;
2605  scaled ic = 0;
2606  scaled target ;
2607  extinfo *ext;
2608  pointer attr_p;
2610  fraction = accentfraction(q);
2611  c = cur_c;
2612  f = cur_f;
2613  s = 1;
2614  if (fraction == 0) {
2615  fraction = 1000;
2616  }
2617  /*tex Compute the amount of skew, or set |s| to an alignment point */
2618  s_is_absolute = compute_accent_skew(q, flags, &s);
2620  w = width(x);
2621  h = height(x);
2622  if (do_new_math(cur_f) && !s_is_absolute) {
2623  s = half(w);
2624  s_is_absolute = true;
2625  }
2626  /*tex Switch to a larger accent if available and appropriate */
2627  y = null;
2628  ext = NULL;
2629  if (flags & OVERLAY_CODE) {
2630  if (fraction > 0) {
2631  target = xn_over_d(h,fraction,1000);
2632  } else {
2633  target = h;
2634  }
2635  } else {
2636  if (fraction > 0) {
2637  target = xn_over_d(w,fraction,1000);
2638  } else {
2639  target = w;
2640  }
2641  }
2642  if ((flags & STRETCH_ACCENT_CODE) && (char_width(f, c) < w)) {
2643  while (1) {
2644  if ((char_tag(f, c) == ext_tag) && ((ext = get_charinfo_hor_variants(char_info(f, c))) != NULL)) {
2645  /*tex a bit weird for an overlay but anyway, here we don't need a factor as we don't step */
2647  break;
2648  } else if (char_tag(f, c) != list_tag) {
2649  break;
2650  } else {
2651  int yy = char_remainder(f, c);
2652  if (!char_exists(f, yy)) {
2653  break;
2654  } else if (flags & OVERLAY_CODE) {
2655  if (char_height(f, yy) > target) {
2656  break;
2657  }
2658  } else {
2659  if (char_width(f, yy) > target)
2660  break;
2661  }
2662  c = yy;
2663  }
2664  }
2665  }
2666  if (y == null) {
2667  /*tex italic gets added to width */
2668  y = char_box(f, c, node_attr(attr_p));
2669  }
2670  if (flags & TOP_CODE) {
2671  if (h < accent_base_height(f)) {
2672  delta = h;
2673  } else {
2675  }
2676  } else if (flags & OVERLAY_CODE) {
2677  /*tex center the accent vertically around the accentee */
2678  delta = half(height(y) + depth(y) + height(x) + depth(x));
2679  } else {
2680  delta = 0; /* hm */
2681  }
2682  if ((supscr(q) != null) || (subscr(q) != null)) {
2683  if (type(nucleus(q)) == math_char_node) {
2684  /*tex swap the subscript and superscript into box |x| */
2685  flush_node_list(x);
2686  x = new_noad();
2687  r = math_clone(nucleus(q));
2688  nucleus(x) = r;
2689  supscr(x) = supscr(q);
2690  supscr(q) = null;
2691  subscr(x) = subscr(q);
2692  subscr(q) = null;
2694  math_list(nucleus(q)) = x;
2696  delta = delta + height(x) - h;
2697  h = height(x);
2698  }
2699  } else if ((vlink(q) != null) && (type(nucleus(q)) == math_char_node)) {
2700  /*tex only pure math char nodes */
2702  if (do_new_math(f)) {
2704  }
2705  }
2706  /*tex the top accents of both characters are aligned */
2707  if (s_is_absolute) {
2708  scaled sa;
2709  if (ext != NULL) {
2710  /*tex if the accent is extensible just take the center */
2711  sa = half(width(y));
2712  } else {
2713  /*tex
2714  There is no bot_accent so let's assume similarity
2715 
2716  \starttyping
2717  if (flags & BOT_CODE) {
2718  sa = char_bot_accent(f, c);
2719  } else {
2720  sa = char_top_accent(f, c);
2721  }
2722  \stoptyping
2723  */
2724  sa = char_top_accent(f, c);
2725  }
2726  if (sa == INT_MIN) {
2727  /*tex just take the center */
2728  sa = half(width(y));
2729  }
2730  if (math_direction_par == dir_TRT) {
2731  shift_amount(y) = s + sa - width(y);
2732  } else {
2733  shift_amount(y) = s - sa;
2734  }
2735  } else {
2736  if (width(y)== 0) {
2737  shift_amount(y) = s + w;
2738  } else if (math_direction_par == dir_TRT) {
2739  shift_amount(y) = s + width(y); /* ok? */
2740  } else {
2741  shift_amount(y) = s + half(w - width(y));
2742  }
2743  }
2744  width(y) = 0;
2745  if (flags & (TOP_CODE | OVERLAY_CODE)) {
2746  p = new_kern(-delta);
2748  couple_nodes(p,x);
2749  couple_nodes(y,p);
2750  } else {
2751  couple_nodes(x,y);
2752  y = x;
2753  }
2757  width(r) = width(x);
2758  y = r;
2759  if (flags & (TOP_CODE | OVERLAY_CODE)) {
2760  if (height(y) < h) {
2761  /*tex make the height of box |y| equal to |h| */
2762  p = new_kern(h - height(y));
2765  list_ptr(y) = p;
2766  height(y) = h;
2767  }
2768  } else {
2769  shift_amount(y) = -(h - height(y));
2770  }
2771  if (ic != 0) {
2772  /*tex old font codepath has ic built in, new font code doesn't */
2773  width(r) += ic ;
2774  }
2775  math_list(nucleus(q)) = y;
2776  type(nucleus(q)) = sub_box_node;
2777 }
2778 
2780 {
2781  int topstretch = !(subtype(q) % 2);
2782  int botstretch = !(subtype(q) / 2);
2783 
2784  if (top_accent_chr(q) != null) {
2786  if (char_exists(cur_f, cur_c)) {
2788  }
2790  top_accent_chr(q) = null;
2791  }
2792  if (bot_accent_chr(q) != null) {
2794  if (char_exists(cur_f, cur_c)) {
2796  }
2798  bot_accent_chr(q) = null;
2799  }
2800  if (overlay_accent_chr(q) != null) {
2802  if (char_exists(cur_f, cur_c)) {
2804  }
2806  overlay_accent_chr(q) = null;
2807  }
2808 }
2809 
2810 /*tex
2811 
2812  The |make_fraction| procedure is a bit different because it sets
2813  |new_hlist(q)| directly rather than making a sub-box.
2814 
2815 */
2816 
2818 {
2819  pointer p, p1, p2, v, x, y, z, l, r, m;
2820  scaled delta, delta1, delta2, shift_up, shift_down, clr1, clr2, f, t;\
2821  /*tex
2822 
2823  We can take the rule width from an explicitly set fam, even if a fraction
2824  itself has no character, otherwise we just use the math parameter.
2825 
2826  */
2827  scaled used_fam = math_rules_fam_par;
2828  if (math_rule_thickness_mode_par > 0 && thickness(q) != 0) {
2829  f = fraction_fam(q);
2830  if (f >= 0) {
2831  t = fam_fnt(f,cur_size);
2832  if (do_new_math(t)) {
2834  if (t != undefined_math_parameter) {
2835  thickness(q) = t;
2836  used_fam = f;
2837  }
2838  }
2839  }
2840  }
2841  if (thickness(q) == default_code)
2843  /*tex
2844 
2845  Create equal-width boxes |x| and |z| for the numerator and denominator,
2846  and compute the default amounts |shift_up| and |shift_down| by which they
2847  are displaced from the baseline.
2848 
2849  */
2852  if (middle_delimiter(q) != null) {
2853  delta = 0;
2855  middle_delimiter(q) = null;
2856  } else {
2857  m = null ;
2858  if (width(x) < width(z)) {
2859  x = rebox(x, width(z));
2860  } else {
2861  z = rebox(z, width(x));
2862  }
2863  }
2864  if (m != null) {
2865  shift_up = 0;
2866  shift_down = 0;
2867  } else if (thickness(q) == 0) {
2868  shift_up = stack_num_up(cur_style);
2869  shift_down = stack_denom_down(cur_style);
2870  /*tex
2871 
2872  The numerator and denominator must be separated by a certain minimum
2873  clearance, called |clr| in the following program. The difference
2874  between |clr| and the actual clearance is |2delta|.
2875 
2876  */
2877  clr1 = stack_vgap(cur_style);
2878  delta = half(clr1 - ((shift_up - depth(x)) - (height(z) - shift_down)));
2879  if (delta > 0) {
2880  shift_up = shift_up + delta;
2881  shift_down = shift_down + delta;
2882  }
2883  } else {
2884  shift_up = fraction_num_up(cur_style);
2885  shift_down = fraction_denom_down(cur_style);
2886  /*tex
2887 
2888  In the case of a fraction line, the minimum clearance depends on the
2889  actual thickness of the line.
2890 
2891  */
2892  clr1 = fraction_num_vgap(cur_style);
2894  delta = half(thickness(q));
2895  if (fractionexact(q)) {
2896  delta1 = clr1 - ((shift_up - depth(x) ) - (math_axis_size(cur_size) + delta));
2897  delta2 = clr2 - ((shift_down - height(z)) + (math_axis_size(cur_size) - delta));
2898  } else {
2899  clr1 = ext_xn_over_d(clr1, thickness(q), fraction_rule(cur_style));
2900  clr2 = ext_xn_over_d(clr2, thickness(q), fraction_rule(cur_style));
2901  delta1 = clr1 - ((shift_up - depth(x) ) - (math_axis_size(cur_size) + delta));
2902  delta2 = clr2 - ((shift_down - height(z)) + (math_axis_size(cur_size) - delta));
2903  }
2904  if (delta1 > 0) {
2905  shift_up = shift_up + delta1;
2906  }
2907  if (delta2 > 0) {
2908  shift_down = shift_down + delta2;
2909  }
2910  }
2911  if (m != null) {
2912  /*tex
2913 
2914  Construct a hlist box for the fraction, according to |hgap| and
2915  |vgap|.
2916 
2917  */
2918  shift_up = skewed_fraction_vgap(cur_style);
2919 
2920  if (!fractionnoaxis(q)) {
2921  shift_up += half(math_axis_size(cur_size));
2922  }
2923  shift_down = shift_up;
2924  v = new_null_box();
2926  type(v) = hlist_node;
2928  list_ptr(v) = x;
2929  width(v) = width(x);
2930  height(v) = height(x) + shift_up;
2931  depth(v) = depth(x);
2932  shift_amount(v) = - shift_up;
2933  x = v;
2934  v = new_null_box();
2936  type(v) = hlist_node;
2938  list_ptr(v) = z;
2939  width(v) = width(z);
2940  height(v) = height(z);
2941  depth(v) = depth(z) + shift_down;
2942  shift_amount(v) = shift_down;
2943  z = v;
2944  v = new_null_box();
2947  type(v) = hlist_node;
2948  if (height(x) > height(z)) {
2949  height(v) = height(x);
2950  } else {
2951  height(v) = height(z);
2952  }
2953  if (depth(x) > depth(z)) {
2954  depth(v) = depth(x);
2955  } else {
2956  depth(v) = depth(z);
2957  }
2958  if (height(m) > height(v)) {
2959  height(v) = height(m);
2960  }
2961  if (depth(m) > depth(v)) {
2962  depth(v) = depth(m);
2963  }
2964  if (fractionexact(q)) {
2965  delta1 = -half(skewed_fraction_hgap(cur_style));
2966  delta2 = delta1;
2968  } else {
2972  width(m) = 0;
2973  }
2974  p1 = new_kern(delta1);
2976  p2 = new_kern(delta2);
2978  couple_nodes(x,p1);
2979  couple_nodes(p1,m);
2980  couple_nodes(m,p2);
2981  couple_nodes(p2,z);
2982  list_ptr(v) = x;
2983  } else {
2984  /*tex
2985 
2986  Construct a vlist box for the fraction, according to |shift_up| and
2987  |shift_down|.
2988 
2989  */
2990  v = new_null_box();
2991  type(v) = vlist_node;
2993  height(v) = shift_up + height(x);
2994  depth(v) = depth(z) + shift_down;
2995  /*tex This also equals |width(z)|. */
2996  width(v) = width(x);
2998  if (thickness(q) && ! fractionnorule(q)) {
3000  p = new_kern((math_axis_size(cur_size) - delta) - (height(z) - shift_down));
3002  couple_nodes(y,p);
3003  couple_nodes(p,z);
3004  p = new_kern((shift_up - depth(x)) - (math_axis_size(cur_size) + delta));
3005  couple_nodes(p,y);
3006  } else {
3007  p = new_kern((shift_up - depth(x)) - (height(z) - shift_down));
3008  couple_nodes(p,z);
3009  }
3011  couple_nodes(x,p);
3012  list_ptr(v) = x;
3013  }
3014  /*tex
3015 
3016  Put the fraction into a box with its delimiters, and make |new_hlist(q)|
3017  point to it.
3018 
3019  */
3020  if (do_new_math(cur_f)) {
3023  delta = get_delimiter_height(depth(v), height(v), true);
3024  }
3025  } else {
3027  }
3028  l = do_delimiter(q, left_delimiter(q), cur_size, delta, false, cur_style, true, NULL, NULL, NULL);
3029  left_delimiter(q) = null;
3030  r = do_delimiter(q, right_delimiter(q), cur_size, delta, false, cur_style, true, NULL, NULL, NULL);
3031  right_delimiter(q) = null;
3032  couple_nodes(l,v);
3033  couple_nodes(v,r);
3034  y = hpack(l, 0, additional, -1);
3036  /*tex There can also be a nested one: */
3038  assign_new_hlist(q, y);
3039 }
3040 
3041 /*tex
3042 
3043  If the nucleus of an |op_noad| is a single character, it is to be centered
3044  vertically with respect to the axis, after first being enlarged (via a
3045  character list in the font) if we are in display style. The normal convention
3046  for placing displayed limits is to put them above and below the operator in
3047  display style.
3048 
3049  The italic correction is removed from the character if there is a subscript
3050  and the limits are not being displayed. The |make_op| routine returns the
3051  value that should be used as an offset between subscript and superscript.
3052 
3053  After |make_op| has acted, |subtype(q)| will be |limits| if and only if the
3054  limits have been set above and below the operator. In that case,
3055  |new_hlist(q)| will already contain the desired final box.
3056 
3057 */
3058 
3059 static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled supshift, scaled subshift);
3061 
3063 {
3064  /*tex offset between subscript and superscript */
3065  scaled delta = 0;
3066  scaled dummy = 0;
3067  /*tex temporary registers for box construction */
3068  pointer p, v, x, y, z, n;
3069  /*tex register for character examination */
3070  int c;
3071  /*tex dimensions for box calculation */
3072  scaled shift_up, shift_down;
3073  boolean axis_shift = false;
3074  scaled ok_size;
3075  if ((subtype(q) == op_noad_type_normal) && (cur_style < text_style)) {
3077  }
3078  if (type(nucleus(q)) == math_char_node) {
3079  fetch(nucleus(q));
3080  if (cur_style < text_style) {
3081  /*tex try to make it larger */
3082  ok_size = minimum_operator_size(cur_style);
3083  if (ok_size != undefined_math_parameter) {
3084  /*tex creating a temporary delimiter is the cleanest way */
3085  y = new_node(delim_node, 0);
3087  small_fam(y) = math_fam(nucleus(q));
3089  x = do_delimiter(q, y, text_size, ok_size, false, cur_style, true, NULL, &delta, NULL);
3090  if (delta != 0) {
3091  if (do_new_math(cur_f)) {
3092  /*tex
3093  As we never added italic correction we don't need to compensate. The ic
3094  is stored in a special field of the node and applied in some occasions.
3095  */
3096  } else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
3097  /*tex
3098  Here we (selectively) remove the italic correction that always gets added
3099  in a traditional font. See (**). In \OPENTYPE\ mode we insert italic kerns,
3100  but in traditional mode it's width manipulation. This actually makes sense
3101  because those fonts have a fake width and the italic correction sets that
3102  right.
3103  */
3104  width(x) -= delta;
3105  }
3106  }
3107  } else {
3108  ok_size = height_plus_depth(cur_f, cur_c) + 1;
3109  while ((char_tag(cur_f, cur_c) == list_tag) && height_plus_depth(cur_f, cur_c) < ok_size) {
3111  if (!char_exists(cur_f, c))
3112  break;
3113  cur_c = c;
3114  math_character(nucleus(q)) = c;
3115  }
3118  if (delta != 0) {
3119  if (do_new_math(cur_f)) {
3120  /*tex we never added italic correction */
3121  } else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
3122  /*tex remove italic correction */
3123  width(x) -= delta;
3124  }
3125  }
3126  axis_shift = true;
3127  }
3128  } else {
3129  /*tex normal size */
3132  if (delta != 0) {
3133  if (do_new_math(cur_f)) {
3134  /*tex we never added italic correction */
3135  } else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
3136  /*tex remove italic correction */
3137  width(x) -= delta;
3138  }
3139  }
3140  axis_shift = true;
3141  }
3142  if (axis_shift) {
3143  /*tex center vertically */
3145  }
3146  type(nucleus(q)) = sub_box_node;
3147  math_list(nucleus(q)) = x;
3148  }
3149  /*tex we now handle op_nod_type_no_limits here too */
3150  if (subtype(q) == op_noad_type_no_limits) {
3151  if (do_new_math(cur_f)) {
3152  /*tex
3153  Not:
3154 
3155  \starttyping
3156  if (delta != 0) {
3157  delta = half(delta) ;
3158  }
3159  \stoptyping
3160  */
3162  if ((subscr(q) == null) && (supscr(q) == null)) {
3163  assign_new_hlist(q, p);
3164  } else {
3165  /*tex
3166  Not:
3167 
3168  \starttyping
3169  make_scripts(q, p, 0, cur_style, delta, -delta);
3170  \stoptyping
3171  */
3172  int mode = math_nolimits_mode_par; /* wins */
3173  /*tex
3174 
3175  For easy configuration ... fonts are somewhat inconsistent
3176  and the values for italic correction run from 30 to 60\% of.
3177  the width.
3178 
3179  */
3180  switch (mode) {
3181  case 0 :
3182  /*tex full bottom correction */
3183  make_scripts(q, p, 0, cur_style, 0, -delta);
3184  break;
3185  case 1 :
3186  /*tex |MathConstants| driven */
3187  make_scripts(q, p, 0, cur_style,
3190  break ;
3191  case 2 :
3192  /*tex no correction */
3193  make_scripts(q, p, 0, cur_style, 0, 0);
3194  break ;
3195  case 3 :
3196  /*tex half bottom correction */
3197  make_scripts(q, p, 0, cur_style, 0, -half(delta));
3198  break;
3199  case 4 :
3200  /*tex half bottom and top correction */
3202  break;
3203  default :
3204  if (mode > 15) {
3205  /*tex for quickly testing values */
3206  make_scripts(q, p, 0, cur_style, 0, -round_xn_over_d(delta, mode, 1000));
3207  } else {
3208  make_scripts(q, p, 0, cur_style, 0, 0);
3209  }
3210  break;
3211  }
3212  }
3213  delta = 0;
3214  } else {
3215  /*tex similar code then the caller (before CHECK_DIMENSIONS) */
3217  if ((subscr(q) == null) && (supscr(q) == null)) {
3218  assign_new_hlist(q, p);
3219  } else {
3220  make_scripts(q, p, delta, cur_style, 0, 0);
3221  }
3222  }
3223  } else if (subtype(q) == op_noad_type_limits) {
3224  /*tex
3225 
3226  The following program builds a vlist box |v| for displayed limits.
3227  The width of the box is not affected by the fact that the limits may
3228  be skewed.
3229 
3230  */
3234  v = new_null_box();
3236  type(v) = vlist_node;
3238  if (do_new_math(cur_f)) {
3239  n = nucleus(q);
3240  if (n != null) {
3241  if ((type(n) == sub_mlist_node) || (type(n) == sub_box_node)) {
3242  n = math_list(n);
3243  if (n != null) {
3244  if (type(n) == hlist_node) {
3245  /*tex just a not scaled char */
3246  n = list_ptr(n);
3247  while (n != null) {
3248  if (type(n) == glyph_node) {
3250  }
3251  n = vlink(n);
3252  }
3253  } else {
3254  while (n != null) {
3255  if (type(n) == fence_noad) {
3256  if (delimiteritalic(n) > delta) {
3257  /*tex we can have dummies, the period ones */
3258  delta = delimiteritalic(n);
3259  }
3260  }
3261  n = vlink(n);
3262  }
3263  }
3264  }
3265  } else {
3266  n = nucleus(q);
3267  if (type(n) == math_char_node) {
3269  }
3270  }
3271  }
3272  }
3273  width(v) = width(y);
3274  if (width(x) > width(v))
3275  width(v) = width(x);
3276  if (width(z) > width(v))
3277  width(v) = width(z);
3278  x = rebox(x, width(v));
3279  y = rebox(y, width(v));
3280  z = rebox(z, width(v));
3281  shift_amount(x) = half(delta);
3283  /*tex v is the still empty target */
3284  height(v) = height(y);
3285  depth(v) = depth(y);
3286  /*tex
3287 
3288  Attach the limits to |y| and adjust |height(v)|, |depth(v)| to
3289  account for their presence.
3290 
3291  We use |shift_up| and |shift_down| in the following program for the
3292  amount of glue between the displayed operator |y| and its limits |x|
3293  and |z|.
3294 
3295  The vlist inside box |v| will consist of |x| followed by |y| followed
3296  by |z|, with kern nodes for the spaces between and around them;
3297  |b| is baseline and |v| is the minumum gap.
3298 
3299  */
3300  if (supscr(q) == null) {
3301  list_ptr(x) = null;
3302  flush_node(x);
3303  list_ptr(v) = y;
3304  } else {
3305  shift_up = limit_above_bgap(cur_style) - depth(x);
3306  if (shift_up < limit_above_vgap(cur_style))
3307  shift_up = limit_above_vgap(cur_style);
3308  p = new_kern(shift_up);
3310  couple_nodes(p,y);
3311  couple_nodes(x,p);
3314  couple_nodes(p,x);
3315  list_ptr(v) = p;
3316  height(v) = height(v) + limit_above_kern(cur_style) + height(x) + depth(x) + shift_up;
3317  }
3318  if (subscr(q) == null) {
3319  list_ptr(z) = null;
3320  flush_node(z);
3321  } else {
3322  shift_down = limit_below_bgap(cur_style) - height(z);
3323  if (shift_down < limit_below_vgap(cur_style))
3324  shift_down = limit_below_vgap(cur_style);
3325  p = new_kern(shift_down);
3327  couple_nodes(y,p);
3328  couple_nodes(p,z);
3331  couple_nodes(z,p);
3332  depth(v) = depth(v) + limit_below_kern(cur_style) + height(z) + depth(z) + shift_down;
3333  }
3334  if (subscr(q) != null) {
3335  math_list(subscr(q)) = null;
3336  flush_node(subscr(q));
3337  subscr(q) = null;
3338  }
3339  if (supscr(q) != null) {
3340  math_list(supscr(q)) = null;
3341  flush_node(supscr(q));
3342  supscr(q) = null;
3343  }
3344  assign_new_hlist(q, v);
3345  if (do_new_math(cur_f)) {
3346  delta = 0;
3347  }
3348  }
3349  return delta;
3350 }
3351 
3352 /*tex
3353 
3354  A ligature found in a math formula does not create a ligature, because there
3355  is no question of hyphenation afterwards; the ligature will simply be stored
3356  in an ordinary |glyph_node|, after residing in an |ord_noad|.
3357 
3358  The |type| is converted to |math_text_char| here if we would not want to
3359  apply an italic correction to the current character unless it belongs to a
3360  math font (i.e., a font with |space=0|).
3361 
3362  No boundary characters enter into these ligatures.
3363 
3364 */
3365 
3366 #define simple_char_noad(p) (\
3367  (p != null) && \
3368  (type(p) == simple_noad) && \
3369  (subtype(p) <= punct_noad_type) && \
3370  (type(nucleus(p)) == math_char_node) \
3371 )
3372 
3373 #define same_nucleus_fam(p,q) \
3374  (math_fam(nucleus(p)) == math_fam(nucleus(q)))
3375 
3376 static void make_ord(pointer q)
3377 {
3378  /*tex the left-side character for lig/kern testing */
3379  int a;
3380  /*tex temporary registers for list manipulation */
3381  pointer p, r, s;
3382  /*tex a kern */
3383  scaled k;
3384  /*tex a ligature */
3385  liginfo lig;
3386  RESTART:
3387  if (subscr(q) == null && supscr(q) == null && type(nucleus(q)) == math_char_node) {
3388  p = vlink(q);
3389  if (simple_char_noad(p) && same_nucleus_fam(p,q)) {
3391  fetch(nucleus(q));
3392  a = cur_c;
3393  /*tex add italic correction */
3396  subtype(p) = italic_kern;
3398  couple_nodes(p,vlink(q));
3399  couple_nodes(q,p);
3400  return;
3401  }
3402  /*tex construct ligatures, quite unlikely in new math fonts */
3403  if ((has_kern(cur_f, a)) || (has_lig(cur_f, a))) {
3405  /*tex
3406 
3407  If character |a| has a kern with |cur_c|, attach the kern
3408  after~|q|; or if it has a ligature with |cur_c|, combine
3409  noads |q| and~|p| appropriately; then |return| if the cursor
3410  has moved past a noad, or |goto restart|.
3411 
3412  Note that a ligature between an |ord_noad| and another kind
3413  of noad is replaced by an |ord_noad|, when the two noads
3414  collapse into one.
3415 
3416  We could make a parenthesis (say) change shape when it
3417  follows certain letters. Presumably a font designer will
3418  define such ligatures only when this convention makes sense.
3419 
3420  */
3421  if (disable_lig_par == 0 && has_lig(cur_f, a)) {
3422  lig = get_ligature(cur_f, a, cur_c);
3423  if (is_valid_ligature(lig)) {
3424  /*tex allow a way out of infinite ligature loop */
3425  check_interrupt();
3426  switch (lig_type(lig)) {
3427  case 1:
3428  /*tex \.{=:\char`\|} */
3429  case 5:
3430  /*tex \.{=:\char`\|>} */
3432  break;
3433  case 2:
3434  /*tex \.{\char`\|=:} */
3435  case 6:
3436  /*tex \.{\char`\|=:>} */
3438  break;
3439  case 3:
3440  /*tex \.{\char`\|=:\char`\|} */
3441  case 7:
3442  /*tex \.{\char`\|=:\char`\|>} */
3443  case 11:
3444  /*tex \.{\char`\|=:\char`\|>>} */
3445  r = new_noad();
3447  s = new_node(math_char_node, 0);
3449  nucleus(r) = s;
3452  couple_nodes(q,r);
3453  couple_nodes(r,p);
3454  if (lig_type(lig) < 11) {
3456  } else {
3457  /*tex prevent combination */
3459  }
3460  break;
3461  default:
3463  math_character(nucleus(q)) = lig_replacement(lig); /* \.{=:} */
3464  subscr(q) = subscr(p);
3465  supscr(q) = supscr(p);
3466  subscr(p) = null ;
3467  supscr(p) = null ;
3468  flush_node(p);
3469  break;
3470  }
3471  if (lig_type(lig) > 3)
3472  return;
3474  goto RESTART;
3475  }
3476  }
3477  if (disable_kern_par == 0 && has_kern(cur_f, a)) {
3478  /*tex todo: should this use mathkerns? */
3479  k = get_kern(cur_f, a, cur_c);
3480  if (k != 0) {
3481  p = new_kern(k);
3483  couple_nodes(p,vlink(q));
3484  couple_nodes(q,p);
3485  return;
3486  }
3487  }
3488  }
3489  }
3490  }
3491 }
3492 
3493 /*tex
3494 
3495  If the fonts for the left and right bits of a mathkern are not both new-style
3496  fonts, then return a sentinel value meaning: please use old-style italic
3497  correction placement
3498 
3499 */
3500 
3501 #define MATH_KERN_NOT_FOUND 0x7FFFFFFF
3502 
3503 /*tex
3504 
3505  This function tries to find the kern needed for proper cut-ins. The left side
3506  doesn't move, but the right side does, so the first order of business is to
3507  create a staggered fence line on the left side of the right character.
3508 
3509  The microsoft spec says that there are four quadrants, but the actual images
3510  say.
3511 
3512 */
3513 
3514 static scaled math_kern_at(internal_font_number f, int c, int side, int v)
3515 {
3516  int h, k, numkerns;
3517  scaled *kerns_heights;
3518  scaled kern = 0;
3519  /*tex Known to exist: */
3520  charinfo *co = char_info(f, c);
3521  numkerns = get_charinfo_math_kerns(co, side);
3522  if (numkerns == 0)
3523  return kern;
3524  if (side == top_left_kern) {
3525  kerns_heights = co->top_left_math_kern_array;
3526  } else if (side == bottom_left_kern) {
3527  kerns_heights = co->bottom_left_math_kern_array;
3528  } else if (side == top_right_kern) {
3529  kerns_heights = co->top_right_math_kern_array;
3530  } else if (side == bottom_right_kern) {
3531  kerns_heights = co->bottom_right_math_kern_array;
3532  } else {
3533  /*tex Not reached: */
3534  confusion("math_kern_at");
3535  kerns_heights = NULL;
3536  }
3537  if (v < kerns_heights[0])
3538  return kerns_heights[1];
3539  for (k = 0; k < numkerns; k++) {
3540  h = kerns_heights[(k * 2)];
3541  kern = kerns_heights[(k * 2) + 1];
3542  if (h > v) {
3543  return kern;
3544  }
3545  }
3546  return kern;
3547 }
3548 
3550 {
3551  scaled corr_height_top = 0, corr_height_bot = 0;
3552  scaled krn_l = 0, krn_r = 0, krn = 0;
3553  if ((!do_new_math(l_f)) || (!do_new_math(r_f)) || (!char_exists(l_f,l_c)) || (!char_exists(r_f,r_c)))
3554  return MATH_KERN_NOT_FOUND;
3555  if (cmd == sup_mark_cmd) {
3556  corr_height_top = char_height(l_f, l_c);
3557  /*tex bottom of superscript */
3558  corr_height_bot = -char_depth(r_f, r_c) + shift;
3559  krn_l = math_kern_at(l_f, l_c, top_right_kern, corr_height_top);
3560  krn_r = math_kern_at(r_f, r_c, bottom_left_kern, corr_height_top);
3561  krn = (krn_l + krn_r);
3562  krn_l = math_kern_at(l_f, l_c, top_right_kern, corr_height_bot);
3563  krn_r = math_kern_at(r_f, r_c, bottom_left_kern, corr_height_bot);
3564  if ((krn_l + krn_r) < krn)
3565  krn = (krn_l + krn_r);
3566  return (krn);
3567  } else if (cmd == sub_mark_cmd) {
3568  /*tex top of subscript */
3569  corr_height_top = char_height(r_f, r_c) - shift;
3570  corr_height_bot = -char_depth(l_f, l_c);
3571  krn_l = math_kern_at(l_f, l_c, bottom_right_kern, corr_height_top);
3572  krn_r = math_kern_at(r_f, r_c, top_left_kern, corr_height_top);
3573  krn = (krn_l + krn_r);
3574  krn_l = math_kern_at(l_f, l_c, bottom_right_kern, corr_height_bot);
3575  krn_r = math_kern_at(r_f, r_c, top_left_kern, corr_height_bot);
3576  if ((krn_l + krn_r) < krn)
3577  krn = (krn_l + krn_r);
3578  return (krn);
3579  } else {
3580  confusion("find_math_kern");
3581  }
3582  /*tex Not reached: */
3583  return 0;
3584 }
3585 
3586 /*tex Just a small helper: */
3587 
3589 {
3590  pointer y;
3591  pointer z = new_kern(delta2);
3592  if (subtyp != 0) {
3593  subtype(z) = subtyp;
3594  }
3596  if (new_hlist(q) == null) {
3597  /*tex this is somewhat weird */
3598  new_hlist(q) = z;
3599  } else {
3600  y = new_hlist(q);
3601  while (vlink(y) != null)
3602  y = vlink(y);
3603  couple_nodes(y,z);
3604  }
3605  return new_hlist(q);
3606 }
3607 
3608 /*tex
3609 
3610  The purpose of |make_scripts(q,it)| is to attach the subscript and/or
3611  superscript of noad |q| to the list that starts at |new_hlist(q)|, given that
3612  subscript and superscript aren't both empty. The superscript will be
3613  horizontally shifted over |delta1|, the subscript over |delta2|.
3614 
3615  We set |shift_down| and |shift_up| to the minimum amounts to shift the
3616  baseline of subscripts and superscripts based on the given nucleus.
3617 
3618  Note: We need to look at a character but also at the first one in a sub list
3619  and there we ignore leading kerns and glue. Elsewhere is code that removes
3620  kerns assuming that is italic correction. The heuristics are unreliable for
3621  the new fonts so eventualy there will be an option to ignore such
3622  corrections.
3623 
3624 */
3625 
3626 #define analyze_script(init,su_n,su_f,su_c) do { \
3627  su_n = init; \
3628  if (su_n != null) { \
3629  if (math_script_char_mode_par > 0 && type(su_n) == math_char_node) { \
3630  fetch(su_n); \
3631  if (char_exists(cur_f, cur_c)) { \
3632  su_f = cur_f; \
3633  su_c = cur_c; \
3634  } else { \
3635  su_n = null; \
3636  } \
3637  } else if (math_script_box_mode_par > 0 && type(su_n) == sub_mlist_node) { \
3638  su_n = math_list(su_n); \
3639  while (su_n != null) { \
3640  if ((type(su_n) == kern_node) || (type(su_n) == glue_node)) { \
3641  su_n = vlink(su_n); \
3642  } else if (type(su_n) == simple_noad) { \
3643  su_n = nucleus(su_n); \
3644  if (type(su_n) == math_char_node) { \
3645  fetch(su_n); \
3646  if (char_exists(cur_f, cur_c)) { \
3647  su_f = cur_f; \
3648  su_c = cur_c; \
3649  } else { \
3650  su_n = null; \
3651  } \
3652  } else { \
3653  su_n = null; \
3654  } \
3655  break; \
3656  } else { \
3657  su_n = null; \
3658  break; \
3659  } \
3660  } \
3661  } else if (type(su_n) == sub_box_node) { \
3662  su_n = math_list(su_n); \
3663  if (su_n != null) { \
3664  if (type(su_n) == hlist_node) { \
3665  su_n = list_ptr(su_n); \
3666  } \
3667  if (su_n != null) { \
3668  if (math_script_box_mode_par == 2) { \
3669  while (su_n != null) { \
3670  if ((type(su_n) == kern_node) || (type(su_n) == glue_node)) { \
3671  su_n = vlink(su_n); \
3672  } else if (type(su_n) == glyph_node) { \
3673  if (char_exists(font(su_n), character(su_n))) { \
3674  su_f = font(su_n); \
3675  su_c = character(su_n); \
3676  } else { \
3677  su_n = null; \
3678  } \
3679  break ; \
3680  } else { \
3681  su_n = null; \
3682  break; \
3683  } \
3684  } \
3685  } else if (math_script_box_mode_par == 3) { \
3686  int boundary = -1; \
3687  while (su_n != null) { \
3688  if ((type(su_n) == boundary_node) && (subtype(su_n) == user_boundary)) { \
3689  boundary = boundary_value(su_n); \
3690  su_n = vlink(su_n); \
3691  } else if ((type(su_n) == kern_node) || (type(su_n) == glue_node)) { \
3692  su_n = vlink(su_n); \
3693  } else if ((boundary > -1) && (type(su_n) == glyph_node)) { \
3694  if (char_exists(font(su_n), character(su_n))) { \
3695  su_f = font(su_n); \
3696  su_c = character(su_n); \
3697  } else { \
3698  su_n = null; \
3699  } \
3700  break ; \
3701  } else { \
3702  su_n = null; \
3703  break; \
3704  } \
3705  } \
3706  } \
3707  } \
3708  } else { \
3709  su_n = null; \
3710  } \
3711  } else { \
3712  su_n = null; \
3713  } \
3714  } \
3715  } while (0) \
3716 
3717 #define x_su_style(n,cur_style,su_style) \
3718  (noadoptionnosubscript(n) ? cur_style : su_style(cur_style))
3719 
3720 static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled supshift, scaled subshift)
3721 {
3722  pointer x, y, z;
3723  scaled shift_up, shift_down, clr;
3724  scaled delta1, delta2;
3725  halfword sub_n, sup_n, subtyp;
3726  internal_font_number sub_f, sup_f;
3727  int sub_c, sup_c;
3728  sub_n = null;
3729  sup_n = null;
3730  sub_f = 0;
3731  sup_f = 0;
3732  sub_c = 0;
3733  sup_c = 0;
3734  delta1 = it;
3735  delta2 = 0;
3736  subtyp = 0;
3737  switch (type(nucleus(q))) {
3738  case math_char_node:
3739  case math_text_char_node:
3740  if ((subscr(q) == null) && (delta1 != 0)) {
3741  /*tex todo: selective italic correction */
3742  x = new_kern(delta1);
3743  subtype(x) = italic_kern;
3745  couple_nodes(p,x);
3746  delta1 = 0;
3747  }
3748  }
3749  assign_new_hlist(q, p);
3750  if (is_char_node(p)) {
3751  shift_up = 0;
3752  shift_down = 0;
3753  } else {
3754  z = hpack(p, 0, additional, -1);
3755  shift_up = height(z) - sup_shift_drop(cur_style); /* r18 */
3756  shift_down = depth(z) + sub_shift_drop(cur_style); /* r19 */
3757  list_ptr(z) = null;
3758  flush_node(z);
3759  }
3760  if (is_char_node(p)) {
3761  /*tex We look at the subscript character (_i) or first character in a list (_{ij}). */
3762  analyze_script(subscr(q),sub_n,sub_f,sub_c);
3763  /*tex We look at the superscript character (^i) or first character in a list (^{ij}). */
3764  analyze_script(supscr(q),sup_n,sup_f,sup_c);
3765  }
3766  if (supscr(q) == null) {
3767  /*tex
3768 
3769  Construct a subscript box |x| when there is no superscript. When
3770  there is a subscript without a superscript, the top of the subscript
3771  should not exceed the baseline plus four-fifths of the x-height.
3772 
3773  */
3776  switch (math_scripts_mode_par) {
3777  case 1:
3778  shift_down = sub_shift_down(cur_style) ;
3779  break;
3780  case 2:
3781  shift_down = sub_sup_shift_down(cur_style) ;
3782  break;
3783  case 3:
3784  shift_down = sub_sup_shift_down(cur_style) ;
3785  break;
3786  case 4:
3788  break;
3789  case 5:
3790  shift_down = sub_shift_down(cur_style) ;
3791  break;
3792  default:
3793  if (shift_down < sub_shift_down(cur_style))
3794  shift_down = sub_shift_down(cur_style);
3795  clr = height(x) - sub_top_max(cur_style);
3796  if (shift_down < clr)
3797  shift_down = clr;
3798  break;
3799  }
3800  shift_amount(x) = shift_down;
3801  /*tex Now find and correct for horizontal shift. */
3802  subtyp = 0;
3803  if (sub_n != null) {
3804  delta2 = find_math_kern(font(p), character(p),sub_f,sub_c,sub_mark_cmd, shift_down);
3805  if (delta2 == MATH_KERN_NOT_FOUND) {
3806  delta2 = subshift ;
3807  } else {
3808  delta2 = delta2 + subshift ;
3809  subtyp = font_kern;
3810  }
3811  } else {
3812  delta2 = subshift ;
3813  }
3814  if (delta2 != 0) {
3815  p = attach_hkern_to_new_hlist(q, delta2, subtyp);
3816  }
3817  } else {
3818  /*tex
3819 
3820  Construct a superscript box |x|. The bottom of a superscript should
3821  never descend below the baseline plus one-fourth of the x-height.
3822 
3823  */
3826  switch (math_scripts_mode_par) {
3827  case 1:
3828  shift_up = sup_shift_up(cur_style);
3829  break;
3830  case 2:
3831  shift_up = sup_shift_up(cur_style) ;
3832  break;
3833  case 3:
3835  break;
3836  case 4:
3838  break;
3839  case 5:
3841  break;
3842  default:
3843  clr = sup_shift_up(cur_style);
3844  if (shift_up < clr)
3845  shift_up = clr;
3846  clr = depth(x) + sup_bottom_min(cur_style);
3847  if (shift_up < clr)
3848  shift_up = clr;
3849  break;
3850  }
3851  if (subscr(q) == null) {
3852  shift_amount(x) = -shift_up;
3853  /*tex Now find and correct for horizontal shift. */
3854  subtyp = 0;
3855  if (sup_n != null) {
3856  clr = find_math_kern(font(p),character(p),sup_f,sup_c,sup_mark_cmd,shift_up);
3857  if (clr == MATH_KERN_NOT_FOUND) {
3858  clr = supshift ;
3859  } else {
3860  clr = clr + supshift ;
3861  subtyp = font_kern;
3862  }
3863  } else {
3864  clr = supshift;
3865  }
3866  if (clr != 0) {
3867  p = attach_hkern_to_new_hlist(q, clr, subtyp);
3868  }
3869  } else {
3870  /*tex
3871 
3872  Construct a sub/superscript combination box |x|, with the
3873  superscript offset by |delta|. When both subscript and
3874  superscript are present, the subscript must be separated from the
3875  superscript by at least four times |default_rule_thickness| If
3876  this condition would be violated, the subscript moves down, after
3877  which both subscript and superscript move up so that the bottom
3878  of the superscript is at least as high as the baseline plus
3879  four-fifths of the x-height.
3880 
3881  */
3884  switch (math_scripts_mode_par) {
3885  case 1:
3886  shift_down = sub_shift_down(cur_style) ;
3887  break;
3888  case 2:
3889  shift_down = sub_sup_shift_down(cur_style) ;
3890  break;
3891  case 3:
3892  shift_down = sub_sup_shift_down(cur_style) ;
3893  break;
3894  case 4:
3896  break;
3897  case 5:
3898  shift_down = sub_shift_down(cur_style) ;
3899  break;
3900  default:
3901  if (shift_down < sub_sup_shift_down(cur_style))
3902  shift_down = sub_sup_shift_down(cur_style);
3903  clr = subsup_vgap(cur_style) - ((shift_up - depth(x)) - (height(y) - shift_down));
3904  if (clr > 0) {
3905  shift_down = shift_down + clr;
3906  clr = sup_sub_bottom_max(cur_style) - (shift_up - depth(x));
3907  if (clr > 0) {
3908  shift_up = shift_up + clr;
3909  shift_down = shift_down - clr;
3910  }
3911  }
3912  break;
3913  }
3914  /*tex Now find and correct for horizontal shift. */
3915  subtyp = 0;
3916  if (sub_n != null) {
3917  delta2 = find_math_kern(font(p), character(p),sub_f,sub_c,sub_mark_cmd, shift_down);
3918  if (delta2 == MATH_KERN_NOT_FOUND) {
3919  delta2 = subshift ;
3920  } else {
3921  delta2 = delta2 + subshift ;
3922  subtyp = font_kern;
3923  }
3924  } else {
3925  delta2 = subshift ;
3926  }
3927  if (delta2 != 0) {
3928  p = attach_hkern_to_new_hlist(q, delta2, subtyp);
3929  }
3930  /*tex
3931 
3932  Now the horizontal shift for the superscript; the superscript is
3933  also to be shifted by |delta1| (the italic correction).
3934 
3935  */
3936  clr = MATH_KERN_NOT_FOUND;
3937  if (sup_n != null) {
3938  clr = find_math_kern(font(p),character(p),sup_f,sup_c,sup_mark_cmd,shift_up);
3939  }
3940  /*tex
3941 
3942  The delta can already have been applied and now be 0.
3943 
3944  */
3945  if (delta2 == MATH_KERN_NOT_FOUND)
3946  delta2 = - supshift ;
3947  else
3948  delta2 = delta2 - supshift ;
3949  if (clr != MATH_KERN_NOT_FOUND) {
3950  shift_amount(x) = clr + delta1 - delta2;
3951  } else {
3952  shift_amount(x) = delta1 - delta2;
3953  }
3954  /*tex todo: only if kern != 0 */
3955  p = new_kern((shift_up - depth(x)) - (height(y) - shift_down));
3957  couple_nodes(x,p);
3958  couple_nodes(p,y);
3959  /*tex We end up with funny dimensions. */
3963  shift_amount(x) = shift_down;
3964  }
3965  }
3966  if (new_hlist(q) == null) {
3967  new_hlist(q) = x;
3968  } else {
3969  p = new_hlist(q);
3970  while (vlink(p) != null)
3971  p = vlink(p);
3972  couple_nodes(p,x);
3973  }
3974  if (subscr(q) != null) {
3975  math_list(subscr(q)) = null;
3976  flush_node(subscr(q));
3977  subscr(q) = null;
3978  }
3979  if (supscr(q) != null) {
3980  math_list(supscr(q)) = null;
3981  flush_node(supscr(q));
3982  supscr(q) = null;
3983  }
3984 }
3985 
3986 /*tex
3987 
3988  The |make_left_right| function constructs a left or right delimiter of the
3989  required size and returns the value |open_noad| or |close_noad|. The
3990  |left_noad_side| and |right_noad_side| will both be based on the original
3991  |style|, so they will have consistent sizes.
3992 
3993 */
3994 
3996 {
3997  scaled delta;
3998  pointer tmp, lst;
3999  scaled ic = 0;
4000  boolean stack = false;
4001  boolean axis = false;
4002  int same = subtype(q);
4004  if ((delimiterheight(q)!=0) || (delimiterdepth(q)!=0)) {
4005 
4007  tmp = do_delimiter(q, delimiter(q), cur_size, delta, false, style, false, &stack, &ic, &same);
4008  delimiteritalic(q) = ic;
4009  /*tex
4010 
4011  Beware, a stacked delimiter has a shift but no corrected height/depth
4012  (yet).
4013 
4014  */
4015  if (stack) {
4016  shift_amount(tmp) = delimiterdepth(q);
4017  }
4018  if (delimiterexact(q)) {
4019  delimiterheight(q) = height(tmp) - shift_amount(tmp);
4020  delimiterdepth(q) = depth(tmp) + shift_amount(tmp);
4021  }
4022  if (delimiteraxis(q)) {
4026  }
4027  lst = new_node(hlist_node,0);
4028  reset_attributes(lst, node_attr(q));
4029  box_dir(lst) = dir_TLT ;
4030  height(lst) = delimiterheight(q);
4031  depth(lst) = delimiterdepth(q);
4032  width(lst) = width(tmp);
4033  list_ptr(lst) = tmp;
4034  tmp = lst ;
4035  } else {
4036  axis = ! delimiternoaxis(q);
4037  delta = get_delimiter_height(max_d,max_h,axis);
4038  tmp = do_delimiter(q, delimiter(q), cur_size, delta, false, style, axis, &stack, &ic, &same);
4039  delimiteritalic(q) = ic;
4040  }
4041  delimiter(q) = null;
4042  assign_new_hlist(q, tmp);
4044  if (delimiterclass(q) >= ord_noad_type) {
4045  if (delimiterclass(q) <= inner_noad_type) {
4046  return delimiterclass(q);
4047  } else {
4048  return ord_noad_type;
4049  }
4050  } else if (subtype(q) == left_noad_side) {
4051  return open_noad_type;
4052  } else {
4053  return close_noad_type;
4054  }
4055 }
4056 
4057 #define TEXT_STYLES(A,B) do { \
4058  def_math_param(A,display_style,(B),level_one); \
4059  def_math_param(A,cramped_display_style,(B),level_one); \
4060  def_math_param(A,text_style,(B),level_one); \
4061  def_math_param(A,cramped_text_style,(B),level_one); \
4062  } while (0)
4063 
4064 #define SCRIPT_STYLES(A,B) do { \
4065  def_math_param(A,script_style,(B),level_one); \
4066  def_math_param(A,cramped_script_style,(B),level_one); \
4067  def_math_param(A,script_script_style,(B),level_one); \
4068  def_math_param(A,cramped_script_script_style,(B),level_one); \
4069  } while (0)
4070 
4071 #define ALL_STYLES(A,B) do { \
4072  TEXT_STYLES(A,(B)); \
4073  SCRIPT_STYLES(A,(B)); \
4074  } while (0)
4075 
4076 #define SPLIT_STYLES(A,B,C) do { \
4077  TEXT_STYLES(A,(B)); \
4078  SCRIPT_STYLES(A,(C)); \
4079