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