1% pdfcolorstack.w 2% 3% Copyright 2009-2011 Taco Hoekwater <taco@@luatex.org> 4% 5% This file is part of LuaTeX. 6% 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. 11% 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. 16% 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/>. 19 20@ @c 21 22 23#include "ptexlib.h" 24 25@* Color Stack and Matrix Transformation Support. 26 27 28@ In the following array and especially stack data structures are used. 29 30They have the following properties: 31 32 \item{-} They automatically grow dynamically. 33 \item{-} The size never decreases. 34 \item{-} The variable with name ending in "size" contains the number how many 35 entries the data structure can hold. 36 \item{-} The variable with name ending in "used" contains the number of 37 actually used entries. 38 \item{-} Memory of strings in stack entries must be allocated and 39 freed if the stack is cleared. 40 41 42@ Color Stack 43@c 44#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| */ 47 48#define COLOR_DEFAULT "0 g 0 G" 49/* |literal_mode|s, see pdftex.web */ 50#define SET_ORIGIN 0 51#define DIRECT_PAGE 1 52#define DIRECT_ALWAYS 2 53 54typedef 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; 67 68static colstack_type *colstacks = NULL; 69static int colstacks_size = 0; 70static int colstacks_used = 0; 71 72@ Initialization is done, if the color stacks are used, 73 |init_colorstacks()| is defined as macro to avoid unnecessary 74 procedure calls. 75@c 76#define init_colorstacks() if (colstacks_size == 0) colstacks_first_init(); 77 78static void colstacks_first_init(void) 79{ 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; 94} 95 96@ @c 97int colorstackused(void) 98{ 99 init_colorstacks(); 100 return colstacks_used; 101} 102 103@ |newcolorstack()| 104 A new color stack is setup with the given parameters. 105 The stack number is returned or -1 in case of error (no room). 106@c 107int newcolorstack(int s, int literal_mode, boolean page_start) 108{ 109 colstack_type *colstack; 110 int colstack_num; 111 char *str; 112 113 init_colorstacks(); 114 115 /* make room */ 116 if (colstacks_used == MAX_COLORSTACKS) { 117 return -1; 118 } 119 if (colstacks_used == colstacks_size) { 120 colstacks_size += STACK_INCREMENT; 121 /* If |(MAX_COLORSTACKS mod STACK_INCREMENT = 0)| then we don't 122 need to check the case that size overruns |MAX_COLORSTACKS|. */ 123 colstacks = 124 xreallocarray(colstacks, colstack_type, (unsigned) colstacks_size); 125 } 126 /* claim new color stack */ 127 colstack_num = colstacks_used++; 128 colstack = &colstacks[colstack_num]; 129 /* configure the new color stack */ 130 colstack->page_stack = NULL; 131 colstack->form_stack = NULL; 132 colstack->page_size = 0; 133 colstack->page_used = 0; 134 colstack->form_size = 0; 135 colstack->form_used = 0; 136 colstack->literal_mode = literal_mode; 137 colstack->page_start = page_start; 138 str = makecstring(s); 139 if (*str == 0) { 140 colstack->page_current = NULL; 141 colstack->form_current = NULL; 142 colstack->form_init = NULL; 143 } else { 144 colstack->page_current = xstrdup(str); 145 colstack->form_current = xstrdup(str); 146 colstack->form_init = xstrdup(str); 147 } 148 free(str); 149 return colstack_num; 150} 151 152@ @c 153#define get_colstack(n) (&colstacks[n]) 154 155@ Puts a string on top of the string pool and updates |pool_ptr|. 156@c 157static void put_cstring_on_str_pool(char *str) 158{ 159 int save_selector = selector; 160 selector = new_string; 161 if (str == NULL || *str == 0) { 162 return; 163 } 164 tprint(str); 165 selector = save_selector; 166} 167 168@ @c 169static int colorstackset(int colstack_no, str_number s) 170{ 171 colstack_type *colstack = get_colstack(colstack_no); 172 173 if (global_shipping_mode == SHIPPING_PAGE) { 174 xfree(colstack->page_current); 175 colstack->page_current = makecstring(s); 176 } else { 177 xfree(colstack->form_current); 178 colstack->form_current = makecstring(s); 179 } 180 return colstack->literal_mode; 181} 182 183@ @c 184int colorstackcurrent(int colstack_no) 185{ 186 colstack_type *colstack = get_colstack(colstack_no); 187 188 if (global_shipping_mode == SHIPPING_PAGE) { 189 put_cstring_on_str_pool(colstack->page_current); 190 } else { 191 put_cstring_on_str_pool(colstack->form_current); 192 } 193 return colstack->literal_mode; 194} 195 196@ @c 197static int colorstackpush(int colstack_no, str_number s) 198{ 199 colstack_type *colstack = get_colstack(colstack_no); 200 char *str; 201 if (global_shipping_mode == SHIPPING_PAGE) { 202 if (colstack->page_used == colstack->page_size) { 203 colstack->page_size += STACK_INCREMENT; 204 xretalloc(colstack->page_stack, (unsigned) colstack->page_size, 205 char *); 206 } 207 colstack->page_stack[colstack->page_used++] = colstack->page_current; 208 str = makecstring(s); 209 if (*str == 0) { 210 colstack->page_current = NULL; 211 } else { 212 colstack->page_current = xstrdup(str); 213 } 214 free(str); 215 } else { 216 if (colstack->form_used == colstack->form_size) { 217 colstack->form_size += STACK_INCREMENT; 218 xretalloc(colstack->form_stack, (unsigned) colstack->form_size, 219 char *); 220 } 221 colstack->form_stack[colstack->form_used++] = colstack->form_current; 222 str = makecstring(s); 223 if (*str == 0) { 224 colstack->form_current = NULL; 225 } else { 226 colstack->form_current = xstrdup(str); 227 } 228 free(str); 229 } 230 return colstack->literal_mode; 231} 232 233@ @c 234int colorstackpop(int colstack_no) 235{ 236 colstack_type *colstack = get_colstack(colstack_no); 237 238 if (global_shipping_mode == SHIPPING_PAGE) { 239 if (colstack->page_used == 0) { 240 luatex_warn("pop empty color page stack %u", 241 (unsigned int) colstack_no); 242 return colstack->literal_mode; 243 } 244 xfree(colstack->page_current); 245 colstack->page_current = colstack->page_stack[--colstack->page_used]; 246 put_cstring_on_str_pool(colstack->page_current); 247 } else { 248 if (colstack->form_used == 0) { 249 luatex_warn("pop empty color form stack %u", 250 (unsigned int) colstack_no); 251 return colstack->literal_mode; 252 } 253 xfree(colstack->form_current); 254 colstack->form_current = colstack->form_stack[--colstack->form_used]; 255 put_cstring_on_str_pool(colstack->form_current); 256 } 257 return colstack->literal_mode; 258} 259 260@ @c 261void colorstackpagestart(void) 262{ 263 int i, j; 264 colstack_type *colstack; 265 266 if (global_shipping_mode == SHIPPING_PAGE) { 267 /* see procedure |pdf_out_colorstack_startpage| */ 268 return; 269 } 270 271 for (i = 0; i < colstacks_used; i++) { 272 colstack = &colstacks[i]; 273 for (j = 0; j < colstack->form_used; j++) { 274 xfree(colstack->form_stack[j]); 275 } 276 colstack->form_used = 0; 277 xfree(colstack->form_current); 278 if (colstack->form_init == NULL) { 279 colstack->form_current = NULL; 280 } else { 281 colstack->form_current = xstrdup(colstack->form_init); 282 } 283 } 284} 285 286@ @c 287int colorstackskippagestart(int colstack_no) 288{ 289 colstack_type *colstack = get_colstack(colstack_no); 290 291 if (!colstack->page_start) { 292 return 1; 293 } 294 if (colstack->page_current == NULL) { 295 return 0; 296 } 297 if (strcmp(COLOR_DEFAULT, colstack->page_current) == 0) { 298 return 2; 299 } 300 return 0; 301} 302 303 304@ @c 305void pdf_out_colorstack(PDF pdf, halfword p) 306{ 307 int old_setting; 308 str_number s; 309 int cmd; 310 int stack_no; 311 int literal_mode; 312 cmd = pdf_colorstack_cmd(p); 313 stack_no = pdf_colorstack_stack(p); 314 literal_mode = 0; 315 if (stack_no >= colorstackused()) { 316 tprint_nl(""); 317 tprint("Color stack "); 318 print_int(stack_no); 319 tprint(" is not initialized for use!"); 320 tprint_nl(""); 321 return; 322 } 323 switch (cmd) { 324 case colorstack_set: 325 case colorstack_push: 326 old_setting = selector; 327 selector = new_string; 328 show_token_list(token_link(pdf_colorstack_data(p)), null, -1); 329 selector = old_setting; 330 s = make_string(); 331 if (cmd == colorstack_set) 332 literal_mode = colorstackset(stack_no, s); 333 else 334 literal_mode = colorstackpush(stack_no, s); 335 if (str_length(s) > 0) 336 pdf_literal(pdf, s, literal_mode, false); 337 flush_str(s); 338 return; 339 break; 340 case colorstack_pop: 341 literal_mode = colorstackpop(stack_no); 342 break; 343 case colorstack_current: 344 literal_mode = colorstackcurrent(stack_no); 345 break; 346 default: 347 break; 348 } 349 if (cur_length > 0) { 350 s = make_string(); 351 pdf_literal(pdf, s, literal_mode, false); 352 flush_str(s); 353 } 354} 355 356@ @c 357void pdf_out_colorstack_startpage(PDF pdf) 358{ 359 int i; 360 int max; 361 int start_status; 362 int literal_mode; 363 str_number s; 364 i = 0; 365 max = colorstackused(); 366 while (i < max) { 367 start_status = colorstackskippagestart(i); 368 if (start_status == 0) { 369 literal_mode = colorstackcurrent(i); 370 if (cur_length > 0) { 371 s = make_string(); 372 pdf_literal(pdf, s, literal_mode, false); 373 flush_str(s); 374 } 375 } 376 i++; 377 } 378} 379