Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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 */
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 */
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 *
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 *
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 *
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
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 *
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
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
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
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
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
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
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
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 */
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
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
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
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
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
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
}