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 int_par
(math_old_code
)
55 #define math_no_italic_compensation int_par
(math_no_italic_compensation_code
)
56 #define math_no_char_italic int_par
(math_no_char_italic_code
)
57 #define math_use_old_fraction_scaling int_par
(math_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_old
(a
) get_math_param
(a
, math_param_fraction_del_size
)
366 #define skewed_fraction_hgap
(a
) get_math_param_or_error
(a
, skewed_fraction_hgap
)
367 #define skewed_fraction_vgap
(a
) get_math_param_or_error
(a
, skewed_fraction_vgap
)
369 #define limit_above_vgap
(a
) get_math_param_or_error
(a
, limit_above_vgap
)
370 #define limit_above_bgap
(a
) get_math_param_or_error
(a
, limit_above_bgap
)
371 #define limit_above_kern
(a
) get_math_param_or_error
(a
, limit_above_kern
)
373 #define limit_below_vgap
(a
) get_math_param_or_error
(a
, limit_below_vgap
)
374 #define limit_below_bgap
(a
) get_math_param_or_error
(a
, limit_below_bgap
)
375 #define limit_below_kern
(a
) get_math_param_or_error
(a
, limit_below_kern
)
377 #define sub_shift_drop
(a
) get_math_param_or_error
(a
, sub_shift_drop
)
378 #define sup_shift_drop
(a
) get_math_param_or_error
(a
, sup_shift_drop
)
379 #define sub_shift_down
(a
) get_math_param_or_error
(a
, sub_shift_down
)
380 #define sub_sup_shift_down
(a
) get_math_param_or_error
(a
, sub_sup_shift_down
)
381 #define sup_shift_up
(a
) get_math_param_or_error
(a
, sup_shift_up
)
382 #define sub_top_max
(a
) get_math_param_or_error
(a
, sub_top_max
)
383 #define sup_bottom_min
(a
) get_math_param_or_error
(a
, sup_bottom_min
)
384 #define sup_sub_bottom_max
(a
) get_math_param_or_error
(a
, sup_sub_bottom_max
)
385 #define subsup_vgap
(a
) get_math_param_or_error
(a
, subsup_vgap
)
387 #define space_after_script
(a
) get_math_param_or_error
(a
, space_after_script
)
390 void fixup_math_parameters
(int fam_id
, int size_id
, int f
, int lvl
)
392 if
(is_new_mathfont
(f
)) { /* fix all known parameters
*/
394 DEFINE_MATH_PARAMETERS
(math_param_quad
, size_id
,
396 DEFINE_DMATH_PARAMETERS
(math_param_quad
, size_id
,
398 DEFINE_MATH_PARAMETERS
(math_param_axis
, size_id
,
399 font_MATH_par
(f
, AxisHeight
), lvl
);
400 DEFINE_DMATH_PARAMETERS
(math_param_axis
, size_id
,
401 font_MATH_par
(f
, AxisHeight
), lvl
);
402 DEFINE_MATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
403 font_MATH_par
(f
, OverbarExtraAscender
), lvl
);
404 DEFINE_DMATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
405 font_MATH_par
(f
, OverbarExtraAscender
), lvl
);
406 DEFINE_MATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
407 font_MATH_par
(f
, OverbarRuleThickness
), lvl
);
408 DEFINE_DMATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
409 font_MATH_par
(f
, OverbarRuleThickness
), lvl
);
410 DEFINE_MATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
411 font_MATH_par
(f
, OverbarVerticalGap
), lvl
);
412 DEFINE_DMATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
413 font_MATH_par
(f
, OverbarVerticalGap
), lvl
);
414 DEFINE_MATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
415 font_MATH_par
(f
, UnderbarExtraDescender
), lvl
);
416 DEFINE_DMATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
417 font_MATH_par
(f
, UnderbarExtraDescender
), lvl
);
418 DEFINE_MATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
419 font_MATH_par
(f
, UnderbarRuleThickness
), lvl
);
420 DEFINE_DMATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
421 font_MATH_par
(f
, UnderbarRuleThickness
), lvl
);
422 DEFINE_MATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
423 font_MATH_par
(f
, UnderbarVerticalGap
), lvl
);
424 DEFINE_DMATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
425 font_MATH_par
(f
, UnderbarVerticalGap
), lvl
);
427 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
428 font_MATH_par
(f
, StretchStackGapAboveMin
), lvl
);
429 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
430 font_MATH_par
(f
, StretchStackGapAboveMin
), lvl
);
431 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
432 font_MATH_par
(f
, StretchStackBottomShiftDown
), lvl
);
433 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
434 font_MATH_par
(f
, StretchStackBottomShiftDown
), lvl
);
436 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
437 font_MATH_par
(f
, StretchStackGapBelowMin
), lvl
);
438 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
439 font_MATH_par
(f
, StretchStackGapBelowMin
), lvl
);
440 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
441 font_MATH_par
(f
, StretchStackTopShiftUp
), lvl
);
442 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
443 font_MATH_par
(f
, StretchStackTopShiftUp
), lvl
);
445 DEFINE_MATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
446 font_MATH_par
(f
, StackTopShiftUp
), lvl
);
447 DEFINE_DMATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
448 font_MATH_par
(f
, StackTopDisplayStyleShiftUp
), lvl
);
449 DEFINE_MATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
450 font_MATH_par
(f
, StackBottomShiftDown
), lvl
);
451 DEFINE_DMATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
452 font_MATH_par
(f
, StackBottomDisplayStyleShiftDown
), lvl
);
453 DEFINE_MATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
454 font_MATH_par
(f
, StackGapMin
), lvl
);
455 DEFINE_DMATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
456 font_MATH_par
(f
, StackDisplayStyleGapMin
), lvl
);
458 DEFINE_MATH_PARAMETERS
(math_param_radical_kern
, size_id
,
459 font_MATH_par
(f
, RadicalExtraAscender
), lvl
);
460 DEFINE_DMATH_PARAMETERS
(math_param_radical_kern
, size_id
,
461 font_MATH_par
(f
, RadicalExtraAscender
), lvl
);
463 DEFINE_DMATH_PARAMETERS
(math_param_operator_size
, size_id
,
464 font_MATH_par
(f
, DisplayOperatorMinHeight
), lvl
);
466 DEFINE_MATH_PARAMETERS
(math_param_radical_rule
, size_id
,
467 font_MATH_par
(f
, RadicalRuleThickness
), lvl
);
468 DEFINE_DMATH_PARAMETERS
(math_param_radical_rule
, size_id
,
469 font_MATH_par
(f
, RadicalRuleThickness
), lvl
);
470 DEFINE_MATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
471 font_MATH_par
(f
, RadicalVerticalGap
), lvl
);
472 DEFINE_DMATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
473 font_MATH_par
(f
, RadicalDisplayStyleVerticalGap
), lvl
);
474 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
475 font_MATH_par
(f
, RadicalKernBeforeDegree
), lvl
);
476 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
477 font_MATH_par
(f
, RadicalKernBeforeDegree
), lvl
);
478 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
479 font_MATH_par
(f
, RadicalKernAfterDegree
), lvl
);
480 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
481 font_MATH_par
(f
, RadicalKernAfterDegree
), lvl
);
482 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
483 font_MATH_par
(f
, RadicalDegreeBottomRaisePercent
), lvl
);
484 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
485 font_MATH_par
(f
, RadicalDegreeBottomRaisePercent
), lvl
);
487 if
(size_id
== text_size
) {
488 def_math_param
(math_param_sup_shift_up
, display_style
,
489 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
490 def_math_param
(math_param_sup_shift_up
, cramped_display_style
,
491 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
492 def_math_param
(math_param_sup_shift_up
, text_style
,
493 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
494 def_math_param
(math_param_sup_shift_up
, cramped_text_style
,
495 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
496 } else if
(size_id
== script_size
) {
497 def_math_param
(math_param_sup_shift_up
, script_style
,
498 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
499 def_math_param
(math_param_sup_shift_up
, cramped_script_style
,
500 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
501 } else if
(size_id
== script_script_size
) {
502 def_math_param
(math_param_sup_shift_up
, script_script_style
,
503 font_MATH_par
(f
, SuperscriptShiftUp
), lvl
);
504 def_math_param
(math_param_sup_shift_up
, cramped_script_script_style
,
505 font_MATH_par
(f
, SuperscriptShiftUpCramped
), lvl
);
508 DEFINE_MATH_PARAMETERS
(math_param_sub_shift_drop
, size_id
,
509 font_MATH_par
(f
, SubscriptBaselineDropMin
), lvl
);
510 DEFINE_DMATH_PARAMETERS
(math_param_sub_shift_drop
, size_id
,
511 font_MATH_par
(f
, SubscriptBaselineDropMin
), lvl
);
512 DEFINE_MATH_PARAMETERS
(math_param_sup_shift_drop
, size_id
,
513 font_MATH_par
(f
, SuperscriptBaselineDropMax
), lvl
);
514 DEFINE_DMATH_PARAMETERS
(math_param_sup_shift_drop
, size_id
,
515 font_MATH_par
(f
, SuperscriptBaselineDropMax
), lvl
);
516 DEFINE_MATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
517 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
518 DEFINE_DMATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
519 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
521 if
(font_MATH_par
(f
, SubscriptShiftDownWithSuperscript
) != undefined_math_parameter
) {
522 DEFINE_MATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
523 font_MATH_par
(f
, SubscriptShiftDownWithSuperscript
), lvl
);
524 DEFINE_DMATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
525 font_MATH_par
(f
, SubscriptShiftDownWithSuperscript
), lvl
);
527 DEFINE_MATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
528 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
529 DEFINE_DMATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
530 font_MATH_par
(f
, SubscriptShiftDown
), lvl
);
533 DEFINE_MATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
534 font_MATH_par
(f
, SubscriptTopMax
), lvl
);
535 DEFINE_DMATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
536 font_MATH_par
(f
, SubscriptTopMax
), lvl
);
537 DEFINE_MATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
538 font_MATH_par
(f
, SuperscriptBottomMin
), lvl
);
539 DEFINE_DMATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
540 font_MATH_par
(f
, SuperscriptBottomMin
), lvl
);
541 DEFINE_MATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
542 font_MATH_par
(f
, SuperscriptBottomMaxWithSubscript
), lvl
);
543 DEFINE_DMATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
544 font_MATH_par
(f
, SuperscriptBottomMaxWithSubscript
), lvl
);
545 DEFINE_MATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
546 font_MATH_par
(f
, SubSuperscriptGapMin
), lvl
);
547 DEFINE_DMATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
548 font_MATH_par
(f
, SubSuperscriptGapMin
), lvl
);
550 DEFINE_MATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
551 font_MATH_par
(f
, UpperLimitGapMin
), lvl
);
552 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
553 font_MATH_par
(f
, UpperLimitGapMin
), lvl
);
554 DEFINE_MATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
555 font_MATH_par
(f
, UpperLimitBaselineRiseMin
), lvl
);
556 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
557 font_MATH_par
(f
, UpperLimitBaselineRiseMin
), lvl
);
558 DEFINE_MATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
560 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
562 DEFINE_MATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
563 font_MATH_par
(f
, LowerLimitGapMin
), lvl
);
564 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
565 font_MATH_par
(f
, LowerLimitGapMin
), lvl
);
566 DEFINE_MATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
567 font_MATH_par
(f
, LowerLimitBaselineDropMin
), lvl
);
568 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
569 font_MATH_par
(f
, LowerLimitBaselineDropMin
), lvl
);
570 DEFINE_MATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
572 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
575 DEFINE_MATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
576 font_MATH_par
(f
, FractionRuleThickness
), lvl
);
577 DEFINE_DMATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
578 font_MATH_par
(f
, FractionRuleThickness
), lvl
);
579 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
580 font_MATH_par
(f
, FractionNumeratorGapMin
), lvl
);
581 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
582 font_MATH_par
(f
, FractionNumeratorDisplayStyleGapMin
), lvl
);
583 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
584 font_MATH_par
(f
, FractionNumeratorShiftUp
), lvl
);
585 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
586 font_MATH_par
(f
, FractionNumeratorDisplayStyleShiftUp
), lvl
);
587 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
588 font_MATH_par
(f
, FractionDenominatorGapMin
), lvl
);
589 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
590 font_MATH_par
(f
,FractionDenominatorDisplayStyleGapMin
), lvl
);
591 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
592 font_MATH_par
(f
, FractionDenominatorShiftDown
), lvl
);
593 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
594 font_MATH_par
(f
, FractionDenominatorDisplayStyleShiftDown
), lvl
);
596 DEFINE_MATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
597 font_MATH_par
(f
, FractionDelimiterSize
), lvl
);
598 DEFINE_DMATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
599 font_MATH_par
(f
, FractionDelimiterDisplayStyleSize
), lvl
);
601 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
602 font_MATH_par
(f
, SkewedFractionHorizontalGap
), lvl
);
603 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
604 font_MATH_par
(f
, SkewedFractionHorizontalGap
), lvl
);
605 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
606 font_MATH_par
(f
, SkewedFractionVerticalGap
), lvl
);
607 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
608 font_MATH_par
(f
, SkewedFractionVerticalGap
), lvl
);
610 DEFINE_MATH_PARAMETERS
(math_param_space_after_script
, size_id
,
611 font_MATH_par
(f
, SpaceAfterScript
), lvl
);
612 DEFINE_DMATH_PARAMETERS
(math_param_space_after_script
, size_id
,
613 font_MATH_par
(f
, SpaceAfterScript
), lvl
);
615 DEFINE_MATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
616 font_MATH_par
(f
, MinConnectorOverlap
), lvl
);
617 DEFINE_DMATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
618 font_MATH_par
(f
, MinConnectorOverlap
), lvl
);
620 } else if
(fam_id
== 2 && is_old_mathfont(f, total_mathsy_params)) {
622 /* fix old-style |sy| parameters
*/
624 DEFINE_MATH_PARAMETERS
(math_param_quad
, size_id
,
625 math_quad
(size_id
), lvl
);
626 DEFINE_DMATH_PARAMETERS
(math_param_quad
, size_id
,
627 math_quad
(size_id
), lvl
);
628 DEFINE_MATH_PARAMETERS
(math_param_axis
, size_id
,
629 axis_height
(size_id
), lvl
);
630 DEFINE_DMATH_PARAMETERS
(math_param_axis
, size_id
,
631 axis_height
(size_id
), lvl
);
632 DEFINE_MATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
634 DEFINE_DMATH_PARAMETERS
(math_param_stack_num_up
, size_id
,
636 DEFINE_MATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
637 denom2
(size_id
), lvl
);
638 DEFINE_DMATH_PARAMETERS
(math_param_stack_denom_down
, size_id
,
639 denom1
(size_id
), lvl
);
640 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
642 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_up
, size_id
,
644 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
645 denom2
(size_id
), lvl
);
646 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_down
, size_id
,
647 denom1
(size_id
), lvl
);
648 DEFINE_MATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
649 delim2
(size_id
), lvl
);
650 DEFINE_DMATH_PARAMETERS
(math_param_fraction_del_size
, size_id
,
651 delim1
(size_id
), lvl
);
653 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
655 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_hgap
, size_id
,
657 DEFINE_MATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
659 DEFINE_DMATH_PARAMETERS
(math_param_skewed_fraction_vgap
, size_id
,
662 if
(size_id
== text_size
) {
663 def_math_param
(math_param_sup_shift_up
, display_style
,
665 def_math_param
(math_param_sup_shift_up
, cramped_display_style
,
667 def_math_param
(math_param_sup_shift_up
, text_style
,
669 def_math_param
(math_param_sup_shift_up
, cramped_text_style
,
671 } else if
(size_id
== script_size
) {
672 def_math_param
(math_param_sub_shift_drop
, display_style
,
673 sub_drop
(size_id
), lvl
);
674 def_math_param
(math_param_sub_shift_drop
, cramped_display_style
,
675 sub_drop
(size_id
), lvl
);
676 def_math_param
(math_param_sub_shift_drop
, text_style
,
677 sub_drop
(size_id
), lvl
);
678 def_math_param
(math_param_sub_shift_drop
, cramped_text_style
,
679 sub_drop
(size_id
), lvl
);
680 def_math_param
(math_param_sup_shift_drop
, display_style
,
681 sup_drop
(size_id
), lvl
);
682 def_math_param
(math_param_sup_shift_drop
, cramped_display_style
,
683 sup_drop
(size_id
), lvl
);
684 def_math_param
(math_param_sup_shift_drop
, text_style
,
685 sup_drop
(size_id
), lvl
);
686 def_math_param
(math_param_sup_shift_drop
, cramped_text_style
,
687 sup_drop
(size_id
), lvl
);
688 def_math_param
(math_param_sup_shift_up
, script_style
,
690 def_math_param
(math_param_sup_shift_up
, cramped_script_style
,
692 } else if
(size_id
== script_script_size
) {
693 def_math_param
(math_param_sub_shift_drop
, script_style
,
694 sub_drop
(size_id
), lvl
);
695 def_math_param
(math_param_sub_shift_drop
, cramped_script_style
,
696 sub_drop
(size_id
), lvl
);
697 def_math_param
(math_param_sub_shift_drop
, script_script_style
,
698 sub_drop
(size_id
), lvl
);
699 def_math_param
(math_param_sub_shift_drop
,
700 cramped_script_script_style
, sub_drop
(size_id
), lvl
);
701 def_math_param
(math_param_sup_shift_drop
, script_style
,
702 sup_drop
(size_id
), lvl
);
703 def_math_param
(math_param_sup_shift_drop
, cramped_script_style
,
704 sup_drop
(size_id
), lvl
);
705 def_math_param
(math_param_sup_shift_drop
, script_script_style
,
706 sup_drop
(size_id
), lvl
);
707 def_math_param
(math_param_sup_shift_drop
,
708 cramped_script_script_style
, sup_drop
(size_id
), lvl
);
709 def_math_param
(math_param_sup_shift_up
, script_script_style
,
711 def_math_param
(math_param_sup_shift_up
, cramped_script_script_style
,
715 DEFINE_MATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
717 DEFINE_DMATH_PARAMETERS
(math_param_sub_shift_down
, size_id
,
719 DEFINE_MATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
721 DEFINE_DMATH_PARAMETERS
(math_param_sub_sup_shift_down
, size_id
,
723 DEFINE_MATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
724 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
725 DEFINE_DMATH_PARAMETERS
(math_param_sub_top_max
, size_id
,
726 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
727 DEFINE_MATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
728 (abs
(math_x_height
(size_id
)) / 4), lvl
);
729 DEFINE_DMATH_PARAMETERS
(math_param_sup_bottom_min
, size_id
,
730 (abs
(math_x_height
(size_id
)) / 4), lvl
);
731 DEFINE_MATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
732 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
733 DEFINE_DMATH_PARAMETERS
(math_param_sup_sub_bottom_max
, size_id
,
734 (abs
(math_x_height
(size_id
) * 4) / 5), lvl
);
737 The display-size |radical_vgap| is done twice because it needs
738 values from both the sy and the ex font.
741 DEFINE_DMATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
742 (default_rule_thickness
(size_id
) + (abs
(math_x_height
(size_id
)) / 4)), lvl
);
743 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
745 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_raise
, size_id
,
747 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
748 xn_over_d
(get_math_quad_size
(size_id
), 5, 18), lvl
);
749 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_before
, size_id
,
750 xn_over_d
(get_math_quad_size
(size_id
), 5, 18), lvl
);
751 DEFINE_MATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
752 (-xn_over_d
(get_math_quad_size
(size_id
), 10, 18)), lvl
);
753 DEFINE_DMATH_PARAMETERS
(math_param_radical_degree_after
, size_id
,
754 (-xn_over_d
(get_math_quad_size
(size_id
), 10, 18)), lvl
);
756 } else if
(fam_id
== 3 && is_old_mathfont(f, total_mathex_params)) {
758 /* fix old-style |ex| parameters
*/
760 DEFINE_MATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
761 default_rule_thickness
(size_id
), lvl
);
762 DEFINE_MATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
763 default_rule_thickness
(size_id
), lvl
);
764 DEFINE_MATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
765 3 * default_rule_thickness
(size_id
), lvl
);
766 DEFINE_DMATH_PARAMETERS
(math_param_overbar_kern
, size_id
,
767 default_rule_thickness
(size_id
), lvl
);
768 DEFINE_DMATH_PARAMETERS
(math_param_overbar_rule
, size_id
,
769 default_rule_thickness
(size_id
), lvl
);
770 DEFINE_DMATH_PARAMETERS
(math_param_overbar_vgap
, size_id
,
771 3 * default_rule_thickness
(size_id
), lvl
);
772 DEFINE_MATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
773 default_rule_thickness
(size_id
), lvl
);
774 DEFINE_MATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
775 default_rule_thickness
(size_id
), lvl
);
776 DEFINE_MATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
777 3 * default_rule_thickness
(size_id
), lvl
);
778 DEFINE_DMATH_PARAMETERS
(math_param_underbar_kern
, size_id
,
779 default_rule_thickness
(size_id
), lvl
);
780 DEFINE_DMATH_PARAMETERS
(math_param_underbar_rule
, size_id
,
781 default_rule_thickness
(size_id
), lvl
);
782 DEFINE_DMATH_PARAMETERS
(math_param_underbar_vgap
, size_id
,
783 3 * default_rule_thickness
(size_id
), lvl
);
784 DEFINE_MATH_PARAMETERS
(math_param_radical_kern
, size_id
,
785 default_rule_thickness
(size_id
), lvl
);
786 DEFINE_DMATH_PARAMETERS
(math_param_radical_kern
, size_id
,
787 default_rule_thickness
(size_id
), lvl
);
788 DEFINE_MATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
789 (default_rule_thickness
(size_id
) + (abs
(default_rule_thickness
(size_id
)) / 4)), lvl
);
790 DEFINE_MATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
791 3 * default_rule_thickness
(size_id
), lvl
);
792 DEFINE_DMATH_PARAMETERS
(math_param_stack_vgap
, size_id
,
793 7 * default_rule_thickness
(size_id
), lvl
);
794 DEFINE_MATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
795 default_rule_thickness
(size_id
), lvl
);
796 DEFINE_DMATH_PARAMETERS
(math_param_fraction_rule
, size_id
,
797 default_rule_thickness
(size_id
), lvl
);
798 DEFINE_MATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
799 default_rule_thickness
(size_id
), lvl
);
800 DEFINE_DMATH_PARAMETERS
(math_param_fraction_num_vgap
, size_id
,
801 3 * default_rule_thickness
(size_id
), lvl
);
802 DEFINE_MATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
803 default_rule_thickness
(size_id
), lvl
);
804 DEFINE_DMATH_PARAMETERS
(math_param_fraction_denom_vgap
, size_id
,
805 3 * default_rule_thickness
(size_id
), lvl
);
806 DEFINE_MATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
807 big_op_spacing1
(size_id
), lvl
);
808 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_vgap
, size_id
,
809 big_op_spacing1
(size_id
), lvl
);
810 DEFINE_MATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
811 big_op_spacing3
(size_id
), lvl
);
812 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_bgap
, size_id
,
813 big_op_spacing3
(size_id
), lvl
);
814 DEFINE_MATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
815 big_op_spacing5
(size_id
), lvl
);
816 DEFINE_DMATH_PARAMETERS
(math_param_limit_above_kern
, size_id
,
817 big_op_spacing5
(size_id
), lvl
);
818 DEFINE_MATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
819 big_op_spacing2
(size_id
), lvl
);
820 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_vgap
, size_id
,
821 big_op_spacing2
(size_id
), lvl
);
822 DEFINE_MATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
823 big_op_spacing4
(size_id
), lvl
);
824 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_bgap
, size_id
,
825 big_op_spacing4
(size_id
), lvl
);
826 DEFINE_MATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
827 big_op_spacing5
(size_id
), lvl
);
828 DEFINE_DMATH_PARAMETERS
(math_param_limit_below_kern
, size_id
,
829 big_op_spacing5
(size_id
), lvl
);
830 DEFINE_MATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
831 4 * default_rule_thickness
(size_id
), lvl
);
832 DEFINE_DMATH_PARAMETERS
(math_param_subsup_vgap
, size_id
,
833 4 * default_rule_thickness
(size_id
), lvl
);
836 All of the |space_after_script|s are done in |finalize_math_parameters|
837 because the \.
{\\scriptspace
} may have been altered by the user
840 DEFINE_MATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
842 DEFINE_DMATH_PARAMETERS
(math_param_connector_overlap_min
, size_id
,
845 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
846 big_op_spacing2
(size_id
), lvl
);
847 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_vgap
, size_id
,
848 big_op_spacing2
(size_id
), lvl
);
849 DEFINE_MATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
850 big_op_spacing4
(size_id
), lvl
);
851 DEFINE_DMATH_PARAMETERS
(math_param_under_delimiter_bgap
, size_id
,
852 big_op_spacing4
(size_id
), lvl
);
853 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
854 big_op_spacing1
(size_id
), lvl
);
855 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_vgap
, size_id
,
856 big_op_spacing1
(size_id
), lvl
);
857 DEFINE_MATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
858 big_op_spacing3
(size_id
), lvl
);
859 DEFINE_DMATH_PARAMETERS
(math_param_over_delimiter_bgap
, size_id
,
860 big_op_spacing3
(size_id
), lvl
);
863 The display-size |radical_vgap| is done twice because it needs
864 values from both the sy and the ex font.
867 DEFINE_DMATH_PARAMETERS
(math_param_radical_vgap
, size_id
,
868 (default_rule_thickness
(size_id
) + (abs
(math_x_height
(size_id
)) / 4)), lvl
);
873 @ This needs to be called just at the start of |mlist_to_hlist|
, for
874 backward compatibility with \.
{\\scriptspace
}.
877 static void finalize_math_parameters
(void
)
879 int saved_trace
= int_par
(tracing_assigns_code
);
880 int_par
(tracing_assigns_code
) = 0;
881 if
(get_math_param
(math_param_space_after_script
, display_style
) == undefined_math_parameter
) {
882 def_math_param
(math_param_space_after_script
, display_style
,
883 script_space
, level_one
);
884 def_math_param
(math_param_space_after_script
, text_style
,
885 script_space
, level_one
);
886 def_math_param
(math_param_space_after_script
, script_style
,
887 script_space
, level_one
);
888 def_math_param
(math_param_space_after_script
, script_script_style
,
889 script_space
, level_one
);
890 def_math_param
(math_param_space_after_script
, cramped_display_style
,
891 script_space
, level_one
);
892 def_math_param
(math_param_space_after_script
, cramped_text_style
,
893 script_space
, level_one
);
894 def_math_param
(math_param_space_after_script
, cramped_script_style
,
895 script_space
, level_one
);
896 def_math_param
(math_param_space_after_script
, cramped_script_script_style
,
897 script_space
, level_one
);
899 int_par
(tracing_assigns_code
) = saved_trace
;
902 @ In order to convert mlists to hlists
, i.e.
, noads to nodes
, we need several
903 subroutines that are conveniently dealt with now.
905 Let us first introduce the macros that make it easy to get at the parameters and
906 other font information. A size code
, which is a multiple of
256, is added to a
907 family number to get an index into the table of internal font numbers
908 for each combination of family and size.
(Be alert
: Size codes get
909 larger as the type gets smaller.
)
912 static const char
*math_size_string
(int s
)
916 else if
(s
== script_size
)
919 return
"scriptscriptfont";
922 @ When the style changes
, the following piece of program computes associated
926 #define setup_cur_size
(a
) do
{ \
927 if
(a
==script_style || \
928 a
==cramped_script_style
) \
929 cur_size
=script_size
; \
930 else if
(a
==script_script_style || \
931 a
==cramped_script_script_style
) \
932 cur_size
=script_script_size
; \
933 else cur_size
=text_size
; \
937 @ a simple routine that creates a flat copy of a nucleus
939 static pointer math_clone
(pointer q
)
944 x
= new_node
(type
(q
), 0);
945 reset_attributes
(x
, node_attr
(q
));
946 if
(type
(q
) == math_char_node
) {
947 math_fam
(x
) = math_fam
(q
);
948 math_character
(x
) = math_character
(q
);
950 math_list
(x
) = math_list
(q
);
955 @ Here is a function that returns a pointer to a rule node having a given
956 thickness |t|. The rule will extend horizontally to the boundary of the vlist
957 that eventually contains it.
960 static pointer do_fraction_rule
(scaled t
, pointer att
)
962 pointer p
; /* the new node
*/
963 p
= new_rule
(normal_rule
);
964 rule_dir
(p
) = math_direction
;
967 reset_attributes
(p
, att
);
971 @ The |overbar| function returns a pointer to a vlist box that consists of
972 a given box |b|
, above which has been placed a kern of height |k| under a
973 fraction rule of thickness |t| under additional space of height |ht|.
976 static pointer overbar
(pointer b
, scaled k
, scaled t
, scaled ht
, pointer att
)
978 pointer p
, q
; /* nodes being constructed
*/
980 reset_attributes
(p
, att
);
982 q
= do_fraction_rule
(t
, att
);
985 reset_attributes
(p
, att
);
987 q
= vpackage
(p
, 0, additional
, max_dimen
, math_direction
);
988 reset_attributes
(q
, att
);
992 @ Here is a subroutine that creates a new box
, whose list contains a
993 single character
, and whose width includes the italic correction for
994 that character. The height or depth of the box will be negative
, if
995 the height or depth of the character is negative
; thus
, this routine
996 may deliver a slightly different result than |hpack| would produce.
999 static pointer char_box
(internal_font_number f
, int c
, pointer bb
)
1001 pointer b
, p
; /* the new box and its character node
*/
1003 if
(is_new_mathfont
(f
))
1004 width
(b
) = char_width
(f
, c
);
1006 width
(b
) = char_width
(f
, c
) + char_italic
(f
, c
);
1007 height
(b
) = char_height
(f
, c
);
1008 depth
(b
) = char_depth
(f
, c
);
1009 reset_attributes
(b
, bb
);
1011 reset_attributes
(p
, bb
);
1016 @ Another handy subroutine computes the height plus depth of
1020 static scaled height_plus_depth
(internal_font_number f
, int c
)
1022 return
(char_height
(f
, c
) + char_depth
(f
, c
));
1025 @ When we build an extensible character
, it's handy to have the
1026 following subroutine
, which puts a given character on top
1027 of the characters already in box |b|
:
1030 static scaled stack_into_box
(pointer b
, internal_font_number f
, int c
)
1032 pointer p
, q
; /* new node placed into |b|
*/
1033 p
= char_box
(f
, c
, node_attr
(b
)); /* italic gets added to width
*/
1034 if
(type
(b
) == vlist_node
) {
1035 try_couple_nodes
(p
,list_ptr
(b
));
1037 height
(b
) = height
(p
);
1038 if
(width
(b
) < width
(p
))
1039 width
(b
) = width
(p
);
1040 return height_plus_depth
(f
, c
);
1046 while
(vlink
(q
) != null
)
1050 if
(height
(b
) < height
(p
))
1051 height
(b
) = height
(p
);
1052 if
(depth
(b
) < depth
(p
))
1053 depth
(b
) = depth
(p
);
1054 return char_width
(f
, c
);
1058 static void stack_glue_into_box
(pointer b
, scaled min
, scaled max
) {
1059 pointer p
, q
; /* new node placed into |b|
*/
1060 q
= new_spec
(zero_glue
);
1062 stretch
(q
) = max-min
;
1064 reset_attributes
(p
, node_attr
(b
));
1065 if
(type
(b
) == vlist_node
) {
1066 try_couple_nodes
(p
,list_ptr
(b
));
1073 while
(vlink
(q
) != null
)
1080 @ \TeX's most important routine for dealing with formulas is called
1081 |mlist_to_hlist|. After a formula has been scanned and represented
1082 as an mlist
, this routine converts it to an hlist that can be placed
1083 into a box or incorporated into the text of a paragraph. The
1084 explicit parameter |cur_mlist| points to the first node or noad in
1085 the given mlist
(and it might be |null|
); the parameter |penalties|
1086 is |true| if penalty nodes for potential line breaks are to be
1087 inserted into the resulting hlist
, the parameter |cur_style| is a
1088 style code. After |mlist_to_hlist| has acted
, |vlink
(temp_head
)|
1089 points to the translated hlist.
1091 Since mlists can be inside mlists
, the procedure is recursive. And since this
1092 is not part of \TeX's inner loop
, the program has been written in a manner
1093 that stresses compactness over efficiency.
1097 int cur_size
; /* size code corresponding to |cur_style|
*/
1100 static pointer get_delim_box
(pointer q
, extinfo
* ext
, internal_font_number f
, scaled v
,
1101 pointer att
, int cur_style
, int boxtype
)
1103 pointer b
; /* new box
*/
1104 scaled b_max
; /* natural
(maximum
) size of the stack
*/
1105 scaled s_max
; /* amount of possible shrink in the stack
*/
1107 scaled min_overlap
, prev_overlap
;
1108 int i
; /* a temporary counter number of extensible pieces
*/
1109 int with_extenders
; /* number of times to repeat each repeatable item in |ext|
*/
1110 int num_extenders
, num_normal
;
1113 assert
(ext
!= NULL);
1115 type
(b
) = (quarterword
) boxtype
;
1116 reset_attributes
(b
, att
);
1117 min_overlap
= connector_overlap_min
(cur_style
);
1118 assert
(min_overlap
>= 0);
1119 with_extenders
= -1;
1124 while
(cur
!= NULL) {
1125 if
(!char_exists
(f
, cur-
>glyph
)) {
1126 const char
*hlp
[] = {
1127 "Each glyph part in an extensible item should exist in the font.",
1128 "I will give up trying to find a suitable size for now. Fix your font!",
1131 tex_error
("Variant part doesn't exist.", hlp
);
1132 width
(b
) = null_delimiter_space
;
1135 if
(cur-
>extender
> 0)
1139 /* no negative overlaps or advances are allowed
*/
1140 if
(cur-
>start_overlap
< 0 || cur-
>end_overlap
< 0 || cur-
>advance
< 0) {
1141 const char
*hlp
[] = {
1142 "All measurements in extensible items should be positive.",
1143 "To get around this problem, I have changed the font metrics.",
1147 tex_error
("Extensible recipe has negative fields.", hlp
);
1148 if
(cur-
>start_overlap
< 0)
1149 cur-
>start_overlap
= 0;
1150 if
(cur-
>end_overlap
< 0)
1151 cur-
>end_overlap
= 0;
1152 if
(cur-
>advance
< 0)
1157 if
(num_normal
== 0) {
1158 const char
*hlp
[] = {
1159 "Each extensible recipe should have at least one non-repeatable part.",
1160 "To get around this problem, I have changed the first part to be",
1161 "non-repeatable. Fix your font!",
1164 tex_error
("Extensible recipe has no fixed parts.", hlp
);
1170 |ext| holds a linked list of numerous items that may or may not be
1171 repeatable. For the total height
, we have to figure out how many items
1172 are needed to create a stack of at least |v|.
1174 The next |while| loop does that. It has two goals
: it finds out
1175 the natural height |b_max| of the all the parts needed to reach
1176 at least |v|
, and it sets |with_extenders| to the number of times
1177 each of the repeatable items in |ext| has to be repeated to reach
1183 while
(b_max
< v
&& num_extenders > 0) {
1187 for
(cur
= ext
; cur
!= NULL; cur
= cur-
>next
) {
1188 if
(cur-
>extender
== 0) {
1189 c
= cur-
>start_overlap
;
1190 if
(min_overlap
< c
)
1192 if
(prev_overlap
< c
)
1197 if
(boxtype
== vlist_node
)
1198 a
= height_plus_depth
(f
, cur-
>glyph
);
1200 a
= char_width
(f
, cur-
>glyph
);
1204 prev_overlap
= cur-
>end_overlap
;
1208 c
= cur-
>start_overlap
;
1209 if
(min_overlap
< c
)
1211 if
(prev_overlap
< c
)
1216 if
(boxtype
== vlist_node
)
1217 a
= height_plus_depth
(f
, cur-
>glyph
);
1219 a
= char_width
(f
, cur-
>glyph
);
1223 prev_overlap
= cur-
>end_overlap
;
1231 assemble box using |with_extenders| copies of each extender
, with
1232 appropriate glue wherever an overlap occurs
1237 for
(cur
= ext
; cur
!= NULL; cur
= cur-
>next
) {
1238 if
(cur-
>extender
== 0) {
1239 c
= cur-
>start_overlap
;
1240 if
(prev_overlap
< c
)
1243 if
(min_overlap
< c
)
1246 stack_glue_into_box
(b
, -d
, -c
);
1247 s_max
+= (-c
) - (-d
);
1250 b_max
+= stack_into_box
(b
, f
, cur-
>glyph
);
1251 prev_overlap
= cur-
>end_overlap
;
1256 c
= cur-
>start_overlap
;
1257 if
(prev_overlap
< c
)
1260 if
(min_overlap
< c
)
1263 stack_glue_into_box
(b
, -d
, -c
);
1264 s_max
+= (-c
) - (-d
);
1267 b_max
+= stack_into_box
(b
, f
, cur-
>glyph
);
1268 prev_overlap
= cur-
>end_overlap
;
1274 /* set glue so as to stretch the connections if needed
*/
1277 if
(v
> b_max
&& s_max > 0) {
1279 /* don't stretch more than |s_max|
*/
1282 glue_order
(b
) = normal
;
1283 glue_sign
(b
) = stretching
;
1284 glue_set
(b
) = unfloat
(d
/(float
) s_max
);
1288 if
(boxtype
== vlist_node
) {
1297 @ The |var_delimiter| function
, which finds or constructs a sufficiently
1298 large delimiter
, is the most interesting of the auxiliary functions that
1299 currently concern us. Given a pointer |d| to a delimiter field in some noad
,
1300 together with a size code |s| and a vertical distance |v|
, this function
1301 returns a pointer to a box that contains the smallest variant of |d| whose
1302 height plus depth is |v| or more.
(And if no variant is large enough
, it
1303 returns the largest available variant.
) In particular
, this routine will
1304 construct arbitrarily large delimiters from extensible components
, if
1305 |d| leads to such characters.
1307 The value returned is a box whose |shift_amount| has been set so that
1308 the box is vertically centered with respect to the axis in the given size.
1309 If a built-up symbol is returned
, the height of the box before shifting
1310 will be the height of its topmost component.
1313 static void endless_loop_error
(internal_font_number g
, int y
)
1316 const char
*hlp
[] = {
1317 "You managed to create a seemingly endless charlist chain in the current",
1318 "font. I have counted until 10000 already and still have not escaped, so"
1319 "I will jump out of the loop all by myself now. Fix your font!",
1322 snprintf
(s
, 256, "Math error: endless loop in charlist (U+%04x in %s)",
1323 (int
) y
, font_name
(g
));
1327 static pointer do_delimiter
(pointer q
, pointer d
, int s
, scaled v
, boolean flat
, int cur_style
, boolean shift
, boolean
*stack
, scaled
*delta
)
1329 pointer b
; /* the box that will be constructed
*/
1330 internal_font_number f
, g
; /* best-so-far and tentative font codes
*/
1331 int c
, i
, x
, y
; /* best-so-far and tentative character codes
*/
1332 scaled u
; /* height-plus-depth of a tentative character
*/
1333 scaled w
; /* largest height-plus-depth so far
*/
1334 int z
; /* runs through font family members
*/
1335 boolean large_attempt
; /* are we trying the ``large'' variant?
*/
1336 pointer att
; /* to save the current attribute list
*/
1344 large_attempt
= false
;
1352 The search process is complicated slightly by the facts that some of the
1353 characters might not be present in some of the fonts
, and they might not
1354 be probed in increasing order of height.
1356 if
((z
!= 0) ||
(x
!= 0)) {
1358 if
(g
!= null_font
) {
1362 if
(char_exists
(g
, y
)) {
1364 u
= char_width
(g
, y
);
1366 u
= height_plus_depth
(g
, y
);
1374 if
(char_tag
(g
, y
) == ext_tag
) {
1382 endless_loop_error
(g
, y
);
1385 if
(char_tag
(g
, y
) == list_tag
) {
1386 y
= char_remainder
(g
, y
);
1393 goto FOUND
; /* there were none large enough
*/
1394 large_attempt
= true
;
1401 node_attr
(d
) = null
;
1404 if
(f
!= null_font
) {
1406 When the following code is executed
, |do_parts| will be true
1407 if a built-up symbol is supposed to be returned.
1410 if
((do_parts
) && ((!flat && (ext = get_charinfo_vert_variants(char_info(f,c))) != NULL)
1411 ||
( flat
&& (ext = get_charinfo_hor_variants (char_info(f,c))) != NULL))) {
1413 b
= get_delim_box
(d
, ext
, f
, v
, att
, cur_style
, hlist_node
);
1415 b
= get_delim_box
(d
, ext
, f
, v
, att
, cur_style
, vlist_node
);
1417 if
(delta
!= NULL) {
1418 if
(is_new_mathfont
(f
)) {
1419 *delta
= char_vert_italic
(f
,x
);
1421 *delta
= char_italic
(f
,x
);
1427 b
= char_box
(f
, c
, att
);
1428 if
(!is_new_mathfont
(f
)) {
1429 /* italic gets added to width
*/
1430 width
(b
) += char_italic
(f
, c
);
1432 if
(delta
!= NULL) {
1433 *delta
= char_italic
(f
,x
);
1440 reset_attributes
(b
, att
);
1444 /* use this width if no delimiter was found
*/
1445 width
(b
) = null_delimiter_space
;
1447 if
(delta
!= NULL) {
1454 /* vertical variant
*/
1455 shift_amount
(b
) = half
(height
(b
) - depth
(b
));
1457 shift_amount
(b
) -= math_axis
(s
);
1460 delete_attribute_ref
(att
);
1464 @ The next subroutine is much simpler
; it is used for numerators and
1465 denominators of fractions as well as for displayed operators and
1466 their limits above and below. It takes a given box~|b| and
1467 changes it so that the new box is centered in a box of width~|w|.
1468 The centering is done by putting \.
{\\hss
} glue at the left and right
1469 of the list inside |b|
, then packaging the new box
; thus
, the
1470 actual box might not really be centered
, if it already contains
1473 The given box might contain a single character whose italic correction
1474 has been added to the width of the box
; in this case a compensating
1478 static pointer rebox
(pointer b
, scaled w
)
1480 pointer p
, q
, r
, att
; /* temporary registers for list manipulation
*/
1481 internal_font_number f
; /* font in a one-character box
*/
1482 scaled v
; /* width of a character without italic correction
*/
1484 if
((width
(b
) != w
) && (list_ptr(b) != null)) {
1485 if
(type
(b
) == vlist_node
) {
1486 p
= hpack
(b
, 0, additional
, -1);
1487 reset_attributes
(p
, node_attr
(b
));
1492 add_node_attr_ref
(att
);
1493 if
((is_char_node
(p
)) && (vlink(p) == null)) {
1495 v
= char_width
(f
, character
(p
));
1496 if
(v
!= width
(b
)) {
1497 q
= new_kern
(width
(b
) - v
);
1498 reset_attributes
(q
, att
);
1504 b
= new_glue
(ss_glue
);
1505 reset_attributes
(b
, att
);
1507 while
(vlink
(p
) != null
)
1509 q
= new_glue
(ss_glue
);
1510 reset_attributes
(q
, att
);
1512 r
= hpack
(b
, w
, exactly
, -1);
1513 reset_attributes
(r
, att
);
1514 delete_attribute_ref
(att
);
1522 @ Here is a subroutine that creates a new glue specification from another
1523 one that is expressed in `\.
{mu
}'
, given the value of the math unit.
1526 #define mu_mult
(A
) mult_and_add
(n
,(A
),xn_over_d
((A
),f
,unity
),max_dimen
)
1528 static pointer math_glue
(pointer g
, scaled m
)
1530 pointer p
; /* the new glue specification
*/
1531 int n
; /* integer part of |m|
*/
1532 scaled f
; /* fraction part of |m|
*/
1533 n
= x_over_n
(m
, unity
);
1539 p
= new_node
(glue_spec_node
, 0);
1540 width
(p
) = mu_mult
(width
(g
)); /* convert \.
{mu
} to \.
{pt
} */
1541 stretch_order
(p
) = stretch_order
(g
);
1542 if
(stretch_order
(p
) == normal
)
1543 stretch
(p
) = mu_mult
(stretch
(g
));
1545 stretch
(p
) = stretch
(g
);
1546 shrink_order
(p
) = shrink_order
(g
);
1547 if
(shrink_order
(p
) == normal
)
1548 shrink
(p
) = mu_mult
(shrink
(g
));
1550 shrink
(p
) = shrink
(g
);
1554 @ The |math_kern| subroutine removes |mu_glue| from a kern node
, given
1555 the value of the math unit.
1558 static void math_kern
(pointer p
, scaled m
)
1560 int n
; /* integer part of |m|
*/
1561 scaled f
; /* fraction part of |m|
*/
1562 if
(subtype
(p
) == mu_glue
) {
1563 n
= x_over_n
(m
, unity
);
1569 width
(p
) = mu_mult
(width
(p
));
1570 subtype
(p
) = italic_kern
;
1575 void run_mlist_to_hlist
(halfword p
, boolean penalties
, int mstyle
)
1579 lua_State
*L
= Luas
;
1581 vlink
(temp_head
) = null
;
1584 finalize_math_parameters
();
1585 callback_id
= callback_defined
(mlist_to_hlist_callback
);
1586 if
(callback_id
> 0) {
1587 sfix
= lua_gettop
(L
);
1588 if
(!get_callback
(L
, callback_id
)) {
1589 lua_settop
(L
, sfix
);
1593 nodelist_to_lua
(L
, p
); /* arg
1 */
1594 lua_pushstring
(L
, math_style_names
[mstyle
]); /* arg
2 */
1595 lua_pushboolean
(L
, penalties
); /* arg
3 */
1596 if
(lua_pcall
(L
, 3, 1, 0) != 0) { /* 3 args
, 1 result
*/
1597 char errmsg
[256]; /* temp hack ... we will have a formatted error
*/
1598 snprintf
(errmsg
, 255, "error: %s\n", lua_tostring
(L
, -1));
1600 lua_settop
(L
, sfix
);
1601 normal_error
("mlist to hlist",errmsg
); /* to be done
*/
1604 a
= nodelist_from_lua
(L
);
1605 /* alink
(vlink
(a
)) = null
; */
1606 lua_settop
(L
, sfix
);
1607 vlink
(temp_head
) = a
;
1608 } else if
(callback_id
== 0) {
1609 mlist_to_hlist
(p
, penalties
, mstyle
);
1611 vlink
(temp_head
) = null
;
1615 @ The recursion in |mlist_to_hlist| is due primarily to a subroutine
1616 called |clean_box| that puts a given noad field into a box using a given
1617 math style
; |mlist_to_hlist| can call |clean_box|
, which can call
1621 The box returned by |clean_box| is ``clean'' in the
1622 sense that its |shift_amount| is zero.
1625 static pointer clean_box
(pointer p
, int s
, int cur_style
)
1627 pointer q
; /* beginning of a list to be boxed
*/
1628 pointer x
; /* box to be returned
*/
1629 pointer r
; /* temporary pointer
*/
1630 pointer mlist
= null
; /* beginning of mlist to be translated
*/
1632 case math_char_node
:
1641 case sub_mlist_node
:
1642 mlist
= math_list
(p
);
1648 mlist_to_hlist
(mlist
, false
, s
);
1649 q
= vlink
(temp_head
); /* recursive call
*/
1650 setup_cur_size
(cur_style
);
1652 if
(is_char_node
(q
) ||
(q
== null
))
1653 x
= hpack
(q
, 0, additional
, -1);
1654 else if
((vlink
(q
) == null
) && (type(q) <= vlist_node) && (shift_amount(q) == 0))
1655 x
= q
; /* it's already clean
*/
1657 x
= hpack
(q
, 0, additional
, -1);
1658 if
(x
!= q
&& q != null)
1659 reset_attributes
(x
, node_attr
(q
));
1660 /* Here we save memory space in a common case.
*/
1662 if
(is_char_node
(q
)) {
1665 if
(vlink
(r
) == null
) {
1666 if
(!is_char_node
(r
)) {
1667 if
(type
(r
) == kern_node
) {
1668 /* unneeded italic correction
*/
1679 @ It is convenient to have a procedure that converts a |math_char|
1680 field to an ``unpacked'' form. The |fetch| routine sets |cur_f| and |cur_c|
1681 to the font code and character code of a given noad field.
1682 It also takes care of issuing error messages for
1683 nonexistent characters
; in such cases
, |char_exists
(cur_f
,cur_c
)| will be |false|
1684 after |fetch| has acted
, and the field will also have been reset to |null|.
1686 The outputs of |fetch| are placed in global variables.
1689 internal_font_number cur_f
; /* the |font| field of a |math_char|
*/
1690 int cur_c
; /* the |character| field of a |math_char|
*/
1692 @ Here we unpack the |math_char| field |a|.
1694 @c static void fetch
(pointer a
)
1696 cur_c
= math_character
(a
);
1697 cur_f
= fam_fnt
(math_fam
(a
), cur_size
);
1698 if
(cur_f
== null_font
) {
1700 const char
*hlp
[] = {
1701 "Somewhere in the math formula just ended, you used the",
1702 "stated character from an undefined font family. For example,",
1703 "plain TeX doesn't allow \\it or \\sl in subscripts. Proceed,",
1704 "and I'll try to forget that I needed that character.",
1708 snprintf
(msg
, 255, "\\%s%d is undefined (character %d)",
1709 math_size_string
(cur_size
), (int
) math_fam
(a
), (int
) cur_c
);
1710 tex_error
(msg
, hlp
);
1712 } else if
(!(char_exists
(cur_f
, cur_c
))) {
1713 char_warning
(cur_f
, cur_c
);
1717 @ We need to do a lot of different things
, so |mlist_to_hlist| makes two
1718 passes over the given mlist.
1720 The first pass does most of the processing
: It removes ``mu'' spacing from
1721 glue
, it recursively evaluates all subsidiary mlists so that only the
1722 top-level mlist remains to be handled
, it puts fractions and square roots
1723 and such things into boxes
, it attaches subscripts and superscripts
, and
1724 it computes the overall height and depth of the top-level mlist so that
1725 the size of delimiters for a |fence_noad| will be known.
1726 The hlist resulting from each noad is recorded in that noad's |new_hlist|
1727 field
, an integer field that replaces the |nucleus| or |thickness|.
1730 The second pass eliminates all noads and inserts the correct glue and
1731 penalties between nodes.
1734 static void assign_new_hlist
(pointer q
, pointer r
)
1738 math_list
(numerator
(q
)) = null
;
1739 flush_node
(numerator
(q
));
1740 numerator
(q
) = null
;
1741 math_list
(denominator
(q
)) = null
;
1742 flush_node
(denominator
(q
));
1743 denominator
(q
) = null
;
1748 if
(nucleus
(q
) != null
) {
1749 math_list
(nucleus
(q
)) = null
;
1750 flush_node
(nucleus
(q
));
1759 #define choose_mlist
(A
) do
{ p
=A
(q
); A
(q
)=null
; } while
(0)
1761 @ Most of the actual construction work of |mlist_to_hlist| is done
1762 by procedures with names like |make_fraction|
, |make_radical|
, etc. To
1763 illustrate the general setup of such procedures
, let's begin with a
1764 couple of simple ones.
1767 static void make_over
(pointer q
, int cur_style
)
1770 p
= overbar
(clean_box
(nucleus
(q
), cramped_style
(cur_style
), cur_style
),
1771 overbar_vgap
(cur_style
), overbar_rule
(cur_style
),
1772 overbar_kern
(cur_style
), node_attr
(nucleus
(q
)));
1773 math_list
(nucleus
(q
)) = p
;
1774 type
(nucleus
(q
)) = sub_box_node
;
1777 static void make_under
(pointer q
, int cur_style
)
1779 pointer p
, x
, y
, r
; /* temporary registers for box construction
*/
1780 scaled delta
; /* overall height plus depth
*/
1781 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
1782 p
= new_kern
(underbar_vgap
(cur_style
));
1783 reset_attributes
(p
, node_attr
(q
));
1785 r
= do_fraction_rule
(underbar_rule
(cur_style
), node_attr
(q
));
1787 y
= vpackage
(x
, 0, additional
, max_dimen
, math_direction
);
1788 reset_attributes
(y
, node_attr
(q
));
1789 delta
= height
(y
) + depth
(y
) + underbar_kern
(cur_style
);
1790 height
(y
) = height
(x
);
1791 depth
(y
) = delta
- height
(y
);
1792 math_list
(nucleus
(q
)) = y
;
1793 type
(nucleus
(q
)) = sub_box_node
;
1796 static void make_vcenter
(pointer q
)
1798 pointer v
; /* the box that should be centered vertically
*/
1799 scaled delta
; /* its height plus depth
*/
1800 v
= math_list
(nucleus
(q
));
1801 if
(type
(v
) != vlist_node
)
1802 confusion
("vcenter");
1803 delta
= height
(v
) + depth
(v
);
1804 height
(v
) = math_axis
(cur_size
) + half
(delta
);
1805 depth
(v
) = delta
- height
(v
);
1808 @ According to the rules in the \.
{DVI
} file specifications
, we ensure alignment
1810 between a square root sign and the rule above its nucleus by assuming that the
1811 baseline of the square-root symbol is the same as the bottom of the rule. The
1812 height of the square-root symbol will be the thickness of the rule
, and the
1813 depth of the square-root symbol should exceed or equal the height-plus-depth
1814 of the nucleus plus a certain minimum clearance~|psi|. The symbol will be
1815 placed so that the actual clearance is |psi| plus half the excess.
1818 static void make_hextension
(pointer q
, int cur_style
)
1822 boolean stack
= false
;
1823 e
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, radicalwidth
(q
), true
, cur_style
, true
, &stack, NULL);
1825 if
(!stack
&& (radicalwidth(q) != 0) && (radicalwidth(q) != width(e))) {
1826 if
(radicalmiddle
(q
)) {
1827 p
= new_kern
(half
(radicalwidth
(q
)-w
));
1828 reset_attributes
(p
, node_attr
(q
));
1831 w
= radicalwidth
(q
);
1832 } else if
(radicalexact
(q
)) {
1833 w
= radicalwidth
(q
);
1836 e
= hpack
(e
, 0, additional
, -1);
1838 reset_attributes
(e
, node_attr
(q
));
1839 math_list
(nucleus
(q
)) = e
;
1840 left_delimiter
(q
) = null
;
1843 static void make_radical
(pointer q
, int cur_style
)
1845 pointer x
, y
, p
, l1
, l2
; /* temporary registers for box construction
*/
1846 scaled delta
, clr
, theta
, h
; /* dimensions involved in the calculation
*/
1847 x
= clean_box
(nucleus
(q
), cramped_style
(cur_style
), cur_style
);
1848 clr
= radical_vgap
(cur_style
);
1849 theta
= radical_rule
(cur_style
);
1850 if
(theta
== undefined_math_parameter
) {
1851 /* a real radical
*/
1852 theta
= fraction_rule
(cur_style
);
1853 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, height
(x
) + depth
(x
) + clr
+ theta
, false
, cur_style
, true
, NULL, NULL);
1855 If |y| is a composite then set |theta| to the height of its top
1856 character
, else set it to the height of |y|.
1859 if
((l1
!= null
) && (type(l1) == hlist_node)) {
1860 /* possible composite
*/
1862 if
((l2
!= null
) && (type(l2) == glyph_node)) {
1864 theta
= char_height
(font
(l2
), character
(l2
));
1872 /* not really a radical but we use its node
, historical sharing
(like in mathml
) */
1873 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, height
(x
) + depth
(x
) + clr
+ theta
, false
, cur_style
, true
, NULL, NULL);
1875 left_delimiter
(q
) = null
;
1876 delta
= (depth
(y
) + height
(y
) - theta
) - (height
(x
) + depth
(x
) + clr
);
1878 /* increase the actual clearance
*/
1879 clr
= clr
+ half
(delta
);
1881 shift_amount
(y
) = (height
(y
) - theta
) - (height
(x
) + clr
);
1882 h
= depth
(y
) + height
(y
);
1883 p
= overbar
(x
, clr
, theta
, radical_kern
(cur_style
), node_attr
(y
));
1885 if
(degree
(q
) != null
) {
1887 pointer r
= clean_box
(degree
(q
), script_script_style
, cur_style
);
1888 reset_attributes
(r
, node_attr
(degree
(q
)));
1893 br
= radical_degree_before
(cur_style
);
1894 ar
= radical_degree_after
(cur_style
);
1895 if
(-ar
> (wr
+ br
))
1898 reset_attributes
(x
, node_attr
(degree
(q
)));
1901 -((xn_over_d
(h
, radical_degree_raise
(cur_style
), 100)) -
1902 depth
(y
) - shift_amount
(y
));
1905 reset_attributes
(x
, node_attr
(degree
(q
)));
1909 /* for \.
{\\Uroot ..
{<list
>}{}} : */
1910 math_list
(degree
(q
)) = null
;
1911 flush_node
(degree
(q
));
1913 p
= hpack
(y
, 0, additional
, -1);
1914 reset_attributes
(p
, node_attr
(q
));
1915 math_list
(nucleus
(q
)) = p
;
1916 type
(nucleus
(q
)) = sub_box_node
;
1919 @ Construct a vlist box
1922 static pointer wrapup_over_under_delimiter
(pointer x
, pointer y
, pointer q
, scaled shift_up
, scaled shift_down
)
1924 pointer p
; /* temporary register for box construction
*/
1925 pointer v
= new_null_box
();
1926 type
(v
) = vlist_node
;
1927 height
(v
) = shift_up
+ height
(x
);
1928 depth
(v
) = depth
(y
) + shift_down
;
1929 reset_attributes
(v
, node_attr
(q
));
1930 p
= new_kern
((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
1931 reset_attributes
(p
, node_attr
(q
));
1938 /* when exact use radicalwidth
(y is delimiter
) */
1942 #define fixup_widths
(q
,x
,y
) do
{ \
1943 if
(width
(y
) >= width
(x
)) { \
1944 if
(radicalwidth
(q
) != zero_glue
) { \
1945 shift_amount
(x
) += half
(width
(y
)-width
(x
)) ; \
1947 width
(x
) = width
(y
); \
1949 if
(radicalwidth
(q
) != zero_glue
) { \
1950 shift_amount
(y
) += half
(width
(x
)-width
(y
)) ; \
1952 width
(y
) = width
(x
); \
1957 #define check_radical
(q
,stack
,r
,t
) do
{ \
1958 if
(!stack
&& (width(r) >= width(t)) && (radicalwidth(q) != zero_glue) && (radicalwidth(q) != width(r))) { \
1959 if
(radicalleft
(q
)) { \
1960 halfword p
= new_kern
(radicalwidth
(q
)-width
(r
)); \
1961 reset_attributes
(p
, node_attr
(q
)); \
1962 couple_nodes
(p
,r
); \
1963 r
= hpack
(p
, 0, additional
, -1); \
1964 width
(r
) = radicalwidth
(q
); \
1965 reset_attributes
(r
, node_attr
(q
)); \
1966 } else if
(radicalmiddle
(q
)) { \
1967 halfword p
= new_kern
(half
(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
(radicalright
(q
)) { \
1974 /* also kind of exact compared to vertical
*/ \
1975 r
= hpack
(r
, 0, additional
, -1); \
1976 width
(r
) = radicalwidth
(q
); \
1977 reset_attributes
(r
, node_attr
(q
)); \
1982 #define check_widths
(q
,p
) do
{ \
1983 if
(radicalwidth
(q
) != zero_glue
) { \
1984 wd
= radicalwidth
(q
); \
1990 @ this has the |nucleus| box |x| as a limit above an extensible delimiter |y|
1993 static void make_over_delimiter
(pointer q
, int cur_style
)
1995 pointer x
, y
, v
; /* temporary registers for box construction
*/
1996 scaled shift_up
, shift_down
, clr
, delta
, wd
;
1998 x
= clean_box
(nucleus
(q
), sub_style
(cur_style
), cur_style
);
2000 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, wd
, true
, cur_style
, true
, &stack, NULL);
2001 left_delimiter
(q
) = null
;
2002 check_radical
(q
,stack
,y
,x
);
2003 fixup_widths
(q
, x
, y
);
2004 shift_up
= over_delimiter_bgap
(cur_style
);
2006 clr
= over_delimiter_vgap
(cur_style
);
2007 delta
= clr
- ((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
2009 shift_up
= shift_up
+ delta
;
2011 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2012 width
(v
) = width
(x
); /* this also equals |width
(y
)|
*/
2013 math_list
(nucleus
(q
)) = v
;
2014 type
(nucleus
(q
)) = sub_box_node
;
2017 @ this has the extensible delimiter |x| as a limit below |nucleus| box |y|
2020 static void make_under_delimiter
(pointer q
, int cur_style
)
2022 pointer x
, y
, v
; /* temporary registers for box construction
*/
2023 scaled shift_up
, shift_down
, clr
, delta
, wd
;
2025 y
= clean_box
(nucleus
(q
), sup_style
(cur_style
), cur_style
);
2027 x
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, wd
, true
, cur_style
, true
, &stack, NULL);
2028 left_delimiter
(q
) = null
;
2029 check_radical
(q
,stack
,x
,y
);
2030 fixup_widths
(q
, x
, y
);
2032 shift_down
= under_delimiter_bgap
(cur_style
);
2033 clr
= under_delimiter_vgap
(cur_style
);
2034 delta
= clr
- ((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
2036 shift_down
= shift_down
+ delta
;
2038 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2039 width
(v
) = width
(y
); /* this also equals |width
(y
)|
*/
2040 math_list
(nucleus
(q
)) = v
;
2041 type
(nucleus
(q
)) = sub_box_node
;
2044 @ this has the extensible delimiter |x| as a limit above |nucleus| box |y|
2047 static void make_delimiter_over
(pointer q
, int cur_style
)
2049 pointer x
, y
, v
; /* temporary registers for box construction
*/
2050 scaled shift_up
, shift_down
, clr
, actual
, wd
;
2052 y
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2054 x
= do_delimiter
(q
, left_delimiter
(q
), cur_size
+ (cur_size
== script_script_size ?
0 : 1), wd
, true
, cur_style
, true
, &stack, NULL);
2055 left_delimiter
(q
) = null
;
2056 check_radical
(q
,stack
,x
,y
);
2057 fixup_widths
(q
, x
, y
);
2058 shift_up
= over_delimiter_bgap
(cur_style
)-height
(x
)-depth
(x
);
2060 clr
= over_delimiter_vgap
(cur_style
);
2061 actual
= shift_up
- height
(y
);
2063 shift_up
= shift_up
+ (clr-actual
);
2065 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2066 width
(v
) = width
(x
); /* this also equals |width
(y
)|
*/
2067 math_list
(nucleus
(q
)) = v
;
2068 type
(nucleus
(q
)) = sub_box_node
;
2071 @ this has the extensible delimiter |y| as a limit below a |nucleus| box |x|
2074 static void make_delimiter_under
(pointer q
, int cur_style
)
2076 pointer x
, y
, v
; /* temporary registers for box construction
*/
2077 scaled shift_up
, shift_down
, clr
, actual
, wd
;
2079 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2081 y
= do_delimiter
(q
, left_delimiter
(q
), cur_size
+ (cur_size
== script_script_size ?
0 : 1), wd
, true
, cur_style
, true
, &stack, NULL);
2082 left_delimiter
(q
) = null
;
2083 check_radical
(q
,stack
,y
,x
);
2084 fixup_widths
(q
, x
, y
);
2086 shift_down
= under_delimiter_bgap
(cur_style
) - height
(y
)-depth
(y
);
2087 clr
= under_delimiter_vgap
(cur_style
);
2088 actual
= shift_down
- depth
(x
);
2090 shift_down
+= (clr-actual
);
2092 v
= wrapup_over_under_delimiter
(x
, y
, q
, shift_up
, shift_down
);
2093 width
(v
) = width
(y
); /* this also equals |width
(y
)|
*/
2094 math_list
(nucleus
(q
)) = v
;
2095 type
(nucleus
(q
)) = sub_box_node
;
2098 @ Slants are not considered when placing accents in math mode. The accenter is
2099 centered over the accentee
, and the accent width is treated as zero with
2100 respect to the size of the final box.
2105 #define OVERLAY_CODE
4
2106 #define STRETCH_ACCENT_CODE
8
2108 static boolean compute_accent_skew
(pointer q
, int flags
, scaled
*s
)
2110 pointer p
; /* temporary register for box construction
*/
2111 boolean s_is_absolute
= false
; /* will be true if a top-accent is placed in |s|
*/
2112 if
(type
(nucleus
(q
)) == math_char_node
) {
2114 if
(is_new_mathfont
(cur_f
)) {
2116 there is no bot_accent so let's assume similarity
2118 if
(flags
& (TOP_CODE | OVERLAY_CODE)) {
2119 *s
= char_top_accent
(cur_f
, cur_c
);
2120 if
(*s
!= INT_MIN
) {
2121 s_is_absolute
= true
;
2124 *s
= char_bot_accent
(cur_f
, cur_c
);
2125 if
(*s
!= INT_MIN
) {
2126 s_is_absolute
= true
;
2130 *s
= char_top_accent
(cur_f
, cur_c
);
2131 if
(*s
!= INT_MIN
) {
2132 s_is_absolute
= true
;
2135 if
(flags
& TOP_CODE) {
2136 *s
= get_kern
(cur_f
, cur_c
, skew_char
(cur_f
));
2141 } else if
(type
(nucleus
(q
)) == sub_mlist_node
) {
2143 if |nucleus
(q
)| is a |sub_mlist_node| composed of an |accent_noad| we
2145 * use the positioning of the nucleus of that noad
, recursing until
2146 * the inner most |accent_noad|. This way multiple stacked accents are
2147 * aligned to the inner most one.
2149 p
= math_list
(nucleus
(q
));
2150 if
(type
(p
) == accent_noad
) {
2151 s_is_absolute
= compute_accent_skew
(p
, flags
, s
);
2155 return s_is_absolute
;
2158 static void do_make_math_accent
(pointer q
, internal_font_number f
, int c
, int flags
, int cur_style
)
2160 pointer p
, r
, x
, y
; /* temporary registers for box construction
*/
2161 scaled s
; /* amount to skew the accent to the right
*/
2162 scaled h
; /* height of character being accented
*/
2163 scaled delta
; /* space to remove between accent and accentee
*/
2164 scaled w
; /* width of the accentee
, not including sub
/superscripts
*/
2165 boolean s_is_absolute
; /* will be true if a top-accent is placed in |s|
*/
2170 attr_p
= (flags
& TOP_CODE ? top_accent_chr(q) : flags & BOT_CODE ? bot_accent_chr(q) : overlay_accent_chr(q));
2171 fraction
= accentfraction
(q
);
2175 if
(fraction
== 0) {
2178 /* Compute the amount of skew
, or set |s| to an alignment point
*/
2179 s_is_absolute
= compute_accent_skew
(q
, flags
, &s);
2180 x
= clean_box
(nucleus
(q
), cramped_style
(cur_style
), cur_style
);
2183 if
(is_new_mathfont
(cur_f
) && !s_is_absolute) {
2185 s_is_absolute
= true
;
2187 /* Switch to a larger accent if available and appropriate
*/
2190 if
(flags
& OVERLAY_CODE) {
2192 target
= xn_over_d
(h
,fraction
,1000);
2198 target
= xn_over_d
(w
,fraction
,1000);
2203 if
((flags
& STRETCH_ACCENT_CODE) && (char_width(f, c) < w)) {
2205 if
((char_tag
(f
, c
) == ext_tag
) && ((ext = get_charinfo_hor_variants(char_info(f, c))) != NULL)) {
2206 /* a bit weird for an overlay but anyway
, here we don't need a factor as we don't step
*/
2207 y
= get_delim_box
(q
, ext
, f
, w
, node_attr
(attr_p
), cur_style
, hlist_node
);
2209 } else if
(char_tag
(f
, c
) != list_tag
) {
2212 int yy
= char_remainder
(f
, c
);
2213 if
(!char_exists
(f
, yy
)) {
2215 } else if
(flags
& OVERLAY_CODE) {
2216 if
(char_height
(f
, yy
) > target
) {
2220 if
(char_width
(f
, yy
) > target
)
2228 y
= char_box
(f
, c
, node_attr
(attr_p
)); /* italic gets added to width
*/
2230 if
(flags
& TOP_CODE) {
2231 if
(h
< accent_base_height
(f
)) {
2234 delta
= accent_base_height
(f
);
2236 } else if
(flags
& OVERLAY_CODE) {
2237 delta
= half
(height
(y
) + depth
(y
) + height
(x
) + depth
(x
)); /* center the accent vertically around the accentee
*/
2241 if
((supscr
(q
) != null
) ||
(subscr
(q
) != null
)) {
2242 if
(type
(nucleus
(q
)) == math_char_node
) {
2243 /* swap the subscript and superscript into box |x|
*/
2246 r
= math_clone
(nucleus
(q
));
2248 supscr
(x
) = supscr
(q
);
2250 subscr
(x
) = subscr
(q
);
2252 type
(nucleus
(q
)) = sub_mlist_node
;
2253 math_list
(nucleus
(q
)) = x
;
2254 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2255 delta
= delta
+ height
(x
) - h
;
2259 /* the top accents of both characters are aligned
*/
2260 if
(s_is_absolute
) {
2263 /* if the accent is extensible just take the center
*/
2264 sa
= half
(width
(y
));
2267 there is no bot_accent so let's assume similarity
2269 if
(flags
& BOT_CODE) {
2270 sa
= char_bot_accent
(f
, c
);
2272 sa
= char_top_accent
(f
, c
);
2275 sa
= char_top_accent
(f
, c
);
2277 if
(sa
== INT_MIN
) {
2278 /* just take the center
*/
2279 sa
= half
(width
(y
));
2281 if
(math_direction
== dir_TRT
) {
2282 shift_amount
(y
) = s
+ sa
- width
(y
);
2284 shift_amount
(y
) = s
- sa
;
2288 shift_amount
(y
) = s
+ w
;
2289 } else if
(math_direction
== dir_TRT
) {
2290 shift_amount
(y
) = s
+ width
(y
); /* ok?
*/
2292 shift_amount
(y
) = s
+ half
(w
- width
(y
));
2296 if
(flags
& (TOP_CODE | OVERLAY_CODE)) {
2297 p
= new_kern
(-delta
);
2298 reset_attributes
(p
, node_attr
(q
));
2305 r
= vpackage
(y
, 0, additional
, max_dimen
, math_direction
);
2306 reset_attributes
(r
, node_attr
(q
));
2307 width
(r
) = width
(x
);
2309 if
(flags
& (TOP_CODE | OVERLAY_CODE)) {
2310 if
(height
(y
) < h
) {
2311 /* make the height of box |y| equal to |h|
*/
2312 p
= new_kern
(h
- height
(y
));
2313 reset_attributes
(p
, node_attr
(q
));
2314 try_couple_nodes
(p
,list_ptr
(y
));
2319 shift_amount
(y
) = -(h
- height
(y
));
2321 math_list
(nucleus
(q
)) = y
;
2322 type
(nucleus
(q
)) = sub_box_node
;
2325 static void make_math_accent
(pointer q
, int cur_style
)
2327 int topstretch
= !(subtype
(q
) % 2);
2328 int botstretch
= !(subtype
(q
) / 2);
2330 if
(top_accent_chr
(q
) != null
) {
2331 fetch
(top_accent_chr
(q
));
2332 if
(char_exists
(cur_f
, cur_c
)) {
2333 do_make_math_accent
(q
, cur_f
, cur_c
, TOP_CODE |
(topstretch ? STRETCH_ACCENT_CODE
: 0), cur_style
);
2335 flush_node
(top_accent_chr
(q
));
2336 top_accent_chr
(q
) = null
;
2338 if
(bot_accent_chr
(q
) != null
) {
2339 fetch
(bot_accent_chr
(q
));
2340 if
(char_exists
(cur_f
, cur_c
)) {
2341 do_make_math_accent
(q
, cur_f
, cur_c
, BOT_CODE |
(botstretch ? STRETCH_ACCENT_CODE
: 0), cur_style
);
2343 flush_node
(bot_accent_chr
(q
));
2344 bot_accent_chr
(q
) = null
;
2346 if
(overlay_accent_chr
(q
) != null
) {
2347 fetch
(overlay_accent_chr
(q
));
2348 if
(char_exists
(cur_f
, cur_c
)) {
2349 do_make_math_accent
(q
, cur_f
, cur_c
, OVERLAY_CODE | STRETCH_ACCENT_CODE
, cur_style
);
2351 flush_node
(overlay_accent_chr
(q
));
2352 overlay_accent_chr
(q
) = null
;
2356 @ The |make_fraction| procedure is a bit different because it sets
2357 |new_hlist
(q
)| directly rather than making a sub-box.
2360 static void make_fraction
(pointer q
, int cur_style
)
2362 pointer p
, p1
, p2
, v
, x
, y
, z
, l
, r
, m
; /* temporary registers for box construction
*/
2363 scaled delta
, delta1
, delta2
, shift_up
, shift_down
, clr1
, clr2
;
2364 /* dimensions for box calculations
*/
2365 if
(thickness
(q
) == default_code
)
2366 thickness
(q
) = fraction_rule
(cur_style
);
2368 Create equal-width boxes |x| and |z| for the numerator and denominator
,
2369 and compute the default amounts |shift_up| and |shift_down| by which they
2370 are displaced from the baseline
2373 x
= clean_box
(numerator
(q
), num_style
(cur_style
), cur_style
);
2374 z
= clean_box
(denominator
(q
), denom_style
(cur_style
), cur_style
);
2376 if
(middle_delimiter
(q
) != null
) {
2378 m
= do_delimiter
(q
, middle_delimiter
(q
), cur_size
, delta
, false
, cur_style
, true
, NULL, NULL);
2379 middle_delimiter
(q
) = null
;
2382 if
(width
(x
) < width
(z
)) {
2383 x
= rebox
(x
, width
(z
));
2385 z
= rebox
(z
, width
(x
));
2392 } else if
(thickness
(q
) == 0) {
2393 shift_up
= stack_num_up
(cur_style
);
2394 shift_down
= stack_denom_down
(cur_style
);
2396 the numerator and denominator must be separated by a certain minimum
2397 clearance
, called |clr| in the following program. The difference between
2398 |clr| and the actual clearance is |
2delta|.
2400 clr1
= stack_vgap
(cur_style
);
2401 delta
= half
(clr1
- ((shift_up
- depth
(x
)) - (height
(z
) - shift_down
)));
2403 shift_up
= shift_up
+ delta
;
2404 shift_down
= shift_down
+ delta
;
2407 shift_up
= fraction_num_up
(cur_style
);
2408 shift_down
= fraction_denom_down
(cur_style
);
2410 in the case of a fraction line
, the minimum clearance depends on the actual
2411 thickness of the line.
2413 clr1
= fraction_num_vgap
(cur_style
);
2414 clr2
= fraction_denom_vgap
(cur_style
);
2415 delta
= half
(thickness
(q
));
2416 if
(fractionexact
(q
)) {
2417 delta1
= clr1
- ((shift_up
- depth
(x
) ) - (math_axis
(cur_size
) + delta
));
2418 delta2
= clr2
- ((shift_down
- height
(z
)) + (math_axis
(cur_size
) - delta
));
2420 delta
= half
(thickness
(q
));
2421 clr1
= ext_xn_over_d
(clr1
, thickness
(q
), fraction_rule
(cur_style
));
2422 clr2
= ext_xn_over_d
(clr2
, thickness
(q
), fraction_rule
(cur_style
));
2423 delta1
= clr1
- ((shift_up
- depth
(x
) ) - (math_axis
(cur_size
) + delta
));
2424 delta2
= clr2
- ((shift_down
- height
(z
)) + (math_axis
(cur_size
) - delta
));
2427 shift_up
= shift_up
+ delta1
;
2430 shift_down
= shift_down
+ delta2
;
2435 construct a hlist box for the fraction
, according to |hgap| and |vgap|
2437 shift_up
= skewed_fraction_vgap
(cur_style
);
2439 if
(!fractionnoaxis
(q
)) {
2440 shift_up
+= half
(math_axis
(cur_size
));
2443 shift_down
= shift_up
;
2445 reset_attributes
(v
, node_attr
(q
));
2446 type
(v
) = hlist_node
;
2448 width
(v
) = width
(x
);
2449 height
(v
) = height
(x
) + shift_up
;
2450 depth
(v
) = depth
(x
);
2451 shift_amount
(v
) = - shift_up
;
2455 reset_attributes
(v
, node_attr
(q
));
2456 type
(v
) = hlist_node
;
2458 width
(v
) = width
(z
);
2459 height
(v
) = height
(z
);
2460 depth
(v
) = depth
(z
) + shift_down
;
2461 shift_amount
(v
) = shift_down
;
2465 reset_attributes
(v
, node_attr
(q
));
2466 type
(v
) = hlist_node
;
2467 if
(height
(x
) > height
(z
)) {
2468 height
(v
) = height
(x
);
2470 height
(v
) = height
(z
);
2472 if
(depth
(x
) > depth
(z
)) {
2473 depth
(v
) = depth
(x
);
2475 depth
(v
) = depth
(z
);
2477 if
(height
(m
) > height
(v
)) {
2478 height
(v
) = height
(m
);
2480 if
(depth
(m
) > depth
(v
)) {
2481 depth
(v
) = depth
(m
);
2484 if
(fractionexact
(q
)) {
2485 delta1
= -half
(skewed_fraction_hgap
(cur_style
));
2487 width
(v
) = width
(x
) + width
(z
) + width
(m
) - skewed_fraction_hgap
(cur_style
);
2489 delta1
= half
(skewed_fraction_hgap
(cur_style
)-width
(m
));
2490 delta2
= half
(skewed_fraction_hgap
(cur_style
)+width
(m
));
2491 width
(v
) = width
(x
) + width
(z
) + skewed_fraction_hgap
(cur_style
);
2495 p1
= new_kern
(delta1
);
2496 reset_attributes
(p1
, node_attr
(q
));
2497 p2
= new_kern
(delta2
);
2498 reset_attributes
(p2
, node_attr
(q
));
2508 construct a vlist box for the fraction
, according to |shift_up| and |shift_down|
2511 type
(v
) = vlist_node
;
2512 height
(v
) = shift_up
+ height
(x
);
2513 depth
(v
) = depth
(z
) + shift_down
;
2514 width
(v
) = width
(x
); /* this also equals |width
(z
)|
*/
2515 reset_attributes
(v
, node_attr
(q
));
2516 if
(thickness
(q
) == 0) {
2517 p
= new_kern
((shift_up
- depth
(x
)) - (height
(z
) - shift_down
));
2520 y
= do_fraction_rule
(thickness
(q
), node_attr
(q
));
2521 p
= new_kern
((math_axis
(cur_size
) - delta
) - (height
(z
) - shift_down
));
2522 reset_attributes
(p
, node_attr
(q
));
2525 p
= new_kern
((shift_up
- depth
(x
)) - (math_axis
(cur_size
) + delta
));
2528 reset_attributes
(p
, node_attr
(q
));
2533 put the fraction into a box with its delimiters
, and make |new_hlist
(q
)|
2536 if
(is_new_mathfont
(cur_f
)) {
2537 if
(math_use_old_fraction_scaling
) {
2538 delta
= fraction_del_size_old
(cur_style
);
2540 delta
= fraction_del_size_new
(cur_style
);
2542 if
(delta
== undefined_math_parameter
) {
2543 delta
= get_delimiter_height
(depth
(v
), height
(v
), true
);
2546 delta
= fraction_del_size_old
(cur_style
);
2549 l
= do_delimiter
(q
, left_delimiter
(q
), cur_size
, delta
, false
, cur_style
, true
, NULL, NULL);
2550 left_delimiter
(q
) = null
;
2551 r
= do_delimiter
(q
, right_delimiter
(q
), cur_size
, delta
, false
, cur_style
, true
, NULL, NULL);
2552 right_delimiter
(q
) = null
;
2555 y
= hpack
(l
, 0, additional
, -1);
2556 reset_attributes
(y
, node_attr
(q
));
2557 assign_new_hlist
(q
, y
);
2560 @ If the nucleus of an |op_noad| is a single character
, it is to be
2561 centered vertically with respect to the axis
, after first being enlarged
2562 (via a character list in the font
) if we are in display style. The normal
2563 convention for placing displayed limits is to put them above and below the
2564 operator in display style.
2566 The italic correction is removed from the character if there is a subscript
2567 and the limits are not being displayed. The |make_op| routine returns the
2568 value that should be used as an offset between subscript and superscript.
2570 After |make_op| has acted
, |subtype
(q
)| will be |limits| if and only if
2571 the limits have been set above and below the operator. In that case
,
2572 |new_hlist
(q
)| will already contain the desired final box.
2575 static void make_scripts
(pointer q
, pointer p
, scaled it
, int cur_style
, scaled supshift
, scaled subshift
);
2576 static pointer check_nucleus_complexity
(halfword q
, scaled
* delta
, int cur_style
);
2578 static scaled make_op
(pointer q
, int cur_style
)
2580 scaled delta
= 0; /* offset between subscript and superscript
*/
2582 pointer p
, v
, x
, y
, z
, n
; /* temporary registers for box construction
*/
2583 int c
; /* register for character examination
*/
2584 scaled shift_up
, shift_down
; /* dimensions for box calculation
*/
2585 boolean axis_shift
= false
;
2587 if
((subtype
(q
) == op_noad_type_normal
) && (cur_style < text_style)) {
2588 subtype
(q
) = op_noad_type_limits
;
2590 if
(type
(nucleus
(q
)) == math_char_node
) {
2592 if
(cur_style
< text_style
) {
2593 /* try to make it larger
*/
2594 ok_size
= minimum_operator_size
(cur_style
);
2595 if
(ok_size
!= undefined_math_parameter
) {
2596 /* creating a temporary delimiter is the cleanest way
*/
2597 y
= new_node
(delim_node
, 0);
2598 reset_attributes
(y
, node_attr
(q
));
2599 small_fam
(y
) = math_fam
(nucleus
(q
));
2600 small_char
(y
) = math_character
(nucleus
(q
));
2601 x
= do_delimiter
(q
, y
, text_size
, ok_size
, false
, cur_style
, true
, NULL, &delta);
2602 if
(is_new_mathfont
(cur_f
)) {
2603 /* we never added italic correction
*/
2604 } else if
((subscr
(q
) != null
) && (subtype(q) != op_noad_type_limits)) {
2605 /* remove italic correction
*/
2609 ok_size
= height_plus_depth
(cur_f
, cur_c
) + 1;
2610 while
((char_tag
(cur_f
, cur_c
) == list_tag
) && height_plus_depth(cur_f, cur_c) < ok_size) {
2611 c
= char_remainder
(cur_f
, cur_c
);
2612 if
(!char_exists
(cur_f
, c
))
2615 math_character
(nucleus
(q
)) = c
;
2617 delta
= char_italic
(cur_f
, cur_c
);
2618 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2619 if
(delta
!= null
) {
2620 if
(is_new_mathfont
(cur_f
)) {
2621 /* we never added italic correction
*/
2622 } else if
((subscr
(q
) != null
) && (subtype(q) != op_noad_type_limits)) {
2623 /* remove italic correction
*/
2624 width
(x
) = width
(x
) - delta
;
2631 delta
= char_italic
(cur_f
, cur_c
);
2632 x
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2634 if
(is_new_mathfont
(cur_f
)) {
2635 /* we never added italic correction
*/
2636 } else if
((subscr
(q
) != null
) && (subtype(q) != op_noad_type_limits)) {
2637 /* remove italic correction
*/
2638 width
(x
) = width
(x
) - delta
;
2644 /* center vertically
*/
2645 shift_amount
(x
) = half
(height
(x
) - depth
(x
)) - math_axis
(cur_size
);
2647 type
(nucleus
(q
)) = sub_box_node
;
2648 math_list
(nucleus
(q
)) = x
;
2651 /* we now handle op_nod_type_no_limits here too
*/
2653 if
(subtype
(q
) == op_noad_type_no_limits
) {
2654 if
(is_new_mathfont
(cur_f
)) {
2656 delta
= half
(delta
) ;
2658 p
= check_nucleus_complexity
(q
, &dummy, cur_style);
2659 if
((subscr
(q
) == null
) && (supscr(q) == null)) {
2660 assign_new_hlist
(q
, p
);
2662 make_scripts
(q
, p
, 0, cur_style
, delta
, -delta
);
2666 /* similar code then the caller
(before CHECK_DIMENSIONS
) */
2667 p
= check_nucleus_complexity
(q
, &delta, cur_style);
2668 if
((subscr
(q
) == null
) && (supscr(q) == null)) {
2669 assign_new_hlist
(q
, p
);
2671 make_scripts
(q
, p
, delta
, cur_style
, 0, 0);
2674 } else if
(subtype
(q
) == op_noad_type_limits
) {
2675 /* The following program builds a vlist box |v| for displayed limits. The
2676 width of the box is not affected by the fact that the limits may be skewed.
*/
2677 x
= clean_box
(supscr
(q
), sup_style
(cur_style
), cur_style
);
2678 y
= clean_box
(nucleus
(q
), cur_style
, cur_style
);
2679 z
= clean_box
(subscr
(q
), sub_style
(cur_style
), cur_style
);
2681 reset_attributes
(v
, node_attr
(q
));
2682 type
(v
) = vlist_node
;
2683 if
(is_new_mathfont
(cur_f
)) {
2685 if
(! math_no_italic_compensation
) {
2688 if
((type
(n
) == sub_mlist_node
) ||
(type
(n
) == sub_box_node
)) {
2691 if
(type
(n
) == hlist_node
) {
2692 n
= list_ptr
(n
); /* just a not scaled char
*/
2694 if
(type
(n
) == glyph_node
) {
2695 delta
= char_italic
(font
(n
),character
(n
));
2701 if
(type
(n
) == fence_noad
) {
2702 if
(delimiteritalic
(n
) > delta
) {
2703 /* we can have dummies
, the period ones
*/
2704 delta
= delimiteritalic
(n
);
2713 if
(type
(n
) == math_char_node
) {
2714 delta
= char_italic
(fam_fnt
(math_fam
(n
),cur_size
),math_character
(n
));
2720 width
(v
) = width
(y
);
2721 if
(width
(x
) > width
(v
))
2722 width
(v
) = width
(x
);
2723 if
(width
(z
) > width
(v
))
2724 width
(v
) = width
(z
);
2725 x
= rebox
(x
, width
(v
));
2726 y
= rebox
(y
, width
(v
));
2727 z
= rebox
(z
, width
(v
));
2728 shift_amount
(x
) = half
(delta
);
2729 shift_amount
(z
) = -shift_amount
(x
);
2730 /* v is the still empty target
*/
2731 height
(v
) = height
(y
);
2732 depth
(v
) = depth
(y
);
2734 attach the limits to |y| and adjust |height
(v
)|
, |depth
(v
)| to
2735 account for their presence
2737 we use |shift_up| and |shift_down| in the following program for the
2738 amount of glue between the displayed operator |y| and its limits |x| and
2741 the vlist inside box |v| will consist of |x| followed by |y| followed
2742 by |z|
, with kern nodes for the spaces between and around them
2744 b
: baseline v
: minumum gap
2747 if
(supscr
(q
) == null
) {
2752 shift_up
= limit_above_bgap
(cur_style
) - depth
(x
);
2753 if
(shift_up
< limit_above_vgap
(cur_style
))
2754 shift_up
= limit_above_vgap
(cur_style
);
2755 p
= new_kern
(shift_up
);
2756 reset_attributes
(p
, node_attr
(q
));
2759 p
= new_kern
(limit_above_kern
(cur_style
));
2760 reset_attributes
(p
, node_attr
(q
));
2763 height
(v
) = height
(v
) + limit_above_kern
(cur_style
) + height
(x
) + depth
(x
) + shift_up
;
2765 if
(subscr
(q
) == null
) {
2769 shift_down
= limit_below_bgap
(cur_style
) - height
(z
);
2770 if
(shift_down
< limit_below_vgap
(cur_style
))
2771 shift_down
= limit_below_vgap
(cur_style
);
2772 if
(shift_down
> 0) {
2773 p
= new_kern
(shift_down
);
2774 reset_attributes
(p
, node_attr
(q
));
2778 p
= new_kern
(limit_below_kern
(cur_style
));
2779 reset_attributes
(p
, node_attr
(q
));
2781 depth
(v
) = depth
(v
) + limit_below_kern
(cur_style
) + height
(z
) + depth
(z
) + shift_down
;
2783 if
(subscr
(q
) != null
) {
2784 math_list
(subscr
(q
)) = null
;
2785 flush_node
(subscr
(q
));
2788 if
(supscr
(q
) != null
) {
2789 math_list
(supscr
(q
)) = null
;
2790 flush_node
(supscr
(q
));
2793 assign_new_hlist
(q
, v
);
2794 if
(is_new_mathfont
(cur_f
)) {
2801 @ A ligature found in a math formula does not create a ligature
, because
2802 there is no question of hyphenation afterwards
; the ligature will simply be
2803 stored in an ordinary |glyph_node|
, after residing in an |ord_noad|.
2805 The |type| is converted to |math_text_char| here if we would not want to
2806 apply an italic correction to the current character unless it belongs
2807 to a math font
(i.e.
, a font with |space
=0|
).
2809 No boundary characters enter into these ligatures.
2812 #define simple_char_noad
(p
) (\
2814 (type
(p
) == simple_noad
) && \
2815 (subtype
(p
) <= punct_noad_type
) && \
2816 (type
(nucleus
(p
)) == math_char_node
) \
2819 #define same_nucleus_fam
(p
,q
) \
2820 (math_fam
(nucleus
(p
)) == math_fam
(nucleus
(q
)))
2822 static void make_ord
(pointer q
)
2824 int a
; /* the left-side character for lig
/kern testing
*/
2825 pointer p
, r
, s
; /* temporary registers for list manipulation
*/
2826 scaled k
; /* a kern
*/
2827 liginfo lig
; /* a ligature
*/
2829 if
(subscr
(q
) == null
&& supscr(q) == null && type(nucleus(q)) == math_char_node) {
2831 if
(simple_char_noad
(p
) && same_nucleus_fam(p,q)) {
2832 type
(nucleus
(q
)) = math_text_char_node
;
2835 /* add italic correction
*/
2836 if
(is_new_mathfont
(cur_f
) && (char_italic(cur_f,math_character(nucleus(q))) != 0)) {
2837 p
= new_kern
(char_italic
(cur_f
,math_character
(nucleus
(q
))));
2838 reset_attributes
(p
, node_attr
(q
));
2839 couple_nodes
(p
,vlink
(q
));
2843 /* construct ligatures
, quite unlikely in new math fonts
*/
2844 if
((has_kern
(cur_f
, a
)) ||
(has_lig
(cur_f
, a
))) {
2845 cur_c
= math_character
(nucleus
(p
));
2847 if character |a| has a kern with |cur_c|
, attach the kern after~|q|
; or if
2848 it has a ligature with |cur_c|
, combine noads |q| and~|p| appropriately
;
2849 then |return| if the cursor has moved past a noad
, or |goto restart|
2851 note that a ligature between an |ord_noad| and another kind of noad
2852 is replaced by an |ord_noad|
, when the two noads collapse into one
2854 we could make a parenthesis
(say
) change shape when it follows
2855 certain letters. Presumably a font designer will define such
2856 ligatures only when this convention makes sense
2859 if
(disable_lig
== 0 && has_lig(cur_f, a)) {
2860 lig
= get_ligature
(cur_f
, a
, cur_c
);
2861 if
(is_valid_ligature
(lig
)) {
2862 check_interrupt
(); /* allow a way out of infinite ligature loop
*/
2863 switch
(lig_type
(lig
)) {
2865 /* \.
{=:\char`\|
} */
2867 /* \.
{=:\char`\|
>} */
2868 math_character
(nucleus
(q
)) = lig_replacement
(lig
);
2871 /* \.
{\char`\|
=:} */
2873 /* \.
{\char`\|
=:>} */
2874 math_character
(nucleus
(p
)) = lig_replacement
(lig
);
2877 /* \.
{\char`\|
=:\char`\|
} */
2879 /* \.
{\char`\|
=:\char`\|
>} */
2881 /* \.
{\char`\|
=:\char`\|
>>} */
2883 reset_attributes
(r
, node_attr
(q
));
2884 s
= new_node
(math_char_node
, 0);
2885 reset_attributes
(s
, node_attr
(q
));
2887 math_character
(nucleus
(r
)) = lig_replacement
(lig
);
2888 math_fam
(nucleus
(r
)) = math_fam
(nucleus
(q
));
2891 if
(lig_type
(lig
) < 11)
2892 type
(nucleus
(r
)) = math_char_node
;
2894 /* prevent combination
*/
2895 type
(nucleus
(r
)) = math_text_char_node
;
2898 try_couple_nodes
(q
,vlink
(p
));
2899 math_character
(nucleus
(q
)) = lig_replacement
(lig
); /* \.
{=:} */
2900 s
= math_clone
(subscr
(p
));
2902 s
= math_clone
(supscr
(p
));
2904 math_reset
(subscr
(p
)); /* just in case
*/
2905 math_reset
(supscr
(p
));
2909 if
(lig_type
(lig
) > 3)
2911 type
(nucleus
(q
)) = math_char_node
;
2915 if
(disable_kern
== 0 && has_kern(cur_f, a)) {
2916 /* todo
: should this use mathkerns?
*/
2917 k
= get_kern
(cur_f
, a
, cur_c
);
2920 reset_attributes
(p
, node_attr
(q
));
2921 couple_nodes
(p
,vlink
(q
));
2931 @ If the fonts for the left and right bits of a mathkern are not
2932 both new-style fonts
, then return a sentinel value meaning
:
2933 please use old-style italic correction placement
2936 #define MATH_KERN_NOT_FOUND
0x7FFFFFFF
2938 @ This function tries to find the kern needed for proper cut-ins.
2939 The left side doesn't move
, but the right side does
, so the first
2940 order of business is to create a staggered fence line on the
2941 left side of the right character.
2943 The microsoft spec says that there are four quadrants
, but the
2947 static scaled math_kern_at
(internal_font_number f
, int c
, int side
, int v
)
2950 scaled
*kerns_heights
;
2952 charinfo
*co
= char_info
(f
, c
); /* known to exist
*/
2953 numkerns
= get_charinfo_math_kerns
(co
, side
);
2955 fprintf
(stderr
, " entries = %d, height = %d\n", numkerns
, v
);
2959 if
(side
== top_left_kern
) {
2960 kerns_heights
= co-
>top_left_math_kern_array
;
2961 } else if
(side
== bottom_left_kern
) {
2962 kerns_heights
= co-
>bottom_left_math_kern_array
;
2963 } else if
(side
== top_right_kern
) {
2964 kerns_heights
= co-
>top_right_math_kern_array
;
2965 } else if
(side
== bottom_right_kern
) {
2966 kerns_heights
= co-
>bottom_right_math_kern_array
;
2968 confusion
("math_kern_at");
2969 kerns_heights
= NULL; /* not reached
*/
2972 fprintf
(stderr
, " entry 0: %d,%d\n", kerns_heights
[0], kerns_heights
[1]);
2974 if
(v
< kerns_heights
[0])
2975 return kerns_heights
[1];
2976 for
(k
= 0; k
< numkerns
; k
++) {
2977 h
= kerns_heights
[(k
* 2)];
2978 kern
= kerns_heights
[(k
* 2) + 1];
2981 fprintf
(stderr
, " entry %d: %d,%d\n", k
, h
, kern
);
2991 static scaled find_math_kern
(internal_font_number l_f
, int l_c
,
2992 internal_font_number r_f
, int r_c
,
2993 int cmd
, scaled shift
)
2995 scaled corr_height_top
= 0, corr_height_bot
= 0;
2996 scaled krn_l
= 0, krn_r
= 0, krn
= 0;
2997 if
((!is_new_mathfont
(l_f
)) ||
(!is_new_mathfont
(r_f
)) ||
(!char_exists
(l_f
, l_c
)) ||
(!char_exists
(r_f
, r_c
)))
2998 return MATH_KERN_NOT_FOUND
;
3000 if
(cmd
== sup_mark_cmd
) {
3001 corr_height_top
= char_height
(l_f
, l_c
);
3002 corr_height_bot
= -char_depth
(r_f
, r_c
) + shift
; /* bottom of superscript
*/
3003 krn_l
= math_kern_at
(l_f
, l_c
, top_right_kern
, corr_height_top
);
3004 krn_r
= math_kern_at
(r_f
, r_c
, bottom_left_kern
, corr_height_top
);
3006 fprintf
(stderr
, "SUPER Top LR = %d,%d (shift %d)\n", krn_l
, krn_r
, shift
);
3008 krn
= (krn_l
+ krn_r
);
3009 krn_l
= math_kern_at
(l_f
, l_c
, top_right_kern
, corr_height_bot
);
3010 krn_r
= math_kern_at
(r_f
, r_c
, bottom_left_kern
, corr_height_bot
);
3012 fprintf
(stderr
, "SUPER Bot LR = %d,%d\n", krn_l
, krn_r
);
3014 if
((krn_l
+ krn_r
) < krn
)
3015 krn
= (krn_l
+ krn_r
);
3018 } else if
(cmd
== sub_mark_cmd
) {
3019 corr_height_top
= char_height
(r_f
, r_c
) - shift
; /* top of subscript
*/
3020 corr_height_bot
= -char_depth
(l_f
, l_c
);
3021 krn_l
= math_kern_at
(l_f
, l_c
, bottom_right_kern
, corr_height_top
);
3022 krn_r
= math_kern_at
(r_f
, r_c
, top_left_kern
, corr_height_top
);
3024 fprintf
(stderr
, "SUB Top LR = %d,%d\n", krn_l
, krn_r
);
3026 krn
= (krn_l
+ krn_r
);
3027 krn_l
= math_kern_at
(l_f
, l_c
, bottom_right_kern
, corr_height_bot
);
3028 krn_r
= math_kern_at
(r_f
, r_c
, top_left_kern
, corr_height_bot
);
3030 fprintf
(stderr
, "SUB Bot LR = %d,%d\n", krn_l
, krn_r
);
3032 if
((krn_l
+ krn_r
) < krn
)
3033 krn
= (krn_l
+ krn_r
);
3037 confusion
("find_math_kern");
3039 return
0; /* not reached
*/
3042 @ just a small helper
3044 static pointer attach_hkern_to_new_hlist
(pointer q
, scaled delta2
)
3047 pointer z
= new_kern
(delta2
);
3048 reset_attributes
(z
, node_attr
(q
));
3049 if
(new_hlist
(q
) == null
) {
3050 /* this is somewhat weird
*/
3054 while
(vlink
(y
) != null
)
3058 return new_hlist
(q
);
3064 void dump_simple_field
(pointer q
)
3067 printf
(" [%d, type=%d, vlink=%d] ", q
, type
(q
), vlink
(q
));
3069 case math_char_node
:
3070 printf
("mathchar ");
3072 case math_text_char_node
:
3078 case sub_mlist_node
:
3082 dump_simple_field
(p
);
3089 void dump_simple_node
(pointer q
)
3091 printf
("node %d, type=%d, vlink=%d\n", q
, type
(q
), vlink
(q
));
3092 printf
("nucleus: ");
3093 dump_simple_field
(nucleus
(q
));
3096 dump_simple_field
(subscr
(q
));
3099 dump_simple_field
(supscr
(q
));
3104 @ The purpose of |make_scripts
(q
,it
)| is to attach the subscript and
/or
3105 superscript of noad |q| to the list that starts at |new_hlist
(q
)|
,
3106 given that subscript and superscript aren't both empty. The superscript
3107 will be horizontally shifted over |delta1|
, the subscript over |delta2|.
3109 We set |shift_down| and |shift_up| to the minimum amounts to shift the
3110 baseline of subscripts and superscripts based on the given nucleus.
3112 Note
: We need to look at a character but also at the first one in a sub list
3113 and there we ignore leading kerns and glue. Elsewhere is code that removes
3114 kerns assuming that is italic correction. The heuristics are unreliable for
3115 the new fonts so eventualy there will be an option to ignore such corrections.
3118 #define analyze_script
(init
,su_n
,su_f
,su_c
) do
{ \
3120 if
(su_n
!= null
) { \
3121 if
(type
(su_n
) == sub_mlist_node
&& math_list(su_n)) { \
3122 su_n
= math_list
(su_n
); \
3123 if
(su_n
!= null
) { \
3125 if
((type
(su_n
) == kern_node
) ||
(type
(su_n
) == glue_node
)) {\
3126 su_n
= vlink
(su_n
); \
3127 } else if
(type
(su_n
) == simple_noad
) { \
3128 su_n
= nucleus
(su_n
); \
3129 if
(type
(su_n
) != math_char_node
) { \
3140 if
((su_n
!= null
) && (type(su_n) == math_char_node)) { \
3142 if
(char_exists
(cur_f
, cur_c
)) { \
3152 static void make_scripts
(pointer q
, pointer p
, scaled it
, int cur_style
, scaled supshift
, scaled subshift
)
3154 pointer x
, y
, z
; /* temporary registers for box construction
*/
3155 scaled shift_up
, shift_down
, clr
; /* dimensions in the calculation
*/
3156 scaled delta1
, delta2
;
3157 halfword sub_n
, sup_n
;
3158 internal_font_number sub_f
, sup_f
;
3170 printf
("it: %d\n", it
);
3171 dump_simple_node
(q
);
3172 printf
("p: node %d, type=%d, subtype=%d\n", p
, type
(p
), subtype
(p
));
3174 switch
(type
(nucleus
(q
))) {
3175 case math_char_node
:
3176 case math_text_char_node
:
3177 if
((subscr
(q
) == null
) && (delta1 != 0)) {
3178 /* todo
: selective
*/
3179 x
= new_kern
(delta1
); /* italic correction
*/
3180 reset_attributes
(x
, node_attr
(nucleus
(q
)));
3185 assign_new_hlist
(q
, p
);
3186 if
(is_char_node
(p
)) {
3190 z
= hpack
(p
, 0, additional
, -1);
3191 shift_up
= height
(z
) - sup_shift_drop
(cur_style
); /* r18
*/
3192 shift_down
= depth
(z
) + sub_shift_drop
(cur_style
); /* r19
*/
3197 if
(is_char_node
(p
)) {
3198 /* we look at the subscript character
(_i
) or first character in a list
(_
{ij
}) */
3199 analyze_script
(subscr
(q
),sub_n
,sub_f
,sub_c
);
3200 /* we look at the superscript character
(^i
) or first character in a list
(^
{ij
}) */
3201 analyze_script
(supscr
(q
),sup_n
,sup_f
,sup_c
);
3204 if
(supscr
(q
) == null
) {
3206 construct a subscript box |x| when there is no superscript
3208 when there is a subscript without a superscript
, the top of the subscript
3209 should not exceed the baseline plus four-fifths of the x-height.
3211 x
= clean_box
(subscr
(q
), sub_style
(cur_style
), cur_style
);
3212 width
(x
) = width
(x
) + space_after_script
(cur_style
);
3213 switch
(scripts_mode
) {
3215 shift_down
= sub_shift_down
(cur_style
) ;
3218 shift_down
= sub_sup_shift_down
(cur_style
) ;
3221 shift_down
= sub_sup_shift_down
(cur_style
) ;
3224 shift_down
= sub_shift_down
(cur_style
) + half
(sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
)) ;
3227 shift_down
= sub_shift_down
(cur_style
) ;
3230 if
(shift_down
< sub_shift_down
(cur_style
))
3231 shift_down
= sub_shift_down
(cur_style
);
3232 clr
= height
(x
) - sub_top_max
(cur_style
);
3233 if
(shift_down
< clr
)
3237 shift_amount
(x
) = shift_down
;
3239 /* now find and correct for horizontal shift
*/
3240 if
(sub_n
!= null
) {
3241 delta2
= find_math_kern
(font
(p
), character
(p
),sub_f
,sub_c
,sub_mark_cmd
, shift_down
);
3242 if
(delta2
== MATH_KERN_NOT_FOUND
) {
3245 delta2
= delta2
+ subshift
;
3251 p
= attach_hkern_to_new_hlist
(q
, delta2
);
3256 construct a superscript box |x|
3258 the bottom of a superscript should never descend below the baseline plus
3259 one-fourth of the x-height.
3261 x
= clean_box
(supscr
(q
), sup_style
(cur_style
), cur_style
);
3262 width
(x
) = width
(x
) + space_after_script
(cur_style
);
3263 switch
(scripts_mode
) {
3265 shift_up
= sup_shift_up
(cur_style
);
3268 shift_up
= sup_shift_up
(cur_style
) ;
3271 shift_up
= sup_shift_up
(cur_style
) + sub_sup_shift_down
(cur_style
) - sub_shift_down
(cur_style
) ;
3274 shift_up
= sup_shift_up
(cur_style
) + half
(sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
)) ;
3277 shift_up
= sup_shift_up
(cur_style
) + sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
) ;
3280 clr
= sup_shift_up
(cur_style
);
3283 clr
= depth
(x
) + sup_bottom_min
(cur_style
);
3288 if
(subscr
(q
) == null
) {
3289 shift_amount
(x
) = -shift_up
;
3290 /* now find and correct for horizontal shift
*/
3291 if
(sup_n
!= null
) {
3292 clr
= find_math_kern
(font
(p
),character
(p
),sup_f
,sup_c
,sup_mark_cmd
,shift_up
);
3293 if
(clr
== MATH_KERN_NOT_FOUND
) {
3296 clr
= clr
+ supshift
;
3302 p
= attach_hkern_to_new_hlist
(q
, clr
);
3306 construct a sub
/superscript combination box |x|
, with the superscript offset
3309 when both subscript and superscript are present
, the subscript must be
3310 separated from the superscript by at least four times |default_rule_thickness|
3312 if this condition would be violated
, the subscript moves down
, after which
3313 both subscript and superscript move up so that the bottom of the superscript
3314 is at least as high as the baseline plus four-fifths of the x-height
3316 y
= clean_box
(subscr
(q
), sub_style
(cur_style
), cur_style
);
3317 width
(y
) = width
(y
) + space_after_script
(cur_style
);
3318 switch
(scripts_mode
) {
3320 shift_down
= sub_shift_down
(cur_style
) ;
3323 shift_down
= sub_sup_shift_down
(cur_style
) ;
3326 shift_down
= sub_sup_shift_down
(cur_style
) ;
3329 shift_down
= sub_shift_down
(cur_style
) + half
(sub_sup_shift_down
(cur_style
)-sub_shift_down
(cur_style
)) ;
3332 shift_down
= sub_shift_down
(cur_style
) ;
3335 if
(shift_down
< sub_sup_shift_down
(cur_style
))
3336 shift_down
= sub_sup_shift_down
(cur_style
);
3337 clr
= subsup_vgap
(cur_style
) - ((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
3339 shift_down
= shift_down
+ clr
;
3340 clr
= sup_sub_bottom_max
(cur_style
) - (shift_up
- depth
(x
));
3342 shift_up
= shift_up
+ clr
;
3343 shift_down
= shift_down
- clr
;
3348 /* now find and correct for horizontal shift
*/
3349 if
(sub_n
!= null
) {
3350 delta2
= find_math_kern
(font
(p
), character
(p
),sub_f
,sub_c
,sub_mark_cmd
, shift_down
);
3351 if
(delta2
== MATH_KERN_NOT_FOUND
) {
3354 delta2
= delta2
+ subshift
;
3360 p
= attach_hkern_to_new_hlist
(q
, delta2
);
3363 now the horizontal shift for the superscript
; the superscript is also to be shifted
3364 by |delta1|
(the italic correction
)
3366 clr
= MATH_KERN_NOT_FOUND
;
3367 if
(sup_n
!= null
) {
3368 clr
= find_math_kern
(font
(p
),character
(p
),sup_f
,sup_c
,sup_mark_cmd
,shift_up
);
3371 /* delta can already have been applied and now be
0 */
3372 if
(delta2
== MATH_KERN_NOT_FOUND
)
3373 delta2
= - supshift
;
3375 delta2
= delta2
- supshift
;
3376 if
(clr
!= MATH_KERN_NOT_FOUND
) {
3377 shift_amount
(x
) = clr
+ delta1
- delta2
;
3379 shift_amount
(x
) = delta1
- delta2
;
3381 /* todo
: only if kern
!= 0 */
3382 p
= new_kern
((shift_up
- depth
(x
)) - (height
(y
) - shift_down
));
3383 reset_attributes
(p
, node_attr
(q
));
3386 /* we end up with funny dimensions
*/
3387 x
= vpackage
(x
, 0, additional
, max_dimen
, math_direction
);
3388 reset_attributes
(x
, node_attr
(q
));
3389 shift_amount
(x
) = shift_down
;
3393 if
(new_hlist
(q
) == null
) {
3397 while
(vlink
(p
) != null
)
3401 if
(subscr
(q
) != null
) {
3402 math_list
(subscr
(q
)) = null
;
3403 flush_node
(subscr
(q
));
3406 if
(supscr
(q
) != null
) {
3407 math_list
(supscr
(q
)) = null
;
3408 flush_node
(supscr
(q
));
3413 @ The |make_left_right| function constructs a left or right delimiter of
3414 the required size and returns the value |open_noad| or |close_noad|. The
3415 |left_noad_side| and |right_noad_side| will both be based on the original |style|
,
3416 so they will have consistent sizes.
3419 static small_number make_left_right
(pointer q
, int style
, scaled max_d
, scaled max_h
)
3423 scaled hd_asked
= 0;
3425 boolean stack
= false
;
3426 boolean axis
= false
;
3429 boolean fitting
= true
;
3430 boolean fence
= false
;
3434 setup_cur_size
(style
);
3436 if
((delimiterheight
(q
)!=0) ||
(delimiterdepth
(q
)!=0)) {
3438 hd_asked
= delimiterheight
(q
) + delimiterdepth
(q
);
3439 tmp
= do_delimiter
(q
, delimiter
(q
), cur_size
, hd_asked
, false
, style
, false
, &stack, &ic);
3440 delimiteritalic
(q
) = ic
;
3442 /* beware
, a stacked delimiter has a shift but no corrected height
/depth
(yet
) */
3445 shift_amount
(tmp
) = delimiterdepth
(q
);
3449 hd_done
= height
(tmp
) + depth
(tmp
);
3450 fitting
= stack ||
((hd_done-hd_asked
) == 0);
3452 if
(type
(delimiter
(q
)) == delim_node
&& (small_char(delimiter(q)) != 0)) {
3453 chr
= small_char
(delimiter
(q
));
3454 cls
= get_math_code
(chr
).class_value
;
3455 fence
= (cls
== 4) ||
(cls
== 5) ;
3458 printf
("delimiter stack %i fence %i fitting %i\n",stack
,fence
,fitting
);
3461 if
(delimiterexact
(q
)) {
3462 delimiterheight
(q
) = height
(tmp
) - shift_amount
(tmp
);
3463 delimiterdepth
(q
) = depth
(tmp
) + shift_amount
(tmp
);
3465 if
(delimiteraxis
(q
)) {
3466 delimiterheight
(q
) += math_axis
(cur_size
);
3467 delimiterdepth
(q
) -= math_axis
(cur_size
);
3468 shift_amount
(tmp
) -= math_axis
(cur_size
);
3470 lst
= new_node
(hlist_node
,0);
3471 reset_attributes
(lst
, node_attr
(q
));
3472 box_dir
(lst
) = dir_TLT
;
3473 height
(lst
) = delimiterheight
(q
);
3474 depth
(lst
) = delimiterdepth
(q
);
3475 width
(lst
) = width
(tmp
);
3476 list_ptr
(lst
) = tmp
;
3479 axis
= ! delimiternoaxis
(q
);
3480 delta
= get_delimiter_height
(max_d
,max_h
,axis
);
3481 tmp
= do_delimiter
(q
, delimiter
(q
), cur_size
, delta
, false
, style
, axis
, &stack, &ic);
3482 delimiteritalic
(q
) = ic
;
3484 delimiter
(q
) = null
;
3485 assign_new_hlist
(q
, tmp
);
3486 if
(delimiterclass
(q
) >= ord_noad_type
) {
3487 if
(delimiterclass
(q
) <= inner_noad_type
) {
3488 return delimiterclass
(q
);
3490 return ord_noad_type
;
3492 } else if
(subtype
(q
) == no_noad_side
) {
3493 return open_noad_type
;
3494 } else if
(subtype
(q
) == left_noad_side
) {
3495 return open_noad_type
;
3497 return close_noad_type
;
3502 #define TEXT_STYLES
(A
,B
) do
{ \
3503 def_math_param
(A
,display_style
,(B
),level_one
); \
3504 def_math_param
(A
,cramped_display_style
,(B
),level_one
); \
3505 def_math_param
(A
,text_style
,(B
),level_one
); \
3506 def_math_param
(A
,cramped_text_style
,(B
),level_one
); \
3509 #define SCRIPT_STYLES
(A
,B
) do
{ \
3510 def_math_param
(A
,script_style
,(B
),level_one
); \
3511 def_math_param
(A
,cramped_script_style
,(B
),level_one
); \
3512 def_math_param
(A
,script_script_style
,(B
),level_one
); \
3513 def_math_param
(A
,cramped_script_script_style
,(B
),level_one
); \
3516 #define ALL_STYLES
(A
,B
) do
{ \
3517 TEXT_STYLES
(A
,(B
)); \
3518 SCRIPT_STYLES
(A
,(B
)); \
3521 #define SPLIT_STYLES
(A
,B
,C
) do
{ \
3522 TEXT_STYLES
(A
,(B
)); \
3523 SCRIPT_STYLES
(A
,(C
)); \
3527 void initialize_math_spacing
(void
)
3530 ALL_STYLES
(math_param_ord_ord_spacing
, 0);
3531 ALL_STYLES
(math_param_ord_op_spacing
, thin_mu_skip_code
);
3532 SPLIT_STYLES
(math_param_ord_bin_spacing
, med_mu_skip_code
, 0);
3533 SPLIT_STYLES
(math_param_ord_rel_spacing
, thick_mu_skip_code
, 0);
3534 ALL_STYLES
(math_param_ord_open_spacing
, 0);
3535 ALL_STYLES
(math_param_ord_close_spacing
, 0);
3536 ALL_STYLES
(math_param_ord_punct_spacing
, 0);
3537 SPLIT_STYLES
(math_param_ord_inner_spacing
, thin_mu_skip_code
, 0);
3539 ALL_STYLES
(math_param_op_ord_spacing
, thin_mu_skip_code
);
3540 ALL_STYLES
(math_param_op_op_spacing
, thin_mu_skip_code
);
3541 ALL_STYLES
(math_param_op_bin_spacing
, 0);
3542 SPLIT_STYLES
(math_param_op_rel_spacing
, thick_mu_skip_code
, 0);
3543 ALL_STYLES
(math_param_op_open_spacing
, 0);
3544 ALL_STYLES
(math_param_op_close_spacing
, 0);
3545 ALL_STYLES
(math_param_op_punct_spacing
, 0);
3546 SPLIT_STYLES
(math_param_op_inner_spacing
, thin_mu_skip_code
, 0);
3548 SPLIT_STYLES
(math_param_bin_ord_spacing
, med_mu_skip_code
, 0);
3549 SPLIT_STYLES
(math_param_bin_op_spacing
, med_mu_skip_code
, 0);
3550 ALL_STYLES
(math_param_bin_bin_spacing
, 0);
3551 ALL_STYLES
(math_param_bin_rel_spacing
, 0);
3552 SPLIT_STYLES
(math_param_bin_open_spacing
, med_mu_skip_code
, 0);
3553 ALL_STYLES
(math_param_bin_close_spacing
, 0);
3554 ALL_STYLES
(math_param_bin_punct_spacing
, 0);
3555 SPLIT_STYLES
(math_param_bin_inner_spacing
, med_mu_skip_code
, 0);
3557 SPLIT_STYLES
(math_param_rel_ord_spacing
, thick_mu_skip_code
, 0);
3558 SPLIT_STYLES
(math_param_rel_op_spacing
, thick_mu_skip_code
, 0);
3559 ALL_STYLES
(math_param_rel_bin_spacing
, 0);
3560 ALL_STYLES
(math_param_rel_rel_spacing
, 0);
3561 SPLIT_STYLES
(math_param_rel_open_spacing
, thick_mu_skip_code
, 0);
3562 ALL_STYLES
(math_param_rel_close_spacing
, 0);
3563 ALL_STYLES
(math_param_rel_punct_spacing
, 0);
3564 SPLIT_STYLES
(math_param_rel_inner_spacing
, thick_mu_skip_code
, 0);
3566 ALL_STYLES
(math_param_open_ord_spacing
, 0);
3567 ALL_STYLES
(math_param_open_op_spacing
, 0);
3568 ALL_STYLES
(math_param_open_bin_spacing
, 0);
3569 ALL_STYLES
(math_param_open_rel_spacing
, 0);
3570 ALL_STYLES
(math_param_open_open_spacing
, 0);
3571 ALL_STYLES
(math_param_open_close_spacing
, 0);
3572 ALL_STYLES
(math_param_open_punct_spacing
, 0);
3573 ALL_STYLES
(math_param_open_inner_spacing
, 0);
3575 ALL_STYLES
(math_param_close_ord_spacing
, 0);
3576 ALL_STYLES
(math_param_close_op_spacing
, thin_mu_skip_code
);
3577 SPLIT_STYLES
(math_param_close_bin_spacing
, med_mu_skip_code
, 0);
3578 SPLIT_STYLES
(math_param_close_rel_spacing
, thick_mu_skip_code
, 0);
3579 ALL_STYLES
(math_param_close_open_spacing
, 0);
3580 ALL_STYLES
(math_param_close_close_spacing
, 0);
3581 ALL_STYLES
(math_param_close_punct_spacing
, 0);
3582 SPLIT_STYLES
(math_param_close_inner_spacing
, thin_mu_skip_code
, 0);
3584 SPLIT_STYLES
(math_param_punct_ord_spacing
, thin_mu_skip_code
, 0);
3585 SPLIT_STYLES
(math_param_punct_op_spacing
, thin_mu_skip_code
, 0);
3586 ALL_STYLES
(math_param_punct_bin_spacing
, 0);
3587 SPLIT_STYLES
(math_param_punct_rel_spacing
, thin_mu_skip_code
, 0);
3588 SPLIT_STYLES
(math_param_punct_open_spacing
, thin_mu_skip_code
, 0);
3589 SPLIT_STYLES
(math_param_punct_close_spacing
, thin_mu_skip_code
, 0);
3590 SPLIT_STYLES
(math_param_punct_punct_spacing
, thin_mu_skip_code
, 0);
3591 SPLIT_STYLES
(math_param_punct_inner_spacing
, thin_mu_skip_code
, 0);
3593 SPLIT_STYLES
(math_param_inner_ord_spacing
, thin_mu_skip_code
, 0);
3594 ALL_STYLES
(math_param_inner_op_spacing
, thin_mu_skip_code
);
3595 SPLIT_STYLES
(math_param_inner_bin_spacing
, med_mu_skip_code
, 0);
3596 SPLIT_STYLES
(math_param_inner_rel_spacing
, thick_mu_skip_code
, 0);
3597 SPLIT_STYLES
(math_param_inner_open_spacing
, thin_mu_skip_code
, 0);
3598 ALL_STYLES
(math_param_inner_close_spacing
, 0);
3599 SPLIT_STYLES
(math_param_inner_punct_spacing
, thin_mu_skip_code
, 0);
3600 SPLIT_STYLES
(math_param_inner_inner_spacing
, thin_mu_skip_code
, 0);
3605 #define both_types
(A
,B
) ((A
)*16+(B
))
3607 static pointer math_spacing_glue
(int l_type
, int r_type
, int mstyle
, scaled mmu
)
3611 if
(l_type
== op_noad_type_limits || l_type
== op_noad_type_no_limits
)
3612 l_type
= op_noad_type_normal
;
3613 if
(r_type
== op_noad_type_limits || r_type
== op_noad_type_no_limits
)
3614 r_type
= op_noad_type_normal
;
3615 switch
(both_types
(l_type
, r_type
)) {
3617 case both_types
(ord_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_ord_ord_spacing
,mstyle
); break
;
3618 case both_types
(ord_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_ord_op_spacing
,mstyle
); break
;
3619 case both_types
(ord_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_ord_bin_spacing
,mstyle
); break
;
3620 case both_types
(ord_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_ord_rel_spacing
,mstyle
); break
;
3621 case both_types
(ord_noad_type
, open_noad_type
): x
= get_math_param
(math_param_ord_open_spacing
,mstyle
); break
;
3622 case both_types
(ord_noad_type
, close_noad_type
): x
= get_math_param
(math_param_ord_close_spacing
,mstyle
); break
;
3623 case both_types
(ord_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_ord_punct_spacing
,mstyle
); break
;
3624 case both_types
(ord_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_ord_inner_spacing
,mstyle
); break
;
3625 case both_types
(op_noad_type_normal
, ord_noad_type
): x
= get_math_param
(math_param_op_ord_spacing
,mstyle
); break
;
3626 case both_types
(op_noad_type_normal
, op_noad_type_normal
): x
= get_math_param
(math_param_op_op_spacing
,mstyle
); break
;
3628 case both_types
(op_noad_type_normal
, bin_noad_type
): x
= get_math_param
(math_param_op_bin_spacing
,mstyle
); break
;
3630 case both_types
(op_noad_type_normal
, rel_noad_type
): x
= get_math_param
(math_param_op_rel_spacing
,mstyle
); break
;
3631 case both_types
(op_noad_type_normal
, open_noad_type
): x
= get_math_param
(math_param_op_open_spacing
,mstyle
); break
;
3632 case both_types
(op_noad_type_normal
, close_noad_type
): x
= get_math_param
(math_param_op_close_spacing
,mstyle
); break
;
3633 case both_types
(op_noad_type_normal
, punct_noad_type
): x
= get_math_param
(math_param_op_punct_spacing
,mstyle
); break
;
3634 case both_types
(op_noad_type_normal
, inner_noad_type
): x
= get_math_param
(math_param_op_inner_spacing
,mstyle
); break
;
3635 case both_types
(bin_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_bin_ord_spacing
,mstyle
); break
;
3636 case both_types
(bin_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_bin_op_spacing
,mstyle
); break
;
3638 case both_types
(bin_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_bin_bin_spacing
,mstyle
); break
;
3639 case both_types
(bin_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_bin_rel_spacing
,mstyle
); break
;
3641 case both_types
(bin_noad_type
, open_noad_type
): x
= get_math_param
(math_param_bin_open_spacing
,mstyle
); break
;
3643 case both_types
(bin_noad_type
, close_noad_type
): x
= get_math_param
(math_param_bin_close_spacing
,mstyle
); break
;
3644 case both_types
(bin_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_bin_punct_spacing
,mstyle
); break
;
3646 case both_types
(bin_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_bin_inner_spacing
,mstyle
); break
;
3647 case both_types
(rel_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_rel_ord_spacing
,mstyle
); break
;
3648 case both_types
(rel_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_rel_op_spacing
,mstyle
); break
;
3650 case both_types
(rel_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_rel_bin_spacing
,mstyle
); break
;
3652 case both_types
(rel_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_rel_rel_spacing
,mstyle
); break
;
3653 case both_types
(rel_noad_type
, open_noad_type
): x
= get_math_param
(math_param_rel_open_spacing
,mstyle
); break
;
3654 case both_types
(rel_noad_type
, close_noad_type
): x
= get_math_param
(math_param_rel_close_spacing
,mstyle
); break
;
3655 case both_types
(rel_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_rel_punct_spacing
,mstyle
); break
;
3656 case both_types
(rel_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_rel_inner_spacing
,mstyle
); break
;
3657 case both_types
(open_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_open_ord_spacing
,mstyle
); break
;
3658 case both_types
(open_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_open_op_spacing
,mstyle
); break
;
3660 case both_types
(open_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_open_bin_spacing
,mstyle
); break
;
3662 case both_types
(open_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_open_rel_spacing
,mstyle
); break
;
3663 case both_types
(open_noad_type
, open_noad_type
): x
= get_math_param
(math_param_open_open_spacing
,mstyle
); break
;
3664 case both_types
(open_noad_type
, close_noad_type
): x
= get_math_param
(math_param_open_close_spacing
,mstyle
); break
;
3665 case both_types
(open_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_open_punct_spacing
,mstyle
); break
;
3666 case both_types
(open_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_open_inner_spacing
,mstyle
); break
;
3667 case both_types
(close_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_close_ord_spacing
,mstyle
); break
;
3668 case both_types
(close_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_close_op_spacing
,mstyle
); break
;
3669 case both_types
(close_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_close_bin_spacing
,mstyle
); break
;
3670 case both_types
(close_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_close_rel_spacing
,mstyle
); break
;
3671 case both_types
(close_noad_type
, open_noad_type
): x
= get_math_param
(math_param_close_open_spacing
,mstyle
); break
;
3672 case both_types
(close_noad_type
, close_noad_type
): x
= get_math_param
(math_param_close_close_spacing
,mstyle
); break
;
3673 case both_types
(close_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_close_punct_spacing
,mstyle
); break
;
3674 case both_types
(close_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_close_inner_spacing
,mstyle
); break
;
3675 case both_types
(punct_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_punct_ord_spacing
,mstyle
); break
;
3676 case both_types
(punct_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_punct_op_spacing
,mstyle
); break
;
3678 case both_types
(punct_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_punct_bin_spacing
,mstyle
); break
;
3680 case both_types
(punct_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_punct_rel_spacing
,mstyle
); break
;
3681 case both_types
(punct_noad_type
, open_noad_type
): x
= get_math_param
(math_param_punct_open_spacing
,mstyle
); break
;
3682 case both_types
(punct_noad_type
, close_noad_type
): x
= get_math_param
(math_param_punct_close_spacing
,mstyle
); break
;
3683 case both_types
(punct_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_punct_punct_spacing
,mstyle
); break
;
3684 case both_types
(punct_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_punct_inner_spacing
,mstyle
); break
;
3685 case both_types
(inner_noad_type
, ord_noad_type
): x
= get_math_param
(math_param_inner_ord_spacing
,mstyle
); break
;
3686 case both_types
(inner_noad_type
, op_noad_type_normal
): x
= get_math_param
(math_param_inner_op_spacing
,mstyle
); break
;
3687 case both_types
(inner_noad_type
, bin_noad_type
): x
= get_math_param
(math_param_inner_bin_spacing
,mstyle
); break
;
3688 case both_types
(inner_noad_type
, rel_noad_type
): x
= get_math_param
(math_param_inner_rel_spacing
,mstyle
); break
;
3689 case both_types
(inner_noad_type
, open_noad_type
): x
= get_math_param
(math_param_inner_open_spacing
,mstyle
); break
;
3690 case both_types
(inner_noad_type
, close_noad_type
): x
= get_math_param
(math_param_inner_close_spacing
,mstyle
); break
;
3691 case both_types
(inner_noad_type
, punct_noad_type
): x
= get_math_param
(math_param_inner_punct_spacing
,mstyle
); break
;
3692 case both_types
(inner_noad_type
, inner_noad_type
): x
= get_math_param
(math_param_inner_inner_spacing
,mstyle
); break
;
3696 confusion
("mathspacing");
3700 if
(x
<= thick_mu_skip_code
) {
3701 /* trap thin
/med
/thick settings cf. old TeX
*/
3702 y
= math_glue
(glue_par
(x
), mmu
);
3704 glue_ref_count
(y
) = null
;
3705 /* store a symbolic subtype
*/
3706 subtype
(z
) = (quarterword
) (x
+ 1);
3708 y
= math_glue
(x
, mmu
);
3710 glue_ref_count
(y
) = null
;
3717 static pointer check_nucleus_complexity
(halfword q
, scaled
* delta
, int cur_style
)
3720 switch
(type
(nucleus
(q
))) {
3721 case math_char_node
:
3722 case math_text_char_node
:
3724 if
(char_exists
(cur_f
, cur_c
)) {
3725 /* we could look at neighbours
*/
3726 if
(is_new_mathfont
(cur_f
)) {
3727 *delta
= 0 ; /* cf spec only the last one
*/
3729 *delta
= char_italic
(cur_f
, cur_c
);
3731 p
= new_glyph
(cur_f
, cur_c
);
3732 reset_attributes
(p
, node_attr
(nucleus
(q
)));
3733 if
(is_new_mathfont
(cur_f
)) {
3734 if
(! math_no_char_italic
) {
3735 /* keep italic
, but bad with two successive letters
*/
3736 } else if
(get_char_cat_code
(cur_c
) == 11) {
3737 /* no italic correction in mid-word of text font
*/
3741 /* no italic correction in mid-word of text font
*/
3742 if
(((type
(nucleus
(q
))) == math_text_char_node
) && (space(cur_f) != 0)) {
3746 /* so we only add italic correction when we have no scripts
*/
3747 if
((subscr
(q
) == null
) && (supscr(q) == null) && (*delta != 0)) {
3748 pointer x
= new_kern
(*delta
);
3749 reset_attributes
(x
, node_attr
(nucleus
(q
)));
3753 if
(is_new_mathfont
(cur_f
)) {
3754 *delta
= char_italic
(cur_f
, cur_c
); /* must be more selective
*/
3759 p
= math_list
(nucleus
(q
));
3761 case sub_mlist_node
:
3762 mlist_to_hlist
(math_list
(nucleus
(q
)), false
, cur_style
); /* recursive call
*/
3763 setup_cur_size
(cur_style
);
3764 p
= hpack
(vlink
(temp_head
), 0, additional
, -1);
3765 reset_attributes
(p
, node_attr
(nucleus
(q
)));
3768 confusion
("mlist2"); /* this can't happen mlist2
*/
3773 @ Here is the overall plan of |mlist_to_hlist|
, and the list of its
3777 void mlist_to_hlist
(pointer mlist
, boolean penalties
, int cur_style
)
3779 pointer q
= mlist
; /* runs through the mlist
*/
3780 pointer r
= null
; /* the most recent noad preceding |q|
*/
3781 int style
= cur_style
; /* tuck global parameter away as local variable
*/
3782 int r_type
= simple_noad
; /* the |type| of noad |r|
, or |op_noad| if |r
=null|
*/
3783 int r_subtype
= op_noad_type_normal
; /* the |subtype| of noad |r| if |r_type| is |fence_noad|
*/
3784 int t
; /* the effective |type| of noad |q| during the second pass
*/
3785 int t_subtype
; /* the effective |subtype| of noad |q| during the second pass
*/
3790 int pen
; /* a penalty to be inserted
*/
3791 scaled max_hl
= 0; /* maximum height of the list translated so far
*/
3792 scaled max_d
= 0; /* maximum depth of the list translated so far
*/
3793 scaled delta
; /* italic correction offset for subscript and superscript
*/
3794 scaled cur_mu
; /* the math unit width corresponding to |cur_size|
*/
3795 r_subtype
= op_noad_type_normal
;
3796 setup_cur_size
(cur_style
);
3797 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
3800 we use the fact that no character nodes appear in an mlist
, hence
3801 the field |type
(q
)| is always present.
3803 one of the things we must do on the first pass is change a |bin_noad| to
3804 an |ord_noad| if the |bin_noad| is not in the context of a binary operator
3806 the values of |r| and |r_type| make this fairly easy
3812 switch
(subtype
(q
)) {
3816 switch
(r_subtype
) {
3818 case op_noad_type_normal
:
3819 case op_noad_type_limits
:
3820 case op_noad_type_no_limits
:
3822 case open_noad_type
:
3823 case punct_noad_type
:
3824 subtype
(q
) = ord_noad_type
;
3830 if
(r_subtype
== left_noad_side
) {
3831 subtype
(q
) = ord_noad_type
; /* so these can best be the same size
*/
3837 case over_noad_type
:
3838 make_over
(q
, cur_style
);
3840 case under_noad_type
:
3841 make_under
(q
, cur_style
);
3843 case vcenter_noad_type
:
3847 case close_noad_type
:
3848 case punct_noad_type
:
3849 if
(r_type
== simple_noad
&& r_subtype == bin_noad_type) {
3850 type
(r
) = simple_noad
; /* assumes the same size .. can't this go
*/
3851 subtype
(r
) = ord_noad_type
;
3854 case op_noad_type_normal
:
3855 case op_noad_type_limits
:
3856 case op_noad_type_no_limits
:
3857 delta
= make_op
(q
, cur_style
);
3858 if
((subtype
(q
) == op_noad_type_limits
) ||
(subtype
(q
) == op_noad_type_no_limits
))
3859 goto CHECK_DIMENSIONS
;
3864 case open_noad_type
:
3865 case inner_noad_type
:
3870 if
(subtype
(q
) != left_noad_side
)
3871 if
(r_type
== simple_noad
&& r_subtype == bin_noad_type) {
3872 type
(r
) = simple_noad
; /* assumes the same size
*/
3873 subtype
(r
) = ord_noad_type
;
3875 goto DONE_WITH_NOAD
;
3878 make_fraction
(q
, cur_style
);
3879 goto CHECK_DIMENSIONS
;
3882 if
(subtype
(q
) == 7)
3883 make_hextension
(q
, cur_style
);
3884 else if
(subtype
(q
) == 6)
3885 make_delimiter_over
(q
, cur_style
);
3886 else if
(subtype
(q
) == 5)
3887 make_delimiter_under
(q
, cur_style
);
3888 else if
(subtype
(q
) == 4)
3889 make_over_delimiter
(q
, cur_style
);
3890 else if
(subtype
(q
) == 3)
3891 make_under_delimiter
(q
, cur_style
);
3893 make_radical
(q
, cur_style
);
3896 make_math_accent
(q
, cur_style
);
3899 cur_style
= subtype
(q
);
3900 setup_cur_size
(cur_style
);
3901 cur_mu
= x_over_n
(get_math_quad
(cur_style
), 18);
3902 goto DONE_WITH_NODE
;
3905 switch
(cur_style
/ 2) {
3906 case
0: /* |display_style
=0|
*/
3907 choose_mlist
(display_mlist
);
3909 case
1: /* |text_style
=2|
*/
3910 choose_mlist
(text_mlist
);
3912 case
2: /* |script_style
=4|
*/
3913 choose_mlist
(script_mlist
);
3915 case
3: /* |script_script_style
=6|
*/
3916 choose_mlist
(script_script_mlist
);
3919 flush_node_list
(display_mlist
(q
));
3920 flush_node_list
(text_mlist
(q
));
3921 flush_node_list
(script_mlist
(q
));
3922 flush_node_list
(script_script_mlist
(q
));
3923 type
(q
) = style_node
;
3924 subtype
(q
) = (quarterword
) cur_style
;
3928 while
(vlink
(p
) != null
)
3930 try_couple_nodes
(p
,z
);
3932 goto DONE_WITH_NODE
;
3941 goto DONE_WITH_NODE
;
3944 if
(height
(q
) > max_hl
)
3946 if
(depth
(q
) > max_d
)
3948 goto DONE_WITH_NODE
;
3952 conditional math glue
(`\.
{\\nonscript
}'
) results in a |glue_node|
3953 pointing to |zero_glue|
, with |subtype
(q
)=cond_math_glue|
; in such a case
3954 the node following will be eliminated if it is a glue or kern node and if the
3955 current size is different from |text_size|
3957 unconditional math glue
(`\.
{\\muskip
}'
) is converted to normal glue by
3958 multiplying the dimensions by |cur_mu|
3961 if
(subtype
(q
) == mu_glue
) {
3963 y
= math_glue
(x
, cur_mu
);
3966 subtype
(q
) = normal
;
3967 } else if
((cur_size
!= text_size
) && (subtype(q) == cond_math_glue)) {
3970 if
((type
(p
) == glue_node
) ||
(type
(p
) == kern_node
)) {
3971 couple_nodes
(q
,vlink
(p
));
3976 goto DONE_WITH_NODE
;
3979 math_kern
(q
, cur_mu
);
3980 goto DONE_WITH_NODE
;
3983 confusion
("mlist1");
3986 When we get to the following part of the program
, we have ``fallen through''
3987 from cases that did not lead to |check_dimensions| or |done_with_noad| or
3988 |done_with_node|. Thus
, |q|~points to a noad whose nucleus may need to be
3989 converted to an hlist
, and whose subscripts and superscripts need to be
3990 appended if they are present.
3992 If |nucleus
(q
)| is not a |math_char|
, the variable |delta| is the amount
3993 by which a superscript should be moved right with respect to a subscript
3994 when both are present.
3997 p
= check_nucleus_complexity
(q
, &delta, cur_style);
3999 if
((subscr
(q
) == null
) && (supscr(q) == null)) {
4000 assign_new_hlist
(q
, p
);
4003 make_scripts
(q
, p
, delta
, cur_style
, 0, 0);
4006 z
= hpack
(new_hlist
(q
), 0, additional
, -1);
4007 if
(height
(z
) > max_hl
)
4009 if
(depth
(z
) > max_d
)
4012 /* only drop the \.
{\\hbox
} */
4017 r_subtype
= subtype
(r
);
4018 if
(r_type
== fence_noad
) {
4019 r_subtype
= left_noad_side
;
4021 setup_cur_size
(cur_style
);
4022 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
4027 if
(r_type
== simple_noad
&& r_subtype == bin_noad_type) {
4028 type
(r
) = simple_noad
;
4029 subtype
(r
) = ord_noad_type
;
4032 Make a second pass over the mlist
, removing all noads and inserting the
4033 proper spacing and penalties.
4035 We have now tied up all the loose ends of the first pass of |mlist_to_hlist|.
4036 The second pass simply goes through and hooks everything together with the
4037 proper glue and penalties. It also handles the |fence_noad|s that
4038 might be present
, since |max_hl| and |max_d| are now known. Variable |p| points
4039 to a node at the current end of the final hlist.
4047 setup_cur_size
(cur_style
);
4048 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
4052 If node |q| is a style node
, change the style and |goto delete_q|
;
4053 otherwise if it is not a noad
, put it into the hlist
,
4054 advance |q|
, and |goto done|
; otherwise set |s| to the size
4055 of noad |q|
, set |t| to the associated type
(|ord_noad..
4056 inner_noad|
), and set |pen| to the associated penalty
4058 Just before doing the big |case| switch in the second pass
, the program
4059 sets up default values so that most of the branches are short.
4062 t_subtype
= ord_noad_type
;
4066 t_subtype
= subtype
(q
);
4067 switch
(t_subtype
) {
4069 pen
= bin_op_penalty
;
4074 case vcenter_noad_type
:
4075 case over_noad_type
:
4076 case under_noad_type
:
4077 t_subtype
= ord_noad_type
;
4086 t_subtype
= inner_noad_type
;
4089 t_subtype
= make_left_right
(q
, style
, max_d
, max_hl
);
4092 /* Change the current style and |goto delete_q|
*/
4093 cur_style
= subtype
(q
);
4094 setup_cur_size
(cur_style
);
4095 cur_mu
= x_over_n
(get_math_quad
(cur_size
), 18);
4114 confusion
("mlist3");
4116 /* Append inter-element spacing based on |r_type| and |t|
*/
4118 /* not the first noad
*/
4119 z
= math_spacing_glue
(r_subtype
, t_subtype
, cur_style
, cur_mu
);
4121 reset_attributes
(z
, node_attr
(p
));
4127 Append any |new_hlist| entries for |q|
, and any appropriate penalties
4129 We insert a penalty node after the hlist entries of noad |q| if |pen|
4130 is not an ``infinite'' penalty
, and if the node immediately following |q|
4131 is not a penalty node or a |rel_noad| or absent entirely.
4133 if
(new_hlist
(q
) != null
) {
4134 couple_nodes
(p
,new_hlist
(q
));
4137 } while
(vlink
(p
) != null
);
4139 if
(penalties
&& vlink(q) != null && pen < inf_penalty) {
4140 r_type
= type
(vlink
(q
));
4141 r_subtype
= subtype
(vlink
(q
));
4142 if
(r_type
!= penalty_node
&& (r_type != simple_noad || r_subtype != rel_noad_type)) {
4143 z
= new_penalty
(pen
);
4144 reset_attributes
(z
, node_attr
(q
));
4149 if
(type
(q
) == fence_noad
&& subtype(q) == right_noad_side) {
4151 t_subtype
= open_noad_type
;
4154 r_subtype
= t_subtype
;
4159 The m-to-hlist conversion takes place in-place
, so the various dependant
4160 fields may not be freed
(as would happen if |flush_node| was called
).
4162 A low-level |free_node| is easier than attempting to nullify such dependant
4163 fields for all possible node and noad types.
4165 if
(nodetype_has_attributes
(type
(r
)))
4166 delete_attribute_ref
(node_attr
(r
));
4167 reset_node_properties
(r
);
4168 free_node
(r
, get_node_size
(type
(r
), subtype
(r
)));