~ubuntu-branches/ubuntu/wily/luatex/wily

« back to all changes in this revision

Viewing changes to source/texk/web2c/luatexdir/pdf/pdfdest.w

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2010-04-29 00:47:19 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20100429004719-o42etkqe90n97b9e
Tags: 0.60.1-1
* new upstream release, adapt build-script patch
* disable patch: upstream-epstopdf_cc_no_xpdf_patching, included upstream
* disable patch: libpoppler-0.12, not needed anymore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
% pdfdest.w
 
2
 
 
3
% Copyright 2009-2010 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
static const char _svn_version[] =
 
22
    "$Id: pdfdest.w 3571 2010-04-02 13:50:45Z taco $"
 
23
    "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.1/source/texk/web2c/luatexdir/pdf/pdfdest.w $";
 
24
 
 
25
#include "ptexlib.h"
 
26
 
 
27
@ @c
 
28
#define pdf_dest_margin          dimen_par(pdf_dest_margin_code)
 
29
 
 
30
@ Here we implement subroutines for work with objects and related things.
 
31
Some of them are used in former parts too, so we need to declare them
 
32
forward.
 
33
 
 
34
@c
 
35
void init_dest_names(PDF pdf)
 
36
{
 
37
    pdf->dest_names_size = inf_dest_names_size;
 
38
    pdf->dest_names = xmallocarray(dest_name_entry, inf_dest_names_size);       /* will grow dynamically */
 
39
}
 
40
 
 
41
@ @c
 
42
void append_dest_name(PDF pdf, char *s, int n)
 
43
{
 
44
    int a;
 
45
    if (pdf->dest_names_ptr == sup_dest_names_size)
 
46
        overflow("number of destination names (dest_names_size)",
 
47
                 (unsigned) pdf->dest_names_size);
 
48
    if (pdf->dest_names_ptr == pdf->dest_names_size) {
 
49
        a = pdf->dest_names_size / 5;
 
50
        if (pdf->dest_names_size < sup_dest_names_size - a)
 
51
            pdf->dest_names_size = pdf->dest_names_size + a;
 
52
        else
 
53
            pdf->dest_names_size = sup_dest_names_size;
 
54
        pdf->dest_names =
 
55
            xreallocarray(pdf->dest_names, dest_name_entry,
 
56
                          (unsigned) pdf->dest_names_size);
 
57
    }
 
58
    pdf->dest_names[pdf->dest_names_ptr].objname = xstrdup(s);
 
59
    pdf->dest_names[pdf->dest_names_ptr].objnum = n;
 
60
    pdf->dest_names_ptr++;
 
61
}
 
62
 
 
63
 
 
64
@ When a destination is created we need to check whether another destination
 
65
with the same identifier already exists and give a warning if needed.
 
66
 
 
67
@c
 
68
void warn_dest_dup(int id, small_number byname, const char *s1, const char *s2)
 
69
{
 
70
    pdf_warning(s1, "destination with the same identifier (", false, false);
 
71
    if (byname > 0) {
 
72
        tprint("name");
 
73
        print_mark(id);
 
74
    } else {
 
75
        tprint("num");
 
76
        print_int(id);
 
77
    }
 
78
    tprint(") ");
 
79
    tprint(s2);
 
80
    print_ln();
 
81
    show_context();
 
82
}
 
83
 
 
84
 
 
85
@ @c
 
86
void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
 
87
{
 
88
    scaledpos pos = pdf->posstruct->pos;
 
89
    scaled_whd alt_rule;
 
90
    int k;
 
91
    if (!is_shipping_page)
 
92
        pdf_error("ext4", "destinations cannot be inside an XForm");
 
93
    if (doing_leaders)
 
94
        return;
 
95
    k = get_obj(pdf, obj_type_dest, pdf_dest_id(p), pdf_dest_named_id(p));
 
96
    if (obj_dest_ptr(pdf, k) != null) {
 
97
        warn_dest_dup(pdf_dest_id(p), (small_number) pdf_dest_named_id(p),
 
98
                      "ext4", "has been already used, duplicate ignored");
 
99
        return;
 
100
    }
 
101
    obj_dest_ptr(pdf, k) = p;
 
102
    addto_page_resources(pdf, obj_type_dest, k);
 
103
    alt_rule.wd = width(p);
 
104
    alt_rule.ht = height(p);
 
105
    alt_rule.dp = depth(p);
 
106
    switch (pdf_dest_type(p)) {
 
107
    case pdf_dest_xyz:
 
108
        if (matrixused())
 
109
            set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
 
110
        else {
 
111
            pdf_ann_left(p) = pos.h;
 
112
            pdf_ann_top(p) = pos.v;
 
113
        }
 
114
        break;
 
115
    case pdf_dest_fith:
 
116
    case pdf_dest_fitbh:
 
117
        if (matrixused())
 
118
            set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
 
119
        else
 
120
            pdf_ann_top(p) = pos.v;
 
121
        break;
 
122
    case pdf_dest_fitv:
 
123
    case pdf_dest_fitbv:
 
124
        if (matrixused())
 
125
            set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
 
126
        else
 
127
            pdf_ann_left(p) = pos.h;
 
128
        break;
 
129
    case pdf_dest_fit:
 
130
    case pdf_dest_fitb:
 
131
        break;
 
132
    case pdf_dest_fitr:
 
133
        set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
 
134
    }
 
135
}
 
