summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/tex/packaging.w
diff options
context:
space:
mode:
authorLuigi Scarso <luigi.scarso@gmail.com>2018-09-05 21:57:30 +0000
committerLuigi Scarso <luigi.scarso@gmail.com>2018-09-05 21:57:30 +0000
commitecd1605a23ef54d2a4a69e1a361172d350e03b3b (patch)
tree8ea1d9745c24dbc5e755f13d801fa01e88944650 /Build/source/texk/web2c/luatexdir/tex/packaging.w
parent04563248956e7059aad4fc4f6bf7da18562f7b8c (diff)
luatex: correct automake file for pplib; replaced cweb files with c files.
git-svn-id: svn://tug.org/texlive/trunk@48594 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/tex/packaging.w')
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/packaging.w2170
1 files changed, 0 insertions, 2170 deletions
diff --git a/Build/source/texk/web2c/luatexdir/tex/packaging.w b/Build/source/texk/web2c/luatexdir/tex/packaging.w
deleted file mode 100644
index f094a0d9665..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/packaging.w
+++ /dev/null
@@ -1,2170 +0,0 @@
-% packaging.w
-%
-% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-#include "ptexlib.h"
-
-@ We're essentially done with the parts of \TeX\ that are concerned with the
-input (|get_next|) and the output (|ship_out|). So it's time to get heavily into
-the remaining part, which does the real work of typesetting.
-
-After lists are constructed, \TeX\ wraps them up and puts them into boxes. Two
-major subroutines are given the responsibility for this task: |hpack| applies to
-horizontal lists (hlists) and |vpack| applies to vertical lists (vlists). The
-main duty of |hpack| and |vpack| is to compute the dimensions of the resulting
-boxes, and to adjust the glue if one of those dimensions is pre-specified. The
-computed sizes normally enclose all of the material inside the new box; but some
-items may stick out if negative glue is used, if the box is overfull, or if a
-\.{\\vbox} includes other boxes that have been shifted left.
-
-The subroutine call |hpack(p,w,m)| returns a pointer to an |hlist_node| for a box
-containing the hlist that starts at |p|. Parameter |w| specifies a width; and
-parameter |m| is either `|exactly|' or `|additional|'. Thus, |hpack(p,w,exactly)|
-produces a box whose width is exactly |w|, while |hpack(p,w,additional)| yields a
-box whose width is the natural width plus |w|. It is convenient to define a macro
-called `|natural|' to cover the most common case, so that we can say
-|hpack(p,natural)| to get a box that has the natural width of list |p|.
-
-Similarly, |vpack(p,w,m)| returns a pointer to a |vlist_node| for a box
-containing the vlist that starts at |p|. In this case |w| represents a height
-instead of a width; the parameter |m| is interpreted as in |hpack|.
-
-@ The parameters to |hpack| and |vpack| correspond to \TeX's primitives like
-`\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note that
-`\.{\\hbox}' with no dimension following it is equivalent to `\.{\\hbox}
-\.{spread} \.{0pt}'. The |scan_spec| subroutine scans such constructions in the
-user's input, including the mandatory left brace that follows them, and it puts
-the specification onto |save_stack| so that the desired box can later be obtained
-by executing the following code: $$\vbox{\halign{#\hfil\cr
-|save_ptr:=save_ptr-1;|\cr |hpack(p,saved_value(0),saved_level(0)).|\cr}}$$
-
-@c
-/*
- void scan_spec(group_code c)
- {
- int spec_code;
- if (scan_keyword("to")) {
- spec_code = exactly;
- scan_normal_dimen();
- } else if (scan_keyword("spread")) {
- spec_code = additional;
- scan_normal_dimen();
- } else {
- spec_code = additional;
- cur_val = 0;
- }
- set_saved_record(0, saved_boxspec, spec_code, cur_val);
- save_ptr++;
- new_save_level(c);
- scan_left_brace();
- }
-*/
-
-void scan_spec(group_code c)
-{ /* scans a box specification and left brace */
- int spec_code;
- boolean done = false ;
- do {
- get_x_token();
- } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
- if (cur_cmd == left_brace_cmd) {
- spec_code = additional;
- cur_val = 0;
- done = true;
- } else {
- /* todo: attr */
- back_input();
- if (scan_keyword("to")) {
- spec_code = exactly;
- scan_normal_dimen();
- } else if (scan_keyword("spread")) {
- spec_code = additional;
- scan_normal_dimen();
- } else {
- spec_code = additional;
- cur_val = 0;
- }
- }
- set_saved_record(0, saved_boxspec, spec_code, cur_val);
- save_ptr++;
- new_save_level(c);
- if (!done) {
- scan_left_brace();
- }
-}
-
-@ When scanning, special care is necessary to ensure that the special
-|save_stack| codes are placed just below the new group code, because scanning can
-change |save_stack| when \.{\\csname} appears.
-
-This coincides with the text on |dir| and |attr| keywords, as these are exaclty
-the uses of \.{\\hbox}, \.{\\vbox}, and \.{\\vtop} in the input stream (the
-others are \.{\\vcenter}, \.{\\valign}, and \.{\\halign}).
-
-@c
-/*
- void scan_full_spec(group_code c, int spec_direction)
- {
- int s;
- int i;
- int v;
- int spec_code;
- halfword attr_list;
- if (attr_list_cache == cache_disabled)
- update_attribute_cache();
- attr_list = attr_list_cache;
- s = saved_value(0);
- CONTINUE:
- while (cur_cmd == relax_cmd || cur_cmd == spacer_cmd) {
- get_x_token();
- if (cur_cmd != relax_cmd && cur_cmd != spacer_cmd)
- back_input();
- }
- if (scan_keyword("attr")) {
- scan_register_num();
- i = cur_val;
- scan_optional_equals();
- scan_int();
- v = cur_val;
- if ((attr_list != null) && (attr_list == attr_list_cache)) {
- attr_list = copy_attribute_list(attr_list_cache);
- add_node_attr_ref(attr_list);
- }
- attr_list = do_set_attribute(attr_list, i, v);
- goto CONTINUE;
- }
- if (scan_keyword("dir")) {
- scan_direction();
- spec_direction = cur_val;
- goto CONTINUE;
- }
- if (attr_list == attr_list_cache) {
- add_node_attr_ref(attr_list);
- }
- if (scan_keyword("to")) {
- spec_code = exactly;
- } else if (scan_keyword("spread")) {
- spec_code = additional;
- } else {
- spec_code = additional;
- cur_val = 0;
- goto FOUND;
- }
- scan_normal_dimen();
- FOUND:
- set_saved_record(0, saved_boxcontext, 0, s);
- set_saved_record(1, saved_boxspec, spec_code, cur_val);
- if (spec_direction != -1) {
- set_saved_record(2, saved_boxdir, spec_direction, text_dir_ptr);
- text_dir_ptr = new_dir(spec_direction);
- } else {
- set_saved_record(2, saved_boxdir, spec_direction, null);
- }
- set_saved_record(3, saved_boxattr, 0, attr_list);
- save_ptr += 4;
- new_save_level(c);
- scan_left_brace();
- eq_word_define(int_base + body_direction_code, spec_direction);
- eq_word_define(int_base + par_direction_code, spec_direction);
- eq_word_define(int_base + text_direction_code, spec_direction);
- }
-*/
-
-/* scans a box specification and left brace */
-
-void scan_full_spec(group_code c, int spec_direction, int just_pack)
-{
- int s, i, v, spec_code;
- boolean done = false ;
- halfword attr_list;
- boolean attr_done = false ;
- if (attr_list_cache == cache_disabled)
- update_attribute_cache();
- attr_list = attr_list_cache;
- s = saved_value(0); /* the box context */
- do {
- get_x_token();
- } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
- if (cur_cmd == left_brace_cmd) {
- goto QUICK;
- } else {
- back_input();
- goto KEYWORDS;
- }
- CONTINUE:
- while (cur_cmd == relax_cmd || cur_cmd == spacer_cmd) {
- get_x_token();
- if (cur_cmd == left_brace_cmd) {
- goto QUICK;
- } else if (cur_cmd != relax_cmd && cur_cmd != spacer_cmd) {
- back_input();
- break;
- }
- }
- KEYWORDS:
- if (scan_keyword("attr")) {
- scan_register_num();
- i = cur_val;
- scan_optional_equals();
- scan_int();
- v = cur_val;
- if (! attr_done) {
- attr_list = copy_attribute_list(attr_list_cache);
- attr_done = true;
- }
- attr_list = do_set_attribute(attr_list, i, v);
- goto CONTINUE;
- }
- if (scan_keyword("dir")) {
- scan_direction();
- spec_direction = cur_val;
- goto CONTINUE;
- }
- if (scan_keyword("to")) {
- spec_code = exactly;
- } else if (scan_keyword("spread")) {
- spec_code = additional;
- } else {
- spec_code = additional;
- cur_val = 0;
- goto FOUND;
- }
- scan_normal_dimen();
- goto FOUND;
- QUICK:
- spec_code = additional;
- cur_val = 0;
- done = true;
- FOUND:
- add_node_attr_ref(attr_list);
- set_saved_record(0, saved_boxcontext, 0, s);
- set_saved_record(1, saved_boxspec, spec_code, cur_val);
- /* DIR: Adjust |text_dir_ptr| for |scan_spec| */
- if (spec_direction != -1) {
- set_saved_record(2, saved_boxdir, spec_direction, text_dir_ptr);
- text_dir_ptr = new_dir(spec_direction);
- } else {
- set_saved_record(2, saved_boxdir, spec_direction, null);
- }
- set_saved_record(3, saved_boxattr, 0, attr_list);
- set_saved_record(4, saved_boxpack, 0, just_pack);
- save_ptr += 5;
- new_save_level(c);
- if (! done) {
- scan_left_brace();
- }
- /* no gain: if (body_direction_par != spec_direction) etc */
- eq_word_define(int_base + body_direction_code, spec_direction);
- eq_word_define(int_base + par_direction_code, spec_direction);
- eq_word_define(int_base + text_direction_code, spec_direction);
-}
-
-
-@ To figure out the glue setting, |hpack| and |vpack| determine how much
-stretchability and shrinkability are present, considering all four orders of
-infinity. The highest order of infinity that has a nonzero coefficient is then
-used as if no other orders were present.
-
-For example, suppose that the given list contains six glue nodes with the
-respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill. Then the
-total is essentially 2fil; and if a total additional space of 6pt is to be
-achieved by stretching, the actual amounts of stretch will be 0pt, 0pt, 15pt,
-0pt, $-9$pt, and 0pt, since only `fil' glue will be considered. (The `fill' glue
-is therefore not really stretching infinitely with respect to `fil'; nobody would
-actually want that to happen.)
-
-The arrays |total_stretch| and |total_shrink| are used to determine how much glue
-of each kind is present. A global variable |last_badness| is used to implement
-\.{\\badness}.
-
-@c
-scaled total_stretch[5];
-scaled total_shrink[5]; /* glue found by |hpack| or |vpack| */
-int last_badness; /* badness of the most recently packaged box */
-
-@ If the global variable |adjust_tail| is non-null, the |hpack| routine also
-removes all occurrences of |ins_node|, |mark_node|, and |adjust_node| items and
-appends the resulting material onto the list that ends at location |adjust_tail|.
-
-@c
-halfword adjust_tail; /* tail of adjustment list */
-
-
-@ Materials in \.{\\vadjust} used with \.{pre} keyword will be appended to
-|pre_adjust_tail| instead of |adjust_tail|.
-
-@c
-halfword pre_adjust_tail;
-
-halfword last_leftmost_char;
-halfword last_rightmost_char;
-
-halfword next_char_p; /* pointer to the next char of an implicit kern */
-halfword prev_char_p; /* pointer to the previous char of an implicit kern */
-
-@ This procedure is called repeatedly from inside the line break algorithm.
-@c
-void set_prev_char_p(halfword p)
-{
- prev_char_p = p;
-}
-
-/*
- the kern stretch / shrink code was (or had become) rather weird ... the width field
- is set, and then used in a second calculation, repeatedly, so why is that ... maybe some
- some weird left-over ... anyway, the values are so small that in practice they are not
- significant at all when the backend sees them because a few hundred sp positive or
- negative are just noise there (so adjustlevel 3 has hardly any consequence for the
- result but is more efficient)
-*/
-
-
-@ @c
-scaled char_stretch(halfword p)
-{
- internal_font_number f = font(p);
- int m = font_max_stretch(f);
- if (m > 0) {
- int c = character(p);
- int ef = get_ef_code(f, c);
- if (ef > 0) {
- scaled dw = calc_char_width(f, c, m) - char_width(f, c) - x_advance(p);
- if (dw > 0) {
- return round_xn_over_d(dw, ef, 1000);
- }
- }
- }
- return 0;
-}
-
-@ @c
-scaled char_shrink(halfword p)
-{
- internal_font_number f = font(p);
- int m = font_max_shrink(f);
- if (m > 0) {
- int c = character(p);
- int ef = get_ef_code(f, c);
- if (ef > 0) {
- scaled dw = char_width(f, c) + x_advance(p) - calc_char_width(f, c, -m);
- if (dw > 0) {
- return round_xn_over_d(dw, ef, 1000);
- }
- }
- }
- return 0;
-}
-
-@ @c
-/*
-scaled kern_stretch(halfword p)
-{
- halfword l, r;
- scaled d;
- int m;
- if ((prev_char_p == null) || (vlink(prev_char_p) != p) || (vlink(p) == null))
- return 0;
- l = prev_char_p;
- // we need a left char
- if (!is_char_node(l))
- return 0;
- r = vlink(p);
- // and a right char
- if (!is_char_node(r))
- return 0;
- // and a reason to kern
- if ((font(l) != font(r)) || (font_max_stretch(font(l)) == 0))
- return 0;
- m = font_max_stretch(font(l));
- d = get_kern(font(l), character(l), character(r)); // real kern, so what is width(p) then; the messed up one
- d = round_xn_over_d(d, 1000 + m, 1000);
- return round_xn_over_d(d - width(p), get_ef_code(font(l), character(l)), 1000);
-}
-*/
-
-scaled kern_stretch(halfword p)
-{
- int m;
- scaled d, e, x;
- scaled w = width(p) ;
- halfword l;
- halfword r;
- if (w == 0) {
- /* why bother about zero kerns */
- return 0;
- }
- l = prev_char_p ;
- if ((l == null) || (vlink(l) != p)) {
- /* we only care about kerns following a char*/
- return 0;
- }
- r = vlink(p);
- if (r == null) {
- /* we only care about kerns between a char and something else */
- }
- if (!(is_char_node(l) && is_char_node(r))) {
- /* we want two chars (but but don't care about the fonts) */
- return 0;
- }
- /* we use the old logic, kind of, but average the ef as we might depend on proper overlap */
- m = (font_max_stretch(font(l)) + font_max_stretch(font(r)))/2;
- if (m == 0) {
- /* nothing to kern */
- return 0;
- }
- d = round_xn_over_d(w, 1000 + m, 1000);
- /* we use the old logic, kind of, but average the ef as we might depend on proper overlap */
- e = (get_ef_code(font(l), character(l)) + get_ef_code(font(r), character(r)))/2 ;
- if (e == 1000) {
- x = d - w;
- } else {
- x = round_xn_over_d(d - w, e, 1000);
- }
- /*
- printf("STRETCH w=%i s=%i x=%i\n",w,e+m,x);
- */
- return x;
-}
-
-@ @c
-/*
-scaled kern_shrink(halfword p)
-{
- halfword l, r;
- scaled d;
- int m;
- if ((prev_char_p == null) || (vlink(prev_char_p) != p) || (vlink(p) == null))
- return 0;
- l = prev_char_p;
- // we need a left char
- if (!is_char_node(l))
- return 0;
- r = vlink(p);
- // and a right char
- if (!is_char_node(r))
- return 0;
- // and a reason to kern
- if ((font(l) != font(r)) || (font_max_shrink(font(l)) == 0))
- return 0;
- m = font_max_shrink(font(l));
- d = get_kern(font(l), character(l), character(r)); // real kern, so what is width(p) then; the messed up one
- d = round_xn_over_d(d, 1000 - m, 1000);
- return round_xn_over_d(width(p) - d, get_ef_code(font(l), character(l)), 1000);
-}
-*/
-
-scaled kern_shrink(halfword p)
-{
- int m;
- scaled d, e, x;
- scaled w = width(p) ;
- halfword l;
- halfword r;
- if (w == 0) {
- /* why bother about zero kerns */
- return 0;
- }
- l = prev_char_p ;
- if ((l == null) || (vlink(l) != p)) {
- /* we only care about kerns following a char*/
- return 0;
- }
- r = vlink(p);
- if (r == null) {
- /* we only care about kerns between a char and something else */
- }
- if (!(is_char_node(l) && is_char_node(r))) {
- /* we want two chars (but but don't care about the fonts) */
- return 0;
- }
- /* we use the old logic, kind of, but average the ef as we might depend on proper overlap */
- m = (font_max_shrink(font(l)) + font_max_shrink(font(r)))/2;
- if (m == 0) {
- /* nothing to kern */
- return 0;
- }
- d = round_xn_over_d(w, 1000 - m, 1000);
- e = (get_ef_code(font(l), character(l)) + get_ef_code(font(r), character(r)))/2 ;
- if (e == 1000) {
- x = w - d ;
- } else {
- x = round_xn_over_d(w - d, e, 1000);
- }
- /*
- printf("SHRINK w=%i s=%i x=%i\n",w,e+m,x);
- */
- return x;
-}
-
-@ @c
-void do_subst_font(halfword p, int ex_ratio)
-{
- if (type(p) == disc_node) {
- halfword r = vlink(pre_break(p));
- while (r != null) {
- if (is_char_node(r))
- do_subst_font(r, ex_ratio);
- r = vlink(r);
- }
- r = vlink(post_break(p));
- while (r != null) {
- if (is_char_node(r))
- do_subst_font(r, ex_ratio);
- r = vlink(r);
- }
- r = vlink(no_break(p));
- while (r != null) {
- if (is_char_node(r))
- do_subst_font(r, ex_ratio);
- r = vlink(r);
- }
- return;
- }
- if (! is_char_node(p)) {
- normal_error("font expansion", "invalid node type");
- return;
- } else {
- internal_font_number f = font(p);
- int ef = get_ef_code(f, character(p));
- if (ef == 0)
- return;
- if ((font_max_stretch(f) > 0) && (ex_ratio > 0)) {
- int ex_stretch = ext_xn_over_d(ex_ratio * ef, font_max_stretch(f), 1000000);
- ex_glyph(p) = fix_expand_value(f, ex_stretch)*1000;
- } else if ((font_max_shrink(f) > 0) && (ex_ratio < 0)) {
- int ex_shrink = ext_xn_over_d(ex_ratio * ef, font_max_shrink(f), 1000000);
- ex_glyph(p) = fix_expand_value(f, ex_shrink)*1000;
- }
- }
-}
-
-@ @c
-scaled char_pw(halfword p, int side)
-{
- internal_font_number f;
- int c, w;
- if (side == left_side)
- last_leftmost_char = null;
- else
- last_rightmost_char = null;
- if (p == null)
- return 0;
- if (!is_char_node(p))
- return 0;
- f = font(p);
- if (side == left_side) {
- c = get_lp_code(f, character(p));
- last_leftmost_char = p;
- } else {
- c = get_rp_code(f, character(p));
- last_rightmost_char = p;
- }
- if (c == 0)
- return 0;
- w = quad(f);
- return round_xn_over_d(w, c, 1000);
-}
-
-@ @c
-halfword new_margin_kern(scaled w, halfword p, int side)
-{
- halfword k, q;
- k = new_node(margin_kern_node, side);
- width(k) = w;
- if (p == null)
- normal_error("margin kerning", "invalid pointer to marginal char node");
- q = new_char(font(p), character(p));
- margin_char(k) = q;
- return k;
-}
-
-@ Here is |hpack|, which is place where we do font substituting when font
-expansion is being used.
-
-@c
-int font_expand_ratio = 0; /* current expansion ratio, needed for recursive call */
-
-int ignore_math_skip(halfword p)
-{
- if (math_skip_mode == 6) {
- if (subtype(p) == after) {
- if (math_skip_boundary(vlink(p))) {
- return 0;
- }
- } else {
- if (math_skip_boundary(alink(p))) {
- return 0;
- }
- }
- } else if (math_skip_mode == 7) {
- if (subtype(p) == after) {
- if (! math_skip_boundary(vlink(p))) {
- return 0;
- }
- } else {
- if (! math_skip_boundary(alink(p))) {
- return 0;
- }
- }
- } else {
- return 0;
- }
- reset_glue_to_zero(p);
- return 1;
-}
-
-halfword hpack(halfword p, scaled w, int m, int pack_direction)
-{
- halfword r; /* the box node that will be returned */
- halfword q; /* trails behind |p| */
- scaled h = 0; /* height */
- scaled d = 0; /* depth */
- scaled x = 0; /* natural width */
- scaled_whd whd;
- scaled s; /* shift amount */
- int o; /* order of infinity */
- halfword dir_ptr1 = null; /* for managing the direction stack */
- int hpack_dir; /* the current direction */
- int disc_level = 0;
- halfword pack_interrupt[8];
- scaled font_stretch = 0;
- scaled font_shrink = 0;
- int adjust_spacing = adjust_spacing_par;
-
-/*
- int font_expand_ratio = 0;
-*/
- last_badness = 0;
- r = new_node(hlist_node, min_quarterword); /* the box node that will be returned */
- if (pack_direction == -1) {
- hpack_dir = text_direction_par;
- } else {
- hpack_dir = pack_direction;
- }
- box_dir(r) = hpack_dir;
- /*
- potential optimimization, save a little but neglectable in practice (not so
- many empty boxes are used)
-
- if (p == null) {
- width(r) = w;
- return r;
- }
- */
- push_dir(dir_ptr1,hpack_dir); /* push null */
- q = r + list_offset; /* hm, adding something to a node address? */
- vlink(q) = p;
- if (m == cal_expand_ratio) {
- prev_char_p = null; /* why not always */
- }
- if (adjust_spacing > 2) {
- adjust_spacing = 0;
- }
- total_stretch[normal] = 0;
- total_shrink[normal] = 0;
- total_stretch[sfi] = 0;
- total_shrink[sfi] = 0;
- total_stretch[fil] = 0;
- total_shrink[fil] = 0;
- total_stretch[fill] = 0;
- total_shrink[fill] = 0;
- total_stretch[filll] = 0;
- total_shrink[filll] = 0;
-
- RESWITCH:
- while ((p != null) || (disc_level > 0)) {
- if (p == null) {
- decr(disc_level);
- p = pack_interrupt[disc_level];
- goto RESWITCH;
- }
- /*
- Examine node |p| in the hlist, taking account of its effect
- on the dimensions of the new box, or moving it to the adjustment list;
- then advance |p| to the next node
- */
- while (is_char_node(p)) {
- /*
- Incorporate character dimensions into the dimensions of the hbox
- that will contain~it, then move to the next node.
-
- The following code is part of \TeX's inner loop; i.e., adding
- another character of text to the user's input will cause each of
- these instructions to be exercised one more time.
- */
- if (m >= cal_expand_ratio) {
- prev_char_p = p;
- if (m == cal_expand_ratio) {
- font_stretch += char_stretch(p);
- font_shrink += char_shrink(p);
- } else if (m == subst_ex_font) {
- do_subst_font(p, font_expand_ratio);
- }
- }
- whd = pack_width_height_depth(hpack_dir, dir_TRT, p, true);
- x += whd.wd;
- if (whd.ht > h)
- h = whd.ht;
- if (whd.dp > d)
- d = whd.dp;
- p = vlink(p);
- }
- if (p != null) {
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- /*
- Incorporate box dimensions into the dimensions of the hbox
- that will contain~it
-
- The code here implicitly uses the fact that running dimensions are
- indicated by |null_flag|, which will be ignored in the calculations
- because it is a highly negative number.
- */
- s = shift_amount(p);
- whd = pack_width_height_depth(hpack_dir, box_dir(p), p, false);
- x += whd.wd;
- if (whd.ht - s > h)
- h = whd.ht - s;
- if (whd.dp + s > d)
- d = whd.dp + s;
- break;
- /*
- case rule_node:
- case unset_node:
- x += width(p);
- if (type(p) >= rule_node) // always
- s = 0;
- else
- s = shift_amount(p);
- if (height(p) - s > h)
- h = height(p) - s;
- if (depth(p) + s > d)
- d = depth(p) + s;
- break;
- */
- case rule_node:
- case unset_node:
- x += width(p);
- if (height(p) > h)
- h = height(p);
- if (depth(p) > d)
- d = depth(p);
- break;
- /* */
- case math_node:
- /* begin mathskip code */
- if (glue_is_zero(p) || ignore_math_skip(p)) {
- x += surround(p);
- break;
- } else {
- /* fall through */
- }
- /* end mathskip code */
- case glue_node:
- /* Incorporate glue into the horizontal totals */
- x += width(p);
- o = stretch_order(p);
- total_stretch[o] = total_stretch[o] + stretch(p);
- o = shrink_order(p);
- total_shrink[o] = total_shrink[o] + shrink(p);
- if (subtype(p) >= a_leaders) {
- halfword g = leader_ptr(p);
- if (height(g) > h)
- h = height(g);
- if (depth(g) > d)
- d = depth(g);
- }
- break;
- case kern_node:
- x += width(p);
- if (subtype(p) == font_kern && adjust_spacing) {
- /* so only when 1 or 2 */
- if (m == cal_expand_ratio) {
- font_stretch = font_stretch + kern_stretch(p);
- font_shrink = font_shrink + kern_shrink(p);
- } else if (m == subst_ex_font) {
- /* this is the finalizer */
- int k = 0;
- if (font_expand_ratio > 0) {
- k = kern_stretch(p);
- } else if (font_expand_ratio < 0) {
- k = kern_shrink(p);
- }
- ex_kern(p) = k;
- x += k;
- /*
- if (x!=0) printf("SET %i %i %i\n",font_expand_ratio,k,x);
- */
- }
- }
- break;
- case disc_node:
- if (m == subst_ex_font)
- do_subst_font(p, font_expand_ratio);
- if ((subtype(p) != select_disc) && (vlink(no_break(p)) != null)) {
- pack_interrupt[disc_level] = vlink(p);
- incr(disc_level);
- p = no_break(p);
- }
- break;
- case dir_node:
- /* Adjust the dir stack for the |hpack| routine */
- if (dir_dir(p) >= 0) {
- hpack_dir = dir_dir(p);
- push_dir_node(dir_ptr1,p);
- } else {
- pop_dir_node(dir_ptr1);
- if (dir_ptr1 != null)
- hpack_dir = dir_dir(dir_ptr1);
- }
- break;
- case margin_kern_node:
- if (m == cal_expand_ratio) {
- int f = font(margin_char(p));
- do_subst_font(margin_char(p), 1000);
- if (f != font(margin_char(p)))
- font_stretch = font_stretch - width(p) - char_pw(margin_char(p), subtype(p));
- font(margin_char(p)) = f;
- do_subst_font(margin_char(p), -1000);
- if (f != font(margin_char(p)))
- font_shrink = font_shrink - width(p) - char_pw(margin_char(p), subtype(p));
- font(margin_char(p)) = f;
- } else if (m == subst_ex_font) {
- do_subst_font(margin_char(p), font_expand_ratio);
- width(p) = -char_pw(margin_char(p), subtype(p));
- }
- x += width(p);
- break;
- case ins_node:
- case mark_node:
- case adjust_node:
- /*
- Transfer node |p| to the adjustment list.
-
- Although node |q| is not necessarily the immediate predecessor of node |p|,
- it always points to some node in the list preceding |p|. Thus, we can delete
- nodes by moving |q| when necessary. The algorithm takes linear time, and the
- extra computation does not intrude on the inner loop unless it is necessary
- to make a deletion.
- */
- if (adjust_tail != null || pre_adjust_tail != null) {
- while (vlink(q) != p)
- q = vlink(q);
- if (type(p) == adjust_node) {
- if (adjust_pre(p) != 0)
- update_adjust_list(pre_adjust_tail);
- else
- update_adjust_list(adjust_tail);
- p = vlink(p);
- adjust_ptr(vlink(q)) = null;
- flush_node(vlink(q));
- } else {
- vlink(adjust_tail) = p;
- adjust_tail = p;
- p = vlink(p);
- }
- vlink(q) = p;
- p = q;
- }
- break;
- /* */
- default:
- break;
- }
- p = vlink(p);
- }
-
- }
-
- if (adjust_tail != null)
- vlink(adjust_tail) = null;
- if (pre_adjust_tail != null)
- vlink(pre_adjust_tail) = null;
- height(r) = h;
- depth(r) = d;
- /*
- Determine the value of |width(r)| and the appropriate glue setting; then
- |return| or |goto common_ending|.
-
- When we get to the present part of the program, |x| is the natural width
- of the box being packaged.
- */
- if (m == additional)
- w = x + w;
- width(r) = w;
- x = w - x;
- /* now |x| is the excess to be made up */
- if (x == 0) {
- glue_sign(r) = normal;
- glue_order(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- goto EXIT;
- } else if (x > 0) {
- /*
- Determine horizontal glue stretch setting, then |return|
- or \hbox{|goto common_ending|}.
-
- If |hpack| is called with |m=cal_expand_ratio| we calculate
- |font_expand_ratio| and return without checking for overfull or
- underfull box.
- */
- if (total_stretch[filll] != 0)
- o = filll;
- else if (total_stretch[fill] != 0)
- o = fill;
- else if (total_stretch[fil] != 0)
- o = fil;
- else if (total_stretch[sfi] != 0)
- o = sfi;
- else
- o = normal;
-
- if ((m == cal_expand_ratio) && (o == normal) && (font_stretch > 0)) {
- font_expand_ratio = divide_scaled_n(x, font_stretch, 1000.0);
- goto EXIT;
- }
- glue_order(r) = (quarterword) o;
- glue_sign(r) = stretching;
- if (total_stretch[o] != 0) {
- glue_set(r) = unfloat((double) x / total_stretch[o]);
- } else {
- /* there's nothing to stretch */
- glue_sign(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- }
- if (o == normal) {
- if (list_ptr(r) != null) {
- /*
- Report an underfull hbox and |goto common_ending|, if this box
- is sufficiently bad.
- */
- last_badness = badness(x, total_stretch[normal]);
- if (last_badness > hbadness_par) {
- int callback_id = callback_defined(hpack_quality_callback);
- if (callback_id > 0) {
- halfword rule = null;
- if (last_badness > 100) {
- run_callback(callback_id, "SdNdd->N","underfull",last_badness,r,abs(pack_begin_line),line,&rule);
- } else {
- run_callback(callback_id, "SdNdd->N","loose",last_badness,r,abs(pack_begin_line),line,&rule);
- }
- if (rule != null) {
- while (vlink(q) != null) {
- q = vlink(q);
- }
- couple_nodes(q,rule);
- }
- } else {
- print_ln();
- if (last_badness > 100) {
- tprint_nl("Underfull \\hbox (badness ");
- } else {
- tprint_nl("Loose \\hbox (badness ");
- }
- print_int(last_badness);
- goto COMMON_ENDING;
- }
- }
- }
- }
- goto EXIT;
- } else {
- /*
- Determine horizontal glue shrink setting, then |return|
- or \hbox{|goto common_ending|},
- */
- if (total_shrink[filll] != 0)
- o = filll;
- else if (total_shrink[fill] != 0)
- o = fill;
- else if (total_shrink[fil] != 0)
- o = fil;
- else if (total_shrink[sfi] != 0)
- o = sfi;
- else
- o = normal;
-
- if ((m == cal_expand_ratio) && (o == normal) && (font_shrink > 0)) {
- font_expand_ratio = divide_scaled_n(x, font_shrink, 1000.0);
- goto EXIT;
- }
- glue_order(r) = (quarterword) o;
- glue_sign(r) = shrinking;
- if (total_shrink[o] != 0) {
- glue_set(r) = unfloat((double) (-x) / (double) total_shrink[o]);
- } else {
- /* there's nothing to shrink */
- glue_sign(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- }
- if ((total_shrink[o] < -x) && (o == normal) && (list_ptr(r) != null)) {
- int overshoot = -x - total_shrink[normal] ;
- last_badness = 1000000;
- /* use the maximum shrinkage */
- set_glue_ratio_one(glue_set(r));
- /*
- Report an overfull hbox and |goto common_ending|, if this box
- is sufficiently bad.
- */
- if ((overshoot > hfuzz_par) || (hbadness_par < 100)) {
- int callback_id = callback_defined(hpack_quality_callback);
- halfword rule = null;
- if (callback_id > 0) {
- run_callback(callback_id, "SdNdd->N","overfull",overshoot,r,abs(pack_begin_line),line,&rule);
- } else if (overfull_rule_par > 0) {
- rule = new_rule(normal_rule);
- rule_dir(rule) = box_dir(r);
- width(rule) = overfull_rule_par;
- }
- if (rule != null) {
- while (vlink(q) != null) {
- q = vlink(q);
- }
- couple_nodes(q,rule);
- }
- if (callback_id == 0) {
- print_ln();
- tprint_nl("Overfull \\hbox (");
- print_scaled(overshoot);
- tprint("pt too wide");
- goto COMMON_ENDING;
- }
- }
- } else if (o == normal) {
- if (list_ptr(r) != null) {
- /*
- Report a tight hbox and |goto common_ending|, if this box is
- sufficiently bad.
- */
- last_badness = badness(-x, total_shrink[normal]);
- if (last_badness > hbadness_par) {
- int callback_id = callback_defined(hpack_quality_callback);
- if (callback_id > 0) {
- halfword rule = null;
- run_callback(callback_id, "SdNdd->N","tight",last_badness,r,abs(pack_begin_line),line,&rule);
- if (rule != null) {
- while (vlink(q) != null) {
- q = vlink(q);
- }
- couple_nodes(q,rule);
- }
- } else {
- print_ln();
- tprint_nl("Tight \\hbox (badness ");
- print_int(last_badness);
- goto COMMON_ENDING;
- }
- }
- }
- }
- goto EXIT;
- }
-
- COMMON_ENDING:
- /*
- Finish issuing a diagnostic message for an overfull or underfull
- hbox.
- */
- if (output_active) {
- tprint(") has occurred while \\output is active");
- } else {
- if (pack_begin_line != 0) {
- if (pack_begin_line > 0) {
- tprint(") in paragraph at lines ");
- } else {
- tprint(") in alignment at lines ");
- }
- print_int(abs(pack_begin_line));
- tprint("--");
- } else {
- tprint(") detected at line ");
- }
- print_int(line);
- }
-
- print_ln();
- font_in_short_display = null_font;
- short_display(list_ptr(r));
- print_ln();
- begin_diagnostic();
- show_box(r);
- end_diagnostic(true);
- EXIT:
- if ((m == cal_expand_ratio) && (font_expand_ratio != 0)) {
- font_expand_ratio = fix_int(font_expand_ratio, -1000, 1000);
- q = list_ptr(r);
- list_ptr(r) = null;
- flush_node(r);
- /* this nested call uses the more or less global font_expand_ratio */
- r = hpack(q, w, subst_ex_font, hpack_dir);
- }
- while (dir_ptr1 != null)
- pop_dir_node(dir_ptr1);
- /* here we reset the font_expan_ratio */
- font_expand_ratio = 0;
- return r;
-}
-
-@ @c
-halfword filtered_hpack(halfword p, halfword qt, scaled w, int m, int grp, int pac, int just_pack, halfword attr)
-{
- halfword q;
- if (just_pack) {
- q = vlink(p);
- } else if (type(p) == temp_node && vlink(p) == null) {
- q = vlink(p);
- /*
- q = new_node(hlist_node, min_quarterword);
- box_dir(q) = (pac == -1) ? text_direction_par : pac;
- width(q) = w;
- return q;
- */
- } else {
- new_hyphenation(p, qt);
- (void) new_ligkern(p, qt); /* we don't care about the tail in this case */
- q = vlink(p);
- /* maybe here: alink(p) = null */
- q = lua_hpack_filter(q, w, m, grp, pac, attr); /* ignores empty anyway */ /* maybe also pass tail */
- }
- return hpack(q, w, m, pac);
-}
-
-@ here is a function to calculate the natural whd of a (horizontal) node list
-
-@c
-scaled_whd natural_sizes(halfword p, halfword pp, glue_ratio g_mult,
- int g_sign, int g_order, int pack_direction)
-{
- scaled s; /* shift amount */
- halfword g; /* points to a glue specification */
- int hpack_dir;
- scaled_whd xx; /* for recursion */
- scaled_whd whd, siz = { 0, 0, 0 };
- scaled gp = 0;
- scaled gm = 0;
- if (pack_direction == -1) {
- hpack_dir = text_direction_par;
- } else {
- hpack_dir = pack_direction;
- }
- while (p != pp && p != null) {
- while (is_char_node(p) && p != pp) {
- whd = pack_width_height_depth(hpack_dir, dir_TRT, p, true);
- siz.wd += whd.wd;
- if (whd.ht > siz.ht)
- siz.ht = whd.ht;
- if (whd.dp > siz.dp)
- siz.dp = whd.dp;
- p = vlink(p);
- }
- if (p != pp && p != null) {
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- s = shift_amount(p);
- whd = pack_width_height_depth(hpack_dir, box_dir(p), p, false);
- siz.wd += whd.wd;
- if (whd.ht - s > siz.ht)
- siz.ht = whd.ht - s;
- if (whd.dp + s > siz.dp)
- siz.dp = whd.dp + s;
- break;
- /*
- case rule_node:
- case unset_node:
- siz.wd += width(p);
- if (type(p) >= rule_node) // always true
- s = 0;
- else
- s = shift_amount(p);
- if (height(p) - s > siz.ht)
- siz.ht = height(p) - s;
- if (depth(p) + s > siz.dp)
- siz.dp = depth(p) + s;
- break;
- */
- case rule_node:
- case unset_node:
- siz.wd += width(p);
- if (height(p) > siz.ht)
- siz.ht = height(p);
- if (depth(p) > siz.dp)
- siz.dp = depth(p);
- break;
- /* */
- case math_node:
- /* begin mathskip code */
- if (glue_is_zero(p) || ignore_math_skip(p)) {
- siz.wd += surround(p);
- break;
- } else {
- /* fall through */
- }
- /* end mathskip code */
- case glue_node:
- siz.wd += width(p);
- if (g_sign != normal) {
- if (g_sign == stretching) {
- if (stretch_order(p) == g_order) {
- /*
- siz.wd += float_round(float_cast(g_mult) * float_cast(stretch(p)));
- */
- gp += stretch(p);
- }
- } else if (shrink_order(p) == g_order) {
- /*
- siz.wd -= float_round(float_cast(g_mult) * float_cast(shrink(p)));
- */
- gm += shrink(p);
- }
- }
- if (subtype(p) >= a_leaders) {
- g = leader_ptr(p);
- if (height(g) > siz.ht)
- siz.ht = height(g);
- if (depth(g) > siz.dp)
- siz.dp = depth(g);
- }
- break;
- case margin_kern_node:
- siz.wd += width(p);
- break;
- case kern_node:
- siz.wd += width(p) + ex_kern(p);
- break;
- case disc_node:
- xx = natural_sizes(no_break(p), null, g_mult, g_sign, g_order, hpack_dir);
- siz.wd += xx.wd;
- if (xx.ht > siz.ht)
- siz.ht = xx.ht;
- if (xx.dp > siz.dp)
- siz.dp = xx.dp;
- break;
- default:
- break;
- }
- p = vlink(p);
- }
-
- }
- if (g_sign != normal) {
- if (g_sign == stretching) {
- siz.wd += float_round(float_cast(g_mult) * float_cast(gp));
- } else {
- siz.wd -= float_round(float_cast(g_mult) * float_cast(gm));
- }
- }
- return siz;
-}
-
-@ In order to provide a decent indication of where an overfull or underfull box
-originated, we use a global variable |pack_begin_line| that is set nonzero only
-when |hpack| is being called by the paragraph builder or the alignment finishing
-routine.
-
-@ The source file line where the current paragraph or alignment began; a negative
-value denotes alignment:
-
-@c
-int pack_begin_line;
-
-@ The |vpack| subroutine is actually a special case of a slightly more general
-routine called |vpackage|, which has four parameters. The fourth parameter, which
-is |max_dimen| in the case of |vpack|, specifies the maximum depth of the page
-box that is constructed. The depth is first computed by the normal rules; if it
-exceeds this limit, the reference point is simply moved down until the limiting
-depth is attained.
-
-@c
-halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
-{
- halfword r; /* the box node that will be returned */
- scaled w = 0; /* width */
- scaled d = 0; /* depth */
- scaled x = 0; /* natural height */
- scaled_whd whd;
- scaled s; /* shift amount */
- int o; /* order of infinity */
- last_badness = 0;
- r = new_node(vlist_node, 0);
- if (pack_direction == -1) {
- box_dir(r) = body_direction_par;
- } else {
- box_dir(r) = pack_direction;
- }
- subtype(r) = min_quarterword;
- shift_amount(r) = 0;
- list_ptr(r) = p;
- total_stretch[normal] = 0;
- total_shrink[normal] = 0;
- total_stretch[sfi] = 0;
- total_shrink[sfi] = 0;
- total_stretch[fil] = 0;
- total_shrink[fil] = 0;
- total_stretch[fill] = 0;
- total_shrink[fill] = 0;
- total_stretch[filll] = 0;
- total_shrink[filll] = 0;
-
- while (p != null) {
- /*
- Examine node |p| in the vlist, taking account of its effect
- on the dimensions of the new box; then advance |p| to the next
- node.
- */
- if (is_char_node(p)) {
- confusion("vpack");
- } else {
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- /*
- Incorporate box dimensions into the dimensions of
- the vbox that will contain it.
- */
- s = shift_amount(p);
- whd = pack_width_height_depth(box_dir(r), box_dir(p), p, false);
- if (whd.wd + s > w)
- w = whd.wd + s;
- x += d + whd.ht;
- d = whd.dp;
- break;
- /*
- case rule_node:
- case unset_node:
- x += d + height(p);
- d = depth(p);
- if (type(p) >= rule_node) // always
- s = 0;
- else
- s = shift_amount(p);
- if (width(p) + s > w)
- w = width(p) + s;
- break;
- */
- case rule_node:
- case unset_node:
- x += d + height(p);
- d = depth(p);
- if (width(p) > w)
- w = width(p);
- break;
- /* */
- case glue_node:
- /* Incorporate glue into the vertical totals */
- x += d;
- d = 0;
- x += width(p);
- o = stretch_order(p);
- total_stretch[o] = total_stretch[o] + stretch(p);
- o = shrink_order(p);
- total_shrink[o] = total_shrink[o] + shrink(p);
- if (subtype(p) >= a_leaders) {
- halfword g = leader_ptr(p);
- if (width(g) > w)
- w = width(g);
- }
- break;
- case kern_node:
- x += d + width(p);
- d = 0;
- break;
- default:
- break;
- }
- }
- p = vlink(p);
- }
- width(r) = w;
- if (d > l) {
- x += d - l;
- depth(r) = l;
- } else {
- depth(r) = d;
- }
- /*
- Determine the value of |height(r)| and the appropriate glue setting;
- then |return| or |goto common_ending|.
-
- When we get to the present part of the program, |x| is the natural
- height of the box being packaged.
- */
- if (m == additional)
- h = x + h;
- height(r) = h;
- x = h - x;
- /* now |x| is the excess to be made up */
- if (x == 0) {
- glue_sign(r) = normal;
- glue_order(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- return r;
- } else if (x > 0) {
- /*
- Determine vertical glue stretch setting, then |return|
- or \hbox{|goto common_ending|}.
- */
- if (total_stretch[filll] != 0)
- o = filll;
- else if (total_stretch[fill] != 0)
- o = fill;
- else if (total_stretch[fil] != 0)
- o = fil;
- else if (total_stretch[sfi] != 0)
- o = sfi;
- else
- o = normal;
-
- glue_order(r) = (quarterword) o;
- glue_sign(r) = stretching;
- if (total_stretch[o] != 0) {
- glue_set(r) = unfloat((double) x / total_stretch[o]);
- } else {
- glue_sign(r) = normal;
- set_glue_ratio_zero(glue_set(r)); /* there's nothing to stretch */
- }
- if (o == normal) {
- if (list_ptr(r) != null) {
- /*
- Report an underfull vbox and |goto common_ending|, if this box
- is sufficiently bad.
- */
- last_badness = badness(x, total_stretch[normal]);
- if (last_badness > vbadness_par) {
- int callback_id = callback_defined(vpack_quality_callback);
- if (callback_id > 0) {
- if (last_badness > 100) {
- run_callback(callback_id, "SdNdd->","underfull",last_badness,r,abs(pack_begin_line),line);
- } else {
- run_callback(callback_id, "SdNdd->","loose",last_badness,r,abs(pack_begin_line),line);
- }
- goto EXIT;
- } else {
- print_ln();
- if (last_badness > 100) {
- tprint_nl("Underfull \\vbox (badness ");
- } else {
- tprint_nl("Loose \\vbox (badness ");
- }
- print_int(last_badness);
- goto COMMON_ENDING;
- }
- }
- }
- }
- return r;
-
- } else {
- /*
- Determine vertical glue shrink setting, then |return|
- or \hbox{|goto common_ending|}.
- */
- if (total_shrink[filll] != 0)
- o = filll;
- else if (total_shrink[fill] != 0)
- o = fill;
- else if (total_shrink[fil] != 0)
- o = fil;
- else if (total_shrink[sfi] != 0)
- o = sfi;
- else
- o = normal;
-
- glue_order(r) = (quarterword) o;
- glue_sign(r) = shrinking;
- if (total_shrink[o] != 0) {
- glue_set(r) = unfloat((double) (-x) / total_shrink[o]);
- } else {
- /* there's nothing to shrink */
- glue_sign(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- }
- if ((total_shrink[o] < -x) && (o == normal) && (list_ptr(r) != null)) {
- int overshoot = -x - total_shrink[normal];
- last_badness = 1000000;
- /* use the maximum shrinkage */
- set_glue_ratio_one(glue_set(r));
- /*
- Report an overfull vbox and |goto common_ending|, if this box
- is sufficiently bad.
- */
- if ((overshoot > vfuzz_par) || (vbadness_par < 100)) {
- int callback_id = callback_defined(vpack_quality_callback);
- if (callback_id > 0) {
- run_callback(callback_id, "SdNdd->","overfull",overshoot,r,abs(pack_begin_line),line);
- goto EXIT;
- } else {
- print_ln();
- tprint_nl("Overfull \\vbox (");
- print_scaled(-x - total_shrink[normal]);
- tprint("pt too high");
- goto COMMON_ENDING;
- }
- }
- } else if (o == normal) {
- if (list_ptr(r) != null) {
- /*
- Report a tight vbox and |goto common_ending|, if this box is
- sufficiently bad.
- */
- last_badness = badness(-x, total_shrink[normal]);
- if (last_badness > vbadness_par) {
- int callback_id = callback_defined(vpack_quality_callback);
- if (callback_id > 0) {
- run_callback(callback_id, "SdNdd->","tight",last_badness,r,abs(pack_begin_line),line);
- goto EXIT;
- } else {
- print_ln();
- tprint_nl("Tight \\vbox (badness ");
- print_int(last_badness);
- goto COMMON_ENDING;
- }
- }
- }
- }
- return r;
- }
-
- COMMON_ENDING:
- /* Finish issuing a diagnostic message or an overfull or underfull vbox */
- if (output_active) {
- tprint(") has occurred while \\output is active");
- } else {
- if (pack_begin_line != 0) {
- /* it's actually negative */
- tprint(") in alignment at lines ");
- print_int(abs(pack_begin_line));
- tprint("--");
- } else {
- tprint(") detected at line ");
- }
- print_int(line);
- print_ln();
- }
- begin_diagnostic();
- show_box(r);
- end_diagnostic(true);
- EXIT:
- return r;
-}
-
-@ @c
-halfword filtered_vpackage(halfword p, scaled h, int m, scaled l, int grp, int pack_direction, int just_pack, halfword attr)
-{
- halfword q = p;
- if (!just_pack)
- /* if (q != null) */
- q = lua_vpack_filter(q, h, m, l, grp, pack_direction, attr);
- return vpackage(q, h, m, l, pack_direction);
-}
-
-@ @c
-void finish_vcenter(void)
-{
- halfword p;
- unsave();
- save_ptr--;
- p = vpack(vlink(cur_list.head_field), saved_value(0), saved_level(0), -1);
- pop_nest();
- p = math_vcenter_group(p);
- tail_append(p);
-}
-
-@ @c
-void package(int c)
-{
- halfword saved0, saved2, saved3, saved4;
- int grp = cur_group;
- scaled d = box_max_depth_par; /* max depth */
- unsave();
- save_ptr -= 5;
- saved0 = saved_value(0);
- saved2 = saved_value(2);
- saved3 = saved_value(3);
- saved4 = saved_value(4);
- if (cur_list.mode_field == -hmode) {
- cur_box = filtered_hpack(cur_list.head_field, cur_list.tail_field,
- saved_value(1), saved_level(1), grp, saved_level(2), saved4, saved3);
- subtype(cur_box) = hbox_list;
- } else {
- cur_box = filtered_vpackage(vlink(cur_list.head_field),
- saved_value(1), saved_level(1), d, grp, saved_level(2), saved4, saved3);
- if (c == vtop_code) {
- /*
- Read just the height and depth of |cur_box|, for \.{\\vtop}. The
- height of a `\.{\\vtop}' box is inherited from the first item on
- its list, if that item is an |hlist_node|, |vlist_node|, or
- |rule_node|; otherwise the \.{\\vtop} height is zero.
- */
- scaled h = 0;
- halfword p = list_ptr(cur_box);
- if ((p != null) && (type(p) <= rule_node)) {
- /* hlist, vlist, rule */
- h = height(p);
- }
- depth(cur_box) = depth(cur_box) - h + height(cur_box);
- height(cur_box) = h;
- }
- }
- if (saved2 != null) {
- /* DIR: Adjust back |text_dir_ptr| for |scan_spec| */
- flush_node_list(text_dir_ptr);
- text_dir_ptr = saved2;
-
- }
- replace_attribute_list(cur_box, saved3);
- pop_nest();
- box_end(saved0);
-}
-
-@ When a box is being appended to the current vertical list, the baselineskip
-calculation is handled by the |append_to_vlist| routine.
-
-@c
-void append_to_vlist(halfword b, int location)
-{
- scaled d; /* deficiency of space between baselines */
- halfword p; /* a new glue node */
- boolean mirrored = (type(b) == hlist_node) && is_mirrored(box_dir(b)) ;
- halfword result = null;
- halfword next_depth = ignore_depth;
- boolean prev_set = false ;
- if (lua_appendtovlist_callback(b,location,prev_depth_par,mirrored,&result,&next_depth,&prev_set)) {
- while (result != null) {
- couple_nodes(cur_list.tail_field, result);
- cur_list.tail_field = result;
- result = vlink(result);
- }
- if (prev_set) {
- prev_depth_par = next_depth;
- }
- } else {
- if (prev_depth_par > ignore_depth) {
- if (mirrored) {
- d = width(baseline_skip_par) - prev_depth_par - depth(b);
- } else {
- d = width(baseline_skip_par) - prev_depth_par - height(b);
- }
- if (d < line_skip_limit_par) {
- p = new_param_glue(line_skip_code);
- } else {
- p = new_skip_param(baseline_skip_code);
- width(p) = d;
- }
- couple_nodes(cur_list.tail_field, p);
- cur_list.tail_field = p;
- }
- couple_nodes(cur_list.tail_field, b);
- cur_list.tail_field = b;
- if (mirrored) {
- prev_depth_par = height(b);
- } else {
- prev_depth_par = depth(b);
- }
- }
-}
-
-@ When |saving_vdiscards| is positive then the glue, kern, and penalty nodes
-removed by the page builder or by \.{\\vsplit} from the top of a vertical list
-are saved in special lists instead of being discarded.
-
-@c
-#define tail_page_disc disc_ptr[copy_code] /* last item removed by page builder */
-#define page_disc disc_ptr[last_box_code] /* first item removed by page builder */
-#define split_disc disc_ptr[vsplit_code] /* first item removed by \.{\\vsplit} */
-
-halfword disc_ptr[(vsplit_code + 1)]; /* list pointers */
-
-@ The |vsplit| procedure, which implements \TeX's \.{\\vsplit} operation, is
-considerably simpler than |line_break| because it doesn't have to worry about
-hyphenation, and because its mission is to discover a single break instead of an
-optimum sequence of breakpoints. But before we get into the details of |vsplit|,
-we need to consider a few more basic things.
-
-A subroutine called |prune_page_top| takes a pointer to a vlist and returns a
-pointer to a modified vlist in which all glue, kern, and penalty nodes have been
-deleted before the first box or rule node. However, the first box or rule is
-actually preceded by a newly created glue node designed so that the topmost
-baseline will be at distance |split_top_skip| from the top, whenever this is
-possible without backspacing.
-
-When the second argument |s| is |false| the deleted nodes are destroyed,
-otherwise they are collected in a list starting at |split_disc|.
-
-@c
-halfword prune_page_top(halfword p, boolean s)
-{
- halfword q;
- halfword prev_p = temp_head; /* lags one step behind |p| */
- halfword r = null;
- vlink(temp_head) = p;
- while (p != null) {
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case rule_node:
- /* Insert glue for |split_top_skip| and set~|p:=null| */
- q = new_skip_param(split_top_skip_code);
- vlink(prev_p) = q;
- vlink(q) = p;
- if (width(q) > height(p))
- width(q) = width(q) - height(p);
- else
- width(q) = 0;
- p = null;
- break;
- case boundary_node:
- case whatsit_node:
- case mark_node:
- case ins_node:
- prev_p = p;
- p = vlink(prev_p);
- break;
- case glue_node:
- case kern_node:
- case penalty_node:
- q = p;
- p = vlink(q);
- vlink(q) = null;
- vlink(prev_p) = p;
- if (s) {
- if (split_disc == null)
- split_disc = q;
- else
- vlink(r) = q;
- r = q;
- } else {
- flush_node_list(q);
- }
- break;
- default:
- confusion("pruning");
- break;
- }
- }
- return vlink(temp_head);
-}
-
-@ The next subroutine finds the best place to break a given vertical list so as
-to obtain a box of height~|h|, with maximum depth~|d|. A pointer to the beginning
-of the vertical list is given, and a pointer to the optimum breakpoint is
-returned. The list is effectively followed by a forced break, i.e., a penalty
-node with the |eject_penalty|; if the best break occurs at this artificial node,
-the value |null| is returned.
-
-@c
-scaled active_height[10]; /* distance from first active node to~|cur_p| */
-
-@ An array of six |scaled| distances is used to keep track of the height from the
-beginning of the list to the current place, just as in |line_break|. In fact, we
-use one of the same arrays, only changing its name to reflect its new
-significance.
-
-@c
-#define do_all_six(A) A(1);A(2);A(3);A(4);A(5);A(6);A(7)
-#define set_height_zero(A) active_height[A]=0 /* initialize the height to zero */
-
-@ A global variable |best_height_plus_depth| will be set to the natural size of
-the box that corresponds to the optimum breakpoint found by |vert_break|. (This
-value is used by the insertion-splitting algorithm of the page builder.)
-
-@ height of the best box, without stretching or shrinking
-
-@c
-scaled best_height_plus_depth;
-
-/* finds optimum page break */
-
-halfword vert_break(halfword p, scaled h, scaled d)
-{
- halfword prev_p = p; /* if |p| is a glue node, |type(prev_p)| determines whether |p| is a
- legal breakpoint, an initial glue node is not a legal breakpoint */
- int pi = 0; /* penalty value */
- int b; /* badness at a trial breakpoint */
- int t; /* |type| of the node following a kern */
- int least_cost; /* the smallest badness plus penalties found so far */
- halfword best_place = null; /* the most recent break that leads to |least_cost| */
- scaled prev_dp = 0; /* depth of previous box in the list */
- least_cost = awful_bad;
- do_all_six(set_height_zero);
- while (1) {
- /* If node |p| is a legal breakpoint, check if this break is
- the best known, and |goto done| if |p| is null or
- if the page-so-far is already too full to accept more stuff */
- /* A subtle point to be noted here is that the maximum depth~|d| might be
- negative, so |cur_height| and |prev_dp| might need to be corrected even
- after a glue or kern node. */
-
- if (p == null) {
- pi = eject_penalty;
- } else {
- /* Use node |p| to update the current height and depth measurements;
- if this node is not a legal breakpoint, |goto not_found|
- or |update_heights|,
- otherwise set |pi| to the associated penalty at the break */
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case rule_node:
- cur_height = cur_height + prev_dp + height(p);
- prev_dp = depth(p);
- goto NOT_FOUND;
- break;
- case boundary_node:
- case whatsit_node:
- goto NOT_FOUND;
- break;
- case glue_node:
- if (precedes_break(prev_p))
- pi = 0;
- else
- goto UPDATE_HEIGHTS;
- break;
- case kern_node:
- if (vlink(p) == null)
- t = penalty_node;
- else
- t = type(vlink(p));
- if (t == glue_node)
- pi = 0;
- else
- goto UPDATE_HEIGHTS;
- break;
- case penalty_node:
- pi = penalty(p);
- break;
- case mark_node:
- case ins_node:
- goto NOT_FOUND;
- break;
- default:
- confusion("vertbreak");
- break;
- }
- }
- /* Check if node |p| is a new champion breakpoint; then |goto done|
- if |p| is a forced break or if the page-so-far is already too full */
- if (pi < inf_penalty) {
- /* Compute the badness, |b|, using |awful_bad| if the box is too full */
- if (cur_height < h) {
- if ((active_height[3] != 0) || (active_height[4] != 0) ||
- (active_height[5] != 0) || (active_height[6] != 0))
- b = 0;
- else
- b = badness(h - cur_height, active_height[2]);
- } else if (cur_height - h > active_height[7]) {
- b = awful_bad;
- } else {
- b = badness(cur_height - h, active_height[7]);
- }
-
- if (b < awful_bad) {
- if (pi <= eject_penalty)
- b = pi;
- else if (b < inf_bad)
- b = b + pi;
- else
- b = deplorable;
- }
- if (b <= least_cost) {
- best_place = p;
- least_cost = b;
- best_height_plus_depth = cur_height + prev_dp;
- }
- if ((b == awful_bad) || (pi <= eject_penalty))
- goto DONE;
- }
-
- if ((type(p) < glue_node) || (type(p) > kern_node))
- goto NOT_FOUND;
- UPDATE_HEIGHTS:
- /* Update the current height and depth measurements with
- respect to a glue or kern node~|p| */
- /* Vertical lists that are subject to the |vert_break| procedure should not
- contain infinite shrinkability, since that would permit any amount of
- information to ``fit'' on one page. */
-
- if (type(p) != kern_node) {
- active_height[2 + stretch_order(p)] += stretch(p);
- active_height[7] += shrink(p);
- if ((shrink_order(p) != normal) && (shrink(p) != 0)) {
- print_err("Infinite glue shrinkage found in box being split");
- help4("The box you are \\vsplitting contains some infinitely",
- "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
- "Such glue doesn't belong there; but you can safely proceed,",
- "since the offensive shrinkability has been made finite.");
- error();
- shrink_order(p) = normal;
- }
- }
- cur_height = cur_height + prev_dp + width(p);
- prev_dp = 0;
- NOT_FOUND:
- if (prev_dp > d) {
- cur_height = cur_height + prev_dp - d;
- prev_dp = d;
- }
- prev_p = p;
- p = vlink(prev_p);
- }
- DONE:
- return best_place;
-}
-
-@ Now we are ready to consider |vsplit| itself. Most of its work is accomplished
-by the two subroutines that we have just considered.
-
-Given the number of a vlist box |n|, and given a desired page height |h|, the
-|vsplit| function finds the best initial segment of the vlist and returns a box
-for a page of height~|h|. The remainder of the vlist, if any, replaces the
-original box, after removing glue and penalties and adjusting for
-|split_top_skip|. Mark nodes in the split-off box are used to set the values of
-|split_first_mark| and |split_bot_mark|; we use the fact that
-|split_first_mark(x)=null| if and only if |split_bot_mark(x)=null|.
-
-The original box becomes ``void'' if and only if it has been entirely extracted.
-The extracted box is ``void'' if and only if the original box was void (or if it
-was, erroneously, an hlist box).
-
-@c
-/* extracts a page of height |h| from box |n| */
-
-halfword vsplit(halfword n, scaled h, int m)
-{
- halfword v; /* the box to be split */
- int vdir; /* the direction of the box to be split */
- halfword p; /* runs through the vlist */
- halfword q; /* points to where the break occurs */
- halfword i; /* for traversing marks lists */
- v = box(n);
- vdir = box_dir(v);
- flush_node_list(split_disc);
- split_disc = null;
- for (i = 0; i <= biggest_used_mark; i++) {
- delete_split_first_mark(i);
- delete_split_bot_mark(i);
- }
- /* Dispense with trivial cases of void or bad boxes */
- if (v == null) {
- return null;
- }
- if (type(v) != vlist_node) {
- print_err("\\vsplit needs a \\vbox");
- help2("The box you are trying to split is an \\hbox.",
- "i can't split such a box, so I''ll leave it alone.");
- error();
- return null;
- }
- q = vert_break(list_ptr(v), h, split_max_depth_par);
- /*
- Look at all the marks in nodes before the break, and set the final
- link to |null| at the break. It's possible that the box begins with
- a penalty node that is the ``best'' break, so we must be careful to
- handle this special case correctly.
- */
- p = list_ptr(v);
- if (p == q) {
- list_ptr(v) = null;
- } else {
- while (1) {
- if (type(p) == mark_node) {
- if (split_first_mark(mark_class(p)) == null) {
- set_split_first_mark(mark_class(p), mark_ptr(p));
- set_split_bot_mark(mark_class(p), split_first_mark(mark_class(p)));
- set_token_ref_count(split_first_mark(mark_class(p)),
- token_ref_count(split_first_mark(mark_class(p))) + 2);
- } else {
- delete_token_ref(split_bot_mark(mark_class(p)));
- set_split_bot_mark(mark_class(p), mark_ptr(p));
- add_token_ref(split_bot_mark(mark_class(p)));
- }
- }
- if (vlink(p) == q) {
- vlink(p) = null;
- break;
- }
- p = vlink(p);
- }
- }
- q = prune_page_top(q, saving_vdiscards_par > 0);
- p = list_ptr(v);
- list_ptr(v) = null;
- flush_node(v);
- if (q == null) {
- /* the |eq_level| of the box stays the same */
- box(n) = null;
- } else {
- box(n) = filtered_vpackage(q, 0, additional, max_depth_par, split_keep_group, vdir, 0, 0);
- }
- if (m == exactly) {
- return filtered_vpackage(p, h, exactly, split_max_depth_par, split_off_group, vdir, 0, 0);
- } else {
- return filtered_vpackage(p, 0, additional, max_depth_par, split_off_group, vdir, 0, 0);
- }
-}
-
-@ Now that we can see what eventually happens to boxes, we can consider the first
-steps in their creation. The |begin_box| routine is called when |box_context| is
-a context specification, |cur_chr| specifies the type of box desired, and
-|cur_cmd=make_box|.
-
-@c
-void begin_box(int box_context)
-{
- halfword q; /* run through the current list */
- halfword k; /* 0 or |vmode| or |hmode| */
- int n; /* a box number */
- int spec_direction = -1;
- int just_pack = 0;
- int split_mode = exactly ;
- switch (cur_chr) {
- case box_code:
- scan_register_num();
- cur_box = box(cur_val);
- /* the box becomes void, at the same level */
- box(cur_val) = null;
- break;
- case copy_code:
- scan_register_num();
- cur_box = copy_node_list(box(cur_val));
- break;
- case last_box_code:
- /*
- If the current list ends with a box node, delete it from
- the list and make |cur_box| point to it; otherwise set
- |cur_box:=null|.
- */
- cur_box = null;
- if (abs(cur_list.mode_field) == mmode) {
- you_cant();
- help1("Sorry; this \\lastbox will be void.");
- error();
- } else if ((cur_list.mode_field == vmode) && (cur_list.head_field == cur_list.tail_field)) {
- you_cant();
- help2("Sorry...I usually can't take things from the current page.",
- "This \\lastbox will therefore be void.");
- error();
- } else {
- if (cur_list.head_field != cur_list.tail_field) {
- /* todo: new code, needs testing */
-
- /* maybe: ((type(cur_list.tail_field) == hlist_node) < rule_node) */
-
- if ((type(cur_list.tail_field) == hlist_node) || (type(cur_list.tail_field) == vlist_node)) {
- /* Remove the last box ... */
- q = alink(cur_list.tail_field);
- if (q == null || vlink(q) != cur_list.tail_field) {
- q = cur_list.head_field;
- while (vlink(q) != cur_list.tail_field)
- q = vlink(q);
- }
- uncouple_node(cur_list.tail_field);
- cur_box = cur_list.tail_field;
- shift_amount(cur_box) = 0;
- cur_list.tail_field = q;
- vlink(cur_list.tail_field) = null;
- }
- }
- }
- break;
- case vsplit_code:
- /*
- Split off part of a vertical box, make |cur_box| point to it. Here we
- deal with things like `\.{\\vsplit 13 to 100pt}'.
- */
- scan_register_num();
- n = cur_val;
- if (scan_keyword("upto")) {
- split_mode = additional ;
- } else if (!scan_keyword("to")) {
- print_err("Missing `to' inserted");
- help2("I'm working on `\\vsplit<box number> to <dimen>';",
- "will look for the <dimen> next.");
- error();
- }
- scan_normal_dimen();
- cur_box = vsplit(n, cur_val, split_mode);
- break;
- default:
- /*
- Initiate the construction of an hbox or vbox, then |return|. Here is
- where we enter restricted horizontal mode or internal vertical mode,
- in order to make a box.
- */
- switch (cur_chr) {
- case tpack_code:
- cur_chr = vtop_code;
- just_pack = 1;
- break;
- case vpack_code:
- cur_chr = vtop_code + vmode;
- just_pack = 1;
- break;
- case hpack_code:
- cur_chr = vtop_code + hmode;
- just_pack = 1;
- break;
- }
- /* */
- k = cur_chr - vtop_code;
- set_saved_record(0, saved_boxcontext, 0, box_context);
- switch (abs(cur_list.mode_field)) {
- case vmode:
- spec_direction = body_direction_par;
- break;
- case hmode:
- spec_direction = text_direction_par;
- break;
- case mmode:
- spec_direction = math_direction_par;
- break;
- }
- if (k == hmode) {
- if ((box_context < box_flag) && (abs(cur_list.mode_field) == vmode))
- scan_full_spec(adjusted_hbox_group, spec_direction,just_pack);
- else
- scan_full_spec(hbox_group, spec_direction,just_pack);
- } else {
- if (k == vmode) {
- scan_full_spec(vbox_group, spec_direction,just_pack);
- } else {
- scan_full_spec(vtop_group, spec_direction,just_pack);
- k = vmode;
- }
- normal_paragraph();
- }
- push_nest();
- cur_list.mode_field = -k;
- if (k == vmode) {
- prev_depth_par = ignore_depth;
- if (every_vbox_par != null)
- begin_token_list(every_vbox_par, every_vbox_text);
- } else {
- space_factor_par = 1000;
- if (every_hbox_par != null)
- begin_token_list(every_hbox_par, every_hbox_text);
- }
- return;
- break;
- }
- /* in simple cases, we use the box immediately */
- box_end(box_context);
-}