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