1
4
5# include "luametatex.h"
6
7
42
43page_builder_state_info lmt_page_builder_state = {
44 .page_tail = null,
45 .contents = 0,
46 .max_depth = 0,
47 .best_break = null,
48 .least_cost = 0,
49 .best_size = 0,
50 .goal = 0,
51 .vsize = 0,
52 .total = 0,
53 .depth = 0,
54 .excess = 0,
55 .page_so_far = { 0 },
56 .insert_penalties = 0,
57 .insert_heights = 0,
58 .last_glue = max_halfword,
59 .last_penalty = 0,
60 .last_kern = 0,
61 .last_node_type = unknown_node_type,
62 .last_node_subtype= unknown_node_subtype,
63 .last_extra_used = 0,
64 .last_boundary = 0,
65 .output_active = 0,
66 .dead_cycles = 0,
67 .current_state = 0
68};
69
70
74
75# define page_stretched(order) lmt_page_builder_state.page_so_far[page_stretch_state+order]
76
77static void tex_aux_fire_up (halfword c);
78
79
127
128void tex_initialize_pagestate(void)
129{
130 lmt_page_builder_state.page_tail = page_head;
131 lmt_page_builder_state.contents = contribute_nothing;
132 lmt_page_builder_state.max_depth = 0;
133 lmt_page_builder_state.best_break = null;
134 lmt_page_builder_state.least_cost = 0;
135 lmt_page_builder_state.best_size = 0;
136 lmt_page_builder_state.goal = 0;
137 lmt_page_builder_state.vsize = 0;
138 lmt_page_builder_state.total = 0;
139 lmt_page_builder_state.depth = 0;
140 for (int i = page_initial_state; i <= page_shrink_state; i++) {
141 lmt_page_builder_state.page_so_far[i] = 0;
142 }
143 lmt_page_builder_state.insert_penalties = 0;
144 lmt_page_builder_state.insert_heights = 0;
145 lmt_page_builder_state.last_glue = max_halfword;
146 lmt_page_builder_state.last_penalty = 0;
147 lmt_page_builder_state.last_kern = 0;
148 lmt_page_builder_state.last_extra_used = 0;
149 lmt_page_builder_state.last_boundary = 0;
150 lmt_page_builder_state.last_node_type = unknown_node_type;
151 lmt_page_builder_state.last_node_subtype = unknown_node_subtype;
152 lmt_page_builder_state.output_active = 0;
153 lmt_page_builder_state.dead_cycles = 0;
154 lmt_page_builder_state.current_state = 0;
155}
156
157void tex_initialize_buildpage(void)
158{
159 node_type(page_insert_head) = split_node;
160 node_subtype(page_insert_head) = insert_split_subtype;
161 insert_index(page_insert_head) = 65535;
162 node_next(page_insert_head) = page_insert_head;
163 node_type(page_head) = glue_node;
164 node_subtype(page_head) = page_glue;
165}
166
167
189
190void tex_additional_page_skip(void)
191{
192 if (page_total > 0 && additional_page_skip_par) {
193 page_stretch += glue_stretch(additional_page_skip_par);
194 page_shrink += glue_shrink(additional_page_skip_par);
195 page_total += glue_amount(additional_page_skip_par);
196 update_tex_additional_page_skip(null);
197 }
198}
199
200static void tex_aux_save_best_page_specs(void)
201{
202 page_last_depth = page_depth;
203 page_last_height = page_total;
204 page_last_stretch = page_stretch;
205 page_last_fistretch = page_fistretch;
206 page_last_filstretch = page_filstretch;
207 page_last_fillstretch = page_fillstretch;
208 page_last_filllstretch = page_filllstretch;
209 page_last_shrink = page_shrink;
210}
211
212static void tex_aux_freeze_page_specs(int s)
213{
214 lmt_page_builder_state.contents = s;
215 lmt_page_builder_state.max_depth = max_depth_par;
216 lmt_page_builder_state.least_cost = awful_bad;
217
218 for (int i = page_initial_state; i <= page_shrink_state; i++) {
219 lmt_page_builder_state.page_so_far[i] = 0;
220 lmt_page_builder_state.page_last_so_far[i] = 0;
221 }
222 page_goal = vsize_par;
223 page_vsize = vsize_par;
224 page_depth = 0;
225 page_total = 0;
226 page_excess = 0;
227 page_except = 0;
228 page_last_depth = 0;
229 page_last_height = 0;
230 if (initial_page_skip_par) {
231 page_stretch = glue_stretch(initial_page_skip_par);
232 page_shrink = glue_shrink(initial_page_skip_par);
233 page_total = glue_amount(initial_page_skip_par);
234 }
235 if (additional_page_skip_par) {
236 page_stretch += glue_stretch(additional_page_skip_par);
237 page_shrink += glue_shrink(additional_page_skip_par);
238 page_total += glue_amount(additional_page_skip_par);
239 update_tex_additional_page_skip(null);
240 }
241 if (tracing_pages_par > 0) {
242 tex_begin_diagnostic();
243 tex_print_format(
244 "[page: frozen state, goal %p, maxdepth %p, contribution %s, insertheights %p]",
245 page_goal,
246 lmt_page_builder_state.max_depth,
247 lmt_interface.page_contribute_values[s].name,
248 lmt_page_builder_state.insert_heights
249 );
250 tex_end_diagnostic();
251 }
252}
253
254static void update_page_goal(halfword index, scaled total, scaled delta)
255{
256 page_goal -= delta;
257 lmt_page_builder_state.insert_heights += total;
258 if (lmt_page_builder_state.insert_heights > max_dimension) {
259 lmt_page_builder_state.insert_heights = max_dimension;
260 }
261 if (tracing_inserts_par > 0) {
262 tex_begin_diagnostic();
263 tex_print_format(
264 "[page: update page goal for insert, index %i, total %p, insertheights %p, vsize %p, delta %p, goal %p]",
265 index, total, lmt_page_builder_state.insert_heights, page_vsize, delta, page_goal
266 );
267 tex_end_diagnostic();
268 }
269}
270
271
278
279static void tex_aux_start_new_page(void)
280{
281 lmt_page_builder_state.contents = contribute_nothing;
282 lmt_page_builder_state.page_tail = page_head;
283 node_next(page_head) = null;
284 lmt_page_builder_state.last_glue = max_halfword;
285 lmt_page_builder_state.last_penalty = 0;
286 lmt_page_builder_state.last_kern = 0;
287 lmt_page_builder_state.last_boundary = 0;
288 lmt_page_builder_state.last_node_type = unknown_node_type;
289 lmt_page_builder_state.last_node_subtype = unknown_node_subtype;
290 page_depth = 0;
291 lmt_page_builder_state.max_depth = 0;
292}
293
294
301
302static halfword tex_aux_delete_box_content(int n, const char *what, int where)
303{
304 if (tracing_pages_par > 0) {
305 tex_begin_diagnostic();
306 tex_print_format("[page: deleting %s box, case %i]", what, where);
307 tex_show_box(n);
308 tex_end_diagnostic();
309 }
310 tex_flush_node_list(n);
311 return null;
312}
313
314
320
321static int tex_aux_valid_insert_content(halfword content)
322{
323 if (content && node_type(content) == hlist_node) {
324
325 tex_handle_error(
326 normal_error_type,
327 "Insertions can only be added to a vbox",
328 "Tut tut: You're trying to \\insert into a \\box register that now contains an\n"
329 "\\hbox. Proceed, and I'll discard its present contents."
330 );
331 return 0;
332 } else {
333 return 1;
334 }
335}
336
337
347
348static void tex_aux_display_page_break_cost(halfword badness, halfword penalty, halfword cost, int moveon, int fireup)
349{
350 tex_begin_diagnostic();
351 tex_print_format("[page: break, total %P, goal %p, badness %B, penalty %i, cost %B%s, moveon %s, fireup %s]",
352 page_total, page_stretch, page_fistretch, page_filstretch, page_fillstretch, page_filllstretch, page_shrink,
353 page_goal, badness, penalty, cost, cost < lmt_page_builder_state.least_cost ? "#" : "",
354 moveon ? "yes" : "no", fireup ? "yes" : "no"
355 );
356 tex_end_diagnostic();
357}
358
359static void tex_aux_display_insertion_split_cost(halfword index, scaled height, halfword penalty)
360{
361
362 tex_begin_diagnostic();
363 tex_print_format("[page: split insert %i: height %p, depth %p, penalty %i]",
364 index, height, lmt_packaging_state.best_height_plus_depth, penalty
365 );
366 tex_end_diagnostic();
367}
368
369static halfword tex_aux_page_badness(scaled goal)
370{
371 if (page_total + page_except < goal) {
372 if (page_fistretch || page_filstretch || page_fillstretch || page_filllstretch) {
373 return 0;
374 } else {
375 return tex_badness(goal - page_total, page_stretch);
376 }
377 } else if (page_total + page_except - goal > page_shrink) {
378 return awful_bad;
379 } else {
380 return tex_badness(page_total + page_except - goal, page_shrink);
381 }
382}
383
384static inline halfword tex_aux_page_costs(halfword badness, halfword penalty)
385{
386 if (lmt_page_builder_state.insert_penalties >= infinite_penalty) {
387 return awful_bad;
388 } else if (badness >= awful_bad) {
389 return badness;
390 } else if (penalty <= eject_penalty) {
391 return penalty;
392 } else if (badness < infinite_bad) {
393 return badness + penalty + lmt_page_builder_state.insert_penalties;
394 } else {
395 return deplorable;
396 }
397}
398
399static halfword tex_aux_insert_topskip(halfword height, int contribution)
400{
401 if (lmt_page_builder_state.contents != contribute_nothing) {
402 lmt_page_builder_state.contents = contribution;
403 } else {
404 tex_aux_freeze_page_specs(contribution);
405 }
406 {
407 halfword glue = tex_new_param_glue_node(tex_glue_is_zero(initial_top_skip_par) ? top_skip_code : initial_top_skip_code, top_skip_glue);
408 if (glue_amount(glue) > height) {
409 glue_amount(glue) -= height;
410 } else {
411 glue_amount(glue) = 0;
412 }
413 return glue;
414 }
415}
416
417
421
422static void tex_aux_append_insert(halfword current)
423{
424 halfword index = insert_index(current);
425 halfword location = page_insert_head;
426 halfword multiplier = tex_get_insert_multiplier(index);
427 halfword content = tex_get_insert_content(index);
428 scaled limit = tex_get_insert_limit(index);
429 int slot = 1;
430 if (lmt_page_builder_state.contents == contribute_nothing) {
431 tex_aux_freeze_page_specs(contribute_insert);
432 }
433 while (index >= insert_index(node_next(location))) {
434 location = node_next(location);
435 slot += 1 ;
436 }
437 if (insert_index(location) != index) {
438
459 halfword splitnode = tex_new_node(split_node, normal_split_subtype);
460 scaled advance = 0;
461 halfword distance = lmt_get_insert_distance(index, slot);
462 split_insert_index(splitnode) = index;
463 tex_try_couple_nodes(splitnode, node_next(location));
464 tex_couple_nodes(location, splitnode);
465 location = splitnode;
466 if (! tex_aux_valid_insert_content(content)) {
467 content = tex_aux_delete_box_content(content, "insert", 1);
468 tex_set_insert_content(index, content);
469 };
470 if (content) {
471 box_height(location) = box_total(content);
472 } else {
473 box_height(location) = 0;
474 }
475 split_best_insert(location) = null;
476 if (multiplier == scaling_factor) {
477 advance = box_height(location);
478 } else {
479 advance = tex_x_over_n(box_height(location), scaling_factor) * multiplier;
480 }
481 advance += glue_amount(distance);
482 update_page_goal(index, 0, advance);
483 page_stretched(glue_stretch_order(distance)) += glue_stretch(distance);
484 page_shrink += glue_shrink(distance);
485 if (glue_shrink_order(distance) != normal_glue_order && glue_shrink(distance)) {
486 tex_handle_error(
487 normal_error_type,
488 "Infinite glue shrinkage inserted from \\skip%i",
489 index,
490 "The correction glue for page breaking with insertions must have finite\n"
491 "shrinkability. But you may proceed, since the offensive shrinkability has been\n"
492 "made finite."
493 );
494 }
495 tex_flush_node(distance);
496 }
497
498 if (node_type(location) == split_node && node_subtype(location) == insert_split_subtype) {
499 lmt_page_builder_state.insert_penalties += insert_float_cost(current);
500 } else {
501 scaled delta = page_goal - page_total - page_depth + page_shrink;
502 scaled needed = insert_total_height(current);
503 split_last_insert(location) = current;
504
505 if (multiplier != scaling_factor) {
506
507 needed = tex_x_over_n(needed, scaling_factor) * multiplier;
508 }
509 if ((needed <= 0 || needed <= delta) && (insert_total_height(current) + box_height(location) <= limit)) {
510 update_page_goal(index, insert_total_height(current), needed);
511 box_height(location) += insert_total_height(current);
512 } else {
513
529 scaled height;
530 halfword breaknode, penalty;
531 if (multiplier <= 0) {
532 height = max_dimension;
533 } else {
534 height = page_goal - page_total - page_depth;
535 if (multiplier != scaling_factor) {
536 height = tex_x_over_n(height, multiplier) * scaling_factor;
537 }
538 }
539 if (height > limit - box_height(location)) {
540 height = limit - box_height(location);
541 }
542 breaknode = tex_vert_break(insert_list(current), height, insert_max_depth(current), 0, 0);
543 box_height(location) += lmt_packaging_state.best_height_plus_depth;
544 penalty = breaknode ? (node_type(breaknode) == penalty_node ? penalty_amount(breaknode) : 0) : eject_penalty;
545 if (tracing_pages_par > 0) {
546 tex_aux_display_insertion_split_cost(index, height, penalty);
547 }
548 if (multiplier != scaling_factor) {
549 lmt_packaging_state.best_height_plus_depth = tex_x_over_n(lmt_packaging_state.best_height_plus_depth, scaling_factor) * multiplier;
550 }
551 update_page_goal(index, lmt_packaging_state.best_height_plus_depth, lmt_packaging_state.best_height_plus_depth);
552 node_subtype(location) = insert_split_subtype;
553 split_broken(location) = breaknode;
554 split_broken_insert(location) = current;
555 lmt_page_builder_state.insert_penalties += penalty;
556 }
557 }
558}
559
560static inline int tex_aux_get_penalty_option(halfword current)
561{
562 while (1) {
563 current = node_prev(current);
564 if (current && current != contribute_head) {
565 switch (node_type(current)) {
566 case glue_node:
567 break;
568 case penalty_node:
569 if (penalty_amount(current) >= infinite_penalty) {
570 if (tex_has_penalty_option(current, penalty_option_widowed)) {
571 if (tracing_pages_par > 1) {
572 tex_begin_diagnostic();
573 tex_print_format("[page: widowed]");
574 tex_end_diagnostic();
575 }
576 return penalty_option_widowed;
577 } else if (tex_has_penalty_option(current, penalty_option_clubbed)) {
578 if (tracing_pages_par > 1) {
579 tex_begin_diagnostic();
580 tex_print_format("[page: clubbed]");
581 tex_end_diagnostic();
582 }
583 return penalty_option_clubbed;
584 }
585 }
586 return 0;
587 default:
588 return 0;
589 }
590 } else {
591 return 0;
592 }
593 }
594
595}
596
597static inline int tex_aux_get_last_penalty(halfword current)
598{
599 return node_type(current) == penalty_node
600 ? penalty_options(current) & (penalty_option_widow | penalty_option_club | penalty_option_broken | penalty_option_shaping)
601 : 0;
602}
603
604static void tex_aux_initialize_show_build_node(int callback_id)
605{
606 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->", initialize_show_build_context);
607}
608
609static void tex_aux_step_show_build_node(int callback_id, halfword current)
610{
611 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dNdd->", step_show_build_context,
612 current,
613 page_goal,
614 page_total
615 );
616}
617
618static void tex_aux_check_show_build_node(int callback_id, halfword current, int badness, int costs, int penalty, int *moveon, int *fireup)
619{
620 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dNbbddd->bb", check_show_build_context,
621 current,
622 *moveon,
623 *fireup,
624 badness,
625 costs,
626 penalty,
627 moveon,
628 fireup
629 );
630}
631
632static void tex_aux_skip_show_build_node(int callback_id, halfword current)
633{
634 (void) current;
635 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dN->", skip_show_build_context);
636}
637
638static void tex_aux_move_show_build_node(int callback_id, halfword current)
639{
640 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dNddddb->", move_show_build_context,
641 current,
642 page_last_height,
643 page_last_depth,
644 page_last_stretch,
645 page_last_shrink,
646 (page_last_fistretch || page_last_filstretch || page_last_fillstretch || page_last_filllstretch) ? 1 : 0
647 );
648}
649
650static void tex_aux_fireup_show_build_node(int callback_id, halfword current)
651{
652 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dN->", fireup_show_build_context,
653 current
654 );
655}
656
657static void tex_aux_wrapup_show_build_node(int callback_id)
658{
659 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "d->", wrapup_show_build_context);
660}
661
662static void tex_aux_show_loner_penalty(int callback_id, halfword options, scaled penalty)
663{
664 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "dd->", options, penalty);
665}
666
667static int tex_aux_topskip_restart(halfword current, int where, scaled height, scaled depth, scaled exdepth, int discard, int tracing)
668{
669 if (lmt_page_builder_state.contents < contribute_box) {
670
674 if (discard) {
675 return 2;
676 } else {
677 halfword gluenode = tex_aux_insert_topskip(height, where);
678 tex_attach_attribute_list_copy(gluenode, current);
679 tex_couple_nodes(gluenode, current);
680 tex_couple_nodes(contribute_head, gluenode);
681 if (tracing > 1) {
682 tex_begin_diagnostic();
683 tex_print_format("[page: initialize, topskip at %s]", where == contribute_box ? "box" : "rule");
684 tex_end_diagnostic();
685 }
686 }
687 return 1;
688 } else {
689
690 page_total += page_depth + height;
691 page_depth = depth;
692 page_except -= height;
693 page_except -= depth;
694 if (exdepth > page_except) {
695 page_except = exdepth;
696 }
697 if (page_except < 0) {
698 page_except = 0;
699 }
700 return 0;
701 }
702}
703
704static int tex_aux_migrating_restart(halfword current, int tracing)
705{
706 if (auto_migrating_mode_permitted(auto_migration_mode_par, auto_migrate_post)) {
707 halfword head = box_post_migrated(current);
708 if (head) {
709 halfword tail = tex_tail_of_node_list(head);
710 if (tracing > 1 || tracing_adjusts_par > 1) {
711 tex_begin_diagnostic();
712 tex_print_format("[adjust: post, mvl]");
713 tex_print_node_list(head, "post", show_box_depth_par, show_box_breadth_par);
714 tex_end_diagnostic();
715 }
716 if (node_next(current)) {
717 tex_couple_nodes(tail, node_next(current));
718 } else {
719 contribute_tail = tail;
720 }
721 tex_couple_nodes(current, head);
722 box_post_migrated(current) = null;
723 }
724 }
725 if (auto_migrating_mode_permitted(auto_migration_mode_par, auto_migrate_pre)) {
726 halfword head = box_pre_migrated(current);
727 if (head) {
728 halfword tail = tex_tail_of_node_list(head);
729 if (tracing > 1 || tracing_adjusts_par > 1) {
730 tex_begin_diagnostic();
731 tex_print_format("[adjust: pre, mvl]");
732 tex_print_node_list(head, "pre", show_box_depth_par, show_box_breadth_par);
733 tex_end_diagnostic();
734 }
735 tex_couple_nodes(tail, current);
736 tex_couple_nodes(contribute_head, current);
737
738
739
740 box_pre_migrated(current) = null;
741 return 1;
742 }
743 }
744 return 0;
745}
746
747
753
754static halfword tex_aux_process_boundary(halfword current)
755{
756 halfword penaltynode = tex_new_node(penalty_node, user_penalty_subtype);
757
758 tex_page_boundary_message("processed as penalty", 0);
759 tex_try_couple_nodes(node_prev(current), penaltynode);
760 tex_try_couple_nodes(penaltynode, node_next(current));
761 tex_flush_node(current);
762 penalty_amount(penaltynode) = boundary_data(current);
763 current = penaltynode;
764 node_next(contribute_head) = current;
765 return current;
766}
767
768static void tex_aux_reconsider_goal(halfword current, halfword *badness, halfword *costs, halfword *penalty, int tracing)
769{
770 (void) current;
771 if (*badness >= awful_bad && page_extra_goal_par) {
772 switch (tex_aux_get_penalty_option(lmt_page_builder_state.page_tail)) {
773 case penalty_option_widowed:
774 if (page_total <= (page_goal + page_extra_goal_par)) {
775 halfword extrabadness = tex_aux_page_badness(page_goal + page_extra_goal_par);
776 halfword extracosts = tex_aux_page_costs(extrabadness, *penalty);
777 if (tracing > 0) {
778 tex_begin_diagnostic();
779 tex_print_format(
780 "[page: extra check, total %P, goal %p, extragoal %p, badness %B, costs %i, extrabadness %B, extracosts %i]",
781 page_total, page_stretch, page_filstretch, page_filstretch, page_fillstretch, page_filllstretch, page_shrink,
782 page_goal, page_extra_goal_par,
783 *badness, *costs, extrabadness, extracosts
784 );
785 tex_end_diagnostic();
786 }
787
788 *badness = extrabadness;
789 *costs = extracosts;
790
791 lmt_page_builder_state.last_extra_used = 1;
792 if (tracing > 1) {
793 tex_begin_diagnostic();
794 tex_print_format("[page: widowed]");
795 tex_end_diagnostic();
796 }
797 }
798 break;
799 case penalty_option_clubbed:
800 if (page_total >= (page_goal - page_extra_goal_par)) {
801
802 *penalty = eject_penalty;
803
804 if (tracing > 1) {
805 tex_begin_diagnostic();
806 tex_print_format("[page: clubbed]");
807 tex_end_diagnostic();
808 }
809 }
810 break;
811 }
812 }
813}
814
815static void tex_aux_contribute_glue(halfword current)
816{
817 page_stretched(glue_stretch_order(current)) += glue_stretch(current);
818 page_shrink += glue_shrink(current);
819 if (glue_shrink_order(current) != normal_glue_order && glue_shrink(current)) {
820 tex_handle_error(
821 normal_error_type,
822 "Infinite glue shrinkage found on current page",
823 "The page about to be output contains some infinitely shrinkable glue, e.g.,\n"
824 "'\\vss' or '\\vskip 0pt minus 1fil'. Such glue doesn't belong there; but you can\n"
825 "safely proceed, since the offensive shrinkability has been made finite."
826 );
827 tex_reset_glue_to_zero(current);
828 glue_shrink_order(current) = normal_glue_order;
829 }
830}
831
832
836
837static inline halfword tex_aux_used_penalty(halfword p)
838{
839 if (double_penalty_mode_par && tex_has_penalty_option(p, penalty_option_double)) {
840 tex_add_penalty_option(p, penalty_option_double_used);
841 return penalty_tnuoma(p);
842 } else {
843 tex_remove_penalty_option(p, penalty_option_double_used);
844 return penalty_amount(p);
845 }
846}
847
848static void tex_process_mvl(halfword context, halfword boundary)
849{
850 if (! lmt_page_builder_state.output_active) {
851 lmt_page_filter_callback(context, boundary);
852 }
853 if (node_next(contribute_head) && ! lmt_page_builder_state.output_active) {
854
855 halfword penalty = 0;
856 int callback_id = lmt_callback_defined(show_build_callback);
857 int tracing = tracing_pages_par;
858 if (callback_id) {
859 tex_aux_initialize_show_build_node(callback_id);
860 }
861 do {
862
866 halfword current = node_next(contribute_head);
867 halfword type = node_type(current);
868 quarterword subtype = node_subtype(current);
869 if (callback_id) {
870 tex_aux_step_show_build_node(callback_id, current);
871 }
872 if (lmt_page_builder_state.last_glue != max_halfword) {
873 tex_flush_node(lmt_page_builder_state.last_glue);
874 lmt_page_builder_state.last_glue = max_halfword;
875 }
876 lmt_page_builder_state.last_penalty = 0;
877 lmt_page_builder_state.last_kern = 0;
878 lmt_page_builder_state.last_boundary = 0;
879 lmt_page_builder_state.last_node_type = type;
880 lmt_page_builder_state.last_node_subtype = subtype;
881 lmt_page_builder_state.last_extra_used = 0;
882
904 switch (type) {
905 case hlist_node:
906 case vlist_node:
907 if (tex_aux_migrating_restart(current, tracing)) {
908 continue;
909 } else {
910 switch (tex_aux_topskip_restart(current, contribute_box, box_height(current), box_depth(current), box_exdepth(current), (box_options(current) & box_option_discardable), tracing)) {
911 case 1:
912 continue;
913 case 2:
914
915 box_height(current) = 0;
916 box_depth(current) = 0;
917 continue;
918 default:
919 goto CONTRIBUTE;
920 }
921 }
922 case rule_node:
923 switch (tex_aux_topskip_restart(current, contribute_rule, rule_height(current), rule_depth(current), 0, (rule_options(current) & rule_option_discardable), tracing)) {
924 case 1:
925 continue;
926 case 2:
927
928 rule_height(current) = 0;
929 rule_depth(current) = 0;
930 continue;
931 default:
932 goto CONTRIBUTE;
933 }
934 case boundary_node:
935 if (subtype == page_boundary) {
936 lmt_page_builder_state.last_boundary = boundary_data(current);
937 }
938 if (lmt_page_builder_state.contents < contribute_box) {
939 goto DISCARD;
940 } else if (subtype == page_boundary) {
941 current = tex_aux_process_boundary(current);
942 penalty = 0;
943 break;
944 } else {
945 goto DISCARD;
946 }
947 case whatsit_node:
948 goto CONTRIBUTE;
949 case glue_node:
950 lmt_page_builder_state.last_glue = tex_new_glue_node(current, subtype);
951 if (lmt_page_builder_state.contents < contribute_box) {
952 goto DISCARD;
953 } else if (precedes_break(lmt_page_builder_state.page_tail)) {
954 penalty = 0;
955 break;
956 } else {
957 goto UPDATEHEIGHTS;
958 }
959 case kern_node:
960 lmt_page_builder_state.last_kern = kern_amount(current);
961 if (lmt_page_builder_state.contents < contribute_box) {
962 goto DISCARD;
963 } else if (! node_next(current)) {
964 return;
965 } else if (node_type(node_next(current)) == glue_node) {
966 penalty = 0;
967 break;
968 } else {
969 goto UPDATEHEIGHTS;
970 }
971 case penalty_node:
972 lmt_page_builder_state.last_penalty = penalty_amount(current);
973 if (lmt_page_builder_state.contents < contribute_box) {
974 goto DISCARD;
975 } else {
976 penalty = tex_aux_used_penalty(current);
977 break;
978 }
979 case mark_node:
980 goto CONTRIBUTE;
981 case insert_node:
982 tex_aux_append_insert(current);
983 goto CONTRIBUTE;
984 default:
985 tex_handle_error(
986
987 succumb_error_type,
988 "Invalid %N node in pagebuilder",
989 current,
990 NULL
991 );
992 goto DISCARD;
993
994 break;
995 }
996
1001 if (tracing > 1) {
1002 tex_begin_diagnostic();
1003 tex_print_format("[page: compute: %N, %d, penalty %i]", current, current, penalty);
1004 tex_end_diagnostic();
1005 }
1006 if (penalty < infinite_penalty) {
1007
1011 halfword badness = tex_aux_page_badness(page_goal);
1012 halfword costs = tex_aux_page_costs(badness, penalty);
1013 lmt_page_builder_state.last_extra_used = 0;
1014 if (tracing > 1) {
1015 tex_begin_diagnostic();
1016 tex_print_format("[page: calculate, %N, %d, total %P, goal %p, badness %B, costs %i]",
1017 current, current,
1018 page_total, page_stretch, page_fistretch, page_filstretch, page_fillstretch, page_filllstretch, page_shrink,
1019 page_goal,
1020 badness, costs
1021 );
1022 tex_end_diagnostic();
1023 }
1024 tex_aux_reconsider_goal(current, &badness, &costs, &penalty, tracing);
1025 {
1026 int moveon = costs <= lmt_page_builder_state.least_cost;
1027 int fireup = costs == awful_bad || penalty <= eject_penalty;
1028 if (callback_id) {
1029 tex_aux_check_show_build_node(callback_id, current, badness, lmt_page_builder_state.last_penalty, costs, &moveon, &fireup);
1030 }
1031 if (tracing > 0) {
1032 tex_aux_display_page_break_cost(badness, penalty, costs, moveon, fireup);
1033 }
1034 if (moveon) {
1035 halfword insert = node_next(page_insert_head);
1036 lmt_page_builder_state.best_break = current;
1037 lmt_page_builder_state.best_size = page_goal;
1038 lmt_page_builder_state.insert_penalties = 0;
1039 lmt_page_builder_state.least_cost = costs;
1040 while (insert != page_insert_head) {
1041 split_best_insert(insert) = split_last_insert(insert);
1042 insert = node_next(insert);
1043 }
1044 tex_aux_save_best_page_specs();
1045 if (callback_id) {
1046 tex_aux_move_show_build_node(callback_id, current);
1047 }
1048 }
1049 if (fireup) {
1050 if (tracing > 1) {
1051 tex_begin_diagnostic();
1052 tex_print_format("[page: fireup: %N, %d]", current, current);
1053 tex_end_diagnostic();
1054 }
1055 if (callback_id) {
1056 tex_aux_fireup_show_build_node(callback_id, current);
1057 }
1058
1059 tex_aux_fire_up(current);
1060 if (lmt_page_builder_state.output_active) {
1061
1062 if (callback_id) {
1063 tex_aux_wrapup_show_build_node(callback_id);
1064 }
1065 return;
1066 } else {
1067
1068 continue;
1069 }
1070 }
1071 }
1072 } else {
1073 if (callback_id) {
1074 tex_aux_skip_show_build_node(callback_id, current);
1075 }
1076 }
1077 UPDATEHEIGHTS:
1078
1082 if (tracing > 1) {
1083 tex_begin_diagnostic();
1084 tex_print_format("[page: update, %N, %d]", current, current);
1085 tex_end_diagnostic();
1086 }
1087 switch(node_type(current)) {
1088 case kern_node:
1089 if (page_except) {
1090 page_except -= kern_amount(current);
1091 if (page_except < 0) {
1092 page_except = 0;
1093 }
1094 }
1095 page_total += page_depth + kern_amount(current);
1096 page_depth = 0;
1097 goto APPEND;
1098 case glue_node:
1099 if (page_except) {
1100 glue_stretch(current) = 0;
1101 page_except -= glue_amount(current);
1102 if (page_except < 0) {
1103 page_except = 0;
1104 }
1105 }
1106 tex_aux_contribute_glue(current);
1107 page_total += page_depth + glue_amount(current);
1108 page_depth = 0;
1109 goto APPEND;
1110 }
1111 CONTRIBUTE:
1112
1116 if (tracing > 1) {
1117 tex_begin_diagnostic();
1118 tex_print_format("[page: contribute, %N, %d]", current, current);
1119 tex_end_diagnostic();
1120 }
1121 if (page_depth > lmt_page_builder_state.max_depth) {
1122 page_total += page_depth - lmt_page_builder_state.max_depth;
1123 page_depth = lmt_page_builder_state.max_depth;
1124 }
1125 APPEND:
1126 if (tracing > 1) {
1127 tex_begin_diagnostic();
1128 tex_print_format("[page: append, %N, %d]", current, current);
1129 tex_end_diagnostic();
1130 }
1131
1132 tex_couple_nodes(lmt_page_builder_state.page_tail, current);
1133 lmt_page_builder_state.page_tail = current;
1134 tex_try_couple_nodes(contribute_head, node_next(current));
1135 node_next(current) = null;
1136 continue;
1137 DISCARD:
1138 if (tracing > 1) {
1139 tex_begin_diagnostic();
1140 tex_print_format("[page: discard, %N, %d]", current, current);
1141 tex_end_diagnostic();
1142 }
1143
1144 tex_try_couple_nodes(contribute_head, node_next(current));
1145 node_next(current) = null;
1146 if (saving_vdiscards_par > 0) {
1147 if (lmt_packaging_state.page_discards_head) {
1148 tex_couple_nodes(lmt_packaging_state.page_discards_tail, current);
1149 } else {
1150 lmt_packaging_state.page_discards_head = current;
1151 }
1152 lmt_packaging_state.page_discards_tail = current;
1153 } else {
1154 tex_flush_node_list(current);
1155 }
1156 } while (node_next(contribute_head));
1157
1158 contribute_tail = contribute_head;
1159 }
1160}
1161
1162void tex_build_page(halfword context, halfword boundary)
1163{
1164 if (! tex_appended_mvl(context, boundary)) {
1165 tex_process_mvl(context, boundary);
1166 }
1167}
1168
1169
1185
1186static void tex_aux_fire_up(halfword c)
1187{
1188
1189 halfword current, previous, lastinsert;
1190
1191 if (node_type(lmt_page_builder_state.best_break) == penalty_node) {
1192 update_tex_output_penalty(penalty_amount(lmt_page_builder_state.best_break));
1193 if (tracing_loners_par) {
1194 int callback_id = lmt_callback_defined(show_loners_callback);
1195
1196 halfword n = tex_aux_get_last_penalty(lmt_page_builder_state.best_break);
1197 if (n) {
1198 halfword penalty = tex_aux_used_penalty(lmt_page_builder_state.best_break);
1199 if (callback_id) {
1200 tex_aux_show_loner_penalty(callback_id, penalty_options(lmt_page_builder_state.best_break), penalty);
1201 } else {
1202 unsigned char state[5] = { '.', '.', '.', '.', '\0' };
1203 if (tex_has_penalty_option(lmt_page_builder_state.best_break, penalty_option_widow )) { state[0] = 'W'; }
1204 if (tex_has_penalty_option(lmt_page_builder_state.best_break, penalty_option_club )) { state[1] = 'C'; }
1205 if (tex_has_penalty_option(lmt_page_builder_state.best_break, penalty_option_broken )) { state[2] = 'B'; }
1206 if (tex_has_penalty_option(lmt_page_builder_state.best_break, penalty_option_shaping)) { state[3] = 'S'; }
1207 tex_begin_diagnostic();
1208 tex_print_format("[page: loner: %s penalty %i]", state, penalty);
1209 tex_end_diagnostic();
1210 }
1211 }
1212 }
1213 penalty_amount(lmt_page_builder_state.best_break) = infinite_penalty;
1214 penalty_tnuoma(lmt_page_builder_state.best_break) = infinite_penalty;
1215 } else {
1216 update_tex_output_penalty(infinite_penalty);
1217 }
1218 tex_update_top_marks();
1219
1228 if (c == lmt_page_builder_state.best_break) {
1229
1230 lmt_page_builder_state.best_break = null;
1231 }
1232
1233 if (box_register(output_box_par)) {
1234 if (! ((no_output_box_error_par > 2) || (no_output_box_error_par & 1))) {
1235 tex_handle_error(
1236 normal_error_type,
1237 "\\box%i is not void",
1238 output_box_par,
1239 "You shouldn't use \\box\\outputbox except in \\output routines. Proceed, and I'll\n"
1240 "discard its present contents."
1241 );
1242 }
1243 box_register(output_box_par) = tex_aux_delete_box_content(box_register(output_box_par), "output", 1);
1244 }
1245
1254
1255 {
1256 halfword save_split_top_skip = split_top_skip_par;
1257 lmt_page_builder_state.insert_penalties = 0;
1258 if (holding_inserts_par <= 0) {
1259
1290 halfword insert = node_next(page_insert_head);
1291 while (insert != page_insert_head) {
1292 if (split_best_insert(insert)) {
1293 halfword index = insert_index(insert);
1294 halfword content = tex_get_insert_content(index);
1295 if (! tex_aux_valid_insert_content(content)) {
1296 content = tex_aux_delete_box_content(content, "insert", 2);
1297 }
1298 if (! content) {
1299
1304 content = tex_new_null_box_node(vlist_node, insert_result_list);
1305 tex_set_insert_content(index, content);
1306 }
1307
1312 split_last_insert(insert) = tex_tail_of_node_list(insert_first_box(content));
1313 }
1314 insert = node_next(insert);
1315 }
1316 }
1317 previous = page_head;
1318 current = node_next(previous);
1319 lastinsert = hold_head;
1320 node_next(lastinsert) = null;
1321 while (current != lmt_page_builder_state.best_break) {
1322 switch (node_type(current)) {
1323 case insert_node:
1324 if (holding_inserts_par <= 0) {
1325
1334
1335 int wait = 0;
1336 halfword insert = node_next(page_insert_head);
1337 while (insert_index(insert) != insert_index(current)) {
1338 insert = node_next(insert);
1339 }
1340 if (split_best_insert(insert)) {
1341 halfword split = split_last_insert(insert);
1342 tex_try_couple_nodes(split, insert_list(current));
1343 if (split_best_insert(insert) == current) {
1344
1348 if (node_type(insert) == split_node && node_subtype(insert) == insert_split_subtype && (split_broken_insert(insert) == current) && split_broken(insert)) {
1349 while (node_next(split) != split_broken(insert)) {
1350 split = node_next(split);
1351 }
1352 node_next(split) = null;
1353 split_top_skip_par = insert_split_top(current);
1354 insert_list(current) = tex_prune_page_top(split_broken(insert), 0);
1355 if (insert_list(current)) {
1356
1360 halfword list = insert_list(current);
1361 halfword result = tex_vpack(list, 0, packing_additional, max_dimension, direction_unknown, holding_none_option, NULL);
1362 insert_total_height(current) = box_total(result);
1363 box_list(result) = null;
1364 tex_flush_node(result);
1365 wait = 1;
1366 }
1367 }
1368 split_best_insert(insert) = null;
1369 {
1370
1374 halfword index = insert_index(insert);
1375 halfword content = tex_get_insert_content(index);
1376 halfword list = box_list(content);
1377 halfword result = tex_vpack(list, 0, packing_additional, max_dimension, dir_lefttoright, holding_none_option, NULL);
1378 tex_set_insert_content(index, result);
1379 box_list(content) = null;
1380 tex_flush_node(content);
1381 }
1382 } else {
1383 split_last_insert(insert) = tex_tail_of_node_list(split);
1384 }
1385 } else {
1386 wait = 1;
1387 }
1388
1392 tex_try_couple_nodes(previous, node_next(current));
1393 node_next(current) = null;
1394 if (wait) {
1395 tex_couple_nodes(lastinsert, current);
1396 lastinsert = current;
1397 ++lmt_page_builder_state.insert_penalties;
1398 } else {
1399 insert_list(current) = null;
1400 tex_flush_node(current);
1401 }
1402 current = previous;
1403 }
1404 break;
1405 case mark_node:
1406 tex_update_first_and_bot_mark(current);
1407 break;
1408 }
1409 previous = current;
1410 current = node_next(current);
1411 }
1412 split_top_skip_par = save_split_top_skip;
1413 }
1414
1427 if (current) {
1428 if (! node_next(contribute_head)) {
1429 contribute_tail = lmt_page_builder_state.page_tail;
1430 }
1431 tex_couple_nodes(lmt_page_builder_state.page_tail, node_next(contribute_head));
1432 tex_couple_nodes(contribute_head, current);
1433 node_next(previous) = null;
1434 }
1435
1436 {
1437 halfword save_vbadness = vbadness_par;
1438 halfword save_vfuzz = vfuzz_par;
1439 vbadness_par = infinite_bad;
1440 vfuzz_par = max_dimension;
1441 tex_show_marks();
1442
1443 box_register(output_box_par) = tex_filtered_vpack(node_next(page_head), lmt_page_builder_state.best_size, packing_exactly, lmt_page_builder_state.max_depth, output_group, dir_lefttoright, 0, 0, 0, holding_none_option, &lmt_page_builder_state.excess);
1444
1445
1446
1447
1448 vbadness_par = save_vbadness;
1449 vfuzz_par = save_vfuzz;
1450 }
1451 if (lmt_page_builder_state.last_glue != max_halfword) {
1452 tex_flush_node(lmt_page_builder_state.last_glue);
1453 lmt_page_builder_state.last_glue = max_halfword;
1454 }
1455
1456 tex_aux_start_new_page();
1457
1458 if (lastinsert != hold_head) {
1459 node_next(page_head) = node_next(hold_head);
1460 lmt_page_builder_state.page_tail = lastinsert;
1461 }
1462
1463 {
1464 halfword r = node_next(page_insert_head);
1465 while (r != page_insert_head) {
1466 lastinsert = node_next(r);
1467 tex_flush_node(r);
1468 r = lastinsert;
1469 }
1470 }
1471 node_next(page_insert_head) = page_insert_head;
1472 tex_update_first_marks();
1473 if (output_routine_par) {
1474 if (lmt_page_builder_state.dead_cycles >= max_dead_cycles_par) {
1475
1476 tex_handle_error(
1477 normal_error_type,
1478 "Output loop --- %i consecutive dead cycles",
1479 lmt_page_builder_state.dead_cycles,
1480 "I've concluded that your \\output is awry; it never does a \\shipout, so I'm\n"
1481 "shipping \\box\\outputbox out myself. Next time increase \\maxdeadcycles if you\n"
1482 "want me to be more patient!"
1483 );
1484 } else {
1485
1486 lmt_page_builder_state.output_active = 1;
1487 ++lmt_page_builder_state.dead_cycles;
1488 tex_push_nest();
1489 cur_list.mode = internal_vmode;
1490 cur_list.prev_depth = ignore_depth_criterion_par;
1491 cur_list.mode_line = -lmt_input_state.input_line;
1492 tex_begin_token_list(output_routine_par, output_text);
1493 tex_new_save_level(output_group);
1494 tex_normal_paragraph(output_par_context);
1495 tex_scan_left_brace();
1496 return;
1497 }
1498 }
1499
1504
1505
1506
1507 if (node_next(page_head)) {
1508 if (node_next(contribute_head)) {
1509 node_next(lmt_page_builder_state.page_tail) = node_next(contribute_head);
1510 }
1511 else {
1512 contribute_tail = lmt_page_builder_state.page_tail;
1513 }
1514 node_next(contribute_head) = node_next(page_head);
1515 node_next(page_head) = null;
1516 lmt_page_builder_state.page_tail = page_head;
1517 }
1518 if (lmt_packaging_state.page_discards_head) {
1519 tex_flush_node_list(lmt_packaging_state.page_discards_head);
1520 lmt_packaging_state.page_discards_head = null;
1521 }
1522 if (box_register(output_box_par)) {
1523 tex_flush_node_list(box_register(output_box_par));
1524 box_register(output_box_par) = null;
1525 }
1526}
1527
1528
1534
1535void tex_resume_after_output(void)
1536{
1537 if (lmt_input_state.cur_input.loc || ((lmt_input_state.cur_input.token_type != output_text) && (lmt_input_state.cur_input.token_type != backed_up_text))) {
1538
1539 tex_fatal_error("Unbalanced output routine");
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551 }
1552
1553 tex_end_token_list();
1554 tex_end_paragraph(bottom_level_group, output_par_context);
1555 tex_unsave();
1556 lmt_page_builder_state.output_active = 0;
1557 lmt_page_builder_state.insert_penalties = 0;
1558
1559 if (box_register(output_box_par)) {
1560 if (! ((no_output_box_error_par > 2) || (no_output_box_error_par & 2))) {
1561 tex_handle_error(
1562 normal_error_type,
1563 "Output routine didn't use all of \\box%i", output_box_par,
1564 "Your \\output commands should empty \\box\\outputbox, e.g., by saying\n"
1565 "'\\shipout\\box\\outputbox'. Proceed; I'll discard its present contents."
1566 );
1567 }
1568 box_register(output_box_par) = tex_aux_delete_box_content(box_register(output_box_par), "output", 1);
1569 }
1570 if (lmt_insert_state.storing == insert_storage_delay && tex_insert_stored()) {
1571 if (tracing_inserts_par > 0) {
1572 tex_print_levels();
1573 tex_print_str(lmt_insert_state.head ? "<delaying inserts>" : "<no inserts to delay>");
1574 if (lmt_insert_state.head && tracing_inserts_par > 1) {
1575 tex_show_node_list(lmt_insert_state.head, max_integer, max_integer);
1576 }
1577 }
1578 tex_try_couple_nodes(lmt_page_builder_state.page_tail, lmt_insert_state.head);
1579 lmt_page_builder_state.page_tail = lmt_insert_state.tail;
1580 lmt_insert_state.head = null;
1581 lmt_insert_state.tail = null;
1582 }
1583 if (cur_list.tail != cur_list.head) {
1584
1585 tex_try_couple_nodes(lmt_page_builder_state.page_tail, node_next(cur_list.head));
1586 lmt_page_builder_state.page_tail = cur_list.tail;
1587 }
1588 if (node_next(page_head)) {
1589
1590 if (! node_next(contribute_head)) {
1591 contribute_tail = lmt_page_builder_state.page_tail;
1592 }
1593 tex_try_couple_nodes(lmt_page_builder_state.page_tail, node_next(contribute_head));
1594 tex_try_couple_nodes(contribute_head, node_next(page_head));
1595 node_next(page_head) = null;
1596 lmt_page_builder_state.page_tail = page_head;
1597 }
1598 if (lmt_insert_state.storing == insert_storage_inject) {
1599 halfword h = node_next(contribute_head);
1600 while (h) {
1601 halfword n = node_next(h);
1602 if (node_type(h) == insert_node) {
1603 tex_try_couple_nodes(node_prev(h), n);
1604 tex_insert_restore(h);
1605 }
1606 h = n;
1607 }
1608 if (tracing_inserts_par > 0) {
1609 tex_print_levels();
1610 tex_print_str(lmt_insert_state.head ? "<storing inserts>" : "<no inserts to store>");
1611 if (lmt_insert_state.head && tracing_inserts_par > 1) {
1612 tex_show_node_list(lmt_insert_state.head, max_integer, max_integer);
1613 }
1614 }
1615 }
1616 lmt_insert_state.storing = insert_storage_ignore;
1617 tex_flush_node_list(lmt_packaging_state.page_discards_head);
1618 lmt_packaging_state.page_discards_head = null;
1619 tex_pop_nest();
1620 tex_build_page(after_output_page_context, 0);
1621}
1622 |