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