xref: /plan9/sys/src/cmd/gs/src/gdevm4.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999 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: gdevm4.c,v 1.4 2002/02/21 22:24:51 giles Exp $ */
18 /* 4-bit-per-pixel "memory" (stored bitmap) device */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gxdevice.h"
22 #include "gxdevmem.h"		/* semi-public definitions */
23 #include "gdevmem.h"		/* private definitions */
24 
25 /* ================ Standard (byte-oriented) device ================ */
26 
27 #undef chunk
28 #define chunk byte
29 #define fpat(byt) mono_fill_make_pattern(byt)
30 
31 /* Procedures */
32 declare_mem_procs(mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle);
33 
34 /* The device descriptor. */
35 const gx_device_memory mem_mapped4_device =
36 mem_device("image4", 4, 0,
37 	   mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
38   mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle,
39 	   mem_gray_strip_copy_rop);
40 
41 /* Convert x coordinate to byte offset in scan line. */
42 #undef x_to_byte
43 #define x_to_byte(x) ((x) >> 1)
44 
45 /* Define the 4-bit fill patterns. */
46 static const mono_fill_chunk tile_patterns[16] =
47 {fpat(0x00), fpat(0x11), fpat(0x22), fpat(0x33),
48  fpat(0x44), fpat(0x55), fpat(0x66), fpat(0x77),
49  fpat(0x88), fpat(0x99), fpat(0xaa), fpat(0xbb),
50  fpat(0xcc), fpat(0xdd), fpat(0xee), fpat(0xff)
51 };
52 
53 
54 /* Fill a rectangle with a color. */
55 private int
mem_mapped4_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)56 mem_mapped4_fill_rectangle(gx_device * dev,
57 			   int x, int y, int w, int h, gx_color_index color)
58 {
59     gx_device_memory * const mdev = (gx_device_memory *)dev;
60 
61     fit_fill(dev, x, y, w, h);
62     bits_fill_rectangle(scan_line_base(mdev, y), x << 2, mdev->raster,
63 			tile_patterns[color], w << 2, h);
64     return 0;
65 }
66 
67 /* Copy a bitmap. */
68 private int
mem_mapped4_copy_mono(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)69 mem_mapped4_copy_mono(gx_device * dev,
70 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
71 	int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
72 {
73     gx_device_memory * const mdev = (gx_device_memory *)dev;
74     const byte *line;
75     declare_scan_ptr(dest);
76     byte invert, bb;
77 
78     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
79     setup_rect(dest);
80     line = base + (sourcex >> 3);
81     /* Divide into opaque and masked cases. */
82     if (one == gx_no_color_index) {
83 	if (zero == gx_no_color_index)
84 	    return 0;		/* nothing to do */
85 	invert = 0xff;
86 	bb = ((byte) zero << 4) | (byte) zero;
87     } else if (zero == gx_no_color_index) {
88 	invert = 0;
89 	bb = ((byte) one << 4) | (byte) one;
90     } else {
91 	/* Opaque case. */
92 	int shift = ~(sourcex ^ x) & 1;
93 	byte oz[4];
94 
95 	oz[0] = (byte)((zero << 4) | zero);
96 	oz[1] = (byte)((zero << 4) | one);
97 	oz[2] = (byte)((one << 4) | zero);
98 	oz[3] = (byte)((one << 4) | one);
99 	do {
100 	    register byte *dptr = (byte *) dest;
101 	    const byte *sptr = line;
102 	    register uint sbyte = *sptr++;
103 	    register int sbit = ~sourcex & 7;
104 	    int count = w;
105 
106 	    /*
107 	     * If the first source bit corresponds to an odd X in the
108 	     * destination, process it now.
109 	     */
110 	    if (x & 1) {
111 		*dptr = (*dptr & 0xf0) |
112 		    ((sbyte >> sbit) & 1 ? one : zero);
113 		--count;	/* may now be 0 */
114 		if (--sbit < 0)
115 		    sbit = 7, sbyte = *sptr++;
116 		++dptr;
117 	    }
118 	    /*
119 	     * Now we know the next destination X is even.  We want to
120 	     * process 2 source bits at a time from now on, so set things up
121 	     * properly depending on whether the next source X (bit) is even
122 	     * or odd.  In both even and odd cases, the active source bits
123 	     * are in bits 8..1 of sbyte.
124 	     */
125 	    sbyte <<= shift;
126 	    sbit += shift - 1;
127 	    /*
128 	     * Now bit # sbit+1 is the most significant unprocessed bit
129 	     * in sbyte.  -1 <= sbit <= 7; sbit is odd.
130 	     * Note that if sbit = -1, all of sbyte has been processed.
131 	     *
132 	     * Continue processing pairs of bits in the first source byte.
133 	     */
134 	    while (count >= 2 && sbit >= 0) {
135 		*dptr++ = oz[(sbyte >> sbit) & 3];
136 		sbit -= 2, count -= 2;
137 	    }
138 	    /*
139 	     * Now sbit = -1 iff we have processed the entire first source
140 	     * byte.
141 	     *
142 	     * Process full source bytes.
143 	     */
144 	    if (shift) {
145 		sbyte >>= 1;	/* in case count < 8 */
146 		for (; count >= 8; dptr += 4, count -= 8) {
147 		    sbyte = *sptr++;
148 		    dptr[0] = oz[sbyte >> 6];
149 		    dptr[1] = oz[(sbyte >> 4) & 3];
150 		    dptr[2] = oz[(sbyte >> 2) & 3];
151 		    dptr[3] = oz[sbyte & 3];
152 		}
153 		sbyte <<= 1;
154 	    } else {
155 		for (; count >= 8; dptr += 4, count -= 8) {
156 		    sbyte = (sbyte << 8) | *sptr++;
157 		    dptr[0] = oz[(sbyte >> 7) & 3];
158 		    dptr[1] = oz[(sbyte >> 5) & 3];
159 		    dptr[2] = oz[(sbyte >> 3) & 3];
160 		    dptr[3] = oz[(sbyte >> 1) & 3];
161 		}
162 	    }
163 	    if (!count)
164 		continue;
165 	    /*
166 	     * Process pairs of bits in the final source byte.  Note that
167 	     * if sbit > 0, this is still the first source byte (the
168 	     * full-byte loop wasn't executed).
169 	     */
170 	    if (sbit < 0) {
171 		sbyte = (sbyte << 8) | (*sptr << shift);
172 		sbit = 7;
173 	    }
174 	    while (count >= 2) {
175 		*dptr++ = oz[(sbyte >> sbit) & 3];
176 		sbit -= 2, count -= 2;
177 	    }
178 	    /*
179 	     * If the final source bit corresponds to an even X value,
180 	     * process it now.
181 	     */
182 	    if (count) {
183 		*dptr = (*dptr & 0x0f) |
184 		    (((sbyte >> sbit) & 2 ? one : zero) << 4);
185 	    }
186 	} while ((line += sraster, inc_ptr(dest, draster), --h) > 0);
187 	return 0;
188     }
189     /* Masked case. */
190     do {
191 	register byte *dptr = (byte *) dest;
192 	const byte *sptr = line;
193 	register int sbyte = *sptr++ ^ invert;
194 	register int sbit = 0x80 >> (sourcex & 7);
195 	register byte mask = (x & 1 ? 0x0f : 0xf0);
196 	int count = w;
197 
198 	do {
199 	    if (sbyte & sbit)
200 		*dptr = (*dptr & ~mask) | (bb & mask);
201 	    if ((sbit >>= 1) == 0)
202 		sbit = 0x80, sbyte = *sptr++ ^ invert;
203 	    dptr += (mask = ~mask) >> 7;
204 	} while (--count > 0);
205 	line += sraster;
206 	inc_ptr(dest, draster);
207     } while (--h > 0);
208     return 0;
209 }
210 
211 /* Copy a color bitmap. */
212 private int
mem_mapped4_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)213 mem_mapped4_copy_color(gx_device * dev,
214 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
215 		       int x, int y, int w, int h)
216 {
217     /* Use monobit copy_mono. */
218     int code;
219 
220     /* Patch the width in the device temporarily. */
221     dev->width <<= 2;
222     code = (*dev_proc(&mem_mono_device, copy_mono))
223 	(dev, base, sourcex << 2, sraster, id,
224 	 x << 2, y, w << 2, h, (gx_color_index) 0, (gx_color_index) 1);
225     /* Restore the correct width. */
226     dev->width >>= 2;
227     return code;
228 }
229 
230 /* ================ "Word"-oriented device ================ */
231 
232 /* Note that on a big-endian machine, this is the same as the */
233 /* standard byte-oriented-device. */
234 
235 #if !arch_is_big_endian
236 
237 /* Procedures */
238 declare_mem_procs(mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle);
239 
240 /* Here is the device descriptor. */
241 const gx_device_memory mem_mapped4_word_device =
242 mem_full_device("image4w", 4, 0, mem_open,
243 		mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
244 	mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle,
245 		gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
246 		gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
247 
248 /* Fill a rectangle with a color. */
249 private int
mem4_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)250 mem4_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
251 			 gx_color_index color)
252 {
253     gx_device_memory * const mdev = (gx_device_memory *)dev;
254     byte *base;
255     uint raster;
256 
257     fit_fill(dev, x, y, w, h);
258     base = scan_line_base(mdev, y);
259     raster = mdev->raster;
260     mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
261     bits_fill_rectangle(base, x << 2, raster,
262 			tile_patterns[color], w << 2, h);
263     mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
264     return 0;
265 }
266 
267 /* Copy a bitmap. */
268 private int
mem4_word_copy_mono(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)269 mem4_word_copy_mono(gx_device * dev,
270 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
271 	int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
272 {
273     gx_device_memory * const mdev = (gx_device_memory *)dev;
274     byte *row;
275     uint raster;
276     bool store;
277 
278     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
279     row = scan_line_base(mdev, y);
280     raster = mdev->raster;
281     store = (zero != gx_no_color_index && one != gx_no_color_index);
282     mem_swap_byte_rect(row, raster, x << 2, w << 2, h, store);
283     mem_mapped4_copy_mono(dev, base, sourcex, sraster, id,
284 			  x, y, w, h, zero, one);
285     mem_swap_byte_rect(row, raster, x << 2, w << 2, h, false);
286     return 0;
287 }
288 
289 /* Copy a color bitmap. */
290 private int
mem4_word_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)291 mem4_word_copy_color(gx_device * dev,
292 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
293 		     int x, int y, int w, int h)
294 {
295     int code;
296 
297     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
298     /* Use monobit copy_mono. */
299     /* Patch the width in the device temporarily. */
300     dev->width <<= 2;
301     code = (*dev_proc(&mem_mono_word_device, copy_mono))
302 	(dev, base, sourcex << 2, sraster, id,
303 	 x << 2, y, w << 2, h, (gx_color_index) 0, (gx_color_index) 1);
304     /* Restore the correct width. */
305     dev->width >>= 2;
306     return code;
307 }
308 
309 #endif /* !arch_is_big_endian */
310