xref: /plan9/sys/src/cmd/gs/src/gxclrect.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gxclrect.c,v 1.7 2004/08/04 19:36:12 stefan Exp $ */
187dd7cddfSDavid du Colombier /* Rectangle-oriented command writing for command list */
197dd7cddfSDavid du Colombier #include "gx.h"
207dd7cddfSDavid du Colombier #include "gserrors.h"
217dd7cddfSDavid du Colombier #include "gsutil.h"		/* for gs_next_ids */
227dd7cddfSDavid du Colombier #include "gxdevice.h"
237dd7cddfSDavid du Colombier #include "gxdevmem.h"		/* must precede gxcldev.h */
247dd7cddfSDavid du Colombier #include "gxcldev.h"
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier /* ---------------- Writing utilities ---------------- */
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier #define cmd_set_rect(rect)\
297dd7cddfSDavid du Colombier   ((rect).x = x, (rect).y = y,\
307dd7cddfSDavid du Colombier    (rect).width = width, (rect).height = height)
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /* Write a rectangle. */
337dd7cddfSDavid du Colombier private int
cmd_size_rect(register const gx_cmd_rect * prect)347dd7cddfSDavid du Colombier cmd_size_rect(register const gx_cmd_rect * prect)
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier     return
377dd7cddfSDavid du Colombier 	cmd_sizew(prect->x) + cmd_sizew(prect->y) +
387dd7cddfSDavid du Colombier 	cmd_sizew(prect->width) + cmd_sizew(prect->height);
397dd7cddfSDavid du Colombier }
407dd7cddfSDavid du Colombier private byte *
cmd_put_rect(register const gx_cmd_rect * prect,register byte * dp)417dd7cddfSDavid du Colombier cmd_put_rect(register const gx_cmd_rect * prect, register byte * dp)
427dd7cddfSDavid du Colombier {
437dd7cddfSDavid du Colombier     cmd_putw(prect->x, dp);
447dd7cddfSDavid du Colombier     cmd_putw(prect->y, dp);
457dd7cddfSDavid du Colombier     cmd_putw(prect->width, dp);
467dd7cddfSDavid du Colombier     cmd_putw(prect->height, dp);
477dd7cddfSDavid du Colombier     return dp;
487dd7cddfSDavid du Colombier }
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier int
cmd_write_rect_cmd(gx_device_clist_writer * cldev,gx_clist_state * pcls,int op,int x,int y,int width,int height)517dd7cddfSDavid du Colombier cmd_write_rect_cmd(gx_device_clist_writer * cldev, gx_clist_state * pcls,
527dd7cddfSDavid du Colombier 		   int op, int x, int y, int width, int height)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier     int dx = x - pcls->rect.x;
557dd7cddfSDavid du Colombier     int dy = y - pcls->rect.y;
567dd7cddfSDavid du Colombier     int dwidth = width - pcls->rect.width;
577dd7cddfSDavid du Colombier     int dheight = height - pcls->rect.height;
587dd7cddfSDavid du Colombier     byte *dp;
597dd7cddfSDavid du Colombier     int code;
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier #define check_range_xy(rmin, rmax)\
627dd7cddfSDavid du Colombier   ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
637dd7cddfSDavid du Colombier    (unsigned)(dy - rmin) <= (rmax - rmin))
647dd7cddfSDavid du Colombier #define check_range_w(rmin, rmax)\
657dd7cddfSDavid du Colombier   ((unsigned)(dwidth - rmin) <= (rmax - rmin))
667dd7cddfSDavid du Colombier #define check_ranges(rmin, rmax)\
677dd7cddfSDavid du Colombier   (check_range_xy(rmin, rmax) && check_range_w(rmin, rmax) &&\
687dd7cddfSDavid du Colombier    (unsigned)(dheight - rmin) <= (rmax - rmin))
697dd7cddfSDavid du Colombier     cmd_set_rect(pcls->rect);
707dd7cddfSDavid du Colombier     if (dheight == 0 && check_range_w(cmd_min_dw_tiny, cmd_max_dw_tiny) &&
717dd7cddfSDavid du Colombier 	check_range_xy(cmd_min_dxy_tiny, cmd_max_dxy_tiny)
727dd7cddfSDavid du Colombier 	) {
737dd7cddfSDavid du Colombier 	byte op_tiny = op + 0x20 + dwidth - cmd_min_dw_tiny;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	if (dx == width - dwidth && dy == 0) {
767dd7cddfSDavid du Colombier 	    code = set_cmd_put_op(dp, cldev, pcls, op_tiny + 8, 1);
777dd7cddfSDavid du Colombier 	    if (code < 0)
787dd7cddfSDavid du Colombier 		return code;
797dd7cddfSDavid du Colombier 	} else {
807dd7cddfSDavid du Colombier 	    code = set_cmd_put_op(dp, cldev, pcls, op_tiny, 2);
817dd7cddfSDavid du Colombier 	    if (code < 0)
827dd7cddfSDavid du Colombier 		return code;
837dd7cddfSDavid du Colombier 	    dp[1] = (dx << 4) + dy - (cmd_min_dxy_tiny * 0x11);
847dd7cddfSDavid du Colombier 	}
857dd7cddfSDavid du Colombier     }
867dd7cddfSDavid du Colombier #define rmin cmd_min_short
877dd7cddfSDavid du Colombier #define rmax cmd_max_short
887dd7cddfSDavid du Colombier     else if (check_ranges(rmin, rmax)) {
897dd7cddfSDavid du Colombier 	int dh = dheight - cmd_min_dxy_tiny;
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier 	if ((unsigned)dh <= cmd_max_dxy_tiny - cmd_min_dxy_tiny &&
927dd7cddfSDavid du Colombier 	    dh != 0 && dy == 0
937dd7cddfSDavid du Colombier 	    ) {
947dd7cddfSDavid du Colombier 	    op += dh;
957dd7cddfSDavid du Colombier 	    code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 3);
967dd7cddfSDavid du Colombier 	    if (code < 0)
977dd7cddfSDavid du Colombier 		return code;
987dd7cddfSDavid du Colombier 	    if_debug3('L', "    rs2:%d,%d,0,%d\n",
997dd7cddfSDavid du Colombier 		      dx, dwidth, dheight);
1007dd7cddfSDavid du Colombier 	} else {
1017dd7cddfSDavid du Colombier 	    code = set_cmd_put_op(dp, cldev, pcls, op + 0x10, 5);
1027dd7cddfSDavid du Colombier 	    if (code < 0)
1037dd7cddfSDavid du Colombier 		return code;
1047dd7cddfSDavid du Colombier 	    if_debug4('L', "    rs4:%d,%d,%d,%d\n",
1057dd7cddfSDavid du Colombier 		      dx, dwidth, dy, dheight);
1067dd7cddfSDavid du Colombier 	    dp[3] = dy - rmin;
1077dd7cddfSDavid du Colombier 	    dp[4] = dheight - rmin;
1087dd7cddfSDavid du Colombier 	}
1097dd7cddfSDavid du Colombier 	dp[1] = dx - rmin;
1107dd7cddfSDavid du Colombier 	dp[2] = dwidth - rmin;
1117dd7cddfSDavid du Colombier     }
1127dd7cddfSDavid du Colombier #undef rmin
1137dd7cddfSDavid du Colombier #undef rmax
1147dd7cddfSDavid du Colombier     else if (dy >= -2 && dy <= 1 && dheight >= -2 && dheight <= 1 &&
1157dd7cddfSDavid du Colombier 	     (dy + dheight) != -4
1167dd7cddfSDavid du Colombier 	) {
1177dd7cddfSDavid du Colombier 	int rcsize = 1 + cmd_sizew(x) + cmd_sizew(width);
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier 	code = set_cmd_put_op(dp, cldev, pcls,
1207dd7cddfSDavid du Colombier 			      op + ((dy + 2) << 2) + dheight + 2, rcsize);
1217dd7cddfSDavid du Colombier 	if (code < 0)
1227dd7cddfSDavid du Colombier 	    return code;
1237dd7cddfSDavid du Colombier 	++dp;
1247dd7cddfSDavid du Colombier 	cmd_put2w(x, width, dp);
1257dd7cddfSDavid du Colombier     } else {
1267dd7cddfSDavid du Colombier 	int rcsize = 1 + cmd_size_rect(&pcls->rect);
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier 	code = set_cmd_put_op(dp, cldev, pcls, op, rcsize);
1297dd7cddfSDavid du Colombier 	if (code < 0)
1307dd7cddfSDavid du Colombier 	    return code;
1317dd7cddfSDavid du Colombier 	if_debug5('L', "    r%d:%d,%d,%d,%d\n",
1327dd7cddfSDavid du Colombier 		  rcsize - 1, dx, dwidth, dy, dheight);
1337dd7cddfSDavid du Colombier 	cmd_put_rect(&pcls->rect, dp + 1);
1347dd7cddfSDavid du Colombier     }
1357dd7cddfSDavid du Colombier     return 0;
1367dd7cddfSDavid du Colombier }
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier /* ---------------- Driver procedures ---------------- */
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier int
clist_fill_rectangle(gx_device * dev,int x,int y,int width,int height,gx_color_index color)1417dd7cddfSDavid du Colombier clist_fill_rectangle(gx_device * dev, int x, int y, int width, int height,
1427dd7cddfSDavid du Colombier 		     gx_color_index color)
1437dd7cddfSDavid du Colombier {
1447dd7cddfSDavid du Colombier     gx_device_clist_writer * const cdev =
1457dd7cddfSDavid du Colombier 	&((gx_device_clist *)dev)->writer;
1467dd7cddfSDavid du Colombier     int code;
1477dd7cddfSDavid du Colombier 
1487dd7cddfSDavid du Colombier     fit_fill(dev, x, y, width, height);
1497dd7cddfSDavid du Colombier     FOR_RECTS {
1507dd7cddfSDavid du Colombier 	pcls->colors_used.or |= color;
1517dd7cddfSDavid du Colombier 	TRY_RECT {
1527dd7cddfSDavid du Colombier 	    code = cmd_disable_lop(cdev, pcls);
1537dd7cddfSDavid du Colombier 	    if (code >= 0 && color != pcls->colors[1])
1547dd7cddfSDavid du Colombier 		code = cmd_put_color(cdev, pcls, &clist_select_color1,
1557dd7cddfSDavid du Colombier 				     color, &pcls->colors[1]);
1567dd7cddfSDavid du Colombier 	    if (code >= 0)
1577dd7cddfSDavid du Colombier 		code = cmd_write_rect_cmd(cdev, pcls, cmd_op_fill_rect, x, y,
1587dd7cddfSDavid du Colombier 					  width, height);
1597dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
1607dd7cddfSDavid du Colombier     } END_RECTS;
1617dd7cddfSDavid du Colombier     return 0;
1627dd7cddfSDavid du Colombier }
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier 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)1657dd7cddfSDavid du Colombier clist_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tile,
1667dd7cddfSDavid du Colombier 			   int x, int y, int width, int height,
1677dd7cddfSDavid du Colombier 	       gx_color_index color0, gx_color_index color1, int px, int py)
1687dd7cddfSDavid du Colombier {
1697dd7cddfSDavid du Colombier     gx_device_clist_writer * const cdev =
1707dd7cddfSDavid du Colombier 	&((gx_device_clist *)dev)->writer;
1717dd7cddfSDavid du Colombier     int depth =
1727dd7cddfSDavid du Colombier 	(color1 == gx_no_color_index && color0 == gx_no_color_index ?
1737dd7cddfSDavid du Colombier 	 dev->color_info.depth : 1);
1747dd7cddfSDavid du Colombier     gx_color_index colors_used =
1757dd7cddfSDavid du Colombier 	(color1 == gx_no_color_index && color0 == gx_no_color_index ?
1767dd7cddfSDavid du Colombier 	 /* We can't know what colors will be used: assume the worst. */
1777dd7cddfSDavid du Colombier 	 ((gx_color_index)1 << depth) - 1 :
1787dd7cddfSDavid du Colombier 	 (color0 == gx_no_color_index ? 0 : color0) |
1797dd7cddfSDavid du Colombier 	 (color1 == gx_no_color_index ? 0 : color1));
1807dd7cddfSDavid du Colombier     int code;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier     fit_fill(dev, x, y, width, height);
1837dd7cddfSDavid du Colombier     FOR_RECTS {
1847dd7cddfSDavid du Colombier 	ulong offset_temp;
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	pcls->colors_used.or |= colors_used;
1877dd7cddfSDavid du Colombier 	TRY_RECT {
1887dd7cddfSDavid du Colombier 	    code = cmd_disable_lop(cdev, pcls);
1897dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
1907dd7cddfSDavid du Colombier 	if (!cls_has_tile_id(cdev, pcls, tile->id, offset_temp)) {
1917dd7cddfSDavid du Colombier 	    code = 0;
1927dd7cddfSDavid du Colombier 	    if (tile->id != gx_no_bitmap_id) {
1937dd7cddfSDavid du Colombier 		TRY_RECT {
1947dd7cddfSDavid du Colombier 		    code = clist_change_tile(cdev, pcls, tile, depth);
1957dd7cddfSDavid du Colombier 		} HANDLE_RECT_UNLESS(code,
1967dd7cddfSDavid du Colombier 		    (code != gs_error_VMerror || !cdev->error_is_retryable));
1977dd7cddfSDavid du Colombier 	    }
1987dd7cddfSDavid du Colombier 	    if (code < 0) {
1997dd7cddfSDavid du Colombier 		/* ok if gx_default... does retries internally: */
2007dd7cddfSDavid du Colombier 		/* it's self-sufficient */
2017dd7cddfSDavid du Colombier 		code = gx_default_strip_tile_rectangle(dev, tile,
2027dd7cddfSDavid du Colombier 						       x, y, width, height,
2037dd7cddfSDavid du Colombier 						       color0, color1,
2047dd7cddfSDavid du Colombier 						       px, py);
2057dd7cddfSDavid du Colombier 		if (code < 0)
2067dd7cddfSDavid du Colombier 		    ERROR_RECT(code);
2077dd7cddfSDavid du Colombier 		goto endr;
2087dd7cddfSDavid du Colombier 	    }
2097dd7cddfSDavid du Colombier 	}
2107dd7cddfSDavid du Colombier 	TRY_RECT {
2117dd7cddfSDavid du Colombier 	    code = 0;
2127dd7cddfSDavid du Colombier 	    if (color0 != pcls->tile_colors[0] || color1 != pcls->tile_colors[1])
2137dd7cddfSDavid du Colombier 		code = cmd_set_tile_colors(cdev, pcls, color0, color1);
2147dd7cddfSDavid du Colombier 	    if (px != pcls->tile_phase.x || py != pcls->tile_phase.y) {
2157dd7cddfSDavid du Colombier 		if (code >= 0)
2167dd7cddfSDavid du Colombier 		    code = cmd_set_tile_phase(cdev, pcls, px, py);
2177dd7cddfSDavid du Colombier 	    }
2187dd7cddfSDavid du Colombier 	    if (code >= 0)
2197dd7cddfSDavid du Colombier 		code = cmd_write_rect_cmd(cdev, pcls, cmd_op_tile_rect, x, y,
2207dd7cddfSDavid du Colombier 					  width, height);
2217dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
2227dd7cddfSDavid du Colombier endr:;
2237dd7cddfSDavid du Colombier     } END_RECTS;
2247dd7cddfSDavid du Colombier     return 0;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 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)2287dd7cddfSDavid du Colombier clist_copy_mono(gx_device * dev,
2297dd7cddfSDavid du Colombier 		const byte * data, int data_x, int raster, gx_bitmap_id id,
2307dd7cddfSDavid du Colombier 		int x, int y, int width, int height,
2317dd7cddfSDavid du Colombier 		gx_color_index color0, gx_color_index color1)
2327dd7cddfSDavid du Colombier {
2337dd7cddfSDavid du Colombier     gx_device_clist_writer * const cdev =
2347dd7cddfSDavid du Colombier 	&((gx_device_clist *)dev)->writer;
2357dd7cddfSDavid du Colombier     int y0;
2367dd7cddfSDavid du Colombier     gx_bitmap_id orig_id = id;
2377dd7cddfSDavid du Colombier     gx_color_index colors_used =
2387dd7cddfSDavid du Colombier 	(color0 == gx_no_color_index ? 0 : color0) |
2397dd7cddfSDavid du Colombier 	(color1 == gx_no_color_index ? 0 : color1);
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
2427dd7cddfSDavid du Colombier     y0 = y;
2437dd7cddfSDavid du Colombier     FOR_RECTS {
2447dd7cddfSDavid du Colombier 	int dx = data_x & 7;
2457dd7cddfSDavid du Colombier 	int w1 = dx + width;
2467dd7cddfSDavid du Colombier 	const byte *row = data + (y - y0) * raster + (data_x >> 3);
2477dd7cddfSDavid du Colombier 	int code;
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier 	pcls->colors_used.or |= colors_used;
2507dd7cddfSDavid du Colombier 	TRY_RECT {
2517dd7cddfSDavid du Colombier 	    code = cmd_disable_lop(cdev, pcls);
2527dd7cddfSDavid du Colombier 	    if (code >= 0)
2537dd7cddfSDavid du Colombier 		code = cmd_disable_clip(cdev, pcls);
2547dd7cddfSDavid du Colombier 	    if (color0 != pcls->colors[0] && code >= 0)
2557dd7cddfSDavid du Colombier 		code = cmd_set_color0(cdev, pcls, color0);
2567dd7cddfSDavid du Colombier 	    if (color1 != pcls->colors[1] && code >= 0)
2577dd7cddfSDavid du Colombier 		code = cmd_set_color1(cdev, pcls, color1);
2587dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
2597dd7cddfSDavid du Colombier 	/* Don't bother to check for a possible cache hit: */
2607dd7cddfSDavid du Colombier 	/* tile_rectangle and fill_mask handle those cases. */
2617dd7cddfSDavid du Colombier copy:{
2627dd7cddfSDavid du Colombier 	gx_cmd_rect rect;
2637dd7cddfSDavid du Colombier 	int rsize;
2647dd7cddfSDavid du Colombier 	byte op = (byte) cmd_op_copy_mono;
2657dd7cddfSDavid du Colombier 	byte *dp;
2667dd7cddfSDavid du Colombier 	uint csize;
2677dd7cddfSDavid du Colombier 	uint compress;
2687dd7cddfSDavid du Colombier 	int code;
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	rect.x = x, rect.y = y;
2717dd7cddfSDavid du Colombier 	rect.width = w1, rect.height = height;
2727dd7cddfSDavid du Colombier 	rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
2737dd7cddfSDavid du Colombier 	TRY_RECT {
2747dd7cddfSDavid du Colombier 	    code = cmd_put_bits(cdev, pcls, row, w1, height, raster,
2757dd7cddfSDavid du Colombier 				rsize, (orig_id == gx_no_bitmap_id ?
2767dd7cddfSDavid du Colombier 					1 << cmd_compress_rle :
2777dd7cddfSDavid du Colombier 					cmd_mask_compress_any),
2787dd7cddfSDavid du Colombier 				&dp, &csize);
2797dd7cddfSDavid du Colombier 	} HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
2807dd7cddfSDavid du Colombier 	compress = (uint)code;
2817dd7cddfSDavid du Colombier 	if (code < 0) {
2827dd7cddfSDavid du Colombier 	    /* The bitmap was too large; split up the transfer. */
2837dd7cddfSDavid du Colombier 	    if (height > 1) {
2847dd7cddfSDavid du Colombier 		/*
2857dd7cddfSDavid du Colombier 		 * Split the transfer by reducing the height.
2867dd7cddfSDavid du Colombier 		 * See the comment above FOR_RECTS in gxcldev.h.
2877dd7cddfSDavid du Colombier 		 */
2887dd7cddfSDavid du Colombier 		height >>= 1;
2897dd7cddfSDavid du Colombier 		goto copy;
2907dd7cddfSDavid du Colombier 	    } else {
2917dd7cddfSDavid du Colombier 		/* Split a single (very long) row. */
2927dd7cddfSDavid du Colombier 		int w2 = w1 >> 1;
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 		NEST_RECT {
2957dd7cddfSDavid du Colombier 		    code = clist_copy_mono(dev, row, dx,
2967dd7cddfSDavid du Colombier 					   raster, gx_no_bitmap_id, x, y,
2977dd7cddfSDavid du Colombier 					   w2, 1, color0, color1);
2987dd7cddfSDavid du Colombier 		    if (code >= 0)
2997dd7cddfSDavid du Colombier 			code = clist_copy_mono(dev, row, dx + w2,
3007dd7cddfSDavid du Colombier 					       raster, gx_no_bitmap_id,
3017dd7cddfSDavid du Colombier 					       x + w2, y,
3027dd7cddfSDavid du Colombier 					       w1 - w2, 1, color0, color1);
3037dd7cddfSDavid du Colombier 		} UNNEST_RECT;
3047dd7cddfSDavid du Colombier 		if (code < 0)
3057dd7cddfSDavid du Colombier 		    ERROR_RECT(code);
3067dd7cddfSDavid du Colombier 		continue;
3077dd7cddfSDavid du Colombier 	    }
3087dd7cddfSDavid du Colombier 	}
3097dd7cddfSDavid du Colombier 	op += compress;
3107dd7cddfSDavid du Colombier 	if (dx) {
3117dd7cddfSDavid du Colombier 	    *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
3127dd7cddfSDavid du Colombier 	    *dp++ = cmd_set_misc_data_x + dx;
3137dd7cddfSDavid du Colombier 	}
3147dd7cddfSDavid du Colombier 	*dp++ = cmd_count_op(op, csize);
3157dd7cddfSDavid du Colombier 	cmd_put2w(x, y, dp);
3167dd7cddfSDavid du Colombier 	cmd_put2w(w1, height, dp);
3177dd7cddfSDavid du Colombier 	pcls->rect = rect;
3187dd7cddfSDavid du Colombier 	}
3197dd7cddfSDavid du Colombier     } END_RECTS;
3207dd7cddfSDavid du Colombier     return 0;
3217dd7cddfSDavid du Colombier }
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 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)3247dd7cddfSDavid du Colombier clist_copy_color(gx_device * dev,
3257dd7cddfSDavid du Colombier 		 const byte * data, int data_x, int raster, gx_bitmap_id id,
3267dd7cddfSDavid du Colombier 		 int x, int y, int width, int height)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier     gx_device_clist_writer * const cdev =
3297dd7cddfSDavid du Colombier 	&((gx_device_clist *)dev)->writer;
3307dd7cddfSDavid du Colombier     int depth = dev->color_info.depth;
3317dd7cddfSDavid du Colombier     int y0;
3327dd7cddfSDavid du Colombier     int data_x_bit;
3337dd7cddfSDavid du Colombier     /* We can't know what colors will be used: assume the worst. */
3347dd7cddfSDavid du Colombier     gx_color_index colors_used = ((gx_color_index)1 << depth) - 1;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
3377dd7cddfSDavid du Colombier     y0 = y;
3387dd7cddfSDavid du Colombier     data_x_bit = data_x * depth;
3397dd7cddfSDavid du Colombier     FOR_RECTS {
3407dd7cddfSDavid du Colombier 	int dx = (data_x_bit & 7) / depth;
3417dd7cddfSDavid du Colombier 	int w1 = dx + width;
3427dd7cddfSDavid du Colombier 	const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
3437dd7cddfSDavid du Colombier 	int code;
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier 	pcls->colors_used.or |= colors_used;
3467dd7cddfSDavid du Colombier 	TRY_RECT {
3477dd7cddfSDavid du Colombier 	    code = cmd_disable_lop(cdev, pcls);
3487dd7cddfSDavid du Colombier 	    if (code >= 0)
3497dd7cddfSDavid du Colombier 		code = cmd_disable_clip(cdev, pcls);
3507dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
3517dd7cddfSDavid du Colombier 	if (pcls->color_is_alpha) {
3527dd7cddfSDavid du Colombier 	    byte *dp;
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	    TRY_RECT {
3557dd7cddfSDavid du Colombier 		code =
3567dd7cddfSDavid du Colombier 		    set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_color, 1);
3577dd7cddfSDavid du Colombier 	    } HANDLE_RECT(code);
3587dd7cddfSDavid du Colombier 	    pcls->color_is_alpha = 0;
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier copy:{
3617dd7cddfSDavid du Colombier 	    gx_cmd_rect rect;
3627dd7cddfSDavid du Colombier 	    int rsize;
3637dd7cddfSDavid du Colombier 	    byte op = (byte) cmd_op_copy_color_alpha;
3647dd7cddfSDavid du Colombier 	    byte *dp;
3657dd7cddfSDavid du Colombier 	    uint csize;
3667dd7cddfSDavid du Colombier 	    uint compress;
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier 	    rect.x = x, rect.y = y;
3697dd7cddfSDavid du Colombier 	    rect.width = w1, rect.height = height;
3707dd7cddfSDavid du Colombier 	    rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
3717dd7cddfSDavid du Colombier 	    TRY_RECT {
3727dd7cddfSDavid du Colombier 		code = cmd_put_bits(cdev, pcls, row, w1 * depth,
3737dd7cddfSDavid du Colombier 				    height, raster, rsize,
3747dd7cddfSDavid du Colombier 				    1 << cmd_compress_rle, &dp, &csize);
3757dd7cddfSDavid du Colombier 	    } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
3767dd7cddfSDavid du Colombier 	    compress = (uint)code;
3777dd7cddfSDavid du Colombier 	    if (code < 0) {
3787dd7cddfSDavid du Colombier 		/* The bitmap was too large; split up the transfer. */
3797dd7cddfSDavid du Colombier 		if (height > 1) {
3807dd7cddfSDavid du Colombier 		    /* Split the transfer by reducing the height.
3817dd7cddfSDavid du Colombier 		     * See the comment above FOR_RECTS in gxcldev.h.
3827dd7cddfSDavid du Colombier 		     */
3837dd7cddfSDavid du Colombier 		    height >>= 1;
3847dd7cddfSDavid du Colombier 		    goto copy;
3857dd7cddfSDavid du Colombier 		} else {
3867dd7cddfSDavid du Colombier 		    /* Split a single (very long) row. */
3877dd7cddfSDavid du Colombier 		    int w2 = w1 >> 1;
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier 		    NEST_RECT {
3907dd7cddfSDavid du Colombier 			code = clist_copy_color(dev, row, dx,
3917dd7cddfSDavid du Colombier 						raster, gx_no_bitmap_id,
3927dd7cddfSDavid du Colombier 						x, y, w2, 1);
3937dd7cddfSDavid du Colombier 			if (code >= 0)
3947dd7cddfSDavid du Colombier 			    code = clist_copy_color(dev, row, dx + w2,
3957dd7cddfSDavid du Colombier 						    raster, gx_no_bitmap_id,
3967dd7cddfSDavid du Colombier 						    x + w2, y, w1 - w2, 1);
3977dd7cddfSDavid du Colombier 		    } UNNEST_RECT;
3987dd7cddfSDavid du Colombier 		    if (code < 0)
3997dd7cddfSDavid du Colombier 			ERROR_RECT(code);
4007dd7cddfSDavid du Colombier 		    continue;
4017dd7cddfSDavid du Colombier 		}
4027dd7cddfSDavid du Colombier 	    }
4037dd7cddfSDavid du Colombier 	    op += compress;
4047dd7cddfSDavid du Colombier 	    if (dx) {
4057dd7cddfSDavid du Colombier 		*dp++ = cmd_count_op(cmd_opv_set_misc, 2);
4067dd7cddfSDavid du Colombier 		*dp++ = cmd_set_misc_data_x + dx;
4077dd7cddfSDavid du Colombier 	    }
4087dd7cddfSDavid du Colombier 	    *dp++ = cmd_count_op(op, csize);
4097dd7cddfSDavid du Colombier 	    cmd_put2w(x, y, dp);
4107dd7cddfSDavid du Colombier 	    cmd_put2w(w1, height, dp);
4117dd7cddfSDavid du Colombier 	    pcls->rect = rect;
4127dd7cddfSDavid du Colombier 	}
4137dd7cddfSDavid du Colombier     } END_RECTS;
4147dd7cddfSDavid du Colombier     return 0;
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier 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)4187dd7cddfSDavid du Colombier clist_copy_alpha(gx_device * dev, const byte * data, int data_x,
4197dd7cddfSDavid du Colombier 	   int raster, gx_bitmap_id id, int x, int y, int width, int height,
4207dd7cddfSDavid du Colombier 		 gx_color_index color, int depth)
4217dd7cddfSDavid du Colombier {
4227dd7cddfSDavid du Colombier     gx_device_clist_writer * const cdev =
4237dd7cddfSDavid du Colombier 	&((gx_device_clist *)dev)->writer;
4247dd7cddfSDavid du Colombier     /* I don't like copying the entire body of clist_copy_color */
4257dd7cddfSDavid du Colombier     /* just to change 2 arguments and 1 opcode, */
4267dd7cddfSDavid du Colombier     /* but I don't see any alternative that doesn't require */
4277dd7cddfSDavid du Colombier     /* another level of procedure call even in the common case. */
4287dd7cddfSDavid du Colombier     int log2_depth = ilog2(depth);
4297dd7cddfSDavid du Colombier     int y0;
4307dd7cddfSDavid du Colombier     int data_x_bit;
4317dd7cddfSDavid du Colombier 
432*593dc095SDavid du Colombier     /* If the target can't perform copy_alpha, exit now */
433*593dc095SDavid du Colombier     if (depth > 1 && (cdev->disable_mask & clist_disable_copy_alpha) != 0)
434*593dc095SDavid du Colombier 	return_error(gs_error_unknownerror);
435*593dc095SDavid du Colombier 
4367dd7cddfSDavid du Colombier     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
4377dd7cddfSDavid du Colombier     y0 = y;
4387dd7cddfSDavid du Colombier     data_x_bit = data_x << log2_depth;
4397dd7cddfSDavid du Colombier     FOR_RECTS {
4407dd7cddfSDavid du Colombier 	int dx = (data_x_bit & 7) >> log2_depth;
4417dd7cddfSDavid du Colombier 	int w1 = dx + width;
4427dd7cddfSDavid du Colombier 	const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
4437dd7cddfSDavid du Colombier 	int code;
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier 	pcls->colors_used.or |= color;
4467dd7cddfSDavid du Colombier 	TRY_RECT {
4477dd7cddfSDavid du Colombier 	    code = cmd_disable_lop(cdev, pcls);
4487dd7cddfSDavid du Colombier 	    if (code >= 0)
4497dd7cddfSDavid du Colombier 		code = cmd_disable_clip(cdev, pcls);
4507dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
4517dd7cddfSDavid du Colombier 	if (!pcls->color_is_alpha) {
4527dd7cddfSDavid du Colombier 	    byte *dp;
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier 	    TRY_RECT {
4557dd7cddfSDavid du Colombier 		code =
4567dd7cddfSDavid du Colombier 		    set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
4577dd7cddfSDavid du Colombier 	    } HANDLE_RECT(code);
4587dd7cddfSDavid du Colombier 	    pcls->color_is_alpha = 1;
4597dd7cddfSDavid du Colombier 	}
4607dd7cddfSDavid du Colombier 	if (color != pcls->colors[1]) {
4617dd7cddfSDavid du Colombier 	    TRY_RECT {
4627dd7cddfSDavid du Colombier 		code = cmd_set_color1(cdev, pcls, color);
4637dd7cddfSDavid du Colombier 	    } HANDLE_RECT(code);
4647dd7cddfSDavid du Colombier 	}
4657dd7cddfSDavid du Colombier copy:{
4667dd7cddfSDavid du Colombier 	    gx_cmd_rect rect;
4677dd7cddfSDavid du Colombier 	    int rsize;
4687dd7cddfSDavid du Colombier 	    byte op = (byte) cmd_op_copy_color_alpha;
4697dd7cddfSDavid du Colombier 	    byte *dp;
4707dd7cddfSDavid du Colombier 	    uint csize;
4717dd7cddfSDavid du Colombier 	    uint compress;
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier 	    rect.x = x, rect.y = y;
4747dd7cddfSDavid du Colombier 	    rect.width = w1, rect.height = height;
4757dd7cddfSDavid du Colombier 	    rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
4767dd7cddfSDavid du Colombier 	    TRY_RECT {
4777dd7cddfSDavid du Colombier 		code = cmd_put_bits(cdev, pcls, row, w1 << log2_depth,
4787dd7cddfSDavid du Colombier 				    height, raster, rsize,
4797dd7cddfSDavid du Colombier 				    1 << cmd_compress_rle, &dp, &csize);
4807dd7cddfSDavid du Colombier 	    } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
4817dd7cddfSDavid du Colombier 	    compress = (uint)code;
4827dd7cddfSDavid du Colombier 	    if (code < 0) {
4837dd7cddfSDavid du Colombier 		/* The bitmap was too large; split up the transfer. */
4847dd7cddfSDavid du Colombier 		if (height > 1) {
4857dd7cddfSDavid du Colombier 		    /* Split the transfer by reducing the height.
4867dd7cddfSDavid du Colombier 		     * See the comment above FOR_RECTS in gxcldev.h.
4877dd7cddfSDavid du Colombier 		     */
4887dd7cddfSDavid du Colombier 		    height >>= 1;
4897dd7cddfSDavid du Colombier 		    goto copy;
4907dd7cddfSDavid du Colombier 		} else {
4917dd7cddfSDavid du Colombier 		    /* Split a single (very long) row. */
4927dd7cddfSDavid du Colombier 		    int w2 = w1 >> 1;
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier 		    NEST_RECT {
4957dd7cddfSDavid du Colombier 			code = clist_copy_alpha(dev, row, dx,
4967dd7cddfSDavid du Colombier 						raster, gx_no_bitmap_id, x, y,
4977dd7cddfSDavid du Colombier 						w2, 1, color, depth);
4987dd7cddfSDavid du Colombier 			if (code >= 0)
4997dd7cddfSDavid du Colombier 			    code = clist_copy_alpha(dev, row, dx + w2,
5007dd7cddfSDavid du Colombier 						    raster, gx_no_bitmap_id,
5017dd7cddfSDavid du Colombier 						    x + w2, y, w1 - w2, 1,
5027dd7cddfSDavid du Colombier 						    color, depth);
5037dd7cddfSDavid du Colombier 		    } UNNEST_RECT;
5047dd7cddfSDavid du Colombier 		    if (code < 0)
5057dd7cddfSDavid du Colombier 			ERROR_RECT(code);
5067dd7cddfSDavid du Colombier 		    continue;
5077dd7cddfSDavid du Colombier 		}
5087dd7cddfSDavid du Colombier 	    }
5097dd7cddfSDavid du Colombier 	    op += compress;
5107dd7cddfSDavid du Colombier 	    if (dx) {
5117dd7cddfSDavid du Colombier 		*dp++ = cmd_count_op(cmd_opv_set_misc, 2);
5127dd7cddfSDavid du Colombier 		*dp++ = cmd_set_misc_data_x + dx;
5137dd7cddfSDavid du Colombier 	    }
5147dd7cddfSDavid du Colombier 	    *dp++ = cmd_count_op(op, csize);
5157dd7cddfSDavid du Colombier 	    *dp++ = depth;
5167dd7cddfSDavid du Colombier 	    cmd_put2w(x, y, dp);
5177dd7cddfSDavid du Colombier 	    cmd_put2w(w1, height, dp);
5187dd7cddfSDavid du Colombier 	    pcls->rect = rect;
5197dd7cddfSDavid du Colombier 	}
5207dd7cddfSDavid du Colombier     } END_RECTS;
5217dd7cddfSDavid du Colombier     return 0;
5227dd7cddfSDavid du Colombier }
5237dd7cddfSDavid du Colombier 
5247dd7cddfSDavid du Colombier 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)5257dd7cddfSDavid du Colombier clist_strip_copy_rop(gx_device * dev,
5267dd7cddfSDavid du Colombier 	     const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
5277dd7cddfSDavid du Colombier 		     const gx_color_index * scolors,
5287dd7cddfSDavid du Colombier 	   const gx_strip_bitmap * textures, const gx_color_index * tcolors,
5297dd7cddfSDavid du Colombier 		     int x, int y, int width, int height,
5307dd7cddfSDavid du Colombier 		     int phase_x, int phase_y, gs_logical_operation_t lop)
5317dd7cddfSDavid du Colombier {
5327dd7cddfSDavid du Colombier     gx_device_clist_writer * const cdev =
5337dd7cddfSDavid du Colombier 	&((gx_device_clist *)dev)->writer;
5347dd7cddfSDavid du Colombier     gs_rop3_t rop = lop_rop(lop);
5357dd7cddfSDavid du Colombier     gx_strip_bitmap tile_with_id;
5367dd7cddfSDavid du Colombier     const gx_strip_bitmap *tiles = textures;
5377dd7cddfSDavid du Colombier     int y0;
5387dd7cddfSDavid du Colombier     /* Compute the set of possible colors that this operation can generate. */
5397dd7cddfSDavid du Colombier     gx_color_index all = ((gx_color_index)1 << dev->color_info.depth) - 1;
5407dd7cddfSDavid du Colombier     bool subtractive = dev->color_info.num_components == 4; /****** HACK ******/
5417dd7cddfSDavid du Colombier     gx_color_index S =
5427dd7cddfSDavid du Colombier 	(scolors ? scolors[0] | scolors[1] : sdata ? all : 0);
5437dd7cddfSDavid du Colombier     gx_color_index T =
5447dd7cddfSDavid du Colombier 	(tcolors ? tcolors[0] | tcolors[1] : textures ? all : 0);
5457dd7cddfSDavid du Colombier     gs_rop3_t color_rop =
5467dd7cddfSDavid du Colombier 	(subtractive ? byte_reverse_bits[rop ^ 0xff] : rop);
5477dd7cddfSDavid du Colombier     bool slow_rop;
5487dd7cddfSDavid du Colombier 
5497dd7cddfSDavid du Colombier     if (scolors != 0 && scolors[0] != scolors[1]) {
5507dd7cddfSDavid du Colombier 	fit_fill(dev, x, y, width, height);
5517dd7cddfSDavid du Colombier     } else {
5527dd7cddfSDavid du Colombier 	fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
5537dd7cddfSDavid du Colombier     }
5547dd7cddfSDavid du Colombier     /*
5557dd7cddfSDavid du Colombier      * On CMYK devices, RasterOps must be executed with complete pixels
5567dd7cddfSDavid du Colombier      * if the operation involves the destination.
5577dd7cddfSDavid du Colombier      * This is because the black plane interacts with the other planes
5587dd7cddfSDavid du Colombier      * in the conversion between RGB and CMYK.  Check for this now.
5597dd7cddfSDavid du Colombier      */
5607dd7cddfSDavid du Colombier     {
5617dd7cddfSDavid du Colombier 	gs_rop3_t rop_used = rop;
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier 	if (scolors && (scolors[0] == scolors[1]))
5647dd7cddfSDavid du Colombier 	    rop_used = (scolors[0] == gx_device_black(dev) ?
5657dd7cddfSDavid du Colombier 			rop3_know_S_0(rop_used) :
5667dd7cddfSDavid du Colombier 			scolors[0] == gx_device_white(dev) ?
5677dd7cddfSDavid du Colombier 			rop3_know_S_1(rop_used) : rop_used);
5687dd7cddfSDavid du Colombier 	if (tcolors && (tcolors[0] == tcolors[1]))
5697dd7cddfSDavid du Colombier 	    rop_used = (tcolors[0] == gx_device_black(dev) ?
5707dd7cddfSDavid du Colombier 			rop3_know_T_0(rop_used) :
5717dd7cddfSDavid du Colombier 			tcolors[0] == gx_device_white(dev) ?
5727dd7cddfSDavid du Colombier 			rop3_know_T_1(rop_used) : rop_used);
5737dd7cddfSDavid du Colombier 	slow_rop = !(rop == rop3_0 || rop == rop3_1 ||
5747dd7cddfSDavid du Colombier 		     rop == rop3_D || rop == rop3_S || rop == rop3_T);
5757dd7cddfSDavid du Colombier     }
5767dd7cddfSDavid du Colombier     y0 = y;
5777dd7cddfSDavid du Colombier     /*
5787dd7cddfSDavid du Colombier      * We shouldn't need to put the logic below inside FOR/END_RECTS,
5797dd7cddfSDavid du Colombier      * but the lop_enabled flags are per-band.
5807dd7cddfSDavid du Colombier      */
5817dd7cddfSDavid du Colombier     FOR_RECTS {
5827dd7cddfSDavid du Colombier 	const byte *row = sdata + (y - y0) * sraster;
5837dd7cddfSDavid du Colombier 	gx_color_index D = pcls->colors_used.or;
5847dd7cddfSDavid du Colombier 	int code;
5857dd7cddfSDavid du Colombier 
586*593dc095SDavid du Colombier 	/* Reducing D, S, T to rop_operand (which apparently is 32 bit) appears safe
587*593dc095SDavid du Colombier 	   due to 'all' a has smaller snumber of significant bits. */
5887dd7cddfSDavid du Colombier 	pcls->colors_used.or =
589*593dc095SDavid du Colombier 	    ((rop_proc_table[color_rop])((rop_operand)D, (rop_operand)S, (rop_operand)T) & all) | D;
5907dd7cddfSDavid du Colombier 	pcls->colors_used.slow_rop |= slow_rop;
5917dd7cddfSDavid du Colombier 	if (rop3_uses_T(rop)) {
5927dd7cddfSDavid du Colombier 	    if (tcolors == 0 || tcolors[0] != tcolors[1]) {
5937dd7cddfSDavid du Colombier 		ulong offset_temp;
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier 		if (!cls_has_tile_id(cdev, pcls, tiles->id, offset_temp)) {
5967dd7cddfSDavid du Colombier 		    /* Change tile.  If there is no id, generate one. */
5977dd7cddfSDavid du Colombier 		    if (tiles->id == gx_no_bitmap_id) {
5987dd7cddfSDavid du Colombier 			tile_with_id = *tiles;
599*593dc095SDavid du Colombier 			tile_with_id.id = gs_next_ids(dev->memory, 1);
6007dd7cddfSDavid du Colombier 			tiles = &tile_with_id;
6017dd7cddfSDavid du Colombier 		    }
6027dd7cddfSDavid du Colombier 		    TRY_RECT {
6037dd7cddfSDavid du Colombier 			code = clist_change_tile(cdev, pcls, tiles,
6047dd7cddfSDavid du Colombier 						 (tcolors != 0 ? 1 :
6057dd7cddfSDavid du Colombier 						  dev->color_info.depth));
6067dd7cddfSDavid du Colombier 		    } HANDLE_RECT_UNLESS(code, code == gs_error_limitcheck);
6077dd7cddfSDavid du Colombier 		    if (code < 0) {
6087dd7cddfSDavid du Colombier 			/*
6097dd7cddfSDavid du Colombier 			 * The error is a limitcheck: we have a tile that
6107dd7cddfSDavid du Colombier 			 * is too big to fit in the command reading buffer.
6117dd7cddfSDavid du Colombier 			 * For now, just divide up the transfer into scan
6127dd7cddfSDavid du Colombier 			 * lines.  (If a single scan line won't fit, punt.)
6137dd7cddfSDavid du Colombier 			 * Eventually, we'll need a way to transfer the tile
6147dd7cddfSDavid du Colombier 			 * in pieces.
6157dd7cddfSDavid du Colombier 			 */
6167dd7cddfSDavid du Colombier 			uint rep_height = tiles->rep_height;
6177dd7cddfSDavid du Colombier 			gs_id ids;
6187dd7cddfSDavid du Colombier 			gx_strip_bitmap line_tile;
6197dd7cddfSDavid du Colombier 			int iy;
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 			if (rep_height == 1 ||
6227dd7cddfSDavid du Colombier 			    /****** CAN'T HANDLE SHIFT YET ******/
6237dd7cddfSDavid du Colombier 			    tiles->rep_shift != 0
6247dd7cddfSDavid du Colombier 			    )
6257dd7cddfSDavid du Colombier 			    return code;
6267dd7cddfSDavid du Colombier 			/*
6277dd7cddfSDavid du Colombier 			 * Allocate enough fake IDs, since the inner call on
6287dd7cddfSDavid du Colombier 			 * clist_strip_copy_rop will need them anyway.
6297dd7cddfSDavid du Colombier 			 */
630*593dc095SDavid du Colombier 			ids = gs_next_ids(dev->memory, min(height, rep_height));
6317dd7cddfSDavid du Colombier 			line_tile = *tiles;
6327dd7cddfSDavid du Colombier 			line_tile.size.y = 1;
6337dd7cddfSDavid du Colombier 			line_tile.rep_height = 1;
6347dd7cddfSDavid du Colombier 			for (iy = 0; iy < height; ++iy) {
6357dd7cddfSDavid du Colombier 			    line_tile.data = tiles->data + line_tile.raster *
6367dd7cddfSDavid du Colombier 				((y + iy + phase_y) % rep_height);
6377dd7cddfSDavid du Colombier 			    line_tile.id = ids + (iy % rep_height);
6387dd7cddfSDavid du Colombier 			    /*
6397dd7cddfSDavid du Colombier 			     * Note that since we're only transferring
6407dd7cddfSDavid du Colombier 			     * a single scan line, phase_y is irrelevant;
6417dd7cddfSDavid du Colombier 			     * we may as well use the current tile phase
6427dd7cddfSDavid du Colombier 			     * so we don't have to write extra commands.
6437dd7cddfSDavid du Colombier 			     */
6447dd7cddfSDavid du Colombier 			    NEST_RECT {
6457dd7cddfSDavid du Colombier 				code = clist_strip_copy_rop(dev,
6467dd7cddfSDavid du Colombier 					(sdata == 0 ? 0 : row + iy * sraster),
6477dd7cddfSDavid du Colombier 					sourcex, sraster,
6487dd7cddfSDavid du Colombier 					gx_no_bitmap_id, scolors,
6497dd7cddfSDavid du Colombier 					&line_tile, tcolors,
6507dd7cddfSDavid du Colombier 					x, y + iy, width, 1,
6517dd7cddfSDavid du Colombier 					phase_x, pcls->tile_phase.y, lop);
6527dd7cddfSDavid du Colombier 			    } UNNEST_RECT;
6537dd7cddfSDavid du Colombier 			    if (code < 0)
6547dd7cddfSDavid du Colombier 				ERROR_RECT(code);
6557dd7cddfSDavid du Colombier 			}
6567dd7cddfSDavid du Colombier 			continue;
6577dd7cddfSDavid du Colombier 		    }
6587dd7cddfSDavid du Colombier 		    if (phase_x != pcls->tile_phase.x ||
6597dd7cddfSDavid du Colombier 			phase_y != pcls->tile_phase.y
6607dd7cddfSDavid du Colombier 			) {
6617dd7cddfSDavid du Colombier 			TRY_RECT {
6627dd7cddfSDavid du Colombier 			    code = cmd_set_tile_phase(cdev, pcls, phase_x,
6637dd7cddfSDavid du Colombier 						      phase_y);
6647dd7cddfSDavid du Colombier 			} HANDLE_RECT(code);
6657dd7cddfSDavid du Colombier 		    }
6667dd7cddfSDavid du Colombier 		}
6677dd7cddfSDavid du Colombier 	    }
6687dd7cddfSDavid du Colombier 	    /* Set the tile colors. */
6697dd7cddfSDavid du Colombier 	    TRY_RECT {
6707dd7cddfSDavid du Colombier 		code =
6717dd7cddfSDavid du Colombier 		    (tcolors != 0 ?
6727dd7cddfSDavid du Colombier 		     cmd_set_tile_colors(cdev, pcls, tcolors[0], tcolors[1]) :
6737dd7cddfSDavid du Colombier 		     cmd_set_tile_colors(cdev, pcls, gx_no_color_index,
6747dd7cddfSDavid du Colombier 					 gx_no_color_index));
6757dd7cddfSDavid du Colombier 	    } HANDLE_RECT(code);
6767dd7cddfSDavid du Colombier 	}
6777dd7cddfSDavid du Colombier 	TRY_RECT {
6787dd7cddfSDavid du Colombier 	    code = 0;
6797dd7cddfSDavid du Colombier 	    if (lop != pcls->lop)
6807dd7cddfSDavid du Colombier 		code = cmd_set_lop(cdev, pcls, lop);
6817dd7cddfSDavid du Colombier 	    if (code >= 0)
6827dd7cddfSDavid du Colombier 		code = cmd_enable_lop(cdev, pcls);
6837dd7cddfSDavid du Colombier 	} HANDLE_RECT(code);
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier 	/* Set lop_enabled to -1 so that fill_rectangle / copy_* */
6867dd7cddfSDavid du Colombier 	/* won't attempt to set it to 0. */
6877dd7cddfSDavid du Colombier 	pcls->lop_enabled = -1;
6887dd7cddfSDavid du Colombier 	NEST_RECT {
6897dd7cddfSDavid du Colombier 	    if (scolors != 0) {
6907dd7cddfSDavid du Colombier 		if (scolors[0] == scolors[1])
6917dd7cddfSDavid du Colombier 		    code = clist_fill_rectangle(dev, x, y, width, height,
6927dd7cddfSDavid du Colombier 						scolors[1]);
6937dd7cddfSDavid du Colombier 		else
6947dd7cddfSDavid du Colombier 		    code = clist_copy_mono(dev, row, sourcex, sraster, id,
6957dd7cddfSDavid du Colombier 					   x, y, width, height,
6967dd7cddfSDavid du Colombier 					   scolors[0], scolors[1]);
6977dd7cddfSDavid du Colombier 	    } else
6987dd7cddfSDavid du Colombier 		code = clist_copy_color(dev, row, sourcex, sraster, id,
6997dd7cddfSDavid du Colombier 					x, y, width, height);
7007dd7cddfSDavid du Colombier 	} UNNEST_RECT;
7017dd7cddfSDavid du Colombier 	pcls->lop_enabled = 1;
7027dd7cddfSDavid du Colombier 	if (code < 0)
7037dd7cddfSDavid du Colombier 	    ERROR_RECT(code);
7047dd7cddfSDavid du Colombier     } END_RECTS;
7057dd7cddfSDavid du Colombier     return 0;
7067dd7cddfSDavid du Colombier }
707