1
4
5
16
17
61
62
69
70
152
153
208
209# include "luametatex.h"
210
211
221
222static void tex_aux_append_hkern_to_box_list (halfword q, scaled delta, halfword subtype, const char *trace);
223static void tex_aux_prepend_hkern_to_box_list(halfword q, scaled delta, halfword subtype, const char *trace);
224
225
267
268typedef struct scriptdata {
269 halfword node;
270 halfword fnt;
271 halfword chr;
272 halfword box;
273 scaled kern;
274 scaled slack;
275 int shifted;
276 int whatever;
277} scriptdata;
278
279typedef struct delimiterextremes {
280 scaled tfont;
281 scaled tchar;
282 scaled bfont;
283 scaled bchar;
284 scaled height;
285 scaled depth;
286} delimiterextremes;
287
288typedef enum limits_modes {
289 limits_unknown_mode,
290 limits_vertical_mode,
291 limits_horizontal_mode,
292} limits_modes;
293
294static inline void tex_math_wipe_kerns(kernset *kerns) {
295 if (kerns) {
296 kerns->topright = 0;
297 kerns->topleft = 0;
298 kerns->bottomright = 0;
299 kerns->bottomleft = 0;
300 kerns->height = 0;
301 kerns->depth = 0;
302 kerns->toptotal = 0;
303 kerns->bottomtotal = 0;
304 kerns->dimensions = 0;
305 kerns->font = null_font;
306 kerns->character = 0;
307 kerns->padding = 0;
308 }
309}
310
311static inline void tex_math_copy_kerns(kernset *kerns, kernset *parent) {
312 if (kerns && parent) {
313 kerns->topright = parent->topright;
314 kerns->topleft = parent->topleft;
315 kerns->bottomright = parent->bottomright;
316 kerns->bottomleft = parent->bottomleft;
317 kerns->height = parent->height;
318 kerns->depth = parent->depth;
319 kerns->toptotal = parent->toptotal;
320 kerns->bottomtotal = parent->bottomtotal;
321 kerns->dimensions = parent->dimensions;
322 kerns->font = parent->font;
323 kerns->character = parent->character;
324 }
325}
326
327
330
331static inline halfword tex_aux_set_style_to_size(halfword style)
332{
333 switch (style) {
334 case script_style:
335 case cramped_script_style:
336 return script_size;
337 case script_script_style:
338 case cramped_script_script_style:
339 return script_script_size;
340 default:
341 return text_size;
342 }
343}
344
345static inline void tex_aux_set_current_math_scale(halfword scale)
346{
347 glyph_scale_par = scale;
348 lmt_math_state.scale = glyph_scale_par;
349}
350
351static inline void tex_aux_set_current_math_size(halfword style)
352{
353 lmt_math_state.size = tex_aux_set_style_to_size(style);
354}
355
356static inline void tex_aux_make_style(halfword current, halfword *current_style, halfword *current_mu)
357{
358 halfword style = node_subtype(current);
359 switch (style) {
360 case scaled_math_style:
361 tex_aux_set_current_math_scale(style_scale(current));
362 break;
363 default:
364 if (is_valid_math_style(style)) {
365 if (current_style) {
366 *current_style = style;
367 }
368 tex_aux_set_current_math_size(style);
369 if (current_mu) {
370 *current_mu = scaledround(tex_get_math_parameter(style, math_parameter_quad, NULL) / 18.0);
371
372 }
373 }
374 break;
375 }
376}
377
378
384
385static inline void tex_aux_set_parameter(halfword current, halfword style)
386{
387 if (is_valid_math_style(node_subtype(current))) {
388 style = node_subtype(current);
389 }
390 tex_def_math_parameter(style, parameter_name(current), parameter_value(current), cur_level + lmt_math_state.level, indirect_math_regular, 0);
391}
392
393void tex_set_math_text_font(halfword style, int usetextfont)
394{
395 halfword size = tex_aux_set_style_to_size(style);
396 halfword font = tex_fam_fnt(cur_fam_par, size);
397 halfword scale = tex_get_math_font_scale(font, size);
398 switch (usetextfont) {
399 case math_atom_text_font_option:
400 scale = scaledround((double) scale * (double) lmt_font_state.fonts[font]->size / (double) lmt_font_state.fonts[cur_font_par]->size);
401 break;
402 case math_atom_math_font_option:
403 update_tex_font(0, font);
404 break;
405 }
406 update_tex_glyph_scale(scale);
407}
408
409static halfword tex_aux_math_penalty_what(int pre, halfword cls, halfword pre_code, halfword post_code)
410{
411 halfword value = count_parameter(pre ? (pre_code + cls) : (post_code + cls));
412 if (value == infinite_penalty) {
413 unsigned parent = (unsigned) count_parameter(first_math_parent_code + cls);
414 cls = pre ? ((parent >> 8) & 0xFF) : (parent & 0xFF);
415 if (! valid_math_class_code(cls)) {
416 return infinite_penalty;
417 }
418 value = count_parameter(pre ? (pre_code + cls) : (post_code + cls));
419 }
420 return value;
421}
422
423static halfword tex_aux_math_penalty(int main_style, int pre, halfword cls)
424{
425 switch (main_style) {
426 case display_style:
427 case cramped_display_style:
428 {
429 halfword value = tex_aux_math_penalty_what(pre, cls, first_math_display_pre_penalty_code, first_math_display_post_penalty_code);
430 if (value != infinite_penalty) {
431 return value;
432 } else {
433 break;
434 }
435 }
436 }
437 return tex_aux_math_penalty_what(pre, cls, first_math_pre_penalty_code, first_math_post_penalty_code);
438}
439
440static inline scaled limited_scaled(long l) {
441 if (l > max_dimension) {
442 return max_dimension;
443 } else if (l < -max_dimension) {
444 return -max_dimension;
445 } else {
446 return (scaled) l;
447 }
448}
449
450static inline scaled limited_rounded(double d) {
451 long l = scaledround(d);
452 if (l > max_dimension) {
453 return max_dimension;
454 } else if (l < -max_dimension) {
455 return -max_dimension;
456 } else {
457 return (scaled) l;
458 }
459}
460
461static inline int tex_aux_math_engine_control(halfword fnt, halfword control)
462{
463
464 if (fnt && (font_mathcontrol(fnt) & math_control_use_font_control) == math_control_use_font_control) {
465
469 return (font_mathcontrol(fnt) & control) == control;
470 }
471 return (math_font_control_par & control) == control;
472}
473
474
481
482static inline scaled tex_aux_math_math_scale(scaled v)
483{
484 return v ? scaledround(0.001 * lmt_math_state.scale * v) : 0;
485}
486
487static inline scaled tex_aux_math_glyph_scale(scaled v)
488{
489 return v ? scaledround(0.001 * glyph_scale_par * v) : 0;
490}
491
492static inline scaled tex_aux_math_glyph_x_scale(scaled v)
493{
494 return v ? scaledround(0.001 * glyph_x_scale_par * v) : 0;
495}
496
497static inline scaled tex_aux_math_glyph_y_scale(scaled v)
498{
499 return v ? scaledround(0.001 * glyph_y_scale_par * v) : 0;
500}
501
502static inline scaled tex_aux_math_glyph_weight(scaled v)
503{
504 return glyph_weight_par + v;
505}
506
507static inline scaled tex_aux_math_x_scaled(scaled v, int style)
508{
509 scaled scale = tex_get_math_parameter(style, math_parameter_x_scale, NULL);
510 return v ? limited_rounded(0.000000001 * glyph_scale_par * glyph_x_scale_par * v * scale) : 0;
511}
512
513static inline scaled tex_aux_math_given_x_scaled(scaled v)
514{
515 return v;
516}
517
518static inline scaled tex_aux_math_y_scaled(scaled v, int style)
519{
520 scaled scale = tex_get_math_parameter(style, math_parameter_y_scale, NULL);
521 return v ? limited_rounded(0.000000001 * glyph_scale_par * glyph_y_scale_par * v * scale) : 0;
522}
523
524static inline scaled tex_aux_math_given_y_scaled(scaled v)
525{
526 return v;
527}
528
529scaled tex_math_parameter_x_scaled(int style, int param)
530{
531 scaled scale = tex_get_math_parameter(style, math_parameter_x_scale, NULL);
532 scaled value = tex_get_math_parameter(style, param, NULL);
533 return value ? limited_rounded(0.000000001 * glyph_scale_par * glyph_x_scale_par * value * scale) : 0;
534}
535
536scaled tex_math_parameter_y_scaled(int style, int param)
537{
538 scaled value = tex_get_math_parameter(style, math_parameter_y_scale, NULL);
539 scaled scale = tex_get_math_parameter(style, param, NULL);
540 return value ? limited_rounded(0.000000001 * glyph_scale_par * glyph_y_scale_par * value * scale) : 0;
541}
542
543static inline scaled tex_aux_math_axis(halfword size)
544{
545 scaled v = tex_get_math_axis_size(size);
546 return v ? limited_rounded(0.000001 * glyph_scale_par * glyph_y_scale_par * v) : 0;
547}
548
549static inline scaled tex_aux_math_exheight(halfword size)
550{
551 scaled v = tex_get_math_exheight_size(size);
552 return v ? limited_rounded(0.000001 * glyph_scale_par * glyph_y_scale_par * v) : 0;
553}
554
555static inline scaled tex_aux_math_emwidth(halfword size)
556{
557 scaled v = tex_get_math_quad_size(size);
558 return v ? limited_rounded(0.000001 * glyph_scale_par * glyph_y_scale_par * v) : 0;
559}
560
561static inline scaled tex_aux_math_x_size_scaled(halfword f, scaled v, halfword size)
562{
563
564 return v ? limited_rounded(0.000000000001 * tex_get_math_font_scale(f, size) * tex_get_math_font_x_scale(f, size) * glyph_scale_par * glyph_x_scale_par * v) : 0;
565}
566
567static inline scaled tex_aux_math_y_size_scaled(halfword f, scaled v, halfword size)
568{
569
570 return v ? limited_rounded(0.000000000001 * tex_get_math_font_scale(f, size) * tex_get_math_font_y_scale(f, size) * glyph_scale_par * glyph_y_scale_par * v) : 0;
571}
572
573halfword tex_math_font_char_ht(halfword fnt, halfword chr, halfword style)
574{
575 return tex_aux_math_y_size_scaled(fnt, tex_char_height_from_font(fnt, chr), tex_aux_set_style_to_size(style));
576}
577
578halfword tex_math_font_char_dp(halfword fnt, halfword chr, halfword style)
579{
580 return tex_aux_math_y_size_scaled(fnt, tex_char_depth_from_font(fnt, chr), tex_aux_set_style_to_size(style));
581}
582
583static inline halfword tex_aux_new_math_glyph(halfword fnt, halfword chr, quarterword subtype) {
584 halfword scale = scaling_factor;
585 halfword xscale = scaling_factor;
586 halfword yscale = scaling_factor;
587 halfword weight = 0;
588 halfword glyph = tex_new_glyph_node(subtype, fnt, tex_get_math_char(fnt, chr, lmt_math_state.size, &scale, &xscale, &yscale, &weight, math_direction_par), null); ;
589 set_glyph_options(glyph, glyph_options_par);
590 glyph_scale(glyph) = tex_aux_math_glyph_scale(scale);
591
592
593 glyph_x_scale(glyph) = tex_aux_math_glyph_x_scale(xscale);
594 glyph_y_scale(glyph) = tex_aux_math_glyph_y_scale(yscale);
595 glyph_protected(glyph) = glyph_protected_math_code;
596glyph_weight(glyph) = tex_aux_math_glyph_weight(weight);
597 return glyph;
598}
599
600halfword tex_new_math_glyph(halfword fnt, halfword chr) {
601 return tex_aux_new_math_glyph(fnt, chr, 0);
602}
603
604static void tex_aux_trace_kerns(halfword kern, const char *what, const char *detail)
605{
606 if (tracing_math_par >= 2) {
607 tex_begin_diagnostic();
608 tex_print_format("[math: %s, %s, amount %p]", what, detail, kern_amount(kern));
609 tex_end_diagnostic();
610 }
611}
612
613static halfword tex_aux_math_insert_font_kern(halfword current, scaled amount, halfword attributetemplate, const char *trace)
614{
615
616 halfword kern = tex_new_kern_node(amount, font_kern_subtype);
617 tex_attach_attribute_list_copy(kern, attributetemplate ? attributetemplate : current);
618 if (node_next(current)) {
619 tex_couple_nodes(kern, node_next(current));
620 }
621 tex_couple_nodes(current, kern);
622 tex_aux_trace_kerns(kern, "adding font kern", trace);
623 return kern;
624}
625
626static halfword tex_aux_math_insert_italic_kern(halfword current, scaled amount, halfword attributetemplate, const char *trace)
627{
628
629 halfword kern = tex_new_kern_node(amount, italic_kern_subtype);
630 tex_attach_attribute_list_copy(kern, attributetemplate ? attributetemplate : current);
631 if (node_next(current)) {
632 tex_couple_nodes(kern, node_next(current));
633 }
634 tex_couple_nodes(current, kern);
635 tex_aux_trace_kerns(kern, "adding italic kern", trace);
636 return kern;
637}
638
639static int tex_aux_math_followed_by_italic_kern(halfword current, const char *trace)
640{
641 if (current) {
642 halfword next = node_next(current);
643 if (next && node_type(next) == kern_node && node_subtype(next) == italic_kern_subtype) {
644 tex_aux_trace_kerns(next, "ignoring italic kern", trace);
645 return 1;
646 }
647 }
648 return 0;
649}
650
651static inline int tex_aux_checked_left_kern_fnt_chr(halfword fnt, halfword chr, halfword state, halfword subtype, halfword size)
652{
653 halfword top = 0;
654 halfword bot = 0;
655 halfword hastop = (state & prime_script_state) || (state & post_super_script_state);
656 halfword hasbot = state & post_sub_script_state;
657 if (hastop && tex_math_has_class_option(subtype, left_top_kern_class_option)) {
658 top = tex_aux_math_x_size_scaled(fnt, tex_char_top_left_kern_from_font(fnt, chr), size);
659 }
660 if (hasbot && tex_math_has_class_option(subtype, left_bottom_kern_class_option)) {
661 bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_left_kern_from_font(fnt, chr), size);
662 }
663 if (hastop && hasbot) {
664 return top > bot ? top : bot;
665 } else if (hastop) {
666 return top;
667 } else {
668 return bot;
669 }
670}
671
672static inline int tex_aux_checked_left_kern(halfword list, halfword state, halfword subtype, halfword size)
673{
674 if (list && node_type(list) == glyph_node) {
675 return tex_aux_checked_left_kern_fnt_chr(glyph_font(list), glyph_character(list), state, subtype, size);
676 } else {
677 return 0;
678 }
679}
680
681static inline int tex_aux_checked_right_kern_fnt_chr(halfword fnt, halfword chr, halfword state, halfword subtype, halfword size)
682{
683 halfword top = 0;
684 halfword bot = 0;
685 halfword hastop = state & pre_super_script_state;
686 halfword hasbot = state & pre_sub_script_state;
687 if (hastop && tex_math_has_class_option(subtype, right_top_kern_class_option)) {
688 top = tex_aux_math_x_size_scaled(fnt, tex_char_top_right_kern_from_font(fnt, chr), size);
689 }
690 if (hasbot && tex_math_has_class_option(subtype, right_bottom_kern_class_option)) {
691 bot = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_right_kern_from_font(fnt, chr), size);
692 }
693 if (hastop && hasbot) {
694 return top < bot ? bot : top;
695 } else if (hastop) {
696 return top;
697 } else {
698 return bot;
699 }
700}
701
702static inline int tex_aux_checked_right_kern(halfword list, halfword state, halfword subtype, halfword size)
703{
704 if (list && node_type(list) == glyph_node) {
705 return tex_aux_checked_right_kern_fnt_chr(glyph_font(list), glyph_character(list), state, subtype, size);
706 } else {
707 return 0;
708 }
709}
710
711static scaled tex_aux_check_rule_thickness(halfword target, int size, halfword *fam, halfword control, halfword param)
712{
713 halfword family = noad_family(target);
714 if (family != unused_math_family) {
715 halfword font = tex_fam_fnt(family, size);
716 if (tex_aux_math_engine_control(font, control)) {
717 scaled thickness = tex_get_font_math_parameter(font, size, param);
718 if (thickness != undefined_math_parameter) {
719 *fam = family;
720 return thickness;
721 }
722 }
723 }
724 return undefined_math_parameter;
725}
726
727
728
729static halfword tex_aux_fake_nucleus(quarterword cls)
730{
731 halfword n = tex_new_node(simple_noad, cls);
732 halfword q = tex_new_node(math_char_node, 0);
733 tex_set_noad_classes(n, cls);
734 noad_nucleus(n) = q;
735 math_kernel_node_set_option(q, math_kernel_ignored_character);
736 return n;
737}
738
739
740
741static void tex_aux_fake_delimiter(halfword result)
742{
743 halfword amount = tex_aux_math_given_x_scaled(null_delimiter_space_par);
744 if (amount) {
745 box_width(result) = amount;
746 box_list(result) = tex_new_kern_node(amount, horizontal_math_kern_subtype);
747 tex_attach_attribute_list_copy(box_list(result), result);
748 }
749}
750
751
754
755static inline int tex_aux_has_delimiter(halfword delimiter, halfword size)
756{
757 return (
758 delimiter && (
759 (tex_fam_fnt(delimiter_small_family(delimiter), size) && delimiter_small_character(delimiter)) ||
760 (tex_fam_fnt(delimiter_large_family(delimiter), size) && delimiter_large_character(delimiter))
761 )
762 );
763}
764
765static inline int tex_aux_has_extensible(halfword delimiter, halfword size)
766{
767 if (delimiter && delimiter_small_character(delimiter)) {
768 halfword curfnt = tex_fam_fnt(delimiter_small_family(delimiter), size);
769 if (curfnt != null_font) {
770 return tex_char_extensible_recipe_front_last(curfnt, delimiter_small_character(delimiter)) ? 1 : 0;
771 }
772 }
773 return 0;
774}
775
776
780
781static scaled tex_aux_get_delimiter_height(scaled height, scaled depth, int axis, int size, int style)
782{
783 scaled delta1 = height + depth;
784 scaled delta2 = depth;
785 scaled delta3 = 0;
786 halfword percent = tex_get_math_parameter_default(style, math_parameter_delimiter_percent, 0);
787 scaled shortfall = tex_get_math_y_parameter_default(style, math_parameter_delimiter_shortfall, 0);
788 if (axis) {
789 delta2 += tex_aux_math_axis(size);
790 }
791 delta1 -= delta2;
792 if (delta2 > delta1) {
793
794 delta1 = delta2;
795 }
796 delta3 = scaledround((delta1 / 500.0) * delimiter_factor_par * (percent / 100.0));
797 delta2 = 2 * delta1 - delimiter_shortfall_par - shortfall;
798 return (delta3 < delta2) ? delta2 : delta3;
799}
800
801
813
814static const char *tex_aux_math_size_string(int s)
815{
816 switch (s) {
817 case script_script_size: return "scriptscriptfont";
818 case script_size: return "scriptfont";
819 default: return "textfont";
820 }
821}
822
823
824
825static halfword tex_aux_math_clone(halfword n)
826{
827 if (n) {
828 halfword result = tex_new_node(node_type(n), 0);
829 tex_attach_attribute_list_copy(result, n);
830 tex_math_copy_char_data(result, n, 0);
831 return result;
832 } else {
833 return null;
834 }
835}
836
837
841
842static halfword tex_aux_make_list_phantom(halfword source, int nowidth, halfword att)
843{
844 halfword target = null;
845 switch (node_type(source)) {
846 case hlist_node:
847 target = tex_new_node(hlist_node, node_subtype(source));
848 break;
849 case vlist_node:
850 target = tex_new_node(vlist_node, node_subtype(source));
851 break;
852 }
853 if (target) {
854 halfword rule = tex_new_rule_node(empty_rule_subtype);
855 tex_attach_attribute_list_attribute(target, att);
856 tex_attach_attribute_list_attribute(rule, att);
857 rule_width(rule) = nowidth ? 0 : box_width(source);
858 rule_height(rule) = box_height(source);
859 rule_depth(rule) = box_depth(source);
860 box_dir(target) = dir_lefttoright ;
861 box_height(target) = rule_height(rule);
862 box_depth(target) = rule_depth(rule);
863 box_width(target) = rule_width(rule);
864 box_shift_amount(target) = box_shift_amount(source);
865 box_list(target) = rule;
866 tex_flush_node_list(source);
867 return target;
868 } else {
869 return source;
870 }
871}
872
873
879
880static halfword tex_aux_fraction_rule(scaled width, scaled height, halfword att, quarterword ruletype, halfword size, halfword fam)
881{
882 halfword rule = null;
883 int callback_id = lmt_callback_defined(math_rule_callback);
884 if (callback_id > 0) {
885 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);
886 if (rule && node_type(rule) != hlist_node) {
887 rule = tex_hpack(rule, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
888 node_subtype(rule) = math_rule_list;
889 tex_attach_attribute_list_attribute(rule, att);
890 }
891 }
892 if (! rule) {
893 if (math_rules_mode_par) {
894 rule = tex_new_rule_node(ruletype);
895 rule_data(rule) = tex_fam_fnt(fam, size);
896 } else {
897 rule = tex_new_rule_node(normal_rule_subtype);
898 }
899 rule_height(rule) = height;
900 rule_depth(rule) = 0;
901 tex_attach_attribute_list_attribute(rule, att);
902 }
903 return rule;
904}
905
906
913
914static 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, halfword variant, int reg);
915
916static halfword tex_aux_overbar(halfword box, scaled gap, scaled height, scaled krn, halfword att, quarterword index, halfword size, halfword fam, halfword topdelimiter, halfword style)
917{
918 halfword rule = (topdelimiter > 0 && tex_aux_has_extensible(topdelimiter, size))
919 ? tex_aux_make_delimiter(null, topdelimiter, size, box_width(box), 1, style, 0, NULL, NULL, 0, 0, NULL, 0, att, 0, 1)
920 : tex_aux_fraction_rule(box_width(box), height, att, index, size, fam);
921
922 if (topdelimiter > 0 && box_width(rule) > box_width(box)) {
923 halfword delta = (box_width(rule) - box_width(box)) / 2;
924 tex_aux_prepend_hkern_to_box_list(box, delta, horizontal_math_kern_subtype, "narrow delimiter");
925 tex_aux_append_hkern_to_box_list(box, delta, horizontal_math_kern_subtype, "narrow delimiter");
926 box_width(box) = box_width(rule);
927 }
928 if (topdelimiter < 0) {
929 node_subtype(rule) = empty_rule_code;
930 }
931 if (gap) {
932 halfword kern = tex_new_kern_node(gap, vertical_math_kern_subtype);
933 tex_attach_attribute_list_attribute(kern, att);
934 tex_couple_nodes(kern, box);
935 tex_couple_nodes(rule, kern);
936 } else {
937 tex_couple_nodes(rule, box);
938 }
939 if (krn) {
940 halfword kern = tex_new_kern_node(krn, vertical_math_kern_subtype);
941 tex_attach_attribute_list_attribute(kern, att);
942 tex_couple_nodes(kern, rule);
943 rule = kern;
944 }
945 rule = tex_vpack(rule, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
946 tex_attach_attribute_list_attribute(rule, att);
947 return rule;
948}
949
950static halfword tex_aux_underbar(halfword box, scaled gap, scaled height, scaled krn, halfword att, quarterword index, halfword size, halfword fam, halfword botdelimiter, halfword style)
951{
952 halfword rule = (botdelimiter && tex_aux_has_extensible(botdelimiter, size))
953 ? tex_aux_make_delimiter(null, botdelimiter, size, box_width(box), 1, style, 0, NULL, NULL, 0, 0, NULL, 0, att, 0, 1)
954 : tex_aux_fraction_rule(box_width(box), height, att, index, size, fam);
955 if (gap) {
956 halfword kern = tex_new_kern_node(gap, vertical_math_kern_subtype);
957 tex_attach_attribute_list_attribute(kern, att);
958 tex_couple_nodes(box, kern);
959 tex_couple_nodes(kern, rule);
960 } else {
961 tex_couple_nodes(box, rule);
962 }
963 if (krn) {
964 halfword kern = tex_new_kern_node(krn, vertical_math_kern_subtype);
965 tex_attach_attribute_list_attribute(kern, att);
966 tex_couple_nodes(rule, kern);
967 }
968 rule = tex_vpack(box, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
969 tex_attach_attribute_list_attribute(rule, att);
970
971
972 box_depth(rule) = box_total(rule) - box_height(box);
973 box_height(rule) = box_height(box);
974
975 return rule;
976}
977
978
1012
1013static 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)
1014{
1015
1016 halfword glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
1017 halfword box = tex_new_null_box_node(hlist_node, math_char_list);
1018 scaledwhd whd = tex_char_whd_from_glyph(glyph);
1019 tex_attach_attribute_list_attribute(glyph, att);
1020 tex_attach_attribute_list_attribute(box, att);
1021 box_width(box) = whd.wd;
1022 box_height(box) = whd.ht;
1023 box_depth(box) = whd.dp;
1024 box_list(box) = glyph;
1025 if (isscaled) {
1026 *isscaled = 0;
1027 }
1028 if (tex_has_glyph_option(glyph, glyph_option_no_italic_correction)) {
1029 whd.ic = 0;
1030 }
1031 if (! (stretch || shrink) && whd.ic) {
1032 if (ic) {
1033 *ic = whd.ic;
1034 }
1035 if (tex_aux_math_engine_control(fnt, math_control_apply_char_italic_kern)) {
1036 tex_aux_math_insert_italic_kern(glyph, whd.ic, glyph, "box");
1037 box_width(box) += whd.ic;
1038 } else {
1039 return box;
1040 }
1041 } else if (ic) {
1042 *ic = 0;
1043 }
1044 if (target && whd.wd > 0) {
1045 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)) {
1046 scaled margin = tex_get_math_x_parameter_default(style, math_parameter_accent_extend_margin, 0);
1047 scaled amount = target - 2 * margin;
1048 if (amount > 0) {
1049 glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * amount/whd.wd);
1050 glyph_x_offset(glyph) = (whd.wd - amount)/2;
1051 if (isscaled) {
1052 *isscaled = 1;
1053 }
1054 }
1055 return box;
1056 }
1057 if ((shrink && (whd.wd > target)) || (stretch && (whd.wd < target))) {
1058 glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * target/whd.wd);
1059
1060 whd = tex_char_whd_from_glyph(glyph);
1061 box_width(box) = whd.wd;
1062 if (isscaled) {
1063 *isscaled = 1;
1064 }
1065 }
1066 }
1067 return box;
1068}
1069
1070
1080
1081static scaled tex_aux_stack_char_into_box(halfword box, halfword fnt, int chr, quarterword subtype, int horiziontal)
1082{
1083 halfword glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
1084 scaledwhd whd = tex_char_whd_from_glyph(glyph);
1085 halfword list = box_list(box);
1086 tex_attach_attribute_list_attribute(glyph, get_attribute_list(box));
1087 if (horiziontal) {
1088 if (list) {
1089 tex_couple_nodes(tex_tail_of_node_list(list), glyph);
1090 } else {
1091 box_list(box) = glyph;
1092 }
1093 if (box_height(box) < whd.ht) {
1094 box_height(box) = whd.ht;
1095 }
1096 if (box_depth(box) < whd.dp) {
1097 box_depth(box) = whd.dp;
1098 }
1099
1100
1101
1102 return whd.wd;
1103 } else {
1104 halfword boxed = tex_new_null_box_node(hlist_node, math_char_list);
1105 tex_attach_attribute_list_attribute(boxed, get_attribute_list(box));
1106 box_width(boxed) = whd.wd;
1107 box_height(boxed) = whd.ht;
1108 box_depth(boxed) = whd.dp;
1109 box_list(boxed) = glyph;
1110 tex_try_couple_nodes(boxed, list);
1111 box_list(box) = boxed;
1112
1113 if (box_width(box) < whd.wd) {
1114 box_width(box) = whd.wd;
1115 }
1116
1117
1118
1119 return whd.ht + whd.dp;
1120 }
1121}
1122
1123static void tex_aux_stack_glue_into_box(halfword box, scaled min, scaled max) {
1124 halfword glue = tex_new_glue_node(zero_glue, user_skip_glue);
1125 glue_amount(glue) = min;
1126 glue_stretch(glue) = max - min;
1127 tex_add_glue_option(glue, glue_option_no_auto_break);
1128 tex_attach_attribute_list_copy(glue, box);
1129 if (node_type(box) == vlist_node) {
1130 tex_try_couple_nodes(glue, box_list(box));
1131 box_list(box) = glue;
1132 } else {
1133 halfword list = box_list(box);
1134 if (list) {
1135 tex_couple_nodes(tex_tail_of_node_list(list), glue);
1136 } else {
1137 box_list(box) = glue;
1138 }
1139 }
1140}
1141
1142
1157
1158static halfword tex_aux_top_extensible_from_box(halfword e)
1159{
1160 if (node_type(e) == vlist_node && node_subtype(e) == math_v_extensible_list) {
1161 e = box_list(e);
1162 while (e) {
1163 if (node_type(e) == hlist_node && box_list(e) && node_type(box_list(e)) == glyph_node) {
1164 return box_list(e);
1165 } else {
1166 e = node_next(e);
1167 }
1168 }
1169 }
1170 return null;
1171}
1172
1173static halfword tex_aux_bottom_extensible_from_box(halfword e)
1174{
1175 halfword g = null;
1176 if (node_type(e) == vlist_node && node_subtype(e) == math_v_extensible_list) {
1177 e = box_list(e);
1178 while (e) {
1179 if (node_type(e) == hlist_node && box_list(e) && node_type(box_list(e)) == glyph_node) {
1180 g = box_list(e);
1181 }
1182 e = node_next(e);
1183 }
1184 }
1185 return g;
1186}
1187
1188
1189
1190static halfword tex_made_extensible(halfword node, halfword fnt, halfword chr, halfword size, scaled width, scaled height, scaled depth, scaled linewidth, scaled axis, scaled exheight, scaled emwidth)
1191{
1192 int callback_id = lmt_callback_defined(make_extensible_callback);
1193 if (callback_id > 0) {
1194 halfword boxed = null;
1195 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "Ndddddddddd->N", node, fnt, chr, size, width, height, depth, linewidth, axis, exheight, emwidth, &boxed);
1196 if (boxed) {
1197 switch (node_type(boxed)) {
1198 case hlist_node:
1199 case vlist_node:
1200 return boxed;
1201 default:
1202 tex_formatted_error("fonts", "invalid f character %i created for font %i, [h|v]list expected", chr, fnt);
1203 break;
1204 }
1205 }
1206 }
1207 return null;
1208}
1209
1210
1211
1212
1213
1214
1215
1216halfword tex_make_extensible(halfword fnt, halfword chr, scaled target, scaled minoverlap, int horizontal, halfword att, halfword size)
1217{
1218
1219 scaled max_natural = 0;
1220
1221 scaled max_shrink = 0;
1222 scaled overlap;
1223
1224 int pieces = 0;
1225
1226 halfword box = tex_new_null_box_node(horizontal ? hlist_node : vlist_node, horizontal ? math_h_extensible_list : math_v_extensible_list);
1227
1228 int with_extenders = -1;
1229 int n_of_extenders = 0;
1230 int n_of_normal = 0;
1231 extinfo *extensible = tex_char_extensible_recipe_from_font(fnt, chr);
1232 if (minoverlap < 0) {
1233 minoverlap = 0;
1234 }
1235 tex_attach_attribute_list_attribute(box, att);
1236 for (extinfo *e = extensible; e; e = e->next) {
1237 if (! tex_char_exists(fnt, e->glyph)) {
1238 tex_handle_error(
1239 normal_error_type,
1240 "Extension part doesn't exist.",
1241 "Each glyph part in an extensible item should exist in the font. I will give up\n"
1242 "trying to find a suitable size for now. Fix your font!"
1243 );
1244 tex_aux_fake_delimiter(box);
1245 return box;
1246 } else {
1247 if (e->extender == math_extension_repeat) {
1248 n_of_extenders++;
1249 } else {
1250 n_of_normal++;
1251 }
1252
1256 if (e->start_overlap < 0 || e->end_overlap < 0 || e->advance < 0) {
1257 tex_handle_error(
1258 normal_error_type,
1259 "Extensible recipe has negative fields.",
1260 "All measurements in extensible items should be positive. To get around this\n"
1261 "problem, I have changed the font metrics. Fix your font!"
1262 );
1263 if (e->start_overlap < 0) {
1264 e->start_overlap = 0;
1265 }
1266 if (e->end_overlap < 0) {
1267 e->end_overlap = 0;
1268 }
1269 if (e->advance < 0) {
1270 e->advance = 0;
1271 }
1272 }
1273 }
1274 }
1275 if (n_of_normal == 0) {
1276 tex_handle_error(
1277 normal_error_type,
1278 "Extensible recipe has no fixed parts.",
1279 "Each extensible recipe should have at least one non-repeatable part. To get\n"
1280 "around this problem, I have changed the first part to be non-repeatable. Fix your\n"
1281 "font!"
1282 );
1283 if (extensible) {
1284 extensible->extender = 0;
1285 }
1286 n_of_normal = 1;
1287 n_of_extenders--;
1288 }
1289
1320 while (max_natural < target && n_of_extenders > 0) {
1321 overlap = 0;
1322 max_natural = 0;
1323 with_extenders++;
1324 if (horizontal) {
1325 for (extinfo *e = extensible; e; e = e->next) {
1326 if (e->extender == 0) {
1327 scaled initial = tex_aux_math_x_size_scaled(fnt, e->start_overlap, size);
1328 scaled advance = tex_aux_math_x_size_scaled(fnt, e->advance, size);
1329 if (minoverlap < initial) {
1330 initial = minoverlap;
1331 }
1332 if (overlap < initial) {
1333 initial = overlap;
1334 }
1335 if (advance == 0) {
1336 advance = tex_aux_math_x_size_scaled(fnt, tex_char_width_from_font(fnt, e->glyph), size);
1337 }
1338 if (advance <= 0) {
1339 tex_formatted_error("fonts", "bad horizontal extensible character %i in font %i", chr, fnt);
1340 }
1341 max_natural += advance - initial;
1342 overlap = tex_aux_math_x_size_scaled(fnt, e->end_overlap, size);
1343 } else {
1344 pieces = with_extenders;
1345 while (pieces > 0) {
1346 scaled initial = tex_aux_math_x_size_scaled(fnt, e->start_overlap, size);
1347 scaled advance = tex_aux_math_x_size_scaled(fnt, e->advance, size);
1348 if (minoverlap < initial) {
1349 initial = minoverlap;
1350 }
1351 if (overlap < initial) {
1352 initial = overlap;
1353 }
1354 if (advance == 0) {
1355 advance = tex_aux_math_x_size_scaled(fnt, tex_char_width_from_font(fnt, e->glyph), size);
1356 }
1357 if (advance <= 0) {
1358 tex_formatted_error("fonts", "bad horizontal extensible character %i in font %i", chr, fnt);
1359 }
1360 max_natural += advance - initial;
1361 overlap = tex_aux_math_x_size_scaled(fnt, e->end_overlap, size);
1362 pieces--;
1363 }
1364 }
1365 }
1366 } else {
1367 for (extinfo *e = extensible; e; e = e->next) {
1368 if (e->extender == 0) {
1369 scaled initial = tex_aux_math_y_size_scaled(fnt, e->start_overlap, size);
1370 scaled advance = tex_aux_math_y_size_scaled(fnt, e->advance, size);
1371 if (minoverlap < initial) {
1372 initial = minoverlap;
1373 }
1374 if (overlap < initial) {
1375 initial = overlap;
1376 }
1377 if (advance == 0) {
1378 advance = tex_aux_math_y_size_scaled(fnt, tex_char_total_from_font(fnt, e->glyph), size);
1379 }
1380 if (advance <= 0) {
1381 tex_formatted_error("fonts", "bad vertical extensible character %i in font %i", chr, fnt);
1382 }
1383 max_natural += advance - initial;
1384 overlap = tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1385 } else {
1386 pieces = with_extenders;
1387 while (pieces > 0) {
1388 scaled initial = tex_aux_math_y_size_scaled(fnt, e->start_overlap, size);
1389 scaled advance = tex_aux_math_y_size_scaled(fnt, e->advance, size);
1390 if (minoverlap < initial) {
1391 initial = minoverlap;
1392 }
1393 if (overlap < initial) {
1394 initial = overlap;
1395 }
1396 if (advance == 0) {
1397 advance = tex_aux_math_y_size_scaled(fnt, tex_char_total_from_font(fnt, e->glyph), size);
1398 }
1399 if (advance <= 0) {
1400 tex_formatted_error("fonts", "bad vertical extensible character %i in font %i", chr, fnt);
1401 }
1402 max_natural += advance - initial;
1403 overlap = tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1404 pieces--;
1405 }
1406 }
1407 }
1408 }
1409 }
1410
1414 overlap = 0;
1415 max_natural = 0;
1416 max_shrink = 0;
1417 for (extinfo *e = extensible; e; e = e->next) {
1418 if (e->extender == 0) {
1419 scaled progress;
1420 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);
1421 if (overlap < initial) {
1422 initial = overlap;
1423 }
1424 progress = initial;
1425 if (minoverlap < initial) {
1426 initial = minoverlap;
1427 }
1428 if (progress > 0) {
1429 tex_aux_stack_glue_into_box(box, -progress, -initial);
1430 max_shrink += (-initial) - (-progress);
1431 max_natural -= progress;
1432 }
1433 max_natural += tex_aux_stack_char_into_box(box, fnt, e->glyph, glyph_math_extensible_subtype, horizontal);
1434 overlap = horizontal ? tex_aux_math_x_size_scaled(fnt, e->end_overlap, size) : tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1435 pieces--;
1436 } else {
1437 pieces = with_extenders;
1438 while (pieces > 0) {
1439 scaled progress;
1440 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);
1441 if (overlap < initial) {
1442 initial = overlap;
1443 }
1444 progress = initial;
1445 if (minoverlap < initial) {
1446 initial = minoverlap;
1447 }
1448 if (progress > 0) {
1449 tex_aux_stack_glue_into_box(box, -progress, -initial);
1450 max_shrink += (-initial) - (-progress);
1451 max_natural -= progress;
1452 }
1453 max_natural += tex_aux_stack_char_into_box(box, fnt, e->glyph, glyph_math_extensible_subtype, horizontal);
1454 overlap = horizontal ? tex_aux_math_x_size_scaled(fnt, e->end_overlap, size) : tex_aux_math_y_size_scaled(fnt, e->end_overlap, size);
1455 pieces--;
1456 }
1457 }
1458 }
1459
1460 if (target > max_natural && max_shrink > 0) {
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475 scaled delta = target - max_natural;
1476
1477 if (delta > max_shrink) {
1478 if (tracing_math_par >= 1) {
1479 tex_begin_diagnostic();
1480 tex_print_format("[math: extensible clipped, target %p, natural %p, shrink %p, clip %p]",
1481 target, max_natural, max_shrink, delta - max_shrink
1482 );
1483 tex_end_diagnostic();
1484 }
1485 delta = max_shrink;
1486 }
1487 box_glue_order(box) = normal_glue_order;
1488 box_glue_sign(box) = stretching_glue_sign;
1489 box_glue_set(box) = (glueratio) (delta / (glueratio) max_shrink);
1490 max_natural += delta;
1491
1492 }
1493 if (horizontal) {
1494 box_width(box) = max_natural;
1495 node_subtype(box) = math_h_extensible_list;
1496 } else {
1497 box_height(box) = max_natural;
1498 node_subtype(box) = math_v_extensible_list;
1499 }
1500 return box;
1501}
1502
1503
1518
1519static halfword register_extensible(halfword fnt, halfword chr, int size, halfword result, halfword att)
1520{
1521 int callback_id = lmt_callback_defined(register_extensible_callback);
1522 if (callback_id > 0) {
1523 halfword boxed = null;
1524 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dddNN->N", fnt, chr, size, att, result, &boxed);
1525 if (boxed) {
1526 switch (node_type(boxed)) {
1527 case hlist_node:
1528 case vlist_node:
1529
1530 return boxed;
1531 default:
1532 tex_formatted_error("fonts", "invalid extensible character %U registered for font %F, [h|v]list expected", chr, fnt);
1533 break;
1534 }
1535 }
1536 }
1537 return result;
1538}
1539
1540
1544
1545static 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, halfword variant, int reg)
1546{
1547
1548 halfword result = null;
1549
1550 halfword fnt = null_font;
1551
1552 int chr = 0;
1553 int nxtchr = 0;
1554
1555 int hasparts = 0;
1556 int isscaled = 0;
1557 int shrink = flat && has_noad_option_shrink(target);
1558 int stretch = flat && has_noad_option_stretch(target);
1559
1560 halfword att = null;
1561 if (extremes) {
1562 extremes->tfont = null_font;
1563 extremes->bfont = null_font;
1564 extremes->tchar = 0;
1565 extremes->bchar = 0;
1566 extremes->height = 0;
1567 extremes->depth = 0;
1568 }
1569 if (! tex_aux_has_delimiter(delimiter, size)) {
1570 halfword result = tex_new_null_box_node(hlist_node, math_v_delimiter_list);
1571 tex_attach_attribute_list_copy(result, delimiter);
1572 if (! flat) {
1573 tex_aux_fake_delimiter(result);
1574 }
1575 tex_flush_node(delimiter);
1576 return result;
1577 }
1578 if (delimiter) {
1579 if (variant) {
1580
1584 int curfam = delimiter_small_family(delimiter);
1585 int curchr = delimiter_small_character(delimiter);
1586 halfword curfnt = tex_fam_fnt(curfam, size);
1587 if (curchr && curfnt != null_font && tex_char_exists(curfnt, curchr)) {
1588 fnt = curfnt;
1589 chr = curchr;
1590 while (--variant && tex_char_has_tag_from_font(curfnt, curchr, list_tag)) {
1591 curchr = tex_char_next_from_font(curfnt, curchr);
1592 if (curchr) {
1593 chr = curchr;
1594 } else {
1595 break;
1596 }
1597 }
1598 }
1599 } else {
1600
1601 scaled besttarget = 0;
1602 int large_attempt = 0;
1603
1604 int curfam = delimiter_small_family(delimiter);
1605 int curchr = 0;
1606 int count = 0;
1607 int prvfnt = null_font;
1608 int prvchr = 0;
1609 nxtchr = delimiter_small_character(delimiter);
1610 while (1) {
1611
1632 if (curfam >= 0 || nxtchr) {
1633 halfword curfnt = tex_fam_fnt(curfam, size);
1634 if (curfnt != null_font) {
1635 curchr = nxtchr;
1636 CONTINUE:
1637 count++;
1638 if (tex_char_exists(curfnt, curchr)) {
1639 if (! tex_char_has_tag_from_font(curfnt, curchr, force_extensible_tag)) {
1640 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);
1641 if (nooverflow && total >= targetsize) {
1642 if (total > targetsize && prvfnt != null_font) {
1643 fnt = prvfnt;
1644 chr = prvchr;
1645 } else {
1646 fnt = curfnt;
1647 chr = curchr;
1648 }
1649 besttarget = total;
1650 goto FOUND;
1651 } else if (total >= besttarget) {
1652 prvfnt = curfnt;
1653 prvchr = curchr;
1654 fnt = curfnt;
1655 chr = curchr;
1656 besttarget = total;
1657 if (total >= (targetsize - tolerance)) {
1658
1705 # if 0
1706 if (delimiter_small_family(delimiter) != delimiter_large_family(delimiter)) {
1707 goto FOUND;
1708 } else if (tex_char_has_tag_from_font(curfnt, curchr, extensible_tag)) {
1709 goto FOUND;
1710 }
1711 # else
1712 goto FOUND;
1713 # endif
1714 }
1715 }
1716 }
1717 if (tex_char_has_tag_from_font(curfnt, curchr, extensible_tag)) {
1718 if (tex_char_has_tag_from_font(curfnt, curchr, horizontal_tag) || tex_char_has_tag_from_font(curfnt, curchr, vertical_tag)) {
1719
1720 if (flat ? tex_char_has_tag_from_font(curfnt, curchr, horizontal_tag) : tex_char_has_tag_from_font(curfnt, curchr, vertical_tag)) {
1721 fnt = curfnt;
1722 chr = curchr;
1723 hasparts = 1;
1724 }
1725 }
1726 goto FOUND;
1727 } else if (count > 1000) {
1728 tex_formatted_warning("fonts", "endless loop in extensible character %U of font %F", curchr, curfnt);
1729 goto FOUND;
1730 } else if (tex_char_has_tag_from_font(curfnt, curchr, list_tag)) {
1731 prvfnt = curfnt;
1732 prvchr = curchr;
1733 curchr = tex_char_next_from_font(curfnt, curchr);
1734 goto CONTINUE;
1735 }
1736 }
1737 }
1738 }
1739 if (large_attempt) {
1740
1744 goto FOUND;
1745 } else {
1746
1750 large_attempt = 1;
1751 curfam = delimiter_large_family(delimiter);
1752 nxtchr = delimiter_large_character(delimiter);
1753 }
1754 }
1755 }
1756 }
1757 FOUND:
1758 if (delimiter) {
1759
1763
1764 att = get_attribute_list(delimiter);
1765 wipe_attribute_list_only(delimiter);
1766 tex_flush_node(delimiter);
1767 }
1768
1769
1770
1771 if (fnt != null_font) {
1772
1776 extinfo *ext = hasparts ? tex_char_extensible_recipe_from_font(fnt, chr) : NULL;
1777 if (ext) {
1778 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);
1779
1780 result = tex_make_extensible(fnt, chr, targetsize, minoverlap, flat, attr ? attr : att, lmt_math_state.size);
1781 if (stretch && flat && (box_width(result) > targetsize)) {
1782 tex_flush_node_list(result);
1783 hasparts = 0;
1784 goto HERE;
1785 }
1786 if (delta) {
1787
1788 if (tex_aux_math_engine_control(fnt, math_control_apply_vertical_italic_kern)) {
1789 *delta = tex_aux_math_x_size_scaled(fnt, tex_char_extensible_italic_from_font(fnt, nxtchr), size);
1790 } else {
1791 *delta = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, nxtchr), size);
1792 }
1793 }
1794 if (stack) {
1795 *stack = 1 ;
1796 }
1797 if (! flat && extremes) {
1798 halfword first = tex_aux_top_extensible_from_box(result);
1799 halfword last = tex_aux_bottom_extensible_from_box(result);
1800 extremes->tfont = glyph_font(first);
1801 extremes->tchar = glyph_character(first);
1802 extremes->bfont = glyph_font(last);
1803 extremes->bchar = glyph_character(last);
1804 extremes->height = box_height(result);
1805 extremes->depth = box_depth(result);
1806 }
1807 } else {
1808
1815 HERE:
1816 result = tex_aux_char_box(fnt, chr, attr ? attr : att, delta, glyph_math_delimiter_subtype, flat ? targetsize : 0, style, shrink, stretch, &isscaled);
1817 if (flat) {
1818
1819 } else {
1820 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)) {
1821 halfword glyph = box_list(result);
1822 if (glyph && node_type(glyph) == glyph_node) {
1823 scaled margin = tex_get_math_y_parameter_default(style, math_parameter_delimiter_extend_margin, 0);
1824 scaled amount = targetsize - 2 * margin;
1825 if (amount > 0) {
1826 double ratio = (double) amount/box_total(result);
1827 glyph_y_scale(glyph) = lround((double) glyph_y_scale(glyph) * ratio);
1828 glyph_y_offset(glyph) = lround((double) box_total(glyph) * ratio);
1829 box_height(result) = lround((double) box_height(result) * ratio);
1830 box_depth(result) = lround((double) box_depth(result) * ratio);
1831 }
1832 }
1833 }
1834 }
1835 if (stack) {
1836 *stack = 0 ;
1837 }
1838 if (! flat && extremes) {
1839 extremes->tfont = fnt;
1840 extremes->tchar = chr;
1841 extremes->bfont = fnt;
1842 extremes->bchar = chr;
1843 extremes->height = box_height(result);
1844 extremes->depth = box_depth(result);
1845 }
1846 }
1847 } else {
1848
1849 result = tex_new_null_box_node(hlist_node, flat ? math_h_delimiter_list : math_v_delimiter_list);
1850 tex_attach_attribute_list_attribute(result, attr ? attr : att);
1851
1852 if (! flat) {
1853 tex_aux_fake_delimiter(result);
1854 }
1855 if (delta) {
1856 *delta = 0;
1857 }
1858 if (stack) {
1859 *stack = 0 ;
1860 }
1861 }
1862 if (hasparts) {
1863 if (target && (has_noad_option_phantom(target) || has_noad_option_void(target))) {
1864 result = tex_aux_make_list_phantom(result, has_noad_option_void(target), attr ? attr : att);
1865 } else if (reg) {
1866 result = register_extensible(fnt, chr, size, result, attr ? attr : att);
1867 }
1868 }
1869 if (! flat) {
1870
1884 switch (shift) {
1885 case 0:
1886 box_shift_amount(result) = tex_half_scaled(box_height(result) - box_depth(result));
1887 break;
1888 case 1:
1889 box_shift_amount(result) = tex_half_scaled(box_height(result) - box_depth(result));
1890 box_shift_amount(result) -= tex_aux_math_axis(size);
1891 break;
1892 case 2:
1893 box_shift_amount(result) = move;
1894 break;
1895 }
1896 if (hasparts && extremes && extremes->height) {
1897 extremes->height -= box_shift_amount(result);
1898 extremes->depth += box_shift_amount(result);
1899 }
1900 }
1901
1902 delete_attribute_reference(att);
1903 if ((node_type(result) == hlist_node || node_type(result) == vlist_node) && node_subtype(result) == unknown_list) {
1904 node_subtype(result) = flat ? math_h_delimiter_list : math_v_delimiter_list;
1905 }
1906 return result;
1907}
1908
1909
1922
1923static halfword tex_aux_rebox(halfword box, scaled width, halfword size)
1924{
1925 (void) size;
1926 if (box_width(box) != width && box_list(box)) {
1927
1928 halfword head = box_list(box);
1929 quarterword subtype = node_subtype(box);
1930 halfword att = get_attribute_list(box);
1931
1932 add_attribute_reference(att);
1933 if (node_type(box) == vlist_node) {
1934 box = tex_hpack(box, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
1935 node_subtype(box) = subtype;
1936 tex_attach_attribute_list_attribute(box, att);
1937 head = box_list(box);
1938 } else if (head && node_type(head) == glyph_node && ! node_next(head)) {
1939
1944 if (tex_aux_math_engine_control(glyph_font(head), math_control_rebox_char_italic_kern)) {
1945 scaled boxwidth = box_width(box);
1946 scaled chrwidth = tex_char_width_from_glyph(head);
1947 if (boxwidth != chrwidth) {
1948
1952 halfword kern = tex_new_kern_node(boxwidth - chrwidth, italic_kern_subtype);
1953 tex_attach_attribute_list_attribute(kern, att);
1954 tex_couple_nodes(head, kern);
1955 }
1956 }
1957 }
1958 box_list(box) = null;
1959 tex_flush_node(box);
1960 {
1961 halfword right = tex_new_glue_node(fi_ss_glue, user_skip_glue);
1962 halfword left = tex_new_glue_node(fi_ss_glue, user_skip_glue);
1963 tex_add_glue_option(left, glue_option_no_auto_break);
1964 tex_add_glue_option(right, glue_option_no_auto_break);
1965 tex_attach_attribute_list_attribute(left, att);
1966 tex_attach_attribute_list_attribute(right, att);
1967 tex_couple_nodes(left, head);
1968 tex_couple_nodes(tex_tail_of_node_list(head), right);
1969 box = tex_hpack(left, width, packing_exactly, direction_unknown, holding_none_option, box_limit_none);
1970 tex_attach_attribute_list_attribute(box, att);
1971 node_subtype(box) = subtype;
1972 }
1973
1974 delete_attribute_reference(att);
1975 } else {
1976 box_width(box) = width;
1977 }
1978 return box;
1979}
1980
1981
1987
1988static inline scaled tex_aux_mu_mult(scaled a, scaled n, scaled f)
1989{
1990 return tex_multiply_and_add(n, a, tex_xn_over_d(a, f, unity), max_dimension);
1991}
1992
1993static inline void tex_aux_calculate_glue(scaled m, scaled *f, scaled *n)
1994{
1995
1996 *f = 0;
1997
1998 *n = tex_x_over_n_r(m, unity, f);
1999
2000 if (*f < 0) {
2001 --n;
2002 f += unity;
2003 }
2004}
2005
2006static halfword tex_aux_math_muglue(halfword g, quarterword subtype, scaled m, halfword detail, int style)
2007{
2008 scaled f, n;
2009 halfword glue = tex_new_node(glue_node, subtype);
2010 tex_aux_calculate_glue(m, &f, &n);
2011
2012 glue_amount(glue) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_amount(g), style), n, f);
2013 if (math_glue_stretch_enabled) {
2014 scaled stretch = tex_aux_math_x_scaled(glue_stretch(g), style);
2015 glue_stretch_order(glue) = glue_stretch_order(g);
2016 glue_stretch(glue) = (glue_stretch_order(glue) == normal_glue_order) ? tex_aux_mu_mult(stretch, n, f) : stretch;
2017 }
2018 if (math_glue_shrink_enabled) {
2019 scaled shrink = tex_aux_math_x_scaled(glue_shrink(g), style);
2020 glue_shrink_order(glue) = glue_shrink_order(g);
2021 glue_shrink(glue) = (glue_shrink_order(glue) == normal_glue_order) ? tex_aux_mu_mult(shrink, n, f) : shrink;
2022 }
2023 if (math_glue_limit_enabled) {
2024 tex_add_glue_option(glue, glue_option_limit);
2025 }
2026 glue_font(glue) = detail;
2027 tex_add_glue_option(glue, glue_option_no_auto_break);
2028 return glue;
2029}
2030
2031static halfword tex_aux_math_glue(halfword g, quarterword subtype, halfword detail)
2032{
2033 halfword glue = tex_new_glue_node(g, subtype);
2034 if (! math_glue_stretch_enabled) {
2035 glue_stretch_order(glue) = normal_glue_order;
2036 glue_stretch(glue) = 0;
2037 }
2038 if (! math_glue_shrink_enabled) {
2039 glue_shrink_order(glue) = normal_glue_order;
2040 glue_shrink(glue) = 0;
2041 }
2042 if (math_glue_limit_enabled) {
2043 tex_add_glue_option(glue, glue_option_limit);
2044 }
2045 glue_font(glue) = detail;
2046 tex_add_glue_option(glue, glue_option_no_auto_break);
2047 return glue;
2048}
2049
2050static halfword tex_aux_math_dimension(halfword g, quarterword subtype, halfword detail)
2051{
2052 halfword glue = tex_new_glue_node(null, subtype);
2053 glue_amount(glue) = g;
2054 glue_font(glue) = detail;
2055 tex_add_glue_option(glue, glue_option_no_auto_break);
2056 if (math_glue_limit_enabled) {
2057 tex_add_glue_option(glue, glue_option_limit);
2058 }
2059 return glue;
2060}
2061
2062static void tex_aux_math_glue_to_glue(halfword p, scaled m, int style)
2063{
2064 scaled f, n;
2065 tex_aux_calculate_glue(m, &f, &n);
2066
2067 glue_amount(p) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_amount(p), style), n, f);
2068 if (! math_glue_stretch_enabled) {
2069 glue_stretch_order(p) = normal_glue_order;
2070 glue_stretch(p) = 0;
2071 } else if (glue_stretch_order(p) == normal_glue_order) {
2072 glue_stretch(p) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_stretch(p), style), n, f);
2073 }
2074 if (! math_glue_shrink_enabled) {
2075 glue_shrink_order(p) = normal_glue_order;
2076 glue_shrink(p) = 0;
2077 } else if (glue_shrink_order(p) == normal_glue_order) {
2078 glue_shrink(p) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_shrink(p), style), n, f);
2079 }
2080 if (math_glue_limit_enabled) {
2081 tex_add_glue_option(p, glue_option_limit);
2082 }
2083
2084 node_subtype(p) = inter_math_skip_glue;
2085 tex_add_glue_option(p, glue_option_no_auto_break);
2086}
2087
2088
2094
2095static void tex_aux_make_kern(halfword current, scaled mu, int style)
2096{
2097 if (node_subtype(current) == explicit_math_kern_subtype) {
2098 scaled f, n;
2099 tex_aux_calculate_glue(mu, &f, &n);
2100 kern_amount(current) = tex_aux_mu_mult(tex_aux_math_x_scaled(glue_amount(current), style), n, f);
2101 node_subtype(current) = explicit_kern_subtype;
2102 }
2103}
2104
2105
2115
2116static void tex_aux_make_glue(halfword current, scaled mu, int style)
2117{
2118 switch (node_subtype(current)) {
2119 case mu_glue:
2120 tex_aux_math_glue_to_glue(current, mu, style);
2121 break;
2122 case conditional_math_glue:
2123 if (lmt_math_state.size != text_size) {
2124 halfword p = node_next(current);
2125 if (p) {
2126 switch (node_type(p)) {
2127 case glue_node:
2128 case kern_node:
2129 if (node_next(p)) {
2130 tex_couple_nodes(current, node_next(p));
2131 node_next(p) = null;
2132 } else {
2133 node_next(current) = null;
2134 }
2135 tex_flush_node_list(p);
2136 break;
2137 }
2138 }
2139 }
2140 break;
2141 case rulebased_math_glue:
2142 break;
2143 }
2144}
2145
2146
2153
2154static inline int tex_aux_is_math_penalty(halfword n)
2155{
2156 return node_type(n) == penalty_node && (node_subtype(n) == math_pre_penalty_subtype || node_subtype(n) == math_post_penalty_subtype);
2157}
2158
2159static void tex_aux_show_math_list(const char *fmt, halfword list)
2160{
2161 tex_begin_diagnostic();
2162 tex_print_format(fmt, lmt_math_state.level);
2163 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);
2164 tex_print_ln();
2165 tex_end_diagnostic();
2166}
2167
2168void tex_run_mlist_to_hlist(halfword mlist, halfword penalties, halfword style, int beginclass, int endclass)
2169{
2170 if (mlist) {
2171 int saved_level = lmt_math_state.level;
2172 int callback_id = lmt_callback_defined(mlist_to_hlist_callback);
2173 lmt_math_state.level = 0;
2174 if (! valid_math_class_code(beginclass)) {
2175 beginclass = unset_noad_class;
2176 }
2177 if (! valid_math_class_code(endclass)) {
2178 endclass = unset_noad_class;
2179 }
2180 math_begin_class_par = unset_noad_class;
2181 math_end_class_par = unset_noad_class;
2182
2183 if (tracing_math_par >= 1) {
2184 tex_begin_diagnostic();
2185 switch (style) {
2186 case display_style:
2187 tex_print_str("> \\displaymath=");
2188 break;
2189 case text_style:
2190 tex_print_str("> \\inlinemath=");
2191 break;
2192 default:
2193 tex_print_str("> \\math=");
2194 break;
2195 }
2196 tex_show_box(mlist);
2197 tex_end_diagnostic();
2198 }
2199 tex_finalize_math_parameters();
2200 if (callback_id > 0) {
2201 lua_State *L = lmt_lua_state.lua_instance;
2202 int top = 0;
2203 if (lmt_callback_okay(L, callback_id, &top)) {
2204 int i;
2205 node_prev(mlist) = null ;
2206 lmt_node_list_to_lua(L, mlist);
2207 lmt_push_math_style_name(L, style);
2208 lua_pushboolean(L, penalties);
2209 lua_pushinteger(L, beginclass);
2210 lua_pushinteger(L, endclass);
2211 lua_pushinteger(L, lmt_math_state.level);
2212 lua_pushinteger(L, cur_list.math_main_style);
2213 i = lmt_callback_call(L, 7, 1, top);
2214 if (i) {
2215 lmt_callback_error(L, top, i);
2216 node_next(temp_head) = null;
2217 } else {
2218 halfword a = lmt_node_list_from_lua(L, -1);
2219
2220 node_next(temp_head) = a;
2221 lmt_callback_wrapup(L, top);
2222 }
2223 } else {
2224 node_next(temp_head) = null;
2225 }
2226 } else if (callback_id == 0) {
2227 node_next(temp_head) = tex_mlist_to_hlist(mlist, penalties, style, beginclass, endclass, NULL, m_to_h_engine);
2228 } else {
2229 node_next(temp_head) = null;
2230 }
2231 if (penalties) {
2232
2233 switch (style) {
2234 case text_style:
2235 case cramped_text_style:
2236 if (math_forward_penalties_par) {
2237 halfword n = tex_get_specification_count(math_forward_penalties_par);
2238 if (n > 0) {
2239 halfword h = node_next(temp_head);
2240 halfword i = 1;
2241 while (h && i <= n) {
2242 if (tex_aux_is_math_penalty(h)) {
2243 penalty_amount(h) += tex_get_specification_penalty(math_forward_penalties_par, i++);
2244 tex_add_penalty_option(h, penalty_option_math_forward);
2245 }
2246 h = node_next(h);
2247 }
2248 }
2249 }
2250 if (math_backward_penalties_par) {
2251 halfword n = tex_get_specification_count(math_backward_penalties_par);
2252 if (n > 0) {
2253 halfword t = tex_tail_of_node_list(node_next(temp_head));
2254 halfword i = 1;
2255 while (t && i <= n) {
2256 if (tex_aux_is_math_penalty(t)) {
2257 penalty_amount(t) += tex_get_specification_penalty(math_backward_penalties_par, i++);
2258 tex_add_penalty_option(t, penalty_option_math_backward);
2259 }
2260 t = node_prev(t);
2261 }
2262 }
2263 }
2264 break;
2265 }
2266 if (node_next(temp_head) && ! tex_glue_is_zero(math_threshold_par)) {
2267 scaledwhd siz = tex_natural_msizes(node_next(temp_head), 0);
2268 if (siz.wd < glue_amount(math_threshold_par)) {
2269 halfword box = tex_new_node(hlist_node, unknown_list);
2270 tex_attach_attribute_list_copy(box, node_next(temp_head));
2271 box_width(box) = siz.wd;
2272 box_height(box) = siz.ht;
2273 box_depth(box) = siz.dp;
2274 box_list(box) = node_next(temp_head);
2275 node_next(temp_head) = box;
2276 if (glue_stretch(math_threshold_par) || glue_shrink(math_threshold_par)) {
2277 halfword glue = tex_new_glue_node(math_threshold_par, u_leaders);
2278 tex_add_glue_option(glue, glue_option_no_auto_break);
2279 tex_attach_attribute_list_copy(glue, box);
2280 glue_amount(glue) = siz.wd;
2281 glue_leader_ptr(glue) = box;
2282
2283 node_next(temp_head) = glue;
2284 } else {
2285 node_next(temp_head) = box;
2286 }
2287 if (tracing_math_par >= 2) {
2288 tex_begin_diagnostic();
2289 tex_print_format("[math: boxing inline, threshold %p, width %p, height %p, depth %p]",
2290 glue_amount(math_threshold_par),
2291 siz.wd, siz.ht, siz.dp
2292 );
2293 tex_end_diagnostic();
2294 }
2295 }
2296 }
2297
2300 {
2301 halfword current = temp_head;
2302 while (current) {
2303
2304 if (node_type(current) == glyph_node && tex_has_glyph_option(current, glyph_option_math_discretionary)) {
2305 if (tracing_math_par >= 2) {
2306 tex_begin_diagnostic();
2307 tex_print_format("[math: promoting glyph with character %U to discretionary]", glyph_character(current));
2308 tex_end_diagnostic();
2309 }
2310 current = tex_glyph_to_discretionary(current, mathematics_discretionary_code, tex_has_glyph_option(current, glyph_option_math_italics_too));
2311 }
2312 current = node_next(current);
2313 }
2314 }
2315 }
2316 lmt_math_state.level = saved_level;
2317 } else {
2318 node_next(temp_head) = null;
2319 }
2320}
2321
2322
2331
2332static inline void tex_aux_remove_italic_after_first_glyph(halfword box)
2333{
2334 halfword list = box_list(box);
2335 if (list && node_type(list) == glyph_node) {
2336 halfword next = node_next(list);
2337
2338 if (next && ! node_next(next) && node_type(next) == kern_node && node_subtype(next) == italic_kern_subtype) {
2339
2340 box_width(box) -= kern_amount(next);
2341 tex_flush_node(next);
2342 node_next(list) = null;
2343 }
2344 }
2345}
2346
2347static halfword tex_aux_clean_box(halfword n, int main_style, int style, quarterword subtype, int keepitalic, kernset *kerns)
2348{
2349
2350 halfword list;
2351
2352 halfword result;
2353
2354 halfword mlist = null;
2355 switch (node_type(n)) {
2356 case math_char_node:
2357 mlist = tex_new_node(simple_noad, ordinary_noad_subtype);
2358 noad_nucleus(mlist) = tex_aux_math_clone(n);
2359 tex_attach_attribute_list_copy(mlist, n);
2360 break;
2361 case sub_box_node:
2362 list = kernel_math_list(n);
2363 goto FOUND;
2364 case sub_mlist_node:
2365 mlist = kernel_math_list(n);
2366 break;
2367 default:
2368 list = tex_new_null_box_node(hlist_node, math_list_list);
2369 tex_attach_attribute_list_copy(list, n);
2370 goto FOUND;
2371 }
2372
2373 list = tex_mlist_to_hlist(mlist, 0, main_style, unset_noad_class, unset_noad_class, kerns, m_to_h_cleanup);
2374
2375 tex_aux_set_current_math_size(style);
2376 FOUND:
2377 if (kerns && list) {
2378 halfword tail = tex_tail_of_node_list(list);
2379 if (node_type(list) == glyph_node) {
2380 halfword fnt = glyph_font(list);
2381 halfword chr = glyph_character(list);
2382 kerns->topleft = tex_aux_math_x_size_scaled(fnt, tex_char_top_left_kern_from_font(fnt, chr), main_style);
2383 kerns->bottomleft = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_left_kern_from_font(fnt, chr), main_style);
2384 }
2385 if (node_type(tail) == glyph_node) {
2386 halfword fnt = glyph_font(tail);
2387 halfword chr = glyph_character(tail);
2388 kerns->topright = tex_aux_math_x_size_scaled(fnt, tex_char_top_right_kern_from_font(fnt, chr), main_style);
2389 kerns->bottomright = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_right_kern_from_font(fnt, chr), main_style);
2390 }
2391 }
2392 if (! list || node_type(list) == glyph_node) {
2393 result = tex_hpack(list, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2394
2395 tex_attach_attribute_list_copy(result, n);
2396 } else if (! node_next(list) && (node_type(list) == hlist_node || node_type(list) == vlist_node) && (box_shift_amount(list) == 0)) {
2397
2398 result = list;
2399 } else {
2400 result = tex_hpack(list, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2401
2402 tex_attach_attribute_list_copy(result, n);
2403 }
2404 node_subtype(result) = subtype;
2405 if (! keepitalic) {
2406 tex_aux_remove_italic_after_first_glyph(result);
2407 }
2408 return result;
2409}
2410
2411
2424
2425static int tex_aux_fetch(halfword n, const char *where, halfword *f, halfword *c)
2426{
2427 if (node_type(n) == glyph_node) {
2428 *f = glyph_font(n);
2429 *c = glyph_character(n);
2430 if (tex_char_exists(*f, *c)) {
2431 return 1;
2432 } else {
2433
2436 tex_missing_character(n, *f, *c, missing_character_math_glyph);
2437 return tex_char_exists(*f, *c) ? 1 : 0;
2438 }
2439 } else {
2440 *f = tex_fam_fnt(kernel_math_family(n), lmt_math_state.size);
2441 *c = kernel_math_character(n);
2442 if (math_kernel_node_has_option(n, math_kernel_ignored_character)) {
2443 return 1;
2444 } else if (*f == null_font) {
2445 tex_handle_error(
2446 normal_error_type,
2447 "\\%s%i is undefined in %s, font id %i, character %i)",
2448 tex_aux_math_size_string(lmt_math_state.size), kernel_math_family(n), where, *f, *c,
2449 "Somewhere in the math formula just ended, you used the stated character from an\n"
2450 "undefined font family. For example, plain TeX doesn't allow \\it or \\sl in\n"
2451 "subscripts. Proceed, and I'll try to forget that I needed that character."
2452 );
2453 return 0;
2454 } else if (tex_math_char_exists(*f, *c, lmt_math_state.size)) {
2455 return 1;
2456 } else {
2457 tex_missing_character(n, *f, *c, missing_character_math_kernel);
2458 return tex_char_exists(*f, *c) ? 1 : 0;
2459 }
2460 }
2461}
2462
2463
2478
2479static void tex_aux_assign_new_hlist(halfword target, halfword hlist)
2480{
2481 switch (node_type(target)) {
2482 case fraction_noad:
2483 kernel_math_list(fraction_numerator(target)) = null;
2484 kernel_math_list(fraction_denominator(target)) = null;
2485 tex_flush_node(fraction_numerator(target));
2486 tex_flush_node(fraction_denominator(target));
2487 fraction_numerator(target) = null;
2488 fraction_denominator(target) = null;
2489 break;
2490 case radical_noad:
2491 case simple_noad:
2492 case accent_noad:
2493 if (noad_nucleus(target)) {
2494 kernel_math_list(noad_nucleus(target)) = null;
2495 tex_flush_node(noad_nucleus(target));
2496 noad_nucleus(target) = null;
2497 }
2498 break;
2499 }
2500 noad_new_hlist(target) = hlist;
2501}
2502
2503
2510
2511static void tex_aux_make_over(halfword target, halfword style, halfword size, halfword fam)
2512{
2513
2519 scaled thickness = tex_get_math_y_parameter_checked(style, math_parameter_overbar_rule);
2520 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_overbar_vgap);
2521 scaled kern = tex_get_math_y_parameter_checked(style, math_parameter_overbar_kern);
2522 {
2523 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_over_rule, OverbarRuleThickness);
2524 if (t != undefined_math_parameter) {
2525 thickness = t;
2526 }
2527 }
2528 {
2529 halfword result = tex_aux_overbar(
2530 tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_over_line_variant), style, math_nucleus_list, 0, NULL),
2531 vgap, thickness, kern,
2532 get_attribute_list(noad_nucleus(target)), math_over_rule_subtype, size, fam,
2533 null, style
2534 );
2535 node_subtype(result) = math_over_list;
2536 kernel_math_list(noad_nucleus(target)) = result;
2537 node_type(noad_nucleus(target)) = sub_box_node;
2538 }
2539}
2540
2541static void tex_aux_make_under(halfword target, halfword style, halfword size, halfword fam)
2542{
2543
2550 scaled thickness = tex_get_math_y_parameter_checked(style, math_parameter_underbar_rule);
2551 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_underbar_vgap);
2552 scaled kern = tex_get_math_y_parameter_checked(style, math_parameter_underbar_kern);
2553 {
2554 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_under_rule, UnderbarRuleThickness);
2555 if (t != undefined_math_parameter) {
2556 thickness = t;
2557 }
2558 }
2559 {
2560 halfword result = tex_aux_underbar(
2561 tex_aux_clean_box(noad_nucleus(target), tex_math_style_variant(style, math_parameter_under_line_variant), style, math_nucleus_list, 0, NULL),
2562 vgap, thickness, kern,
2563 get_attribute_list(noad_nucleus(target)), math_under_rule_subtype, size, fam,
2564 null, style
2565 );
2566 node_subtype(result) = math_over_list;
2567 kernel_math_list(noad_nucleus(target)) = result;
2568 node_type(noad_nucleus(target)) = sub_box_node;
2569 }
2570}
2571
2572
2578
2579static void tex_aux_make_vcenter(halfword target, halfword style, halfword size)
2580{
2581 halfword box = kernel_math_list(noad_nucleus(target));
2582 if (node_type(box) != vlist_node) {
2583 box = tex_aux_clean_box(noad_nucleus(target), style, style, math_list_list, 0, NULL);
2584 kernel_math_list(noad_nucleus(target)) = box;
2585 node_type(noad_nucleus(target)) = sub_box_node;
2586 }
2587 {
2588 scaled total = box_total(box);
2589 scaled axis = tex_has_box_option(box, box_option_no_math_axis) ? 0 : tex_aux_math_axis(size);
2590 box_height(box) = axis + tex_half_scaled(total);
2591 box_depth(box) = total - box_height(box);
2592 }
2593}
2594
2595
2605
2606static void tex_aux_make_hextension(halfword target, int style, int size)
2607{
2608 int stack = 0;
2609 scaled radicalwidth = tex_aux_math_given_x_scaled(noad_width(target));
2610 halfword extensible = radical_left_delimiter(target);
2611 halfword mergedattr = tex_merge_attribute_list(node_attr(extensible), noad_extra_attr(target));
2612 halfword delimiter = null;
2613 scaled delimiterwidth =0;
2614
2615 if (has_noad_option_use_callback(target)) {
2616 halfword fam = delimiter_small_family(extensible);
2617 halfword chr = delimiter_small_character(extensible);
2618 halfword fnt = tex_fam_fnt(fam, size);
2619 if (chr && fnt != null_font) {
2620 halfword thickness = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
2621 scaled axis = tex_aux_math_axis(size);
2622 scaled exheight = tex_aux_math_exheight(size);
2623 scaled emwidth = tex_aux_math_emwidth(size);
2624 halfword result = tex_made_extensible(target, fnt, chr, size, radicalwidth, 0, 0, thickness, axis, exheight, emwidth);
2625 if (result) {
2626 delimiter = register_extensible(fnt, chr, size, result, mergedattr);
2627 goto PICKUP;
2628 }
2629 }
2630 }
2631 delimiter = tex_aux_make_delimiter(target, extensible, size, radicalwidth, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, mergedattr, 0, 1);
2632 PICKUP:
2633
2634 delimiterwidth = box_width(delimiter);
2635 if (! stack && radicalwidth && (radicalwidth != delimiterwidth)) {
2636 if (has_noad_option_middle(target)) {
2637 scaled delta = tex_half_scaled(radicalwidth - delimiterwidth);
2638 if (delta) {
2639 halfword kern = tex_new_kern_node(delta, horizontal_math_kern_subtype);
2640 tex_attach_attribute_list_copy(kern, target);
2641 tex_couple_nodes(kern, delimiter);
2642 delimiter = kern;
2643 }
2644 delimiterwidth = radicalwidth;
2645 } else if (has_noad_option_exact(target)) {
2646 delimiterwidth = radicalwidth;
2647 }
2648 }
2649 delimiter = tex_hpack(delimiter, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2650 box_width(delimiter) = delimiterwidth;
2651
2652 tex_attach_attribute_list_copy(delimiter, extensible);
2653 kernel_math_list(noad_nucleus(target)) = delimiter;
2654 radical_left_delimiter(target) = null;
2655 radical_right_delimiter(target) = null;
2656 if (mergedattr) {
2657 delete_attribute_reference(mergedattr);
2658 delete_attribute_reference(noad_extra_attr(target));
2659 }
2660}
2661
2662static void tex_aux_preroll_root_radical(halfword target, int style, int size)
2663{
2664 (void) size;
2665 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);
2666}
2667
2668static halfword tex_aux_link_radical(halfword nucleus, halfword delimiter, halfword companion, halfword rightdelimiter)
2669{
2670 if (companion) {
2671
2672 tex_couple_nodes(delimiter, nucleus);
2673 tex_couple_nodes(nucleus, companion);
2674 return delimiter;
2675 } else if (rightdelimiter) {
2676 tex_couple_nodes(nucleus, delimiter);
2677 return nucleus;
2678 } else {
2679 tex_couple_nodes(delimiter, nucleus);
2680 return delimiter;
2681 }
2682}
2683
2684static void tex_aux_assign_radical(halfword target, halfword radical)
2685{
2686 halfword result = tex_hpack(radical, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2687 node_subtype(result) = math_radical_list;
2688 tex_attach_attribute_list_copy(result, target);
2689 kernel_math_list(noad_nucleus(target)) = result;
2690 node_type(noad_nucleus(target)) = sub_box_node;
2691 radical_left_delimiter(target) = null;
2692 radical_right_delimiter(target) = null;
2693}
2694
2695static void tex_aux_set_radical_kerns(delimiterextremes *extremes, kernset *kerns, halfword size)
2696{
2697 if (kerns && extremes->tfont) {
2698 if (tex_math_has_class_option(radical_noad_subtype, carry_over_left_top_kern_class_option)) {
2699 kerns->topleft = tex_aux_math_x_size_scaled(extremes->tfont, tex_char_top_left_kern_from_font(extremes->tfont, extremes->tchar), size);
2700 }
2701 if (tex_math_has_class_option(radical_noad_subtype, carry_over_left_bottom_kern_class_option)) {
2702 kerns->bottomleft = tex_aux_math_x_size_scaled(extremes->bfont, tex_char_bottom_left_kern_from_font(extremes->bfont, extremes->bchar), size);
2703 }
2704 if (tex_math_has_class_option(radical_noad_subtype, carry_over_right_top_kern_class_option)) {
2705 kerns->topright = tex_aux_math_x_size_scaled(extremes->tfont, tex_char_top_right_kern_from_font(extremes->tfont, extremes->tchar), size);
2706 }
2707 if (tex_math_has_class_option(radical_noad_subtype, carry_over_right_bottom_kern_class_option)) {
2708 kerns->bottomright = tex_aux_math_x_size_scaled(extremes->bfont, tex_char_bottom_right_kern_from_font(extremes->bfont, extremes->bchar), size);
2709 }
2710 if (tex_math_has_class_option(radical_noad_subtype, prefer_delimiter_dimensions_class_option)) {
2711 kerns->height = extremes->height;
2712 kerns->depth = extremes->depth;
2713 kerns->dimensions = 1;
2714 kerns->font = extremes->tfont;
2715 }
2716 }
2717}
2718
2719
2720
2721static void tex_aux_make_root_radical(halfword target, int style, int size, kernset *kerns)
2722{
2723 halfword nucleus = noad_new_hlist(target);
2724 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_radical_vgap);
2725 scaled theta = tex_get_math_y_parameter(style, math_parameter_radical_rule);
2726 scaled kern = tex_get_math_y_parameter_checked(style, math_parameter_radical_kern);
2727 halfword leftdelimiter = radical_left_delimiter(target);
2728 halfword rightdelimiter = radical_right_delimiter(target);
2729 halfword topdelimiter = radical_top_delimiter(target);
2730 halfword delimiter = leftdelimiter ? leftdelimiter : rightdelimiter;
2731 halfword companion = leftdelimiter ? rightdelimiter : null;
2732 halfword radical = null;
2733 halfword fam = delimiter_small_family(leftdelimiter);
2734 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
2735 scaled innerx = INT_MIN;
2736 scaled innery = INT_MIN;
2737 int norule = has_noad_option_norule(target);
2738 halfword mergedattr = tex_merge_attribute_list(node_attr(delimiter), noad_extra_attr(target));
2739 noad_new_hlist(target) = null;
2740
2744 {
2745 scaled t = tex_aux_check_rule_thickness(target, size, &fam, math_control_radical_rule, RadicalRuleThickness);
2746 if (t != undefined_math_parameter) {
2747 theta = t;
2748 }
2749 }
2750 {
2751 halfword weird = theta == undefined_math_parameter;
2752 if (weird) {
2753
2754 theta = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
2755 }
2756 {
2757 scaled targetsize = box_total(nucleus) + clearance + theta;
2758 if (has_noad_option_use_callback(target)) {
2759 halfword chr = delimiter_small_character(leftdelimiter);
2760 halfword fnt = tex_fam_fnt(fam, size);
2761 if (chr && fnt != null_font) {
2762 scaled axis = tex_aux_math_axis(size);
2763 scaled exheight = tex_aux_math_exheight(size);
2764 scaled emwidth = tex_aux_math_emwidth(size);
2765 scaled width = box_width(nucleus)
2766 + tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_before, 0)
2767 + tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_after, 0);
2768 halfword result = tex_made_extensible(target, fnt, chr, size, width, targetsize, 0, theta, axis, exheight, emwidth);
2769 if (result) {
2770 delimiter = register_extensible(fnt, chr, size, result, mergedattr);
2771 norule = 1;
2772 box_width(result) -= width;
2773 goto PICKUP;
2774 }
2775
2776
2777
2778
2779
2780
2781 }
2782 }
2783 delimiter = tex_aux_make_delimiter(target, delimiter, size, targetsize, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, 0, mergedattr, 0, 1);
2784 }
2785 PICKUP:
2786 if (extremes.bfont) {
2787 scaled margin = tex_char_left_margin_from_font(extremes.bfont, extremes.bchar);
2788 if (margin && margin != INT_MIN) {
2789 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");
2790 }
2791 }
2792 if (radical_degree(target)) {
2793 halfword innerf = 0;
2794 halfword innerc = 0;
2795 if (tex_char_has_tag_from_font(extremes.bfont, extremes.bchar, inner_left_tag)) {
2796 innerf = extremes.bfont;
2797 innerc = extremes.bchar;
2798 } else if (tex_char_has_tag_from_font(extremes.tfont, extremes.tchar, inner_left_tag)) {
2799 innerf = extremes.tfont;
2800 innerc = extremes.tchar;
2801 }
2802 if (innerc) {
2803 innerx = tex_char_inner_x_offset_from_font(innerf, innerc);
2804 innery = tex_char_inner_y_offset_from_font(innerf, innerc);
2805 innerx = innerx == INT_MIN ? 0 : tex_aux_math_y_size_scaled(innerf, innerx, size);
2806 innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(innerf, innery, size);
2807 }
2808 }
2809 if (companion) {
2810
2814 if (mergedattr) {
2815 delete_attribute_reference(mergedattr);
2816 }
2817 mergedattr = tex_merge_attribute_list(node_attr(companion), noad_extra_attr(target));
2818 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, mergedattr, 0, 1);
2819 if (extremes.bfont) {
2820 scaled margin = tex_char_right_margin_from_font(extremes.bfont, extremes.bchar);
2821 if (margin && margin != INT_MIN) {
2822 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");
2823 }
2824 }
2825 }
2826 if (weird) {
2827
2831 halfword list = box_list(delimiter);
2832 if (list && (node_type(list) == hlist_node)) {
2833
2834 halfword glyph = box_list(list);
2835 if (glyph && node_type(glyph) == glyph_node) {
2836
2837 theta = tex_char_height_from_glyph(glyph);
2838 } else {
2839 theta = box_height(delimiter);
2840 }
2841 } else {
2842 theta = box_height(delimiter);
2843 }
2844 }
2845 }
2846
2850 tex_aux_set_radical_kerns(&extremes, kerns, size);
2851
2858 {
2859 halfword delta = (box_total(delimiter) - theta) - (box_total(nucleus) + clearance);
2860 if (delta > 0) {
2861
2862 clearance += tex_half_scaled(delta);
2863 }
2864 if (has_noad_option_reflected(target)) {
2865 box_shift_amount(delimiter) = - ((box_depth(delimiter) - theta) - (box_depth(nucleus) + clearance));
2866 if (companion) {
2867 box_shift_amount(companion) = - ((box_depth(companion) - theta) - (box_depth(nucleus) + clearance));
2868 }
2869 } else {
2870 box_shift_amount(delimiter) = (box_height(delimiter) - theta) - (box_height(nucleus) + clearance);
2871 if (companion) {
2872 box_shift_amount(companion) = (box_height(companion) - theta) - (box_height(nucleus) + clearance);
2873 }
2874 }
2875 }
2876 if (node_type(delimiter) == vlist_node && node_subtype(delimiter) == math_v_delimiter_list) {
2877 halfword before = tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_before, 0);
2878 tex_aux_prepend_hkern_to_box_list(nucleus, before, horizontal_math_kern_subtype, "bad delimiter");
2879 }
2880 if (node_type(companion) == vlist_node && node_subtype(companion) == math_v_delimiter_list) {
2881 halfword after = tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_after, 0);
2882 tex_aux_append_hkern_to_box_list(nucleus, after, horizontal_math_kern_subtype, "bad delimiter");
2883 }
2884 {
2885
2886 halfword total = box_total(delimiter);
2887 halfword list = (has_noad_option_reflected(target) ? tex_aux_underbar : tex_aux_overbar)
2888 (nucleus, clearance, theta, kern,
2889 get_attribute_list(delimiter),
2890
2891 math_radical_rule_subtype, size, fam, norule ? -1 : topdelimiter, style);
2892
2893 radical = tex_aux_link_radical(list, delimiter, companion, rightdelimiter);
2894
2895 if (radical_degree(target)) {
2896
2900 halfword degreestyle = tex_math_style_variant(noad_style(target) == yet_unset_math_style ? noad_style(target) : style, math_parameter_degree_variant);
2901
2902 halfword degree = tex_aux_clean_box(radical_degree(target), degreestyle, style, math_degree_list, 0, NULL);
2903 scaled width = box_width(degree);
2904 tex_attach_attribute_list_copy(degree, radical_degree(target));
2905 if (width) {
2906 scaled before = tex_get_math_x_parameter_checked(style, math_parameter_radical_degree_before);
2907 scaled after = tex_get_math_x_parameter_checked(style, math_parameter_radical_degree_after);
2908 scaled raise = tex_get_math_parameter_checked(style, math_parameter_radical_degree_raise);
2909 if (innerx != INT_MIN) {
2910 tex_aux_append_hkern_to_box_list(degree, innerx, horizontal_math_kern_subtype, "bad degree");
2911 width += innerx;
2912 }
2913 if (-after > width) {
2914 before += -after - width;
2915 }
2916 if (after) {
2917 halfword kern = tex_new_kern_node(after, horizontal_math_kern_subtype);
2918 tex_attach_attribute_list_copy(kern, radical_degree(target));
2919 tex_couple_nodes(kern, radical);
2920 nucleus = kern;
2921 } else {
2922 nucleus = radical;
2923 }
2924 if (innery != INT_MIN) {
2925 box_shift_amount(degree) = - innery + box_depth(radical) + box_shift_amount(radical);
2926 } else {
2927 box_shift_amount(degree) = - (tex_xn_over_d(total, raise, 100) - box_depth(radical) - box_shift_amount(radical));
2928 }
2929 tex_couple_nodes(degree, nucleus);
2930 if (before) {
2931 halfword kern = tex_new_kern_node(before, horizontal_math_kern_subtype);
2932 tex_attach_attribute_list_copy(kern, radical_degree(target));
2933 tex_couple_nodes(kern, degree);
2934 radical = kern;
2935 } else {
2936 radical = degree;
2937 }
2938 } else {
2939 tex_flush_node(degree);
2940 }
2941
2942 kernel_math_list(radical_degree(target)) = null;
2943 tex_flush_node(radical_degree(target));
2944 radical_degree(target) = null;
2945 }
2946 }
2947 tex_aux_assign_radical(target, radical);
2948 if (mergedattr) {
2949 delete_attribute_reference(mergedattr);
2950 delete_attribute_reference(noad_extra_attr(target));
2951 }
2952}
2953
2954
2958
2959static halfword tex_aux_radical_delimiter_cb(halfword target, halfword delimiter, int style, int size, halfword mergedattr, scaled linewidth, scaled targetsize)
2960{
2961 if (has_noad_option_use_callback(target)) {
2962 halfword fam = delimiter_small_family(delimiter);
2963 halfword chr = delimiter_small_character(delimiter);
2964 halfword fnt = tex_fam_fnt(fam, size);
2965 if (chr && fnt != null_font) {
2966 scaled axis = tex_aux_math_axis(size);
2967 scaled exheight = tex_aux_math_exheight(size);
2968 scaled emwidth = tex_aux_math_emwidth(size);
2969 scaled width = box_width(noad_nucleus(target))
2970 + tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_before, 0)
2971 + tex_get_math_x_parameter_default(style, math_parameter_radical_extensible_after, 0);
2972 halfword result = tex_made_extensible(target, fnt, chr, size, width, targetsize, 0, linewidth, axis, exheight, emwidth);
2973 if (result) {
2974 halfword delimiter = register_extensible(fnt, chr, size, result, mergedattr);
2975 box_width(result) -= width;
2976 return delimiter;
2977 }
2978 }
2979 }
2980 return null;
2981}
2982
2983
2984
2985
2986
2987
2988
2989
2990static void tex_aux_make_delimited_radical(halfword target, int style, int size, kernset *kerns)
2991{
2992 halfword nucleus = noad_new_hlist(target);
2993
2994 halfword leftdelimiter = radical_left_delimiter(target);
2995 halfword rightdelimiter = radical_right_delimiter(target);
2996 halfword delimiter = leftdelimiter ? leftdelimiter : rightdelimiter;
2997 halfword companion = leftdelimiter ? rightdelimiter : null;
2998 halfword radical = null;
2999 halfword depth = has_noad_option_exact(target) ? radical_depth(target) : (box_depth(nucleus) + radical_depth(target));
3000 halfword height = has_noad_option_exact(target) ? radical_height(target) : (box_height(nucleus) + radical_height(target));
3001 halfword targetsize = height + depth;
3002 scaled linewidth = tex_get_math_y_parameter(style, math_parameter_radical_rule);
3003 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
3004 halfword mergedattr = tex_merge_attribute_list(node_attr(delimiter), noad_extra_attr(target));
3005 noad_new_hlist(target) = null;
3006 size += radical_size(target);
3007 if (size < text_size) {
3008 size = text_size;
3009 } else if (size > script_script_size) {
3010 size = script_script_size;
3011 }
3012 {
3013 halfword result = tex_aux_radical_delimiter_cb(target, delimiter, style, size, mergedattr, linewidth, targetsize);
3014 if (! result) {
3015 result = tex_aux_make_delimiter(target, delimiter, size, targetsize, 0, style, 2, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, depth, mergedattr, 0, 1);
3016 } else if (depth) {
3017
3018 }
3019 delimiter = result;
3020 }
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044 if (companion) {
3045
3046 if (mergedattr) {
3047 delete_attribute_reference(mergedattr);
3048 }
3049 mergedattr = tex_merge_attribute_list(node_attr(companion), noad_extra_attr(target));
3050 companion = tex_aux_make_delimiter(target, companion, size, targetsize, 0, style, 2, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, depth, mergedattr, 0, 1);
3051 }
3052 tex_aux_set_radical_kerns(&extremes, kerns, size);
3053 radical = tex_aux_link_radical(nucleus, delimiter, companion, rightdelimiter);
3054 tex_aux_assign_radical(target, radical);
3055 if (mergedattr) {
3056 delete_attribute_reference(mergedattr);
3057 delete_attribute_reference(noad_extra_attr(target));
3058 }
3059}
3060
3061
3062
3063static halfword tex_aux_wrapup_over_under_delimiter(halfword target, halfword x, halfword y, scaled shift_up, scaled shift_down, quarterword st)
3064{
3065 halfword box = tex_new_null_box_node(vlist_node, st);
3066 scaled delta = (shift_up - box_depth(x)) - (box_height(y) - shift_down);
3067 box_height(box) = shift_up + box_height(x);
3068 box_depth(box) = box_depth(y) + shift_down;
3069 tex_attach_attribute_list_copy(box, target);
3070 if (delta) {
3071 halfword kern = tex_new_kern_node(delta, vertical_math_kern_subtype);
3072 tex_attach_attribute_list_copy(kern, target);
3073 tex_couple_nodes(x, kern);
3074 tex_couple_nodes(kern, y);
3075 } else {
3076 tex_couple_nodes(x, y);
3077 }
3078 box_list(box) = x;
3079 return box;
3080}
3081
3082
3083
3084static inline halfword tex_aux_check_radical(halfword target, int stack, halfword r, halfword t)
3085{
3086 if (! stack && (box_width(r) >= box_width(t))) {
3087 scaled width = tex_aux_math_given_x_scaled(noad_width(target));
3088 if (width) {
3089 scaled delta = width - box_width(r);
3090 if (delta) {
3091 if (has_noad_option_left(target)) {
3092 halfword kern = tex_new_kern_node(delta, horizontal_math_kern_subtype);
3093 tex_attach_attribute_list_copy(kern, target);
3094 tex_couple_nodes(kern, r);
3095 } else if (has_noad_option_middle(target)) {
3096 halfword kern = tex_new_kern_node(tex_half_scaled(delta), horizontal_math_kern_subtype);
3097 tex_attach_attribute_list_copy(kern, target);
3098 tex_couple_nodes(kern, r);
3099 } else if (has_noad_option_right(target)) {
3100
3101 } else {
3102 return r;
3103 }
3104 r = tex_hpack(r, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3105 box_width(r) = noad_width(target);
3106 tex_attach_attribute_list_copy(r, target);
3107 }
3108 }
3109 }
3110 return r;
3111}
3112
3113static inline void tex_aux_fixup_radical_width(halfword target, halfword x, halfword y)
3114{
3115 if (box_width(y) >= box_width(x)) {
3116 if (noad_width(target)) {
3117 box_shift_amount(x) += tex_half_scaled(box_width(y) - box_width(x)) ;
3118 }
3119 box_width(x) = box_width(y);
3120 } else {
3121 if (noad_width(target)) {
3122 box_shift_amount(y) += tex_half_scaled(box_width(x) - box_width(y)) ;
3123 }
3124 box_width(y) = box_width(x);
3125 }
3126}
3127
3128static inline halfword tex_aux_get_radical_width(halfword target, halfword p)
3129{
3130 return noad_width(target) ? noad_width(target) : box_width(p);
3131}
3132
3133
3138
3139static void tex_aux_make_over_delimiter(halfword target, int style, int size)
3140{
3141 halfword result = null;
3142 scaled delta = 0;
3143 int stack = 0;
3144 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_bgap);
3145 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_vgap);
3146 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);
3147 scaled width = tex_aux_get_radical_width(target, content);
3148 halfword over_delimiter = fraction_left_delimiter(target);
3149 halfword mergedattr = tex_merge_attribute_list(node_attr(over_delimiter), noad_extra_attr(target));
3150 scaled linewidth = tex_get_math_y_parameter(style, math_parameter_radical_rule);
3151
3152 halfword delimiter = tex_aux_radical_delimiter_cb(target, over_delimiter, style, size, mergedattr, linewidth, width);
3153 if (! delimiter) {
3154 delimiter = tex_aux_make_delimiter(target, over_delimiter, size, width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, mergedattr, 0, 1);
3155 }
3156
3157 fraction_left_delimiter(target) = null;
3158 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
3159 tex_aux_fixup_radical_width(target, content, delimiter);
3160 delta = clearance - (shift - box_depth(content) - box_height(delimiter));
3161 if (delta > 0) {
3162 shift += delta;
3163 }
3164 result = tex_aux_wrapup_over_under_delimiter(target, content, delimiter, shift, 0, math_over_delimiter_list);
3165 box_width(result) = box_width(content);
3166 kernel_math_list(noad_nucleus(target)) = result;
3167 node_type(noad_nucleus(target)) = sub_box_node;
3168 if (mergedattr) {
3169 delete_attribute_reference(mergedattr);
3170 delete_attribute_reference(noad_extra_attr(target));
3171 }
3172}
3173
3174
3177
3178static void tex_aux_make_under_delimiter(halfword target, int style, int size)
3179{
3180 halfword result = null;
3181 scaled delta = 0;
3182 int stack = 0;
3183 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_bgap);
3184 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_vgap);
3185 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);
3186 scaled width = tex_aux_get_radical_width(target, content);
3187 halfword under_delimiter = fraction_left_delimiter(target);
3188 halfword mergedattr = tex_merge_attribute_list(node_attr(under_delimiter), noad_extra_attr(target));
3189 scaled linewidth = tex_get_math_y_parameter(style, math_parameter_radical_rule);
3190
3191 halfword delimiter = tex_aux_radical_delimiter_cb(target, under_delimiter, style, size, mergedattr, linewidth, width);
3192 if (! delimiter) {
3193 delimiter = tex_aux_make_delimiter(target, under_delimiter, size, width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, mergedattr, 0, 1);
3194 }
3195 fraction_left_delimiter(target) = null;
3196 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
3197 tex_aux_fixup_radical_width(target, delimiter, content);
3198 delta = clearance - (- box_depth(delimiter) - (box_height(content) - shift));
3199 if (delta > 0) {
3200 shift += delta;
3201 }
3202 result = tex_aux_wrapup_over_under_delimiter(target, delimiter, content, 0, shift, math_under_delimiter_list);
3203 box_width(result) = box_width(content);
3204 kernel_math_list(noad_nucleus(target)) = result;
3205 node_type(noad_nucleus(target)) = sub_box_node;
3206 if (mergedattr) {
3207 delete_attribute_reference(mergedattr);
3208 delete_attribute_reference(noad_extra_attr(target));
3209 }
3210}
3211
3212
3215
3216static void tex_aux_make_delimiter_over(halfword target, int style, int size)
3217{
3218 halfword result;
3219 scaled actual;
3220 halfword delimiter;
3221 int stack = 0;
3222 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_bgap);
3223 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_over_delimiter_vgap);
3224 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);
3225 scaled width = tex_aux_get_radical_width(target, content);
3226 halfword over_delimiter = fraction_left_delimiter(target);
3227 halfword mergedattr = tex_merge_attribute_list(node_attr(over_delimiter), noad_extra_attr(target));
3228 scaled linewidth = tex_get_math_y_parameter(style, math_parameter_radical_rule);
3229
3230 if (size != script_script_size) {
3231 size += 1;
3232 }
3233
3234 delimiter = tex_aux_radical_delimiter_cb(target, over_delimiter, style, size, mergedattr, linewidth, width);
3235 if (! delimiter) {
3236 delimiter = tex_aux_make_delimiter(target, over_delimiter, size, width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(over_delimiter), NULL, 0, mergedattr, 0, 1);
3237 }
3238
3239 fraction_left_delimiter(target) = null;
3240 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
3241 tex_aux_fixup_radical_width(target, delimiter, content);
3242 shift -= box_total(delimiter);
3243 actual = shift - box_height(content);
3244 if (actual < clearance) {
3245 shift += (clearance - actual);
3246 }
3247 result = tex_aux_wrapup_over_under_delimiter(target, delimiter, content, shift, 0, math_over_delimiter_list);
3248 box_width(result) = box_width(delimiter);
3249 kernel_math_list(noad_nucleus(target)) = result;
3250 node_type(noad_nucleus(target)) = sub_box_node;
3251 if (mergedattr) {
3252 delete_attribute_reference(mergedattr);
3253 delete_attribute_reference(noad_extra_attr(target));
3254 }
3255}
3256
3257
3260
3261static void tex_aux_make_delimiter_under(halfword target, int style, int size)
3262{
3263 halfword result;
3264 scaled actual;
3265 halfword delimiter;
3266 int stack = 0;
3267 scaled shift = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_bgap);
3268 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_under_delimiter_vgap);
3269 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);
3270 scaled width = tex_aux_get_radical_width(target, content);
3271 halfword under_delimiter = fraction_left_delimiter(target);
3272 halfword mergedattr = tex_merge_attribute_list(node_attr(under_delimiter), noad_extra_attr(target));
3273 scaled linewidth = tex_get_math_y_parameter(style, math_parameter_radical_rule);
3274
3275 if (size != script_script_size) {
3276 size += 1;
3277 }
3278
3279 delimiter = tex_aux_radical_delimiter_cb(target, under_delimiter, style, size, mergedattr, linewidth, width);
3280 if (! delimiter) {
3281 delimiter = tex_aux_make_delimiter(target, under_delimiter, size, width, 1, style, 1, &stack, NULL, 0, has_noad_option_nooverflow(under_delimiter), NULL, 0, mergedattr, 0, 1);
3282 }
3283
3284 fraction_left_delimiter(target) = null;
3285 delimiter = tex_aux_check_radical(target, stack, delimiter, content);
3286 tex_aux_fixup_radical_width(target, content, delimiter);
3287 shift -= box_total(delimiter);
3288 actual = shift - box_depth(content);
3289 if (actual < clearance) {
3290 shift += (clearance - actual);
3291 }
3292 result = tex_aux_wrapup_over_under_delimiter(target, content, delimiter, 0, shift, math_under_delimiter_list);
3293
3294 box_width(result) = box_width(delimiter);
3295 kernel_math_list(noad_nucleus(target)) = result;
3296 node_type(noad_nucleus(target)) = sub_box_node;
3297 if (mergedattr) {
3298 delete_attribute_reference(mergedattr);
3299 delete_attribute_reference(noad_extra_attr(target));
3300 }
3301}
3302
3303static void tex_aux_make_radical(halfword target, int style, int size, kernset *kerns)
3304{
3305 switch (node_subtype(target)) {
3306 case under_delimiter_radical_subtype:
3307 tex_aux_make_under_delimiter(target, style, size);
3308 break;
3309 case over_delimiter_radical_subtype:
3310 tex_aux_make_over_delimiter(target, style, size);
3311 break;
3312 case delimiter_under_radical_subtype:
3313 tex_aux_make_delimiter_under(target, style, size);
3314 break;
3315 case delimiter_over_radical_subtype:
3316 tex_aux_make_delimiter_over(target, style, size);
3317 break;
3318 case delimited_radical_subtype:
3319 tex_aux_make_delimited_radical(target, style, size, kerns);
3320 break;
3321 case h_extensible_radical_subtype:
3322 tex_aux_make_hextension(target, style, size);
3323 break;
3324 default:
3325 tex_aux_make_root_radical(target, style, size, kerns);
3326 break;
3327 }
3328 if (noad_source(target)) {
3329 halfword result = kernel_math_list(noad_nucleus(target));
3330 if (result) {
3331 box_source_anchor(result) = noad_source(target);
3332 tex_set_box_geometry(result, anchor_geometry);
3333 }
3334 }
3335}
3336
3337static void tex_aux_preroll_radical(halfword target, int style, int size)
3338{
3339 switch (node_subtype(target)) {
3340 case under_delimiter_radical_subtype:
3341 case over_delimiter_radical_subtype:
3342 case delimiter_under_radical_subtype:
3343 case delimiter_over_radical_subtype:
3344 case h_extensible_radical_subtype:
3345 break;
3346 default:
3347 tex_aux_preroll_root_radical(target, style, size);
3348 break;
3349 }
3350}
3351
3352
3358
3359typedef enum math_accent_location_codes {
3360 top_accent_code = 1,
3361 bot_accent_code = 2,
3362 overlay_accent_code = 4,
3363 stretch_accent_code = 8,
3364} math_accent_location_codes;
3365
3366static int tex_aux_compute_accent_skew(halfword target, int flags, scaled *skew, halfword size)
3367{
3368
3369 int absolute = 0;
3370 switch (node_type(noad_nucleus(target))) {
3371 case math_char_node:
3372 {
3373 halfword chr = null;
3374 halfword fnt = null;
3375 tex_aux_fetch(noad_nucleus(target), "accent", &fnt, &chr);
3376
3377 chr = tex_get_math_char(fnt, chr, size, NULL, NULL, NULL, NULL, 0);
3378 if (tex_aux_math_engine_control(fnt, math_control_accent_skew_apply)) {
3379
3383 if (flags & bot_accent_code) {
3384 *skew = tex_char_unchecked_bottom_anchor_from_font(fnt, chr);
3385 } else {
3386 *skew = tex_char_unchecked_top_anchor_from_font(fnt, chr);
3387 }
3388 if (*skew != INT_MIN) {
3389 *skew = tex_aux_math_x_size_scaled(fnt, *skew, size);
3390 absolute = 1;
3391 } else {
3392 *skew = 0;
3393 }
3394 } else if (flags & top_accent_code) {
3395 *skew = tex_aux_math_x_size_scaled(fnt, tex_get_kern(fnt, chr, font_skew_char(fnt)), size);
3396 } else {
3397 *skew = 0;
3398 }
3399 if (tracing_math_par >= 2) {
3400 tex_begin_diagnostic();
3401 tex_print_format("[math: accent skew, font %i, chr %x, skew %p, absolute %i]", fnt, chr, *skew, absolute);
3402 tex_end_diagnostic();
3403 }
3404 break;
3405 }
3406 case sub_mlist_node:
3407 {
3408
3434 halfword p = kernel_math_list(noad_nucleus(target));
3435 if (p && (! node_next(p))) {
3436 switch (node_type(p)) {
3437 case accent_noad:
3438 absolute = tex_aux_compute_accent_skew(p, flags, skew, size);
3439 break;
3440 case simple_noad:
3441 if (! noad_has_following_scripts(p)) {
3442 absolute = tex_aux_compute_accent_skew(p, flags, skew, size);
3443 }
3444 break;
3445 }
3446 }
3447 if (tracing_math_par >= 2) {
3448 tex_begin_diagnostic();
3449 tex_print_format("[math: accent skew, absolute %i]", absolute);
3450 tex_end_diagnostic();
3451 }
3452 break;
3453 }
3454 }
3455 return absolute;
3456}
3457
3458static void tex_aux_do_make_math_accent(halfword target, halfword source, halfword accentfnt, halfword accentchr, int flags, int style, int size, scaled *accenttotal, scaled *leftkern, scaled *rightkern)
3459{
3460
3461 scaled baseheight = 0;
3462
3463 scaled basewidth = 0;
3464 scaled usedwidth = 0;
3465
3466 scaled delta = 0;
3467 scaled overshoot = 0;
3468 extinfo *extended = NULL;
3469 scaled fraction = accent_fraction(target) > 0 ? accent_fraction(target) : scaling_factor;
3470 scaled skew = 0;
3471 scaled offset = 0;
3472 scaled innery = 0;
3473 halfword accent = null;
3474 halfword base = null;
3475 halfword nucleus = noad_nucleus(target);
3476 halfword stretch = (flags & stretch_accent_code) == stretch_accent_code;
3477 halfword basefnt = null_font;
3478 halfword basechr = 0;
3479 halfword accentbasefnt = accentfnt;
3480 halfword accentbasechr = accentchr;
3481 halfword mergedattr = tex_merge_attribute_list(node_attr(source), noad_extra_attr(target));
3482 int found = 0;
3483 int isscaled = 0;
3484 int keep = 0;
3485
3490 int absolute = tex_aux_compute_accent_skew(target, flags, &skew, size);
3491 {
3492
3493 halfword usedstyle;
3494 kernset localkerns;
3495 if (flags & top_accent_code) {
3496 usedstyle = tex_math_style_variant(style, math_parameter_top_accent_variant);
3497 } else if (flags & bot_accent_code) {
3498 usedstyle = tex_math_style_variant(style, math_parameter_bottom_accent_variant);
3499 } else {
3500 usedstyle = tex_math_style_variant(style, math_parameter_overlay_accent_variant);
3501 }
3502 tex_math_wipe_kerns(&localkerns);
3503
3504 base = tex_aux_clean_box(noad_nucleus(target), usedstyle, style, math_nucleus_list, 1, &localkerns);
3505 if (flags & top_accent_code) {
3506 if (leftkern) {
3507 *leftkern = localkerns.bottomleft;
3508 }
3509 if (rightkern) {
3510 *rightkern = localkerns.bottomright;
3511 }
3512 } else if (flags & bot_accent_code) {
3513 if (leftkern) {
3514 *leftkern = localkerns.topleft;
3515 }
3516 if (rightkern) {
3517 *rightkern = localkerns.topright;
3518 }
3519 }
3520 basewidth = box_width(base);
3521 baseheight = box_height(base);
3522
3523 }
3524 if (base) {
3525
3526 halfword list = box_list(base);
3527 if (list && node_type(list) == glyph_node) {
3528
3529 basefnt = glyph_font(list);
3530 basechr = glyph_character(list);
3531 }
3532 }
3533 if (stretch && absolute && (flags & top_accent_code) && tex_aux_math_engine_control(accentfnt, math_control_accent_top_skew_with_offset)) {
3534
3543 if (base && basefnt && basechr) {
3544 offset = tex_char_top_overshoot_from_font(basefnt, basechr);
3545 offset = offset == INT_MIN ? 0 : tex_aux_math_x_size_scaled(basefnt, offset, size);
3546 }
3547 usedwidth = 2 * ((skew < (basewidth - skew) ? skew : (basewidth - skew)) + offset);
3548 } else if (! absolute && tex_aux_math_engine_control(accentfnt, math_control_accent_skew_half)) {
3549 skew = tex_half_scaled(basewidth);
3550 absolute = 1;
3551 usedwidth = basewidth;
3552 } else {
3553 usedwidth = basewidth;
3554 }
3555
3559
3560 if (has_noad_option_use_callback(target)) {
3561 halfword thickness = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
3562 scaled axis = tex_aux_math_axis(size);
3563 scaled exheight = tex_aux_math_exheight(size);
3564 scaled emwidth = tex_aux_math_emwidth(size);
3565 halfword result = tex_made_extensible(target, accentfnt, accentchr, size, usedwidth, baseheight, 0, thickness, axis, exheight, emwidth);
3566 if (result) {
3567 accent = register_extensible(accentfnt, accentchr, size, result, mergedattr);
3568 found = 1;
3569 goto PICKUP;
3570 }
3571 }
3572
3573 if (stretch && (tex_char_width_from_font(accentfnt, accentchr) < usedwidth)) {
3574
3575 scaled target = 0;
3576 if (flags & overlay_accent_code) {
3577 target = baseheight;
3578 } else {
3579 target += usedwidth;
3580 if (base && basefnt && basechr) {
3581 target += tex_aux_math_x_size_scaled(basefnt, tex_char_right_margin_from_font(basefnt, basechr), size);
3582 target += tex_aux_math_x_size_scaled(basefnt, tex_char_left_margin_from_font(basefnt, basechr), size);
3583 }
3584 }
3585 if (fraction > 0) {
3586 target = tex_xn_over_d(target, fraction, scaling_factor);
3587 }
3588 while (1) {
3589 if (tex_char_has_tag_from_font(accentfnt, accentchr, extensible_tag)) {
3590 extended = tex_char_extensible_recipe_from_font(accentfnt, accentchr);
3591 }
3592 if (extended) {
3593
3597 halfword overlap = tex_get_math_x_parameter_checked(style, math_parameter_connector_overlap_min);
3598
3599 accent = tex_make_extensible(accentfnt, accentchr, usedwidth, overlap, 1, mergedattr, lmt_math_state.size);
3600 accent = register_extensible(accentfnt, accentchr, size, accent, mergedattr);
3601 break;
3602 } else if (! tex_char_has_tag_from_font(accentfnt, accentchr, list_tag)) {
3603 break;
3604 } else {
3605 halfword next = tex_char_next_from_font(accentfnt, accentchr);
3606 if (! tex_char_exists(accentfnt, next)) {
3607 break;
3608 } else if (flags & overlay_accent_code) {
3609 if (tex_aux_math_y_size_scaled(accentfnt, tex_char_height_from_font(accentfnt, next), size) > target) {
3610 break;
3611 }
3612 } else {
3613 if (tex_aux_math_x_size_scaled(accentfnt, tex_char_width_from_font(accentfnt, next), size) > target) {
3614 break;
3615 }
3616 }
3617 accentchr = next;
3618 }
3619 }
3620
3621 }
3622 PICKUP:
3623 keep = (accentfnt == accentbasefnt) && (accentchr == accentbasechr) && (has_noad_option_keep_base(target) || tex_char_has_tag_from_font(accentfnt, accentchr, keep_base_tag));
3624 if (accent) {
3625
3628 } else {
3629
3633 accent = tex_aux_char_box(accentfnt, accentchr, mergedattr, NULL, glyph_math_accent_subtype, usedwidth, style, keep ? 0 : has_noad_option_shrink(target), keep ? 0 : has_noad_option_stretch(target), &isscaled);
3634 found = 1;
3635 }
3636 if (flags & top_accent_code) {
3637 scaled b = tex_get_math_y_parameter(style, math_parameter_accent_base_height);
3638 scaled u = tex_get_math_y_parameter(style, math_parameter_accent_top_shift_up);
3639 if (found && ! tex_aux_math_engine_control(accentfnt, math_control_ignore_flat_accents)) {
3640 scaled f = tex_get_math_y_parameter(style, math_parameter_flattened_accent_base_height);
3641 if (f != undefined_math_parameter && baseheight > f) {
3642 int keep = (accentfnt == accentbasefnt) && (accentchr == accentbasechr) && (has_noad_option_keep_base(target) || tex_char_has_tag_from_font(accentfnt, accentchr, keep_base_tag));
3643 halfword flatchr = tex_char_flat_accent_from_font(accentfnt, accentchr);
3644 if (flatchr && flatchr != INT_MIN && flatchr != accentchr) {
3645 scaled uf = tex_get_math_y_parameter(style, math_parameter_flattened_accent_top_shift_up);
3646 if (uf != undefined_math_parameter) {
3647 u = uf;
3648 }
3649 tex_flush_node(accent);
3650 accent = tex_aux_char_box(accentfnt, flatchr, mergedattr, NULL, glyph_math_accent_subtype, usedwidth, style, keep ? 0 : has_noad_option_shrink(target), keep ? 0 : has_noad_option_stretch(target), &isscaled);
3651 if (tracing_math_par >= 2) {
3652 tex_begin_diagnostic();
3653 tex_print_format("[math: flattening accent, old %x, new %x]", accentchr, flatchr);
3654 tex_end_diagnostic();
3655 }
3656 accentchr = flatchr;
3657 }
3658 }
3659 }
3660 if (has_noad_option_auto_base(target)) {
3661 b = - box_depth(accent);
3662 }
3663 if (b != undefined_math_parameter) {
3664
3665 delta = baseheight < b ? baseheight : b;
3666 }
3667 if (u != undefined_math_parameter) {
3668 delta -= u;
3669 }
3670 if (tex_char_has_tag_from_font(accentfnt, accentchr, inner_top_tag)) {
3671 innery = tex_char_inner_y_offset_from_font(accentfnt, accentchr);
3672 innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(accentfnt, innery, size);
3673 }
3674 } else if (flags & bot_accent_code) {
3675
3676
3677 scaled l = tex_get_math_y_parameter(style, stretch ? math_parameter_flattened_accent_bottom_shift_down : math_parameter_accent_bottom_shift_down);
3678
3679
3680
3681
3682 if (l != undefined_math_parameter) {
3683 delta += l;
3684 }
3685 if (tex_char_has_tag_from_font(accentfnt, accentchr, inner_bottom_tag)) {
3686 innery = tex_char_inner_y_offset_from_font(accentfnt, accentchr);
3687 innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(accentfnt, innery, size);
3688 }
3689 } else {
3690
3691 if (has_noad_option_exact(target)) {
3692 delta = box_height(base) + box_depth(accent);
3693 } else {
3694 delta = tex_half_scaled(box_total(accent) + box_total(base));
3695 }
3696
3697
3698
3699 }
3700 if (accenttotal) {
3701 *accenttotal = box_total(accent);
3702 }
3703 if (node_type(nucleus) != math_char_node) {
3704
3705 } else if (noad_has_following_scripts(target)) {
3706
3707 tex_flush_node_list(base);
3708 base = tex_new_node(simple_noad, ordinary_noad_subtype);
3709 tex_attach_attribute_list_copy(base, nucleus);
3710 noad_nucleus(base) = tex_aux_math_clone(nucleus);
3711
3712 node_type(nucleus) = sub_mlist_node;
3713 kernel_math_list(nucleus) = base;
3714 base = tex_aux_clean_box(nucleus, style, style, math_nucleus_list, 1, NULL);
3715 delta = delta + box_height(base) - baseheight;
3716 baseheight = box_height(base);
3717 }
3718
3719 if (flags & overlay_accent_code) {
3720
3721 box_shift_amount(accent) = tex_half_scaled(basewidth - box_width(accent));
3722 box_width(accent) = 0;
3723 } else {
3724 halfword accentwidth = box_width(accent);
3725 if (accentwidth > basewidth && has_noad_option_nooverflow(target)) {
3726
3731 scaled leftkern = tex_half_scaled(accentwidth - basewidth);
3732 if (leftkern > 0) {
3733 halfword kern = tex_new_kern_node(leftkern, horizontal_math_kern_subtype);
3734 tex_attach_attribute_list_copy(kern, target);
3735 tex_try_couple_nodes(kern, base);
3736 base = tex_hpack(kern, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3737 tex_attach_attribute_list_copy(base, target);
3738 basewidth = accentwidth;
3739 box_width(base) = accentwidth;
3740 }
3741 } else {
3742 if (absolute) {
3743 scaled anchor = 0;
3744 if (extended || isscaled) {
3745
3746 anchor = tex_half_scaled(accentwidth);
3747 } else {
3748
3749 if (flags & top_accent_code) {
3750 anchor = tex_char_unchecked_top_anchor_from_font(accentfnt, accentchr);
3751 } else if (flags & bot_accent_code) {
3752 anchor = tex_char_unchecked_bottom_anchor_from_font(accentfnt, accentchr);
3753 } else {
3754 anchor = INT_MIN;
3755 }
3756 if (anchor == INT_MIN || has_noad_option_center(target)) {
3757
3758 anchor = tex_half_scaled(accentwidth);
3759 } else {
3760 anchor = tex_aux_math_x_size_scaled(accentfnt, anchor, size);
3761 }
3762 }
3763 if (math_direction_par == dir_righttoleft) {
3764 skew += anchor - accentwidth;
3765 } else {
3766 skew -= anchor;
3767 }
3768 } else if (accentwidth == 0) {
3769 skew += basewidth;
3770 } else if (math_direction_par == dir_righttoleft) {
3771 skew += accentwidth;
3772 } else {
3773 skew += tex_half_scaled(basewidth - accentwidth);
3774 }
3775 box_shift_amount(accent) = skew;
3776 box_width(accent) = 0;
3777 if (accentwidth) {
3778 overshoot = accentwidth + skew - basewidth;
3779 }
3780 if (overshoot < 0) {
3781 overshoot = 0;
3782 }
3783 }
3784 }
3785 if (flags & (top_accent_code)) {
3786 accent_top_overshoot(target) = overshoot;
3787 }
3788 if (flags & (bot_accent_code)) {
3789 accent_bot_overshoot(target) = overshoot;
3790 }
3791 {
3792 halfword result = null;
3793 if (flags & (top_accent_code | overlay_accent_code)) {
3794 delta += innery;
3795 if (delta) {
3796 halfword kern = tex_new_kern_node(-delta, vertical_math_kern_subtype);
3797 tex_attach_attribute_list_copy(kern, target);
3798 tex_couple_nodes(accent, kern);
3799 tex_couple_nodes(kern, base);
3800 } else {
3801 tex_couple_nodes(accent, base);
3802 }
3803 result = accent;
3804 } else if ((flags & bot_accent_code) && innery) {
3805 halfword kern = tex_new_kern_node(innery, vertical_math_kern_subtype);
3806 tex_attach_attribute_list_copy(kern, target);
3807 tex_couple_nodes(base, kern);
3808 tex_couple_nodes(kern, accent);
3809 result = base;
3810 } else {
3811 tex_couple_nodes(base, accent);
3812 result = base;
3813 }
3814 result = tex_vpack(result, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
3815 tex_attach_attribute_list_copy(result, target);
3816 node_subtype(result) = math_accent_list;
3817 box_width(result) = box_width(base);
3818 delta = baseheight - box_height(result);
3819 if (flags & (top_accent_code | overlay_accent_code)) {
3820 if (delta > 0) {
3821
3822 halfword kern = tex_new_kern_node(delta, vertical_math_kern_subtype);
3823 tex_attach_attribute_list_copy(kern, target);
3824 tex_try_couple_nodes(kern, box_list(result));
3825 box_list(result) = kern;
3826 box_height(result) = baseheight;
3827 }
3828 } else {
3829 box_shift_amount(result) = - delta;
3830 }
3831 box_width(result) += overshoot;
3832 if (node_type(result) == vlist_node) {
3833 result = tex_hpack(result, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3834 tex_attach_attribute_list_copy(result, target);
3835 node_subtype(result) = math_accent_list;
3836 }
3837 kernel_math_list(nucleus) = result;
3838 node_type(nucleus) = sub_box_node;
3839 }
3840 if (mergedattr) {
3841 delete_attribute_reference(mergedattr);
3842 delete_attribute_reference(noad_extra_attr(target));
3843 }
3844}
3845
3846static void tex_aux_make_accent(halfword target, int style, int size, kernset *kerns)
3847{
3848 int topstretch = 0;
3849 int botstretch = 0;
3850 halfword fnt = null;
3851 halfword chr = null;
3852
3855 switch (node_subtype(target)) {
3856 case bothflexible_accent_subtype: topstretch = 1; botstretch = 1; break;
3857 case fixedtop_accent_subtype : botstretch = 1; break;
3858 case fixedbottom_accent_subtype : topstretch = 1; break;
3859 case fixedboth_accent_subtype : break;
3860 }
3861
3865 if (accent_top_character(target)) {
3866 if (tex_aux_fetch(accent_top_character(target), "top accent", &fnt, &chr)) {
3867 tex_aux_do_make_math_accent(target, accent_top_character(target), fnt, chr, top_accent_code | (topstretch ? stretch_accent_code : 0), style, size, &(kerns->toptotal),
3868 tex_math_has_class_option(accent_noad_subtype, left_bottom_kern_class_option) ? &(kerns->bottomleft) : NULL,
3869 tex_math_has_class_option(accent_noad_subtype, right_bottom_kern_class_option) ? &(kerns->bottomright) : NULL
3870 );
3871 }
3872 tex_flush_node(accent_top_character(target));
3873 accent_top_character(target) = null;
3874 }
3875 if (accent_bottom_character(target)) {
3876 if (tex_aux_fetch(accent_bottom_character(target), "bottom accent", &fnt, &chr)) {
3877 tex_aux_do_make_math_accent(target, accent_bottom_character(target), fnt, chr, bot_accent_code | (botstretch ? stretch_accent_code : 0), style, size, &(kerns->bottomtotal),
3878 tex_math_has_class_option(accent_noad_subtype, left_bottom_kern_class_option) ? &(kerns->topleft) : NULL,
3879 tex_math_has_class_option(accent_noad_subtype, right_bottom_kern_class_option) ? &(kerns->topright) : NULL
3880 );
3881 }
3882 tex_flush_node(accent_bottom_character(target));
3883 accent_bottom_character(target) = null;
3884 }
3885 if (accent_middle_character(target)) {
3886 if (tex_aux_fetch(accent_middle_character(target), "overlay accent", &fnt, &chr)) {
3887 tex_aux_do_make_math_accent(target, accent_middle_character(target), fnt, chr, overlay_accent_code | stretch_accent_code, style, size, NULL, NULL, NULL);
3888 }
3889 tex_flush_node(accent_middle_character(target));
3890 accent_middle_character(target) = null;
3891 }
3892 if (noad_source(target)) {
3893 halfword result = kernel_math_list(noad_nucleus(target));
3894 if (result) {
3895 box_source_anchor(result) = noad_source(target);
3896 tex_set_box_geometry(result, anchor_geometry);
3897 }
3898 }
3899}
3900
3901
3914
3915
3920
3921static void tex_aux_wrap_fraction_parts(halfword target, int style, int size, halfword *numerator, halfword *denominator, int check)
3922{
3923 if (noad_style(target) == unused_math_style) {
3924 *numerator = tex_aux_clean_box(fraction_numerator(target), tex_math_style_variant(style, math_parameter_numerator_variant), style, math_numerator_list, 0, NULL);
3925 *denominator = tex_aux_clean_box(fraction_denominator(target), tex_math_style_variant(style, math_parameter_denominator_variant), style, math_denominator_list, 0, NULL);
3926 } else {
3927 *numerator = tex_aux_clean_box(fraction_numerator(target), noad_style(target), style, math_numerator_list, 0, NULL);
3928 *denominator = tex_aux_clean_box(fraction_denominator(target), noad_style(target), style, math_denominator_list, 0, NULL);
3929 }
3930 if (check) {
3931 if (box_width(*numerator) < box_width(*denominator)) {
3932 *numerator = tex_aux_rebox(*numerator, box_width(*denominator), size);
3933 } else {
3934 *denominator = tex_aux_rebox(*denominator, box_width(*numerator), size);
3935 }
3936 }
3937}
3938
3939
3942
3943static void tex_aux_wrap_fraction_result(halfword target, int style, int size, halfword fraction, kernset *kerns)
3944{
3945 halfword result = null;
3946 halfword left_delimiter = fraction_left_delimiter(target);
3947 halfword right_delimiter = fraction_right_delimiter(target);
3948 if (left_delimiter || right_delimiter) {
3949 halfword left = null;
3950 halfword right = null;
3951 halfword delta = tex_get_math_y_parameter(style, math_parameter_fraction_del_size);
3952 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
3953 if (delta == undefined_math_parameter) {
3954 delta = tex_aux_get_delimiter_height(box_height(fraction), box_depth(fraction), 1, size, style);
3955 }
3956
3957 left = tex_aux_make_delimiter(target, left_delimiter, size, delta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), NULL, 0, null, 0, 1);
3958 right = tex_aux_make_delimiter(target, right_delimiter, size, delta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, 0, null, 0, 1);
3959 if (kerns && extremes.tfont) {
3960 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_left_top_kern_class_option)) {
3961 kerns->topleft = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_left_kern_from_font(extremes.tfont, extremes.tchar), size);
3962 }
3963 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_left_bottom_kern_class_option)) {
3964 kerns->bottomleft = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_left_kern_from_font(extremes.bfont, extremes.bchar), size);
3965 }
3966 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_right_top_kern_class_option)) {
3967 kerns->topright = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_right_kern_from_font(extremes.tfont, extremes.tchar), size);
3968 }
3969 if (tex_math_has_class_option(fraction_noad_subtype, carry_over_right_bottom_kern_class_option)) {
3970 kerns->bottomright = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_right_kern_from_font(extremes.bfont, extremes.bchar), size);
3971 }
3972 if (tex_math_has_class_option(fraction_noad_subtype, prefer_delimiter_dimensions_class_option)) {
3973 kerns->height = extremes.height;
3974 kerns->depth = extremes.depth;
3975 kerns->dimensions = 1;
3976 kerns->font = extremes.tfont;
3977 }
3978 }
3979
3980 tex_couple_nodes(left, fraction);
3981 tex_couple_nodes(fraction, right);
3982 fraction = left;
3983 }
3984 result = tex_hpack(fraction, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
3985 tex_attach_attribute_list_copy(result, target);
3986
3987 node_subtype(result) = math_fraction_list;
3988 tex_aux_assign_new_hlist(target, result);
3989 if (noad_source(target)) {
3990 box_source_anchor(result) = noad_source(target);
3991
3992 tex_set_box_geometry(result, anchor_geometry);
3993 }
3994}
3995
3996
4003
4004static void tex_aux_calculate_fraction_shifts(halfword target, int style, int size, scaled *shift_up, scaled *shift_down, int up, int down)
4005{
4006 (void) size;
4007 *shift_up = tex_get_math_y_parameter_checked(style, up);
4008 *shift_down = tex_get_math_y_parameter_checked(style, down);
4009 *shift_up = tex_round_xn_over_d(*shift_up, fraction_v_factor(target), scaling_factor);
4010 *shift_down = tex_round_xn_over_d(*shift_down, fraction_v_factor(target), scaling_factor);
4011}
4012
4013static 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)
4014{
4015 scaled clearance = tex_get_math_y_parameter_checked(style, math_parameter_stack_vgap);
4016 tex_aux_calculate_fraction_shifts(target, style, size, shift_up, shift_down, math_parameter_stack_num_up, math_parameter_stack_denom_down);
4017 *delta = tex_half_scaled(clearance - ((*shift_up - box_depth(numerator)) - (box_height(denominator) - *shift_down)));
4018 if (*delta > 0) {
4019 *shift_up += *delta;
4020 *shift_down += *delta;
4021 }
4022}
4023
4024static 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)
4025{
4026 scaled axis = tex_aux_math_axis(size);
4027 scaled numerator_clearance = tex_get_math_y_parameter_checked(style, math_parameter_fraction_num_vgap);
4028 scaled denominator_clearance = tex_get_math_y_parameter_checked(style, math_parameter_fraction_denom_vgap);
4029 scaled delta_up = 0;
4030 scaled delta_down = 0;
4031 tex_aux_calculate_fraction_shifts(target, style, size, shift_up, shift_down, math_parameter_fraction_num_up, math_parameter_fraction_denom_down);
4032
4033 *delta = tex_half_scaled(tex_aux_math_given_y_scaled(fraction_rule_thickness(target)));
4034 delta_up = numerator_clearance - ((*shift_up - box_depth(numerator) ) - (axis + *delta));
4035 delta_down = denominator_clearance - ((*shift_down - box_height(denominator)) + (axis - *delta));
4036 if (delta_up > 0) {
4037 *shift_up += delta_up;
4038 }
4039 if (delta_down > 0) {
4040 *shift_down += delta_down;
4041 }
4042}
4043
4044static scaled tex_aux_check_fraction_rule(halfword target, int style, int size, int fractiontype, halfword *usedfam)
4045{
4046 scaled preferfont = has_noad_option_preferfontthickness(target);
4047 halfword fam = math_rules_fam_par;
4048 (void) style;
4049
4053 if (preferfont) {
4054
4055 } else if (fractiontype == above_fraction_subtype) {
4056
4057 preferfont = 0;
4058 if (has_noad_option_proportional(target)) {
4059
4060 scaled text = tex_get_math_y_parameter_checked(text_style, math_parameter_fraction_rule);
4061 scaled here = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
4062 fraction_rule_thickness(target) = tex_ext_xn_over_d(fraction_rule_thickness(target), here, text);
4063 }
4064 } else if (fraction_rule_thickness(target)) {
4065
4066 preferfont = 1;
4067 }
4068 if (preferfont) {
4069 halfword t = tex_aux_check_rule_thickness(target, size, &fam, math_control_fraction_rule, FractionRuleThickness);
4070 if (t != undefined_math_parameter) {
4071 fraction_rule_thickness(target) = t;
4072 }
4073 }
4074 if (fraction_rule_thickness(target) == preset_rule_thickness) {
4075 fraction_rule_thickness(target) = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
4076 }
4077 if (usedfam) {
4078 *usedfam = fam;
4079 }
4080 return tex_aux_math_given_y_scaled(fraction_rule_thickness(target));
4081}
4082
4083static void tex_aux_compensate_fraction_rule(halfword target, halfword fraction, halfword separator, scaled thickness)
4084{
4085 (void) target;
4086 if (box_total(separator) != thickness) {
4087 scaled half = tex_half_scaled(box_total(separator) - thickness);
4088 box_height(fraction) += half;
4089 box_depth(fraction) += half;
4090 }
4091}
4092
4093static void tex_aux_apply_fraction_shifts(halfword fraction, halfword numerator, halfword denominator, scaled shift_up, scaled shift_down)
4094{
4095 box_height(fraction) = shift_up + box_height(numerator);
4096 box_depth(fraction) = box_depth(denominator) + shift_down;
4097 box_width(fraction) = box_width(numerator);
4098}
4099
4100
4105
4106static 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)
4107{
4108 (void) target;
4109 (void) style;
4110 if (separator) {
4111 scaled axis = tex_aux_math_axis(size);
4112 halfword after = tex_new_kern_node((axis - delta) - (box_height(denominator) - shift_down), vertical_math_kern_subtype);
4113 halfword before = tex_new_kern_node((shift_up - box_depth(numerator)) - (axis + delta), vertical_math_kern_subtype);
4114 tex_attach_attribute_list_copy(after, target);
4115 tex_attach_attribute_list_copy(before, target);
4116 tex_couple_nodes(separator, after);
4117 tex_couple_nodes(after, denominator);
4118 tex_couple_nodes(before, separator);
4119 tex_couple_nodes(numerator, before);
4120 } else {
4121 halfword between = tex_new_kern_node((shift_up - box_depth(numerator)) - (box_height(denominator) - shift_down), vertical_math_kern_subtype);
4122 tex_attach_attribute_list_copy(between, target);
4123 tex_couple_nodes(between, denominator);
4124 tex_couple_nodes(numerator, between);
4125 }
4126 return numerator;
4127}
4128
4129
4147
4148static halfword tex_aux_make_skewed_fraction(halfword target, int style, int size, kernset *kerns)
4149{
4150 halfword middle = null;
4151 halfword fraction = null;
4152 halfword numerator = null;
4153 halfword denominator = null;
4154 halfword delimiter = fraction_middle_delimiter(target);
4155 scaled maxheight = 0;
4156 scaled maxdepth = 0;
4157 scaled maxtotal = 0;
4158 scaled ngap = 0;
4159 scaled dgap = 0;
4160 scaled hgap = 0;
4161 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
4162 scaled tolerance = tex_get_math_y_parameter_default(style, math_parameter_skewed_delimiter_tolerance, 0);
4163 scaled axis = tex_aux_math_axis(size);
4164 scaled shift = tex_round_xn_over_d(axis, fraction_v_factor(target), scaling_factor);
4165 halfword mergedattr = tex_merge_attribute_list(node_attr(delimiter), noad_extra_attr(target));
4166 (void) kerns;
4167 tex_aux_wrap_fraction_parts(target, style, size, &numerator, &denominator, 0);
4168 if (! has_noad_option_noaxis(target)) {
4169 shift += axis;
4170 }
4171 shift = tex_half_scaled(shift);
4172
4176 {
4177 scaled ht = box_height(numerator) + shift;
4178 scaled dp = box_depth(numerator) - shift;
4179 if (dp < 0) {
4180 dp = 0;
4181 }
4182 if (ht < 0) {
4183 ht = 0;
4184 }
4185 if (ht > maxheight) {
4186 maxheight = ht;
4187 }
4188 if (dp > maxdepth) {
4189 maxdepth = dp;
4190 }
4191 }
4192 {
4193 scaled ht = box_height(denominator) - shift;
4194 scaled dp = box_depth(denominator) + shift;
4195 if (dp < 0) {
4196 dp = 0;
4197 }
4198 if (ht < 0) {
4199 ht = 0;
4200 }
4201 if (ht > maxheight) {
4202 maxheight = ht;
4203 }
4204 if (dp > maxdepth) {
4205 maxdepth = dp;
4206 }
4207 }
4208 box_shift_amount(numerator) = -shift;
4209 box_shift_amount(denominator) = shift;
4210 maxtotal = maxheight + maxdepth;
4211
4212 if (has_noad_option_use_callback(target)) {
4213 halfword fam = delimiter_small_family(delimiter);
4214 halfword chr = delimiter_small_character(delimiter);
4215 halfword fnt = tex_fam_fnt(fam, size);
4216 if (chr && fnt != null_font) {
4217
4218 halfword thickness = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
4219 scaled exheight = tex_aux_math_exheight(size);
4220 scaled emwidth = tex_aux_math_emwidth(size);
4221 halfword result = tex_made_extensible(target, fnt, chr, size, 0, maxheight, maxdepth, thickness, axis, exheight, emwidth);
4222 if (result) {
4223 middle = register_extensible(fnt, chr, size, result, mergedattr);
4224 goto PICKUP;
4225 }
4226 }
4227 }
4228
4229 middle = tex_aux_make_delimiter(target, delimiter, size, maxtotal, 0, style, 1, NULL, NULL, tolerance, has_noad_option_nooverflow(target), &extremes, 0, mergedattr, 0, 1);
4230 PICKUP:
4231 fraction = tex_new_null_box_node(hlist_node, math_fraction_list);
4232
4235
4238 hgap = box_width(middle);
4239 hgap = tex_round_xn_over_d(hgap, fraction_h_factor(target), scaling_factor);
4240 tex_attach_attribute_list_copy(fraction, target);
4241 box_width(fraction) = box_width(numerator) + box_width(denominator) + box_width(middle) - hgap;
4242 hgap = -tex_half_scaled(hgap);
4243 box_height(fraction) = box_height(middle) > maxheight ? box_height(middle) : maxheight;
4244 box_depth(fraction) = box_depth(middle) > maxdepth ? box_depth(middle) : maxdepth;
4245 ngap = hgap;
4246 dgap = hgap;
4247
4250
4258 if (ngap || dgap) {
4259 halfword nkern = tex_new_kern_node(ngap, horizontal_math_kern_subtype);
4260 halfword dkern = tex_new_kern_node(dgap, horizontal_math_kern_subtype);
4261 tex_attach_attribute_list_copy(nkern, target);
4262 tex_attach_attribute_list_copy(dkern, target);
4263 tex_couple_nodes(numerator, nkern);
4264 tex_couple_nodes(nkern, middle);
4265 tex_couple_nodes(middle, dkern);
4266 tex_couple_nodes(dkern, denominator);
4267 } else {
4268 tex_couple_nodes(numerator, middle);
4269 tex_couple_nodes(middle, denominator);
4270 }
4271 box_list(fraction) = numerator;
4272 if (mergedattr) {
4273 delete_attribute_reference(mergedattr);
4274 delete_attribute_reference(noad_extra_attr(target));
4275 }
4276 return fraction;
4277}
4278
4279static halfword tex_aux_make_ruled_fraction(halfword target, int style, int size, kernset *kerns, int fractiontype)
4280{
4281 halfword numerator = null;
4282 halfword denominator = null;
4283 scaled shift_up = 0;
4284 scaled shift_down = 0;
4285 scaled delta = 0;
4286 halfword fam = 0;
4287 halfword thickness = tex_aux_check_fraction_rule(target, style, size, fractiontype, &fam);
4288 halfword fraction = tex_new_null_box_node(vlist_node, math_fraction_list);
4289 halfword rule = null;
4290 halfword mergedattr = tex_merge_attribute_list(null, noad_extra_attr(target));
4291 (void) kerns;
4292 tex_attach_attribute_list_copy(fraction, target);
4293 tex_aux_wrap_fraction_parts(target, style, size, &numerator, &denominator, 1);
4294 if (fraction_rule_thickness(target) == 0) {
4295 tex_aux_calculate_fraction_shifts_stack(target, style, size, numerator, denominator, &shift_up, &shift_down, &delta);
4296 } else {
4297 tex_aux_calculate_fraction_shifts_normal(target, style, size, numerator, denominator, &shift_up, &shift_down, &delta);
4298 }
4299 tex_aux_apply_fraction_shifts(fraction, numerator, denominator, shift_up, shift_down);
4300 if (fractiontype != atop_fraction_subtype) {
4301 rule = tex_aux_fraction_rule(box_width(fraction), thickness, mergedattr, math_fraction_rule_subtype, size, fam);
4302 tex_aux_compensate_fraction_rule(target, fraction, rule, thickness);
4303 }
4304 box_list(fraction) = tex_aux_assemble_fraction(target, style, size, numerator, denominator, rule, delta, shift_up, shift_down);
4305 if (mergedattr) {
4306 delete_attribute_reference(mergedattr);
4307 delete_attribute_reference(noad_extra_attr(target));
4308 }
4309 return fraction;
4310}
4311
4312static halfword tex_aux_make_stretched_fraction(halfword target, int style, int size, kernset *kerns)
4313{
4314 halfword delimiter = fraction_middle_delimiter(target);
4315 if (tex_aux_has_extensible(delimiter, size)) {
4316 halfword middle = null;
4317 halfword numerator = null;
4318 halfword denominator = null;
4319 scaled shift_up = 0;
4320 scaled shift_down = 0;
4321 scaled delta = 0;
4322 halfword thickness = tex_aux_check_fraction_rule(target, style, size, stretched_fraction_subtype, NULL);
4323 halfword fraction = tex_new_null_box_node(vlist_node, math_fraction_list);
4324 halfword mergedattr = tex_merge_attribute_list(node_attr(delimiter), noad_extra_attr(target));
4325 (void) kerns;
4326 tex_attach_attribute_list_copy(fraction, target);
4327 tex_aux_wrap_fraction_parts(target, style, size, &numerator, &denominator, 1);
4328 tex_aux_calculate_fraction_shifts_normal(target, style, size, numerator, denominator, &shift_up, &shift_down, &delta);
4329 tex_aux_apply_fraction_shifts(fraction, numerator, denominator, shift_up, shift_down);
4330 middle = tex_aux_make_delimiter(target, delimiter, size, box_width(fraction), 1, style, 0, NULL, NULL, 0, 0, NULL, 0, mergedattr, 0, 1);
4331 if (box_width(middle) < box_width(fraction)) {
4332
4333 scaled delta = (box_width(fraction) - box_width(middle)) / 2;
4334 tex_aux_prepend_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "narrow delimiter");
4335 tex_aux_append_hkern_to_box_list(middle, delta, horizontal_math_kern_subtype, "narrow delimiter");
4336 box_width(middle) = box_width(fraction);
4337 } else if (box_width(middle) > box_width(fraction)) {
4338 scaled delta = (box_width(middle) - box_width(fraction)) / 2;
4339 tex_aux_prepend_hkern_to_box_list(numerator, delta, horizontal_math_kern_subtype, "wide delimiter");
4340 tex_aux_append_hkern_to_box_list(numerator, delta, horizontal_math_kern_subtype, "wide delimiter");
4341 tex_aux_prepend_hkern_to_box_list(denominator, delta, horizontal_math_kern_subtype, "wide delimiter");
4342 tex_aux_append_hkern_to_box_list(denominator, delta, horizontal_math_kern_subtype, "wide delimiter");
4343 box_width(fraction) = box_width(middle);
4344 }
4345 tex_aux_compensate_fraction_rule(target, fraction, middle, thickness);
4346 box_list(fraction) = tex_aux_assemble_fraction(target, style, size, numerator, denominator, middle, delta, shift_up, shift_down);
4347 if (mergedattr) {
4348 delete_attribute_reference(mergedattr);
4349 delete_attribute_reference(noad_extra_attr(target));
4350 }
4351 return fraction;
4352 } else {
4353 return tex_aux_make_ruled_fraction(target, style, size, kerns, over_fraction_subtype);
4354 }
4355}
4356
4357
4361
4362static void tex_aux_make_fraction(halfword target, int style, int size, kernset *kerns)
4363{
4364 quarterword fractiontype = node_subtype(target);
4365 halfword fraction = null;
4366 TRYAGAIN:
4367 switch (fractiontype) {
4368 case over_fraction_subtype:
4369 case atop_fraction_subtype:
4370 case above_fraction_subtype:
4371 tex_flush_node_list(fraction_middle_delimiter(target));
4372 fraction_middle_delimiter(target) = null;
4373 fraction = tex_aux_make_ruled_fraction(target, style, size, kerns, fractiontype);
4374 break;
4375 case skewed_fraction_subtype:
4376 fraction_rule_thickness(target) = 0;
4377 fraction = tex_aux_make_skewed_fraction(target, style, size, kerns);
4378 break;
4379 case stretched_fraction_subtype:
4380 fraction = tex_aux_make_stretched_fraction(target, style, size, kerns);
4381 break;
4382 default:
4383 fractiontype = atop_fraction_subtype;
4384 goto TRYAGAIN;
4385 }
4386 tex_aux_wrap_fraction_result(target, style, size, fraction, kerns);
4387 fraction_left_delimiter(target) = null;
4388 fraction_middle_delimiter(target) = null;
4389 fraction_right_delimiter(target) = null;
4390}
4391
4392
4412
4413static void tex_aux_make_scripts (
4414 halfword target,
4415 halfword kernel,
4416 scaled italic,
4417 int style,
4418 scaled supshift,
4419 scaled subshift,
4420 scaled supdrop,
4421 kernset *kerns,
4422 halfword single
4423);
4424
4425static halfword tex_aux_check_nucleus_complexity (
4426 halfword target,
4427 scaled *delta,
4428 halfword style,
4429 halfword size,
4430 kernset *kerns
4431);
4432
4433
4437
4438static void tex_aux_get_shifts(int mode, int style, scaled delta, scaled *top, scaled *bot)
4439{
4440 switch (mode) {
4441 case 0:
4442
4443 *top = 0;
4444 *bot = -delta;
4445 break;
4446 case 1:
4447
4448 *top = tex_round_xn_over_d(delta, tex_get_math_parameter_default(style, math_parameter_nolimit_sup_factor, 0), scaling_factor);
4449 *bot = -tex_round_xn_over_d(delta, tex_get_math_parameter_default(style, math_parameter_nolimit_sub_factor, 0), scaling_factor);
4450 break ;
4451 case 2:
4452
4453 *top = 0;
4454 *bot = 0;
4455 break ;
4456 case 3:
4457
4458 *top = 0;
4459 *bot = -tex_half_scaled(delta);
4460 break;
4461 case 4:
4462
4463 *top = tex_half_scaled(delta);
4464 *bot = -tex_half_scaled(delta);
4465 break;
4466 default :
4467
4468 *top = 0;
4469 *bot = (mode > 15) ? -tex_round_xn_over_d(delta, mode, scaling_factor) : 0;
4470 break;
4471 }
4472}
4473
4474static scaled tex_aux_op_no_limits(halfword target, int style, int size, int italic, kernset *kerns, int forceitalics)
4475{
4476 kernset localkerns ;
4477 halfword kernel;
4478 (void) size;
4479 (void) forceitalics;
4480 if (kerns) {
4481 tex_math_copy_kerns(&localkerns, kerns);
4482 } else {
4483 tex_math_wipe_kerns(&localkerns);
4484 }
4485 kernel = tex_aux_check_nucleus_complexity(target, NULL, style, lmt_math_state.size, &localkerns);
4486 if (noad_has_scripts(target)) {
4487 scaled topshift = 0;
4488 scaled botshift = 0;
4489 if (localkerns.topright || localkerns.bottomright) {
4490 italic = 0;
4491 }
4492 tex_aux_get_shifts(math_nolimits_mode_par, style, italic, &topshift, &botshift);
4493 tex_aux_make_scripts(target, kernel, 0, style, topshift, botshift, 0, &localkerns, 0);
4494 } else {
4495 tex_aux_assign_new_hlist(target, kernel);
4496 }
4497
4498 return 0;
4499}
4500
4501static scaled tex_aux_op_do_limits(halfword target, int style, int size, int italic, kernset *kerns, int forceitalics)
4502{
4503 halfword nucleus = noad_nucleus(target);
4504 halfword superscript = tex_aux_clean_box(noad_supscr(target), tex_math_style_variant(style, math_parameter_superscript_variant), style, math_sup_list, 0, NULL);
4505 halfword kernel = tex_aux_clean_box(nucleus, style, style, math_nucleus_list, forceitalics, NULL);
4506 halfword subscript = tex_aux_clean_box(noad_subscr(target), tex_math_style_variant(style, math_parameter_subscript_variant), style, math_sub_list, 0, NULL);
4507 halfword result = tex_new_null_box_node(vlist_node, math_modifier_list);
4508 (void) kerns;
4509 tex_attach_attribute_list_copy(result, target);
4510 if (nucleus) {
4511
4512 switch (node_type(nucleus)) {
4513 case sub_mlist_node:
4514 case sub_box_node:
4515 {
4516 halfword n = kernel_math_list(nucleus);
4517 if (! n) {
4518
4519 } else if (node_type(n) == hlist_node) {
4520
4521 n = box_list(n);
4522 while (n) {
4523 if (node_type(n) == glyph_node && ! tex_has_glyph_option(n, glyph_option_no_italic_correction)) {
4524 if (tex_aux_math_engine_control(glyph_font(n), math_control_apply_boxed_italic_kern)) {
4525 italic = tex_aux_math_x_size_scaled(glyph_font(n), tex_char_italic_from_font(glyph_font(n), glyph_character(n)), size);
4526 }
4527 }
4528 n = node_next(n);
4529 }
4530 } else {
4531
4532 while (n) {
4533 if (node_type(n) == fence_noad && noad_italic(n) > italic) {
4534
4535 italic = tex_aux_math_given_x_scaled(noad_italic(n));
4536 }
4537 n = node_next(n);
4538 }
4539 }
4540 break;
4541 }
4542 case math_char_node:
4543 {
4544 halfword fnt = tex_fam_fnt(kernel_math_family(nucleus), size);
4545 halfword chr = kernel_math_character(nucleus);
4546 italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
4547 break;
4548 }
4549 }
4550 }
4551
4552 if (noad_supscr(target) || noad_subscr(target)) {
4553 scaled supwidth = box_width(superscript);
4554 scaled boxwidth = box_width(kernel);
4555 scaled subwidth = box_width(subscript);
4556 scaled halfitalic = tex_half_scaled(italic);
4557 scaled topshift = halfitalic;
4558 scaled bottomshift = halfitalic;
4559
4560 if (kerns && ! halfitalic) {
4561 halfword fnt = kerns->font;
4562 halfword chr = kerns->character;
4563 if (fnt && chr) {
4564 scaled topanchor = tex_aux_math_x_size_scaled(fnt, tex_char_top_anchor_from_font(fnt, chr), size);
4565 scaled bottomanchor = tex_aux_math_x_size_scaled(fnt, tex_char_bottom_anchor_from_font(fnt, chr), size);
4566 if (topanchor) {
4567 topshift = topanchor - boxwidth/2;
4568 }
4569 if (bottomanchor) {
4570 bottomshift = boxwidth/2 - bottomanchor;
4571 }
4572 }
4573 }
4574 if (math_limits_mode_par >= 1) {
4575
4581 halfword savedwidth = boxwidth;
4582 halfword overshoot = 0;
4583 superscript = tex_aux_rebox(superscript, supwidth, size);
4584 kernel = tex_aux_rebox(kernel, boxwidth, size);
4585 subscript = tex_aux_rebox(subscript, subwidth, size);
4586 if (supwidth) {
4587 halfword shift = savedwidth/2 + topshift - supwidth/2;
4588 halfword delta = supwidth + shift - savedwidth;
4589 box_shift_amount(superscript) = shift;
4590 if (delta > 0) {
4591 boxwidth = boxwidth + delta;
4592 }
4593 overshoot = supwidth - boxwidth;
4594 if (overshoot > 0) {
4595 box_shift_amount(superscript) += overshoot;
4596 box_shift_amount(kernel) += overshoot;
4597 boxwidth = boxwidth + overshoot;
4598 } else {
4599 overshoot = 0;
4600 }
4601 }
4602 if (subwidth) {
4603 halfword shift = savedwidth/2 - bottomshift - subwidth/2 + overshoot;
4604 box_shift_amount(subscript) = shift;
4605 if (shift < 0) {
4606 box_shift_amount(superscript) -= shift;
4607 box_shift_amount(subscript) -= shift;
4608 box_shift_amount(kernel) -= shift;
4609 boxwidth = boxwidth - shift;
4610 }
4611 overshoot = subwidth - boxwidth;
4612 if (overshoot > 0) {
4613 boxwidth += overshoot;
4614 }
4615 }
4616 box_width(kernel) = boxwidth;
4617 } else {
4618
4619 if (supwidth > boxwidth) {
4620 boxwidth = supwidth;
4621 }
4622 if (subwidth > boxwidth) {
4623 boxwidth = subwidth;
4624 }
4625 superscript = tex_aux_rebox(superscript, boxwidth, size);
4626 kernel = tex_aux_rebox(kernel, boxwidth, size);
4627 subscript = tex_aux_rebox(subscript, boxwidth, size);
4628
4629 box_shift_amount(superscript) = topshift;
4630 box_shift_amount(subscript) = -bottomshift;
4631 }
4632
4633 box_width(result) = boxwidth;
4634 box_height(result) = box_height(kernel);
4635 box_depth(result) = box_depth(kernel);
4636 } else {
4637 box_width(result) = box_width(kernel);
4638 box_height(result) = box_height(kernel);
4639 box_depth(result) = box_depth(kernel);
4640 }
4641
4654 if (noad_supscr(target)) {
4655 scaled bgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_above_bgap);
4656 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_above_vgap);
4657 scaled vkern = tex_get_math_y_parameter_checked(style, math_parameter_limit_above_kern);
4658 scaled vshift = bgap - box_depth(superscript);
4659 if (vshift < vgap) {
4660 vshift = vgap;
4661 }
4662 if (vshift) {
4663 halfword kern = tex_new_kern_node(vshift, vertical_math_kern_subtype);
4664
4665 tex_attach_attribute_list_copy(kern, superscript);
4666 tex_couple_nodes(kern, kernel);
4667 tex_couple_nodes(superscript, kern);
4668 } else {
4669 tex_couple_nodes(kernel, superscript);
4670 }
4671 if (vkern) {
4672 halfword kern = tex_new_kern_node(vkern, vertical_math_kern_subtype);
4673
4674 tex_attach_attribute_list_copy(kern, superscript);
4675 tex_couple_nodes(kern, superscript);
4676 box_list(result) = kern;
4677 } else {
4678 box_list(result) = superscript;
4679 }
4680 box_height(result) += vkern + box_total(superscript) + vshift;
4681 } else {
4682 box_list(superscript) = null;
4683 tex_flush_node(superscript);
4684 box_list(result) = kernel;
4685 }
4686 if (noad_subscr(target)) {
4687 scaled bgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_below_bgap);
4688 scaled vgap = tex_get_math_y_parameter_checked(style, math_parameter_limit_below_vgap);
4689 scaled vkern = tex_get_math_y_parameter_checked(style, math_parameter_limit_below_kern);
4690 scaled vshift = bgap - box_height(subscript);
4691 if (vshift < vgap) {
4692 vshift = vgap;
4693 }
4694 if (vshift) {
4695 halfword kern = tex_new_kern_node(vshift, vertical_math_kern_subtype);
4696
4697 tex_attach_attribute_list_copy(kern, subscript);
4698 tex_couple_nodes(kernel, kern);
4699 tex_couple_nodes(kern, subscript);
4700 } else {
4701 tex_couple_nodes(kernel, subscript);
4702 }
4703 if (vkern) {
4704 halfword kern = tex_new_kern_node(vkern, vertical_math_kern_subtype);
4705
4706 tex_attach_attribute_list_copy(kern, subscript);
4707 tex_couple_nodes(subscript, kern);
4708 }
4709 box_depth(result) += vkern + box_total(subscript) + vshift;
4710 } else {
4711 box_list(subscript) = null;
4712 tex_flush_node(subscript);
4713 }
4714 if (noad_subscr(target)) {
4715 kernel_math_list(noad_subscr(target)) = null;
4716 tex_flush_node(noad_subscr(target));
4717 noad_subscr(target) = null;
4718 }
4719 if (noad_supscr(target)) {
4720 kernel_math_list(noad_supscr(target)) = null;
4721 tex_flush_node(noad_supscr(target));
4722 noad_supscr(target) = null;
4723 }
4724 tex_aux_assign_new_hlist(target, result);
4725
4726 return 0;
4727}
4728
4729
4733
4734static scaled tex_aux_op_wrapup(halfword target, int style, int size, int italic, kernset *kerns, int forceitalics)
4735{
4736 halfword box;
4737 int shiftaxis = 0;
4738 halfword chr = null;
4739 halfword fnt = null;
4740 halfword autoleft = null;
4741 halfword autoright = null;
4742 halfword autosize = has_noad_option_auto(target);
4743 scaled openupheight = has_noad_option_openupheight(target) ? noad_height(target) : 0;
4744 scaled openupdepth = has_noad_option_openupdepth(target) ? noad_depth(target) : 0;
4745 (void) kerns;
4746 if (has_noad_option_adapttoleft(target) && node_prev(target)) {
4747 autoleft = node_prev(target);
4748 if (node_type(autoleft) != simple_noad) {
4749 autoleft = null;
4750 } else {
4751 autoleft = noad_new_hlist(autoleft);
4752 }
4753 }
4754 if (has_noad_option_adapttoright(target) && node_next(target)) {
4755
4756 autoright = noad_nucleus(node_next(target));
4757 }
4758 tex_aux_fetch(noad_nucleus(target), "operator", &fnt, &chr);
4759
4760 if ((style < text_style) || autoleft || autoright || autosize) {
4761
4762 scaled opsize = tex_get_math_parameter(style, math_parameter_operator_size, NULL);
4763 if ((autoleft || autoright || autosize) && (opsize == undefined_math_parameter)) {
4764 opsize = 0;
4765 }
4766 if (opsize != undefined_math_parameter) {
4767
4768 halfword y = tex_new_node(delimiter_node, 0);
4769 tex_attach_attribute_list_copy(y, noad_nucleus(target));
4770 delimiter_small_family(y) = kernel_math_family(noad_nucleus(target));
4771 delimiter_small_character(y) = kernel_math_character(noad_nucleus(target));
4772 opsize = tex_aux_math_y_scaled(opsize, style);
4773 if (autoright) {
4774
4775 scaledwhd siz = tex_natural_msizes(autoright, 0);
4776 scaled total = siz.ht + siz.dp;
4777 if (total > opsize) {
4778 opsize = total;
4779 }
4780 }
4781 if (autoleft && box_total(autoleft) > opsize) {
4782
4783 opsize = box_total(autoleft);
4784 }
4785
4786 opsize += limited_scaled(openupheight);
4787 opsize += openupdepth;
4788 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, 0, 1);
4789 } else {
4790
4795 opsize = tex_char_total_from_font(fnt, chr) + openupheight + openupdepth + 1;
4796
4801 while (tex_char_has_tag_from_font(fnt, chr, list_tag) && tex_char_total_from_font(fnt, chr) < opsize) {
4802 halfword next = tex_char_next_from_font(fnt, chr);
4803 if (chr != next && tex_char_exists(fnt, next)) {
4804 chr = next;
4805 kernel_math_character(noad_nucleus(target)) = chr;
4806 } else {
4807 break;
4808 }
4809 }
4810 if (math_kernel_node_has_option(noad_nucleus(target), math_kernel_no_italic_correction) && ! forceitalics) {
4811 italic = 0;
4812 } else {
4813 italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
4814 }
4815 box = tex_aux_clean_box(noad_nucleus(target), style, style, math_nucleus_list, 0, NULL);
4816 shiftaxis = 1;
4817 }
4818 } else {
4819
4820 italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
4821 box = tex_aux_clean_box(noad_nucleus(target), style, style, math_nucleus_list, 0, NULL);
4822 box_height(box) += openupheight;
4823 box_depth(box) += openupdepth;
4824 shiftaxis = 1;
4825 }
4826 if (shiftaxis) {
4827
4828 box_shift_amount(box) = tex_half_scaled(box_height(box) - box_depth(box)) - tex_aux_math_axis(size);
4829 }
4830 if ((node_type(box) == hlist_node) && (openupheight || openupdepth)) {
4831 box_shift_amount(box) -= openupheight/2;
4832 box_shift_amount(box) += openupdepth/2;
4833 }
4834 if (forceitalics && italic && box_list(box)) {
4835
4848 tex_aux_math_insert_italic_kern(tex_tail_of_node_list(box_list(box)), italic, noad_nucleus(target), "operator");
4849 box_width(box) += italic;
4850 italic = 0;
4851 }
4852 node_type(noad_nucleus(target)) = sub_box_node;
4853 kernel_math_list(noad_nucleus(target)) = box;
4854 return italic;
4855}
4856
4857static scaled tex_aux_make_op(halfword target, int style, int size, int italic, int limits_mode, kernset *kerns)
4858{
4859 int forceitalics = node_subtype(target) == operator_noad_subtype && tex_math_has_class_option(operator_noad_subtype, operator_italic_correction_class_option);
4860 if (limits_mode == limits_horizontal_mode) {
4861
4862 } else if (! has_noad_option_limits(target) && ! has_noad_option_nolimits(target) && (style == display_style || style == cramped_display_style)) {
4863 limits_mode = limits_vertical_mode;
4864 noad_options(target) |= noad_option_limits;
4865 } else if (has_noad_option_nolimits(target)) {
4866 limits_mode = limits_horizontal_mode;
4867 } else if (has_noad_option_limits(target)) {
4868 limits_mode = limits_vertical_mode;
4869 }
4870 if (node_type(noad_nucleus(target)) == math_char_node) {
4871 italic = tex_aux_op_wrapup(target, style, size, italic, kerns, forceitalics);
4872 }
4873 switch (limits_mode) {
4874 case limits_horizontal_mode:
4875
4881 return tex_aux_op_no_limits(target, style, size, italic, kerns, forceitalics);
4882 case limits_vertical_mode:
4883
4889 return tex_aux_op_do_limits(target, style, size, italic, kerns, forceitalics);
4890 default:
4891
4895 return italic;
4896 }
4897}
4898
4899
4912
4913
4914
4915
4916
4934
4935static halfword tex_aux_check_ord(halfword current, halfword size, halfword next)
4936{
4937 if (! noad_has_following_scripts(current)) {
4938 halfword nucleus = noad_nucleus(current);
4939 switch (node_type(nucleus)) {
4940 case sub_mlist_node:
4941 {
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957 break;
4958 }
4959 case math_char_node:
4960 {
4961 halfword curchr = null;
4962 halfword curfnt = null;
4963 if (! next) {
4964 next = node_next(current);
4965 }
4966 tex_aux_fetch(nucleus, "ordinal", &curfnt, &curchr);
4967 if (curfnt && curchr) {
4968 halfword kern = 0;
4969 halfword italic = 0;
4970
4975 if (next && node_type(next) == simple_noad) {
4976 halfword nxtnucleus = noad_nucleus(next);
4977 halfword nxtfnt = null;
4978 halfword nxtchr = null;
4979 if (nxtnucleus && node_type(nxtnucleus) == math_char_node && kernel_math_family(nucleus) == kernel_math_family(nxtnucleus)) {
4980 tex_aux_fetch(nxtnucleus, "ordinal", &nxtfnt, &nxtchr);
4981 if (nxtfnt && nxtchr) {
4982 halfword mainclass = node_subtype(current);
4983
4984 if (tex_aux_math_engine_control(curfnt, math_control_apply_ordinary_kern_pair)) {
4985 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)) {
4986
4987 } else if (tex_math_has_class_option(mainclass, check_italic_correction_class_option)) {
4988
4989 } else {
4990 kern = tex_aux_math_x_size_scaled(curfnt, tex_get_kern(curfnt, curchr, nxtchr), size);
4991 }
4992 }
4993 if (tex_aux_math_engine_control(curfnt, math_control_apply_ordinary_italic_kern)) {
4994 if (math_kernel_node_has_option(nucleus, math_kernel_no_italic_correction)) {
4995
4996 } else if (tex_math_has_class_option(mainclass, check_kern_pair_class_option)) {
4997
4998 } else {
4999 italic = tex_aux_math_x_size_scaled(curfnt, tex_char_italic_from_font(curfnt, curchr), size);
5000 }
5001 }
5002 }
5003 }
5004 }
5005 if (kern) {
5006 current = tex_aux_math_insert_font_kern(current, kern, current, "ord");
5007 }
5008 if (italic) {
5009
5010 current = tex_aux_math_insert_italic_kern(current, italic, current, "ord");
5011 }
5012 }
5013 }
5014 break;
5015 }
5016 }
5017 return current;
5018}
5019
5020static halfword tex_aux_prepend_hkern_to_new_hlist(halfword box, scaled delta, halfword subtype, const char *trace)
5021{
5022 halfword list = noad_new_hlist(box);
5023 halfword kern = tex_new_kern_node(delta, (quarterword) subtype);
5024 tex_attach_attribute_list_copy(kern, box);
5025 if (list) {
5026 tex_couple_nodes(kern, list);
5027 }
5028 list = kern;
5029 noad_new_hlist(box) = list;
5030 tex_aux_trace_kerns(kern, "adding kern", trace);
5031 return list;
5032}
5033
5034static void tex_aux_append_hkern_to_box_list(halfword box, scaled delta, halfword subtype, const char *trace)
5035{
5036 halfword list = box_list(box);
5037 halfword kern = tex_new_kern_node(delta, (quarterword) subtype);
5038 tex_attach_attribute_list_copy(kern, box);
5039 if (list) {
5040 tex_couple_nodes(tex_tail_of_node_list(list), kern);
5041 } else {
5042 list = kern;
5043 }
5044 box_list(box) = list;
5045 box_width(box) += delta;
5046 tex_aux_trace_kerns(kern, "adding kern", trace);
5047}
5048
5049static void tex_aux_prepend_hkern_to_box_list(halfword box, scaled delta, halfword subtype, const char *trace)
5050{
5051 halfword list = box_list(box);
5052 halfword kern = tex_new_kern_node(delta, (quarterword) subtype);
5053 tex_attach_attribute_list_copy(kern, box);
5054 if (list) {
5055 tex_couple_nodes(kern, list);
5056 }
5057 list = kern;
5058 box_list(box) = list;
5059 box_width(box) += delta;
5060 tex_aux_trace_kerns(kern, "adding kern", trace);
5061}
5062
5063
5087
5088static halfword tex_aux_analyze_script(halfword init, scriptdata *data)
5089{
5090 if (init) {
5091 switch (node_type(init)) {
5092 case math_char_node :
5093 if (tex_aux_math_engine_control(null, math_control_analyze_script_nucleus_char)) {
5094 if (tex_aux_fetch(init, "script char", &(data->fnt), &(data->chr))) {
5095 return init;
5096 } else {
5097 goto NOTHING;
5098 }
5099 } else {
5100 break;
5101 }
5102 case sub_mlist_node:
5103 if (tex_aux_math_engine_control(null, math_control_analyze_script_nucleus_list)) {
5104 init = kernel_math_list(init);
5105 while (init) {
5106 switch (node_type(init)) {
5107 case kern_node:
5108 case glue_node:
5109 init = node_next(init);
5110 break;
5111 case simple_noad:
5112 {
5113 init = noad_nucleus(init);
5114 if (node_type(init) != math_char_node) {
5115 return null;
5116 } else if (tex_aux_fetch(init, "script list", &(data->fnt), &(data->chr))) {
5117 return init;
5118 } else {
5119 goto NOTHING;
5120 }
5121 }
5122 case accent_noad:
5123 data->whatever = 1;
5124 goto NOTHING;
5125 default:
5126 goto NOTHING;
5127 }
5128 }
5129 }
5130 break;
5131 case sub_box_node:
5132 if (tex_aux_math_engine_control(null, math_control_analyze_script_nucleus_box)) {
5133 init = kernel_math_list(init);
5134 if (init && node_type(init) == hlist_node) {
5135 init = box_list(init);
5136 }
5137 while (init) {
5138 switch (node_type(init)) {
5139 case kern_node:
5140 case glue_node:
5141 init = node_next(init);
5142 break;
5143 case glyph_node:
5144 if (tex_aux_fetch(init, "script box", &(data->fnt), &(data->chr))) {
5145 return init;
5146 } else {
5147 goto NOTHING;
5148 }
5149 default:
5150 goto NOTHING;
5151 }
5152 }
5153 }
5154 break;
5155 }
5156 }
5157 NOTHING:
5158 data->fnt = null;
5159 data->chr = null;
5160 return null;
5161}
5162
5163
5170
5171static void tex_aux_get_math_sup_shifts(halfword target, halfword sup, halfword style, scaled *shift_up)
5172{
5173 if (has_noad_option_fixed_super_or_sub_script(target) || has_noad_option_fixed_super_and_sub_script(target)) {
5174 *shift_up = tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_up);
5175 } else {
5176 scaled clr = tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_up);
5177 scaled bot = tex_get_math_y_parameter_checked(style, math_parameter_superscript_bottom_min);
5178 if (*shift_up < clr) {
5179 *shift_up = clr;
5180 }
5181 clr = box_depth(sup) + bot;
5182 if (*shift_up < clr) {
5183 *shift_up = clr;
5184 }
5185 }
5186}
5187
5188static void tex_aux_get_math_sub_shifts(halfword target, halfword sub, halfword style, scaled *shift_down)
5189{
5190 if (has_noad_option_fixed_super_or_sub_script(target)) {
5191 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_down);
5192 } else if (has_noad_option_fixed_super_and_sub_script(target)) {
5193 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_shift_down);
5194 } else {
5195 scaled clr = tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_down);
5196 scaled top = tex_get_math_y_parameter_checked(style, math_parameter_subscript_top_max);
5197 if (*shift_down < clr) {
5198 *shift_down = clr;
5199 }
5200 clr = box_height(sub) - top;
5201 if (*shift_down < clr) {
5202 *shift_down = clr;
5203 }
5204 }
5205}
5206
5207static void tex_aux_get_math_sup_sub_shifts(halfword target, halfword sup, halfword sub, halfword style, scaled *shift_up, scaled *shift_down)
5208{
5209 if (has_noad_option_fixed_super_or_sub_script(target)) {
5210 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_down);
5211 } else if (has_noad_option_fixed_super_and_sub_script(target)) {
5212 *shift_down = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_shift_down);
5213 } else {
5214 scaled clr = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_shift_down);
5215 scaled gap = tex_get_math_y_parameter_checked(style, math_parameter_subscript_superscript_vgap);
5216 scaled bot = tex_get_math_y_parameter_checked(style, math_parameter_superscript_subscript_bottom_max);
5217 if (*shift_down < clr) {
5218 *shift_down = clr;
5219 }
5220 clr = gap - ((*shift_up - box_depth(sup)) - (box_height(sub) - *shift_down));
5221 if (clr > 0) {
5222 *shift_down += clr;
5223 clr = bot - (*shift_up - box_depth(sup));
5224 if (clr > 0) {
5225 *shift_up += clr;
5226 *shift_down -= clr;
5227 }
5228 }
5229 }
5230}
5231
5232static halfword tex_aux_combine_script(halfword target, halfword width, halfword pre, halfword post, halfword *k1, halfword *k2, quarterword subtype)
5233{
5234 *k1 = tex_new_kern_node(-(width + box_width(pre)), horizontal_math_kern_subtype);
5235 *k2 = tex_new_kern_node(width, horizontal_math_kern_subtype);
5236 tex_couple_nodes(*k1, pre);
5237 tex_couple_nodes(pre, *k2);
5238 if (post) {
5239 tex_couple_nodes(*k2, post);
5240 }
5241 post = tex_hpack(*k1, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
5242 tex_attach_attribute_list_copy(*k1, target);
5243 tex_attach_attribute_list_copy(*k2, target);
5244 tex_attach_attribute_list_copy(post, target);
5245 node_subtype(post) = subtype;
5246 return post;
5247}
5248
5249
5275
5276
5289
5290static scaled tex_aux_math_kern_at(halfword fnt, int chr, int side, int value, int simple)
5291{
5292
5293 charinfo *ci = tex_get_charinfo(fnt, chr);
5294 if (ci->math) {
5295 scaled *kerns_heights;
5296 int n_of_kerns = tex_get_charinfo_math_kerns(ci, side);
5297 if (n_of_kerns == 0 || simple) {
5298
5299 switch (side) {
5300 case top_left_kern:
5301 return tex_char_top_left_kern_from_font(fnt, chr);
5302 case bottom_left_kern:
5303 return tex_char_bottom_left_kern_from_font(fnt, chr);
5304 case top_right_kern:
5305 return tex_char_top_right_kern_from_font(fnt, chr);
5306 case bottom_right_kern:
5307 return tex_char_bottom_right_kern_from_font(fnt, chr);
5308 default:
5309 return 0;
5310 }
5311 } else {
5312 switch (side) {
5313 case top_left_kern:
5314 kerns_heights = ci->math->top_left_math_kern_array;
5315 break;
5316 case bottom_left_kern:
5317 kerns_heights = ci->math->bottom_left_math_kern_array;
5318 break;
5319 case top_right_kern:
5320 kerns_heights = ci->math->top_right_math_kern_array;
5321 break;
5322 case bottom_right_kern:
5323 kerns_heights = ci->math->bottom_right_math_kern_array;
5324 break;
5325 default:
5326
5327 kerns_heights = NULL;
5328 return tex_confusion("math kern at");
5329 }
5330 }
5331 if (value < kerns_heights[0]) {
5332 return kerns_heights[1];
5333 } else {
5334 scaled kern = 0;
5335 for (int i = 0; i < n_of_kerns; i++) {
5336 scaled height = kerns_heights[i * 2];
5337 kern = kerns_heights[(i * 2) + 1];
5338 if (height > value) {
5339 return kern;
5340 }
5341 }
5342 return kern;
5343 }
5344 } else {
5345 return 0;
5346 }
5347}
5348
5349static scaled tex_aux_find_math_kern_simple(halfword f, int c, int cmd, int *found)
5350{
5351 if (tex_aux_math_engine_control(f, math_control_staircase_kern) && tex_char_exists(f, c)) {
5352
5353 scaled krn = tex_aux_math_kern_at(f, c, cmd == superscript_cmd ? top_right_kern : bottom_right_kern, 0, 1);
5354 *found = 1;
5355 return krn ? tex_aux_math_x_size_scaled(f, krn, lmt_math_state.size) : 0;
5356 } else {
5357 return MATH_KERN_NOT_FOUND;
5358 }
5359}
5360
5361static inline scaled tex_aux_max_left_kern_value(scaled *kerns, int n)
5362{
5363 if (kerns && n > 0) {
5364 scaled kern = 0;
5365 for (int i = 0; i < n; i++) {
5366 scaled value = kerns[(i * 2) + 1];
5367 if (value < kern) {
5368 kern = value;
5369 }
5370 }
5371 return -kern;
5372 } else {
5373 return 0;
5374 }
5375}
5376
5377static scaled tex_aux_math_left_kern(halfword fnt, int chr)
5378{
5379 charinfo *ci = tex_get_charinfo(fnt, chr);
5380 if (ci->math) {
5381 scaled top = 0;
5382 scaled bot = 0;
5383 {
5384 scaled *a = ci->math->top_left_math_kern_array;
5385 halfword n = a ? tex_get_charinfo_math_kerns(ci, top_left_kern) : 0;
5386 if (n) {
5387 top = tex_aux_max_left_kern_value(a, n);
5388 } else {
5389 top = tex_char_top_left_kern_from_font(fnt, chr);
5390 }
5391 }
5392 {
5393 scaled *a = ci->math->bottom_left_math_kern_array;
5394 halfword n = a ? tex_get_charinfo_math_kerns(ci, bottom_left_kern) : 0;
5395 if (n) {
5396 bot = tex_aux_max_left_kern_value(a, n);
5397 } else {
5398 bot = tex_char_bottom_left_kern_from_font(fnt, chr);
5399 }
5400 }
5401
5402 return top < bot ? top : bot;
5403 } else {
5404 return 0;
5405 }
5406}
5407
5408
5456
5457static scaled tex_aux_find_math_kern(halfword l_f, int l_c, halfword r_f, int r_c, int cmd, scaled shift, int *found)
5458{
5459 if (tex_aux_math_engine_control(l_f, math_control_staircase_kern) &&
5460 tex_aux_math_engine_control(r_f, math_control_staircase_kern) &&
5461
5462 tex_char_exists(l_f, l_c) && tex_char_exists(r_f, r_c)) {
5463 scaled krn_l = 0;
5464 scaled krn_r = 0;
5465 scaled krn = 0;
5466 switch (cmd) {
5467 case superscript_cmd:
5468
5469 {
5470 scaled corr_height_top = tex_char_height_from_font(l_f, l_c);
5471 scaled corr_height_bot = -tex_char_depth_from_font(r_f, r_c) + shift;
5472 krn_l = tex_aux_math_kern_at(l_f, l_c, top_right_kern, corr_height_top, 0);
5473 krn_r = tex_aux_math_kern_at(r_f, r_c, bottom_left_kern, corr_height_top, 0);
5474 krn = krn_l + krn_r;
5475 krn_l = tex_aux_math_kern_at(l_f, l_c, top_right_kern, corr_height_bot, 0);
5476 krn_r = tex_aux_math_kern_at(r_f, r_c, bottom_left_kern, corr_height_bot, 0);
5477 }
5478 break;
5479 case subscript_cmd:
5480
5481 {
5482 scaled corr_height_top = tex_char_height_from_font(r_f, r_c) - shift;
5483 scaled corr_height_bot = -tex_char_depth_from_font(l_f, l_c);
5484 krn_l = tex_aux_math_kern_at(l_f, l_c, bottom_right_kern, corr_height_top, 0);
5485 krn_r = tex_aux_math_kern_at(r_f, r_c, top_left_kern, corr_height_top, 0);
5486 krn = krn_l + krn_r;
5487 krn_l = tex_aux_math_kern_at(l_f, l_c, bottom_right_kern, corr_height_bot, 0);
5488 krn_r = tex_aux_math_kern_at(r_f, r_c, top_left_kern, corr_height_bot, 0);
5489 }
5490 break;
5491 default:
5492 return tex_confusion("find math kern");
5493 }
5494 *found = 1;
5495 if ((krn_l + krn_r) < krn) {
5496 krn = krn_l + krn_r;
5497 }
5498 return krn ? tex_aux_math_x_size_scaled(l_f, krn, lmt_math_state.size) : 0;
5499 } else {
5500 return MATH_KERN_NOT_FOUND;
5501 }
5502}
5503
5504
5510
5511static int tex_aux_discard_shape_kerns(halfword target)
5512{
5513 if (has_noad_option_continuation(target)) {
5514
5515 if (has_noad_option_discard_shape_kern(target)) {
5516 return 1;
5517 }
5518 } else if (node_next(target) && has_noad_option_continuation(node_next(target))) {
5519
5520 if (has_noad_option_discard_shape_kern(node_next(target))) {
5521 return 1;
5522 }
5523 } if (node_prev(target)) {
5524
5525 if (has_noad_option_discard_shape_kern(node_prev(target))) {
5526 return 1;
5527 }
5528 }
5529 return 0;
5530}
5531
5532static int tex_aux_get_sup_kern(halfword kernel, scriptdata *sup, scaled shift_up, scaled supshift, scaled *supkern, kernset *kerns, int discard)
5533{
5534 int found = 0;
5535
5536 if (discard) {
5537
5538 *supkern = 0;
5539 return found;
5540 }
5541
5542 *supkern = MATH_KERN_NOT_FOUND;
5543 if (sup->whatever) {
5544 *supkern = tex_aux_find_math_kern_simple(glyph_font(kernel), glyph_character(kernel), superscript_cmd, &found);
5545 if (found) {
5546 return found;
5547 }
5548 }
5549 if (sup->node) {
5550 *supkern = tex_aux_find_math_kern(glyph_font(kernel), glyph_character(kernel), sup->fnt, sup->chr, superscript_cmd, shift_up, &found);
5551 if (*supkern == MATH_KERN_NOT_FOUND) {
5552 *supkern = supshift;
5553 } else {
5554 if (*supkern) {
5555 tex_aux_trace_kerns(*supkern, "superscript kern", "regular");
5556 }
5557 *supkern += supshift;
5558 }
5559 return found;
5560 }
5561 if (kerns && kerns->topright) {
5562 *supkern = kerns->topright;
5563 if (*supkern == MATH_KERN_NOT_FOUND) {
5564 *supkern = supshift;
5565 } else {
5566 if (*supkern) {
5567 tex_aux_trace_kerns(*supkern, "superscript kern", "kernset top right");
5568 }
5569 *supkern += supshift;
5570 }
5571 return found;
5572 }
5573 *supkern = supshift;
5574 return found;
5575}
5576
5577static int tex_aux_get_sub_kern(halfword kernel, scriptdata *sub, scaled shift_down, scaled subshift, scaled *subkern, kernset *kerns, int discard)
5578{
5579 int found = 0;
5580
5581 if (discard) {
5582
5583 *subkern = 0;
5584 return found;
5585 }
5586
5587 *subkern = MATH_KERN_NOT_FOUND;
5588 if (sub->whatever) {
5589 *subkern = tex_aux_find_math_kern_simple(glyph_font(kernel), glyph_character(kernel), subscript_cmd, &found);
5590 if (found) {
5591 return found;
5592 }
5593 }
5594 if (sub->node) {
5595 *subkern = tex_aux_find_math_kern(glyph_font(kernel), glyph_character(kernel), sub->fnt, sub->chr, subscript_cmd, shift_down, &found);
5596 if (*subkern == MATH_KERN_NOT_FOUND) {
5597 *subkern = subshift;
5598 } else {
5599 if (*subkern) {
5600 tex_aux_trace_kerns(*subkern, "subscript kern", "regular");
5601 }
5602 *subkern += subshift;
5603 }
5604 return found;
5605 }
5606 if (kerns && kerns->bottomright) {
5607 *subkern = kerns->bottomright;
5608 if (*subkern == MATH_KERN_NOT_FOUND) {
5609 *subkern = subshift;
5610 } else {
5611 if (*subkern) {
5612 tex_aux_trace_kerns(*subkern, "subscript kern", "kernset bottom right");
5613 }
5614 *subkern += subshift;
5615 }
5616 return found;
5617 }
5618 *subkern = subshift;
5619 return found;
5620}
5621
5622
5636
5637static inline scaled tex_aux_insert_italic_now(halfword target, halfword kernel, scaled italic)
5638{
5639 switch (node_type(noad_nucleus(target))) {
5640 case math_char_node:
5641 case math_text_char_node:
5642 {
5643 halfword fam = kernel_math_family(noad_nucleus(target));
5644 if (fam != unused_math_family) {
5645 halfword fnt = tex_fam_fnt(fam, lmt_math_state.size);
5646 if (! tex_aux_math_engine_control(fnt, math_control_apply_script_italic_kern)) {
5647
5648 italic = 0;
5649 } else if (noad_subscr(target)) {
5650
5651 } else {
5652
5653 tex_aux_math_insert_italic_kern(kernel, italic, noad_nucleus(target), "scripts");
5654 italic = 0;
5655 }
5656 } else {
5657
5658 italic = 0;
5659 }
5660 }
5661 break;
5662 }
5663 return italic;
5664}
5665
5666static inline int tex_aux_raise_prime_composed(halfword target)
5667{
5668 int mainclass = -1 ;
5669
5670 switch (node_type(target)) {
5671 case simple_noad:
5672 mainclass = node_subtype(target);
5673 break;
5674 case radical_noad:
5675 mainclass = radical_noad_subtype;
5676 break;
5677 case fraction_noad:
5678 mainclass = fraction_noad_subtype;
5679 break;
5680 case accent_noad:
5681 mainclass = accent_noad_subtype;
5682 break;
5683 case fence_noad:
5684
5685 mainclass = fenced_noad_subtype;
5686 break;
5687 }
5688 return mainclass >= 0 ? tex_math_has_class_option(mainclass, raise_prime_option) : 0;
5689}
5690
5691static halfword tex_aux_shift_to_kern(halfword target, halfword box, scaled shift)
5692{
5693 halfword result;
5694 if (box_source_anchor(box)) {
5695 halfword kern = tex_new_kern_node(shift, vertical_math_kern_subtype);
5696 tex_attach_attribute_list_copy(kern, target);
5697 tex_couple_nodes(kern, box);
5698 result = tex_vpack(kern, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
5699 tex_attach_attribute_list_copy(result, target);
5700 node_subtype(result) = math_scripts_list;
5701 box_shift_amount(result) = shift;
5702 } else {
5703 box_shift_amount(box) = shift;
5704 result = box;
5705 }
5706 return result;
5707}
5708
5709static int tex_aux_singled(halfword target, scaledwhd kernelsize, int style, halfword single)
5710{
5711 (void) target;
5712 if (single) {
5713 scaled ht = tex_get_math_y_parameter_default(style, math_parameter_superscript_snap, 0);
5714 scaled dp = tex_get_math_y_parameter_default(style, math_parameter_subscript_snap, 0);
5715 return ht > 0 && dp > 0 && kernelsize.ht <= ht && kernelsize.dp <= dp;
5716 } else {
5717 return 0;
5718 }
5719}
5720
5721static int tex_aux_math_empty_script(halfword n)
5722{
5723 return ! n || (node_type(n) == sub_mlist_node && ! kernel_math_list(n));
5724}
5725
5726
5736
5737static void tex_aux_make_scripts(halfword target, halfword kernel, scaled italic, int style, scaled supshift, scaled subshift, scaled supdrop, kernset *kerns, halfword single)
5738{
5739 halfword result = null;
5740 halfword preresult = null;
5741 scaled prekern = 0;
5742 scaled primekern = 0;
5743 scaled shift_up = 0;
5744 scaled shift_down = 0;
5745 scaled prime_up = 0;
5746 scriptdata postsubdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .whatever = 0 };
5747 scriptdata postsupdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .whatever = 0 };
5748 scriptdata presubdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .whatever = 0 };
5749 scriptdata presupdata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .whatever = 0 };
5750 scriptdata primedata = { .node = null, .fnt = null_font, .chr = 0, .box = null, .kern = null, .slack = 0, .whatever = 0 };
5751 halfword maxleftkern = 0;
5752
5753 scaled leftslack = 0;
5754 scaled rightslack = 0;
5755 scaledwhd kernelsize = { .wd = 0, .ht = 0, .dp = 0, .ic = 0 };
5756
5757 scaled topovershoot = 0;
5758 scaled botovershoot = 0;
5759 int splitscripts = 0;
5760 halfword primetarget = target;
5761 scaled prime_drop = noad_prime(target) ? tex_get_math_y_parameter_default(style, math_parameter_prime_shift_drop, 0) : 0;
5762 quarterword primestate = prime_unknown_location;
5763 int discard = tex_aux_discard_shape_kerns(target);
5764
5778 if (has_noad_option_ignore_empty_super_script(target) && tex_aux_math_empty_script(noad_supscr(target))) {
5779 tex_flush_node(noad_supscr(target));
5780 noad_supscr(target) = null;
5781 }
5782 if (has_noad_option_ignore_empty_sub_script(target) && tex_aux_math_empty_script(noad_subscr(target))) {
5783 tex_flush_node(noad_subscr(target));
5784 noad_subscr(target) = null;
5785 }
5786 if (has_noad_option_ignore_empty_prime_script(target) && tex_aux_math_empty_script(noad_prime(target))) {
5787 tex_flush_node(noad_prime(target));
5788 noad_prime(target) = null;
5789 }
5790
5794 if (node_type(target) == accent_noad) {
5795 scaled top = tex_get_math_parameter_default(style, math_parameter_accent_top_overshoot, 0);
5796 scaled bot = tex_get_math_parameter_default(style, math_parameter_accent_bottom_overshoot, 0);
5797 topovershoot = scaledround(accent_top_overshoot(target) * top / 100.0);
5798 botovershoot = scaledround(accent_top_overshoot(target) * bot / 100.0);
5799 }
5800
5806 if (italic) {
5807 italic = tex_aux_insert_italic_now(target, kernel, italic);
5808 }
5809
5813 if (node_type(target) == simple_noad) {
5814 switch (node_subtype(target)) {
5815 case fenced_noad_subtype:
5816 splitscripts = tex_math_has_class_option(fenced_noad_subtype, unpack_class_option);
5817 break;
5818 case ghost_noad_subtype:
5819 splitscripts = has_noad_option_unpacklist(target);
5820 break;
5821 }
5822 }
5823
5828 tex_aux_assign_new_hlist(target, kernel);
5829 kernelsize = tex_natural_msizes(kernel, 0);
5830 if (kerns && kerns->dimensions) {
5831 if (tex_aux_math_engine_control(kerns->font, math_control_ignore_kern_dimensions)) {
5832
5833 } else {
5834 if (kerns->height) {
5835 kernelsize.ht = kerns->height;
5836 }
5837 if (kerns->depth) {
5838 kernelsize.dp = kerns->depth;
5839 }
5840 }
5841 }
5842 switch (node_type(kernel)) {
5843 case glyph_node:
5844 postsubdata.node = tex_aux_analyze_script(noad_subscr(target), &postsubdata);
5845 postsupdata.node = tex_aux_analyze_script(noad_supscr(target), &postsupdata);
5846 primedata.node = tex_aux_analyze_script(noad_prime(target), &primedata);
5847 maxleftkern = tex_aux_math_left_kern(glyph_font(kernel), glyph_character(kernel));
5848
5849 maxleftkern = tex_aux_math_x_scaled(maxleftkern, style);
5850 prime_up = 0;
5851 shift_up = 0;
5852 shift_down = 0;
5853 break;
5854 default:
5855 if (has_noad_option_single(target) || tex_aux_singled(target, kernelsize, style, single)) {
5856 prime_up = 0;
5857 shift_up = 0;
5858 shift_down = 0;
5859 } else {
5860
5861 kernelsize.ht -= supdrop;
5862
5863 shift_up = kernelsize.ht - tex_get_math_y_parameter_checked(style, math_parameter_superscript_shift_drop);
5864 shift_down = kernelsize.dp + tex_get_math_y_parameter_checked(style, math_parameter_subscript_shift_drop);
5865 if (noad_prime(target)) {
5866 prime_up = kernelsize.ht;
5867 if (kernelsize.ht <= 0) {
5868
5874
5875 halfword prev = node_prev(target);
5876 while (prev) {
5877 if (tex_math_scripts_allowed(prev)) {
5878 scaledwhd whd = tex_natural_msizes(noad_new_hlist(prev), 1);
5879 if (noad_primeshift(prev)) {
5880 prime_up = noad_primeshift(prev) + prime_drop ;
5881 } else if (whd.ht > prime_up) {
5882 prime_up = whd.ht;
5883 }
5884 primetarget = prev;
5885 if (! has_noad_option_continuation(prev)) {
5886 break;
5887 }
5888 }
5889 prev = node_prev(prev);
5890 }
5891
5892 }
5893 } else {
5894 prime_up = 0;
5895 }
5896 }
5897 }
5898
5902 if (noad_prime(target)) {
5903
5904 scaled raise = tex_get_math_y_parameter_default(style, tex_aux_raise_prime_composed(primetarget) ? math_parameter_prime_raise_composed : math_parameter_prime_raise, 0);
5905 scaled distance = tex_get_math_x_parameter_default(style, math_parameter_prime_space_after, 0);
5906 if (prime_up) {
5907 prime_up -= prime_drop;
5908 } else {
5909 prime_up = tex_get_math_y_parameter_default(style, math_parameter_prime_shift_up, 0);
5910 }
5911 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_prime_list, 0, NULL);
5912 box_shift_amount(primedata.box) -= prime_up;
5913 box_shift_amount(primedata.box) -= scaledround(box_height(primedata.box) * raise / 100.0);
5914 kernel_math_list(noad_prime(target)) = null;
5915 tex_flush_node(noad_prime(target));
5916 noad_prime(target) = null;
5917
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932 if (noad_supscr(target)) {
5933 primestate = prime_at_end_location;
5934 } else if (noad_subscr(target)) {
5935 primestate = prime_above_sub_location;
5936 } else {
5937 primestate = prime_at_begin_location;
5938 }
5939 if (distance) {
5940 tex_aux_append_hkern_to_box_list(primedata.box, distance, horizontal_math_kern_subtype, "prime distance");
5941 }
5942 primedata.slack = distance;
5943 switch (primestate) {
5944
5945 case prime_at_begin_location:
5946 {
5947
5948 tex_aux_get_sup_kern(kernel, &primedata, shift_up, supshift, &primekern, kerns, discard);
5949 if (italic) {
5950
5951 primekern += italic;
5952 italic = 0;
5953 }
5954 }
5955 break;
5956
5957 case prime_above_sub_location:
5958 {
5959
5960 tex_aux_get_sup_kern(kernel, &primedata, shift_up, supshift, &primekern, kerns, discard);
5961 if (italic) {
5962
5963 primekern += italic;
5964 italic = 0;
5965 }
5966 if (primekern) {
5967 tex_aux_prepend_hkern_to_box_list(primedata.box, primekern, math_shape_kern_subtype, "prime kern");
5968
5969 primekern = 0;
5970 }
5971 }
5972 break;
5973
5974 case prime_at_end_location:
5975 {
5976 primekern = 0;
5977 }
5978 break;
5979 }
5980 }
5981
5987 if (noad_supscr(target)) {
5988 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_superscript_shift);
5989 postsupdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_superscript_space);
5990 postsupdata.slack += tex_round_xn_over_d(tex_get_math_x_parameter_default(style, math_parameter_space_after_script, 0), script_space_after_factor_par, scaling_factor);
5991 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);
5992 if (extra) {
5993 box_height(postsupdata.box) += extra;
5994 box_shift_amount(postsupdata.box) -= extra;
5995 }
5996 if (postsupdata.slack) {
5997 tex_aux_append_hkern_to_box_list(postsupdata.box, postsupdata.slack, right_math_slack_kern_subtype, "post sup slack");
5998 }
5999 kernel_math_list(noad_supscr(target)) = null;
6000 tex_flush_node(noad_supscr(target));
6001 noad_supscr(target) = null;
6002 }
6003 if (noad_subscr(target)) {
6004 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_subscript_shift);
6005 postsubdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_subscript_space);
6006 postsubdata.slack += tex_round_xn_over_d(tex_get_math_x_parameter_default(style, math_parameter_space_after_script, 0), script_space_after_factor_par, scaling_factor);
6007 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);
6008 if (extra) {
6009 box_depth(postsubdata.box) += extra;
6010 box_shift_amount(postsubdata.box) += extra;
6011 }
6012 if (postsubdata.slack) {
6013 tex_aux_append_hkern_to_box_list(postsubdata.box, postsubdata.slack, right_math_slack_kern_subtype, "post sub slack");
6014 }
6015 kernel_math_list(noad_subscr(target)) = null;
6016 tex_flush_node(noad_subscr(target));
6017 noad_subscr(target) = null;
6018 }
6019 if (noad_supprescr(target)) {
6020 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_superprescript_shift);
6021 presupdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_superprescript_space);
6022 presupdata.slack += tex_round_xn_over_d(tex_get_math_x_parameter_default(style, math_parameter_space_before_script, 0), script_space_before_factor_par, scaling_factor);
6023 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);
6024 if (maxleftkern) {
6025 tex_aux_append_hkern_to_box_list(presupdata.box, maxleftkern, math_shape_kern_subtype, "max left shape");
6026 }
6027 if (extra) {
6028 box_height(presupdata.box) += extra;
6029 box_shift_amount(presupdata.box) -= extra;
6030 }
6031 if (presupdata.slack) {
6032 tex_aux_prepend_hkern_to_box_list(presupdata.box, presupdata.slack, left_math_slack_kern_subtype, "pre sup slack");
6033 }
6034 kernel_math_list(noad_supprescr(target)) = null;
6035 tex_flush_node(noad_supprescr(target));
6036 noad_supprescr(target) = null;
6037 }
6038 if (noad_subprescr(target)) {
6039 halfword extra = tex_get_math_y_parameter_checked(style, math_parameter_extra_subprescript_shift);
6040 presubdata.slack = tex_get_math_x_parameter_checked(style, math_parameter_extra_subprescript_space);
6041 presubdata.slack += tex_round_xn_over_d(tex_get_math_x_parameter_default(style, math_parameter_space_before_script, 0), script_space_before_factor_par, scaling_factor);
6042 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);
6043 if (maxleftkern) {
6044 tex_aux_append_hkern_to_box_list(presubdata.box, maxleftkern, math_shape_kern_subtype, "max left shape");
6045 }
6046 if (extra) {
6047 box_depth(presubdata.box) += extra;
6048 box_shift_amount(presubdata.box) += extra;
6049 }
6050 if (presubdata.slack) {
6051 tex_aux_prepend_hkern_to_box_list(presubdata.box, presubdata.slack, left_math_slack_kern_subtype, "pre sub slack");
6052 }
6053 kernel_math_list(noad_subprescr(target)) = null;
6054 tex_flush_node(noad_subprescr(target));
6055 noad_subprescr(target) = null;
6056 }
6057
6061 if (presupdata.box) {
6062 noad_script_state(target) |= pre_super_script_state;
6063 }
6064 if (presubdata.box) {
6065 noad_script_state(target) |= pre_sub_script_state;
6066 }
6067 if (postsupdata.box) {
6068 noad_script_state(target) |= post_super_script_state;
6069 }
6070 if (postsubdata.box) {
6071 noad_script_state(target) |= post_sub_script_state;
6072 }
6073 if (primedata.box) {
6074 noad_script_state(target) |= prime_script_state;
6075 }
6076
6077 if (primestate == prime_above_sub_location) {
6078 rightslack = box_width(primedata.box) > box_width(postsubdata.box) ? primedata.slack : postsubdata.slack;
6079 } else if (postsupdata.box) {
6080 if (postsubdata.box) {
6081
6082 rightslack = box_width(postsupdata.box) > box_width(postsubdata.box) ? postsupdata.slack : postsubdata.slack;
6083 } else {
6084 rightslack = postsupdata.slack;
6085 }
6086 } else if (postsubdata.box) {
6087 rightslack = postsubdata.slack;
6088 }
6089
6090 if (primestate == prime_above_sub_location) {
6091 halfword list = noad_new_hlist(target);
6092 if (list) {
6093
6094 halfword overshoot = box_width(primedata.box) - box_width(postsubdata.box);
6095 halfword primebox = tex_hpack(primedata.box, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
6096 tex_attach_attribute_list_copy(primebox, primedata.box);
6097 box_width(primebox) = 0;
6098 tex_couple_nodes(tex_tail_of_node_list(list), primebox);
6099 primedata.box = null;
6100 if (overshoot > 0) {
6101 tex_aux_append_hkern_to_box_list(postsubdata.box, overshoot, math_shape_kern_subtype, "prime overshoot kern");
6102 }
6103 } else {
6104 list = primedata.box;
6105 }
6106 noad_new_hlist(target) = list;
6107 }
6108
6109 if (presupdata.box) {
6110 if (presubdata.box) {
6111
6112 leftslack = box_width(presupdata.box) > box_width(presubdata.box) ? presupdata.slack : presubdata.slack;
6113 } else {
6114 leftslack = presupdata.slack;
6115 }
6116 } else if (presubdata.box) {
6117 leftslack = presubdata.slack;
6118 }
6119 switch (primestate) {
6120 case prime_at_begin_location:
6121 kernelsize.wd += box_width(primedata.box);
6122 break;
6123 case prime_above_sub_location:
6124
6125 break;
6126 }
6127 if (postsupdata.box || postsubdata.box) {
6128
6131 scaled supkern = 0;
6132 scaled subkern = 0;
6133 if (! splitscripts) {
6134 if (presupdata.box) {
6135 prekern = box_width(presupdata.box);
6136 postsupdata.box = tex_aux_combine_script(target, kernelsize.wd, presupdata.box, postsupdata.box, &presupdata.kern, &postsupdata.kern, math_pre_post_sup_list);
6137 presupdata.box = null;
6138 }
6139 if (presubdata.box) {
6140
6141 if (box_width(presubdata.box) > prekern) {
6142 prekern = box_width(presubdata.box);
6143 }
6144 postsubdata.box = tex_aux_combine_script(target, kernelsize.wd, presubdata.box, postsubdata.box, &presubdata.kern, &postsubdata.kern, math_pre_post_sub_list);
6145 presubdata.box = null;
6146 }
6147 }
6148
6149 if (postsupdata.box) {
6150
6151 tex_aux_get_math_sup_shifts(target, postsupdata.box, style, &shift_up);
6152 if (postsubdata.box) {
6153 tex_aux_get_math_sup_sub_shifts(target, postsupdata.box, postsubdata.box, style, &shift_up, &shift_down);
6154 tex_aux_get_sup_kern(kernel, &postsupdata, shift_up, supshift, &supkern, kerns, discard);
6155 tex_aux_get_sub_kern(kernel, &postsubdata, shift_down, subshift, &subkern, kerns, discard);
6156 if (primestate == prime_at_begin_location) {
6157 primekern += supkern ;
6158 subkern = 0;
6159 supkern = 0;
6160 } else {
6161 if (supkern) {
6162 tex_aux_prepend_hkern_to_box_list(postsupdata.box, supkern, math_shape_kern_subtype, "post sup shape");
6163 }
6164 if (subkern) {
6165 tex_aux_prepend_hkern_to_box_list(postsubdata.box, subkern, math_shape_kern_subtype, "post sub shape");
6166 }
6167 }
6168 if (italic) {
6169 tex_aux_prepend_hkern_to_box_list(postsupdata.box, italic, italic_kern_subtype, "italic");
6170 }
6171 if (presubdata.kern) {
6172 kern_amount(presubdata.kern) += -subkern;
6173 kern_amount(postsubdata.kern) += subkern;
6174 }
6175 if (presupdata.kern) {
6176
6177 kern_amount(presupdata.kern) += -supkern - italic;
6178 kern_amount(postsupdata.kern) += supkern + italic;
6179 }
6180 {
6181 halfword kern = tex_new_kern_node((shift_up - box_depth(postsupdata.box)) - (box_height(postsubdata.box) - shift_down), vertical_math_kern_subtype);
6182 tex_attach_attribute_list_copy(kern, target);
6183 tex_couple_nodes(postsupdata.box, kern);
6184 tex_couple_nodes(kern, postsubdata.box);
6185 result = tex_vpack(postsupdata.box, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
6186 tex_attach_attribute_list_copy(result, target);
6187 node_subtype(result) = math_scripts_list;
6188 box_shift_amount(result) = shift_down;
6189 }
6190 } else {
6191 tex_aux_get_sup_kern(kernel, &postsupdata, shift_up, supshift, &supkern, kerns, discard);
6192 if (primestate == prime_at_begin_location) {
6193 primekern += supkern ;
6194 supkern = 0;
6195 } else if (supkern) {
6196 tex_aux_prepend_hkern_to_box_list(postsupdata.box, supkern, math_shape_kern_subtype, "post sup shape");
6197 }
6198 result = tex_aux_shift_to_kern(target, postsupdata.box, -shift_up);
6199 if (presupdata.kern) {
6200 kern_amount(presupdata.kern) += -supkern - subkern - italic;
6201 kern_amount(postsupdata.kern) += supkern + subkern + italic;
6202 }
6203 }
6204 } else {
6205 tex_aux_get_math_sub_shifts(target, postsubdata.box, style, &shift_down);
6206 tex_aux_get_sub_kern(kernel, &postsubdata, shift_down, subshift, &subkern, kerns, discard);
6207 if (primestate == prime_at_begin_location) {
6208 subkern = 0;
6209 } else if (subkern) {
6210 tex_aux_prepend_hkern_to_box_list(postsubdata.box, subkern, math_shape_kern_subtype, "post sub shape");
6211 }
6212 result = tex_aux_shift_to_kern(target, postsubdata.box, shift_down);
6213 if (presubdata.kern) {
6214 kern_amount(presubdata.kern) += -subkern;
6215 kern_amount(postsubdata.kern) += subkern;
6216 }
6217 }
6218
6219 if (! splitscripts) {
6220 if (topovershoot) {
6221
6222 if (noad_script_state(target) & pre_super_script_state) {
6223 kern_amount(postsubdata.kern) -= topovershoot;
6224 kern_amount(postsupdata.kern) -= topovershoot;
6225 }
6226 if (noad_script_state(target) & post_sub_script_state) {
6227 kern_amount(presupdata.kern) += topovershoot;
6228 }
6229 }
6230 if (botovershoot) {
6231
6232 if (noad_script_state(target) & pre_sub_script_state) {
6233 kern_amount(presubdata.kern) -= botovershoot;
6234 kern_amount(presupdata.kern) -= botovershoot;
6235 }
6236 if (noad_script_state(target) & post_sub_script_state) {
6237 kern_amount(presubdata.kern) += botovershoot;
6238 }
6239 }
6240 goto PICKUP;
6241 }
6242 }
6243 if (presubdata.box) {
6244 if (presupdata.box) {
6245
6246 tex_aux_get_math_sup_shifts(target, presupdata.box, style, &shift_up);
6247 tex_aux_get_math_sup_sub_shifts(target, presupdata.box, presubdata.box, style, &shift_up, &shift_down);
6248 prekern = box_width(presupdata.box);
6249
6250 if (! splitscripts) {
6251 if (box_width(presubdata.box) > prekern) {
6252 prekern = box_width(presubdata.box);
6253 }
6254 presupdata.box = tex_aux_combine_script(target, kernelsize.wd, presupdata.box, null, &presupdata.kern, &postsupdata.kern, math_pre_post_sup_list);
6255 presubdata.box = tex_aux_combine_script(target, kernelsize.wd, presubdata.box, null, &presubdata.kern, &postsubdata.kern, math_pre_post_sub_list);
6256 }
6257 {
6258 halfword k = tex_new_kern_node((shift_up - box_depth(presupdata.box)) - (box_height(presubdata.box) - shift_down), vertical_math_kern_subtype);
6259 tex_attach_attribute_list_copy(k, target);
6260 tex_couple_nodes(presupdata.box, k);
6261 tex_couple_nodes(k, presubdata.box);
6262 preresult = tex_vpack(presupdata.box, 0, packing_additional, max_dimension, (singleword) math_direction_par, holding_none_option, NULL);
6263 tex_attach_attribute_list_copy(preresult, target);
6264 node_subtype(preresult) = math_scripts_list;
6265 box_shift_amount(preresult) = shift_down;
6266 }
6267 } else {
6268 tex_aux_get_math_sub_shifts(target, presubdata.box, style, &shift_down);
6269 if (! splitscripts) {
6270 prekern = box_width(presubdata.box);
6271 presubdata.box = tex_aux_combine_script(target, kernelsize.wd, presubdata.box, null, &presubdata.kern, &postsubdata.kern, math_pre_post_sub_list);
6272 }
6273 box_shift_amount(presubdata.box) = shift_down;
6274 preresult = presubdata.box;
6275 }
6276 } else if (presupdata.box) {
6277 tex_aux_get_math_sup_shifts(target, presupdata.box, style, &shift_up);
6278 if (! splitscripts) {
6279 prekern = box_width(presupdata.box);
6280 presupdata.box = tex_aux_combine_script(target, kernelsize.wd, presupdata.box, null, &presupdata.kern, &postsupdata.kern, math_pre_post_sup_list);
6281 }
6282 box_shift_amount(presupdata.box) = -shift_up;
6283 preresult = presupdata.box;
6284 }
6285 PICKUP:
6286 if (primestate == prime_at_begin_location) {
6287 halfword list = noad_new_hlist(target);
6288 if (primekern) {
6289 tex_aux_prepend_hkern_to_box_list(primedata.box, primekern, math_shape_kern_subtype, "prime");
6290 }
6291 if (list) {
6292 tex_couple_nodes(tex_tail_of_node_list(list), primedata.box);
6293 } else {
6294 list = primedata.box;
6295 }
6296 noad_new_hlist(target) = list;
6297 }
6298 if (splitscripts) {
6299 halfword list = noad_new_hlist(target);
6300 if (preresult) {
6301 if (list) {
6302 tex_couple_nodes(preresult, list);
6303 }
6304 list = preresult;
6305 }
6306 if (result) {
6307 if (list) {
6308 tex_couple_nodes(tex_tail_of_node_list(list), result);
6309 } else {
6310 list = result;
6311 }
6312 }
6313 noad_new_hlist(target) = list;
6314 } else {
6315 if (preresult) {
6316 result = preresult;
6317 }
6318 if (prekern) {
6319 halfword list = tex_aux_prepend_hkern_to_new_hlist(target, prekern, horizontal_math_kern_subtype, "pre compensation");
6320 tex_couple_nodes(tex_tail_of_node_list(list), result);
6321 } else if (noad_new_hlist(target)) {
6322 tex_couple_nodes(tex_tail_of_node_list(noad_new_hlist(target)), result);
6323 } else {
6324 noad_new_hlist(target) = result;
6325 }
6326 }
6327
6328 switch (primestate) {
6329 case prime_at_end_location:
6330 tex_couple_nodes(tex_tail_of_node_list(result), primedata.box);
6331 rightslack = primedata.slack;
6332 break;
6333 case prime_at_begin_location:
6334 rightslack = primedata.slack;
6335 break;
6336 }
6337 if (math_slack_mode_par > 0) {
6338 noad_left_slack(target) = leftslack;
6339 noad_right_slack(target) = rightslack;
6340 if (tracing_math_par >= 2) {
6341 tex_begin_diagnostic();
6342 tex_print_format("[math: script slack, left %p, right %p]", leftslack, rightslack);
6343 tex_end_diagnostic();
6344 }
6345 }
6346 if (presubdata.box || postsubdata.box) {
6347 noad_subshift(target) = shift_down;
6348 }
6349 if (presupdata.box || postsupdata.box) {
6350 noad_supshift(target) = shift_up;
6351 }
6352 if (primedata.box) {
6353 noad_primeshift(target) = prime_up;
6354 }
6355 noad_script_kern(target) = tex_round_xn_over_d(tex_get_math_x_parameter_default(style, math_parameter_space_between_script, 0), script_space_between_factor_par, scaling_factor);
6356}
6357
6358
6365
6366static halfword tex_aux_make_left_right(halfword target, int style, scaled max_d, scaled max_h, int size, delimiterextremes *extremes)
6367{
6368 halfword tmp;
6369 scaled ic = 0;
6370 int stack = 0;
6371 halfword mainclass = get_noad_main_class(target);
6372 halfword leftclass = get_noad_left_class(target);
6373 halfword rightclass = get_noad_right_class(target);
6374 scaled height = tex_aux_math_given_y_scaled(noad_height(target));
6375 scaled depth = tex_aux_math_given_y_scaled(noad_depth(target));
6376 int leftoperator = node_type(target) == fence_noad && node_subtype(target) == left_operator_side;
6377 halfword delimiter = fence_delimiter(target);
6378 halfword mergedattr = tex_merge_attribute_list(node_attr(delimiter), noad_extra_attr(target));
6379 max_h += fence_top_overshoot(target);
6380 max_d += fence_bottom_overshoot(target);
6381 if (extremes) {
6382 extremes->tfont = null_font;
6383 extremes->bfont = null_font;
6384 extremes->tchar = 0;
6385 extremes->tchar = 0;
6386 extremes->height = 0;
6387 extremes->depth = 0;
6388 }
6389 if (has_noad_option_scale(target)) {
6390 height = tex_aux_math_math_scale(height);
6391 depth = tex_aux_math_math_scale(depth);
6392 }
6393 tex_aux_set_current_math_size(style);
6394
6395 if (has_noad_option_use_callback(target)) {
6396 halfword fam = delimiter_small_family(delimiter);
6397 halfword chr = delimiter_small_character(delimiter);
6398 halfword fnt = tex_fam_fnt(fam, size);
6399 halfword thickness = tex_get_math_y_parameter_checked(style, math_parameter_fraction_rule);
6400 scaled axis = tex_aux_math_axis(size);
6401 scaled exheight = tex_aux_math_exheight(size);
6402 scaled emwidth = tex_aux_math_emwidth(size);
6403 halfword result = tex_made_extensible(target, fnt, chr, size, 0, max_h, max_d, thickness, axis, exheight, emwidth);
6404 if (result) {
6405 tmp = register_extensible(fnt, chr, size, result, mergedattr);
6406 goto PICKUP;
6407 }
6408 }
6409
6410 if (fence_delimiter_variant(target)) {
6411 int axis = ! has_noad_option_noaxis(target);
6412 scaled delta = 0;
6413
6414
6415
6416
6417
6418 tmp = tex_aux_make_delimiter(target, delimiter, size, delta, 0, style, axis, &stack, &ic, 0, has_noad_option_nooverflow(target), extremes, 0, mergedattr, fence_delimiter_variant(target), 1);
6419 } else if (height || depth || has_noad_option_exact(target)) {
6420 halfword lst;
6421 scaled delta = height + depth;
6422 tmp = tex_aux_make_delimiter(target, delimiter, size, delta, 0, style, 0, &stack, &ic, 0, has_noad_option_nooverflow(target), extremes, 0, mergedattr, 0, 1);
6423
6424 noad_italic(target) = ic;
6425
6428
6429 if (! stack && has_noad_option_exact(target)) {
6430 if (extremes && extremes->height < height) {
6431 height = extremes->height;
6432 }
6433 if (extremes && extremes->depth < depth) {
6434 depth = extremes->depth;
6435 }
6436 }
6437 if (stack) {
6438 box_shift_amount(tmp) = depth;
6439 }
6440 if (has_noad_option_exact(target)) {
6441 height = box_height(tmp) - box_shift_amount(tmp);
6442 depth = box_depth(tmp) + box_shift_amount(tmp);
6443 }
6444 if (has_noad_option_axis(target)) {
6445 if (has_noad_option_noaxis(target) && stack) {
6446
6447 } else {
6448 halfword axis = tex_aux_math_axis(size);
6449 height += axis;
6450 depth -= axis;
6451 box_shift_amount(tmp) -= axis;
6452 }
6453 }
6454 lst = tex_new_node(hlist_node, 0);
6455 tex_attach_attribute_list_copy(lst, target);
6456 box_dir(lst) = dir_lefttoright ;
6457 box_height(lst) = height;
6458 box_depth(lst) = depth;
6459 box_width(lst) = box_width(tmp);
6460 box_list(lst) = tmp;
6461 tmp = lst;
6462 } else {
6463 int axis = ! has_noad_option_noaxis(target);
6464 scaled delta = 0;
6465 if (leftoperator && has_noad_option_auto(target)) {
6466
6467 if (style < text_style) {
6468 scaled s = tex_get_math_y_parameter_checked(style, math_parameter_operator_size);
6469 if (s > max_h + max_d) {
6470 max_h = scaledround(s / 2.0);
6471 max_d = max_h;
6472 delta = max_h + max_d;
6473 }
6474 }
6475 }
6476 if (has_noad_option_auto_middle(target)) {
6477 delta = max_h + max_d;
6478 } else if (! delta) {
6479 delta = tex_aux_get_delimiter_height(max_h, max_d, axis, size, style);
6480 }
6481 tmp = tex_aux_make_delimiter(target, delimiter, size, delta, 0, style, axis, &stack, &ic, 0, has_noad_option_nooverflow(target), extremes, 0, mergedattr, 0, 1);
6482 }
6483 PICKUP:
6484
6485 noad_height(target) = height;
6486 noad_depth(target) = depth;
6487 fence_delimiter(target) = null;
6488 noad_italic(target) = ic;
6489
6490 if (noad_source(target)) {
6491 box_source_anchor(tmp) = noad_source(target);
6492
6493 tex_set_box_geometry(tmp, anchor_geometry);
6494 }
6495
6496 if (leftoperator) {
6497 halfword nucleus = tex_new_node(sub_box_node, 0);
6498 kernset kerns;
6499 tex_math_wipe_kerns(&kerns);
6500 tex_flush_node_list(noad_supscr(target));
6501 tex_flush_node_list(noad_subscr(target));
6502 tex_flush_node_list(noad_nucleus(target));
6503 if (fence_delimiter_top(target) && kernel_math_list(fence_delimiter_top(target))) {
6504 noad_supscr(target) = fence_delimiter_top(target);
6505 fence_delimiter_top(target) = null;
6506 }
6507 if (fence_delimiter_bottom(target) && kernel_math_list(fence_delimiter_bottom(target))) {
6508 noad_subscr(target) = fence_delimiter_bottom(target);
6509 fence_delimiter_bottom(target) = null;
6510 }
6511 kernel_math_list(nucleus) = tmp;
6512 noad_nucleus(target) = nucleus;
6513
6514 if (extremes && extremes->tfont) {
6515 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_top_kern_class_option)) {
6516 kerns.topright = tex_aux_math_x_size_scaled(extremes->tfont, tex_char_top_right_kern_from_font(extremes->tfont, extremes->tchar), size);
6517 }
6518 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_bottom_kern_class_option)) {
6519 kerns.bottomright = tex_aux_math_x_size_scaled(extremes->bfont, tex_char_bottom_right_kern_from_font(extremes->bfont, extremes->bchar), size);
6520 }
6521 if (tex_math_has_class_option(fenced_noad_subtype, prefer_delimiter_dimensions_class_option)) {
6522 kerns.height = extremes->height;
6523 kerns.depth = extremes->depth;
6524 kerns.dimensions = 1;
6525 kerns.font = extremes->tfont;
6526 kerns.character = extremes->tchar;
6527 }
6528 }
6529
6530 tex_aux_make_op(target, style, size, ic, limits_unknown_mode, &kerns);
6531
6532 kernel_math_list(nucleus) = null;
6533 tex_flush_node(nucleus);
6534 } else {
6535 tex_aux_assign_new_hlist(target, tmp);
6536 }
6537
6538 if (mergedattr) {
6539 delete_attribute_reference(mergedattr);
6540 delete_attribute_reference(noad_extra_attr(target));
6541 }
6542 switch (node_subtype(target)) {
6543 case left_fence_side:
6544 if (leftclass != unset_noad_class) {
6545 return leftclass;
6546 } else if (mainclass != unset_noad_class) {
6547 return mainclass;
6548 } else {
6549 return open_noad_subtype;
6550 }
6551 case middle_fence_side:
6552 if (mainclass != unset_noad_class) {
6553 return mainclass;
6554 } else {
6555 return middle_noad_subtype;
6556 }
6557 case right_fence_side:
6558 if (rightclass != unset_noad_class) {
6559 return rightclass;
6560 } else if (mainclass != unset_noad_class) {
6561 return mainclass;
6562 } else {
6563 return close_noad_subtype;
6564 }
6565 case left_operator_side:
6566 if (leftclass != unset_noad_class) {
6567 return leftclass;
6568 } else if (mainclass != unset_noad_class) {
6569 return mainclass;
6570 } else {
6571 return operator_noad_subtype;
6572 }
6573 default:
6574 if (mainclass != unset_noad_class) {
6575 return mainclass;
6576 } else {
6577
6578 return ordinary_noad_subtype;
6579 }
6580 }
6581}
6582
6583static inline int tex_aux_fallback_math_spacing_class(halfword style, halfword mathclass)
6584{
6585 unsigned parent = (unsigned) count_parameter(first_math_class_code + mathclass);
6586 switch (style) {
6587 case display_style: case cramped_display_style: return (parent >> 24) & 0xFF;
6588 case text_style: case cramped_text_style: return (parent >> 16) & 0xFF;
6589 case script_style: case cramped_script_style: return (parent >> 8) & 0xFF;
6590 case script_script_style: case cramped_script_script_style: return (parent >> 0) & 0xFF;
6591 default: return 0;
6592 }
6593}
6594
6595static halfword tex_aux_math_spacing_glue(halfword ltype, halfword rtype, halfword style, scaled mmu)
6596{
6597 halfword c = tex_to_math_spacing_parameter(ltype, rtype);
6598 halfword s = c;
6599 for (int i = 1; i <= 2; i++) {
6600 if (s >= 0) {
6601 halfword d = 0;
6602 halfword x = tex_get_math_parameter(style, s, &d);
6603 if (x) {
6604 switch (d) {
6605 case no_val_level:
6606 break;
6607 case dimension_val_level:
6608 if (x) {
6609 x = tex_aux_math_dimension(x, inter_math_skip_glue, c);
6610 if (tracing_math_par >= 2) {
6611 tex_begin_diagnostic();
6612 tex_print_format("[math: inter atom kern, left %n, right %n, resolved %i, amount %p]", ltype, rtype, s, kern_amount(x));
6613 tex_end_diagnostic();
6614 }
6615 return x;
6616 }
6617 goto NONE;
6618 case glue_val_level:
6619 if (! tex_glue_is_zero(x)) {
6620 x = tex_aux_math_glue(x, inter_math_skip_glue, c);
6621 if (tracing_math_par >= 2) {
6622 tex_begin_diagnostic();
6623 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));
6624 tex_end_diagnostic();
6625 }
6626 return x;
6627 }
6628 goto NONE;
6629 case muglue_val_level:
6630 if (! tex_math_glue_is_zero(x)) {
6631 x = tex_aux_math_muglue(x, inter_math_skip_glue, mmu, c, style);
6632 if (tracing_math_par >= 2) {
6633 tex_begin_diagnostic();
6634 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));
6635 tex_end_diagnostic();
6636 }
6637 return x;
6638 }
6639 goto NONE;
6640 default:
6641 if (tracing_math_par >= 2) {
6642 tex_begin_diagnostic();
6643 tex_print_format("[math: inter atom (mu) glue, left %n, right %n, resolved %i, unset]", ltype, rtype, s);
6644 tex_end_diagnostic();
6645 }
6646 goto NONE;
6647 }
6648 }
6649
6650 {
6651 halfword lparent = tex_aux_fallback_math_spacing_class(style, ltype);
6652 halfword rparent = tex_aux_fallback_math_spacing_class(style, rtype);
6653
6654 if (lparent != ltype || rparent != rtype) {
6655 s = tex_to_math_spacing_parameter(lparent, rtype);
6656 if (tex_has_math_parameter(style, s)) {
6657 goto FOUND;
6658 }
6659 s = tex_to_math_spacing_parameter(ltype, rparent);
6660 if (tex_has_math_parameter(style, s)) {
6661 goto FOUND;
6662 }
6663 s = tex_to_math_spacing_parameter(lparent, rparent);
6664 if (tex_has_math_parameter(style, s)) {
6665 goto FOUND;
6666 }
6667 }
6668
6669 s = tex_to_math_spacing_parameter(ltype, math_all_class);
6670 if (tex_has_math_parameter(style, s)) {
6671 goto FOUND;
6672 }
6673 s = tex_to_math_spacing_parameter(math_all_class, rtype);
6674 if (tex_has_math_parameter(style, s)) {
6675 goto FOUND;
6676 }
6677 s = tex_to_math_spacing_parameter(lparent, math_all_class);
6678 if (tex_has_math_parameter(style, s)) {
6679 goto FOUND;
6680 }
6681 s = tex_to_math_spacing_parameter(math_all_class, rparent);
6682 if (tex_has_math_parameter(style, s)) {
6683 goto FOUND;
6684 }
6685
6686 if (tracing_math_par >= 2) {
6687 tex_begin_diagnostic();
6688 tex_print_format("[math: inter atom fallback, left %n, right %n, left parent %n, right parent %n, not resolved]", ltype, rtype, lparent, rparent);
6689 tex_end_diagnostic();
6690 }
6691 goto NONE;
6692 FOUND:
6693 if (tracing_math_par >= 2) {
6694 tex_begin_diagnostic();
6695 tex_print_format("[math: inter atom fallback, left %n, right %n, left parent %n, right parent %n, resolved %i]", ltype, rtype, lparent, rparent, s);
6696 tex_end_diagnostic();
6697 }
6698 }
6699 } else {
6700
6701 goto NONE;
6702 }
6703 }
6704 NONE:
6705 if (math_spacing_mode_par && c >= 0) {
6706 if (math_spacing_mode_par == 1 && (ltype == math_begin_class || rtype == math_end_class)) {
6707 return null;
6708 } else {
6709 return tex_aux_math_dimension(0, inter_math_skip_glue, c);
6710 }
6711 } else {
6712 return null;
6713 }
6714}
6715
6716static inline int tex_aux_fallback_math_ruling_class(halfword style, halfword mathclass)
6717{
6718 unsigned parent = (unsigned) count_parameter(first_math_atom_code + mathclass);
6719 switch (style) {
6720 case display_style: case cramped_display_style: return (parent >> 24) & 0xFF;
6721 case text_style: case cramped_text_style: return (parent >> 16) & 0xFF;
6722 case script_style: case cramped_script_style: return (parent >> 8) & 0xFF;
6723 case script_script_style: case cramped_script_script_style: return (parent >> 0) & 0xFF;
6724 default: return 0;
6725 }
6726}
6727
6728static halfword tex_aux_math_ruling(halfword ltype, halfword rtype, halfword style)
6729{
6730 halfword c = tex_to_math_rules_parameter(ltype, rtype);
6731 halfword s = c;
6732 for (int i = 1; i <= 2; i++) {
6733 if (s >= 0) {
6734 halfword x = tex_get_math_parameter(style, s, NULL);
6735 if (x != MATHPARAMDEFAULT) {
6736 return x;
6737 } else {
6738 halfword lparent = tex_aux_fallback_math_ruling_class(style, ltype);
6739 halfword rparent = tex_aux_fallback_math_ruling_class(style, rtype);
6740 if (lparent != ltype || rparent != rtype) {
6741 s = tex_to_math_rules_parameter(lparent, rparent);
6742 } else {
6743 return MATHPARAMDEFAULT;
6744 }
6745 }
6746 } else {
6747 return MATHPARAMDEFAULT;
6748 }
6749 }
6750 return MATHPARAMDEFAULT;
6751}
6752
6753
6756
6757halfword tex_math_spacing_glue(halfword ltype, halfword rtype, halfword style)
6758{
6759
6760 halfword mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
6761 halfword sg = tex_aux_math_spacing_glue(ltype, rtype, style, mu);
6762 if (node_type(sg) == glue_node) {
6763 tex_add_glue_option(sg, glue_option_no_auto_break);
6764 }
6765 return sg;
6766}
6767
6768
6775
6776static halfword tex_aux_check_nucleus_complexity(halfword target, scaled *italic, halfword style, halfword size, kernset *kerns)
6777{
6778 halfword nucleus = noad_nucleus(target);
6779 if (nucleus) {
6780 if (italic) {
6781 *italic = 0;
6782 }
6783 switch (node_type(nucleus)) {
6784 case math_char_node:
6785 case math_text_char_node:
6786 {
6787 halfword chr = null;
6788 halfword fnt = null;
6789 if (tex_aux_fetch(nucleus, "(text) char", &fnt, &chr)) {
6790
6791 halfword glyph;
6792 quarterword subtype = glyph_unset_subtype;
6793 singleword mathclass = (singleword) node_subtype(nucleus);
6794
6795 if (real_math_class_code(noad_class_main(target))) {
6796 mathclass = noad_class_main(target);
6797 }
6798
6799 switch (mathclass) {
6800 case ordinary_noad_subtype: subtype = glyph_math_ordinary_subtype; break;
6801 case operator_noad_subtype: subtype = glyph_math_operator_subtype; break;
6802 case binary_noad_subtype: subtype = glyph_math_binary_subtype; break;
6803 case relation_noad_subtype: subtype = glyph_math_relation_subtype; break;
6804 case open_noad_subtype: subtype = glyph_math_open_subtype; break;
6805 case close_noad_subtype: subtype = glyph_math_close_subtype; break;
6806 case punctuation_noad_subtype: subtype = glyph_math_punctuation_subtype; break;
6807 case variable_noad_subtype: subtype = glyph_math_variable_subtype; break;
6808 case active_noad_subtype: subtype = glyph_math_active_subtype; break;
6809 case inner_noad_subtype: subtype = glyph_math_inner_subtype; break;
6810 case over_noad_subtype: subtype = glyph_math_over_subtype; break;
6811 case under_noad_subtype: subtype = glyph_math_under_subtype; break;
6812 case fraction_noad_subtype: subtype = glyph_math_fraction_subtype; break;
6813 case radical_noad_subtype: subtype = glyph_math_radical_subtype; break;
6814 case middle_noad_subtype: subtype = glyph_math_middle_subtype; break;
6815 case prime_noad_subtype: subtype = glyph_math_prime_subtype; break;
6816 case accent_noad_subtype: subtype = glyph_math_accent_subtype; break;
6817 case fenced_noad_subtype: subtype = glyph_math_fenced_subtype; break;
6818 case ghost_noad_subtype: subtype = glyph_math_ghost_subtype; break;
6819 default:
6820 if (real_math_class_code(mathclass)) {
6821
6827 subtype = glyph_math_extra_subtype + node_subtype(nucleus);
6828 }
6829 break;
6830
6831 }
6832
6833 glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
6834 tex_attach_attribute_list_copy(glyph, nucleus);
6835 if (node_type(nucleus) == math_char_node) {
6836 glyph_properties(glyph) = kernel_math_properties(nucleus);
6837 glyph_group(glyph) = kernel_math_group(nucleus);
6838 glyph_index(glyph) = kernel_math_index(nucleus);
6839 if (math_kernel_node_has_option(nucleus, math_kernel_auto_discretionary)) {
6840 tex_add_glyph_option(glyph, glyph_option_math_discretionary);
6841 }
6842 if (math_kernel_node_has_option(nucleus, math_kernel_full_discretionary)) {
6843 tex_add_glyph_option(glyph, glyph_option_math_italics_too);
6844 }
6845 }
6846
6850 if (math_kernel_node_has_option(nucleus, math_kernel_no_italic_correction)) {
6851
6854 } else if (tex_aux_math_followed_by_italic_kern(target, "complexity")) {
6855
6859 } else if (tex_aux_math_engine_control(fnt, math_control_apply_text_italic_kern)) {
6860
6864 if (italic) {
6865 *italic = tex_aux_math_x_size_scaled(fnt, tex_char_italic_from_font(fnt, chr), size);
6866 if (*italic) {
6867 if (node_type(nucleus) == math_text_char_node) {
6868 if (tex_aux_math_engine_control(fnt, math_control_check_text_italic_kern)) {
6869
6874 if (chr == letter_cmd) {
6875 *italic = 0;
6876 }
6877 }
6878 if (tex_aux_math_engine_control(fnt, math_control_check_space_italic_kern)) {
6879
6884 if (tex_get_font_space(fnt)) {
6885
6890 *italic = 0;
6891 }
6892 }
6893 }
6894 if (*italic && ! noad_has_following_scripts(target)) {
6895
6900 tex_aux_math_insert_italic_kern(glyph, *italic, nucleus, "check");
6901 *italic = 0;
6902 }
6903 }
6904 }
6905 }
6906 return glyph;
6907 } else {
6908 return tex_new_node(hlist_node, unknown_list);
6909 }
6910 }
6911 case sub_box_node:
6912 return kernel_math_list(nucleus);
6913 case sub_mlist_node:
6914 {
6915 halfword list = kernel_math_list(nucleus);
6916 halfword package = null;
6917 halfword fenced = node_type(target) == simple_noad && node_subtype(target) == fenced_noad_subtype;
6918 halfword ghost = node_type(target) == simple_noad && node_subtype(target) == ghost_noad_subtype;
6919 halfword last = fenced ? tex_tail_of_node_list(list) : null;
6920 int unpack = tex_math_has_class_option(node_subtype(target), unpack_class_option) || has_noad_option_unpacklist(target);
6921 halfword result = tex_mlist_to_hlist(list, unpack, style, unset_noad_class, unset_noad_class, kerns, m_to_h_sublist);
6922 tex_aux_set_current_math_size(style);
6923 package = tex_hpack(result, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
6924 if (ghost) {
6925 noad_class_left(target) = (singleword) cur_list.math_begin;
6926 noad_class_right(target) = (singleword) cur_list.math_end;
6927 }
6928 if (fenced) {
6929 node_subtype(package) = math_fence_list;
6930 if (list && node_type(list) == fence_noad && noad_analyzed(list) != unset_noad_class) {
6931 set_noad_left_class(target, noad_analyzed(list));
6932 }
6933 if (last && node_type(last) == fence_noad && noad_analyzed(last) != unset_noad_class) {
6934 set_noad_right_class(target, noad_analyzed(last));
6935 }
6936 } else if (unpack) {
6937 node_subtype(package) = math_list_list;
6938 } else if (noad_class_main(target) == unset_noad_class) {
6939 node_subtype(package) = math_pack_list;
6940 } else {
6941 node_subtype(package) = 0x100 + noad_class_main(target);
6942 }
6943
6944 tex_attach_attribute_list_copy(package, target);
6945 return package;
6946 }
6947 case hlist_node:
6948
6949 break;
6950 default:
6951 tex_confusion("check nucleus complexity");
6952 }
6953 } else {
6954 tex_normal_warning("math", "recovering from missing nucleus, best check it out");
6955 noad_nucleus(target) = tex_aux_fake_nucleus(ghost_noad_subtype);
6956 }
6957 return tex_new_node(hlist_node, unknown_list);
6958}
6959
6960
6964
6965static halfword tex_aux_make_choice(halfword current, halfword style)
6966{
6967 halfword prv = node_prev(current);
6968 halfword nxt = node_next(current);
6969 halfword signal = tex_new_node(style_node, former_choice_math_style);
6970
6971 tex_try_couple_nodes(prv, signal);
6972 tex_try_couple_nodes(signal, nxt);
6973 switch (node_subtype(current)) {
6974 case normal_choice_subtype:
6975 {
6976 halfword choice = null;
6977 switch (style) {
6978 case display_style:
6979 case cramped_display_style:
6980 choice = choice_display_mlist(current);
6981 choice_display_mlist(current) = null;
6982 break;
6983 case text_style:
6984 case cramped_text_style:
6985 choice = choice_text_mlist(current);
6986 choice_text_mlist(current) = null;
6987 break;
6988 case script_style:
6989 case cramped_script_style:
6990 choice = choice_script_mlist(current);
6991 choice_script_mlist(current) = null;
6992 break;
6993 case script_script_style:
6994 case cramped_script_script_style:
6995 choice = choice_script_script_mlist(current);
6996 choice_script_script_mlist(current) = null;
6997 break;
6998 }
6999
7000 if (choice) {
7001 tex_couple_nodes(signal, choice);
7002 tex_try_couple_nodes(tex_tail_of_node_list(choice), nxt);
7003 }
7004 }
7005 break;
7006 case discretionary_choice_subtype:
7007 {
7008 halfword disc = tex_new_disc_node(normal_discretionary_code);
7009 halfword pre = choice_pre_break(current);
7010 halfword post = choice_post_break(current);
7011 halfword replace = choice_no_break(current);
7012 choice_pre_break(current) = null;
7013 choice_post_break(current) = null;
7014 choice_no_break(current) = null;
7015 if (pre) {
7016 pre = tex_mlist_to_hlist(pre, 0, style, unset_noad_class, unset_noad_class, NULL, m_to_h_pre);
7017 tex_set_disc_field(disc, pre_break_code, pre);
7018 }
7019 if (post) {
7020 post = tex_mlist_to_hlist(post, 0, style, unset_noad_class, unset_noad_class, NULL, m_to_h_post);
7021 tex_set_disc_field(disc, post_break_code, post);
7022 }
7023 if (replace) {
7024 replace = tex_mlist_to_hlist(replace, 0, style, unset_noad_class, unset_noad_class, NULL, m_to_h_replace);
7025 tex_set_disc_field(disc, no_break_code, replace);
7026 }
7027 disc_class(disc) = choice_class(current);
7028 disc = tex_math_make_disc(disc);
7029 tex_couple_nodes(signal, disc);
7030 tex_try_couple_nodes(disc, nxt);
7031 }
7032 break;
7033 }
7034
7035 tex_flush_node(current);
7036 return signal;
7037}
7038
7039
7044
7045static int tex_aux_make_fenced(halfword current, halfword current_style, halfword size, noad_classes *fenceclasses)
7046{
7047 halfword nucleus = noad_nucleus(current);
7048 (void) current_style;
7049 (void) size;
7050 if (nucleus) {
7051 halfword list = kernel_math_list(nucleus);
7052 if (list && node_type(list) == fence_noad && node_subtype(list) == left_operator_side) {
7053
7054 fenceclasses->main = noad_class_main(list);
7055 fenceclasses->left = noad_class_left(list);
7056 fenceclasses->right = noad_class_right(list);
7057 if (noad_supscr(current) && ! (fence_delimiter_top(list) && kernel_math_list(fence_delimiter_top(list)))) {
7058 halfword n = tex_new_node(simple_noad, ordinary_noad_subtype);
7059 halfword top = tex_new_node(sub_mlist_node, 0);
7060 fence_delimiter_top(list) = top;
7061 node_subtype(n) = math_char_node;
7062 noad_nucleus(n) = noad_supscr(current);
7063 kernel_math_list(top) = n;
7064 noad_supscr(current) = null;
7065 if (tracing_math_par >= 2) {
7066 tex_begin_diagnostic();
7067 tex_print_str("[math: promoting supscript to top delimiter]");
7068 tex_end_diagnostic();
7069 }
7070 }
7071 if (noad_subscr(current) && ! (fence_delimiter_bottom(list) && kernel_math_list(fence_delimiter_bottom(list)))) {
7072 halfword n = tex_new_node(simple_noad, ordinary_noad_subtype);
7073 halfword bottom = tex_new_node(sub_mlist_node, 0);
7074 fence_delimiter_bottom(list) = bottom;
7075 node_subtype(n) = math_char_node;
7076 noad_nucleus(n) = noad_subscr(current);
7077 kernel_math_list(bottom) = n;
7078 noad_subscr(current) = null;
7079 if (tracing_math_par >= 2) {
7080 tex_begin_diagnostic();
7081 tex_print_str("[math: promoting subscript to bottom delimiter]");
7082 tex_end_diagnostic();
7083 }
7084 }
7085
7089 {
7090 halfword nxt = node_next(list);
7091 if (nxt && node_type(nxt) == fence_noad && node_subtype(nxt) == right_fence_side) {
7092
7093 node_next(list) = null;
7094 tex_flush_node_list(nxt);
7095 }
7096 }
7097 return 1;
7098 }
7099 }
7100 return 0;
7101}
7102
7103static void tex_aux_finish_fenced(halfword current, halfword main_style, halfword main_size, scaled max_depth, scaled max_height, kernset *kerns)
7104{
7105 delimiterextremes extremes = { .tfont = null_font, .tchar = 0, .bfont = null_font, .bchar = 0, .height = 0, .depth = 0 };
7106 noad_analyzed(current) = (singleword) tex_aux_make_left_right(current, main_style, max_depth, max_height, main_size, &extremes);
7107 if (kerns && extremes.tfont) {
7108 switch (node_subtype(current)) {
7109 case left_fence_side:
7110 case extended_left_fence_side:
7111 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_left_top_kern_class_option)) {
7112 kerns->topleft = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_left_kern_from_font(extremes.tfont, extremes.tchar), main_size);
7113 }
7114 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_left_bottom_kern_class_option)) {
7115 kerns->bottomleft = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_left_kern_from_font(extremes.bfont, extremes.bchar), main_size);
7116 }
7117 if (tex_math_has_class_option(fenced_noad_subtype, prefer_delimiter_dimensions_class_option)) {
7118 kerns->height = extremes.height;
7119 kerns->depth = extremes.depth;
7120 kerns->dimensions = 1;
7121 kerns->font = extremes.tfont;
7122 }
7123 break;
7124 case right_fence_side:
7125 case extended_right_fence_side:
7126 case left_operator_side:
7127 case no_fence_side:
7128 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_top_kern_class_option)) {
7129 kerns->topright = tex_aux_math_x_size_scaled(extremes.tfont, tex_char_top_right_kern_from_font(extremes.tfont, extremes.tchar), main_size);
7130 }
7131 if (tex_math_has_class_option(fenced_noad_subtype, carry_over_right_bottom_kern_class_option)) {
7132 kerns->bottomright = tex_aux_math_x_size_scaled(extremes.bfont, tex_char_bottom_right_kern_from_font(extremes.bfont, extremes.bchar), main_size);
7133 }
7134 if (tex_math_has_class_option(fenced_noad_subtype, prefer_delimiter_dimensions_class_option)) {
7135 kerns->height = extremes.height;
7136 kerns->depth = extremes.depth;
7137 }
7138 break;
7139 }
7140 }
7141}
7142
7143
7154
7155static halfword tex_aux_unroll_noad(halfword tail, halfword l, quarterword s)
7156{
7157 while (l) {
7158 halfword n = node_next(l);
7159 node_next(l) = null;
7160 if (node_type(l) == hlist_node && node_subtype(l) == s && ! box_source_anchor(l)) {
7161 if (box_list(l)) {
7162 tex_couple_nodes(tail, box_list(l));
7163 tail = tex_tail_of_node_list(tail);
7164 box_list(l) = null;
7165 }
7166 tex_flush_node(l);
7167 } else {
7168 tex_couple_nodes(tail, l);
7169 tail = l;
7170 }
7171 l = n;
7172 }
7173 return tail;
7174}
7175
7176static halfword tex_aux_unroll_list(halfword tail, halfword l)
7177{
7178 while (l) {
7179 halfword n = node_next(l);
7180 node_next(l) = null;
7181 if (node_type(l) == hlist_node && ! box_source_anchor(l)) {
7182 halfword list = box_list(l);
7183 if (list) {
7184 halfword subtype = node_subtype(l);
7185 switch (subtype) {
7186 case hbox_list:
7187 case container_list:
7188 case math_list_list:
7189
7190 tex_couple_nodes(tail, list);
7191 tail = tex_tail_of_node_list(tail);
7192 box_list(l) = null;
7193 tex_flush_node(l);
7194 break;
7195 case math_text_list:
7196 {
7197 while (list) {
7198 halfword next = node_next(list);
7199 if (node_type(list) == hlist_node) {
7200 tex_couple_nodes(tail, box_list(list));
7201 tail = tex_tail_of_node_list(tail);
7202 box_list(list) = null;
7203 tex_flush_node(list);
7204 } else {
7205 tex_couple_nodes(tail, list);
7206 tail = list;
7207 }
7208 list = next;
7209 }
7210 box_list(l) = null;
7211 tex_flush_node(l);
7212 }
7213 break;
7214 default:
7215
7220 if (subtype >= noad_class_list_base && node_type(list) == hlist_node && ! node_next(list)) {
7221 tex_couple_nodes(tail, box_list(list));
7222 tail = tex_tail_of_node_list(tail);
7223 box_list(l) = null;
7224 tex_flush_node(l);
7225 box_list(list) = null;
7226 tex_flush_node(list);
7227 } else {
7228 tex_couple_nodes(tail, l);
7229 tail = l;
7230 }
7231 break;
7232 }
7233 } else {
7234 tex_flush_node(l);
7235 }
7236 } else {
7237 tex_couple_nodes(tail, l);
7238 tail = l;
7239 }
7240 l = n;
7241 }
7242 return tail;
7243}
7244
7245static inline void tex_aux_wipe_noad(halfword n)
7246{
7247 if (tex_nodetype_has_attributes(node_type(n))) {
7248 remove_attribute_list(n);
7249 }
7250 tex_reset_node_properties(n);
7251 tex_free_node(n, get_node_size(node_type(n)));
7252}
7253
7254static halfword tex_aux_append_ghost(halfword ghost, halfword p, int wipe)
7255{
7256 halfword l = noad_new_hlist(ghost);
7257 if (l) {
7258 if (has_noad_option_unpacklist(ghost)) {
7259
7260 p = tex_aux_unroll_noad(p, l, math_list_list);
7261 } else if (has_noad_option_unrolllist(ghost)) {
7262 p = tex_aux_unroll_list(p, l);
7263 } else {
7264 if (node_type(l) == hlist_node && ! node_next(l)) {
7265 node_subtype(l) = math_ghost_list;
7266 }
7267 tex_couple_nodes(p, l);
7268 p = tex_tail_of_node_list(p);
7269 }
7270 noad_new_hlist(ghost) = null;
7271 }
7272 if (wipe) {
7273 tex_aux_wipe_noad(ghost);
7274 }
7275 return p;
7276}
7277
7278static halfword tex_aux_get_plus_glyph(halfword current)
7279{
7280 if (node_type(current) == simple_noad) {
7281 halfword list = noad_new_hlist(current);
7282 if (list && node_type(list) == hlist_node) {
7283 list = box_list(list);
7284 }
7285 if (list && node_type(list) == glue_node) {
7286 list = node_next(list);
7287 }
7288 if (list && node_type(list) == glyph_node && ! node_next(list)) {
7289 return list;
7290 }
7291 }
7292 return null;
7293}
7294
7295static halfword tex_aux_check_source(halfword current, halfword list, int repack)
7296{
7297 if (list && noad_source(current)) {
7298 switch (node_type(list)) {
7299 case hlist_node:
7300 case vlist_node:
7301
7302 box_source_anchor(list) = noad_source(current);
7303 tex_set_box_geometry(list, anchor_geometry);
7304 noad_source(current) = 0;
7305 break;
7306 default:
7307 if (repack) {
7308 if (tracing_math_par >= 2) {
7309 tex_begin_diagnostic();
7310 tex_print_format("[math: packing due to source field %D]", noad_source(current));
7311 tex_end_diagnostic();
7312 }
7313 list = tex_hpack(list, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
7314
7315 tex_attach_attribute_list_copy(list, current);
7316 box_source_anchor(list) = noad_source(current);
7317 noad_source(current) = 0;
7318 tex_set_box_geometry(list, anchor_geometry);
7319 noad_new_hlist(current) = list;
7320 node_subtype(list) = math_pack_list;
7321 }
7322 break;
7323 }
7324 } else {
7325
7326 }
7327 return list;
7328}
7329
7330static void tex_aux_wrapup_nucleus_and_add_scripts(halfword current, halfword nxt, int current_style, halfword *italic, kernset *kerns)
7331{
7332 halfword p = tex_aux_check_nucleus_complexity(current, italic, current_style, lmt_math_state.size, kerns);
7333 if (p && noad_source(current)) {
7334 p = tex_aux_check_source(current, p, has_noad_option_source_on_nucleus(current));
7335 }
7336 if (noad_has_scripts(current)) {
7337 scaled drop = 0;
7338 if (node_type(current) == accent_noad && noad_has_superscripts(current)) {
7339 drop = tex_get_math_y_parameter_default(current_style, math_parameter_accent_superscript_drop, 0);
7340 drop += scaledround(kerns->toptotal * tex_get_math_parameter_default(current_style, math_parameter_accent_superscript_percent, 0) / 100.0);
7341 }
7342 tex_aux_make_scripts(current, p, *italic, current_style, 0, 0, drop, kerns, lmt_math_state.single);
7343 lmt_math_state.single = 0;
7344 } else {
7345
7351 if (nxt && *italic) {
7352 if (node_type(nxt) == simple_noad && tex_math_has_class_option(node_subtype(nxt), no_italic_correction_class_option)) {
7353 *italic = 0;
7354 }
7355 if (*italic) {
7356
7357 tex_aux_math_insert_italic_kern(p, *italic, current, "final");
7358 }
7359 }
7360 tex_aux_assign_new_hlist(current, p);
7361 }
7362}
7363
7364
7374
7375typedef struct mliststate {
7376 halfword mlist;
7377 int penalties;
7378 int main_style;
7379 int beginclass;
7380 int endclass;
7381 kernset *kerns;
7382 halfword scale;
7383 scaled max_height;
7384 scaled max_depth;
7385 halfword single;
7386 halfword padding;
7387} mliststate;
7388
7389static void tex_mlist_to_hlist_set_boundaries(mliststate *state)
7390{
7391 halfword b = tex_aux_fake_nucleus((quarterword) state->beginclass);
7392 halfword e = tex_aux_fake_nucleus((quarterword) state->endclass);
7393 if (state->mlist) {
7394 tex_couple_nodes(b, state->mlist);
7395 }
7396 state->mlist = b;
7397 tex_couple_nodes(tex_tail_of_node_list(state->mlist), e);
7398 state->beginclass = unset_noad_class;
7399 state->endclass = unset_noad_class;
7400}
7401
7402static void tex_mlist_to_hlist_preroll_radicals(mliststate *state)
7403{
7404 halfword current = state->mlist;
7405 halfword current_style = state->main_style;
7406 halfword height = 0;
7407 halfword depth = 0;
7408 tex_aux_set_current_math_size(current_style);
7409 tex_aux_set_current_math_scale(state->scale);
7410 if (tracing_math_par >= 2) {
7411 tex_aux_show_math_list("[math: radical sizing pass, level %i]", state->mlist);
7412 }
7413 while (current) {
7414 switch (node_type(current)) {
7415 case radical_noad:
7416 {
7417 halfword body = null;
7418 tex_aux_preroll_radical(current, current_style, lmt_math_state.size);
7419 body = noad_new_hlist(current);
7420 if (box_height(body) > height) {
7421 height = box_height(body);
7422 }
7423 if (box_depth(body) > depth) {
7424 depth = box_depth(body);
7425 }
7426 }
7427 break;
7428 case style_node:
7429 tex_aux_make_style(current, ¤t_style, NULL);
7430 break;
7431 case parameter_node:
7432 tex_aux_set_parameter(current, current_style);
7433 break;
7434 }
7435 current = node_next(current);
7436 }
7437
7441 current = state->mlist;
7442 while (current) {
7443 if (node_type(current) == radical_noad) {
7444 switch (node_subtype(current)) {
7445 case normal_radical_subtype:
7446 case radical_radical_subtype:
7447 case root_radical_subtype:
7448 case rooted_radical_subtype:
7449 {
7450 halfword body = noad_new_hlist(current);
7451 if (radical_height(current) == max_dimension) {
7452 box_height(body) = height;
7453 } else if (radical_height(current) < 0) {
7454 box_height(body) += radical_height(current);
7455 if (box_height(body) < 0) {
7456 box_height(body) = 0;
7457 }
7458 } else if (radical_height(current)) {
7459 box_height(body) = radical_height(current);
7460 }
7461 if (radical_depth(current) == max_dimension) {
7462 box_depth(body) = depth;
7463 } else if (radical_depth(current) < 0) {
7464 box_depth(body) += radical_depth(current);
7465 if (box_depth(body) < 0) {
7466 box_depth(body) = 0;
7467 }
7468 } else if (radical_depth(current)) {
7469 box_depth(body) = radical_depth(current);
7470 }
7471 }
7472 break;
7473 }
7474 }
7475 current = node_next(current);
7476 }
7477}
7478
7479
7483
7484static void tex_mlist_to_hlist_preroll_dimensions(mliststate *state)
7485{
7486 halfword current = state->mlist;
7487 scaled current_mu = 0;
7488 halfword current_style = state->main_style;
7489 int blockrulebased = 0;
7490
7491 tex_aux_set_current_math_size(current_style);
7492 tex_aux_set_current_math_scale(state->scale);
7493
7494 current_mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
7495 if (tracing_math_par >= 2) {
7496 tex_aux_show_math_list("[math: preroll dimensions pass, level %i]", state->mlist);
7497 }
7498 while (current) {
7499
7500 scaled italic = 0;
7501 halfword nxt = node_next(current);
7502 noad_classes fenceclasses = { unset_noad_class, unset_noad_class, unset_noad_class };
7503 kernset localkerns;
7504 tex_math_wipe_kerns(&localkerns);
7505
7512 if (blockrulebased > 0) {
7513 blockrulebased -= 1;
7514 }
7515 switch (node_type(current)) {
7516 case simple_noad:
7517
7522 if (blockrulebased > 0) {
7523 noad_options(current) |= noad_option_no_ruling;
7524 blockrulebased = 0;
7525 }
7526 switch (node_subtype(current)) {
7527 case under_noad_subtype:
7528 tex_aux_make_under(current, current_style, lmt_math_state.size, math_rules_fam_par);
7529 break;
7530 case over_noad_subtype:
7531 tex_aux_make_over(current, current_style, lmt_math_state.size, math_rules_fam_par);
7532 break;
7533 case vcenter_noad_subtype:
7534 tex_aux_make_vcenter(current, current_style, lmt_math_state.size);
7535 break;
7536 case fenced_noad_subtype:
7537 if (tex_aux_make_fenced(current, current_style, lmt_math_state.size, &fenceclasses)) {
7538
7539 } else {
7540 break;
7541 }
7542 case operator_noad_subtype:
7543
7544 if (! (has_noad_option_limits(current) || has_noad_option_nolimits(current))) {
7545
7546 noad_options(current) |= (current_style == display_style || current_style == cramped_display_style) ? noad_option_limits : noad_option_no_limits;
7547 }
7548 goto PROCESS;
7549 default:
7550
7551 if ((has_noad_option_limits(current) && has_noad_option_nolimits(current))) {
7552 if (current_style == display_style || current_style == cramped_display_style) {
7553 noad_options(current) = unset_option(noad_options(current), noad_option_no_limits);
7554 noad_options(current) |= noad_option_limits;
7555 } else {
7556 noad_options(current) = unset_option(noad_options(current), noad_option_limits);
7557 noad_options(current) |= noad_option_no_limits;
7558 }
7559 }
7560 PROCESS:
7561 if (
7562
7563 has_noad_option_limits(current) || has_noad_option_nolimits(current)
7564 || has_noad_option_openupheight(current) || has_noad_option_openupdepth(current)
7565 || has_noad_option_adapttoleft(current) || has_noad_option_adapttoright(current)
7566 ) {
7567 if (node_subtype(current) == fenced_noad_subtype && ! noad_has_scripts(current)) {
7568
7573 italic = tex_aux_make_op(current, current_style, lmt_math_state.size, 0, limits_horizontal_mode, NULL);
7574 } else {
7575 italic = tex_aux_make_op(current, current_style, lmt_math_state.size, 0, limits_unknown_mode, NULL);
7576 }
7577
7578 if (node_subtype(current) != operator_noad_subtype) {
7579 italic = 0;
7580 }
7581 if (fenceclasses.main != unset_noad_class) {
7582 noad_class_main(current) = fenceclasses.main;
7583 }
7584 if (fenceclasses.left != unset_noad_class) {
7585 noad_class_left(current) = fenceclasses.left;
7586 }
7587 if (fenceclasses.right != unset_noad_class) {
7588 noad_class_right(current) = fenceclasses.right;
7589 }
7590 if (has_noad_option_limits(current) || has_noad_option_nolimits(current)) {
7591 goto CHECK_DIMENSIONS;
7592 }
7593 } else {
7594
7595 tex_aux_check_ord(current, lmt_math_state.size, null);
7596 }
7597 break;
7598 }
7599 break;
7600 case fence_noad:
7601 {
7602 state->single = has_noad_option_single(current);
7603
7604 current_style = state->main_style;
7605 tex_aux_set_current_math_size(current_style);
7606
7607 current_mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
7608
7609 goto DONE_WITH_NODE;
7610 }
7611 case fraction_noad:
7612 tex_aux_make_fraction(current, current_style, lmt_math_state.size, state->kerns);
7613 goto CHECK_DIMENSIONS;
7614 case radical_noad:
7615 tex_aux_make_radical(current, current_style, lmt_math_state.size, &localkerns);
7616 break;
7617 case accent_noad:
7618 tex_aux_make_accent(current, current_style, lmt_math_state.size, &localkerns);
7619 break;
7620 case style_node:
7621 tex_aux_make_style(current, ¤t_style, ¤t_mu);
7622 goto DONE_WITH_NODE;
7623 case choice_node:
7624 current = tex_aux_make_choice(current, current_style);
7625 goto DONE_WITH_NODE;
7626 case parameter_node:
7627
7628 tex_aux_set_parameter(current, current_style);
7629 goto DONE_WITH_NODE;
7630 case insert_node:
7631 case mark_node:
7632 case adjust_node:
7633 case boundary_node:
7634 case whatsit_node:
7635 case penalty_node:
7636 case disc_node:
7637 case par_node:
7638 goto DONE_WITH_NODE;
7639 case rule_node:
7640 tex_aux_check_math_strut_rule(current, current_style);
7641 if (rule_height(current) > state->max_height) {
7642 state->max_height = rule_height(current);
7643 }
7644 if (rule_depth(current) > state->max_depth) {
7645 state->max_depth = rule_depth(current);
7646 }
7647 goto DONE_WITH_NODE;
7648 case glue_node:
7649 if (node_subtype(current) == rulebased_math_glue) {
7650 blockrulebased = 2;
7651 }
7652 tex_aux_make_glue(current, current_mu, current_style);
7653 goto DONE_WITH_NODE;
7654 case kern_node:
7655 tex_aux_make_kern(current, current_mu, current_style);
7656 goto DONE_WITH_NODE;
7657 default:
7658 tex_confusion("mlist to hlist, case 1");
7659 }
7660
7669 tex_aux_wrapup_nucleus_and_add_scripts(current, nxt, current_style, &italic, &localkerns);
7670 CHECK_DIMENSIONS:
7671 {
7672 scaledwhd siz = tex_natural_msizes(noad_new_hlist(current), 0);
7673 if (siz.ht > state->max_height) {
7674 state->max_height = siz.ht;
7675 }
7676 if (siz.dp > state->max_depth) {
7677 state->max_depth = siz.dp;
7678 }
7679 }
7680
7681 if ((node_type(current) == simple_noad) && noad_new_hlist(current)) {
7682 if (has_noad_option_phantom(current) || has_noad_option_void(current)) {
7683 noad_new_hlist(current) = tex_aux_make_list_phantom(noad_new_hlist(current), has_noad_option_void(current), get_attribute_list(current));
7684 }
7685 }
7686 DONE_WITH_NODE:
7687 current = node_next(current);
7688 }
7689}
7690
7691
7692
7693static singleword tex_mlist_aux_guess_class(halfword target)
7694{
7695 if (noad_class_right(target) != unset_noad_class) {
7696 return noad_class_right(target);
7697 } else if (noad_class_main(target) != unset_noad_class) {
7698 return noad_class_main(target);
7699 } else {
7700 switch (node_type(target)) {
7701 case simple_noad:
7702 return (singleword) node_subtype(target);
7703 case radical_noad:
7704 switch (node_subtype(target)) {
7705 case normal_radical_subtype:
7706 case radical_radical_subtype:
7707 case root_radical_subtype:
7708 case rooted_radical_subtype:
7709 case delimited_radical_subtype:
7710 return radical_noad_subtype;
7711 case under_delimiter_radical_subtype:
7712 case delimiter_under_radical_subtype:
7713 return under_noad_subtype;
7714 case over_delimiter_radical_subtype:
7715 case delimiter_over_radical_subtype:
7716 return over_noad_subtype;
7717
7718
7719 default:
7720 return accent_noad_subtype;
7721 }
7722 case accent_noad:
7723 return get_noad_main_class(target);
7724 case fraction_noad:
7725 return fraction_noad_subtype;
7726 case fence_noad:
7727 return noad_analyzed(target);
7728 default:
7729 return ordinary_noad_subtype;
7730 }
7731 }
7732}
7733
7734static void tex_mlist_mark_continuation(halfword n, int ok)
7735{
7736 while (n) {
7737 switch (node_type(n)) {
7738 case glyph_node:
7739 if (ok) {
7740 glyph_options(n) |= glyph_option_is_continuation;
7741 }
7742 break;
7743 case hlist_node:
7744 case vlist_node:
7745 switch (node_subtype(n)) {
7746 case math_sup_list:
7747 case math_sub_list:
7748
7749
7750 tex_mlist_mark_continuation(box_list(n), 1);
7751 break;
7752 default:
7753 tex_mlist_mark_continuation(box_list(n), ok);
7754 break;
7755 }
7756 break;
7757 }
7758 n = node_next(n);
7759 }
7760}
7761
7762static void tex_mlist_aux_realign(halfword first, halfword last)
7763{
7764 scaled up = 0;
7765 scaled down = 0;
7766 scaled prime = 0;
7767 halfword current = first;
7768 halfword kernel = first;
7769 int realign = 0;
7770 while (current) {
7771 if (tex_math_scripts_allowed(current)) {
7772 if (has_noad_option_continuation_kernel(current)) {
7773 kernel = current;
7774
7775 if (noad_supshift(current) > up) {
7776 up = noad_supshift(current);
7777
7778 }
7779 if (noad_subshift(current) > down) {
7780 down = noad_subshift(current);
7781
7782 }
7783 if (noad_primeshift(current) > prime) {
7784 prime = noad_primeshift(current);
7785
7786 }
7787 } else {
7788
7789 tex_mlist_mark_continuation(noad_new_hlist(current), 0);
7790 }
7791 if (has_noad_option_realign_scripts(current)) {
7792
7793 if (noad_supshift(current) > up) {
7794 up = noad_supshift(current);
7795
7796 }
7797 if (noad_subshift(current) > down) {
7798 down = noad_subshift(current);
7799
7800 }
7801 if (noad_primeshift(current) > prime) {
7802 prime = noad_primeshift(current);
7803
7804 }
7805 realign = 1;
7806 } else {
7807
7808 }
7809 }
7810 if (current == last) {
7811 break;
7812 } else {
7813 current = node_next(current);
7814 }
7815 }
7816
7817 if (realign) {
7818
7819 }
7820
7821 current = first;
7822 while (current) {
7823 if (tex_math_scripts_allowed(current)) {
7824 halfword list = noad_new_hlist(current);
7825 if (list) {
7826 scaled u = up - noad_supshift(current);
7827 scaled d = down - noad_subshift(current);
7828 scaled p = prime - noad_primeshift(current);
7829 while (list) {
7830
7831 switch (node_type(list)) {
7832 case hlist_node:
7833 if (has_noad_option_realign_scripts(current)) {
7834 switch (node_subtype(list)) {
7835 case math_sup_list:
7836
7837 box_shift_amount(list) -= u;
7838 break;
7839 case math_prime_list:
7840
7841 box_shift_amount(list) -= p;
7842 break;
7843 case math_sub_list:
7844
7845 box_shift_amount(list) += d;
7846 break;
7847 case math_pre_post_sup_list:
7848
7849 box_shift_amount(list) -= u;
7850 break;
7851 case math_pre_post_sub_list:
7852
7853 box_shift_amount(list) += d;
7854 break;
7855 }
7856 }
7857 break;
7858 case vlist_node:
7859 switch (node_subtype(list)) {
7860 case math_scripts_list:
7861 {
7862 halfword b = box_list(list);
7863 while (b) {
7864 switch(node_type(b)) {
7865 case kern_node:
7866 if (has_noad_option_realign_scripts(last)) {
7867
7868 box_height(list) += u;
7869 box_depth(list) += d;
7870 kern_amount(b) += d + u;
7871 }
7872 break;
7873 case hlist_node:
7874 break;
7875 }
7876 b = node_next(b);
7877 }
7878 }
7879 break;
7880 }
7881 break;
7882 }
7883 list = node_next(list);
7884 }
7885 }
7886 }
7887 if (current == last) {
7888 break;
7889 } else {
7890 halfword next = node_next(current);
7891 scaled amount = noad_script_kern(first) - noad_right_slack(current);
7892
7893 if (amount) {
7894 halfword kern = tex_new_kern_node(amount, horizontal_math_kern_subtype);
7895 tex_attach_attribute_list_copy(kern, first);
7896 tex_couple_nodes(current, kern);
7897 tex_couple_nodes(kern, next);
7898 }
7899 current = next;
7900 }
7901 }
7902 if (has_noad_option_inherit_class(last)) {
7903 noad_class_right(last) = tex_mlist_aux_guess_class(kernel);
7904 noad_class_left(first) = noad_class_right(last);
7905 }
7906}
7907
7908static void tex_mlist_to_hlist_preroll_continuation(mliststate *state)
7909{
7910 halfword current = state->mlist;
7911 halfword first = null;
7912 halfword last = null;
7913 if (tracing_math_par >= 2) {
7914 tex_aux_show_math_list("[math: continuation pass, level %i]", state->mlist);
7915 }
7916 while (current) {
7917 if (tex_math_scripts_allowed(current)) {
7918 if (has_noad_option_continuation(current)) {
7919 if (! first) {
7920 first = current;
7921 }
7922 last = current;
7923 } else if (first != last) {
7924 tex_mlist_aux_realign(first, last);
7925 first = null;
7926 last = null;
7927 } else {
7928 first = current;
7929 last = current;
7930 }
7931 } else {
7932 if (first != last) {
7933 tex_mlist_aux_realign(first, last);
7934 }
7935 first = null;
7936 last = null;
7937 }
7938 current = node_next(current);
7939 }
7940 if (first != last) {
7941 tex_mlist_aux_realign(first, last);
7942 }
7943}
7944
7945
7959
7960static void tex_mlist_to_hlist_size_fences(mliststate *state)
7961{
7962 halfword current = state->mlist;
7963 halfword current_style = state->main_style;
7964 scaled height = 0;
7965 scaled depth = 0;
7966 tex_aux_set_current_math_size(current_style);
7967 tex_aux_set_current_math_scale(state->scale);
7968 if (tracing_math_par >= 2) {
7969 tex_aux_show_math_list("[math: fence sizing pass, level %i]", state->mlist);
7970 }
7971
7972 while (current) {
7973 switch (node_type(current)) {
7974 case fence_noad:
7975 if (node_subtype(current) != middle_fence_side) {
7976 tex_aux_finish_fenced(current, current_style, lmt_math_state.size, state->max_depth, state->max_height, state->kerns);
7977 if (node_subtype(current) == left_fence_side || node_subtype(current) == right_fence_side) {
7978 halfword list = noad_new_hlist(current);
7979 if (list) {
7980 height = box_height(list);
7981 depth = box_depth(list);
7982 }
7983 }
7984 }
7985 break;
7986 case style_node:
7987 tex_aux_make_style(current, ¤t_style, NULL);
7988 break;
7989 case parameter_node:
7990
7991 tex_aux_set_parameter(current, current_style);
7992 break;
7993 }
7994 current = node_next(current);
7995 }
7996 current = state->mlist;
7997 while (current) {
7998 switch (node_type(current)) {
7999 case fence_noad:
8000 if (node_subtype(current) == middle_fence_side) {
8001 int automiddle = has_noad_option_auto_middle(current) && (height || depth);
8002 tex_aux_finish_fenced(current, current_style, lmt_math_state.size, automiddle ? depth : state->max_depth, automiddle ? height : state->max_height, state->kerns);
8003 }
8004 break;
8005 }
8006 current = node_next(current);
8007 }
8008}
8009
8010
8014
8015static void tex_mlist_to_hlist_finalize_list(mliststate *state)
8016{
8017 halfword recent = null;
8018 int recent_type = 0;
8019 int recent_subtype = ordinary_noad_subtype;
8020 halfword current_style = state->main_style;
8021 halfword fenced = null;
8022 halfword packedfence = null;
8023 halfword recent_left_slack = 0;
8024 halfword recent_right_slack = 0;
8025 halfword recent_class_overload = unset_noad_class;
8026 halfword recent_script_state = 0;
8027 halfword recent_plus_glyph = null;
8028 scaled current_mu = 0;
8029 halfword current = state->mlist;
8030 halfword p = temp_head;
8031 int boundarylevel = 0;
8032 int boundaryfactor = scaling_factor;
8033 int nestinglevel = 0;
8034 int nestingfactor = scaling_factor;
8035 node_next(p) = null;
8036 tex_aux_set_current_math_size(current_style);
8037 tex_aux_set_current_math_scale(state->scale);
8038 current_mu = tex_get_math_quad_size_unscaled(lmt_math_state.size);
8039 if (math_penalties_mode_par) {
8040 state->penalties = 1;
8041 }
8042 if (tracing_math_par >= 2) {
8043 tex_aux_show_math_list("[math: finalize pass, level %i]", state->mlist);
8044 }
8045 RESTART:
8046 while (current) {
8047
8062
8063 halfword current_type = simple_noad;
8064
8065 halfword current_subtype = ordinary_noad_subtype;
8066
8067 halfword post_penalty = infinite_penalty;
8068 halfword pre_penalty = infinite_penalty;
8069
8070 halfword current_left_slack = 0;
8071 halfword current_right_slack = 0;
8072 halfword current_script_state = 0;
8073 halfword current_plus_glyph = 0;
8074 halfword old_recent = 0;
8075 halfword old_current = 0;
8076 HERE:
8077 switch (node_type(current)) {
8078 case simple_noad:
8079 {
8080 if (node_subtype(current) == ghost_noad_subtype && ! has_noad_option_carry_over_classes(current)) {
8081 p = tex_aux_append_ghost(current, p, 0);
8082 recent = current;
8083 current = node_next(current);
8084 goto WIPE;
8085 }
8086
8089 current_subtype = node_subtype(current);
8090 current_left_slack = noad_left_slack(current);
8091 current_right_slack = noad_right_slack(current);
8092 current_script_state = noad_script_state(current);
8093 switch (current_subtype) {
8094 case fenced_noad_subtype:
8095 {
8096 fenced = current;
8097 if (get_noad_right_class(fenced) != unset_noad_class) {
8098 current_subtype = get_noad_left_class(fenced);
8099 } else if (get_noad_main_class(fenced) != unset_noad_class) {
8100 current_subtype = get_noad_main_class(fenced);
8101 } else {
8102 current_subtype = open_noad_subtype;
8103 }
8104 break;
8105 }
8106 default:
8107 {
8108 halfword list = noad_new_hlist(current);
8109 if (list && tex_is_math_disc(list)) {
8110 current_type = simple_noad;
8111 current_subtype = disc_class(box_list(list));
8112 }
8113 if (list && noad_source(current)) {
8114 tex_aux_check_source(current, list, 1);
8115 }
8116 break;
8117 }
8118 }
8119 if (get_noad_left_class(current) != unset_noad_class) {
8120 current_subtype = get_noad_left_class(current);
8121 } else if (get_noad_main_class(current) != unset_noad_class) {
8122 current_subtype = get_noad_main_class(current);
8123 }
8124 }
8125 break;
8126 case radical_noad:
8127 switch (node_subtype(current)) {
8128 case normal_radical_subtype:
8129 case radical_radical_subtype:
8130 case root_radical_subtype:
8131 case rooted_radical_subtype:
8132 case delimited_radical_subtype:
8133 current_type = simple_noad;
8134 current_subtype = radical_noad_subtype;
8135 break;
8136 case under_delimiter_radical_subtype:
8137 case delimiter_under_radical_subtype:
8138 current_type = simple_noad;
8139 current_subtype = under_noad_subtype;
8140 break;
8141 case over_delimiter_radical_subtype:
8142 case delimiter_over_radical_subtype:
8143 current_type = simple_noad;
8144 current_subtype = over_noad_subtype;
8145 break;
8146 case h_extensible_radical_subtype:
8147 current_type = simple_noad;
8148 current_subtype = accent_noad_subtype;
8149 break;
8150 }
8151 break;
8152 case accent_noad:
8153 current_type = simple_noad;
8154 current_subtype = get_noad_main_class(current);
8155 current_left_slack = noad_left_slack(current);
8156 current_right_slack = noad_right_slack(current);
8157 break;
8158 case fraction_noad:
8159 current_type = simple_noad;
8160 current_subtype = fraction_noad_subtype;
8161 break;
8162 case fence_noad:
8163
8164 current_type = simple_noad;
8165 current_subtype = noad_analyzed(current);
8166 if (fence_nesting_factor(current) && fence_nesting_factor(current) != scaling_factor) {
8167 switch(current_subtype) {
8168 case open_noad_subtype:
8169 boundarylevel++;
8170 boundaryfactor = fence_nesting_factor(current);
8171 break;
8172 case close_noad_subtype:
8173 if (boundarylevel > 0) {
8174 boundarylevel--;
8175 if (boundarylevel == 0) {
8176 boundaryfactor = scaling_factor;
8177 } else {
8178 boundaryfactor = fence_nesting_factor(current);
8179 }
8180 } else {
8181 boundaryfactor = scaling_factor;
8182 }
8183 break;
8184 }
8185 }
8186 packedfence = current;
8187 break;
8188 case style_node:
8189 tex_aux_make_style(current, ¤t_style, ¤t_mu);
8190 recent = current;
8191 current = node_next(current);
8192 tex_aux_wipe_noad(recent);
8193 goto RESTART;
8194 case parameter_node:
8195 tex_aux_set_parameter(current, current_style);
8196 recent = current;
8197 current = node_next(current);
8198 tex_aux_wipe_noad(recent);
8199 goto RESTART;
8200 case glue_node:
8201 switch (node_subtype(current)) {
8202 case conditional_math_glue:
8203 case rulebased_math_glue:
8204 {
8205 halfword t = current;
8206 current = node_next(current);
8207 tex_flush_node(t);
8208 goto MOVEON;
8209 }
8210 default:
8211 break;
8212 }
8213 case boundary_node:
8214 if (node_subtype(current) == math_boundary) {
8215 halfword l = boundary_data(current);
8216 switch(l) {
8217 case begin_math_implicit_boundary:
8218 case begin_math_explicit_boundary:
8219 boundarylevel++;
8220 if (l == begin_math_explicit_boundary) {
8221 boundaryfactor = boundary_reserved(current) ? boundary_reserved(current) : scaling_factor;
8222 }
8223 break;
8224 case end_math_implicit_boundary:
8225 case end_math_explicit_boundary:
8226 if (boundarylevel > 0) {
8227 boundarylevel--;
8228 if (boundarylevel == 0) {
8229 boundaryfactor = scaling_factor;
8230 } else if (l == end_math_explicit_boundary) {
8231 boundaryfactor = boundary_reserved(current) ? boundary_reserved(current) : scaling_factor;
8232 }
8233 } else {
8234 tex_formatted_warning("math", "invalid math boundary %i nesting", l);
8235 }
8236 break;
8237 default:
8238 tex_formatted_warning("math", "invalid math boundary value");
8239
8240 break;
8241 }
8242 }
8243 goto PICKUP;
8244
8245 case disc_node:
8246 case hlist_node:
8247 case whatsit_node:
8248 case penalty_node:
8249 case rule_node:
8250 case adjust_node:
8251 case insert_node:
8252 case mark_node:
8253 case par_node:
8254 case kern_node:
8255 PICKUP:
8256 tex_couple_nodes(p, current);
8257 p = current;
8258 current = node_next(current);
8259 node_next(p) = null;
8260 MOVEON:
8261 if (current) {
8262
8263 switch (node_type(p)) {
8264 case boundary_node:
8265 case adjust_node:
8266 case insert_node:
8267 case mark_node:
8268 case par_node:
8269 goto HERE;
8270 case rule_node:
8271 if (node_subtype(p) == strut_rule_subtype) {
8272 goto HERE;
8273 }
8274 }
8275 }
8276 continue;
8277
8278 default:
8279 tex_confusion("mlist to hlist, case 2");
8280 }
8281
8288 recent_class_overload = get_noad_right_class(current);
8289 if (current_type == simple_noad && state->beginclass == unset_noad_class) {
8290 if (noad_new_hlist(current)) {
8291 tex_flush_node(noad_new_hlist(current));
8292 noad_new_hlist(current) = null;
8293 }
8294 state->beginclass = current_subtype;
8295
8296 recent_type = current_type;
8297 recent_subtype = current_subtype;
8298 recent = current;
8299 current = node_next(current);
8300 goto WIPE;
8301 }
8302 if (recent_subtype == math_begin_class) {
8303 state->beginclass = current_subtype;
8304 }
8305
8309 if (tex_math_has_class_option(current_subtype, look_ahead_for_end_class_option)) {
8310 halfword endhack = node_next(current);
8311 if (endhack && node_type(endhack) == simple_noad && (node_subtype(endhack) == math_end_class || get_noad_main_class(endhack) == math_end_class)) {
8312 halfword value = tex_aux_math_ruling(current_subtype, math_end_class, current_style);
8313 if (value != MATHPARAMDEFAULT) {
8314
8315
8316 current_subtype = (value >> 16) & 0xFF;
8317 }
8318
8319 }
8320 }
8321 old_recent = recent_subtype;
8322 old_current = current_subtype;
8323 if (current_subtype != unset_noad_class && recent_subtype != unset_noad_class && current_type == simple_noad) {
8324 if (recent_type == simple_noad && ! has_noad_option_noruling(current)) {
8325 halfword value = tex_aux_math_ruling(recent_subtype, current_subtype, current_style);
8326 if (value != MATHPARAMDEFAULT) {
8327 recent_subtype = (value >> 16) & 0xFF;
8328 current_subtype = value & 0xFF;
8329 }
8330 }
8331 if (tracing_math_par >= 2) {
8332 tex_begin_diagnostic();
8333 if (old_recent != recent_subtype || old_current != current_subtype) {
8334 tex_print_format("[math: atom ruling, recent %n, current %n, new recent %n, new current %n]", old_recent, old_current, recent_subtype, current_subtype);
8335 } else {
8336 tex_print_format("[math: atom ruling, recent %n, current %n]", old_recent, old_current);
8337 }
8338 tex_end_diagnostic();
8339 }
8340 }
8341
8342 if (current_type == simple_noad) {
8343 pre_penalty = tex_aux_math_penalty(state->main_style, 1, current_subtype);
8344 post_penalty = tex_aux_math_penalty(state->main_style, 0, current_subtype);
8345 }
8346
8347 current_plus_glyph = tex_aux_get_plus_glyph(current);
8348
8349 if (current_plus_glyph && recent_script_state) {
8350
8351 halfword plus = tex_aux_checked_left_kern(current_plus_glyph, recent_script_state, current_subtype, lmt_math_state.size);
8352 if (plus) {
8353 halfword kern = tex_new_kern_node(plus, math_shape_kern_subtype);
8354 tex_attach_attribute_list_copy(kern, current);
8355 tex_couple_nodes(p, kern);
8356 p = kern;
8357 if (tracing_math_par >= 2) {
8358 tex_begin_diagnostic();
8359 tex_print_format("[math: state driven left shape kern %p]", plus);
8360 tex_end_diagnostic();
8361 }
8362 }
8363 }
8364 if (recent_type > 0) {
8365 halfword last = node_type(p);
8366 halfword glue = tex_aux_math_spacing_glue(recent_subtype, current_subtype, current_style, current_mu);
8367 halfword kern = null;
8368 if (glue) {
8369 tex_attach_attribute_list_copy(glue, current);
8370 }
8371 if (recent_right_slack) {
8372 halfword kern = tex_new_kern_node(-recent_right_slack, right_math_slack_kern_subtype);
8373 tex_attach_attribute_list_copy(kern, current);
8374 tex_couple_nodes(p, kern);
8375 p = kern;
8376 if (current_subtype >= 0 && tex_math_has_class_option(current_subtype, no_pre_slack_class_option)) {
8377
8378 } else if (! glue) {
8379 glue = tex_aux_math_dimension(recent_right_slack, inter_math_skip_glue, -2);
8380 } else {
8381 glue_amount(glue) += recent_right_slack;
8382 }
8383 if (tracing_math_par >= 2) {
8384 tex_begin_diagnostic();
8385 tex_print_format("[math: migrating right slack %p]", recent_right_slack);
8386 tex_end_diagnostic();
8387 }
8388 recent_right_slack = 0;
8389 }
8390 if (recent_plus_glyph && current_script_state) {
8391
8392 halfword plus = tex_aux_checked_right_kern(recent_plus_glyph, current_script_state, recent_subtype, lmt_math_state.size);
8393 if (plus) {
8394 halfword kern = tex_new_kern_node(plus, math_shape_kern_subtype);
8395 tex_attach_attribute_list_copy(kern, current);
8396 tex_couple_nodes(p, kern);
8397 p = kern;
8398 if (tracing_math_par >= 2) {
8399 tex_begin_diagnostic();
8400 tex_print_format("[math: state driven right shape kern %p]", plus);
8401 tex_end_diagnostic();
8402 }
8403 }
8404 }
8405 if (current_left_slack) {
8406 kern = tex_new_kern_node(-current_left_slack, left_math_slack_kern_subtype);
8407 tex_attach_attribute_list_copy(kern, current);
8408
8409
8410 if (recent_subtype >= 0 && tex_math_has_class_option(recent_subtype, no_post_slack_class_option)) {
8411
8412 } else if (! glue) {
8413 glue = tex_aux_math_dimension(current_left_slack, inter_math_skip_glue, -1);
8414 } else {
8415 glue_amount(glue) += current_left_slack;
8416 }
8417 current_left_slack = 0;
8418 }
8419
8422 if (tex_math_has_class_option(current_subtype, push_nesting_class_option)) {
8423 nestinglevel++;
8424 switch (current_style) {
8425 case display_style:
8426 case cramped_display_style:
8427 nestingfactor = math_display_penalty_factor_par ? math_display_penalty_factor_par : scaling_factor;
8428 break;
8429 default:
8430 nestingfactor = math_inline_penalty_factor_par ? math_inline_penalty_factor_par : scaling_factor;
8431 break;
8432 }
8433 } else if (tex_math_has_class_option(current_subtype, pop_nesting_class_option) && nestinglevel > 0) {
8434 nestinglevel--;
8435 if (nestinglevel == 0) {
8436 nestingfactor = scaling_factor;
8437 }
8438 }
8439 if (state->penalties && node_type(last) != penalty_node && pre_penalty <= infinite_penalty && (! boundarylevel || (boundaryfactor != scaling_factor || nestingfactor != scaling_factor))) {
8440 if (boundaryfactor != scaling_factor) {
8441 pre_penalty = tex_xn_over_d(pre_penalty, boundaryfactor, scaling_factor);
8442 } else if (nestingfactor != scaling_factor && tex_math_has_class_option(current_subtype, obey_nesting_class_option)) {
8443 pre_penalty = tex_xn_over_d(pre_penalty, nestingfactor, scaling_factor);
8444 }
8445 if (pre_penalty < infinite_penalty) {
8446
8447 halfword penalty = tex_new_penalty_node(pre_penalty, math_pre_penalty_subtype);
8448 tex_attach_attribute_list_copy(penalty, current);
8449 tex_couple_nodes(p, penalty);
8450 p = penalty;
8451 if (tracing_math_par >= 2) {
8452 tex_begin_diagnostic();
8453 tex_print_format("[math: pre penalty, left %n, right %n, amount %i]", recent_subtype, current_subtype, penalty_amount(penalty));
8454 tex_end_diagnostic();
8455 }
8456 }
8457 }
8458 if (tex_math_has_class_option(current_subtype, remove_italic_correction_class_option)) {
8459 if (node_type(p) == kern_node && node_subtype(p) == italic_kern_subtype) {
8460 halfword prv = node_prev(p);
8461 if (prv) {
8462 if (tracing_math_par >= 2) {
8463 tex_begin_diagnostic();
8464 tex_print_format("[math: removing italic correction %D between %i and %i]", kern_amount(p), recent_subtype, current_subtype);
8465 tex_end_diagnostic();
8466 }
8467 tex_flush_node(p);
8468 p = prv;
8469 }
8470 }
8471 }
8472 if (glue) {
8473 tex_couple_nodes(p, glue);
8474 p = glue;
8475 }
8476 if (kern) {
8477 tex_couple_nodes(p, kern);
8478 p = kern;
8479 }
8480 }
8481 {
8482 halfword l = noad_new_hlist(current);
8483 if (! l) {
8484
8485 } else if (current_subtype == ghost_noad_subtype) {
8486 p = tex_aux_append_ghost(current, p, 0);
8487 } else if (node_type(l) == hlist_node && box_source_anchor(l)) {
8488 tex_couple_nodes(p, l);
8489 } else if (packedfence) {
8490
8491
8492 if (tex_math_has_class_option(fenced_noad_subtype, unpack_class_option)) {
8493 p = tex_aux_unroll_noad(p, l, math_fence_list);
8494 } else {
8495 tex_couple_nodes(p, l);
8496 }
8497 } else if ((current_subtype == open_noad_subtype || current_subtype == fenced_noad_subtype) && tex_math_has_class_option(fenced_noad_subtype, unpack_class_option)) {
8498
8499 p = tex_aux_unroll_noad(p, l, math_fence_list);
8500 } else if (has_noad_option_unpacklist(current) || tex_math_has_class_option(current_subtype, unpack_class_option)) {
8501
8502 p = tex_aux_unroll_noad(p, l, math_list_list);
8503 } else if (has_noad_option_unrolllist(current)) {
8504 p = tex_aux_unroll_list(p, l);
8505 } else if (tex_is_math_disc(l)) {
8506
8507 tex_couple_nodes(p, box_list(l));
8508 box_list(l) = null;
8509 tex_flush_node(l);
8510 } else if (current_type == simple_noad && (current_subtype == math_end_class || current_subtype == math_begin_class)) {
8511 if (noad_new_hlist(current)) {
8512 tex_flush_node(noad_new_hlist(current));
8513 noad_new_hlist(current) = null;
8514 }
8515 } else {
8516 tex_couple_nodes(p, l);
8517 }
8518 p = tex_tail_of_node_list(p);
8519 if (fenced) {
8520 if (get_noad_right_class(fenced) != unset_noad_class) {
8521 current_subtype = get_noad_right_class(fenced);
8522 } else if (get_noad_main_class(fenced) != unset_noad_class) {
8523 current_subtype = get_noad_main_class(fenced);
8524 } else {
8525 current_subtype = close_noad_subtype;
8526 }
8527 fenced = null;
8528 }
8529 noad_new_hlist(current) = null;
8530 packedfence = null;
8531 }
8532
8541 if (state->penalties && node_next(current) && post_penalty <= infinite_penalty && (! boundarylevel || (boundaryfactor != scaling_factor || nestingfactor != scaling_factor))) {
8542 if (boundaryfactor != scaling_factor) {
8543 post_penalty = tex_xn_over_d(post_penalty, boundaryfactor, scaling_factor);
8544 } else if (nestingfactor != scaling_factor && tex_math_has_class_option(current_subtype, obey_nesting_class_option)) {
8545 post_penalty = tex_xn_over_d(post_penalty, nestingfactor, scaling_factor);
8546 }
8547 if (post_penalty < infinite_penalty) {
8548 halfword recent = node_next(current);
8549 recent_type = node_type(recent);
8550 recent_subtype = node_subtype(recent);
8551
8552 if ((recent_type != penalty_node) && ! (recent_type == simple_noad && tex_math_has_class_option(recent_subtype, omit_penalty_class_option))) {
8553 halfword penalty = tex_new_penalty_node(post_penalty, math_post_penalty_subtype);
8554 tex_attach_attribute_list_copy(penalty, current);
8555 tex_couple_nodes(p, penalty);
8556 p = penalty;
8557 if (tracing_math_par >= 2) {
8558 tex_begin_diagnostic();
8559 tex_print_format("[math: post penalty, left %n, right %n, amount %i]", recent_subtype, current_subtype, penalty_amount(penalty));
8560 tex_end_diagnostic();
8561 }
8562 }
8563 }
8564 }
8565 if (recent_class_overload != unset_noad_class) {
8566 current_type = simple_noad;
8567 current_subtype = recent_class_overload;
8568 }
8569 if (current_type == simple_noad && current_subtype != math_end_class) {
8570 state->endclass = current_subtype;
8571 }
8572 recent_type = current_type;
8573 recent_subtype = current_subtype;
8574 recent_left_slack = current_left_slack;
8575 recent_right_slack = current_right_slack;
8576 recent_script_state = current_script_state;
8577 recent_plus_glyph = current_plus_glyph;
8578
8583
8584 if (p == temp_head && recent_left_slack) {
8585 halfword kern = tex_new_kern_node(-recent_left_slack, left_math_slack_kern_subtype);
8586 halfword head = node_next(temp_head);
8587 tex_attach_attribute_list_copy(kern, head);
8588 tex_couple_nodes(kern, head);
8589 node_next(temp_head) = kern;
8590 if (tracing_math_par >= 2) {
8591 tex_begin_diagnostic();
8592 tex_print_format("[math: nilling recent left slack %D]", recent_left_slack);
8593 tex_end_diagnostic();
8594 }
8595 }
8596 recent = current;
8597 current = node_next(current);
8598 if (! current && recent_right_slack) {
8599 halfword kern = tex_new_kern_node(-recent_right_slack, right_math_slack_kern_subtype);
8600 tex_attach_attribute_list_copy(kern, p);
8601 tex_couple_nodes(p, kern);
8602 p = kern;
8603 if (tracing_math_par >= 2) {
8604 tex_begin_diagnostic();
8605 tex_print_format("[math: nilling recent right slack %D]", recent_right_slack);
8606 tex_end_diagnostic();
8607 }
8608 }
8609
8610
8616 WIPE:
8617 tex_aux_wipe_noad(recent);
8618 }
8619 if (tracing_math_par >= 3) {
8620 tex_aux_show_math_list("[math: result, level %i]", node_next(temp_head));
8621 }
8622}
8623
8624
8637
8638static void tex_mlist_to_hlist_prepare(mliststate *state)
8639{
8640 if (state->mlist) {
8641 halfword current = state->mlist;
8642 halfword first = null;
8643 if (tracing_math_par >= 2) {
8644 tex_aux_show_math_list("[math: prescript reordering pass, level %i]", state->mlist);
8645 }
8646 while (current) {
8647 halfword next = node_next(current);
8648 if (tex_math_scripts_allowed(current)) {
8649 if (has_noad_option_continuation_head(current)) {
8650 first = current;
8651 } else if (! has_noad_option_continuation(current)) {
8652 first = null;
8653 } else if (has_noad_option_reorder_pre_scripts(current) && (noad_subprescr(current) || noad_supprescr(current))) {
8654 halfword temp = null;
8655 if (noad_subscr(current) || noad_supscr(current) || noad_prime(current)) {
8656
8657 temp = tex_new_math_continuation_atom(null, current);
8658 noad_subprescr(temp) = noad_subprescr(current);
8659 noad_supprescr(temp) = noad_supprescr(current);
8660 noad_subprescr(current) = null;
8661 noad_supprescr(current) = null;
8662 } else {
8663
8664 temp = current;
8665 tex_try_couple_nodes(node_prev(current), next);
8666 }
8667 if (! first) {
8668 first = state->mlist;
8669 }
8670 tex_couple_nodes(temp, first);
8671 if (first == state->mlist) {
8672 state->mlist = temp;
8673 }
8674 tex_remove_noad_option(first, noad_option_continuation_head);
8675 tex_add_noad_option(first, noad_option_continuation);
8676 tex_remove_noad_option(temp, noad_option_continuation);
8677 tex_add_noad_option(temp, noad_option_continuation_head);
8678 first = temp;
8679 }
8680 }
8681 current = next;
8682 }
8683 }
8684
8685}
8686
8687halfword tex_mlist_to_hlist(halfword mlist, int penalties, int main_style, int beginclass, int endclass, kernset *kerns, int where)
8688{
8689
8695 mliststate state = {
8696 .mlist = mlist,
8697 .penalties = penalties,
8698 .main_style = main_style,
8699 .beginclass = beginclass == unset_noad_class ? math_begin_class : beginclass,
8700 .endclass = endclass == unset_noad_class ? math_end_class : endclass,
8701 .kerns = kerns,
8702 .scale = glyph_scale_par,
8703 .max_height = 0,
8704 .max_depth = 0,
8705 .single = 0,
8706 };
8707 (void) where;
8708
8709 if (kerns) {
8710 tex_math_wipe_kerns(kerns);
8711 }
8712 ++lmt_math_state.level;
8713
8714tex_mlist_to_hlist_prepare(&state);
8715
8716
8720
8721 tex_mlist_to_hlist_set_boundaries(&state);
8722
8726
8727 tex_mlist_to_hlist_preroll_radicals(&state);
8728
8732
8733 tex_mlist_to_hlist_preroll_dimensions(&state);
8734
8737
8738 tex_mlist_to_hlist_preroll_continuation(&state);
8739
8742
8743 tex_mlist_to_hlist_size_fences(&state);
8744
8757
8758 tex_mlist_to_hlist_finalize_list(&state);
8759
8763
8764 tex_unsave_math_data(cur_level + lmt_math_state.level);
8765
8766 cur_list.math_begin = state.beginclass;
8767 cur_list.math_end = state.endclass;
8768 lmt_math_state.single = state.single;
8769 glyph_scale_par = state.scale;
8770 --lmt_math_state.level;
8771 node_prev(node_next(temp_head)) = null;
8772
8773 return node_next(temp_head);
8774}
8775 |