1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gxclutil.c 9666 2009-04-20 19:16:24Z mvrhel $ */
15 /* Command list writing utilities. */
16 
17 #include "memory_.h"
18 #include "string_.h"
19 #include "gx.h"
20 #include "gp.h"
21 #include "gpcheck.h"
22 #include "gserrors.h"
23 #include "gxdevice.h"
24 #include "gxdevmem.h"		/* must precede gxcldev.h */
25 #include "gxcldev.h"
26 #include "gxclpath.h"
27 #include "gsparams.h"
28 
29 /* ---------------- Statistics ---------------- */
30 
31 #ifdef DEBUG
32 const char *const cmd_op_names[16] =
33 {cmd_op_name_strings};
34 static const char *const cmd_misc_op_names[16] =
35 {cmd_misc_op_name_strings};
36 static const char *const cmd_misc2_op_names[16] =
37 {cmd_misc2_op_name_strings};
38 static const char *const cmd_segment_op_names[16] =
39 {cmd_segment_op_name_strings};
40 static const char *const cmd_path_op_names[16] =
41 {cmd_path_op_name_strings};
42 const char *const *const cmd_sub_op_names[16] =
43 {cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
44  0, 0, 0, 0,
45  0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names
46 };
47 struct stats_cmd_s {
48     ulong op_counts[256];
49     ulong op_sizes[256];
50     ulong tile_reset, tile_found, tile_added;
51     ulong same_band, other_band;
52 } stats_cmd;
53 extern ulong stats_cmd_diffs[5];	/* in gxclpath.c */
54 int
cmd_count_op(int op,uint size)55 cmd_count_op(int op, uint size)
56 {
57     stats_cmd.op_counts[op]++;
58     stats_cmd.op_sizes[op] += size;
59     if (gs_debug_c('L')) {
60 	const char *const *sub = cmd_sub_op_names[op >> 4];
61 
62 	if (sub)
63 	    dlprintf2(", %s(%u)\n", sub[op & 0xf], size);
64 	else
65 	    dlprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf,
66 		      size);
67 	dflush();
68     }
69     return op;
70 }
71 void
cmd_uncount_op(int op,uint size)72 cmd_uncount_op(int op, uint size)
73 {
74     stats_cmd.op_counts[op]--;
75     stats_cmd.op_sizes[op] -= size;
76 }
77 #endif
78 
79 /* Print statistics. */
80 #ifdef DEBUG
81 void
cmd_print_stats(void)82 cmd_print_stats(void)
83 {
84     int ci, cj;
85 
86     dlprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
87 	      stats_cmd.tile_reset, stats_cmd.tile_found,
88 	      stats_cmd.tile_added);
89     dlprintf5("     diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
90 	      stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2],
91 	      stats_cmd_diffs[3], stats_cmd_diffs[4]);
92     dlprintf2("     same_band = %lu, other_band = %lu\n",
93 	      stats_cmd.same_band, stats_cmd.other_band);
94     for (ci = 0; ci < 0x100; ci += 0x10) {
95 	const char *const *sub = cmd_sub_op_names[ci >> 4];
96 
97 	if (sub != 0) {
98 	    dlprintf1("[l]  %s =", cmd_op_names[ci >> 4]);
99 	    for (cj = ci; cj < ci + 0x10; cj += 2)
100 		dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
101 			 sub[cj - ci],
102 			 stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj],
103 			 sub[cj - ci + 1],
104 		   stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]);
105 	} else {
106 	    ulong tcounts = 0, tsizes = 0;
107 
108 	    for (cj = ci; cj < ci + 0x10; cj++)
109 		tcounts += stats_cmd.op_counts[cj],
110 		    tsizes += stats_cmd.op_sizes[cj];
111 	    dlprintf3("[l]  %s (%lu,%lu) =\n\t",
112 		      cmd_op_names[ci >> 4], tcounts, tsizes);
113 	    for (cj = ci; cj < ci + 0x10; cj++)
114 		if (stats_cmd.op_counts[cj] == 0)
115 		    dputs(" -");
116 		else
117 		    dprintf2(" %lu(%lu)", stats_cmd.op_counts[cj],
118 			     stats_cmd.op_sizes[cj]);
119 	}
120 	dputs("\n");
121     }
122 }
123 #endif /* DEBUG */
124 
125 /* ---------------- Writing utilities ---------------- */
126 
127 /* Write the commands for one band or band range. */
128 static int	/* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
cmd_write_band(gx_device_clist_writer * cldev,int band_min,int band_max,cmd_list * pcl,gx_band_complexity_t * band_complexity,byte cmd_end)129 cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
130 	       cmd_list * pcl, gx_band_complexity_t *band_complexity, byte cmd_end)
131 {
132     const cmd_prefix *cp = pcl->head;
133     int code_b = 0;
134     int code_c = 0;
135 
136     if (cp != 0 || cmd_end != cmd_opv_end_run) {
137 	clist_file_ptr cfile = cldev->page_cfile;
138 	clist_file_ptr bfile = cldev->page_bfile;
139 	cmd_block cb;
140 	byte end = cmd_count_op(cmd_end, 1);
141 
142 	if (cfile == 0 || bfile == 0)
143  	    return_error(gs_error_ioerror);
144 	cb.band_min = band_min;
145 	cb.band_max = band_max;
146 	cb.pos = cldev->page_info.io_procs->ftell(cfile);
147 	clist_copy_band_complexity(&cb.band_complexity, band_complexity);
148 	if_debug4('l', "[l]writing for bands (%d,%d) at %ld K %d \n",
149 		  band_min, band_max, (long)cb.pos, cb.band_complexity.uses_color);
150 	cldev->page_info.io_procs->fwrite_chars(&cb, sizeof(cb), bfile);
151 	if (cp != 0) {
152 	    pcl->tail->next = 0;	/* terminate the list */
153 	    for (; cp != 0; cp = cp->next) {
154 #ifdef DEBUG
155 		if ((const byte *)cp < cldev->cbuf ||
156 		    (const byte *)cp >= cldev->cend ||
157 		    cp->size > cldev->cend - (const byte *)cp
158 		    ) {
159 		    lprintf1("cmd_write_band error at 0x%lx\n", (ulong) cp);
160 		    return_error(gs_error_Fatal);
161 		}
162 #endif
163 		if_debug2('L',"[L]Wrote cmd id=%ld at %ld\n", cp->id,
164 		    (long)cldev->page_info.io_procs->ftell(cfile));
165 		cldev->page_info.io_procs->fwrite_chars(cp + 1, cp->size, cfile);
166 	    }
167 	    pcl->head = pcl->tail = 0;
168 	}
169 	cldev->page_info.io_procs->fwrite_chars(&end, 1, cfile);
170 	process_interrupts(cldev->memory);
171 	code_b = cldev->page_info.io_procs->ferror_code(bfile);
172 	code_c = cldev->page_info.io_procs->ferror_code(cfile);
173 	if (code_b < 0)
174 	    return_error(code_b);
175 	if (code_c < 0)
176 	    return_error(code_c);
177     }
178     return code_b | code_c;
179 }
180 
181 /* Write out the buffered commands, and reset the buffer. */
182 int	/* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
cmd_write_buffer(gx_device_clist_writer * cldev,byte cmd_end)183 cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
184 {
185     int nbands = cldev->nbands;
186     gx_clist_state *pcls;
187     int band;
188     int code = cmd_write_band(cldev, cldev->band_range_min,
189 			      cldev->band_range_max,
190 			      &cldev->band_range_list,
191 			      NULL,
192 			      cmd_opv_end_run);
193 
194     int warning = code;
195 
196     for (band = 0, pcls = cldev->states;
197 	 code >= 0 && band < nbands; band++, pcls++
198 	 ) {
199 	code = cmd_write_band(cldev, band, band, &pcls->list, &pcls->band_complexity, cmd_end);
200 	warning |= code;
201     }
202     /* If an error occurred, finish cleaning up the pointers. */
203     for (; band < nbands; band++, pcls++)
204 	pcls->list.head = pcls->list.tail = 0;
205     cldev->cnext = cldev->cbuf;
206     cldev->ccl = 0;
207 #ifdef DEBUG
208     if (gs_debug_c('l'))
209 	cmd_print_stats();
210 #endif
211     return_check_interrupt(cldev->memory, code != 0 ? code : warning);
212 }
213 
214 /*
215  * Add a command to the appropriate band list, and allocate space for its
216  * data.  Return the pointer to the data area.  If an error or (low-memory
217  * warning) occurs, set cldev->error_code and return 0.
218  */
219 #define cmd_headroom (sizeof(cmd_prefix) + ARCH_ALIGN_PTR_MOD)
220 byte *
cmd_put_list_op(gx_device_clist_writer * cldev,cmd_list * pcl,uint size)221 cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size)
222 {
223     byte *dp = cldev->cnext;
224 
225     if (size + cmd_headroom > cldev->cend - dp) {
226 	if ((cldev->error_code =
227              cmd_write_buffer(cldev, cmd_opv_end_run)) != 0 ||
228             (size + cmd_headroom > cldev->cend - cldev->cnext)) {
229 	    if (cldev->error_code < 0)
230 		cldev->error_is_retryable = 0;	/* hard error */
231 	    else {
232 		/* upgrade lo-mem warning into an error */
233 		if (!cldev->ignore_lo_mem_warnings)
234 		    cldev->error_code = gs_note_error(gs_error_VMerror);
235 		cldev->error_is_retryable = 1;
236 	    }
237 	    return 0;
238 	}
239 	else
240 	    return cmd_put_list_op(cldev, pcl, size);
241     }
242     if (cldev->ccl == pcl) {	/* We're adding another command for the same band. */
243 	/* Tack it onto the end of the previous one. */
244 	cmd_count_add1(stats_cmd.same_band);
245 #ifdef DEBUG
246 	if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) {
247 	    lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong) pcl->tail);
248 	}
249 #endif
250 	if_debug2('L', ", to id=%ld , offset=%ld", pcl->tail->id, (long)pcl->tail->size);
251 	pcl->tail->size += size;
252     } else {
253 	/* Skip to an appropriate alignment boundary. */
254 	/* (We assume the command buffer itself is aligned.) */
255 	cmd_prefix *cp = (cmd_prefix *)
256 	    (dp + ((cldev->cbuf - dp) & (ARCH_ALIGN_PTR_MOD - 1)));
257 
258 	cmd_count_add1(stats_cmd.other_band);
259 	dp = (byte *) (cp + 1);
260 	if (pcl->tail != 0) {
261 #ifdef DEBUG
262 	    if (pcl->tail < pcl->head ||
263 		pcl->tail->size > dp - (byte *) (pcl->tail + 1)
264 		) {
265 		lprintf1("cmd_put_list_op error at 0x%lx\n",
266 			 (ulong) pcl->tail);
267 	    }
268 #endif
269 	    pcl->tail->next = cp;
270 	} else
271 	    pcl->head = cp;
272 	pcl->tail = cp;
273 	cldev->ccl = pcl;
274 	cp->size = size;
275 	cp->id = cldev->ins_count;
276 	if_debug1('L', ", id=%ld ", cldev->ins_count);
277 	cldev->ins_count++;
278     }
279     cldev->cnext = dp + size;
280     return dp;
281 }
282 
283 /* Request a space in the buffer.
284    Writes out the buffer if necessary.
285    Returns the size of available space. */
286 int
cmd_get_buffer_space(gx_device_clist_writer * cldev,gx_clist_state * pcls,uint size)287 cmd_get_buffer_space(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
288 {
289     if (size + cmd_headroom > cldev->cend - cldev->cnext) {
290 	cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run);
291 	if (cldev->error_code < 0) {
292 	    cldev->error_is_retryable = 0;	/* hard error */
293 	    return cldev->error_code;
294 	}
295     }
296     return cldev->cend - cldev->cnext - cmd_headroom;
297 }
298 
299 #ifdef DEBUG
300 byte *
cmd_put_op(gx_device_clist_writer * cldev,gx_clist_state * pcls,uint size)301 cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
302 {
303     if_debug3('L', "[L]band %d: size=%u, left=%u",
304 	      (int)(pcls - cldev->states),
305 	      size, 0);
306     return cmd_put_list_op(cldev, &pcls->list, size);
307 }
308 #endif
309 
310 /* Add a command for a range of bands. */
311 byte *
cmd_put_range_op(gx_device_clist_writer * cldev,int band_min,int band_max,uint size)312 cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max,
313 		 uint size)
314 {
315     if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
316 	      band_min, band_max, size, 0);
317     if (cldev->ccl != 0 &&
318 	(cldev->ccl != &cldev->band_range_list ||
319 	 band_min != cldev->band_range_min ||
320 	 band_max != cldev->band_range_max)
321 	) {
322 	if ((cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
323 	    if (cldev->error_code < 0)
324 		cldev->error_is_retryable = 0;	/* hard error */
325 	    else {
326 		/* upgrade lo-mem warning into an error */
327 		cldev->error_code = gs_error_VMerror;
328 		cldev->error_is_retryable = 1;
329 	    }
330 	    return 0;
331 	}
332 	cldev->band_range_min = band_min;
333 	cldev->band_range_max = band_max;
334     }
335     return cmd_put_list_op(cldev, &cldev->band_range_list, size);
336 }
337 
338 /* Write a variable-size positive integer. */
339 int
cmd_size_w(register uint w)340 cmd_size_w(register uint w)
341 {
342     register int size = 1;
343 
344     while (w > 0x7f)
345 	w >>= 7, size++;
346     return size;
347 }
348 byte *
cmd_put_w(register uint w,register byte * dp)349 cmd_put_w(register uint w, register byte * dp)
350 {
351     while (w > 0x7f)
352 	*dp++ = w | 0x80, w >>= 7;
353     *dp = w;
354     return dp + 1;
355 }
356 /* Write a variable-size positive fractional. */
357 int
cmd_size_frac31(register frac31 w)358 cmd_size_frac31(register frac31 w)
359 {
360     register int size = 1;
361     register uint32_t v = w;
362 
363     while (v & 0x01FFFFFF)
364 	v <<= 7, size++;
365     return size;
366 }
367 byte *
cmd_put_frac31(register frac31 w,register byte * dp)368 cmd_put_frac31(register frac31 w, register byte * dp)
369 {
370     register uint32_t v = w;
371 
372     while (v & 0x01FFFFFF)
373 	*dp++ = (v >> 24) | 1, v <<= 7;
374     *dp = (v >> 24);
375     return dp + 1;
376 }
377 
378 
379 
380 /*
381  * This next two arrays are used for the 'delta' mode of placing a color
382  * in the clist.  These arrays are indexed by the number of bytes in the
383  * color value (the depth).
384  *
385  * Delta values are calculated by subtracting the old value for the color
386  * from the desired new value.  Then each byte of the differenece is
387  * examined.  For most bytes, if the difference fits into 4 bits (signed)
388  * then those bits are packed into the clist along with an opcode.  If
389  * the size of the color (the depth) is an odd number of bytes then instead
390  * of four bits per byte, extra bits are used for the upper three bytes
391  * of the color.  In this case, five bits are used for the first byte,
392  * six bits for the second byte, and five bits for third byte.  This
393  * maximizes the chance that the 'delta' mode can be used for placing
394  * colors in the clist.
395  */
396 /*
397  * Depending upon the compiler and user choices, the size of a gx_color_index
398  * may be 4 to 8 bytes.  We will define table entries for up to 8 bytes.
399  * This macro is being used to prevent compiler warnings if gx_color_index is
400  * only 4 bytes.
401  */
402 #define tab_entry(x) ((x) & (~((gx_color_index) 0)))
403 
404 const gx_color_index cmd_delta_offsets[] = {
405 	tab_entry(0),
406 	tab_entry(0),
407 	tab_entry(0x0808),
408 	tab_entry(0x102010),
409 	tab_entry(0x08080808),
410 	tab_entry(0x1020100808),
411 	tab_entry(0x080808080808),
412 	tab_entry(0x10201008080808),
413 	tab_entry(0x0808080808080808),
414 	};
415 
416 static const gx_color_index cmd_delta_masks[] = {
417 	tab_entry(0),
418 	tab_entry(0),
419 	tab_entry(0x0f0f),
420 	tab_entry(0x1f3f1f),
421 	tab_entry(0x0f0f0f0f),
422 	tab_entry(0x1f3f1f0f0f),
423 	tab_entry(0x0f0f0f0f0f0f),
424 	tab_entry(0x1f3f1f0f0f0f0f),
425 	tab_entry(0x0f0f0f0f0f0f0f0f),
426 	};
427 
428 #undef tab_entry
429 
430 /*
431  * There are currently only four different color "types" that can be placed
432  * into the clist.  These are called "color0", "color1", and "tile_color0",
433  * and "tile_color1".  There are separate command codes for color0 versus
434  * color1, both for the full value and delta commands - see cmd_put_color.
435  * Tile colors are preceded by a cmd_opv_set_tile_color command.
436  */
437 const clist_select_color_t
438     clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 0},
439     clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 0},
440     clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 1},
441     clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 1};
442 
443 /*
444  * This routine is used to place a color into the clist.  Colors, in the
445  * clist, can be specified either as by a full value or by a "delta" value.
446  *
447  * See the comments before cmd_delta_offsets[] for a description of the
448  * 'delta' mode.  The delta mode may allow for a smaller command in the clist.
449  *
450  * For the full value mode, values are sent as a cmd code plus n bytes of
451  * data.  To minimize the number of bytes, a count is made of any low order
452  * bytes which are zero.  This count is packed into the low order 4 bits
453  * of the cmd code.  The data for these bytes are not sent.
454  *
455  * The gx_no_color_index value is treated as a special case.  This is done
456  * because it is both a commonly sent value and because it may require
457  * more bytes then the other color values.
458  *
459  * Parameters:
460  *   cldev - Pointer to clist device
461  *   pcls - Pointer to clist state
462  *   select - Descriptor record for type of color being sent.  See comments
463  *       by clist_select_color_t.
464  *   color - The new color value.
465  *   pcolor - Pointer to previous color value.  (If the color value is the
466  *       same as the previous value then nothing is placed into the clist.)
467  *
468  * Returns:
469  *   Error code
470  *   clist and pcls and cldev may be updated.
471  */
472 int
cmd_put_color(gx_device_clist_writer * cldev,gx_clist_state * pcls,const clist_select_color_t * select,gx_color_index color,gx_color_index * pcolor)473 cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
474 	      const clist_select_color_t * select,
475 	      gx_color_index color, gx_color_index * pcolor)
476 {
477     byte * dp;		/* This is manipulated by the set_cmd_put_op macro */
478     gx_color_index diff = color - *pcolor;
479     byte op, op_delta;
480     int code;
481 
482     if (diff == 0)
483 	return 0;
484 
485     /* If this is a tile color then send tile color type */
486     if (select->tile_color) {
487 	code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
488 	if (code < 0)
489 	    return code;
490     }
491     op = select->set_op;
492     op_delta = select->delta_op;
493     if (color == gx_no_color_index) {
494 	/*
495 	 * We must handle this specially, because it may take more
496 	 * bytes than the color depth.
497 	 */
498 	code = set_cmd_put_op(dp, cldev, pcls, op + cmd_no_color_index, 1);
499 	if (code < 0)
500 	    return code;
501     } else {
502 	/* Check if the "delta" mode command can be used. */
503 	int num_bytes = (cldev->clist_color_info.depth + 7) >> 3;  /* clist_color_info may be different than target device
504                                                                       due to transparency group during clist writing phase */
505 	int delta_bytes = (num_bytes + 1) / 2;
506 	gx_color_index delta_offset = cmd_delta_offsets[num_bytes];
507 	gx_color_index delta_mask = cmd_delta_masks[num_bytes];
508 	gx_color_index delta = (diff + delta_offset) & delta_mask;
509 	bool use_delta = (color == (*pcolor + delta - delta_offset));
510 	int bytes_dropped = 0;
511 	gx_color_index data = color;
512 
513 	/*
514 	 * If we use the full value mode, we do not send low order bytes
515 	 * which are zero. Determine how many low order bytes are zero.
516 	 */
517 	if (color == 0) {
518 	    bytes_dropped = num_bytes;
519 	}
520 	else  {
521 	    while ((data & 0xff) == 0) {
522 	        bytes_dropped++;
523 		data >>= 8;
524 	    }
525 	}
526 
527 	/* Now send one of the two command forms */
528 	if (use_delta && delta_bytes < num_bytes - bytes_dropped) {
529 	    code = set_cmd_put_op(dp, cldev, pcls,
530 	    				op_delta, delta_bytes + 1);
531 	    if (code < 0)
532 	        return code;
533 	    /*
534 	     * If we have an odd number of bytes then use extra bits for
535 	     * the high order three bytes of the color.
536 	     */
537 	    if ((num_bytes >= 3) && (num_bytes & 1)) {
538 		data = delta >> ((num_bytes - 3) * 8);
539 	        dp[delta_bytes--] = (byte)(((data >> 13) & 0xf8) + ((data >> 11) & 0x07));
540 	        dp[delta_bytes--] = (byte)(((data >> 3) & 0xe0) + (data & 0x1f));
541 	    }
542 	    for(; delta_bytes>0; delta_bytes--) {
543 	        dp[delta_bytes] = (byte)((delta >> 4) + delta);
544 		delta >>= 16;
545 	    }
546 	}
547 	else {
548 	    num_bytes -= bytes_dropped;
549 	    code = set_cmd_put_op(dp, cldev, pcls,
550 	    			(byte)(op + bytes_dropped), num_bytes + 1);
551 	    if (code < 0)
552 	        return code;
553 	    for(; num_bytes>0; num_bytes--) {
554 	        dp[num_bytes] = (byte)data;
555 		data >>= 8;
556 	    }
557 	}
558     }
559     *pcolor = color;
560     return 0;
561 }
562 
563 
564 /* Put out a command to set the tile colors. */
565 int
cmd_set_tile_colors(gx_device_clist_writer * cldev,gx_clist_state * pcls,gx_color_index color0,gx_color_index color1)566 cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
567 		    gx_color_index color0, gx_color_index color1)
568 {
569     int code = 0;
570 
571     if (color0 != pcls->tile_colors[0]) {
572 	code = cmd_put_color(cldev, pcls,
573 			     &clist_select_tile_color0,
574 			     color0, &pcls->tile_colors[0]);
575 	if (code != 0)
576 	    return code;
577     }
578     if (color1 != pcls->tile_colors[1])
579 	code = cmd_put_color(cldev, pcls,
580 			     &clist_select_tile_color1,
581 			     color1, &pcls->tile_colors[1]);
582     return code;
583 }
584 
585 /* Put out a command to set the tile phase. */
586 int
cmd_set_tile_phase_generic(gx_device_clist_writer * cldev,gx_clist_state * pcls,int px,int py,bool all_bands)587 cmd_set_tile_phase_generic(gx_device_clist_writer * cldev, gx_clist_state * pcls,
588 		   int px, int py, bool all_bands)
589 {
590     int pcsize;
591     byte *dp;
592     int code;
593 
594     pcsize = 1 + cmd_size2w(px, py);
595     if (all_bands)
596 	code = set_cmd_put_all_op(dp, cldev, (byte)cmd_opv_set_tile_phase, pcsize);
597     else
598 	code = set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
599     if (code < 0)
600 	return code;
601     ++dp;
602     pcls->tile_phase.x = px;
603     pcls->tile_phase.y = py;
604     cmd_putxy(pcls->tile_phase, dp);
605     return 0;
606 }
607 
608 int
cmd_set_tile_phase(gx_device_clist_writer * cldev,gx_clist_state * pcls,int px,int py)609 cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls,
610 		   int px, int py)
611 {
612     return cmd_set_tile_phase_generic(cldev, pcls, px, py, false);
613 }
614 
615 
616 /* Write a command to enable or disable the logical operation. */
617 int
cmd_put_enable_lop(gx_device_clist_writer * cldev,gx_clist_state * pcls,int enable)618 cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
619 		   int enable)
620 {
621     byte *dp;
622     int code = set_cmd_put_op(dp, cldev, pcls,
623 			      (byte)(enable ? cmd_opv_enable_lop :
624 				     cmd_opv_disable_lop),
625 			      1);
626 
627     if (code < 0)
628 	return code;
629     pcls->lop_enabled = enable;
630     return 0;
631 }
632 
633 /* Write a command to enable or disable clipping. */
634 /* This routine is only called if the path extensions are included. */
635 int
cmd_put_enable_clip(gx_device_clist_writer * cldev,gx_clist_state * pcls,int enable)636 cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls,
637 		    int enable)
638 {
639     byte *dp;
640     int code = set_cmd_put_op(dp, cldev, pcls,
641 			      (byte)(enable ? cmd_opv_enable_clip :
642 				     cmd_opv_disable_clip),
643 			      1);
644 
645     if (code < 0)
646 	return code;
647     pcls->clip_enabled = enable;
648     return 0;
649 }
650 
651 /* Write a command to set the logical operation. */
652 int
cmd_set_lop(gx_device_clist_writer * cldev,gx_clist_state * pcls,gs_logical_operation_t lop)653 cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
654 	    gs_logical_operation_t lop)
655 {
656     byte *dp;
657     uint lop_msb = lop >> 6;
658     int code = set_cmd_put_op(dp, cldev, pcls,
659 			      cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
660 
661     if (code < 0)
662 	return code;
663     dp[1] = cmd_set_misc_lop + (lop & 0x3f);
664     cmd_put_w(lop_msb, dp + 2);
665     pcls->lop = lop;
666     return 0;
667 }
668 
669 /* Disable (if default) or enable the logical operation, setting it if */
670 /* needed. */
671 int
cmd_update_lop(gx_device_clist_writer * cldev,gx_clist_state * pcls,gs_logical_operation_t lop)672 cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
673 	       gs_logical_operation_t lop)
674 {
675     int code;
676 
677     if (lop == lop_default)
678 	return cmd_disable_lop(cldev, pcls);
679     code = cmd_set_lop(cldev, pcls, lop);
680     if (code < 0)
681 	return code;
682     return cmd_enable_lop(cldev, pcls);
683 }
684 
685 /* Write a parameter list */
686 int	/* ret 0 all ok, -ve error */
cmd_put_params(gx_device_clist_writer * cldev,gs_param_list * param_list)687 cmd_put_params(gx_device_clist_writer *cldev,
688 	       gs_param_list *param_list) /* NB open for READ */
689 {
690     byte *dp;
691     int code;
692     byte local_buf[512];	/* arbitrary */
693     int param_length;
694 
695     /* Get serialized list's length + try to get it into local var if it fits. */
696     param_length = code =
697 	gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
698     if (param_length > 0) {
699 	/* Get cmd buffer space for serialized */
700 	code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend,
701 				  2 + sizeof(unsigned) + param_length);
702 	if (code < 0)
703 	    return code;
704 
705 	/* write param list to cmd list: needs to all fit in cmd buffer */
706 	if_debug1('l', "[l]put_params, length=%d\n", param_length);
707 	dp[1] = cmd_opv_ext_put_params;
708 	dp += 2;
709 	memcpy(dp, &param_length, sizeof(unsigned));
710 	dp += sizeof(unsigned);
711 	if (param_length > sizeof(local_buf)) {
712 	    int old_param_length = param_length;
713 
714 	    param_length = code =
715 		gs_param_list_serialize(param_list, dp, old_param_length);
716 	    if (param_length >= 0)
717 		code = (old_param_length != param_length ?
718 			gs_note_error(gs_error_unknownerror) : 0);
719 	    if (code < 0) {
720 		/* error serializing: back out by writing a 0-length parm list */
721 		memset(dp - sizeof(unsigned), 0, sizeof(unsigned));
722 		cmd_shorten_list_op(cldev, &cldev->band_range_list,
723 				    old_param_length);
724 	    }
725 	} else
726 	    memcpy(dp, local_buf, param_length);	    /* did this when computing length */
727     }
728     return code;
729 }
730 
731 /* Initialize CCITTFax filters. */
732 static void
clist_cf_init(stream_CF_state * ss,int width)733 clist_cf_init(stream_CF_state *ss, int width)
734 {
735     ss->K = -1;
736     ss->Columns = width;
737 #if 0 /* Disabled due to a crash with ppmraw -r216 c327.bin :
738 	 the decoding filter overruns in 1 byte.
739        */
740     ss->EndOfBlock = false;
741 #else
742     ss->EndOfBlock = true;
743 #endif
744     ss->BlackIs1 = true;
745     ss->DecodedByteAlign = align_bitmap_mod;
746 }
747 void
clist_cfe_init(stream_CFE_state * ss,int width,gs_memory_t * mem)748 clist_cfe_init(stream_CFE_state *ss, int width, gs_memory_t *mem)
749 {
750     s_init_state((stream_state *)ss, &s_CFE_template, mem);
751     s_CFE_set_defaults_inline(ss);
752     clist_cf_init((stream_CF_state *)ss, width);
753     s_CFE_template.init((stream_state *)(ss));
754 }
755 void
clist_cfd_init(stream_CFD_state * ss,int width,int height,gs_memory_t * mem)756 clist_cfd_init(stream_CFD_state *ss, int width, int height, gs_memory_t *mem)
757 {
758     s_init_state((stream_state *)ss, &s_CFD_template, mem);
759     s_CFD_template.set_defaults((stream_state *)ss);
760     clist_cf_init((stream_CF_state *)ss, width);
761     ss->Rows = height;
762     s_CFD_template.init((stream_state *)(ss));
763 }
764 
765 /* Initialize RunLength filters. */
766 void
clist_rle_init(stream_RLE_state * ss)767 clist_rle_init(stream_RLE_state *ss)
768 {
769     s_init_state((stream_state *)ss, &s_RLE_template, (gs_memory_t *)0);
770     s_RLE_set_defaults_inline(ss);
771     s_RLE_init_inline(ss);
772 }
773 void
clist_rld_init(stream_RLD_state * ss)774 clist_rld_init(stream_RLD_state *ss)
775 {
776     s_init_state((stream_state *)ss, &s_RLD_template, (gs_memory_t *)0);
777     s_RLD_set_defaults_inline(ss);
778     s_RLD_init_inline(ss);
779 }
780 
781 /* Read a transformation matrix. */
782 const byte *
cmd_read_matrix(gs_matrix * pmat,const byte * cbp)783 cmd_read_matrix(gs_matrix * pmat, const byte * cbp)
784 {
785     stream s;
786 
787     s_init(&s, NULL);
788     sread_string(&s, cbp, 1 + sizeof(*pmat));
789     sget_matrix(&s, pmat);
790     return cbp + stell(&s);
791 }
792 
793