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
/>.
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
;
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
);
38 formatted_error
("pdf backend","no output function for node %s",n
);
42 static void init_none_backend_functions
(void
)
44 backend_struct
*p
= &backend[OMODE_NONE];
45 p-
>name
= strdup
("(None)");
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;
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;
83 void init_backend_functionpointers
(output_mode o_mode
)
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
)
115 while
((q
!= null
) && (vlink(q) != null)) {
124 case margin_kern_node
:
129 /* hh
: the frontend should append already
*/
130 if
(vlink
(no_break
(q
)) != null
)
131 w
+= simple_advance_width
(no_break
(q
));
140 static halfword calculate_width_to_enddir
(halfword p
, real cur_glue
, scaled cur_g
, halfword this_box
)
143 halfword q
= p
, enddir_ptr
= p
;
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)) {
152 w
+= pack_width
(box_dir
(this_box
), dir_TRT
, q
, true
);
157 w
+= pack_width
(box_dir
(this_box
), box_dir
(q
), q
, false
);
160 case margin_kern_node
:
165 /* begin mathskip code
*/
166 if
(glue_ptr
(q
) == zero_glue
) {
170 /* fall through
: mathskip
*/
172 /* end mathskip code
*/
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
);
192 /* hh
: the frontend should append already
*/
193 if
(vlink
(no_break
(q
)) != null
)
194 w
+= simple_advance_width
(no_break
(q
));
203 dir_cur_h
(enddir_ptr
) = w
;
213 /* no enddir found
, just transport w by begindir
*/
214 dir_cur_h
(enddir_ptr
) = w
;
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.
)
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
);
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
) {
250 } else if
(subtype
(p
) == close_node
) {
252 } else if
(valid_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");
267 case user_defined_node
:
270 /* this should give an error about missing whatsit backend function
*/
271 backend_out_whatsit
[subtype
(p
)] (pdf
, p
);
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
*/
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
);
312 if
(cur_s
> max_push
)
315 if
(output_mode_used
== OMODE_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
);
329 synctexhlist
(this_box
);
332 if
(is_char_node
(p
)) {
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
))
343 cur.h
+= ci.ht
+ ci.dp
;
344 synch_pos_with_cur
(pdf-
>posstruct
, refpos
, cur
);
346 } while
(is_char_node
(p
));
350 /* output the non-|char_node| |p| for |hlist_out| and move to the next node
*/
354 if
(textdir_parallel
(box_dir
(p
), localpos.dir
)) {
355 effective_horizontal
= width
(p
);
357 if
(textdir_opposite
(box_dir
(p
), localpos.dir
))
358 basepoint.h
= width
(p
);
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
);
367 basepoint.h
= depth
(p
);
369 if
(partextdir_eq
(box_dir
(p
), localpos.dir
))
370 basepoint.h
= depth
(p
);
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
*/
378 basepoint.v
= width
(p
) / 2; /* down
*/
379 } else if
(is_mirrored
(localpos.dir
)) {
380 if
(partextdir_eq
(localpos.dir
, box_dir
(p
)))
383 basepoint.v
= width
(p
); /* down
*/
385 if
(partextdir_eq
(localpos.dir
, box_dir
(p
)))
386 basepoint.v
= -width
(p
); /* up
*/
391 if
(!is_mirrored
(localpos.dir
))
392 basepoint.v
= basepoint.v
+ shift_amount
(p
); /* shift the box down
*/
394 basepoint.v
= basepoint.v
- shift_amount
(p
); /* shift the box up
*/
395 if
(list_ptr
(p
) == null
) {
397 if
(type
(p
) == vlist_node
)
398 synctexvoidvlist
(p
, this_box
);
400 synctexvoidhlist
(p
, this_box
);
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
);
409 hlist_out
(pdf
, p
, rule_callback_id
);
411 cur.h
+= effective_horizontal
;
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
*/
419 q
= vlink
(no_break
(p
));
420 vlink
(no_break
(p
)) = null
;
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
);
452 if
(textdir_parallel
(box_dir
(leader_box
), localpos.dir
))
453 leader_wd
= width
(leader_box
);
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
;
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
) {
466 switch
(localpos.dir
) {
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
;
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
;
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
;
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
;
493 } else if
(subtype
(p
) == a_leaders
) {
495 cur.h
= leader_wd
* (cur.h
/ leader_wd
);
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
) {
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
)) {
512 if
(textdir_opposite
(box_dir
(leader_box
), localpos.dir
))
513 basepoint.h
= width
(leader_box
);
517 if
(!is_mirrored
(box_dir
(leader_box
))) {
518 if
(partextdir_eq
(box_dir
(leader_box
), localpos.dir
))
519 basepoint.h
= height
(leader_box
);
521 basepoint.h
= depth
(leader_box
);
523 if
(partextdir_eq
(box_dir
(leader_box
), localpos.dir
))
524 basepoint.h
= depth
(leader_box
);
526 basepoint.h
= height
(leader_box
);
528 if
(partextdir_eq
(localpos.dir
, box_dir
(leader_box
)))
529 basepoint.v
= -(width
(leader_box
) / 2);
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
*/
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
);
545 hlist_out
(pdf
, leader_box
, rule_callback_id
);
546 doing_leaders
= outer_doing_leaders
;
547 cur.h
+= leader_wd
+ lx
;
558 synctexkern
(p
, this_box
);
563 rule_dir
(p
) = localpos.dir
;
564 if
(pardir_parallel
(rule_dir
(p
), localpos.dir
)) {
569 rule.ht
= width
(p
) / 2;
570 rule.dp
= width
(p
) / 2;
571 rule.wd
= height
(p
) + depth
(p
);
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
);
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
);
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
);
612 /* output the whatsit node |p| in |hlist_out|
*/
613 switch
(subtype
(p
)) {
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
);
624 case pdf_start_link_node
:
626 case pdf_start_thread_node
:
627 case pdf_thread_node
:
628 backend_out_whatsit
[subtype
(p
)] (pdf
, p
, this_box
, cur
);
636 synctexmath
(p
, this_box
);
638 /* begin mathskip code
*/
639 if
(glue_ptr
(p
) == zero_glue
) {
640 cur.h
+= surround
(p
);
643 /* fall through
: mathskip
*/
645 /* end mathskip code
*/
646 case margin_kern_node
:
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
) {
664 size.v
= rule.ht
+ rule.dp
;
669 size.v
= rule.ht
+ rule.dp
;
674 size.h
= rule.ht
+ rule.dp
;
680 size.h
= rule.ht
+ rule.dp
;
686 formatted_warning
("pdf backend","forcing bad dir %i to TLT in hlist case 2",localpos.dir
);
687 localpos.dir
= dir_TLT
;
689 size.v
= rule.ht
+ rule.dp
;
693 if
(type
(p
) == glue_node
) {
695 if
((q
) && (type(q) == rule_node)) {
696 backend_out
[rule_node
] (pdf
, q
, size
, rule_callback_id
);
699 backend_out
[rule_node
] (pdf
, p
, size
, rule_callback_id
);
705 synch_pos_with_cur
(pdf-
>posstruct
, refpos
, cur
);
706 synctexhorizontalruleorglue
(p
, this_box
);
710 synch_pos_with_cur
(pdf-
>posstruct
, refpos
, cur
);
714 synctextsilh
(this_box
);
715 if
(output_mode_used
== OMODE_DVI
) {
716 prune_movements
(save_loc
);
723 pdf-
>posstruct
= refpos
;
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
*/
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
);
759 cur.v
= -height
(this_box
);
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
);
768 if
(cur_s
> max_push
)
771 if
(output_mode_used
== OMODE_DVI
) {
776 save_loc
= dvi_offset
+ dvi_ptr
;
780 synctexvlist
(this_box
);
782 /* create thread for the current vbox if needed
*/
783 check_running_thread
(pdf
, this_box
, cur
);
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
);
804 basepoint.v
= height
(p
);
805 if
(textdir_opposite
(box_dir
(p
), localpos.dir
))
806 basepoint.h
= width
(p
);
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
);
815 basepoint.h
= depth
(p
);
817 if
(partextdir_eq
(box_dir
(p
), localpos.dir
))
818 basepoint.h
= depth
(p
);
820 basepoint.h
= height
(p
);
822 if
(partextdir_eq
(localpos.dir
, box_dir
(p
)))
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
;
831 synch_pos_with_cur
(pdf-
>posstruct
, refpos
, cur
);
832 if
(type
(p
) == vlist_node
)
833 synctexvoidvlist
(p
, this_box
);
835 synctexvoidhlist
(p
, this_box
);
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
);
844 hlist_out
(pdf
, p
, rule_callback_id
);
845 cur.v
+= effective_vertical
;
850 rule_dir
(p
) = localpos.dir
;
851 if
(pardir_parallel
(rule_dir
(p
), localpos.dir
)) {
856 rule.ht
= width
(p
) / 2;
857 rule.dp
= width
(p
) / 2;
858 rule.wd
= height
(p
) + depth
(p
);
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
);
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
;
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
) {
900 switch
(localpos.dir
) {
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
;
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
;
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
;
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
;
927 } else if
(subtype
(p
) == a_leaders
) {
929 cur.v
= top_edge
+ leader_ht
* ((cur.v
- top_edge
) / leader_ht
);
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
) {
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
);
953 hlist_out
(pdf
, leader_box
, rule_callback_id
);
954 doing_leaders
= outer_doing_leaders
;
955 cur.v
+= leader_ht
+ lx
;
968 /* output the whatsit node |p| in |vlist_out|
*/
969 switch
(subtype
(p
)) {
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
);
980 case pdf_start_link_node
:
982 case pdf_start_thread_node
:
983 case pdf_thread_node
:
984 backend_out_whatsit
[subtype
(p
)] (pdf
, p
, this_box
, cur
);
992 confusion
("vlistout"); /* this can't happen
*/
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
) {
1007 size.v
= rule.ht
+ rule.dp
;
1012 size.v
= rule.ht
+ rule.dp
;
1017 size.h
= rule.ht
+ rule.dp
;
1022 size.h
= rule.ht
+ rule.dp
;
1028 formatted_warning
("pdf backend","forcing bad dir %i to TLT in vlist case 2",localpos.dir
);
1029 localpos.dir
= dir_TLT
;
1031 size.v
= rule.ht
+ rule.dp
;
1035 if
(type
(p
) == glue_node
) {
1037 if
((q
) && (type(q) == rule_node)) {
1038 backend_out
[rule_node
] (pdf
, q
, size
, rule_callback_id
);
1041 backend_out
[rule_node
] (pdf
, p
, size
, rule_callback_id
);
1044 cur.v
+= rule.ht
+ rule.dp
;
1050 synch_pos_with_cur
(pdf-
>posstruct
, refpos
, cur
);
1053 synctextsilv
(this_box
);
1055 if
(output_mode_used
== OMODE_DVI
) {
1056 prune_movements
(save_loc
);
1063 pdf-
>posstruct
= refpos
;