1
4
5
6
50
51
133
134
189
190# include "luametatex.h"
191
192
202
203static void tex_aux_append_hkern_to_box_list (halfword q, scaled delta, halfword subtype, const char *trace);
204static void tex_aux_prepend_hkern_to_box_list(halfword q, scaled delta, halfword subtype, const char *trace);
205
206
248
249typedef struct scriptdata {
250 halfword node;
251 halfword fnt;
252 halfword chr;
253 halfword box;
254 scaled kern;
255 scaled slack;
256 int shifted;
257 int whatever;
258} scriptdata;
259
260typedef struct delimiterextremes {
261 scaled tfont;
262 scaled tchar;
263 scaled bfont;
264 scaled bchar;
265 scaled height;
266 scaled depth;
267} delimiterextremes;
268
269typedef enum limits_modes {
270 limits_unknown_mode,
271 limits_vertical_mode,
272 limits_horizontal_mode,
273} limits_modes;
274
275inline static void tex_math_wipe_kerns(kernset *kerns) {
276 if (kerns) {
277 kerns->topright = 0;
278 kerns->topleft = 0;
279 kerns->bottomright = 0;
280 kerns->bottomleft = 0;
281 kerns->height = 0;
282 kerns->depth = 0;
283 kerns->toptotal = 0;
284 kerns->bottomtotal = 0;
285 kerns->dimensions = 0;
286 kerns->font = null_font;
287 kerns->character = 0;
288 kerns->padding = 0;
289 }
290}
291
292inline static void tex_math_copy_kerns(kernset *kerns, kernset *parent) {
293 if (kerns && parent) {
294 kerns->topright = parent->topright;
295 kerns->topleft = parent->topleft;
296 kerns->bottomright = parent->bottomright;
297 kerns->bottomleft = parent->bottomleft;
298 kerns->height = parent->height;
299 kerns->depth = parent->depth;
300 kerns->toptotal = parent->toptotal;
301 kerns->bottomtotal = parent->bottomtotal;
302 kerns->dimensions = parent->dimensions;
303 kerns->font = parent->font;
304 kerns->character = parent->character;
305 }
306}
307
308
311
312inline static halfword tex_aux_set_style_to_size(halfword style)
313{
314 switch (style) {
315 case script_style:
316 case cramped_script_style:
317 return script_size;
318 case script_script_style:
319 case cramped_script_script_style:
320 return script_script_size;
321 default:
322 return text_size;
323 }
324}
325
326inline static void tex_aux_set_current_math_scale(halfword scale)
327{
328 glyph_scale_par = scale;
329 lmt_math_state.scale = glyph_scale_par;
330}
331
332inline static void tex_aux_set_current_math_size(halfword style)
333{
334 lmt_math_state.size = tex_aux_set_style_to_size(style);
335}
336
337inline static void tex_aux_make_style(halfword current, halfword *current_style, halfword *current_mu)
338{
339 halfword style = node_subtype(current);
340 switch (style) {
341 case scaled_math_style:
342 tex_aux_set_current_math_scale(style_scale(current));
343 break;
344 default:
345 if (is_valid_math_style(style)) {
346 if (current_style) {
347 *current_style = style;
348 }
349 tex_aux_set_current_math_size(style);
350 if (current_mu) {
351 *current_mu = scaledround(tex_get_math_parameter(style, math_parameter_quad, NULL) / 18.0);
352
353 }
354 }
355 break;
356 }
357}
358
359
365
366inline static void tex_aux_set_parameter(halfword current, halfword style)
367{
368 if (is_valid_math_style(node_subtype(current))) {
369 style = node_subtype(current);
370 }
371 tex_def_math_parameter(style, parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular, 0);
372}
373
374void tex_set_math_text_font(halfword style, int usetextfont)
375{
376 halfword size = tex_aux_set_style_to_size(style);
377 halfword font = tex_fam_fnt(cur_fam_par, size);
378 halfword scale = tex_get_math_font_scale(font, size);
379 switch (usetextfont) {
380 case math_atom_text_font_option:
381 scale = scaledround((double) scale * (double) lmt_font_state.fonts[font]->size / (double) lmt_font_state.fonts[cur_font_par]->size);
382 break;
383 case math_atom_math_font_option:
384 update_tex_font(0, font);
385 break;
386 }
387 update_tex_glyph_scale(scale);
388}
389
390static halfword tex_aux_math_penalty_what(int pre, halfword cls, halfword pre_code, halfword post_code)
391{
392 halfword value = count_parameter(pre ? (pre_code + cls) : (post_code + cls));
393 if (value == infinite_penalty) {
394 unsigned parent = (unsigned) count_parameter(first_math_parent_code + cls);
395 cls = pre ? ((parent >> 8) & 0xFF) : (parent & 0xFF);
396 if (! valid_math_class_code(cls)) {
397 return infinite_penalty;
398 }
399 value = count_parameter(pre ? (pre_code + cls) : (post_code + cls));
400 }
401 return value;
402}
403
404static halfword tex_aux_math_penalty(int main_style, int pre, halfword cls)
405{
406 switch (main_style) {
407 case display_style:
408 case cramped_display_style:
409 {
410 halfword value = tex_aux_math_penalty_what(pre, cls, first_math_display_pre_penalty_code, first_math_display_post_penalty_code);
411 if (value != infinite_penalty) {
412 return value;
413 } else {
414 break;
415 }
416 }
417 }
418 return tex_aux_math_penalty_what(pre, cls, first_math_pre_penalty_code, first_math_post_penalty_code);
419}
420
421inline static scaled limited_scaled(long l) {
422 if (l > max_dimension) {
423 return max_dimension;
424 } else if (l < -max_dimension) {
425 return -max_dimension;
426 } else {
427 return (scaled) l;
428 }
429}
430
431inline static scaled limited_rounded(double d) {
432 long l = scaledround(d);
433 if (l > max_dimension) {
434 return max_dimension;
435 } else if (l < -max_dimension) {
436 return -max_dimension;
437 } else {
438 return (scaled) l;
439 }
440}
441
442inline static int tex_aux_math_engine_control(halfword fnt, halfword control)
443{
444
445 if (fnt && (font_mathcontrol(fnt) & math_control_use_font_control) == math_control_use_font_control) {
446
450 return (font_mathcontrol(fnt) & control) == control;
451 }
452 return (math_font_control_par & control) == control;
453}
454
455
462
463inline static scaled tex_aux_math_math_scale(scaled v)
464{
465 return v ? scaledround(0.001 * lmt_math_state.scale * v) : 0;
466}
467
468inline static scaled tex_aux_math_glyph_scale(scaled v)
469{
470 return v ? scaledround(0.001 * glyph_scale_par * v) : 0;
471}
472
473inline static scaled tex_aux_math_x_scaled(scaled v, int style)
474{
475 scaled scale = tex_get_math_parameter(style, math_parameter_x_scale, NULL);
476 return v ? limited_rounded(0.000000001 * glyph_scale_par * glyph_x_scale_par * v * scale) : 0;
477}
478
479inline static scaled tex_aux_math_given_x_scaled(scaled v)
480{
481 return v;
482}
483
484inline static scaled tex_aux_math_y_scaled(scaled v, int style)
485{
486 scaled scale = tex_get_math_parameter(style, math_parameter_y_scale, NULL);
487 return v ? limited_rounded(0.000000001 * glyph_scale_par * glyph_y_scale_par * v * scale) : 0;
488}
489
490inline static scaled tex_aux_math_given_y_scaled(scaled v)
491{
492 return v;
493}
494
495scaled tex_math_parameter_x_scaled(int style, int param)
496{
497 scaled scale = tex_get_math_parameter(style, math_parameter_x_scale, NULL);
498 scaled value = tex_get_math_parameter(style, param, NULL);
499 return value ? limited_rounded(0.000000001 * glyph_scale_par * glyph_x_scale_par * value * scale) : 0;
500}
501
502scaled tex_math_parameter_y_scaled(int style, int param)
503{
504 scaled value = tex_get_math_parameter(style, math_parameter_y_scale, NULL);
505 scaled scale = tex_get_math_parameter(style, param, NULL);
506 return value ? limited_rounded(0.000000001 * glyph_scale_par * glyph_y_scale_par * value * scale) : 0;
507}
508
509inline static scaled tex_aux_math_axis(halfword size)
510{
511 scaled v = tex_math_axis_size(size);
512 return v ? limited_rounded(0.000001 * glyph_scale_par * glyph_y_scale_par * v) : 0;
513}
514
515inline static scaled tex_aux_math_x_size_scaled(halfword f, scaled v, halfword size)
516{
517 return v ? limited_rounded(0.000000001 * tex_get_math_font_scale(f, size) * glyph_scale_par * glyph_x_scale_par * v) : 0;
518}
519
520inline static scaled tex_aux_math_y_size_scaled(halfword f, scaled v, halfword size)
521{
522 return v ? limited_rounded(0.000000001 * tex_get_math_font_scale(f, size) * glyph_scale_par * glyph_y_scale_par * v) : 0;
523}
524
525halfword tex_math_font_char_ht(halfword fnt, halfword chr, halfword style)
526{
527 return tex_aux_math_y_size_scaled(fnt, tex_char_height_from_font(fnt, chr), tex_aux_set_style_to_size(style));
528}
529
530halfword tex_math_font_char_dp(halfword fnt, halfword chr, halfword style)
531{
532 return tex_aux_math_y_size_scaled(fnt, tex_char_depth_from_font(fnt, chr), tex_aux_set_style_to_size(style));
533}
534
535inline static halfword tex_aux_new_math_glyph(halfword fnt, halfword chr, quarterword subtype) {
536 halfword scale = scaling_factor;
537 halfword glyph = tex_new_glyph_node(subtype, fnt, tex_get_math_char(fnt, chr, lmt_math_state.size, &scale, math_direction_par), null); ;
538 set_glyph_options(glyph, glyph_options_par);
539 glyph_scale(glyph) = tex_aux_math_glyph_scale(scale);
540 glyph_x_scale(glyph) = glyph_x_scale_par;
541 glyph_y_scale(glyph) = glyph_y_scale_par;
542 glyph_protected(glyph) = glyph_protected_math_code;
543 return glyph;
544}
545
546halfword tex_new_math_glyph(halfword fnt, halfword chr) {
547 return tex_aux_new_math_glyph(fnt, chr, 0);
548}
549
550static void tex_aux_trace_kerns(halfword kern, const char *what, const char *detail)
551{
552 if (tracing_math_par >= 2) {
553 tex_begin_diagnostic();
554 tex_print_format("[math: %s, %s, amount %p]", what, detail, kern_amount(kern));
555 tex_end_diagnostic();
556 }
557}
558
559static halfword tex_aux_math_insert_font_kern(halfword current, scaled amount, halfword attributetemplate, const char *trace)
560{
561
562 halfword kern = tex_new_kern_node(amount, font_kern_subtype);
563 tex_attach_attribute_list_copy(kern, attributetemplate ? attributetemplate : current);
564 if (node_next(current)) {
565 tex_couple_nodes(kern, node_next(current));
566 }
567 tex_couple_nodes(current, kern);
568 tex_aux_trace_kerns(kern, "adding font kern", trace);
569 return kern;
570}
571
572static halfword tex_aux_math_insert_italic_kern(halfword current, scaled amount, halfword attributetemplate, const char *trace)
573{
574
575 halfword kern = tex_new_kern_node(amount, italic_kern_subtype);
576 tex_attach_attribute_list_copy(kern, attributetemplate ? attributetemplate : current);
577 if (node_next(current)) {
578 tex_couple_nodes(kern, node_next(current));
579 }
580 tex_couple_nodes(current, kern);
581 tex_aux_trace_kerns(kern, "adding italic kern", trace);
582 return kern;
583}
584
585static int tex_aux_math_followed_by_italic_kern(halfword current, const char *trace)
586{
587 if (current) {
588 halfword next = node_next(current);
589 if (next && node_type(next) == kern_node && node_subtype(next) == italic_kern_subtype) {
590 tex_aux_trace_kerns(next, "ignoring italic kern", trace);
591 return 1;
592 }
593 }
594 return 0;
595}
596
597inline static int tex_aux_checked_left_kern_fnt_chr(halfword fnt, halfword chr, halfword state, halfword subtype, halfword size)
598{
599 halfword top = 0;
600 halfword bot = 0;
601 halfword hastop = (state & prime_script_state) || (state & post_super_script_state);
602 halfword hasbot = state & post_sub_script_state;
603 if (hastop && tex_math_has_class_option(subtype, left_top_kern_class_option)) {
604 top = tex_aux_math_x_size_scaled(fnt, tex_char_top_left_kern_from_font(fnt, chr), size);
605 }
606 if (hasbot && tex_math_has_class_option(subtype, left_bottom_kern_class_option)) {
607 bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_left_kern_from_font(fnt, chr), size);
608 }
609 if (hastop && hasbot) {
610 return top > bot ? top : bot;
611 } else if (hastop) {
612 return top;
613 } else {
614 return bot;
615 }
616}
617
618inline static int tex_aux_checked_left_kern(halfword list, halfword state, halfword subtype, halfword size)
619{
620 if (list && node_type(list) == glyph_node) {
621 return tex_aux_checked_left_kern_fnt_chr(glyph_font(list), glyph_character(list), state, subtype, size);
622 } else {
623 return 0;
624 }
625}
626
627inline static int tex_aux_checked_right_kern_fnt_chr(halfword fnt, halfword chr, halfword state, halfword subtype, halfword size)
628{
629 halfword top = 0;
630 halfword bot = 0;
631 halfword hastop = state & pre_super_script_state;
632 halfword hasbot = state & pre_sub_script_state;
633 if (hastop && tex_math_has_class_option(subtype, right_top_kern_class_option)) {
634 top = tex_aux_math_x_size_scaled(fnt, tex_char_top_right_kern_from_font(fnt, chr), size);
635 }
636 if (hasbot && tex_math_has_class_option(subtype, right_bottom_kern_class_option)) {
637 bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_right_kern_from_font(fnt, chr), size);
638 }
639 if (hastop && hasbot) {
640 return top < bot ? bot : top;
641 } else if (hastop) {
642 return top;
643 } else {
644 return bot;
645 }
646}
647
648inline static int tex_aux_checked_right_kern(halfword list, halfword state, halfword subtype, halfword size)
649{
650 if (list && node_type(list) == glyph_node) {
651 return tex_aux_checked_right_kern_fnt_chr(glyph_font(list), glyph_character(list), state, subtype, size);
652 } else {
653 return 0;
654 }
655}
656
657static scaled tex_aux_check_rule_thickness(halfword target, int size, halfword *fam, halfword control, halfword param)
658{
659 halfword family = noad_family(target);
660 if (family != unused_math_family) {
661 halfword font = tex_fam_fnt(family, size);
662 if (tex_aux_math_engine_control(font, control)) {
663 scaled thickness = tex_get_font_math_parameter(font, size, param);
664 if (thickness != undefined_math_parameter) {
665 *fam = family;
666 return thickness;
667 }
668 }
669 }
670 return undefined_math_parameter;
671}
672
673
674
675
676
677
678
679
680
681
682static halfword tex_aux_fake_nucleus(quarterword cls)
683{
684 halfword n = tex_new_node(simple_noad, cls);
685 halfword q = tex_new_node(math_char_node, 0);
686 set_noad_classes(n, cls);
687 noad_nucleus(n) = q;
688 math_kernel_node_set_option(q, math_kernel_ignored_character);
689 return n;
690}
691
692
693
694static void tex_aux_fake_delimiter(halfword result)
695{
696 halfword amount = tex_aux_math_given_x_scaled(null_delimiter_space_par);
697 if (amount) {
698 box_width(result) = amount;
699 box_list(result) = tex_new_kern_node(amount, horizontal_math_kern_subtype);
700 tex_attach_attribute_list_copy(box_list(result), result);
701 }
702}
703
704
707
708inline static int tex_aux_has_delimiter(halfword delimiter, halfword size)
709{
710 return (
711 delimiter && (
712 (tex_fam_fnt(delimiter_small_family(delimiter), size) && delimiter_small_character(delimiter)) ||
713 (tex_fam_fnt(delimiter_large_family(delimiter), size) && delimiter_large_character(delimiter))
714 )
715 );
716}
717
718inline static int tex_aux_has_extensible(halfword delimiter, halfword size)
719{
720 if (delimiter && delimiter_small_character(delimiter)) {
721 halfword curfnt = tex_fam_fnt(delimiter_small_family(delimiter), size);
722 if (curfnt != null_font) {
723 return tex_char_extensible_recipe_front_last(curfnt, delimiter_small_character(delimiter)) ? 1 : 0;
724 }
725 }
726 return 0;
727}
728
729
733
734static scaled tex_aux_get_delimiter_height(scaled height, scaled depth, int axis, int size, int style)
735{
736 scaled delta1 = height + depth;
737 scaled delta2 = depth;
738 scaled delta3 = 0;
739 halfword percent = tex_get_math_parameter_default(style, math_parameter_delimiter_percent, 0);
740 scaled shortfall = tex_get_math_y_parameter_default(style, math_parameter_delimiter_shortfall, 0);
741 if (axis) {
742 delta2 += tex_aux_math_axis(size);
743 }
744 delta1 -= delta2;
745 if (delta2 > delta1) {
746
747 delta1 = delta2;
748 }
749 delta3 = scaledround((delta1 / 500.0) * delimiter_factor_par * (percent / 100.0));
750 delta2 = 2 * delta1 - delimiter_shortfall_par - shortfall;
751 return (delta3 < delta2) ? delta2 : delta3;
752}
753
754
766
767static const char *tex_aux_math_size_string(int s)
768{
769 switch (s) {
770 case script_script_size: return "scriptscriptfont";
771 case script_size: return "scriptfont";
772 default: return "textfont";
773 }
774}
775
776
777
778static halfword tex_aux_math_clone(halfword n)
779{
780 if (n) {
781 halfword result = tex_new_node(node_type(n), 0);
782 tex_attach_attribute_list_copy(result, n);
783 tex_math_copy_char_data(result, n, 0);
784 return result;
785 } else {
786 return null;
787 }
788}
789
790
794
795static halfword tex_aux_make_list_phantom(halfword source, int nowidth, halfword att)
796{
797 halfword target = null;
798 switch (node_type(source)) {
799 case hlist_node:
800 target = tex_new_node(hlist_node, node_subtype(source));
801 break;
802 case vlist_node:
803 target = tex_new_node(vlist_node, node_subtype(source));
804 break;
805 }
806 if (target) {
807 halfword rule = tex_new_rule_node(empty_rule_subtype);
808 tex_attach_attribute_list_attribute(target, att);
809 tex_attach_attribute_list_attribute(rule, att);
810 rule_width(rule) = nowidth ? 0 : box_width(source);
811 rule_height(rule) = box_height(source);
812 rule_depth(rule) = box_depth(source);
813 box_dir(target) = dir_lefttoright ;
814 box_height(target) = rule_height(rule);
815 box_depth(target) = rule_depth(rule);
816 box_width(target) = rule_width(rule);
817 box_shift_amount(target) = box_shift_amount(source);
818 box_list(target) = rule;
819 tex_flush_node_list(source);
820 return target;
821 } else {
822 return source;
823 }
824}
825
826
832
833static halfword tex_aux_fraction_rule(scaled width, scaled height, halfword att, quarterword ruletype, halfword size, halfword fam)
834{
835 halfword rule = null;
836 int callback_id = lmt_callback_defined(math_rule_callback);
837 if (callback_id > 0) {
838 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "ddddN->N", math_rules_mode_par ? ruletype : normal_rule_subtype, tex_fam_fnt(fam, size), width, height, att, &rule);
839 if (rule && node_type(rule) != hlist_node) {
840 rule = tex_hpack(rule, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
841 node_subtype(rule) = math_rule_list;
842 tex_attach_attribute_list_attribute(rule, att);
843 }
844 }
845 if (! rule) {
846 if (math_rules_mode_par) {
847 rule = tex_new_rule_node(ruletype);
848 rule_data(rule) = tex_fam_fnt(fam, size);
849 } else {
850 rule = tex_new_rule_node(normal_rule_subtype);
851 }
852 rule_height(rule) = height;
853 rule_depth(rule) = 0;
854 tex_attach_attribute_list_attribute(rule, att);
855 }
856 return rule;
857}
858
859
866
867static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int size, scaled targetsize, int flat, int style, int shift, int *stack, scaled *delta, scaled tolerance, int nooverflow, delimiterextremes *extremes, scaled move, halfword attr);
868
869static halfword tex_aux_overbar(halfword box, scaled gap, scaled height, scaled krn, halfword att, quarterword index, halfword size, halfword fam, halfword topdelimiter, halfword style)
870{
871 halfword rule = (topdelimiter > 0 && tex_aux_has_extensible(topdelimiter, size))
872 ? tex_aux_make_delimiter(null, topdelimiter, size, box_width(box), 1, style, 0, NULL, NULL, 0, 0, NULL, 0, att)
873 : tex_aux_fraction_rule(box_width(box), height, att, index, size, fam);
874
875 if (topdelimiter > 0 && box_width(rule) > box_width(box)) {
876 halfword delta = (box_width(rule) - box_width(box)) / 2;
877 tex_aux_prepend_hkern_to_box_list(box, delta, horizontal_math_kern_subtype, "narrow delimiter");
878 tex_aux_append_hkern_to_box_list(box, delta, horizontal_math_kern_subtype, "narrow delimiter");
879 box_width(box) = box_width(rule);
880 }
881 if (topdelimiter < 0) {
882 node_subtype(rule) = empty_rule_code;
883 }
884 if (gap) {
885 halfword kern = tex_new_kern_node(gap, vertical_math_kern_subtype);
886 tex_attach_attribute_list_attribute(kern, att);
887 tex_couple_nodes(kern, box);
888 tex_couple_nodes(rule, kern);
889 } else {
890 tex_couple_nodes(rule, box);
891 }
892 if (krn) {
893 halfword kern = tex_new_kern_node(krn, vertical_math_kern_subtype);
894 tex_attach_attribute_list_attribute(kern, att);
895 tex_couple_nodes(kern, rule);
896 rule = kern;
897 }
898 rule = tex_vpack(rule, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
899 tex_attach_attribute_list_attribute(rule, att);
900 return rule;
901}
902
903static halfword tex_aux_underbar(halfword box, scaled gap, scaled height, scaled krn, halfword att, quarterword index, halfword size, halfword fam, halfword botdelimiter, halfword style)
904{
905 halfword rule = (botdelimiter && tex_aux_has_extensible(botdelimiter, size))
906 ? tex_aux_make_delimiter(null, botdelimiter, size, box_width(box), 1, style, 0, NULL, NULL, 0, 0, NULL, 0, att)
907 : tex_aux_fraction_rule(box_width(box), height, att, index, size, fam);
908 if (gap) {
909 halfword kern = tex_new_kern_node(gap, vertical_math_kern_subtype);
910 tex_attach_attribute_list_attribute(kern, att);
911 tex_couple_nodes(box, kern);
912 tex_couple_nodes(kern, rule);
913 } else {
914 tex_couple_nodes(box, rule);
915 }
916 if (krn) {
917 halfword kern = tex_new_kern_node(krn, vertical_math_kern_subtype);
918 tex_attach_attribute_list_attribute(kern, att);
919 tex_couple_nodes(rule, kern);
920 }
921 rule = tex_vpack(box, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
922 tex_attach_attribute_list_attribute(rule, att);
923
924
925 box_depth(rule) = box_total(rule) - box_height(box);
926 box_height(rule) = box_height(box);
927
928 return rule;
929}
930
931
965
966static halfword tex_aux_char_box(halfword fnt, int chr, halfword att, scaled *ic, quarterword subtype, scaled target, int style, int shrink, int stretch, int *isscaled)
967{
968
969 halfword glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
970 halfword box = tex_new_null_box_node(hlist_node, math_char_list);
971 scaledwhd whd = tex_char_whd_from_glyph(glyph);
972 tex_attach_attribute_list_attribute(glyph, att);
973 tex_attach_attribute_list_attribute(box, att);
974 box_width(box) = whd.wd;
975 box_height(box) = whd.ht;
976 box_depth(box) = whd.dp;
977 box_list(box) = glyph;
978 if (isscaled) {
979 *isscaled = 0;
980 }
981 if (tex_has_glyph_option(glyph, glyph_option_no_italic_correction)) {
982 whd.ic = 0;
983 }
984 if (! (stretch || shrink) && whd.ic) {
985 if (ic) {
986 *ic = whd.ic;
987 }
988 if (tex_aux_math_engine_control(fnt, math_control_apply_char_italic_kern)) {
989 tex_aux_math_insert_italic_kern(glyph, whd.ic, glyph, "box");
990 box_width(box) += whd.ic;
991 } else {
992 return box;
993 }
994 } else if (ic) {
995 *ic = 0;
996 }
997 if (target && whd.wd > 0) {
998 if (whd.wd < target && tex_aux_math_engine_control(fnt, math_control_extend_accents) && tex_char_has_tag_from_font(fnt, chr, extend_last_tag)) {
999 scaled margin = tex_get_math_x_parameter_default(style, math_parameter_accent_extend_margin, 0);
1000 scaled amount = target - 2 * margin;
1001 if (amount > 0) {
1002 glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * amount/whd.wd);
1003 glyph_x_offset(glyph) = (whd.wd - amount)/2;
1004 if (isscaled) {
1005 *isscaled = 1;
1006 }
1007 }
1008 return box;
1009 }
1010 if ((shrink && (whd.wd > target)) || (stretch && (whd.wd < target))) {
1011 glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * target/whd.wd);
1012
1013 whd = tex_char_whd_from_glyph(glyph);
1014 box_width(box) = whd.wd;
1015 if (isscaled) {
1016 *isscaled = 1;
1017 }
1018 }
1019 }
1020 return box;
1021}
1022
1023
1033
1034static scaled tex_aux_stack_char_into_box(halfword box, halfword fnt, int chr, quarterword subtype, int horiziontal)
1035{
1036 halfword glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
1037 scaledwhd whd = tex_char_whd_from_glyph(glyph);
1038 halfword list = box_list(box);
1039 tex_attach_attribute_list_attribute(glyph, get_attribute_list(box));
1040 if (horiziontal) {
1041 if (list) {
1042 tex_couple_nodes(tex_tail_of_node_list(list), glyph);
1043 } else {
1044 box_list(box) = glyph;
1045 }
1046 if (box_height(box) < whd.ht) {
1047 box_height(box) = whd.ht;
1048 }
1049 if (box_depth(box) < whd.dp) {
1050 box_depth(box) = whd.dp;
1051 }
1052
1053
1054
1055 return whd.wd;
1056 } else {
1057 halfword boxed = tex_new_null_box_node(hlist_node, math_char_list);
1058 tex_attach_attribute_list_attribute(boxed, get_attribute_list(box));
1059 box_width(boxed) = whd.wd;
1060 box_height(boxed) = whd.ht;
1061 box_depth(boxed) = whd.dp;
1062 box_list(boxed) = glyph;
1063 tex_try_couple_nodes(boxed, list);
1064 box_list(box) = boxed;
1065
1066 if (box_width(box) < whd.wd) {
1067 box_width(box) = whd.wd;
1068 }
1069
1070
1071
1072 return whd.ht + whd.dp;
1073 }
1074}
1075
1076static void tex_aux_stack_glue_into_box(halfword box, scaled min, scaled max) {
1077 halfword glue = tex_new_glue_node(zero_glue, user_skip_glue);
1078 glue_amount(glue) = min;
1079 glue_stretch(glue) = max - min;
1080 tex_add_glue_option(glue, glue_option_no_auto_break);
1081 tex_attach_attribute_list_copy(glue, box);
1082 if (node_type(box) == vlist_node) {
1083 tex_try_couple_nodes(glue, box_list(box));
1084 box_list(box) = glue;
1085 } else {
1086 halfword list = box_list(box);
1087 if (list) {
1088 tex_couple_nodes(tex_tail_of_node_list(list), glue);
1089 } else {
1090 box_list(box) = glue;
1091 }
1092 }
1093}
1094
1095
1110
1111static halfword tex_aux_top_extensible_from_box(halfword e)
1112{
1113 if (node_type(e) == vlist_node && node_subtype(e) == math_v_extensible_list) {
1114 e = box_list(e);
1115 while (e) {
1116 if (node_type(e) == hlist_node && box_list(e) && node_type(box_list(e)) == glyph_node) {
1117 return box_list(e);
1118 } else {
1119 e = node_next(e);
1120 }
1121 }
1122 }
1123 return null;
1124}
1125
1126static halfword tex_aux_bottom_extensible_from_box(halfword e)
1127{
1128 halfword g = null;
1129 if (node_type(e) == vlist_node && node_subtype(e) == math_v_extensible_list) {
1130 e = box_list(e);
1131 while (e) {
1132 if (node_type(e) == hlist_node && box_list(e) && node_type(box_list(e)) == glyph_node) {
1133 g = box_list(e);
1134 }
1135 e = node_next(e);
1136 }
1137 }
1138 return g;
1139}
1140
1141static halfword tex_aux_get_delimiter_box(halfword fnt, halfword chr, scaled target, scaled minoverlap, int horizontal, halfword att)
1142{
1143 halfword size = lmt_math_state.size;
1144 int callback_id = lmt_callback_defined(make_extensible_callback);
1145 if (callback_id > 0) {
1146
1150 halfword boxed = null;
1151 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "ddddbNd->N", fnt, chr, target, minoverlap, horizontal, att, size, &boxed);
1152 if (boxed) {
1153 switch (node_type(boxed)) {
1154 case hlist_node:
1155 case vlist_node:
1156 return boxed;
1157 default:
1158 tex_formatted_error("fonts", "invalid extensible character %i created for font %i, [h|v]list expected", chr, fnt);
1159 break;
1160 }
1161 }
1162 }
1163 return tex_make_extensible(fnt, chr, target, minoverlap, horizontal, att, size);
1164}
1165
1166halfword tex_make_extensible(halfword fnt, halfword chr, scaled target, scaled minoverlap, int horizontal, halfword att, halfword size)
1167{
1168
1169 scaled max_natural = 0;
1170
1171 scaled max_shrink = 0;
1172 scaled overlap;
1173
1174 int pieces = 0;
1175
1176 halfword box = tex_new_null_box_node(horizontal ? hlist_node : vlist_node, horizontal ? math_h_extensible_list : math_v_extensible_list);
1177
1178 int with_extenders = -1;
1179 int n_of_extenders = 0;
1180 int n_of_normal = 0;
1181 extinfo *extensible = tex_char_extensible_recipe_from_font(fnt, chr);
1182 if (minoverlap < 0) {
1183 minoverlap = 0;
1184 }
1185 tex_attach_attribute_list_attribute(box, att);
1186 for (extinfo *e = extensible; e; e = e->next) {
1187 if (! tex_char_exists(fnt, e->glyph)) {
1188 tex_handle_error(
1189 normal_error_type,
1190 "Extension part doesn't exist.",
1191 "Each glyph part in an extensible item should exist in the font. I will give up\n"
1192 "trying to find a suitable size for now. Fix your font!"
1193 );
1194 tex_aux_fake_delimiter(box);
1195 return box;
1196 } else {
1197 if (e->extender == math_extension_repeat) {
1198 n_of_extenders++;
1199 } else {
1200 n_of_normal++;
1201 }
1202
1206 if (e->start_overlap < 0 || e->end_overlap < 0 || e->advance < 0) {
1207 tex_handle_error(
1208 normal_error_type,
1209 "Extensible recipe has negative fields.",
1210 "All measurements in extensible items should be positive. To get around this\n"
1211 "problem, I have changed the font metrics. Fix your font!"
1212 );
1213 if (e->start_overlap < 0) {
1214 e->start_overlap = 0;
1215 }
1216 if (e->end_overlap < 0) {
1217 e->end_overlap = 0;
1218 }
1219 if (e->advance < 0) {
1220 e->advance = 0;
1221 }
1222 }
1223 }
1224 }
1225 if (n_of_normal == 0) {
1226 tex_handle_error(
1227 normal_error_type,
1228 "Extensible recipe has no fixed parts.",
1229 "Each extensible recipe should have at least one non-repeatable part. To get\n"
1230 "around this problem, I have changed the first part to be non-repeatable. Fix your\n"
1231 "font!"
1232 );
1233 if (extensible) {
1234 extensible->extender = 0;
1235 }
1236 n_of_normal = 1;
1237 n_of_extenders--;
1238 }
1239
1270 while (max_natural < target && n_of_extenders > 0) {
1271 overlap = 0;
1272 max_natural = 0;
1273 with_extenders++;
1274 if (horizontal) {
1275 for (extinfo *e = extensible; e; e = e->next) {
1276 if (e->extender == 0) {
1277 scaled initial = tex_aux_math_x_size_scaled(fnt, e->start_overlap, size);
1278 scaled advance = tex_aux_math_x_size_scaled(fnt, e->advance, size);
1279 if (minoverlap < initial) {
1280 initial = minoverlap;
1281 }
1282 if (overlap < initial) {
1283 initial = overlap;
1284 }
1285 if (advance == 0) {
1286 advance = tex_aux_math_x_size_scaled(fnt, tex_char_width_from_font(fnt, e->glyph), size);
1287 }
1288 if (advance <= 0) {
1289 tex_formatted_error("fonts", "bad horizontal extensible character %i in font %i", chr, fnt);
1290 }
1291 max_natural += advance - initial;
1292 overlap = tex_aux_math_x_size_scaled(fnt, e->end_overlap, size);
1293 } else {
1294 pieces = with_extenders;
1295 while (pieces > 0) {
1296 scaled initial = tex_aux_math_x_size_scaled(fnt, e->start_overlap, size);
1297 scaled advance = tex_aux_math_x_size_scaled(fnt, e->advance, size);
1298 if (minoverlap < initial) {
1299 initial = minoverlap;
1300 }
1301 if (overlap < initial) {
1302 initial = overlap;
1303 }
1304 if (advance == 0) {
1305 advance = tex_aux_math_x_size_scaled(fnt, tex_char_width_from_font(fnt, e->glyph), size);
1306 }
1307 if (advance <= 0) {
1308 tex_formatted_error("fonts", "bad horizontal extensible character %i in font %i", chr, fnt);
1309 }
1310 max_natural += advance - initial;
1311 overlap = tex_aux_math_x_size_scaled(fnt, e->end_overlap, size);
1312 pieces--;
1313 }
1314 }
1315 }
1316 } else {
1317 for (extinfo *e = extensible; e; e = e->next) {
1318 if (e->extender == 0) {
1319 scaled initial = tex_aux_math_y_size_scaled(fnt, e->start_overlap, size);
1320 scaled advance = tex_aux_math_y_size_scaled(fnt, e->advance, size);
1321 if (minoverlap < initial) {
1322 initial = minoverlap;
1323 }
1324 if (overlap < initial) {
1325 initial = overlap;
1326 }
1327 if (advance == 0) {
1328 advance = tex_aux_math_y_size_scaled(fnt, tex_char_total_from_font(fnt, e->glyph), size);
1329 }
1330 if (advance <= 0) {
1331 tex_formatted_error("fonts", "bad vertical extensible character %i in font %i", chr, fnt);
1332 }
1333 max_natural += advance - initial;
1334 overlap = tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1335 } else {
1336 pieces = with_extenders;
1337 while (pieces > 0) {
1338 scaled initial = tex_aux_math_y_size_scaled(fnt, e->start_overlap, size);
1339 scaled advance = tex_aux_math_y_size_scaled(fnt, e->advance, size);
1340 if (minoverlap < initial) {
1341 initial = minoverlap;
1342 }
1343 if (overlap < initial) {
1344 initial = overlap;
1345 }
1346 if (advance == 0) {
1347 advance = tex_aux_math_y_size_scaled(fnt, tex_char_total_from_font(fnt, e->glyph), size);
1348 }
1349 if (advance <= 0) {
1350 tex_formatted_error("fonts", "bad vertical extensible character %i in font %i", chr, fnt);
1351 }
1352 max_natural += advance - initial;
1353 overlap = tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1354 pieces--;
1355 }
1356 }
1357 }
1358 }
1359 }
1360
1364 overlap = 0;
1365 max_natural = 0;
1366 max_shrink = 0;
1367 for (extinfo *e = extensible; e; e = e->next) {
1368 if (e->extender == 0) {
1369 scaled progress;
1370 scaled initial = horizontal ? tex_aux_math_x_size_scaled(fnt, e->start_overlap, size) : tex_aux_math_y_size_scaled(fnt, e->start_overlap, size);
1371 if (overlap < initial) {
1372 initial = overlap;
1373 }
1374 progress = initial;
1375 if (minoverlap < initial) {
1376 initial = minoverlap;
1377 }
1378 if (progress > 0) {
1379 tex_aux_stack_glue_into_box(box, -progress, -initial);
1380 max_shrink += (-initial) - (-progress);
1381 max_natural -= progress;
1382 }
1383 max_natural += tex_aux_stack_char_into_box(box, fnt, e->glyph, glyph_math_extensible_subtype, horizontal);
1384 overlap = horizontal ? tex_aux_math_x_size_scaled(fnt, e->end_overlap, size) : tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1385 pieces--;
1386 } else {
1387 pieces = with_extenders;
1388 while (pieces > 0) {
1389 scaled progress;
1390 scaled initial = horizontal ? tex_aux_math_x_size_scaled(fnt, e->start_overlap, size) : tex_aux_math_y_size_scaled(fnt, e->start_overlap, size);
1391 if (overlap < initial) {
1392 initial = overlap;
1393 }
1394 progress = initial;
1395 if (minoverlap < initial) {
1396 initial = minoverlap;
1397 }
1398 if (progress > 0) {
1399 tex_aux_stack_glue_into_box(box, -progress, -initial);
1400 max_shrink += (-initial) - (-progress);
1401 max_natural -= progress;
1402 }
1403 max_natural += tex_aux_stack_char_into_box(box, fnt, e->glyph, glyph_math_extensible_subtype, horizontal);
1404 overlap = horizontal ? tex_aux_math_x_size_scaled(fnt, e->end_overlap, size) : tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1405 pieces--;
1406 }
1407 }
1408 }
1409
1410 if (target > max_natural && max_shrink > 0) {
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425 scaled delta = target - max_natural;
1426
1427 if (delta > max_shrink) {
1428 if (tracing_math_par >= 1) {
1429 tex_begin_diagnostic();
1430 tex_print_format("[math: extensible clipped, target %p, natural %p, shrink %p, clip %p]",
1431 target, max_natural, max_shrink, delta - max_shrink
1432 );
1433 tex_end_diagnostic();
1434 }
1435 delta = max_shrink;
1436 }
1437 box_glue_order(box) = normal_glue_order;
1438 box_glue_sign(box) = stretching_glue_sign;
1439 box_glue_set(box) = (glueratio) (delta / (glueratio) max_shrink);
1440 max_natural += delta;
1441
1442 }
1443 if (horizontal) {
1444 box_width(box) = max_natural;
1445 node_subtype(box) = math_h_extensible_list;
1446 } else {
1447 box_height(box) = max_natural;
1448 node_subtype(box) = math_v_extensible_list;
1449 }
1450 return box;
1451}
1452
1453
1468
1469static halfword register_extensible(halfword fnt, halfword chr, int size, halfword result, halfword att)
1470{
1471 int callback_id = lmt_callback_defined(register_extensible_callback);
1472 if (callback_id > 0) {
1473 halfword boxed = null;
1474 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "ddddN->N", fnt, chr, size, att, result, &boxed);
1475 if (boxed) {
1476 switch (node_type(boxed)) {
1477 case hlist_node:
1478 case vlist_node:
1479
1480 return boxed;
1481 default:
1482 tex_formatted_error("fonts", "invalid extensible character %U registered for font %F, [h|v]list expected", chr, fnt);
1483 break;
1484 }
1485 }
1486 }
1487 return result;
1488}
1489
1490
1494
1495static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int size, scaled targetsize, int flat, int style, int shift, int *stack, scaled *delta, scaled tolerance, int nooverflow, delimiterextremes *extremes, scaled move, halfword attr)
1496{
1497
1498 halfword result = null;
1499
1500 halfword fnt = null_font;
1501
1502 int chr = 0;
1503 int nxtchr = 0;
1504
1505 int large_attempt = 0;
1506 int do_parts = 0;
1507 int isscaled = 0;
1508 int shrink = flat && has_noad_option_shrink(target);
1509 int stretch = flat && has_noad_option_stretch(target);
1510
1511 halfword att = null;
1512 if (extremes) {
1513 extremes->tfont = null_font;
1514 extremes->bfont = null_font;
1515 extremes->tchar = 0;
1516 extremes->bchar = 0;
1517 extremes->height = 0;
1518 extremes->depth = 0;
1519 }
1520 if (! tex_aux_has_delimiter(delimiter, size)) {
1521 halfword result = tex_new_null_box_node(hlist_node, math_v_delimiter_list);
1522 tex_attach_attribute_list_copy(result, delimiter);
1523 if (! flat) {
1524 tex_aux_fake_delimiter(result);
1525 }
1526 tex_flush_node(delimiter);
1527 return result;
1528 }
1529 if (delimiter) {
1530
1531 scaled besttarget = 0;
1532
1533 int curfam = delimiter_small_family(delimiter);
1534 int curchr = 0;
1535 int count = 0;
1536 int prvfnt = null_font;
1537 int prvchr = 0;
1538 nxtchr = delimiter_small_character(delimiter);
1539 while (1) {
1540
1546 if (curfam || nxtchr) {
1547 halfword curfnt = tex_fam_fnt(curfam, size);
1548 if (curfnt != null_font) {
1549 curchr = nxtchr;
1550 CONTINUE:
1551 count++;
1552 if (tex_char_exists(curfnt, curchr)) {
1553 if (! tex_char_has_tag_from_font(curfnt, curchr, force_extensible_tag)) {
1554 scaled total = flat ? tex_aux_math_x_size_scaled(curfnt, tex_char_width_from_font(curfnt, curchr), size): tex_aux_math_y_size_scaled(curfnt, tex_char_total_from_font(curfnt, curchr), size);
1555 if (nooverflow && total >= targetsize) {
1556 if (total > targetsize && prvfnt != null_font) {
1557 fnt = prvfnt;
1558 chr = prvchr;
1559 } else {
1560 fnt = curfnt;
1561 chr = curchr;
1562 }
1563 besttarget = total;
1564 goto FOUND;
1565 } else if (total >= besttarget) {
1566 prvfnt = curfnt;
1567 prvchr = curchr;
1568 fnt = curfnt;
1569 chr = curchr;
1570 besttarget = total;
1571 if (total >= (targetsize - tolerance)) {
1572 goto FOUND;
1573 }
1574 }
1575 }
1576 if (tex_char_has_tag_from_font(curfnt, curchr, extensible_tag)) {
1577 if (tex_char_has_tag_from_font(curfnt, curchr, horizontal_tag) || tex_char_has_tag_from_font(curfnt, curchr, vertical_tag)) {
1578
1579 if (flat ? tex_char_has_tag_from_font(curfnt, curchr, horizontal_tag) : tex_char_has_tag_from_font(curfnt, curchr, vertical_tag)) {
1580 fnt = curfnt;
1581 chr = curchr;
1582 do_parts = 1;
1583 }
1584 }
1585 goto FOUND;
1586 } else if (count > scaling_factor) {
1587 tex_formatted_warning("fonts", "endless loop in extensible character %U of font %F", curchr, curfnt);
1588 goto FOUND;
1589 } else if (tex_char_has_tag_from_font(curfnt, curchr, list_tag)) {
1590 prvfnt = curfnt;
1591 prvchr = curchr;
1592 curchr = tex_char_next_from_font(curfnt, curchr);
1593 goto CONTINUE;
1594 }
1595 }
1596 }
1597 }
1598 if (large_attempt) {
1599
1600 goto FOUND;
1601 } else {
1602 large_attempt = 1;
1603 curfam = delimiter_large_family(delimiter);
1604 nxtchr = delimiter_large_character(delimiter);
1605 }
1606 }
1607 }
1608 FOUND:
1609 if (delimiter) {
1610
1614 att = get_attribute_list(delimiter);
1615 wipe_attribute_list_only(delimiter);
1616 tex_flush_node(delimiter);
1617 }
1618
1619
1620
1621 if (fnt != null_font) {
1622
1626 extinfo *ext = do_parts ? tex_char_extensible_recipe_from_font(fnt, chr) : NULL;
1627 if (ext) {
1628 scaled minoverlap = flat ? tex_get_math_x_parameter_default(style, math_parameter_connector_overlap_min, 0) : tex_get_math_y_parameter_default(style, math_parameter_connector_overlap_min, 0);
1629 result = tex_aux_get_delimiter_box(fnt, chr, targetsize, minoverlap, flat, attr ? attr : att);
1630 if (stretch && flat && (box_width(result) > targetsize)) {
1631 tex_flush_node_list(result);
1632 do_parts = 0;
1633 goto HERE;
1634 }
1635 if (delta) {
1636
1637 if (tex_aux_math_engine_control(fnt, math_control_apply_vertical_italic_kern)) {
1638 *delta = tex_aux_math_x_size_scaled(fnt, tex_char_extensible_italic_from_font(fnt, nxtchr), size);
1639 } else {
1640 *delta = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, nxtchr), size);
1641 }
1642 }
1643 if (stack) {
1644 *stack = 1 ;
1645 }
1646 if (! flat && extremes) {
1647 halfword first = tex_aux_top_extensible_from_box(result);
1648 halfword last = tex_aux_bottom_extensible_from_box(result);
1649 extremes->tfont = glyph_font(first);
1650 extremes->tchar = glyph_character(first);
1651 extremes->bfont = glyph_font(last);
1652 extremes->bchar = glyph_character(last);
1653 extremes->height = box_height(result);
1654 extremes->depth = box_depth(result);
1655 }
1656 } else {
1657
1664 HERE:
1665 result = tex_aux_char_box(fnt, chr, att, delta, glyph_math_delimiter_subtype, flat ? targetsize : 0, style, shrink, stretch, &isscaled);
1666 if (flat) {
1667
1668 } else {
1669 if (box_total(result) < targetsize && tex_aux_math_engine_control(fnt, math_control_extend_delimiters) && tex_char_has_tag_from_font(fnt, chr, extend_last_tag)) {
1670 halfword glyph = box_list(result);
1671 if (glyph && node_type(glyph) == glyph_node) {
1672 scaled margin = tex_get_math_y_parameter_default(style, math_parameter_delimiter_extend_margin, 0);
1673 scaled amount = targetsize - 2 * margin;
1674 if (amount > 0) {
1675 double ratio = (double) amount/box_total(result);
1676 glyph_y_scale(glyph) = lround((double) glyph_y_scale(glyph) * ratio);
1677 glyph_y_offset(glyph) = lround((double) box_total(glyph) * ratio);
1678 box_height(result) = lround((double) box_height(result) * ratio);
1679 box_depth(result) = lround((double) box_depth(result) * ratio);
1680 }
1681 }
1682 }
1683 }
1684 if (stack) {
1685 *stack = 0 ;
1686 }
1687 if (! flat && extremes) {
1688 extremes->tfont = fnt;
1689 extremes->tchar = chr;
1690 extremes->bfont = fnt;
1691 extremes->bchar = chr;
1692 extremes->height = box_height(result);
1693 extremes->depth = box_depth(result);
1694 }
1695 }
1696 } else {
1697
1698 result = tex_new_null_box_node(hlist_node, flat ? math_h_delimiter_list : math_v_delimiter_list);
1699 tex_attach_attribute_list_attribute(result, att);
1700
1701 if (! flat) {
1702 tex_aux_fake_delimiter(result);
1703 }
1704 if (delta) {
1705 *delta = 0;
1706 }
1707 if (stack) {
1708 *stack = 0 ;
1709 }
1710 }
1711 if (do_parts) {
1712 if (target && (has_noad_option_phantom(target) || has_noad_option_void(target))) {
1713 result = tex_aux_make_list_phantom(result, has_noad_option_void(target), att);
1714 } else {
1715 result = register_extensible(fnt, chr, size, result, att);
1716 }
1717 }
1718 if (! flat) {
1719
1733 switch (shift) {
1734 case 0:
1735 box_shift_amount(result) = tex_half_scaled(box_height(result) - box_depth(result));
1736 break;
1737 case 1:
1738 box_shift_amount(result) = tex_half_scaled(box_height(result) - box_depth(result));
1739 box_shift_amount(result) -= tex_aux_math_axis(size);
1740 break;
1741 case 2:
1742 box_shift_amount(result) = move;
1743 break;
1744 }
1745 if (do_parts && extremes && extremes->height) {
1746 extremes->height -= box_shift_amount(result);
1747 extremes->depth += box_shift_amount(result);
1748 }
1749 }
1750
1751 delete_attribute_reference(att);
1752 if ((node_type(result) == hlist_node || node_type(result) == vlist_node) && node_subtype(result) == unknown_list) {
1753 node_subtype(result) = flat ? math_h_delimiter_list : math_v_delimiter_list;
1754 }
1755 return result;
1756}
1757
1758
1771
1772static halfword tex_aux_rebox(halfword box, scaled width, halfword size)
1773{
1774 (void) size;
1775 if (box_width(box) != width && box_list(box)) {
1776
1777 halfword head = box_list(box);
1778 quarterword subtype = node_subtype(box);
1779 halfword att = get_attribute_list(box);
1780
1781 add_attribute_reference(att);
1782 if (node_type(box) == vlist_node) {
1783 box = tex_hpack(box, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
1784 node_subtype(box) = subtype;
1785 tex_attach_attribute_list_attribute(box, att);
1786 head = box_list(box);
1787 } else if (head && node_type(head) == glyph_node && ! node_next(head)) {
1788
1793 if (tex_aux_math_engine_control(glyph_font(head), math_control_rebox_char_italic_kern)) {
1794 scaled boxwidth = box_width(box);
1795 scaled chrwidth = tex_char_width_from_glyph(head);
1796 if (boxwidth != chrwidth) {
1797
1801 halfword kern = tex_new_kern_node(boxwidth - chrwidth, italic_kern_subtype);
1802 tex_attach_attribute_list_attribute(kern, att);
1803 tex_couple_nodes(head, kern);
1804 }
1805 }
1806 }
1807 box_list(box) = null;
1808 tex_flush_node(box);
1809 {
1810 halfword right = tex_new_glue_node(fi_ss_glue, user_skip_glue);
1811 halfword left = tex_new_glue_node(fi_ss_glue, user_skip_glue);
1812 tex_add_glue_option(left, glue_option_no_auto_break);
1813 tex_add_glue_option(right, glue_option_no_auto_break);
1814 tex_attach_attribute_list_attribute(left, att);
1815 tex_attach_attribute_list_attribute(right, att);
1816 tex_couple_nodes(left, head);
1817 tex_couple_nodes(tex_tail_of_node_list(head), right);
1818 box = tex_hpack(left, width, packing_exactly, direction_unknown, holding_none_option, box_limit_none);
1819 tex_attach_attribute_list_attribute(box, att);
1820 node_subtype(box) = subtype;
1821 }
1822
1823 delete_attribute_reference(att);
1824 } else {
1825 box_width(box) = width;
1826 }
1827 return box;
1828}
1829
1830
1836
1837inline static scaled tex_aux_mu_mult(scaled a, scaled n, scaled f)
1838{
1839 return tex_multiply_and_add(n, a, tex_xn_over_d(a, f, unity), max_dimension);
1840}
1841
1842inline static void tex_aux_calculate_glue(scaled m, scaled *f, scaled *n)
1843{
1844
1845 *f = 0;
1846
1847 *n = tex_x_over_n_r(m, unity, f);
1848
1849 if (*f < 0) {
1850 --n;
1851 f += unity;
1852 }
1853}
1854
1855static halfword tex_aux_math_muglue(halfword g, quarterword subtype, scaled m, halfword detail, int style)
1856{
1857 scaled f, n;
1858 halfword glue = tex_new_node(glue_node, subtype);
1859 tex_aux_calculate_glue(m, &f, &n);
1860
1861 glue_amount(glue) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_amount(g), style), n, f);
1862 if (math_glue_stretch_enabled) {
1863 scaled stretch = tex_aux_math_x_scaled(glue_stretch(g), style);
1864 glue_stretch_order(glue) = glue_stretch_order(g);
1865 glue_stretch(glue) = (glue_stretch_order(glue) == normal_glue_order) ? tex_aux_mu_mult(stretch, n, f) : stretch;
1866 }
1867 if (math_glue_shrink_enabled) {
1868 scaled shrink = tex_aux_math_x_scaled(glue_shrink(g), style);
1869 glue_shrink_order(glue) = glue_shrink_order(g);
1870 glue_shrink(glue) = (glue_shrink_order(glue) == normal_glue_order) ? tex_aux_mu_mult(shrink, n, f) : shrink;
1871 }
1872 if (math_glue_limit_enabled) {
1873 tex_add_glue_option(glue, glue_option_limit);
1874 }
1875 glue_font(glue) = detail;
1876 tex_add_glue_option(glue, glue_option_no_auto_break);
1877 return glue;
1878}
1879
1880static halfword tex_aux_math_glue(halfword g, quarterword subtype, halfword detail)
1881{
1882 halfword glue = tex_new_glue_node(g, subtype);
1883 if (! math_glue_stretch_enabled) {
1884 glue_stretch_order(glue) = normal_glue_order;
1885 glue_stretch(glue) = 0;
1886 }
1887 if (! math_glue_shrink_enabled) {
1888 glue_shrink_order(glue) = normal_glue_order;
1889 glue_shrink(glue) = 0;
1890 }
1891 if (math_glue_limit_enabled) {
1892 tex_add_glue_option(glue, glue_option_limit);
1893 }
1894 glue_font(glue) = detail;
1895 tex_add_glue_option(glue, glue_option_no_auto_break);
1896 return glue;
1897}
1898
1899static halfword tex_aux_math_dimension(halfword g, quarterword subtype, halfword detail)
1900{
1901 halfword glue = tex_new_glue_node(null, subtype);
1902 glue_amount(glue) = g;
1903 glue_font(glue) = detail;
1904 tex_add_glue_option(glue, glue_option_no_auto_break);
1905 if (math_glue_limit_enabled) {
1906 tex_add_glue_option(glue, glue_option_limit);
1907 }
1908 return glue;
1909}
1910
1911static void tex_aux_math_glue_to_glue(halfword p, scaled m, int style)
1912{
1913 scaled f, n;
1914 tex_aux_calculate_glue(m, &f, &n);
1915
1916 glue_amount(p) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_amount(p), style), n, f);
1917 if (! math_glue_stretch_enabled) {
1918 glue_stretch_order(p) = normal_glue_order;
1919 glue_stretch(p) = 0;
1920 } else if (glue_stretch_order(p) == normal_glue_order) {
1921 glue_stretch(p) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_stretch(p), style), n, f);
1922 }
1923 if (! math_glue_shrink_enabled) {
1924 glue_shrink_order(p) = normal_glue_order;
1925 glue_shrink(p) = 0;
1926 } else if (glue_shrink_order(p) == normal_glue_order) {
1927 glue_shrink(p) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_shrink(p), style), n, f);
1928 }
1929 if (math_glue_limit_enabled) {
1930 tex_add_glue_option(p, glue_option_limit);
1931 }
1932
1933 node_subtype(p) = inter_math_skip_glue;
1934 tex_add_glue_option(p, glue_option_no_auto_break);
1935}
1936
1937
1943
1944static void tex_aux_make_kern(halfword current, scaled mu, int style)
1945{
1946 if (node_subtype(current) == explicit_math_kern_subtype) {
1947 scaled f, n;
1948 tex_aux_calculate_glue(mu, &f, &n);
1949 kern_amount(current) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_amount(current), style), n, f);
1950 node_subtype(current) = explicit_kern_subtype;
1951 }
1952}
1953
1954
1964
1965static void tex_aux_make_glue(halfword current, scaled mu, int style)
1966{
1967 switch (node_subtype(current)) {
1968 case mu_glue:
1969 tex_aux_math_glue_to_glue(current, mu, style);
1970 break;
1971 case conditional_math_glue:
1972 if (lmt_math_state.size != text_size) {
1973 halfword p = node_next(current);
1974 if (p) {
1975 switch (node_type(p)) {
1976 case glue_node:
1977 case kern_node:
1978 if (node_next(p)) {
1979 tex_couple_nodes(current, node_next(p));
1980 node_next(p) = null;
1981 } else {
1982 node_next(current) = null;
1983 }
1984 tex_flush_node_list(p);
1985 break;
1986 }
1987 }
1988 }
1989 break;
1990 case rulebased_math_glue:
1991 break;
1992 }
1993}
1994
1995
2002
2003inline static int tex_aux_is_math_penalty(halfword n)
2004{
2005 return node_type(n) == penalty_node && (node_subtype(n) == math_pre_penalty_subtype || node_subtype(n) == math_post_penalty_subtype);
2006}
2007
2008void tex_run_mlist_to_hlist(halfword mlist, halfword penalties, halfword style, int beginclass, int endclass)
2009{
2010 if (mlist) {
2011 int saved_level = lmt_math_state.level;
2012 int callback_id = lmt_callback_defined(mlist_to_hlist_callback);
2013 lmt_math_state.level = 0;
2014 if (! valid_math_class_code(beginclass)) {
2015 beginclass = unset_noad_class;
2016 }
2017 if (! valid_math_class_code(endclass)) {
2018 endclass = unset_noad_class;
2019 }
2020 math_begin_class_par = unset_noad_class;
2021 math_end_class_par = unset_noad_class;
2022
2023 if (tracing_math_par >= 1) {
2024 tex_begin_diagnostic();
2025 switch (style) {
2026 case display_style:
2027 tex_print_str("> \\displaymath=");
2028 break;
2029 case text_style:
2030 tex_print_str("> \\inlinemath=");
2031 break;
2032 default:
2033 tex_print_str("> \\math=");
2034 break;
2035 }
2036 tex_show_box(mlist);
2037 tex_end_diagnostic();
2038 }
2039 tex_finalize_math_parameters();
2040 if (callback_id > 0) {
2041 lua_State *L = lmt_lua_state.lua_instance;
2042 int top = 0;
2043 if (lmt_callback_okay(L, callback_id, &top)) {
2044 int i;
2045 node_prev(mlist) = null ;
2046 lmt_node_list_to_lua(L, mlist);
2047 lmt_push_math_style_name(L, style);
2048 lua_pushboolean(L, penalties);
2049 lua_pushinteger(L, beginclass);
2050 lua_pushinteger(L, endclass);
2051 lua_pushinteger(L, lmt_math_state.level);
2052 i = lmt_callback_call(L, 6, 1, top);
2053 if (i) {
2054 lmt_callback_error(L, top, i);
2055 node_next(temp_head) = null;
2056 } else {
2057 halfword a = lmt_node_list_from_lua(L, -1);
2058
2059 node_next(temp_head) = a;
2060 lmt_callback_wrapup(L, top);
2061 }
2062 } else {
2063 node_next(temp_head) = null;
2064 }
2065 } else if (callback_id == 0) {
2066 node_next(temp_head) = tex_mlist_to_hlist(mlist, penalties, style, beginclass, endclass, NULL);
2067 } else {
2068 node_next(temp_head) = null;
2069 }
2070 if (penalties) {
2071
2072 switch (style) {
2073 case text_style:
2074 case cramped_text_style:
2075 if (math_forward_penalties_par) {
2076 halfword n = tex_get_specification_count(math_forward_penalties_par);
2077 if (n > 0) {
2078 halfword h = node_next(temp_head);
2079 halfword i = 1;
2080 while (h && i <= n) {
2081 if (tex_aux_is_math_penalty(h)) {
2082 penalty_amount(h) += tex_get_specification_penalty(math_forward_penalties_par, i++);
2083 tex_add_penalty_option(h, penalty_option_math_forward);
2084 }
2085 h = node_next(h);
2086 }
2087 }
2088 }
2089 if (math_backward_penalties_par) {
2090 halfword n = tex_get_specification_count(math_backward_penalties_par);
2091 if (n > 0) {
2092 halfword t = tex_tail_of_node_list(node_next(temp_head));
2093 halfword i = 1;
2094 while (t && i <= n) {
2095 if (tex_aux_is_math_penalty(t)) {
2096 penalty_amount(t) += tex_get_specification_penalty(math_backward_penalties_par, i++);
2097 tex_add_penalty_option(t, penalty_option_math_backward);
2098 }
2099 t = node_prev(t);
2100 }
2101 }
2102 }
2103 break;
2104 }
2105 if (node_next(temp_head) && ! tex_glue_is_zero(math_threshold_par)) {
2106 scaledwhd siz = tex_natural_hsizes(node_next(temp_head), null, 0.0, 0, 0);
2107 if (siz.wd < glue_amount(math_threshold_par)) {
2108 halfword box = tex_new_node(hlist_node, unknown_list);
2109 tex_attach_attribute_list_copy(box, node_next(temp_head));
2110 box_width(box) = siz.wd;
2111 box_height(box) = siz.ht;
2112 box_depth(box) = siz.dp;
2113 box_list(box) = node_next(temp_head);
2114 node_next(temp_head) = box;
2115 if (glue_stretch(math_threshold_par) || glue_shrink(math_threshold_par)) {
2116 halfword glue = tex_new_glue_node(math_threshold_par, u_leaders);
2117 tex_add_glue_option(glue, glue_option_no_auto_break);
2118 tex_attach_attribute_list_copy(glue, box);
2119 glue_amount(glue) = siz.wd;
2120 glue_leader_ptr(glue) = box;
2121
2122 node_next(temp_head) = glue;
2123 } else {
2124 node_next(temp_head) = box;
2125 }
2126 if (tracing_math_par >= 2) {
2127 tex_begin_diagnostic();
2128 tex_print_format("[math: boxing inline, threshold %p, width %p, height %p, depth %p]",
2129 glue_amount(math_threshold_par),
2130 siz.wd, siz.ht, siz.dp
2131 );
2132 tex_end_diagnostic();
2133 }
2134 }
2135 }
2136
2139 {
2140 halfword current = temp_head;
2141 while (current) {
2142
2143 if (node_type(current) == glyph_node && tex_has_glyph_option(current, glyph_option_math_discretionary)) {
2144 if (tracing_math_par >= 2) {
2145 tex_begin_diagnostic();
2146 tex_print_format("[math: promoting glyph with character %U to discretionary]", glyph_character(current));
2147 tex_end_diagnostic();
2148 }
2149 current = tex_glyph_to_discretionary(current, mathematics_discretionary_code, tex_has_glyph_option(current, glyph_option_math_italics_too));
2150 }
2151 current = node_next(current);
2152 }
2153 }
2154 }
2155 lmt_math_state.level = saved_level;
2156 } else {
2157 node_next(temp_head) = null;
2158 }
2159}
2160
2161
2170
2171inline static void tex_aux_remove_italic_after_first_glyph(halfword box)
2172{
2173 halfword list = box_list(box);
2174 if (list && node_type(list) == glyph_node) {
2175 halfword next = node_next(list);
2176
2177 if (next && ! node_next(next) && node_type(next) == kern_node && node_subtype(next) == italic_kern_subtype) {
2178
2179 box_width(box) -= kern_amount(next);
2180 tex_flush_node(next);
2181 node_next(list) = null;
2182 }
2183 }
2184}
2185
2186static halfword tex_aux_clean_box(halfword n, int main_style, int style, quarterword subtype, int keepitalic, kernset *kerns)
2187{
2188
2189 halfword list;
2190
2191 halfword result;
2192
2193 halfword mlist = null;
2194 switch (node_type(n)) {
2195 case math_char_node:
2196 mlist = tex_new_node(simple_noad, ordinary_noad_subtype);
2197 noad_nucleus(mlist) = tex_aux_math_clone(n);
2198 tex_attach_attribute_list_copy(mlist, n);
2199 break;
2200 case sub_box_node:
2201 list = kernel_math_list(n);
2202 goto FOUND;
2203 case sub_mlist_node:
2204 mlist = kernel_math_list(n);
2205 break;
2206 default:
2207 list = tex_new_null_box_node(hlist_node, math_list_list);
2208 tex_attach_attribute_list_copy(list, n);
2209 goto FOUND;
2210 }
2211
2212 list = tex_mlist_to_hlist(mlist, 0, main_style, unset_noad_class, unset_noad_class, kerns);
2213
2214 tex_aux_set_current_math_size(style);
2215 FOUND:
2216 if (kerns && list) {
2217 halfword tail = tex_tail_of_node_list(list);
2218 if (node_type(list) == glyph_node) {
2219 halfword fnt = glyph_font(list);
2220 halfword chr = glyph_character(list);
2221 kerns->topleft = tex_aux_math_x_size_scaled(fnt, tex_char_top_left_kern_from_font(fnt, chr), main_style);
2222 kerns->bottomleft = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_left_kern_from_font(fnt, chr), main_style);
2223 }
2224 if (node_type(tail) == glyph_node) {
2225 halfword fnt = glyph_font(tail);
2226 halfword chr = glyph_character(tail);
2227 kerns->topright = tex_aux_math_x_size_scaled(fnt, tex_char_top_right_kern_from_font(fnt, chr), main_style);
2228 kerns->bottomright = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_right_kern_from_font(fnt, chr), main_style);
2229 }
2230 }
2231 if (! list || node_type(list) == glyph_node) {
2232 result = tex_hpack(list, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2233 tex_attach_attribute_list_copy(result, list);
2234 } else if (! node_next(list) && (node_type(list) == hlist_node || node_type(list) == vlist_node) && (box_shift_amount(list) == 0)) {
2235
2236 result = list;
2237 } else {
2238 result = tex_hpack(list, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2239 tex_attach_attribute_list_copy(result, list);
2240 }
2241 node_subtype(result) = subtype;
2242 if (! keepitalic) {
2243 tex_aux_remove_italic_after_first_glyph(result);
2244 }
2245 return result;
2246}
2247
2248
2261
2262static int tex_aux_fetch(halfword n, const char *where, halfword *f, halfword *c)
2263{
2264 if (node_type(n) == glyph_node) {
2265 *f = glyph_font(n);
2266 *c = glyph_character(n);
2267 if (tex_char_exists(*f, *c)) {
2268 return 1;
2269 } else {
2270 tex_char_warning(*f, *c);
2271 return 0;
2272 }
2273 } else {
2274 *f = tex_fam_fnt(kernel_math_family(n), lmt_math_state.size);
2275 *c = kernel_math_character(n);
2276 if (math_kernel_node_has_option(n, math_kernel_ignored_character)) {
2277 return 1;
2278 } else if (*f == null_font) {
2279 tex_handle_error(
2280 normal_error_type,
2281 "\\%s%i is undefined in %s, font id %i, character %i)",
2282 tex_aux_math_size_string(lmt_math_state.size), kernel_math_family(n), where, *f, *c,
2283 "Somewhere in the math formula just ended, you used the stated character from an\n"
2284 "undefined font family. For example, plain TeX doesn't allow \\it or \\sl in\n"
2285 "subscripts. Proceed, and I'll try to forget that I needed that character."
2286 );
2287 return 0;
2288 } else if (tex_math_char_exists(*f, *c, lmt_math_state.size)) {
2289 return 1;
2290 } else {
2291 tex_char_warning(*f, *c);
2292 return 0;
2293 }
2294 }
2295}
2296
2297
2312
2313static void tex_aux_assign_new_hlist(halfword target, halfword hlist)
2314{
2315 switch (node_type(target)) {
2316 case fraction_noad:
2317 kernel_math_list(fraction_numerator(target)) = null;
2318 kernel_math_list(fraction_denominator(target)) = null;
2319 tex_flush_node(fraction_numerator(target));
2320 tex_flush_node(fraction_denominator(target));
2321 fraction_numerator(target) = null;
2322 fraction_denominator(target) = null;
2323 break;
2324 case radical_noad:
2325 case simple_noad:
2326 case accent_noad:
2327 if (noad_nucleus(target)) {
2328 kernel_math_list(noad_nucleus(target)) = null;
2329 tex_flush_node(noad_nucleus(target));
2330 noad_nucleus(target) = null;
2331 }
2332 break;
2333 }
2334 noad_new_hlist(target) = hlist;
2335}
2336
2337
2344
2345static void tex_aux_make_over(halfword target, halfword style, halfword size, halfword fam)
2346{
2347
2353 scaled thickness = tex_get_math_y_parameter_checked(style, math_parameter_overbar_rule);
2354 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_overbar_vgap);
2355 scaled kern = tex_get_math_y_parameter_checked(style, math_parameter_overbar_kern);
2356 {
2357 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_over_rule, OverbarRuleThickness);
2358 if (t != undefined_math_parameter) {
2359 thickness = t;
2360 }
2361 }
2362 {
2363 halfword result = tex_aux_overbar(
2364 tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_over_line_variant), style, math_nucleus_list, 0, NULL),
2365 vgap, thickness, kern,
2366 get_attribute_list(noad_nucleus(target)), math_over_rule_subtype, size, fam,
2367 null, style
2368 );
2369 node_subtype(result) = math_over_list;
2370 kernel_math_list(noad_nucleus(target)) = result;
2371 node_type(noad_nucleus(target)) = sub_box_node;
2372 }
2373}
2374
2375static void tex_aux_make_under(halfword target, halfword style, halfword size, halfword fam)
2376{
2377
2384 scaled thickness = tex_get_math_y_parameter_checked(style, math_parameter_underbar_rule);
2385 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_underbar_vgap);
2386 scaled kern = tex_get_math_y_parameter_checked(style, math_parameter_underbar_kern);
2387 {
2388 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_under_rule, UnderbarRuleThickness);
2389 if (t != undefined_math_parameter) {
2390 thickness = t;
2391 }
2392 }
2393 {
2394 halfword result = tex_aux_underbar(
2395 tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_under_line_variant), style, math_nucleus_list, 0, NULL),
2396 vgap, thickness, kern,
2397 get_attribute_list(noad_nucleus(target)), math_under_rule_subtype, size, fam,
2398 null, style
2399 );
2400 node_subtype(result) = math_over_list;
2401 kernel_math_list(noad_nucleus(target)) = result;
2402 node_type(noad_nucleus(target)) = sub_box_node;
2403 }
2404}
2405
2406
2412
2413static void tex_aux_make_vcenter(halfword target, halfword style, halfword size)
2414{
2415 halfword box = kernel_math_list(noad_nucleus(target));
2416 if (node_type(box) != vlist_node) {
2417 box = tex_aux_clean_box(noad_nucleus(target), style, style, math_list_list, 0, NULL);
2418 kernel_math_list(noad_nucleus(target)) = box;
2419 node_type(noad_nucleus(target)) = sub_box_node;
2420 }
2421 {
2422 scaled total = box_total(box);
2423 scaled axis = has_box_axis(box, no_math_axis) ? 0 : tex_aux_math_axis(size);
2424 box_height(box) = axis + tex_half_scaled(total);
2425 box_depth(box) = total - box_height(box);
2426 }
2427}
2428
2429
2439
2440static void tex_aux_make_hextension(halfword target, int style, int size)
2441{
2442 int stack = 0;
2443 scaled radicalwidth = tex_aux_math_given_x_scaled(noad_width(target));
2444 halfword extensible = radical_left_delimiter(target);
2445 halfword delimiter = tex_aux_make_delimiter(target, extensible, size, radicalwidth, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, null);
2446 halfword delimiterwidth = box_width(delimiter);
2447 if (! stack && radicalwidth && (radicalwidth != delimiterwidth)) {
2448 if (has_noad_option_middle(target)) {
2449 scaled delta = tex_half_scaled(radicalwidth - delimiterwidth);
2450 if (delta) {
2451 halfword kern = tex_new_kern_node(delta, horizontal_math_kern_subtype);
2452 tex_attach_attribute_list_copy(kern, target);
2453 tex_couple_nodes(kern, delimiter);
2454 delimiter = kern;
2455 }
2456 delimiterwidth = radicalwidth;
2457 } else if (has_noad_option_exact(target)) {
2458 delimiterwidth = radicalwidth;
2459 }
2460 }
2461 delimiter = tex_hpack(delimiter, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2462 box_width(delimiter) = delimiterwidth;
2463 tex_attach_attribute_list_copy(delimiter, target);
2464 kernel_math_list(noad_nucleus(target)) = delimiter;
2465 radical_left_delimiter(target) = null;
2466 radical_right_delimiter(target) = null;
2467}
2468
2469static void tex_aux_preroll_root_radical(halfword target, int style, int size)
2470{
2471 (void) size;
2472 noad_new_hlist(target) = tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_radical_variant), style, math_nucleus_list, 0, NULL);
2473}
2474
2475static halfword tex_aux_link_radical(halfword nucleus, halfword delimiter, halfword companion, halfword rightdelimiter)
2476{
2477 if (companion) {
2478 tex_couple_nodes(delimiter, nucleus);
2479 tex_couple_nodes(nucleus, companion);
2480 return delimiter;
2481 } else if (rightdelimiter) {
2482 tex_couple_nodes(nucleus, delimiter);
2483 return nucleus;
2484 } else {
2485 tex_couple_nodes(delimiter, nucleus);
2486 return delimiter;
2487 }
2488}
2489
2490static void tex_aux_assign_radical(halfword target, halfword radical)
2491{
2492 halfword result = tex_hpack(radical, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2493 node_subtype(result) = math_radical_list;
2494 tex_attach_attribute_list_copy(result, target);
2495 kernel_math_list(noad_nucleus(target)) = result;
2496 node_type(noad_nucleus(target)) = sub_box_node;
2497 radical_left_delimiter(target) = null;
2498 radical_right_delimiter(target) = null;
2499}
2500
2501static void tex_aux_set_radical_kerns(delimiterextremes *extremes, kernset *kerns, halfword size)
2502{
2503 if (kerns && extremes->tfont) {
2504 if (tex_math_has_class_option(radical_noad_subtype, carry_over_left_top_kern_class_option)) {
2505 kerns->topleft = tex_aux_math_x_size_scaled(extremes->tfont, tex_char_top_left_kern_from_font(extremes->tfont, extremes->tchar), size);
2506 }
2507 if (tex_math_has_class_option(radical_noad_subtype, carry_over_left_bottom_kern_class_option)) {
2508 kerns->bottomleft = tex_aux_math_x_size_scaled(extremes->bfont, tex_char_bottom_left_kern_from_font(extremes->bfont, extremes->bchar), size);
2509 }
2510 if (tex_math_has_class_option(radical_noad_subtype, carry_over_right_top_kern_class_option)) {
2511 kerns->topright = tex_aux_math_x_size_scaled(extremes->tfont, tex_char_top_right_kern_from_font(extremes->tfont, extremes->tchar), size);
2512 }
2513 if (tex_math_has_class_option(radical_noad_subtype, carry_over_right_bottom_kern_class_option)) {
2514 kerns->bottomright = tex_aux_math_x_size_scaled(extremes->bfont, tex_char_bottom_right_kern_from_font(extremes->bfont, extremes->bchar), size);
2515 }
2516 if (tex_math_has_class_option(radical_noad_subtype, prefer_delimiter_dimensions_class_option)) {
2517 kerns->height = extremes->height;
2518 kerns->depth = extremes->depth;
2519 kerns->dimensions = 1;
2520 kerns->font = extremes->tfont;
2521 }
2522 }
2523}
2524
2525static void tex_aux_make_root_radical(halfword target, int style, int size, kernset *kerns)
2526{
2527 halfword nucleus = noad_new_hlist(target);
2528 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_radical_vgap);
2529 scaled theta = tex_get_math_y_parameter(style, math_parameter_radical_rule);
2530 scaled kern = tex_get_math_y_parameter_checked(style, math_parameter_radical_kern);
2531 scaled fam = delimiter_small_family(radical_left_delimiter(target));
2532 halfword leftdelimiter = radical_left_delimiter(target);
2533 halfword rightdelimiter = radical_right_delimiter(target);
2534 halfword topdelimiter = radical_top_delimiter(target);
2535 halfword delimiter = leftdelimiter ? leftdelimiter : rightdelimiter;
2536 halfword companion = leftdelimiter ? rightdelimiter : null;
2537 halfword radical = null;
2538 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
2539 scaled innerx = INT_MIN;
2540 scaled innery = INT_MIN;
2541 int norule = has_noad_option_norule(target);
2542 noad_new_hlist(target) = null;
2543
2547 {
2548 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_radical_rule, RadicalRuleThickness);
2549 if (t != undefined_math_parameter) {
2550 theta = t;
2551 }
2552 }
2553 {
2554 halfword weird = theta == undefined_math_parameter;
2555 if (weird) {
2556
2557 theta = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
2558 }
2559 delimiter = tex_aux_make_delimiter(target, delimiter, size, box_total(nucleus) + clearance + theta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, 0, null);
2560 if (extremes.bfont) {
2561 scaled margin = tex_char_left_margin_from_font(extremes.bfont, extremes.bchar);
2562 if (margin && margin != INT_MIN) {
2563 tex_aux_prepend_hkern_to_box_list(nucleus, tex_aux_math_y_size_scaled(extremes.bfont, margin, size), horizontal_math_kern_subtype, "bad radical body");
2564 }
2565 }
2566 if (radical_degree(target)) {
2567 halfword innerf = 0;
2568 halfword innerc = 0;
2569 if (tex_char_has_tag_from_font(extremes.bfont, extremes.bchar, inner_left_tag)) {
2570 innerf = extremes.bfont;
2571 innerc = extremes.bchar;
2572 } else if (tex_char_has_tag_from_font(extremes.tfont, extremes.tchar, inner_left_tag)) {
2573 innerf = extremes.tfont;
2574 innerc = extremes.tchar;
2575 }
2576 if (innerc) {
2577 innerx = tex_char_inner_x_offset_from_font(innerf, innerc);
2578 innery = tex_char_inner_y_offset_from_font(innerf, innerc);
2579 innerx = innerx == INT_MIN ? 0 : tex_aux_math_y_size_scaled(innerf, innerx, size);
2580 innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(innerf, innery, size);
2581 }
2582 }
2583 if (companion) {
2584
2588 companion = tex_aux_make_delimiter(target, companion, size, box_total(nucleus) + clearance + theta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, 0, null);
2589 if (extremes.bfont) {
2590 scaled margin = tex_char_right_margin_from_font(extremes.bfont, extremes.bchar);
2591 if (margin && margin != INT_MIN) {
2592 tex_aux_append_hkern_to_box_list(nucleus, tex_aux_math_y_size_scaled(extremes.bfont, margin, size), horizontal_math_kern_subtype, "bad radical body");
2593 }
2594 }
2595 }
2596 if (weird) {
2597
2601 halfword list = box_list(delimiter);
2602 if (list && (node_type(list) == hlist_node)) {
2603
2604 halfword glyph = box_list(list);
2605 if (glyph && node_type(glyph) == glyph_node) {
2606
2607 theta = tex_char_height_from_glyph(glyph);
2608 } else {
2609 theta = box_height(delimiter);
2610 }
2611 } else {
2612 theta = box_height(delimiter);
2613 }
2614 }
2615 }
2616
2620 tex_aux_set_radical_kerns(&extremes, kerns, size);
2621
2628 {
2629 halfword delta = (box_total(delimiter) - theta) - (box_total(nucleus) + clearance);
2630 if (delta > 0) {
2631
2632 clearance += tex_half_scaled(delta);
2633 }
2634 if (has_noad_option_reflected(target)) {
2635 box_shift_amount(delimiter) = - ((box_depth(delimiter) - theta) - (box_depth(nucleus) + clearance));
2636 if (companion) {
2637 box_shift_amount(companion) = - ((box_depth(companion) - theta) - (box_depth(nucleus) + clearance));
2638 }
2639 } else {
2640 box_shift_amount(delimiter) = (box_height(delimiter) - theta) - (box_height(nucleus) + clearance);
2641 if (companion) {
2642 box_shift_amount(companion) = (box_height(companion) - theta) - (box_height(nucleus) + clearance);
2643 }
2644 }
2645 }
2646 if (node_type(delimiter) == vlist_node && node_subtype(delimiter) == math_v_delimiter_list) {
2647 halfword before = tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_before, 0);
2648 tex_aux_prepend_hkern_to_box_list(nucleus, before, horizontal_math_kern_subtype, "bad delimiter");
2649 }
2650 if (node_type(companion) == vlist_node && node_subtype(companion) == math_v_delimiter_list) {
2651 halfword after = tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_after, 0);
2652 tex_aux_append_hkern_to_box_list(nucleus, after, horizontal_math_kern_subtype, "bad delimiter");
2653 }
2654 {
2655
2656 halfword total = box_total(delimiter);
2657 halfword list = (has_noad_option_reflected(target) ? tex_aux_underbar : tex_aux_overbar)
2658 (nucleus,clearance,theta,kern,get_attribute_list(delimiter),math_radical_rule_subtype,size,fam,norule ? -1 : topdelimiter,style);
2659 radical = tex_aux_link_radical(list, delimiter, companion, rightdelimiter);
2660 if (radical_degree(target)) {
2661
2665 halfword degreestyle = tex_math_style_variant(noad_style(target) == yet_unset_math_style ? noad_style(target) : style, math_parameter_degree_variant);
2666
2667 halfword degree = tex_aux_clean_box(radical_degree(target), degreestyle, style, math_degree_list, 0, NULL);
2668 scaled width = box_width(degree);
2669 tex_attach_attribute_list_copy(degree, radical_degree(target));
2670 if (width) {
2671 scaled before = tex_get_math_x_parameter_checked(style, math_parameter_radical_degree_before);
2672 scaled after = tex_get_math_x_parameter_checked(style, math_parameter_radical_degree_after);
2673 scaled raise = tex_get_math_parameter_checked(style, math_parameter_radical_degree_raise);
2674 if (innerx != INT_MIN) {
2675 tex_aux_append_hkern_to_box_list(degree, innerx, horizontal_math_kern_subtype, "bad degree");
2676 width += innerx;
2677 }
2678 if (-after > width) {
2679 before += -after - width;
2680 }
2681 if (after) {
2682 halfword kern = tex_new_kern_node(after, horizontal_math_kern_subtype);
2683 tex_attach_attribute_list_copy(kern, radical_degree(target));
2684 tex_couple_nodes(kern, radical);
2685 nucleus = kern;
2686 } else {
2687 nucleus = radical;
2688 }
2689 if (innery != INT_MIN) {
2690 box_shift_amount(degree) = - innery + box_depth(radical) + box_shift_amount(radical);
2691 } else {
2692 box_shift_amount(degree) = - (tex_xn_over_d(total, raise, 100) - box_depth(radical) - box_shift_amount(radical));
2693 }
2694 tex_couple_nodes(degree, nucleus);
2695 if (before) {
2696 halfword kern = tex_new_kern_node(before, horizontal_math_kern_subtype);
2697 tex_attach_attribute_list_copy(kern, radical_degree(target));
2698 tex_couple_nodes(kern, degree);
2699 radical = kern;
2700 } else {
2701 radical = degree;
2702 }
2703 } else {
2704 tex_flush_node(degree);
2705 }
2706
2707 kernel_math_list(radical_degree(target)) = null;
2708 tex_flush_node(radical_degree(target));
2709 radical_degree(target) = null;
2710 }
2711 }
2712 tex_aux_assign_radical(target, radical);
2713}
2714
2715
2719
2720static void tex_aux_make_delimited_radical(halfword target, int style, int size, kernset *kerns)
2721{
2722 halfword nucleus = noad_new_hlist(target);
2723
2724 halfword leftdelimiter = radical_left_delimiter(target);
2725 halfword rightdelimiter = radical_right_delimiter(target);
2726 halfword delimiter = leftdelimiter ? leftdelimiter : rightdelimiter;
2727 halfword companion = leftdelimiter ? rightdelimiter : null;
2728 halfword radical = null;
2729 halfword depth = has_noad_option_exact(target) ? radical_depth(target) : (box_depth(nucleus) + radical_depth(target));
2730 halfword height = has_noad_option_exact(target) ? radical_height(target) : (box_height(nucleus) + radical_height(target));
2731 halfword total = height + depth;
2732 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
2733 noad_new_hlist(target) = null;
2734 size += radical_size(target);
2735 if (size < text_size) {
2736 size = text_size;
2737 } else if (size > script_script_size) {
2738 size = script_script_size;
2739 }
2740 delimiter = tex_aux_make_delimiter(target, delimiter, size, total, 0, style, 2, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, depth, null);
2741 if (companion) {
2742
2743 companion = tex_aux_make_delimiter(target, companion, size, total, 0, style, 2, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, depth, null);
2744 }
2745 tex_aux_set_radical_kerns(&extremes, kerns, size);
2746 radical = tex_aux_link_radical(nucleus, delimiter, companion, rightdelimiter);
2747 tex_aux_assign_radical(target, radical);
2748}
2749
2750
2751
2752static halfword tex_aux_wrapup_over_under_delimiter(halfword target, halfword x, halfword y, scaled shift_up, scaled shift_down, quarterword st)
2753{
2754 halfword box = tex_new_null_box_node(vlist_node, st);
2755 scaled delta = (shift_up - box_depth(x)) - (box_height(y) - shift_down);
2756 box_height(box) = shift_up + box_height(x);
2757 box_depth(box) = box_depth(y) + shift_down;
2758 tex_attach_attribute_list_copy(box, target);
2759 if (delta) {
2760 halfword kern = tex_new_kern_node(delta, vertical_math_kern_subtype);
2761 tex_attach_attribute_list_copy(kern, target);
2762 tex_couple_nodes(x, kern);
2763 tex_couple_nodes(kern, y);
2764 } else {
2765 tex_couple_nodes(x, y);
2766 }
2767 box_list(box) = x;
2768 return box;
2769}
2770
2771
2772
2773inline static halfword tex_aux_check_radical(halfword target, int stack, halfword r, halfword t)
2774{
2775 if (! stack && (box_width(r) >= box_width(t))) {
2776 scaled width = tex_aux_math_given_x_scaled(noad_width(target));
2777 if (width) {
2778 scaled delta = width - box_width(r);
2779 if (delta) {
2780 if (has_noad_option_left(target)) {
2781 halfword kern = tex_new_kern_node(delta, horizontal_math_kern_subtype);
2782 tex_attach_attribute_list_copy(kern, target);
2783 tex_couple_nodes(kern, r);
2784 } else if (has_noad_option_middle(target)) {
2785 halfword kern = tex_new_kern_node(tex_half_scaled(delta), horizontal_math_kern_subtype);
2786 tex_attach_attribute_list_copy(kern, target);
2787 tex_couple_nodes(kern, r);
2788 } else if (has_noad_option_right(target)) {
2789
2790 } else {
2791 return r;
2792 }
2793 r = tex_hpack(r, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2794 box_width(r) = noad_width(target);
2795 tex_attach_attribute_list_copy(r, target);
2796 }
2797 }
2798 }
2799 return r;
2800}
2801
2802inline static void tex_aux_fixup_radical_width(halfword target, halfword x, halfword y)
2803{
2804 if (box_width(y) >= box_width(x)) {
2805 if (noad_width(target)) {
2806 box_shift_amount(x) += tex_half_scaled(box_width(y) - box_width(x)) ;
2807 }
2808 box_width(x) = box_width(y);
2809 } else {
2810 if (noad_width(target)) {
2811 box_shift_amount(y) += tex_half_scaled(box_width(x) - box_width(y)) ;
2812 }
2813 box_width(y) = box_width(x);
2814 }
2815}
2816
2817inline static halfword tex_aux_get_radical_width(halfword target, halfword p)
2818{
2819 return noad_width(target) ? noad_width(target) : box_width(p);
2820}
2821
2822
2827
2828static void tex_aux_make_over_delimiter(halfword target, int style, int size)
2829{
2830 halfword result;
2831 scaled delta;
2832 int stack;
2833 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_bgap);
2834 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_vgap);
2835 halfword content = tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_over_delimiter_variant), style, math_nucleus_list, 0, NULL);
2836 scaled width = tex_aux_get_radical_width(target, content);
2837 halfword over_delimiter = fraction_left_delimiter(target);
2838 halfword delimiter = tex_aux_make_delimiter(target, over_delimiter, size, width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, null);
2839 fraction_left_delimiter(target) = null;
2840 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
2841 tex_aux_fixup_radical_width(target, content, delimiter);
2842 delta = clearance - (shift - box_depth(content) - box_height(delimiter));
2843 if (delta > 0) {
2844 shift += delta;
2845 }
2846 result = tex_aux_wrapup_over_under_delimiter(target, content, delimiter, shift, 0, math_over_delimiter_list);
2847 box_width(result) = box_width(content);
2848 kernel_math_list(noad_nucleus(target)) = result;
2849 node_type(noad_nucleus(target)) = sub_box_node;
2850}
2851
2852
2855
2856static void tex_aux_make_under_delimiter(halfword target, int style, int size)
2857{
2858 halfword result;
2859 scaled delta;
2860 int stack;
2861 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_bgap);
2862 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_vgap);
2863 halfword content = tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_under_delimiter_variant), style, math_nucleus_list, 0, NULL);
2864 scaled width = tex_aux_get_radical_width(target, content);
2865 halfword under_delimiter = fraction_left_delimiter(target);
2866 halfword delimiter = tex_aux_make_delimiter(target, under_delimiter, size, width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, null);
2867 fraction_left_delimiter(target) = null;
2868 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
2869 tex_aux_fixup_radical_width(target, delimiter, content);
2870 delta = clearance - (- box_depth(delimiter) - (box_height(content) - shift));
2871 if (delta > 0) {
2872 shift += delta;
2873 }
2874 result = tex_aux_wrapup_over_under_delimiter(target, delimiter, content, 0, shift, math_under_delimiter_list);
2875 box_width(result) = box_width(content);
2876 kernel_math_list(noad_nucleus(target)) = result;
2877 node_type(noad_nucleus(target)) = sub_box_node;
2878}
2879
2880
2883
2884static void tex_aux_make_delimiter_over(halfword target, int style, int size)
2885{
2886 halfword result;
2887 scaled actual;
2888 int stack;
2889 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_bgap);
2890 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_vgap);
2891 halfword content = tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_delimiter_over_variant), style, math_nucleus_list, 0, NULL);
2892 scaled width = tex_aux_get_radical_width(target, content);
2893 halfword over_delimiter = fraction_left_delimiter(target);
2894 halfword delimiter = tex_aux_make_delimiter(target, over_delimiter, size + (size == script_script_size ? 0 : 1), width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(over_delimiter), NULL, 0, null);
2895 fraction_left_delimiter(target) = null;
2896 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
2897 tex_aux_fixup_radical_width(target, delimiter, content);
2898 shift -= box_total(delimiter);
2899 actual = shift - box_height(content);
2900 if (actual < clearance) {
2901 shift += (clearance - actual);
2902 }
2903 result = tex_aux_wrapup_over_under_delimiter(target, delimiter, content, shift, 0, math_over_delimiter_list);
2904 box_width(result) = box_width(delimiter);
2905 kernel_math_list(noad_nucleus(target)) = result;
2906 node_type(noad_nucleus(target)) = sub_box_node;
2907}
2908
2909
2912
2913static void tex_aux_make_delimiter_under(halfword target, int style, int size)
2914{
2915 halfword result;
2916 scaled actual;
2917 int stack;
2918 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_bgap);
2919 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_vgap);
2920 halfword content = tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_delimiter_under_variant), style, math_nucleus_list, 0, NULL);
2921 scaled width = tex_aux_get_radical_width(target, content);
2922 halfword under_delimiter = fraction_left_delimiter(target);
2923 halfword delimiter = tex_aux_make_delimiter(target, under_delimiter, size + (size == script_script_size ? 0 : 1), width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(under_delimiter), NULL, 0, null);
2924 fraction_left_delimiter(target) = null;
2925 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
2926 tex_aux_fixup_radical_width(target, content, delimiter);
2927 shift -= box_total(delimiter);
2928 actual = shift - box_depth(content);
2929 if (actual < clearance) {
2930 shift += (clearance - actual);
2931 }
2932 result = tex_aux_wrapup_over_under_delimiter(target, content, delimiter, 0, shift, math_under_delimiter_list);
2933
2934 box_width(result) = box_width(delimiter);
2935 kernel_math_list(noad_nucleus(target)) = result;
2936 node_type(noad_nucleus(target)) = sub_box_node;
2937}
2938
2939static void tex_aux_make_radical(halfword target, int style, int size, kernset *kerns)
2940{
2941 switch (node_subtype(target)) {
2942 case under_delimiter_radical_subtype:
2943 tex_aux_make_under_delimiter(target, style, size);
2944 break;
2945 case over_delimiter_radical_subtype:
2946 tex_aux_make_over_delimiter(target, style, size);
2947 break;
2948 case delimiter_under_radical_subtype:
2949 tex_aux_make_delimiter_under(target, style, size);
2950 break;
2951 case delimiter_over_radical_subtype:
2952 tex_aux_make_delimiter_over(target, style, size);
2953 break;
2954 case delimited_radical_subtype:
2955 tex_aux_make_delimited_radical(target, style, size, kerns);
2956 break;
2957 case h_extensible_radical_subtype:
2958 tex_aux_make_hextension(target, style, size);
2959 break;
2960 default:
2961 tex_aux_make_root_radical(target, style, size, kerns);
2962 break;
2963 }
2964 if (noad_source(target)) {
2965 halfword result = kernel_math_list(noad_nucleus(target));
2966 if (result) {
2967 box_source_anchor(result) = noad_source(target);
2968 tex_set_box_geometry(result, anchor_geometry);
2969 }
2970 }
2971}
2972
2973static void tex_aux_preroll_radical(halfword target, int style, int size)
2974{
2975 switch (node_subtype(target)) {
2976 case under_delimiter_radical_subtype:
2977 case over_delimiter_radical_subtype:
2978 case delimiter_under_radical_subtype:
2979 case delimiter_over_radical_subtype:
2980 case h_extensible_radical_subtype:
2981 break;
2982 default:
2983 tex_aux_preroll_root_radical(target, style, size);
2984 break;
2985 }
2986}
2987
2988
2994
2995typedef enum math_accent_location_codes {
2996 top_accent_code = 1,
2997 bot_accent_code = 2,
2998 overlay_accent_code = 4,
2999 stretch_accent_code = 8,
3000} math_accent_location_codes;
3001
3002static int tex_aux_compute_accent_skew(halfword target, int flags, scaled *skew, halfword size)
3003{
3004
3005 int absolute = 0;
3006 switch (node_type(noad_nucleus(target))) {
3007 case math_char_node:
3008 {
3009 halfword chr = null;
3010 halfword fnt = null;
3011 tex_aux_fetch(noad_nucleus(target), "accent", &fnt, &chr);
3012
3013 chr = tex_get_math_char(fnt, chr, size, NULL, 0);
3014 if (tex_aux_math_engine_control(fnt, math_control_accent_skew_apply)) {
3015
3019 if (flags & bot_accent_code) {
3020 *skew = tex_char_unchecked_bottom_anchor_from_font(fnt, chr);
3021 } else {
3022 *skew = tex_char_unchecked_top_anchor_from_font(fnt, chr);
3023 }
3024 if (*skew != INT_MIN) {
3025 *skew = tex_aux_math_x_size_scaled(fnt, *skew, size);
3026 absolute = 1;
3027 } else {
3028 *skew = 0;
3029 }
3030 } else if (flags & top_accent_code) {
3031 *skew = tex_aux_math_x_size_scaled(fnt, tex_get_kern(fnt, chr, font_skew_char(fnt)), size);
3032 } else {
3033 *skew = 0;
3034 }
3035 if (tracing_math_par >= 2) {
3036 tex_begin_diagnostic();
3037 tex_print_format("[math: accent skew, font %i, chr %x, skew %p, absolute %i]", fnt, chr, *skew, absolute);
3038 tex_end_diagnostic();
3039 }
3040 break;
3041 }
3042 case sub_mlist_node:
3043 {
3044
3070 halfword p = kernel_math_list(noad_nucleus(target));
3071 if (p && (! node_next(p))) {
3072 switch (node_type(p)) {
3073 case accent_noad:
3074 absolute = tex_aux_compute_accent_skew(p, flags, skew, size);
3075 break;
3076 case simple_noad:
3077 if (! noad_has_following_scripts(p)) {
3078 absolute = tex_aux_compute_accent_skew(p, flags, skew, size);
3079 }
3080 break;
3081 }
3082 }
3083 if (tracing_math_par >= 2) {
3084 tex_begin_diagnostic();
3085 tex_print_format("[math: accent skew, absolute %i]", absolute);
3086 tex_end_diagnostic();
3087 }
3088 break;
3089 }
3090 }
3091 return absolute;
3092}
3093
3094static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, halfword accentchr, int flags, int style, int size, scaled *accenttotal, scaled *leftkern, scaled *rightkern)
3095{
3096
3097 scaled baseheight = 0;
3098
3099 scaled basewidth = 0;
3100 scaled usedwidth = 0;
3101
3102 scaled delta = 0;
3103 scaled overshoot = 0;
3104 extinfo *extended = NULL;
3105 halfword attrlist = node_attr(target);
3106 scaled fraction = accent_fraction(target) > 0 ? accent_fraction(target) : scaling_factor;
3107 scaled skew = 0;
3108 scaled offset = 0;
3109 scaled innery = 0;
3110 halfword accent = null;
3111 halfword base = null;
3112 halfword result = null;
3113 halfword nucleus = noad_nucleus(target);
3114 halfword stretch = (flags & stretch_accent_code) == stretch_accent_code;
3115 halfword basefnt = null_font;
3116 halfword basechr = 0;
3117 halfword accentbasefnt = accentfnt;
3118 halfword accentbasechr = accentchr;
3119 int found = 0;
3120 int isscaled = 0;
3121 int keep = 0;
3122
3127 int absolute = tex_aux_compute_accent_skew(target, flags, &skew, size);
3128 {
3129
3130 halfword usedstyle;
3131 kernset localkerns;
3132 if (flags & top_accent_code) {
3133 usedstyle = tex_math_style_variant(style, math_parameter_top_accent_variant);
3134 } else if (flags & bot_accent_code) {
3135 usedstyle = tex_math_style_variant(style, math_parameter_bottom_accent_variant);
3136 } else {
3137 usedstyle = tex_math_style_variant(style, math_parameter_overlay_accent_variant);
3138 }
3139 tex_math_wipe_kerns(&localkerns);
3140
3141 base = tex_aux_clean_box(noad_nucleus(target), usedstyle, style, math_nucleus_list, 1, &localkerns);
3142 if (flags & top_accent_code) {
3143 if (leftkern) {
3144 *leftkern = localkerns.bottomleft;
3145 }
3146 if (rightkern) {
3147 *rightkern = localkerns.bottomright;
3148 }
3149 } else if (flags & bot_accent_code) {
3150 if (leftkern) {
3151 *leftkern = localkerns.topleft;
3152 }
3153 if (rightkern) {
3154 *rightkern = localkerns.topright;
3155 }
3156 }
3157 basewidth = box_width(base);
3158 baseheight = box_height(base);
3159
3160 }
3161 if (base) {
3162
3163 halfword list = box_list(base);
3164 if (list && node_type(list) == glyph_node) {
3165
3166 basefnt = glyph_font(list);
3167 basechr = glyph_character(list);
3168 }
3169 }
3170 if (stretch && absolute && (flags & top_accent_code) && tex_aux_math_engine_control(accentfnt, math_control_accent_top_skew_with_offset)) {
3171
3180 if (base && basefnt && basechr) {
3181 offset = tex_char_top_overshoot_from_font(basefnt, basechr);
3182 offset = offset == INT_MIN ? 0 : tex_aux_math_x_size_scaled(basefnt, offset, size);
3183 }
3184 usedwidth = 2 * ((skew < (basewidth - skew) ? skew : (basewidth - skew)) + offset);
3185 } else if (! absolute && tex_aux_math_engine_control(accentfnt, math_control_accent_skew_half)) {
3186 skew = tex_half_scaled(basewidth);
3187 absolute = 1;
3188 usedwidth = basewidth;
3189 } else {
3190 usedwidth = basewidth;
3191 }
3192
3196 if (stretch && (tex_char_width_from_font(accentfnt, accentchr) < usedwidth)) {
3197
3198 scaled target = 0;
3199 if (flags & overlay_accent_code) {
3200 target = baseheight;
3201 } else {
3202 target += usedwidth;
3203 if (base && basefnt && basechr) {
3204 target += tex_aux_math_x_size_scaled(basefnt, tex_char_right_margin_from_font(basefnt, basechr), size);
3205 target += tex_aux_math_x_size_scaled(basefnt, tex_char_left_margin_from_font(basefnt, basechr), size);
3206 }
3207 }
3208 if (fraction > 0) {
3209 target = tex_xn_over_d(target, fraction, scaling_factor);
3210 }
3211 while (1) {
3212 if (tex_char_has_tag_from_font(accentfnt, accentchr, extensible_tag)) {
3213 extended = tex_char_extensible_recipe_from_font(accentfnt, accentchr);
3214 }
3215 if (extended) {
3216
3220 halfword overlap = tex_get_math_x_parameter_checked(style, math_parameter_connector_overlap_min);
3221 accent = tex_aux_get_delimiter_box(accentfnt, accentchr, usedwidth, overlap, 1, attrlist);
3222 accent = register_extensible(accentfnt, accentchr, size, accent, attrlist);
3223 break;
3224 } else if (! tex_char_has_tag_from_font(accentfnt, accentchr, list_tag)) {
3225 break;
3226 } else {
3227 halfword next = tex_char_next_from_font(accentfnt, accentchr);
3228 if (! tex_char_exists(accentfnt, next)) {
3229 break;
3230 } else if (flags & overlay_accent_code) {
3231 if (tex_aux_math_y_size_scaled(accentfnt, tex_char_height_from_font(accentfnt, next), size) > target) {
3232 break;
3233 }
3234 } else {
3235 if (tex_aux_math_x_size_scaled(accentfnt, tex_char_width_from_font(accentfnt, next), size) > target) {
3236 break;
3237 }
3238 }
3239 accentchr = next;
3240 }
3241 }
3242
3243 }
3244 keep = (accentfnt == accentbasefnt) && (accentchr == accentbasechr) && (has_noad_option_keep_base(target) || tex_char_has_tag_from_font(accentfnt, accentchr, keep_base_tag));
3245 if (accent) {
3246
3249 } else {
3250
3254 accent = tex_aux_char_box(accentfnt, accentchr, attrlist, NULL, glyph_math_accent_subtype, usedwidth, style, keep ? 0 : has_noad_option_shrink(target), keep ? 0 : has_noad_option_stretch(target), &isscaled);
3255 found = 1;
3256 }
3257 if (flags & top_accent_code) {
3258 scaled b = tex_get_math_y_parameter(style, math_parameter_accent_base_height);
3259 scaled u = tex_get_math_y_parameter(style, math_parameter_accent_top_shift_up);
3260 if (found && ! tex_aux_math_engine_control(accentfnt, math_control_ignore_flat_accents)) {
3261 scaled f = tex_get_math_y_parameter(style, math_parameter_flattened_accent_base_height);
3262 if (f != undefined_math_parameter && baseheight > f) {
3263 int keep = (accentfnt == accentbasefnt) && (accentchr == accentbasechr) && (has_noad_option_keep_base(target) || tex_char_has_tag_from_font(accentfnt, accentchr, keep_base_tag));
3264 halfword flatchr = tex_char_flat_accent_from_font(accentfnt, accentchr);
3265 if (flatchr && flatchr != INT_MIN && flatchr != accentchr) {
3266 scaled uf = tex_get_math_y_parameter(style, math_parameter_flattened_accent_top_shift_up);
3267 if (uf != undefined_math_parameter) {
3268 u = uf;
3269 }
3270 tex_flush_node(accent);
3271 accent = tex_aux_char_box(accentfnt, flatchr, attrlist, NULL, glyph_math_accent_subtype, usedwidth, style, keep ? 0 : has_noad_option_shrink(target), keep ? 0 : has_noad_option_stretch(target), &isscaled);
3272 if (tracing_math_par >= 2) {
3273 tex_begin_diagnostic();
3274 tex_print_format("[math: flattening accent, old %x, new %x]", accentchr, flatchr);
3275 tex_end_diagnostic();
3276 }
3277 accentchr = flatchr;
3278 }
3279 }
3280 }
3281 if (has_noad_option_auto_base(target)) {
3282 b = - box_depth(accent);
3283 }
3284 if (b != undefined_math_parameter) {
3285
3286 delta = baseheight < b ? baseheight : b;
3287 }
3288 if (u != undefined_math_parameter) {
3289 delta -= u;
3290 }
3291 if (tex_char_has_tag_from_font(accentfnt, accentchr, inner_top_tag)) {
3292 innery = tex_char_inner_y_offset_from_font(accentfnt, accentchr);
3293 innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(accentfnt, innery, size);
3294 }
3295 } else if (flags & bot_accent_code) {
3296
3297
3298 scaled l = tex_get_math_y_parameter(style, stretch ? math_parameter_flattened_accent_bottom_shift_down : math_parameter_accent_bottom_shift_down);
3299
3300
3301
3302
3303 if (l != undefined_math_parameter) {
3304 delta += l;
3305 }
3306 if (tex_char_has_tag_from_font(accentfnt, accentchr, inner_bottom_tag)) {
3307 innery = tex_char_inner_y_offset_from_font(accentfnt, accentchr);
3308 innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(accentfnt, innery, size);
3309 }
3310 } else {
3311
3312 if (has_noad_option_exact(target)) {
3313 delta = box_height(base) + box_depth(accent);
3314 } else {
3315 delta = tex_half_scaled(box_total(accent) + box_total(base));
3316 }
3317
3318
3319
3320 }
3321 if (accenttotal) {
3322 *accenttotal = box_total(accent);
3323 }
3324 if (node_type(nucleus) != math_char_node) {
3325
3326 } else if (noad_has_following_scripts(target)) {
3327
3328 tex_flush_node_list(base);
3329 base = tex_new_node(simple_noad, ordinary_noad_subtype);
3330 tex_attach_attribute_list_copy(base, nucleus);
3331 noad_nucleus(base) = tex_aux_math_clone(nucleus);
3332
3333 node_type(nucleus) = sub_mlist_node;
3334 kernel_math_list(nucleus) = base;
3335 base = tex_aux_clean_box(nucleus, style, style, math_nucleus_list, 1, NULL);
3336 delta = delta + box_height(base) - baseheight;
3337 baseheight = box_height(base);
3338 }
3339
3340 if (flags & overlay_accent_code) {
3341
3342 box_shift_amount(accent) = tex_half_scaled(basewidth - box_width(accent));
3343 box_width(accent) = 0;
3344 } else {
3345 halfword accentwidth = box_width(accent);
3346 if (accentwidth > basewidth && has_noad_option_nooverflow(target)) {
3347
3352 scaled leftkern = tex_half_scaled(accentwidth - basewidth);
3353 if (leftkern > 0) {
3354 halfword kern = tex_new_kern_node(leftkern, horizontal_math_kern_subtype);
3355 tex_attach_attribute_list_copy(kern, target);
3356 tex_try_couple_nodes(kern, base);
3357 base = tex_hpack(kern, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3358 tex_attach_attribute_list_copy(base, target);
3359 basewidth = accentwidth;
3360 box_width(base) = accentwidth;
3361 }
3362 } else {
3363 if (absolute) {
3364 scaled anchor = 0;
3365 if (extended || isscaled) {
3366
3367 anchor = tex_half_scaled(accentwidth);
3368 } else {
3369
3370 if (flags & top_accent_code) {
3371 anchor = tex_char_unchecked_top_anchor_from_font(accentfnt, accentchr);
3372 } else if (flags & bot_accent_code) {
3373 anchor = tex_char_unchecked_bottom_anchor_from_font(accentfnt, accentchr);
3374 } else {
3375 anchor = INT_MIN;
3376 }
3377 if (anchor == INT_MIN || has_noad_option_center(target)) {
3378
3379 anchor = tex_half_scaled(accentwidth);
3380 } else {
3381 anchor = tex_aux_math_x_size_scaled(accentfnt, anchor, size);
3382 }
3383 }
3384 if (math_direction_par == dir_righttoleft) {
3385 skew += anchor - accentwidth;
3386 } else {
3387 skew -= anchor;
3388 }
3389 } else if (accentwidth == 0) {
3390 skew += basewidth;
3391 } else if (math_direction_par == dir_righttoleft) {
3392 skew += accentwidth;
3393 } else {
3394 skew += tex_half_scaled(basewidth - accentwidth);
3395 }
3396 box_shift_amount(accent) = skew;
3397 box_width(accent) = 0;
3398 if (accentwidth) {
3399 overshoot = accentwidth + skew - basewidth;
3400 }
3401 if (overshoot < 0) {
3402 overshoot = 0;
3403 }
3404 }
3405 }
3406 if (flags & (top_accent_code)) {
3407 accent_top_overshoot(target) = overshoot;
3408 }
3409 if (flags & (bot_accent_code)) {
3410 accent_bot_overshoot(target) = overshoot;
3411 }
3412 if (flags & (top_accent_code | overlay_accent_code)) {
3413 delta += innery;
3414 if (delta) {
3415 halfword kern = tex_new_kern_node(-delta, vertical_math_kern_subtype);
3416 tex_attach_attribute_list_copy(kern, target);
3417 tex_couple_nodes(accent, kern);
3418 tex_couple_nodes(kern, base);
3419 } else {
3420 tex_couple_nodes(accent, base);
3421 }
3422 result = accent;
3423 } else if ((flags & bot_accent_code) && innery) {
3424 halfword kern = tex_new_kern_node(innery, vertical_math_kern_subtype);
3425 tex_attach_attribute_list_copy(kern, target);
3426 tex_couple_nodes(base, kern);
3427 tex_couple_nodes(kern, accent);
3428 result = base;
3429 } else {
3430 tex_couple_nodes(base, accent);
3431 result = base;
3432 }
3433 result = tex_vpack(result, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
3434 tex_attach_attribute_list_copy(result, target);
3435 node_subtype(result) = math_accent_list;
3436 box_width(result) = box_width(base);
3437 delta = baseheight - box_height(result);
3438 if (flags & (top_accent_code | overlay_accent_code)) {
3439 if (delta > 0) {
3440
3441 halfword kern = tex_new_kern_node(delta, vertical_math_kern_subtype);
3442 tex_attach_attribute_list_copy(kern, target);
3443 tex_try_couple_nodes(kern, box_list(result));
3444 box_list(result) = kern;
3445 box_height(result) = baseheight;
3446 }
3447 } else {
3448 box_shift_amount(result) = - delta;
3449 }
3450 box_width(result) += overshoot;
3451
3452if (node_type(result) == vlist_node) {
3453 result = tex_hpack(result, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3454 tex_attach_attribute_list_copy(result, target);
3455 node_subtype(result) = math_accent_list;
3456}
3457
3458 kernel_math_list(nucleus) = result;
3459 node_type(nucleus) = sub_box_node;
3460}
3461
3462static void tex_aux_make_accent(halfword target, int style, int size, kernset *kerns)
3463{
3464 int topstretch = 0;
3465 int botstretch = 0;
3466 halfword fnt = null;
3467 halfword chr = null;
3468
3471 switch (node_subtype(target)) {
3472 case bothflexible_accent_subtype: topstretch = 1; botstretch = 1; break;
3473 case fixedtop_accent_subtype : botstretch = 1; break;
3474 case fixedbottom_accent_subtype : topstretch = 1; break;
3475 case fixedboth_accent_subtype : break;
3476 }
3477
3481 if (accent_top_character(target)) {
3482 if (tex_aux_fetch(accent_top_character(target), "top accent", &fnt, &chr)) {
3483 tex_aux_do_make_math_accent(target, fnt, chr, top_accent_code | (topstretch ? stretch_accent_code : 0), style, size, &(kerns->toptotal),
3484 tex_math_has_class_option(accent_noad_subtype, left_bottom_kern_class_option) ? &(kerns->bottomleft) : NULL,
3485 tex_math_has_class_option(accent_noad_subtype, right_bottom_kern_class_option) ? &(kerns->bottomright) : NULL
3486 );
3487 }
3488 tex_flush_node(accent_top_character(target));
3489 accent_top_character(target) = null;
3490 }
3491 if (accent_bottom_character(target)) {
3492 if (tex_aux_fetch(accent_bottom_character(target), "bottom accent", &fnt, &chr)) {
3493 tex_aux_do_make_math_accent(target, fnt, chr, bot_accent_code | (botstretch ? stretch_accent_code : 0), style, size, &(kerns->bottomtotal),
3494 tex_math_has_class_option(accent_noad_subtype, left_bottom_kern_class_option) ? &(kerns->topleft) : NULL,
3495 tex_math_has_class_option(accent_noad_subtype, right_bottom_kern_class_option) ? &(kerns->topright) : NULL
3496 );
3497 }
3498 tex_flush_node(accent_bottom_character(target));
3499 accent_bottom_character(target) = null;
3500 }
3501 if (accent_middle_character(target)) {
3502 if (tex_aux_fetch(accent_middle_character(target), "overlay accent", &fnt, &chr)) {
3503 tex_aux_do_make_math_accent(target, fnt, chr, overlay_accent_code | stretch_accent_code, style, size, NULL, NULL, NULL);
3504 }
3505 tex_flush_node(accent_middle_character(target));
3506 accent_middle_character(target) = null;
3507 }
3508 if (noad_source(target)) {
3509 halfword result = kernel_math_list(noad_nucleus(target));
3510 if (result) {
3511 box_source_anchor(result) = noad_source(target);
3512 tex_set_box_geometry(result, anchor_geometry);
3513 }
3514 }
3515}
3516
3517
3530
3531
3536
3537static void tex_aux_wrap_fraction_parts(halfword target, int style, int size, halfword *numerator, halfword *denominator, int check)
3538{
3539 if (noad_style(target) == unused_math_style) {
3540 *numerator = tex_aux_clean_box(fraction_numerator(target), tex_math_style_variant(style, math_parameter_numerator_variant), style, math_numerator_list, 0, NULL);
3541 *denominator = tex_aux_clean_box(fraction_denominator(target), tex_math_style_variant(style, math_parameter_denominator_variant), style, math_denominator_list, 0, NULL);
3542 } else {
3543 *numerator = tex_aux_clean_box(fraction_numerator(target), noad_style(target), style, math_numerator_list, 0, NULL);
3544 *denominator = tex_aux_clean_box(fraction_denominator(target), noad_style(target), style, math_denominator_list, 0, NULL);
3545 }
3546 if (check) {
3547 if (box_width(*numerator) < box_width(*denominator)) {
3548 *numerator = tex_aux_rebox(*numerator, box_width(*denominator), size);
3549 } else {
3550 *denominator = tex_aux_rebox(*denominator, box_width(*numerator), size);
3551 }
3552 }
3553}
3554
3555
3558
3559static void tex_aux_wrap_fraction_result(halfword target, int style, int size, halfword fraction, kernset *kerns)
3560{
3561 halfword result = null;
3562 halfword left_delimiter = fraction_left_delimiter(target);
3563 halfword right_delimiter = fraction_right_delimiter(target);
3564 if (left_delimiter || right_delimiter) {
3565 halfword left = null;
3566 halfword right = null;
3567 halfword delta = tex_get_math_y_parameter(style, math_parameter_fraction_del_size);
3568 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
3569 if (delta == undefined_math_parameter) {
3570 delta = tex_aux_get_delimiter_height(box_height(fraction), box_depth(fraction), 1, size, style);
3571 }
3572
3573 left = tex_aux_make_delimiter(target, left_delimiter, size, delta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, null);
3574 right = tex_aux_make_delimiter(target, right_delimiter, size, delta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, 0, null);
3575 if (kerns && extremes.tfont) {
3576 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_left_top_kern_class_option)) {
3577 kerns->topleft = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_left_kern_from_font(extremes.tfont, extremes.tchar), size);
3578 }
3579 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_left_bottom_kern_class_option)) {
3580 kerns->bottomleft = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_left_kern_from_font(extremes.bfont, extremes.bchar), size);
3581 }
3582 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_right_top_kern_class_option)) {
3583 kerns->topright = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_right_kern_from_font(extremes.tfont, extremes.tchar), size);
3584 }
3585 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_right_bottom_kern_class_option)) {
3586 kerns->bottomright = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_right_kern_from_font(extremes.bfont, extremes.bchar), size);
3587 }
3588 if (tex_math_has_class_option(fraction_noad_subtype, prefer_delimiter_dimensions_class_option)) {
3589 kerns->height = extremes.height;
3590 kerns->depth = extremes.depth;
3591 kerns->dimensions = 1;
3592 kerns->font = extremes.tfont;
3593 }
3594 }
3595
3596 tex_couple_nodes(left, fraction);
3597 tex_couple_nodes(fraction, right);
3598 fraction = left;
3599 }
3600 result = tex_hpack(fraction, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3601 tex_attach_attribute_list_copy(result, target);
3602
3603 node_subtype(result) = math_fraction_list;
3604 tex_aux_assign_new_hlist(target, result);
3605 if (noad_source(target)) {
3606 box_source_anchor(result) = noad_source(target);
3607
3608 tex_set_box_geometry(result, anchor_geometry);
3609 }
3610}
3611
3612
3619
3620static void tex_aux_calculate_fraction_shifts(halfword target, int style, int size, scaled *shift_up, scaled *shift_down, int up, int down)
3621{
3622 (void) size;
3623 *shift_up = tex_get_math_y_parameter_checked(style, up);
3624 *shift_down = tex_get_math_y_parameter_checked(style, down);
3625 *shift_up = tex_round_xn_over_d(*shift_up, fraction_v_factor(target), scaling_factor);
3626 *shift_down = tex_round_xn_over_d(*shift_down, fraction_v_factor(target), scaling_factor);
3627}
3628
3629static void tex_aux_calculate_fraction_shifts_stack(halfword target, int style, int size, halfword numerator, halfword denominator, scaled *shift_up, scaled *shift_down, scaled *delta)
3630{
3631 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_stack_vgap);
3632 tex_aux_calculate_fraction_shifts(target, style, size, shift_up, shift_down, math_parameter_stack_num_up, math_parameter_stack_denom_down);
3633 *delta = tex_half_scaled(clearance - ((*shift_up - box_depth(numerator)) - (box_height(denominator) - *shift_down)));
3634 if (*delta > 0) {
3635 *shift_up += *delta;
3636 *shift_down += *delta;
3637 }
3638}
3639
3640static void tex_aux_calculate_fraction_shifts_normal(halfword target, int style, int size, halfword numerator, halfword denominator, scaled *shift_up, scaled *shift_down, scaled *delta)
3641{
3642 scaled axis = tex_aux_math_axis(size);
3643 scaled numerator_clearance = tex_get_math_y_parameter_checked(style, math_parameter_fraction_num_vgap);
3644 scaled denominator_clearance = tex_get_math_y_parameter_checked(style, math_parameter_fraction_denom_vgap);
3645 scaled delta_up = 0;
3646 scaled delta_down = 0;
3647 tex_aux_calculate_fraction_shifts(target, style, size, shift_up, shift_down, math_parameter_fraction_num_up, math_parameter_fraction_denom_down);
3648
3649 *delta = tex_half_scaled(tex_aux_math_given_y_scaled(fraction_rule_thickness(target)));
3650 delta_up = numerator_clearance - ((*shift_up - box_depth(numerator) ) - (axis + *delta));
3651 delta_down = denominator_clearance - ((*shift_down - box_height(denominator)) + (axis - *delta));
3652 if (delta_up > 0) {
3653 *shift_up += delta_up;
3654 }
3655 if (delta_down > 0) {
3656 *shift_down += delta_down;
3657 }
3658}
3659
3660static scaled tex_aux_check_fraction_rule(halfword target, int style, int size, int fractiontype, halfword *usedfam)
3661{
3662 scaled preferfont = has_noad_option_preferfontthickness(target);
3663 halfword fam = math_rules_fam_par;
3664 (void) style;
3665
3669 if (preferfont) {
3670
3671 } else if (fractiontype == above_fraction_subtype) {
3672
3673 preferfont = 0;
3674 if (has_noad_option_proportional(target)) {
3675
3676 scaled text = tex_get_math_y_parameter_checked(text_style, math_parameter_fraction_rule);
3677 scaled here = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
3678 fraction_rule_thickness(target) = tex_ext_xn_over_d(fraction_rule_thickness(target), here, text);
3679 }
3680 } else if (fraction_rule_thickness(target)) {
3681
3682 preferfont = 1;
3683 }
3684 if (preferfont) {
3685 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_fraction_rule, FractionRuleThickness);
3686 if (t != undefined_math_parameter) {
3687 fraction_rule_thickness(target) = t;
3688 }
3689 }
3690 if (fraction_rule_thickness(target) == preset_rule_thickness) {
3691 fraction_rule_thickness(target) = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
3692 }
3693 if (usedfam) {
3694 *usedfam = fam;
3695 }
3696 return tex_aux_math_given_y_scaled(fraction_rule_thickness(target));
3697}
3698
3699static void tex_aux_compensate_fraction_rule(halfword target, halfword fraction, halfword separator, scaled thickness)
3700{
3701 (void) target;
3702 if (box_total(separator) != thickness) {
3703 scaled half = tex_half_scaled(box_total(separator) - thickness);
3704 box_height(fraction) += half;
3705 box_depth(fraction) += half;
3706 }
3707}
3708
3709static void tex_aux_apply_fraction_shifts(halfword fraction, halfword numerator, halfword denominator, scaled shift_up, scaled shift_down)
3710{
3711 box_height(fraction) = shift_up + box_height(numerator);
3712 box_depth(fraction) = box_depth(denominator) + shift_down;
3713 box_width(fraction) = box_width(numerator);
3714}
3715
3716
3721
3722static halfword tex_aux_assemble_fraction(halfword target, int style, int size, halfword numerator, halfword denominator, halfword separator, scaled delta, scaled shift_up, scaled shift_down)
3723{
3724 (void) target;
3725 (void) style;
3726 if (separator) {
3727 scaled axis = tex_aux_math_axis(size);
3728 halfword after = tex_new_kern_node((axis - delta) - (box_height(denominator) - shift_down), vertical_math_kern_subtype);
3729 halfword before = tex_new_kern_node((shift_up - box_depth(numerator)) - (axis + delta), vertical_math_kern_subtype);
3730 tex_attach_attribute_list_copy(after, target);
3731 tex_attach_attribute_list_copy(before, target);
3732 tex_couple_nodes(separator, after);
3733 tex_couple_nodes(after, denominator);
3734 tex_couple_nodes(before, separator);
3735 tex_couple_nodes(numerator, before);
3736 } else {
3737 halfword between = tex_new_kern_node((shift_up - box_depth(numerator)) - (box_height(denominator) - shift_down), vertical_math_kern_subtype);
3738 tex_attach_attribute_list_copy(between, target);
3739 tex_couple_nodes(between, denominator);
3740 tex_couple_nodes(numerator, between);
3741 }
3742 return numerator;
3743}
3744
3745static halfword tex_aux_make_skewed_fraction(halfword target, int style, int size, kernset *kerns)
3746{
3747 halfword middle = null;
3748 halfword fraction = null;
3749 halfword numerator = null;
3750 halfword denominator = null;
3751 scaled delta = 0;
3752 halfword middle_delimiter = fraction_middle_delimiter(target);
3753 scaled maxheight = 0;
3754 scaled maxdepth = 0;
3755 scaled ngap = 0;
3756 scaled dgap = 0;
3757 scaled hgap = 0;
3758 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
3759 scaled tolerance = tex_get_math_y_parameter_default(style, math_parameter_skewed_delimiter_tolerance, 0);
3760 scaled shift_up = 0;
3761 scaled shift_down = 0;
3762 (void) kerns;
3763 if (! has_noad_option_center(target)) {
3764 shift_up = tex_get_math_y_parameter_checked(style, math_parameter_skewed_fraction_vgap);
3765 shift_down = tex_round_xn_over_d(shift_up, fraction_v_factor(target), scaling_factor);
3766 }
3767 tex_aux_wrap_fraction_parts(target, style, size, &numerator, &denominator, 0);
3768
3771 if (! has_noad_option_noaxis(target)) {
3772 shift_up += tex_half_scaled(tex_aux_math_axis(size));
3773 shift_down = shift_up;
3774 }
3775
3778 hgap = tex_get_math_x_parameter_checked(style, math_parameter_skewed_fraction_hgap);
3779 hgap = tex_round_xn_over_d(hgap, fraction_h_factor(target), scaling_factor);
3780 {
3781 scaled ht = box_height(numerator) + shift_up;
3782 scaled dp = box_depth(numerator) - shift_up;
3783 if (dp < 0) {
3784 dp = 0;
3785 }
3786 if (ht < 0) {
3787 ht = 0;
3788 }
3789 if (ht > maxheight) {
3790 maxheight = ht;
3791 }
3792 if (dp > maxdepth) {
3793 maxdepth = dp;
3794 }
3795 }
3796 {
3797 scaled ht = box_height(denominator) - shift_down;
3798 scaled dp = box_depth(denominator) + shift_down;
3799 if (dp < 0) {
3800 dp = 0;
3801 }
3802 if (ht < 0) {
3803 ht = 0;
3804 }
3805 if (ht > maxheight) {
3806 maxheight = ht;
3807 }
3808 if (dp > maxdepth) {
3809 maxdepth = dp;
3810 }
3811 }
3812 box_shift_amount(numerator) = -shift_up;
3813 box_shift_amount(denominator) = shift_down;
3814 delta = maxheight + maxdepth;
3815 middle = tex_aux_make_delimiter(target, middle_delimiter, size, delta, 0, style, 1, NULL, NULL, tolerance, has_noad_option_nooverflow(target), &extremes, 0, null);
3816 if (has_noad_option_center(target)) {
3817 box_shift_amount(middle) -= box_total(middle) - delta;
3818 }
3819 fraction = tex_new_null_box_node(hlist_node, math_fraction_list);
3820 tex_attach_attribute_list_copy(fraction, target);
3821 box_width(fraction) = box_width(numerator) + box_width(denominator) + box_width(middle) - hgap;
3822 hgap = -tex_half_scaled(hgap);
3823 box_height(fraction) = box_height(middle) > maxheight ? box_height(middle) : maxheight;
3824 box_depth(fraction) = box_depth(middle) > maxdepth ? box_depth(middle) : maxdepth;
3825 ngap = hgap;
3826 dgap = hgap;
3827
3828
3836 if (ngap || dgap) {
3837
3838 halfword nkern = tex_new_kern_node(ngap, horizontal_math_kern_subtype);
3839 halfword dkern = tex_new_kern_node(dgap, horizontal_math_kern_subtype);
3840 tex_attach_attribute_list_copy(nkern, target);
3841 tex_attach_attribute_list_copy(dkern, target);
3842 tex_couple_nodes(numerator, nkern);
3843 tex_couple_nodes(nkern, middle);
3844 tex_couple_nodes(middle, dkern);
3845 tex_couple_nodes(dkern, denominator);
3846 } else {
3847 tex_couple_nodes(numerator, middle);
3848 tex_couple_nodes(middle, denominator);
3849 }
3850 box_list(fraction) = numerator;
3851 return fraction;
3852}
3853
3854static halfword tex_aux_make_ruled_fraction(halfword target, int style, int size, kernset *kerns, int fractiontype)
3855{
3856 halfword numerator = null;
3857 halfword denominator = null;
3858 scaled shift_up = 0;
3859 scaled shift_down = 0;
3860 scaled delta = 0;
3861 halfword fam = 0;
3862 halfword thickness = tex_aux_check_fraction_rule(target, style, size, fractiontype, &fam);
3863 halfword fraction = tex_new_null_box_node(vlist_node, math_fraction_list);
3864 halfword rule = null;
3865 (void) kerns;
3866 tex_attach_attribute_list_copy(fraction, target);
3867 tex_aux_wrap_fraction_parts(target, style, size, &numerator, &denominator, 1);
3868 if (fraction_rule_thickness(target) == 0) {
3869 tex_aux_calculate_fraction_shifts_stack(target, style, size, numerator, denominator, &shift_up, &shift_down, &delta);
3870 } else {
3871 tex_aux_calculate_fraction_shifts_normal(target, style, size, numerator, denominator, &shift_up, &shift_down, &delta);
3872 }
3873 tex_aux_apply_fraction_shifts(fraction, numerator, denominator, shift_up, shift_down);
3874 if (fractiontype != atop_fraction_subtype) {
3875 rule = tex_aux_fraction_rule(box_width(fraction), thickness, get_attribute_list(target), math_fraction_rule_subtype, size, fam);
3876 tex_aux_compensate_fraction_rule(target, fraction, rule, thickness);
3877 }
3878 box_list(fraction) = tex_aux_assemble_fraction(target, style, size, numerator, denominator, rule, delta, shift_up, shift_down);
3879 return fraction;
3880}
3881
3882static halfword tex_aux_make_stretched_fraction(halfword target, int style, int size, kernset *kerns)
3883{
3884 halfword middle_delimiter = fraction_middle_delimiter(target);
3885 if (tex_aux_has_extensible(middle_delimiter, size)) {
3886 halfword middle = null;
3887 halfword numerator = null;
3888 halfword denominator = null;
3889 scaled shift_up = 0;
3890 scaled shift_down = 0;
3891 scaled delta = 0;
3892 halfword thickness = tex_aux_check_fraction_rule(target, style, size, stretched_fraction_subtype, NULL);
3893 halfword fraction = tex_new_null_box_node(vlist_node, math_fraction_list);
3894 (void) kerns;
3895 tex_attach_attribute_list_copy(fraction, target);
3896 tex_aux_wrap_fraction_parts(target, style, size, &numerator, &denominator, 1);
3897 tex_aux_calculate_fraction_shifts_normal(target, style, size, numerator, denominator, &shift_up, &shift_down, &delta);
3898 tex_aux_apply_fraction_shifts(fraction, numerator, denominator, shift_up, shift_down);
3899 middle = tex_aux_make_delimiter(target, middle_delimiter, size, box_width(fraction), 1, style, 0, NULL, NULL, 0, 0, NULL, 0, node_attr(target));
3900 if (box_width(middle) < box_width(fraction)) {
3901
3902 scaled delta = (box_width(fraction) - box_width(middle)) / 2;
3903 tex_aux_prepend_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "narrow delimiter");
3904 tex_aux_append_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "narrow delimiter");
3905 box_width(middle) = box_width(fraction);
3906 } else if (box_width(middle) > box_width(fraction)) {
3907 scaled delta = (box_width(middle) - box_width(fraction)) / 2;
3908 tex_aux_prepend_hkern_to_box_list(numerator, delta, horizontal_math_kern_subtype, "wide delimiter");
3909 tex_aux_append_hkern_to_box_list(numerator, delta, horizontal_math_kern_subtype, "wide delimiter");
3910 tex_aux_prepend_hkern_to_box_list(denominator, delta, horizontal_math_kern_subtype, "wide delimiter");
3911 tex_aux_append_hkern_to_box_list(denominator, delta, horizontal_math_kern_subtype, "wide delimiter");
3912 box_width(fraction) = box_width(middle);
3913 }
3914 tex_aux_compensate_fraction_rule(target, fraction, middle, thickness);
3915 box_list(fraction) = tex_aux_assemble_fraction(target, style, size, numerator, denominator, middle, delta, shift_up, shift_down);
3916 return fraction;
3917 } else {
3918 return tex_aux_make_ruled_fraction(target, style, size, kerns, over_fraction_subtype);
3919 }
3920}
3921
3922
3926
3927static void tex_aux_make_fraction(halfword target, int style, int size, kernset *kerns)
3928{
3929 quarterword fractiontype = node_subtype(target);
3930 halfword fraction = null;
3931 TRYAGAIN:
3932 switch (fractiontype) {
3933 case over_fraction_subtype:
3934 case atop_fraction_subtype:
3935 case above_fraction_subtype:
3936 tex_flush_node_list(fraction_middle_delimiter(target));
3937 fraction_middle_delimiter(target) = null;
3938 fraction = tex_aux_make_ruled_fraction(target, style, size, kerns, fractiontype);
3939 break;
3940 case skewed_fraction_subtype:
3941 fraction_rule_thickness(target) = 0;
3942 fraction = tex_aux_make_skewed_fraction(target, style, size, kerns);
3943 break;
3944 case stretched_fraction_subtype:
3945 fraction = tex_aux_make_stretched_fraction(target, style, size, kerns);
3946 break;
3947 default:
3948 fractiontype = atop_fraction_subtype;
3949 goto TRYAGAIN;
3950 }
3951 tex_aux_wrap_fraction_result(target, style, size, fraction, kerns);
3952 fraction_left_delimiter(target) = null;
3953 fraction_middle_delimiter(target) = null;
3954 fraction_right_delimiter(target) = null;
3955}
3956
3957
3977
3978static void tex_aux_make_scripts (
3979 halfword target,
3980 halfword kernel,
3981 scaled italic,
3982 int style,
3983 scaled supshift,
3984 scaled subshift,
3985 scaled supdrop,
3986 kernset *kerns,
3987 halfword single
3988);
3989
3990static halfword tex_aux_check_nucleus_complexity (
3991 halfword target,
3992 scaled *delta,
3993 halfword style,
3994 halfword size,
3995 kernset *kerns
3996);
3997
3998
4002
4003static void tex_aux_get_shifts(int mode, int style, scaled delta, scaled *top, scaled *bot)
4004{
4005 switch (mode) {
4006 case 0:
4007
4008 *top = 0;
4009 *bot = -delta;
4010 break;
4011 case 1:
4012
4013 *top = tex_round_xn_over_d(delta, tex_get_math_parameter_default(style, math_parameter_nolimit_sup_factor, 0), scaling_factor);
4014 *bot = -tex_round_xn_over_d(delta, tex_get_math_parameter_default(style, math_parameter_nolimit_sub_factor, 0), scaling_factor);
4015 break ;
4016 case 2:
4017
4018 *top = 0;
4019 *bot = 0;
4020 break ;
4021 case 3:
4022
4023 *top = 0;
4024 *bot = -tex_half_scaled(delta);
4025 break;
4026 case 4:
4027
4028 *top = tex_half_scaled(delta);
4029 *bot = -tex_half_scaled(delta);
4030 break;
4031 default :
4032
4033 *top = 0;
4034 *bot = (mode > 15) ? -tex_round_xn_over_d(delta, mode, scaling_factor) : 0;
4035 break;
4036 }
4037}
4038
4039static scaled tex_aux_op_no_limits(halfword target, int style, int size, int italic, kernset *kerns, int forceitalics)
4040{
4041 kernset localkerns ;
4042 halfword kernel;
4043 (void) size;
4044 (void) forceitalics;
4045 if (kerns) {
4046 tex_math_copy_kerns(&localkerns, kerns);
4047 } else {
4048 tex_math_wipe_kerns(&localkerns);
4049 }
4050 kernel = tex_aux_check_nucleus_complexity(target, NULL, style, lmt_math_state.size, &localkerns);
4051 if (noad_has_scripts(target)) {
4052 scaled topshift = 0;
4053 scaled botshift = 0;
4054 if (localkerns.topright || localkerns.bottomright) {
4055 italic = 0;
4056 }
4057 tex_aux_get_shifts(math_nolimits_mode_par, style, italic, &topshift, &botshift);
4058 tex_aux_make_scripts(target, kernel, 0, style, topshift, botshift, 0, &localkerns, 0);
4059 } else {
4060 tex_aux_assign_new_hlist(target, kernel);
4061 }
4062
4063 return 0;
4064}
4065
4066static scaled tex_aux_op_do_limits(halfword target, int style, int size, int italic, kernset *kerns, int forceitalics)
4067{
4068 halfword nucleus = noad_nucleus(target);
4069 halfword superscript = tex_aux_clean_box(noad_supscr(target), tex_math_style_variant(style, math_parameter_superscript_variant), style, math_sup_list, 0, NULL);
4070 halfword kernel = tex_aux_clean_box(nucleus, style, style, math_nucleus_list, forceitalics, NULL);
4071 halfword subscript = tex_aux_clean_box(noad_subscr(target), tex_math_style_variant(style, math_parameter_subscript_variant), style, math_sub_list, 0, NULL);
4072 halfword result = tex_new_null_box_node(vlist_node, math_modifier_list);
4073 (void) kerns;
4074 tex_attach_attribute_list_copy(result, target);
4075 if (nucleus) {
4076
4077 switch (node_type(nucleus)) {
4078 case sub_mlist_node:
4079 case sub_box_node:
4080 {
4081 halfword n = kernel_math_list(nucleus);
4082 if (! n) {
4083
4084 } else if (node_type(n) == hlist_node) {
4085
4086 n = box_list(n);
4087 while (n) {
4088 if (node_type(n) == glyph_node && ! tex_has_glyph_option(n, glyph_option_no_italic_correction)) {
4089 if (tex_aux_math_engine_control(glyph_font(n), math_control_apply_boxed_italic_kern)) {
4090 italic = tex_aux_math_x_size_scaled(glyph_font(n), tex_char_italic_from_font(glyph_font(n), glyph_character(n)), size);
4091 }
4092 }
4093 n = node_next(n);
4094 }
4095 } else {
4096
4097 while (n) {
4098 if (node_type(n) == fence_noad && noad_italic(n) > italic) {
4099
4100 italic = tex_aux_math_given_x_scaled(noad_italic(n));
4101 }
4102 n = node_next(n);
4103 }
4104 }
4105 break;
4106 }
4107 case math_char_node:
4108 {
4109 halfword fnt = tex_fam_fnt(kernel_math_family(nucleus), size);
4110 halfword chr = kernel_math_character(nucleus);
4111 italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
4112 break;
4113 }
4114 }
4115 }
4116
4117 if (noad_supscr(target) || noad_subscr(target)) {
4118 scaled supwidth = box_width(superscript);
4119 scaled boxwidth = box_width(kernel);
4120 scaled subwidth = box_width(subscript);
4121 scaled halfitalic = tex_half_scaled(italic);
4122 scaled topshift = halfitalic;
4123 scaled bottomshift = halfitalic;
4124
4125 if (kerns && ! halfitalic) {
4126 halfword fnt = kerns->font;
4127 halfword chr = kerns->character;
4128 if (fnt && chr) {
4129 scaled topanchor = tex_aux_math_x_size_scaled(fnt, tex_char_top_anchor_from_font(fnt, chr), size);
4130 scaled bottomanchor = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_anchor_from_font(fnt, chr), size);
4131
4132 if (topanchor) {
4133 topshift = topanchor - boxwidth;
4134 }
4135 if (bottomanchor) {
4136 bottomshift = boxwidth - bottomanchor;
4137 }
4138 }
4139 }
4140 if (math_limits_mode_par >= 1) {
4141
4147 halfword savedwidth = boxwidth;
4148 halfword overshoot = 0;
4149 superscript = tex_aux_rebox(superscript, supwidth, size);
4150 kernel = tex_aux_rebox(kernel, boxwidth, size);
4151 subscript = tex_aux_rebox(subscript, subwidth, size);
4152 if (supwidth) {
4153 halfword shift = savedwidth/2 + topshift - supwidth/2;
4154 halfword delta = supwidth + shift - savedwidth;
4155 box_shift_amount(superscript) = shift;
4156 if (delta > 0) {
4157 boxwidth = boxwidth + delta;
4158 }
4159 overshoot = supwidth - boxwidth;
4160 if (overshoot > 0) {
4161 box_shift_amount(superscript) += overshoot;
4162 box_shift_amount(kernel) += overshoot;
4163 boxwidth = boxwidth + overshoot;
4164 } else {
4165 overshoot = 0;
4166 }
4167 }
4168 if (subwidth) {
4169 halfword shift = savedwidth/2 - bottomshift - subwidth/2 + overshoot;
4170 box_shift_amount(subscript) = shift;
4171 if (shift < 0) {
4172 box_shift_amount(superscript) -= shift;
4173 box_shift_amount(subscript) -= shift;
4174 box_shift_amount(kernel) -= shift;
4175 boxwidth = boxwidth - shift;
4176 }
4177 overshoot = subwidth - boxwidth;
4178 if (overshoot > 0) {
4179 boxwidth += overshoot;
4180 }
4181 }
4182 box_width(kernel) = boxwidth;
4183 } else {
4184
4185 if (supwidth > boxwidth) {
4186 boxwidth = supwidth;
4187 }
4188 if (subwidth > boxwidth) {
4189 boxwidth = subwidth;
4190 }
4191 superscript = tex_aux_rebox(superscript, boxwidth, size);
4192 kernel = tex_aux_rebox(kernel, boxwidth, size);
4193 subscript = tex_aux_rebox(subscript, boxwidth, size);
4194
4195 box_shift_amount(superscript) = topshift;
4196 box_shift_amount(subscript) = -bottomshift;
4197 }
4198
4199 box_width(result) = boxwidth;
4200 box_height(result) = box_height(kernel);
4201 box_depth(result) = box_depth(kernel);
4202 } else {
4203 box_width(result) = box_width(kernel);
4204 box_height(result) = box_height(kernel);
4205 box_depth(result) = box_depth(kernel);
4206 }
4207
4220 if (noad_supscr(target)) {
4221 scaled bgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_above_bgap);
4222 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_above_vgap);
4223 scaled vkern = tex_get_math_y_parameter_checked(style, math_parameter_limit_above_kern);
4224 scaled vshift = bgap - box_depth(superscript);
4225 if (vshift < vgap) {
4226 vshift = vgap;
4227 }
4228 if (vshift) {
4229 halfword kern = tex_new_kern_node(vshift, vertical_math_kern_subtype);
4230 tex_attach_attribute_list_copy(kern, target);
4231 tex_couple_nodes(kern, kernel);
4232 tex_couple_nodes(superscript, kern);
4233 } else {
4234 tex_couple_nodes(kernel, superscript);
4235 }
4236 if (vkern) {
4237 halfword kern = tex_new_kern_node(vkern, vertical_math_kern_subtype);
4238 tex_attach_attribute_list_copy(kern, target);
4239 tex_couple_nodes(kern, superscript);
4240 box_list(result) = kern;
4241 } else {
4242 box_list(result) = superscript;
4243 }
4244 box_height(result) += vkern + box_total(superscript) + vshift;
4245 } else {
4246 box_list(superscript) = null;
4247 tex_flush_node(superscript);
4248 box_list(result) = kernel;
4249 }
4250 if (noad_subscr(target)) {
4251 scaled bgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_below_bgap);
4252 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_below_vgap);
4253 scaled vkern = tex_get_math_y_parameter_checked(style, math_parameter_limit_below_kern);
4254 scaled vshift = bgap - box_height(subscript);
4255 if (vshift < vgap) {
4256 vshift = vgap;
4257 }
4258 if (vshift) {
4259 halfword kern = tex_new_kern_node(vshift, vertical_math_kern_subtype);
4260 tex_attach_attribute_list_copy(kern, target);
4261 tex_couple_nodes(kernel, kern);
4262 tex_couple_nodes(kern, subscript);
4263 } else {
4264 tex_couple_nodes(kernel, subscript);
4265 }
4266 if (vkern) {
4267 halfword kern = tex_new_kern_node(vkern, vertical_math_kern_subtype);
4268 tex_attach_attribute_list_copy(kern, target);
4269 tex_couple_nodes(subscript, kern);
4270 }
4271 box_depth(result) += vkern + box_total(subscript) + vshift;
4272 } else {
4273 box_list(subscript) = null;
4274 tex_flush_node(subscript);
4275 }
4276 if (noad_subscr(target)) {
4277 kernel_math_list(noad_subscr(target)) = null;
4278 tex_flush_node(noad_subscr(target));
4279 noad_subscr(target) = null;
4280 }
4281 if (noad_supscr(target)) {
4282 kernel_math_list(noad_supscr(target)) = null;
4283 tex_flush_node(noad_supscr(target));
4284 noad_supscr(target) = null;
4285 }
4286 tex_aux_assign_new_hlist(target, result);
4287
4288 return 0;
4289}
4290
4291
4295
4296static scaled tex_aux_op_wrapup(halfword target, int style, int size, int italic, kernset *kerns, int forceitalics)
4297{
4298 halfword box;
4299 int shiftaxis = 0;
4300 halfword chr = null;
4301 halfword fnt = null;
4302 halfword autoleft = null;
4303 halfword autoright = null;
4304 halfword autosize = has_noad_option_auto(target);
4305 scaled openupheight = has_noad_option_openupheight(target) ? noad_height(target) : 0;
4306 scaled openupdepth = has_noad_option_openupdepth(target) ? noad_depth(target) : 0;
4307 (void) kerns;
4308 if (has_noad_option_adapttoleft(target) && node_prev(target)) {
4309 autoleft = node_prev(target);
4310 if (node_type(autoleft) != simple_noad) {
4311 autoleft = null;
4312 } else {
4313 autoleft = noad_new_hlist(autoleft);
4314 }
4315 }
4316 if (has_noad_option_adapttoright(target) && node_next(target)) {
4317
4318 autoright = noad_nucleus(node_next(target));
4319 }
4320 tex_aux_fetch(noad_nucleus(target), "operator", &fnt, &chr);
4321
4322 if ((style < text_style) || autoleft || autoright || autosize) {
4323
4324 scaled opsize = tex_get_math_parameter(style, math_parameter_operator_size, NULL);
4325 if ((autoleft || autoright || autosize) && (opsize == undefined_math_parameter)) {
4326 opsize = 0;
4327 }
4328 if (opsize != undefined_math_parameter) {
4329
4330 halfword y = tex_new_node(delimiter_node, 0);
4331 tex_attach_attribute_list_copy(y, noad_nucleus(target));
4332 delimiter_small_family(y) = kernel_math_family(noad_nucleus(target));
4333 delimiter_small_character(y) = kernel_math_character(noad_nucleus(target));
4334 opsize = tex_aux_math_y_scaled(opsize, style);
4335 if (autoright) {
4336
4337 scaledwhd siz = tex_natural_hsizes(autoright, null, 0.0, 0, 0);
4338 scaled total = siz.ht + siz.dp;
4339 if (total > opsize) {
4340 opsize = total;
4341 }
4342 }
4343 if (autoleft && box_total(autoleft) > opsize) {
4344
4345 opsize = box_total(autoleft);
4346 }
4347
4348 opsize += limited_scaled(openupheight);
4349 opsize += openupdepth;
4350 box = tex_aux_make_delimiter(target, y, text_size, opsize, 0, style, ! has_noad_option_noaxis(target), NULL, &italic, 0, has_noad_option_nooverflow(target), NULL, 0, null);
4351 } else {
4352
4357 opsize = tex_char_total_from_font(fnt, chr) + openupheight + openupdepth + 1;
4358
4363 while (tex_char_has_tag_from_font(fnt, chr, list_tag) && tex_char_total_from_font(fnt, chr) < opsize) {
4364 halfword next = tex_char_next_from_font(fnt, chr);
4365 if (chr != next && tex_char_exists(fnt, next)) {
4366 chr = next;
4367 kernel_math_character(noad_nucleus(target)) = chr;
4368 } else {
4369 break;
4370 }
4371 }
4372 if (math_kernel_node_has_option(noad_nucleus(target), math_kernel_no_italic_correction) && ! forceitalics) {
4373 italic = 0;
4374 } else {
4375 italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
4376 }
4377 box = tex_aux_clean_box(noad_nucleus(target), style, style, math_nucleus_list, 0, NULL);
4378 shiftaxis = 1;
4379 }
4380 } else {
4381
4382 italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
4383 box = tex_aux_clean_box(noad_nucleus(target), style, style, math_nucleus_list, 0, NULL);
4384 box_height(box) += openupheight;
4385 box_depth(box) += openupdepth;
4386 shiftaxis = 1;
4387 }
4388 if (shiftaxis) {
4389
4390 box_shift_amount(box) = tex_half_scaled(box_height(box) - box_depth(box)) - tex_aux_math_axis(size);
4391 }
4392 if ((node_type(box) == hlist_node) && (openupheight || openupdepth)) {
4393 box_shift_amount(box) -= openupheight/2;
4394 box_shift_amount(box) += openupdepth/2;
4395 }
4396 if (forceitalics && italic && box_list(box)) {
4397
4410 tex_aux_math_insert_italic_kern(tex_tail_of_node_list(box_list(box)), italic, noad_nucleus(target), "operator");
4411 box_width(box) += italic;
4412 italic = 0;
4413 }
4414 node_type(noad_nucleus(target)) = sub_box_node;
4415 kernel_math_list(noad_nucleus(target)) = box;
4416 return italic;
4417}
4418
4419static scaled tex_aux_make_op(halfword target, int style, int size, int italic, int limits_mode, kernset *kerns)
4420{
4421 int forceitalics = node_subtype(target) == operator_noad_subtype && tex_math_has_class_option(operator_noad_subtype, operator_italic_correction_class_option);
4422 if (limits_mode == limits_horizontal_mode) {
4423
4424 } else if (! has_noad_option_limits(target) && ! has_noad_option_nolimits(target) && (style == display_style || style == cramped_display_style)) {
4425 limits_mode = limits_vertical_mode;
4426 noad_options(target) |= noad_option_limits;
4427 } else if (has_noad_option_nolimits(target)) {
4428 limits_mode = limits_horizontal_mode;
4429 } else if (has_noad_option_limits(target)) {
4430 limits_mode = limits_vertical_mode;
4431 }
4432 if (node_type(noad_nucleus(target)) == math_char_node) {
4433 italic = tex_aux_op_wrapup(target, style, size, italic, kerns, forceitalics);
4434 }
4435 switch (limits_mode) {
4436 case limits_horizontal_mode:
4437
4443 return tex_aux_op_no_limits(target, style, size, italic, kerns, forceitalics);
4444 case limits_vertical_mode:
4445
4451 return tex_aux_op_do_limits(target, style, size, italic, kerns, forceitalics);
4452 default:
4453
4457 return italic;
4458 }
4459}
4460
4461
4474
4475
4476
4477
4478
4496
4497static halfword tex_aux_check_ord(halfword current, halfword size, halfword next)
4498{
4499 if (! noad_has_following_scripts(current)) {
4500 halfword nucleus = noad_nucleus(current);
4501 switch (node_type(nucleus)) {
4502 case sub_mlist_node:
4503 {
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519 break;
4520 }
4521 case math_char_node:
4522 {
4523 halfword curchr = null;
4524 halfword curfnt = null;
4525 if (! next) {
4526 next = node_next(current);
4527 }
4528 tex_aux_fetch(nucleus, "ordinal", &curfnt, &curchr);
4529 if (curfnt && curchr) {
4530 halfword kern = 0;
4531 halfword italic = 0;
4532 if (next) {
4533 halfword nxtnucleus = noad_nucleus(next);
4534 halfword nxtfnt = null;
4535 halfword nxtchr = null;
4536 if (node_type(nxtnucleus) == math_char_node && kernel_math_family(nucleus) == kernel_math_family(nxtnucleus)) {
4537 tex_aux_fetch(nxtnucleus, "ordinal", &nxtfnt, &nxtchr);
4538 if (nxtfnt && nxtchr) {
4539 halfword mainclass = node_subtype(current);
4540
4541 if (tex_aux_math_engine_control(curfnt, math_control_apply_ordinary_kern_pair)) {
4542 if (math_kernel_node_has_option(nucleus, math_kernel_no_right_pair_kern) || math_kernel_node_has_option(nxtnucleus, math_kernel_no_left_pair_kern)) {
4543
4544 } else if (tex_math_has_class_option(mainclass, check_italic_correction_class_option)) {
4545
4546 } else if (tex_aux_math_engine_control(curfnt, math_control_apply_ordinary_italic_kern)) {
4547 kern = tex_aux_math_x_size_scaled(curfnt, tex_get_kern(curfnt, curchr, nxtchr), size);
4548 }
4549 }
4550 if (tex_aux_math_engine_control(curfnt, math_control_apply_ordinary_italic_kern)) {
4551 if (math_kernel_node_has_option(nucleus, math_kernel_no_italic_correction)) {
4552
4553 } else if (tex_math_has_class_option(mainclass, check_kern_pair_class_option)) {
4554
4555 } else if (tex_aux_math_engine_control(curfnt, math_control_apply_ordinary_italic_kern)) {
4556 italic = tex_aux_math_x_size_scaled(curfnt, tex_char_italic_from_font(curfnt, curchr), size);
4557 }
4558 }
4559 }
4560 }
4561 }
4562 if (kern) {
4563 current = tex_aux_math_insert_font_kern(current, kern, current, "ord");
4564 }
4565 if (italic) {
4566
4567 current = tex_aux_math_insert_italic_kern(current, italic, current, "ord");
4568 }
4569 }
4570 }
4571 break;
4572 }
4573 }
4574 return current;
4575}
4576
4577static halfword tex_aux_prepend_hkern_to_new_hlist(halfword box, scaled delta, halfword subtype, const char *trace)
4578{
4579 halfword list = noad_new_hlist(box);
4580 halfword kern = tex_new_kern_node(delta, (quarterword) subtype);
4581 tex_attach_attribute_list_copy(kern, box);
4582 if (list) {
4583 tex_couple_nodes(kern, list);
4584 }
4585 list = kern;
4586 noad_new_hlist(box) = list;
4587 tex_aux_trace_kerns(kern, "adding kern", trace);
4588 return list;
4589}
4590
4591static void tex_aux_append_hkern_to_box_list(halfword box, scaled delta, halfword subtype, const char *trace)
4592{
4593 halfword list = box_list(box);
4594 halfword kern = tex_new_kern_node(delta, (quarterword) subtype);
4595 tex_attach_attribute_list_copy(kern, box);
4596 if (list) {
4597 tex_couple_nodes(tex_tail_of_node_list(list), kern);
4598 } else {
4599 list = kern;
4600 }
4601 box_list(box) = list;
4602 box_width(box) += delta;
4603 tex_aux_trace_kerns(kern, "adding kern", trace);
4604}
4605
4606static void tex_aux_prepend_hkern_to_box_list(halfword box, scaled delta, halfword subtype, const char *trace)
4607{
4608 halfword list = box_list(box);
4609 halfword kern = tex_new_kern_node(delta, (quarterword) subtype);
4610 tex_attach_attribute_list_copy(kern, box);
4611 if (list) {
4612 tex_couple_nodes(kern, list);
4613 }
4614 list = kern;
4615 box_list(box) = list;
4616 box_width(box) += delta;
4617 tex_aux_trace_kerns(kern, "adding kern", trace);
4618}
4619
4620
4639
4640static halfword tex_aux_analyze_script(halfword init, scriptdata *data)
4641{
4642 if (init) {
4643 switch (node_type(init)) {
4644 case math_char_node :
4645 if (tex_aux_math_engine_control(null, math_control_analyze_script_nucleus_char)) {
4646 if (tex_aux_fetch(init, "script char", &(data->fnt), &(data->chr))) {
4647 return init;
4648 } else {
4649 goto NOTHING;
4650 }
4651 } else {
4652 break;
4653 }
4654 case sub_mlist_node:
4655 if (tex_aux_math_engine_control(null, math_control_analyze_script_nucleus_list)) {
4656 init = kernel_math_list(init);
4657 while (init) {
4658 switch (node_type(init)) {
4659 case kern_node:
4660 case glue_node:
4661 init = node_next(init);
4662 break;
4663 case simple_noad:
4664 {
4665 init = noad_nucleus(init);
4666 if (node_type(init) != math_char_node) {
4667 return null;
4668 } else if (tex_aux_fetch(init, "script list", &(data->fnt), &(data->chr))) {
4669 return init;
4670 } else {
4671 goto NOTHING;
4672 }
4673 }
4674case accent_noad:
4675 data->whatever = 1;
4676 goto NOTHING;
4677 default:
4678 goto NOTHING;
4679 }
4680 }
4681 }
4682 break;
4683 case sub_box_node:
4684 if (tex_aux_math_engine_control(null, math_control_analyze_script_nucleus_box)) {
4685 init = kernel_math_list(init);
4686 if (init && node_type(init) == hlist_node) {
4687 init = box_list(init);
4688 }
4689 while (init) {
4690 switch (node_type(init)) {
4691 case kern_node:
4692 case glue_node:
4693 init = node_next(init);
4694 break;
4695 case glyph_node:
4696 if (tex_aux_fetch(init, "script box", &(data->fnt), &(data->chr))) {
4697 return init;
4698 } else {
4699 goto NOTHING;
4700 }
4701 default:
4702 goto NOTHING;
4703 }
4704 }
4705 }
4706 break;
4707 }
4708 }
4709 NOTHING:
4710 data->fnt = null;
4711 data->chr = null;
4712 return null;
4713}
4714
4715
4722
4723static void tex_aux_get_math_sup_shifts(halfword target, halfword sup, halfword style, scaled *shift_up)
4724{
4725 if (has_noad_option_fixed_super_or_sub_script(target) || has_noad_option_fixed_super_and_sub_script(target)) {
4726 *shift_up = tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_up);
4727 } else {
4728 scaled clr = tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_up);
4729 scaled bot = tex_get_math_y_parameter_checked(style, math_parameter_superscript_bottom_min);
4730 if (*shift_up < clr) {
4731 *shift_up = clr;
4732 }
4733 clr = box_depth(sup) + bot;
4734 if (*shift_up < clr) {
4735 *shift_up = clr;
4736 }
4737 }
4738}
4739
4740static void tex_aux_get_math_sub_shifts(halfword target, halfword sub, halfword style, scaled *shift_down)
4741{
4742 if (has_noad_option_fixed_super_or_sub_script(target)) {
4743 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_down);
4744 } else if (has_noad_option_fixed_super_and_sub_script(target)) {
4745 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_shift_down);
4746 } else {
4747 scaled clr = tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_down);
4748 scaled top = tex_get_math_y_parameter_checked(style, math_parameter_subscript_top_max);
4749 if (*shift_down < clr) {
4750 *shift_down = clr;
4751 }
4752 clr = box_height(sub) - top;
4753 if (*shift_down < clr) {
4754 *shift_down = clr;
4755 }
4756 }
4757}
4758
4759static void tex_aux_get_math_sup_sub_shifts(halfword target, halfword sup, halfword sub, halfword style, scaled *shift_up, scaled *shift_down)
4760{
4761 if (has_noad_option_fixed_super_or_sub_script(target)) {
4762 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_down);
4763 } else if (has_noad_option_fixed_super_and_sub_script(target)) {
4764 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_shift_down);
4765 } else {
4766 scaled clr = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_shift_down);
4767 scaled gap = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_vgap);
4768 scaled bot = tex_get_math_y_parameter_checked(style, math_parameter_superscript_subscript_bottom_max);
4769 if (*shift_down < clr) {
4770 *shift_down = clr;
4771 }
4772 clr = gap - ((*shift_up - box_depth(sup)) - (box_height(sub) - *shift_down));
4773 if (clr > 0) {
4774 *shift_down += clr;
4775 clr = bot - (*shift_up - box_depth(sup));
4776 if (clr > 0) {
4777 *shift_up += clr;
4778 *shift_down -= clr;
4779 }
4780 }
4781 }
4782}
4783
4784static halfword tex_aux_combine_script(halfword target, halfword width, halfword pre, halfword post, halfword *k1, halfword *k2)
4785{
4786 *k1 = tex_new_kern_node(-(width + box_width(pre)), horizontal_math_kern_subtype);
4787 *k2 = tex_new_kern_node(width, horizontal_math_kern_subtype);
4788 tex_couple_nodes(*k1, pre);
4789 tex_couple_nodes(pre, *k2);
4790 if (post) {
4791 tex_couple_nodes(*k2, post);
4792 }
4793 post = tex_hpack(*k1, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
4794 tex_attach_attribute_list_copy(*k1, target);
4795 tex_attach_attribute_list_copy(*k2, target);
4796 tex_attach_attribute_list_copy(post, target);
4797 node_subtype(post) = math_pre_post_list;
4798 return post;
4799}
4800
4801
4827
4828
4841
4842static scaled tex_aux_math_kern_at(halfword fnt, int chr, int side, int value, int simple)
4843{
4844
4845 charinfo *ci = tex_get_charinfo(fnt, chr);
4846 if (ci->math) {
4847 scaled *kerns_heights;
4848 int n_of_kerns = tex_get_charinfo_math_kerns(ci, side);
4849 if (n_of_kerns == 0 || simple) {
4850
4851 switch (side) {
4852 case top_left_kern:
4853 return tex_char_top_left_kern_from_font(fnt, chr);
4854 case bottom_left_kern:
4855 return tex_char_bottom_left_kern_from_font(fnt, chr);
4856 case top_right_kern:
4857 return tex_char_top_right_kern_from_font(fnt, chr);
4858 case bottom_right_kern:
4859 return tex_char_bottom_right_kern_from_font(fnt, chr);
4860 default:
4861 return 0;
4862 }
4863 } else {
4864 switch (side) {
4865 case top_left_kern:
4866 kerns_heights = ci->math->top_left_math_kern_array;
4867 break;
4868 case bottom_left_kern:
4869 kerns_heights = ci->math->bottom_left_math_kern_array;
4870 break;
4871 case top_right_kern:
4872 kerns_heights = ci->math->top_right_math_kern_array;
4873 break;
4874 case bottom_right_kern:
4875 kerns_heights = ci->math->bottom_right_math_kern_array;
4876 break;
4877 default:
4878
4879 kerns_heights = NULL;
4880 return tex_confusion("math kern at");
4881 }
4882 }
4883 if (value < kerns_heights[0]) {
4884 return kerns_heights[1];
4885 } else {
4886 scaled kern = 0;
4887 for (int i = 0; i < n_of_kerns; i++) {
4888 scaled height = kerns_heights[i * 2];
4889 kern = kerns_heights[(i * 2) + 1];
4890 if (height > value) {
4891 return kern;
4892 }
4893 }
4894 return kern;
4895 }
4896 } else {
4897 return 0;
4898 }
4899}
4900
4901static scaled tex_aux_find_math_kern_simple(halfword f, int c, int cmd, int *found)
4902{
4903 if (tex_aux_math_engine_control(f, math_control_staircase_kern) && tex_char_exists(f, c)) {
4904
4905 scaled krn = tex_aux_math_kern_at(f, c, cmd == superscript_cmd ? top_right_kern : bottom_right_kern, 0, 1);
4906 *found = 1;
4907 return krn ? tex_aux_math_x_size_scaled(f, krn, lmt_math_state.size) : 0;
4908 } else {
4909 return MATH_KERN_NOT_FOUND;
4910 }
4911}
4912
4913inline static scaled tex_aux_max_left_kern_value(scaled *kerns, int n)
4914{
4915 if (kerns && n > 0) {
4916 scaled kern = 0;
4917 for (int i = 0; i < n; i++) {
4918 scaled value = kerns[(i * 2) + 1];
4919 if (value < kern) {
4920 kern = value;
4921 }
4922 }
4923 return -kern;
4924 } else {
4925 return 0;
4926 }
4927}
4928
4929static scaled tex_aux_math_left_kern(halfword fnt, int chr)
4930{
4931 charinfo *ci = tex_get_charinfo(fnt, chr);
4932 if (ci->math) {
4933 scaled top = 0;
4934 scaled bot = 0;
4935 {
4936 scaled *a = ci->math->top_left_math_kern_array;
4937 halfword n = a ? tex_get_charinfo_math_kerns(ci, top_left_kern) : 0;
4938 if (n) {
4939 top = tex_aux_max_left_kern_value(a, n);
4940 } else {
4941 top = tex_char_top_left_kern_from_font(fnt, chr);
4942 }
4943 }
4944 {
4945 scaled *a = ci->math->bottom_left_math_kern_array;
4946 halfword n = a ? tex_get_charinfo_math_kerns(ci, bottom_left_kern) : 0;
4947 if (n) {
4948 bot = tex_aux_max_left_kern_value(a, n);
4949 } else {
4950 bot = tex_char_bottom_left_kern_from_font(fnt, chr);
4951 }
4952 }
4953 return top > bot ? top : bot;
4954 } else {
4955 return 0;
4956 }
4957}
4958
4959
5007
5008static scaled tex_aux_find_math_kern(halfword l_f, int l_c, halfword r_f, int r_c, int cmd, scaled shift, int *found)
5009{
5010 if (tex_aux_math_engine_control(l_f, math_control_staircase_kern) &&
5011 tex_aux_math_engine_control(r_f, math_control_staircase_kern) &&
5012
5013 tex_char_exists(l_f, l_c) && tex_char_exists(r_f, r_c)) {
5014 scaled krn_l = 0;
5015 scaled krn_r = 0;
5016 scaled krn = 0;
5017 switch (cmd) {
5018 case superscript_cmd:
5019
5020 {
5021 scaled corr_height_top = tex_char_height_from_font(l_f, l_c);
5022 scaled corr_height_bot = -tex_char_depth_from_font(r_f, r_c) + shift;
5023 krn_l = tex_aux_math_kern_at(l_f, l_c, top_right_kern, corr_height_top, 0);
5024 krn_r = tex_aux_math_kern_at(r_f, r_c, bottom_left_kern, corr_height_top, 0);
5025 krn = krn_l + krn_r;
5026 krn_l = tex_aux_math_kern_at(l_f, l_c, top_right_kern, corr_height_bot, 0);
5027 krn_r = tex_aux_math_kern_at(r_f, r_c, bottom_left_kern, corr_height_bot, 0);
5028 }
5029 break;
5030 case subscript_cmd:
5031
5032 {
5033 scaled corr_height_top = tex_char_height_from_font(r_f, r_c) - shift;
5034 scaled corr_height_bot = -tex_char_depth_from_font(l_f, l_c);
5035 krn_l = tex_aux_math_kern_at(l_f, l_c, bottom_right_kern, corr_height_top, 0);
5036 krn_r = tex_aux_math_kern_at(r_f, r_c, top_left_kern, corr_height_top, 0);
5037 krn = krn_l + krn_r;
5038 krn_l = tex_aux_math_kern_at(l_f, l_c, bottom_right_kern, corr_height_bot, 0);
5039 krn_r = tex_aux_math_kern_at(r_f, r_c, top_left_kern, corr_height_bot, 0);
5040 }
5041 break;
5042 default:
5043 return tex_confusion("find math kern");
5044 }
5045 *found = 1;
5046 if ((krn_l + krn_r) < krn) {
5047 krn = krn_l + krn_r;
5048 }
5049 return krn ? tex_aux_math_x_size_scaled(l_f, krn, lmt_math_state.size) : 0;
5050 } else {
5051 return MATH_KERN_NOT_FOUND;
5052 }
5053}
5054
5055
5061
5062static int tex_aux_get_sup_kern(halfword kernel, scriptdata *sup, scaled shift_up, scaled supshift, scaled *supkern, kernset *kerns)
5063{
5064 int found = 0;
5065 *supkern = MATH_KERN_NOT_FOUND;
5066 if (sup->whatever) {
5067 *supkern = tex_aux_find_math_kern_simple(glyph_font(kernel), glyph_character(kernel), superscript_cmd, &found);
5068 if (found) {
5069 return found;
5070 }
5071 }
5072 if (sup->node) {
5073 *supkern = tex_aux_find_math_kern(glyph_font(kernel), glyph_character(kernel), sup->fnt, sup->chr, superscript_cmd, shift_up, &found);
5074 if (*supkern == MATH_KERN_NOT_FOUND) {
5075 *supkern = supshift;
5076 } else {
5077 if (*supkern) {
5078 tex_aux_trace_kerns(*supkern, "superscript kern", "regular");
5079 }
5080 *supkern += supshift;
5081 }
5082 return found;
5083 }
5084 if (kerns && kerns->topright) {
5085 *supkern = kerns->topright;
5086 if (*supkern == MATH_KERN_NOT_FOUND) {
5087 *supkern = supshift;
5088 } else {
5089 if (*supkern) {
5090 tex_aux_trace_kerns(*supkern, "superscript kern", "kernset top right");
5091 }
5092 *supkern += supshift;
5093 }
5094 return found;
5095 }
5096 *supkern = supshift;
5097 return found;
5098}
5099
5100static int tex_aux_get_sub_kern(halfword kernel, scriptdata *sub, scaled shift_down, scaled subshift, scaled *subkern, kernset *kerns)
5101{
5102 int found = 0;
5103 *subkern = MATH_KERN_NOT_FOUND;
5104 if (sub->whatever) {
5105 *subkern = tex_aux_find_math_kern_simple(glyph_font(kernel), glyph_character(kernel), subscript_cmd, &found);
5106 if (found) {
5107 return found;
5108 }
5109 }
5110 if (sub->node) {
5111 *subkern = tex_aux_find_math_kern(glyph_font(kernel), glyph_character(kernel), sub->fnt, sub->chr, subscript_cmd, shift_down, &found);
5112 if (*subkern == MATH_KERN_NOT_FOUND) {
5113 *subkern = subshift;
5114 } else {
5115 if (*subkern) {
5116 tex_aux_trace_kerns(*subkern, "subscript kern", "regular");
5117 }
5118 *subkern += subshift;
5119 }
5120 return found;
5121 }
5122 if (kerns && kerns->bottomright) {
5123 *subkern = kerns->bottomright;
5124 if (*subkern == MATH_KERN_NOT_FOUND) {
5125 *subkern = subshift;
5126 } else {
5127 if (*subkern) {
5128 tex_aux_trace_kerns(*subkern, "subscript kern", "kernset bottom right");
5129 }
5130 *subkern += subshift;
5131 }
5132 return found;
5133 }
5134 *subkern = subshift;
5135 return found;
5136}
5137
5138
5152
5153inline static scaled tex_aux_insert_italic_now(halfword target, halfword kernel, scaled italic)
5154{
5155 switch (node_type(noad_nucleus(target))) {
5156 case math_char_node:
5157 case math_text_char_node:
5158 {
5159 halfword fam = kernel_math_family(noad_nucleus(target));
5160 if (fam != unused_math_family) {
5161 halfword fnt = tex_fam_fnt(fam, lmt_math_state.size);
5162 if (! tex_aux_math_engine_control(fnt, math_control_apply_script_italic_kern)) {
5163
5164 italic = 0;
5165 } else if (noad_subscr(target)) {
5166
5167 } else {
5168
5169 tex_aux_math_insert_italic_kern(kernel, italic, noad_nucleus(target), "scripts");
5170 italic = 0;
5171 }
5172 } else {
5173
5174 italic = 0;
5175 }
5176 }
5177 break;
5178 }
5179 return italic;
5180}
5181
5182inline static int tex_aux_raise_prime_composed(halfword target)
5183{
5184 int mainclass = -1 ;
5185
5186 switch (node_type(target)) {
5187 case simple_noad:
5188 mainclass = node_subtype(target);
5189 break;
5190 case radical_noad:
5191 mainclass = radical_noad_subtype;
5192 break;
5193 case fraction_noad:
5194 mainclass = fraction_noad_subtype;
5195 break;
5196 case accent_noad:
5197 mainclass = accent_noad_subtype;
5198 break;
5199 case fence_noad:
5200
5201 mainclass = fenced_noad_subtype;
5202 break;
5203 }
5204 return mainclass >= 0 ? tex_math_has_class_option(mainclass, raise_prime_option) : 0;
5205}
5206
5207static halfword tex_aux_shift_to_kern(halfword target, halfword box, scaled shift)
5208{
5209 halfword result;
5210 if (box_source_anchor(box)) {
5211 halfword kern = tex_new_kern_node(shift, vertical_math_kern_subtype);
5212 tex_attach_attribute_list_copy(kern, target);
5213 tex_couple_nodes(kern, box);
5214 result = tex_vpack(kern, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
5215 tex_attach_attribute_list_copy(result, target);
5216 node_subtype(result) = math_scripts_list;
5217 box_shift_amount(result) = shift;
5218 } else {
5219 box_shift_amount(box) = shift;
5220 result = box;
5221 }
5222 return result;
5223}
5224
5225static int tex_aux_singled(halfword target, scaledwhd kernelsize, int style, halfword single)
5226{
5227 if (single) {
5228 scaled ht = tex_get_math_y_parameter_default(style, math_parameter_superscript_snap, 0);
5229 scaled dp = tex_get_math_y_parameter_default(style, math_parameter_subscript_snap, 0);
5230 return ht > 0 && dp > 0 && kernelsize.ht <= ht && kernelsize.dp <= dp;
5231 } else {
5232 return 0;
5233 }
5234}
5235
5236static void tex_aux_make_scripts(halfword target, halfword kernel, scaled italic, int style, scaled supshift, scaled subshift, scaled supdrop, kernset *kerns, halfword single)
5237{
5238 halfword result = null;
5239 halfword preresult = null;
5240 scaled prekern = 0;
5241 scaled primekern = 0;
5242 scaled shift_up = 0;
5243 scaled shift_down = 0;
5244 scaled prime_up = 0;
5245 scriptdata postsubdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .shifted = 0, .whatever = 0 };
5246 scriptdata postsupdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .shifted = 0, .whatever = 0 };
5247 scriptdata presubdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .shifted = 0, .whatever = 0 };
5248 scriptdata presupdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .shifted = 0, .whatever = 0 };
5249 scriptdata primedata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .shifted = 0, .whatever = 0 };
5250 halfword maxleftkern = 0;
5251
5252 scaled leftslack = 0;
5253 scaled rightslack = 0;
5254 scaledwhd kernelsize = { .wd = 0, .ht = 0, .dp = 0, .ic = 0 };
5255
5256 scaled topovershoot = 0;
5257 scaled botovershoot = 0;
5258 int italicmultiplier = 1;
5259 int splitscripts = 0;
5260 quarterword primestate = prime_unknown_location;
5261
5276 if (node_type(target) == accent_noad) {
5277 scaled top = tex_get_math_parameter_default(style, math_parameter_accent_top_overshoot, 0);
5278 scaled bot = tex_get_math_parameter_default(style, math_parameter_accent_bottom_overshoot, 0);
5279 topovershoot = scaledround(accent_top_overshoot(target) * top / 100.0);
5280 botovershoot = scaledround(accent_top_overshoot(target) * bot / 100.0);
5281 }
5282
5288 if (italic) {
5289 italic = tex_aux_insert_italic_now(target, kernel, italic);
5290 }
5291
5295 if (node_type(target) == simple_noad) {
5296 switch (node_subtype(target)) {
5297 case fenced_noad_subtype:
5298 splitscripts = tex_math_has_class_option(fenced_noad_subtype, unpack_class_option);
5299 break;
5300 case ghost_noad_subtype:
5301 splitscripts = has_noad_option_unpacklist(target);
5302 break;
5303 }
5304 }
5305
5310 tex_aux_assign_new_hlist(target, kernel);
5311 kernelsize = tex_natural_hsizes(kernel, null, 0.0, 0, 0);
5312 if (kerns && kerns->dimensions) {
5313 if (tex_aux_math_engine_control(kerns->font, math_control_ignore_kern_dimensions)) {
5314
5315 } else {
5316 if (kerns->height) {
5317 kernelsize.ht = kerns->height;
5318 }
5319 if (kerns->depth) {
5320 kernelsize.dp = kerns->depth;
5321 }
5322 }
5323 }
5324 switch (node_type(kernel)) {
5325 case glyph_node:
5326 postsubdata.node = tex_aux_analyze_script(noad_subscr(target), &postsubdata);
5327 postsupdata.node = tex_aux_analyze_script(noad_supscr(target), &postsupdata);
5328 primedata.node = tex_aux_analyze_script(noad_prime(target), &primedata);
5329 maxleftkern = tex_aux_math_left_kern(glyph_font(kernel), glyph_character(kernel));
5330
5331maxleftkern = tex_aux_math_x_scaled(maxleftkern, style);
5332 prime_up = 0;
5333 shift_up = 0;
5334 shift_down = 0;
5335 break;
5336 default:
5337 if (has_noad_option_single(target) || tex_aux_singled(target, kernelsize, style, single)) {
5338 prime_up = 0;
5339 shift_up = 0;
5340 shift_down = 0;
5341 } else {
5342
5343 kernelsize.ht -= supdrop;
5344
5345 prime_up = kernelsize.ht - tex_get_math_y_parameter_default(style, math_parameter_prime_shift_drop, 0);
5346 shift_up = kernelsize.ht - tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_drop);
5347 shift_down = kernelsize.dp + tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_drop);
5348 }
5349 break;
5350 }
5351
5355 if (noad_prime(target)) {
5356
5357 scaled shift = tex_get_math_y_parameter_default(style, math_parameter_prime_shift_up, 0);
5358 scaled raise = tex_get_math_y_parameter_default(style, tex_aux_raise_prime_composed(target) ? math_parameter_prime_raise_composed : math_parameter_prime_raise, 0);
5359 scaled distance = tex_get_math_x_parameter_default(style, math_parameter_prime_space_after, 0);
5360
5361 primedata.box = tex_aux_clean_box(noad_prime(target), (has_noad_option_nosupscript(target) ? style : tex_math_style_variant(style, math_parameter_prime_variant)), style, math_sup_list, 0, NULL);
5362 box_shift_amount(primedata.box) -= prime_up ? prime_up : shift;
5363 box_shift_amount(primedata.box) -= scaledround(box_height(primedata.box) * raise / 100.0);
5364 kernel_math_list(noad_prime(target)) = null;
5365 tex_flush_node(noad_prime(target));
5366 noad_prime(target) = null;
5367 if (noad_supscr(target)) {
5368 primestate = prime_at_end_location;
5369 } else if (noad_subscr(target)) {
5370 primestate = prime_above_sub_location;
5371 } else {
5372 primestate = prime_at_begin_location;
5373 }
5374 if (distance) {
5375 tex_aux_append_hkern_to_box_list(primedata.box, distance, horizontal_math_kern_subtype, "prime distance");
5376 }
5377 primedata.slack = distance;
5378 switch (primestate) {
5379
5380 case prime_at_begin_location:
5381 {
5382
5383 tex_aux_get_sup_kern(kernel, &primedata, shift_up, supshift, &primekern, kerns);
5384 if (italic) {
5385
5386 primekern += italic;
5387 italic = 0;
5388 }
5389 }
5390 break;
5391
5392 case prime_above_sub_location:
5393 {
5394
5395 tex_aux_get_sup_kern(kernel, &primedata, shift_up, supshift, &primekern, kerns);
5396 if (italic) {
5397
5398 primekern += italic;
5399 italic = 0;
5400 }
5401 if (primekern) {
5402 tex_aux_prepend_hkern_to_box_list(primedata.box, primekern, math_shape_kern_subtype, "prime kern");
5403
5404 primekern = 0;
5405 }
5406 }
5407 break;
5408
5409 case prime_at_end_location:
5410 {
5411 primekern = 0;
5412 }
5413 break;
5414 }
5415 }
5416
5422 postsupdata.shifted = noad_supscr(target) && has_noad_option_shiftedsupscript(target);
5423 postsubdata.shifted = noad_subscr(target) && has_noad_option_shiftedsubscript(target);
5424 presupdata.shifted = noad_supprescr(target) && has_noad_option_shiftedsupprescript(target);
5425 presubdata.shifted = noad_subprescr(target) && has_noad_option_shiftedsubprescript(target);
5426
5430 if (noad_supscr(target)) {
5431 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_superscript_shift);
5432 postsupdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_superscript_space);
5433 postsupdata.slack += tex_get_math_x_parameter_checked(style, math_parameter_space_after_script);
5434 postsupdata.box = tex_aux_clean_box(noad_supscr(target), (has_noad_option_nosupscript(target) ? style : tex_math_style_variant(style, math_parameter_superscript_variant)), style, math_sup_list, 0, NULL);
5435 if (extra) {
5436 box_height(postsupdata.box) += extra;
5437 box_shift_amount(postsupdata.box) -= extra;
5438 }
5439 if (postsupdata.slack) {
5440 tex_aux_append_hkern_to_box_list(postsupdata.box, postsupdata.slack, horizontal_math_kern_subtype, "post sup slack");
5441 }
5442 kernel_math_list(noad_supscr(target)) = null;
5443 tex_flush_node(noad_supscr(target));
5444 noad_supscr(target) = null;
5445 }
5446 if (noad_subscr(target)) {
5447 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_subscript_shift);
5448 postsubdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_subscript_space);
5449 postsubdata.slack += tex_get_math_x_parameter_checked(style, math_parameter_space_after_script);
5450 postsubdata.box = tex_aux_clean_box(noad_subscr(target), (has_noad_option_nosubscript(target) ? style : tex_math_style_variant(style, math_parameter_subscript_variant)), style, math_sub_list, 0, NULL);
5451 if (extra) {
5452 box_depth(postsubdata.box) += extra;
5453 box_shift_amount(postsubdata.box) += extra;
5454 }
5455 if (postsubdata.slack) {
5456 tex_aux_append_hkern_to_box_list(postsubdata.box, postsubdata.slack, horizontal_math_kern_subtype, "post sub slack");
5457 }
5458 kernel_math_list(noad_subscr(target)) = null;
5459 tex_flush_node(noad_subscr(target));
5460 noad_subscr(target) = null;
5461 }
5462 if (noad_supprescr(target)) {
5463 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_superprescript_shift);
5464 presupdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_superprescript_space);
5465 presupdata.slack += tex_get_math_x_parameter_default(style, math_parameter_space_before_script, 0);
5466 presupdata.box = tex_aux_clean_box(noad_supprescr(target), (has_noad_option_nosupprescript(target) ? style : tex_math_style_variant(style, math_parameter_superscript_variant)), style, math_sup_list, 0, NULL);
5467 if (maxleftkern) {
5468 tex_aux_append_hkern_to_box_list(presupdata.box, maxleftkern, math_shape_kern_subtype, "max left shape");
5469 }
5470 if (extra) {
5471 box_height(presupdata.box) += extra;
5472 box_shift_amount(presupdata.box) -= extra;
5473 }
5474 if (presupdata.slack) {
5475 tex_aux_prepend_hkern_to_box_list(presupdata.box, presupdata.slack, horizontal_math_kern_subtype, "pre sup slack");
5476 }
5477 kernel_math_list(noad_supprescr(target)) = null;
5478 tex_flush_node(noad_supprescr(target));
5479 noad_supprescr(target) = null;
5480 }
5481 if (noad_subprescr(target)) {
5482 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_subprescript_shift);
5483 presubdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_subprescript_space);
5484 presubdata.slack += tex_get_math_x_parameter_default(style, math_parameter_space_before_script, 0);
5485 presubdata.box = tex_aux_clean_box(noad_subprescr(target), (has_noad_option_nosubprescript(target) ? style : tex_math_style_variant(style, math_parameter_subscript_variant)), style, math_sub_list, 0, NULL);
5486 if (maxleftkern) {
5487 tex_aux_append_hkern_to_box_list(presubdata.box, maxleftkern, math_shape_kern_subtype, "max left shape");
5488 }
5489 if (extra) {
5490 box_depth(presubdata.box) += extra;
5491 box_shift_amount(presubdata.box) += extra;
5492 }
5493 if (presubdata.slack) {
5494 tex_aux_prepend_hkern_to_box_list(presubdata.box, presubdata.slack, horizontal_math_kern_subtype, "pre sub slack");
5495 }
5496 kernel_math_list(noad_subprescr(target)) = null;
5497 tex_flush_node(noad_subprescr(target));
5498 noad_subprescr(target) = null;
5499 }
5500
5504 if (presupdata.box) {
5505 noad_script_state(target) |= pre_super_script_state;
5506 }
5507 if (presubdata.box) {
5508 noad_script_state(target) |= pre_sub_script_state;
5509 }
5510 if (postsupdata.box) {
5511 noad_script_state(target) |= post_super_script_state;
5512 }
5513 if (postsubdata.box) {
5514 noad_script_state(target) |= post_sub_script_state;
5515 }
5516 if (primedata.box) {
5517 noad_script_state(target) |= prime_script_state;
5518 }
5519
5520 if (primestate == prime_above_sub_location) {
5521 rightslack = box_width(primedata.box) > box_width(postsubdata.box) ? primedata.slack : postsubdata.slack;
5522 } else if (postsupdata.box) {
5523 if (postsubdata.box) {
5524
5525 rightslack = box_width(postsupdata.box) > box_width(postsubdata.box) ? postsupdata.slack : postsubdata.slack;
5526 } else {
5527 rightslack = postsupdata.slack;
5528 }
5529 } else if (postsubdata.box) {
5530 rightslack = postsubdata.slack;
5531 }
5532
5533 if (primestate == prime_above_sub_location) {
5534 halfword list = noad_new_hlist(target);
5535 if (list) {
5536
5537 halfword overshoot = box_width(primedata.box) - box_width(postsubdata.box);
5538 halfword primebox = tex_hpack(primedata.box, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
5539 tex_attach_attribute_list_copy(primebox, primedata.box);
5540 box_width(primebox) = 0;
5541 tex_couple_nodes(tex_tail_of_node_list(list), primebox);
5542 primedata.box = null;
5543 if (overshoot > 0) {
5544 tex_aux_append_hkern_to_box_list(postsubdata.box, overshoot, math_shape_kern_subtype, "prime overshoot kern");
5545 }
5546 } else {
5547 list = primedata.box;
5548 }
5549 noad_new_hlist(target) = list;
5550 }
5551
5552 if (presupdata.box) {
5553 if (presubdata.box) {
5554
5555 leftslack = box_width(presupdata.box) > box_width(presubdata.box) ? presupdata.slack : presubdata.slack;
5556 } else {
5557 leftslack = presupdata.slack;
5558 }
5559 } else if (presubdata.box) {
5560 leftslack = presubdata.slack;
5561 }
5562 switch (primestate) {
5563 case prime_at_begin_location:
5564 kernelsize.wd += box_width(primedata.box);
5565 break;
5566 case prime_above_sub_location:
5567
5568 break;
5569 }
5570 if (postsupdata.box || postsubdata.box) {
5571
5574 scaled supkern = 0;
5575 scaled subkern = 0;
5576 if (! splitscripts) {
5577 if (presupdata.box) {
5578 prekern = box_width(presupdata.box);
5579 postsupdata.box = tex_aux_combine_script(target, kernelsize.wd, presupdata.box, postsupdata.box, &presupdata.kern, &postsupdata.kern);
5580 presupdata.box = null;
5581 }
5582 if (presubdata.box) {
5583
5584 if (box_width(presubdata.box) > prekern) {
5585 prekern = box_width(presubdata.box);
5586 }
5587 postsubdata.box = tex_aux_combine_script(target, kernelsize.wd, presubdata.box, postsubdata.box, &presubdata.kern, &postsubdata.kern);
5588 presubdata.box = null;
5589 }
5590 }
5591
5598 if (postsubdata.box && postsupdata.shifted) {
5599 halfword shift = tex_get_math_x_parameter_checked(style, math_parameter_subscript_shift_distance);
5600 halfword amount = box_width(postsupdata.box) + shift;
5601 tex_aux_prepend_hkern_to_box_list(postsubdata.box, amount, horizontal_math_kern_subtype, "post shifted");
5602 } else if (postsupdata.box && postsubdata.shifted) {
5603 halfword shift = tex_get_math_x_parameter_checked(style, math_parameter_superscript_shift_distance);
5604 halfword amount = box_width(postsubdata.box) + shift;
5605 tex_aux_prepend_hkern_to_box_list(postsupdata.box, amount, horizontal_math_kern_subtype, "post shifted");
5606 }
5607 if (presubdata.box && presupdata.shifted) {
5608 halfword shift = tex_get_math_x_parameter_checked(style, math_parameter_subprescript_shift_distance);
5609 halfword amount = box_width(presupdata.box) + shift;
5610 tex_aux_append_hkern_to_box_list(presubdata.box, amount, horizontal_math_kern_subtype, "pre shifted");
5611 } else if (presupdata.box && presubdata.shifted) {
5612 halfword shift = tex_get_math_x_parameter_checked(style, math_parameter_superprescript_shift_distance);
5613 halfword amount = box_width(presubdata.box) + shift;
5614 tex_aux_append_hkern_to_box_list(presupdata.box, amount, horizontal_math_kern_subtype, "pre shifted");
5615 }
5616
5617 if (postsupdata.box) {
5618
5619 tex_aux_get_math_sup_shifts(target, postsupdata.box, style, &shift_up);
5620 if (postsubdata.box) {
5621 tex_aux_get_math_sup_sub_shifts(target, postsupdata.box, postsubdata.box, style, &shift_up, &shift_down);
5622 tex_aux_get_sup_kern(kernel, &postsupdata, shift_up, supshift, &supkern, kerns);
5623 tex_aux_get_sub_kern(kernel, &postsubdata, shift_down, subshift, &subkern, kerns);
5624 if (primestate == prime_at_begin_location) {
5625 primekern += supkern ;
5626 subkern = 0;
5627 supkern = 0;
5628 } else {
5629 if (supkern) {
5630 tex_aux_prepend_hkern_to_box_list(postsupdata.box, supkern, math_shape_kern_subtype, "post sup shape");
5631 }
5632 if (subkern) {
5633 tex_aux_prepend_hkern_to_box_list(postsubdata.box, subkern, math_shape_kern_subtype, "post sub shape");
5634 }
5635 }
5636 if (italic) {
5637 tex_aux_prepend_hkern_to_box_list(postsupdata.box, italic, italic_kern_subtype, "italic");
5638 }
5639 if (presubdata.kern) {
5640 kern_amount(presubdata.kern) += -subkern;
5641 kern_amount(postsubdata.kern) += subkern;
5642 }
5643 if (presupdata.kern) {
5644
5645 kern_amount(presupdata.kern) += -supkern - italicmultiplier * italic;
5646 kern_amount(postsupdata.kern) += supkern + italicmultiplier * italic;
5647 }
5648 {
5649 halfword kern = tex_new_kern_node((shift_up - box_depth(postsupdata.box)) - (box_height(postsubdata.box) - shift_down), vertical_math_kern_subtype);
5650 tex_attach_attribute_list_copy(kern, target);
5651 tex_couple_nodes(postsupdata.box, kern);
5652 tex_couple_nodes(kern, postsubdata.box);
5653 result = tex_vpack(postsupdata.box, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
5654 tex_attach_attribute_list_copy(result, target);
5655 node_subtype(result) = math_scripts_list;
5656 box_shift_amount(result) = shift_down;
5657 }
5658 } else {
5659 tex_aux_get_sup_kern(kernel, &postsupdata, shift_up, supshift, &supkern, kerns);
5660 if (primestate == prime_at_begin_location) {
5661 primekern += supkern ;
5662 supkern = 0;
5663 } else if (supkern) {
5664 tex_aux_prepend_hkern_to_box_list(postsupdata.box, supkern, math_shape_kern_subtype, "post sup shape");
5665 }
5666 result = tex_aux_shift_to_kern(target, postsupdata.box, -shift_up);
5667 if (presupdata.kern) {
5668 kern_amount(presupdata.kern) += -supkern - subkern - italicmultiplier * italic;
5669 kern_amount(postsupdata.kern) += supkern + subkern + italicmultiplier * italic;
5670 }
5671 }
5672 } else {
5673 tex_aux_get_math_sub_shifts(target, postsubdata.box, style, &shift_down);
5674 tex_aux_get_sub_kern(kernel, &postsubdata, shift_down, subshift, &subkern, kerns);
5675 if (primestate == prime_at_begin_location) {
5676 subkern = 0;
5677 } else if (subkern) {
5678 tex_aux_prepend_hkern_to_box_list(postsubdata.box, subkern, math_shape_kern_subtype, "post sub shape");
5679 }
5680 result = tex_aux_shift_to_kern(target, postsubdata.box, shift_down);
5681 if (presubdata.kern) {
5682 kern_amount(presubdata.kern) += -subkern;
5683 kern_amount(postsubdata.kern) += subkern;
5684 }
5685 }
5686
5687 if (! splitscripts) {
5688 if (topovershoot) {
5689
5690 if (noad_script_state(target) & pre_super_script_state) {
5691 kern_amount(postsubdata.kern) -= topovershoot;
5692 kern_amount(postsupdata.kern) -= topovershoot;
5693 }
5694 if (noad_script_state(target) & post_sub_script_state) {
5695 kern_amount(presupdata.kern) += topovershoot;
5696 }
5697 }
5698 if (botovershoot) {
5699
5700 if (noad_script_state(target) & pre_sub_script_state) {
5701 kern_amount(presubdata.kern) -= botovershoot;
5702 kern_amount(presupdata.kern) -= botovershoot;
5703 }
5704 if (noad_script_state(target) & post_sub_script_state) {
5705 kern_amount(presubdata.kern) += botovershoot;
5706 }
5707 }
5708 goto PICKUP;
5709 }
5710 }
5711 if (presubdata.box) {
5712 if (presupdata.box) {
5713
5714 tex_aux_get_math_sup_shifts(target, presupdata.box, style, &shift_up);
5715 tex_aux_get_math_sup_sub_shifts(target, presupdata.box, presubdata.box, style, &shift_up, &shift_down);
5716 prekern = box_width(presupdata.box);
5717
5718 if (! splitscripts) {
5719 if (box_width(presubdata.box) > prekern) {
5720 prekern = box_width(presubdata.box);
5721 }
5722 presupdata.box = tex_aux_combine_script(target, kernelsize.wd, presupdata.box, null, &presupdata.kern, &postsupdata.kern);
5723 presubdata.box = tex_aux_combine_script(target, kernelsize.wd, presubdata.box, null, &presubdata.kern, &postsubdata.kern);
5724 }
5725 {
5726 halfword k = tex_new_kern_node((shift_up - box_depth(presupdata.box)) - (box_height(presubdata.box) - shift_down), vertical_math_kern_subtype);
5727 tex_attach_attribute_list_copy(k, target);
5728 tex_couple_nodes(presupdata.box, k);
5729 tex_couple_nodes(k, presubdata.box);
5730 preresult = tex_vpack(presupdata.box, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
5731 tex_attach_attribute_list_copy(preresult, target);
5732 node_subtype(preresult) = math_scripts_list;
5733 box_shift_amount(preresult) = shift_down;
5734 }
5735 } else {
5736 tex_aux_get_math_sub_shifts(target, presubdata.box, style, &shift_down);
5737 if (! splitscripts) {
5738 prekern = box_width(presubdata.box);
5739 presubdata.box = tex_aux_combine_script(target, kernelsize.wd, presubdata.box, null, &presubdata.kern, &postsubdata.kern);
5740 }
5741 box_shift_amount(presubdata.box) = shift_down;
5742 preresult = presubdata.box;
5743 }
5744 } else if (presupdata.box) {
5745 tex_aux_get_math_sup_shifts(target, presupdata.box, style, &shift_up);
5746 if (! splitscripts) {
5747 prekern = box_width(presupdata.box);
5748 presupdata.box = tex_aux_combine_script(target, kernelsize.wd, presupdata.box, null, &presupdata.kern, &postsupdata.kern);
5749 }
5750 box_shift_amount(presupdata.box) = -shift_up;
5751 preresult = presupdata.box;
5752 }
5753 PICKUP:
5754 if (primestate == prime_at_begin_location) {
5755 halfword list = noad_new_hlist(target);
5756 if (primekern) {
5757 tex_aux_prepend_hkern_to_box_list(primedata.box, primekern, math_shape_kern_subtype, "prime");
5758 }
5759 if (list) {
5760 tex_couple_nodes(tex_tail_of_node_list(list), primedata.box);
5761 } else {
5762 list = primedata.box;
5763 }
5764 noad_new_hlist(target) = list;
5765 }
5766 if (splitscripts) {
5767 halfword list = noad_new_hlist(target);
5768 if (preresult) {
5769 if (list) {
5770 tex_couple_nodes(preresult, list);
5771 }
5772 list = preresult;
5773 }
5774 if (result) {
5775 if (list) {
5776 tex_couple_nodes(tex_tail_of_node_list(list), result);
5777 } else {
5778 list = result;
5779 }
5780 }
5781 noad_new_hlist(target) = list;
5782 } else {
5783 if (preresult) {
5784 result = preresult;
5785 }
5786 if (prekern) {
5787
5788 halfword list = tex_aux_prepend_hkern_to_new_hlist(target, prekern, horizontal_math_kern_subtype, "pre compensation");
5789 tex_couple_nodes(tex_tail_of_node_list(list), result);
5790 } else if (noad_new_hlist(target)) {
5791 tex_couple_nodes(tex_tail_of_node_list(noad_new_hlist(target)), result);
5792 } else {
5793 noad_new_hlist(target) = result;
5794 }
5795 }
5796 if (primestate == prime_at_end_location) {
5797 tex_couple_nodes(tex_tail_of_node_list(result), primedata.box);
5798 rightslack = primedata.slack;
5799 }
5800 if (math_slack_mode_par > 0) {
5801 noad_left_slack(target) = leftslack;
5802 noad_right_slack(target) = rightslack;
5803 if (tracing_math_par >= 2) {
5804 tex_begin_diagnostic();
5805 tex_print_format("[math: script slack, left %p, right %p]", leftslack, rightslack);
5806 tex_end_diagnostic();
5807 }
5808 }
5809}
5810
5811
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835static halfword tex_aux_make_left_right(halfword target, int style, scaled max_d, scaled max_h, int size, delimiterextremes *extremes)
5836{
5837 halfword tmp;
5838 scaled ic = 0;
5839 int stack = 0;
5840 halfword mainclass = get_noad_main_class(target);
5841 halfword leftclass = get_noad_left_class(target);
5842 halfword rightclass = get_noad_right_class(target);
5843 scaled height = tex_aux_math_given_y_scaled(noad_height(target));
5844 scaled depth = tex_aux_math_given_y_scaled(noad_depth(target));
5845 int leftoperator = node_type(target) == fence_noad && node_subtype(target) == left_operator_side;
5846 max_h += fence_top_overshoot(target);
5847 max_d += fence_bottom_overshoot(target);
5848 if (extremes) {
5849 extremes->tfont = null_font;
5850 extremes->bfont = null_font;
5851 extremes->tchar = 0;
5852 extremes->tchar = 0;
5853 extremes->height = 0;
5854 extremes->depth = 0;
5855 }
5856 if (has_noad_option_scale(target)) {
5857 height = tex_aux_math_math_scale(height);
5858 depth = tex_aux_math_math_scale(depth);
5859 }
5860 tex_aux_set_current_math_size(style);
5861 if (height || depth || has_noad_option_exact(target)) {
5862 halfword lst;
5863 scaled delta = height + depth;
5864 tmp = tex_aux_make_delimiter(target, fence_delimiter_list(target), size, delta, 0, style, 0, &stack, &ic, 0, has_noad_option_nooverflow(target), extremes, 0, null);
5865
5866 noad_italic(target) = ic;
5867
5870
5871 if (! stack && has_noad_option_exact(target)) {
5872 if (extremes && extremes->height < height) {
5873 height = extremes->height;
5874 }
5875 if (extremes && extremes->depth < depth) {
5876 depth = extremes->depth;
5877 }
5878 }
5879 if (stack) {
5880 box_shift_amount(tmp) = depth;
5881 }
5882 if (has_noad_option_exact(target)) {
5883 height = box_height(tmp) - box_shift_amount(tmp);
5884 depth = box_depth(tmp) + box_shift_amount(tmp);
5885 }
5886 if (has_noad_option_axis(target)) {
5887
5888 if (has_noad_option_noaxis(target) && stack) {
5889
5890 } else {
5891 halfword axis = tex_aux_math_axis(size);
5892 height += axis;
5893 depth -= axis;
5894 box_shift_amount(tmp) -= axis;
5895 }
5896 }
5897 lst = tex_new_node(hlist_node, 0);
5898 tex_attach_attribute_list_copy(lst, target);
5899 box_dir(lst) = dir_lefttoright ;
5900 box_height(lst) = height;
5901 box_depth(lst) = depth;
5902 box_width(lst) = box_width(tmp);
5903 box_list(lst) = tmp;
5904 tmp = lst;
5905 } else {
5906 int axis = ! has_noad_option_noaxis(target);
5907 scaled delta = 0;
5908 if (leftoperator && has_noad_option_auto(target)) {
5909
5910 if (style < text_style) {
5911 scaled s = tex_get_math_y_parameter_checked(style, math_parameter_operator_size);
5912 if (s > max_h + max_d) {
5913 max_h = scaledround(s / 2.0);
5914 max_d = max_h;
5915 delta = max_h + max_d;
5916 }
5917 }
5918 }
5919 if (has_noad_option_auto_middle(target)) {
5920 delta = max_h + max_d;
5921 } else if (! delta) {
5922 delta = tex_aux_get_delimiter_height(max_h, max_d, axis, size, style);
5923 }
5924 tmp = tex_aux_make_delimiter(target, fence_delimiter_list(target), size, delta, 0, style, axis, &stack, &ic, 0, has_noad_option_nooverflow(target), extremes, 0, null);
5925 }
5926
5927 noad_height(target) = height;
5928 noad_depth(target) = depth;
5929 fence_delimiter_list(target) = null;
5930 noad_italic(target) = ic;
5931
5932 if (noad_source(target)) {
5933 box_source_anchor(tmp) = noad_source(target);
5934
5935 tex_set_box_geometry(tmp, anchor_geometry);
5936 }
5937
5938 if (leftoperator) {
5939 halfword s = tex_new_node(sub_box_node, 0);
5940 kernset kerns;
5941 tex_math_wipe_kerns(&kerns);
5942 tex_flush_node_list(noad_supscr(target));
5943 tex_flush_node_list(noad_subscr(target));
5944 tex_flush_node_list(noad_nucleus(target));
5945 if (kernel_math_list(fence_delimiter_top(target))) {
5946 noad_supscr(target) = fence_delimiter_top(target);
5947 fence_delimiter_top(target) = null;
5948 }
5949 if (kernel_math_list(fence_delimiter_bottom(target))) {
5950 noad_subscr(target) = fence_delimiter_bottom(target);
5951 fence_delimiter_bottom(target) = null;
5952 }
5953 kernel_math_list(s) = tmp;
5954 noad_nucleus(target) = s;
5955
5956 if (extremes && extremes->tfont) {
5957 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_top_kern_class_option)) {
5958 kerns.topright = tex_aux_math_x_size_scaled(extremes->tfont, tex_char_top_right_kern_from_font(extremes->tfont, extremes->tchar), size);
5959 }
5960 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_bottom_kern_class_option)) {
5961 kerns.bottomright = tex_aux_math_x_size_scaled(extremes->bfont, tex_char_bottom_right_kern_from_font(extremes->bfont, extremes->bchar), size);
5962 }
5963 if (tex_math_has_class_option(fenced_noad_subtype, prefer_delimiter_dimensions_class_option)) {
5964 kerns.height = extremes->height;
5965 kerns.depth = extremes->depth;
5966 kerns.dimensions = 1;
5967 kerns.font = extremes->tfont;
5968 kerns.character = extremes->tchar;
5969 }
5970 }
5971
5972 tex_aux_make_op(target, style, size, ic, limits_unknown_mode, &kerns);
5973
5974 kernel_math_list(s) = null;
5975 tex_flush_node(s);
5976 } else {
5977 tex_aux_assign_new_hlist(target, tmp);
5978 }
5979
5980 switch (node_subtype(target)) {
5981 case left_fence_side:
5982 if (leftclass != unset_noad_class) {
5983 return leftclass;
5984 } else if (mainclass != unset_noad_class) {
5985 return mainclass;
5986 } else {
5987 return open_noad_subtype;
5988 }
5989 case middle_fence_side:
5990 if (mainclass != unset_noad_class) {
5991 return mainclass;
5992 } else {
5993 return middle_noad_subtype;
5994 }
5995 case right_fence_side:
5996 if (rightclass != unset_noad_class) {
5997 return rightclass;
5998 } else if (mainclass != unset_noad_class) {
5999 return mainclass;
6000 } else {
6001 return close_noad_subtype;
6002 }
6003 case left_operator_side:
6004 if (leftclass != unset_noad_class) {
6005 return leftclass;
6006 } else if (mainclass != unset_noad_class) {
6007 return mainclass;
6008 } else {
6009 return operator_noad_subtype;
6010 }
6011 default:
6012 if (mainclass != unset_noad_class) {
6013 return mainclass;
6014 } else {
6015
6016 return ordinary_noad_subtype;
6017 }
6018 }
6019}
6020
6021inline static int tex_aux_fallback_math_spacing_class(halfword style, halfword mathclass)
6022{
6023 unsigned parent = (unsigned) count_parameter(first_math_class_code + mathclass);
6024 switch (style) {
6025 case display_style: case cramped_display_style: return (parent >> 24) & 0xFF;
6026 case text_style: case cramped_text_style: return (parent >> 16) & 0xFF;
6027 case script_style: case cramped_script_style: return (parent >> 8) & 0xFF;
6028 case script_script_style: case cramped_script_script_style: return (parent >> 0) & 0xFF;
6029 default: return 0;
6030 }
6031}
6032
6033static halfword tex_aux_math_spacing_glue(halfword ltype, halfword rtype, halfword style, scaled mmu)
6034{
6035 halfword c = tex_to_math_spacing_parameter(ltype, rtype);
6036 halfword s = c;
6037 for (int i = 1; i <= 2; i++) {
6038 if (s >= 0) {
6039 halfword d = 0;
6040 halfword x = tex_get_math_parameter(style, s, &d);
6041 if (x) {
6042 switch (d) {
6043 case no_val_level:
6044 break;
6045 case dimension_val_level:
6046 if (x) {
6047 x = tex_aux_math_dimension(x, inter_math_skip_glue, c);
6048 if (tracing_math_par >= 2) {
6049 tex_begin_diagnostic();
6050 tex_print_format("[math: inter atom kern, left %n, right %n, resolved %i, amount %p]", ltype, rtype, s, kern_amount(x));
6051 tex_end_diagnostic();
6052 }
6053 return x;
6054 }
6055 goto NONE;
6056 case glue_val_level:
6057 if (! tex_glue_is_zero(x)) {
6058 x = tex_aux_math_glue(x, inter_math_skip_glue, c);
6059 if (tracing_math_par >= 2) {
6060 tex_begin_diagnostic();
6061 tex_print_format("[math: inter atom glue, left %n, right %n, resolved %i, amount %P]", ltype, rtype, s, glue_amount(x), glue_stretch(x), NULL, NULL, NULL, glue_shrink(x));
6062 tex_end_diagnostic();
6063 }
6064 return x;
6065 }
6066 goto NONE;
6067 case muglue_val_level:
6068 if (! tex_math_glue_is_zero(x)) {
6069 x = tex_aux_math_muglue(x, inter_math_skip_glue, mmu, c, style);
6070 if (tracing_math_par >= 2) {
6071 tex_begin_diagnostic();
6072 tex_print_format("[math: inter atom (mu) glue, left %n, right %n, resolved %i, amount %P]", ltype, rtype, s, glue_amount(x), glue_stretch(x), NULL, NULL, NULL, glue_shrink(x));
6073 tex_end_diagnostic();
6074 }
6075 return x;
6076 }
6077 goto NONE;
6078 default:
6079 if (tracing_math_par >= 2) {
6080 tex_begin_diagnostic();
6081 tex_print_format("[math: inter atom (mu) glue, left %n, right %n, resolved %i, unset]", ltype, rtype, s);
6082 tex_end_diagnostic();
6083 }
6084 goto NONE;
6085 }
6086 }
6087
6088 {
6089 halfword lparent = tex_aux_fallback_math_spacing_class(style, ltype);
6090 halfword rparent = tex_aux_fallback_math_spacing_class(style, rtype);
6091
6092 if (lparent != ltype || rparent != rtype) {
6093 s = tex_to_math_spacing_parameter(lparent, rtype);
6094 if (tex_has_math_parameter(style, s)) {
6095 goto FOUND;
6096 }
6097 s = tex_to_math_spacing_parameter(ltype, rparent);
6098 if (tex_has_math_parameter(style, s)) {
6099 goto FOUND;
6100 }
6101 s = tex_to_math_spacing_parameter(lparent, rparent);
6102 if (tex_has_math_parameter(style, s)) {
6103 goto FOUND;
6104 }
6105 }
6106
6107 s = tex_to_math_spacing_parameter(ltype, math_all_class);
6108 if (tex_has_math_parameter(style, s)) {
6109 goto FOUND;
6110 }
6111 s = tex_to_math_spacing_parameter(math_all_class, rtype);
6112 if (tex_has_math_parameter(style, s)) {
6113 goto FOUND;
6114 }
6115 s = tex_to_math_spacing_parameter(lparent, math_all_class);
6116 if (tex_has_math_parameter(style, s)) {
6117 goto FOUND;
6118 }
6119 s = tex_to_math_spacing_parameter(math_all_class, rparent);
6120 if (tex_has_math_parameter(style, s)) {
6121 goto FOUND;
6122 }
6123
6124 if (tracing_math_par >= 2) {
6125 tex_begin_diagnostic();
6126 tex_print_format("[math: inter atom fallback, left %n, right %n, left parent %n, right parent %n, not resolved]", ltype, rtype, lparent, rparent);
6127 tex_end_diagnostic();
6128 }
6129 goto NONE;
6130 FOUND:
6131 if (tracing_math_par >= 2) {
6132 tex_begin_diagnostic();
6133 tex_print_format("[math: inter atom fallback, left %n, right %n, left parent %n, right parent %n, resolved %i]", ltype, rtype, lparent, rparent, s);
6134 tex_end_diagnostic();
6135 }
6136 }
6137 } else {
6138
6139 goto NONE;
6140 }
6141 }
6142 NONE:
6143 if (math_spacing_mode_par && c >= 0) {
6144 if (math_spacing_mode_par == 1 && (ltype == math_begin_class || rtype == math_end_class)) {
6145 return null;
6146 } else {
6147 return tex_aux_math_dimension(0, inter_math_skip_glue, c);
6148 }
6149 } else {
6150 return null;
6151 }
6152}
6153
6154inline static int tex_aux_fallback_math_ruling_class(halfword style, halfword mathclass)
6155{
6156 unsigned parent = (unsigned) count_parameter(first_math_atom_code + mathclass);
6157 switch (style) {
6158 case display_style: case cramped_display_style: return (parent >> 24) & 0xFF;
6159 case text_style: case cramped_text_style: return (parent >> 16) & 0xFF;
6160 case script_style: case cramped_script_style: return (parent >> 8) & 0xFF;
6161 case script_script_style: case cramped_script_script_style: return (parent >> 0) & 0xFF;
6162 default: return 0;
6163 }
6164}
6165
6166static halfword tex_aux_math_ruling(halfword ltype, halfword rtype, halfword style)
6167{
6168 halfword c = tex_to_math_rules_parameter(ltype, rtype);
6169 halfword s = c;
6170 for (int i = 1; i <= 2; i++) {
6171 if (s >= 0) {
6172 halfword x = tex_get_math_parameter(style, s, NULL);
6173 if (x != MATHPARAMDEFAULT) {
6174 return x;
6175 } else {
6176 halfword lparent = tex_aux_fallback_math_ruling_class(style, ltype);
6177 halfword rparent = tex_aux_fallback_math_ruling_class(style, rtype);
6178 if (lparent != ltype || rparent != rtype) {
6179 s = tex_to_math_rules_parameter(lparent, rparent);
6180 } else {
6181 return MATHPARAMDEFAULT;
6182 }
6183 }
6184 } else {
6185 return MATHPARAMDEFAULT;
6186 }
6187 }
6188 return MATHPARAMDEFAULT;
6189}
6190
6191
6194
6195halfword tex_math_spacing_glue(halfword ltype, halfword rtype, halfword style)
6196{
6197
6198 halfword mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
6199 halfword sg = tex_aux_math_spacing_glue(ltype, rtype, style, mu);
6200 if (node_type(sg) == glue_node) {
6201 tex_add_glue_option(sg, glue_option_no_auto_break);
6202 }
6203 return sg;
6204}
6205
6206
6213
6214static halfword tex_aux_check_nucleus_complexity(halfword target, scaled *italic, halfword style, halfword size, kernset *kerns)
6215{
6216 halfword nucleus = noad_nucleus(target);
6217 if (nucleus) {
6218 if (italic) {
6219 *italic = 0;
6220 }
6221 switch (node_type(nucleus)) {
6222 case math_char_node:
6223 case math_text_char_node:
6224 {
6225 halfword chr = null;
6226 halfword fnt = null;
6227 if (tex_aux_fetch(nucleus, "(text) char", &fnt, &chr)) {
6228
6229 halfword glyph;
6230 quarterword subtype = 0;
6231
6232 switch (node_subtype(nucleus)) {
6233 case ordinary_noad_subtype: subtype = glyph_math_ordinary_subtype; break;
6234 case operator_noad_subtype: subtype = glyph_math_operator_subtype; break;
6235 case binary_noad_subtype: subtype = glyph_math_binary_subtype; break;
6236 case relation_noad_subtype: subtype = glyph_math_relation_subtype; break;
6237 case open_noad_subtype: subtype = glyph_math_open_subtype; break;
6238 case close_noad_subtype: subtype = glyph_math_close_subtype; break;
6239 case punctuation_noad_subtype: subtype = glyph_math_punctuation_subtype; break;
6240 case variable_noad_subtype: subtype = glyph_math_variable_subtype; break;
6241 case active_noad_subtype: subtype = glyph_math_active_subtype; break;
6242 case inner_noad_subtype: subtype = glyph_math_inner_subtype; break;
6243 case over_noad_subtype: subtype = glyph_math_over_subtype; break;
6244 case under_noad_subtype: subtype = glyph_math_under_subtype; break;
6245 case fraction_noad_subtype: subtype = glyph_math_fraction_subtype; break;
6246 case radical_noad_subtype: subtype = glyph_math_radical_subtype; break;
6247 case middle_noad_subtype: subtype = glyph_math_middle_subtype; break;
6248 case accent_noad_subtype: subtype = glyph_math_accent_subtype; break;
6249 case fenced_noad_subtype: subtype = glyph_math_fenced_subtype; break;
6250 case ghost_noad_subtype: subtype = glyph_math_ghost_subtype; break;
6251 default:
6252 if (node_subtype(nucleus) < math_begin_class) {
6253
6259 subtype = glyph_math_extra_subtype + node_subtype(nucleus);
6260 }
6261 break;
6262
6263 }
6264 glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
6265 tex_attach_attribute_list_copy(glyph, nucleus);
6266 if (node_type(nucleus) == math_char_node) {
6267 glyph_properties(glyph) = kernel_math_properties(nucleus);
6268 glyph_group(glyph) = kernel_math_group(nucleus);
6269 glyph_index(glyph) = kernel_math_index(nucleus);
6270 if (math_kernel_node_has_option(nucleus, math_kernel_auto_discretionary)) {
6271 tex_add_glyph_option(glyph, glyph_option_math_discretionary);
6272 }
6273 if (math_kernel_node_has_option(nucleus, math_kernel_full_discretionary)) {
6274 tex_add_glyph_option(glyph, glyph_option_math_italics_too);
6275 }
6276 }
6277
6281 if (math_kernel_node_has_option(nucleus, math_kernel_no_italic_correction)) {
6282
6285 } else if (tex_aux_math_followed_by_italic_kern(target, "complexity")) {
6286
6290 } else if (tex_aux_math_engine_control(fnt, math_control_apply_text_italic_kern)) {
6291
6295 if (italic) {
6296 *italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
6297 if (*italic) {
6298 if (node_type(nucleus) == math_text_char_node) {
6299 if (tex_aux_math_engine_control(fnt, math_control_check_text_italic_kern)) {
6300
6305 if (chr == letter_cmd) {
6306 *italic = 0;
6307 }
6308 }
6309 if (tex_aux_math_engine_control(fnt, math_control_check_space_italic_kern)) {
6310
6315 if (tex_get_font_space(fnt)) {
6316
6321 *italic = 0;
6322 }
6323 }
6324 }
6325 if (*italic && ! noad_has_following_scripts(target)) {
6326
6331 tex_aux_math_insert_italic_kern(glyph, *italic, nucleus, "check");
6332 *italic = 0;
6333 }
6334 }
6335 }
6336 }
6337 return glyph;
6338 } else {
6339 return tex_new_node(hlist_node, unknown_list);
6340 }
6341 }
6342 case sub_box_node:
6343 return kernel_math_list(nucleus);
6344 case sub_mlist_node:
6345 {
6346 halfword list = kernel_math_list(nucleus);
6347 halfword package = null;
6348 halfword fenced = node_type(target) == simple_noad && node_subtype(target) == fenced_noad_subtype;
6349 halfword last = fenced ? tex_tail_of_node_list(list) : null;
6350 int unpack = tex_math_has_class_option(node_subtype(target), unpack_class_option) || has_noad_option_unpacklist(target);
6351 halfword result = tex_mlist_to_hlist(list, unpack, style, unset_noad_class, unset_noad_class, kerns);
6352 tex_attach_attribute_list_copy(result, target);
6353 tex_aux_set_current_math_size(style);
6354 package = tex_hpack(result, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
6355 if (fenced) {
6356 node_subtype(package) = math_fence_list;
6357 if (list && node_type(list) == fence_noad && noad_analyzed(list) != unset_noad_class) {
6358 set_noad_left_class(target, noad_analyzed(list));
6359 }
6360 if (last && node_type(last) == fence_noad && noad_analyzed(last) != unset_noad_class) {
6361 set_noad_right_class(target, noad_analyzed(last));
6362 }
6363 } else if (unpack) {
6364 node_subtype(package) = math_list_list;
6365 } else if (noad_class_main(target) == unset_noad_class) {
6366 node_subtype(package) = math_pack_list;
6367 } else {
6368 node_subtype(package) = 0x100 + noad_class_main(target);
6369 }
6370
6371tex_attach_attribute_list_copy(package, target);
6372 return package;
6373 }
6374 case hlist_node:
6375
6376 break;
6377 default:
6378 tex_confusion("check nucleus complexity");
6379 }
6380 } else {
6381 tex_normal_warning("math", "recovering from missing nucleus, best check it out");
6382 noad_nucleus(target) = tex_aux_fake_nucleus(ghost_noad_subtype);
6383 }
6384 return tex_new_node(hlist_node, unknown_list);
6385}
6386
6387
6391
6392static halfword tex_aux_make_choice(halfword current, halfword style)
6393{
6394 halfword prv = node_prev(current);
6395 halfword nxt = node_next(current);
6396 halfword signal = tex_new_node(style_node, former_choice_math_style);
6397
6398 tex_try_couple_nodes(prv, signal);
6399 tex_try_couple_nodes(signal, nxt);
6400 switch (node_subtype(current)) {
6401 case normal_choice_subtype:
6402 {
6403 halfword choice = null;
6404 switch (style) {
6405 case display_style:
6406 case cramped_display_style:
6407 choice = choice_display_mlist(current);
6408 choice_display_mlist(current) = null;
6409 break;
6410 case text_style:
6411 case cramped_text_style:
6412 choice = choice_text_mlist(current);
6413 choice_text_mlist(current) = null;
6414 break;
6415 case script_style:
6416 case cramped_script_style:
6417 choice = choice_script_mlist(current);
6418 choice_script_mlist(current) = null;
6419 break;
6420 case script_script_style:
6421 case cramped_script_script_style:
6422 choice = choice_script_script_mlist(current);
6423 choice_script_script_mlist(current) = null;
6424 break;
6425 }
6426
6427 if (choice) {
6428 tex_couple_nodes(signal, choice);
6429 tex_try_couple_nodes(tex_tail_of_node_list(choice), nxt);
6430 }
6431 }
6432 break;
6433 case discretionary_choice_subtype:
6434 {
6435 halfword disc = tex_new_disc_node(normal_discretionary_code);
6436 halfword pre = choice_pre_break(current);
6437 halfword post = choice_post_break(current);
6438 halfword replace = choice_no_break(current);
6439 choice_pre_break(current) = null;
6440 choice_post_break(current) = null;
6441 choice_no_break(current) = null;
6442 if (pre) {
6443 pre = tex_mlist_to_hlist(pre, 0, style, unset_noad_class, unset_noad_class, NULL);
6444 tex_set_disc_field(disc, pre_break_code, pre);
6445 }
6446 if (post) {
6447 post = tex_mlist_to_hlist(post, 0, style, unset_noad_class, unset_noad_class, NULL);
6448 tex_set_disc_field(disc, post_break_code, post);
6449 }
6450 if (replace) {
6451 replace = tex_mlist_to_hlist(replace, 0, style, unset_noad_class, unset_noad_class, NULL);
6452 tex_set_disc_field(disc, no_break_code, replace);
6453 }
6454 disc_class(disc) = choice_class(current);
6455 disc = tex_math_make_disc(disc);
6456 tex_couple_nodes(signal, disc);
6457 tex_try_couple_nodes(disc, nxt);
6458 }
6459 break;
6460 }
6461
6462 tex_flush_node(current);
6463 return signal;
6464}
6465
6466
6471
6472static int tex_aux_make_fenced(halfword current, halfword current_style, halfword size, noad_classes *fenceclasses)
6473{
6474 halfword nucleus = noad_nucleus(current);
6475 (void) current_style;
6476 (void) size;
6477 if (nucleus) {
6478 halfword list = kernel_math_list(nucleus);
6479 if (list && node_type(list) == fence_noad && node_subtype(list) == left_operator_side) {
6480
6481 fenceclasses->main = noad_class_main(list);
6482 fenceclasses->left = noad_class_left(list);
6483 fenceclasses->right = noad_class_right(list);
6484 if (noad_supscr(current) && ! kernel_math_list(fence_delimiter_top(list))) {
6485 halfword n = tex_new_node(simple_noad, ordinary_noad_subtype);
6486 node_subtype(n) = math_char_node;
6487 noad_nucleus(n) = noad_supscr(current);
6488 kernel_math_list(fence_delimiter_top(list)) = n;
6489 noad_supscr(current) = null;
6490 if (tracing_math_par >= 2) {
6491 tex_begin_diagnostic();
6492 tex_print_str("[math: promoting supscript to top delimiter]");
6493 tex_end_diagnostic();
6494 }
6495 }
6496 if (noad_subscr(current) && ! kernel_math_list(fence_delimiter_bottom(list))) {
6497 halfword n = tex_new_node(simple_noad, ordinary_noad_subtype);
6498 node_subtype(n) = math_char_node;
6499 noad_nucleus(n) = noad_subscr(current);
6500 kernel_math_list(fence_delimiter_bottom(list)) = n;
6501 noad_subscr(current) = null;
6502 if (tracing_math_par >= 2) {
6503 tex_begin_diagnostic();
6504 tex_print_str("[math: promoting subscript to bottom delimiter]");
6505 tex_end_diagnostic();
6506 }
6507 }
6508
6512 {
6513 halfword nxt = node_next(list);
6514 if (nxt && node_type(nxt) == fence_noad && node_subtype(nxt) == right_fence_side) {
6515
6516 node_next(list) = null;
6517 tex_flush_node_list(nxt);
6518 }
6519 }
6520 return 1;
6521 }
6522 }
6523 return 0;
6524}
6525
6526static void tex_aux_finish_fenced(halfword current, halfword main_style, halfword main_size, scaled max_depth, scaled max_height, kernset *kerns)
6527{
6528 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
6529 noad_analyzed(current) = (singleword) tex_aux_make_left_right(current, main_style, max_depth, max_height, main_size, &extremes);
6530 if (kerns && extremes.tfont) {
6531 switch (node_subtype(current)) {
6532 case left_fence_side:
6533 case extended_left_fence_side:
6534 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_left_top_kern_class_option)) {
6535 kerns->topleft = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_left_kern_from_font(extremes.tfont, extremes.tchar), main_size);
6536 }
6537 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_left_bottom_kern_class_option)) {
6538 kerns->bottomleft = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_left_kern_from_font(extremes.bfont, extremes.bchar), main_size);
6539 }
6540 if (tex_math_has_class_option(fenced_noad_subtype, prefer_delimiter_dimensions_class_option)) {
6541 kerns->height = extremes.height;
6542 kerns->depth = extremes.depth;
6543 kerns->dimensions = 1;
6544 kerns->font = extremes.tfont;
6545 }
6546 break;
6547 case right_fence_side:
6548 case extended_right_fence_side:
6549 case left_operator_side:
6550 case no_fence_side:
6551 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_top_kern_class_option)) {
6552 kerns->topright = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_right_kern_from_font(extremes.tfont, extremes.tchar), main_size);
6553 }
6554 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_bottom_kern_class_option)) {
6555 kerns->bottomright = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_right_kern_from_font(extremes.bfont, extremes.bchar), main_size);
6556 }
6557 if (tex_math_has_class_option(fenced_noad_subtype, prefer_delimiter_dimensions_class_option)) {
6558 kerns->height = extremes.height;
6559 kerns->depth = extremes.depth;
6560 }
6561 break;
6562 }
6563 }
6564}
6565
6566
6574
6575static halfword tex_aux_unroll_noad(halfword tail, halfword l, quarterword s)
6576{
6577 while (l) {
6578 halfword n = node_next(l);
6579 node_next(l) = null;
6580 if (node_type(l) == hlist_node && node_subtype(l) == s && ! box_source_anchor(l)) {
6581 if (box_list(l)) {
6582 tex_couple_nodes(tail, box_list(l));
6583 tail = tex_tail_of_node_list(tail);
6584 box_list(l) = null;
6585 }
6586 tex_flush_node(l);
6587 } else {
6588 tex_couple_nodes(tail, l);
6589 tail = l;
6590 }
6591 l = n;
6592 }
6593 return tail;
6594}
6595
6596static halfword tex_aux_unroll_list(halfword tail, halfword l)
6597{
6598 while (l) {
6599 halfword n = node_next(l);
6600 node_next(l) = null;
6601 if (node_type(l) == hlist_node && ! box_source_anchor(l)) {
6602 if (box_list(l)) {
6603 switch (node_subtype(l)) {
6604 case hbox_list:
6605 case container_list:
6606 case math_list_list:
6607 tex_couple_nodes(tail, box_list(l));
6608 tail = tex_tail_of_node_list(tail);
6609 box_list(l) = null;
6610 break;
6611 default:
6612 tex_couple_nodes(tail, l);
6613 tail = l;
6614 break;
6615 }
6616 }
6617 tex_flush_node(l);
6618 } else {
6619 tex_couple_nodes(tail, l);
6620 tail = l;
6621 }
6622 l = n;
6623 }
6624 return tail;
6625}
6626
6627inline static void tex_aux_wipe_noad(halfword n)
6628{
6629 if (tex_nodetype_has_attributes(node_type(n))) {
6630 remove_attribute_list(n);
6631 }
6632 tex_reset_node_properties(n);
6633 tex_free_node(n, get_node_size(node_type(n)));
6634}
6635
6636static halfword tex_aux_append_ghost(halfword ghost, halfword p)
6637{
6638 halfword l = noad_new_hlist(ghost);
6639 if (l) {
6640 if (has_noad_option_unpacklist(ghost)) {
6641
6642 p = tex_aux_unroll_noad(p, l, math_list_list);
6643 } else if (has_noad_option_unrolllist(ghost)) {
6644 p = tex_aux_unroll_list(p, l);
6645 } else {
6646 if (node_type(l) == hlist_node && ! node_next(l)) {
6647 node_subtype(l) = math_ghost_list;
6648 }
6649 tex_couple_nodes(p, l);
6650 p = tex_tail_of_node_list(p);
6651 }
6652 noad_new_hlist(ghost) = null;
6653 }
6654 tex_aux_wipe_noad(ghost);
6655 return p;
6656}
6657
6658static halfword tex_aux_get_plus_glyph(halfword current)
6659{
6660 if (node_type(current) == simple_noad) {
6661 halfword list = noad_new_hlist(current);
6662 if (list && node_type(list) == hlist_node) {
6663 list = box_list(list);
6664 }
6665 if (list && node_type(list) == glue_node) {
6666 list = node_next(list);
6667 }
6668 if (list && node_type(list) == glyph_node && ! node_next(list)) {
6669 return list;
6670 }
6671 }
6672 return null;
6673}
6674
6675static void tex_aux_show_math_list(const char *fmt, halfword list)
6676{
6677 tex_begin_diagnostic();
6678 tex_print_format(fmt, lmt_math_state.level);
6679 tex_show_node_list(list, tracing_math_par >= 3 ? max_integer : show_box_depth_par, tracing_math_par >= 3 ? max_integer : show_box_breadth_par);
6680 tex_print_ln();
6681 tex_end_diagnostic();
6682}
6683
6684static halfword tex_aux_check_source(halfword current, halfword list, int repack)
6685{
6686 if (list && noad_source(current)) {
6687 switch (node_type(list)) {
6688 case hlist_node:
6689 case vlist_node:
6690
6691 box_source_anchor(list) = noad_source(current);
6692 tex_set_box_geometry(list, anchor_geometry);
6693 noad_source(current) = 0;
6694 break;
6695 default:
6696 if (repack) {
6697 if (tracing_math_par >= 2) {
6698 tex_begin_diagnostic();
6699 tex_print_format("[math: packing due to source field %D]", noad_source(current));
6700 tex_end_diagnostic();
6701 }
6702 list = tex_hpack(list, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
6703
6704 tex_attach_attribute_list_copy(list, current);
6705 box_source_anchor(list) = noad_source(current);
6706 noad_source(current) = 0;
6707 tex_set_box_geometry(list, anchor_geometry);
6708 noad_new_hlist(current) = list;
6709 node_subtype(list) = math_pack_list;
6710 }
6711 break;
6712 }
6713 } else {
6714
6715 }
6716 return list;
6717}
6718
6719static void tex_aux_wrapup_nucleus_and_add_scripts(halfword current, halfword nxt, int current_style, halfword *italic, kernset *kerns)
6720{
6721 halfword p = tex_aux_check_nucleus_complexity(current, italic, current_style, lmt_math_state.size, kerns);
6722 if (p && noad_source(current)) {
6723 p = tex_aux_check_source(current, p, has_noad_option_source_on_nucleus(current));
6724 }
6725 if (noad_has_scripts(current)) {
6726 scaled drop = 0;
6727 if (node_type(current) == accent_noad && noad_has_superscripts(current)) {
6728 drop = tex_get_math_y_parameter_default(current_style, math_parameter_accent_superscript_drop, 0);
6729 drop += scaledround(kerns->toptotal * tex_get_math_parameter_default(current_style, math_parameter_accent_superscript_percent, 0) / 100.0);
6730 }
6731 tex_aux_make_scripts(current, p, *italic, current_style, 0, 0, drop, kerns, lmt_math_state.single);
6732 lmt_math_state.single = 0;
6733 } else {
6734
6740 if (nxt && *italic) {
6741 if (node_type(nxt) == simple_noad && tex_math_has_class_option(node_subtype(nxt), no_italic_correction_class_option)) {
6742 *italic = 0;
6743 }
6744 if (*italic) {
6745
6746 tex_aux_math_insert_italic_kern(p, *italic, current, "final");
6747 }
6748 }
6749 tex_aux_assign_new_hlist(current, p);
6750 }
6751}
6752
6753
6763
6764typedef struct mliststate {
6765 halfword mlist;
6766 int penalties;
6767 int main_style;
6768 int beginclass;
6769 int endclass;
6770 kernset *kerns;
6771 halfword scale;
6772 scaled max_height;
6773 scaled max_depth;
6774 halfword single;
6775 halfword padding;
6776} mliststate;
6777
6778static void tex_mlist_to_hlist_set_boundaries(mliststate *state)
6779{
6780 halfword b = tex_aux_fake_nucleus((quarterword) state->beginclass);
6781 halfword e = tex_aux_fake_nucleus((quarterword) state->endclass);
6782 if (state->mlist) {
6783 tex_couple_nodes(b, state->mlist);
6784 }
6785 state->mlist = b;
6786 tex_couple_nodes(tex_tail_of_node_list(state->mlist), e);
6787 state->beginclass = unset_noad_class;
6788 state->endclass = unset_noad_class;
6789}
6790
6791static void tex_mlist_to_hlist_preroll_radicals(mliststate *state)
6792{
6793 halfword current = state->mlist;
6794 halfword current_style = state->main_style;
6795 halfword height = 0;
6796 halfword depth = 0;
6797 tex_aux_set_current_math_size(current_style);
6798 tex_aux_set_current_math_scale(state->scale);
6799 if (tracing_math_par >= 2) {
6800 tex_aux_show_math_list("[math: radical sizing pass, level %i]", state->mlist);
6801 }
6802 while (current) {
6803 switch (node_type(current)) {
6804 case radical_noad:
6805 {
6806 halfword body = null;
6807 tex_aux_preroll_radical(current, current_style, lmt_math_state.size);
6808 body = noad_new_hlist(current);
6809 if (box_height(body) > height) {
6810 height = box_height(body);
6811 }
6812 if (box_depth(body) > depth) {
6813 depth = box_depth(body);
6814 }
6815 }
6816 break;
6817 case style_node:
6818 tex_aux_make_style(current, ¤t_style, NULL);
6819 break;
6820 case parameter_node:
6821 tex_aux_set_parameter(current, current_style);
6822 break;
6823 }
6824 current = node_next(current);
6825 }
6826
6830 current = state->mlist;
6831 while (current) {
6832 if (node_type(current) == radical_noad) {
6833 switch (node_subtype(current)) {
6834 case normal_radical_subtype:
6835 case radical_radical_subtype:
6836 case root_radical_subtype:
6837 case rooted_radical_subtype:
6838 {
6839 halfword body = noad_new_hlist(current);
6840 if (radical_height(current) == max_dimension) {
6841 box_height(body) = height;
6842 } else if (radical_height(current) < 0) {
6843 box_height(body) += radical_height(current);
6844 if (box_height(body) < 0) {
6845 box_height(body) = 0;
6846 }
6847 } else if (radical_height(current)) {
6848 box_height(body) = radical_height(current);
6849 }
6850 if (radical_depth(current) == max_dimension) {
6851 box_depth(body) = depth;
6852 } else if (radical_depth(current) < 0) {
6853 box_depth(body) += radical_depth(current);
6854 if (box_depth(body) < 0) {
6855 box_depth(body) = 0;
6856 }
6857 } else if (radical_depth(current)) {
6858 box_depth(body) = radical_depth(current);
6859 }
6860 }
6861 break;
6862 }
6863 }
6864 current = node_next(current);
6865 }
6866}
6867
6868
6872
6873static void tex_mlist_to_hlist_preroll_dimensions(mliststate *state)
6874{
6875 halfword current = state->mlist;
6876 scaled current_mu = 0;
6877 halfword current_style = state->main_style;
6878 int blockrulebased = 0;
6879
6880 tex_aux_set_current_math_size(current_style);
6881 tex_aux_set_current_math_scale(state->scale);
6882
6883 current_mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
6884 if (tracing_math_par >= 2) {
6885 tex_aux_show_math_list("[math: first pass, level %i]", state->mlist);
6886 }
6887 while (current) {
6888
6889 scaled italic = 0;
6890 halfword nxt = node_next(current);
6891 noad_classes fenceclasses = { unset_noad_class, unset_noad_class, unset_noad_class };
6892 kernset localkerns;
6893 tex_math_wipe_kerns(&localkerns);
6894
6901 if (blockrulebased > 0) {
6902 blockrulebased -= 1;
6903 }
6904 switch (node_type(current)) {
6905 case simple_noad:
6906
6911 if (blockrulebased > 0) {
6912 noad_options(current) |= noad_option_no_ruling;
6913 blockrulebased = 0;
6914 }
6915 switch (node_subtype(current)) {
6916 case under_noad_subtype:
6917 tex_aux_make_under(current, current_style, lmt_math_state.size, math_rules_fam_par);
6918 break;
6919 case over_noad_subtype:
6920 tex_aux_make_over(current, current_style, lmt_math_state.size, math_rules_fam_par);
6921 break;
6922 case vcenter_noad_subtype:
6923 tex_aux_make_vcenter(current, current_style, lmt_math_state.size);
6924 break;
6925 case fenced_noad_subtype:
6926 if (tex_aux_make_fenced(current, current_style, lmt_math_state.size, &fenceclasses)) {
6927
6928 } else {
6929 break;
6930 }
6931 case operator_noad_subtype:
6932
6933 if (! (has_noad_option_limits(current) || has_noad_option_nolimits(current))) {
6934
6935 noad_options(current) |= (current_style == display_style || current_style == cramped_display_style) ? noad_option_limits : noad_option_no_limits;
6936 }
6937 goto PROCESS;
6938 default:
6939
6940 if ((has_noad_option_limits(current) && has_noad_option_nolimits(current))) {
6941 if (current_style == display_style || current_style == cramped_display_style) {
6942 noad_options(current) = unset_option(noad_options(current), noad_option_no_limits);
6943 noad_options(current) |= noad_option_limits;
6944 } else {
6945 noad_options(current) = unset_option(noad_options(current), noad_option_limits);
6946 noad_options(current) |= noad_option_no_limits;
6947 }
6948 }
6949 PROCESS:
6950 if (
6951
6952 has_noad_option_limits(current) || has_noad_option_nolimits(current)
6953 || has_noad_option_openupheight(current) || has_noad_option_openupdepth(current)
6954 || has_noad_option_adapttoleft(current) || has_noad_option_adapttoright(current)
6955 ) {
6956 if (node_subtype(current) == fenced_noad_subtype && ! noad_has_scripts(current)) {
6957
6962 italic = tex_aux_make_op(current, current_style, lmt_math_state.size, 0, limits_horizontal_mode, NULL);
6963 } else {
6964 italic = tex_aux_make_op(current, current_style, lmt_math_state.size, 0, limits_unknown_mode, NULL);
6965 }
6966
6967 if (node_subtype(current) != operator_noad_subtype) {
6968 italic = 0;
6969 }
6970 if (fenceclasses.main != unset_noad_class) {
6971 noad_class_main(current) = fenceclasses.main;
6972 }
6973 if (fenceclasses.left != unset_noad_class) {
6974 noad_class_left(current) = fenceclasses.left;
6975 }
6976 if (fenceclasses.right != unset_noad_class) {
6977 noad_class_right(current) = fenceclasses.right;
6978 }
6979 if (has_noad_option_limits(current) || has_noad_option_nolimits(current)) {
6980 goto CHECK_DIMENSIONS;
6981 }
6982 } else {
6983
6984 tex_aux_check_ord(current, lmt_math_state.size, null);
6985 }
6986 break;
6987 }
6988 break;
6989 case fence_noad:
6990 {
6991 state->single = has_noad_option_single(current);
6992
6993 current_style = state->main_style;
6994 tex_aux_set_current_math_size(current_style);
6995
6996 current_mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
6997
6998 goto DONE_WITH_NODE;
6999 }
7000 case fraction_noad:
7001 tex_aux_make_fraction(current, current_style, lmt_math_state.size, state->kerns);
7002 goto CHECK_DIMENSIONS;
7003 case radical_noad:
7004 tex_aux_make_radical(current, current_style, lmt_math_state.size, &localkerns);
7005 break;
7006 case accent_noad:
7007 tex_aux_make_accent(current, current_style, lmt_math_state.size, &localkerns);
7008 break;
7009 case style_node:
7010 tex_aux_make_style(current, ¤t_style, ¤t_mu);
7011 goto DONE_WITH_NODE;
7012 case choice_node:
7013 current = tex_aux_make_choice(current, current_style);
7014 goto DONE_WITH_NODE;
7015 case parameter_node:
7016
7017 tex_aux_set_parameter(current, current_style);
7018 goto DONE_WITH_NODE;
7019 case insert_node:
7020 case mark_node:
7021 case adjust_node:
7022 case boundary_node:
7023 case whatsit_node:
7024 case penalty_node:
7025 case disc_node:
7026 case par_node:
7027 goto DONE_WITH_NODE;
7028 case rule_node:
7029 tex_aux_check_math_strut_rule(current, current_style);
7030 if (rule_height(current) > state->max_height) {
7031 state->max_height = rule_height(current);
7032 }
7033 if (rule_depth(current) > state->max_depth) {
7034 state->max_depth = rule_depth(current);
7035 }
7036 goto DONE_WITH_NODE;
7037 case glue_node:
7038 if (node_subtype(current) == rulebased_math_glue) {
7039 blockrulebased = 2;
7040 }
7041 tex_aux_make_glue(current, current_mu, current_style);
7042 goto DONE_WITH_NODE;
7043 case kern_node:
7044 tex_aux_make_kern(current, current_mu, current_style);
7045 goto DONE_WITH_NODE;
7046 default:
7047 tex_confusion("mlist to hlist, case 1");
7048 }
7049
7058 tex_aux_wrapup_nucleus_and_add_scripts(current, nxt, current_style, &italic, &localkerns);
7059 CHECK_DIMENSIONS:
7060 {
7061 scaledwhd siz = tex_natural_hsizes(noad_new_hlist(current), null, normal_glue_multiplier, normal_glue_sign, normal_glue_sign);
7062 if (siz.ht > state->max_height) {
7063 state->max_height = siz.ht;
7064 }
7065 if (siz.dp > state->max_depth) {
7066 state->max_depth = siz.dp;
7067 }
7068 }
7069
7070 if ((node_type(current) == simple_noad) && noad_new_hlist(current)) {
7071 if (has_noad_option_phantom(current) || has_noad_option_void(current)) {
7072 noad_new_hlist(current) = tex_aux_make_list_phantom(noad_new_hlist(current), has_noad_option_void(current), get_attribute_list(current));
7073 }
7074 }
7075 DONE_WITH_NODE:
7076 current = node_next(current);
7077 }
7078}
7079
7080
7094
7095static void tex_mlist_to_hlist_size_fences(mliststate *state)
7096{
7097 halfword current = state->mlist;
7098 halfword current_style = state->main_style;
7099 scaled height = 0;
7100 scaled depth = 0;
7101 tex_aux_set_current_math_size(current_style);
7102 tex_aux_set_current_math_scale(state->scale);
7103 if (tracing_math_par >= 2) {
7104 tex_aux_show_math_list("[math: fence sizing pass, level %i]", state->mlist);
7105 }
7106
7107 while (current) {
7108 switch (node_type(current)) {
7109 case fence_noad:
7110 if (node_subtype(current) != middle_fence_side) {
7111 tex_aux_finish_fenced(current, current_style, lmt_math_state.size, state->max_depth, state->max_height, state->kerns);
7112 if (node_subtype(current) == left_fence_side || node_subtype(current) == right_fence_side) {
7113 halfword list = noad_new_hlist(current);
7114 if (list) {
7115 height = box_height(list);
7116 depth = box_depth(list);
7117 }
7118 }
7119 }
7120 break;
7121 case style_node:
7122 tex_aux_make_style(current, ¤t_style, NULL);
7123 break;
7124 case parameter_node:
7125
7126 tex_aux_set_parameter(current, current_style);
7127 break;
7128 }
7129 current = node_next(current);
7130 }
7131 current = state->mlist;
7132 while (current) {
7133 switch (node_type(current)) {
7134 case fence_noad:
7135 if (node_subtype(current) == middle_fence_side) {
7136 int automiddle = has_noad_option_auto_middle(current) && (height || depth);
7137 tex_aux_finish_fenced(current, current_style, lmt_math_state.size, automiddle ? depth : state->max_depth, automiddle ? height : state->max_height, state->kerns);
7138 }
7139 break;
7140 }
7141 current = node_next(current);
7142 }
7143}
7144
7145
7149
7150static void tex_mlist_to_hlist_finalize_list(mliststate *state)
7151{
7152 halfword recent = null;
7153 int recent_type = 0;
7154 int recent_subtype = ordinary_noad_subtype;
7155 halfword current_style = state->main_style;
7156 halfword fenced = null;
7157 halfword packedfence = null;
7158 halfword recent_left_slack = 0;
7159 halfword recent_right_slack = 0;
7160 halfword recent_class_overload = unset_noad_class;
7161 halfword recent_script_state = 0;
7162 halfword recent_plus_glyph = null;
7163 scaled current_mu = 0;
7164 halfword current = state->mlist;
7165 halfword p = temp_head;
7166 halfword ghost = null;
7167 int boundarylevel = 0;
7168 int boundaryfactor = scaling_factor;
7169 int nestinglevel = 0;
7170 int nestingfactor = scaling_factor;
7171 node_next(p) = null;
7172 tex_aux_set_current_math_size(current_style);
7173 tex_aux_set_current_math_scale(state->scale);
7174
7175 current_mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
7176 if (math_penalties_mode_par) {
7177 state->penalties = 1;
7178 }
7179 if (tracing_math_par >= 2) {
7180 tex_aux_show_math_list("[math: second pass, level %i]", state->mlist);
7181 }
7182 RESTART:
7183 while (current) {
7184
7199
7200 halfword current_type = simple_noad;
7201
7202 halfword current_subtype = ordinary_noad_subtype;
7203
7204 halfword post_penalty = infinite_penalty;
7205 halfword pre_penalty = infinite_penalty;
7206
7207 halfword current_left_slack = 0;
7208 halfword current_right_slack = 0;
7209 halfword current_script_state = 0;
7210 halfword current_plus_glyph = 0;
7211 halfword old_recent = 0;
7212 halfword old_current = 0;
7213 HERE:
7214 switch (node_type(current)) {
7215 case simple_noad:
7216 if (node_subtype(current) == ghost_noad_subtype) {
7217
7218 halfword nxt = node_next(current);
7219 if (ghost) {
7220
7221 halfword p = tex_tail_of_node_list(noad_new_hlist(ghost));
7222 noad_class_right(ghost) = noad_class_right(current);
7223 p = tex_aux_append_ghost(current, p);
7224 noad_new_hlist(ghost) = tex_head_of_node_list(p);
7225 } else {
7226 ghost = current;
7227 }
7228 current = nxt;
7229 if (current) {
7230 goto HERE;
7231 } else {
7232 goto RESTART;
7233 }
7234 } else {
7235
7238 current_subtype = node_subtype(current);
7239 current_left_slack = noad_left_slack(current);
7240 current_right_slack = noad_right_slack(current);
7241 current_script_state = noad_script_state(current);
7242 switch (current_subtype) {
7243 case fenced_noad_subtype:
7244 {
7245 fenced = current;
7246 if (get_noad_right_class(fenced) != unset_noad_class) {
7247 current_subtype = get_noad_left_class(fenced);
7248 } else if (get_noad_main_class(fenced) != unset_noad_class) {
7249 current_subtype = get_noad_main_class(fenced);
7250 } else {
7251 current_subtype = open_noad_subtype;
7252 }
7253 break;
7254 }
7255 default:
7256 {
7257 halfword list = noad_new_hlist(current);
7258 if (list && tex_is_math_disc(list)) {
7259 current_type = simple_noad;
7260 current_subtype = disc_class(box_list(list));
7261 }
7262 if (list && noad_source(current)) {
7263 tex_aux_check_source(current, list, 1);
7264 }
7265 break;
7266 }
7267 }
7268 if (get_noad_left_class(current) != unset_noad_class) {
7269 current_subtype = get_noad_left_class(current);
7270 } else if (get_noad_main_class(current) != unset_noad_class) {
7271 current_subtype = get_noad_main_class(current);
7272 }
7273 }
7274 break;
7275 case radical_noad:
7276 switch (node_subtype(current)) {
7277 case normal_radical_subtype:
7278 case radical_radical_subtype:
7279 case root_radical_subtype:
7280 case rooted_radical_subtype:
7281 case delimited_radical_subtype:
7282 current_type = simple_noad;
7283 current_subtype = radical_noad_subtype;
7284 break;
7285 case under_delimiter_radical_subtype:
7286 case delimiter_under_radical_subtype:
7287 current_type = simple_noad;
7288 current_subtype = under_noad_subtype;
7289 break;
7290 case over_delimiter_radical_subtype:
7291 case delimiter_over_radical_subtype:
7292 current_type = simple_noad;
7293 current_subtype = over_noad_subtype;
7294 break;
7295 case h_extensible_radical_subtype:
7296 current_type = simple_noad;
7297 current_subtype = accent_noad_subtype;
7298 break;
7299 }
7300 break;
7301 case accent_noad:
7302 current_type = simple_noad;
7303
7304 current_subtype = get_noad_main_class(current);
7305 current_left_slack = noad_left_slack(current);
7306 current_right_slack = noad_right_slack(current);
7307 break;
7308 case fraction_noad:
7309 current_type = simple_noad;
7310 current_subtype = fraction_noad_subtype;
7311 break;
7312 case fence_noad:
7313
7314 current_type = simple_noad;
7315 current_subtype = noad_analyzed(current);
7316 if (fence_nesting_factor(current) && fence_nesting_factor(current) != scaling_factor) {
7317 switch(current_subtype) {
7318 case open_noad_subtype:
7319 boundarylevel++;
7320 boundaryfactor = fence_nesting_factor(current);
7321 break;
7322 case close_noad_subtype:
7323 if (boundarylevel > 0) {
7324 boundarylevel--;
7325 if (boundarylevel == 0) {
7326 boundaryfactor = scaling_factor;
7327 } else {
7328 boundaryfactor = fence_nesting_factor(current);
7329 }
7330 } else {
7331 boundaryfactor = scaling_factor;
7332 }
7333 break;
7334 }
7335 }
7336 packedfence = current;
7337 break;
7338 case style_node:
7339 tex_aux_make_style(current, ¤t_style, ¤t_mu);
7340 recent = current;
7341 current = node_next(current);
7342 tex_aux_wipe_noad(recent);
7343 goto RESTART;
7344 case parameter_node:
7345 tex_aux_set_parameter(current, current_style);
7346 recent = current;
7347 current = node_next(current);
7348 tex_aux_wipe_noad(recent);
7349 goto RESTART;
7350 case glue_node:
7351 switch (node_subtype(current)) {
7352 case conditional_math_glue:
7353 case rulebased_math_glue:
7354 {
7355 halfword t = current;
7356 current = node_next(current);
7357 tex_flush_node(t);
7358 goto MOVEON;
7359 }
7360 default:
7361 break;
7362 }
7363 case boundary_node:
7364 if (node_subtype(current) == math_boundary) {
7365 halfword l = boundary_data(current);
7366 switch(l) {
7367 case 0:
7368 case 2:
7369 boundarylevel++;
7370 if (l == 2) {
7371 boundaryfactor = boundary_reserved(current) ? boundary_reserved(current) : scaling_factor;
7372 }
7373 break;
7374 case 1:
7375 case 3:
7376 if (boundarylevel > 0) {
7377 boundarylevel--;
7378 if (boundarylevel == 0) {
7379 boundaryfactor = scaling_factor;
7380 } else if (l == 2) {
7381 boundaryfactor = boundary_reserved(current) ? boundary_reserved(current) : scaling_factor;
7382 }
7383 } else {
7384 tex_formatted_warning("math", "invalid math boundary %i nesting", l);
7385 }
7386 break;
7387 default:
7388 tex_formatted_warning("math", "invalid math boundary value");
7389
7390 break;
7391 }
7392 }
7393 goto PICKUP;
7394
7395 case disc_node:
7396 case hlist_node:
7397 case whatsit_node:
7398 case penalty_node:
7399 case rule_node:
7400 case adjust_node:
7401 case insert_node:
7402 case mark_node:
7403 case par_node:
7404 case kern_node:
7405 PICKUP:
7406 tex_couple_nodes(p, current);
7407 p = current;
7408 current = node_next(current);
7409 node_next(p) = null;
7410 MOVEON:
7411 if (current) {
7412
7413 switch (node_type(p)) {
7414 case boundary_node:
7415 case adjust_node:
7416 case insert_node:
7417 case mark_node:
7418 case par_node:
7419 goto HERE;
7420 case rule_node:
7421 if (node_subtype(p) == strut_rule_subtype) {
7422 goto HERE;
7423 }
7424 }
7425 }
7426 continue;
7427
7428 default:
7429 tex_confusion("mlist to hlist, case 2");
7430 }
7431
7438 recent_class_overload = get_noad_right_class(current);
7439 if (current_type == simple_noad && state->beginclass == unset_noad_class) {
7440 if (noad_new_hlist(current)) {
7441 tex_flush_node(noad_new_hlist(current));
7442 noad_new_hlist(current) = null;
7443 }
7444 state->beginclass = current_subtype;
7445
7446 recent_type = current_type;
7447 recent_subtype = current_subtype;
7448 recent = current;
7449 current = node_next(current);
7450 goto WIPE;
7451 }
7452 if (recent_subtype == math_begin_class) {
7453 state->beginclass = current_subtype;
7454 }
7455
7459 if (tex_math_has_class_option(current_subtype, look_ahead_for_end_class_option)) {
7460 halfword endhack = node_next(current);
7461 if (endhack && node_type(endhack) == simple_noad && (node_subtype(endhack) == math_end_class || get_noad_main_class(endhack) == math_end_class)) {
7462 halfword value = tex_aux_math_ruling(current_subtype, math_end_class, current_style);
7463 if (value != MATHPARAMDEFAULT) {
7464
7465
7466 current_subtype = (value >> 16) & 0xFF;
7467 }
7468
7469 }
7470 }
7471 old_recent = recent_subtype;
7472 old_current = current_subtype;
7473 if (current_subtype != unset_noad_class && recent_subtype != unset_noad_class && current_type == simple_noad) {
7474 if (recent_type == simple_noad && ! has_noad_option_noruling(current)) {
7475 halfword value = tex_aux_math_ruling(recent_subtype, current_subtype, current_style);
7476 if (value != MATHPARAMDEFAULT) {
7477 recent_subtype = (value >> 16) & 0xFF;
7478 current_subtype = value & 0xFF;
7479 }
7480 }
7481 if (tracing_math_par >= 2) {
7482 tex_begin_diagnostic();
7483 if (old_recent != recent_subtype || old_current != current_subtype) {
7484 tex_print_format("[math: atom ruling, recent %n, current %n, new recent %n, new current %n]", old_recent, old_current, recent_subtype, current_subtype);
7485 } else {
7486 tex_print_format("[math: atom ruling, recent %n, current %n]", old_recent, old_current);
7487 }
7488 tex_end_diagnostic();
7489 }
7490 }
7491
7492 if (ghost && ! has_noad_option_right(ghost)) {
7493 p = tex_aux_append_ghost(ghost, p);
7494 ghost = null;
7495 }
7496 if (current_type == simple_noad) {
7497 pre_penalty = tex_aux_math_penalty(state->main_style, 1, current_subtype);
7498 post_penalty = tex_aux_math_penalty(state->main_style, 0, current_subtype);
7499 }
7500
7501 current_plus_glyph = tex_aux_get_plus_glyph(current);
7502
7503 if (current_plus_glyph && recent_script_state) {
7504
7505 halfword plus = tex_aux_checked_left_kern(current_plus_glyph, recent_script_state, current_subtype, lmt_math_state.size);
7506 if (plus) {
7507 halfword kern = tex_new_kern_node(plus, math_shape_kern_subtype);
7508 tex_attach_attribute_list_copy(kern, current);
7509 tex_couple_nodes(p, kern);
7510 p = kern;
7511 if (tracing_math_par >= 2) {
7512 tex_begin_diagnostic();
7513 tex_print_format("[math: state driven left shape kern %p]", plus);
7514 tex_end_diagnostic();
7515 }
7516 }
7517 }
7518 if (recent_type > 0) {
7519 halfword last = node_type(p);
7520 halfword glue = tex_aux_math_spacing_glue(recent_subtype, current_subtype, current_style, current_mu);
7521 halfword kern = null;
7522 if (glue) {
7523 tex_attach_attribute_list_copy(glue, current);
7524 }
7525 if (recent_right_slack) {
7526 halfword kern = tex_new_kern_node(-recent_right_slack, horizontal_math_kern_subtype);
7527 tex_attach_attribute_list_copy(kern, current);
7528 tex_couple_nodes(p, kern);
7529 p = kern;
7530 if (current_subtype >= 0 && tex_math_has_class_option(current_subtype, no_pre_slack_class_option)) {
7531
7532 } else if (! glue) {
7533 glue = tex_aux_math_dimension(recent_right_slack, inter_math_skip_glue, -2);
7534 } else {
7535 glue_amount(glue) += recent_right_slack;
7536 }
7537 if (tracing_math_par >= 2) {
7538 tex_begin_diagnostic();
7539 tex_print_format("[math: migrating right slack %p]", recent_right_slack);
7540 tex_end_diagnostic();
7541 }
7542 recent_right_slack = 0;
7543 }
7544 if (recent_plus_glyph && current_script_state) {
7545
7546 halfword plus = tex_aux_checked_right_kern(recent_plus_glyph, current_script_state, recent_subtype, lmt_math_state.size);
7547 if (plus) {
7548 halfword kern = tex_new_kern_node(plus, math_shape_kern_subtype);
7549 tex_attach_attribute_list_copy(kern, current);
7550 tex_couple_nodes(p, kern);
7551 p = kern;
7552 if (tracing_math_par >= 2) {
7553 tex_begin_diagnostic();
7554 tex_print_format("[math: state driven right shape kern %p]", plus);
7555 tex_end_diagnostic();
7556 }
7557 }
7558 }
7559 if (current_left_slack) {
7560 kern = tex_new_kern_node(-current_left_slack, horizontal_math_kern_subtype);
7561 tex_attach_attribute_list_copy(kern, p);
7562
7563
7564 if (recent_subtype >= 0 && tex_math_has_class_option(recent_subtype, no_post_slack_class_option)) {
7565
7566 } else if (! glue) {
7567 glue = tex_aux_math_dimension(current_left_slack, inter_math_skip_glue, -1);
7568 } else {
7569 glue_amount(glue) += current_left_slack;
7570 }
7571 current_left_slack = 0;
7572 }
7573
7576 if (tex_math_has_class_option(current_subtype, push_nesting_class_option)) {
7577 nestinglevel++;
7578 switch (current_style) {
7579 case display_style:
7580 case cramped_display_style:
7581 nestingfactor = math_display_penalty_factor_par ? math_display_penalty_factor_par : scaling_factor;
7582 break;
7583 default:
7584 nestingfactor = math_inline_penalty_factor_par ? math_inline_penalty_factor_par : scaling_factor;
7585 break;
7586 }
7587 } else if (tex_math_has_class_option(current_subtype, pop_nesting_class_option) && nestinglevel > 0) {
7588 nestinglevel--;
7589 if (nestinglevel == 0) {
7590 nestingfactor = scaling_factor;
7591 }
7592 }
7593 if (state->penalties && node_type(last) != penalty_node && pre_penalty <= infinite_penalty && (! boundarylevel || (boundaryfactor != scaling_factor || nestingfactor != scaling_factor))) {
7594 if (boundaryfactor != scaling_factor) {
7595 pre_penalty = tex_xn_over_d(pre_penalty, boundaryfactor, scaling_factor);
7596 } else if (nestingfactor != scaling_factor && tex_math_has_class_option(current_subtype, obey_nesting_class_option)) {
7597 pre_penalty = tex_xn_over_d(pre_penalty, nestingfactor, scaling_factor);
7598 }
7599 if (pre_penalty < infinite_penalty) {
7600
7601 halfword penalty = tex_new_penalty_node(pre_penalty, math_pre_penalty_subtype);
7602 tex_attach_attribute_list_copy(penalty, current);
7603 tex_couple_nodes(p, penalty);
7604 p = penalty;
7605 if (tracing_math_par >= 2) {
7606 tex_begin_diagnostic();
7607 tex_print_format("[math: pre penalty, left %n, right %n, amount %i]", recent_subtype, current_subtype, penalty_amount(penalty));
7608 tex_end_diagnostic();
7609 }
7610 }
7611 }
7612 if (tex_math_has_class_option(current_subtype, remove_italic_correction_class_option)) {
7613 if (node_type(p) == kern_node && node_subtype(p) == italic_kern_subtype) {
7614 halfword prv = node_prev(p);
7615 if (prv) {
7616 if (tracing_math_par >= 2) {
7617 tex_begin_diagnostic();
7618 tex_print_format("[math: removing italic correction %D between %i and %i]", kern_amount(p), recent_subtype, current_subtype);
7619 tex_end_diagnostic();
7620 }
7621 tex_flush_node(p);
7622 p = prv;
7623 }
7624 }
7625 }
7626 if (glue) {
7627 tex_couple_nodes(p, glue);
7628 p = glue;
7629 }
7630 if (kern) {
7631 tex_couple_nodes(p, kern);
7632 p = kern;
7633 }
7634 }
7635 if (ghost) {
7636 p = tex_aux_append_ghost(ghost, p);
7637 ghost = null;
7638 }
7639 {
7640 halfword l = noad_new_hlist(current);
7641 if (! l) {
7642
7643 } else if (node_type(l) == hlist_node && box_source_anchor(l)) {
7644 tex_couple_nodes(p, l);
7645 } else if (packedfence) {
7646
7647
7648 if (tex_math_has_class_option(fenced_noad_subtype, unpack_class_option)) {
7649 p = tex_aux_unroll_noad(p, l, math_fence_list);
7650 } else {
7651 tex_couple_nodes(p, l);
7652 }
7653 } else if ((current_subtype == open_noad_subtype || current_subtype == fenced_noad_subtype) && tex_math_has_class_option(fenced_noad_subtype, unpack_class_option)) {
7654
7655 p = tex_aux_unroll_noad(p, l, math_fence_list);
7656 } else if (has_noad_option_unpacklist(current) || tex_math_has_class_option(current_subtype, unpack_class_option)) {
7657
7658 p = tex_aux_unroll_noad(p, l, math_list_list);
7659 } else if (has_noad_option_unrolllist(current)) {
7660 p = tex_aux_unroll_list(p, l);
7661 } else if (tex_is_math_disc(l)) {
7662
7663 tex_couple_nodes(p, box_list(l));
7664 box_list(l) = null;
7665 tex_flush_node(l);
7666 } else if (current_type == simple_noad && (current_subtype == math_end_class || current_subtype == math_begin_class)) {
7667 if (noad_new_hlist(current)) {
7668 tex_flush_node(noad_new_hlist(current));
7669 noad_new_hlist(current) = null;
7670 }
7671 } else {
7672 tex_couple_nodes(p, l);
7673 }
7674 p = tex_tail_of_node_list(p);
7675 if (fenced) {
7676 if (get_noad_right_class(fenced) != unset_noad_class) {
7677 current_subtype = get_noad_right_class(fenced);
7678 } else if (get_noad_main_class(fenced) != unset_noad_class) {
7679 current_subtype = get_noad_main_class(fenced);
7680 } else {
7681 current_subtype = close_noad_subtype;
7682 }
7683 fenced = null;
7684 }
7685 noad_new_hlist(current) = null;
7686 packedfence = null;
7687 }
7688
7697 if (state->penalties && node_next(current) && post_penalty <= infinite_penalty && (! boundarylevel || (boundaryfactor != scaling_factor || nestingfactor != scaling_factor))) {
7698 if (boundaryfactor != scaling_factor) {
7699 post_penalty = tex_xn_over_d(post_penalty, boundaryfactor, scaling_factor);
7700 } else if (nestingfactor != scaling_factor && tex_math_has_class_option(current_subtype, obey_nesting_class_option)) {
7701 post_penalty = tex_xn_over_d(post_penalty, nestingfactor, scaling_factor);
7702 }
7703 if (post_penalty < infinite_penalty) {
7704 halfword recent = node_next(current);
7705 recent_type = node_type(recent);
7706 recent_subtype = node_subtype(recent);
7707
7708 if ((recent_type != penalty_node) && ! (recent_type == simple_noad && tex_math_has_class_option(recent_subtype, omit_penalty_class_option))) {
7709 halfword penalty = tex_new_penalty_node(post_penalty, math_post_penalty_subtype);
7710 tex_attach_attribute_list_copy(penalty, current);
7711 tex_couple_nodes(p, penalty);
7712 p = penalty;
7713 if (tracing_math_par >= 2) {
7714 tex_begin_diagnostic();
7715 tex_print_format("[math: post penalty, left %n, right %n, amount %i]", recent_subtype, current_subtype, penalty_amount(penalty));
7716 tex_end_diagnostic();
7717 }
7718 }
7719 }
7720 }
7721 if (recent_class_overload != unset_noad_class) {
7722 current_type = simple_noad;
7723 current_subtype = recent_class_overload;
7724 }
7725 if (current_type == simple_noad && current_subtype != math_end_class) {
7726 state->endclass = current_subtype;
7727 }
7728 recent_type = current_type;
7729 recent_subtype = current_subtype;
7730 recent_left_slack = current_left_slack;
7731 recent_right_slack = current_right_slack;
7732 recent_script_state = current_script_state;
7733 recent_plus_glyph = current_plus_glyph;
7734
7739
7740 if (p == temp_head && recent_left_slack) {
7741 halfword kern = tex_new_kern_node(-recent_left_slack, horizontal_math_kern_subtype);
7742 halfword head = node_next(temp_head);
7743 tex_attach_attribute_list_copy(kern, p);
7744 tex_couple_nodes(kern, head);
7745 node_next(temp_head) = kern;
7746 if (tracing_math_par >= 2) {
7747 tex_begin_diagnostic();
7748 tex_print_format("[math: nilling recent left slack %D]", recent_left_slack);
7749 tex_end_diagnostic();
7750 }
7751 }
7752 recent = current;
7753 current = node_next(current);
7754 if (! current && recent_right_slack) {
7755 halfword kern = tex_new_kern_node(-recent_right_slack, horizontal_math_kern_subtype);
7756 tex_attach_attribute_list_copy(kern, p);
7757 tex_couple_nodes(p, kern);
7758 p = kern;
7759 if (tracing_math_par >= 2) {
7760 tex_begin_diagnostic();
7761 tex_print_format("[math: nilling recent right slack %D]", recent_right_slack);
7762 tex_end_diagnostic();
7763 }
7764 }
7765
7766
7772 WIPE:
7773 tex_aux_wipe_noad(recent);
7774 }
7775 if (tracing_math_par >= 3) {
7776 tex_aux_show_math_list("[math: result, level %i]", node_next(temp_head));
7777 }
7778}
7779
7780halfword tex_mlist_to_hlist(halfword mlist, int penalties, int main_style, int beginclass, int endclass, kernset *kerns)
7781{
7782
7788 mliststate state;
7789 state.mlist = mlist;
7790 state.penalties = penalties;
7791 state.main_style = main_style;
7792 state.beginclass = beginclass == unset_noad_class ? math_begin_class : beginclass;
7793 state.endclass = endclass == unset_noad_class ? math_end_class : endclass;
7794 state.kerns = kerns;
7795 state.scale = glyph_scale_par;
7796 state.max_height = 0;
7797 state.max_depth = 0;
7798 state.single = 0;
7799 if (state.kerns) {
7800 tex_math_wipe_kerns(state.kerns);
7801 }
7802 ++lmt_math_state.level;
7803
7807 tex_mlist_to_hlist_set_boundaries(&state);
7808
7812 tex_mlist_to_hlist_preroll_radicals(&state);
7813
7817 tex_mlist_to_hlist_preroll_dimensions(&state);
7818
7821 tex_mlist_to_hlist_size_fences(&state);
7822
7835 tex_mlist_to_hlist_finalize_list(&state);
7836
7840 tex_unsave_math_data(cur_level + lmt_math_state.level);
7841 cur_list.math_begin = state.beginclass;
7842 cur_list.math_end = state.endclass;
7843 lmt_math_state.single = state.single;
7844 glyph_scale_par = state.scale;
7845 --lmt_math_state.level;
7846 node_prev(node_next(temp_head)) = null;
7847 return node_next(temp_head);
7848}
7849 |