1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
13
/* $Id: gdevm24.c 8539 2008-02-22 20:18:08Z leonardo $ */
14
/* 24-bit-per-pixel "memory" (stored bitmap) device */
18
#include "gxdevmem.h" /* semi-public definitions */
19
#include "gdevmem.h" /* private definitions */
22
#define mem_true24_strip_copy_rop mem_gray8_rgb24_strip_copy_rop
25
* Define whether to use the library's memset.
27
/*#define USE_MEMSET*/
29
* Define whether to use memcpy for very wide fills. We thought this
30
* made a big difference, but it turned out to be an artifact of the
33
/*#define USE_MEMCPY*/
35
/* Define debugging statistics. */
37
struct stats_mem24_s {
39
fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
43
static int prev_count = 0;
44
static uint prev_colors[256];
45
# define INCR(v) (++(stats_mem24.v))
47
# define INCR(v) DO_NOTHING
51
/* ================ Standard (byte-oriented) device ================ */
57
declare_mem_procs(mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle);
58
static dev_proc_copy_alpha(mem_true24_copy_alpha);
60
/* The device descriptor. */
61
const gx_device_memory mem_true24_device =
62
mem_full_alpha_device("image24", 24, 0, mem_open,
63
gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
64
mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle,
65
gx_default_map_cmyk_color, mem_true24_copy_alpha,
66
gx_default_strip_tile_rectangle, mem_true24_strip_copy_rop,
67
mem_get_bits_rectangle);
69
/* Convert x coordinate to byte offset in scan line. */
71
#define x_to_byte(x) ((x) * 3)
73
/* Unpack a color into its bytes. */
74
#define declare_unpack_color(r, g, b, color)\
75
byte r = (byte)(color >> 16);\
76
byte g = (byte)((uint)color >> 8);\
78
/* Put a 24-bit color into the bitmap. */
79
#define put3(ptr, r, g, b)\
80
(ptr)[0] = r, (ptr)[1] = g, (ptr)[2] = b
81
/* Put 4 bytes of color into the bitmap. */
82
#define putw(ptr, wxyz)\
83
*(bits32 *)(ptr) = (wxyz)
84
/* Load the 3-word 24-bit-color cache. */
85
/* Free variables: [m]dev, rgbr, gbrg, brgb. */
86
#if arch_is_big_endian
87
# define set_color24_cache(crgb, r, g, b)\
88
mdev->color24.rgbr = rgbr = ((bits32)(crgb) << 8) | (r),\
89
mdev->color24.gbrg = gbrg = (rgbr << 8) | (g),\
90
mdev->color24.brgb = brgb = (gbrg << 8) | (b),\
91
mdev->color24.rgb = (crgb)
93
# define set_color24_cache(crgb, r, g, b)\
94
mdev->color24.rgbr = rgbr =\
95
((bits32)(r) << 24) | ((bits32)(b) << 16) |\
96
((bits16)(g) << 8) | (r),\
97
mdev->color24.brgb = brgb = (rgbr << 8) | (b),\
98
mdev->color24.gbrg = gbrg = (brgb << 8) | (g),\
99
mdev->color24.rgb = (crgb)
102
/* Fill a rectangle with a color. */
104
mem_true24_fill_rectangle(gx_device * dev,
105
int x, int y, int w, int h, gx_color_index color)
107
gx_device_memory * const mdev = (gx_device_memory *)dev;
108
declare_unpack_color(r, g, b, color);
109
declare_scan_ptr(dest);
111
if_debug4('b', "[b]device y=%d h=%d x=%d w=%d\n", y + mdev->band_y, h, x, w);
113
* In order to avoid testing w > 0 and h > 0 twice, we defer
114
* executing setup_rect, and use fit_fill_xywh instead of
117
fit_fill_xywh(dev, x, y, w, h);
120
stats_mem24.ftotal += w;
127
if (r == g && r == b) {
129
/* We think we can do better than the library's memset.... */
130
int bcntm7 = w * 3 - 7;
131
register bits32 cword = color | (color << 24);
133
INCR(fgray[min(w, 100)]);
135
register byte *pptr = dest;
136
byte *limit = pptr + bcntm7;
138
/* We want to store full words, but we have to */
139
/* guarantee that they are word-aligned. */
142
*pptr++ = (byte) cword;
144
*pptr++ = (byte) cword;
146
*pptr++ = (byte) cword;
149
/* Even with w = 5, we always store at least */
150
/* 3 full words, regardless of the starting x. */
152
((bits32 *) pptr)[1] =
153
((bits32 *) pptr)[2] = cword;
155
while (pptr < limit) {
157
((bits32 *) pptr)[1] = cword;
160
switch ((int)(pptr - limit)) {
162
pptr[6] = (byte) cword;
164
pptr[5] = (byte) cword;
166
pptr[4] = (byte) cword;
168
*(bits32 *) pptr = cword;
171
pptr[2] = (byte) cword;
173
pptr[1] = (byte) cword;
175
pptr[0] = (byte) cword;
178
inc_ptr(dest, draster);
183
INCR(fgray[min(w, 100)]);
185
memset(dest, r, bcnt);
186
inc_ptr(dest, draster);
190
int x3 = -x & 3, ww = w - x3; /* we know ww >= 2 */
191
bits32 rgbr, gbrg, brgb;
193
if (mdev->color24.rgb == color) {
194
rgbr = mdev->color24.rgbr;
195
gbrg = mdev->color24.gbrg;
196
brgb = mdev->color24.brgb;
199
set_color24_cache(color, r, g, b);
204
for (ci = 0; ci < prev_count; ++ci)
205
if (prev_colors[ci] == color)
208
if (ci == prev_count) {
209
if (ci < countof(prev_colors))
215
memmove(&prev_colors[1], &prev_colors[0],
216
ci * sizeof(prev_colors[0]));
217
prev_colors[0] = color;
220
INCR(fcolor[min(w, 100)]);
222
register byte *pptr = dest;
233
putw(pptr + 2, brgb);
238
putw(pptr + 1, gbrg);
239
putw(pptr + 5, brgb);
247
* For very wide fills, it's most efficient to fill a few
248
* pixels and then use memcpy to fill the rest.
251
#define PUTW4(ptr, w)\
253
putw(ptr, w); putw((ptr)+12, w); putw((ptr)+24, w); putw((ptr)+36, w);\
256
PUTW4(pptr + 4, gbrg);
257
PUTW4(pptr + 8, brgb);
260
memcpy(pptr + 48, pptr, 48);
261
memcpy(pptr + 96, pptr, 96);
262
for (pptr += 192; (w1 -= 64) >= 64; pptr += 192)
263
memcpy(pptr, pptr - 192, 192);
266
for (; (w1 -= 16) >= 16; pptr += 48)
267
memcpy(pptr, pptr - 48, 48);
272
putw(pptr + 4, gbrg);
273
putw(pptr + 8, brgb);
288
putw(pptr + 4, gbrg);
294
inc_ptr(dest, draster);
297
} else if (h > 0) { /* w < 5 */
298
INCR(fnarrow[max(w, 0)]);
303
dest[9] = dest[6] = dest[3] = dest[0] = r;
304
dest[10] = dest[7] = dest[4] = dest[1] = g;
305
dest[11] = dest[8] = dest[5] = dest[2] = b;
306
inc_ptr(dest, draster);
312
dest[6] = dest[3] = dest[0] = r;
313
dest[7] = dest[4] = dest[1] = g;
314
dest[8] = dest[5] = dest[2] = b;
315
inc_ptr(dest, draster);
321
dest[3] = dest[0] = r;
322
dest[4] = dest[1] = g;
323
dest[5] = dest[2] = b;
324
inc_ptr(dest, draster);
330
dest[0] = r, dest[1] = g, dest[2] = b;
331
inc_ptr(dest, draster);
343
/* Copy a monochrome bitmap. */
345
mem_true24_copy_mono(gx_device * dev,
346
const byte * base, int sourcex, int sraster, gx_bitmap_id id,
347
int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
349
gx_device_memory * const mdev = (gx_device_memory *)dev;
354
declare_scan_ptr(dest);
356
fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
358
line = base + (sourcex >> 3);
360
first_bit = 0x80 >> sbit;
361
if (zero != gx_no_color_index) { /* Loop for halftones or inverted masks */
363
declare_unpack_color(r0, g0, b0, zero);
364
declare_unpack_color(r1, g1, b1, one);
366
register byte *pptr = dest;
367
const byte *sptr = line;
368
register int sbyte = *sptr++;
369
register int bit = first_bit;
374
if (one != gx_no_color_index) {
375
put3(pptr, r1, g1, b1);
376
vd_pixel(int2fixed((pptr - mdev->line_ptrs[y]) / 3), int2fixed(y), RGB(r1, g1, b1));
379
put3(pptr, r0, g0, b0);
380
vd_pixel(int2fixed((pptr - mdev->line_ptrs[y]) / 3), int2fixed(y), RGB(r0, g0, b0));
383
if ((bit >>= 1) == 0)
384
bit = 0x80, sbyte = *sptr++;
388
inc_ptr(dest, draster);
390
} else if (one != gx_no_color_index) { /* Loop for character and pattern masks. */
391
/* This is used heavily. */
392
declare_unpack_color(r1, g1, b1, one);
393
int first_mask = first_bit << 1;
394
int first_count, first_skip;
398
first_count = 8 - sbit;
400
first_mask -= first_mask >> w,
402
first_skip = first_count * 3;
404
register byte *pptr = dest;
405
const byte *sptr = line;
406
register int sbyte = *sptr++ & first_mask;
407
int count = w - first_count;
410
register int bit = first_bit;
414
put3(pptr, r1, g1, b1);
417
while ((bit >>= 1) & first_mask);
424
put3(pptr, r1, g1, b1);
426
put3(pptr + 3, r1, g1, b1);
428
put3(pptr + 6, r1, g1, b1);
430
put3(pptr + 9, r1, g1, b1);
434
put3(pptr + 12, r1, g1, b1);
436
put3(pptr + 15, r1, g1, b1);
438
put3(pptr + 18, r1, g1, b1);
440
put3(pptr + 21, r1, g1, b1);
446
register int bit = 0x80;
451
put3(pptr, r1, g1, b1);
458
inc_ptr(dest, draster);
464
/* Copy a color bitmap. */
466
mem_true24_copy_color(gx_device * dev,
467
const byte * base, int sourcex, int sraster, gx_bitmap_id id,
468
int x, int y, int w, int h)
470
gx_device_memory * const mdev = (gx_device_memory *)dev;
472
if_debug1('w', "[w]device y=%d:\n", y + mdev->band_y); /* See siscale.c about 'w'. */
473
fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
474
mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
478
/* Copy an alpha map. */
480
mem_true24_copy_alpha(gx_device * dev, const byte * base, int sourcex,
481
int sraster, gx_bitmap_id id, int x, int y, int w, int h,
482
gx_color_index color, int depth)
484
gx_device_memory * const mdev = (gx_device_memory *)dev;
487
declare_scan_ptr(dest);
488
declare_unpack_color(r, g, b, color);
490
fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
494
register byte *pptr = dest;
497
for (sx = sourcex; sx < sourcex + w; ++sx, pptr += 3) {
500
if (depth == 2) /* map 0 - 3 to 0 - 15 */
502
((line[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 5;
504
alpha2 = line[sx >> 1],
505
alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4);
506
if (alpha == 15) { /* Just write the new color. */
508
} else if (alpha != 0) { /* Blend RGB values. */
509
#define make_shade(old, clr, alpha, amax) \
510
(old) + (((int)(clr) - (int)(old)) * (alpha) / (amax))
511
pptr[0] = make_shade(pptr[0], r, alpha, 15);
512
pptr[1] = make_shade(pptr[1], g, alpha, 15);
513
pptr[2] = make_shade(pptr[2], b, alpha, 15);
518
inc_ptr(dest, draster);
523
/* ================ "Word"-oriented device ================ */
525
/* Note that on a big-endian machine, this is the same as the */
526
/* standard byte-oriented-device. */
528
#if !arch_is_big_endian
531
declare_mem_procs(mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle);
533
/* Here is the device descriptor. */
534
const gx_device_memory mem_true24_word_device =
535
mem_full_device("image24w", 24, 0, mem_open,
536
gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
537
mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle,
538
gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
539
gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
541
/* Fill a rectangle with a color. */
543
mem24_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
544
gx_color_index color)
546
gx_device_memory * const mdev = (gx_device_memory *)dev;
550
fit_fill(dev, x, y, w, h);
551
base = scan_line_base(mdev, y);
552
raster = mdev->raster;
553
mem_swap_byte_rect(base, raster, x * 24, w * 24, h, true);
554
mem_true24_fill_rectangle(dev, x, y, w, h, color);
555
mem_swap_byte_rect(base, raster, x * 24, w * 24, h, false);
561
mem24_word_copy_mono(gx_device * dev,
562
const byte * base, int sourcex, int sraster, gx_bitmap_id id,
563
int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
565
gx_device_memory * const mdev = (gx_device_memory *)dev;
570
fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
571
row = scan_line_base(mdev, y);
572
raster = mdev->raster;
573
store = (zero != gx_no_color_index && one != gx_no_color_index);
574
mem_swap_byte_rect(row, raster, x * 24, w * 24, h, store);
575
mem_true24_copy_mono(dev, base, sourcex, sraster, id,
576
x, y, w, h, zero, one);
577
mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false);
581
/* Copy a color bitmap. */
583
mem24_word_copy_color(gx_device * dev,
584
const byte * base, int sourcex, int sraster, gx_bitmap_id id,
585
int x, int y, int w, int h)
587
gx_device_memory * const mdev = (gx_device_memory *)dev;
591
fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
592
row = scan_line_base(mdev, y);
593
raster = mdev->raster;
594
mem_swap_byte_rect(row, raster, x * 24, w * 24, h, true);
595
bytes_copy_rectangle(row + x * 3, raster, base + sourcex * 3, sraster,
597
mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false);
601
#endif /* !arch_is_big_endian */