136
 
 
137
@ @c
 
138
void write_out_pdf_mark_destinations(PDF pdf)
 
139
{
 
140
    pdf_object_list *k;
 
141
    if ((k = get_page_resources_list(pdf, obj_type_dest)) != NULL) {
 
142
        while (k != NULL) {
 
143
            if (is_obj_written(pdf, k->info)) {
 
144
                pdf_error("ext5",
 
145
                          "destination has been already written (this shouldn't happen)");
 
146
            } else {
 
147
                int i;
 
148
                i = obj_dest_ptr(pdf, k->info);
 
149
                if (pdf_dest_named_id(i) > 0) {
 
150
                    pdf_begin_dict(pdf, k->info, 1);
 
151
                    pdf_printf(pdf, "/D ");
 
152
                } else {
 
153
                    pdf_begin_obj(pdf, k->info, 1);
 
154
                }
 
155
                pdf_out(pdf, '[');
 
156
                pdf_print_int(pdf, pdf->last_page);
 
157
                pdf_printf(pdf, " 0 R ");
 
158
                switch (pdf_dest_type(i)) {
 
159
                case pdf_dest_xyz:
 
160
                    pdf_printf(pdf, "/XYZ ");
 
161
                    pdf_print_mag_bp(pdf, pdf_ann_left(i));
 
162
                    pdf_out(pdf, ' ');
 
163
                    pdf_print_mag_bp(pdf, pdf_ann_top(i));
 
164
                    pdf_out(pdf, ' ');
 
165
                    if (pdf_dest_xyz_zoom(i) == null) {
 
166
                        pdf_printf(pdf, "null");
 
167
                    } else {
 
168
                        pdf_print_int(pdf, pdf_dest_xyz_zoom(i) / 1000);
 
169
                        pdf_out(pdf, '.');
 
170
                        pdf_print_int(pdf, (pdf_dest_xyz_zoom(i) % 1000));
 
171
                    }
 
172
                    break;
 
173
                case pdf_dest_fit:
 
174
                    pdf_printf(pdf, "/Fit");
 
175
                    break;
 
176
                case pdf_dest_fith:
 
177
                    pdf_printf(pdf, "/FitH ");
 
178
                    pdf_print_mag_bp(pdf, pdf_ann_top(i));
 
179
                    break;
 
180
                case pdf_dest_fitv:
 
181
                    pdf_printf(pdf, "/FitV ");
 
182
                    pdf_print_mag_bp(pdf, pdf_ann_left(i));
 
183
                    break;
 
184
                case pdf_dest_fitb:
 
185
                    pdf_printf(pdf, "/FitB");
 
186
                    break;
 
187
                case pdf_dest_fitbh:
 
188
                    pdf_printf(pdf, "/FitBH ");
 
189
                    pdf_print_mag_bp(pdf, pdf_ann_top(i));
 
190
                    break;
 
191
                case pdf_dest_fitbv:
 
192
                    pdf_printf(pdf, "/FitBV ");
 
193
                    pdf_print_mag_bp(pdf, pdf_ann_left(i));
 
194
                    break;
 
195
                case pdf_dest_fitr:
 
196
                    pdf_printf(pdf, "/FitR ");
 
197
                    pdf_print_rect_spec(pdf, i);
 
198
                    break;
 
199
                default:
 
200
                    pdf_error("ext5", "unknown dest type");
 
201
                    break;
 
202
                }
 
203
                pdf_printf(pdf, "]\n");
 
204
                if (pdf_dest_named_id(i) > 0)
 
205
                    pdf_end_dict(pdf);
 
206
                else
 
207
                    pdf_end_obj(pdf);
 
208
            }
 
209
            k = k->link;
 
210
        }
 
211
    }
 
212
}
 
213
 
 
214
@ @c
 
215
void scan_pdfdest(PDF pdf)
 
