1% pdfshipout.w
2%
3% Copyright 2010-2012 Taco Hoekwater <taco@@luatex.org>
4%
5% This file is part of LuaTeX.
6%
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.
11%
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.
16%
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/>.
19
20@ @c
21
22
23#include "ptexlib.h"
24
25@ @c
26#define count(A) eqtb[count_base+(A)].cint
27#define h_offset dimen_par(h_offset_code)
28#define mag int_par(mag_code)
29#define page_bottom_offset dimen_par(page_bottom_offset_code)
30#define page_direction int_par(page_direction_code)
31#define page_height dimen_par(page_height_code)
32#define page_left_offset dimen_par(page_left_offset_code)
33#define page_right_offset dimen_par(page_right_offset_code)
34#define page_top_offset dimen_par(page_top_offset_code)
35#define page_width dimen_par(page_width_code)
36#define pdf_h_origin dimen_par(pdf_h_origin_code)
37#define pdf_v_origin dimen_par(pdf_v_origin_code)
38#define tracing_output int_par(tracing_output_code)
39#define tracing_stats int_par(tracing_stats_code)
40#define v_offset dimen_par(v_offset_code)
41
42scaledpos shipbox_refpos;
43
44@ |ship_out| is used to shipout a box to PDF or DVI mode.
45If |shipping_mode| is set to |SHIPPING_FORM| then the output will be a Form object
46(only PDF), and if it is set to |SHIPPING_PAGE| it will be a Page object.
47
48@c
49void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
50{
51    /* output the box |p| */
52    int j, k;                   /* indices to first ten count registers */
53    int post_callback_id;
54    int pre_callback_id;
55    posstructure refpoint;      /* the origin pos. on the page */
56    scaledpos cur = { 0, 0 };
57    refpoint.pos.h = 0;
58    refpoint.pos.v = 0;
59
60    ensure_output_state(pdf, ST_HEADER_WRITTEN);
61    fix_o_mode(pdf);            /* this is only for complaining if \.{\\pdfoutput} has changed */
62    init_backend_functionpointers(pdf->o_mode);
63
64    pdf->f_cur = null_font;
65
66    /* Start sheet {\sl Sync\TeX} information record */
67    /* {\sl Sync\TeX}: we assume that |pdf_output| is properly set up */
68    if (int_par(synctex_code))
69        synctexsheet(mag);
70
71    pre_callback_id = callback_defined(start_page_number_callback);
72    post_callback_id = callback_defined(stop_page_number_callback);
73    if ((tracing_output > 0) && (pre_callback_id == 0)) {
74        tprint_nl("");
75        print_ln();
76        tprint("Completed box being shipped out");
77    }
78    global_shipping_mode = shipping_mode;
79    if (shipping_mode == SHIPPING_PAGE) {
80        if (pre_callback_id > 0)
81            (void) run_callback(pre_callback_id, "->");
82        else if (pre_callback_id == 0) {
83            if (term_offset > max_print_line - 9)
84                print_ln();
85            else if ((term_offset > 0) || (file_offset > 0))
86                print_char(' ');
87            print_char('[');
88            j = 9;
89            while ((count(j) == 0) && (j > 0))
90                j--;
91            for (k = 0; k <= j; k++) {
92                print_int(count(k));
93                if (k < j)
94                    print_char('.');
95            }
96        }
97    }
98    if ((tracing_output > 0) && shipping_mode == SHIPPING_PAGE) {
99        print_char(']');
100        update_terminal();
101        begin_diagnostic();
102        show_box(p);
103        end_diagnostic(true);
104    }
105
106    /* Ship box |p| out */
107    if (shipping_mode == SHIPPING_PAGE && box_dir(p) != page_direction)
108        pdf_warning("\\shipout",
109                    "\\pagedir != \\bodydir; "
110                    "\\box\\outputbox may be placed wrongly on the page.", true,
111                    true);
112    /* Update the values of |max_h| and |max_v|; but if the page is too large, |goto done| */
113    /* Sometimes the user will generate a huge page because other error messages
114       are being ignored. Such pages are not output to the \.{dvi} file, since they
115       may confuse the printing software. */
116
117    if ((height(p) > max_dimen) || (depth(p) > max_dimen)
118        || (height(p) + depth(p) + v_offset > max_dimen)
119        || (width(p) + h_offset > max_dimen)) {
120        const char *hlp[] =
121            { "The page just created is more than 18 feet tall or",
122            "more than 18 feet wide, so I suspect something went wrong.",
123            NULL
124        };
125        tex_error("Huge page cannot be shipped out", hlp);
126        if (tracing_output <= 0) {
127            begin_diagnostic();
128            tprint_nl("The following box has been deleted:");
129            show_box(p);
130            end_diagnostic(true);
131        }
132        goto DONE;
133    }
134    if (height(p) + depth(p) + v_offset > max_v)
135        max_v = height(p) + depth(p) + v_offset;
136    if (width(p) + h_offset > max_h)
137        max_h = width(p) + h_offset;
138
139    /* Calculate page dimensions and margins */
140    if (global_shipping_mode == SHIPPING_PAGE) {
141        if (page_width > 0)
142            pdf->page_size.h = page_width;
143        else {
144            switch (page_direction) {
145            case dir_TLT:
146                pdf->page_size.h = width(p) + 2 * page_left_offset;
147                break;
148            case dir_TRT:
149                pdf->page_size.h = width(p) + 2 * page_right_offset;
150                break;
151            case dir_LTL:
152                pdf->page_size.h = height(p) + depth(p) + 2 * page_left_offset;
153                break;
154            case dir_RTT:
155                pdf->page_size.h = height(p) + depth(p) + 2 * page_right_offset;
156                break;
157            default:
158                assert(0);
159            }
160        }
161        if (page_height > 0)
162            pdf->page_size.v = page_height;
163        else {
164            switch (page_direction) {
165            case dir_TLT:
166            case dir_TRT:
167                pdf->page_size.v = height(p) + depth(p) + 2 * page_top_offset;
168                break;
169            case dir_LTL:
170            case dir_RTT:
171                pdf->page_size.v = width(p) + 2 * page_top_offset;
172                break;
173            default:
174                assert(0);
175            }
176        }
177
178        /* Think in upright page/paper coordinates (page origin = lower left edge).
179           First preset |refpoint.pos| to the DVI origin (near upper left page edge). */
180
181        switch (pdf->o_mode) {
182        case OMODE_DVI:
183            refpoint.pos.h = one_true_inch;
184            refpoint.pos.v = pdf->page_size.v - one_true_inch;
185            dvi = refpoint.pos;
186            break;
187        case OMODE_PDF:
188        case OMODE_LUA:
189            refpoint.pos.h = pdf_h_origin;
190            refpoint.pos.v = pdf->page_size.v - pdf_v_origin;
191            break;
192        default:
193            assert(0);
194        }
195
196        /* Then shift |refpoint.pos| of the DVI origin depending on the
197           |page_direction| within the upright (TLT) page coordinate system */
198
199        switch (page_direction) {
200        case dir_TLT:
201        case dir_LTL:
202            refpoint.pos.h += h_offset;
203            refpoint.pos.v -= v_offset;
204            break;
205        case dir_TRT:
206        case dir_RTT:
207            refpoint.pos.h +=
208                pdf->page_size.h - page_right_offset - one_true_inch;
209            refpoint.pos.v -= v_offset;
210            break;
211        default:
212            assert(0);
213        }
214
215        /* Then switch to page box coordinate system; do |height(p)| movement,
216           to get the location of the box origin. */
217
218        pdf->posstruct->dir = page_direction;
219        cur.h = 0;
220        cur.v = height(p);
221        synch_pos_with_cur(pdf->posstruct, &refpoint, cur);
222    } else {                    /* shipping a /Form */
223        assert(pdf->o_mode == OMODE_PDF);
224        pdf->posstruct->dir = box_dir(p);
225        switch (pdf->posstruct->dir) {
226        case dir_TLT:
227        case dir_TRT:
228            pdf->page_size.h = width(p);
229            pdf->page_size.v = height(p) + depth(p);
230            break;
231        case dir_LTL:
232        case dir_RTT:
233            pdf->page_size.h = height(p) + depth(p);
234            pdf->page_size.v = width(p);
235            break;
236        default:
237            assert(0);
238        }
239        switch (pdf->posstruct->dir) {
240        case dir_TLT:
241            pdf->posstruct->pos.h = 0;
242            pdf->posstruct->pos.v = depth(p);
243            break;
244        case dir_TRT:
245            pdf->posstruct->pos.h = width(p);
246            pdf->posstruct->pos.v = depth(p);
247            break;
248        case dir_LTL:
249            pdf->posstruct->pos.h = height(p);
250            pdf->posstruct->pos.v = width(p);
251            break;
252        case dir_RTT:
253            pdf->posstruct->pos.h = depth(p);
254            pdf->posstruct->pos.v = width(p);
255            break;
256        default:
257            assert(0);
258        }
259    }
260
261    /* Now we are at the point on the page where the origin of the page box should go. */
262
263    shipbox_refpos = pdf->posstruct->pos;       /* for \.{\\gleaders} */
264
265    switch (pdf->o_mode) {
266    case OMODE_DVI:
267        assert(shipping_mode == SHIPPING_PAGE);
268        dvi_begin_page(pdf);
269        break;
270    case OMODE_PDF:
271        pdf_begin_page(pdf);
272        break;
273    case OMODE_LUA:
274        assert(shipping_mode == SHIPPING_PAGE);
275        lua_begin_page(pdf);
276        break;
277    default:
278        assert(0);
279    }
280
281    switch (type(p)) {
282    case vlist_node:
283        vlist_out(pdf, p);
284        break;
285    case hlist_node:
286        hlist_out(pdf, p);
287        break;
288    default:
289        assert(0);
290    }
291
292    if (shipping_mode == SHIPPING_PAGE)
293        total_pages++;
294    cur_s = -1;
295
296    /* Finish shipping */
297
298    switch (pdf->o_mode) {
299    case OMODE_DVI:
300        dvi_end_page(pdf);
301        break;
302    case OMODE_PDF:
303        pdf_end_page(pdf);
304        break;
305    case OMODE_LUA:
306        lua_end_page(pdf);
307        break;
308    default:
309        assert(0);
310    }
311
312  DONE:
313    if ((tracing_output <= 0) && (post_callback_id == 0)
314        && shipping_mode == SHIPPING_PAGE) {
315        print_char(']');
316        update_terminal();
317    }
318    dead_cycles = 0;
319    /* Flush the box from memory, showing statistics if requested */
320    if ((tracing_stats > 1) && (pre_callback_id == 0)) {
321        tprint_nl("Memory usage before: ");
322        print_int(var_used);
323        print_char('&');
324        print_int(dyn_used);
325        print_char(';');
326    }
327    flush_node_list(p);
328    if ((tracing_stats > 1) && (post_callback_id == 0)) {
329        tprint(" after: ");
330        print_int(var_used);
331        print_char('&');
332        print_int(dyn_used);
333        print_ln();
334    }
335    if (shipping_mode == SHIPPING_PAGE && (post_callback_id > 0))
336        (void) run_callback(post_callback_id, "->");
337
338    /* Finish sheet {\sl Sync\TeX} information record */
339    if (int_par(synctex_code))
340        synctexteehs();
341
342    global_shipping_mode = NOT_SHIPPING;
343}
344