xref: /plan9-contrib/sys/src/cmd/gs/src/gdevmr1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1995, 2000 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: gdevmr1.c,v 1.5 2002/08/22 07:12:28 henrys Exp $ */
187dd7cddfSDavid du Colombier /* RasterOp implementation for monobit memory devices */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gsbittab.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gsropt.h"
247dd7cddfSDavid du Colombier #include "gxcindex.h"
257dd7cddfSDavid du Colombier #include "gxdcolor.h"
267dd7cddfSDavid du Colombier #include "gxdevice.h"
277dd7cddfSDavid du Colombier #include "gxdevmem.h"
287dd7cddfSDavid du Colombier #include "gxdevrop.h"
297dd7cddfSDavid du Colombier #include "gdevmrop.h"
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /* Calculate the X offset for a given Y value, */
327dd7cddfSDavid du Colombier /* taking shift into account if necessary. */
337dd7cddfSDavid du Colombier #define x_offset(px, ty, textures)\
347dd7cddfSDavid du Colombier   ((textures)->shift == 0 ? (px) :\
357dd7cddfSDavid du Colombier    (px) + (ty) / (textures)->rep_height * (textures)->rep_shift)
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier /* ---------------- Monobit RasterOp ---------------- */
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier int
mem_mono_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)407dd7cddfSDavid du Colombier mem_mono_strip_copy_rop(gx_device * dev,
417dd7cddfSDavid du Colombier 	     const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
427dd7cddfSDavid du Colombier 			const gx_color_index * scolors,
437dd7cddfSDavid du Colombier 	   const gx_strip_bitmap * textures, const gx_color_index * tcolors,
447dd7cddfSDavid du Colombier 			int x, int y, int width, int height,
457dd7cddfSDavid du Colombier 			int phase_x, int phase_y, gs_logical_operation_t lop)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier     gx_device_memory *mdev = (gx_device_memory *) dev;
487dd7cddfSDavid du Colombier     gs_rop3_t rop = gs_transparent_rop(lop);	/* handle transparency */
497dd7cddfSDavid du Colombier     gx_strip_bitmap no_texture;
507dd7cddfSDavid du Colombier     bool invert;
517dd7cddfSDavid du Colombier     uint draster = mdev->raster;
527dd7cddfSDavid du Colombier     uint traster;
537dd7cddfSDavid du Colombier     int line_count;
547dd7cddfSDavid du Colombier     byte *drow;
557dd7cddfSDavid du Colombier     const byte *srow;
567dd7cddfSDavid du Colombier     int ty;
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier     /* If map_rgb_color isn't the default one for monobit memory */
597dd7cddfSDavid du Colombier     /* devices, palette might not be set; set it now if needed. */
60*593dc095SDavid du Colombier     if (mdev->palette.data == 0) {
61*593dc095SDavid du Colombier         gx_color_value cv[3];
62*593dc095SDavid du Colombier         cv[0] = cv[1] = cv[2] = 0;
637dd7cddfSDavid du Colombier 	gdev_mem_mono_set_inverted(mdev,
647dd7cddfSDavid du Colombier 				   (*dev_proc(dev, map_rgb_color))
65*593dc095SDavid du Colombier 				   (dev, cv) != 0);
66*593dc095SDavid du Colombier     }
677dd7cddfSDavid du Colombier     invert = mdev->palette.data[0] != 0;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier #ifdef DEBUG
707dd7cddfSDavid du Colombier     if (gs_debug_c('b'))
717dd7cddfSDavid du Colombier 	trace_copy_rop("mem_mono_strip_copy_rop",
727dd7cddfSDavid du Colombier 		       dev, sdata, sourcex, sraster,
737dd7cddfSDavid du Colombier 		       id, scolors, textures, tcolors,
747dd7cddfSDavid du Colombier 		       x, y, width, height, phase_x, phase_y, lop);
757dd7cddfSDavid du Colombier     if (gs_debug_c('B'))
767dd7cddfSDavid du Colombier 	debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
777dd7cddfSDavid du Colombier 			  height, "initial dest bits");
787dd7cddfSDavid du Colombier #endif
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier     /*
817dd7cddfSDavid du Colombier      * RasterOp is defined as operating in RGB space; in the monobit
827dd7cddfSDavid du Colombier      * case, this means black = 0, white = 1.  However, most monobit
837dd7cddfSDavid du Colombier      * devices use the opposite convention.  To make this work,
847dd7cddfSDavid du Colombier      * we must precondition the Boolean operation by swapping the
857dd7cddfSDavid du Colombier      * order of bits end-for-end and then inverting.
867dd7cddfSDavid du Colombier      */
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier     if (invert)
897dd7cddfSDavid du Colombier 	rop = byte_reverse_bits[rop] ^ 0xff;
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier     /*
927dd7cddfSDavid du Colombier      * From this point on, rop works in terms of device pixel values,
937dd7cddfSDavid du Colombier      * not RGB-space values.
947dd7cddfSDavid du Colombier      */
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier     /* Modify the raster operation according to the source palette. */
977dd7cddfSDavid du Colombier     if (scolors != 0) {		/* Source with palette. */
987dd7cddfSDavid du Colombier 	switch ((int)((scolors[1] << 1) + scolors[0])) {
997dd7cddfSDavid du Colombier 	    case 0:
1007dd7cddfSDavid du Colombier 		rop = rop3_know_S_0(rop);
1017dd7cddfSDavid du Colombier 		break;
1027dd7cddfSDavid du Colombier 	    case 1:
1037dd7cddfSDavid du Colombier 		rop = rop3_invert_S(rop);
1047dd7cddfSDavid du Colombier 		break;
1057dd7cddfSDavid du Colombier 	    case 2:
1067dd7cddfSDavid du Colombier 		break;
1077dd7cddfSDavid du Colombier 	    case 3:
1087dd7cddfSDavid du Colombier 		rop = rop3_know_S_1(rop);
1097dd7cddfSDavid du Colombier 		break;
1107dd7cddfSDavid du Colombier 	}
1117dd7cddfSDavid du Colombier     }
1127dd7cddfSDavid du Colombier     /* Modify the raster operation according to the texture palette. */
1137dd7cddfSDavid du Colombier     if (tcolors != 0) {		/* Texture with palette. */
1147dd7cddfSDavid du Colombier 	switch ((int)((tcolors[1] << 1) + tcolors[0])) {
1157dd7cddfSDavid du Colombier 	    case 0:
1167dd7cddfSDavid du Colombier 		rop = rop3_know_T_0(rop);
1177dd7cddfSDavid du Colombier 		break;
1187dd7cddfSDavid du Colombier 	    case 1:
1197dd7cddfSDavid du Colombier 		rop = rop3_invert_T(rop);
1207dd7cddfSDavid du Colombier 		break;
1217dd7cddfSDavid du Colombier 	    case 2:
1227dd7cddfSDavid du Colombier 		break;
1237dd7cddfSDavid du Colombier 	    case 3:
1247dd7cddfSDavid du Colombier 		rop = rop3_know_T_1(rop);
1257dd7cddfSDavid du Colombier 		break;
1267dd7cddfSDavid du Colombier 	}
1277dd7cddfSDavid du Colombier     }
1287dd7cddfSDavid du Colombier     /* Handle constant source and/or texture, and other special cases. */
1297dd7cddfSDavid du Colombier     {
1307dd7cddfSDavid du Colombier 	gx_color_index color0, color1;
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 	switch (rop_usage_table[rop]) {
1337dd7cddfSDavid du Colombier 	    case rop_usage_none:
1347dd7cddfSDavid du Colombier 		/* We're just filling with a constant. */
1357dd7cddfSDavid du Colombier 		return (*dev_proc(dev, fill_rectangle))
1367dd7cddfSDavid du Colombier 		    (dev, x, y, width, height, (gx_color_index) (rop & 1));
1377dd7cddfSDavid du Colombier 	    case rop_usage_D:
1387dd7cddfSDavid du Colombier 		/* This is either D (no-op) or ~D. */
1397dd7cddfSDavid du Colombier 		if (rop == rop3_D)
1407dd7cddfSDavid du Colombier 		    return 0;
1417dd7cddfSDavid du Colombier 		/* Code no_S inline, then finish with no_T. */
1427dd7cddfSDavid du Colombier 		fit_fill(dev, x, y, width, height);
1437dd7cddfSDavid du Colombier 		sdata = scan_line_base(mdev, 0);
1447dd7cddfSDavid du Colombier 		sourcex = x;
1457dd7cddfSDavid du Colombier 		sraster = 0;
1467dd7cddfSDavid du Colombier 		goto no_T;
1477dd7cddfSDavid du Colombier 	    case rop_usage_S:
1487dd7cddfSDavid du Colombier 		/* This is either S or ~S, which copy_mono can handle. */
1497dd7cddfSDavid du Colombier 		if (rop == rop3_S)
1507dd7cddfSDavid du Colombier 		    color0 = 0, color1 = 1;
1517dd7cddfSDavid du Colombier 		else
1527dd7cddfSDavid du Colombier 		    color0 = 1, color1 = 0;
1537dd7cddfSDavid du Colombier 	      do_copy:return (*dev_proc(dev, copy_mono))
1547dd7cddfSDavid du Colombier 		    (dev, sdata, sourcex, sraster, id, x, y, width, height,
1557dd7cddfSDavid du Colombier 		     color0, color1);
1567dd7cddfSDavid du Colombier 	    case rop_usage_DS:
1577dd7cddfSDavid du Colombier 		/* This might be a case that copy_mono can handle. */
1587dd7cddfSDavid du Colombier #define copy_case(c0, c1) color0 = c0, color1 = c1; goto do_copy;
1597dd7cddfSDavid du Colombier 		switch ((uint) rop) {	/* cast shuts up picky compilers */
1607dd7cddfSDavid du Colombier 		    case rop3_D & rop3_not(rop3_S):
1617dd7cddfSDavid du Colombier 			copy_case(gx_no_color_index, 0);
1627dd7cddfSDavid du Colombier 		    case rop3_D | rop3_S:
1637dd7cddfSDavid du Colombier 			copy_case(gx_no_color_index, 1);
1647dd7cddfSDavid du Colombier 		    case rop3_D & rop3_S:
1657dd7cddfSDavid du Colombier 			copy_case(0, gx_no_color_index);
1667dd7cddfSDavid du Colombier 		    case rop3_D | rop3_not(rop3_S):
1677dd7cddfSDavid du Colombier 			copy_case(1, gx_no_color_index);
1687dd7cddfSDavid du Colombier 		    default:;
1697dd7cddfSDavid du Colombier 		}
1707dd7cddfSDavid du Colombier #undef copy_case
1717dd7cddfSDavid du Colombier 		fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
1727dd7cddfSDavid du Colombier 	      no_T:		/* Texture is not used; textures may be garbage. */
1737dd7cddfSDavid du Colombier 		no_texture.data = scan_line_base(mdev, 0);  /* arbitrary */
1747dd7cddfSDavid du Colombier 		no_texture.raster = 0;
1757dd7cddfSDavid du Colombier 		no_texture.size.x = width;
1767dd7cddfSDavid du Colombier 		no_texture.size.y = height;
1777dd7cddfSDavid du Colombier 		no_texture.rep_width = no_texture.rep_height = 1;
1787dd7cddfSDavid du Colombier 		no_texture.rep_shift = no_texture.shift = 0;
1797dd7cddfSDavid du Colombier 		textures = &no_texture;
1807dd7cddfSDavid du Colombier 		break;
1817dd7cddfSDavid du Colombier 	    case rop_usage_T:
1827dd7cddfSDavid du Colombier 		/* This is either T or ~T, which tile_rectangle can handle. */
1837dd7cddfSDavid du Colombier 		if (rop == rop3_T)
1847dd7cddfSDavid du Colombier 		    color0 = 0, color1 = 1;
1857dd7cddfSDavid du Colombier 		else
1867dd7cddfSDavid du Colombier 		    color0 = 1, color1 = 0;
1877dd7cddfSDavid du Colombier 	      do_tile:return (*dev_proc(dev, strip_tile_rectangle))
1887dd7cddfSDavid du Colombier 		    (dev, textures, x, y, width, height, color0, color1,
1897dd7cddfSDavid du Colombier 		     phase_x, phase_y);
1907dd7cddfSDavid du Colombier 	    case rop_usage_DT:
1917dd7cddfSDavid du Colombier 		/* This might be a case that tile_rectangle can handle. */
1927dd7cddfSDavid du Colombier #define tile_case(c0, c1) color0 = c0, color1 = c1; goto do_tile;
1937dd7cddfSDavid du Colombier 		switch ((uint) rop) {	/* cast shuts up picky compilers */
1947dd7cddfSDavid du Colombier 		    case rop3_D & rop3_not(rop3_T):
1957dd7cddfSDavid du Colombier 			tile_case(gx_no_color_index, 0);
1967dd7cddfSDavid du Colombier 		    case rop3_D | rop3_T:
1977dd7cddfSDavid du Colombier 			tile_case(gx_no_color_index, 1);
1987dd7cddfSDavid du Colombier 		    case rop3_D & rop3_T:
1997dd7cddfSDavid du Colombier 			tile_case(0, gx_no_color_index);
2007dd7cddfSDavid du Colombier 		    case rop3_D | rop3_not(rop3_T):
2017dd7cddfSDavid du Colombier 			tile_case(1, gx_no_color_index);
2027dd7cddfSDavid du Colombier 		    default:;
2037dd7cddfSDavid du Colombier 		}
2047dd7cddfSDavid du Colombier #undef tile_case
2057dd7cddfSDavid du Colombier 		fit_fill(dev, x, y, width, height);
2067dd7cddfSDavid du Colombier 		/* Source is not used; sdata et al may be garbage. */
2077dd7cddfSDavid du Colombier 		sdata = mdev->base;	/* arbitrary, as long as all */
2087dd7cddfSDavid du Colombier 					/* accesses are valid */
2097dd7cddfSDavid du Colombier 		sourcex = x;	/* guarantee no source skew */
2107dd7cddfSDavid du Colombier 		sraster = 0;
2117dd7cddfSDavid du Colombier 		break;
2127dd7cddfSDavid du Colombier 	    default:		/* rop_usage_[D]ST */
2137dd7cddfSDavid du Colombier 		fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
2147dd7cddfSDavid du Colombier 	}
2157dd7cddfSDavid du Colombier     }
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier #ifdef DEBUG
2187dd7cddfSDavid du Colombier     if_debug1('b', "final rop=0x%x\n", rop);
2197dd7cddfSDavid du Colombier #endif
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier     /* Set up transfer parameters. */
2227dd7cddfSDavid du Colombier     line_count = height;
2237dd7cddfSDavid du Colombier     srow = sdata;
2247dd7cddfSDavid du Colombier     drow = scan_line_base(mdev, y);
2257dd7cddfSDavid du Colombier     traster = textures->raster;
2267dd7cddfSDavid du Colombier     ty = y + phase_y;
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier     /* Loop over scan lines. */
2297dd7cddfSDavid du Colombier     for (; line_count-- > 0; drow += draster, srow += sraster, ++ty) {
2307dd7cddfSDavid du Colombier 	int sx = sourcex;
2317dd7cddfSDavid du Colombier 	int dx = x;
2327dd7cddfSDavid du Colombier 	int w = width;
2337dd7cddfSDavid du Colombier 	const byte *trow =
2347dd7cddfSDavid du Colombier 	textures->data + (ty % textures->rep_height) * traster;
2357dd7cddfSDavid du Colombier 	int xoff = x_offset(phase_x, ty, textures);
2367dd7cddfSDavid du Colombier 	int nw;
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier 	/* Loop over (horizontal) copies of the tile. */
2397dd7cddfSDavid du Colombier 	for (; w > 0; sx += nw, dx += nw, w -= nw) {
2407dd7cddfSDavid du Colombier 	    int dbit = dx & 7;
2417dd7cddfSDavid du Colombier 	    int sbit = sx & 7;
2427dd7cddfSDavid du Colombier 	    int sskew = sbit - dbit;
2437dd7cddfSDavid du Colombier 	    int tx = (dx + xoff) % textures->rep_width;
2447dd7cddfSDavid du Colombier 	    int tbit = tx & 7;
2457dd7cddfSDavid du Colombier 	    int tskew = tbit - dbit;
2467dd7cddfSDavid du Colombier 	    int left = nw = min(w, textures->size.x - tx);
2477dd7cddfSDavid du Colombier 	    byte lmask = 0xff >> dbit;
2487dd7cddfSDavid du Colombier 	    byte rmask = 0xff << (~(dbit + nw - 1) & 7);
2497dd7cddfSDavid du Colombier 	    byte mask = lmask;
2507dd7cddfSDavid du Colombier 	    int nx = 8 - dbit;
2517dd7cddfSDavid du Colombier 	    byte *dptr = drow + (dx >> 3);
2527dd7cddfSDavid du Colombier 	    const byte *sptr = srow + (sx >> 3);
2537dd7cddfSDavid du Colombier 	    const byte *tptr = trow + (tx >> 3);
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	    if (sskew < 0)
2567dd7cddfSDavid du Colombier 		--sptr, sskew += 8;
2577dd7cddfSDavid du Colombier 	    if (tskew < 0)
2587dd7cddfSDavid du Colombier 		--tptr, tskew += 8;
2597dd7cddfSDavid du Colombier 	    for (; left > 0;
2607dd7cddfSDavid du Colombier 		 left -= nx, mask = 0xff, nx = 8,
2617dd7cddfSDavid du Colombier 		 ++dptr, ++sptr, ++tptr
2627dd7cddfSDavid du Colombier 		) {
2637dd7cddfSDavid du Colombier 		byte dbyte = *dptr;
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier #define fetch1(ptr, skew)\
2667dd7cddfSDavid du Colombier   (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr)
2677dd7cddfSDavid du Colombier 		byte sbyte = fetch1(sptr, sskew);
2687dd7cddfSDavid du Colombier 		byte tbyte = fetch1(tptr, tskew);
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier #undef fetch1
2717dd7cddfSDavid du Colombier 		byte result =
2727dd7cddfSDavid du Colombier 		(*rop_proc_table[rop]) (dbyte, sbyte, tbyte);
2737dd7cddfSDavid du Colombier 
2747dd7cddfSDavid du Colombier 		if (left <= nx)
2757dd7cddfSDavid du Colombier 		    mask &= rmask;
2767dd7cddfSDavid du Colombier 		*dptr = (mask == 0xff ? result :
2777dd7cddfSDavid du Colombier 			 (result & mask) | (dbyte & ~mask));
2787dd7cddfSDavid du Colombier 	    }
2797dd7cddfSDavid du Colombier 	}
2807dd7cddfSDavid du Colombier     }
2817dd7cddfSDavid du Colombier #ifdef DEBUG
2827dd7cddfSDavid du Colombier     if (gs_debug_c('B'))
2837dd7cddfSDavid du Colombier 	debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
2847dd7cddfSDavid du Colombier 			  height, "final dest bits");
2857dd7cddfSDavid du Colombier #endif
2867dd7cddfSDavid du Colombier     return 0;
2877dd7cddfSDavid du Colombier }
288