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