1 /* Copyright (C) 1997, 1998, 1999 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: gxclrect.c,v 1.7 2004/08/04 19:36:12 stefan Exp $ */
18 /* Rectangle-oriented command writing for command list */
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gsutil.h" /* for gs_next_ids */
22 #include "gxdevice.h"
23 #include "gxdevmem.h" /* must precede gxcldev.h */
24 #include "gxcldev.h"
25
26 /* ---------------- Writing utilities ---------------- */
27
28 #define cmd_set_rect(rect)\
29 ((rect).x = x, (rect).y = y,\
30 (rect).width = width, (rect).height = height)
31
32 /* Write a rectangle. */
33 private int
cmd_size_rect(register const gx_cmd_rect * prect)34 cmd_size_rect(register const gx_cmd_rect * prect)
35 {
36 return
37 cmd_sizew(prect->x) + cmd_sizew(prect->y) +
38 cmd_sizew(prect->width) + cmd_sizew(prect->height);
39 }
40 private byte *
cmd_put_rect(register const gx_cmd_rect * prect,register byte * dp)41 cmd_put_rect(register const gx_cmd_rect * prect, register byte * dp)
42 {
43 cmd_putw(prect->x, dp);
44 cmd_putw(prect->y, dp);
45 cmd_putw(prect->width, dp);
46 cmd_putw(prect->height, dp);
47 return dp;
48 }
49
50 int
cmd_write_rect_cmd(gx_device_clist_writer * cldev,gx_clist_state * pcls,int op,int x,int y,int width,int height)51 cmd_write_rect_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
52 int op, int x, int y, int width, int height)
53 {
54 int dx = x - pcls->rect.x;
55 int dy = y - pcls->rect.y;
56 int dwidth = width - pcls->rect.width;
57 int dheight = height - pcls->rect.height;
58 byte *dp;
59 int code;
60
61 #define check_range_xy(rmin, rmax)\
62 ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
63 (unsigned)(dy - rmin) <= (rmax - rmin))
64 #define check_range_w(rmin, rmax)\
65 ((unsigned)(dwidth - rmin) <= (rmax - rmin))
66 #define check_ranges(rmin, rmax)\
67 (check_range_xy(rmin, rmax) && check_range_w(rmin, rmax) &&\
68 (unsigned)(dheight - rmin) <= (rmax - rmin))
69 cmd_set_rect(pcls->rect);
70 if (dheight == 0 && check_range_w(cmd_min_dw_tiny, cmd_max_dw_tiny) &&
71 check_range_xy(cmd_min_dxy_tiny, cmd_max_dxy_tiny)
72 ) {
73 byte op_tiny = op + 0x20 + dwidth - cmd_min_dw_tiny;
74
75 if (dx == width - dwidth && dy == 0) {
76 code = set_cmd_put_op(dp, cldev, pcls, op_tiny + 8, 1);
77 if (code < 0)
78 return code;
79 } else {
80 code = set_cmd_put_op(dp, cldev, pcls, op_tiny, 2);
81 if (code < 0)
82 return code;
83 dp[1] = (dx << 4) + dy - (cmd_min_dxy_tiny * 0x11);
84 }
85 }
86 #define rmin cmd_min_short
87 #define rmax cmd_max_short
88 else if (check_ranges(rmin, rmax)) {
89 int dh = dheight - cmd_min_dxy_tiny;
90
91 if ((unsigned)dh <= cmd_max_dxy_tiny - cmd_min_dxy_tiny &&
92 dh != 0 && dy == 0
93 ) {
94 op += dh;
95 code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 3);
96 if (code < 0)
97 return code;
98 if_debug3('L', " rs2:%d,%d,0,%d\n",
99 dx, dwidth, dheight);
100 } else {
101 code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 5);
102 if (code < 0)
103 return code;
104 if_debug4('L', " rs4:%d,%d,%d,%d\n",
105 dx, dwidth, dy, dheight);
106 dp[3] = dy - rmin;
107 dp[4] = dheight - rmin;
108 }
109 dp[1] = dx - rmin;
110 dp[2] = dwidth - rmin;
111 }
112 #undef rmin
113 #undef rmax
114 else if (dy >= -2 && dy <= 1 && dheight >= -2 && dheight <= 1 &&
115 (dy + dheight) != -4
116 ) {
117 int rcsize = 1 + cmd_sizew(x) + cmd_sizew(width);
118
119 code = set_cmd_put_op(dp, cldev, pcls,
120 op + ((dy + 2) << 2) + dheight + 2, rcsize);
121 if (code < 0)
122 return code;
123 ++dp;
124 cmd_put2w(x, width, dp);
125 } else {
126 int rcsize = 1 + cmd_size_rect(&pcls->rect);
127
128 code = set_cmd_put_op(dp, cldev, pcls, op, rcsize);
129 if (code < 0)
130 return code;
131 if_debug5('L', " r%d:%d,%d,%d,%d\n",
132 rcsize - 1, dx, dwidth, dy, dheight);
133 cmd_put_rect(&pcls->rect, dp + 1);
134 }
135 return 0;
136 }
137
138 /* ---------------- Driver procedures ---------------- */
139
140 int
clist_fill_rectangle(gx_device * dev,int x,int y,int width,int height,gx_color_index color)141 clist_fill_rectangle(gx_device * dev, int x, int y, int width, int height,
142 gx_color_index color)
143 {
144 gx_device_clist_writer * const cdev =
145 &((gx_device_clist *)dev)->writer;
146 int code;
147
148 fit_fill(dev, x, y, width, height);
149 FOR_RECTS {
150 pcls->colors_used.or |= color;
151 TRY_RECT {
152 code = cmd_disable_lop(cdev, pcls);
153 if (code >= 0 && color != pcls->colors[1])
154 code = cmd_put_color(cdev, pcls, &clist_select_color1,
155 color, &pcls->colors[1]);
156 if (code >= 0)
157 code = cmd_write_rect_cmd(cdev, pcls, cmd_op_fill_rect, x, y,
158 width, height);
159 } HANDLE_RECT(code);
160 } END_RECTS;
161 return 0;
162 }
163
164 int
clist_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tile,int x,int y,int width,int height,gx_color_index color0,gx_color_index color1,int px,int py)165 clist_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tile,
166 int x, int y, int width, int height,
167 gx_color_index color0, gx_color_index color1, int px, int py)
168 {
169 gx_device_clist_writer * const cdev =
170 &((gx_device_clist *)dev)->writer;
171 int depth =
172 (color1 == gx_no_color_index && color0 == gx_no_color_index ?
173 dev->color_info.depth : 1);
174 gx_color_index colors_used =
175 (color1 == gx_no_color_index && color0 == gx_no_color_index ?
176 /* We can't know what colors will be used: assume the worst. */
177 ((gx_color_index)1 << depth) - 1 :
178 (color0 == gx_no_color_index ? 0 : color0) |
179 (color1 == gx_no_color_index ? 0 : color1));
180 int code;
181
182 fit_fill(dev, x, y, width, height);
183 FOR_RECTS {
184 ulong offset_temp;
185
186 pcls->colors_used.or |= colors_used;
187 TRY_RECT {
188 code = cmd_disable_lop(cdev, pcls);
189 } HANDLE_RECT(code);
190 if (!cls_has_tile_id(cdev, pcls, tile->id, offset_temp)) {
191 code = 0;
192 if (tile->id != gx_no_bitmap_id) {
193 TRY_RECT {
194 code = clist_change_tile(cdev, pcls, tile, depth);
195 } HANDLE_RECT_UNLESS(code,
196 (code != gs_error_VMerror || !cdev->error_is_retryable));
197 }
198 if (code < 0) {
199 /* ok if gx_default... does retries internally: */
200 /* it's self-sufficient */
201 code = gx_default_strip_tile_rectangle(dev, tile,
202 x, y, width, height,
203 color0, color1,
204 px, py);
205 if (code < 0)
206 ERROR_RECT(code);
207 goto endr;
208 }
209 }
210 TRY_RECT {
211 code = 0;
212 if (color0 != pcls->tile_colors[0] || color1 != pcls->tile_colors[1])
213 code = cmd_set_tile_colors(cdev, pcls, color0, color1);
214 if (px != pcls->tile_phase.x || py != pcls->tile_phase.y) {
215 if (code >= 0)
216 code = cmd_set_tile_phase(cdev, pcls, px, py);
217 }
218 if (code >= 0)
219 code = cmd_write_rect_cmd(cdev, pcls, cmd_op_tile_rect, x, y,
220 width, height);
221 } HANDLE_RECT(code);
222 endr:;
223 } END_RECTS;
224 return 0;
225 }
226
227 int
clist_copy_mono(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color0,gx_color_index color1)228 clist_copy_mono(gx_device * dev,
229 const byte * data, int data_x, int raster, gx_bitmap_id id,
230 int x, int y, int width, int height,
231 gx_color_index color0, gx_color_index color1)
232 {
233 gx_device_clist_writer * const cdev =
234 &((gx_device_clist *)dev)->writer;
235 int y0;
236 gx_bitmap_id orig_id = id;
237 gx_color_index colors_used =
238 (color0 == gx_no_color_index ? 0 : color0) |
239 (color1 == gx_no_color_index ? 0 : color1);
240
241 fit_copy(dev, data, data_x, raster, id, x, y, width, height);
242 y0 = y;
243 FOR_RECTS {
244 int dx = data_x & 7;
245 int w1 = dx + width;
246 const byte *row = data + (y - y0) * raster + (data_x >> 3);
247 int code;
248
249 pcls->colors_used.or |= colors_used;
250 TRY_RECT {
251 code = cmd_disable_lop(cdev, pcls);
252 if (code >= 0)
253 code = cmd_disable_clip(cdev, pcls);
254 if (color0 != pcls->colors[0] && code >= 0)
255 code = cmd_set_color0(cdev, pcls, color0);
256 if (color1 != pcls->colors[1] && code >= 0)
257 code = cmd_set_color1(cdev, pcls, color1);
258 } HANDLE_RECT(code);
259 /* Don't bother to check for a possible cache hit: */
260 /* tile_rectangle and fill_mask handle those cases. */
261 copy:{
262 gx_cmd_rect rect;
263 int rsize;
264 byte op = (byte) cmd_op_copy_mono;
265 byte *dp;
266 uint csize;
267 uint compress;
268 int code;
269
270 rect.x = x, rect.y = y;
271 rect.width = w1, rect.height = height;
272 rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
273 TRY_RECT {
274 code = cmd_put_bits(cdev, pcls, row, w1, height, raster,
275 rsize, (orig_id == gx_no_bitmap_id ?
276 1 << cmd_compress_rle :
277 cmd_mask_compress_any),
278 &dp, &csize);
279 } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
280 compress = (uint)code;
281 if (code < 0) {
282 /* The bitmap was too large; split up the transfer. */
283 if (height > 1) {
284 /*
285 * Split the transfer by reducing the height.
286 * See the comment above FOR_RECTS in gxcldev.h.
287 */
288 height >>= 1;
289 goto copy;
290 } else {
291 /* Split a single (very long) row. */
292 int w2 = w1 >> 1;
293
294 NEST_RECT {
295 code = clist_copy_mono(dev, row, dx,
296 raster, gx_no_bitmap_id, x, y,
297 w2, 1, color0, color1);
298 if (code >= 0)
299 code = clist_copy_mono(dev, row, dx + w2,
300 raster, gx_no_bitmap_id,
301 x + w2, y,
302 w1 - w2, 1, color0, color1);
303 } UNNEST_RECT;
304 if (code < 0)
305 ERROR_RECT(code);
306 continue;
307 }
308 }
309 op += compress;
310 if (dx) {
311 *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
312 *dp++ = cmd_set_misc_data_x + dx;
313 }
314 *dp++ = cmd_count_op(op, csize);
315 cmd_put2w(x, y, dp);
316 cmd_put2w(w1, height, dp);
317 pcls->rect = rect;
318 }
319 } END_RECTS;
320 return 0;
321 }
322
323 int
clist_copy_color(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height)324 clist_copy_color(gx_device * dev,
325 const byte * data, int data_x, int raster, gx_bitmap_id id,
326 int x, int y, int width, int height)
327 {
328 gx_device_clist_writer * const cdev =
329 &((gx_device_clist *)dev)->writer;
330 int depth = dev->color_info.depth;
331 int y0;
332 int data_x_bit;
333 /* We can't know what colors will be used: assume the worst. */
334 gx_color_index colors_used = ((gx_color_index)1 << depth) - 1;
335
336 fit_copy(dev, data, data_x, raster, id, x, y, width, height);
337 y0 = y;
338 data_x_bit = data_x * depth;
339 FOR_RECTS {
340 int dx = (data_x_bit & 7) / depth;
341 int w1 = dx + width;
342 const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
343 int code;
344
345 pcls->colors_used.or |= colors_used;
346 TRY_RECT {
347 code = cmd_disable_lop(cdev, pcls);
348 if (code >= 0)
349 code = cmd_disable_clip(cdev, pcls);
350 } HANDLE_RECT(code);
351 if (pcls->color_is_alpha) {
352 byte *dp;
353
354 TRY_RECT {
355 code =
356 set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_color, 1);
357 } HANDLE_RECT(code);
358 pcls->color_is_alpha = 0;
359 }
360 copy:{
361 gx_cmd_rect rect;
362 int rsize;
363 byte op = (byte) cmd_op_copy_color_alpha;
364 byte *dp;
365 uint csize;
366 uint compress;
367
368 rect.x = x, rect.y = y;
369 rect.width = w1, rect.height = height;
370 rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
371 TRY_RECT {
372 code = cmd_put_bits(cdev, pcls, row, w1 * depth,
373 height, raster, rsize,
374 1 << cmd_compress_rle, &dp, &csize);
375 } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
376 compress = (uint)code;
377 if (code < 0) {
378 /* The bitmap was too large; split up the transfer. */
379 if (height > 1) {
380 /* Split the transfer by reducing the height.
381 * See the comment above FOR_RECTS in gxcldev.h.
382 */
383 height >>= 1;
384 goto copy;
385 } else {
386 /* Split a single (very long) row. */
387 int w2 = w1 >> 1;
388
389 NEST_RECT {
390 code = clist_copy_color(dev, row, dx,
391 raster, gx_no_bitmap_id,
392 x, y, w2, 1);
393 if (code >= 0)
394 code = clist_copy_color(dev, row, dx + w2,
395 raster, gx_no_bitmap_id,
396 x + w2, y, w1 - w2, 1);
397 } UNNEST_RECT;
398 if (code < 0)
399 ERROR_RECT(code);
400 continue;
401 }
402 }
403 op += compress;
404 if (dx) {
405 *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
406 *dp++ = cmd_set_misc_data_x + dx;
407 }
408 *dp++ = cmd_count_op(op, csize);
409 cmd_put2w(x, y, dp);
410 cmd_put2w(w1, height, dp);
411 pcls->rect = rect;
412 }
413 } END_RECTS;
414 return 0;
415 }
416
417 int
clist_copy_alpha(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index color,int depth)418 clist_copy_alpha(gx_device * dev, const byte * data, int data_x,
419 int raster, gx_bitmap_id id, int x, int y, int width, int height,
420 gx_color_index color, int depth)
421 {
422 gx_device_clist_writer * const cdev =
423 &((gx_device_clist *)dev)->writer;
424 /* I don't like copying the entire body of clist_copy_color */
425 /* just to change 2 arguments and 1 opcode, */
426 /* but I don't see any alternative that doesn't require */
427 /* another level of procedure call even in the common case. */
428 int log2_depth = ilog2(depth);
429 int y0;
430 int data_x_bit;
431
432 /* If the target can't perform copy_alpha, exit now */
433 if (depth > 1 && (cdev->disable_mask & clist_disable_copy_alpha) != 0)
434 return_error(gs_error_unknownerror);
435
436 fit_copy(dev, data, data_x, raster, id, x, y, width, height);
437 y0 = y;
438 data_x_bit = data_x << log2_depth;
439 FOR_RECTS {
440 int dx = (data_x_bit & 7) >> log2_depth;
441 int w1 = dx + width;
442 const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
443 int code;
444
445 pcls->colors_used.or |= color;
446 TRY_RECT {
447 code = cmd_disable_lop(cdev, pcls);
448 if (code >= 0)
449 code = cmd_disable_clip(cdev, pcls);
450 } HANDLE_RECT(code);
451 if (!pcls->color_is_alpha) {
452 byte *dp;
453
454 TRY_RECT {
455 code =
456 set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
457 } HANDLE_RECT(code);
458 pcls->color_is_alpha = 1;
459 }
460 if (color != pcls->colors[1]) {
461 TRY_RECT {
462 code = cmd_set_color1(cdev, pcls, color);
463 } HANDLE_RECT(code);
464 }
465 copy:{
466 gx_cmd_rect rect;
467 int rsize;
468 byte op = (byte) cmd_op_copy_color_alpha;
469 byte *dp;
470 uint csize;
471 uint compress;
472
473 rect.x = x, rect.y = y;
474 rect.width = w1, rect.height = height;
475 rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
476 TRY_RECT {
477 code = cmd_put_bits(cdev, pcls, row, w1 << log2_depth,
478 height, raster, rsize,
479 1 << cmd_compress_rle, &dp, &csize);
480 } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
481 compress = (uint)code;
482 if (code < 0) {
483 /* The bitmap was too large; split up the transfer. */
484 if (height > 1) {
485 /* Split the transfer by reducing the height.
486 * See the comment above FOR_RECTS in gxcldev.h.
487 */
488 height >>= 1;
489 goto copy;
490 } else {
491 /* Split a single (very long) row. */
492 int w2 = w1 >> 1;
493
494 NEST_RECT {
495 code = clist_copy_alpha(dev, row, dx,
496 raster, gx_no_bitmap_id, x, y,
497 w2, 1, color, depth);
498 if (code >= 0)
499 code = clist_copy_alpha(dev, row, dx + w2,
500 raster, gx_no_bitmap_id,
501 x + w2, y, w1 - w2, 1,
502 color, depth);
503 } UNNEST_RECT;
504 if (code < 0)
505 ERROR_RECT(code);
506 continue;
507 }
508 }
509 op += compress;
510 if (dx) {
511 *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
512 *dp++ = cmd_set_misc_data_x + dx;
513 }
514 *dp++ = cmd_count_op(op, csize);
515 *dp++ = depth;
516 cmd_put2w(x, y, dp);
517 cmd_put2w(w1, height, dp);
518 pcls->rect = rect;
519 }
520 } END_RECTS;
521 return 0;
522 }
523
524 int
clist_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int width,int height,int phase_x,int phase_y,gs_logical_operation_t lop)525 clist_strip_copy_rop(gx_device * dev,
526 const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
527 const gx_color_index * scolors,
528 const gx_strip_bitmap * textures, const gx_color_index * tcolors,
529 int x, int y, int width, int height,
530 int phase_x, int phase_y, gs_logical_operation_t lop)
531 {
532 gx_device_clist_writer * const cdev =
533 &((gx_device_clist *)dev)->writer;
534 gs_rop3_t rop = lop_rop(lop);
535 gx_strip_bitmap tile_with_id;
536 const gx_strip_bitmap *tiles = textures;
537 int y0;
538 /* Compute the set of possible colors that this operation can generate. */
539 gx_color_index all = ((gx_color_index)1 << dev->color_info.depth) - 1;
540 bool subtractive = dev->color_info.num_components == 4; /****** HACK ******/
541 gx_color_index S =
542 (scolors ? scolors[0] | scolors[1] : sdata ? all : 0);
543 gx_color_index T =
544 (tcolors ? tcolors[0] | tcolors[1] : textures ? all : 0);
545 gs_rop3_t color_rop =
546 (subtractive ? byte_reverse_bits[rop ^ 0xff] : rop);
547 bool slow_rop;
548
549 if (scolors != 0 && scolors[0] != scolors[1]) {
550 fit_fill(dev, x, y, width, height);
551 } else {
552 fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
553 }
554 /*
555 * On CMYK devices, RasterOps must be executed with complete pixels
556 * if the operation involves the destination.
557 * This is because the black plane interacts with the other planes
558 * in the conversion between RGB and CMYK. Check for this now.
559 */
560 {
561 gs_rop3_t rop_used = rop;
562
563 if (scolors && (scolors[0] == scolors[1]))
564 rop_used = (scolors[0] == gx_device_black(dev) ?
565 rop3_know_S_0(rop_used) :
566 scolors[0] == gx_device_white(dev) ?
567 rop3_know_S_1(rop_used) : rop_used);
568 if (tcolors && (tcolors[0] == tcolors[1]))
569 rop_used = (tcolors[0] == gx_device_black(dev) ?
570 rop3_know_T_0(rop_used) :
571 tcolors[0] == gx_device_white(dev) ?
572 rop3_know_T_1(rop_used) : rop_used);
573 slow_rop = !(rop == rop3_0 || rop == rop3_1 ||
574 rop == rop3_D || rop == rop3_S || rop == rop3_T);
575 }
576 y0 = y;
577 /*
578 * We shouldn't need to put the logic below inside FOR/END_RECTS,
579 * but the lop_enabled flags are per-band.
580 */
581 FOR_RECTS {
582 const byte *row = sdata + (y - y0) * sraster;
583 gx_color_index D = pcls->colors_used.or;
584 int code;
585
586 /* Reducing D, S, T to rop_operand (which apparently is 32 bit) appears safe
587 due to 'all' a has smaller snumber of significant bits. */
588 pcls->colors_used.or =
589 ((rop_proc_table[color_rop])((rop_operand)D, (rop_operand)S, (rop_operand)T) & all) | D;
590 pcls->colors_used.slow_rop |= slow_rop;
591 if (rop3_uses_T(rop)) {
592 if (tcolors == 0 || tcolors[0] != tcolors[1]) {
593 ulong offset_temp;
594
595 if (!cls_has_tile_id(cdev, pcls, tiles->id, offset_temp)) {
596 /* Change tile. If there is no id, generate one. */
597 if (tiles->id == gx_no_bitmap_id) {
598 tile_with_id = *tiles;
599 tile_with_id.id = gs_next_ids(dev->memory, 1);
600 tiles = &tile_with_id;
601 }
602 TRY_RECT {
603 code = clist_change_tile(cdev, pcls, tiles,
604 (tcolors != 0 ? 1 :
605 dev->color_info.depth));
606 } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
607 if (code < 0) {
608 /*
609 * The error is a limitcheck: we have a tile that
610 * is too big to fit in the command reading buffer.
611 * For now, just divide up the transfer into scan
612 * lines. (If a single scan line won't fit, punt.)
613 * Eventually, we'll need a way to transfer the tile
614 * in pieces.
615 */
616 uint rep_height = tiles->rep_height;
617 gs_id ids;
618 gx_strip_bitmap line_tile;
619 int iy;
620
621 if (rep_height == 1 ||
622 /****** CAN'T HANDLE SHIFT YET ******/
623 tiles->rep_shift != 0
624 )
625 return code;
626 /*
627 * Allocate enough fake IDs, since the inner call on
628 * clist_strip_copy_rop will need them anyway.
629 */
630 ids = gs_next_ids(dev->memory, min(height, rep_height));
631 line_tile = *tiles;
632 line_tile.size.y = 1;
633 line_tile.rep_height = 1;
634 for (iy = 0; iy < height; ++iy) {
635 line_tile.data = tiles->data + line_tile.raster *
636 ((y + iy + phase_y) % rep_height);
637 line_tile.id = ids + (iy % rep_height);
638 /*
639 * Note that since we're only transferring
640 * a single scan line, phase_y is irrelevant;
641 * we may as well use the current tile phase
642 * so we don't have to write extra commands.
643 */
644 NEST_RECT {
645 code = clist_strip_copy_rop(dev,
646 (sdata == 0 ? 0 : row + iy * sraster),
647 sourcex, sraster,
648 gx_no_bitmap_id, scolors,
649 &line_tile, tcolors,
650 x, y + iy, width, 1,
651 phase_x, pcls->tile_phase.y, lop);
652 } UNNEST_RECT;
653 if (code < 0)
654 ERROR_RECT(code);
655 }
656 continue;
657 }
658 if (phase_x != pcls->tile_phase.x ||
659 phase_y != pcls->tile_phase.y
660 ) {
661 TRY_RECT {
662 code = cmd_set_tile_phase(cdev, pcls, phase_x,
663 phase_y);
664 } HANDLE_RECT(code);
665 }
666 }
667 }
668 /* Set the tile colors. */
669 TRY_RECT {
670 code =
671 (tcolors != 0 ?
672 cmd_set_tile_colors(cdev, pcls, tcolors[0], tcolors[1]) :
673 cmd_set_tile_colors(cdev, pcls, gx_no_color_index,
674 gx_no_color_index));
675 } HANDLE_RECT(code);
676 }
677 TRY_RECT {
678 code = 0;
679 if (lop != pcls->lop)
680 code = cmd_set_lop(cdev, pcls, lop);
681 if (code >= 0)
682 code = cmd_enable_lop(cdev, pcls);
683 } HANDLE_RECT(code);
684
685 /* Set lop_enabled to -1 so that fill_rectangle / copy_* */
686 /* won't attempt to set it to 0. */
687 pcls->lop_enabled = -1;
688 NEST_RECT {
689 if (scolors != 0) {
690 if (scolors[0] == scolors[1])
691 code = clist_fill_rectangle(dev, x, y, width, height,
692 scolors[1]);
693 else
694 code = clist_copy_mono(dev, row, sourcex, sraster, id,
695 x, y, width, height,
696 scolors[0], scolors[1]);
697 } else
698 code = clist_copy_color(dev, row, sourcex, sraster, id,
699 x, y, width, height);
700 } UNNEST_RECT;
701 pcls->lop_enabled = 1;
702 if (code < 0)
703 ERROR_RECT(code);
704 } END_RECTS;
705 return 0;
706 }
707