texlinebreak.h /size: 9404 b    last modification: 2025-02-21 11:03
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
45// typedef enum fitness_value {
46//     very_loose_fit,       /*tex lines stretching more than their stretchability */
47//     loose_fit,
48//     almost_loose_fit,     /*tex lines stretching 0.5 to 1.0 of their stretchability */
49//     barely_loose_fit,
50//     decent_fit,           /*tex for all other lines */
51//     barely_tight_fit,
52//     almost_tight_fit,     /*tex lines shrinking 0.5 to 1.0 of their shrinkability */
53//     tight_fit,
54//     very_tight_fit,
55//     n_of_finess_values,   /* also padding */
56// } fitness_value;
57
58/*tex
59
60    Some of the next variables can now be local but I don't want to divert too much from the
61    orginal, so for now we keep them in the info variable.
62
63*/
64
65typedef halfword fitcriterion[max_n_of_fitness_values] ;
66
67typedef struct break_passes { 
68    int n_of_break_calls;
69    int n_of_first_passes;
70    int n_of_second_passes;
71    int n_of_final_passes;
72    int n_of_specification_passes;
73    int n_of_sub_passes;
74    int n_of_left_twins; 
75    int n_of_right_twins; 
76} break_passes;
77
78typedef struct linebreak_state_info {
79    /*tex the |hlist_node| for the last line of the new paragraph */
80    halfword     just_box;
81    halfword     last_line_fill;
82    int          no_shrink_error_yet;
83    int          threshold;
84    halfword     quality;
85    int          callback_id; 
86    int          obey_hyphenation;
87    int          force_check_hyphenation;
88    halfword     adjust_spacing;
89    halfword     adjust_spacing_step;
90    halfword     adjust_spacing_shrink;
91    halfword     adjust_spacing_stretch;
92    halfword     current_font_step;
93    scaled       extra_background_stretch;
94    halfword     passive;
95    halfword     printed_node;
96    halfword     serial_number;
97    scaled       active_width[n_of_glue_amounts];
98    scaled       background[n_of_glue_amounts];
99    scaled       break_width[n_of_glue_amounts];
100    scaled       disc_width[n_of_glue_amounts];
101    scaled       fill_width[4];
102    halfword     internal_interline_penalty;
103    halfword     internal_broken_penalty;
104    halfword     internal_left_box;
105    scaled       internal_left_box_width;
106    halfword     internal_left_box_init;       /* hm: |_init| */
107    scaled       internal_left_box_width_init; /* hm: |_init| */
108    halfword     internal_right_box;
109    scaled       internal_right_box_width;
110    scaled       internal_middle_box;
111    fitcriterion minimal_demerits;
112    halfword     minimum_demerits;
113    halfword     easy_line;
114    halfword     last_special_line;
115    scaled       first_width;
116    scaled       second_width;
117    scaled       first_indent;
118    scaled       second_indent;
119    scaled       emergency_amount;
120    halfword     emergency_percentage;
121    halfword     emergency_factor;
122    scaled       emergency_width_amount;
123    halfword     emergency_width_extra;
124    scaled       emergency_left_amount;
125    halfword     emergency_left_extra;
126    scaled       emergency_right_amount;
127    halfword     emergency_right_extra;
128    halfword     best_bet;
129    halfword     fewest_demerits;
130    halfword     best_line;
131    halfword     actual_looseness;
132    int          do_last_line_fit;
133    halfword     dir_ptr;
134    halfword     warned;
135    halfword     calling_back;
136    int          saved_threshold;   /*tex Saves the value outside inline math. */
137    int          global_threshold;  /*tex Saves the value outside local par states. */
138    int          checked_expansion; 
139    int          line_break_dir;
140    break_passes passes[n_of_par_context_codes];
141    int          n_of_left_twins;
142    int          n_of_right_twins;
143    int          n_of_double_twins;
144    halfword     internal_par_node;
145    halfword     emergency_left_skip;
146    halfword     emergency_right_skip;
147    int          artificial_encountered; 
148    halfword     inject_after_par;
149    int          current_line_number; 
150    int          has_orphans;
151    int          has_toddlers; /* < 0: not found, == 0: tobechecked, > 0: #found */
152} linebreak_state_info;
153
154extern linebreak_state_info lmt_linebreak_state;
155
156typedef enum linebreak_quality_states { 
157    par_has_glyph    = 0x0001, 
158    par_has_disc     = 0x0002, 
159    par_has_math     = 0x0004,
160    par_has_space    = 0x0008,
161    par_has_glue     = 0x0010,
162    par_has_uleader  = 0x0020,
163    par_has_factor   = 0x0040,
164    par_has_optional = 0x0100,
165    par_is_overfull  = 0x0200,
166    par_is_underfull = 0x0400,
167} linebreak_quality_states;
168
169# define paragraph_has_text(state)     ((state & par_has_glyph) || (state & par_has_disc))
170# define paragraph_has_math(state)     (state & par_has_math)
171# define paragraph_has_glue(state)     (state & par_has_glue)
172# define paragraph_has_factor(state)   (state & par_has_factor)
173# define paragraph_has_optional(state) (state & par_has_optional)
174
175extern void tex_line_break_prepare (
176    halfword  par, 
177    halfword *tail, 
178    halfword *parinit_left_skip_glue,
179    halfword *parinit_right_skip_glue,
180    halfword *parfill_left_skip_glue,
181    halfword *parfill_right_skip_glue,
182    halfword *final_line_penalty
183);
184
185extern void tex_check_fitness_classes(
186    halfword fitnessclasses
187);
188
189extern halfword tex_default_fitness_classes(
190    void
191);
192
193extern void tex_line_break (
194    int group_context,
195    int par_context,
196    int display_math 
197);
198
199extern void tex_initialize_active (
200    void
201);
202
203extern void tex_get_linebreak_info (
204    int *f, 
205    int *a
206);
207
208extern void tex_do_line_break (
209    line_break_properties *properties
210);
211
212extern halfword tex_wipe_margin_kerns(
213    halfword head
214);
215
216/*tex
217
218    We can have skipable nodes at the margins during character protrusion. Two extra functions are
219    defined for usage in |cp_skippable|.
220
221*/
222
223static inline int tex_zero_box_dimensions(halfword a)
224{
225    return box_width(a) == 0 && box_height(a) == 0 && box_depth(a) == 0;
226}
227
228static inline int tex_zero_rule_dimensions(halfword a)
229{
230    return rule_width(a) == 0 && rule_height(a) == 0 && rule_depth(a) == 0;
231}
232
233static inline int tex_empty_disc(halfword a)
234{
235    return (! disc_pre_break_head(a)) && (! disc_post_break_head(a)) && (! disc_no_break_head(a));
236}
237
238static inline int tex_protrusion_skipable(halfword a)
239{
240    if (a) {
241        switch (node_type(a)) {
242            case glyph_node:
243                return 0;
244            case glue_node:
245                return tex_glue_is_zero(a);
246            case disc_node:
247                return tex_empty_disc(a);
248            case kern_node:
249                return (kern_amount(a) == 0) || (node_subtype(a) == font_kern_subtype);
250            case rule_node:
251                return tex_zero_rule_dimensions(a);
252            case math_node:
253                return (math_surround(a) == 0) || tex_math_glue_is_zero(a);
254            case hlist_node:
255                return (! box_list(a)) && tex_zero_box_dimensions(a);
256            case penalty_node:
257            case dir_node:
258            case par_node:
259            case insert_node:
260            case mark_node:
261            case adjust_node:
262            case boundary_node:
263            case whatsit_node:
264                return 1;
265        }
266    }
267    return 0;
268 }
269
270static inline void tex_append_list(halfword head, halfword tail)
271{
272    tex_couple_nodes(cur_list.tail, node_next(head));
273    cur_list.tail = tail;
274}
275
276extern void tex_get_line_content_range(
277    halfword  head, 
278    halfword  tail, 
279    halfword *first, 
280    halfword *last
281); 
282
283/*tex Some more shared helpers: */
284
285extern void tex_aux_print_break_node(
286    halfword active, 
287    halfword passive, 
288    int      do_last_line_fit
289);
290
291extern void tex_aux_print_feasible_break(
292    halfword current, 
293    halfword breakpoint, 
294    halfword badness, 
295    halfword penalty, 
296    halfword d, 
297    halfword artificial_demerits, 
298    halfword fit_class, 
299    halfword printed_node
300);
301
302
303# endif
304