1
4
5# include "luametatex.h"
6
7typedef struct adjust_properties {
8 halfword options;
9 halfword code;
10 halfword index;
11 scaled depthbefore;
12 scaled depthafter;
13 halfword attrlist;
14} adjust_properties;
15
16typedef enum saved_adjust_entries {
17 saved_adjust_location_entry = 0,
18 saved_adjust_options_entry = 0,
19 saved_adjust_index_entry = 0,
20 saved_adjust_attr_list_entry = 1,
21 saved_adjust_depth_before_entry = 1,
22 saved_adjust_depth_after_entry = 1,
23 saved_adjust_target_entry = 2,
24 saved_adjust_n_of_records = 3,
25} saved_adjust_entries;
26
27inline static void saved_adjust_initialize(void)
28{
29 saved_type(0) = saved_record_0;
30 saved_type(1) = saved_record_1;
31 saved_type(2) = saved_record_2;
32 saved_record(0) = adjust_save_type;
33 saved_record(1) = adjust_save_type;
34 saved_record(2) = adjust_save_type;
35}
36
37# define saved_adjust_location saved_value_1(saved_adjust_location_entry)
38# define saved_adjust_options saved_value_2(saved_adjust_options_entry)
39# define saved_adjust_index saved_value_3(saved_adjust_index_entry)
40# define saved_adjust_attr_list saved_value_1(saved_adjust_attr_list_entry)
41# define saved_adjust_depth_before saved_value_2(saved_adjust_depth_before_entry)
42# define saved_adjust_depth_after saved_value_3(saved_adjust_depth_after_entry)
43# define saved_adjust_target saved_value_1(saved_adjust_target_entry)
44
45void tex_show_adjust_group(void)
46{
47 tex_print_str_esc("vadjust");
48 if (saved_adjust_location == pre_adjust_code) {
49 tex_print_str(" pre");
50 }
51 if (saved_adjust_options & adjust_option_before) {
52 tex_print_str(" before");
53 }
54}
55
56int tex_show_adjust_record(void)
57{
58 tex_print_str("adjust ");
59 switch (saved_type(0)) {
60 case saved_record_0:
61 tex_print_format("location %i, options %i, index %i", saved_value_1(0), saved_value_2(0), saved_value_3(0));
62 break;
63 case saved_record_1:
64 tex_print_format("attrlist %i, depth before %p, depth after %p", saved_value_1(0), saved_value_2(0), saved_value_3(0));
65 break;
66 case saved_record_2:
67 tex_print_format("target %i", saved_value_1(0));
68 break;
69 default:
70 return 0;
71 }
72 return 1;
73}
74
75static void tex_scan_adjust_keys(adjust_properties *properties)
76{
77 properties->code = post_adjust_code;
78 properties->options = adjust_option_none;
79 properties->index = 0;
80 properties->depthbefore = 0;
81 properties->depthafter = 0;
82 properties->attrlist = null;
83 while (1) {
84 switch (tex_scan_character("abdipABDIP", 0, 1, 0)) {
85 case 'p': case 'P':
86 switch (tex_scan_character("roRO", 0, 0, 0)) {
87 case 'r': case 'R':
88 if (tex_scan_mandate_keyword("pre", 2)) {
89 properties->code = pre_adjust_code;
90 }
91 break;
92 case 'o': case 'O':
93 if (tex_scan_mandate_keyword("post", 2)) {
94 properties->code = post_adjust_code;
95 }
96 break;
97 default:
98 tex_aux_show_keyword_error("pre|post");
99 goto DONE;
100 }
101 break;
102 case 'b': case 'B':
103 switch (tex_scan_character("aeAE", 0, 0, 0)) {
104 case 'a': case 'A':
105 if (tex_scan_mandate_keyword("baseline", 2)) {
106 properties->options |= adjust_option_baseline;
107 }
108 break;
109 case 'e': case 'E':
110 if (tex_scan_mandate_keyword("before", 2)) {
111 properties->options |= adjust_option_before;
112 }
113 break;
114 default:
115 tex_aux_show_keyword_error("baseline|before");
116 goto DONE;
117 }
118 break;
119 case 'i': case 'I':
120 if (tex_scan_mandate_keyword("index", 1)) {
121 properties->index = tex_scan_integer(0, NULL);
122 if (! tex_valid_adjust_index(properties->index)) {
123 properties->index = 0;
124 }
125 }
126 break;
127 case 'a': case 'A':
128 switch (tex_scan_character("ftFT", 0, 0, 0)) {
129 case 'f': case 'F':
130 if (tex_scan_mandate_keyword("after", 2)) {
131 properties->options &= ~(adjust_option_before | properties->options);
132 }
133 break;
134 case 't': case 'T':
135 if (tex_scan_mandate_keyword("attr", 2)) {
136 properties->attrlist = tex_scan_attribute(properties->attrlist);
137 }
138 break;
139 default:
140 tex_aux_show_keyword_error("after|attr");
141 goto DONE;
142 }
143 break;
144 case 'd': case 'D':
145 if (tex_scan_mandate_keyword("depth", 1)) {
146 switch (tex_scan_character("abclABCL", 0, 1, 0)) {
147 case 'a': case 'A':
148 if (tex_scan_mandate_keyword("after", 1)) {
149 properties->options |= adjust_option_depth_after;
150 properties->depthafter = tex_scan_dimension(0, 0, 0, 0, NULL);
151 }
152 break;
153 case 'b': case 'B':
154 if (tex_scan_mandate_keyword("before", 1)) {
155 properties->options |= adjust_option_depth_before;
156 properties->depthbefore = tex_scan_dimension(0, 0, 0, 0, NULL);
157 }
158 break;
159 case 'c': case 'C':
160 if (tex_scan_mandate_keyword("check", 1)) {
161 properties->options |= adjust_option_depth_check;
162 }
163 break;
164 case 'l': case 'L':
165 if (tex_scan_mandate_keyword("last", 1)) {
166 properties->options |= adjust_option_depth_last;
167 }
168 break;
169 default:
170 tex_aux_show_keyword_error("after|before|check|last");
171 goto DONE;
172 }
173 }
174 break;
175 default:
176 goto DONE;
177 }
178 }
179 DONE:
180 if (! properties->attrlist) {
181 properties->attrlist = tex_current_attribute_list();
182 add_attribute_reference(properties->attrlist);
183 }
184}
185
186int tex_valid_adjust_index(halfword n)
187{
188 return n >= 0;
189}
190
191void tex_set_vadjust(halfword target)
192{
193 adjust_properties properties;
194 tex_scan_adjust_keys(&properties);
195 saved_adjust_initialize();
196 saved_adjust_location = properties.code;
197 saved_adjust_options = properties.options;
198 saved_adjust_index = properties.index;
199 saved_adjust_attr_list = properties.attrlist;
200 saved_adjust_depth_before = properties.depthbefore;
201 saved_adjust_depth_after = properties.depthafter;
202 saved_adjust_target = target;
203 lmt_save_state.save_stack_data.ptr += saved_adjust_n_of_records;
204 tex_new_save_level(vadjust_group);
205 tex_scan_left_brace();
206 tex_normal_paragraph(vadjust_par_context);
207 tex_push_nest();
208 cur_list.mode = internal_vmode;
209 cur_list.prev_depth = ignore_depth_criterion_par;
210}
211
212void tex_run_vadjust(void)
213{
214 tex_set_vadjust(-1);
215}
216
217void tex_finish_vadjust_group(void)
218{
219 if (! tex_wrapped_up_paragraph(vadjust_par_context, 0)) {
220 halfword box, adjust, target;
221 tex_end_paragraph(vadjust_group, vadjust_par_context);
222 tex_unsave();
223 lmt_save_state.save_stack_data.ptr -= saved_adjust_n_of_records;
224 box = tex_vpack(node_next(cur_list.head), 0, packing_additional, max_dimension, direction_unknown, holding_none_option, NULL);
225 tex_pop_nest();
226 adjust = tex_new_node(adjust_node, (quarterword) saved_adjust_location);
227 target = saved_adjust_target;
228 adjust_list(adjust) = box_list(box);
229 adjust_options(adjust) = (halfword) saved_adjust_options;
230 adjust_index(adjust) = (halfword) saved_adjust_index;
231 adjust_depth_before(adjust) = (halfword) saved_adjust_depth_before;
232 adjust_depth_after(adjust) = (halfword) saved_adjust_depth_after;
233 tex_attach_attribute_list_attribute(adjust, (halfword) saved_adjust_attr_list);
234 if (target < 1) {
235 tex_tail_append(adjust);
236 } else {
237 tex_adjust_attach(target, adjust);
238 }
239 box_list(box) = null;
240 tex_flush_node(box);
241
242 if (target < 0 && lmt_nest_state.nest_data.ptr == 0) {
243 tex_build_page(vadjust_page_context, 0);
244 }
245 }
246}
247
248
249
250halfword tex_append_adjust_list(halfword head, halfword tail, halfword adjust, const char *detail)
251{
252 while (adjust && node_type(adjust) == adjust_node) {
253 halfword next = node_next(adjust);
254 if (tail == head) {
255 node_next(head) = adjust;
256 } else {
257 tex_couple_nodes(tail, adjust);
258 }
259 if (tracing_adjusts_par > 1) {
260 tex_begin_diagnostic();
261 tex_print_format("[adjust: index %i, location %s, append, %s]", adjust_index(adjust), tex_aux_subtype_str(adjust), detail);
262 tex_print_node_list(adjust_list(adjust), "adjust",show_box_depth_par, show_box_breadth_par);
263 tex_end_diagnostic();
264 }
265 tail = adjust;
266 adjust = next;
267 }
268 return tail;
269}
270
271halfword tex_prepend_adjust_list(halfword head, halfword tail, halfword adjust, const char *detail)
272{
273 while (adjust && node_type(adjust) == adjust_node) {
274 halfword next = node_next(adjust);
275 if (tail == head) {
276 node_next(head) = adjust;
277 tail = adjust;
278 } else {
279 tex_try_couple_nodes(adjust, node_next(node_next(head)));
280 tex_couple_nodes(node_next(head), adjust);
281 }
282 if (tracing_adjusts_par > 1) {
283 tex_begin_diagnostic();
284 tex_print_format("[adjust: index %i, location %s, prepend, %s]", adjust_index(adjust), tex_aux_subtype_str(adjust), detail);
285 tex_print_node_list(adjust_list(adjust), "adjust", show_box_depth_par, show_box_breadth_par);
286 tex_end_diagnostic();
287 }
288 adjust = next;
289 }
290 return tail;
291}
292
293void tex_inject_adjust_list(halfword adjust, int obeyoptions, halfword nextnode, const line_break_properties *properties)
294{
295 if (adjust && node_type(adjust) == temp_node) {
296 adjust = node_next(adjust);
297 }
298 while (adjust && node_type(adjust) == adjust_node) {
299 halfword next = node_next(adjust);
300 halfword list = adjust_list(adjust);
301 if (tracing_adjusts_par > 1) {
302 tex_begin_diagnostic();
303 tex_print_format("[adjust: index %i, location %s, inject]", adjust_index(adjust), tex_aux_subtype_str(adjust));
304 tex_print_node_list(adjust_list(adjust), "adjust", show_box_depth_par, show_box_breadth_par);
305 tex_end_diagnostic();
306 }
307 if (list) {
308 if (obeyoptions && has_adjust_option(adjust, adjust_option_baseline)) {
309
313 if (node_type(list) == hlist_node || node_type(list) == vlist_node) {
314 if (nextnode) {
315
319 if (node_type(nextnode) == hlist_node || node_type(nextnode) == vlist_node) {
320 if (box_height(nextnode) > box_height(list)) {
321 box_height(list) = box_height(nextnode);
322 }
323 if (box_depth(list) > box_depth(nextnode)) {
324 box_depth(nextnode) = box_depth(list);
325 }
326
327 box_y_offset(nextnode) += box_height(nextnode);
328 tex_check_box_geometry(nextnode);
329
330 box_height(nextnode) = 0;
331 box_depth(list) = 0;
332 }
333 } else {
334
338 halfword prevnode = cur_list.tail;
339 if (node_type(prevnode) == hlist_node || node_type(prevnode) == vlist_node) {
340 if (box_height(prevnode) < box_height(list)) {
341 box_height(prevnode) = box_height(list);
342 }
343 if (box_depth(list) < box_depth(prevnode)) {
344 box_depth(list) = box_depth(prevnode);
345 }
346 box_height(list) = 0;
347 box_depth(prevnode) = 0;
348 }
349 }
350 }
351 }
352 if (obeyoptions && has_adjust_option(adjust, adjust_option_depth_before)) {
353 cur_list.prev_depth = adjust_depth_before(adjust);
354 }
355 if (obeyoptions && has_adjust_option(adjust, adjust_option_depth_check)) {
356 tex_append_to_vlist(list, -1, properties);
357 } else {
358 tex_tail_append_list(list);
359
360
361 }
362 if (obeyoptions && has_adjust_option(adjust, adjust_option_depth_after)) {
363 cur_list.prev_depth = adjust_depth_after(adjust);
364 } else if (obeyoptions && has_adjust_option(adjust, adjust_option_depth_last)) {
365 cur_list.prev_depth = box_depth(list);
366 }
367
368 if (! lmt_page_builder_state.output_active) {
369 lmt_append_line_filter_callback(post_adjust_append_line_context, adjust_index(adjust));
370 }
371 adjust_list(adjust) = null;
372 }
373 tex_flush_node(adjust);
374 adjust = next;
375 }
376}
377
378void tex_adjust_attach(halfword box, halfword adjust)
379{
380 if (adjust_list(adjust)) {
381 node_prev(adjust) = null;
382 node_next(adjust) = null;
383 if (tracing_adjusts_par > 1) {
384 tex_begin_diagnostic();
385 tex_print_format("[adjust: index %i, location %s, attach]", adjust_index(adjust), tex_aux_subtype_str(adjust));
386 tex_print_node_list(adjust_list(adjust), "attach",show_box_depth_par, show_box_breadth_par);
387 tex_end_diagnostic();
388 }
389 switch (node_subtype(adjust)) {
390 case pre_adjust_code:
391 if (! box_pre_adjusted(box)) {
392 box_pre_adjusted(box) = adjust;
393 } else if (has_adjust_option(adjust, adjust_option_before)) {
394 tex_couple_nodes(adjust, box_pre_adjusted(box));
395 box_pre_adjusted(box) = adjust;
396 } else {
397 tex_couple_nodes(tex_tail_of_node_list(box_pre_adjusted(box)), adjust);
398 }
399 node_subtype(adjust) = local_adjust_code;
400 break;
401 case post_adjust_code:
402 if (! box_post_adjusted(box)) {
403 box_post_adjusted(box) = adjust;
404 } else if (has_adjust_option(adjust, adjust_option_before)) {
405 tex_couple_nodes(adjust, box_post_adjusted(box));
406 box_post_adjusted(box) = adjust;
407 } else {
408 tex_couple_nodes(tex_tail_of_node_list(box_post_adjusted(box)), adjust);
409 }
410 node_subtype(adjust) = local_adjust_code;
411 break;
412 case local_adjust_code:
413 tex_normal_error("vadjust post", "unexpected local attach");
414 break;
415 }
416 } else {
417 tex_flush_node(adjust);
418 }
419}
420
421void tex_adjust_passon(halfword box, halfword adjust)
422{
423 halfword head = adjust ? adjust_list(adjust) : null;
424 (void) box;
425 if (head) {
426 node_prev(adjust) = null;
427 node_next(adjust) = null;
428 switch (node_subtype(adjust)) {
429 case pre_adjust_code:
430 if (lmt_packaging_state.pre_adjust_tail) {
431 if (lmt_packaging_state.pre_adjust_tail != pre_adjust_head && has_adjust_option(adjust, adjust_option_before)) {
432 lmt_packaging_state.pre_adjust_tail = tex_prepend_adjust_list(pre_adjust_head, lmt_packaging_state.pre_adjust_tail, adjust, "passon");
433 } else {
434 lmt_packaging_state.pre_adjust_tail = tex_append_adjust_list(pre_adjust_head, lmt_packaging_state.pre_adjust_tail, adjust, "passon");
435 }
436 } else {
437 tex_normal_error("vadjust pre", "invalid list");
438 }
439 break;
440 case post_adjust_code:
441 if (lmt_packaging_state.post_adjust_tail) {
442 if (lmt_packaging_state.post_adjust_tail != post_adjust_head && has_adjust_option(adjust, adjust_option_before)) {
443 lmt_packaging_state.post_adjust_tail = tex_prepend_adjust_list(post_adjust_head, lmt_packaging_state.post_adjust_tail, adjust, "passon");
444 } else {
445 lmt_packaging_state.post_adjust_tail = tex_append_adjust_list(post_adjust_head, lmt_packaging_state.post_adjust_tail, adjust, "passon");
446 }
447 } else {
448 tex_normal_error("vadjust post", "invalid list");
449 }
450 break;
451 case local_adjust_code:
452 tex_normal_error("vadjust post", "unexpected local passon");
453 break;
454 }
455 } else {
456 tex_flush_node(adjust);
457 }
458}
459
460static void tex_aux_show_flush_adjust(halfword adjust, const char *what, const char *detail)
461{
462 if (tracing_adjusts_par > 1) {
463 tex_begin_diagnostic();
464 tex_print_format("[adjust: index %i, location %s, flush, %s]", adjust_index(adjust), tex_aux_subtype_str(adjust), detail);
465 tex_print_node_list(adjust_list(adjust), what, show_box_depth_par, show_box_breadth_par);
466 tex_end_diagnostic();
467 }
468}
469
470halfword tex_flush_adjust_append(halfword adjust, halfword tail)
471{
472 while (adjust) {
473 halfword p = adjust;
474 halfword h = adjust_list(adjust);
475 if (h) {
476 int ishmode = is_h_mode(cur_list.mode);
477 tex_aux_show_flush_adjust(p, "append", ishmode ? "repack" : "direct");
478 if (ishmode) {
479 halfword n = tex_new_node(adjust_node, post_adjust_code);
480
481 adjust_list(n) = h;
482 h = n;
483 }
484 tex_try_couple_nodes(tail, h);
485 tail = tex_tail_of_node_list(h);
486 adjust_list(p) = null;
487 }
488 adjust = node_next(p);
489 tex_flush_node(p);
490 }
491 return tail;
492}
493
494halfword tex_flush_adjust_prepend(halfword adjust, halfword tail)
495{
496 while (adjust) {
497 halfword p = adjust;
498 halfword h = adjust_list(adjust);
499 if (h) {
500 int ishmode = is_h_mode(cur_list.mode);
501 tex_aux_show_flush_adjust(p, "prepend", ishmode ? "repack" : "direct");
502 if (ishmode) {
503 halfword n = tex_new_node(adjust_node, pre_adjust_code);
504
505 adjust_list(n) = h;
506 h = n;
507 }
508 tex_try_couple_nodes(tail, h);
509 tail = tex_tail_of_node_list(h);
510 adjust_list(p) = null;
511 }
512 adjust = node_next(p);
513 tex_flush_node(p);
514 }
515 return tail;
516}
517
518void tex_initialize_adjust(void)
519{
520}
521
522void tex_cleanup_adjust(void)
523{
524}
525 |