3 % Copyright
2006-2010 Taco Hoekwater
<taco@@luatex.org
>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software
; you can redistribute it and
/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation
; either version
2 of the License
, or
(at your
10 % option
) any later version.
12 % LuaTeX is distributed in the hope that it will be useful
, but WITHOUT
13 % ANY WARRANTY
; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX
; if not
, see
<http
://www.gnu.org
/licenses
/>.
22 @ In traditional \TeX\ the italic correction is added to the width of the glyph. This
23 is part of the engine design and related font design. In opentype math this is
24 different. There the italic correction had more explicit usage. The
1.7 spec
29 When a run of slanted characters is followed by a straight character
(such as
30 an operator or a delimiter
), the italics correction of the last glyph is added
33 When positioning limits on an N-ary operator
(e.g.
, integral sign
), the horizontal
34 position of the upper limit is moved to the right by ½ of the italics correction
,
35 while the position of the lower limit is moved to the left by the same distance.
37 When positioning superscripts and subscripts
, their default horizontal positions are
38 also different by the amount of the italics correction of the preceding glyph.
42 Set the default horizontal position for the superscript as shifted relative to the
43 position of the subscript by the italics correction of the base glyph.
45 Before this was specified we had to gamble a bit and assume that cambria was the font
46 benchmark and trust our eyes
(and msword
) for the logic. I must admit that I have been
47 fighting these italics in fonts
(and the heuristics that Lua\TeX\ provided
) right from
48 the start
(e.g. using Lua based postprocessing
) but by now we know more and have more
49 fonts to test with. More fonts are handy because not all fonts are alike when it comes
50 to italics. Axis are another area of concern
, as it looks like opentype math fonts often
51 already apply that shift.
54 #define math_old mathoption_int_par
(c_mathoption_old_code
)
55 #define math_no_italic_compensation mathoption_int_par
(c_mathoption_no_italic_compensation_code
)
56 #define math_no_char_italic mathoption_int_par
(c_mathoption_no_char_italic_code
)
57 #define math_use_old_fraction_scaling mathoption_int_par
(c_mathoption_use_old_fraction_scaling_code
)
59 #define is_new_mathfont
(A
) ((font_math_params
(A
) >0) && (math_old == 0))
60 #define is_old_mathfont
(A
,B
) ((font_math_params
(A
)==0) && (font_params(A)>=(B)))
68 #include
"lua/luatex-api.h"
71 #define delimiter_factor int_par
(delimiter_factor_code
)
72 #define delimiter_shortfall dimen_par
(delimiter_shortfall_code
)
73 #define bin_op_penalty int_par
(bin_op_penalty_code
)
74 #define rel_penalty int_par
(rel_penalty_code
)
75 #define null_delimiter_space dimen_par
(null_delimiter_space_code
)
76 #define script_space dimen_par
(script_space_code
)
77 #define disable_lig int_par
(disable_lig_code
)
78 #define disable_kern int_par
(disable_kern_code
)
79 #define disable_space int_par
(disable_space_code
)
80 #define scripts_mode int_par
(math_scripts_mode_code
)
84 #define reset_attributes
(p
,newatt
) do
{ \
85 delete_attribute_ref
(node_attr
(p
)); \
86 node_attr
(p
) = newatt
; \
88 assert
(type
(newatt
)==attribute_list_node
); \
89 add_node_attr_ref
(node_attr
(p
)); \
93 #define DEFINE_MATH_PARAMETERS
(A
,B
,C
,D
) do
{ \
95 def_math_param
(A
, text_style
, (C
),D
); \
96 def_math_param
(A
, cramped_text_style
, (C
),D
); \
97 } else if
(B
==script_size
) { \
98 def_math_param
(A
, script_style
, (C
),D
); \
99 def_math_param
(A
, cramped_script_style
, (C
),D
); \
100 } else if
(B
==script_script_size
) { \
101 def_math_param
(A
, script_script_style
, (C
),D
); \
102 def_math_param
(A
, cramped_script_script_style
, (C
),D
); \
106 #define DEFINE_DMATH_PARAMETERS
(A
,B
,C
,D
) do
{ \
107 if
(B
==text_size
) { \
108 def_math_param
(A
, display_style
,(C
),D
); \
109 def_math_param
(A
, cramped_display_style
,(C
),D
); \
113 #define font_MATH_par
(a
,b
) \
114 (font_math_params
(a
)>=b ? font_math_param
(a
,b
) : undefined_math_parameter
)
116 @ here are the math parameters that are font-dependant
118 @ Before an mlist is converted to an hlist
, \TeX\ makes sure that
119 the fonts in family~
2 have enough parameters to be math-symbol
120 fonts
, and that the fonts in family~
3 have enough parameters to be
121 math-extension fonts. The math-symbol parameters are referred to by using the
122 following macros
, which take a size code as their parameter
; for example
,
123 |num1
(cur_size
)| gives the value of the |num1| parameter for the current size.
124 @^parameters for symbols@
>
128 #define total_mathsy_params
22
129 #define total_mathex_params
13
131 #define mathsy
(A
,B
) font_param
(fam_fnt
(2,A
),B
)
133 #define math_x_height
(A
) mathsy
(A
,5) /* height of `\.x'
*/
134 #define math_quad
(A
) mathsy
(A
,6) /* \.
{18mu
} */
135 #define num1
(A
) mathsy
(A
,8) /* numerator shift-up in display styles
*/
136 #define num2
(A
) mathsy
(A
,9) /* numerator shift-up in non-display
, non-\.
{\\atop
} */
137 #define num3
(A
) mathsy
(A
,10) /* numerator shift-up in non-display \.
{\\atop
} */
138 #define denom1
(A
) mathsy
(A
,11) /* denominator shift-down in display styles
*/
139 #define denom2
(A
) mathsy
(A
,12) /* denominator shift-down in non-display styles
*/
140 #define sup1
(A
) mathsy
(A
,13) /* superscript shift-up in uncramped display style
*/
141 #define sup2
(A
) mathsy
(A
,14) /* superscript shift-up in uncramped non-display
*/
142 #define sup3
(A
) mathsy
(A
,15) /* superscript shift-up in cramped styles
*/
143 #define sub1
(A
) mathsy
(A
,16) /* subscript shift-down if superscript is absent
*/
144 #define sub2
(A
) mathsy
(A
,17) /* subscript shift-down if superscript is present
*/
145 #define sup_drop
(A
) mathsy
(A
,18) /* superscript baseline below top of large box
*/
146 #define sub_drop
(A
) mathsy
(A
,19) /* subscript baseline below bottom of large box
*/
147 #define delim1
(A
) mathsy
(A
,20) /* size of \.
{\\atopwithdelims
} delimiters in display styles
*/
148 #define delim2
(A
) mathsy
(A
,21) /* size of \.
{\\atopwithdelims
} delimiters in non-displays
*/
149 #define axis_height
(A
) mathsy
(A
,22) /* height of fraction lines above the baseline
*/
151 @ The math-extension parameters have similar macros
, but the size code is
152 omitted
(since it is always |cur_size| when we refer to such parameters
).
153 @^parameters for symbols@
>
157 #define mathex
(A
,B
) font_param
(fam_fnt
(3,A
),B
)
158 #define default_rule_thickness
(A
) mathex
(A
,8) /* thickness of \.
{\\over
} bars
*/
159 #define big_op_spacing1
(A
) mathex
(A
,9) /* minimum clearance above a displayed op
*/
160 #define big_op_spacing2
(A
) mathex
(A
,10) /* minimum clearance below a displayed op
*/
161 #define big_op_spacing3
(A
) mathex
(A
,11) /* minimum baselineskip above displayed op
*/
162 #define big_op_spacing4
(A
) mathex
(A
,12) /* minimum baselineskip below displayed op
*/
163 #define big_op_spacing5
(A
) mathex
(A
,13) /* padding above and below displayed limits
*/
165 @ I
(TH
) made a bunch of extensions cf. the MATH table in OpenType
, but some of
166 the MathConstants values have no matching usage in \LuaTeX\ right now.
168 ScriptPercentScaleDown
,
169 ScriptScriptPercentScaleDown
:
170 These should be handled by the macro package
, on the engine
171 side there are three separate fonts
173 DelimitedSubFormulaMinHeight
:
174 This is perhaps related to word's natural math input? I have
175 no idea what to do about it
178 LuaTeX does not currently handle multi-line displays
, and
179 the parameter does not seem to make much sense elsewhere
181 FlattenedAccentBaseHeight
:
182 This is based on the 'flac' GSUB feature. It would not be hard
183 to support that
, but proper math accent placements cf. MATH
184 needs support for MathTopAccentAttachment table to be
187 Also still TODO for OpenType Math
:
190 @ this is not really a math parameter at all
193 static void math_param_error
(const char
*param
, int style
)
196 const char
*hlp
[] = {
197 "Sorry, but I can't typeset math unless various parameters have",
198 "been set. This is normally done by loading special math fonts",
199 "into the math family slots. Your font set is lacking at least",
200 "the parameter mentioned earlier.",
203 snprintf
(s
, 256, "Math error: parameter \\Umath%s\\%sstyle is not set",
204 param
, math_style_names
[style
]);
213 static scaled accent_base_height
(int f
)
216 if
(is_new_mathfont
(f
)) {
217 a
= font_MATH_par
(f
, AccentBaseHeight
);
218 if
(a
== undefined_math_parameter
)
226 @ the non-staticness of this function is for the benefit of |texmath.w|
229 scaled get_math_quad
(int var
)
231 scaled a
= get_math_param
(math_param_quad
, var
);
232 if
(a
== undefined_math_parameter
) {
233 math_param_error
("quad", var
);
239 @ this parameter is different because it is called with a size
240 specifier instead of a style specifier.
243 static scaled math_axis
(int b
)
247 if
(b
== script_size
)
249 else if
(b
== script_script_size
)
250 var
= script_script_style
;
253 a
= get_math_param
(math_param_axis
, var
);
254 if
(a
== undefined_math_parameter
) {
255 math_param_error
("axis", var
);
262 static scaled get_math_quad_size
(int b
)
265 if
(b
== script_size
)
267 else if
(b
== script_script_size
)
268 var
= script_script_style
;
271 return get_math_param
(math_param_quad
, var
);
275 static scaled minimum_operator_size
(int var
)
277 scaled a
= get_math_param
(math_param_operator_size
, var
);
281 @ Old-style fonts do not define the |radical_rule|. This allows |make_radical| to select
282 the backward compatibility code
, and it means that we can't raise an error here.
285 static scaled radical_rule
(int var
)
287 scaled a
= get_math_param
(math_param_radical_rule
, var
);
291 @ now follow all the trivial math parameters
294 #define get_math_param_or_error
(a
,b
) do_get_math_param_or_error
(a
, math_param_##b
, #b
)
296 static scaled do_get_math_param_or_error
(int var
, int param
, const char
*name
)
298 scaled a
= get_math_param
(param
, var
);
299 if
(a
== undefined_math_parameter
) {
300 math_param_error
(name
, var
);
306 @ A variant on a suggestion on the list based on analysis by UV.
309 static scaled get_delimiter_height
(scaled max_d
, scaled max_h
, boolean axis
) {
310 scaled delta
, delta1
, delta2
;
312 delta2
= max_d
+ math_axis
(cur_size
);
316 delta1
= max_h
+ max_d
- delta2
;
317 if
(delta2
> delta1
) {
318 /* |delta1| is max distance from axis
*/
321 delta
= (delta1
/ 500) * delimiter_factor
;
322 delta2
= delta1
+ delta1
- delimiter_shortfall
;
323 if
(delta
< delta2
) {
331 #define radical_degree_before
(a
) get_math_param_or_error
(a
, radical_degree_before
)
332 #define radical_degree_after
(a
) get_math_param_or_error
(a
, radical_degree_after
)
333 #define radical_degree_raise
(a
) get_math_param_or_error
(a
, radical_degree_raise
)
335 #define connector_overlap_min
(a
) get_math_param_or_error
(a
, connector_overlap_min
)
337 #define overbar_rule
(a
) get_math_param_or_error
(a
, overbar_rule
)
338 #define overbar_kern
(a
) get_math_param_or_error
(a
, overbar_kern
)
339 #define overbar_vgap
(a
) get_math_param_or_error
(a
, overbar_vgap
)
341 #define underbar_rule
(a
) get_math_param_or_error
(a
, underbar_rule
)
342 #define underbar_kern
(a
) get_math_param_or_error
(a
, underbar_kern
)
343 #define underbar_vgap
(a
) get_math_param_or_error
(a
, underbar_vgap
)
345 #define under_delimiter_vgap
(a
) get_math_param_or_error
(a
, under_delimiter_vgap
)
346 #define under_delimiter_bgap
(a
) get_math_param_or_error
(a
, under_delimiter_bgap
)
348 #define over_delimiter_vgap
(a
) get_math_param_or_error
(a
, over_delimiter_vgap
)
349 #define over_delimiter_bgap
(a
) get_math_param_or_error
(a
, over_delimiter_bgap
)
351 #define radical_vgap
(a
) get_math_param_or_error
(a
, radical_vgap
)
352 #define radical_kern
(a
) get_math_param_or_error
(a
, radical_kern
)
354 #define stack_vgap
(a
) get_math_param_or_error
(a
, stack_vgap
)
355 #define stack_num_up
(a
) get_math_param_or_error
(a
, stack_num_up
)
356 #define stack_denom_down
(a
) get_math_param_or_error
(a
, stack_denom_down
)
358 #define fraction_rule
(a
) get_math_param_or_error
(a
, fraction_rule
)
359 #define fraction_num_vgap
(a
) get_math_param_or_error
(a
, fraction_num_vgap
)
360 #define fraction_denom_vgap
(a
) get_math_param_or_error
(a
, fraction_denom_vgap
)
361 #define fraction_num_up
(a
) get_math_param_or_error
(a
, fraction_num_up
)
362 #define fraction_denom_down
(a
) get_math_param_or_error
(a
, fraction_denom_down
)
363 #define fraction_del_size_new
(a
) get_math_param_or_error
(a
, fraction_del_size
)
364 #define fraction_del_size_new
(a
) get_math_param_or_error
(a
, fraction_del_size
)
366 #define fraction_del_size_old
(a
) get_math_param
(a
, math_param_fraction_del_size
)
368 #define fraction_del_size_old
(a
) get_math_param_or_error
(a
, fraction_del_size
)
370 #define skewed_fraction_hgap
(a
) get_math_param_or_error
(a
, skewed_fraction_hgap
)
371 #define skewed_fraction_vgap
(a
) get_math_param_or_error
(a
, skewed_fraction_vgap
)
373 #define limit_above_vgap
(a
) get_math_param_or_error
(a
, limit_above_vgap
)
374 #define limit_above_bgap
(a
) get_math_param_or_error
(a
, limit_above_bgap
)
375 #define limit_above_kern
(a
) get_math_param_or_error
(a
, limit_above_kern
)
377 #define limit_below_vgap
(a
) get_math_param_or_error
(a
, limit_below_vgap
)
378 #define limit_below_bgap
(a
) get_math_param_or_error
(a
, limit_below_bgap
)
379 #define limit_below_kern
(a
) get_math_param_or_error
(a
, limit_below_kern
)
381 #define sub_shift_drop
(a
) get_math_param_or_error
(a
, sub_shift_drop
)
382 #define sup_shift_drop
(a
) get_math_param_or_error
(a
, sup_shift_drop
)
383 #define sub_shift_down
(a
) get_math_param_or_error
(a
, sub_shift_down
)
384 #define sub_sup_shift_down
(a
) get_math_param_or_error
(a
, sub_sup_shift_down
)
385 #define sup_shift_up
(a
) get_math_param_or_error
(a
, sup_shift_up
)
386 #define sub_top_max
(a
) get_math_param_or_error
(a
, sub_top_max
)
387 #define sup_bottom_min
(a
) get_math_param_or_error
(a
, sup_bottom_min
)
388 #define sup_sub_bottom_max
(a
) get_math_param_or_error
(a
, sup_sub_bottom_max
)
389 #define subsup_vgap
(a
) get_math_param_or_error
(a
, subsup_vgap
)
391 #define space_after_script
(a
) get_math_param_or_error
(a
, space_after_script
)
394 void fixup_math_parameters
(int fam_id
, int size_id
, int f
, int lvl
)
396 if
(is_new_mathfont
(f
)) { /* fix all known parameters
*/
398 DEFINE_MATH_PARAMETERS
(math_param_quad
, size_id
,
400 DEFINE_DMATH_PARAMETERS
(math_param_quad
, size_id
,
402 DEFINE_MATH_PARAMETERS
(math_param_axis
, size_id
,
403 font_MATH_par
(f
, AxisHeight
), lvl
);
404 DEFINE_DMATH_PARAMETERS
(math_param_axis
, size_id
,
405 font_MATH_par
(f
, AxisHeight
), lvl
);
406 DEFINE_MATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
407 font_MATH_par
(f
, OverbarExtraAscender
), lvl
);
408 DEFINE_DMATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
409 font_MATH_par
(f
, OverbarExtraAscender
), lvl
);
410 DEFINE_MATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
411 font_MATH_par
(f
, OverbarRuleThickness
), lvl
);
412 DEFINE_DMATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
413 font_MATH_par
(f
, OverbarRuleThickness
), lvl
);
414 DEFINE_MATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
415 font_MATH_par
(f
, OverbarVerticalGap
), lvl
);
416 DEFINE_DMATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
417 font_MATH_par
(f
, OverbarVerticalGap
), lvl
);
418 DEFINE_MATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
419 font_MATH_par
(f
, UnderbarExtraDescender
), lvl
);
420 DEFINE_DMATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
421 font_MATH_par
(f
, UnderbarExtraDescender
), lvl
);
422 DEFINE_MATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
423 font_MATH_par
(f
, UnderbarRuleThickness
), lvl
);
424 DEFINE_DMATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
425 font_MATH_par
(f
, UnderbarRuleThickness
), lvl
);
426 DEFINE_MATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
427 font_MATH_par
(f
, UnderbarVerticalGap
), lvl
);
428 DEFINE_DMATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
429 font_MATH_par
(f
, UnderbarVerticalGap
), lvl
);
431 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
432 font_MATH_par
(f
, StretchStackGapAboveMin
), lvl
);
433 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
434 font_MATH_par
(f
, StretchStackGapAboveMin
), lvl
);
435 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
436 font_MATH_par
(f
, StretchStackBottomShiftDown
), lvl
);
437 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
438 font_MATH_par
(f
, StretchStackBottomShiftDown
), lvl
);
440 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
441 font_MATH_par
(f
, StretchStackGapBelowMin
), lvl
);
442 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
443 font_MATH_par
(f
, StretchStackGapBelowMin
), lvl
);
444 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
445 font_MATH_par
(f
, StretchStackTopShiftUp
), lvl
);
446 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
447 font_MATH_par
(f
, StretchStackTopShiftUp
), lvl
);
449 DEFINE_MATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
450 font_MATH_par
(f
, StackTopShiftUp
), lvl
);
451 DEFINE_DMATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
452 font_MATH_par
(f
, StackTopDisplayStyleShiftUp
), lvl
);
453 DEFINE_MATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
454 font_MATH_par
(f
, StackBottomShiftDown
), lvl
);
455 DEFINE_DMATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
456 font_MATH_par
(f
, StackBottomDisplayStyleShiftDown
), lvl
);
457 DEFINE_MATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
458 font_MATH_par
(f
, StackGapMin
), lvl
);
459 DEFINE_DMATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
460 font_MATH_par
(f
, StackDisplayStyleGapMin
), lvl
);
462 DEFINE_MATH_PARAMETERS
(math_param_radical_kern
, size_id
,
463 font_MATH_par
(f
, RadicalExtraAscender
), lvl
);
464 DEFINE_DMATH_PARAMETERS
(math_param_radical_kern
, size_id
,
465 font_MATH_par
(f
, RadicalExtraAscender
), lvl
);
467 DEFINE_DMATH_PARAMETERS
(math_param_operator_size
, size_id
,
468 font_MATH_par
(f
, DisplayOperatorMinHeight
), lvl
);
470 DEFINE_MATH_PARAMETERS
(math_param_radical_rule
, size_id
,
471 font_MATH_par
(f
, RadicalRuleThickness
), lvl
);
472 DEFINE_DMATH_PARAMETERS
(math_param_radical_rule
, size_id
,
473 font_MATH_par
(f
, RadicalRuleThickness
), lvl
);
474 DEFINE_MATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
475 font_MATH_par
(f
, RadicalVerticalGap
), lvl
);
476 DEFINE_DMATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
477 font_MATH_par
(f
, RadicalDisplayStyleVerticalGap
), lvl
);
478 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
479 font_MATH_par
(f
, RadicalKernBeforeDegree
), lvl
);
480 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
481 font_MATH_par
(f
, RadicalKernBeforeDegree
), lvl
);
482 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
483 font_MATH_par
(f
, RadicalKernAfterDegree
), lvl
);
484 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
485 font_MATH_par
(f
, RadicalKernAfterDegree
), lvl
);
486 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
487 font_MATH_par
(f
, RadicalDegreeBottomRaisePercent
), lvl
);
488 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
489 font_MATH_par
(f
, RadicalDegreeBottomRaisePercent
), lvl
);
491 if
(size_id
== text_size
) {
492 def_math_param
(math_param_sup_shift_up
, display_style
,
493 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
494 def_math_param
(math_param_sup_shift_up
, cramped_display_style
,
495 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
496 def_math_param
(math_param_sup_shift_up
, text_style
,
497 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
498 def_math_param
(math_param_sup_shift_up
, cramped_text_style
,
499 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
500 } else if
(size_id
== script_size
) {
501 def_math_param
(math_param_sup_shift_up
, script_style
,
502 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
503 def_math_param
(math_param_sup_shift_up
, cramped_script_style
,
504 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
505 } else if
(size_id
== script_script_size
) {
506 def_math_param
(math_param_sup_shift_up
, script_script_style
,
507 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
508 def_math_param
(math_param_sup_shift_up
, cramped_script_script_style
,
509 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
512 DEFINE_MATH_PARAMETERS
(math_param_sub_shift_drop
, size_id
,
513 font_MATH_par
(f
, SubscriptBaselineDropMin
), lvl
);
514 DEFINE_DMATH_PARAMETERS
(math_param_sub_shift_drop
, size_id
,
515 font_MATH_par
(f
, SubscriptBaselineDropMin
), lvl
);
516 DEFINE_MATH_PARAMETERS
(math_param_sup_shift_drop
, size_id
,
517 font_MATH_par
(f
, SuperscriptBaselineDropMax
), lvl
);
518 DEFINE_DMATH_PARAMETERS
(math_param_sup_shift_drop
, size_id
,
519 font_MATH_par
(f
, SuperscriptBaselineDropMax
), lvl
);
520 DEFINE_MATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
521 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
522 DEFINE_DMATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
523 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
525 if
(font_MATH_par
(f
, SubscriptShiftDownWithSuperscript
) != undefined_math_parameter
) {
526 DEFINE_MATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
527 font_MATH_par
(f
, SubscriptShiftDownWithSuperscript
), lvl
);
528 DEFINE_DMATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
529 font_MATH_par
(f
, SubscriptShiftDownWithSuperscript
), lvl
);
531 DEFINE_MATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
532 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
533 DEFINE_DMATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
534 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
537 DEFINE_MATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
538 font_MATH_par
(f
, SubscriptTopMax
), lvl
);
539 DEFINE_DMATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
540 font_MATH_par
(f
, SubscriptTopMax
), lvl
);
541 DEFINE_MATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
542 font_MATH_par
(f
, SuperscriptBottomMin
), lvl
);
543 DEFINE_DMATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
544 font_MATH_par
(f
, SuperscriptBottomMin
), lvl
);
545 DEFINE_MATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
546 font_MATH_par
(f
, SuperscriptBottomMaxWithSubscript
), lvl
);
547 DEFINE_DMATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
548 font_MATH_par
(f
, SuperscriptBottomMaxWithSubscript
), lvl
);
549 DEFINE_MATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
550 font_MATH_par
(f
, SubSuperscriptGapMin
), lvl
);
551 DEFINE_DMATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
552 font_MATH_par
(f
, SubSuperscriptGapMin
), lvl
);
554 DEFINE_MATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
555 font_MATH_par
(f
, UpperLimitGapMin
), lvl
);
556 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
557 font_MATH_par
(f
, UpperLimitGapMin
), lvl
);
558 DEFINE_MATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
559 font_MATH_par
(f
, UpperLimitBaselineRiseMin
), lvl
);
560 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
561 font_MATH_par
(f
, UpperLimitBaselineRiseMin
), lvl
);
562 DEFINE_MATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
564 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
566 DEFINE_MATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
567 font_MATH_par
(f
, LowerLimitGapMin
), lvl
);
568 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
569 font_MATH_par
(f
, LowerLimitGapMin
), lvl
);
570 DEFINE_MATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
571 font_MATH_par
(f
, LowerLimitBaselineDropMin
), lvl
);
572 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
573 font_MATH_par
(f
, LowerLimitBaselineDropMin
), lvl
);
574 DEFINE_MATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
576 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
579 DEFINE_MATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
580 font_MATH_par
(f
, FractionRuleThickness
), lvl
);
581 DEFINE_DMATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
582 font_MATH_par
(f
, FractionRuleThickness
), lvl
);
583 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
584 font_MATH_par
(f
, FractionNumeratorGapMin
), lvl
);
585 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
586 font_MATH_par
(f
, FractionNumeratorDisplayStyleGapMin
), lvl
);
587 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
588 font_MATH_par
(f
, FractionNumeratorShiftUp
), lvl
);
589 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
590 font_MATH_par
(f
, FractionNumeratorDisplayStyleShiftUp
), lvl
);
591 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
592 font_MATH_par
(f
, FractionDenominatorGapMin
), lvl
);
593 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
594 font_MATH_par
(f
,FractionDenominatorDisplayStyleGapMin
), lvl
);
595 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
596 font_MATH_par
(f
, FractionDenominatorShiftDown
), lvl
);
597 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
598 font_MATH_par
(f
, FractionDenominatorDisplayStyleShiftDown
), lvl
);
600 DEFINE_MATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
601 font_MATH_par
(f
, FractionDelimiterSize
), lvl
);
602 DEFINE_DMATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
603 font_MATH_par
(f
, FractionDelimiterDisplayStyleSize
), lvl
);
605 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
606 font_MATH_par
(f
, SkewedFractionHorizontalGap
), lvl
);
607 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
608 font_MATH_par
(f
, SkewedFractionHorizontalGap
), lvl
);
609 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
610 font_MATH_par
(f
, SkewedFractionVerticalGap
), lvl
);
611 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
612 font_MATH_par
(f
, SkewedFractionVerticalGap
), lvl
);
614 DEFINE_MATH_PARAMETERS
(math_param_space_after_script
, size_id
,
615 font_MATH_par
(f
, SpaceAfterScript
), lvl
);
616 DEFINE_DMATH_PARAMETERS
(math_param_space_after_script
, size_id
,
617 font_MATH_par
(f
, SpaceAfterScript
), lvl
);
619 DEFINE_MATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
620 font_MATH_par
(f
, MinConnectorOverlap
), lvl
);
621 DEFINE_DMATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
622 font_MATH_par
(f
, MinConnectorOverlap
), lvl
);
624 } else if
(fam_id
== 2 && is_old_mathfont(f, total_mathsy_params)) {
626 /* fix old-style |sy| parameters
*/
628 DEFINE_MATH_PARAMETERS
(math_param_quad
, size_id
,
629 math_quad
(size_id
), lvl
);
630 DEFINE_DMATH_PARAMETERS
(math_param_quad
, size_id
,
631 math_quad
(size_id
), lvl
);
632 DEFINE_MATH_PARAMETERS
(math_param_axis
, size_id
,
633 axis_height
(size_id
), lvl
);
634 DEFINE_DMATH_PARAMETERS
(math_param_axis
, size_id
,
635 axis_height
(size_id
), lvl
);
636 DEFINE_MATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
638 DEFINE_DMATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
640 DEFINE_MATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
641 denom2
(size_id
), lvl
);
642 DEFINE_DMATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
643 denom1
(size_id
), lvl
);
644 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
646 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
648 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
649 denom2
(size_id
), lvl
);
650 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
651 denom1
(size_id
), lvl
);
652 DEFINE_MATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
653 delim2
(size_id
), lvl
);
654 DEFINE_DMATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
655 delim1
(size_id
), lvl
);
657 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
659 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
661 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
663 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
666 if
(size_id
== text_size
) {
667 def_math_param
(math_param_sup_shift_up
, display_style
,
669 def_math_param
(math_param_sup_shift_up
, cramped_display_style
,
671 def_math_param
(math_param_sup_shift_up
, text_style
,
673 def_math_param
(math_param_sup_shift_up
, cramped_text_style
,
675 } else if
(size_id
== script_size
) {
676 def_math_param
(math_param_sub_shift_drop
, display_style
,
677 sub_drop
(size_id
), lvl
);
678 def_math_param
(math_param_sub_shift_drop
, cramped_display_style
,
679 sub_drop
(size_id
), lvl
);
680 def_math_param
(math_param_sub_shift_drop
, text_style
,
681 sub_drop
(size_id
), lvl
);
682 def_math_param
(math_param_sub_shift_drop
, cramped_text_style
,
683 sub_drop
(size_id
), lvl
);
684 def_math_param
(math_param_sup_shift_drop
, display_style
,
685 sup_drop
(size_id
), lvl
);
686 def_math_param
(math_param_sup_shift_drop
, cramped_display_style
,
687 sup_drop
(size_id
), lvl
);
688 def_math_param
(math_param_sup_shift_drop
, text_style
,
689 sup_drop
(size_id
), lvl
);
690 def_math_param
(math_param_sup_shift_drop
, cramped_text_style
,
691 sup_drop
(size_id
), lvl
);
692 def_math_param
(math_param_sup_shift_up
, script_style
,
694 def_math_param
(math_param_sup_shift_up
, cramped_script_style
,
696 } else if
(size_id
== script_script_size
) {
697 def_math_param
(math_param_sub_shift_drop
, script_style
,
698 sub_drop
(size_id
), lvl
);
699 def_math_param
(math_param_sub_shift_drop
, cramped_script_style
,
700 sub_drop
(size_id
), lvl
);
701 def_math_param
(math_param_sub_shift_drop
, script_script_style
,
702 sub_drop
(size_id
), lvl
);
703 def_math_param
(math_param_sub_shift_drop
,
704 cramped_script_script_style
, sub_drop
(size_id
), lvl
);
705 def_math_param
(math_param_sup_shift_drop
, script_style
,
706 sup_drop
(size_id
), lvl
);
707 def_math_param
(math_param_sup_shift_drop
, cramped_script_style
,
708 sup_drop
(size_id
), lvl
);
709 def_math_param
(math_param_sup_shift_drop
, script_script_style
,
710 sup_drop
(size_id
), lvl
);
711 def_math_param
(math_param_sup_shift_drop
,
712 cramped_script_script_style
, sup_drop
(size_id
), lvl
);
713 def_math_param
(math_param_sup_shift_up
, script_script_style
,
715 def_math_param
(math_param_sup_shift_up
, cramped_script_script_style
,
719 DEFINE_MATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
721 DEFINE_DMATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
723 DEFINE_MATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
725 DEFINE_DMATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
727 DEFINE_MATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
728 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
729 DEFINE_DMATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
730 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
731 DEFINE_MATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
732 (abs
(math_x_height
(size_id
)) / 4), lvl
);
733 DEFINE_DMATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
734 (abs
(math_x_height
(size_id
)) / 4), lvl
);
735 DEFINE_MATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
736 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
737 DEFINE_DMATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
738 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
741 The display-size |radical_vgap| is done twice because it needs
742 values from both the sy and the ex font.
745 DEFINE_DMATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
746 (default_rule_thickness
(size_id
) + (abs
(math_x_height
(size_id
)) / 4)), lvl
);
747 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
749 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
751 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
752 xn_over_d
(get_math_quad_size
(size_id
), 5, 18), lvl
);
753 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
754 xn_over_d
(get_math_quad_size
(size_id
), 5, 18), lvl
);
755 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
756 (-xn_over_d
(get_math_quad_size
(size_id
), 10, 18)), lvl
);
757 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
758 (-xn_over_d
(get_math_quad_size
(size_id
), 10, 18)), lvl
);
760 } else if
(fam_id
== 3 && is_old_mathfont(f, total_mathex_params)) {
762 /* fix old-style |ex| parameters
*/
764 DEFINE_MATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
765 default_rule_thickness
(size_id
), lvl
);
766 DEFINE_MATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
767 default_rule_thickness
(size_id
), lvl
);
768 DEFINE_MATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
769 3 * default_rule_thickness
(size_id
), lvl
);
770 DEFINE_DMATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
771 default_rule_thickness
(size_id
), lvl
);
772 DEFINE_DMATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
773 default_rule_thickness
(size_id
), lvl
);
774 DEFINE_DMATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
775 3 * default_rule_thickness
(size_id
), lvl
);
776 DEFINE_MATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
777 default_rule_thickness
(size_id
), lvl
);
778 DEFINE_MATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
779 default_rule_thickness
(size_id
), lvl
);
780 DEFINE_MATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
781 3 * default_rule_thickness
(size_id
), lvl
);
782 DEFINE_DMATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
783 default_rule_thickness
(size_id
), lvl
);
784 DEFINE_DMATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
785 default_rule_thickness
(size_id
), lvl
);
786 DEFINE_DMATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
787 3 * default_rule_thickness
(size_id
), lvl
);
788 DEFINE_MATH_PARAMETERS
(math_param_radical_kern
, size_id
,
789 default_rule_thickness
(size_id
), lvl
);
790 DEFINE_DMATH_PARAMETERS
(math_param_radical_kern
, size_id
,
791 default_rule_thickness
(size_id
), lvl
);
792 DEFINE_MATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
793 (default_rule_thickness
(size_id
) + (abs
(default_rule_thickness
(size_id
)) / 4)), lvl
);
794 DEFINE_MATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
795 3 * default_rule_thickness
(size_id
), lvl
);
796 DEFINE_DMATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
797 7 * default_rule_thickness
(size_id
), lvl
);
798 DEFINE_MATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
799 default_rule_thickness
(size_id
), lvl
);
800 DEFINE_DMATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
801 default_rule_thickness
(size_id
), lvl
);
802 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
803 default_rule_thickness
(size_id
), lvl
);
804 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
805 3 * default_rule_thickness
(size_id
), lvl
);
806 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
807 default_rule_thickness
(size_id
), lvl
);
808 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
809 3 * default_rule_thickness
(size_id
), lvl
);
810 DEFINE_MATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
811 big_op_spacing1
(size_id
), lvl
);
812 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
813 big_op_spacing1
(size_id
), lvl
);
814 DEFINE_MATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
815 big_op_spacing3
(size_id
), lvl
);
816 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
817 big_op_spacing3
(size_id
), lvl
);
818 DEFINE_MATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
819 big_op_spacing5
(size_id
), lvl
);
820 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
821 big_op_spacing5
(size_id
), lvl
);
822 DEFINE_MATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
823 big_op_spacing2
(size_id
), lvl
);
824 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
825 big_op_spacing2
(size_id
), lvl
);
826 DEFINE_MATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
827 big_op_spacing4
(size_id
), lvl
);
828 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
829 big_op_spacing4
(size_id
), lvl
);
830 DEFINE_MATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
831 big_op_spacing5
(size_id
), lvl
);
832 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
833 big_op_spacing5
(size_id
), lvl
);
834 DEFINE_MATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
835 4 * default_rule_thickness
(size_id
), lvl
);
836 DEFINE_DMATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
837 4 * default_rule_thickness
(size_id
), lvl
);
840 All of the |space_after_script|s are done in |finalize_math_parameters|
841 because the \.
{\\scriptspace
} may have been altered by the user
844 DEFINE_MATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
846 DEFINE_DMATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
849 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
850 big_op_spacing2
(size_id
), lvl
);
851 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
852 big_op_spacing2
(size_id
), lvl
);
853 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
854 big_op_spacing4
(size_id
), lvl
);
855 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
856 big_op_spacing4
(size_id
), lvl
);
857 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
858 big_op_spacing1
(size_id
), lvl
);
859 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
860 big_op_spacing1
(size_id
), lvl
);
861 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
862 big_op_spacing3
(size_id
), lvl
);
863 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
864 big_op_spacing3
(size_id
), lvl
);
867 The display-size |radical_vgap| is done twice because it needs
868 values from both the sy and the ex font.
871 DEFINE_DMATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
872 (default_rule_thickness
(size_id
) + (abs
(math_x_height
(size_id
)) / 4)), lvl
);
877 @ This needs to be called just at the start of |mlist_to_hlist|
, for
878 backward compatibility with \.
{\\scriptspace
}.
881 static void finalize_math_parameters
(void
)
883 int saved_trace
= int_par
(tracing_assigns_code
);
884 int_par
(tracing_assigns_code
) = 0;
885 if
(get_math_param
(math_param_space_after_script
, display_style
) == undefined_math_parameter
) {
886 def_math_param
(math_param_space_after_script
, display_style
,
887 script_space
, level_one
);
888 def_math_param
(math_param_space_after_script
, text_style
,
889 script_space
, level_one
);
890 def_math_param
(math_param_space_after_script
, script_style
,
891 script_space
, level_one
);
892 def_math_param
(math_param_space_after_script
, script_script_style
,
893 script_space
, level_one
);
894 def_math_param
(math_param_space_after_script
, cramped_display_style
,
895 script_space
, level_one
);
896 def_math_param
(math_param_space_after_script
, cramped_text_style
,
897 script_space
, level_one
);
898 def_math_param
(math_param_space_after_script
, cramped_script_style
,
899 script_space
, level_one
);
900 def_math_param
(math_param_space_after_script
, cramped_script_script_style
,
901 script_space
, level_one
);
903 int_par
(tracing_assigns_code
) = saved_trace
;
906 @ In order to convert mlists to hlists
, i.e.
, noads to nodes
, we need several
907 subroutines that are conveniently dealt with now.
909 Let us first introduce the macros that make it easy to get at the parameters and
910 other font information. A size code
, which is a multiple of
256, is added to a
911 family number to get an index into the table of internal font numbers
912 for each combination of family and size.
(Be alert
: Size codes get
913 larger as the type gets smaller.
)
916 static const char
*math_size_string
(int s
)
920 else if
(s
== script_size
)
923 return
"scriptscriptfont";
926 @ When the style changes
, the following piece of program computes associated
930 #define setup_cur_size
(a
) do
{ \
931 if
(a
==script_style || \
932 a
==cramped_script_style
) \
933 cur_size
=script_size
; \
934 else if
(a
==script_script_style || \
935 a
==cramped_script_script_style
) \
936 cur_size
=script_script_size
; \
937 else cur_size
=text_size
; \
941 @ a simple routine that creates a flat copy of a nucleus
943 static pointer math_clone
(pointer q
)
948 x
= new_node
(type
(q
), 0);
949 reset_attributes
(x
, node_attr
(q
));
950 if
(type
(q
) == math_char_node
) {
951 math_fam
(x
) = math_fam
(q
);
952 math_character
(x
) = math_character
(q
);
954 math_list
(x
) = math_list
(q
);
959 @ Here is a function that returns a pointer to a rule node having a given
960 thickness |t|. The rule will extend horizontally to the boundary of the vlist
961 that eventually contains it.
964 static pointer do_fraction_rule
(scaled t
, pointer att
)
966 pointer p
; /* the new node
*/
967 p
= new_rule
(normal_rule
);
968 rule_dir
(p
) = math_direction
;
971 reset_attributes
(p
, att
);
975 @ The |overbar| function returns a pointer to a vlist box that consists of
976 a given box |b|
, above which has been placed a kern of height |k| under a
977 fraction rule of thickness |t| under additional space of height |ht|.
980 static pointer overbar
(pointer b
, scaled k
, scaled t
, scaled ht
, pointer att
)
982 pointer p
, q
; /* nodes being constructed
*/
984 reset_attributes
(p
, att
);
986 q
= do_fraction_rule
(t
, att
);
989 reset_attributes
(p
, att
);
991 q
= vpackage
(p
, 0, additional
, max_dimen
, math_direction
);
992 reset_attributes
(q
, att
);
996 @ Here is a subroutine that creates a new box
, whose list contains a
997 single character
, and whose width includes the italic correction for
998 that character. The height or depth of the box will be negative
, if
999 the height or depth of the character is negative
; thus
, this routine
1000 may deliver a slightly different result than |hpack| would produce.
1003 static pointer char_box
(internal_font_number f
, int c
, pointer bb
)
1005 pointer b
, p
; /* the new box and its character node
*/
1007 if
(is_new_mathfont
(f
))
1008 width
(b
) = char_width
(f
, c
);
1010 width
(b
) = char_width
(f
, c
) + char_italic
(f
, c
);
1011 height
(b
) = char_height
(f
, c
);
1012 depth
(b
) = char_depth
(f
, c
);
1013 reset_attributes
(b
, bb
);
1015 reset_attributes
(p
, bb
);
1020 @ Another handy subroutine computes the height plus depth of
1024 static scaled height_plus_depth
(internal_font_number f
, int c
)
1026 return
(char_height
(f
, c
) + char_depth
(f
, c
));
1029 @ When we build an extensible character
, it's handy to have the
1030 following subroutine
, which puts a given character on top
1031 of the characters already in box |b|
:
1034 static scaled stack_into_box
(pointer b
, internal_font_number f
, int c
)
1036 pointer p
, q
; /* new node placed into |b|
*/
1037 p
= char_box
(f
, c
, node_attr
(b
)); /* italic gets added to width
*/
1038 if
(type
(b
) == vlist_node
) {
1039 try_couple_nodes
(p
,list_ptr
(b
));
1041 height
(b
) = height
(p
);
1042 if
(width
(b
) < width
(p
))
1043 width
(b
) = width
(p
);
1044 return height_plus_depth
(f
, c
);
1050 while
(vlink
(q
) != null
)
1054 if
(height
(b
) < height
(p
))
1055 height
(b
) = height
(p
);
1056 if
(depth
(b
) < depth
(p
))
1057 depth
(b
) = depth
(p
);
1058 return char_width
(f
, c
);
1062 static void stack_glue_into_box
(pointer b
, scaled min
, scaled max
) {
1063 pointer p
, q
; /* new node placed into |b|
*/
1064 q
= new_spec
(zero_glue
);
1066 stretch
(q
) = max-min
;
1068 reset_attributes
(p
, node_attr
(b
));
1069 if
(type
(b
) == vlist_node
) {
1070 try_couple_nodes
(p
,list_ptr
(b
));
1077 while
(vlink
(q
) != null
)
1084 @ \TeX's most important routine for dealing with formulas is called
1085 |mlist_to_hlist|. After a formula has been scanned and represented
1086 as an mlist
, this routine converts it to an hlist that can be placed
1087 into a box or incorporated into the text of a paragraph. The
1088 explicit parameter |cur_mlist| points to the first node or noad in
1089 the given mlist
(and it might be |null|
); the parameter |penalties|
1090 is |true| if penalty nodes for potential line breaks are to be
1091 inserted into the resulting hlist
, the parameter |cur_style| is a
1092 style code. After |mlist_to_hlist| has acted
, |vlink
(temp_head
)|
1093 points to the translated hlist.
1095 Since mlists can be inside mlists
, the procedure is recursive. And since this
1096 is not part of \TeX's inner loop
, the program has been written in a manner
1097 that stresses compactness over efficiency.
1101 int cur_size
; /* size code corresponding to |cur_style|
*/
1104 static pointer get_delim_box
(pointer q
, extinfo
* ext
, internal_font_number f
, scaled v
,
1105 pointer att
, int cur_style
, int boxtype
)
1107 pointer b
; /* new box
*/
1108 scaled b_max
; /* natural
(maximum
) size of the stack
*/
1109 scaled s_max
; /* amount of possible shrink in the stack
*/
1111 scaled min_overlap
, prev_overlap
;
1112 int i
; /* a temporary counter number of extensible pieces
*/
1113 int with_extenders
; /* number of times to repeat each repeatable item in |ext|
*/
1114 int num_extenders
, num_normal
;
1117 assert
(ext
!= NULL);
1119 type
(b
) = (quarterword
) boxtype
;
1120 reset_attributes
(b
, att
);
1121 min_overlap
= connector_overlap_min
(cur_style
);
1122 assert
(min_overlap
>= 0);
1123 with_extenders
= -1;
1128 while
(cur
!= NULL) {
1129 if
(!char_exists
(f
, cur-
>glyph
)) {
1130 const char
*hlp
[] = {
1131 "Each glyph part in an extensible item should exist in the font.",
1132 "I will give up trying to find a suitable size for now. Fix your font!",
1135 tex_error
("Variant part doesn't exist.", hlp
);
1136 width
(b
) = null_delimiter_space
;
1139 if
(cur-
>extender
> 0)
1143 /* no negative overlaps or advances are allowed
*/
1144 if
(cur-
>start_overlap
< 0 || cur-
>end_overlap
< 0 || cur-
>advance
< 0) {
1145 const char
*hlp
[] = {
1146 "All measurements in extensible items should be positive.",
1147 "To get around this problem, I have changed the font metrics.",
1151 tex_error
("Extensible recipe has negative fields.", hlp
);
1152 if
(cur-
>start_overlap
< 0)
1153 cur-
>start_overlap
= 0;
1154 if
(cur-
>end_overlap
< 0)
1155 cur-
>end_overlap
= 0;
1156 if
(cur-
>advance
< 0)
1161 if
(num_normal
== 0) {
1162 const char
*hlp
[] = {
1163 "Each extensible recipe should have at least one non-repeatable part.",
1164 "To get around this problem, I have changed the first part to be",
1165 "non-repeatable. Fix your font!",
1168 tex_error
("Extensible recipe has no fixed parts.", hlp
);
1174 |ext| holds a linked list of numerous items that may or may not be
1175 repeatable. For the total height
, we have to figure out how many items
1176 are needed to create a stack of at least |v|.
1178 The next |while| loop does that. It has two goals
: it finds out
1179 the natural height |b_max| of the all the parts needed to reach
1180 at least |v|
, and it sets |with_extenders| to the number of times
1181 each of the repeatable items in |ext| has to be repeated to reach
1187 while
(b_max
< v
&& num_extenders > 0) {
1191 for
(cur
= ext
; cur
!= NULL; cur
= cur-
>next
) {
1192 if
(cur-
>extender
== 0) {
1193 c
= cur-
>start_overlap
;
1194 if
(min_overlap
< c
)
1196 if
(prev_overlap
< c
)
1201 if
(boxtype
== vlist_node
)
1202 a
= height_plus_depth
(f
, cur-
>glyph
);
1204 a
= char_width
(f
, cur-
>glyph
);
1208 prev_overlap
= cur-
>end_overlap
;
1212 c
= cur-
>start_overlap
;
1213 if
(min_overlap
< c
)
1215 if
(prev_overlap
< c
)
1220 if
(boxtype
== vlist_node
)
1221 a
= height_plus_depth
(f
, cur-
>glyph
);
1223 a
= char_width
(f
, cur-
>glyph
);
1227 prev_overlap
= cur-
>end_overlap
;
1235 assemble box using |with_extenders| copies of each extender
, with
1236 appropriate glue wherever an overlap occurs
1241 for
(cur
= ext
; cur
!= NULL; cur
= cur-
>next
) {
1242 if
(cur-
>extender
== 0) {
1243 c
= cur-
>start_overlap
;
1244 if
(prev_overlap
< c
)
1247 if
(min_overlap
< c
)
1250 stack_glue_into_box
(b
, -d
, -c
);
1251 s_max
+= (-c
) - (-d
);
1254 b_max
+= stack_into_box
(b
, f
, cur-
>glyph
);
1255 prev_overlap
= cur-
>end_overlap
;
1260 c
= cur-
>start_overlap
;
1261 if
(prev_overlap
< c
)
1264 if
(min_overlap
< c
)
1267 stack_glue_into_box
(b
, -d
, -c
);
1268 s_max
+= (-c
) - (-d
);
1271 b_max
+= stack_into_box
(b
, f
, cur-
>glyph
);
1272 prev_overlap
= cur-
>end_overlap
;
1278 /* set glue so as to stretch the connections if needed
*/
1281 if
(v
> b_max
&& s_max > 0) {
1283 /* don't stretch more than |s_max|
*/
1286 glue_order
(b
) = normal
;
1287 glue_sign
(b
) = stretching
;
1288 glue_set
(b
) = unfloat
(d
/(float
) s_max
);
1292 if
(boxtype
== vlist_node
) {
1301 @ The |var_delimiter| function
, which finds or constructs a sufficiently
1302 large delimiter
, is the most interesting of the auxiliary functions that
1303 currently concern us. Given a pointer |d| to a delimiter field in some noad
,
1304 together with a size code |s| and a vertical distance |v|
, this function
1305 returns a pointer to a box that contains the smallest variant of |d| whose
1306 height plus depth is |v| or more.
(And if no variant is large enough
, it
1307 returns the largest available variant.
) In particular
, this routine will
1308 construct arbitrarily large delimiters from extensible components
, if
1309 |d| leads to such characters.
1311 The value returned is a box whose |shift_amount| has been set so that
1312 the box is vertically centered with respect to the axis in the given size.
1313 If a built-up symbol is returned
, the height of the box before shifting
1314 will be the height of its topmost component.
1317 static void endless_loop_error
(internal_font_number g
, int y
)
1320 const char
*hlp
[] = {
1321 "You managed to create a seemingly endless charlist chain in the current",
1322 "font. I have counted until 10000 already and still have not escaped, so"
1323 "I will jump out of the loop all by myself now. Fix your font!",
1326 snprintf
(s
, 256, "Math error: endless loop in charlist (U+%04x in %s)",
1327 (int
) y
, font_name
(g
));
1331 static pointer do_delimiter
(pointer q
, pointer d
, int s
, scaled v
, boolean flat
, int cur_style
, boolean shift
, boolean
*stack
, scaled
*delta
)
1333 pointer b
; /* the box that will be constructed
*/
1334 internal_font_number f
, g
; /* best-so-far and tentative font codes
*/
1335 int c
, i
, x
, y
; /* best-so-far and tentative character codes
*/
1336 scaled u
; /* height-plus-depth of a tentative character
*/
1337 scaled w
; /* largest height-plus-depth so far
*/
1338 int z
; /* runs through font family members
*/
1339 boolean large_attempt
; /* are we trying the ``large'' variant?
*/
1340 pointer att
; /* to save the current attribute list
*/
1348 large_attempt
= false
;
1356 The search process is complicated slightly by the facts that some of the
1357 characters might not be present in some of the fonts
, and they might not
1358 be probed in increasing order of height.
1360 if
((z
!= 0) ||
(x
!= 0)) {
1362 if
(g
!= null_font
) {
1366 if
(char_exists
(g
, y
)) {
1368 u
= char_width
(g
, y
);
1370 u
= height_plus_depth
(g
, y
);
1378 if
(char_tag
(g
, y
) == ext_tag
) {
1386 endless_loop_error
(g
, y
);
1389 if
(char_tag
(g
, y
) == list_tag
) {
1390 y
= char_remainder
(g
, y
);
1397 goto FOUND
; /* there were none large enough
*/
1398 large_attempt
= true
;
1405 node_attr
(d
) = null
;
1408 if
(f
!= null_font
) {
1410 When the following code is executed
, |do_parts| will be true
1411 if a built-up symbol is supposed to be returned.
1414 if
((do_parts
) && ((!flat && (ext = get_charinfo_vert_variants(char_info(f,c))) != NULL)
1415 ||
( flat
&& (ext = get_charinfo_hor_variants (char_info(f,c))) != NULL))) {
1417 b
= get_delim_box
(d
, ext
, f
, v
, att
, cur_style
, hlist_node
);
1419 b
= get_delim_box
(d
, ext
, f
, v
, att
, cur_style
, vlist_node
);
1421 if
(delta
!= NULL) {
1422 if
(is_new_mathfont
(f
)) {
1423 *delta
= char_vert_italic
(f
,x
);
1425 *delta
= char_italic
(f
,x
);
1431 b
= char_box
(f
, c
, att
);
1432 if
(!is_new_mathfont
(f
)) {
1433 /* italic gets added to width
*/
1434 width
(b
) += char_italic
(f
, c
);
1436 if
(delta
!= NULL) {
1437 *delta
= char_italic
(f
,x
);
1444 reset_attributes
(b
, att
);
1448 /* use this width if no delimiter was found
*/
1449 width
(b
) = null_delimiter_space
;
1451 if
(delta
!= NULL) {
1458 /* vertical variant
*/
1459 shift_amount
(b
) = half
(height
(b
) - depth
(b
));
1461 shift_amount
(b
) -= math_axis
(s
);
1464 delete_attribute_ref
(att
);
1468 @ The next subroutine is much simpler
; it is used for numerators and
1469 denominators of fractions as well as for displayed operators and
1470 their limits above and below. It takes a given box~|b| and
1471 changes it so that the new box is centered in a box of width~|w|.
1472 The centering is done by putting \.
{\\hss
} glue at the left and right
1473 of the list inside |b|
, then packaging the new box
; thus
, the
1474 actual box might not really be centered
, if it already contains
1477 The given box might contain a single character whose italic correction
1478 has been added to the width of the box
; in this case a compensating
1482 static pointer rebox
(pointer b
, scaled w
)
1484 pointer p
, q
, r
, att
; /* temporary registers for list manipulation
*/
1485 internal_font_number f
; /* font in a one-character box
*/
1486 scaled v
; /* width of a character without italic correction
*/
1488 if
((width
(b
) != w
) && (list_ptr(b) != null)) {
1489 if
(type
(b
) == vlist_node
) {
1490 p
= hpack
(b
, 0, additional
, -1);
1491 reset_attributes
(p
, node_attr
(b
));
1496 add_node_attr_ref
(att
);
1497 if
((is_char_node
(p
)) && (vlink(p) == null)) {
1499 v
= char_width
(f
, character
(p
));
1500 if
(v
!= width
(b
)) {
1501 q
= new_kern
(width
(b
) - v
);
1502 reset_attributes
(q
, att
);
1508 b
= new_glue
(ss_glue
);
1509 reset_attributes
(b
, att
);
1511 while
(vlink
(p
) != null
)
1513 q
= new_glue
(ss_glue
);
1514 reset_attributes
(q
, att
);
1516 r
= hpack
(b
, w
, exactly
, -1);
1517 reset_attributes
(r
, att
);
1518 delete_attribute_ref
(att
);
1526 @ Here is a subroutine that creates a new glue specification from another
1527 one that is expressed in `\.
{mu
}'
, given the value of the math unit.
1530 #define mu_mult
(A
) mult_and_add
(n
,(A
),xn_over_d
((A
),f
,unity
),max_dimen
)
1532 static pointer math_glue
(pointer g
, scaled m
)
1534 pointer p
; /* the new glue specification
*/
1535 int n
; /* integer part of |m|
*/
1536 scaled f
; /* fraction part of |m|
*/
1537 n
= x_over_n
(m
, unity
);
1543 p
= new_node
(glue_spec_node
, 0);
1544 width
(p
) = mu_mult
(width
(g
)); /* convert \.
{mu
} to \.
{pt
} */
1545 stretch_order
(p
) = stretch_order
(g
);
1546 if
(stretch_order
(p
) == normal
)
1547 stretch
(p
) = mu_mult
(stretch
(g
));
1549 stretch
(p
) = stretch
(g
);
1550 shrink_order
(p
) = shrink_order
(g
);
1551 if
(shrink_order
(p
) == normal
)
1552 shrink
(p
) = mu_mult
(shrink
(g
));
1554 shrink
(p
) = shrink
(g
);
1558 @ The |math_kern| subroutine removes |mu_glue| from a kern node
, given
1559 the value of the math unit.
1562 static void math_kern
(pointer p
, scaled m
)
1564 int n
; /* integer part of |m|
*/
1565 scaled f
; /* fraction part of |m|
*/
1566 if
(subtype
(p
) == mu_glue
) {
1567 n
= x_over_n
(m
, unity
);
1573 width
(p
) = mu_mult
(width
(p
));
1574 subtype
(p
) = italic_kern
;
1579 void run_mlist_to_hlist
(halfword p
, boolean penalties
, int mstyle
)
1583 lua_State
*L
= Luas
;
1585 vlink
(temp_head
) = null
;
1588 finalize_math_parameters
();
1589 callback_id
= callback_defined
(mlist_to_hlist_callback
);
1590 if
(callback_id
> 0) {
1591 sfix
= lua_gettop
(L
);
1592 if
(!get_callback
(L
, callback_id
)) {
1593 lua_settop
(L
, sfix
);
1597 nodelist_to_lua
(L
, p
);
1599 lua_pushstring
(L
, math_style_names
[mstyle
]);
1601 lua_push_math_style_name
(L
,mstyle
);
1602 lua_pushboolean
(L
, penalties
);
1603 if
(lua_pcall
(L
, 3, 1, 0) != 0) { /* 3 args
, 1 result
*/
1604 char errmsg
[256]; /* temp hack ... we will have a formatted error
*/
1605 snprintf
(errmsg
, 255, "error: %s\n", lua_tostring
(L
, -1));
1607 lua_settop
(L
, sfix
);
1608 normal_error
("mlist to hlist",errmsg
); /* to be done
*/
1611 a
= nodelist_from_lua
(L
);
1612 /* alink
(vlink
(a
)) = null
; */
1613 lua_settop
(L
, sfix
);
1614 vlink
(temp_head
) = a
;
1615 } else if
(callback_id
== 0) {
1616 mlist_to_hlist
(p
, penalties
, mstyle
);
1618 vlink
(temp_head
) = null
;
1622 @ The recursion in |mlist_to_hlist| is due primarily to a subroutine
1623 called |clean_box| that puts a given noad field into a box using a given
1624 math style
; |mlist_to_hlist| can call |clean_box|
, which can call
1628 The box returned by |clean_box| is ``clean'' in the
1629 sense that its |shift_amount| is zero.
1632 static pointer clean_box
(pointer p
, int s
, int cur_style
)
1634 pointer q
; /* beginning of a list to be boxed
*/
1635 pointer x
; /* box to be returned
*/
1636 pointer r
; /* temporary pointer
*/
1637 pointer mlist
= null
; /* beginning of mlist to be translated
*/
1639 case math_char_node
:
1648 case sub_mlist_node
:
1649 mlist
= math_list
(p
);
1655 mlist_to_hlist
(mlist
, false
, s
);
1656 q
= vlink
(temp_head
); /* recursive call
*/
1657 setup_cur_size
(cur_style
);
1659 if
(is_char_node
(q
) ||
(q
== null
))
1660 x
= hpack
(q
, 0, additional
, -1);
1661 else if
((vlink
(q
) == null
) && (type(q) <= vlist_node) && (shift_amount(q) == 0))
1662 x
= q
; /* it's already clean
*/
1664 x
= hpack
(q
, 0, additional
, -1);
1665 if
(x
!= q
&& q != null)
1666 reset_attributes
(x
, node_attr
(q
));
1667 /* Here we save memory space in a common case.
*/
1669 if
(is_char_node
(q
)) {
1672 if
(vlink
(r
) == null
) {
1673 if
(!is_char_node
(r
)) {
1674 if
(type
(r
) == kern_node
) {
1675 /* unneeded italic correction
*/
1686 @ It is convenient to have a procedure that converts a |math_char|
1687 field to an ``unpacked'' form. The |fetch| routine sets |cur_f| and |cur_c|
1688 to the font code and character code of a given noad field.
1689 It also takes care of issuing error messages for
1690 nonexistent characters
; in such cases
, |char_exists
(cur_f
,cur_c
)| will be |false|
1691 after |fetch| has acted
, and the field will also have been reset to |null|.
1693 The outputs of |fetch| are placed in global variables.
1696 internal_font_number cur_f
; /* the |font| field of a |math_char|
*/
1697 int cur_c
; /* the |character| field of a |math_char|
*/
1699 @ Here we unpack the |math_char| field |a|.
1701 @c static void fetch
(pointer a
)
1703 cur_c
= math_character
(a
);
1704 cur_f
= fam_fnt
(math_fam
(a
), cur_size
);
1705 if
(cur_f
== null_font
) {
1707 const char
*hlp
[] = {
1708 "Somewhere in the math formula just ended, you used the",
1709 "stated character from an undefined font family. For example,",
1710 "plain TeX doesn't allow \\it or \\sl in subscripts. Proceed,",
1711 "and I'll try to forget that I needed that character.",
1715 snprintf
(msg
, 255, "\\%s%d is undefined (character %d)",
1716 math_size_string
(cur_size
), (int
) math_fam
(a
), (int
) cur_c
);
1717 tex_error
(msg
, hlp
);
1719 } else if
(!(char_exists
(cur_f
, cur_c
))) {
1720 char_warning
(cur_f
, cur_c
);
1724 @ We need to do a lot of different things
, so |mlist_to_hlist| makes two
1725 passes over the given mlist.
1727 The first pass does most of the processing
: It removes ``mu'' spacing from
1728 glue
, it recursively evaluates all subsidiary mlists so that only the
1729 top-level mlist remains to be handled
, it puts fractions and square roots
1730 and such things into boxes
, it attaches subscripts and superscripts
, and
1731 it computes the overall height and depth of the top-level mlist so that
1732 the size of delimiters for a |fence_noad| will be known.
1733 The hlist resulting from each noad is recorded in that noad's |new_hlist|
1734 field
, an integer field that replaces the |nucleus| or |thickness|.
1737 The second pass eliminates all noads and inserts the correct glue and
1738 penalties between nodes.
1741 static void assign_new_hlist
(pointer q
, pointer r
)
1745 math_list
(numerator
(q
)) = null
;
1746 flush_node
(numerator
(q
));
1747 numerator
(q
) = null
;
1748 math_list
(denominator
(q
)) = null
;
1749 flush_node
(denominator
(q
));
1750 denominator
(q
) = null
;
1755 if
(nucleus
(q
) != null
) {
1756 math_list
(nucleus
(q
)) = null
;
1757 flush_node
(nucleus
(q
));
1766 #define choose_mlist
(A
) do
{ p
=A
(q
); A
(q
)=null
; } while
(0)
1768 @ Most of the actual construction work of |mlist_to_hlist| is done
1769 by procedures with names like |make_fraction|
, |make_radical|
, etc. To
1770 illustrate the general setup of such procedures
, let's begin with a
1771 couple of simple ones.
1774 static void make_over
(pointer q
, int cur_style
)
1777 p
= overbar
(clean_box
(nucleus
(q
), cramped_style
(cur_style
), cur_style
),
1778 overbar_vgap
(cur_style
), overbar_rule
(cur_style
),
1779 overbar_kern
(cur_style
), node_attr
(nucleus
(q
)));
1780 math_list
(nucleus
(q
)) = p
;
1781 type
(nucleus
(q
)) = sub_box_node
;
1784 static void make_under
(pointer q
, int cur_style
)
1786 pointer p
, x
, y
, r
; /* temporary registers for box construction
*/
1787 scaled delta
; /* overall height plus depth
*/
1788 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
1789 p
= new_kern
(underbar_vgap
(cur_style
));
1790 reset_attributes
(p
, node_attr
(q
));
1792 r
= do_fraction_rule
(underbar_rule
(cur_style
), node_attr
(q
));
1794 y
= vpackage
(x
, 0, additional
, max_dimen
, math_direction
);
1795 reset_attributes
(y
, node_attr
(q
));
1796 delta
= height
(y
) + depth
(y
) + underbar_kern
(cur_style
);
1797 height
(y
) = height
(x
);
1798 depth
(y
) = delta
- height
(y
);
1799 math_list
(nucleus
(q
)) = y
;
1800 type
(nucleus
(q
)) = sub_box_node
;
1803 static void make_vcenter
(pointer q
)
1805 pointer v
; /* the box that should be centered vertically
*/
1806 scaled delta
; /* its height plus depth
*/
1807 v
= math_list
(nucleus
(q
));
1808 if
(type
(v
) != vlist_node
)
1809 confusion
("vcenter");
1810 delta
= height
(v
) + depth
(v
);
1811 height
(v
) = math_axis
(cur_size
) + half
(delta
);
1812 depth
(v
) = delta
- height
(v
);
1815 @ According to the rules in the \.
{DVI
} file specifications
, we ensure alignment
1817 between a square root sign and the rule above its nucleus by assuming that the
1818 baseline of the square-root symbol is the same as the bottom of the rule. The
1819 height of the square-root symbol will be the thickness of the rule
, and the
1820 depth of the square-root symbol should exceed or equal the height-plus-depth
1821 of the nucleus plus a certain minimum clearance~|psi|. The symbol will be
1822 placed so that the actual clearance is |psi| plus half the excess.
1825 static void make_hextension
(pointer q
, int cur_style
)
1829 boolean stack
= false
;
1830 e
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, radicalwidth
(q
), true
, cur_style
, true
, &stack, NULL);
1832 if
(!stack
&& (radicalwidth(q) != 0) && (radicalwidth(q) != width(e))) {
1833 if
(radicalmiddle
(q
)) {
1834 p
= new_kern
(half
(radicalwidth
(q
)-w
));
1835 reset_attributes
(p
, node_attr
(q
));
1838 w
= radicalwidth
(q
);
1839 } else if
(radicalexact
(q
)) {
1840 w
= radicalwidth
(q
);
1843 e
= hpack
(e
, 0, additional
, -1);
1845 reset_attributes
(e
, node_attr
(q
));
1846 math_list
(nucleus
(q
)) = e
;
1847 left_delimiter
(q
) = null
;
1850 static void make_radical
(pointer q
, int cur_style
)
1852 pointer x
, y
, p
, l1
, l2
; /* temporary registers for box construction
*/
1853 scaled delta
, clr
, theta
, h
; /* dimensions involved in the calculation
*/
1854 x
= clean_box
(nucleus
(q
), cramped_style
(cur_style
), cur_style
);
1855 clr
= radical_vgap
(cur_style
);
1856 theta
= radical_rule
(cur_style
);
1857 if
(theta
== undefined_math_parameter
) {
1858 /* a real radical
*/
1859 theta
= fraction_rule
(cur_style
);
1860 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, height
(x
) + depth
(x
) + clr
+ theta
, false
, cur_style
, true
, NULL, NULL);
1862 If |y| is a composite then set |theta| to the height of its top
1863 character
, else set it to the height of |y|.
1866 if
((l1
!= null
) && (type(l1) == hlist_node)) {
1867 /* possible composite
*/
1869 if
((l2
!= null
) && (type(l2) == glyph_node)) {
1871 theta
= char_height
(font
(l2
), character
(l2
));
1879 /* not really a radical but we use its node
, historical sharing
(like in mathml
) */
1880 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, height
(x
) + depth
(x
) + clr
+ theta
, false
, cur_style
, true
, NULL, NULL);
1882 left_delimiter
(q
) = null
;
1883 delta
= (depth
(y
) + height
(y
) - theta
) - (height
(x
) + depth
(x
) + clr
);
1885 /* increase the actual clearance
*/
1886 clr
= clr
+ half
(delta
);
1888 shift_amount
(y
) = (height
(y
) - theta
) - (height
(x
) + clr
);
1889 h
= depth
(y
) + height
(y
);
1890 p
= overbar
(x
, clr
, theta
, radical_kern
(cur_style
), node_attr
(y
));
1892 if
(degree
(q
) != null
) {
1894 pointer r
= clean_box
(degree
(q
), script_script_style
, cur_style
);
1895 reset_attributes
(r
, node_attr
(degree
(q
)));
1900 br
= radical_degree_before
(cur_style
);
1901 ar
= radical_degree_after
(cur_style
);
1902 if
(-ar
> (wr
+ br
))
1905 reset_attributes
(x
, node_attr
(degree
(q
)));
1908 -((xn_over_d
(h
, radical_degree_raise
(cur_style
), 100)) -
1909 depth
(y
) - shift_amount
(y
));
1912 reset_attributes
(x
, node_attr
(degree
(q
)));
1916 /* for \.
{\\Uroot ..
{<list
>}{}} : */
1917 math_list
(degree
(q
)) = null
;
1918 flush_node
(degree
(q
));
1920 p
= hpack
(y
, 0, additional
, -1);
1921 reset_attributes
(p
, node_attr
(q
));
1922 math_list
(nucleus
(q
)) = p
;
1923 type
(nucleus
(q
)) = sub_box_node
;
1926 @ Construct a vlist box
1929 static pointer wrapup_over_under_delimiter
(pointer x
, pointer y
, pointer q
, scaled shift_up
, scaled shift_down
)
1931 pointer p
; /* temporary register for box construction
*/
1932 pointer v
= new_null_box
();
1933 type
(v
) = vlist_node
;
1934 height
(v
) = shift_up
+ height
(x
);
1935 depth
(v
) = depth
(y
) + shift_down
;
1936 reset_attributes
(v
, node_attr
(q
));
1937 p
= new_kern
((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
1938 reset_attributes
(p
, node_attr
(q
));
1945 /* when exact use radicalwidth
(y is delimiter
) */
1949 #define fixup_widths
(q
,x
,y
) do
{ \
1950 if
(width
(y
) >= width
(x
)) { \
1951 if
(radicalwidth
(q
) != zero_glue
) { \
1952 shift_amount
(x
) += half
(width
(y
)-width
(x
)) ; \
1954 width
(x
) = width
(y
); \
1956 if
(radicalwidth
(q
) != zero_glue
) { \
1957 shift_amount
(y
) += half
(width
(x
)-width
(y
)) ; \
1959 width
(y
) = width
(x
); \
1964 #define check_radical
(q
,stack
,r
,t
) do
{ \
1965 if
(!stack
&& (width(r) >= width(t)) && (radicalwidth(q) != zero_glue) && (radicalwidth(q) != width(r))) { \
1966 if
(radicalleft
(q
)) { \
1967 halfword p
= new_kern
(radicalwidth
(q
)-width
(r
)); \
1968 reset_attributes
(p
, node_attr
(q
)); \
1969 couple_nodes
(p
,r
); \
1970 r
= hpack
(p
, 0, additional
, -1); \
1971 width
(r
) = radicalwidth
(q
); \
1972 reset_attributes
(r
, node_attr
(q
)); \
1973 } else if
(radicalmiddle
(q
)) { \
1974 halfword p
= new_kern
(half
(radicalwidth
(q
)-width
(r
))); \
1975 reset_attributes
(p
, node_attr
(q
)); \
1976 couple_nodes
(p
,r
); \
1977 r
= hpack
(p
, 0, additional
, -1); \
1978 width
(r
) = radicalwidth
(q
); \
1979 reset_attributes
(r
, node_attr
(q
)); \
1980 } else if
(radicalright
(q
)) { \
1981 /* also kind of exact compared to vertical
*/ \
1982 r
= hpack
(r
, 0, additional
, -1); \
1983 width
(r
) = radicalwidth
(q
); \
1984 reset_attributes
(r
, node_attr
(q
)); \
1989 #define check_widths
(q
,p
) do
{ \
1990 if
(radicalwidth
(q
) != zero_glue
) { \
1991 wd
= radicalwidth
(q
); \
1997 @ this has the |nucleus| box |x| as a limit above an extensible delimiter |y|
2000 static void make_over_delimiter
(pointer q
, int cur_style
)
2002 pointer x
, y
, v
; /* temporary registers for box construction
*/
2003 scaled shift_up
, shift_down
, clr
, delta
, wd
;
2005 x
= clean_box
(nucleus
(q
), sub_style
(cur_style
), cur_style
);
2007 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, wd
, true
, cur_style
, true
, &stack, NULL);
2008 left_delimiter
(q
) = null
;
2009 check_radical
(q
,stack
,y
,x
);
2010 fixup_widths
(q
, x
, y
);
2011 shift_up
= over_delimiter_bgap
(cur_style
);
2013 clr
= over_delimiter_vgap
(cur_style
);
2014 delta
= clr
- ((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
2016 shift_up
= shift_up
+ delta
;
2018 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2019 width
(v
) = width
(x
); /* this also equals |width
(y
)|
*/
2020 math_list
(nucleus
(q
)) = v
;
2021 type
(nucleus
(q
)) = sub_box_node
;
2024 @ this has the extensible delimiter |x| as a limit below |nucleus| box |y|
2027 static void make_under_delimiter
(pointer q
, int cur_style
)
2029 pointer x
, y
, v
; /* temporary registers for box construction
*/
2030 scaled shift_up
, shift_down
, clr
, delta
, wd
;
2032 y
= clean_box
(nucleus
(q
), sup_style
(cur_style
), cur_style
);
2034 x
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, wd
, true
, cur_style
, true
, &stack, NULL);
2035 left_delimiter
(q
) = null
;
2036 check_radical
(q
,stack
,x
,y
);
2037 fixup_widths
(q
, x
, y
);
2039 shift_down
= under_delimiter_bgap
(cur_style
);
2040 clr
= under_delimiter_vgap
(cur_style
);
2041 delta
= clr
- ((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
2043 shift_down
= shift_down
+ delta
;
2045 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2046 width
(v
) = width
(y
); /* this also equals |width
(y
)|
*/
2047 math_list
(nucleus
(q
)) = v
;
2048 type
(nucleus
(q
)) = sub_box_node
;
2051 @ this has the extensible delimiter |x| as a limit above |nucleus| box |y|
2054 static void make_delimiter_over
(pointer q
, int cur_style
)
2056 pointer x
, y
, v
; /* temporary registers for box construction
*/
2057 scaled shift_up
, shift_down
, clr
, actual
, wd
;
2059 y
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2061 x
= do_delimiter
(q
, left_delimiter
(q
), cur_size
+ (cur_size
== script_script_size ?
0 : 1), wd
, true
, cur_style
, true
, &stack, NULL);
2062 left_delimiter
(q
) = null
;
2063 check_radical
(q
,stack
,x
,y
);
2064 fixup_widths
(q
, x
, y
);
2065 shift_up
= over_delimiter_bgap
(cur_style
)-height
(x
)-depth
(x
);
2067 clr
= over_delimiter_vgap
(cur_style
);
2068 actual
= shift_up
- height
(y
);
2070 shift_up
= shift_up
+ (clr-actual
);
2072 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2073 width
(v
) = width
(x
); /* this also equals |width
(y
)|
*/
2074 math_list
(nucleus
(q
)) = v
;
2075 type
(nucleus
(q
)) = sub_box_node
;
2078 @ this has the extensible delimiter |y| as a limit below a |nucleus| box |x|
2081 static void make_delimiter_under
(pointer q
, int cur_style
)
2083 pointer x
, y
, v
; /* temporary registers for box construction
*/
2084 scaled shift_up
, shift_down
, clr
, actual
, wd
;
2086 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2088 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
+ (cur_size
== script_script_size ?
0 : 1), wd
, true
, cur_style
, true
, &stack, NULL);
2089 left_delimiter
(q
) = null
;
2090 check_radical
(q
,stack
,y
,x
);
2091 fixup_widths
(q
, x
, y
);
2093 shift_down
= under_delimiter_bgap
(cur_style
) - height
(y
)-depth
(y
);
2094 clr
= under_delimiter_vgap
(cur_style
);
2095 actual
= shift_down
- depth
(x
);
2097 shift_down
+= (clr-actual
);
2099 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2100 width
(v
) = width
(y
); /* this also equals |width
(y
)|
*/
2101 math_list
(nucleus
(q
)) = v
;
2102 type
(nucleus
(q
)) = sub_box_node
;
2105 @ Slants are not considered when placing accents in math mode. The accenter is
2106 centered over the accentee
, and the accent width is treated as zero with
2107 respect to the size of the final box.
2112 #define OVERLAY_CODE
4
2113 #define STRETCH_ACCENT_CODE
8
2115 static boolean compute_accent_skew
(pointer q
, int flags
, scaled
*s
)
2117 pointer p
; /* temporary register for box construction
*/
2118 boolean s_is_absolute
= false
; /* will be true if a top-accent is placed in |s|
*/
2119 if
(type
(nucleus
(q
)) == math_char_node
) {
2121 if
(is_new_mathfont
(cur_f
)) {
2123 there is no bot_accent so let's assume similarity
2125 if
(flags
& (TOP_CODE | OVERLAY_CODE)) {
2126 *s
= char_top_accent
(cur_f
, cur_c
);
2127 if
(*s
!= INT_MIN
) {
2128 s_is_absolute
= true
;
2131 *s
= char_bot_accent
(cur_f
, cur_c
);
2132 if
(*s
!= INT_MIN
) {
2133 s_is_absolute
= true
;
2137 *s
= char_top_accent
(cur_f
, cur_c
);
2138 if
(*s
!= INT_MIN
) {
2139 s_is_absolute
= true
;
2142 if
(flags
& TOP_CODE) {
2143 *s
= get_kern
(cur_f
, cur_c
, skew_char
(cur_f
));
2148 } else if
(type
(nucleus
(q
)) == sub_mlist_node
) {
2150 if |nucleus
(q
)| is a |sub_mlist_node| composed of an |accent_noad| we
2152 * use the positioning of the nucleus of that noad
, recursing until
2153 * the inner most |accent_noad|. This way multiple stacked accents are
2154 * aligned to the inner most one.
2156 p
= math_list
(nucleus
(q
));
2157 if
(type
(p
) == accent_noad
) {
2158 s_is_absolute
= compute_accent_skew
(p
, flags
, s
);
2162 return s_is_absolute
;
2165 static void do_make_math_accent
(pointer q
, internal_font_number f
, int c
, int flags
, int cur_style
)
2167 pointer p
, r
, x
, y
; /* temporary registers for box construction
*/
2168 scaled s
; /* amount to skew the accent to the right
*/
2169 scaled h
; /* height of character being accented
*/
2170 scaled delta
; /* space to remove between accent and accentee
*/
2171 scaled w
; /* width of the accentee
, not including sub
/superscripts
*/
2172 boolean s_is_absolute
; /* will be true if a top-accent is placed in |s|
*/
2177 attr_p
= (flags
& TOP_CODE ? top_accent_chr(q) : flags & BOT_CODE ? bot_accent_chr(q) : overlay_accent_chr(q));
2178 fraction
= accentfraction
(q
);
2182 if
(fraction
== 0) {
2185 /* Compute the amount of skew
, or set |s| to an alignment point
*/
2186 s_is_absolute
= compute_accent_skew
(q
, flags
, &s);
2187 x
= clean_box
(nucleus
(q
), cramped_style
(cur_style
), cur_style
);
2190 if
(is_new_mathfont
(cur_f
) && !s_is_absolute) {
2192 s_is_absolute
= true
;
2194 /* Switch to a larger accent if available and appropriate
*/
2197 if
(flags
& OVERLAY_CODE) {
2199 target
= xn_over_d
(h
,fraction
,1000);
2205 target
= xn_over_d
(w
,fraction
,1000);
2210 if
((flags
& STRETCH_ACCENT_CODE) && (char_width(f, c) < w)) {
2212 if
((char_tag
(f
, c
) == ext_tag
) && ((ext = get_charinfo_hor_variants(char_info(f, c))) != NULL)) {
2213 /* a bit weird for an overlay but anyway
, here we don't need a factor as we don't step
*/
2214 y
= get_delim_box
(q
, ext
, f
, w
, node_attr
(attr_p
), cur_style
, hlist_node
);
2216 } else if
(char_tag
(f
, c
) != list_tag
) {
2219 int yy
= char_remainder
(f
, c
);
2220 if
(!char_exists
(f
, yy
)) {
2222 } else if
(flags
& OVERLAY_CODE) {
2223 if
(char_height
(f
, yy
) > target
) {
2227 if
(char_width
(f
, yy
) > target
)
2235 y
= char_box
(f
, c
, node_attr
(attr_p
)); /* italic gets added to width
*/
2237 if
(flags
& TOP_CODE) {
2238 if
(h
< accent_base_height
(f
)) {
2241 delta
= accent_base_height
(f
);
2243 } else if
(flags
& OVERLAY_CODE) {
2244 delta
= half
(height
(y
) + depth
(y
) + height
(x
) + depth
(x
)); /* center the accent vertically around the accentee
*/
2248 if
((supscr
(q
) != null
) ||
(subscr
(q
) != null
)) {
2249 if
(type
(nucleus
(q
)) == math_char_node
) {
2250 /* swap the subscript and superscript into box |x|
*/
2253 r
= math_clone
(nucleus
(q
));
2255 supscr
(x
) = supscr
(q
);
2257 subscr
(x
) = subscr
(q
);
2259 type
(nucleus
(q
)) = sub_mlist_node
;
2260 math_list
(nucleus
(q
)) = x
;
2261 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2262 delta
= delta
+ height
(x
) - h
;
2266 /* the top accents of both characters are aligned
*/
2267 if
(s_is_absolute
) {
2270 /* if the accent is extensible just take the center
*/
2271 sa
= half
(width
(y
));
2274 there is no bot_accent so let's assume similarity
2276 if
(flags
& BOT_CODE) {
2277 sa
= char_bot_accent
(f
, c
);
2279 sa
= char_top_accent
(f
, c
);
2282 sa
= char_top_accent
(f
, c
);
2284 if
(sa
== INT_MIN
) {
2285 /* just take the center
*/
2286 sa
= half
(width
(y
));
2288 if
(math_direction
== dir_TRT
) {
2289 shift_amount
(y
) = s
+ sa
- width
(y
);
2291 shift_amount
(y
) = s
- sa
;
2295 shift_amount
(y
) = s
+ w
;
2296 } else if
(math_direction
== dir_TRT
) {
2297 shift_amount
(y
) = s
+ width
(y
); /* ok?
*/
2299 shift_amount
(y
) = s
+ half
(w
- width
(y
));
2303 if
(flags
& (TOP_CODE | OVERLAY_CODE)) {
2304 p
= new_kern
(-delta
);
2305 reset_attributes
(p
, node_attr
(q
));
2312 r
= vpackage
(y
, 0, additional
, max_dimen
, math_direction
);
2313 reset_attributes
(r
, node_attr
(q
));
2314 width
(r
) = width
(x
);
2316 if
(flags
& (TOP_CODE | OVERLAY_CODE)) {
2317 if
(height
(y
) < h
) {
2318 /* make the height of box |y| equal to |h|
*/
2319 p
= new_kern
(h
- height
(y
));
2320 reset_attributes
(p
, node_attr
(q
));
2321 try_couple_nodes
(p
,list_ptr
(y
));
2326 shift_amount
(y
) = -(h
- height
(y
));
2328 math_list
(nucleus
(q
)) = y
;
2329 type
(nucleus
(q
)) = sub_box_node
;
2332 static void make_math_accent
(pointer q
, int cur_style
)
2334 int topstretch
= !(subtype
(q
) % 2);
2335 int botstretch
= !(subtype
(q
) / 2);
2337 if
(top_accent_chr
(q
) != null
) {
2338 fetch
(top_accent_chr
(q
));
2339 if
(char_exists
(cur_f
, cur_c
)) {
2340 do_make_math_accent
(q
, cur_f
, cur_c
, TOP_CODE |
(topstretch ? STRETCH_ACCENT_CODE
: 0), cur_style
);
2342 flush_node
(top_accent_chr
(q
));
2343 top_accent_chr
(q
) = null
;
2345 if
(bot_accent_chr
(q
) != null
) {
2346 fetch
(bot_accent_chr
(q
));
2347 if
(char_exists
(cur_f
, cur_c
)) {
2348 do_make_math_accent
(q
, cur_f
, cur_c
, BOT_CODE |
(botstretch ? STRETCH_ACCENT_CODE
: 0), cur_style
);
2350 flush_node
(bot_accent_chr
(q
));
2351 bot_accent_chr
(q
) = null
;
2353 if
(overlay_accent_chr
(q
) != null
) {
2354 fetch
(overlay_accent_chr
(q
));
2355 if
(char_exists
(cur_f
, cur_c
)) {
2356 do_make_math_accent
(q
, cur_f
, cur_c
, OVERLAY_CODE | STRETCH_ACCENT_CODE
, cur_style
);
2358 flush_node
(overlay_accent_chr
(q
));
2359 overlay_accent_chr
(q
) = null
;
2363 @ The |make_fraction| procedure is a bit different because it sets
2364 |new_hlist
(q
)| directly rather than making a sub-box.
2367 static void make_fraction
(pointer q
, int cur_style
)
2369 pointer p
, p1
, p2
, v
, x
, y
, z
, l
, r
, m
; /* temporary registers for box construction
*/
2370 scaled delta
, delta1
, delta2
, shift_up
, shift_down
, clr1
, clr2
;
2371 /* dimensions for box calculations
*/
2372 if
(thickness
(q
) == default_code
)
2373 thickness
(q
) = fraction_rule
(cur_style
);
2375 Create equal-width boxes |x| and |z| for the numerator and denominator
,
2376 and compute the default amounts |shift_up| and |shift_down| by which they
2377 are displaced from the baseline
2380 x
= clean_box
(numerator
(q
), num_style
(cur_style
), cur_style
);
2381 z
= clean_box
(denominator
(q
), denom_style
(cur_style
), cur_style
);
2383 if
(middle_delimiter
(q
) != null
) {
2385 m
= do_delimiter
(q
, middle_delimiter
(q
), cur_size
, delta
, false
, cur_style
, true
, NULL, NULL);
2386 middle_delimiter
(q
) = null
;
2389 if
(width
(x
) < width
(z
)) {
2390 x
= rebox
(x
, width
(z
));
2392 z
= rebox
(z
, width
(x
));
2399 } else if
(thickness
(q
) == 0) {
2400 shift_up
= stack_num_up
(cur_style
);
2401 shift_down
= stack_denom_down
(cur_style
);
2403 the numerator and denominator must be separated by a certain minimum
2404 clearance
, called |clr| in the following program. The difference between
2405 |clr| and the actual clearance is |
2delta|.
2407 clr1
= stack_vgap
(cur_style
);
2408 delta
= half
(clr1
- ((shift_up
- depth
(x
)) - (height
(z
) - shift_down
)));
2410 shift_up
= shift_up
+ delta
;
2411 shift_down
= shift_down
+ delta
;
2414 shift_up
= fraction_num_up
(cur_style
);
2415 shift_down
= fraction_denom_down
(cur_style
);
2417 in the case of a fraction line
, the minimum clearance depends on the actual
2418 thickness of the line.
2420 clr1
= fraction_num_vgap
(cur_style
);
2421 clr2
= fraction_denom_vgap
(cur_style
);
2422 delta
= half
(thickness
(q
));
2423 if
(fractionexact
(q
)) {
2424 delta1
= clr1
- ((shift_up
- depth
(x
) ) - (math_axis
(cur_size
) + delta
));
2425 delta2
= clr2
- ((shift_down
- height
(z
)) + (math_axis
(cur_size
) - delta
));
2427 delta
= half
(thickness
(q
));
2428 clr1
= ext_xn_over_d
(clr1
, thickness
(q
), fraction_rule
(cur_style
));
2429 clr2
= ext_xn_over_d
(clr2
, thickness
(q
), fraction_rule
(cur_style
));
2430 delta1
= clr1
- ((shift_up
- depth
(x
) ) - (math_axis
(cur_size
) + delta
));
2431 delta2
= clr2
- ((shift_down
- height
(z
)) + (math_axis
(cur_size
) - delta
));
2434 shift_up
= shift_up
+ delta1
;
2437 shift_down
= shift_down
+ delta2
;
2442 construct a hlist box for the fraction
, according to |hgap| and |vgap|
2444 shift_up
= skewed_fraction_vgap
(cur_style
);
2446 if
(!fractionnoaxis
(q
)) {
2447 shift_up
+= half
(math_axis
(cur_size
));
2450 shift_down
= shift_up
;
2452 reset_attributes
(v
, node_attr
(q
));
2453 type
(v
) = hlist_node
;
2455 width
(v
) = width
(x
);
2456 height
(v
) = height
(x
) + shift_up
;
2457 depth
(v
) = depth
(x
);
2458 shift_amount
(v
) = - shift_up
;
2462 reset_attributes
(v
, node_attr
(q
));
2463 type
(v
) = hlist_node
;
2465 width
(v
) = width
(z
);
2466 height
(v
) = height
(z
);
2467 depth
(v
) = depth
(z
) + shift_down
;
2468 shift_amount
(v
) = shift_down
;
2472 reset_attributes
(v
, node_attr
(q
));
2473 type
(v
) = hlist_node
;
2474 if
(height
(x
) > height
(z
)) {
2475 height
(v
) = height
(x
);
2477 height
(v
) = height
(z
);
2479 if
(depth
(x
) > depth
(z
)) {
2480 depth
(v
) = depth
(x
);
2482 depth
(v
) = depth
(z
);
2484 if
(height
(m
) > height
(v
)) {
2485 height
(v
) = height
(m
);
2487 if
(depth
(m
) > depth
(v
)) {
2488 depth
(v
) = depth
(m
);
2491 if
(fractionexact
(q
)) {
2492 delta1
= -half
(skewed_fraction_hgap
(cur_style
));
2494 width
(v
) = width
(x
) + width
(z
) + width
(m
) - skewed_fraction_hgap
(cur_style
);
2496 delta1
= half
(skewed_fraction_hgap
(cur_style
)-width
(m
));
2497 delta2
= half
(skewed_fraction_hgap
(cur_style
)+width
(m
));
2498 width
(v
) = width
(x
) + width
(z
) + skewed_fraction_hgap
(cur_style
);
2502 p1
= new_kern
(delta1
);
2503 reset_attributes
(p1
, node_attr
(q
));
2504 p2
= new_kern
(delta2
);
2505 reset_attributes
(p2
, node_attr
(q
));
2515 construct a vlist box for the fraction
, according to |shift_up| and |shift_down|
2518 type
(v
) = vlist_node
;
2519 height
(v
) = shift_up
+ height
(x
);
2520 depth
(v
) = depth
(z
) + shift_down
;
2521 width
(v
) = width
(x
); /* this also equals |width
(z
)|
*/
2522 reset_attributes
(v
, node_attr
(q
));
2523 if
(thickness
(q
) == 0) {
2524 p
= new_kern
((shift_up
- depth
(x
)) - (height
(z
) - shift_down
));
2527 y
= do_fraction_rule
(thickness
(q
), node_attr
(q
));
2528 p
= new_kern
((math_axis
(cur_size
) - delta
) - (height
(z
) - shift_down
));
2529 reset_attributes
(p
, node_attr
(q
));
2532 p
= new_kern
((shift_up
- depth
(x
)) - (math_axis
(cur_size
) + delta
));
2535 reset_attributes
(p
, node_attr
(q
));
2540 put the fraction into a box with its delimiters
, and make |new_hlist
(q
)|
2543 if
(is_new_mathfont
(cur_f
)) {
2544 if
(math_use_old_fraction_scaling
) {
2545 delta
= fraction_del_size_old
(cur_style
);
2547 delta
= fraction_del_size_new
(cur_style
);
2549 if
(delta
== undefined_math_parameter
) {
2550 delta
= get_delimiter_height
(depth
(v
), height
(v
), true
);
2553 delta
= fraction_del_size_old
(cur_style
);
2556 l
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, delta
, false
, cur_style
, true
, NULL, NULL);
2557 left_delimiter
(q
) = null
;
2558 r
= do_delimiter
(q
, right_delimiter
(q
), cur_size
, delta
, false
, cur_style
, true
, NULL, NULL);
2559 right_delimiter
(q
) = null
;
2562 y
= hpack
(l
, 0, additional
, -1);
2563 reset_attributes
(y
, node_attr
(q
));
2564 assign_new_hlist
(q
, y
);
2567 @ If the nucleus of an |op_noad| is a single character
, it is to be
2568 centered vertically with respect to the axis
, after first being enlarged
2569 (via a character list in the font
) if we are in display style. The normal
2570 convention for placing displayed limits is to put them above and below the
2571 operator in display style.
2573 The italic correction is removed from the character if there is a subscript
2574 and the limits are not being displayed. The |make_op| routine returns the
2575 value that should be used as an offset between subscript and superscript.
2577 After |make_op| has acted
, |subtype
(q
)| will be |limits| if and only if
2578 the limits have been set above and below the operator. In that case
,
2579 |new_hlist
(q
)| will already contain the desired final box.
2582 static void make_scripts
(pointer q
, pointer p
, scaled it
, int cur_style
, scaled supshift
, scaled subshift
);
2583 static pointer check_nucleus_complexity
(halfword q
, scaled
* delta
, int cur_style
);
2585 static scaled make_op
(pointer q
, int cur_style
)
2587 scaled delta
= 0; /* offset between subscript and superscript
*/
2589 pointer p
, v
, x
, y
, z
, n
; /* temporary registers for box construction
*/
2590 int c
; /* register for character examination
*/
2591 scaled shift_up
, shift_down
; /* dimensions for box calculation
*/
2592 boolean axis_shift
= false
;
2594 if
((subtype
(q
) == op_noad_type_normal
) && (cur_style < text_style)) {
2595 subtype
(q
) = op_noad_type_limits
;
2597 if
(type
(nucleus
(q
)) == math_char_node
) {
2599 if
(cur_style
< text_style
) {
2600 /* try to make it larger
*/
2601 ok_size
= minimum_operator_size
(cur_style
);
2602 if
(ok_size
!= undefined_math_parameter
) {
2603 /* creating a temporary delimiter is the cleanest way
*/
2604 y
= new_node
(delim_node
, 0);
2605 reset_attributes
(y
, node_attr
(q
));
2606 small_fam
(y
) = math_fam
(nucleus
(q
));
2607 small_char
(y
) = math_character
(nucleus
(q
));
2608 x
= do_delimiter
(q
, y
, text_size
, ok_size
, false
, cur_style
, true
, NULL, &delta);
2609 if
(is_new_mathfont
(cur_f
)) {
2610 /* we never added italic correction
*/
2611 } else if
((subscr
(q
) != null
) && (subtype(q) != op_noad_type_limits)) {
2612 /* remove italic correction
*/
2616 ok_size
= height_plus_depth
(cur_f
, cur_c
) + 1;
2617 while
((char_tag
(cur_f
, cur_c
) == list_tag
) && height_plus_depth(cur_f, cur_c) < ok_size) {
2618 c
= char_remainder
(cur_f
, cur_c
);
2619 if
(!char_exists
(cur_f
, c
))
2622 math_character
(nucleus
(q
)) = c
;
2624 delta
= char_italic
(cur_f
, cur_c
);
2625 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2626 if
(delta
!= null
) {
2627 if
(is_new_mathfont
(cur_f
)) {
2628 /* we never added italic correction
*/
2629 } else if
((subscr
(q
) != null
) && (subtype(q) != op_noad_type_limits)) {
2630 /* remove italic correction
*/
2631 width
(x
) = width
(x
) - delta
;
2638 delta
= char_italic
(cur_f
, cur_c
);
2639 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2641 if
(is_new_mathfont
(cur_f
)) {
2642 /* we never added italic correction
*/
2643 } else if
((subscr
(q
) != null
) && (subtype(q) != op_noad_type_limits)) {
2644 /* remove italic correction
*/
2645 width
(x
) = width
(x
) - delta
;
2651 /* center vertically
*/
2652 shift_amount
(x
) = half
(height
(x
) - depth
(x
)) - math_axis
(cur_size
);
2654 type
(nucleus
(q
)) = sub_box_node
;
2655 math_list
(nucleus
(q
)) = x
;
2658 /* we now handle op_nod_type_no_limits here too
*/
2660 if
(subtype
(q
) == op_noad_type_no_limits
) {
2661 if
(is_new_mathfont
(cur_f
)) {
2663 delta
= half
(delta
) ;
2665 p
= check_nucleus_complexity
(q
, &dummy, cur_style);
2666 if
((subscr
(q
) == null
) && (supscr(q) == null)) {
2667 assign_new_hlist
(q
, p
);
2669 make_scripts
(q
, p
, 0, cur_style
, delta
, -delta
);
2673 /* similar code then the caller
(before CHECK_DIMENSIONS
) */
2674 p
= check_nucleus_complexity
(q
, &delta, cur_style);
2675 if
((subscr
(q
) == null
) && (supscr(q) == null)) {
2676 assign_new_hlist
(q
, p
);
2678 make_scripts
(q
, p
, delta
, cur_style
, 0, 0);
2681 } else if
(subtype
(q
) == op_noad_type_limits
) {
2682 /* The following program builds a vlist box |v| for displayed limits. The
2683 width of the box is not affected by the fact that the limits may be skewed.
*/
2684 x
= clean_box
(supscr
(q
), sup_style
(cur_style
), cur_style
);
2685 y
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2686 z
= clean_box
(subscr
(q
), sub_style
(cur_style
), cur_style
);
2688 reset_attributes
(v
, node_attr
(q
));
2689 type
(v
) = vlist_node
;
2690 if
(is_new_mathfont
(cur_f
)) {
2692 if
(! math_no_italic_compensation
) {
2695 if
((type
(n
) == sub_mlist_node
) ||
(type
(n
) == sub_box_node
)) {
2698 if
(type
(n
) == hlist_node
) {
2699 n
= list_ptr
(n
); /* just a not scaled char
*/
2701 if
(type
(n
) == glyph_node
) {
2702 delta
= char_italic
(font
(n
),character
(n
));
2708 if
(type
(n
) == fence_noad
) {
2709 if
(delimiteritalic
(n
) > delta
) {
2710 /* we can have dummies
, the period ones
*/
2711 delta
= delimiteritalic
(n
);
2720 if
(type
(n
) == math_char_node
) {
2721 delta
= char_italic
(fam_fnt
(math_fam
(n
),cur_size
),math_character
(n
));
2727 width
(v
) = width
(y
);
2728 if
(width
(x
) > width
(v
))
2729 width
(v
) = width
(x
);
2730 if
(width
(z
) > width
(v
))
2731 width
(v
) = width
(z
);
2732 x
= rebox
(x
, width
(v
));
2733 y
= rebox
(y
, width
(v
));
2734 z
= rebox
(z
, width
(v
));
2735 shift_amount
(x
) = half
(delta
);
2736 shift_amount
(z
) = -shift_amount
(x
);
2737 /* v is the still empty target
*/
2738 height
(v
) = height
(y
);
2739 depth
(v
) = depth
(y
);
2741 attach the limits to |y| and adjust |height
(v
)|
, |depth
(v
)| to
2742 account for their presence
2744 we use |shift_up| and |shift_down| in the following program for the
2745 amount of glue between the displayed operator |y| and its limits |x| and
2748 the vlist inside box |v| will consist of |x| followed by |y| followed
2749 by |z|
, with kern nodes for the spaces between and around them
2751 b
: baseline v
: minumum gap
2754 if
(supscr
(q
) == null
) {
2759 shift_up
= limit_above_bgap
(cur_style
) - depth
(x
);
2760 if
(shift_up
< limit_above_vgap
(cur_style
))
2761 shift_up
= limit_above_vgap
(cur_style
);
2762 p
= new_kern
(shift_up
);
2763 reset_attributes
(p
, node_attr
(q
));
2766 p
= new_kern
(limit_above_kern
(cur_style
));
2767 reset_attributes
(p
, node_attr
(q
));
2770 height
(v
) = height
(v
) + limit_above_kern
(cur_style
) + height
(x
) + depth
(x
) + shift_up
;
2772 if
(subscr
(q
) == null
) {
2776 shift_down
= limit_below_bgap
(cur_style
) - height
(z
);
2777 if
(shift_down
< limit_below_vgap
(cur_style
))
2778 shift_down
= limit_below_vgap
(cur_style
);
2779 if
(shift_down
> 0) {
2780 p
= new_kern
(shift_down
);
2781 reset_attributes
(p
, node_attr
(q
));
2785 p
= new_kern
(limit_below_kern
(cur_style
));
2786 reset_attributes
(p
, node_attr
(q
));
2788 depth
(v
) = depth
(v
) + limit_below_kern
(cur_style
) + height
(z
) + depth
(z
) + shift_down
;
2790 if
(subscr
(q
) != null
) {
2791 math_list
(subscr
(q
)) = null
;
2792 flush_node
(subscr
(q
));
2795 if
(supscr
(q
) != null
) {
2796 math_list
(supscr
(q
)) = null
;
2797 flush_node
(supscr
(q
));
2800 assign_new_hlist
(q
, v
);
2801 if
(is_new_mathfont
(cur_f
)) {
2808 @ A ligature found in a math formula does not create a ligature
, because
2809 there is no question of hyphenation afterwards
; the ligature will simply be
2810 stored in an ordinary |glyph_node|
, after residing in an |ord_noad|.
2812 The |type| is converted to |math_text_char| here if we would not want to
2813 apply an italic correction to the current character unless it belongs
2814 to a math font
(i.e.
, a font with |space
=0|
).
2816 No boundary characters enter into these ligatures.
2819 #define simple_char_noad
(p
) (\
2821 (type
(p
) == simple_noad
) && \
2822 (subtype
(p
) <= punct_noad_type
) && \
2823 (type
(nucleus
(p
)) == math_char_node
) \
2826 #define same_nucleus_fam
(p
,q
) \
2827 (math_fam
(nucleus
(p
)) == math_fam
(nucleus
(q
)))
2829 static void make_ord
(pointer q
)
2831 int a
; /* the left-side character for lig
/kern testing
*/
2832 pointer p
, r
, s
; /* temporary registers for list manipulation
*/
2833 scaled k
; /* a kern
*/
2834 liginfo lig
; /* a ligature
*/
2836 if
(subscr
(q
) == null
&& supscr(q) == null && type(nucleus(q)) == math_char_node) {
2838 if
(simple_char_noad
(p
) && same_nucleus_fam(p,q)) {
2839 type
(nucleus
(q
)) = math_text_char_node
;
2842 /* add italic correction
*/
2843 if
(is_new_mathfont
(cur_f
) && (char_italic(cur_f,math_character(nucleus(q))) != 0)) {
2844 p
= new_kern
(char_italic
(cur_f
,math_character
(nucleus
(q
))));
2845 reset_attributes
(p
, node_attr
(q
));
2846 couple_nodes
(p
,vlink
(q
));
2850 /* construct ligatures
, quite unlikely in new math fonts
*/
2851 if
((has_kern
(cur_f
, a
)) ||
(has_lig
(cur_f
, a
))) {
2852 cur_c
= math_character
(nucleus
(p
));
2854 if character |a| has a kern with |cur_c|
, attach the kern after~|q|
; or if
2855 it has a ligature with |cur_c|
, combine noads |q| and~|p| appropriately
;
2856 then |return| if the cursor has moved past a noad
, or |goto restart|
2858 note that a ligature between an |ord_noad| and another kind of noad
2859 is replaced by an |ord_noad|
, when the two noads collapse into one
2861 we could make a parenthesis
(say
) change shape when it follows
2862 certain letters. Presumably a font designer will define such
2863 ligatures only when this convention makes sense
2866 if
(disable_lig
== 0 && has_lig(cur_f, a)) {
2867 lig
= get_ligature
(cur_f
, a
, cur_c
);
2868 if
(is_valid_ligature
(lig
)) {
2869 check_interrupt
(); /* allow a way out of infinite ligature loop
*/
2870 switch
(lig_type
(lig
)) {
2872 /* \.
{=:\char`\|
} */
2874 /* \.
{=:\char`\|
>} */
2875 math_character
(nucleus
(q
)) = lig_replacement
(lig
);
2878 /* \.
{\char`\|
=:} */
2880 /* \.
{\char`\|
=:>} */
2881 math_character
(nucleus
(p
)) = lig_replacement
(lig
);
2884 /* \.
{\char`\|
=:\char`\|
} */
2886 /* \.
{\char`\|
=:\char`\|
>} */
2888 /* \.
{\char`\|
=:\char`\|
>>} */
2890 reset_attributes
(r
, node_attr
(q
));
2891 s
= new_node
(math_char_node
, 0);
2892 reset_attributes
(s
, node_attr
(q
));
2894 math_character
(nucleus
(r
)) = lig_replacement
(lig
);
2895 math_fam
(nucleus
(r
)) = math_fam
(nucleus
(q
));
2898 if
(lig_type
(lig
) < 11)
2899 type
(nucleus
(r
)) = math_char_node
;
2901 /* prevent combination
*/
2902 type
(nucleus
(r
)) = math_text_char_node
;
2905 try_couple_nodes
(q
,vlink
(p
));
2906 math_character
(nucleus
(q
)) = lig_replacement
(lig
); /* \.
{=:} */
2907 s
= math_clone
(subscr
(p
));
2909 s
= math_clone
(supscr
(p
));
2911 math_reset
(subscr
(p
)); /* just in case
*/
2912 math_reset
(supscr
(p
));
2916 if
(lig_type
(lig
) > 3)
2918 type
(nucleus
(q
)) = math_char_node
;
2922 if
(disable_kern
== 0 && has_kern(cur_f, a)) {
2923 /* todo
: should this use mathkerns?
*/
2924 k
= get_kern
(cur_f
, a
, cur_c
);
2927 reset_attributes
(p
, node_attr
(q
));
2928 couple_nodes
(p
,vlink
(q
));
2938 @ If the fonts for the left and right bits of a mathkern are not
2939 both new-style fonts
, then return a sentinel value meaning
:
2940 please use old-style italic correction placement
2943 #define MATH_KERN_NOT_FOUND
0x7FFFFFFF
2945 @ This function tries to find the kern needed for proper cut-ins.
2946 The left side doesn't move
, but the right side does
, so the first
2947 order of business is to create a staggered fence line on the
2948 left side of the right character.
2950 The microsoft spec says that there are four quadrants
, but the
2954 static scaled math_kern_at
(internal_font_number f
, int c
, int side
, int v
)
2957 scaled
*kerns_heights
;
2959 charinfo
*co
= char_info
(f
, c
); /* known to exist
*/
2960 numkerns
= get_charinfo_math_kerns
(co
, side
);
2962 fprintf
(stderr
, " entries = %d, height = %d\n", numkerns
, v
);
2966 if
(side
== top_left_kern
) {
2967 kerns_heights
= co-
>top_left_math_kern_array
;
2968 } else if
(side
== bottom_left_kern
) {
2969 kerns_heights
= co-
>bottom_left_math_kern_array
;
2970 } else if
(side
== top_right_kern
) {
2971 kerns_heights
= co-
>top_right_math_kern_array
;
2972 } else if
(side
== bottom_right_kern
) {
2973 kerns_heights
= co-
>bottom_right_math_kern_array
;
2975 confusion
("math_kern_at");
2976 kerns_heights
= NULL; /* not reached
*/
2979 fprintf
(stderr
, " entry 0: %d,%d\n", kerns_heights
[0], kerns_heights
[1]);
2981 if
(v
< kerns_heights
[0])
2982 return kerns_heights
[1];
2983 for
(k
= 0; k
< numkerns
; k
++) {
2984 h
= kerns_heights
[(k
* 2)];
2985 kern
= kerns_heights
[(k
* 2) + 1];
2988 fprintf
(stderr
, " entry %d: %d,%d\n", k
, h
, kern
);
2998 static scaled find_math_kern
(internal_font_number l_f
, int l_c
,
2999 internal_font_number r_f
, int r_c
,
3000 int cmd
, scaled shift
)
3002 scaled corr_height_top
= 0, corr_height_bot
= 0;
3003 scaled krn_l
= 0, krn_r
= 0, krn
= 0;
3004 if
((!is_new_mathfont
(l_f
)) ||
(!is_new_mathfont
(r_f
)) ||
(!char_exists
(l_f
, l_c
)) ||
(!char_exists
(r_f
, r_c
)))
3005 return MATH_KERN_NOT_FOUND
;
3007 if
(cmd
== sup_mark_cmd
) {
3008 corr_height_top
= char_height
(l_f
, l_c
);
3009 corr_height_bot
= -char_depth
(r_f
, r_c
) + shift
; /* bottom of superscript
*/
3010 krn_l
= math_kern_at
(l_f
, l_c
, top_right_kern
, corr_height_top
);
3011 krn_r
= math_kern_at
(r_f
, r_c
, bottom_left_kern
, corr_height_top
);
3013 fprintf
(stderr
, "SUPER Top LR = %d,%d (shift %d)\n", krn_l
, krn_r
, shift
);
3015 krn
= (krn_l
+ krn_r
);
3016 krn_l
= math_kern_at
(l_f
, l_c
, top_right_kern
, corr_height_bot
);
3017 krn_r
= math_kern_at
(r_f
, r_c
, bottom_left_kern
, corr_height_bot
);
3019 fprintf
(stderr
, "SUPER Bot LR = %d,%d\n", krn_l
, krn_r
);
3021 if
((krn_l
+ krn_r
) < krn
)
3022 krn
= (krn_l
+ krn_r
);
3025 } else if
(cmd
== sub_mark_cmd
) {
3026 corr_height_top
= char_height
(r_f
, r_c
) - shift
; /* top of subscript
*/
3027 corr_height_bot
= -char_depth
(l_f
, l_c
);
3028 krn_l
= math_kern_at
(l_f
, l_c
, bottom_right_kern
, corr_height_top
);
3029 krn_r
= math_kern_at
(r_f
, r_c
, top_left_kern
, corr_height_top
);
3031 fprintf
(stderr
, "SUB Top LR = %d,%d\n", krn_l
, krn_r
);
3033 krn
= (krn_l
+ krn_r
);
3034 krn_l
= math_kern_at
(l_f
, l_c
, bottom_right_kern
, corr_height_bot
);
3035 krn_r
= math_kern_at
(r_f
, r_c
, top_left_kern
, corr_height_bot
);
3037 fprintf
(stderr
, "SUB Bot LR = %d,%d\n", krn_l
, krn_r
);
3039 if
((krn_l
+ krn_r
) < krn
)
3040 krn
= (krn_l
+ krn_r
);
3044 confusion
("find_math_kern");
3046 return
0; /* not reached
*/
3049 @ just a small helper
3051 static pointer attach_hkern_to_new_hlist
(pointer q
, scaled delta2
)
3054 pointer z
= new_kern
(delta2
);
3055 reset_attributes
(z
, node_attr
(q
));
3056 if
(new_hlist
(q
) == null
) {
3057 /* this is somewhat weird
*/
3061 while
(vlink
(y
) != null
)
3065 return new_hlist
(q
);
3071 void dump_simple_field
(pointer q
)
3074 printf
(" [%d, type=%d, vlink=%d] ", q
, type
(q
), vlink
(q
));
3076 case math_char_node
:
3077 printf
("mathchar ");
3079 case math_text_char_node
:
3085 case sub_mlist_node
:
3089 dump_simple_field
(p
);
3096 void dump_simple_node
(pointer q
)
3098 printf
("node %d, type=%d, vlink=%d\n", q
, type
(q
), vlink
(q
));
3099 printf
("nucleus: ");
3100 dump_simple_field
(nucleus
(q
));
3103 dump_simple_field
(subscr
(q
));
3106 dump_simple_field
(supscr
(q
));
3111 @ The purpose of |make_scripts
(q
,it
)| is to attach the subscript and
/or
3112 superscript of noad |q| to the list that starts at |new_hlist
(q
)|
,
3113 given that subscript and superscript aren't both empty. The superscript
3114 will be horizontally shifted over |delta1|
, the subscript over |delta2|.
3116 We set |shift_down| and |shift_up| to the minimum amounts to shift the
3117 baseline of subscripts and superscripts based on the given nucleus.
3119 Note
: We need to look at a character but also at the first one in a sub list
3120 and there we ignore leading kerns and glue. Elsewhere is code that removes
3121 kerns assuming that is italic correction. The heuristics are unreliable for
3122 the new fonts so eventualy there will be an option to ignore such corrections.
3125 #define analyze_script
(init
,su_n
,su_f
,su_c
) do
{ \
3127 if
(su_n
!= null
) { \
3128 if
(type
(su_n
) == sub_mlist_node
&& math_list(su_n)) { \
3129 su_n
= math_list
(su_n
); \
3130 if
(su_n
!= null
) { \
3132 if
((type
(su_n
) == kern_node
) ||
(type
(su_n
) == glue_node
)) {\
3133 su_n
= vlink
(su_n
); \
3134 } else if
(type
(su_n
) == simple_noad
) { \
3135 su_n
= nucleus
(su_n
); \
3136 if
(type
(su_n
) != math_char_node
) { \
3147 if
((su_n
!= null
) && (type(su_n) == math_char_node)) { \
3149 if
(char_exists
(cur_f
, cur_c
)) { \
3159 static void make_scripts
(pointer q
, pointer p
, scaled it
, int cur_style
, scaled supshift
, scaled subshift
)
3161 pointer x
, y
, z
; /* temporary registers for box construction
*/
3162 scaled shift_up
, shift_down
, clr
; /* dimensions in the calculation
*/
3163 scaled delta1
, delta2
;
3164 halfword sub_n
, sup_n
;
3165 internal_font_number sub_f
, sup_f
;
3177 printf
("it: %d\n", it
);
3178 dump_simple_node
(q
);
3179 printf
("p: node %d, type=%d, subtype=%d\n", p
, type
(p
), subtype
(p
));
3181 switch
(type
(nucleus
(q
))) {
3182 case math_char_node
:
3183 case math_text_char_node
:
3184 if
((subscr
(q
) == null
) && (delta1 != 0)) {
3185 /* todo
: selective
*/
3186 x
= new_kern
(delta1
); /* italic correction
*/
3187 reset_attributes
(x
, node_attr
(nucleus
(q
)));
3192 assign_new_hlist
(q
, p
);
3193 if
(is_char_node
(p
)) {
3197 z
= hpack
(p
, 0, additional
, -1);
3198 shift_up
= height
(z
) - sup_shift_drop
(cur_style
); /* r18
*/
3199 shift_down
= depth
(z
) + sub_shift_drop
(cur_style
); /* r19
*/
3204 if
(is_char_node
(p
)) {
3205 /* we look at the subscript character
(_i
) or first character in a list
(_
{ij
}) */
3206 analyze_script
(subscr
(q
),sub_n
,sub_f
,sub_c
);
3207 /* we look at the superscript character
(^i
) or first character in a list
(^
{ij
}) */
3208 analyze_script
(supscr
(q
),sup_n
,sup_f
,sup_c
);
3211 if
(supscr
(q
) == null
) {
3213 construct a subscript box |x| when there is no superscript
3215 when there is a subscript without a superscript
, the top of the subscript
3216 should not exceed the baseline plus four-fifths of the x-height.
3218 x
= clean_box
(subscr
(q
), sub_style
(cur_style
), cur_style
);
3219 width
(x
) = width
(x
) + space_after_script
(cur_style
);
3220 switch
(scripts_mode
) {
3222 shift_down
= sub_shift_down
(cur_style
) ;
3225 shift_down
= sub_sup_shift_down
(cur_style
) ;
3228 shift_down
= sub_sup_shift_down
(cur_style
) ;
3231 shift_down
= sub_shift_down
(cur_style
) + half
(sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
)) ;
3234 shift_down
= sub_shift_down
(cur_style
) ;
3237 if
(shift_down
< sub_shift_down
(cur_style
))
3238 shift_down
= sub_shift_down
(cur_style
);
3239 clr
= height
(x
) - sub_top_max
(cur_style
);
3240 if
(shift_down
< clr
)
3244 shift_amount
(x
) = shift_down
;
3246 /* now find and correct for horizontal shift
*/
3247 if
(sub_n
!= null
) {
3248 delta2
= find_math_kern
(font
(p
), character
(p
),sub_f
,sub_c
,sub_mark_cmd
, shift_down
);
3249 if
(delta2
== MATH_KERN_NOT_FOUND
) {
3252 delta2
= delta2
+ subshift
;
3258 p
= attach_hkern_to_new_hlist
(q
, delta2
);
3263 construct a superscript box |x|
3265 the bottom of a superscript should never descend below the baseline plus
3266 one-fourth of the x-height.
3268 x
= clean_box
(supscr
(q
), sup_style
(cur_style
), cur_style
);
3269 width
(x
) = width
(x
) + space_after_script
(cur_style
);
3270 switch
(scripts_mode
) {
3272 shift_up
= sup_shift_up
(cur_style
);
3275 shift_up
= sup_shift_up
(cur_style
) ;
3278 shift_up
= sup_shift_up
(cur_style
) + sub_sup_shift_down
(cur_style
) - sub_shift_down
(cur_style
) ;
3281 shift_up
= sup_shift_up
(cur_style
) + half
(sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
)) ;
3284 shift_up
= sup_shift_up
(cur_style
) + sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
) ;
3287 clr
= sup_shift_up
(cur_style
);
3290 clr
= depth
(x
) + sup_bottom_min
(cur_style
);
3295 if
(subscr
(q
) == null
) {
3296 shift_amount
(x
) = -shift_up
;
3297 /* now find and correct for horizontal shift
*/
3298 if
(sup_n
!= null
) {
3299 clr
= find_math_kern
(font
(p
),character
(p
),sup_f
,sup_c
,sup_mark_cmd
,shift_up
);
3300 if
(clr
== MATH_KERN_NOT_FOUND
) {
3303 clr
= clr
+ supshift
;
3309 p
= attach_hkern_to_new_hlist
(q
, clr
);
3313 construct a sub
/superscript combination box |x|
, with the superscript offset
3316 when both subscript and superscript are present
, the subscript must be
3317 separated from the superscript by at least four times |default_rule_thickness|
3319 if this condition would be violated
, the subscript moves down
, after which
3320 both subscript and superscript move up so that the bottom of the superscript
3321 is at least as high as the baseline plus four-fifths of the x-height
3323 y
= clean_box
(subscr
(q
), sub_style
(cur_style
), cur_style
);
3324 width
(y
) = width
(y
) + space_after_script
(cur_style
);
3325 switch
(scripts_mode
) {
3327 shift_down
= sub_shift_down
(cur_style
) ;
3330 shift_down
= sub_sup_shift_down
(cur_style
) ;
3333 shift_down
= sub_sup_shift_down
(cur_style
) ;
3336 shift_down
= sub_shift_down
(cur_style
) + half
(sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
)) ;
3339 shift_down
= sub_shift_down
(cur_style
) ;
3342 if
(shift_down
< sub_sup_shift_down
(cur_style
))
3343 shift_down
= sub_sup_shift_down
(cur_style
);
3344 clr
= subsup_vgap
(cur_style
) - ((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
3346 shift_down
= shift_down
+ clr
;
3347 clr
= sup_sub_bottom_max
(cur_style
) - (shift_up
- depth
(x
));
3349 shift_up
= shift_up
+ clr
;
3350 shift_down
= shift_down
- clr
;
3355 /* now find and correct for horizontal shift
*/
3356 if
(sub_n
!= null
) {
3357 delta2
= find_math_kern
(font
(p
), character
(p
),sub_f
,sub_c
,sub_mark_cmd
, shift_down
);
3358 if
(delta2
== MATH_KERN_NOT_FOUND
) {
3361 delta2
= delta2
+ subshift
;
3367 p
= attach_hkern_to_new_hlist
(q
, delta2
);
3370 now the horizontal shift for the superscript
; the superscript is also to be shifted
3371 by |delta1|
(the italic correction
)
3373 clr
= MATH_KERN_NOT_FOUND
;
3374 if
(sup_n
!= null
) {
3375 clr
= find_math_kern
(font
(p
),character
(p
),sup_f
,sup_c
,sup_mark_cmd
,shift_up
);
3378 /* delta can already have been applied and now be
0 */
3379 if
(delta2
== MATH_KERN_NOT_FOUND
)
3380 delta2
= - supshift
;
3382 delta2
= delta2
- supshift
;
3383 if
(clr
!= MATH_KERN_NOT_FOUND
) {
3384 shift_amount
(x
) = clr
+ delta1
- delta2
;
3386 shift_amount
(x
) = delta1
- delta2
;
3388 /* todo
: only if kern
!= 0 */
3389 p
= new_kern
((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
3390 reset_attributes
(p
, node_attr
(q
));
3393 /* we end up with funny dimensions
*/
3394 x
= vpackage
(x
, 0, additional
, max_dimen
, math_direction
);
3395 reset_attributes
(x
, node_attr
(q
));
3396 shift_amount
(x
) = shift_down
;
3400 if
(new_hlist
(q
) == null
) {
3404 while
(vlink
(p
) != null
)
3408 if
(subscr
(q
) != null
) {
3409 math_list
(subscr
(q
)) = null
;
3410 flush_node
(subscr
(q
));
3413 if
(supscr
(q
) != null
) {
3414 math_list
(supscr
(q
)) = null
;
3415 flush_node
(supscr
(q
));
3420 @ The |make_left_right| function constructs a left or right delimiter of
3421 the required size and returns the value |open_noad| or |close_noad|. The
3422 |left_noad_side| and |right_noad_side| will both be based on the original |style|
,
3423 so they will have consistent sizes.
3426 static small_number make_left_right
(pointer q
, int style
, scaled max_d
, scaled max_h
)
3430 scaled hd_asked
= 0;
3432 boolean stack
= false
;
3433 boolean axis
= false
;
3436 boolean fitting
= true
;
3437 boolean fence
= false
;
3441 setup_cur_size
(style
);
3443 if
((delimiterheight
(q
)!=0) ||
(delimiterdepth
(q
)!=0)) {
3445 hd_asked
= delimiterheight
(q
) + delimiterdepth
(q
);
3446 tmp
= do_delimiter
(q
, delimiter
(q
), cur_size
, hd_asked
, false
, style
, false
, &stack, &ic);
3447 delimiteritalic
(q
) = ic
;
3449 /* beware
, a stacked delimiter has a shift but no corrected height
/depth
(yet
) */
3452 shift_amount
(tmp
) = delimiterdepth
(q
);
3456 hd_done
= height
(tmp
) + depth
(tmp
);
3457 fitting
= stack ||
((hd_done-hd_asked
) == 0);
3459 if
(type
(delimiter
(q
)) == delim_node
&& (small_char(delimiter(q)) != 0)) {
3460 chr
= small_char
(delimiter
(q
));
3461 cls
= get_math_code
(chr
).class_value
;
3462 fence
= (cls
== 4) ||
(cls
== 5) ;
3465 printf
("delimiter stack %i fence %i fitting %i\n",stack
,fence
,fitting
);
3468 if
(delimiterexact
(q
)) {
3469 delimiterheight
(q
) = height
(tmp
) - shift_amount
(tmp
);
3470 delimiterdepth
(q
) = depth
(tmp
) + shift_amount
(tmp
);
3472 if
(delimiteraxis
(q
)) {
3473 delimiterheight
(q
) += math_axis
(cur_size
);
3474 delimiterdepth
(q
) -= math_axis
(cur_size
);
3475 shift_amount
(tmp
) -= math_axis
(cur_size
);
3477 lst
= new_node
(hlist_node
,0);
3478 reset_attributes
(lst
, node_attr
(q
));
3479 box_dir
(lst
) = dir_TLT
;
3480 height
(lst
) = delimiterheight
(q
);
3481 depth
(lst
) = delimiterdepth
(q
);
3482 width
(lst
) = width
(tmp
);
3483 list_ptr
(lst
) = tmp
;
3486 axis
= ! delimiternoaxis
(q
);
3487 delta
= get_delimiter_height
(max_d
,max_h
,axis
);
3488 tmp
= do_delimiter
(q
, delimiter
(q
), cur_size
, delta
, false
, style
, axis
, &stack, &ic);
3489 delimiteritalic
(q
) = ic
;
3491 delimiter
(q
) = null
;
3492 assign_new_hlist
(q
, tmp
);
3493 if
(delimiterclass
(q
) >= ord_noad_type
) {
3494 if
(delimiterclass
(q
) <= inner_noad_type
) {
3495 return delimiterclass
(q
);
3497 return ord_noad_type
;
3499 } else if
(subtype
(q
) == no_noad_side
) {
3500 return open_noad_type
;
3501 } else if
(subtype
(q
) == left_noad_side
) {
3502 return open_noad_type
;
3504 return close_noad_type
;
3509 #define TEXT_STYLES
(A
,B
) do
{ \
3510 def_math_param
(A
,display_style
,(B
),level_one
); \
3511 def_math_param
(A
,cramped_display_style
,(B
),level_one
); \
3512 def_math_param
(A
,text_style
,(B
),level_one
); \
3513 def_math_param
(A
,cramped_text_style
,(B
),level_one
); \
3516 #define SCRIPT_STYLES
(A
,B
) do
{ \
3517 def_math_param
(A
,script_style
,(B
),level_one
); \
3518 def_math_param
(A
,cramped_script_style
,(B
),level_one
); \
3519 def_math_param
(A
,script_script_style
,(B
),level_one
); \
3520 def_math_param
(A
,cramped_script_script_style
,(B
),level_one
); \
3523 #define ALL_STYLES
(A
,B
) do
{ \
3524 TEXT_STYLES
(A
,(B
)); \
3525 SCRIPT_STYLES
(A
,(B
)); \
3528 #define SPLIT_STYLES
(A
,B
,C
) do
{ \
3529 TEXT_STYLES
(A
,(B
)); \
3530 SCRIPT_STYLES
(A
,(C
)); \
3534 void initialize_math_spacing
(void
)
3537 ALL_STYLES
(math_param_ord_ord_spacing
, 0);
3538 ALL_STYLES
(math_param_ord_op_spacing
, thin_mu_skip_code
);
3539 SPLIT_STYLES
(math_param_ord_bin_spacing
, med_mu_skip_code
, 0);
3540 SPLIT_STYLES
(math_param_ord_rel_spacing
, thick_mu_skip_code
, 0);
3541 ALL_STYLES
(math_param_ord_open_spacing
, 0);
3542 ALL_STYLES
(math_param_ord_close_spacing
, 0);
3543 ALL_STYLES
(math_param_ord_punct_spacing
, 0);
3544 SPLIT_STYLES
(math_param_ord_inner_spacing
, thin_mu_skip_code
, 0);
3546 ALL_STYLES
(math_param_op_ord_spacing
, thin_mu_skip_code
);
3547 ALL_STYLES
(math_param_op_op_spacing
, thin_mu_skip_code
);
3548 ALL_STYLES
(math_param_op_bin_spacing
, 0);
3549 SPLIT_STYLES
(math_param_op_rel_spacing
, thick_mu_skip_code
, 0);
3550 ALL_STYLES
(math_param_op_open_spacing
, 0);
3551 ALL_STYLES
(math_param_op_close_spacing
, 0);
3552 ALL_STYLES
(math_param_op_punct_spacing
, 0);
3553 SPLIT_STYLES
(math_param_op_inner_spacing
, thin_mu_skip_code
, 0);
3555 SPLIT_STYLES
(math_param_bin_ord_spacing
, med_mu_skip_code
, 0);
3556 SPLIT_STYLES
(math_param_bin_op_spacing
, med_mu_skip_code
, 0);
3557 ALL_STYLES
(math_param_bin_bin_spacing
, 0);
3558 ALL_STYLES
(math_param_bin_rel_spacing
, 0);
3559 SPLIT_STYLES
(math_param_bin_open_spacing
, med_mu_skip_code
, 0);
3560 ALL_STYLES
(math_param_bin_close_spacing
, 0);
3561 ALL_STYLES
(math_param_bin_punct_spacing
, 0);
3562 SPLIT_STYLES
(math_param_bin_inner_spacing
, med_mu_skip_code
, 0);
3564 SPLIT_STYLES
(math_param_rel_ord_spacing
, thick_mu_skip_code
, 0);
3565 SPLIT_STYLES
(math_param_rel_op_spacing
, thick_mu_skip_code
, 0);
3566 ALL_STYLES
(math_param_rel_bin_spacing
, 0);
3567 ALL_STYLES
(math_param_rel_rel_spacing
, 0);
3568 SPLIT_STYLES
(math_param_rel_open_spacing
, thick_mu_skip_code
, 0);
3569 ALL_STYLES
(math_param_rel_close_spacing
, 0);
3570 ALL_STYLES
(math_param_rel_punct_spacing
, 0);
3571 SPLIT_STYLES
(math_param_rel_inner_spacing
, thick_mu_skip_code
, 0);
3573 ALL_STYLES
(math_param_open_ord_spacing
, 0);
3574 ALL_STYLES
(math_param_open_op_spacing
, 0);
3575 ALL_STYLES
(math_param_open_bin_spacing
, 0);
3576 ALL_STYLES
(math_param_open_rel_spacing
, 0);
3577 ALL_STYLES
(math_param_open_open_spacing
, 0);
3578 ALL_STYLES
(math_param_open_close_spacing
, 0);
3579 ALL_STYLES
(math_param_open_punct_spacing
, 0);
3580 ALL_STYLES
(math_param_open_inner_spacing
, 0);
3582 ALL_STYLES
(math_param_close_ord_spacing
, 0);
3583 ALL_STYLES
(math_param_close_op_spacing
, thin_mu_skip_code
);
3584 SPLIT_STYLES
(math_param_close_bin_spacing
, med_mu_skip_code
, 0);
3585 SPLIT_STYLES
(math_param_close_rel_spacing
, thick_mu_skip_code
, 0);
3586 ALL_STYLES
(math_param_close_open_spacing
, 0);
3587 ALL_STYLES
(math_param_close_close_spacing
, 0);
3588 ALL_STYLES
(math_param_close_punct_spacing
, 0);
3589 SPLIT_STYLES
(math_param_close_inner_spacing
, thin_mu_skip_code
, 0);
3591 SPLIT_STYLES
(math_param_punct_ord_spacing
, thin_mu_skip_code
, 0);
3592 SPLIT_STYLES
(math_param_punct_op_spacing
, thin_mu_skip_code
, 0);
3593 ALL_STYLES
(math_param_punct_bin_spacing
, 0);
3594 SPLIT_STYLES
(math_param_punct_rel_spacing
, thin_mu_skip_code
, 0);
3595 SPLIT_STYLES
(math_param_punct_open_spacing
, thin_mu_skip_code
, 0);
3596 SPLIT_STYLES
(math_param_punct_close_spacing
, thin_mu_skip_code
, 0);
3597 SPLIT_STYLES
(math_param_punct_punct_spacing
, thin_mu_skip_code
, 0);
3598 SPLIT_STYLES
(math_param_punct_inner_spacing
, thin_mu_skip_code
, 0);
3600 SPLIT_STYLES
(math_param_inner_ord_spacing
, thin_mu_skip_code
, 0);
3601 ALL_STYLES
(math_param_inner_op_spacing
, thin_mu_skip_code
);
3602 SPLIT_STYLES
(math_param_inner_bin_spacing
, med_mu_skip_code
, 0);
3603 SPLIT_STYLES
(math_param_inner_rel_spacing
, thick_mu_skip_code
, 0);
3604 SPLIT_STYLES
(math_param_inner_open_spacing
, thin_mu_skip_code
, 0);
3605 ALL_STYLES
(math_param_inner_close_spacing
, 0);
3606 SPLIT_STYLES
(math_param_inner_punct_spacing
, thin_mu_skip_code
, 0);
3607 SPLIT_STYLES
(math_param_inner_inner_spacing
, thin_mu_skip_code
, 0);
3612 #define both_types
(A
,B
) ((A
)*16+(B
))
3614 static pointer math_spacing_glue
(int l_type
, int r_type
, int mstyle
, scaled mmu
)
3618 if
(l_type
== op_noad_type_limits || l_type
== op_noad_type_no_limits
)
3619 l_type
= op_noad_type_normal
;
3620 if
(r_type
== op_noad_type_limits || r_type
== op_noad_type_no_limits
)
3621 r_type
= op_noad_type_normal
;
3622 switch
(both_types
(l_type
, r_type
)) {
3624 case both_types
(ord_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_ord_ord_spacing
,mstyle
); break
;
3625 case both_types
(ord_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_ord_op_spacing
,mstyle
); break
;
3626 case both_types
(ord_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_ord_bin_spacing
,mstyle
); break
;
3627 case both_types
(ord_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_ord_rel_spacing
,mstyle
); break
;
3628 case both_types
(ord_noad_type
, open_noad_type
): x
= get_math_param
(math_param_ord_open_spacing
,mstyle
); break
;
3629 case both_types
(ord_noad_type
, close_noad_type
): x
= get_math_param
(math_param_ord_close_spacing
,mstyle
); break
;
3630 case both_types
(ord_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_ord_punct_spacing
,mstyle
); break
;
3631 case both_types
(ord_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_ord_inner_spacing
,mstyle
); break
;
3632 case both_types
(op_noad_type_normal
, ord_noad_type
): x
= get_math_param
(math_param_op_ord_spacing
,mstyle
); break
;
3633 case both_types
(op_noad_type_normal
, op_noad_type_normal
): x
= get_math_param
(math_param_op_op_spacing
,mstyle
); break
;
3635 case both_types
(op_noad_type_normal
, bin_noad_type
): x
= get_math_param
(math_param_op_bin_spacing
,mstyle
); break
;
3637 case both_types
(op_noad_type_normal
, rel_noad_type
): x
= get_math_param
(math_param_op_rel_spacing
,mstyle
); break
;
3638 case both_types
(op_noad_type_normal
, open_noad_type
): x
= get_math_param
(math_param_op_open_spacing
,mstyle
); break
;
3639 case both_types
(op_noad_type_normal
, close_noad_type
): x
= get_math_param
(math_param_op_close_spacing
,mstyle
); break
;
3640 case both_types
(op_noad_type_normal
, punct_noad_type
): x
= get_math_param
(math_param_op_punct_spacing
,mstyle
); break
;
3641 case both_types
(op_noad_type_normal
, inner_noad_type
): x
= get_math_param
(math_param_op_inner_spacing
,mstyle
); break
;
3642 case both_types
(bin_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_bin_ord_spacing
,mstyle
); break
;
3643 case both_types
(bin_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_bin_op_spacing
,mstyle
); break
;
3645 case both_types
(bin_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_bin_bin_spacing
,mstyle
); break
;
3646 case both_types
(bin_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_bin_rel_spacing
,mstyle
); break
;
3648 case both_types
(bin_noad_type
, open_noad_type
): x
= get_math_param
(math_param_bin_open_spacing
,mstyle
); break
;
3650 case both_types
(bin_noad_type
, close_noad_type
): x
= get_math_param
(math_param_bin_close_spacing
,mstyle
); break
;
3651 case both_types
(bin_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_bin_punct_spacing
,mstyle
); break
;
3653 case both_types
(bin_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_bin_inner_spacing
,mstyle
); break
;
3654 case both_types
(rel_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_rel_ord_spacing
,mstyle
); break
;
3655 case both_types
(rel_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_rel_op_spacing
,mstyle
); break
;
3657 case both_types
(rel_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_rel_bin_spacing
,mstyle
); break
;
3659 case both_types
(rel_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_rel_rel_spacing
,mstyle
); break
;
3660 case both_types
(rel_noad_type
, open_noad_type
): x
= get_math_param
(math_param_rel_open_spacing
,mstyle
); break
;
3661 case both_types
(rel_noad_type
, close_noad_type
): x
= get_math_param
(math_param_rel_close_spacing
,mstyle
); break
;
3662 case both_types
(rel_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_rel_punct_spacing
,mstyle
); break
;
3663 case both_types
(rel_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_rel_inner_spacing
,mstyle
); break
;
3664 case both_types
(open_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_open_ord_spacing
,mstyle
); break
;
3665 case both_types
(open_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_open_op_spacing
,mstyle
); break
;
3667 case both_types
(open_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_open_bin_spacing
,mstyle
); break
;
3669 case both_types
(open_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_open_rel_spacing
,mstyle
); break
;
3670 case both_types
(open_noad_type
, open_noad_type
): x
= get_math_param
(math_param_open_open_spacing
,mstyle
); break
;
3671 case both_types
(open_noad_type
, close_noad_type
): x
= get_math_param
(math_param_open_close_spacing
,mstyle
); break
;
3672 case both_types
(open_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_open_punct_spacing
,mstyle
); break
;
3673 case both_types
(open_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_open_inner_spacing
,mstyle
); break
;
3674 case both_types
(close_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_close_ord_spacing
,mstyle
); break
;
3675 case both_types
(close_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_close_op_spacing
,mstyle
); break
;
3676 case both_types
(close_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_close_bin_spacing
,mstyle
); break
;
3677 case both_types
(close_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_close_rel_spacing
,mstyle
); break
;
3678 case both_types
(close_noad_type
, open_noad_type
): x
= get_math_param
(math_param_close_open_spacing
,mstyle
); break
;
3679 case both_types
(close_noad_type
, close_noad_type
): x
= get_math_param
(math_param_close_close_spacing
,mstyle
); break
;
3680 case both_types
(close_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_close_punct_spacing
,mstyle
); break
;
3681 case both_types
(close_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_close_inner_spacing
,mstyle
); break
;
3682 case both_types
(punct_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_punct_ord_spacing
,mstyle
); break
;
3683 case both_types
(punct_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_punct_op_spacing
,mstyle
); break
;
3685 case both_types
(punct_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_punct_bin_spacing
,mstyle
); break
;
3687 case both_types
(punct_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_punct_rel_spacing
,mstyle
); break
;
3688 case both_types
(punct_noad_type
, open_noad_type
): x
= get_math_param
(math_param_punct_open_spacing
,mstyle
); break
;
3689 case both_types
(punct_noad_type
, close_noad_type
): x
= get_math_param
(math_param_punct_close_spacing
,mstyle
); break
;
3690 case both_types
(punct_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_punct_punct_spacing
,mstyle
); break
;
3691 case both_types
(punct_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_punct_inner_spacing
,mstyle
); break
;
3692 case both_types
(inner_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_inner_ord_spacing
,mstyle
); break
;
3693 case both_types
(inner_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_inner_op_spacing
,mstyle
); break
;
3694 case both_types
(inner_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_inner_bin_spacing
,mstyle
); break
;
3695 case both_types
(inner_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_inner_rel_spacing
,mstyle
); break
;
3696 case both_types
(inner_noad_type
, open_noad_type
): x
= get_math_param
(math_param_inner_open_spacing
,mstyle
); break
;
3697 case both_types
(inner_noad_type
, close_noad_type
): x
= get_math_param
(math_param_inner_close_spacing
,mstyle
); break
;
3698 case both_types
(inner_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_inner_punct_spacing
,mstyle
); break
;
3699 case both_types
(inner_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_inner_inner_spacing
,mstyle
); break
;
3703 confusion
("mathspacing");
3707 if
(x
<= thick_mu_skip_code
) {
3708 /* trap thin
/med
/thick settings cf. old TeX
*/
3709 y
= math_glue
(glue_par
(x
), mmu
);
3711 glue_ref_count
(y
) = null
;
3712 /* store a symbolic subtype
*/
3713 subtype
(z
) = (quarterword
) (x
+ 1);
3715 y
= math_glue
(x
, mmu
);
3717 glue_ref_count
(y
) = null
;
3724 static pointer check_nucleus_complexity
(halfword q
, scaled
* delta
, int cur_style
)
3727 switch
(type
(nucleus
(q
))) {
3728 case math_char_node
:
3729 case math_text_char_node
:
3731 if
(char_exists
(cur_f
, cur_c
)) {
3732 /* we could look at neighbours
*/
3733 if
(is_new_mathfont
(cur_f
)) {
3734 *delta
= 0 ; /* cf spec only the last one
*/
3736 *delta
= char_italic
(cur_f
, cur_c
);
3738 p
= new_glyph
(cur_f
, cur_c
);
3739 reset_attributes
(p
, node_attr
(nucleus
(q
)));
3740 if
(is_new_mathfont
(cur_f
)) {
3741 if
(! math_no_char_italic
) {
3742 /* keep italic
, but bad with two successive letters
*/
3743 } else if
(get_char_cat_code
(cur_c
) == 11) {
3744 /* no italic correction in mid-word of text font
*/
3748 /* no italic correction in mid-word of text font
*/
3749 if
(((type
(nucleus
(q
))) == math_text_char_node
) && (space(cur_f) != 0)) {
3753 /* so we only add italic correction when we have no scripts
*/
3754 if
((subscr
(q
) == null
) && (supscr(q) == null) && (*delta != 0)) {
3755 pointer x
= new_kern
(*delta
);
3756 reset_attributes
(x
, node_attr
(nucleus
(q
)));
3760 if
(is_new_mathfont
(cur_f
)) {
3761 *delta
= char_italic
(cur_f
, cur_c
); /* must be more selective
*/
3766 p
= math_list
(nucleus
(q
));
3768 case sub_mlist_node
:
3769 mlist_to_hlist
(math_list
(nucleus
(q
)), false
, cur_style
); /* recursive call
*/
3770 setup_cur_size
(cur_style
);
3771 p
= hpack
(vlink
(temp_head
), 0, additional
, -1);
3772 reset_attributes
(p
, node_attr
(nucleus
(q
)));
3775 confusion
("mlist2"); /* this can't happen mlist2
*/
3780 @ Here is the overall plan of |mlist_to_hlist|
, and the list of its
3784 void mlist_to_hlist
(pointer mlist
, boolean penalties
, int cur_style
)
3786 pointer q
= mlist
; /* runs through the mlist
*/
3787 pointer r
= null
; /* the most recent noad preceding |q|
*/
3788 int style
= cur_style
; /* tuck global parameter away as local variable
*/
3789 int r_type
= simple_noad
; /* the |type| of noad |r|
, or |op_noad| if |r
=null|
*/
3790 int r_subtype
= op_noad_type_normal
; /* the |subtype| of noad |r| if |r_type| is |fence_noad|
*/
3791 int t
; /* the effective |type| of noad |q| during the second pass
*/
3792 int t_subtype
; /* the effective |subtype| of noad |q| during the second pass
*/
3797 int pen
; /* a penalty to be inserted
*/
3798 scaled max_hl
= 0; /* maximum height of the list translated so far
*/
3799 scaled max_d
= 0; /* maximum depth of the list translated so far
*/
3800 scaled delta
; /* italic correction offset for subscript and superscript
*/
3801 scaled cur_mu
; /* the math unit width corresponding to |cur_size|
*/
3802 r_subtype
= op_noad_type_normal
;
3803 setup_cur_size
(cur_style
);
3804 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
3807 we use the fact that no character nodes appear in an mlist
, hence
3808 the field |type
(q
)| is always present.
3810 one of the things we must do on the first pass is change a |bin_noad| to
3811 an |ord_noad| if the |bin_noad| is not in the context of a binary operator
3813 the values of |r| and |r_type| make this fairly easy
3819 switch
(subtype
(q
)) {
3823 switch
(r_subtype
) {
3825 case op_noad_type_normal
:
3826 case op_noad_type_limits
:
3827 case op_noad_type_no_limits
:
3829 case open_noad_type
:
3830 case punct_noad_type
:
3831 subtype
(q
) = ord_noad_type
;
3837 if
(r_subtype
== left_noad_side
) {
3838 subtype
(q
) = ord_noad_type
; /* so these can best be the same size
*/
3844 case over_noad_type
:
3845 make_over
(q
, cur_style
);
3847 case under_noad_type
:
3848 make_under
(q
, cur_style
);
3850 case vcenter_noad_type
:
3854 case close_noad_type
:
3855 case punct_noad_type
:
3856 if
(r_type
== simple_noad
&& r_subtype == bin_noad_type) {
3857 type
(r
) = simple_noad
; /* assumes the same size .. can't this go
*/
3858 subtype
(r
) = ord_noad_type
;
3861 case op_noad_type_normal
:
3862 case op_noad_type_limits
:
3863 case op_noad_type_no_limits
:
3864 delta
= make_op
(q
, cur_style
);
3865 if
((subtype
(q
) == op_noad_type_limits
) ||
(subtype
(q
) == op_noad_type_no_limits
))
3866 goto CHECK_DIMENSIONS
;
3871 case open_noad_type
:
3872 case inner_noad_type
:
3877 if
(subtype
(q
) != left_noad_side
)
3878 if
(r_type
== simple_noad
&& r_subtype == bin_noad_type) {
3879 type
(r
) = simple_noad
; /* assumes the same size
*/
3880 subtype
(r
) = ord_noad_type
;
3882 goto DONE_WITH_NOAD
;
3885 make_fraction
(q
, cur_style
);
3886 goto CHECK_DIMENSIONS
;
3889 if
(subtype
(q
) == 7)
3890 make_hextension
(q
, cur_style
);
3891 else if
(subtype
(q
) == 6)
3892 make_delimiter_over
(q
, cur_style
);
3893 else if
(subtype
(q
) == 5)
3894 make_delimiter_under
(q
, cur_style
);
3895 else if
(subtype
(q
) == 4)
3896 make_over_delimiter
(q
, cur_style
);
3897 else if
(subtype
(q
) == 3)
3898 make_under_delimiter
(q
, cur_style
);
3900 make_radical
(q
, cur_style
);
3903 make_math_accent
(q
, cur_style
);
3906 cur_style
= subtype
(q
);
3907 setup_cur_size
(cur_style
);
3908 cur_mu
= x_over_n
(get_math_quad
(cur_style
), 18);
3909 goto DONE_WITH_NODE
;
3912 switch
(cur_style
/ 2) {
3913 case
0: /* |display_style
=0|
*/
3914 choose_mlist
(display_mlist
);
3916 case
1: /* |text_style
=2|
*/
3917 choose_mlist
(text_mlist
);
3919 case
2: /* |script_style
=4|
*/
3920 choose_mlist
(script_mlist
);
3922 case
3: /* |script_script_style
=6|
*/
3923 choose_mlist
(script_script_mlist
);
3926 flush_node_list
(display_mlist
(q
));
3927 flush_node_list
(text_mlist
(q
));
3928 flush_node_list
(script_mlist
(q
));
3929 flush_node_list
(script_script_mlist
(q
));
3930 type
(q
) = style_node
;
3931 subtype
(q
) = (quarterword
) cur_style
;
3935 while
(vlink
(p
) != null
)
3937 try_couple_nodes
(p
,z
);
3939 goto DONE_WITH_NODE
;
3948 goto DONE_WITH_NODE
;
3951 if
(height
(q
) > max_hl
)
3953 if
(depth
(q
) > max_d
)
3955 goto DONE_WITH_NODE
;
3959 conditional math glue
(`\.
{\\nonscript
}'
) results in a |glue_node|
3960 pointing to |zero_glue|
, with |subtype
(q
)=cond_math_glue|
; in such a case
3961 the node following will be eliminated if it is a glue or kern node and if the
3962 current size is different from |text_size|
3964 unconditional math glue
(`\.
{\\muskip
}'
) is converted to normal glue by
3965 multiplying the dimensions by |cur_mu|
3968 if
(subtype
(q
) == mu_glue
) {
3970 y
= math_glue
(x
, cur_mu
);
3973 subtype
(q
) = normal
;
3974 } else if
((cur_size
!= text_size
) && (subtype(q) == cond_math_glue)) {
3977 if
((type
(p
) == glue_node
) ||
(type
(p
) == kern_node
)) {
3978 couple_nodes
(q
,vlink
(p
));
3983 goto DONE_WITH_NODE
;
3986 math_kern
(q
, cur_mu
);
3987 goto DONE_WITH_NODE
;
3990 confusion
("mlist1");
3993 When we get to the following part of the program
, we have ``fallen through''
3994 from cases that did not lead to |check_dimensions| or |done_with_noad| or
3995 |done_with_node|. Thus
, |q|~points to a noad whose nucleus may need to be
3996 converted to an hlist
, and whose subscripts and superscripts need to be
3997 appended if they are present.
3999 If |nucleus
(q
)| is not a |math_char|
, the variable |delta| is the amount
4000 by which a superscript should be moved right with respect to a subscript
4001 when both are present.
4004 p
= check_nucleus_complexity
(q
, &delta, cur_style);
4006 if
((subscr
(q
) == null
) && (supscr(q) == null)) {
4007 assign_new_hlist
(q
, p
);
4010 make_scripts
(q
, p
, delta
, cur_style
, 0, 0);
4013 z
= hpack
(new_hlist
(q
), 0, additional
, -1);
4014 if
(height
(z
) > max_hl
)
4016 if
(depth
(z
) > max_d
)
4019 /* only drop the \.
{\\hbox
} */
4024 r_subtype
= subtype
(r
);
4025 if
(r_type
== fence_noad
) {
4026 r_subtype
= left_noad_side
;
4028 setup_cur_size
(cur_style
);
4029 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
4034 if
(r_type
== simple_noad
&& r_subtype == bin_noad_type) {
4035 type
(r
) = simple_noad
;
4036 subtype
(r
) = ord_noad_type
;
4039 Make a second pass over the mlist
, removing all noads and inserting the
4040 proper spacing and penalties.
4042 We have now tied up all the loose ends of the first pass of |mlist_to_hlist|.
4043 The second pass simply goes through and hooks everything together with the
4044 proper glue and penalties. It also handles the |fence_noad|s that
4045 might be present
, since |max_hl| and |max_d| are now known. Variable |p| points
4046 to a node at the current end of the final hlist.
4054 setup_cur_size
(cur_style
);
4055 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
4059 If node |q| is a style node
, change the style and |goto delete_q|
;
4060 otherwise if it is not a noad
, put it into the hlist
,
4061 advance |q|
, and |goto done|
; otherwise set |s| to the size
4062 of noad |q|
, set |t| to the associated type
(|ord_noad..
4063 inner_noad|
), and set |pen| to the associated penalty
4065 Just before doing the big |case| switch in the second pass
, the program
4066 sets up default values so that most of the branches are short.
4069 t_subtype
= ord_noad_type
;
4073 t_subtype
= subtype
(q
);
4074 switch
(t_subtype
) {
4076 pen
= bin_op_penalty
;
4081 case vcenter_noad_type
:
4082 case over_noad_type
:
4083 case under_noad_type
:
4084 t_subtype
= ord_noad_type
;
4093 t_subtype
= inner_noad_type
;
4096 t_subtype
= make_left_right
(q
, style
, max_d
, max_hl
);
4099 /* Change the current style and |goto delete_q|
*/
4100 cur_style
= subtype
(q
);
4101 setup_cur_size
(cur_style
);
4102 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
4121 confusion
("mlist3");
4123 /* Append inter-element spacing based on |r_type| and |t|
*/
4125 /* not the first noad
*/
4126 z
= math_spacing_glue
(r_subtype
, t_subtype
, cur_style
, cur_mu
);
4128 reset_attributes
(z
, node_attr
(p
));
4134 Append any |new_hlist| entries for |q|
, and any appropriate penalties
4136 We insert a penalty node after the hlist entries of noad |q| if |pen|
4137 is not an ``infinite'' penalty
, and if the node immediately following |q|
4138 is not a penalty node or a |rel_noad| or absent entirely.
4140 if
(new_hlist
(q
) != null
) {
4141 couple_nodes
(p
,new_hlist
(q
));
4144 } while
(vlink
(p
) != null
);
4146 if
(penalties
&& vlink(q) != null && pen < inf_penalty) {
4147 r_type
= type
(vlink
(q
));
4148 r_subtype
= subtype
(vlink
(q
));
4149 if
(r_type
!= penalty_node
&& (r_type != simple_noad || r_subtype != rel_noad_type)) {
4150 z
= new_penalty
(pen
);
4151 reset_attributes
(z
, node_attr
(q
));
4156 if
(type
(q
) == fence_noad
&& subtype(q) == right_noad_side) {
4158 t_subtype
= open_noad_type
;
4161 r_subtype
= t_subtype
;
4166 The m-to-hlist conversion takes place in-place
, so the various dependant
4167 fields may not be freed
(as would happen if |flush_node| was called
).
4169 A low-level |free_node| is easier than attempting to nullify such dependant
4170 fields for all possible node and noad types.
4172 if
(nodetype_has_attributes
(type
(r
)))
4173 delete_attribute_ref
(node_attr
(r
));
4174 reset_node_properties
(r
);
4175 free_node
(r
, get_node_size
(type
(r
), subtype
(r
)));