beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / pdf / pdfthread.w
blobb11e48c5fc028d9b9978bbd93655d131ade33408
1 % pdfthread.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 @ @c
25 #define page_width dimen_par(page_width_code)
26 #define page_height dimen_par(page_height_code)
28 @ Threads are handled in similar way as link annotations
30 void append_bead(PDF pdf, halfword p)
32 int a, b, c, t;
33 if (global_shipping_mode == SHIPPING_FORM)
34 normal_error("pdf backend", "threads cannot be inside an xform");
35 t = pdf_get_obj(pdf, obj_type_thread, pdf_thread_id(p), pdf_thread_named_id(p));
36 b = pdf_create_obj(pdf, obj_type_others, 0);
37 obj_bead_ptr(pdf, b) = pdf_get_mem(pdf, pdfmem_bead_size);
38 set_obj_bead_page(pdf, b, pdf->last_page);
39 set_obj_bead_data(pdf, b, p);
40 if (pdf_thread_attr(p) != null)
41 set_obj_bead_attr(pdf, b, tokens_to_string(pdf_thread_attr(p)));
42 else
43 set_obj_bead_attr(pdf, b, 0);
44 if (obj_thread_first(pdf, t) == 0) {
45 obj_thread_first(pdf, t) = b;
46 set_obj_bead_next(pdf, b, b);
47 set_obj_bead_prev(pdf, b, b);
48 } else {
49 a = obj_thread_first(pdf, t);
50 c = obj_bead_prev(pdf, a);
51 set_obj_bead_prev(pdf, b, c);
52 set_obj_bead_next(pdf, b, a);
53 set_obj_bead_prev(pdf, a, b);
54 set_obj_bead_next(pdf, c, b);
56 addto_page_resources(pdf, obj_type_bead, b);
59 @ @c
60 void do_thread(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
62 scaled_whd alt_rule;
63 if ((type(p) == hlist_node) && (subtype(p) == pdf_start_thread_node))
64 normal_error("pdf backend", "'startthread' ended up in hlist");
65 if (doing_leaders)
66 return;
67 if (subtype(p) == pdf_start_thread_node) {
68 pdf->thread.wd = width(p);
69 pdf->thread.ht = height(p);
70 pdf->thread.dp = depth(p);
71 pdf->last_thread_id = pdf_thread_id(p);
72 pdf->last_thread_named_id = (pdf_thread_named_id(p) > 0);
73 if (pdf->last_thread_named_id)
74 add_token_ref(pdf_thread_id(p));
75 pdf->thread_level = cur_s;
77 alt_rule.wd = width(p);
78 alt_rule.ht = height(p);
79 alt_rule.dp = depth(p);
80 set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_thread_margin);
81 append_bead(pdf, p);
82 pdf->last_thread = p;
85 @ @c
86 void append_thread(PDF pdf, halfword parent_box, scaledpos cur)
88 scaled_whd alt_rule;
89 halfword p = new_node(whatsit_node, pdf_thread_data_node);
90 width(p) = pdf->thread.wd;
91 height(p) = pdf->thread.ht;
92 depth(p) = pdf->thread.dp;
93 pdf_thread_attr(p) = null;
94 pdf_thread_id(p) = pdf->last_thread_id;
95 if (pdf->last_thread_named_id) {
96 add_token_ref(pdf_thread_id(p));
97 pdf_thread_named_id(p) = 1;
98 } else {
99 pdf_thread_named_id(p) = 0;
101 alt_rule.wd = width(p);
102 alt_rule.ht = height(p);
103 alt_rule.dp = depth(p);
104 set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_thread_margin);
105 append_bead(pdf, p);
106 pdf->last_thread = p;
109 @ @c
110 void end_thread(PDF pdf, halfword p)
112 scaledpos pos = pdf->posstruct->pos;
113 if (type(p) == hlist_node)
114 normal_error("pdf backend", "'endthread' ended up in hlist");
115 if (pdf->thread_level != cur_s)
116 normal_error("pdf backend", "'endthread' ended up in different nesting level than 'startthread'");
117 if (is_running(pdf->thread.dp) && (pdf->last_thread != null)) {
118 switch (pdf->posstruct->dir) {
119 case dir_TLT:
120 case dir_TRT:
121 pdf_ann_bottom(pdf->last_thread) = pos.v - pdf_thread_margin;
122 break;
123 case dir_LTL:
124 pdf_ann_right(pdf->last_thread) = pos.h + pdf_thread_margin;
125 break;
126 case dir_RTT:
127 pdf_ann_left(pdf->last_thread) = pos.h - pdf_thread_margin;
128 break;
129 default:
130 formatted_warning("pdf backend","forcing bad dir %i to TLT in end tread",pdf->posstruct->dir);
133 if (pdf->last_thread_named_id)
134 delete_token_ref(pdf->last_thread_id);
135 pdf->last_thread = null;
138 @ The following function are needed for outputing article thread.
140 void thread_title(PDF pdf, int t)
142 pdf_add_name(pdf, "Title");
143 pdf_out(pdf, '(');
144 if (obj_info(pdf, t) < 0)
145 pdf_print(pdf, -obj_info(pdf, t));
146 else
147 pdf_print_int(pdf, obj_info(pdf, t));
148 pdf_out(pdf, ')');
151 void pdf_fix_thread(PDF pdf, int t)
153 halfword a;
154 if (obj_info(pdf, t) < 0) {
155 char *ss = makecstring(-obj_info(pdf, t));
156 formatted_warning("pdf backend", "unknown thread destination name '%s'",ss);
157 } else {
158 formatted_warning("pdf backend", "unknown thread destination num '%d'",obj_info(pdf, t));
160 a = pdf_create_obj(pdf, obj_type_others, 0);
161 pdf_begin_obj(pdf, a, OBJSTM_ALWAYS);
162 pdf_begin_dict(pdf);
163 pdf_dict_add_ref(pdf, "T", t);
164 pdf_dict_add_ref(pdf, "V", a);
165 pdf_dict_add_ref(pdf, "N", a);
166 pdf_dict_add_ref(pdf, "P", pdf->last_page);
167 pdf_add_name(pdf, "R");
168 pdf_begin_array(pdf);
169 pdf_add_int(pdf, 0);
170 pdf_add_int(pdf, 0);
171 pdf_add_bp(pdf, page_width);
172 pdf_add_bp(pdf, page_height);
173 pdf_end_array(pdf);
174 pdf_end_dict(pdf);
175 pdf_end_obj(pdf);
176 pdf_begin_obj(pdf, t, OBJSTM_ALWAYS);
177 pdf_begin_dict(pdf);
178 pdf_add_name(pdf, "I");
179 pdf_begin_dict(pdf);
180 thread_title(pdf, t);
181 pdf_end_dict(pdf);
182 pdf_dict_add_ref(pdf, "F", a);
183 pdf_end_dict(pdf);
184 pdf_end_obj(pdf);
187 void out_thread(PDF pdf, int t)
189 halfword a, b;
190 int last_attr;
191 if (obj_thread_first(pdf, t) == 0) {
192 pdf_fix_thread(pdf, t);
193 return;
195 pdf_begin_obj(pdf, t, OBJSTM_ALWAYS);
196 pdf_begin_dict(pdf);
197 a = obj_thread_first(pdf, t);
198 b = a;
199 last_attr = 0;
200 do {
201 if (obj_bead_attr(pdf, a) != 0)
202 last_attr = obj_bead_attr(pdf, a);
203 a = obj_bead_next(pdf, a);
204 } while (a != b);
205 if (last_attr != 0) {
206 pdf_print_ln(pdf, last_attr);
207 } else {
208 pdf_add_name(pdf, "I");
209 pdf_begin_dict(pdf);
210 thread_title(pdf, t);
211 pdf_end_dict(pdf);
213 pdf_dict_add_ref(pdf, "F", a);
214 pdf_end_dict(pdf);
215 pdf_end_obj(pdf);
216 do {
217 pdf_begin_obj(pdf, a, OBJSTM_ALWAYS);
218 pdf_begin_dict(pdf);
219 if (a == b)
220 pdf_dict_add_ref(pdf, "T", t);
221 pdf_dict_add_ref(pdf, "V", obj_bead_prev(pdf, a));
222 pdf_dict_add_ref(pdf, "N", obj_bead_next(pdf, a));
223 pdf_dict_add_ref(pdf, "P", obj_bead_page(pdf, a));
224 pdf_dict_add_ref(pdf, "R", obj_bead_rect(pdf, a));
225 pdf_end_dict(pdf);
226 pdf_end_obj(pdf);
227 a = obj_bead_next(pdf, a);
228 } while (a != b);
231 @ @c
232 void scan_thread_id(void)
234 if (scan_keyword("num")) {
235 scan_int();
236 if (cur_val <= 0)
237 normal_error("pdf backend", "num identifier must be positive");
238 if (cur_val > max_halfword)
239 normal_error("pdf backend", "number too big");
240 set_pdf_thread_id(cur_list.tail_field, cur_val);
241 set_pdf_thread_named_id(cur_list.tail_field, 0);
242 } else if (scan_keyword("name")) {
243 scan_toks(false, true);
244 set_pdf_thread_id(cur_list.tail_field, def_ref);
245 set_pdf_thread_named_id(cur_list.tail_field, 1);
246 } else {
247 normal_error("pdf backend", "identifier type missing");
251 void check_running_thread(PDF pdf, halfword this_box, scaledpos cur)
253 if ((pdf->last_thread != null) && is_running(pdf->thread.dp)
254 && (pdf->thread_level == cur_s))
255 append_thread(pdf, this_box, cur);
258 @ @c
259 void print_bead_rectangles(PDF pdf)
261 halfword i;
262 pdf_object_list *k;
263 int l;
264 if ((k = get_page_resources_list(pdf, obj_type_bead)) != NULL) {
265 while (k != NULL) {
266 l = pdf_create_obj(pdf, obj_type_others, 0);
267 pdf_begin_obj(pdf, l, OBJSTM_ALWAYS);
268 pdf_begin_array(pdf);
269 i = obj_bead_data(pdf, k->info); /* pointer to a whatsit or whatsit-like node */
270 pdf_add_rect_spec(pdf, i);
271 if (subtype(i) == pdf_thread_data_node)
272 flush_node(i);
273 pdf_end_array(pdf);
274 pdf_end_obj(pdf);
275 set_obj_bead_rect(pdf, k->info, l); /* rewrite |obj_bead_data| */
276 k = k->link;