3 % Copyright
2006-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
/>.
27 # define PAGES_TREE_KIDSMAX
10
29 static struct avl_table
*divert_list_tree
= NULL;
31 typedef struct pages_entry_
{
32 int objnum
; /* object number of this
/Pages object
*/
33 int number_of_pages
; /* total number of all pages below
*/
34 int number_of_kids
; /* number of direct kid objects
*/
35 int kids
[PAGES_TREE_KIDSMAX
]; /* array of kid object numbers
*/
36 struct pages_entry_
*next
;
39 typedef struct divert_list_entry_
{
45 static int comp_divert_list_entry
(const void
*pa
, const void
*pb
, void
*p
)
48 if
(((const divert_list_entry
*) pa
)->divnum
> ((const divert_list_entry
*) pb
)->divnum
)
50 if
(((const divert_list_entry
*) pa
)->divnum
< ((const divert_list_entry
*) pb
)->divnum
)
56 static pages_entry
*new_pages_entry
(PDF pdf
)
59 pages_entry
*p
= xtalloc
(1, pages_entry
);
60 p-
>number_of_pages
= p-
>number_of_kids
= 0;
61 for
(i
= 0; i
< PAGES_TREE_KIDSMAX
; i
++)
64 p-
>objnum
= pdf_create_obj
(pdf
, obj_type_pages
, 0);
69 static divert_list_entry
*new_divert_list_entry
(void
)
72 d
= xtalloc
(1, divert_list_entry
);
73 d-
>first
= d-
>last
= NULL;
78 static void ensure_list_tree
(void
)
80 if
(divert_list_tree
== NULL) {
81 divert_list_tree
= avl_create
(comp_divert_list_entry
, NULL, &avl_xallocator);
86 static divert_list_entry
*get_divert_list
(int divnum
)
88 divert_list_entry
*d
, tmp
;
91 d
= (divert_list_entry
*) avl_find
(divert_list_tree
, &tmp);
93 d
= new_divert_list_entry
();
95 /* the next bit of code can actually be removed
*/
96 aa
= avl_probe
(divert_list_tree
, d
);
98 normal_error
("pdf backend","page list lookup error");
104 @ |pdf_do_page_divert
()| returns the current
/Parent object number
106 int pdf_do_page_divert
(PDF pdf
, int objnum
, int divnum
)
108 divert_list_entry
*d
;
110 /* initialize the tree
*/
112 /* make sure we have a list for this diversion
*/
113 d
= get_divert_list
(divnum
);
114 if
(d-
>first
== NULL || d-
>last-
>number_of_kids
== PAGES_TREE_KIDSMAX
) {
115 /* append a new |pages_entry|
*/
116 p
= new_pages_entry
(pdf
);
117 if
(d-
>first
== NULL)
124 p-
>kids
[p-
>number_of_kids
++] = objnum
;
125 p-
>number_of_pages
++;
130 static void movelist
(divert_list_entry
* d
, divert_list_entry
* dto
)
132 if
(d
!= NULL && d->first != NULL && d->divnum != dto->divnum) {
133 /* no undivert of empty list or into self
*/
134 if
(dto-
>first
== NULL)
135 dto-
>first
= d-
>first
;
137 dto-
>last-
>next
= d-
>first
;
139 /* one could as well remove this |divert_list_entry|
*/
140 d-
>first
= d-
>last
= NULL;
144 @ undivert from diversion |divnum| into diversion |curdivnum|
146 void pdf_do_page_undivert
(int divnum
, int curdivnum
)
148 divert_list_entry
*d
, *dto
, tmp
;
149 struct avl_traverser t
;
150 /* initialize the tree
*/
152 /* find the diversion |curdivnum| list where diversion |divnum| should go
*/
153 dto
= get_divert_list
(curdivnum
);
155 /* 0 = special case
: undivert
{\it all\
/} lists
*/
156 avl_t_init
(&t, divert_list_tree);
157 for
(d
= avl_t_first
(&t, divert_list_tree); d != NULL;
162 d
= (divert_list_entry
*) avl_find
(divert_list_tree
, &tmp);
167 @ write a
/Pages object
170 static void write_pages
(PDF pdf
, pages_entry
* p
, int parent
)
173 int pages_attributes
;
174 pdf_begin_obj
(pdf
, p-
>objnum
, OBJSTM_ALWAYS
);
176 pdf_dict_add_name
(pdf
, "Type", "Pages");
179 pages_attributes
= pdf_pages_attr
; /* lookup once
*/
180 if
(pages_attributes
!= null
) {
181 pdf_print_toks
(pdf
, pages_attributes
);
184 print_pdf_table_string
(pdf
, "pagesattributes");
187 pdf_dict_add_ref
(pdf
, "Parent", parent
);
188 pdf_dict_add_int
(pdf
, "Count", (int
) p-
>number_of_pages
);
189 pdf_add_name
(pdf
, "Kids");
190 pdf_begin_array
(pdf
);
191 for
(i
= 0; i
< p-
>number_of_kids
; i
++)
192 pdf_add_ref
(pdf
, (int
) p-
>kids
[i
]);
198 @ loop over all
/Pages objects
, output them
, create their parents
,
199 recursing bottom up
, return the
/Pages root object number
202 static int output_pages_list
(PDF pdf
, pages_entry
* pe
)
204 pages_entry
*p
, *q
, *r
;
205 if
(pe-
>next
== NULL) {
206 /* everything fits into one |pages_entry|
*/
207 write_pages
(pdf
, pe
, 0); /* /Pages root found
*/
210 q
= r
= new_pages_entry
(pdf
); /* one level higher needed
*/
211 for
(p
= pe
; p
!= NULL; p
= p-
>next
) {
212 if
(q-
>number_of_kids
== PAGES_TREE_KIDSMAX
) {
213 q-
>next
= new_pages_entry
(pdf
);
216 q-
>kids
[q-
>number_of_kids
++] = p-
>objnum
;
217 q-
>number_of_pages
+= p-
>number_of_pages
;
218 write_pages
(pdf
, p
, q-
>objnum
);
220 return output_pages_list
(pdf
, r
); /* recurse through next higher level
*/
224 int output_pages_tree
(PDF pdf
)
226 divert_list_entry
*d
;
227 pdf_do_page_undivert
(0, 0); /* concatenate all diversions into diversion
0 */
228 d
= get_divert_list
(0); /* get diversion
0 */
229 return output_pages_list
(pdf
, d-
>first
);