xref: /plan9/sys/src/cmd/gs/src/gdevm64.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: gdevm64.c,v 1.4 2005/06/20 08:59:23 igor Exp $ */
18 /* 64-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_mem64_s {
28     long
29 	fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
30 	fprevc[257];
31     double ftotal;
32 } stats_mem64;
33 static int prev_count = 0;
34 static gx_color_index prev_colors[256];
35 # define INCR(v) (++(stats_mem64.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 2
46 
47 /* Procedures */
48 declare_mem_procs(mem_true64_copy_mono, mem_true64_copy_color, mem_true64_fill_rectangle);
49 
50 /* The device descriptor. */
51 const gx_device_memory mem_true64_device =
52 mem_full_alpha_device("image64", 64, 0, mem_open,
53 		 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
54      mem_true64_copy_mono, mem_true64_copy_color, mem_true64_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) << 3)
62 
63 /* Put a 64-bit color into the bitmap. */
64 #define put8(ptr, abcd, efgh)\
65 	(ptr)[0] = abcd, (ptr)[1] = efgh
66 /* Free variables: [m]dev, abcd, degh. */
67 #if arch_is_big_endian
68 /* Unpack a color into 32 bit chunks. */
69 #  define declare_unpack_color(abcd, efgh, color)\
70 	bits32 abcd = (bits32)((color) >> 32);\
71 	bits32 efgh = (bits32)(color)
72 #else
73 /* Unpack a color into 32 bit chunks. */
74 #  define declare_unpack_color(abcd, efgh, color)\
75 	bits32 abcd = (bits32)((0x000000ff & ((color) >> 56)) |\
76 		               (0x0000ff00 & ((color) >> 40)) |\
77 		               (0x00ff0000 & ((color) >> 24)) |\
78 		               (0xff000000 & ((color) >> 8)));\
79 	bits32 efgh = (bits32)((0x000000ff & ((color) >> 24)) |\
80 		               (0x0000ff00 & ((color) >> 8)) |\
81 		               (0x00ff0000 & ((color) << 8)) |\
82 		               (0xff000000 & ((color) << 24)))
83 #endif
84 #define dest32 ((bits32 *)dest)
85 
86 /* Fill a rectangle with a color. */
87 private int
mem_true64_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)88 mem_true64_fill_rectangle(gx_device * dev,
89 			  int x, int y, int w, int h, gx_color_index color)
90 {
91     gx_device_memory * const mdev = (gx_device_memory *)dev;
92     declare_scan_ptr(dest);
93     declare_unpack_color(abcd, efgh, color);
94 
95     /*
96      * In order to avoid testing w > 0 and h > 0 twice, we defer
97      * executing setup_rect, and use fit_fill_xywh instead of
98      * fit_fill.
99      */
100     fit_fill_xywh(dev, x, y, w, h);
101     INCR(fill);
102 #ifdef DEBUG
103     stats_mem64.ftotal += w;
104 #endif
105     if (h <= 0)
106 	return 0;
107     if (w >= 5) {
108 	INCR(fwide);
109 	setup_rect(dest);
110 #ifdef DEBUG
111 	{
112 	    int ci;
113 	    for (ci = 0; ci < prev_count; ++ci)
114 		if (prev_colors[ci] == color)
115 	    	    break;
116 	    INCR(fprevc[ci]);
117 	    if (ci == prev_count) {
118 		if (ci < countof(prev_colors))
119 	    	    ++prev_count;
120 		else
121 	    	    --ci;
122 	    }
123 	    if (ci) {
124 		memmove(&prev_colors[1], &prev_colors[0],
125 			ci * sizeof(prev_colors[0]));
126 		prev_colors[0] = color;
127 	    }
128 	}
129 #endif
130 	INCR(fcolor[min(w, 100)]);
131 	while (h-- > 0) {
132 	    register bits32 *pptr = dest32;
133 	    int w1 = w;
134 
135 	    while (w1 >= 4) {
136 		put8(pptr, abcd, efgh);
137 		put8(pptr + 2, abcd, efgh);
138 		put8(pptr + 4, abcd, efgh);
139 		put8(pptr + 6, abcd, efgh);
140 		pptr += 4 * PIXEL_SIZE;
141 		w1 -= 4;
142 	    }
143 	    switch (w1) {
144 		case 1:
145 		    put8(pptr, abcd, efgh);
146 		    break;
147 		case 2:
148 		    put8(pptr, abcd, efgh);
149 		    put8(pptr + 2, abcd, efgh);
150 		    break;
151 		case 3:
152 		    put8(pptr, abcd, efgh);
153 		    put8(pptr + 2, abcd, efgh);
154 		    put8(pptr + 4, abcd, efgh);
155 		    break;
156 		case 0:
157 		    ;
158 	    }
159 	    inc_ptr(dest, draster);
160 	}
161     } else {		/* w < 5 */
162 	INCR(fnarrow[max(w, 0)]);
163 	setup_rect(dest);
164 	switch (w) {
165 	    case 4:
166 		do {
167 		    put8(dest32, abcd, efgh);
168 		    put8(dest32 + 2, abcd, efgh);
169 		    put8(dest32 + 4, abcd, efgh);
170 		    put8(dest32 + 6, abcd, efgh);
171 		    inc_ptr(dest, draster);
172 		}
173 		while (--h);
174 		break;
175 	    case 3:
176 		do {
177 		    put8(dest32, abcd, efgh);
178 		    put8(dest32 + 2, abcd, efgh);
179 		    put8(dest32 + 4, abcd, efgh);
180 		    inc_ptr(dest, draster);
181 		}
182 		while (--h);
183 		break;
184 	    case 2:
185 		do {
186 		    put8(dest32, abcd, efgh);
187 		    put8(dest32 + 2, abcd, efgh);
188 		    inc_ptr(dest, draster);
189 		}
190 		while (--h);
191 		break;
192 	    case 1:
193 		do {
194 		    put8(dest32, abcd, efgh);
195 		    inc_ptr(dest, draster);
196 		}
197 		while (--h);
198 		break;
199 	    case 0:
200 	    default:
201 		;
202 	}
203     }
204     return 0;
205 }
206 
207 /* Copy a monochrome bitmap. */
208 private int
mem_true64_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)209 mem_true64_copy_mono(gx_device * dev,
210 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
211 	int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
212 {
213     gx_device_memory * const mdev = (gx_device_memory *)dev;
214     const byte *line;
215     int sbit;
216     int first_bit;
217 
218     declare_scan_ptr(dest);
219 
220     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
221     setup_rect(dest);
222     line = base + (sourcex >> 3);
223     sbit = sourcex & 7;
224     first_bit = 0x80 >> sbit;
225     if (zero != gx_no_color_index) {	/* Loop for halftones or inverted masks */
226 	/* (never used). */
227 	declare_unpack_color(abcd0, efgh0, zero);
228 	declare_unpack_color(abcd1, efgh1, one);
229 	while (h-- > 0) {
230 	    register bits32 *pptr = dest32;
231 	    const byte *sptr = line;
232 	    register int sbyte = *sptr++;
233 	    register int bit = first_bit;
234 	    int count = w;
235 
236 	    do {
237 		if (sbyte & bit) {
238 		    if (one != gx_no_color_index)
239 			put8(pptr, abcd1, efgh1);
240 		} else
241 		    put8(pptr, abcd0, efgh0);
242 		pptr += PIXEL_SIZE;
243 		if ((bit >>= 1) == 0)
244 		    bit = 0x80, sbyte = *sptr++;
245 	    }
246 	    while (--count > 0);
247 	    line += sraster;
248 	    inc_ptr(dest, draster);
249 	}
250     } else if (one != gx_no_color_index) {	/* Loop for character and pattern masks. */
251 	/* This is used heavily. */
252 	declare_unpack_color(abcd1, efgh1, one);
253 	int first_mask = first_bit << 1;
254 	int first_count, first_skip;
255 
256 	if (sbit + w > 8)
257 	    first_mask -= 1,
258 		first_count = 8 - sbit;
259 	else
260 	    first_mask -= first_mask >> w,
261 		first_count = w;
262 	first_skip = first_count * PIXEL_SIZE;
263 	while (h-- > 0) {
264 	    register bits32 *pptr = dest32;
265 	    const byte *sptr = line;
266 	    register int sbyte = *sptr++ & first_mask;
267 	    int count = w - first_count;
268 
269 	    if (sbyte) {
270 		register int bit = first_bit;
271 
272 		do {
273 		    if (sbyte & bit)
274 			put8(pptr, abcd1, efgh1);
275 		    pptr += PIXEL_SIZE;
276 		}
277 		while ((bit >>= 1) & first_mask);
278 	    } else
279 		pptr += first_skip;
280 	    while (count >= 8) {
281 		sbyte = *sptr++;
282 		if (sbyte & 0xf0) {
283 		    if (sbyte & 0x80)
284 			put8(pptr, abcd1, efgh1);
285 		    if (sbyte & 0x40)
286 			put8(pptr + 2, abcd1, efgh1);
287 		    if (sbyte & 0x20)
288 			put8(pptr + 4, abcd1, efgh1);
289 		    if (sbyte & 0x10)
290 			put8(pptr + 6, abcd1, efgh1);
291 		}
292 		if (sbyte & 0xf) {
293 		    if (sbyte & 8)
294 			put8(pptr + 8, abcd1, efgh1);
295 		    if (sbyte & 4)
296 			put8(pptr + 10, abcd1, efgh1);
297 		    if (sbyte & 2)
298 			put8(pptr + 12, abcd1, efgh1);
299 		    if (sbyte & 1)
300 			put8(pptr + 14, abcd1, efgh1);
301 		}
302 		pptr += 8 * PIXEL_SIZE;
303 		count -= 8;
304 	    }
305 	    if (count > 0) {
306 		register int bit = 0x80;
307 
308 		sbyte = *sptr++;
309 		do {
310 		    if (sbyte & bit)
311 			put8(pptr, abcd1, efgh1);
312 		    pptr += PIXEL_SIZE;
313 		    bit >>= 1;
314 		}
315 		while (--count > 0);
316 	    }
317 	    line += sraster;
318 	    inc_ptr(dest, draster);
319 	}
320     }
321     return 0;
322 }
323 
324 /* Copy a color bitmap. */
325 private int
mem_true64_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)326 mem_true64_copy_color(gx_device * dev,
327 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
328 		      int x, int y, int w, int h)
329 {
330     gx_device_memory * const mdev = (gx_device_memory *)dev;
331 
332     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
333     mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
334     return 0;
335 }
336 
337 /* ================ "Word"-oriented device ================ */
338 
339 /* Note that on a big-endian machine, this is the same as the */
340 /* standard byte-oriented-device. */
341 
342 #if !arch_is_big_endian
343 
344 /* Procedures */
345 declare_mem_procs(mem64_word_copy_mono, mem64_word_copy_color, mem64_word_fill_rectangle);
346 
347 /* Here is the device descriptor. */
348 const gx_device_memory mem_true64_word_device =
349 mem_full_device("image64w", 64, 0, mem_open,
350 		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
351      mem64_word_copy_mono, mem64_word_copy_color, mem64_word_fill_rectangle,
352 		gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,
353 		gx_no_strip_copy_rop, mem_word_get_bits_rectangle);
354 
355 /* Fill a rectangle with a color. */
356 private int
mem64_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)357 mem64_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
358 			  gx_color_index color)
359 {
360     gx_device_memory * const mdev = (gx_device_memory *)dev;
361     byte *base;
362     uint raster;
363 
364     fit_fill(dev, x, y, w, h);
365     base = scan_line_base(mdev, y);
366     raster = mdev->raster;
367     mem_swap_byte_rect(base, raster, x * 64, w * 64, h, true);
368     mem_true64_fill_rectangle(dev, x, y, w, h, color);
369     mem_swap_byte_rect(base, raster, x * 64, w * 64, h, false);
370     return 0;
371 }
372 
373 /* Copy a bitmap. */
374 private int
mem64_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)375 mem64_word_copy_mono(gx_device * dev,
376 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
377 	int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
378 {
379     gx_device_memory * const mdev = (gx_device_memory *)dev;
380     byte *row;
381     uint raster;
382     bool store;
383 
384     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
385     row = scan_line_base(mdev, y);
386     raster = mdev->raster;
387     store = (zero != gx_no_color_index && one != gx_no_color_index);
388     mem_swap_byte_rect(row, raster, x * 64, w * 64, h, store);
389     mem_true64_copy_mono(dev, base, sourcex, sraster, id,
390 			 x, y, w, h, zero, one);
391     mem_swap_byte_rect(row, raster, x * 64, w * 64, h, false);
392     return 0;
393 }
394 
395 /* Copy a color bitmap. */
396 private int
mem64_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)397 mem64_word_copy_color(gx_device * dev,
398 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
399 		      int x, int y, int w, int h)
400 {
401     gx_device_memory * const mdev = (gx_device_memory *)dev;
402     byte *row;
403     uint raster;
404 
405     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
406     row = scan_line_base(mdev, y);
407     raster = mdev->raster;
408     mem_swap_byte_rect(row, raster, x * 64, w * 64, h, true);
409     bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
410     				sraster, w * PIXEL_SIZE, h);
411     mem_swap_byte_rect(row, raster, x * 64, w * 64, h, false);
412     return 0;
413 }
414 
415 #endif /* !arch_is_big_endian */
416