texlinebreak.h /size: 6646 b    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# ifndef LMT_LINEBREAK_H
6# define LMT_LINEBREAK_H
7
8// # define max_hlist_stack 1024 /*tex This should be more than enough for sane usage. */
9
10
11/*tex
12
13    When looking for optimal line breaks, \TEX\ creates a \quote {break node} for each break that
14    is {\em feasible}, in the sense that there is a way to end a line at the given place without
15    requiring any line to stretch more than a given tolerance. A break node is characterized by
16    three things: the position of the break (which is a pointer to a |glue_node|, |math_node|,
17    |penalty_node|, or |disc_node|); the ordinal number of the line that will follow this breakpoint;
18    and the fitness classification of the line that has just ended, i.e., |tight_fit|, |decent_fit|,
19    |loose_fit|, or |very_loose_fit|.
20
21    Todo: 0..0.25 / 0.25-0.50 / 0.50-0.75 / 0.75-1.00
22
23    TeX by Topic gives a good explanation of the way lines are broken.
24
25    veryloose stretch badness >= 100
26    loose     stretch badness >= 13
27    decent            badness <= 12
28    tight     shrink  badness >= 13
29
30    adjacent  delta two lines > 1 : visually incompatible
31
32    if badness of any line > pretolerance : second pass
33    if pretolerance < 0                   : first pass is skipped
34    if badness of any line > tolerance    : third pass (with emergencystretch)
35
36    in lua(meta)tex: always hypnehenated lists (in regular tex second pass+)
37
38    badness of 800 : stretch ratio 2
39
40    One day I will play with a pluggedin badness calculation but there os some performance impact 
41    there as well as danger to overflow (unless we go double or very long integers). 
42
43*/
44
45typedef enum fitness_value {
46    very_loose_fit, /*tex lines stretching more than their stretchability */
47    loose_fit,      /*tex lines stretching 0.5 to 1.0 of their stretchability */
48    semi_loose_fit,
49    decent_fit,     /*tex for all other lines */
50    semi_tight_fit,
51    tight_fit,      /*tex lines shrinking 0.5 to 1.0 of their shrinkability */
52    n_of_finess_values
53} fitness_value;
54
55/*tex
56
57    Some of the next variables can now be local but I don't want to divert too much from the
58    orginal, so for now we keep them in the info variable.
59
60*/
61
62typedef struct linebreak_state_info {
63    /*tex the |hlist_node| for the last line of the new paragraph */
64    halfword just_box;
65    halfword last_line_fill;
66    int      no_shrink_error_yet;
67    int      second_pass;
68    int      final_pass;
69    int      threshold;
70    halfword adjust_spacing;
71    halfword adjust_spacing_step;
72    halfword adjust_spacing_shrink;
73    halfword adjust_spacing_stretch;
74    int      max_stretch_ratio;
75    int      max_shrink_ratio;
76    halfword current_font_step;
77    halfword passive;
78    halfword printed_node;
79    halfword pass_number;
80 /* int      auto_breaking; */ /* is gone */
81 /* int      math_level;    */ /* was never used */
82    scaled   active_width[n_of_glue_amounts];
83    scaled   background[n_of_glue_amounts];
84    scaled   break_width[n_of_glue_amounts];
85    scaled   disc_width[n_of_glue_amounts];
86    scaled   fill_width[4];
87    halfword internal_penalty_interline;
88    halfword internal_penalty_broken;
89    halfword internal_left_box;
90    scaled   internal_left_box_width;
91    halfword internal_left_box_init;
92    scaled   internal_left_box_width_init;
93    halfword internal_right_box;
94    scaled   internal_right_box_width;
95    scaled   internal_middle_box;
96    halfword minimal_demerits[n_of_finess_values];
97    halfword minimum_demerits;
98    halfword easy_line;
99    halfword last_special_line;
100    scaled   first_width;
101    scaled   second_width;
102    scaled   first_indent;
103    scaled   second_indent;
104    halfword best_bet;
105    halfword fewest_demerits;
106    halfword best_line;
107    halfword actual_looseness;
108    halfword line_difference;
109    int      do_last_line_fit;
110    halfword dir_ptr;
111    halfword warned;
112    halfword calling_back;
113    int      saved_threshold; 
114    int      checked_expansion; 
115    int      line_break_dir;
116} linebreak_state_info;
117
118extern linebreak_state_info lmt_linebreak_state;
119
120typedef enum linebreak_quality { 
121    par_has_glyph    = 0x0001, 
122    par_has_disc     = 0x0002, 
123    par_has_space    = 0x0004,
124    par_has_uleader  = 0x0008,
125    par_is_overfull  = 0x0010,
126    par_is_underfull = 0x0020,
127} linebreak_quality;
128
129void tex_line_break_prepare (
130    halfword par, 
131    halfword *tail, 
132    halfword *parinit_left_skip_glue,
133    halfword *parinit_right_skip_glue,
134    halfword *parfill_left_skip_glue,
135    halfword *parfill_right_skip_glue,
136    halfword *final_line_penalty
137);
138
139extern void tex_line_break (
140    int d, 
141    int line_break_context
142);
143
144extern void tex_initialize_active (
145    void
146);
147
148extern void tex_get_linebreak_info (
149    int *f, 
150    int *a
151);
152
153extern void tex_do_line_break (
154    line_break_properties *properties
155);
156
157extern halfword tex_wipe_margin_kerns(
158    halfword head
159);
160
161/*tex
162
163    We can have skipable nodes at the margins during character protrusion. Two extra functions are
164    defined for usage in |cp_skippable|.
165
166*/
167
168static inline int tex_zero_box_dimensions(halfword a)
169{
170    return box_width(a) == 0 && box_height(a) == 0 && box_depth(a) == 0;
171}
172
173static inline int tex_zero_rule_dimensions(halfword a)
174{
175    return rule_width(a) == 0 && rule_height(a) == 0 && rule_depth(a) == 0;
176}
177
178static inline int tex_empty_disc(halfword a)
179{
180    return (! disc_pre_break_head(a)) && (! disc_post_break_head(a)) && (! disc_no_break_head(a));
181}
182
183static inline int tex_protrusion_skipable(halfword a)
184{
185    if (a) {
186        switch (node_type(a)) {
187            case glyph_node:
188                return 0;
189            case glue_node:
190                return tex_glue_is_zero(a);
191            case disc_node:
192                return tex_empty_disc(a);
193            case kern_node:
194                return (kern_amount(a) == 0) || (node_subtype(a) == font_kern_subtype);
195            case rule_node:
196                return tex_zero_rule_dimensions(a);
197            case math_node:
198                return (math_surround(a) == 0) || tex_math_glue_is_zero(a);
199            case hlist_node:
200                return (! box_list(a)) && tex_zero_box_dimensions(a);
201            case penalty_node:
202            case dir_node:
203            case par_node:
204            case insert_node:
205            case mark_node:
206            case adjust_node:
207            case boundary_node:
208            case whatsit_node:
209                return 1;
210        }
211    }
212    return 0;
213 }
214
215static inline void tex_append_list(halfword head, halfword tail)
216{
217    tex_couple_nodes(cur_list.tail, node_next(head));
218    cur_list.tail = tail;
219}
220
221# endif
222