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