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