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