xref: /plan9/sys/src/cmd/gs/src/gdevm1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1989, 1995, 1996, 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: gdevm1.c,v 1.6 2002/10/07 08:28:56 ghostgum Exp $ */
187dd7cddfSDavid du Colombier /* Monobit "memory" (stored bitmap) device */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gxdevice.h"
227dd7cddfSDavid du Colombier #include "gxdevmem.h"		/* semi-public definitions */
237dd7cddfSDavid du Colombier #include "gdevmem.h"		/* private definitions */
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier /* Optionally, use the slow RasterOp implementations for testing. */
267dd7cddfSDavid du Colombier /*#define USE_COPY_ROP */
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier #ifdef USE_COPY_ROP
297dd7cddfSDavid du Colombier #include "gsrop.h"
307dd7cddfSDavid du Colombier #endif
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /* ================ Standard (byte-oriented) device ================ */
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier /* Procedures */
357dd7cddfSDavid du Colombier private dev_proc_map_rgb_color(mem_mono_map_rgb_color);
367dd7cddfSDavid du Colombier private dev_proc_map_color_rgb(mem_mono_map_color_rgb);
377dd7cddfSDavid du Colombier private dev_proc_copy_mono(mem_mono_copy_mono);
387dd7cddfSDavid du Colombier private dev_proc_fill_rectangle(mem_mono_fill_rectangle);
397dd7cddfSDavid du Colombier private dev_proc_strip_tile_rectangle(mem_mono_strip_tile_rectangle);
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier /* The device descriptor. */
427dd7cddfSDavid du Colombier /* The instance is public. */
437dd7cddfSDavid du Colombier const gx_device_memory mem_mono_device =
447dd7cddfSDavid du Colombier mem_full_alpha_device("image1", 0, 1, mem_open,
457dd7cddfSDavid du Colombier 		      mem_mono_map_rgb_color, mem_mono_map_color_rgb,
467dd7cddfSDavid du Colombier 	 mem_mono_copy_mono, gx_default_copy_color, mem_mono_fill_rectangle,
477dd7cddfSDavid du Colombier 		      gx_default_map_cmyk_color, gx_no_copy_alpha,
487dd7cddfSDavid du Colombier 		      mem_mono_strip_tile_rectangle, mem_mono_strip_copy_rop,
497dd7cddfSDavid du Colombier 		      mem_get_bits_rectangle);
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier /* Map color to/from RGB.  This may be inverted. */
527dd7cddfSDavid du Colombier private gx_color_index
mem_mono_map_rgb_color(gx_device * dev,const gx_color_value cv[])53*593dc095SDavid du Colombier mem_mono_map_rgb_color(gx_device * dev, const gx_color_value cv[])
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
56*593dc095SDavid du Colombier     return (gx_default_w_b_map_rgb_color(dev, cv) ^ mdev->palette.data[0]) & 1;
577dd7cddfSDavid du Colombier }
58*593dc095SDavid du Colombier 
597dd7cddfSDavid du Colombier private int
mem_mono_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])607dd7cddfSDavid du Colombier mem_mono_map_color_rgb(gx_device * dev, gx_color_index color,
617dd7cddfSDavid du Colombier 		       gx_color_value prgb[3])
627dd7cddfSDavid du Colombier {
637dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
64*593dc095SDavid du Colombier     /* NB code doesn't make sense... map_color_rgb procedures return an error code */
65*593dc095SDavid du Colombier     return (gx_default_w_b_map_color_rgb(dev, color, prgb) ^ mdev->palette.data[0]) & 1;
667dd7cddfSDavid du Colombier }
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier /* Fill a rectangle with a color. */
697dd7cddfSDavid du Colombier private int
mem_mono_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)707dd7cddfSDavid du Colombier mem_mono_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
717dd7cddfSDavid du Colombier 			gx_color_index color)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier #ifdef USE_COPY_ROP
767dd7cddfSDavid du Colombier     return mem_mono_copy_rop(dev, NULL, 0, 0, gx_no_bitmap_id, NULL,
777dd7cddfSDavid du Colombier 			     NULL, NULL,
787dd7cddfSDavid du Colombier 			     x, y, w, h, 0, 0,
797dd7cddfSDavid du Colombier 			     (color ? rop3_1 : rop3_0));
807dd7cddfSDavid du Colombier #else
817dd7cddfSDavid du Colombier     fit_fill(dev, x, y, w, h);
827dd7cddfSDavid du Colombier     bits_fill_rectangle(scan_line_base(mdev, y), x, mdev->raster,
83*593dc095SDavid du Colombier 			-(int)(mono_fill_chunk) color, w, h);
847dd7cddfSDavid du Colombier     return 0;
857dd7cddfSDavid du Colombier #endif
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier /* Convert x coordinate to byte offset in scan line. */
897dd7cddfSDavid du Colombier #define x_to_byte(x) ((x) >> 3)
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier /* Copy a monochrome bitmap. */
927dd7cddfSDavid du Colombier #undef mono_masks
937dd7cddfSDavid du Colombier #define mono_masks mono_copy_masks
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier /*
967dd7cddfSDavid du Colombier  * Fetch a chunk from the source.
977dd7cddfSDavid du Colombier  *
987dd7cddfSDavid du Colombier  * Since source and destination are both always big-endian,
997dd7cddfSDavid du Colombier  * fetching an aligned chunk never requires byte swapping.
1007dd7cddfSDavid du Colombier  */
1017dd7cddfSDavid du Colombier #define CFETCH_ALIGNED(cptr)\
1027dd7cddfSDavid du Colombier   (*(const chunk *)(cptr))
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier /*
1057dd7cddfSDavid du Colombier  * Note that the macros always cast cptr,
1067dd7cddfSDavid du Colombier  * so it doesn't matter what the type of cptr is.
1077dd7cddfSDavid du Colombier  */
1087dd7cddfSDavid du Colombier /* cshift = chunk_bits - shift. */
1097dd7cddfSDavid du Colombier #undef chunk
1107dd7cddfSDavid du Colombier #if arch_is_big_endian
1117dd7cddfSDavid du Colombier #  define chunk uint
1127dd7cddfSDavid du Colombier #  define CFETCH_RIGHT(cptr, shift, cshift)\
1137dd7cddfSDavid du Colombier 	(CFETCH_ALIGNED(cptr) >> shift)
1147dd7cddfSDavid du Colombier #  define CFETCH_LEFT(cptr, shift, cshift)\
1157dd7cddfSDavid du Colombier 	(CFETCH_ALIGNED(cptr) << shift)
1167dd7cddfSDavid du Colombier #  define CFETCH_USES_CSKEW 0
1177dd7cddfSDavid du Colombier /* Fetch a chunk that straddles a chunk boundary. */
1187dd7cddfSDavid du Colombier #  define CFETCH2(cptr, cskew, skew)\
1197dd7cddfSDavid du Colombier     (CFETCH_LEFT(cptr, cskew, skew) +\
1207dd7cddfSDavid du Colombier      CFETCH_RIGHT((const chunk *)(cptr) + 1, skew, cskew))
1217dd7cddfSDavid du Colombier #else /* little-endian */
1227dd7cddfSDavid du Colombier #  define chunk bits16
1237dd7cddfSDavid du Colombier private const bits16 right_masks2[9] =
1247dd7cddfSDavid du Colombier {
1257dd7cddfSDavid du Colombier     0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0x0f0f, 0x0707, 0x0303, 0x0101, 0x0000
1267dd7cddfSDavid du Colombier };
1277dd7cddfSDavid du Colombier private const bits16 left_masks2[9] =
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier     0xffff, 0xfefe, 0xfcfc, 0xf8f8, 0xf0f0, 0xe0e0, 0xc0c0, 0x8080, 0x0000
1307dd7cddfSDavid du Colombier };
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier #  define CCONT(cptr, off) (((const chunk *)(cptr))[off])
1337dd7cddfSDavid du Colombier #  define CFETCH_RIGHT(cptr, shift, cshift)\
1347dd7cddfSDavid du Colombier 	((shift) < 8 ?\
1357dd7cddfSDavid du Colombier 	 ((CCONT(cptr, 0) >> (shift)) & right_masks2[shift]) +\
1367dd7cddfSDavid du Colombier 	  (CCONT(cptr, 0) << (cshift)) :\
1377dd7cddfSDavid du Colombier 	 ((chunk)*(const byte *)(cptr) << (cshift)) & 0xff00)
1387dd7cddfSDavid du Colombier #  define CFETCH_LEFT(cptr, shift, cshift)\
1397dd7cddfSDavid du Colombier 	((shift) < 8 ?\
1407dd7cddfSDavid du Colombier 	 ((CCONT(cptr, 0) << (shift)) & left_masks2[shift]) +\
1417dd7cddfSDavid du Colombier 	  (CCONT(cptr, 0) >> (cshift)) :\
1427dd7cddfSDavid du Colombier 	 ((CCONT(cptr, 0) & 0xff00) >> (cshift)) & 0xff)
1437dd7cddfSDavid du Colombier #  define CFETCH_USES_CSKEW 1
1447dd7cddfSDavid du Colombier /* Fetch a chunk that straddles a chunk boundary. */
1457dd7cddfSDavid du Colombier /* We can avoid testing the shift amount twice */
1467dd7cddfSDavid du Colombier /* by expanding the CFETCH_LEFT/right macros in-line. */
1477dd7cddfSDavid du Colombier #  define CFETCH2(cptr, cskew, skew)\
1487dd7cddfSDavid du Colombier 	((cskew) < 8 ?\
1497dd7cddfSDavid du Colombier 	 ((CCONT(cptr, 0) << (cskew)) & left_masks2[cskew]) +\
1507dd7cddfSDavid du Colombier 	  (CCONT(cptr, 0) >> (skew)) +\
1517dd7cddfSDavid du Colombier 	  (((chunk)(((const byte *)(cptr))[2]) << (cskew)) & 0xff00) :\
1527dd7cddfSDavid du Colombier 	 (((CCONT(cptr, 0) & 0xff00) >> (skew)) & 0xff) +\
1537dd7cddfSDavid du Colombier 	  ((CCONT(cptr, 1) >> (skew)) & right_masks2[skew]) +\
1547dd7cddfSDavid du Colombier 	   (CCONT(cptr, 1) << (cskew)))
1557dd7cddfSDavid du Colombier #endif
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier typedef enum {
1587dd7cddfSDavid du Colombier     COPY_OR = 0, COPY_STORE, COPY_AND, COPY_FUNNY
1597dd7cddfSDavid du Colombier } copy_function;
1607dd7cddfSDavid du Colombier typedef struct {
1617dd7cddfSDavid du Colombier     int invert;
1627dd7cddfSDavid du Colombier     copy_function op;
1637dd7cddfSDavid du Colombier } copy_mode;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier /*
1667dd7cddfSDavid du Colombier  * Map from <color0,color1> to copy_mode.
1677dd7cddfSDavid du Colombier  * Logically, this is a 2-D array.
1687dd7cddfSDavid du Colombier  * The indexing is (transparent, 0, 1, unused). */
1697dd7cddfSDavid du Colombier private const copy_mode copy_modes[16] = {
1707dd7cddfSDavid du Colombier     {~0, COPY_FUNNY},		/* NN */
1717dd7cddfSDavid du Colombier     {~0, COPY_AND},		/* N0 */
1727dd7cddfSDavid du Colombier     {0, COPY_OR},		/* N1 */
1737dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1747dd7cddfSDavid du Colombier     {0, COPY_AND},		/* 0N */
1757dd7cddfSDavid du Colombier     {0, COPY_FUNNY},		/* 00 */
1767dd7cddfSDavid du Colombier     {0, COPY_STORE},		/* 01 */
1777dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1787dd7cddfSDavid du Colombier     {~0, COPY_OR},		/* 1N */
1797dd7cddfSDavid du Colombier     {~0, COPY_STORE},		/* 10 */
1807dd7cddfSDavid du Colombier     {0, COPY_FUNNY},		/* 11 */
1817dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1827dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1837dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1847dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1857dd7cddfSDavid du Colombier     {0, 0},			/* unused */
1867dd7cddfSDavid du Colombier };
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier /* Handle the funny cases that aren't supposed to happen. */
1897dd7cddfSDavid du Colombier #define FUNNY_CASE()\
1907dd7cddfSDavid du Colombier   (invert ? gs_note_error(-1) :\
1917dd7cddfSDavid du Colombier    mem_mono_fill_rectangle(dev, x, y, w, h, color0))
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier private int
mem_mono_copy_mono(gx_device * dev,const byte * source_data,int source_x,int source_raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)1947dd7cddfSDavid du Colombier mem_mono_copy_mono(gx_device * dev,
1957dd7cddfSDavid du Colombier  const byte * source_data, int source_x, int source_raster, gx_bitmap_id id,
1967dd7cddfSDavid du Colombier    int x, int y, int w, int h, gx_color_index color0, gx_color_index color1)
1977dd7cddfSDavid du Colombier {
1987dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier #ifdef USE_COPY_ROP
2017dd7cddfSDavid du Colombier     return mem_mono_copy_rop(dev, source_data, source_x, source_raster,
2027dd7cddfSDavid du Colombier 			     id, NULL, NULL, NULL,
2037dd7cddfSDavid du Colombier 			     x, y, w, h, 0, 0,
2047dd7cddfSDavid du Colombier 			     ((color0 == gx_no_color_index ? rop3_D :
2057dd7cddfSDavid du Colombier 			       color0 == 0 ? rop3_0 : rop3_1) & ~rop3_S) |
2067dd7cddfSDavid du Colombier 			     ((color1 == gx_no_color_index ? rop3_D :
2077dd7cddfSDavid du Colombier 			       color1 == 0 ? rop3_0 : rop3_1) & rop3_S));
2087dd7cddfSDavid du Colombier #else /* !USE_COPY_ROP */
2097dd7cddfSDavid du Colombier     register const byte *bptr;	/* actually chunk * */
2107dd7cddfSDavid du Colombier     int dbit, wleft;
2117dd7cddfSDavid du Colombier     uint mask;
2127dd7cddfSDavid du Colombier     copy_mode mode;
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier     DECLARE_SCAN_PTR_VARS(dbptr, byte *, dest_raster);
2157dd7cddfSDavid du Colombier #define optr ((chunk *)dbptr)
2167dd7cddfSDavid du Colombier     register int skew;
2177dd7cddfSDavid du Colombier     register uint invert;
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier     fit_copy(dev, source_data, source_x, source_raster, id, x, y, w, h);
2207dd7cddfSDavid du Colombier #if gx_no_color_index_value != -1	/* hokey! */
2217dd7cddfSDavid du Colombier     if (color0 == gx_no_color_index)
2227dd7cddfSDavid du Colombier 	color0 = -1;
2237dd7cddfSDavid du Colombier     if (color1 == gx_no_color_index)
2247dd7cddfSDavid du Colombier 	color1 = -1;
2257dd7cddfSDavid du Colombier #endif
2267dd7cddfSDavid du Colombier     mode = copy_modes[((int)color0 << 2) + (int)color1 + 5];
2277dd7cddfSDavid du Colombier     invert = (uint)mode.invert;	/* load register */
2287dd7cddfSDavid du Colombier     SETUP_RECT_VARS(dbptr, byte *, dest_raster);
2297dd7cddfSDavid du Colombier     bptr = source_data + ((source_x & ~chunk_align_bit_mask) >> 3);
2307dd7cddfSDavid du Colombier     dbit = x & chunk_align_bit_mask;
2317dd7cddfSDavid du Colombier     skew = dbit - (source_x & chunk_align_bit_mask);
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier /* Macros for writing partial chunks. */
2347dd7cddfSDavid du Colombier /* The destination pointer is always named optr, */
2357dd7cddfSDavid du Colombier /* and must be declared as chunk *. */
2367dd7cddfSDavid du Colombier /* CINVERT may be temporarily redefined. */
2377dd7cddfSDavid du Colombier #define CINVERT(bits) ((bits) ^ invert)
2387dd7cddfSDavid du Colombier #define WRITE_OR_MASKED(bits, mask, off)\
2397dd7cddfSDavid du Colombier   optr[off] |= (CINVERT(bits) & mask)
2407dd7cddfSDavid du Colombier #define WRITE_STORE_MASKED(bits, mask, off)\
2417dd7cddfSDavid du Colombier   optr[off] = ((optr[off] & ~mask) | (CINVERT(bits) & mask))
2427dd7cddfSDavid du Colombier #define WRITE_AND_MASKED(bits, mask, off)\
2437dd7cddfSDavid du Colombier   optr[off] &= (CINVERT(bits) | ~mask)
2447dd7cddfSDavid du Colombier /* Macros for writing full chunks. */
2457dd7cddfSDavid du Colombier #define WRITE_OR(bits)  *optr |= CINVERT(bits)
2467dd7cddfSDavid du Colombier #define WRITE_STORE(bits) *optr = CINVERT(bits)
2477dd7cddfSDavid du Colombier #define WRITE_AND(bits) *optr &= CINVERT(bits)
2487dd7cddfSDavid du Colombier /* Macro for incrementing to next chunk. */
2497dd7cddfSDavid du Colombier #define NEXT_X_CHUNK()\
2507dd7cddfSDavid du Colombier   bptr += chunk_bytes; dbptr += chunk_bytes
2517dd7cddfSDavid du Colombier /* Common macro for the end of each scan line. */
2527dd7cddfSDavid du Colombier #define END_Y_LOOP(sdelta, ddelta)\
2537dd7cddfSDavid du Colombier   bptr += sdelta; dbptr += ddelta
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier     if ((wleft = w + dbit - chunk_bits) <= 0) {		/* The entire operation fits in one (destination) chunk. */
2567dd7cddfSDavid du Colombier 	set_mono_thin_mask(mask, w, dbit);
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier #define WRITE_SINGLE(wr_op, src)\
2597dd7cddfSDavid du Colombier   for ( ; ; )\
2607dd7cddfSDavid du Colombier    { wr_op(src, mask, 0);\
2617dd7cddfSDavid du Colombier      if ( --h == 0 ) break;\
2627dd7cddfSDavid du Colombier      END_Y_LOOP(source_raster, dest_raster);\
2637dd7cddfSDavid du Colombier    }
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier #define WRITE1_LOOP(src)\
2667dd7cddfSDavid du Colombier   switch ( mode.op ) {\
2677dd7cddfSDavid du Colombier     case COPY_OR: WRITE_SINGLE(WRITE_OR_MASKED, src); break;\
2687dd7cddfSDavid du Colombier     case COPY_STORE: WRITE_SINGLE(WRITE_STORE_MASKED, src); break;\
2697dd7cddfSDavid du Colombier     case COPY_AND: WRITE_SINGLE(WRITE_AND_MASKED, src); break;\
2707dd7cddfSDavid du Colombier     default: return FUNNY_CASE();\
2717dd7cddfSDavid du Colombier   }
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	if (skew >= 0) {	/* single -> single, right/no shift */
2747dd7cddfSDavid du Colombier 	    if (skew == 0) {	/* no shift */
2757dd7cddfSDavid du Colombier 		WRITE1_LOOP(CFETCH_ALIGNED(bptr));
2767dd7cddfSDavid du Colombier 	    } else {		/* right shift */
2777dd7cddfSDavid du Colombier #if CFETCH_USES_CSKEW
2787dd7cddfSDavid du Colombier 		int cskew = chunk_bits - skew;
2797dd7cddfSDavid du Colombier #endif
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 		WRITE1_LOOP(CFETCH_RIGHT(bptr, skew, cskew));
2827dd7cddfSDavid du Colombier 	    }
2837dd7cddfSDavid du Colombier 	} else if (wleft <= skew) {	/* single -> single, left shift */
2847dd7cddfSDavid du Colombier #if CFETCH_USES_CSKEW
2857dd7cddfSDavid du Colombier 	    int cskew = chunk_bits + skew;
2867dd7cddfSDavid du Colombier #endif
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier 	    skew = -skew;
2897dd7cddfSDavid du Colombier 	    WRITE1_LOOP(CFETCH_LEFT(bptr, skew, cskew));
2907dd7cddfSDavid du Colombier 	} else {		/* double -> single */
2917dd7cddfSDavid du Colombier 	    int cskew = -skew;
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	    skew += chunk_bits;
2947dd7cddfSDavid du Colombier 	    WRITE1_LOOP(CFETCH2(bptr, cskew, skew));
2957dd7cddfSDavid du Colombier 	}
2967dd7cddfSDavid du Colombier #undef WRITE1_LOOP
2977dd7cddfSDavid du Colombier #undef WRITE_SINGLE
2987dd7cddfSDavid du Colombier     } else if (wleft <= skew) {	/* 1 source chunk -> 2 destination chunks. */
2997dd7cddfSDavid du Colombier 	/* This is an important special case for */
3007dd7cddfSDavid du Colombier 	/* both characters and halftone tiles. */
3017dd7cddfSDavid du Colombier 	uint rmask;
3027dd7cddfSDavid du Colombier 	int cskew = chunk_bits - skew;
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	set_mono_left_mask(mask, dbit);
3057dd7cddfSDavid du Colombier 	set_mono_right_mask(rmask, wleft);
3067dd7cddfSDavid du Colombier #undef CINVERT
3077dd7cddfSDavid du Colombier #define CINVERT(bits) (bits)	/* pre-inverted here */
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier #if arch_is_big_endian		/* no byte swapping */
3107dd7cddfSDavid du Colombier #  define WRITE_1TO2(wr_op)\
3117dd7cddfSDavid du Colombier   for ( ; ; )\
3127dd7cddfSDavid du Colombier    { register uint bits = CFETCH_ALIGNED(bptr) ^ invert;\
3137dd7cddfSDavid du Colombier      wr_op(bits >> skew, mask, 0);\
3147dd7cddfSDavid du Colombier      wr_op(bits << cskew, rmask, 1);\
3157dd7cddfSDavid du Colombier      if ( --h == 0 ) break;\
3167dd7cddfSDavid du Colombier      END_Y_LOOP(source_raster, dest_raster);\
3177dd7cddfSDavid du Colombier    }
3187dd7cddfSDavid du Colombier #else /* byte swapping */
3197dd7cddfSDavid du Colombier #  define WRITE_1TO2(wr_op)\
3207dd7cddfSDavid du Colombier   for ( ; ; )\
3217dd7cddfSDavid du Colombier    { wr_op(CFETCH_RIGHT(bptr, skew, cskew) ^ invert, mask, 0);\
3227dd7cddfSDavid du Colombier      wr_op(CFETCH_LEFT(bptr, cskew, skew) ^ invert, rmask, 1);\
3237dd7cddfSDavid du Colombier      if ( --h == 0 ) break;\
3247dd7cddfSDavid du Colombier      END_Y_LOOP(source_raster, dest_raster);\
3257dd7cddfSDavid du Colombier    }
3267dd7cddfSDavid du Colombier #endif
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier 	switch (mode.op) {
3297dd7cddfSDavid du Colombier 	    case COPY_OR:
3307dd7cddfSDavid du Colombier 		WRITE_1TO2(WRITE_OR_MASKED);
3317dd7cddfSDavid du Colombier 		break;
3327dd7cddfSDavid du Colombier 	    case COPY_STORE:
3337dd7cddfSDavid du Colombier 		WRITE_1TO2(WRITE_STORE_MASKED);
3347dd7cddfSDavid du Colombier 		break;
3357dd7cddfSDavid du Colombier 	    case COPY_AND:
3367dd7cddfSDavid du Colombier 		WRITE_1TO2(WRITE_AND_MASKED);
3377dd7cddfSDavid du Colombier 		break;
3387dd7cddfSDavid du Colombier 	    default:
3397dd7cddfSDavid du Colombier 		return FUNNY_CASE();
3407dd7cddfSDavid du Colombier 	}
3417dd7cddfSDavid du Colombier #undef CINVERT
3427dd7cddfSDavid du Colombier #define CINVERT(bits) ((bits) ^ invert)
3437dd7cddfSDavid du Colombier #undef WRITE_1TO2
3447dd7cddfSDavid du Colombier     } else {			/* More than one source chunk and more than one */
3457dd7cddfSDavid du Colombier 	/* destination chunk are involved. */
3467dd7cddfSDavid du Colombier 	uint rmask;
3477dd7cddfSDavid du Colombier 	int words = (wleft & ~chunk_bit_mask) >> 3;
3487dd7cddfSDavid du Colombier 	uint sskip = source_raster - words;
3497dd7cddfSDavid du Colombier 	uint dskip = dest_raster - words;
3507dd7cddfSDavid du Colombier 	register uint bits;
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	set_mono_left_mask(mask, dbit);
3537dd7cddfSDavid du Colombier 	set_mono_right_mask(rmask, wleft & chunk_bit_mask);
3547dd7cddfSDavid du Colombier 	if (skew == 0) {	/* optimize the aligned case */
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier #define WRITE_ALIGNED(wr_op, wr_op_masked)\
3577dd7cddfSDavid du Colombier   for ( ; ; )\
3587dd7cddfSDavid du Colombier    { int count = wleft;\
3597dd7cddfSDavid du Colombier      /* Do first partial chunk. */\
3607dd7cddfSDavid du Colombier      wr_op_masked(CFETCH_ALIGNED(bptr), mask, 0);\
3617dd7cddfSDavid du Colombier      /* Do full chunks. */\
3627dd7cddfSDavid du Colombier      while ( (count -= chunk_bits) >= 0 )\
3637dd7cddfSDavid du Colombier       { NEXT_X_CHUNK(); wr_op(CFETCH_ALIGNED(bptr)); }\
3647dd7cddfSDavid du Colombier      /* Do last chunk */\
3657dd7cddfSDavid du Colombier      if ( count > -chunk_bits )\
3667dd7cddfSDavid du Colombier       { wr_op_masked(CFETCH_ALIGNED(bptr + chunk_bytes), rmask, 1); }\
3677dd7cddfSDavid du Colombier      if ( --h == 0 ) break;\
3687dd7cddfSDavid du Colombier      END_Y_LOOP(sskip, dskip);\
3697dd7cddfSDavid du Colombier    }
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier 	    switch (mode.op) {
3727dd7cddfSDavid du Colombier 		case COPY_OR:
3737dd7cddfSDavid du Colombier 		    WRITE_ALIGNED(WRITE_OR, WRITE_OR_MASKED);
3747dd7cddfSDavid du Colombier 		    break;
3757dd7cddfSDavid du Colombier 		case COPY_STORE:
3767dd7cddfSDavid du Colombier 		    WRITE_ALIGNED(WRITE_STORE, WRITE_STORE_MASKED);
3777dd7cddfSDavid du Colombier 		    break;
3787dd7cddfSDavid du Colombier 		case COPY_AND:
3797dd7cddfSDavid du Colombier 		    WRITE_ALIGNED(WRITE_AND, WRITE_AND_MASKED);
3807dd7cddfSDavid du Colombier 		    break;
3817dd7cddfSDavid du Colombier 		default:
3827dd7cddfSDavid du Colombier 		    return FUNNY_CASE();
3837dd7cddfSDavid du Colombier 	    }
3847dd7cddfSDavid du Colombier #undef WRITE_ALIGNED
3857dd7cddfSDavid du Colombier 	} else {		/* not aligned */
3867dd7cddfSDavid du Colombier 	    int cskew = -skew & chunk_bit_mask;
3877dd7cddfSDavid du Colombier 	    bool case_right =
3887dd7cddfSDavid du Colombier 	    (skew >= 0 ? true :
3897dd7cddfSDavid du Colombier 	     ((bptr += chunk_bytes), false));
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	    skew &= chunk_bit_mask;
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier #define WRITE_UNALIGNED(wr_op, wr_op_masked)\
3947dd7cddfSDavid du Colombier   /* Prefetch partial word. */\
3957dd7cddfSDavid du Colombier   bits =\
3967dd7cddfSDavid du Colombier     (case_right ? CFETCH_RIGHT(bptr, skew, cskew) :\
3977dd7cddfSDavid du Colombier      CFETCH2(bptr - chunk_bytes, cskew, skew));\
3987dd7cddfSDavid du Colombier   wr_op_masked(bits, mask, 0);\
3997dd7cddfSDavid du Colombier   /* Do full chunks. */\
4007dd7cddfSDavid du Colombier   while ( count >= chunk_bits )\
4017dd7cddfSDavid du Colombier     { bits = CFETCH2(bptr, cskew, skew);\
4027dd7cddfSDavid du Colombier       NEXT_X_CHUNK(); wr_op(bits); count -= chunk_bits;\
4037dd7cddfSDavid du Colombier     }\
4047dd7cddfSDavid du Colombier   /* Do last chunk */\
4057dd7cddfSDavid du Colombier   if ( count > 0 )\
4067dd7cddfSDavid du Colombier     { bits = CFETCH_LEFT(bptr, cskew, skew);\
4077dd7cddfSDavid du Colombier       if ( count > skew ) bits += CFETCH_RIGHT(bptr + chunk_bytes, skew, cskew);\
4087dd7cddfSDavid du Colombier       wr_op_masked(bits, rmask, 1);\
4097dd7cddfSDavid du Colombier     }
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier 	    switch (mode.op) {
4127dd7cddfSDavid du Colombier 		case COPY_OR:
4137dd7cddfSDavid du Colombier 		    for (;;) {
4147dd7cddfSDavid du Colombier 			int count = wleft;
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 			WRITE_UNALIGNED(WRITE_OR, WRITE_OR_MASKED);
4177dd7cddfSDavid du Colombier 			if (--h == 0)
4187dd7cddfSDavid du Colombier 			    break;
4197dd7cddfSDavid du Colombier 			END_Y_LOOP(sskip, dskip);
4207dd7cddfSDavid du Colombier 		    }
4217dd7cddfSDavid du Colombier 		    break;
4227dd7cddfSDavid du Colombier 		case COPY_STORE:
4237dd7cddfSDavid du Colombier 		    for (;;) {
4247dd7cddfSDavid du Colombier 			int count = wleft;
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 			WRITE_UNALIGNED(WRITE_STORE, WRITE_STORE_MASKED);
4277dd7cddfSDavid du Colombier 			if (--h == 0)
4287dd7cddfSDavid du Colombier 			    break;
4297dd7cddfSDavid du Colombier 			END_Y_LOOP(sskip, dskip);
4307dd7cddfSDavid du Colombier 		    }
4317dd7cddfSDavid du Colombier 		    break;
4327dd7cddfSDavid du Colombier 		case COPY_AND:
4337dd7cddfSDavid du Colombier 		    for (;;) {
4347dd7cddfSDavid du Colombier 			int count = wleft;
4357dd7cddfSDavid du Colombier 
4367dd7cddfSDavid du Colombier 			WRITE_UNALIGNED(WRITE_AND, WRITE_AND_MASKED);
4377dd7cddfSDavid du Colombier 			if (--h == 0)
4387dd7cddfSDavid du Colombier 			    break;
4397dd7cddfSDavid du Colombier 			END_Y_LOOP(sskip, dskip);
4407dd7cddfSDavid du Colombier 		    }
4417dd7cddfSDavid du Colombier 		    break;
4427dd7cddfSDavid du Colombier 		default /*case COPY_FUNNY */ :
4437dd7cddfSDavid du Colombier 		    return FUNNY_CASE();
4447dd7cddfSDavid du Colombier 	    }
4457dd7cddfSDavid du Colombier #undef WRITE_UNALIGNED
4467dd7cddfSDavid du Colombier 	}
4477dd7cddfSDavid du Colombier     }
4487dd7cddfSDavid du Colombier #undef END_Y_LOOP
4497dd7cddfSDavid du Colombier #undef NEXT_X_CHUNK
4507dd7cddfSDavid du Colombier     return 0;
4517dd7cddfSDavid du Colombier #undef optr
4527dd7cddfSDavid du Colombier #endif /* !USE_COPY_ROP */
4537dd7cddfSDavid du Colombier }
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier /* Strip-tile with a monochrome halftone. */
4567dd7cddfSDavid du Colombier /* This is a performance bottleneck for monochrome devices, */
4577dd7cddfSDavid du Colombier /* so we re-implement it, even though it takes a lot of code. */
4587dd7cddfSDavid du Colombier private int
mem_mono_strip_tile_rectangle(gx_device * dev,register const gx_strip_bitmap * tiles,int tx,int y,int tw,int th,gx_color_index color0,gx_color_index color1,int px,int py)4597dd7cddfSDavid du Colombier mem_mono_strip_tile_rectangle(gx_device * dev,
4607dd7cddfSDavid du Colombier 			      register const gx_strip_bitmap * tiles,
4617dd7cddfSDavid du Colombier int tx, int y, int tw, int th, gx_color_index color0, gx_color_index color1,
4627dd7cddfSDavid du Colombier 			      int px, int py)
4637dd7cddfSDavid du Colombier {
4647dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
4657dd7cddfSDavid du Colombier 
4667dd7cddfSDavid du Colombier #ifdef USE_COPY_ROP
4677dd7cddfSDavid du Colombier     return mem_mono_strip_copy_rop(dev, NULL, 0, 0, tile->id, NULL,
4687dd7cddfSDavid du Colombier 				   tiles, NULL,
4697dd7cddfSDavid du Colombier 				   tx, y, tw, th, px, py,
4707dd7cddfSDavid du Colombier 				   ((color0 == gx_no_color_index ? rop3_D :
4717dd7cddfSDavid du Colombier 				 color0 == 0 ? rop3_0 : rop3_1) & ~rop3_T) |
4727dd7cddfSDavid du Colombier 				   ((color1 == gx_no_color_index ? rop3_D :
4737dd7cddfSDavid du Colombier 				  color1 == 0 ? rop3_0 : rop3_1) & rop3_T));
4747dd7cddfSDavid du Colombier #else /* !USE_COPY_ROP */
4757dd7cddfSDavid du Colombier     register uint invert;
4767dd7cddfSDavid du Colombier     int source_raster;
4777dd7cddfSDavid du Colombier     uint tile_bits_size;
4787dd7cddfSDavid du Colombier     const byte *source_data;
4797dd7cddfSDavid du Colombier     const byte *end;
4807dd7cddfSDavid du Colombier     int x, rw, w, h;
4817dd7cddfSDavid du Colombier     register const byte *bptr;	/* actually chunk * */
4827dd7cddfSDavid du Colombier     int dbit, wleft;
4837dd7cddfSDavid du Colombier     uint mask;
4847dd7cddfSDavid du Colombier     byte *dbase;
4857dd7cddfSDavid du Colombier 
4867dd7cddfSDavid du Colombier     DECLARE_SCAN_PTR_VARS(dbptr, byte *, dest_raster);
4877dd7cddfSDavid du Colombier #define optr ((chunk *)dbptr)
4887dd7cddfSDavid du Colombier     register int skew;
4897dd7cddfSDavid du Colombier 
4907dd7cddfSDavid du Colombier     /* This implementation doesn't handle strips yet. */
4917dd7cddfSDavid du Colombier     if (color0 != (color1 ^ 1) || tiles->shift != 0)
4927dd7cddfSDavid du Colombier 	return gx_default_strip_tile_rectangle(dev, tiles, tx, y, tw, th,
4937dd7cddfSDavid du Colombier 					       color0, color1, px, py);
4947dd7cddfSDavid du Colombier     fit_fill(dev, tx, y, tw, th);
495*593dc095SDavid du Colombier     invert = (uint)(-(int) color0);
4967dd7cddfSDavid du Colombier     source_raster = tiles->raster;
4977dd7cddfSDavid du Colombier     source_data = tiles->data + ((y + py) % tiles->rep_height) * source_raster;
4987dd7cddfSDavid du Colombier     tile_bits_size = tiles->size.y * source_raster;
4997dd7cddfSDavid du Colombier     end = tiles->data + tile_bits_size;
5007dd7cddfSDavid du Colombier #undef END_Y_LOOP
5017dd7cddfSDavid du Colombier #define END_Y_LOOP(sdelta, ddelta)\
5027dd7cddfSDavid du Colombier   if ( end - bptr <= sdelta )	/* wrap around */\
5037dd7cddfSDavid du Colombier     bptr -= tile_bits_size;\
5047dd7cddfSDavid du Colombier   bptr += sdelta; dbptr += ddelta
5057dd7cddfSDavid du Colombier     dest_raster = mdev->raster;
5067dd7cddfSDavid du Colombier     dbase = scan_line_base(mdev, y);
5077dd7cddfSDavid du Colombier     x = tx;
5087dd7cddfSDavid du Colombier     rw = tw;
5097dd7cddfSDavid du Colombier     /*
5107dd7cddfSDavid du Colombier      * The outermost loop here works horizontally, one iteration per
5117dd7cddfSDavid du Colombier      * copy of the tile.  Note that all iterations except the first
5127dd7cddfSDavid du Colombier      * have source_x = 0.
5137dd7cddfSDavid du Colombier      */
5147dd7cddfSDavid du Colombier     {
5157dd7cddfSDavid du Colombier 	int source_x = (x + px) % tiles->rep_width;
5167dd7cddfSDavid du Colombier 
5177dd7cddfSDavid du Colombier 	w = tiles->size.x - source_x;
5187dd7cddfSDavid du Colombier 	bptr = source_data + ((source_x & ~chunk_align_bit_mask) >> 3);
5197dd7cddfSDavid du Colombier 	dbit = x & chunk_align_bit_mask;
5207dd7cddfSDavid du Colombier 	skew = dbit - (source_x & chunk_align_bit_mask);
5217dd7cddfSDavid du Colombier     }
5227dd7cddfSDavid du Colombier   outer:if (w > rw)
5237dd7cddfSDavid du Colombier 	w = rw;
5247dd7cddfSDavid du Colombier     h = th;
5257dd7cddfSDavid du Colombier     dbptr = dbase + ((x >> 3) & -chunk_align_bytes);
5267dd7cddfSDavid du Colombier     if ((wleft = w + dbit - chunk_bits) <= 0) {		/* The entire operation fits in one (destination) chunk. */
5277dd7cddfSDavid du Colombier 	set_mono_thin_mask(mask, w, dbit);
5287dd7cddfSDavid du Colombier #define WRITE1_LOOP(src)\
5297dd7cddfSDavid du Colombier   for ( ; ; )\
5307dd7cddfSDavid du Colombier    { WRITE_STORE_MASKED(src, mask, 0);\
5317dd7cddfSDavid du Colombier      if ( --h == 0 ) break;\
5327dd7cddfSDavid du Colombier      END_Y_LOOP(source_raster, dest_raster);\
5337dd7cddfSDavid du Colombier    }
5347dd7cddfSDavid du Colombier 	if (skew >= 0) {	/* single -> single, right/no shift */
5357dd7cddfSDavid du Colombier 	    if (skew == 0) {	/* no shift */
5367dd7cddfSDavid du Colombier 		WRITE1_LOOP(CFETCH_ALIGNED(bptr));
5377dd7cddfSDavid du Colombier 	    } else {		/* right shift */
5387dd7cddfSDavid du Colombier #if CFETCH_USES_CSKEW
5397dd7cddfSDavid du Colombier 		int cskew = chunk_bits - skew;
5407dd7cddfSDavid du Colombier #endif
5417dd7cddfSDavid du Colombier 
5427dd7cddfSDavid du Colombier 		WRITE1_LOOP(CFETCH_RIGHT(bptr, skew, cskew));
5437dd7cddfSDavid du Colombier 	    }
5447dd7cddfSDavid du Colombier 	} else if (wleft <= skew) {	/* single -> single, left shift */
5457dd7cddfSDavid du Colombier #if CFETCH_USES_CSKEW
5467dd7cddfSDavid du Colombier 	    int cskew = chunk_bits + skew;
5477dd7cddfSDavid du Colombier #endif
5487dd7cddfSDavid du Colombier 
5497dd7cddfSDavid du Colombier 	    skew = -skew;
5507dd7cddfSDavid du Colombier 	    WRITE1_LOOP(CFETCH_LEFT(bptr, skew, cskew));
5517dd7cddfSDavid du Colombier 	} else {		/* double -> single */
5527dd7cddfSDavid du Colombier 	    int cskew = -skew;
5537dd7cddfSDavid du Colombier 
5547dd7cddfSDavid du Colombier 	    skew += chunk_bits;
5557dd7cddfSDavid du Colombier 	    WRITE1_LOOP(CFETCH2(bptr, cskew, skew));
5567dd7cddfSDavid du Colombier 	}
5577dd7cddfSDavid du Colombier #undef WRITE1_LOOP
5587dd7cddfSDavid du Colombier     } else if (wleft <= skew) {	/* 1 source chunk -> 2 destination chunks. */
5597dd7cddfSDavid du Colombier 	/* This is an important special case for */
5607dd7cddfSDavid du Colombier 	/* both characters and halftone tiles. */
5617dd7cddfSDavid du Colombier 	uint rmask;
5627dd7cddfSDavid du Colombier 	int cskew = chunk_bits - skew;
5637dd7cddfSDavid du Colombier 
5647dd7cddfSDavid du Colombier 	set_mono_left_mask(mask, dbit);
5657dd7cddfSDavid du Colombier 	set_mono_right_mask(rmask, wleft);
5667dd7cddfSDavid du Colombier #if arch_is_big_endian		/* no byte swapping */
5677dd7cddfSDavid du Colombier #undef CINVERT
5687dd7cddfSDavid du Colombier #define CINVERT(bits) (bits)	/* pre-inverted here */
5697dd7cddfSDavid du Colombier 	for (;;) {
5707dd7cddfSDavid du Colombier 	    register uint bits = CFETCH_ALIGNED(bptr) ^ invert;
5717dd7cddfSDavid du Colombier 
5727dd7cddfSDavid du Colombier 	    WRITE_STORE_MASKED(bits >> skew, mask, 0);
5737dd7cddfSDavid du Colombier 	    WRITE_STORE_MASKED(bits << cskew, rmask, 1);
5747dd7cddfSDavid du Colombier 	    if (--h == 0)
5757dd7cddfSDavid du Colombier 		break;
5767dd7cddfSDavid du Colombier 	    END_Y_LOOP(source_raster, dest_raster);
5777dd7cddfSDavid du Colombier 	}
5787dd7cddfSDavid du Colombier #undef CINVERT
5797dd7cddfSDavid du Colombier #define CINVERT(bits) ((bits) ^ invert)
5807dd7cddfSDavid du Colombier #else /* byte swapping */
5817dd7cddfSDavid du Colombier 	for (;;) {
5827dd7cddfSDavid du Colombier 	    WRITE_STORE_MASKED(CFETCH_RIGHT(bptr, skew, cskew), mask, 0);
5837dd7cddfSDavid du Colombier 	    WRITE_STORE_MASKED(CFETCH_LEFT(bptr, cskew, skew), rmask, 1);
5847dd7cddfSDavid du Colombier 	    if (--h == 0)
5857dd7cddfSDavid du Colombier 		break;
5867dd7cddfSDavid du Colombier 	    END_Y_LOOP(source_raster, dest_raster);
5877dd7cddfSDavid du Colombier 	}
5887dd7cddfSDavid du Colombier #endif
5897dd7cddfSDavid du Colombier     } else {			/* More than one source chunk and more than one */
5907dd7cddfSDavid du Colombier 	/* destination chunk are involved. */
5917dd7cddfSDavid du Colombier 	uint rmask;
5927dd7cddfSDavid du Colombier 	int words = (wleft & ~chunk_bit_mask) >> 3;
5937dd7cddfSDavid du Colombier 	uint sskip = source_raster - words;
5947dd7cddfSDavid du Colombier 	uint dskip = dest_raster - words;
5957dd7cddfSDavid du Colombier 	register uint bits;
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier #define NEXT_X_CHUNK()\
5987dd7cddfSDavid du Colombier   bptr += chunk_bytes; dbptr += chunk_bytes
5997dd7cddfSDavid du Colombier 
6007dd7cddfSDavid du Colombier 	set_mono_right_mask(rmask, wleft & chunk_bit_mask);
6017dd7cddfSDavid du Colombier 	if (skew == 0) {	/* optimize the aligned case */
6027dd7cddfSDavid du Colombier 	    if (dbit == 0)
6037dd7cddfSDavid du Colombier 		mask = 0;
6047dd7cddfSDavid du Colombier 	    else
6057dd7cddfSDavid du Colombier 		set_mono_left_mask(mask, dbit);
6067dd7cddfSDavid du Colombier 	    for (;;) {
6077dd7cddfSDavid du Colombier 		int count = wleft;
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier 		/* Do first partial chunk. */
6107dd7cddfSDavid du Colombier 		if (mask)
6117dd7cddfSDavid du Colombier 		    WRITE_STORE_MASKED(CFETCH_ALIGNED(bptr), mask, 0);
6127dd7cddfSDavid du Colombier 		else
6137dd7cddfSDavid du Colombier 		    WRITE_STORE(CFETCH_ALIGNED(bptr));
6147dd7cddfSDavid du Colombier 		/* Do full chunks. */
6157dd7cddfSDavid du Colombier 		while ((count -= chunk_bits) >= 0) {
6167dd7cddfSDavid du Colombier 		    NEXT_X_CHUNK();
6177dd7cddfSDavid du Colombier 		    WRITE_STORE(CFETCH_ALIGNED(bptr));
6187dd7cddfSDavid du Colombier 		}
6197dd7cddfSDavid du Colombier 		/* Do last chunk */
6207dd7cddfSDavid du Colombier 		if (count > -chunk_bits) {
6217dd7cddfSDavid du Colombier 		    WRITE_STORE_MASKED(CFETCH_ALIGNED(bptr + chunk_bytes), rmask, 1);
6227dd7cddfSDavid du Colombier 		}
6237dd7cddfSDavid du Colombier 		if (--h == 0)
6247dd7cddfSDavid du Colombier 		    break;
6257dd7cddfSDavid du Colombier 		END_Y_LOOP(sskip, dskip);
6267dd7cddfSDavid du Colombier 	    }
6277dd7cddfSDavid du Colombier 	} else {		/* not aligned */
6287dd7cddfSDavid du Colombier 	    bool case_right =
6297dd7cddfSDavid du Colombier 	    (skew >= 0 ? true :
6307dd7cddfSDavid du Colombier 	     ((bptr += chunk_bytes), false));
6317dd7cddfSDavid du Colombier 	    int cskew = -skew & chunk_bit_mask;
6327dd7cddfSDavid du Colombier 
6337dd7cddfSDavid du Colombier 	    skew &= chunk_bit_mask;
6347dd7cddfSDavid du Colombier 	    set_mono_left_mask(mask, dbit);
6357dd7cddfSDavid du Colombier 	    for (;;) {
6367dd7cddfSDavid du Colombier 		int count = wleft;
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier 		if (case_right)
6397dd7cddfSDavid du Colombier 		    bits = CFETCH_RIGHT(bptr, skew, cskew);
6407dd7cddfSDavid du Colombier 		else
6417dd7cddfSDavid du Colombier 		    bits = CFETCH2(bptr - chunk_bytes, cskew, skew);
6427dd7cddfSDavid du Colombier 		WRITE_STORE_MASKED(bits, mask, 0);
6437dd7cddfSDavid du Colombier 		/* Do full chunks. */
6447dd7cddfSDavid du Colombier 		while (count >= chunk_bits) {
6457dd7cddfSDavid du Colombier 		    bits = CFETCH2(bptr, cskew, skew);
6467dd7cddfSDavid du Colombier 		    NEXT_X_CHUNK();
6477dd7cddfSDavid du Colombier 		    WRITE_STORE(bits);
6487dd7cddfSDavid du Colombier 		    count -= chunk_bits;
6497dd7cddfSDavid du Colombier 		}
6507dd7cddfSDavid du Colombier 		/* Do last chunk */
6517dd7cddfSDavid du Colombier 		if (count > 0) {
6527dd7cddfSDavid du Colombier 		    bits = CFETCH_LEFT(bptr, cskew, skew);
6537dd7cddfSDavid du Colombier 		    if (count > skew)
6547dd7cddfSDavid du Colombier 			bits += CFETCH_RIGHT(bptr + chunk_bytes, skew, cskew);
6557dd7cddfSDavid du Colombier 		    WRITE_STORE_MASKED(bits, rmask, 1);
6567dd7cddfSDavid du Colombier 		}
6577dd7cddfSDavid du Colombier 		if (--h == 0)
6587dd7cddfSDavid du Colombier 		    break;
6597dd7cddfSDavid du Colombier 		END_Y_LOOP(sskip, dskip);
6607dd7cddfSDavid du Colombier 	    }
6617dd7cddfSDavid du Colombier 	}
6627dd7cddfSDavid du Colombier     }
6637dd7cddfSDavid du Colombier #undef END_Y_LOOP
6647dd7cddfSDavid du Colombier #undef NEXT_X_CHUNK
6657dd7cddfSDavid du Colombier #undef optr
6667dd7cddfSDavid du Colombier     if ((rw -= w) > 0) {
6677dd7cddfSDavid du Colombier 	x += w;
6687dd7cddfSDavid du Colombier 	w = tiles->size.x;
6697dd7cddfSDavid du Colombier 	bptr = source_data;
6707dd7cddfSDavid du Colombier 	skew = dbit = x & chunk_align_bit_mask;
6717dd7cddfSDavid du Colombier 	goto outer;
6727dd7cddfSDavid du Colombier     }
6737dd7cddfSDavid du Colombier     return 0;
6747dd7cddfSDavid du Colombier #endif /* !USE_COPY_ROP */
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier /* ================ "Word"-oriented device ================ */
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier /* Note that on a big-endian machine, this is the same as the */
6807dd7cddfSDavid du Colombier /* standard byte-oriented-device. */
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier #if !arch_is_big_endian
6837dd7cddfSDavid du Colombier 
6847dd7cddfSDavid du Colombier /* Procedures */
6857dd7cddfSDavid du Colombier private dev_proc_copy_mono(mem1_word_copy_mono);
6867dd7cddfSDavid du Colombier private dev_proc_fill_rectangle(mem1_word_fill_rectangle);
6877dd7cddfSDavid du Colombier 
6887dd7cddfSDavid du Colombier #define mem1_word_strip_tile_rectangle gx_default_strip_tile_rectangle
6897dd7cddfSDavid du Colombier 
6907dd7cddfSDavid du Colombier /* Here is the device descriptor. */
6917dd7cddfSDavid du Colombier const gx_device_memory mem_mono_word_device =
6927dd7cddfSDavid du Colombier mem_full_alpha_device("image1w", 0, 1, mem_open,
6937dd7cddfSDavid du Colombier 		      mem_mono_map_rgb_color, mem_mono_map_color_rgb,
6947dd7cddfSDavid du Colombier        mem1_word_copy_mono, gx_default_copy_color, mem1_word_fill_rectangle,
6957dd7cddfSDavid du Colombier 		      gx_default_map_cmyk_color, gx_no_copy_alpha,
6967dd7cddfSDavid du Colombier 		      mem1_word_strip_tile_rectangle, gx_no_strip_copy_rop,
6977dd7cddfSDavid du Colombier 		      mem_word_get_bits_rectangle);
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier /* Fill a rectangle with a color. */
7007dd7cddfSDavid du Colombier private int
mem1_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)7017dd7cddfSDavid du Colombier mem1_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
7027dd7cddfSDavid du Colombier 			 gx_color_index color)
7037dd7cddfSDavid du Colombier {
7047dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
7057dd7cddfSDavid du Colombier     byte *base;
7067dd7cddfSDavid du Colombier     uint raster;
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier     fit_fill(dev, x, y, w, h);
7097dd7cddfSDavid du Colombier     base = scan_line_base(mdev, y);
7107dd7cddfSDavid du Colombier     raster = mdev->raster;
7117dd7cddfSDavid du Colombier     mem_swap_byte_rect(base, raster, x, w, h, true);
712*593dc095SDavid du Colombier     bits_fill_rectangle(base, x, raster, -(int)(mono_fill_chunk) color, w, h);
7137dd7cddfSDavid du Colombier     mem_swap_byte_rect(base, raster, x, w, h, true);
7147dd7cddfSDavid du Colombier     return 0;
7157dd7cddfSDavid du Colombier }
7167dd7cddfSDavid du Colombier 
7177dd7cddfSDavid du Colombier /* Copy a bitmap. */
7187dd7cddfSDavid du Colombier private int
mem1_word_copy_mono(gx_device * dev,const byte * source_data,int source_x,int source_raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)7197dd7cddfSDavid du Colombier mem1_word_copy_mono(gx_device * dev,
7207dd7cddfSDavid du Colombier  const byte * source_data, int source_x, int source_raster, gx_bitmap_id id,
7217dd7cddfSDavid du Colombier    int x, int y, int w, int h, gx_color_index color0, gx_color_index color1)
7227dd7cddfSDavid du Colombier {
7237dd7cddfSDavid du Colombier     gx_device_memory * const mdev = (gx_device_memory *)dev;
7247dd7cddfSDavid du Colombier     byte *row;
7257dd7cddfSDavid du Colombier     uint raster;
7267dd7cddfSDavid du Colombier     bool store;
7277dd7cddfSDavid du Colombier 
7287dd7cddfSDavid du Colombier     fit_copy(dev, source_data, source_x, source_raster, id, x, y, w, h);
7297dd7cddfSDavid du Colombier     row = scan_line_base(mdev, y);
7307dd7cddfSDavid du Colombier     raster = mdev->raster;
7317dd7cddfSDavid du Colombier     store = (color0 != gx_no_color_index && color1 != gx_no_color_index);
7327dd7cddfSDavid du Colombier     mem_swap_byte_rect(row, raster, x, w, h, store);
7337dd7cddfSDavid du Colombier     mem_mono_copy_mono(dev, source_data, source_x, source_raster, id,
7347dd7cddfSDavid du Colombier 		       x, y, w, h, color0, color1);
7357dd7cddfSDavid du Colombier     mem_swap_byte_rect(row, raster, x, w, h, false);
7367dd7cddfSDavid du Colombier     return 0;
7377dd7cddfSDavid du Colombier }
7387dd7cddfSDavid du Colombier 
7397dd7cddfSDavid du Colombier #endif /* !arch_is_big_endian */
740