1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 /* $Id: gdevmr1.c 10526 2009-12-18 21:14:17Z giles $ */
14 /* RasterOp implementation for monobit memory devices */
15 #include "memory_.h"
16 #include "gx.h"
17 #include "gsbittab.h"
18 #include "gserrors.h"
19 #include "gsropt.h"
20 #include "gxcindex.h"
21 #include "gxdcolor.h"
22 #include "gxdevice.h"
23 #include "gxdevmem.h"
24 #include "gxdevrop.h"
25 #include "gdevmem.h"
26 #include "gdevmrop.h"
27 
28 /* Calculate the X offset for a given Y value, */
29 /* taking shift into account if necessary. */
30 #define x_offset(px, ty, textures)\
31   ((textures)->shift == 0 ? (px) :\
32    (px) + (ty) / (textures)->rep_height * (textures)->rep_shift)
33 
34 /* ---------------- Monobit RasterOp ---------------- */
35 
36 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)37 mem_mono_strip_copy_rop(gx_device * dev,
38 	     const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
39 			const gx_color_index * scolors,
40 	   const gx_strip_bitmap * textures, const gx_color_index * tcolors,
41 			int x, int y, int width, int height,
42 			int phase_x, int phase_y, gs_logical_operation_t lop)
43 {
44     gx_device_memory *mdev = (gx_device_memory *) dev;
45     gs_rop3_t rop = gs_transparent_rop(lop);	/* handle transparency */
46     gx_strip_bitmap no_texture;
47     bool invert;
48     uint draster = mdev->raster;
49     uint traster;
50     int line_count;
51     byte *drow;
52     const byte *srow;
53     int ty;
54 
55     /* If map_rgb_color isn't the default one for monobit memory */
56     /* devices, palette might not be set; set it now if needed. */
57     if (mdev->palette.data == 0) {
58         gx_color_value cv[3];
59         cv[0] = cv[1] = cv[2] = 0;
60 	gdev_mem_mono_set_inverted(mdev,
61 				   (*dev_proc(dev, map_rgb_color))
62 				   (dev, cv) != 0);
63     }
64     invert = mdev->palette.data[0] != 0;
65 
66 #ifdef DEBUG
67     if (gs_debug_c('b'))
68 	trace_copy_rop("mem_mono_strip_copy_rop",
69 		       dev, sdata, sourcex, sraster,
70 		       id, scolors, textures, tcolors,
71 		       x, y, width, height, phase_x, phase_y, lop);
72     if (gs_debug_c('B'))
73 	debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
74 			  height, "initial dest bits");
75 #endif
76 
77     /*
78      * RasterOp is defined as operating in RGB space; in the monobit
79      * case, this means black = 0, white = 1.  However, most monobit
80      * devices use the opposite convention.  To make this work,
81      * we must precondition the Boolean operation by swapping the
82      * order of bits end-for-end and then inverting.
83      */
84 
85     if (invert)
86 	rop = byte_reverse_bits[rop] ^ 0xff;
87 
88     /*
89      * From this point on, rop works in terms of device pixel values,
90      * not RGB-space values.
91      */
92 
93     /* Modify the raster operation according to the source palette. */
94     if (scolors != 0) {		/* Source with palette. */
95 	switch ((int)((scolors[1] << 1) + scolors[0])) {
96 	    case 0:
97 		rop = rop3_know_S_0(rop);
98 		break;
99 	    case 1:
100 		rop = rop3_invert_S(rop);
101 		break;
102 	    case 2:
103 		break;
104 	    case 3:
105 		rop = rop3_know_S_1(rop);
106 		break;
107 	}
108     }
109     /* Modify the raster operation according to the texture palette. */
110     if (tcolors != 0) {		/* Texture with palette. */
111 	switch ((int)((tcolors[1] << 1) + tcolors[0])) {
112 	    case 0:
113 		rop = rop3_know_T_0(rop);
114 		break;
115 	    case 1:
116 		rop = rop3_invert_T(rop);
117 		break;
118 	    case 2:
119 		break;
120 	    case 3:
121 		rop = rop3_know_T_1(rop);
122 		break;
123 	}
124     }
125     /* Handle constant source and/or texture, and other special cases. */
126     {
127 	gx_color_index color0, color1;
128 
129 	switch (rop_usage_table[rop]) {
130 	    case rop_usage_none:
131 		/* We're just filling with a constant. */
132 		return (*dev_proc(dev, fill_rectangle))
133 		    (dev, x, y, width, height, (gx_color_index) (rop & 1));
134 	    case rop_usage_D:
135 		/* This is either D (no-op) or ~D. */
136 		if (rop == rop3_D)
137 		    return 0;
138 		/* Code no_S inline, then finish with no_T. */
139 		fit_fill(dev, x, y, width, height);
140 		sdata = scan_line_base(mdev, 0);
141 		sourcex = x;
142 		sraster = 0;
143 		goto no_T;
144 	    case rop_usage_S:
145 		/* This is either S or ~S, which copy_mono can handle. */
146 		if (rop == rop3_S)
147 		    color0 = 0, color1 = 1;
148 		else
149 		    color0 = 1, color1 = 0;
150 	      do_copy:return (*dev_proc(dev, copy_mono))
151 		    (dev, sdata, sourcex, sraster, id, x, y, width, height,
152 		     color0, color1);
153 	    case rop_usage_DS:
154 		/* This might be a case that copy_mono can handle. */
155 #define copy_case(c0, c1) color0 = c0, color1 = c1; goto do_copy;
156 		switch ((uint) rop) {	/* cast shuts up picky compilers */
157 		    case rop3_D & rop3_not(rop3_S):
158 			copy_case(gx_no_color_index, 0);
159 		    case rop3_D | rop3_S:
160 			copy_case(gx_no_color_index, 1);
161 		    case rop3_D & rop3_S:
162 			copy_case(0, gx_no_color_index);
163 		    case rop3_D | rop3_not(rop3_S):
164 			copy_case(1, gx_no_color_index);
165 		    default:;
166 		}
167 #undef copy_case
168 		fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
169 	      no_T:		/* Texture is not used; textures may be garbage. */
170 		no_texture.data = scan_line_base(mdev, 0);  /* arbitrary */
171 		no_texture.raster = 0;
172 		no_texture.size.x = width;
173 		no_texture.size.y = height;
174 		no_texture.rep_width = no_texture.rep_height = 1;
175 		no_texture.rep_shift = no_texture.shift = 0;
176 		textures = &no_texture;
177 		break;
178 	    case rop_usage_T:
179 		/* This is either T or ~T, which tile_rectangle can handle. */
180 		if (rop == rop3_T)
181 		    color0 = 0, color1 = 1;
182 		else
183 		    color0 = 1, color1 = 0;
184 	      do_tile:return (*dev_proc(dev, strip_tile_rectangle))
185 		    (dev, textures, x, y, width, height, color0, color1,
186 		     phase_x, phase_y);
187 	    case rop_usage_DT:
188 		/* This might be a case that tile_rectangle can handle. */
189 #define tile_case(c0, c1) color0 = c0, color1 = c1; goto do_tile;
190 		switch ((uint) rop) {	/* cast shuts up picky compilers */
191 		    case rop3_D & rop3_not(rop3_T):
192 			tile_case(gx_no_color_index, 0);
193 		    case rop3_D | rop3_T:
194 			tile_case(gx_no_color_index, 1);
195 		    case rop3_D & rop3_T:
196 			tile_case(0, gx_no_color_index);
197 		    case rop3_D | rop3_not(rop3_T):
198 			tile_case(1, gx_no_color_index);
199 		    default:;
200 		}
201 #undef tile_case
202 		fit_fill(dev, x, y, width, height);
203 		/* Source is not used; sdata et al may be garbage. */
204 		sdata = mdev->base;	/* arbitrary, as long as all */
205 					/* accesses are valid */
206 		sourcex = x;	/* guarantee no source skew */
207 		sraster = 0;
208 		break;
209 	    default:		/* rop_usage_[D]ST */
210 		fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
211 	}
212     }
213 
214 #ifdef DEBUG
215     if_debug1('b', "final rop=0x%x\n", rop);
216 #endif
217 
218     /* Set up transfer parameters. */
219     line_count = height;
220     srow = sdata;
221     drow = scan_line_base(mdev, y);
222     traster = textures->raster;
223     ty = y + phase_y;
224 
225     /* Loop over scan lines. */
226     for (; line_count-- > 0; drow += draster, srow += sraster, ++ty) {
227 	int sx = sourcex;
228 	int dx = x;
229 	int w = width;
230 	const byte *trow =
231 	textures->data + (ty % textures->rep_height) * traster;
232 	int xoff = x_offset(phase_x, ty, textures);
233 	int nw;
234 
235 	/* Loop over (horizontal) copies of the tile. */
236 	for (; w > 0; sx += nw, dx += nw, w -= nw) {
237 	    int dbit = dx & 7;
238 	    int sbit = sx & 7;
239 	    int sskew = sbit - dbit;
240 	    int tx = (dx + xoff) % textures->rep_width;
241 	    int tbit = tx & 7;
242 	    int tskew = tbit - dbit;
243 	    int left = nw = min(w, textures->size.x - tx);
244 	    byte lmask = 0xff >> dbit;
245 	    byte rmask = 0xff << (~(dbit + nw - 1) & 7);
246 	    byte mask = lmask;
247 	    int nx = 8 - dbit;
248 	    byte *dptr = drow + (dx >> 3);
249 	    const byte *sptr = srow + (sx >> 3);
250 	    const byte *tptr = trow + (tx >> 3);
251 
252 	    if (sskew < 0)
253 		--sptr, sskew += 8;
254 	    if (tskew < 0)
255 		--tptr, tskew += 8;
256 	    for (; left > 0;
257 		 left -= nx, mask = 0xff, nx = 8,
258 		 ++dptr, ++sptr, ++tptr
259 		) {
260 		byte dbyte = *dptr;
261 
262 #define fetch1(ptr, skew)\
263   (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr)
264 		byte sbyte = fetch1(sptr, sskew);
265 		byte tbyte = fetch1(tptr, tskew);
266 
267 #undef fetch1
268 		byte result =
269 		(*rop_proc_table[rop]) (dbyte, sbyte, tbyte);
270 
271 		if (left <= nx)
272 		    mask &= rmask;
273 		*dptr = (mask == 0xff ? result :
274 			 (result & mask) | (dbyte & ~mask));
275 	    }
276 	}
277     }
278 #ifdef DEBUG
279     if (gs_debug_c('B'))
280 	debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
281 			  height, "final dest bits");
282 #endif
283     return 0;
284 }
285