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