xref: /plan9/sys/src/cmd/gs/src/gdevm48.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: 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