xref: /plan9/sys/src/cmd/gs/src/gxcldev.h (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 2000 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: gxcldev.h,v 1.14 2005/03/14 18:08:36 dan Exp $ */
18 /* Internal definitions for Ghostscript command lists. */
19 
20 #ifndef gxcldev_INCLUDED
21 #  define gxcldev_INCLUDED
22 
23 #include "gxclist.h"
24 #include "gsropt.h"
25 #include "gxht.h"		/* for gxdht.h */
26 #include "gxtmap.h"		/* ditto */
27 #include "gxdht.h"		/* for halftones */
28 #include "strimpl.h"		/* for compressed bitmaps */
29 #include "scfx.h"		/* ditto */
30 #include "srlx.h"		/* ditto */
31 #include "gsdcolor.h"
32 
33 /* ---------------- Commands ---------------- */
34 
35 /* Define the compression modes for bitmaps. */
36 /*#define cmd_compress_none 0 *//* (implicit) */
37 #define cmd_compress_rle 1
38 #define cmd_compress_cfe 2
39 #define cmd_mask_compress_any\
40   ((1 << cmd_compress_rle) | (1 << cmd_compress_cfe))
41 /* Exported by gxclutil.c */
42 void clist_rle_init(stream_RLE_state *ss);
43 void clist_rld_init(stream_RLD_state *ss);
44 void clist_cfe_init(stream_CFE_state *ss, int width, gs_memory_t *mem);
45 void clist_cfd_init(stream_CFD_state *ss, int width, int height,
46 		    gs_memory_t *mem);
47 
48 /*
49  * A command always consists of an operation followed by operands;
50  * the syntax of the operands depends on the operation.
51  * In the operation definitions below:
52  *      + (prefixed) means the operand is in the low 4 bits of the opcode.
53  *      # means a variable-size operand encoded with the variable-size
54  *         integer encoding.
55  *      % means a variable-size operand encoded with the variable-size
56  *         fixed coordinate encoding.
57  *      $ means a color sized according to the device depth.
58  *      <> means the operand size depends on other state information
59  *         and/or previous operands.
60  */
61 typedef enum {
62     cmd_op_misc = 0x00,		/* (see below) */
63     cmd_opv_end_run = 0x00,	/* (nothing) */
64     cmd_opv_set_tile_size = 0x01,   /* rs?(1)nry?(1)nrx?(1)depth(5, encoded), */
65 				/* rep_width#, rep_height#, */
66 				/* [, nreps_x#][, nreps_y #] */
67 				/* [, rep_shift#] */
68     cmd_opv_set_tile_phase = 0x02,	/* x#, y# */
69     cmd_opv_set_tile_bits = 0x03,	/* index#, offset#, <bits> */
70     cmd_opv_set_bits = 0x04,	/* depth*4+compress, width#, height#, */
71 				/* index#, offset#, <bits> */
72     cmd_opv_set_tile_color = 0x05,	/* (nothing; next set/delta_color */
73 				/* refers to tile) */
74     cmd_opv_set_misc = 0x06,
75 #define cmd_set_misc_lop (0 << 6)	/* 00: lop_lsb(6), lop_msb# */
76 #define cmd_set_misc_data_x (1 << 6)	/* 01: more(1)dx_lsb(5)[, dx_msb#] */
77 #define cmd_set_misc_map (2 << 6)	/* 10: contents(2)map_index(4) */
78     /* [, n x frac] */
79 #define cmd_set_misc_halftone (3 << 6)	/* 11: type(6), num_comp# */
80     cmd_opv_enable_lop = 0x07,	/* (nothing) */
81     cmd_opv_disable_lop = 0x08,	/* (nothing) */
82     /* obsolete */
83     /* cmd_opv_set_ht_order = 0x09, */	/* component+1#[, cname#], */
84 				/* width#, height#, raster#, */
85 				/* shift#, num_levels#, num_bits#, */
86 				/* order_procs_index */
87     /* obsolete */
88     /* cmd_opv_set_ht_data = 0x0a, */	/* n, n x (uint|gx_ht_bit|ushort) */
89     cmd_opv_end_page = 0x0b,	/* (nothing) */
90     cmd_opv_delta_color0 = 0x0c,	/* See cmd_put_color in gxclutil.c */
91     cmd_opv_delta_color1 = 0x0d,	/* <<same as color0>> */
92     cmd_opv_set_copy_color = 0x0e,	/* (nothing) */
93     cmd_opv_set_copy_alpha = 0x0f,	/* (nothing) */
94     cmd_op_set_color0 = 0x10,	/* +n = number of low order zero bytes | */
95 #define cmd_no_color_index 15	/* +15 = transparent - "no color" */
96     cmd_op_set_color1 = 0x20,	/* <<same as color0>> */
97     cmd_op_fill_rect = 0x30,	/* +dy2dh2, x#, w# | +0, rect# */
98     cmd_op_fill_rect_short = 0x40,	/* +dh, dx, dw | +0, rect_short */
99     cmd_op_fill_rect_tiny = 0x50,	/* +dw+0, rect_tiny | +dw+8 */
100     cmd_op_tile_rect = 0x60,	/* +dy2dh2, x#, w# | +0, rect# */
101     cmd_op_tile_rect_short = 0x70,	/* +dh, dx, dw | +0, rect_short */
102     cmd_op_tile_rect_tiny = 0x80,	/* +dw+0, rect_tiny | +dw+8 */
103     cmd_op_copy_mono = 0x90,	/* +compress, x#, y#, (w+data_x)#, */
104 				/* h#, <bits> | */
105 #define cmd_copy_ht_color 4
106 				/* +4+compress, x#, y#, (w+data_x)#, */
107 				/* h#, <bits> | */
108 #define cmd_copy_use_tile 8
109 				/* +8 (use tile), x#, y# | */
110 				/* +12 (use tile), x#, y# */
111     cmd_op_copy_color_alpha = 0xa0,	/* (same as copy_mono, except: */
112 				/* if color, ignore ht_color; */
113 				/* if alpha & !use_tile, depth is */
114 				/*   first operand) */
115     cmd_op_delta_tile_index = 0xb0,	/* +delta+8 */
116     cmd_op_set_tile_index = 0xc0	/* +index[11:8], index[7:0] */
117 } gx_cmd_op;
118 
119 #define cmd_op_name_strings\
120   "(misc)", "set_color[0]", "set_color[1]", "fill_rect",\
121   "fill_rect_short", "fill_rect_tiny", "tile_rect", "tile_rect_short",\
122   "tile_rect_tiny", "copy_mono", "copy_color_alpha", "delta_tile_index",\
123   "set_tile_index", "(misc2)", "(segment)", "(path)"
124 
125 #define cmd_misc_op_name_strings\
126   "end_run", "set_tile_size", "set_tile_phase", "set_tile_bits",\
127   "set_bits", "set_tile_color", "set_misc", "enable_lop",\
128   "disable_lop", "set_ht_order", "set_ht_data", "end_page",\
129   "delta2_color0", "delta2_color1", "set_copy_color", "set_copy_alpha",
130 
131 #ifdef DEBUG
132 extern const char *const cmd_op_names[16];
133 extern const char *const *const cmd_sub_op_names[16];
134 #endif
135 
136 /*
137  * Define the size of the largest command, not counting any bitmap or
138  * similar variable-length operands.
139  * The variable-size integer encoding is little-endian.  The low 7 bits
140  * of each byte contain data; the top bit is 1 for all but the last byte.
141  */
142 #define cmd_max_intsize(siz)\
143   (((siz) * 8 + 6) / 7)
144 #define cmd_largest_size\
145   (2 + (1 + cmd_max_dash) * sizeof(float))
146 
147 /* ---------------- Command parameters ---------------- */
148 
149 /* Rectangle */
150 typedef struct {
151     int x, y, width, height;
152 } gx_cmd_rect;
153 
154 /* Short rectangle */
155 typedef struct {
156     byte dx, dwidth, dy, dheight;	/* dy and dheight are optional */
157 } gx_cmd_rect_short;
158 
159 #define cmd_min_short (-128)
160 #define cmd_max_short 127
161 /* Tiny rectangle */
162 #define cmd_min_dw_tiny (-4)
163 #define cmd_max_dw_tiny 3
164 typedef struct {
165     unsigned dx:4;
166     unsigned dy:4;
167 } gx_cmd_rect_tiny;
168 
169 #define cmd_min_dxy_tiny (-8)
170 #define cmd_max_dxy_tiny 7
171 
172 /*
173  * Encoding for tile depth information.
174  *
175  * The cmd_opv_set_tile_size command code stores tile depth information
176  * as part of the first byte following the command code. Only 5 bits of
177  * this byte are available, which held the value depth - 1. The DeviceN
178  * code requires depths of > 32 bits, so a new encoding is required. The
179  * encoding selected represents depth information either directly (for
180  * depth <= 15), or as a multiple of 8. The high-order bit determines
181  * which is the case; it is cleared if the depth is represented directly,
182  * and set if the depth is represented as a multiple of 8.
183  */
184 #define cmd_depth_to_code(d)    ((d) > 0xf ? 0x10 | ((d) >> 3) : (d))
185 #define cmd_code_to_depth(v)    \
186     (((v) & 0x10) != 0 ? ((v) & 0xf) << 3 : (v) & 0xf)
187 
188 /*
189  * When we write bitmaps, we remove raster padding selectively:
190  *      - If the bitmap is compressed, we don't remove any padding;
191  *      - If the width is <= 6 bytes, we remove all the padding;
192  *      - If the bitmap is only 1 scan line high, we remove the padding;
193  *      - If the bitmap is going to be replicated horizontally (see the
194  *      definition of decompress_spread below), we remove the padding;
195  *      - Otherwise, we remove the padding only from the last scan line.
196  */
197 #define cmd_max_short_width_bytes 6
198 #define cmd_max_short_width_bits (cmd_max_short_width_bytes * 8)
199 /*
200  * Determine the (possibly unpadded) width in bytes for writing a bitmap,
201  * per the algorithm just outlined.  If compression_mask has any of the
202  * cmd_mask_compress_any bits set, we assume the bitmap will be compressed.
203  * Return the total size of the bitmap.
204  */
205 uint clist_bitmap_bytes(uint width_bits, uint height,
206 			int compression_mask,
207 			uint * width_bytes, uint * raster);
208 
209 /*
210  * For halftone cells, we always write an unreplicated bitmap, but we
211  * reserve cache space for the reading pass based on the replicated size.
212  * See the clist_change_tile procedure for the algorithm that chooses the
213  * replication factors.
214  */
215 
216 /* ---------------- Block file entries ---------------- */
217 
218 typedef struct cmd_block_s {
219     int band_min, band_max;
220 #define cmd_band_end (-1)	/* end of band file */
221     long pos;			/* starting position in cfile */
222 } cmd_block;
223 
224 /* ---------------- Band state ---------------- */
225 
226 /* Remember the current state of one band when writing or reading. */
227 struct gx_clist_state_s {
228     gx_color_index colors[2];	/* most recent colors */
229     gx_device_color_saved sdc;  /* last device color for this band */
230     uint tile_index;		/* most recent tile index */
231     gx_bitmap_id tile_id;	/* most recent tile id */
232 /* Since tile table entries may be deleted and/or moved at any time, */
233 /* the following is the only reliable way to check whether tile_index */
234 /* references a particular tile id: */
235 #define cls_has_tile_id(cldev, pcls, tid, offset_temp)\
236   ((pcls)->tile_id == (tid) &&\
237    (offset_temp = cldev->tile_table[(pcls)->tile_index].offset) != 0 &&\
238    ((tile_slot *)(cldev->data + offset_temp))->id == (tid))
239     gs_int_point tile_phase;	/* most recent tile phase */
240     gx_color_index tile_colors[2];	/* most recent tile colors */
241     gx_cmd_rect rect;		/* most recent rectangle */
242     gs_logical_operation_t lop;	/* most recent logical op */
243     short lop_enabled;		/* 0 = don't use lop, 1 = use lop, */
244 				/* -1 is used internally */
245     short clip_enabled;		/* 0 = don't clip, 1 = do clip, */
246 				/* -1 is used internally */
247     bool color_is_alpha;	/* for copy_color_alpha */
248     uint known;			/* flags for whether this band */
249 				/* knows various misc. parameters */
250     /* We assign 'known' flags here from the high end; */
251     /* gxclpath.h assigns them from the low end. */
252 #define tile_params_known (1<<15)
253 #define begin_image_known (1<<14) /* gxclimag.c */
254 #define initial_known 0x3fff	/* exclude tile & image params */
255     /* Following are only used when writing */
256     cmd_list list;		/* list of commands for band */
257     /* Following are set when writing, read when reading */
258     ulong cost;			/* cost of rendering the band */
259     gx_colors_used_t colors_used;
260 };
261 
262 /* The initial values for a band state */
263 /*static const gx_clist_state cls_initial */
264 #define cls_initial_values\
265 	 { gx_no_color_index, gx_no_color_index },\
266 	{ gx_dc_type_none },\
267 	0, gx_no_bitmap_id,\
268 	 { 0, 0 }, { gx_no_color_index, gx_no_color_index },\
269 	 { 0, 0, 0, 0 }, lop_default, 0, 0, 0, initial_known,\
270 	{ 0, 0 }, 0, { 0 }
271 
272 /* Define the size of the command buffer used for reading. */
273 /* This is needed to split up operations with a large amount of data, */
274 /* primarily large copy_ operations. */
275 #define cbuf_size 4096
276 
277 /* ---------------- Driver procedures ---------------- */
278 
279 /* In gxclrect.c */
280 dev_proc_fill_rectangle(clist_fill_rectangle);
281 dev_proc_copy_mono(clist_copy_mono);
282 dev_proc_copy_color(clist_copy_color);
283 dev_proc_copy_alpha(clist_copy_alpha);
284 dev_proc_strip_tile_rectangle(clist_strip_tile_rectangle);
285 dev_proc_strip_copy_rop(clist_strip_copy_rop);
286 
287 /* In gxclimag.c */
288 dev_proc_fill_mask(clist_fill_mask);
289 dev_proc_begin_typed_image(clist_begin_typed_image);
290 dev_proc_create_compositor(clist_create_compositor);
291 
292 /* In gxclread.c */
293 dev_proc_get_bits_rectangle(clist_get_bits_rectangle);
294 
295 /* ---------------- Driver procedure support ---------------- */
296 
297 /*
298  * The procedures and macros defined here are used when writing
299  * (gxclist.c, gxclbits.c, gxclimag.c, gxclpath.c, gxclrect.c).
300  * Note that none of the cmd_put_xxx procedures do VMerror recovery;
301  * they convert low-memory warnings to VMerror errors.
302  */
303 
304 /* ------ Exported by gxclist.c ------ */
305 
306 /*
307  * Error recovery procedures for writer-side VMerrors, for async rendering
308  * support.  This logic assumes that the command list file and/or the
309  * renderer allocate memory from the same pool as the writer. Hence, when
310  * the writer runs out of memory, it tries to pause and let the renderer run
311  * for a while in hope that enough memory will be freed by it to allow the
312  * writer to allocate enough memory to proceed. Once a VMerror is detected,
313  * error recovery proceeds in two escalating stages:
314  *
315  *  1) The recovery logic repeatedly calls clist_VMerror_recover(), which
316  *     waits until the next page has finished rendering. The recovery logic
317  *     keeps calling clist_VMerror_recover() until enough memory is freed,
318  *     or until clist_VMerror_recover() signals that no more pages
319  *     remain to be rendered (when return code < 0).
320  *
321  *  2) If enough memory is not free, the recovery logic calls
322  *     clist_VMerror_recover_flush() once. This routine terminates and
323  *     flushes out the partially-completed page that the writer is currently
324  *     writing to the command file, then waits for the partial page to finish
325  *     rendering. It then opens up a new command list "file" and resets the
326  *     state of the command list machinery to an initial state as if a new
327  *     page were beginning.
328  *
329  * If insufficient memory is available after the 2nd step, the situation
330  * is the same as if it ocurred in a non-async setup: the writer program
331  * simply used up too much memory and cannot continue.
332  *
333  * The first stage of error recovery (no flush) is performed without
334  * flushing out the current page, so failing commands can simply be
335  * restarted after such recovery. This is not true of 2nd stage recovery
336  * (flush): as part of its operation, the flush resets the state of both
337  * writer and renderer to initial values.  In this event, the recovery logic
338  * which called clist_try_recover_VMerror_flush() must force any pertinent
339  * state information to be re-emitted before re-issuing the failing command.
340  *
341  * In case of a VMerror, the internal procedures that support the driver
342  * procedures simply return the error code: they do not attempt recovery.
343  * Note that all such procedures must take care that (1) they don't update
344  * any writer state to reflect information written to the band list unless
345  * the write actually succeeds, and (2) they are idempotent, since they may
346  * be re-executed after first-stage VMerror recovery.
347  *
348  * Error recovery is only performed by the driver procedures themselves
349  * (fill_rectangle, copy_mono, fill_path, etc.) and a few other procedures
350  * at the same level of control.  The implementation of error recovery is
351  * packaged up in the FOR_RECTS et al macros defined below, but -- as noted
352  * above -- recovery is not fully transparent.  Other routines which perform
353  * error recovery are those which open the device, begin a new page, or
354  * reopen the device (put_params).
355  */
356 int clist_VMerror_recover(gx_device_clist_writer *, int);
357 int clist_VMerror_recover_flush(gx_device_clist_writer *, int);
358 
359 /* Write out device parameters. */
360 int cmd_put_params(gx_device_clist_writer *, gs_param_list *);
361 
362 /* Conditionally keep command statistics. */
363 #ifdef DEBUG
364 int cmd_count_op(int op, uint size);
365 void cmd_uncount_op(int op, uint size);
366 void cmd_print_stats(void);
367 #  define cmd_count_add1(v) (v++)
368 #else
369 #  define cmd_count_op(op, size) (op)
370 #  define cmd_uncount_op(op, size) DO_NOTHING
371 #  define cmd_count_add1(v) DO_NOTHING
372 #endif
373 
374 /* Add a command to the appropriate band list, */
375 /* and allocate space for its data. */
376 byte *cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size);
377 
378 #ifdef DEBUG
379 byte *cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size);
380 #else
381 #  define cmd_put_op(cldev, pcls, size)\
382      cmd_put_list_op(cldev, &(pcls)->list, size)
383 #endif
384 /* Call cmd_put_op and update stats if no error occurs. */
385 #define set_cmd_put_op(dp, cldev, pcls, op, csize)\
386   ( (dp = cmd_put_op(cldev, pcls, csize)) == 0 ?\
387       (cldev)->error_code :\
388     (*dp = cmd_count_op(op, csize), 0) )
389 
390 /* Add a command for all bands or a range of bands. */
391 byte *cmd_put_range_op(gx_device_clist_writer * cldev, int band_min,
392 		       int band_max, uint size);
393 
394 #define cmd_put_all_op(cldev, size)\
395   cmd_put_range_op(cldev, 0, (cldev)->nbands - 1, size)
396 /* Call cmd_put_all/range_op and update stats if no error occurs. */
397 #define set_cmd_put_range_op(dp, cldev, op, bmin, bmax, csize)\
398   ( (dp = cmd_put_range_op(cldev, bmin, bmax, csize)) == 0 ?\
399       (cldev)->error_code :\
400     (*dp = cmd_count_op(op, csize), 0) )
401 #define set_cmd_put_all_op(dp, cldev, op, csize)\
402   set_cmd_put_range_op(dp, cldev, op, 0, (cldev)->nbands - 1, csize)
403 
404 /* Shorten the last allocated command. */
405 /* Note that this does not adjust the statistics. */
406 #define cmd_shorten_list_op(cldev, pcls, delta)\
407   ((pcls)->tail->size -= (delta), (cldev)->cnext -= (delta))
408 #define cmd_shorten_op(cldev, pcls, delta)\
409   cmd_shorten_list_op(cldev, &(pcls)->list, delta)
410 
411 /* Write out the buffered commands, and reset the buffer. */
412 /* Return 0 if OK, 1 if OK with low-memory warning, */
413 /* or the usual negative error code. */
414 int cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end);
415 
416 /* End a page by flushing the buffer and terminating the command list. */
417 int clist_end_page(gx_device_clist_writer *);
418 
419 /* Compute the # of bytes required to represent a variable-size integer. */
420 /* (This works for negative integers also; they are written as though */
421 /* they were unsigned.) */
422 int cmd_size_w(uint);
423 
424 #define w1byte(w) (!((w) & ~0x7f))
425 #define w2byte(w) (!((w) & ~0x3fff))
426 #define cmd_sizew(w)\
427   (w1byte(w) ? 1 : w2byte(w) ? 2 : cmd_size_w((uint)(w)))
428 #define cmd_size2w(wx,wy)\
429   (w1byte((wx) | (wy)) ? 2 :\
430    cmd_size_w((uint)(wx)) + cmd_size_w((uint)(wy)))
431 #define cmd_sizexy(xy) cmd_size2w((xy).x, (xy).y)
432 #define cmd_sizew_max ((sizeof(uint) * 8 + 6) / 7)
433 
434 /* Put a variable-size integer in the buffer. */
435 byte *cmd_put_w(uint, byte *);
436 
437 #define cmd_putw(w,dp)\
438   (w1byte(w) ? (*dp = w, ++dp) :\
439    w2byte(w) ? (*dp = (w) | 0x80, dp[1] = (w) >> 7, dp += 2) :\
440    (dp = cmd_put_w((uint)(w), dp)))
441 #define cmd_put2w(wx,wy,dp)\
442   (w1byte((wx) | (wy)) ? (dp[0] = (wx), dp[1] = (wy), dp += 2) :\
443    (dp = cmd_put_w((uint)(wy), cmd_put_w((uint)(wx), dp))))
444 #define cmd_putxy(xy,dp) cmd_put2w((xy).x, (xy).y, dp)
445 
446 /* Put out a command to set a color. */
447 typedef struct {
448     byte set_op;
449     byte delta_op;
450     bool tile_color;
451 } clist_select_color_t;
452 extern const clist_select_color_t
453       clist_select_color0, clist_select_color1, clist_select_tile_color0,
454       clist_select_tile_color1;
455 
456 /* See comments in gxclutil.c */
457 int cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
458                   const clist_select_color_t * select,
459                   gx_color_index color, gx_color_index * pcolor);
460 
461 extern const gx_color_index cmd_delta_offsets[];	/* In gxclutil.c */
462 
463 #define cmd_set_color0(dev, pcls, color0)\
464   cmd_put_color(dev, pcls, &clist_select_color0, color0, &(pcls)->colors[0])
465 #define cmd_set_color1(dev, pcls, color1)\
466   cmd_put_color(dev, pcls, &clist_select_color1, color1, &(pcls)->colors[1])
467 
468 /* Put out a command to set the tile colors. */
469 int cmd_set_tile_colors(gx_device_clist_writer *cldev, gx_clist_state * pcls,
470 			gx_color_index color0, gx_color_index color1);
471 
472 /* Put out a command to set the tile phase. */
473 int cmd_set_tile_phase(gx_device_clist_writer *cldev, gx_clist_state * pcls,
474 		       int px, int py);
475 
476 /* Enable or disable the logical operation. */
477 int cmd_put_enable_lop(gx_device_clist_writer *, gx_clist_state *, int);
478 #define cmd_do_enable_lop(cldev, pcls, enable)\
479   ( (pcls)->lop_enabled == ((enable) ^ 1) &&\
480     cmd_put_enable_lop(cldev, pcls, enable) < 0 ?\
481       (cldev)->error_code : 0 )
482 #define cmd_enable_lop(cldev, pcls)\
483   cmd_do_enable_lop(cldev, pcls, 1)
484 #define cmd_disable_lop(cldev, pcls)\
485   cmd_do_enable_lop(cldev, pcls, 0)
486 
487 /* Enable or disable clipping. */
488 int cmd_put_enable_clip(gx_device_clist_writer *, gx_clist_state *, int);
489 
490 #define cmd_do_enable_clip(cldev, pcls, enable)\
491   ( (pcls)->clip_enabled == ((enable) ^ 1) &&\
492     cmd_put_enable_clip(cldev, pcls, enable) < 0 ?\
493       (cldev)->error_code : 0 )
494 #define cmd_enable_clip(cldev, pcls)\
495   cmd_do_enable_clip(cldev, pcls, 1)
496 #define cmd_disable_clip(cldev, pcls)\
497   cmd_do_enable_clip(cldev, pcls, 0)
498 
499 /* Write a command to set the logical operation. */
500 int cmd_set_lop(gx_device_clist_writer *, gx_clist_state *,
501 		gs_logical_operation_t);
502 
503 /* Disable (if default) or enable the logical operation, setting it if */
504 /* needed. */
505 int cmd_update_lop(gx_device_clist_writer *, gx_clist_state *,
506 		   gs_logical_operation_t);
507 
508 /*
509  * Define macros for dividing up an operation into bands, per the
510  * template
511 
512     FOR_RECTS[_NO_ERROR] {
513 	... process rectangle x, y, width, height in band pcls ...
514     } END_RECTS[_NO_ERROR];
515 
516  * Note that FOR_RECTS resets y and height.  It is OK for the code that
517  * processes each band to reset height to a smaller (positive) value; the
518  * vertical subdivision code in copy_mono, copy_color, and copy_alpha makes
519  * use of this.  The band processing code may `continue' (to reduce nesting
520  * of conditionals).
521  *
522  * If the processing code detects an error that may be a recoverable
523  * VMerror, the code may call ERROR_RECT(), which will attempt to fix the
524  * VMerror by flushing and closing the band and resetting the imager state,
525  * and then restart emitting the entire band. Before flushing the file, the
526  * 'on_error' clause of END_RECTS_ON_ERROR (defaults to the constant 1 if
527  * END_RECT is used) is evaluated and tested.  The 'on_error' clause enables
528  * mop-up actions to be executed before flushing, and/or selectively
529  * inhibits the flush, close, reset and restart process.  Similarly, the
530  * 'after_recovering' clause of END_RECTS_ON_ERROR allows an action to get
531  * performed after successfully recovering.
532  *
533  * The band processing code may wrap an operation with TRY_RECT { ...  }
534  * HANDLE_RECT_UNLESS(code, unless_action) (or HANDLE_RECT(code)). This will
535  * perform local first-stage VMerror recovery, by waiting for some memory to
536  * become free and then retrying the failed operation starting at the
537  * TRY_RECT. If local recovery is unsuccessful, the local recovery code
538  * calls ERROR_RECT.
539  *
540  * The band processing loop should use the _NO_ERROR macros iff it doesn't
541  * call ERROR_RECT anywhere.
542  *
543  * In a few cases, the band processing code calls other driver procedures
544  * (e.g., clist_copy_mono calls itself recursively if it must split up the
545  * operation into smaller pieces) or other procedures that may attempt
546  * VMerror recovery.  In such cases, the recursive call must not attempt
547  * second-stage VMerror recovery, since the caller would have no way of
548  * knowing that the writer state had been reset.  Such recursive calls
549  * should be wrapped in NEST_RECT { ... } UNNEST_RECT, which causes
550  * ERROR_RECT simply to return the error code rather than attempting
551  * recovery.  (TRY/HANDLE_RECT will still attempt local recovery, as
552  * described above, but this is harmless since it is transparent.) By
553  * convention, calls to cmd_put_xxx or cmd_set_xxx never attempt recovery
554  * and so never require NEST_RECTs.
555  *
556  * If a put_params call fails, the device will be left in a closed state,
557  * but higher-level code won't notice this fact.  We flag this by setting
558  * permanent_error, which prevents writing to the command list.
559  */
560 
561 /*
562  * The "if (1)" statements in the following macros are there to prevent
563  * stupid compilers from giving "statement not reached" warnings.
564  */
565 
566 #define FOR_RECTS_NO_ERROR\
567     BEGIN\
568 	int yend = y + height;\
569 	int band_height = cdev->page_band_height;\
570 	/* no band_code */\
571 \
572 	if (cdev->permanent_error < 0)\
573 	  return (cdev->permanent_error);\
574 	do {\
575 	    int band = y / band_height;\
576 	    gx_clist_state *pcls = cdev->states + band;\
577 	    int band_end = (band + 1) * band_height;\
578 \
579 	    height = min(band_end, yend) - y;\
580 /* no retry_rect: */
581 #define FOR_RECTS\
582     BEGIN\
583 	int yend = y + height;\
584 	int band_height = cdev->page_band_height;\
585 	int band_code;\
586 \
587 	if (cdev->permanent_error < 0)\
588 	  return (cdev->permanent_error);\
589 	do {\
590 	    int band = y / band_height;\
591 	    gx_clist_state *pcls = cdev->states + band;\
592 	    int band_end = (band + 1) * band_height;\
593 \
594 	    height = min(band_end, yend) - y;\
595 retry_rect:\
596 	    ;
597 #define NEST_RECT    ++cdev->driver_call_nesting;
598 #define UNNEST_RECT  --cdev->driver_call_nesting
599 #define ERROR_RECT(code_value)\
600 		BEGIN\
601 		    band_code = (code_value);\
602 		    if (1) goto error_in_rect;\
603 		END
604 #define TRY_RECT\
605 		BEGIN\
606 		    do
607 #define HANDLE_RECT_UNLESS(codevar, unless_clause)\
608 		    while (codevar < 0 &&\
609 			   (codevar = clist_VMerror_recover(cdev, codevar)) >= 0\
610 			   );\
611 		    if (codevar < 0 && !(unless_clause))\
612 			ERROR_RECT(codevar);\
613 		END
614 #define HANDLE_RECT(codevar)\
615 		HANDLE_RECT_UNLESS(codevar, 0)
616 #define END_RECTS_ON_ERROR(retry_cleanup, is_error, after_recovering)\
617 	    continue;\
618 error_in_rect:\
619 		if (cdev->error_is_retryable) {\
620 		    retry_cleanup;\
621 		    if ((is_error) &&\
622 			cdev->driver_call_nesting == 0 &&\
623 			(band_code =\
624 			 clist_VMerror_recover_flush(cdev, band_code)) >= 0 &&\
625 			(after_recovering)\
626 			)\
627 			goto retry_rect;\
628 		}\
629 		if (1) return band_code;\
630 	} while ((y += height) < yend);\
631     END
632 #define END_RECTS END_RECTS_ON_ERROR(DO_NOTHING, 1, 1)
633 #define END_RECTS_NO_ERROR\
634 	} while ((y += height) < yend);\
635     END
636 
637 /* ------ Exported by gxclrect.c ------ */
638 
639 /* Put out a fill or tile rectangle command. */
640 int cmd_write_rect_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
641 		       int op, int x, int y, int width, int height);
642 
643 /* ------ Exported by gxclbits.c ------ */
644 
645 /*
646  * Put a bitmap in the buffer, compressing if appropriate.
647  * pcls == 0 means put the bitmap in all bands.
648  * Return <0 if error, otherwise the compression method.
649  * A return value of gs_error_limitcheck means that the bitmap was too big
650  * to fit in the command reading buffer.
651  * Note that this leaves room for the command and initial arguments,
652  * but doesn't fill them in.
653  *
654  * If decompress_elsewhere is set in the compression_mask, it is OK
655  * to write out a compressed bitmap whose decompressed size is too large
656  * to fit in the command reading buffer.  (This is OK when reading a
657  * cached bitmap, but not a bitmap for a one-time copy operation.)
658  */
659 #define decompress_elsewhere 0x100
660 /*
661  * If decompress_spread is set, the decompressed data will be spread out
662  * for replication, so we drop all the padding even if the width is
663  * greater than cmd_max_short_width_bytes (see above).
664  */
665 #define decompress_spread 0x200
666 
667 int cmd_put_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
668 		 const byte * data, uint width_bits, uint height,
669 		 uint raster, int op_size, int compression_mask,
670 		 byte ** pdp, uint * psize);
671 
672 /*
673  * Put out commands for a color map (transfer function, black generation, or
674  * undercolor removal).  If pid != 0, write the map only if its ID differs
675  * from the current one, and update the saved ID in the case.
676  */
677 typedef enum {
678     cmd_map_transfer = 0,	/* all transfer functions */
679     cmd_map_transfer_0,		/* transfer[0] */
680     cmd_map_transfer_1,		/* transfer[1] */
681     cmd_map_transfer_2,		/* transfer[2] */
682     cmd_map_transfer_3,		/* transfer[3] */
683     cmd_map_black_generation,
684     cmd_map_undercolor_removal
685 } cmd_map_index;
686 typedef enum {
687     cmd_map_none = 0,		/* no map, use default */
688     cmd_map_identity,		/* identity map */
689     cmd_map_other		/* other map */
690 } cmd_map_contents;
691 int cmd_put_color_map(gx_device_clist_writer * cldev,
692                       cmd_map_index map_index, int comp_num,
693                       const gx_transfer_map * map, gs_id * pid);
694 
695 /*
696  * Change tiles for clist_tile_rectangle.  (We make this a separate
697  * procedure primarily for readability.)
698  */
699 int clist_change_tile(gx_device_clist_writer * cldev, gx_clist_state * pcls,
700 		      const gx_strip_bitmap * tiles, int depth);
701 
702 /*
703  * Change "tile" for clist_copy_*.  Only uses tiles->{data, id, raster,
704  * rep_width, rep_height}.  tiles->[rep_]shift must be zero.
705  */
706 int clist_change_bits(gx_device_clist_writer * cldev, gx_clist_state * pcls,
707 		      const gx_strip_bitmap * tiles, int depth);
708 
709 /* ------ Exported by gxclimag.c ------ */
710 
711 /*
712  * Write out any necessary color mapping data.
713  */
714 int cmd_put_color_mapping(gx_device_clist_writer * cldev,
715 				  const gs_imager_state * pis);
716 /*
717  * Add commands to represent a full (device) halftone.
718  * (This routine should probably be in some other module.)
719  */
720 int cmd_put_halftone(gx_device_clist_writer * cldev,
721 		     const gx_device_halftone * pdht);
722 
723 /* ------ Exported by gxclrast.c for gxclread.c ------ */
724 
725 /*
726  * Define whether we are actually rendering a band, or just executing
727  * the put_params that occurs at the beginning of each page.
728  */
729 typedef enum {
730     playback_action_render,
731     playback_action_setup
732 } clist_playback_action;
733 
734 /* Play back and rasterize one band. */
735 int clist_playback_band(clist_playback_action action,
736 			gx_device_clist_reader *cdev,
737 			stream *s, gx_device *target,
738 			int x0, int y0, gs_memory_t *mem);
739 
740 #endif /* gxcldev_INCLUDED */
741