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/>.
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 $";
28
#define pdf_dest_margin dimen_par(pdf_dest_margin_code)
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
35
void init_dest_names(PDF pdf)
37
pdf->dest_names_size = inf_dest_names_size;
38
pdf->dest_names = xmallocarray(dest_name_entry, inf_dest_names_size); /* will grow dynamically */
42
void append_dest_name(PDF pdf, char *s, int n)
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;
53
pdf->dest_names_size = sup_dest_names_size;
55
xreallocarray(pdf->dest_names, dest_name_entry,
56
(unsigned) pdf->dest_names_size);
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++;
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.
68
void warn_dest_dup(int id, small_number byname, const char *s1, const char *s2)
70
pdf_warning(s1, "destination with the same identifier (", false, false);
86
void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
88
scaledpos pos = pdf->posstruct->pos;
91
if (!is_shipping_page)
92
pdf_error("ext4", "destinations cannot be inside an XForm");
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");
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)) {
109
set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
111
pdf_ann_left(p) = pos.h;
112
pdf_ann_top(p) = pos.v;
118
set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
120
pdf_ann_top(p) = pos.v;
125
set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
127
pdf_ann_left(p) = pos.h;
133
set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin);
138
void write_out_pdf_mark_destinations(PDF pdf)
141
if ((k = get_page_resources_list(pdf, obj_type_dest)) != NULL) {
143
if (is_obj_written(pdf, k->info)) {
145
"destination has been already written (this shouldn't happen)");
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 ");
153
pdf_begin_obj(pdf, k->info, 1);
156
pdf_print_int(pdf, pdf->last_page);
157
pdf_printf(pdf, " 0 R ");
158
switch (pdf_dest_type(i)) {
160
pdf_printf(pdf, "/XYZ ");
161
pdf_print_mag_bp(pdf, pdf_ann_left(i));
163
pdf_print_mag_bp(pdf, pdf_ann_top(i));
165
if (pdf_dest_xyz_zoom(i) == null) {
166
pdf_printf(pdf, "null");
168
pdf_print_int(pdf, pdf_dest_xyz_zoom(i) / 1000);
170
pdf_print_int(pdf, (pdf_dest_xyz_zoom(i) % 1000));
174
pdf_printf(pdf, "/Fit");
177
pdf_printf(pdf, "/FitH ");
178
pdf_print_mag_bp(pdf, pdf_ann_top(i));
181
pdf_printf(pdf, "/FitV ");
182
pdf_print_mag_bp(pdf, pdf_ann_left(i));
185
pdf_printf(pdf, "/FitB");
188
pdf_printf(pdf, "/FitBH ");
189
pdf_print_mag_bp(pdf, pdf_ann_top(i));
192
pdf_printf(pdf, "/FitBV ");
193
pdf_print_mag_bp(pdf, pdf_ann_left(i));
196
pdf_printf(pdf, "/FitR ");
197
pdf_print_rect_spec(pdf, i);
200
pdf_error("ext5", "unknown dest type");
203
pdf_printf(pdf, "]\n");
204
if (pdf_dest_named_id(i) > 0)
215
void scan_pdfdest(PDF pdf)
221
q = cur_list.tail_field;
222
new_whatsit(pdf_dest_node);
223
if (scan_keyword("num")) {
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")) {
233
set_pdf_dest_id(cur_list.tail_field, def_ref);
234
set_pdf_dest_named_id(cur_list.tail_field, 1);
236
pdf_error("ext1", "identifier type missing");
238
if (scan_keyword("xyz")) {
239
set_pdf_dest_type(cur_list.tail_field, pdf_dest_xyz);
240
if (scan_keyword("zoom")) {
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);
246
set_pdf_dest_xyz_zoom(cur_list.tail_field, null);
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);
263
pdf_error("ext1", "destination type missing");
265
/* Scan an optional space */
267
if (cur_cmd != spacer_cmd)
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);
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);
281
k = find_obj(pdf, obj_type_dest, pdf_dest_id(cur_list.tail_field),
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;
294
@ sorts |dest_names| by names
296
static int dest_cmp(const void *a, const void *b)
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);
304
void sort_dest_names(PDF pdf)
306
qsort(pdf->dest_names, (size_t) pdf->dest_names_ptr,
307
sizeof(dest_name_entry), dest_cmp);
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
317
int output_name_tree(PDF pdf)
319
boolean is_names = true; /* flag for name tree output: is it Names or Kids? */
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) */
325
int names_head = 0, names_tail = 0;
326
if (pdf->dest_names_ptr == 0) {
329
sort_dest_names(pdf);
334
pdf_create_obj(pdf, obj_type_others, 0); /* create a new node */
337
b = l; /* first in this level */
338
if (names_head == 0) {
342
set_obj_link(pdf, names_tail, l);
345
set_obj_link(pdf, names_tail, 0);
346
/* Output the current node in this level */
347
pdf_begin_dict(pdf, l, 1);
350
set_obj_start(pdf, l, pdf->dest_names[k].objname);
351
pdf_printf(pdf, "/Names [");
353
pdf_print_str(pdf, pdf->dest_names[k].objname);
355
pdf_print_int(pdf, pdf->dest_names[k].objnum);
356
pdf_printf(pdf, " 0 R ");
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) {
370
set_obj_start(pdf, l, obj_start(pdf, k));
371
pdf_printf(pdf, "/Kids [");
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);
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");
385
pdf_printf(pdf, "/Limits [");
386
pdf_print_str(pdf, obj_start(pdf, l));
388
pdf_print_str(pdf, obj_stop(pdf, l));
389
pdf_printf(pdf, "]\n");
403
if ((dests != 0) || (pdf_names_toks != null)) {
404
pdf_new_dict(pdf, obj_type_others, 0, 1);
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;