beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / pdf / pdflistout.w
blob2bd15f3cedf481d8db628c848a78d6e33929900a
1 % pdflistout.w
3 % Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software; you can redistribute it and/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation; either version 2 of the License, or (at your
10 % option) any later version.
12 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20 \def\pdfTeX{pdf\TeX}
22 @ @c
23 #include "ptexlib.h"
25 @ @c
26 pos_info_structure pos_info; /* to be accessed from Lua */
28 static backend_struct *backend = NULL;
29 backend_function *backend_out, *backend_out_whatsit;
31 @ @c
32 static void missing_backend_function(PDF pdf, halfword p)
34 const char *n = get_node_name(type(p), subtype(p));
35 if (type(p) == whatsit_node)
36 formatted_error("pdf backend","no output function for whatsit %s",n);
37 else
38 formatted_error("pdf backend","no output function for node %s",n);
41 @ @c
42 static void init_none_backend_functions(void)
44 backend_struct *p = &backend[OMODE_NONE];
45 p->name = strdup("(None)");
48 @ @c
49 static void init_pdf_backend_functions(void)
51 backend_struct *p = &backend[OMODE_PDF];
52 p->name = strdup("PDF");
53 p->node_fu[rule_node] = &pdf_place_rule;
54 p->node_fu[glyph_node] = &pdf_place_glyph;
55 p->whatsit_fu[special_node] = &pdf_special;
56 p->whatsit_fu[pdf_literal_node] = &pdf_out_literal;
57 p->whatsit_fu[pdf_refobj_node] = &pdf_ref_obj;
58 p->whatsit_fu[pdf_annot_node] = &do_annot;
59 p->whatsit_fu[pdf_start_link_node] = &do_link;
60 p->whatsit_fu[pdf_end_link_node] = &end_link;
61 p->whatsit_fu[pdf_dest_node] = &do_dest;
62 p->whatsit_fu[pdf_thread_node] = &do_thread;
63 p->whatsit_fu[pdf_end_thread_node] = &end_thread;
64 p->whatsit_fu[late_lua_node] = &late_lua;
65 p->whatsit_fu[pdf_colorstack_node] = &pdf_out_colorstack;
66 p->whatsit_fu[pdf_setmatrix_node] = &pdf_out_setmatrix;
67 p->whatsit_fu[pdf_save_node] = &pdf_out_save;
68 p->whatsit_fu[pdf_restore_node] = &pdf_out_restore;
71 @ @c
72 static void init_dvi_backend_functions(void)
74 backend_struct *p = &backend[OMODE_DVI];
75 p->name = strdup("DVI");
76 p->node_fu[rule_node] = &dvi_place_rule;
77 p->node_fu[glyph_node] = &dvi_place_glyph;
78 p->whatsit_fu[special_node] = &dvi_special;
79 p->whatsit_fu[late_lua_node] = &late_lua;
82 @ @c
83 void init_backend_functionpointers(output_mode o_mode)
85 int i, j;
86 if (backend == NULL) {
87 backend = xmalloc((MAX_OMODE + 1) * sizeof(backend_struct));
88 for (i = 0; i <= MAX_OMODE; i++) {
89 backend[i].node_fu = xmalloc((MAX_NODE_TYPE + 1) * sizeof(backend_function));
90 backend[i].whatsit_fu = xmalloc((MAX_WHATSIT_TYPE + 1) * sizeof(backend_function));
91 for (j = 0; j < MAX_NODE_TYPE + 1; j++)
92 backend[i].node_fu[j] = &missing_backend_function;
93 for (j = 0; j < MAX_WHATSIT_TYPE + 1; j++)
94 backend[i].whatsit_fu[j] = &missing_backend_function;
96 init_none_backend_functions();
97 init_dvi_backend_functions();
98 init_pdf_backend_functions();
100 backend_out = backend[o_mode].node_fu;
101 backend_out_whatsit = backend[o_mode].whatsit_fu;
104 @ This code scans forward to the ending |dir_node| while keeping
105 track of the needed width in |w|. When it finds the node that will end
106 this segment, it stores the accumulated with in the |dir_dvi_h| field
107 of that end node, so that when that node is found later in the
108 processing, the correct glue correction can be applied.
111 static scaled simple_advance_width(halfword p)
113 halfword q = p;
114 scaled w = 0;
115 while ((q != null) && (vlink(q) != null)) {
116 q = vlink(q);
117 switch (type(q)) {
118 case glyph_node:
119 w += glyph_width(q);
120 break;
121 case hlist_node:
122 case vlist_node:
123 case rule_node:
124 case margin_kern_node:
125 case kern_node:
126 w += width(q);
127 break;
128 case disc_node:
129 /* hh: the frontend should append already */
130 if (vlink(no_break(q)) != null)
131 w += simple_advance_width(no_break(q));
132 default:
133 break;
136 return w;
139 @ @c
140 static halfword calculate_width_to_enddir(halfword p, real cur_glue, scaled cur_g, halfword this_box)
142 int dir_nest = 1;
143 halfword q = p, enddir_ptr = p;
144 scaled w = 0;
145 halfword g; /* this is normally a global variable, but that is just too hideous */
146 real glue_temp; /* glue value before rounding */
147 int g_sign = glue_sign(this_box);
148 int g_order = glue_order(this_box);
149 while ((q != null) && (vlink(q) != null)) {
150 q = vlink(q);
151 if (is_char_node(q))
152 w += pack_width(box_dir(this_box), dir_TRT, q, true);
153 else {
154 switch (type(q)) {
155 case hlist_node:
156 case vlist_node:
157 w += pack_width(box_dir(this_box), box_dir(q), q, false);
158 break;
159 case rule_node:
160 case margin_kern_node:
161 case kern_node:
162 w += width(q);
163 break;
164 case math_node:
165 /* begin mathskip code */
166 if (glue_ptr(q) == zero_glue) {
167 w += surround(q);
168 break;
169 } else {
170 /* fall through: mathskip */
172 /* end mathskip code */
173 case glue_node:
174 g = glue_ptr(q);
175 w += width(g) - cur_g;
176 if (g_sign != normal) {
177 if (g_sign == stretching) {
178 if (stretch_order(g) == g_order) {
179 cur_glue = cur_glue + stretch(g);
180 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
181 cur_g = float_round(glue_temp);
183 } else if (shrink_order(g) == g_order) {
184 cur_glue = cur_glue - shrink(g);
185 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
186 cur_g = float_round(glue_temp);
189 w += cur_g;
190 break;
191 case disc_node:
192 /* hh: the frontend should append already */
193 if (vlink(no_break(q)) != null)
194 w += simple_advance_width(no_break(q));
195 break;
196 case dir_node:
197 if (dir_dir(q) >= 0)
198 dir_nest++;
199 else
200 dir_nest--;
201 if (dir_nest == 0) {
202 enddir_ptr = q;
203 dir_cur_h(enddir_ptr) = w;
204 q = null;
206 break;
207 default:
208 break;
212 if (enddir_ptr == p)
213 /* no enddir found, just transport w by begindir */
214 dir_cur_h(enddir_ptr) = w;
215 return enddir_ptr;
218 @ The |out_what| procedure takes care of outputting the whatsit nodes for
219 |vlist_out| and |hlist_out|, which are similar for either case.
221 We don't implement \.{\\write} inside of leaders. (The reason is that
222 the number of times a leader box appears might be different in different
223 implementations, due to machine-dependent rounding in the glue calculations.)
224 @^leaders@>
227 void out_what(PDF pdf, halfword p)
229 switch (subtype(p)) {
230 case special_node: /* |pdf_special(pdf, p)|; */
231 case late_lua_node: /* |late_lua(pdf, p)|; */
232 case pdf_save_node: /* |pdf_out_save(pdf, p)|; */
233 case pdf_restore_node: /* |pdf_out_restore(pdf, p)|; */
234 case pdf_end_link_node: /* |end_link(pdf, p)|; */
235 case pdf_end_thread_node: /* |end_thread(pdf, p)|; */
236 case pdf_literal_node: /* |pdf_out_literal(pdf, p)|; */
237 case pdf_colorstack_node: /* |pdf_out_colorstack(pdf, p)|; */
238 case pdf_setmatrix_node: /* |pdf_out_setmatrix(pdf, p)|; */
239 case pdf_refobj_node: /* |pdf_ref_obj(pdf, p)| */
240 backend_out_whatsit[subtype(p)] (pdf, p);
241 break;
242 case open_node:
243 case write_node:
244 case close_node:
245 /* do some work that has been queued up for \.{\\write} */
246 if (!doing_leaders) {
247 int j = write_stream(p);
248 if (subtype(p) == write_node) {
249 write_out(p);
250 } else if (subtype(p) == close_node) {
251 close_write_file(j);
252 } else if (valid_write_file(j)) {
253 char *fn;
254 close_write_file(j);
255 cur_name = open_name(p);
256 cur_area = open_area(p);
257 cur_ext = open_ext(p);
258 if (cur_ext == get_nullstr())
259 cur_ext = maketexstring(".tex");
260 fn = pack_file_name(cur_name, cur_area, cur_ext);
261 while (! open_write_file(j,fn)) {
262 fn = prompt_file_name("output file name", ".tex");
266 break;
267 case user_defined_node:
268 break;
269 default:
270 /* this should give an error about missing whatsit backend function */
271 backend_out_whatsit[subtype(p)] (pdf, p);
275 @ @c
276 void hlist_out(PDF pdf, halfword this_box, int rule_callback_id)
278 posstructure localpos; /* the position structure local within this function */
279 posstructure *refpos; /* the list origin pos. on the page, provided by the caller */
280 scaledpos cur = { 0, 0 }, tmpcur, basepoint;
281 scaledpos size = { 0, 0 }; /* rule dimensions */
282 scaled effective_horizontal;
283 scaled save_h; /* what |cur.h| should pop to */
284 scaled edge; /* right edge of sub-box or leader space */
285 halfword enddir_ptr; /* temporary pointer to enddir node */
286 int g_order; /* applicable order of infinity for glue */
287 int g_sign; /* selects type of glue */
288 halfword p, q; /* current position in the hlist */
289 halfword leader_box; /* the leader box being replicated */
290 scaled leader_wd; /* width of leader box being replicated */
291 scaled lx; /* extra space between leader boxes */
292 boolean outer_doing_leaders; /* were we doing leaders? */
293 real glue_temp; /* glue value before rounding */
294 real cur_glue = 0.0; /* glue seen so far */
295 scaled cur_g = 0; /* rounded equivalent of |cur_glue| times the glue ratio */
296 scaled_whd rule, ci;
297 int i; /* index to scan |pdf_link_stack| */
298 int save_loc = 0; /* DVI! \.{DVI} byte location upon entry */
299 scaledpos save_dvi = { 0, 0 }; /* DVI! what |dvi| should pop to */
300 int synctex = int_par(synctex_code) ;
302 g_order = glue_order(this_box);
303 g_sign = glue_sign(this_box);
304 p = list_ptr(this_box);
306 refpos = pdf->posstruct;
307 pdf->posstruct = &localpos; /* use local structure for recursion */
308 localpos.pos = refpos->pos;
309 localpos.dir = box_dir(this_box);
311 cur_s++;
312 if (cur_s > max_push)
313 max_push = cur_s;
315 if (output_mode_used == OMODE_DVI) {
316 if (cur_s > 0) {
317 dvi_push();
318 save_dvi = dvi;
320 save_loc = dvi_offset + dvi_ptr;
323 for (i = 1; i <= pdf->link_stack_ptr; i++) {
324 if (pdf->link_stack[i].nesting_level == cur_s)
325 append_link(pdf, this_box, cur, (small_number) i);
328 if (synctex)
329 synctexhlist(this_box);
331 while (p != null) {
332 if (is_char_node(p)) {
333 do {
334 if (x_displace(p) != 0 || y_displace(p) != 0) {
335 tmpcur.h = cur.h + x_displace(p);
336 tmpcur.v = cur.v - y_displace(p);
337 synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
339 ci = output_one_char(pdf, p);
340 if (textdir_parallel(localpos.dir, dir_TLT))
341 cur.h += ci.wd;
342 else
343 cur.h += ci.ht + ci.dp;
344 synch_pos_with_cur(pdf->posstruct, refpos, cur);
345 p = vlink(p);
346 } while (is_char_node(p));
347 if (synctex)
348 synctexcurrent();
349 } else {
350 /* output the non-|char_node| |p| for |hlist_out| and move to the next node */
351 switch (type(p)) {
352 case hlist_node:
353 case vlist_node:
354 if (textdir_parallel(box_dir(p), localpos.dir)) {
355 effective_horizontal = width(p);
356 basepoint.v = 0;
357 if (textdir_opposite(box_dir(p), localpos.dir))
358 basepoint.h = width(p);
359 else
360 basepoint.h = 0;
361 } else {
362 effective_horizontal = height(p) + depth(p);
363 if (!is_mirrored(box_dir(p))) {
364 if (partextdir_eq(box_dir(p), localpos.dir))
365 basepoint.h = height(p);
366 else
367 basepoint.h = depth(p);
368 } else {
369 if (partextdir_eq(box_dir(p), localpos.dir))
370 basepoint.h = depth(p);
371 else
372 basepoint.h = height(p);
374 if (is_rotated(localpos.dir)) {
375 if (partextdir_eq(localpos.dir, box_dir(p)))
376 basepoint.v = -width(p) / 2; /* up */
377 else
378 basepoint.v = width(p) / 2; /* down */
379 } else if (is_mirrored(localpos.dir)) {
380 if (partextdir_eq(localpos.dir, box_dir(p)))
381 basepoint.v = 0;
382 else
383 basepoint.v = width(p); /* down */
384 } else {
385 if (partextdir_eq(localpos.dir, box_dir(p)))
386 basepoint.v = -width(p); /* up */
387 else
388 basepoint.v = 0;
391 if (!is_mirrored(localpos.dir))
392 basepoint.v = basepoint.v + shift_amount(p); /* shift the box down */
393 else
394 basepoint.v = basepoint.v - shift_amount(p); /* shift the box up */
395 if (list_ptr(p) == null) {
396 if (synctex) {
397 if (type(p) == vlist_node)
398 synctexvoidvlist(p, this_box);
399 else
400 synctexvoidhlist(p, this_box);
402 } else {
403 tmpcur.h = cur.h + basepoint.h;
404 tmpcur.v = basepoint.v;
405 synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
406 if (type(p) == vlist_node)
407 vlist_out(pdf, p, rule_callback_id);
408 else
409 hlist_out(pdf, p, rule_callback_id);
411 cur.h += effective_horizontal;
412 break;
413 case disc_node:
414 /* hh: the frontend should append already */
415 if (vlink(no_break(p)) != null) {
416 if (subtype(p) != select_disc) {
417 q = tail_of_list(vlink(no_break(p))); /* this could be a tlink */
418 vlink(q) = vlink(p);
419 q = vlink(no_break(p));
420 vlink(no_break(p)) = null;
421 vlink(p) = q;
424 break;
425 case glue_node:
427 /* move right or output leaders, we use real multiplication */
428 halfword g = glue_ptr(p);
429 rule.wd = width(g) - cur_g;
430 if (g_sign != normal) {
431 if (g_sign == stretching) {
432 if (stretch_order(g) == g_order) {
433 cur_glue = cur_glue + stretch(g);
434 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
435 cur_g = float_round(glue_temp);
437 } else if (shrink_order(g) == g_order) {
438 cur_glue = cur_glue - shrink(g);
439 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
440 cur_g = float_round(glue_temp);
443 rule.wd = rule.wd + cur_g;
444 if (subtype(p) >= a_leaders) {
445 /* output leaders in an hlist, |goto fin_rule| if a rule or to |next_p| if done */
446 leader_box = leader_ptr(p);
447 if (type(leader_box) == rule_node) {
448 rule.ht = height(leader_box);
449 rule.dp = depth(leader_box);
450 goto FIN_RULE;
452 if (textdir_parallel(box_dir(leader_box), localpos.dir))
453 leader_wd = width(leader_box);
454 else
455 leader_wd = height(leader_box) + depth(leader_box);
456 if ((leader_wd > 0) && (rule.wd > 0)) {
457 rule.wd = rule.wd + 10; /* compensate for floating-point rounding */
458 edge = cur.h + rule.wd;
459 lx = 0;
461 let |cur.h| be the position of the first box, and set |leader_wd+lx|
462 to the spacing between corresponding parts of boxes
464 if (subtype(p) == g_leaders) {
465 save_h = cur.h;
466 switch (localpos.dir) {
467 case dir_TLT:
468 cur.h += refpos->pos.h - shipbox_refpos.h;
469 cur.h = leader_wd * (cur.h / leader_wd);
470 cur.h -= refpos->pos.h - shipbox_refpos.h;
471 break;
472 case dir_TRT:
473 cur.h = refpos->pos.h - shipbox_refpos.h - cur.h;
474 cur.h = leader_wd * (cur.h / leader_wd);
475 cur.h = refpos->pos.h - shipbox_refpos.h - cur.h;
476 break;
477 case dir_LTL:
478 case dir_RTT:
479 cur.h = refpos->pos.v - shipbox_refpos.v - cur.h;
480 cur.h = leader_wd * (cur.h / leader_wd);
481 cur.h = refpos->pos.v - shipbox_refpos.v - cur.h;
482 break;
483 default:
484 formatted_warning("pdf backend","forcing bad dir %i to TLT in hlist case 1",localpos.dir);
485 localpos.dir = dir_TLT;
486 cur.h += refpos->pos.h - shipbox_refpos.h;
487 cur.h = leader_wd * (cur.h / leader_wd);
488 cur.h -= refpos->pos.h - shipbox_refpos.h;
489 break;
491 if (cur.h < save_h)
492 cur.h += leader_wd;
493 } else if (subtype(p) == a_leaders) {
494 save_h = cur.h;
495 cur.h = leader_wd * (cur.h / leader_wd);
496 if (cur.h < save_h)
497 cur.h += leader_wd;
498 } else {
499 lq = rule.wd / leader_wd; /* the number of box copies */
500 lr = rule.wd % leader_wd; /* the remaining space */
501 if (subtype(p) == c_leaders) {
502 cur.h += lr / 2;
503 } else {
504 lx = lr / (lq + 1);
505 cur.h += (lr - (lq - 1) * lx) / 2;
508 while (cur.h + leader_wd <= edge) {
509 /* output a leader box at |cur.h|, then advance |cur.h| by |leader_wd+lx| */
510 if (pardir_parallel(box_dir(leader_box), localpos.dir)) {
511 basepoint.v = 0;
512 if (textdir_opposite(box_dir(leader_box), localpos.dir))
513 basepoint.h = width(leader_box);
514 else
515 basepoint.h = 0;
516 } else {
517 if (!is_mirrored(box_dir(leader_box))) {
518 if (partextdir_eq(box_dir(leader_box), localpos.dir))
519 basepoint.h = height(leader_box);
520 else
521 basepoint.h = depth(leader_box);
522 } else {
523 if (partextdir_eq(box_dir(leader_box), localpos.dir))
524 basepoint.h = depth(leader_box);
525 else
526 basepoint.h = height(leader_box);
528 if (partextdir_eq(localpos.dir, box_dir(leader_box)))
529 basepoint.v = -(width(leader_box) / 2);
530 else
531 basepoint.v = (width(leader_box) / 2);
533 if (!is_mirrored(localpos.dir))
534 basepoint.v = basepoint.v + shift_amount(leader_box); /* shift the box down */
535 else
536 basepoint.v = basepoint.v - shift_amount(leader_box); /* shift the box up */
537 tmpcur.h = cur.h + basepoint.h;
538 tmpcur.v = basepoint.v;
539 synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
540 outer_doing_leaders = doing_leaders;
541 doing_leaders = true;
542 if (type(leader_box) == vlist_node)
543 vlist_out(pdf, leader_box, rule_callback_id);
544 else
545 hlist_out(pdf, leader_box, rule_callback_id);
546 doing_leaders = outer_doing_leaders;
547 cur.h += leader_wd + lx;
549 cur.h = edge - 10;
550 goto NEXTP;
554 goto MOVE_PAST;
555 break;
556 case kern_node:
557 if (synctex)
558 synctexkern(p, this_box);
559 cur.h += width(p);
560 break;
561 case rule_node:
562 if (rule_dir(p) < 0)
563 rule_dir(p) = localpos.dir;
564 if (pardir_parallel(rule_dir(p), localpos.dir)) {
565 rule.ht = height(p);
566 rule.dp = depth(p);
567 rule.wd = width(p);
568 } else {
569 rule.ht = width(p) / 2;
570 rule.dp = width(p) / 2;
571 rule.wd = height(p) + depth(p);
573 goto FIN_RULE;
574 break;
575 case dir_node:
576 /* output a reflection instruction if the direction has changed */
577 if (dir_dir(p) >= 0) {
579 Calculate the needed width to the matching |enddir|, return the
580 |enddir| node, with width info
582 enddir_ptr = calculate_width_to_enddir(p, cur_glue, cur_g, this_box);
583 if (textdir_parallel(dir_dir(p), localpos.dir)) {
584 dir_cur_h(enddir_ptr) += cur.h;
585 if (textdir_opposite(dir_dir(p), localpos.dir))
586 cur.h = dir_cur_h(enddir_ptr);
587 } else
588 dir_cur_h(enddir_ptr) = cur.h;
589 if (enddir_ptr != p) {
590 /* only if it is an enddir */
591 dir_cur_v(enddir_ptr) = cur.v;
592 dir_refpos_h(enddir_ptr) = refpos->pos.h;
593 dir_refpos_v(enddir_ptr) = refpos->pos.v;
594 /* negative: mark it as |enddir| */
595 dir_dir(enddir_ptr) = localpos.dir - dir_swap;
597 /* fake a nested |hlist_out| */
598 synch_pos_with_cur(pdf->posstruct, refpos, cur);
599 refpos->pos = pdf->posstruct->pos;
600 localpos.dir = dir_dir(p);
601 cur.h = 0;
602 cur.v = 0;
603 } else {
604 refpos->pos.h = dir_refpos_h(p);
605 refpos->pos.v = dir_refpos_v(p);
606 localpos.dir = dir_dir(p) + dir_swap;
607 cur.h = dir_cur_h(p);
608 cur.v = dir_cur_v(p);
610 break;
611 case whatsit_node:
612 /* output the whatsit node |p| in |hlist_out| */
613 switch (subtype(p)) {
614 case save_pos_node:
615 last_position = pdf->posstruct->pos;
616 pos_info.curpos = pdf->posstruct->pos;
617 pos_info.boxpos.pos = refpos->pos;
618 pos_info.boxpos.dir = localpos.dir;
619 pos_info.boxdim.wd = width(this_box);
620 pos_info.boxdim.ht = height(this_box);
621 pos_info.boxdim.dp = depth(this_box);
622 break;
623 case pdf_annot_node:
624 case pdf_start_link_node:
625 case pdf_dest_node:
626 case pdf_start_thread_node:
627 case pdf_thread_node:
628 backend_out_whatsit[subtype(p)] (pdf, p, this_box, cur);
629 break;
630 default:
631 out_what(pdf, p);
633 break;
634 case math_node:
635 if (synctex) {
636 synctexmath(p, this_box);
638 /* begin mathskip code */
639 if (glue_ptr(p) == zero_glue) {
640 cur.h += surround(p);
641 break;
642 } else {
643 /* fall through: mathskip */
645 /* end mathskip code */
646 case margin_kern_node:
647 cur.h += width(p);
648 break;
649 default:
650 break;
652 goto NEXTP;
653 FIN_RULE:
654 /* output a rule in an hlist */
655 if (is_running(rule.ht))
656 rule.ht = height(this_box);
657 if (is_running(rule.dp))
658 rule.dp = depth(this_box);
659 /* we don't output empty rules */
660 if ((rule.ht + rule.dp) > 0 && rule.wd > 0) {
661 switch (localpos.dir) {
662 case dir_TLT:
663 size.h = rule.wd;
664 size.v = rule.ht + rule.dp;
665 pos_down(rule.dp);
666 break;
667 case dir_TRT:
668 size.h = rule.wd;
669 size.v = rule.ht + rule.dp;
670 pos_left(size.h);
671 pos_down(rule.dp);
672 break;
673 case dir_LTL:
674 size.h = rule.ht + rule.dp;
675 size.v = rule.wd;
676 pos_left(rule.ht);
677 pos_down(size.v);
678 break;
679 case dir_RTT:
680 size.h = rule.ht + rule.dp;
681 size.v = rule.wd;
682 pos_left(rule.dp);
683 pos_down(size.v);
684 break;
685 default:
686 formatted_warning("pdf backend","forcing bad dir %i to TLT in hlist case 2",localpos.dir);
687 localpos.dir = dir_TLT;
688 size.h = rule.wd;
689 size.v = rule.ht + rule.dp;
690 pos_down(rule.dp);
691 break;
693 if (type(p) == glue_node) {
694 q = leader_ptr(p);
695 if ((q) && (type(q) == rule_node)) {
696 backend_out[rule_node] (pdf, q, size, rule_callback_id);
698 } else {
699 backend_out[rule_node] (pdf, p, size, rule_callback_id);
702 MOVE_PAST:
703 cur.h += rule.wd;
704 if (synctex) {
705 synch_pos_with_cur(pdf->posstruct, refpos, cur);
706 synctexhorizontalruleorglue(p, this_box);
708 NEXTP:
709 p = vlink(p);
710 synch_pos_with_cur(pdf->posstruct, refpos, cur);
713 if (synctex)
714 synctextsilh(this_box);
715 if (output_mode_used == OMODE_DVI) {
716 prune_movements(save_loc);
717 if (cur_s > 0) {
718 dvi_pop(save_loc);
719 dvi = save_dvi;
722 cur_s--;
723 pdf->posstruct = refpos;
726 @ @c
727 void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
729 posstructure localpos; /* the position structure local within this function */
730 posstructure *refpos; /* the list origin pos. on the page, provided by the caller */
732 scaledpos cur, tmpcur, basepoint;
733 scaledpos size = { 0, 0 }; /* rule dimensions */
734 scaled effective_vertical;
735 scaled save_v; /* what |cur.v| should pop to */
736 scaled top_edge; /* the top coordinate for this box */
737 scaled edge; /* bottom boundary of leader space */
738 glue_ord g_order; /* applicable order of infinity for glue */
739 int g_sign; /* selects type of glue */
740 halfword p; /* current position in the vlist */
741 halfword q; /* temp */
742 halfword leader_box; /* the leader box being replicated */
743 scaled leader_ht; /* height of leader box being replicated */
744 scaled lx; /* extra space between leader boxes */
745 boolean outer_doing_leaders; /* were we doing leaders? */
746 real glue_temp; /* glue value before rounding */
747 real cur_glue = 0.0; /* glue seen so far */
748 scaled cur_g = 0; /* rounded equivalent of |cur_glue| times the glue ratio */
749 scaled_whd rule;
750 int save_loc = 0; /* DVI byte location upon entry */
751 scaledpos save_dvi = { 0, 0 }; /* DVI! what |dvi| should pop to */
752 int synctex = int_par(synctex_code) ;
754 g_order = (glue_ord) glue_order(this_box);
755 g_sign = glue_sign(this_box);
756 p = list_ptr(this_box);
758 cur.h = 0;
759 cur.v = -height(this_box);
760 top_edge = cur.v;
762 refpos = pdf->posstruct;
763 pdf->posstruct = &localpos; /* use local structure for recursion */
764 localpos.dir = box_dir(this_box);
765 synch_pos_with_cur(pdf->posstruct, refpos, cur);
767 cur_s++;
768 if (cur_s > max_push)
769 max_push = cur_s;
771 if (output_mode_used == OMODE_DVI) {
772 if (cur_s > 0) {
773 dvi_push();
774 save_dvi = dvi;
776 save_loc = dvi_offset + dvi_ptr;
779 if (synctex)
780 synctexvlist(this_box);
782 /* create thread for the current vbox if needed */
783 check_running_thread(pdf, this_box, cur);
785 while (p != null) {
786 switch (type(p)) {
787 case hlist_node:
788 case vlist_node:
790 output a box in a vlist:
792 todo: the direct test to switch between |width(p)| and |-width(p)|
793 is definately wrong, because it does not nest properly. But at least
794 it fixes a very obvious problem that otherwise occured with
795 \.{\\pardir TLT} in a document with \.{\\bodydir TRT}, and so it
796 will have to do for now. (hh: is this still true?)
799 if (pardir_parallel(box_dir(p), localpos.dir)) {
800 effective_vertical = height(p) + depth(p);
801 if ((type(p) == hlist_node) && is_mirrored(box_dir(p)))
802 basepoint.v = depth(p);
803 else
804 basepoint.v = height(p);
805 if (textdir_opposite(box_dir(p), localpos.dir))
806 basepoint.h = width(p);
807 else
808 basepoint.h = 0;
809 } else {
810 effective_vertical = width(p);
811 if (!is_mirrored(box_dir(p))) {
812 if (partextdir_eq(box_dir(p), localpos.dir))
813 basepoint.h = height(p);
814 else
815 basepoint.h = depth(p);
816 } else {
817 if (partextdir_eq(box_dir(p), localpos.dir))
818 basepoint.h = depth(p);
819 else
820 basepoint.h = height(p);
822 if (partextdir_eq(localpos.dir, box_dir(p)))
823 basepoint.v = 0;
824 else
825 basepoint.v = width(p);
827 basepoint.h = basepoint.h + shift_amount(p); /* shift the box right */
828 if (list_ptr(p) == null) {
829 cur.v += effective_vertical;
830 if (synctex) {
831 synch_pos_with_cur(pdf->posstruct, refpos, cur);
832 if (type(p) == vlist_node)
833 synctexvoidvlist(p, this_box);
834 else
835 synctexvoidhlist(p, this_box);
837 } else {
838 tmpcur.h = basepoint.h;
839 tmpcur.v = cur.v + basepoint.v;
840 synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
841 if (type(p) == vlist_node)
842 vlist_out(pdf, p, rule_callback_id);
843 else
844 hlist_out(pdf, p, rule_callback_id);
845 cur.v += effective_vertical;
847 break;
848 case rule_node:
849 if (rule_dir(p) < 0)
850 rule_dir(p) = localpos.dir;
851 if (pardir_parallel(rule_dir(p), localpos.dir)) {
852 rule.ht = height(p);
853 rule.dp = depth(p);
854 rule.wd = width(p);
855 } else {
856 rule.ht = width(p) / 2;
857 rule.dp = width(p) / 2;
858 rule.wd = height(p) + depth(p);
860 goto FIN_RULE;
861 break;
862 case glue_node:
864 /* move down or output leaders, we use real multiplication */
865 halfword g = glue_ptr(p);
866 rule.ht = width(g) - cur_g;
867 if (g_sign != normal) {
868 if (g_sign == stretching) {
869 if (stretch_order(g) == g_order) {
870 cur_glue = cur_glue + stretch(g);
871 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
872 cur_g = float_round(glue_temp);
874 } else if (shrink_order(g) == g_order) {
875 cur_glue = cur_glue - shrink(g);
876 vet_glue(float_cast(glue_set(this_box)) * cur_glue);
877 cur_g = float_round(glue_temp);
880 rule.ht = rule.ht + cur_g;
881 if (subtype(p) >= a_leaders) {
882 /* output leaders in a vlist, |goto fin_rulefin_rule| if a rule or to |next_p| if done */
883 leader_box = leader_ptr(p);
884 if (type(leader_box) == rule_node) {
885 rule.wd = width(leader_box);
886 rule.dp = 0;
887 goto FIN_RULE;
889 leader_ht = height(leader_box) + depth(leader_box);
890 if ((leader_ht > 0) && (rule.ht > 0)) {
891 rule.ht = rule.ht + 10; /* compensate for floating-point rounding */
892 edge = cur.v + rule.ht;
893 lx = 0;
895 let |cur.v| be the position of the first box, and set |leader_ht+lx|
896 to the spacing between corresponding parts of boxes
898 if (subtype(p) == g_leaders) {
899 save_v = cur.v;
900 switch (localpos.dir) {
901 case dir_LTL:
902 cur.v += refpos->pos.h - shipbox_refpos.h;
903 cur.v = leader_ht * (cur.v / leader_ht);
904 cur.v -= refpos->pos.h - shipbox_refpos.h;
905 break;
906 case dir_RTT:
907 cur.v = refpos->pos.h - shipbox_refpos.h - cur.v;
908 cur.v = leader_ht * (cur.v / leader_ht);
909 cur.v = refpos->pos.h - shipbox_refpos.h - cur.v;
910 break;
911 case dir_TLT:
912 case dir_TRT:
913 cur.v = refpos->pos.v - shipbox_refpos.v - cur.v;
914 cur.v = leader_ht * (cur.v / leader_ht);
915 cur.v = refpos->pos.v - shipbox_refpos.v - cur.v;
916 break;
917 default:
918 formatted_warning("pdf backend","forcing bad dir %i to TLT in vlist case 1",localpos.dir);
919 localpos.dir = dir_TLT;
920 cur.v += refpos->pos.h - shipbox_refpos.h;
921 cur.v = leader_ht * (cur.v / leader_ht);
922 cur.v -= refpos->pos.h - shipbox_refpos.h;
923 break;
925 if (cur.v < save_v)
926 cur.v += leader_ht;
927 } else if (subtype(p) == a_leaders) {
928 save_v = cur.v;
929 cur.v = top_edge + leader_ht * ((cur.v - top_edge) / leader_ht);
930 if (cur.v < save_v)
931 cur.v += leader_ht;
932 } else {
933 lq = rule.ht / leader_ht; /* the number of box copies */
934 lr = rule.ht % leader_ht; /* the remaining space */
935 if (subtype(p) == c_leaders) {
936 cur.v += lr / 2;
937 } else {
938 lx = lr / (lq + 1);
939 cur.v += (lr - (lq - 1) * lx) / 2;
943 while (cur.v + leader_ht <= edge) {
944 /* output a leader box at |cur.v|, then advance |cur.v| by |leader_ht+lx| */
945 tmpcur.h = shift_amount(leader_box);
946 tmpcur.v = cur.v + height(leader_box);
947 synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
948 outer_doing_leaders = doing_leaders;
949 doing_leaders = true;
950 if (type(leader_box) == vlist_node)
951 vlist_out(pdf, leader_box, rule_callback_id);
952 else
953 hlist_out(pdf, leader_box, rule_callback_id);
954 doing_leaders = outer_doing_leaders;
955 cur.v += leader_ht + lx;
957 cur.v = edge - 10;
958 goto NEXTP;
962 goto MOVE_PAST;
963 break;
964 case kern_node:
965 cur.v += width(p);
966 break;
967 case whatsit_node:
968 /* output the whatsit node |p| in |vlist_out| */
969 switch (subtype(p)) {
970 case save_pos_node:
971 last_position = pdf->posstruct->pos;
972 pos_info.curpos = pdf->posstruct->pos;
973 pos_info.boxpos.pos = refpos->pos;
974 pos_info.boxpos.dir = localpos.dir;
975 pos_info.boxdim.wd = width(this_box);
976 pos_info.boxdim.ht = height(this_box);
977 pos_info.boxdim.dp = depth(this_box);
978 break;
979 case pdf_annot_node:
980 case pdf_start_link_node:
981 case pdf_dest_node:
982 case pdf_start_thread_node:
983 case pdf_thread_node:
984 backend_out_whatsit[subtype(p)] (pdf, p, this_box, cur);
985 break;
986 default:
987 out_what(pdf, p);
989 break;
990 case glyph_node:
991 case disc_node:
992 confusion("vlistout"); /* this can't happen */
993 break;
994 default:
995 break;
997 goto NEXTP;
998 FIN_RULE:
999 /* output a rule in a vlist, |goto next_p| */
1000 if (is_running(rule.wd))
1001 rule.wd = width(this_box);
1002 /* we don't output empty rules */
1003 if ((rule.ht + rule.dp) > 0 && rule.wd > 0) {
1004 switch (localpos.dir) {
1005 case dir_TLT:
1006 size.h = rule.wd;
1007 size.v = rule.ht + rule.dp;
1008 pos_down(size.v);
1009 break;
1010 case dir_TRT:
1011 size.h = rule.wd;
1012 size.v = rule.ht + rule.dp;
1013 pos_left(size.h);
1014 pos_down(size.v);
1015 break;
1016 case dir_LTL:
1017 size.h = rule.ht + rule.dp;
1018 size.v = rule.wd;
1019 pos_down(size.v);
1020 break;
1021 case dir_RTT:
1022 size.h = rule.ht + rule.dp;
1023 size.v = rule.wd;
1024 pos_left(size.h);
1025 pos_down(size.v);
1026 break;
1027 default:
1028 formatted_warning("pdf backend","forcing bad dir %i to TLT in vlist case 2",localpos.dir);
1029 localpos.dir = dir_TLT;
1030 size.h = rule.wd;
1031 size.v = rule.ht + rule.dp;
1032 pos_down(size.v);
1033 break;
1035 if (type(p) == glue_node) {
1036 q = leader_ptr(p);
1037 if ((q) && (type(q) == rule_node)) {
1038 backend_out[rule_node] (pdf, q, size, rule_callback_id);
1040 } else {
1041 backend_out[rule_node] (pdf, p, size, rule_callback_id);
1044 cur.v += rule.ht + rule.dp;
1045 goto NEXTP;
1046 MOVE_PAST:
1047 cur.v += rule.ht;
1048 NEXTP:
1049 p = vlink(p);
1050 synch_pos_with_cur(pdf->posstruct, refpos, cur);
1052 if (synctex)
1053 synctextsilv(this_box);
1055 if (output_mode_used == OMODE_DVI) {
1056 prune_movements(save_loc);
1057 if (cur_s > 0) {
1058 dvi_pop(save_loc);
1059 dvi = save_dvi;
1062 cur_s--;
1063 pdf->posstruct = refpos;