1 /* Copyright (C) 2001-2019 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.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /* 2-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_mapped2_copy_mono, mem_mapped2_copy_color, mem_mapped2_fill_rectangle);
31 
32 /* The device descriptor. */
33 const gx_device_memory mem_mapped2_device =
34 mem_device("image2", 2, 0,
35            mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
36            mem_mapped2_copy_mono, mem_mapped2_copy_color,
37            mem_mapped2_fill_rectangle, 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) >> 2)
42 
43 /* Define the 2-bit fill patterns. */
44 static const mono_fill_chunk tile_patterns[4] = {
45     fpat(0x00), fpat(0x55), fpat(0xaa), fpat(0xff)
46 };
47 
48 /* Fill a rectangle with a color. */
49 static int
mem_mapped2_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)50 mem_mapped2_fill_rectangle(gx_device * dev,
51                            int x, int y, int w, int h, gx_color_index color)
52 {
53     gx_device_memory * const mdev = (gx_device_memory *)dev;
54 
55     fit_fill(dev, x, y, w, h);
56     bits_fill_rectangle(scan_line_base(mdev, y), x << 1, mdev->raster,
57                         tile_patterns[color], w << 1, h);
58     return 0;
59 }
60 
61 /* Copy a bitmap. */
62 static int
mem_mapped2_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)63 mem_mapped2_copy_mono(gx_device * dev,
64                       const byte * base, int sourcex, int sraster,
65                       gx_bitmap_id id, int x, int y, int w, int h,
66                       gx_color_index zero, gx_color_index one)
67 {
68     gx_device_memory * const mdev = (gx_device_memory *)dev;
69     const byte *line;
70     int first_bit;
71     byte first_mask, b0, b1, bxor, left_mask, right_mask;
72     static const byte btab[4] = {0, 0x55, 0xaa, 0xff};
73     static const byte bmask[4] = {0xc0, 0x30, 0xc, 3};
74     static const byte lmask[4] = {0, 0xc0, 0xf0, 0xfc};
75 
76     declare_scan_ptr(dest);
77 
78     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
79     setup_rect(dest);
80     line = base + (sourcex >> 3);
81     first_bit = 0x80 >> (sourcex & 7);
82     first_mask = bmask[x & 3];
83     left_mask = lmask[x & 3];
84     right_mask = ~lmask[(x + w) & 3];
85     if ((x & 3) + w <= 3)
86         left_mask = right_mask = left_mask | right_mask;
87     b0 = btab[zero & 3];
88     b1 = btab[one & 3];
89     bxor = b0 ^ b1;
90     while (h-- > 0) {
91         register byte *pptr = (byte *) dest;
92         const byte *sptr = line;
93         register int sbyte = *sptr++;
94         register int bit = first_bit;
95         register byte mask = first_mask;
96         int count = w;
97 
98         /* We have 4 cases, of which only 2 really matter. */
99         if (one != gx_no_color_index) {
100             if (zero != gx_no_color_index) {	/* Copying an opaque bitmap. */
101                 byte data = (*pptr & left_mask) | (b0 & ~left_mask);
102 
103                 for ( ; ; ) {
104                     if (sbyte & bit)
105                         data ^= bxor & mask;
106                     if ((bit >>= 1) == 0)
107                         bit = 0x80, sbyte = *sptr++;
108                     if ((mask >>= 2) == 0)
109                         mask = 0xc0, *pptr++ = data, data = b0;
110                     if (--count <= 0)
111                         break;
112                 }
113                 if (mask != 0xc0)
114                     *pptr =
115                         (*pptr & right_mask) | (data & ~right_mask);
116             } else {		/* Filling a mask. */
117                 for ( ; ; ) {
118                     if (sbyte & bit)
119                         *pptr = (*pptr & ~mask) | (b1 & mask);
120                     if (--count <= 0)
121                         break;
122                     if ((bit >>= 1) == 0)
123                         bit = 0x80, sbyte = *sptr++;
124                     if ((mask >>= 2) == 0)
125                         mask = 0xc0, pptr++;
126                 }
127             }
128         } else {		/* Some other case. */
129             for ( ; ; ) {
130                 if (!(sbyte & bit)) {
131                     if (zero != gx_no_color_index)
132                         *pptr = (*pptr & ~mask) | (b0 & mask);
133                 }
134                 if (--count <= 0)
135                     break;
136                 if ((bit >>= 1) == 0)
137                     bit = 0x80, sbyte = *sptr++;
138                 if ((mask >>= 2) == 0)
139                     mask = 0xc0, pptr++;
140             }
141         }
142         line += sraster;
143         inc_ptr(dest, draster);
144     }
145     return 0;
146 }
147 
148 /* Copy a color bitmap. */
149 static int
mem_mapped2_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)150 mem_mapped2_copy_color(gx_device * dev,
151                        const byte * base, int sourcex, int sraster,
152                        gx_bitmap_id id, int x, int y, int w, int h)
153 {
154     int code;
155 
156     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
157     /* Use monobit copy_mono. */
158     /* Patch the width in the device temporarily. */
159     dev->width <<= 1;
160     code = (*dev_proc(&mem_mono_device, copy_mono))
161         (dev, base, sourcex << 1, sraster, id,
162          x << 1, y, w << 1, h, (gx_color_index) 0, (gx_color_index) 1);
163     /* Restore the correct width. */
164     dev->width >>= 1;
165     return code;
166 }
167 
168 /* ================ "Word"-oriented device ================ */
169 
170 /* Note that on a big-endian machine, this is the same as the */
171 /* standard byte-oriented-device. */
172 
173 #if !ARCH_IS_BIG_ENDIAN
174 
175 /* Procedures */
176 declare_mem_procs(mem2_word_copy_mono, mem2_word_copy_color, mem2_word_fill_rectangle);
177 
178 /* Here is the device descriptor. */
179 const gx_device_memory mem_mapped2_word_device =
180 mem_full_device("image2w", 2, 0, mem_open,
181                 mem_mapped_map_rgb_color, mem_mapped_map_color_rgb,
182                 mem2_word_copy_mono, mem2_word_copy_color,
183                 mem2_word_fill_rectangle, gx_default_map_cmyk_color,
184                 gx_default_strip_tile_rectangle, gx_no_strip_copy_rop,
185                 mem_word_get_bits_rectangle);
186 
187 /* Fill a rectangle with a color. */
188 static int
mem2_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)189 mem2_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
190                          gx_color_index color)
191 {
192     gx_device_memory * const mdev = (gx_device_memory *)dev;
193     byte *base;
194     uint raster;
195 
196     fit_fill(dev, x, y, w, h);
197     base = scan_line_base(mdev, y);
198     raster = mdev->raster;
199     mem_swap_byte_rect(base, raster, x << 1, w << 1, h, true);
200     bits_fill_rectangle(base, x << 1, raster,
201                         tile_patterns[color], w << 1, h);
202     mem_swap_byte_rect(base, raster, x << 1, w << 1, h, true);
203     return 0;
204 }
205 
206 /* Copy a bitmap. */
207 static int
mem2_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)208 mem2_word_copy_mono(gx_device * dev,
209                     const byte * base, int sourcex, int sraster,
210                     gx_bitmap_id id, int x, int y, int w, int h,
211                     gx_color_index zero, gx_color_index one)
212 {
213     gx_device_memory * const mdev = (gx_device_memory *)dev;
214     byte *row;
215     uint raster;
216     bool store;
217 
218     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
219     row = scan_line_base(mdev, y);
220     raster = mdev->raster;
221     store = (zero != gx_no_color_index && one != gx_no_color_index);
222     mem_swap_byte_rect(row, raster, x << 1, w << 1, h, store);
223     mem_mapped2_copy_mono(dev, base, sourcex, sraster, id,
224                           x, y, w, h, zero, one);
225     mem_swap_byte_rect(row, raster, x << 1, w << 1, h, false);
226     return 0;
227 }
228 
229 /* Copy a color bitmap. */
230 static int
mem2_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)231 mem2_word_copy_color(gx_device * dev,
232                      const byte * base, int sourcex, int sraster,
233                      gx_bitmap_id id, int x, int y, int w, int h)
234 {
235     int code;
236 
237     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
238     /* Use monobit copy_mono. */
239     /* Patch the width in the device temporarily. */
240     dev->width <<= 1;
241     code = (*dev_proc(&mem_mono_word_device, copy_mono))
242         (dev, base, sourcex << 1, sraster, id,
243          x << 1, y, w << 1, h, (gx_color_index) 0, (gx_color_index) 1);
244     /* Restore the correct width. */
245     dev->width >>= 1;
246     return code;
247 }
248 
249 #endif /* !ARCH_IS_BIG_ENDIAN */
250