1 /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises, 2001 Artifex Software. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /*$Id: gdevm48.c,v 1.3 2005/06/20 08:59:23 igor Exp $ */
18 /* 48-bit-per-pixel "memory" (stored bitmap) device */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gxdevice.h"
22 #include "gxdevmem.h" /* semi-public definitions */
23 #include "gdevmem.h" /* private definitions */
24
25 /* Define debugging statistics. */
26 #ifdef DEBUG
27 struct stats_mem48_s {
28 long
29 fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
30 fprevc[257];
31 double ftotal;
32 } stats_mem48;
33 static int prev_count = 0;
34 static gx_color_index prev_colors[256];
35 # define INCR(v) (++(stats_mem48.v))
36 #else
37 # define INCR(v) DO_NOTHING
38 #endif
39
40
41 /* ================ Standard (byte-oriented) device ================ */
42
43 #undef chunk
44 #define chunk byte
45 #define PIXEL_SIZE 6
46
47 /* Procedures */
48 declare_mem_procs(mem_true48_copy_mono, mem_true48_copy_color, mem_true48_fill_rectangle);
49
50 /* The device descriptor. */
51 const gx_device_memory mem_true48_device =
52 mem_full_alpha_device("image48", 48, 0, mem_open,
53 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
54 mem_true48_copy_mono, mem_true48_copy_color, mem_true48_fill_rectangle,
55 gx_default_map_cmyk_color, gx_default_copy_alpha,
56 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop,
57 mem_get_bits_rectangle);
58
59 /* Convert x coordinate to byte offset in scan line. */
60 #undef x_to_byte
61 #define x_to_byte(x) ((x) * PIXEL_SIZE)
62
63 /* Unpack a color into its bytes. */
64 #define declare_unpack_color(a, b, c, d, e, f, color)\
65 byte a = (byte)(color >> 40);\
66 byte b = (byte)(color >> 32);\
67 byte c = (byte)((uint)color >> 24);\
68 byte d = (byte)((uint)color >> 16);\
69 byte e = (byte)((uint)color >> 8);\
70 byte f = (byte)color
71 /* Put a 48-bit color into the bitmap. */
72 #define put6(ptr, a, b, c, d, e, f)\
73 (ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e, (ptr)[5] = f
74 /* Put 4 bytes of color into the bitmap. */
75 #define putw(ptr, wxyz)\
76 *(bits32 *)(ptr) = (wxyz)
77 /* Load the 3-word 48-bit-color cache. */
78 /* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */
79 #if arch_is_big_endian
80 # define set_color48_cache(color, a, b, c, d, e, f)\
81 mdev->color48.abcd = abcd = (color) >> 16, \
82 mdev->color48.cdef = cdef = (abcd << 16) | ((e) <<8) | (f),\
83 mdev->color48.efab = efab = (cdef << 16) | ((a) <<8) | (b),\
84 mdev->color48.abcdef = (color)
85 #else
86 # define set_color48_cache(color, a, b, c, d, e, f)\
87 mdev->color48.abcd = abcd =\
88 ((bits32)(d) << 24) | ((bits32)(c) << 16) |\
89 ((bits16)(b) << 8) | (a),\
90 mdev->color48.efab = efab = (abcd << 16) | ((f) <<8) | (e),\
91 mdev->color48.cdef = cdef = (efab << 16) | ((d) <<8) | (c),\
92 mdev->color48.abcdef = (color)
93 #endif
94
95 /* Fill a rectangle with a color. */
96 private int
mem_true48_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)97 mem_true48_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, f, 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_mem48.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 && e == f) {
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 x1 = -x & 1, ww = w - x1; /* we know ww >= 4 */
129 bits32 abcd, cdef, efab;
130
131 if (mdev->color48.abcdef == color) {
132 abcd = mdev->color48.abcd;
133 cdef = mdev->color48.cdef;
134 efab = mdev->color48.efab;
135 } else {
136 INCR(fsetc);
137 set_color48_cache(color, a, b, c, d, e, f);
138 }
139 #ifdef DEBUG
140 {
141 int ci;
142 for (ci = 0; ci < prev_count; ++ci)
143 if (prev_colors[ci] == color)
144 break;
145 INCR(fprevc[ci]);
146 if (ci == prev_count) {
147 if (ci < countof(prev_colors))
148 ++prev_count;
149 else
150 --ci;
151 }
152 if (ci) {
153 memmove(&prev_colors[1], &prev_colors[0],
154 ci * sizeof(prev_colors[0]));
155 prev_colors[0] = color;
156 }
157 }
158 #endif
159 INCR(fcolor[min(w, 100)]);
160 while (h-- > 0) {
161 register byte *pptr = dest;
162 int w1 = ww;
163
164 switch (x1) {
165 case 1:
166 pptr[0] = a;
167 pptr[1] = b;
168 putw(pptr + 2, cdef);
169 pptr += PIXEL_SIZE;
170 break;
171 case 0:
172 ;
173 }
174 while (w1 >= 2) {
175 putw(pptr, abcd);
176 putw(pptr + 4, efab);
177 putw(pptr + 8, cdef);
178 pptr += 2 * PIXEL_SIZE;
179 w1 -= 2;
180 }
181 switch (w1) {
182 case 1:
183 putw(pptr, abcd);
184 pptr[4] = e;
185 pptr[5] = f;
186 break;
187 case 0:
188 ;
189 }
190 inc_ptr(dest, draster);
191 }
192 }
193 } else if (h > 0) { /* w < 5 */
194 INCR(fnarrow[max(w, 0)]);
195 setup_rect(dest);
196 switch (w) {
197 case 4:
198 do {
199 dest[18] = dest[12] = dest[6] = dest[0] = a;
200 dest[19] = dest[13] = dest[7] = dest[1] = b;
201 dest[20] = dest[14] = dest[8] = dest[2] = c;
202 dest[21] = dest[15] = dest[9] = dest[3] = d;
203 dest[22] = dest[16] = dest[10] = dest[4] = e;
204 dest[23] = dest[17] = dest[11] = dest[5] = f;
205 inc_ptr(dest, draster);
206 }
207 while (--h);
208 break;
209 case 3:
210 do {
211 dest[12] = dest[6] = dest[0] = a;
212 dest[13] = dest[7] = dest[1] = b;
213 dest[14] = dest[8] = dest[2] = c;
214 dest[15] = dest[9] = dest[3] = d;
215 dest[16] = dest[10] = dest[4] = e;
216 dest[17] = dest[11] = dest[5] = f;
217 inc_ptr(dest, draster);
218 }
219 while (--h);
220 break;
221 case 2:
222 do {
223 dest[6] = dest[0] = a;
224 dest[7] = dest[1] = b;
225 dest[8] = dest[2] = c;
226 dest[9] = dest[3] = d;
227 dest[10] = dest[4] = e;
228 dest[11] = dest[5] = f;
229 inc_ptr(dest, draster);
230 }
231 while (--h);
232 break;
233 case 1:
234 do {
235 dest[0] = a; dest[1] = b; dest[2] = c;
236 dest[3] = d; dest[4] = e; dest[5] = f;
237 inc_ptr(dest, draster);
238 }
239 while (--h);
240 break;
241 case 0:
242 default:
243 ;
244 }
245 }
246 return 0;
247 }
248
249 /* Copy a monochrome bitmap. */
250 private int
mem_true48_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)251 mem_true48_copy_mono(gx_device * dev,
252 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
253 int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
254 {
255 gx_device_memory * const mdev = (gx_device_memory *)dev;
256 const byte *line;
257 int sbit;
258 int first_bit;
259
260 declare_scan_ptr(dest);
261
262 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
263 setup_rect(dest);
264 line = base + (sourcex >> 3);
265 sbit = sourcex & 7;
266 first_bit = 0x80 >> sbit;
267 if (zero != gx_no_color_index) { /* Loop for halftones or inverted masks */
268 /* (never used). */
269 declare_unpack_color(a0, b0, c0, d0, e0, f0, zero);
270 declare_unpack_color(a1, b1, c1, d1, e1, f1, one);
271 while (h-- > 0) {
272 register byte *pptr = dest;
273 const byte *sptr = line;
274 register int sbyte = *sptr++;
275 register int bit = first_bit;
276 int count = w;
277
278 do {
279 if (sbyte & bit) {
280 if (one != gx_no_color_index)
281 put6(pptr, a1, b1, c1, d1, e1, f1);
282 } else
283 put6(pptr, a0, b0, c0, d0, e0, f0);
284 pptr += PIXEL_SIZE;
285 if ((bit >>= 1) == 0)
286 bit = 0x80, sbyte = *sptr++;
287 }
288 while (--count > 0);
289 line += sraster;
290 inc_ptr(dest, draster);
291 }
292 } else if (one != gx_no_color_index) { /* Loop for character and pattern masks. */
293 /* This is used heavily. */
294 declare_unpack_color(a1, b1, c1, d1, e1, f1, one);
295 int first_mask = first_bit << 1;
296 int first_count, first_skip;
297
298 if (sbit + w > 8)
299 first_mask -= 1,
300 first_count = 8 - sbit;
301 else
302 first_mask -= first_mask >> w,
303 first_count = w;
304 first_skip = first_count * PIXEL_SIZE;
305 while (h-- > 0) {
306 register byte *pptr = dest;
307 const byte *sptr = line;
308 register int sbyte = *sptr++ & first_mask;
309 int count = w - first_count;
310
311 if (sbyte) {
312 register int bit = first_bit;
313
314 do {
315 if (sbyte & bit)
316 put6(pptr, a1, b1, c1, d1, e1, f1);
317 pptr += PIXEL_SIZE;
318 }
319 while ((bit >>= 1) & first_mask);
320 } else
321 pptr += first_skip;
322 while (count >= 8) {
323 sbyte = *sptr++;
324 if (sbyte & 0xf0) {
325 if (sbyte & 0x80)
326 put6(pptr, a1, b1, c1, d1, e1, f1);
327 if (sbyte & 0x40)
328 put6(pptr + 6, a1, b1, c1, d1, e1, f1);
329 if (sbyte & 0x20)
330 put6(pptr + 12, a1, b1, c1, d1, e1, f1);
331 if (sbyte & 0x10)
332 put6(pptr + 18, a1, b1, c1, d1, e1, f1);
333 }
334 if (sbyte & 0xf) {
335 if (sbyte & 8)
336 put6(pptr + 24, a1, b1, c1, d1, e1, f1);
337 if (sbyte & 4)
338 put6(pptr + 30, a1, b1, c1, d1, e1, f1);
339 if (sbyte & 2)
340 put6(pptr + 36, a1, b1, c1, d1, e1, f1);
341 if (sbyte & 1)
342 put6(pptr + 42, a1, b1, c1, d1, e1, f1);
343 }
344 pptr += 8 * PIXEL_SIZE;
345 count -= 8;
346 }
347 if (count > 0) {
348 register int bit = 0x80;
349
350 sbyte = *sptr++;
351 do {
352 if (sbyte & bit)
353 put6(pptr, a1, b1, c1, d1, e1, f1);
354 pptr += PIXEL_SIZE;
355 bit >>= 1;
356 }
357 while (--count > 0);
358 }
359 line += sraster;
360 inc_ptr(dest, draster);
361 }
362 }
363 return 0;
364 }
365
366 /* Copy a color bitmap. */
367 private int
mem_true48_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)368 mem_true48_copy_color(gx_device * dev,
369 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
370 int x, int y, int w, int h)
371 {
372 gx_device_memory * const mdev = (gx_device_memory *)dev;
373
374 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
375 mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
376 return 0;
377 }
378
379 /* ================ "Word"-oriented device ================ */
380
381 /* Note that on a big-endian machine, this is the same as the */
382 /* standard byte-oriented-device. */
383
384 #if !arch_is_big_endian
385
386 /* Procedures */
387 declare_mem_procs(mem48_word_copy_mono, mem48_word_copy_color, mem48_word_fill_rectangle);
388
389 /* Here is the device descriptor. */
390 const gx_device_memory mem_true48_word_device =
391 mem_full_device("image48w", 48, 0, mem_open,
392 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
393 mem48_word_copy_mono, mem48_word_copy_color, mem48_word_fill_rectangle,
394 gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
395 gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
396
397 /* Fill a rectangle with a color. */
398 private int
mem48_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)399 mem48_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
400 gx_color_index color)
401 {
402 gx_device_memory * const mdev = (gx_device_memory *)dev;
403 byte *base;
404 uint raster;
405
406 fit_fill(dev, x, y, w, h);
407 base = scan_line_base(mdev, y);
408 raster = mdev->raster;
409 mem_swap_byte_rect(base, raster, x * 48, w * 48, h, true);
410 mem_true48_fill_rectangle(dev, x, y, w, h, color);
411 mem_swap_byte_rect(base, raster, x * 48, w * 48, h, false);
412 return 0;
413 }
414
415 /* Copy a bitmap. */
416 private int
mem48_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)417 mem48_word_copy_mono(gx_device * dev,
418 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
419 int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
420 {
421 gx_device_memory * const mdev = (gx_device_memory *)dev;
422 byte *row;
423 uint raster;
424 bool store;
425
426 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
427 row = scan_line_base(mdev, y);
428 raster = mdev->raster;
429 store = (zero != gx_no_color_index && one != gx_no_color_index);
430 mem_swap_byte_rect(row, raster, x * 48, w * 48, h, store);
431 mem_true48_copy_mono(dev, base, sourcex, sraster, id,
432 x, y, w, h, zero, one);
433 mem_swap_byte_rect(row, raster, x * 48, w * 48, h, false);
434 return 0;
435 }
436
437 /* Copy a color bitmap. */
438 private int
mem48_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)439 mem48_word_copy_color(gx_device * dev,
440 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
441 int x, int y, int w, int h)
442 {
443 gx_device_memory * const mdev = (gx_device_memory *)dev;
444 byte *row;
445 uint raster;
446
447 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
448 row = scan_line_base(mdev, y);
449 raster = mdev->raster;
450 mem_swap_byte_rect(row, raster, x * 48, w * 48, h, true);
451 bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
452 sraster, w * PIXEL_SIZE, h);
453 mem_swap_byte_rect(row, raster, x * 48, w * 48, h, false);
454 return 0;
455 }
456
457 #endif /* !arch_is_big_endian */
458