texrules.c /size: 14 Kb    last modification: 2025-02-21 11:03
1/*
2    See license.txt in the root of this project.
3*/
4
5# include "luametatex.h"
6
7/*tex 
8
9    We have a a limited set of codes (normal, empty, strut and virtual) but at the \LUA\ end one
10    can have more subtypes, like outline or image. The four common ones have the same numbers but 
11    the codes are (as usual) used in the primitive commands. 
12
13    In theory we could win some on also supporting shorter keywords but in the current setup there 
14    is little gain (e.g. 50K times nothing 0.004, one 0.007, two 0.010 and three 0.013, and in 
15    practice scanning the dimension takes much of that). 
16
17    \starttabulate[|Tl|Tl|]
18    \NC wd  \NC dimen \NC \NR
19    \NC ht  \NC dimen \NC \NR 
20    \NC dp  \NC dimen  \NC \NR
21    \NC hd  \NC dimen dimen \NC \NR
22    \NC whd \NC dimen dimen dimen \NC \NR
23    \stoptabulate 
24
25    Virtual rules don't accept |left|, |right|,  |top|, |bottom|, |char|, |font| and |fam| keys
26    because they use these fields for other purposes. 
27
28    The default nullflags also serve as a signal, for instance un strut rules combined with char 
29    keys. Because a strut is meant for vertical purposes we set the width to zero. 
30
31*/
32
33halfword tex_aux_scan_rule_spec(rule_types type, halfword code)
34{
35    /*tex |width|, |depth|, and |height| all equal |null_flag| now */
36    halfword rule = tex_new_rule_node((quarterword) code); /* here code == subtype */
37    halfword attr = node_attr(rule);
38    if (code == strut_rule_code) { 
39        rule_width(rule) = 0;
40        switch (type) {
41            case h_rule_type:
42                rule_options(rule) |= rule_option_horizontal;
43                break;
44            case v_rule_type:
45                rule_options(rule) |= rule_option_vertical;
46                break;
47            default: 
48                break;
49        }
50    } else { 
51        switch (type) {
52            case h_rule_type:
53                rule_height(rule) = default_rule;
54                rule_depth(rule) = 0;
55                rule_options(rule) |= rule_option_horizontal;
56                break;
57            case v_rule_type:
58                rule_options(rule) |= rule_option_vertical;
59                /* fall through */
60            case m_rule_type:
61                rule_width(rule) = default_rule;
62                break;
63        }
64    }
65    while (1) {
66        switch (tex_scan_character("awhdpxylrtbcfoAWHDPXYLRTBCFO", 0, 1, 0)) {
67            case 0:
68                goto DONE;
69            case 'a': case 'A':
70                if (tex_scan_mandate_keyword("attr", 1)) {
71                    attr = tex_scan_attribute(attr);
72                }
73                break;
74            case 'w': case 'W':
75                if (tex_scan_mandate_keyword("width", 1)) {
76                    rule_width(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
77                }
78                break;
79            case 'h': case 'H':
80                if (tex_scan_mandate_keyword("height", 1)) {
81                    rule_height(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
82                }
83                break;
84            case 'd': case 'D':
85             // if (tex_scan_mandate_keyword("depth", 1)) {
86             //     rule_depth(rule) = tex_scan_dimension(0, 0, 0, 0, NULL);
87             // }
88                switch (tex_scan_character("eiEI", 0, 0, 0)) {
89                    case 'e': case 'E':
90                        if (tex_scan_mandate_keyword("depth", 2)) {
91                            rule_depth(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
92                        }
93                        break;
94                    case 'i': case 'I':
95                        if (tex_scan_mandate_keyword("discardable", 2)) {
96                            rule_options(rule) |= rule_option_discardable;
97                        }
98                        break;
99                    default:
100                        tex_aux_show_keyword_error("depth|discardable");
101                        goto DONE;
102                }
103                break;
104            case 'p': case 'P':
105                if (tex_scan_mandate_keyword("pair", 1)) {
106                    rule_height(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
107                    rule_depth(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
108                }
109                break;
110            case 'l': case 'L':
111                if (code != virtual_rule_code) { 
112                    if (tex_scan_mandate_keyword("left", 1)) {
113                        rule_left(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
114                    }
115                } else { 
116                    goto DONE;
117                }
118                break;
119            case 'r': case 'R':
120                if (code != virtual_rule_code) { 
121                    switch (tex_scan_character("uiUI", 0, 0, 0)) {
122                        case 'u': case 'U':
123                            if (tex_scan_mandate_keyword("running", 2)) {
124                                rule_width(rule) = null_flag;
125                                rule_height(rule) = null_flag;
126                                rule_depth(rule) = null_flag;
127                            }
128                            break;
129                        case 'i': case 'I':
130                            if (tex_scan_mandate_keyword("right", 2)) {
131                                rule_right(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
132                            }
133                            break;
134                        default:
135                            tex_aux_show_keyword_error("right|running");
136                            goto DONE;
137                    }
138                } else {
139                    if (tex_scan_mandate_keyword("running", 1)) {
140                        tex_set_rule_font(rule, tex_scan_font_identifier(NULL));
141                    }
142                }
143                break;
144            case 't': case 'T': /* just because it's nicer */
145                if (code != virtual_rule_code) { 
146                    if (tex_scan_mandate_keyword("top", 1)) {
147                        rule_left(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
148                    }
149                    break;
150                } else {
151                    goto DONE;
152                }
153            case 'b': case 'B': /* just because it's nicer */
154                if (code != virtual_rule_code) { 
155                    if (tex_scan_mandate_keyword("bottom", 1)) {
156                        rule_right(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
157                    }
158                    break;
159                } else {
160                    goto DONE;
161                }
162            case 'x': case 'X':
163                if (tex_scan_mandate_keyword("xoffset", 1)) {
164                    rule_x_offset(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
165                }
166                break;
167            case 'y': case 'Y':
168                if (tex_scan_mandate_keyword("yoffset", 1)) {
169                    rule_y_offset(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
170                }
171                break;
172            case 'f': case 'F':
173                if (code != virtual_rule_code) { 
174                    switch (tex_scan_character("aoAO", 0, 0, 0)) {
175                        case 'o': case 'O':
176                            if (tex_scan_mandate_keyword("font", 2)) {
177                                tex_set_rule_font(rule, tex_scan_font_identifier(NULL));
178                            }
179                            break;
180                        case 'a': case 'A':
181                            if (tex_scan_mandate_keyword("fam", 2)) {
182                                tex_set_rule_family(rule, tex_scan_math_family_number());
183                            }
184                            break;
185                        default:
186                            tex_aux_show_keyword_error("font|fam");
187                            goto DONE;
188                    }
189                    break;
190                } else { 
191                    goto DONE;
192                }
193            case 'o': case 'O':
194                if (code == normal_rule_code) { 
195                    switch (tex_scan_character("nfNF", 0, 0, 0)) {
196                        case 'n': case 'N':
197                            rule_line_on(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
198                            break;
199                        case 'f': case 'F':
200                            if (tex_scan_mandate_keyword("off", 2)) {
201                                rule_line_off(rule) = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
202                            }
203                            break;
204                        default:
205                            tex_aux_show_keyword_error("on|off");
206                            goto DONE;
207                    }
208                    break;
209                } else { 
210                    goto DONE;
211                }
212            case 'c': case 'C':
213                if (code == strut_rule_code) { 
214                    if (tex_scan_mandate_keyword("char", 1)) {
215                        rule_strut_character(rule) = tex_scan_char_number(0);
216                    }
217                    break;
218                } else { 
219                    goto DONE;
220                }
221            default:
222                goto DONE;
223        }
224    }
225  DONE:
226  //  if (! attr) {
227    if (attr) {
228        /* Also bumps reference and replaces the one set. */
229        tex_attach_attribute_list_attribute(rule, attr);
230    }    
231    switch (code) {
232        case strut_rule_code:
233            if (type == v_rule_type) {
234                tex_aux_check_text_strut_rule(rule, text_style);
235            }
236            break;
237        case virtual_rule_code:
238            rule_virtual_width(rule) = rule_width(rule);
239            rule_virtual_height(rule) = rule_height(rule);
240            rule_virtual_depth(rule) = rule_depth(rule);
241            rule_width(rule) = 0;
242            rule_height(rule) = 0;
243            rule_depth(rule) = 0;
244            break;
245    }
246    if (type == h_rule_type) { 
247        if (rule_width(rule) == null_flag) { 
248            rule_options(rule) |= rule_option_running;
249        }
250    } else { 
251        if (rule_height(rule) == null_flag && rule_width(rule) == null_flag) { 
252            rule_options(rule) |= rule_option_running;
253        }
254    }
255    return rule;
256}
257
258void tex_aux_run_vrule(void)
259{
260    tex_tail_append(tex_aux_scan_rule_spec(v_rule_type, cur_chr));
261    cur_list.space_factor = default_space_factor;
262}
263
264void tex_aux_run_hrule(void)
265{
266    tex_tail_append(tex_aux_scan_rule_spec(h_rule_type, cur_chr));
267    cur_list.prev_depth = ignore_depth_criterion_par;
268}
269
270void tex_aux_run_mrule(void)
271{
272    tex_tail_append(tex_aux_scan_rule_spec(m_rule_type, cur_chr));
273}
274
275void tex_aux_check_math_strut_rule(halfword rule, halfword style)
276{
277    if (node_subtype(rule) == strut_rule_subtype) {
278        scaled ht = rule_height(rule);
279        scaled dp = rule_depth(rule);
280        if (ht == null_flag || dp == null_flag) {
281            halfword fnt = tex_get_rule_font(rule, style);
282            halfword chr = rule_strut_character(rule);
283            if (fnt > 0 && chr && tex_char_exists(fnt, chr)) {
284                if (ht == null_flag) {
285                    ht = tex_math_font_char_ht(fnt, chr, style);
286                }
287                if (dp == null_flag) {
288                    dp = tex_math_font_char_dp(fnt, chr, style);
289                }
290            } else {
291                if (ht == null_flag) {
292                    ht = tex_get_math_y_parameter(style, math_parameter_rule_height);
293                }
294                if (dp == null_flag) {
295                    dp = tex_get_math_y_parameter(style, math_parameter_rule_depth);
296                }
297            }
298                rule_height(rule) = ht;
299            rule_depth(rule) = dp;
300        }
301    }
302}
303
304void tex_aux_check_text_strut_rule(halfword rule, halfword style)
305{
306    if (node_subtype(rule) == strut_rule_subtype) {
307        scaled ht = rule_height(rule);
308        scaled dp = rule_depth(rule);
309        if (ht == null_flag || dp == null_flag) {
310            halfword fnt = tex_get_rule_font(rule, style);
311            halfword chr = rule_strut_character(rule);
312            if (fnt > 0 && chr && tex_char_exists(fnt, chr)) {
313                scaledwhd whd = tex_char_whd_from_font(fnt, chr);
314                if (ht == null_flag) {
315                    rule_height(rule) = whd.ht;
316                }
317                if (dp == null_flag) {
318                    rule_depth(rule) = whd.dp;
319                }
320            }
321        }
322    }
323}
324
325halfword tex_get_rule_font(halfword n, halfword style)
326{
327    if (node_subtype(n) != virtual_rule_subtype) {
328        halfword fnt = rule_strut_font(n);
329        if (fnt >= rule_font_fam_offset) {
330            halfword fam = fnt - rule_font_fam_offset;
331            if (fam_par_in_range(fam)) {
332                fnt = tex_fam_fnt(fam, tex_size_of_style(style));
333            }
334       }
335        if (fnt < 0 || fnt >= max_n_of_fonts) {
336            return null_font;
337        } else {
338            return fnt;
339        }
340    } else { 
341        return null_font;
342    }
343}
344
345halfword tex_get_rule_family(halfword n)
346{
347    if (node_subtype(n) != virtual_rule_subtype) {
348        halfword fnt = rule_strut_font(n);
349        if (fnt >= rule_font_fam_offset) {
350            halfword fam = fnt - rule_font_fam_offset;
351            if (fam_par_in_range(fam)) {
352                return fam;
353            }
354        }
355    }
356    return 0;
357}
358
359void tex_set_rule_font(halfword n, halfword fnt)
360{
361    if (node_subtype(n) != virtual_rule_subtype) {
362        if (fnt < 0 || fnt >= rule_font_fam_offset) {
363            rule_strut_font(n) = 0;
364        } else {
365            rule_strut_font(n) = fnt;
366        }
367    }
368}
369
370void tex_set_rule_family(halfword n, halfword fam)
371{
372    if (node_subtype(n) != virtual_rule_subtype) {
373        if (fam < 0 || fam >= max_n_of_math_families) {
374            rule_strut_font(n) = rule_font_fam_offset;
375        } else {
376            rule_strut_font(n) = rule_font_fam_offset + fam;
377        }
378    }
379}
380
381halfword tex_get_rule_left(halfword n)
382{
383    return node_subtype(n) == virtual_rule_subtype ? 0 : rule_left(n); 
384}
385
386halfword tex_get_rule_right(halfword n)
387{
388    return node_subtype(n) == virtual_rule_subtype ? 0 : rule_right(n); 
389}
390
391void tex_set_rule_left(halfword n, halfword value)
392{
393    if (node_subtype(n) != virtual_rule_subtype) {
394        rule_left(n) = value; 
395    }
396}
397
398void tex_set_rule_right(halfword n, halfword value)
399{
400    if (node_subtype(n) != virtual_rule_subtype) {
401        rule_right(n) = value; 
402    }
403}
404
405halfword tex_get_rule_on(halfword n)
406{
407    return node_subtype(n) == normal_rule_subtype ? rule_line_on(n) : 0; 
408}
409
410halfword tex_get_rule_off(halfword n)
411{
412    return node_subtype(n) == normal_rule_subtype ? rule_line_off(n) : 0; 
413}
414
415void tex_set_rule_on(halfword n, halfword value)
416{
417    if (node_subtype(n) == normal_rule_subtype) {
418        rule_line_on(n) = value; 
419    }
420}
421
422void tex_set_rule_off(halfword n, halfword value)
423{
424    if (node_subtype(n) == normal_rule_subtype) {
425        rule_line_off(n) = value; 
426    }
427}
428
429
430