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 /* 64-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 /* Define debugging statistics. */
24 #if defined(DEBUG) && !defined(GS_THREADSAFE)
25 struct stats_mem64_s {
26 long
27 fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
28 fprevc[257];
29 double ftotal;
30 } stats_mem64;
31 static int prev_count = 0;
32 static gx_color_index prev_colors[256];
33 # define INCR(v) (++(stats_mem64.v))
34 #else
35 # define INCR(v) DO_NOTHING
36 #endif
37
38 /* ================ Standard (byte-oriented) device ================ */
39
40 #undef chunk
41 #define chunk byte
42 #define PIXEL_SIZE 2
43
44 /* Procedures */
45 declare_mem_procs(mem_true64_copy_mono, mem_true64_copy_color, mem_true64_fill_rectangle);
46
47 /* The device descriptor. */
48 const gx_device_memory mem_true64_device =
49 mem_full_alpha_device("image64", 64, 0, mem_open,
50 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
51 mem_true64_copy_mono, mem_true64_copy_color, mem_true64_fill_rectangle,
52 gx_default_map_cmyk_color, gx_default_copy_alpha,
53 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop,
54 mem_get_bits_rectangle);
55
56 /* Convert x coordinate to byte offset in scan line. */
57 #undef x_to_byte
58 #define x_to_byte(x) ((x) << 3)
59
60 /* Put a 64-bit color into the bitmap. */
61 #define put8(ptr, abcd, efgh)\
62 (ptr)[0] = abcd, (ptr)[1] = efgh
63 /* Free variables: [m]dev, abcd, degh. */
64 #if ARCH_IS_BIG_ENDIAN
65 /* Unpack a color into 32 bit chunks. */
66 # define declare_unpack_color(abcd, efgh, color)\
67 bits32 abcd = (bits32)((color) >> 32);\
68 bits32 efgh = (bits32)(color)
69 #else
70 /* Unpack a color into 32 bit chunks. */
71 # define declare_unpack_color(abcd, efgh, color)\
72 bits32 abcd = (bits32)((0x000000ff & (((color) >> 28) >> 28)) |\
73 (0x0000ff00 & (((color) >> 24) >> 16)) |\
74 (0x00ff0000 & ((color) >> 24)) |\
75 (0xff000000 & ((color) >> 8)));\
76 bits32 efgh = (bits32)((0x000000ff & ((color) >> 24)) |\
77 (0x0000ff00 & ((color) >> 8)) |\
78 (0x00ff0000 & ((color) << 8)) |\
79 (0xff000000 & ((color) << 24)))
80 #endif
81 #define dest32 ((bits32 *)dest)
82
83 /* Fill a rectangle with a color. */
84 static int
mem_true64_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)85 mem_true64_fill_rectangle(gx_device * dev,
86 int x, int y, int w, int h, gx_color_index color)
87 {
88 gx_device_memory * const mdev = (gx_device_memory *)dev;
89 declare_scan_ptr(dest);
90 declare_unpack_color(abcd, efgh, color);
91
92 /*
93 * In order to avoid testing w > 0 and h > 0 twice, we defer
94 * executing setup_rect, and use fit_fill_xywh instead of
95 * fit_fill.
96 */
97 fit_fill_xywh(dev, x, y, w, h);
98 INCR(fill);
99 #if defined(DEBUG) && !defined(GS_THREADSAFE)
100 stats_mem64.ftotal += w;
101 #endif
102 if (h <= 0)
103 return 0;
104 if (w >= 5) {
105 INCR(fwide);
106 setup_rect(dest);
107 #if defined(DEBUG) && !defined(GS_THREADSAFE)
108 {
109 int ci;
110 for (ci = 0; ci < prev_count; ++ci)
111 if (prev_colors[ci] == color)
112 break;
113 INCR(fprevc[ci]);
114 if (ci == prev_count) {
115 if (ci < countof(prev_colors))
116 ++prev_count;
117 else
118 --ci;
119 }
120 if (ci) {
121 memmove(&prev_colors[1], &prev_colors[0],
122 ci * sizeof(prev_colors[0]));
123 prev_colors[0] = color;
124 }
125 }
126 #endif
127 INCR(fcolor[min(w, 100)]);
128 while (h-- > 0) {
129 register bits32 *pptr = dest32;
130 int w1 = w;
131
132 while (w1 >= 4) {
133 put8(pptr, abcd, efgh);
134 put8(pptr + 2, abcd, efgh);
135 put8(pptr + 4, abcd, efgh);
136 put8(pptr + 6, abcd, efgh);
137 pptr += 4 * PIXEL_SIZE;
138 w1 -= 4;
139 }
140 switch (w1) {
141 case 1:
142 put8(pptr, abcd, efgh);
143 break;
144 case 2:
145 put8(pptr, abcd, efgh);
146 put8(pptr + 2, abcd, efgh);
147 break;
148 case 3:
149 put8(pptr, abcd, efgh);
150 put8(pptr + 2, abcd, efgh);
151 put8(pptr + 4, abcd, efgh);
152 break;
153 case 0:
154 ;
155 }
156 inc_ptr(dest, draster);
157 }
158 } else { /* w < 5 */
159 INCR(fnarrow[max(w, 0)]);
160 setup_rect(dest);
161 switch (w) {
162 case 4:
163 do {
164 put8(dest32, abcd, efgh);
165 put8(dest32 + 2, abcd, efgh);
166 put8(dest32 + 4, abcd, efgh);
167 put8(dest32 + 6, abcd, efgh);
168 inc_ptr(dest, draster);
169 }
170 while (--h);
171 break;
172 case 3:
173 do {
174 put8(dest32, abcd, efgh);
175 put8(dest32 + 2, abcd, efgh);
176 put8(dest32 + 4, abcd, efgh);
177 inc_ptr(dest, draster);
178 }
179 while (--h);
180 break;
181 case 2:
182 do {
183 put8(dest32, abcd, efgh);
184 put8(dest32 + 2, abcd, efgh);
185 inc_ptr(dest, draster);
186 }
187 while (--h);
188 break;
189 case 1:
190 do {
191 put8(dest32, abcd, efgh);
192 inc_ptr(dest, draster);
193 }
194 while (--h);
195 break;
196 case 0:
197 default:
198 ;
199 }
200 }
201 return 0;
202 }
203
204 /* Copy a monochrome bitmap. */
205 static int
mem_true64_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)206 mem_true64_copy_mono(gx_device * dev,
207 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
208 int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
209 {
210 gx_device_memory * const mdev = (gx_device_memory *)dev;
211 const byte *line;
212 int sbit;
213 int first_bit;
214
215 declare_scan_ptr(dest);
216
217 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
218 setup_rect(dest);
219 line = base + (sourcex >> 3);
220 sbit = sourcex & 7;
221 first_bit = 0x80 >> sbit;
222 if (zero != gx_no_color_index) { /* Loop for halftones or inverted masks */
223 /* (never used). */
224 declare_unpack_color(abcd0, efgh0, zero);
225 declare_unpack_color(abcd1, efgh1, one);
226 while (h-- > 0) {
227 register bits32 *pptr = dest32;
228 const byte *sptr = line;
229 register int sbyte = *sptr++;
230 register int bit = first_bit;
231 int count = w;
232
233 do {
234 if (sbyte & bit) {
235 if (one != gx_no_color_index)
236 put8(pptr, abcd1, efgh1);
237 } else
238 put8(pptr, abcd0, efgh0);
239 pptr += PIXEL_SIZE;
240 if ((bit >>= 1) == 0)
241 bit = 0x80, sbyte = *sptr++;
242 }
243 while (--count > 0);
244 line += sraster;
245 inc_ptr(dest, draster);
246 }
247 } else if (one != gx_no_color_index) { /* Loop for character and pattern masks. */
248 /* This is used heavily. */
249 declare_unpack_color(abcd1, efgh1, one);
250 int first_mask = first_bit << 1;
251 int first_count, first_skip;
252
253 if (sbit + w > 8)
254 first_mask -= 1,
255 first_count = 8 - sbit;
256 else
257 first_mask -= first_mask >> w,
258 first_count = w;
259 first_skip = first_count * PIXEL_SIZE;
260 while (h-- > 0) {
261 register bits32 *pptr = dest32;
262 const byte *sptr = line;
263 register int sbyte = *sptr++ & first_mask;
264 int count = w - first_count;
265
266 if (sbyte) {
267 register int bit = first_bit;
268
269 do {
270 if (sbyte & bit)
271 put8(pptr, abcd1, efgh1);
272 pptr += PIXEL_SIZE;
273 }
274 while ((bit >>= 1) & first_mask);
275 } else
276 pptr += first_skip;
277 while (count >= 8) {
278 sbyte = *sptr++;
279 if (sbyte & 0xf0) {
280 if (sbyte & 0x80)
281 put8(pptr, abcd1, efgh1);
282 if (sbyte & 0x40)
283 put8(pptr + 2, abcd1, efgh1);
284 if (sbyte & 0x20)
285 put8(pptr + 4, abcd1, efgh1);
286 if (sbyte & 0x10)
287 put8(pptr + 6, abcd1, efgh1);
288 }
289 if (sbyte & 0xf) {
290 if (sbyte & 8)
291 put8(pptr + 8, abcd1, efgh1);
292 if (sbyte & 4)
293 put8(pptr + 10, abcd1, efgh1);
294 if (sbyte & 2)
295 put8(pptr + 12, abcd1, efgh1);
296 if (sbyte & 1)
297 put8(pptr + 14, abcd1, efgh1);
298 }
299 pptr += 8 * PIXEL_SIZE;
300 count -= 8;
301 }
302 if (count > 0) {
303 register int bit = 0x80;
304
305 sbyte = *sptr++;
306 do {
307 if (sbyte & bit)
308 put8(pptr, abcd1, efgh1);
309 pptr += PIXEL_SIZE;
310 bit >>= 1;
311 }
312 while (--count > 0);
313 }
314 line += sraster;
315 inc_ptr(dest, draster);
316 }
317 }
318 return 0;
319 }
320
321 /* Copy a color bitmap. */
322 static int
mem_true64_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)323 mem_true64_copy_color(gx_device * dev,
324 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
325 int x, int y, int w, int h)
326 {
327 gx_device_memory * const mdev = (gx_device_memory *)dev;
328
329 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
330 mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
331 return 0;
332 }
333
334 /* ================ "Word"-oriented device ================ */
335
336 /* Note that on a big-endian machine, this is the same as the */
337 /* standard byte-oriented-device. */
338
339 #if !ARCH_IS_BIG_ENDIAN
340
341 /* Procedures */
342 declare_mem_procs(mem64_word_copy_mono, mem64_word_copy_color, mem64_word_fill_rectangle);
343
344 /* Here is the device descriptor. */
345 const gx_device_memory mem_true64_word_device =
346 mem_full_device("image64w", 64, 0, mem_open,
347 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
348 mem64_word_copy_mono, mem64_word_copy_color, mem64_word_fill_rectangle,
349 gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
350 gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
351
352 /* Fill a rectangle with a color. */
353 static int
mem64_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)354 mem64_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
355 gx_color_index color)
356 {
357 gx_device_memory * const mdev = (gx_device_memory *)dev;
358 byte *base;
359 uint raster;
360
361 fit_fill(dev, x, y, w, h);
362 base = scan_line_base(mdev, y);
363 raster = mdev->raster;
364 mem_swap_byte_rect(base, raster, x * 64, w * 64, h, true);
365 mem_true64_fill_rectangle(dev, x, y, w, h, color);
366 mem_swap_byte_rect(base, raster, x * 64, w * 64, h, false);
367 return 0;
368 }
369
370 /* Copy a bitmap. */
371 static int
mem64_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)372 mem64_word_copy_mono(gx_device * dev,
373 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
374 int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
375 {
376 gx_device_memory * const mdev = (gx_device_memory *)dev;
377 byte *row;
378 uint raster;
379 bool store;
380
381 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
382 row = scan_line_base(mdev, y);
383 raster = mdev->raster;
384 store = (zero != gx_no_color_index && one != gx_no_color_index);
385 mem_swap_byte_rect(row, raster, x * 64, w * 64, h, store);
386 mem_true64_copy_mono(dev, base, sourcex, sraster, id,
387 x, y, w, h, zero, one);
388 mem_swap_byte_rect(row, raster, x * 64, w * 64, h, false);
389 return 0;
390 }
391
392 /* Copy a color bitmap. */
393 static int
mem64_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)394 mem64_word_copy_color(gx_device * dev,
395 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
396 int x, int y, int w, int h)
397 {
398 gx_device_memory * const mdev = (gx_device_memory *)dev;
399 byte *row;
400 uint raster;
401
402 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
403 row = scan_line_base(mdev, y);
404 raster = mdev->raster;
405 mem_swap_byte_rect(row, raster, x * 64, w * 64, h, true);
406 bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
407 sraster, w * PIXEL_SIZE, h);
408 mem_swap_byte_rect(row, raster, x * 64, w * 64, h, false);
409 return 0;
410 }
411
412 #endif /* !ARCH_IS_BIG_ENDIAN */
413