beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / pdf / pdflink.w
blobb21d0774ecdc6060d54c390396055f5acef2e346
1 % pdflink.w
3 % Copyright 2009-2012 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 @ @c
22 #include "ptexlib.h"
24 @ To implement nested link annotations, we need a stack to hold copy of
25 |pdf_start_link_node|'s that are being written out, together with their box
26 nesting level.
29 void push_link_level(PDF pdf, halfword p)
31 if (pdf->link_stack_ptr >= pdf_max_link_level)
32 overflow("pdf link stack size", pdf_max_link_level);
33 pdf->link_stack_ptr++;
34 pdf->link_stack[pdf->link_stack_ptr].nesting_level = cur_s;
35 pdf->link_stack[pdf->link_stack_ptr].link_node = copy_node_list(p);
36 pdf->link_stack[pdf->link_stack_ptr].ref_link_node = p;
39 @ @c
40 void pop_link_level(PDF pdf)
42 flush_node_list(pdf->link_stack[pdf->link_stack_ptr].link_node);
43 pdf->link_stack_ptr--;
46 @ @c
47 void do_link(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
49 scaled_whd alt_rule;
50 int k;
51 if (type(p) == vlist_node)
52 normal_error("pdf backend", "'startlink' ended up in vlist");
53 if (global_shipping_mode == SHIPPING_FORM)
54 normal_error("pdf backend", "link annotations cannot be inside an xform");
55 if (is_obj_scheduled(pdf, pdf_link_objnum(p)))
56 pdf_link_objnum(p) = pdf_create_obj(pdf, obj_type_others, 0);
57 push_link_level(pdf, p);
58 alt_rule.wd = width(p);
59 alt_rule.ht = height(p);
60 alt_rule.dp = depth(p);
61 set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin);
62 obj_annot_ptr(pdf, pdf_link_objnum(p)) = p; /* the reference for the pdf annot object must be set here */
63 k = pdf_link_objnum(p);
64 set_obj_scheduled(pdf, pdf_link_objnum(p));
65 addto_page_resources(pdf, obj_type_link, k);
68 @ @c
69 void end_link(PDF pdf, halfword p)
71 halfword q;
72 scaledpos pos = pdf->posstruct->pos;
73 if (type(p) == vlist_node)
74 normal_error("pdf backend","'endlink' ended up in vlist");
75 if (pdf->link_stack_ptr < 1)
76 normal_error("pdf backend","pdf link_stack empty, 'endlink' used without 'startlink'");
77 if (pdf->link_stack[pdf->link_stack_ptr].nesting_level != cur_s)
78 normal_error("pdf backend","'endlink' ended up in different nesting level than 'startlink'");
80 NOTA BENE: test for running link must be done on |link_node| and not
81 |ref_link_node|, as |ref_link_node| can be set by |do_link| or
82 |append_link| already
84 if (is_running(width(pdf->link_stack[pdf->link_stack_ptr].link_node))) {
85 q = pdf->link_stack[pdf->link_stack_ptr].ref_link_node;
86 if (global_shipping_mode == SHIPPING_PAGE && matrixused()) {
87 matrixrecalculate(pos.h + pdf_link_margin);
88 pdf_ann_left(q) = getllx() - pdf_link_margin;
89 pdf_ann_top(q) = getlly() - pdf_link_margin;
90 pdf_ann_right(q) = geturx() + pdf_link_margin;
91 pdf_ann_bottom(q) = getury() + pdf_link_margin;
92 } else {
93 switch (pdf->posstruct->dir) {
94 case dir_TLT:
95 pdf_ann_right(q) = pos.h + pdf_link_margin;
96 break;
97 case dir_TRT:
98 pdf_ann_left(q) = pos.h - pdf_link_margin;
99 break;
100 case dir_LTL:
101 case dir_RTT:
102 pdf_ann_bottom(q) = pos.v - pdf_link_margin;
103 break;
104 default:
105 pdf_ann_right(q) = pos.h + pdf_link_margin;
106 formatted_warning("pdf backend","forcing bad dir %i to TLT in link",pdf->posstruct->dir);
110 pop_link_level(pdf);
113 @ For ``running'' annotations we must append a new node when the end of
114 annotation is in other box than its start. The new created node is identical to
115 corresponding whatsit node representing the start of annotation, but its |info|
116 field is |max_halfword|. We set |info| field just before destroying the node, in
117 order to use |flush_node_list| to do the job.
119 @ Append a new pdf annot to |pdf_link_list|.
122 void append_link(PDF pdf, halfword parent_box, scaledpos cur, small_number i)
124 halfword p;
125 int k;
126 scaled_whd alt_rule;
127 p = copy_node(pdf->link_stack[(int) i].link_node);
128 pdf->link_stack[(int) i].ref_link_node = p;
129 subtype(p) = pdf_link_data_node; /* this node is not a normal link node */
130 alt_rule.wd = width(p);
131 alt_rule.ht = height(p);
132 alt_rule.dp = depth(p);
133 set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin);
134 k = pdf_create_obj(pdf, obj_type_others, 0);
135 obj_annot_ptr(pdf, k) = p;
136 set_obj_scheduled(pdf, pdf_link_objnum(p));
137 addto_page_resources(pdf, obj_type_link, k);
140 @ @c
141 void scan_startlink(PDF pdf)
143 int k;
144 halfword r;
145 if (abs(cur_list.mode_field) == vmode)
146 normal_error("pdf backend", "startlink cannot be used in vertical mode");
147 k = pdf_create_obj(pdf, obj_type_others, 0);
148 new_annot_whatsit(pdf_start_link_node);
149 set_pdf_link_attr(cur_list.tail_field, null);
150 if (scan_keyword("attr")) {
151 scan_toks(false, true);
152 set_pdf_link_attr(cur_list.tail_field, def_ref);
154 r = scan_action(pdf);
155 set_pdf_link_action(cur_list.tail_field, r);
156 set_pdf_link_objnum(cur_list.tail_field, k);
157 pdf_last_link = k;
159 NOTA BENE: although it is possible to set |obj_annot_ptr(k) := tail|
160 here, it is not safe if nodes are later copied/destroyed/moved; a better
161 place to do this is inside |do_link|, when the whatsit node is written