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 /* 56-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_mem56_s {
26     long
27         fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
28         fprevc[257];
29     double ftotal;
30 } stats_mem56;
31 static int prev_count;
32 static gx_color_index prev_colors[256];
33 # define INCR(v) (++(stats_mem56.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 7
43 
44 /* Procedures */
45 declare_mem_procs(mem_true56_copy_mono, mem_true56_copy_color, mem_true56_fill_rectangle);
46 
47 /* The device descriptor. */
48 const gx_device_memory mem_true56_device =
49 mem_full_alpha_device("image56", 56, 0, mem_open,
50                  gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
51      mem_true56_copy_mono, mem_true56_copy_color, mem_true56_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) * PIXEL_SIZE)
59 
60 /* Unpack a color into its bytes. */
61 #define declare_unpack_color(a, b, c, d, e, f, g, color)\
62         byte a = (byte)((color >> 24) >> 24);\
63         byte b = (byte)((color >> 24) >> 16);\
64         byte c = (byte)((color >> 16) >> 16);\
65         byte d = (byte)((uint)color >> 24);\
66         byte e = (byte)((uint)color >> 16);\
67         byte f = (byte)((uint)color >> 8);\
68         byte g = (byte)color
69 /* Put a 56-bit color into the bitmap. */
70 #define put7(ptr, a, b, c, d, e, f, g)\
71         (ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e, \
72         (ptr)[5] = f, (ptr)[6] = g
73 /* Put 4 bytes of color into the bitmap. */
74 #define putw(ptr, wxyz)\
75         *(bits32 *)(ptr) = (wxyz)
76 /* Load the 7-word 56-bit-color cache. */
77 /* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */
78 #if ARCH_IS_BIG_ENDIAN
79 #  define set_color56_cache(color, a, b, c, d, e, f, g)\
80         mdev->color56.abcd = abcd = (color) >> 24, \
81         mdev->color56.bcde = bcde = (abcd << 8) | (e),\
82         mdev->color56.cdef = cdef = (bcde << 8) | (f),\
83         mdev->color56.defg = defg = (cdef << 8) | (g),\
84         mdev->color56.efga = efga = (defg << 8) | (a),\
85         mdev->color56.fgab = fgab = (efga << 8) | (b),\
86         mdev->color56.gabc = gabc = (fgab << 8) | (c),\
87         mdev->color56.abcdefg = (color)
88 #else
89 #  define set_color56_cache(color, a, b, c, d, e, f, g)\
90         mdev->color56.abcd = abcd =\
91                 ((bits32)(d) << 24) | ((bits32)(c) << 16) |\
92                 ((bits16)(b) << 8) | (a),\
93         mdev->color56.gabc = gabc = (abcd << 8) | (g),\
94         mdev->color56.fgab = fgab = (gabc << 8) | (f),\
95         mdev->color56.efga = efga = (fgab << 8) | (e),\
96         mdev->color56.defg = defg = (efga << 8) | (d),\
97         mdev->color56.cdef = cdef = (defg << 8) | (c),\
98         mdev->color56.bcde = bcde = (cdef << 8) | (b),\
99         mdev->color56.abcdefg = (color)
100 #endif
101 
102 /* Fill a rectangle with a color. */
103 static int
mem_true56_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)104 mem_true56_fill_rectangle(gx_device * dev,
105                           int x, int y, int w, int h, gx_color_index color)
106 {
107     gx_device_memory * const mdev = (gx_device_memory *)dev;
108     declare_unpack_color(a, b, c, d, e, f, g, color);
109     declare_scan_ptr(dest);
110 
111     /*
112      * In order to avoid testing w > 0 and h > 0 twice, we defer
113      * executing setup_rect, and use fit_fill_xywh instead of
114      * fit_fill.
115      */
116     fit_fill_xywh(dev, x, y, w, h);
117     INCR(fill);
118 #if defined(DEBUG) && !defined(GS_THREADSAFE)
119     stats_mem56.ftotal += w;
120 #endif
121     if (w >= 5) {
122         if (h <= 0)
123             return 0;
124         INCR(fwide);
125         setup_rect(dest);
126         if (a == b && b == c && c == d && d == e && e == f && f == g) {
127             int bcnt = w * PIXEL_SIZE;
128 
129             INCR(fgray[min(w, 100)]);
130             while (h-- > 0) {
131                 memset(dest, a, bcnt);
132                 inc_ptr(dest, draster);
133             }
134         } else {
135             int x3 = -x & 3, ww = w - x3;	/* we know ww >= 2 */
136             bits32 abcd, bcde, cdef, defg, efga, fgab, gabc;
137 
138             if (mdev->color56.abcdefg == color) {
139                 abcd = mdev->color56.abcd;
140                 bcde = mdev->color56.bcde;
141                 cdef = mdev->color56.cdef;
142                 defg = mdev->color56.defg;
143                 efga = mdev->color56.efga;
144                 fgab = mdev->color56.fgab;
145                 gabc = mdev->color56.gabc;
146             } else {
147                 INCR(fsetc);
148                 set_color56_cache(color, a, b, c, d, e, f, g);
149             }
150 #if defined(DEBUG) && !defined(GS_THREADSAFE)
151             {
152                 int ci;
153                 for (ci = 0; ci < prev_count; ++ci)
154                     if (prev_colors[ci] == color)
155                         break;
156                 INCR(fprevc[ci]);
157                 if (ci == prev_count) {
158                     if (ci < countof(prev_colors))
159                         ++prev_count;
160                     else
161                         --ci;
162                 }
163                 if (ci) {
164                     memmove(&prev_colors[1], &prev_colors[0],
165                             ci * sizeof(prev_colors[0]));
166                     prev_colors[0] = color;
167                 }
168             }
169 #endif
170             INCR(fcolor[min(w, 100)]);
171             while (h-- > 0) {
172                 register byte *pptr = dest;
173                 int w1 = ww;
174 
175                 switch (x3) {
176                     case 1:
177                         pptr[0] = a;
178                         pptr[1] = b;
179                         pptr[2] = c;
180                         putw(pptr + 3, defg);
181                         pptr += PIXEL_SIZE;
182                         break;
183                     case 2:
184                         pptr[0] = a;
185                         pptr[1] = b;
186                         putw(pptr + 2, cdef);
187                         putw(pptr + 6, gabc);
188                         putw(pptr + 10, defg);
189                         pptr += 2 * PIXEL_SIZE;
190                         break;
191                     case 3:
192                         pptr[0] = a;
193                         putw(pptr + 1, bcde);
194                         putw(pptr + 5, fgab);
195                         putw(pptr + 9, cdef);
196                         putw(pptr + 13, gabc);
197                         putw(pptr + 17, defg);
198                         pptr += 3 * PIXEL_SIZE;
199                         break;
200                     case 0:
201                         ;
202                 }
203                 while (w1 >= 4) {
204                     putw(pptr, abcd);
205                     putw(pptr + 4, efga);
206                     putw(pptr + 8, bcde);
207                     putw(pptr + 12, fgab);
208                     putw(pptr + 16, cdef);
209                     putw(pptr + 20, gabc);
210                     putw(pptr + 24, defg);
211                     pptr += 4 * PIXEL_SIZE;
212                     w1 -= 4;
213                 }
214                 switch (w1) {
215                     case 1:
216                         putw(pptr, abcd);
217                         pptr[4] = e;
218                         pptr[5] = f;
219                         pptr[6] = g;
220                         break;
221                     case 2:
222                         putw(pptr, abcd);
223                         putw(pptr + 4, efga);
224                         putw(pptr + 8, bcde);
225                         pptr[12] = f;
226                         pptr[13] = g;
227                         break;
228                     case 3:
229                         putw(pptr, abcd);
230                         putw(pptr + 4, efga);
231                         putw(pptr + 8, bcde);
232                         putw(pptr + 12, fgab);
233                         putw(pptr + 16, cdef);
234                         pptr[20] = g;
235                         break;
236                     case 0:
237                         ;
238                 }
239                 inc_ptr(dest, draster);
240             }
241         }
242     } else if (h > 0) {		/* w < 5 */
243         INCR(fnarrow[max(w, 0)]);
244         setup_rect(dest);
245         switch (w) {
246             case 4:
247                 do {
248                     dest[21] = dest[14] = dest[7] = dest[0] = a;
249                     dest[22] = dest[15] = dest[8] = dest[1] = b;
250                     dest[23] = dest[16] = dest[9] = dest[2] = c;
251                     dest[24] = dest[17] = dest[10] = dest[3] = d;
252                     dest[25] = dest[18] = dest[11] = dest[4] = e;
253                     dest[26] = dest[19] = dest[12] = dest[5] = f;
254                     dest[27] = dest[20] = dest[13] = dest[6] = g;
255                     inc_ptr(dest, draster);
256                 }
257                 while (--h);
258                 break;
259             case 3:
260                 do {
261                     dest[14] = dest[7] = dest[0] = a;
262                     dest[15] = dest[8] = dest[1] = b;
263                     dest[16] = dest[9] = dest[2] = c;
264                     dest[17] = dest[10] = dest[3] = d;
265                     dest[18] = dest[11] = dest[4] = e;
266                     dest[19] = dest[12] = dest[5] = f;
267                     dest[20] = dest[13] = dest[6] = g;
268                     inc_ptr(dest, draster);
269                 }
270                 while (--h);
271                 break;
272             case 2:
273                 do {
274                     dest[7] = dest[0] = a;
275                     dest[8] = dest[1] = b;
276                     dest[9] = dest[2] = c;
277                     dest[10] = dest[3] = d;
278                     dest[11] = dest[4] = e;
279                     dest[12] = dest[5] = f;
280                     dest[13] = dest[6] = g;
281                     inc_ptr(dest, draster);
282                 }
283                 while (--h);
284                 break;
285             case 1:
286                 do {
287                     dest[0] = a; dest[1] = b; dest[2] = c; dest[3] = d;
288                     dest[4] = e; dest[5] = f; dest[6] = g;
289                     inc_ptr(dest, draster);
290                 }
291                 while (--h);
292                 break;
293             case 0:
294             default:
295                 ;
296         }
297     }
298     return 0;
299 }
300 
301 /* Copy a monochrome bitmap. */
302 static int
mem_true56_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)303 mem_true56_copy_mono(gx_device * dev,
304                const byte * base, int sourcex, int sraster, gx_bitmap_id id,
305         int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
306 {
307     gx_device_memory * const mdev = (gx_device_memory *)dev;
308     const byte *line;
309     int sbit;
310     int first_bit;
311 
312     declare_scan_ptr(dest);
313 
314     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
315     setup_rect(dest);
316     line = base + (sourcex >> 3);
317     sbit = sourcex & 7;
318     first_bit = 0x80 >> sbit;
319     if (zero != gx_no_color_index) {	/* Loop for halftones or inverted masks */
320         /* (never used). */
321         declare_unpack_color(a0, b0, c0, d0, e0, f0, g0, zero);
322         declare_unpack_color(a1, b1, c1, d1, e1, f1, g1, one);
323         while (h-- > 0) {
324             register byte *pptr = dest;
325             const byte *sptr = line;
326             register int sbyte = *sptr++;
327             register int bit = first_bit;
328             int count = w;
329 
330             do {
331                 if (sbyte & bit) {
332                     if (one != gx_no_color_index)
333                         put7(pptr, a1, b1, c1, d1, e1, f1, g1);
334                 } else
335                     put7(pptr, a0, b0, c0, d0, e0, f0, g0);
336                 pptr += PIXEL_SIZE;
337                 if ((bit >>= 1) == 0)
338                     bit = 0x80, sbyte = *sptr++;
339             }
340             while (--count > 0);
341             line += sraster;
342             inc_ptr(dest, draster);
343         }
344     } else if (one != gx_no_color_index) {	/* Loop for character and pattern masks. */
345         /* This is used heavily. */
346         declare_unpack_color(a1, b1, c1, d1, e1, f1, g1, one);
347         int first_mask = first_bit << 1;
348         int first_count, first_skip;
349 
350         if (sbit + w > 8)
351             first_mask -= 1,
352                 first_count = 8 - sbit;
353         else
354             first_mask -= first_mask >> w,
355                 first_count = w;
356         first_skip = first_count * PIXEL_SIZE;
357         while (h-- > 0) {
358             register byte *pptr = dest;
359             const byte *sptr = line;
360             register int sbyte = *sptr++ & first_mask;
361             int count = w - first_count;
362 
363             if (sbyte) {
364                 register int bit = first_bit;
365 
366                 do {
367                     if (sbyte & bit)
368                         put7(pptr, a1, b1, c1, d1, e1, f1, g1);
369                     pptr += PIXEL_SIZE;
370                 }
371                 while ((bit >>= 1) & first_mask);
372             } else
373                 pptr += first_skip;
374             while (count >= 8) {
375                 sbyte = *sptr++;
376                 if (sbyte & 0xf0) {
377                     if (sbyte & 0x80)
378                         put7(pptr, a1, b1, c1, d1, e1, f1, g1);
379                     if (sbyte & 0x40)
380                         put7(pptr + 7, a1, b1, c1, d1, e1, f1, g1);
381                     if (sbyte & 0x20)
382                         put7(pptr + 14, a1, b1, c1, d1, e1, f1, g1);
383                     if (sbyte & 0x10)
384                         put7(pptr + 21, a1, b1, c1, d1, e1, f1, g1);
385                 }
386                 if (sbyte & 0xf) {
387                     if (sbyte & 8)
388                         put7(pptr + 28, a1, b1, c1, d1, e1, f1, g1);
389                     if (sbyte & 4)
390                         put7(pptr + 35, a1, b1, c1, d1, e1, f1, g1);
391                     if (sbyte & 2)
392                         put7(pptr + 42, a1, b1, c1, d1, e1, f1, g1);
393                     if (sbyte & 1)
394                         put7(pptr + 49, a1, b1, c1, d1, e1, f1, g1);
395                 }
396                 pptr += 8 * PIXEL_SIZE;
397                 count -= 8;
398             }
399             if (count > 0) {
400                 register int bit = 0x80;
401 
402                 sbyte = *sptr++;
403                 do {
404                     if (sbyte & bit)
405                         put7(pptr, a1, b1, c1, d1, e1, f1, g1);
406                     pptr += PIXEL_SIZE;
407                     bit >>= 1;
408                 }
409                 while (--count > 0);
410             }
411             line += sraster;
412             inc_ptr(dest, draster);
413         }
414     }
415     return 0;
416 }
417 
418 /* Copy a color bitmap. */
419 static int
mem_true56_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)420 mem_true56_copy_color(gx_device * dev,
421                const byte * base, int sourcex, int sraster, gx_bitmap_id id,
422                       int x, int y, int w, int h)
423 {
424     gx_device_memory * const mdev = (gx_device_memory *)dev;
425 
426     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
427     mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
428     return 0;
429 }
430 
431 /* ================ "Word"-oriented device ================ */
432 
433 /* Note that on a big-endian machine, this is the same as the */
434 /* standard byte-oriented-device. */
435 
436 #if !ARCH_IS_BIG_ENDIAN
437 
438 /* Procedures */
439 declare_mem_procs(mem56_word_copy_mono, mem56_word_copy_color, mem56_word_fill_rectangle);
440 
441 /* Here is the device descriptor. */
442 const gx_device_memory mem_true56_word_device =
443 mem_full_device("image56w", 56, 0, mem_open,
444                 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
445      mem56_word_copy_mono, mem56_word_copy_color, mem56_word_fill_rectangle,
446                 gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
447                 gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
448 
449 /* Fill a rectangle with a color. */
450 static int
mem56_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)451 mem56_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
452                           gx_color_index color)
453 {
454     gx_device_memory * const mdev = (gx_device_memory *)dev;
455     byte *base;
456     uint raster;
457 
458     fit_fill(dev, x, y, w, h);
459     base = scan_line_base(mdev, y);
460     raster = mdev->raster;
461     mem_swap_byte_rect(base, raster, x * 56, w * 56, h, true);
462     mem_true56_fill_rectangle(dev, x, y, w, h, color);
463     mem_swap_byte_rect(base, raster, x * 56, w * 56, h, false);
464     return 0;
465 }
466 
467 /* Copy a bitmap. */
468 static int
mem56_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)469 mem56_word_copy_mono(gx_device * dev,
470                const byte * base, int sourcex, int sraster, gx_bitmap_id id,
471         int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
472 {
473     gx_device_memory * const mdev = (gx_device_memory *)dev;
474     byte *row;
475     uint raster;
476     bool store;
477 
478     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
479     row = scan_line_base(mdev, y);
480     raster = mdev->raster;
481     store = (zero != gx_no_color_index && one != gx_no_color_index);
482     mem_swap_byte_rect(row, raster, x * 56, w * 56, h, store);
483     mem_true56_copy_mono(dev, base, sourcex, sraster, id,
484                          x, y, w, h, zero, one);
485     mem_swap_byte_rect(row, raster, x * 56, w * 56, h, false);
486     return 0;
487 }
488 
489 /* Copy a color bitmap. */
490 static int
mem56_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)491 mem56_word_copy_color(gx_device * dev,
492                const byte * base, int sourcex, int sraster, gx_bitmap_id id,
493                       int x, int y, int w, int h)
494 {
495     gx_device_memory * const mdev = (gx_device_memory *)dev;
496     byte *row;
497     uint raster;
498 
499     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
500     row = scan_line_base(mdev, y);
501     raster = mdev->raster;
502     mem_swap_byte_rect(row, raster, x * 56, w * 56, h, true);
503     bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
504                                 sraster, w * PIXEL_SIZE, h);
505     mem_swap_byte_rect(row, raster, x * 56, w * 56, h, false);
506     return 0;
507 }
508 
509 #endif /* !ARCH_IS_BIG_ENDIAN */
510