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