1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. 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: gdevm1.c,v 1.6 2002/10/07 08:28:56 ghostgum Exp $ */
18 /* Monobit "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 /* Optionally, use the slow RasterOp implementations for testing. */
26 /*#define USE_COPY_ROP */
27
28 #ifdef USE_COPY_ROP
29 #include "gsrop.h"
30 #endif
31
32 /* ================ Standard (byte-oriented) device ================ */
33
34 /* Procedures */
35 private dev_proc_map_rgb_color(mem_mono_map_rgb_color);
36 private dev_proc_map_color_rgb(mem_mono_map_color_rgb);
37 private dev_proc_copy_mono(mem_mono_copy_mono);
38 private dev_proc_fill_rectangle(mem_mono_fill_rectangle);
39 private dev_proc_strip_tile_rectangle(mem_mono_strip_tile_rectangle);
40
41 /* The device descriptor. */
42 /* The instance is public. */
43 const gx_device_memory mem_mono_device =
44 mem_full_alpha_device("image1", 0, 1, mem_open,
45 mem_mono_map_rgb_color, mem_mono_map_color_rgb,
46 mem_mono_copy_mono, gx_default_copy_color, mem_mono_fill_rectangle,
47 gx_default_map_cmyk_color, gx_no_copy_alpha,
48 mem_mono_strip_tile_rectangle, mem_mono_strip_copy_rop,
49 mem_get_bits_rectangle);
50
51 /* Map color to/from RGB. This may be inverted. */
52 private gx_color_index
mem_mono_map_rgb_color(gx_device * dev,const gx_color_value cv[])53 mem_mono_map_rgb_color(gx_device * dev, const gx_color_value cv[])
54 {
55 gx_device_memory * const mdev = (gx_device_memory *)dev;
56 return (gx_default_w_b_map_rgb_color(dev, cv) ^ mdev->palette.data[0]) & 1;
57 }
58
59 private int
mem_mono_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])60 mem_mono_map_color_rgb(gx_device * dev, gx_color_index color,
61 gx_color_value prgb[3])
62 {
63 gx_device_memory * const mdev = (gx_device_memory *)dev;
64 /* NB code doesn't make sense... map_color_rgb procedures return an error code */
65 return (gx_default_w_b_map_color_rgb(dev, color, prgb) ^ mdev->palette.data[0]) & 1;
66 }
67
68 /* Fill a rectangle with a color. */
69 private int
mem_mono_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)70 mem_mono_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
71 gx_color_index color)
72 {
73 gx_device_memory * const mdev = (gx_device_memory *)dev;
74
75 #ifdef USE_COPY_ROP
76 return mem_mono_copy_rop(dev, NULL, 0, 0, gx_no_bitmap_id, NULL,
77 NULL, NULL,
78 x, y, w, h, 0, 0,
79 (color ? rop3_1 : rop3_0));
80 #else
81 fit_fill(dev, x, y, w, h);
82 bits_fill_rectangle(scan_line_base(mdev, y), x, mdev->raster,
83 -(int)(mono_fill_chunk) color, w, h);
84 return 0;
85 #endif
86 }
87
88 /* Convert x coordinate to byte offset in scan line. */
89 #define x_to_byte(x) ((x) >> 3)
90
91 /* Copy a monochrome bitmap. */
92 #undef mono_masks
93 #define mono_masks mono_copy_masks
94
95 /*
96 * Fetch a chunk from the source.
97 *
98 * Since source and destination are both always big-endian,
99 * fetching an aligned chunk never requires byte swapping.
100 */
101 #define CFETCH_ALIGNED(cptr)\
102 (*(const chunk *)(cptr))
103
104 /*
105 * Note that the macros always cast cptr,
106 * so it doesn't matter what the type of cptr is.
107 */
108 /* cshift = chunk_bits - shift. */
109 #undef chunk
110 #if arch_is_big_endian
111 # define chunk uint
112 # define CFETCH_RIGHT(cptr, shift, cshift)\
113 (CFETCH_ALIGNED(cptr) >> shift)
114 # define CFETCH_LEFT(cptr, shift, cshift)\
115 (CFETCH_ALIGNED(cptr) << shift)
116 # define CFETCH_USES_CSKEW 0
117 /* Fetch a chunk that straddles a chunk boundary. */
118 # define CFETCH2(cptr, cskew, skew)\
119 (CFETCH_LEFT(cptr, cskew, skew) +\
120 CFETCH_RIGHT((const chunk *)(cptr) + 1, skew, cskew))
121 #else /* little-endian */
122 # define chunk bits16
123 private const bits16 right_masks2[9] =
124 {
125 0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0x0f0f, 0x0707, 0x0303, 0x0101, 0x0000
126 };
127 private const bits16 left_masks2[9] =
128 {
129 0xffff, 0xfefe, 0xfcfc, 0xf8f8, 0xf0f0, 0xe0e0, 0xc0c0, 0x8080, 0x0000
130 };
131
132 # define CCONT(cptr, off) (((const chunk *)(cptr))[off])
133 # define CFETCH_RIGHT(cptr, shift, cshift)\
134 ((shift) < 8 ?\
135 ((CCONT(cptr, 0) >> (shift)) & right_masks2[shift]) +\
136 (CCONT(cptr, 0) << (cshift)) :\
137 ((chunk)*(const byte *)(cptr) << (cshift)) & 0xff00)
138 # define CFETCH_LEFT(cptr, shift, cshift)\
139 ((shift) < 8 ?\
140 ((CCONT(cptr, 0) << (shift)) & left_masks2[shift]) +\
141 (CCONT(cptr, 0) >> (cshift)) :\
142 ((CCONT(cptr, 0) & 0xff00) >> (cshift)) & 0xff)
143 # define CFETCH_USES_CSKEW 1
144 /* Fetch a chunk that straddles a chunk boundary. */
145 /* We can avoid testing the shift amount twice */
146 /* by expanding the CFETCH_LEFT/right macros in-line. */
147 # define CFETCH2(cptr, cskew, skew)\
148 ((cskew) < 8 ?\
149 ((CCONT(cptr, 0) << (cskew)) & left_masks2[cskew]) +\
150 (CCONT(cptr, 0) >> (skew)) +\
151 (((chunk)(((const byte *)(cptr))[2]) << (cskew)) & 0xff00) :\
152 (((CCONT(cptr, 0) & 0xff00) >> (skew)) & 0xff) +\
153 ((CCONT(cptr, 1) >> (skew)) & right_masks2[skew]) +\
154 (CCONT(cptr, 1) << (cskew)))
155 #endif
156
157 typedef enum {
158 COPY_OR = 0, COPY_STORE, COPY_AND, COPY_FUNNY
159 } copy_function;
160 typedef struct {
161 int invert;
162 copy_function op;
163 } copy_mode;
164
165 /*
166 * Map from <color0,color1> to copy_mode.
167 * Logically, this is a 2-D array.
168 * The indexing is (transparent, 0, 1, unused). */
169 private const copy_mode copy_modes[16] = {
170 {~0, COPY_FUNNY}, /* NN */
171 {~0, COPY_AND}, /* N0 */
172 {0, COPY_OR}, /* N1 */
173 {0, 0}, /* unused */
174 {0, COPY_AND}, /* 0N */
175 {0, COPY_FUNNY}, /* 00 */
176 {0, COPY_STORE}, /* 01 */
177 {0, 0}, /* unused */
178 {~0, COPY_OR}, /* 1N */
179 {~0, COPY_STORE}, /* 10 */
180 {0, COPY_FUNNY}, /* 11 */
181 {0, 0}, /* unused */
182 {0, 0}, /* unused */
183 {0, 0}, /* unused */
184 {0, 0}, /* unused */
185 {0, 0}, /* unused */
186 };
187
188 /* Handle the funny cases that aren't supposed to happen. */
189 #define FUNNY_CASE()\
190 (invert ? gs_note_error(-1) :\
191 mem_mono_fill_rectangle(dev, x, y, w, h, color0))
192
193 private int
mem_mono_copy_mono(gx_device * dev,const byte * source_data,int source_x,int source_raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)194 mem_mono_copy_mono(gx_device * dev,
195 const byte * source_data, int source_x, int source_raster, gx_bitmap_id id,
196 int x, int y, int w, int h, gx_color_index color0, gx_color_index color1)
197 {
198 gx_device_memory * const mdev = (gx_device_memory *)dev;
199
200 #ifdef USE_COPY_ROP
201 return mem_mono_copy_rop(dev, source_data, source_x, source_raster,
202 id, NULL, NULL, NULL,
203 x, y, w, h, 0, 0,
204 ((color0 == gx_no_color_index ? rop3_D :
205 color0 == 0 ? rop3_0 : rop3_1) & ~rop3_S) |
206 ((color1 == gx_no_color_index ? rop3_D :
207 color1 == 0 ? rop3_0 : rop3_1) & rop3_S));
208 #else /* !USE_COPY_ROP */
209 register const byte *bptr; /* actually chunk * */
210 int dbit, wleft;
211 uint mask;
212 copy_mode mode;
213
214 DECLARE_SCAN_PTR_VARS(dbptr, byte *, dest_raster);
215 #define optr ((chunk *)dbptr)
216 register int skew;
217 register uint invert;
218
219 fit_copy(dev, source_data, source_x, source_raster, id, x, y, w, h);
220 #if gx_no_color_index_value != -1 /* hokey! */
221 if (color0 == gx_no_color_index)
222 color0 = -1;
223 if (color1 == gx_no_color_index)
224 color1 = -1;
225 #endif
226 mode = copy_modes[((int)color0 << 2) + (int)color1 + 5];
227 invert = (uint)mode.invert; /* load register */
228 SETUP_RECT_VARS(dbptr, byte *, dest_raster);
229 bptr = source_data + ((source_x & ~chunk_align_bit_mask) >> 3);
230 dbit = x & chunk_align_bit_mask;
231 skew = dbit - (source_x & chunk_align_bit_mask);
232
233 /* Macros for writing partial chunks. */
234 /* The destination pointer is always named optr, */
235 /* and must be declared as chunk *. */
236 /* CINVERT may be temporarily redefined. */
237 #define CINVERT(bits) ((bits) ^ invert)
238 #define WRITE_OR_MASKED(bits, mask, off)\
239 optr[off] |= (CINVERT(bits) & mask)
240 #define WRITE_STORE_MASKED(bits, mask, off)\
241 optr[off] = ((optr[off] & ~mask) | (CINVERT(bits) & mask))
242 #define WRITE_AND_MASKED(bits, mask, off)\
243 optr[off] &= (CINVERT(bits) | ~mask)
244 /* Macros for writing full chunks. */
245 #define WRITE_OR(bits) *optr |= CINVERT(bits)
246 #define WRITE_STORE(bits) *optr = CINVERT(bits)
247 #define WRITE_AND(bits) *optr &= CINVERT(bits)
248 /* Macro for incrementing to next chunk. */
249 #define NEXT_X_CHUNK()\
250 bptr += chunk_bytes; dbptr += chunk_bytes
251 /* Common macro for the end of each scan line. */
252 #define END_Y_LOOP(sdelta, ddelta)\
253 bptr += sdelta; dbptr += ddelta
254
255 if ((wleft = w + dbit - chunk_bits) <= 0) { /* The entire operation fits in one (destination) chunk. */
256 set_mono_thin_mask(mask, w, dbit);
257
258 #define WRITE_SINGLE(wr_op, src)\
259 for ( ; ; )\
260 { wr_op(src, mask, 0);\
261 if ( --h == 0 ) break;\
262 END_Y_LOOP(source_raster, dest_raster);\
263 }
264
265 #define WRITE1_LOOP(src)\
266 switch ( mode.op ) {\
267 case COPY_OR: WRITE_SINGLE(WRITE_OR_MASKED, src); break;\
268 case COPY_STORE: WRITE_SINGLE(WRITE_STORE_MASKED, src); break;\
269 case COPY_AND: WRITE_SINGLE(WRITE_AND_MASKED, src); break;\
270 default: return FUNNY_CASE();\
271 }
272
273 if (skew >= 0) { /* single -> single, right/no shift */
274 if (skew == 0) { /* no shift */
275 WRITE1_LOOP(CFETCH_ALIGNED(bptr));
276 } else { /* right shift */
277 #if CFETCH_USES_CSKEW
278 int cskew = chunk_bits - skew;
279 #endif
280
281 WRITE1_LOOP(CFETCH_RIGHT(bptr, skew, cskew));
282 }
283 } else if (wleft <= skew) { /* single -> single, left shift */
284 #if CFETCH_USES_CSKEW
285 int cskew = chunk_bits + skew;
286 #endif
287
288 skew = -skew;
289 WRITE1_LOOP(CFETCH_LEFT(bptr, skew, cskew));
290 } else { /* double -> single */
291 int cskew = -skew;
292
293 skew += chunk_bits;
294 WRITE1_LOOP(CFETCH2(bptr, cskew, skew));
295 }
296 #undef WRITE1_LOOP
297 #undef WRITE_SINGLE
298 } else if (wleft <= skew) { /* 1 source chunk -> 2 destination chunks. */
299 /* This is an important special case for */
300 /* both characters and halftone tiles. */
301 uint rmask;
302 int cskew = chunk_bits - skew;
303
304 set_mono_left_mask(mask, dbit);
305 set_mono_right_mask(rmask, wleft);
306 #undef CINVERT
307 #define CINVERT(bits) (bits) /* pre-inverted here */
308
309 #if arch_is_big_endian /* no byte swapping */
310 # define WRITE_1TO2(wr_op)\
311 for ( ; ; )\
312 { register uint bits = CFETCH_ALIGNED(bptr) ^ invert;\
313 wr_op(bits >> skew, mask, 0);\
314 wr_op(bits << cskew, rmask, 1);\
315 if ( --h == 0 ) break;\
316 END_Y_LOOP(source_raster, dest_raster);\
317 }
318 #else /* byte swapping */
319 # define WRITE_1TO2(wr_op)\
320 for ( ; ; )\
321 { wr_op(CFETCH_RIGHT(bptr, skew, cskew) ^ invert, mask, 0);\
322 wr_op(CFETCH_LEFT(bptr, cskew, skew) ^ invert, rmask, 1);\
323 if ( --h == 0 ) break;\
324 END_Y_LOOP(source_raster, dest_raster);\
325 }
326 #endif
327
328 switch (mode.op) {
329 case COPY_OR:
330 WRITE_1TO2(WRITE_OR_MASKED);
331 break;
332 case COPY_STORE:
333 WRITE_1TO2(WRITE_STORE_MASKED);
334 break;
335 case COPY_AND:
336 WRITE_1TO2(WRITE_AND_MASKED);
337 break;
338 default:
339 return FUNNY_CASE();
340 }
341 #undef CINVERT
342 #define CINVERT(bits) ((bits) ^ invert)
343 #undef WRITE_1TO2
344 } else { /* More than one source chunk and more than one */
345 /* destination chunk are involved. */
346 uint rmask;
347 int words = (wleft & ~chunk_bit_mask) >> 3;
348 uint sskip = source_raster - words;
349 uint dskip = dest_raster - words;
350 register uint bits;
351
352 set_mono_left_mask(mask, dbit);
353 set_mono_right_mask(rmask, wleft & chunk_bit_mask);
354 if (skew == 0) { /* optimize the aligned case */
355
356 #define WRITE_ALIGNED(wr_op, wr_op_masked)\
357 for ( ; ; )\
358 { int count = wleft;\
359 /* Do first partial chunk. */\
360 wr_op_masked(CFETCH_ALIGNED(bptr), mask, 0);\
361 /* Do full chunks. */\
362 while ( (count -= chunk_bits) >= 0 )\
363 { NEXT_X_CHUNK(); wr_op(CFETCH_ALIGNED(bptr)); }\
364 /* Do last chunk */\
365 if ( count > -chunk_bits )\
366 { wr_op_masked(CFETCH_ALIGNED(bptr + chunk_bytes), rmask, 1); }\
367 if ( --h == 0 ) break;\
368 END_Y_LOOP(sskip, dskip);\
369 }
370
371 switch (mode.op) {
372 case COPY_OR:
373 WRITE_ALIGNED(WRITE_OR, WRITE_OR_MASKED);
374 break;
375 case COPY_STORE:
376 WRITE_ALIGNED(WRITE_STORE, WRITE_STORE_MASKED);
377 break;
378 case COPY_AND:
379 WRITE_ALIGNED(WRITE_AND, WRITE_AND_MASKED);
380 break;
381 default:
382 return FUNNY_CASE();
383 }
384 #undef WRITE_ALIGNED
385 } else { /* not aligned */
386 int cskew = -skew & chunk_bit_mask;
387 bool case_right =
388 (skew >= 0 ? true :
389 ((bptr += chunk_bytes), false));
390
391 skew &= chunk_bit_mask;
392
393 #define WRITE_UNALIGNED(wr_op, wr_op_masked)\
394 /* Prefetch partial word. */\
395 bits =\
396 (case_right ? CFETCH_RIGHT(bptr, skew, cskew) :\
397 CFETCH2(bptr - chunk_bytes, cskew, skew));\
398 wr_op_masked(bits, mask, 0);\
399 /* Do full chunks. */\
400 while ( count >= chunk_bits )\
401 { bits = CFETCH2(bptr, cskew, skew);\
402 NEXT_X_CHUNK(); wr_op(bits); count -= chunk_bits;\
403 }\
404 /* Do last chunk */\
405 if ( count > 0 )\
406 { bits = CFETCH_LEFT(bptr, cskew, skew);\
407 if ( count > skew ) bits += CFETCH_RIGHT(bptr + chunk_bytes, skew, cskew);\
408 wr_op_masked(bits, rmask, 1);\
409 }
410
411 switch (mode.op) {
412 case COPY_OR:
413 for (;;) {
414 int count = wleft;
415
416 WRITE_UNALIGNED(WRITE_OR, WRITE_OR_MASKED);
417 if (--h == 0)
418 break;
419 END_Y_LOOP(sskip, dskip);
420 }
421 break;
422 case COPY_STORE:
423 for (;;) {
424 int count = wleft;
425
426 WRITE_UNALIGNED(WRITE_STORE, WRITE_STORE_MASKED);
427 if (--h == 0)
428 break;
429 END_Y_LOOP(sskip, dskip);
430 }
431 break;
432 case COPY_AND:
433 for (;;) {
434 int count = wleft;
435
436 WRITE_UNALIGNED(WRITE_AND, WRITE_AND_MASKED);
437 if (--h == 0)
438 break;
439 END_Y_LOOP(sskip, dskip);
440 }
441 break;
442 default /*case COPY_FUNNY */ :
443 return FUNNY_CASE();
444 }
445 #undef WRITE_UNALIGNED
446 }
447 }
448 #undef END_Y_LOOP
449 #undef NEXT_X_CHUNK
450 return 0;
451 #undef optr
452 #endif /* !USE_COPY_ROP */
453 }
454
455 /* Strip-tile with a monochrome halftone. */
456 /* This is a performance bottleneck for monochrome devices, */
457 /* so we re-implement it, even though it takes a lot of code. */
458 private int
mem_mono_strip_tile_rectangle(gx_device * dev,register const gx_strip_bitmap * tiles,int tx,int y,int tw,int th,gx_color_index color0,gx_color_index color1,int px,int py)459 mem_mono_strip_tile_rectangle(gx_device * dev,
460 register const gx_strip_bitmap * tiles,
461 int tx, int y, int tw, int th, gx_color_index color0, gx_color_index color1,
462 int px, int py)
463 {
464 gx_device_memory * const mdev = (gx_device_memory *)dev;
465
466 #ifdef USE_COPY_ROP
467 return mem_mono_strip_copy_rop(dev, NULL, 0, 0, tile->id, NULL,
468 tiles, NULL,
469 tx, y, tw, th, px, py,
470 ((color0 == gx_no_color_index ? rop3_D :
471 color0 == 0 ? rop3_0 : rop3_1) & ~rop3_T) |
472 ((color1 == gx_no_color_index ? rop3_D :
473 color1 == 0 ? rop3_0 : rop3_1) & rop3_T));
474 #else /* !USE_COPY_ROP */
475 register uint invert;
476 int source_raster;
477 uint tile_bits_size;
478 const byte *source_data;
479 const byte *end;
480 int x, rw, w, h;
481 register const byte *bptr; /* actually chunk * */
482 int dbit, wleft;
483 uint mask;
484 byte *dbase;
485
486 DECLARE_SCAN_PTR_VARS(dbptr, byte *, dest_raster);
487 #define optr ((chunk *)dbptr)
488 register int skew;
489
490 /* This implementation doesn't handle strips yet. */
491 if (color0 != (color1 ^ 1) || tiles->shift != 0)
492 return gx_default_strip_tile_rectangle(dev, tiles, tx, y, tw, th,
493 color0, color1, px, py);
494 fit_fill(dev, tx, y, tw, th);
495 invert = (uint)(-(int) color0);
496 source_raster = tiles->raster;
497 source_data = tiles->data + ((y + py) % tiles->rep_height) * source_raster;
498 tile_bits_size = tiles->size.y * source_raster;
499 end = tiles->data + tile_bits_size;
500 #undef END_Y_LOOP
501 #define END_Y_LOOP(sdelta, ddelta)\
502 if ( end - bptr <= sdelta ) /* wrap around */\
503 bptr -= tile_bits_size;\
504 bptr += sdelta; dbptr += ddelta
505 dest_raster = mdev->raster;
506 dbase = scan_line_base(mdev, y);
507 x = tx;
508 rw = tw;
509 /*
510 * The outermost loop here works horizontally, one iteration per
511 * copy of the tile. Note that all iterations except the first
512 * have source_x = 0.
513 */
514 {
515 int source_x = (x + px) % tiles->rep_width;
516
517 w = tiles->size.x - source_x;
518 bptr = source_data + ((source_x & ~chunk_align_bit_mask) >> 3);
519 dbit = x & chunk_align_bit_mask;
520 skew = dbit - (source_x & chunk_align_bit_mask);
521 }
522 outer:if (w > rw)
523 w = rw;
524 h = th;
525 dbptr = dbase + ((x >> 3) & -chunk_align_bytes);
526 if ((wleft = w + dbit - chunk_bits) <= 0) { /* The entire operation fits in one (destination) chunk. */
527 set_mono_thin_mask(mask, w, dbit);
528 #define WRITE1_LOOP(src)\
529 for ( ; ; )\
530 { WRITE_STORE_MASKED(src, mask, 0);\
531 if ( --h == 0 ) break;\
532 END_Y_LOOP(source_raster, dest_raster);\
533 }
534 if (skew >= 0) { /* single -> single, right/no shift */
535 if (skew == 0) { /* no shift */
536 WRITE1_LOOP(CFETCH_ALIGNED(bptr));
537 } else { /* right shift */
538 #if CFETCH_USES_CSKEW
539 int cskew = chunk_bits - skew;
540 #endif
541
542 WRITE1_LOOP(CFETCH_RIGHT(bptr, skew, cskew));
543 }
544 } else if (wleft <= skew) { /* single -> single, left shift */
545 #if CFETCH_USES_CSKEW
546 int cskew = chunk_bits + skew;
547 #endif
548
549 skew = -skew;
550 WRITE1_LOOP(CFETCH_LEFT(bptr, skew, cskew));
551 } else { /* double -> single */
552 int cskew = -skew;
553
554 skew += chunk_bits;
555 WRITE1_LOOP(CFETCH2(bptr, cskew, skew));
556 }
557 #undef WRITE1_LOOP
558 } else if (wleft <= skew) { /* 1 source chunk -> 2 destination chunks. */
559 /* This is an important special case for */
560 /* both characters and halftone tiles. */
561 uint rmask;
562 int cskew = chunk_bits - skew;
563
564 set_mono_left_mask(mask, dbit);
565 set_mono_right_mask(rmask, wleft);
566 #if arch_is_big_endian /* no byte swapping */
567 #undef CINVERT
568 #define CINVERT(bits) (bits) /* pre-inverted here */
569 for (;;) {
570 register uint bits = CFETCH_ALIGNED(bptr) ^ invert;
571
572 WRITE_STORE_MASKED(bits >> skew, mask, 0);
573 WRITE_STORE_MASKED(bits << cskew, rmask, 1);
574 if (--h == 0)
575 break;
576 END_Y_LOOP(source_raster, dest_raster);
577 }
578 #undef CINVERT
579 #define CINVERT(bits) ((bits) ^ invert)
580 #else /* byte swapping */
581 for (;;) {
582 WRITE_STORE_MASKED(CFETCH_RIGHT(bptr, skew, cskew), mask, 0);
583 WRITE_STORE_MASKED(CFETCH_LEFT(bptr, cskew, skew), rmask, 1);
584 if (--h == 0)
585 break;
586 END_Y_LOOP(source_raster, dest_raster);
587 }
588 #endif
589 } else { /* More than one source chunk and more than one */
590 /* destination chunk are involved. */
591 uint rmask;
592 int words = (wleft & ~chunk_bit_mask) >> 3;
593 uint sskip = source_raster - words;
594 uint dskip = dest_raster - words;
595 register uint bits;
596
597 #define NEXT_X_CHUNK()\
598 bptr += chunk_bytes; dbptr += chunk_bytes
599
600 set_mono_right_mask(rmask, wleft & chunk_bit_mask);
601 if (skew == 0) { /* optimize the aligned case */
602 if (dbit == 0)
603 mask = 0;
604 else
605 set_mono_left_mask(mask, dbit);
606 for (;;) {
607 int count = wleft;
608
609 /* Do first partial chunk. */
610 if (mask)
611 WRITE_STORE_MASKED(CFETCH_ALIGNED(bptr), mask, 0);
612 else
613 WRITE_STORE(CFETCH_ALIGNED(bptr));
614 /* Do full chunks. */
615 while ((count -= chunk_bits) >= 0) {
616 NEXT_X_CHUNK();
617 WRITE_STORE(CFETCH_ALIGNED(bptr));
618 }
619 /* Do last chunk */
620 if (count > -chunk_bits) {
621 WRITE_STORE_MASKED(CFETCH_ALIGNED(bptr + chunk_bytes), rmask, 1);
622 }
623 if (--h == 0)
624 break;
625 END_Y_LOOP(sskip, dskip);
626 }
627 } else { /* not aligned */
628 bool case_right =
629 (skew >= 0 ? true :
630 ((bptr += chunk_bytes), false));
631 int cskew = -skew & chunk_bit_mask;
632
633 skew &= chunk_bit_mask;
634 set_mono_left_mask(mask, dbit);
635 for (;;) {
636 int count = wleft;
637
638 if (case_right)
639 bits = CFETCH_RIGHT(bptr, skew, cskew);
640 else
641 bits = CFETCH2(bptr - chunk_bytes, cskew, skew);
642 WRITE_STORE_MASKED(bits, mask, 0);
643 /* Do full chunks. */
644 while (count >= chunk_bits) {
645 bits = CFETCH2(bptr, cskew, skew);
646 NEXT_X_CHUNK();
647 WRITE_STORE(bits);
648 count -= chunk_bits;
649 }
650 /* Do last chunk */
651 if (count > 0) {
652 bits = CFETCH_LEFT(bptr, cskew, skew);
653 if (count > skew)
654 bits += CFETCH_RIGHT(bptr + chunk_bytes, skew, cskew);
655 WRITE_STORE_MASKED(bits, rmask, 1);
656 }
657 if (--h == 0)
658 break;
659 END_Y_LOOP(sskip, dskip);
660 }
661 }
662 }
663 #undef END_Y_LOOP
664 #undef NEXT_X_CHUNK
665 #undef optr
666 if ((rw -= w) > 0) {
667 x += w;
668 w = tiles->size.x;
669 bptr = source_data;
670 skew = dbit = x & chunk_align_bit_mask;
671 goto outer;
672 }
673 return 0;
674 #endif /* !USE_COPY_ROP */
675 }
676
677 /* ================ "Word"-oriented device ================ */
678
679 /* Note that on a big-endian machine, this is the same as the */
680 /* standard byte-oriented-device. */
681
682 #if !arch_is_big_endian
683
684 /* Procedures */
685 private dev_proc_copy_mono(mem1_word_copy_mono);
686 private dev_proc_fill_rectangle(mem1_word_fill_rectangle);
687
688 #define mem1_word_strip_tile_rectangle gx_default_strip_tile_rectangle
689
690 /* Here is the device descriptor. */
691 const gx_device_memory mem_mono_word_device =
692 mem_full_alpha_device("image1w", 0, 1, mem_open,
693 mem_mono_map_rgb_color, mem_mono_map_color_rgb,
694 mem1_word_copy_mono, gx_default_copy_color, mem1_word_fill_rectangle,
695 gx_default_map_cmyk_color, gx_no_copy_alpha,
696 mem1_word_strip_tile_rectangle, gx_no_strip_copy_rop,
697 mem_word_get_bits_rectangle);
698
699 /* Fill a rectangle with a color. */
700 private int
mem1_word_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)701 mem1_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
702 gx_color_index color)
703 {
704 gx_device_memory * const mdev = (gx_device_memory *)dev;
705 byte *base;
706 uint raster;
707
708 fit_fill(dev, x, y, w, h);
709 base = scan_line_base(mdev, y);
710 raster = mdev->raster;
711 mem_swap_byte_rect(base, raster, x, w, h, true);
712 bits_fill_rectangle(base, x, raster, -(int)(mono_fill_chunk) color, w, h);
713 mem_swap_byte_rect(base, raster, x, w, h, true);
714 return 0;
715 }
716
717 /* Copy a bitmap. */
718 private int
mem1_word_copy_mono(gx_device * dev,const byte * source_data,int source_x,int source_raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)719 mem1_word_copy_mono(gx_device * dev,
720 const byte * source_data, int source_x, int source_raster, gx_bitmap_id id,
721 int x, int y, int w, int h, gx_color_index color0, gx_color_index color1)
722 {
723 gx_device_memory * const mdev = (gx_device_memory *)dev;
724 byte *row;
725 uint raster;
726 bool store;
727
728 fit_copy(dev, source_data, source_x, source_raster, id, x, y, w, h);
729 row = scan_line_base(mdev, y);
730 raster = mdev->raster;
731 store = (color0 != gx_no_color_index && color1 != gx_no_color_index);
732 mem_swap_byte_rect(row, raster, x, w, h, store);
733 mem_mono_copy_mono(dev, source_data, source_x, source_raster, id,
734 x, y, w, h, color0, color1);
735 mem_swap_byte_rect(row, raster, x, w, h, false);
736 return 0;
737 }
738
739 #endif /* !arch_is_big_endian */
740