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