216
{
 
217
    halfword q;
 
218
    int k;
 
219
    str_number i;
 
220
    scaled_whd alt_rule;
 
221
    q = cur_list.tail_field;
 
222
    new_whatsit(pdf_dest_node);
 
223
    if (scan_keyword("num")) {
 
224
        scan_int();
 
225
        if (cur_val <= 0)
 
226
            pdf_error("ext1", "num identifier must be positive");
 
227
        if (cur_val > max_halfword)
 
228
            pdf_error("ext1", "number too big");
 
229
        set_pdf_dest_id(cur_list.tail_field, cur_val);
 
230
        set_pdf_dest_named_id(cur_list.tail_field, 0);
 
231
    } else if (scan_keyword("name")) {
 
232
        scan_pdf_ext_toks();
 
233
        set_pdf_dest_id(cur_list.tail_field, def_ref);
 
234
        set_pdf_dest_named_id(cur_list.tail_field, 1);
 
235
    } else {
 
236
        pdf_error("ext1", "identifier type missing");
 
237
    }
 
238
    if (scan_keyword("xyz")) {
 
239
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_xyz);
 
240
        if (scan_keyword("zoom")) {
 
241
            scan_int();
 
242
            if (cur_val > max_halfword)
 
243
                pdf_error("ext1", "number too big");
 
244
            set_pdf_dest_xyz_zoom(cur_list.tail_field, cur_val);
 
245
        } else {
 
246
            set_pdf_dest_xyz_zoom(cur_list.tail_field, null);
 
247
        }
 
248
    } else if (scan_keyword("fitbh")) {
 
249
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitbh);
 
250
    } else if (scan_keyword("fitbv")) {
 
251
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitbv);
 
252
    } else if (scan_keyword("fitb")) {
 
253
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitb);
 
254
    } else if (scan_keyword("fith")) {
 
255
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fith);
 
256
    } else if (scan_keyword("fitv")) {
 
257
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitv);
 
258
    } else if (scan_keyword("fitr")) {
 
259
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitr);
 
260
    } else if (scan_keyword("fit")) {
 
261
        set_pdf_dest_type(cur_list.tail_field, pdf_dest_fit);
 
262
    } else {
 
263
        pdf_error("ext1", "destination type missing");
 
264
    }
 
265
    /* Scan an optional space */
 
266
    get_x_token();
 
267
    if (cur_cmd != spacer_cmd)
 
268
        back_input();
 
269
 
 
270
    if (pdf_dest_type(cur_list.tail_field) == pdf_dest_fitr) {
 
271
        alt_rule = scan_alt_rule();     /* scans |<rule spec>| to |alt_rule| */
 
272
        set_width(cur_list.tail_field, alt_rule.wd);
 
273
        set_height(cur_list.tail_field, alt_rule.ht);
 
274
        set_depth(cur_list.tail_field, alt_rule.dp);
 
275
    }
 
276
    if (pdf_dest_named_id(cur_list.tail_field) != 0) {
 
277
        i = tokens_to_string(pdf_dest_id(cur_list.tail_field));
 
278
        k = find_obj(pdf, obj_type_dest, i, true);
 
279
        flush_str(i);
 
280
    } else {
 
281
        k = find_obj(pdf, obj_type_dest, pdf_dest_id(cur_list.tail_field),
 
282
                     false);
 
283
    }
 
284
    if ((k != 0) && (obj_dest_ptr(pdf, k) != null)) {
 
285
        warn_dest_dup(pdf_dest_id(cur_list.tail_field),
 
286
                      (small_number) pdf_dest_named_id(cur_list.tail_field),
 
287
                      "ext4", "has been already used, duplicate ignored");
 
288
        flush_node_list(cur_list.tail_field);
 
289
        cur_list.tail_field = q;
 
290
        vlink(q) = null;
 
291
    }
 
292
}
 
293
 
 
294
@ sorts |dest_names| by names
 
295
@c
 
296
static int dest_cmp(const void *a, const void *b)
 
297
{
 
298
    dest_name_entry aa = *(const dest_name_entry *) a;
 
299
    dest_name_entry bb = *(const dest_name_entry *) b;
 
300
    return strcmp(aa.objname, bb.objname);
 
301
}
 
302
 
 
303
@ @c
 
304
void sort_dest_names(PDF pdf)
 
305
{
 
306
    qsort(pdf->dest_names, (size_t) pdf->dest_names_ptr,
 
307
          sizeof(dest_name_entry), dest_cmp);
 
308
}
 
309
 
 
310
 
 
311
@ Output the name tree. The tree nature of the destination list forces the
 
312
storing of intermediate data in |obj_info| and |obj_aux| fields, which
 
