/src/ghostpdl/base/gdevm4.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, 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, mem_dev_initialize_device_procs); |
35 | | |
36 | | const gdev_mem_functions gdev_mem_fns_4 = |
37 | | { |
38 | | mem_mapped_map_rgb_color, |
39 | | mem_mapped_map_color_rgb, |
40 | | mem_mapped4_fill_rectangle, |
41 | | mem_mapped4_copy_mono, |
42 | | mem_mapped4_copy_color, |
43 | | gx_default_copy_alpha, |
44 | | gx_default_strip_tile_rectangle, |
45 | | mem_gray_strip_copy_rop2, |
46 | | mem_get_bits_rectangle |
47 | | }; |
48 | | |
49 | | /* Convert x coordinate to byte offset in scan line. */ |
50 | | #undef x_to_byte |
51 | 61.5M | #define x_to_byte(x) ((x) >> 1) |
52 | | |
53 | | /* Define the 4-bit fill patterns. */ |
54 | | static const mono_fill_chunk tile_patterns[16] = |
55 | | {fpat(0x00), fpat(0x11), fpat(0x22), fpat(0x33), |
56 | | fpat(0x44), fpat(0x55), fpat(0x66), fpat(0x77), |
57 | | fpat(0x88), fpat(0x99), fpat(0xaa), fpat(0xbb), |
58 | | fpat(0xcc), fpat(0xdd), fpat(0xee), fpat(0xff) |
59 | | }; |
60 | | |
61 | | /* Fill a rectangle with a color. */ |
62 | | static int |
63 | | mem_mapped4_fill_rectangle(gx_device * dev, |
64 | | int x, int y, int w, int h, gx_color_index color) |
65 | 162M | { |
66 | 162M | gx_device_memory * const mdev = (gx_device_memory *)dev; |
67 | | |
68 | 162M | fit_fill(dev, x, y, w, h); |
69 | 137M | bits_fill_rectangle(scan_line_base(mdev, y), x << 2, mdev->raster, |
70 | 137M | tile_patterns[color], w << 2, h); |
71 | 137M | return 0; |
72 | 162M | } |
73 | | |
74 | | /* Copy a bitmap. */ |
75 | | static int |
76 | | mem_mapped4_copy_mono(gx_device * dev, |
77 | | const byte * base, int sourcex, int sraster, gx_bitmap_id id, |
78 | | int x, int y, int w, int h, gx_color_index zero, gx_color_index one) |
79 | 61.5M | { |
80 | 61.5M | gx_device_memory * const mdev = (gx_device_memory *)dev; |
81 | 61.5M | const byte *line; |
82 | 61.5M | declare_scan_ptr(dest); |
83 | 61.5M | byte invert, bb; |
84 | | |
85 | 61.5M | fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); |
86 | 61.5M | setup_rect(dest); |
87 | 61.5M | line = base + (sourcex >> 3); |
88 | | /* Divide into opaque and masked cases. */ |
89 | 61.5M | if (one == gx_no_color_index) { |
90 | 20.4k | if (zero == gx_no_color_index) |
91 | 0 | return 0; /* nothing to do */ |
92 | 20.4k | invert = 0xff; |
93 | 20.4k | bb = ((byte) zero << 4) | (byte) zero; |
94 | 61.5M | } else if (zero == gx_no_color_index) { |
95 | 6.22M | invert = 0; |
96 | 6.22M | bb = ((byte) one << 4) | (byte) one; |
97 | 55.2M | } else { |
98 | | /* Opaque case. */ |
99 | 55.2M | int shift = ~(sourcex ^ x) & 1; |
100 | 55.2M | byte oz[4]; |
101 | | |
102 | 55.2M | oz[0] = (byte)((zero << 4) | zero); |
103 | 55.2M | oz[1] = (byte)((zero << 4) | one); |
104 | 55.2M | oz[2] = (byte)((one << 4) | zero); |
105 | 55.2M | oz[3] = (byte)((one << 4) | one); |
106 | 69.0M | do { |
107 | 69.0M | register byte *dptr = (byte *) dest; |
108 | 69.0M | const byte *sptr = line; |
109 | 69.0M | register uint sbyte = *sptr++; |
110 | 69.0M | register int sbit = ~sourcex & 7; |
111 | 69.0M | int count = w; |
112 | | |
113 | | /* |
114 | | * If the first source bit corresponds to an odd X in the |
115 | | * destination, process it now. |
116 | | */ |
117 | 69.0M | if (x & 1) { |
118 | 30.0M | *dptr = (*dptr & 0xf0) | |
119 | 30.0M | ((sbyte >> sbit) & 1 ? one : zero); |
120 | 30.0M | --count; /* may now be 0 */ |
121 | 30.0M | if (--sbit < 0) |
122 | 2.59M | sbit = 7, sbyte = *sptr++; |
123 | 30.0M | ++dptr; |
124 | 30.0M | } |
125 | | /* |
126 | | * Now we know the next destination X is even. We want to |
127 | | * process 2 source bits at a time from now on, so set things up |
128 | | * properly depending on whether the next source X (bit) is even |
129 | | * or odd. In both even and odd cases, the active source bits |
130 | | * are in bits 8..1 of sbyte. |
131 | | */ |
132 | 69.0M | sbyte <<= shift; |
133 | 69.0M | sbit += shift - 1; |
134 | | /* |
135 | | * Now bit # sbit+1 is the most significant unprocessed bit |
136 | | * in sbyte. -1 <= sbit <= 7; sbit is odd. |
137 | | * Note that if sbit = -1, all of sbyte has been processed. |
138 | | * |
139 | | * Continue processing pairs of bits in the first source byte. |
140 | | */ |
141 | 200M | while (count >= 2 && sbit >= 0) { |
142 | 131M | *dptr++ = oz[(sbyte >> sbit) & 3]; |
143 | 131M | sbit -= 2, count -= 2; |
144 | 131M | } |
145 | | /* |
146 | | * Now sbit = -1 iff we have processed the entire first source |
147 | | * byte. |
148 | | * |
149 | | * Process full source bytes. |
150 | | */ |
151 | 69.0M | if (shift) { |
152 | 47.4M | sbyte >>= 1; /* in case count < 8 */ |
153 | 525M | for (; count >= 8; dptr += 4, count -= 8) { |
154 | 477M | sbyte = *sptr++; |
155 | 477M | dptr[0] = oz[sbyte >> 6]; |
156 | 477M | dptr[1] = oz[(sbyte >> 4) & 3]; |
157 | 477M | dptr[2] = oz[(sbyte >> 2) & 3]; |
158 | 477M | dptr[3] = oz[sbyte & 3]; |
159 | 477M | } |
160 | 47.4M | sbyte <<= 1; |
161 | 47.4M | } else { |
162 | 193M | for (; count >= 8; dptr += 4, count -= 8) { |
163 | 171M | sbyte = (sbyte << 8) | *sptr++; |
164 | 171M | dptr[0] = oz[(sbyte >> 7) & 3]; |
165 | 171M | dptr[1] = oz[(sbyte >> 5) & 3]; |
166 | 171M | dptr[2] = oz[(sbyte >> 3) & 3]; |
167 | 171M | dptr[3] = oz[(sbyte >> 1) & 3]; |
168 | 171M | } |
169 | 21.6M | } |
170 | 69.0M | if (!count) |
171 | 22.4M | continue; |
172 | | /* |
173 | | * Process pairs of bits in the final source byte. Note that |
174 | | * if sbit > 0, this is still the first source byte (the |
175 | | * full-byte loop wasn't executed). |
176 | | */ |
177 | 46.5M | if (sbit < 0) { |
178 | 35.3M | sbyte = (sbyte << 8) | (*sptr << shift); |
179 | 35.3M | sbit = 7; |
180 | 35.3M | } |
181 | 102M | while (count >= 2) { |
182 | 56.1M | *dptr++ = oz[(sbyte >> sbit) & 3]; |
183 | 56.1M | sbit -= 2, count -= 2; |
184 | 56.1M | } |
185 | | /* |
186 | | * If the final source bit corresponds to an even X value, |
187 | | * process it now. |
188 | | */ |
189 | 46.5M | if (count) { |
190 | 31.2M | *dptr = (*dptr & 0x0f) | |
191 | 31.2M | (((sbyte >> sbit) & 2 ? one : zero) << 4); |
192 | 31.2M | } |
193 | 69.0M | } while ((line += sraster, inc_ptr(dest, draster), --h) > 0); |
194 | 0 | return 0; |
195 | 55.2M | } |
196 | | /* Masked case. */ |
197 | 93.1M | do { |
198 | 93.1M | register byte *dptr = (byte *) dest; |
199 | 93.1M | const byte *sptr = line; |
200 | 93.1M | register int sbyte = *sptr++ ^ invert; |
201 | 93.1M | register int sbit = 0x80 >> (sourcex & 7); |
202 | 93.1M | register byte mask = (x & 1 ? 0x0f : 0xf0); |
203 | 93.1M | int count = w; |
204 | | |
205 | 1.54G | do { |
206 | 1.54G | if (sbyte & sbit) |
207 | 498M | *dptr = (*dptr & ~mask) | (bb & mask); |
208 | 1.54G | if ((sbit >>= 1) == 0) |
209 | 158M | sbit = 0x80, sbyte = *sptr++ ^ invert; |
210 | 1.54G | dptr += (mask = ~mask) >> 7; |
211 | 1.54G | } while (--count > 0); |
212 | 93.1M | line += sraster; |
213 | 93.1M | inc_ptr(dest, draster); |
214 | 93.1M | } while (--h > 0); |
215 | 6.24M | return 0; |
216 | 61.5M | } |
217 | | |
218 | | /* Copy a color bitmap. */ |
219 | | static int |
220 | | mem_mapped4_copy_color(gx_device * dev, |
221 | | const byte * base, int sourcex, int sraster, gx_bitmap_id id, |
222 | | int x, int y, int w, int h) |
223 | 202M | { |
224 | | /* Use monobit copy_mono. */ |
225 | 202M | int code; |
226 | | |
227 | | /* Patch the width in the device temporarily. */ |
228 | 202M | dev->width <<= 2; |
229 | 202M | code = mem_mono_copy_mono(dev, base, sourcex << 2, sraster, id, |
230 | 202M | x << 2, y, w << 2, h, |
231 | 202M | (gx_color_index) 0, (gx_color_index) 1); |
232 | | /* Restore the correct width. */ |
233 | 202M | dev->width >>= 2; |
234 | 202M | return code; |
235 | 202M | } |
236 | | |
237 | | /* ================ "Word"-oriented device ================ */ |
238 | | |
239 | | /* Note that on a big-endian machine, this is the same as the */ |
240 | | /* standard byte-oriented-device. */ |
241 | | |
242 | | #if !ARCH_IS_BIG_ENDIAN |
243 | | |
244 | | /* Procedures */ |
245 | | declare_mem_procs(mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle); |
246 | | |
247 | | /* Here is the device descriptor. */ |
248 | | const gx_device_memory mem_mapped4_word_device = |
249 | | mem_device("image4w", 4, 0, mem_word_dev_initialize_device_procs); |
250 | | |
251 | | const gdev_mem_functions gdev_mem_fns_4w = |
252 | | { |
253 | | mem_mapped_map_rgb_color, |
254 | | mem_mapped_map_color_rgb, |
255 | | mem4_word_fill_rectangle, |
256 | | mem4_word_copy_mono, |
257 | | mem4_word_copy_color, |
258 | | gx_default_copy_alpha, |
259 | | gx_default_strip_tile_rectangle, |
260 | | gx_no_strip_copy_rop2, |
261 | | mem_word_get_bits_rectangle |
262 | | }; |
263 | | |
264 | | /* Fill a rectangle with a color. */ |
265 | | static int |
266 | | mem4_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h, |
267 | | gx_color_index color) |
268 | 0 | { |
269 | 0 | gx_device_memory * const mdev = (gx_device_memory *)dev; |
270 | 0 | byte *base; |
271 | 0 | size_t raster; |
272 | |
|
273 | 0 | fit_fill(dev, x, y, w, h); |
274 | 0 | base = scan_line_base(mdev, y); |
275 | 0 | raster = mdev->raster; |
276 | 0 | mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true); |
277 | 0 | bits_fill_rectangle(base, x << 2, raster, |
278 | 0 | tile_patterns[color], w << 2, h); |
279 | 0 | mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true); |
280 | 0 | return 0; |
281 | 0 | } |
282 | | |
283 | | /* Copy a bitmap. */ |
284 | | static int |
285 | | mem4_word_copy_mono(gx_device * dev, |
286 | | const byte * base, int sourcex, int sraster, gx_bitmap_id id, |
287 | | int x, int y, int w, int h, gx_color_index zero, gx_color_index one) |
288 | 0 | { |
289 | 0 | gx_device_memory * const mdev = (gx_device_memory *)dev; |
290 | 0 | byte *row; |
291 | 0 | size_t raster; |
292 | 0 | bool store; |
293 | |
|
294 | 0 | fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); |
295 | 0 | row = scan_line_base(mdev, y); |
296 | 0 | raster = mdev->raster; |
297 | 0 | store = (zero != gx_no_color_index && one != gx_no_color_index); |
298 | 0 | mem_swap_byte_rect(row, raster, x << 2, w << 2, h, store); |
299 | 0 | mem_mapped4_copy_mono(dev, base, sourcex, sraster, id, |
300 | 0 | x, y, w, h, zero, one); |
301 | 0 | mem_swap_byte_rect(row, raster, x << 2, w << 2, h, false); |
302 | 0 | return 0; |
303 | 0 | } |
304 | | |
305 | | /* Copy a color bitmap. */ |
306 | | static int |
307 | | mem4_word_copy_color(gx_device * dev, |
308 | | const byte * base, int sourcex, int sraster, gx_bitmap_id id, |
309 | | int x, int y, int w, int h) |
310 | 0 | { |
311 | 0 | int code; |
312 | |
|
313 | 0 | fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); |
314 | | /* Use monobit copy_mono. */ |
315 | | /* Patch the width in the device temporarily. */ |
316 | 0 | dev->width <<= 2; |
317 | 0 | code = gdev_mem_word_functions_for_bits(1)->copy_mono |
318 | 0 | (dev, base, sourcex << 2, sraster, id, |
319 | 0 | x << 2, y, w << 2, h, (gx_color_index) 0, (gx_color_index) 1); |
320 | | /* Restore the correct width. */ |
321 | 0 | dev->width >>= 2; |
322 | 0 | return code; |
323 | 0 | } |
324 | | |
325 | | #endif /* !ARCH_IS_BIG_ENDIAN */ |