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