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, ¶m_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