313
is further uglified by the fact that |obj_tab| entries do not accept char
 
314
pointers.
 
315
 
 
316
@c
 
317
int output_name_tree(PDF pdf)
 
318
{
 
319
    boolean is_names = true;    /* flag for name tree output: is it Names or Kids? */
 
320
    int b = 0, j, l;
 
321
    int k = 0;                  /* index of current child of |l|; if |k < pdf_dest_names_ptr|
 
322
                                   then this is pointer to |dest_names| array;
 
323
                                   otherwise it is the pointer to |obj_tab| (object number) */
 
324
    int dests = 0;
 
325
    int names_head = 0, names_tail = 0;
 
326
    if (pdf->dest_names_ptr == 0) {
 
327
        goto DONE;
 
328
    }
 
329
    sort_dest_names(pdf);
 
330
 
 
331
    while (true) {
 
332
 
 
333
        do {
 
334
            pdf_create_obj(pdf, obj_type_others, 0);    /* create a new node */
 
335
            l = pdf->obj_ptr;
 
336
            if (b == 0)
 
337
                b = l;          /* first in this level */
 
338
            if (names_head == 0) {
 
339
                names_head = l;
 
340
                names_tail = l;
 
341
            } else {
 
342
                set_obj_link(pdf, names_tail, l);
 
343
                names_tail = l;
 
344
            }
 
345
            set_obj_link(pdf, names_tail, 0);
 
346
            /* Output the current node in this level */
 
347
            pdf_begin_dict(pdf, l, 1);
 
348
            j = 0;
 
349
            if (is_names) {
 
350
                set_obj_start(pdf, l, pdf->dest_names[k].objname);
 
351
                pdf_printf(pdf, "/Names [");
 
352
                do {
 
353
                    pdf_print_str(pdf, pdf->dest_names[k].objname);
 
354
                    pdf_out(pdf, ' ');
 
355
                    pdf_print_int(pdf, pdf->dest_names[k].objnum);
 
356
                    pdf_printf(pdf, " 0 R ");
 
357
                    j++;
 
358
                    k++;
 
359
                } while (j != name_tree_kids_max && k != pdf->dest_names_ptr);
 
360
                pdf_remove_last_space(pdf);
 
361
                pdf_printf(pdf, "]\n");
 
362
                set_obj_stop(pdf, l, pdf->dest_names[k - 1].objname);   /* for later */
 
363
                if (k == pdf->dest_names_ptr) {
 
364
                    is_names = false;
 
365
                    k = names_head;
 
366
                    b = 0;
 
367
                }
 
368
 
 
369
            } else {
 
370
                set_obj_start(pdf, l, obj_start(pdf, k));
 
371
                pdf_printf(pdf, "/Kids [");
 
372
                do {
 
373
                    pdf_print_int(pdf, k);
 
374
                    pdf_printf(pdf, " 0 R ");
 
375
                    set_obj_stop(pdf, l, obj_stop(pdf, k));
 
376
                    k = obj_link(pdf, k);
 
377
                    j++;
 
378
                } while (j != name_tree_kids_max && k != b
 
379
                         && obj_link(pdf, k) != 0);
 
380
                pdf_remove_last_space(pdf);
 
381
                pdf_printf(pdf, "]\n");
 
382
                if (k == b)
 
383
                    b = 0;
 
384
            }
 
385
            pdf_printf(pdf, "/Limits [");
 
386
            pdf_print_str(pdf, obj_start(pdf, l));
 
387
            pdf_out(pdf, ' ');
 
388
            pdf_print_str(pdf, obj_stop(pdf, l));
 
389
            pdf_printf(pdf, "]\n");
 
390
            pdf_end_dict(pdf);
 
391
 
 
392
 
 
393
        } while (b != 0);
 
394
 
 
395
        if (k == l) {
 
396
            dests = l;
 
397
            goto DONE;
 
398
        }
 
399
 
 
400
    }
 
401
 
 
402
  DONE:
 
403
    if ((dests != 0) || (pdf_names_toks != null)) {
 
404
        pdf_new_dict(pdf, obj_type_others, 0, 1);
 
405
        if (dests != 0)
 
406
            pdf_indirect_ln(pdf, "Dests", dests);
 
407
        if (pdf_names_toks != null) {
 
408
            pdf_print_toks_ln(pdf, pdf_names_toks);
 
409
            delete_token_ref(pdf_names_toks);
 
410
            pdf_names_toks = null;
 
411
        }
 
412
        pdf_end_dict(pdf);
 
413
        return pdf->obj_ptr;
 
414
    } else {
 
415
        return 0;
 
416
    }
 
417
}