beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / pdf / pdfcolorstack.w
blobbcc7145c6ce3b8c4ad8f9613954ee1285ed4507d
1 % pdfcolorstack.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 @* Color Stack and Matrix Transformation Support.
26 @ In the following array and especially stack data structures are used.
28 They have the following properties:
30 \item{-} They automatically grow dynamically.
31 \item{-} The size never decreases.
32 \item{-} The variable with name ending in "size" contains the number how many
33 entries the data structure can hold.
34 \item{-} The variable with name ending in "used" contains the number of
35 actually used entries.
36 \item{-} Memory of strings in stack entries must be allocated and
37 freed if the stack is cleared.
39 @ Color Stack
42 #define MAX_COLORSTACKS 32768
45 The colorstack number is stored in two bytes (info field of the node);
46 condition (newcolorstack): |MAX_COLORSTACKS mod STACK_INCREMENT = 0|
49 #define COLOR_DEFAULT "0 g 0 G"
50 #define SET_ORIGIN 0
51 #define DIRECT_PAGE 1
52 #define DIRECT_ALWAYS 2
54 typedef struct {
55 char **page_stack;
56 char **form_stack;
57 char *page_current;
58 char *form_current;
59 char *form_init;
60 int page_size;
61 int form_size;
62 int page_used;
63 int form_used;
64 int literal_mode;
65 boolean page_start;
66 } colstack_type;
68 static colstack_type *colstacks = NULL;
69 static int colstacks_size = 0;
70 static int colstacks_used = 0;
72 @ Initialization is done, if the color stacks are used, |init_colorstacks()| is defined
73 as macro to avoid unnecessary procedure calls.
76 #define init_colorstacks() if (colstacks_size == 0) colstacks_first_init();
78 static void colstacks_first_init(void)
80 colstacks_size = STACK_INCREMENT;
81 colstacks = xtalloc((unsigned) colstacks_size, colstack_type);
82 colstacks_used = 1;
83 colstacks[0].page_stack = NULL;
84 colstacks[0].form_stack = NULL;
85 colstacks[0].page_size = 0;
86 colstacks[0].form_size = 0;
87 colstacks[0].page_used = 0;
88 colstacks[0].form_used = 0;
89 colstacks[0].page_current = xstrdup(COLOR_DEFAULT);
90 colstacks[0].form_current = xstrdup(COLOR_DEFAULT);
91 colstacks[0].form_init = xstrdup(COLOR_DEFAULT);
92 colstacks[0].literal_mode = DIRECT_ALWAYS;
93 colstacks[0].page_start = true;
96 @ @c
97 int colorstackused(void)
99 init_colorstacks();
100 return colstacks_used;
103 @ A new color stack is setup with the given parameters. The stack number is returned
104 or -1 in case of error (no room).
107 int newcolorstack(const char *str, int literal_mode, boolean page_start)
109 colstack_type *colstack;
110 int colstack_num;
111 init_colorstacks();
112 /* make room */
113 if (colstacks_used == MAX_COLORSTACKS) {
114 return -1;
116 if (colstacks_used == colstacks_size) {
117 colstacks_size += STACK_INCREMENT;
119 If |(MAX_COLORSTACKS mod STACK_INCREMENT = 0)| then we don't
120 need to check the case that size overruns |MAX_COLORSTACKS|.
122 colstacks = xreallocarray(colstacks, colstack_type, (unsigned) colstacks_size);
124 /* claim new color stack */
125 colstack_num = colstacks_used++;
126 colstack = &colstacks[colstack_num];
127 /* configure the new color stack */
128 colstack->page_stack = NULL;
129 colstack->form_stack = NULL;
130 colstack->page_size = 0;
131 colstack->page_used = 0;
132 colstack->form_size = 0;
133 colstack->form_used = 0;
134 colstack->literal_mode = literal_mode;
135 colstack->page_start = page_start;
136 colstack->page_current = NULL;
137 colstack->form_current = NULL;
138 colstack->form_init = NULL;
139 if (str) {
140 colstack->page_current = xstrdup(str);
141 colstack->form_current = xstrdup(str);
142 colstack->form_init = xstrdup(str);
144 return colstack_num;
147 @ @c
148 #define get_colstack(n) (&colstacks[n])
150 @ Puts a string on top of the string pool and updates |pool_ptr|.
152 @c static void put_cstring_on_str_pool(char *str)
154 int save_selector = selector;
155 selector = new_string;
156 if (str == NULL || *str == 0) {
157 return;
159 tprint(str);
160 selector = save_selector;
163 @ @c
164 static int colorstackset(int colstack_no, str_number s)
166 colstack_type *colstack = get_colstack(colstack_no);
168 if (global_shipping_mode == SHIPPING_PAGE) {
169 xfree(colstack->page_current);
170 colstack->page_current = makecstring(s);
171 } else {
172 xfree(colstack->form_current);
173 colstack->form_current = makecstring(s);
175 return colstack->literal_mode;
178 @ @c
179 int colorstackcurrent(int colstack_no)
181 colstack_type *colstack = get_colstack(colstack_no);
183 if (global_shipping_mode == SHIPPING_PAGE) {
184 put_cstring_on_str_pool(colstack->page_current);
185 } else {
186 put_cstring_on_str_pool(colstack->form_current);
188 return colstack->literal_mode;
191 @ @c
192 static int colorstackpush(int colstack_no, str_number s)
194 colstack_type *colstack = get_colstack(colstack_no);
195 char *str;
196 if (global_shipping_mode == SHIPPING_PAGE) {
197 if (colstack->page_used == colstack->page_size) {
198 colstack->page_size += STACK_INCREMENT;
199 xretalloc(colstack->page_stack, (unsigned) colstack->page_size, char *);
201 colstack->page_stack[colstack->page_used++] = colstack->page_current;
202 str = makecstring(s);
203 if (*str == 0) {
204 colstack->page_current = NULL;
205 } else {
206 colstack->page_current = xstrdup(str);
208 free(str);
209 } else {
210 if (colstack->form_used == colstack->form_size) {
211 colstack->form_size += STACK_INCREMENT;
212 xretalloc(colstack->form_stack, (unsigned) colstack->form_size, char *);
214 colstack->form_stack[colstack->form_used++] = colstack->form_current;
215 str = makecstring(s);
216 if (*str == 0) {
217 colstack->form_current = NULL;
218 } else {
219 colstack->form_current = xstrdup(str);
221 free(str);
223 return colstack->literal_mode;
226 @ @c
227 int colorstackpop(int colstack_no)
229 colstack_type *colstack = get_colstack(colstack_no);
230 if (global_shipping_mode == SHIPPING_PAGE) {
231 if (colstack->page_used == 0) {
232 formatted_warning("pdf backend","pop empty color page stack %u",(unsigned int) colstack_no);
233 return colstack->literal_mode;
235 xfree(colstack->page_current);
236 colstack->page_current = colstack->page_stack[--colstack->page_used];
237 put_cstring_on_str_pool(colstack->page_current);
238 } else {
239 if (colstack->form_used == 0) {
240 formatted_warning("pdf backend","pop empty color form stack %u",(unsigned int) colstack_no);
241 return colstack->literal_mode;
243 xfree(colstack->form_current);
244 colstack->form_current = colstack->form_stack[--colstack->form_used];
245 put_cstring_on_str_pool(colstack->form_current);
247 return colstack->literal_mode;
250 @ @c
251 void colorstackpagestart(void)
253 int i, j;
254 colstack_type *colstack;
255 if (global_shipping_mode == SHIPPING_PAGE) {
256 /* see procedure |pdf_out_colorstack_startpage| */
257 return;
260 for (i = 0; i < colstacks_used; i++) {
261 colstack = &colstacks[i];
262 for (j = 0; j < colstack->form_used; j++) {
263 xfree(colstack->form_stack[j]);
265 colstack->form_used = 0;
266 xfree(colstack->form_current);
267 if (colstack->form_init == NULL) {
268 colstack->form_current = NULL;
269 } else {
270 colstack->form_current = xstrdup(colstack->form_init);
275 @ @c
276 int colorstackskippagestart(int colstack_no)
278 colstack_type *colstack = get_colstack(colstack_no);
279 if (!colstack->page_start) {
280 return 1;
282 if (colstack->page_current == NULL) {
283 return 0;
285 if (strcmp(COLOR_DEFAULT, colstack->page_current) == 0) {
286 return 2;
288 return 0;
292 @ @c
293 void pdf_out_colorstack(PDF pdf, halfword p)
295 int old_setting;
296 str_number s;
297 int cmd = pdf_colorstack_cmd(p);
298 int stack_no = pdf_colorstack_stack(p);
299 int literal_mode = 0;
300 if (stack_no >= colorstackused()) {
301 tprint_nl("");
302 tprint("Color stack ");
303 print_int(stack_no);
304 tprint(" is not initialized for use!");
305 tprint_nl("");
306 return;
308 switch (cmd) {
309 case colorstack_set:
310 case colorstack_push:
311 old_setting = selector;
312 selector = new_string;
313 show_token_list(token_link(pdf_colorstack_data(p)), null, -1);
314 selector = old_setting;
315 s = make_string();
316 if (cmd == colorstack_set)
317 literal_mode = colorstackset(stack_no, s);
318 else
319 literal_mode = colorstackpush(stack_no, s);
320 if (str_length(s) > 0)
321 pdf_literal(pdf, s, literal_mode, false);
322 flush_str(s);
323 return;
324 break;
325 case colorstack_pop:
326 literal_mode = colorstackpop(stack_no);
327 break;
328 case colorstack_current:
329 literal_mode = colorstackcurrent(stack_no);
330 break;
331 default:
332 break;
334 if (cur_length > 0) {
335 s = make_string();
336 pdf_literal(pdf, s, literal_mode, false);
337 flush_str(s);
341 @ @c
342 void pdf_out_colorstack_startpage(PDF pdf)
344 int start_status;
345 int literal_mode;
346 str_number s;
347 int i = 0;
348 int max = colorstackused();
349 while (i < max) {
350 start_status = colorstackskippagestart(i);
351 if (start_status == 0) {
352 literal_mode = colorstackcurrent(i);
353 if (cur_length > 0) {
354 s = make_string();
355 pdf_literal(pdf, s, literal_mode, false);
356 flush_str(s);
359 i++;