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