beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / pdf / pdfoutline.w
blob6c0a30a88d9f450bc5fe459368b77ca6efeba904
1 % pdfoutline.w
3 % Copyright 2009-2011 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 @ Data structure of outlines; it's not able to write out outline entries before
25 all outline entries are defined, so memory allocated for outline entries can't
26 not be deallocated and will stay in memory. For this reason we will store data of
27 outline entries in |pdf->mem| instead of |mem|
30 #define pdfmem_outline_size 8 /* size of memory in |pdf->mem| which |obj_outline_ptr| points to */
32 #define obj_outline_count obj_info /* count of all opened children */
33 #define obj_outline_ptr obj_aux /* pointer to |pdf->mem| */
35 #define obj_outline_title(pdf,A) pdf->mem[obj_outline_ptr(pdf,A)]
36 #define obj_outline_parent(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 1]
37 #define obj_outline_prev(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 2]
38 #define obj_outline_next(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 3]
39 #define obj_outline_first(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 4]
40 #define obj_outline_last(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 5]
41 #define obj_outline_action_objnum(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 6] /* object number of action */
42 #define obj_outline_attr(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 7]
44 #define set_obj_outline_count(pdf,A,B) obj_outline_count(pdf,A)=B
45 #define set_obj_outline_ptr(pdf,A,B) obj_outline_ptr(pdf,A)=B
46 #define set_obj_outline_action_objnum(pdf,A,B) obj_outline_action_objnum(pdf,A)=B
47 #define set_obj_outline_title(pdf,A,B) obj_outline_title(pdf,A)=B
48 #define set_obj_outline_prev(pdf,A,B) obj_outline_prev(pdf,A)=B
49 #define set_obj_outline_next(pdf,A,B) obj_outline_next(pdf,A)=B
50 #define set_obj_outline_first(pdf,A,B) obj_outline_first(pdf,A)=B
51 #define set_obj_outline_last(pdf,A,B) obj_outline_last(pdf,A)=B
52 #define set_obj_outline_parent(pdf,A,B) obj_outline_parent(pdf,A)=B
53 #define set_obj_outline_attr(pdf,A,B) obj_outline_attr(pdf,A)=B
55 @ @c
56 static int open_subentries(PDF pdf, halfword p)
58 int c, l, r;
59 int k = 0;
60 if (obj_outline_first(pdf, p) != 0) {
61 l = obj_outline_first(pdf, p);
62 do {
63 k++;
64 c = open_subentries(pdf, l);
65 if (obj_outline_count(pdf, l) > 0)
66 k = k + c;
67 obj_outline_parent(pdf, l) = p;
68 r = obj_outline_next(pdf, l);
69 if (r == 0)
70 obj_outline_last(pdf, p) = l;
71 l = r;
72 } while (l != 0);
74 if (obj_outline_count(pdf, p) > 0)
75 obj_outline_count(pdf, p) = k;
76 else
77 obj_outline_count(pdf, p) = -k;
78 return k;
81 @ return number of outline entries in the same level with |p|
84 static int outline_list_count(PDF pdf, pointer p)
86 int k = 1;
87 while (obj_outline_prev(pdf, p) != 0) {
88 k++;
89 p = obj_outline_prev(pdf, p);
91 return k;
94 @ @c
95 void scan_pdfoutline(PDF pdf)
97 halfword q, r;
98 int i, k, l;
99 int j = 0;
100 halfword p = null;
101 if (scan_keyword("attr")) {
102 scan_toks(false, true);
103 r = def_ref;
104 } else {
105 r = 0;
107 if (scan_keyword("useobjnum")) {
108 scan_int();
109 j = cur_val;
110 } else {
111 p = scan_action(pdf);
113 if (scan_keyword("count")) {
114 scan_int();
115 i = cur_val;
116 } else {
117 i = 0;
119 scan_toks(false, true);
120 q = def_ref;
121 if (j == 0) {
122 j = pdf_create_obj(pdf, obj_type_others, 0);
123 pdf_begin_obj(pdf, j, OBJSTM_ALWAYS);
124 write_action(pdf, p);
125 pdf_end_obj(pdf);
126 delete_action_ref(p);
128 k = pdf_create_obj(pdf, obj_type_outline, 0);
129 set_obj_outline_ptr(pdf, k, pdf_get_mem(pdf, pdfmem_outline_size));
130 set_obj_outline_action_objnum(pdf, k, j);
131 set_obj_outline_count(pdf, k, i);
132 l = pdf_create_obj(pdf, obj_type_others, 0);
133 pdf_begin_obj(pdf, l, OBJSTM_ALWAYS);
135 char *s = tokenlist_to_cstring(q, true, NULL);
136 pdf_print_str_ln(pdf, s);
137 xfree(s);
139 delete_token_ref(q);
140 pdf_end_obj(pdf);
141 set_obj_outline_title(pdf, k, l);
142 set_obj_outline_prev(pdf, k, 0);
143 set_obj_outline_next(pdf, k, 0);
144 set_obj_outline_first(pdf, k, 0);
145 set_obj_outline_last(pdf, k, 0);
146 set_obj_outline_parent(pdf, k, pdf->parent_outline);
147 set_obj_outline_attr(pdf, k, r);
148 if (pdf->first_outline == 0)
149 pdf->first_outline = k;
150 if (pdf->last_outline == 0) {
151 if (pdf->parent_outline != 0)
152 set_obj_outline_first(pdf, pdf->parent_outline, k);
153 } else {
154 set_obj_outline_next(pdf, pdf->last_outline, k);
155 set_obj_outline_prev(pdf, k, pdf->last_outline);
157 pdf->last_outline = k;
158 if (obj_outline_count(pdf, k) != 0) {
159 pdf->parent_outline = k;
160 pdf->last_outline = 0;
161 } else if ((pdf->parent_outline != 0) &&
162 (outline_list_count(pdf, k) ==
163 abs(obj_outline_count(pdf, pdf->parent_outline)))) {
164 j = pdf->last_outline;
165 do {
166 set_obj_outline_last(pdf, pdf->parent_outline, j);
167 j = pdf->parent_outline;
168 pdf->parent_outline = obj_outline_parent(pdf, pdf->parent_outline);
169 } while (!((pdf->parent_outline == 0) ||
170 (outline_list_count(pdf, j) <
171 abs(obj_outline_count(pdf, pdf->parent_outline)))));
172 if (pdf->parent_outline == 0)
173 pdf->last_outline = pdf->first_outline;
174 else
175 pdf->last_outline = obj_outline_first(pdf, pdf->parent_outline);
176 while (obj_outline_next(pdf, pdf->last_outline) != 0)
177 pdf->last_outline = obj_outline_next(pdf, pdf->last_outline);
181 @ In the end we must flush PDF objects that cannot be written out immediately
182 after shipping out pages.
185 int print_outlines(PDF pdf)
187 int k, l, a;
188 int outlines;
189 if (pdf->first_outline != 0) {
190 outlines = pdf_create_obj(pdf, obj_type_others, 0);
191 l = pdf->first_outline;
192 k = 0;
193 do {
194 k++;
195 a = open_subentries(pdf, l);
196 if (obj_outline_count(pdf, l) > 0)
197 k = k + a;
198 set_obj_outline_parent(pdf, l, pdf->obj_ptr);
199 l = obj_outline_next(pdf, l);
200 } while (l != 0);
201 pdf_begin_obj(pdf, outlines, OBJSTM_ALWAYS);
202 pdf_begin_dict(pdf);
203 pdf_dict_add_name(pdf, "Type", "Outlines");
204 pdf_dict_add_ref(pdf, "First", pdf->first_outline);
205 pdf_dict_add_ref(pdf, "Last", pdf->last_outline);
206 pdf_dict_add_int(pdf, "Count", k);
207 pdf_end_dict(pdf);
208 pdf_end_obj(pdf);
209 /* Output PDF outline entries */
211 k = pdf->head_tab[obj_type_outline];
212 while (k != 0) {
213 if (obj_outline_parent(pdf, k) == pdf->parent_outline) {
214 if (obj_outline_prev(pdf, k) == 0)
215 pdf->first_outline = k;
216 if (obj_outline_next(pdf, k) == 0)
217 pdf->last_outline = k;
219 pdf_begin_obj(pdf, k, OBJSTM_ALWAYS);
220 pdf_begin_dict(pdf);
221 pdf_dict_add_ref(pdf, "Title", obj_outline_title(pdf, k));
222 pdf_dict_add_ref(pdf, "A", obj_outline_action_objnum(pdf, k));
223 if (obj_outline_parent(pdf, k) != 0)
224 pdf_dict_add_ref(pdf, "Parent", obj_outline_parent(pdf, k));
225 if (obj_outline_prev(pdf, k) != 0)
226 pdf_dict_add_ref(pdf, "Prev", obj_outline_prev(pdf, k));
227 if (obj_outline_next(pdf, k) != 0)
228 pdf_dict_add_ref(pdf, "Next", obj_outline_next(pdf, k));
229 if (obj_outline_first(pdf, k) != 0)
230 pdf_dict_add_ref(pdf, "First", obj_outline_first(pdf, k));
231 if (obj_outline_last(pdf, k) != 0)
232 pdf_dict_add_ref(pdf, "Last", obj_outline_last(pdf, k));
233 if (obj_outline_count(pdf, k) != 0)
234 pdf_dict_add_int(pdf, "Count", obj_outline_count(pdf, k));
235 if (obj_outline_attr(pdf, k) != 0) {
236 pdf_out(pdf, '\n');
237 pdf_print_toks(pdf, obj_outline_attr(pdf, k));
238 pdf_out(pdf, '\n');
239 delete_token_ref(obj_outline_attr(pdf, k));
240 set_obj_outline_attr(pdf, k, null);
242 pdf_end_dict(pdf);
243 pdf_end_obj(pdf);
244 k = obj_link(pdf, k);
247 } else {
248 outlines = 0;
250 return outlines;