xref: /plan9/sys/src/cmd/gs/src/gsbitops.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1994, 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: gsbitops.c,v 1.8 2002/10/07 08:28:56 ghostgum Exp $ */
18 /* Bitmap filling, copying, and transforming operations */
19 #include "stdio_.h"
20 #include "memory_.h"
21 #include "gdebug.h"
22 #include "gserror.h"
23 #include "gserrors.h"
24 #include "gstypes.h"
25 #include "gsbittab.h"
26 #include "gxbitops.h"
27 #include "gxcindex.h"
28 
29 /* ---------------- Bit-oriented operations ---------------- */
30 
31 /* Define masks for little-endian operation. */
32 /* masks[i] has the first i bits off and the rest on. */
33 #if !arch_is_big_endian
34 const bits16 mono_copy_masks[17] = {
35     0xffff, 0xff7f, 0xff3f, 0xff1f,
36     0xff0f, 0xff07, 0xff03, 0xff01,
37     0xff00, 0x7f00, 0x3f00, 0x1f00,
38     0x0f00, 0x0700, 0x0300, 0x0100,
39     0x0000
40 };
41 const bits32 mono_fill_masks[33] = {
42 #define mask(n)\
43   ((~0xff | (0xff >> (n & 7))) << (n & -8))
44     mask( 0),mask( 1),mask( 2),mask( 3),mask( 4),mask( 5),mask( 6),mask( 7),
45     mask( 8),mask( 9),mask(10),mask(11),mask(12),mask(13),mask(14),mask(15),
46     mask(16),mask(17),mask(18),mask(19),mask(20),mask(21),mask(22),mask(23),
47     mask(24),mask(25),mask(26),mask(27),mask(28),mask(29),mask(30),mask(31),
48     0
49 #undef mask
50 };
51 #endif
52 
53 /* Fill a rectangle of bits with an 8x1 pattern. */
54 /* The pattern argument must consist of the pattern in every byte, */
55 /* e.g., if the desired pattern is 0xaa, the pattern argument must */
56 /* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
57 #undef chunk
58 #define chunk mono_fill_chunk
59 #undef mono_masks
60 #define mono_masks mono_fill_masks
61 void
bits_fill_rectangle(byte * dest,int dest_bit,uint draster,mono_fill_chunk pattern,int width_bits,int height)62 bits_fill_rectangle(byte * dest, int dest_bit, uint draster,
63 		    mono_fill_chunk pattern, int width_bits, int height)
64 {
65     uint bit;
66     chunk right_mask;
67     int line_count = height;
68     chunk *ptr;
69     int last_bit;
70 
71 #define FOR_EACH_LINE(stat)\
72 	do { stat } while ( inc_ptr(ptr, draster), --line_count )
73 
74     dest += (dest_bit >> 3) & -chunk_align_bytes;
75     ptr = (chunk *) dest;
76     bit = dest_bit & chunk_align_bit_mask;
77     last_bit = width_bits + bit - (chunk_bits + 1);
78 
79     if (last_bit < 0) {		/* <=1 chunk */
80 	set_mono_thin_mask(right_mask, width_bits, bit);
81 	if (pattern == 0)
82 	    FOR_EACH_LINE(*ptr &= ~right_mask;);
83 	else if (pattern == (mono_fill_chunk)(-1))
84 	    FOR_EACH_LINE(*ptr |= right_mask;);
85 	else
86 	    FOR_EACH_LINE(
87 		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
88     } else {
89 	chunk mask;
90 	int last = last_bit >> chunk_log2_bits;
91 
92 	set_mono_left_mask(mask, bit);
93 	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
94 	switch (last) {
95 	    case 0:		/* 2 chunks */
96 		if (pattern == 0)
97 		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
98 		else if (pattern == (mono_fill_chunk)(-1))
99 		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
100 		else
101 		    FOR_EACH_LINE(
102 		        *ptr = (*ptr & ~mask) | (pattern & mask);
103 			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
104 		break;
105 	    case 1:		/* 3 chunks */
106 		if (pattern == 0)
107 		    FOR_EACH_LINE( *ptr &= ~mask;
108 				   ptr[1] = 0;
109 				   ptr[2] &= ~right_mask; );
110 		else if (pattern == (mono_fill_chunk)(-1))
111 		    FOR_EACH_LINE( *ptr |= mask;
112 				   ptr[1] = ~(chunk) 0;
113 				   ptr[2] |= right_mask; );
114 		else
115 		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
116 				    ptr[1] = pattern;
117 				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
118 		break;
119 	    default:{		/* >3 chunks */
120 		    uint byte_count = (last_bit >> 3) & -chunk_bytes;
121 
122 		    if (pattern == 0)
123 			FOR_EACH_LINE( *ptr &= ~mask;
124 				       memset(ptr + 1, 0, byte_count);
125 				       ptr[last + 1] &= ~right_mask; );
126 		    else if (pattern == (mono_fill_chunk)(-1))
127 			FOR_EACH_LINE( *ptr |= mask;
128 				       memset(ptr + 1, 0xff, byte_count);
129 				       ptr[last + 1] |= right_mask; );
130 		    else
131 			FOR_EACH_LINE(
132 				*ptr = (*ptr & ~mask) | (pattern & mask);
133 				memset(ptr + 1, (byte) pattern, byte_count);
134 				ptr[last + 1] = (ptr[last + 1] & ~right_mask) |
135 					        (pattern & right_mask); 	);
136 		}
137 	}
138     }
139 #undef FOR_EACH_LINE
140 }
141 
142 /*
143  * Similar to bits_fill_rectangle, but with an additional source mask.
144  * The src_mask variable is 1 for those bits of the original that are
145  * to be retained. The mask argument must consist of the requisite value
146  * in every byte, in the same manner as the pattern.
147  */
148 void
bits_fill_rectangle_masked(byte * dest,int dest_bit,uint draster,mono_fill_chunk pattern,mono_fill_chunk src_mask,int width_bits,int height)149 bits_fill_rectangle_masked(byte * dest, int dest_bit, uint draster,
150 		    mono_fill_chunk pattern, mono_fill_chunk src_mask,
151 		    int width_bits, int height)
152 {
153     uint bit;
154     chunk right_mask;
155     int line_count = height;
156     chunk *ptr;
157     int last_bit;
158 
159 #define FOR_EACH_LINE(stat)\
160 	do { stat } while ( inc_ptr(ptr, draster), --line_count )
161 
162     dest += (dest_bit >> 3) & -chunk_align_bytes;
163     ptr = (chunk *) dest;
164     bit = dest_bit & chunk_align_bit_mask;
165     last_bit = width_bits + bit - (chunk_bits + 1);
166 
167     if (last_bit < 0) {		/* <=1 chunk */
168 	set_mono_thin_mask(right_mask, width_bits, bit);
169 	right_mask &= ~src_mask;
170 	if (pattern == 0)
171 	    FOR_EACH_LINE(*ptr &= ~right_mask;);
172 	else if (pattern == (mono_fill_chunk)(-1))
173 	    FOR_EACH_LINE(*ptr |= right_mask;);
174 	else
175 	    FOR_EACH_LINE(
176 		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
177     } else {
178 	chunk mask;
179 	int last = last_bit >> chunk_log2_bits;
180 
181 	set_mono_left_mask(mask, bit);
182 	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
183 	mask &= ~src_mask;
184 	right_mask &= ~src_mask;
185 	switch (last) {
186 	    case 0:		/* 2 chunks */
187 		if (pattern == 0)
188 		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
189 		else if (pattern == (mono_fill_chunk)(-1))
190 		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
191 		else
192 		    FOR_EACH_LINE(
193 		        *ptr = (*ptr & ~mask) | (pattern & mask);
194 			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
195 		break;
196 	    case 1:		/* 3 chunks */
197 		if (pattern == 0)
198 		    FOR_EACH_LINE( *ptr &= ~mask;
199 				   ptr[1] &= src_mask;
200 				   ptr[2] &= ~right_mask; );
201 		else if (pattern == (mono_fill_chunk)(-1))
202 		    FOR_EACH_LINE( *ptr |= mask;
203 				   ptr[1] |= ~src_mask;
204 				   ptr[2] |= right_mask; );
205 		else
206 		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
207 				    ptr[1] =(ptr[1] & src_mask) | pattern;
208 				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
209 		break;
210 	    default:{		/* >3 chunks */
211                     int     i;
212 
213 		    if (pattern == 0)
214 			FOR_EACH_LINE( *ptr++ &= ~mask;
215 				       for (i = 0; i < last; i++)
216 					   *ptr++ &= src_mask;
217 				       *ptr &= ~right_mask; );
218 		    else if (pattern == (mono_fill_chunk)(-1))
219 			FOR_EACH_LINE( *ptr++ |= mask;
220 				       for (i = 0; i < last; i++)
221 					   *ptr++ |= ~src_mask;
222 					*ptr |= right_mask; );
223 		    else
224 			FOR_EACH_LINE(
225 			    /* note: we know (pattern & ~src_mask) == pattern */
226 			    *ptr = (*ptr & ~mask) | (pattern & mask);
227 			    ++ptr;
228 			    for (i = 0; i < last; i++, ptr++)
229                                 *ptr = (*ptr & src_mask) | pattern;
230 				*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
231 		}
232 	}
233     }
234 #undef FOR_EACH_LINE
235 }
236 
237 /* Replicate a bitmap horizontally in place. */
238 void
bits_replicate_horizontally(byte * data,uint width,uint height,uint raster,uint replicated_width,uint replicated_raster)239 bits_replicate_horizontally(byte * data, uint width, uint height,
240 		 uint raster, uint replicated_width, uint replicated_raster)
241 {
242     /* The current algorithm is extremely inefficient! */
243     const byte *orig_row = data + (height - 1) * raster;
244     byte *tile_row = data + (height - 1) * replicated_raster;
245     uint y;
246 
247     if (!(width & 7)) {
248 	uint src_bytes = width >> 3;
249 	uint dest_bytes = replicated_width >> 3;
250 
251 	for (y = height; y-- > 0;
252 	     orig_row -= raster, tile_row -= replicated_raster
253 	     ) {
254 	    uint move = src_bytes;
255 	    const byte *from = orig_row;
256 	    byte *to = tile_row + dest_bytes - src_bytes;
257 
258 	    memmove(to, from, move);
259 	    while (to - tile_row >= move) {
260 		from = to;
261 		to -= move;
262 		memmove(to, from, move);
263 		move <<= 1;
264 	    }
265 	    if (to != tile_row)
266 		memmove(tile_row, to, to - tile_row);
267 	}
268     } else {
269 	/*
270 	 * This algorithm is inefficient, but probably not worth improving.
271 	 */
272 	uint bit_count = width & (uint)(-(int)width);  /* lowest bit: 1, 2, or 4 */
273 	uint left_mask = (0xff00 >> bit_count) & 0xff;
274 
275 	for (y = height; y-- > 0;
276 	     orig_row -= raster, tile_row -= replicated_raster
277 	     ) {
278 	    uint sx;
279 
280 	    for (sx = width; sx > 0;) {
281 		uint bits, dx;
282 
283 		sx -= bit_count;
284 		bits = (orig_row[sx >> 3] << (sx & 7)) & left_mask;
285 		for (dx = sx + replicated_width; dx >= width;) {
286 		    byte *dp;
287 		    int dbit;
288 
289 		    dx -= width;
290 		    dbit = dx & 7;
291 		    dp = tile_row + (dx >> 3);
292 		    *dp = (*dp & ~(left_mask >> dbit)) | (bits >> dbit);
293 		}
294 	    }
295 	}
296     }
297 }
298 
299 /* Replicate a bitmap vertically in place. */
300 void
bits_replicate_vertically(byte * data,uint height,uint raster,uint replicated_height)301 bits_replicate_vertically(byte * data, uint height, uint raster,
302 			  uint replicated_height)
303 {
304     byte *dest = data;
305     uint h = replicated_height;
306     uint size = raster * height;
307 
308     while (h > height) {
309 	memcpy(dest + size, dest, size);
310 	dest += size;
311 	h -= height;
312     }
313 }
314 
315 /* Find the bounding box of a bitmap. */
316 /* Assume bits beyond the width are zero. */
317 void
bits_bounding_box(const byte * data,uint height,uint raster,gs_int_rect * pbox)318 bits_bounding_box(const byte * data, uint height, uint raster,
319 		  gs_int_rect * pbox)
320 {
321     register const ulong *lp;
322     static const byte first_1[16] = {
323 	4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
324     };
325     static const byte last_1[16] = {
326 	0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4
327     };
328 
329     /* Count trailing blank rows. */
330     /* Since the raster is a multiple of sizeof(long), */
331     /* we don't need to scan by bytes, only by longs. */
332 
333     lp = (const ulong *)(data + raster * height);
334     while ((const byte *)lp > data && !lp[-1])
335 	--lp;
336     if ((const byte *)lp == data) {
337 	pbox->p.x = pbox->q.x = pbox->p.y = pbox->q.y = 0;
338 	return;
339     }
340     pbox->q.y = height = ((const byte *)lp - data + raster - 1) / raster;
341 
342     /* Count leading blank rows. */
343 
344     lp = (const ulong *)data;
345     while (!*lp)
346 	++lp;
347     {
348 	uint n = ((const byte *)lp - data) / raster;
349 
350 	pbox->p.y = n;
351 	if (n)
352 	    height -= n, data += n * raster;
353     }
354 
355     /* Find the left and right edges. */
356     /* We know that the first and last rows are non-blank. */
357 
358     {
359 	uint raster_longs = raster >> arch_log2_sizeof_long;
360 	uint left = raster_longs - 1, right = 0;
361 	ulong llong = 0, rlong = 0;
362 	const byte *q;
363 	uint h, n;
364 
365 	for (q = data, h = height; h-- > 0; q += raster) {	/* Work from the left edge by longs. */
366 	    for (lp = (const ulong *)q, n = 0;
367 		 n < left && !*lp; lp++, n++
368 		);
369 	    if (n < left)
370 		left = n, llong = *lp;
371 	    else
372 		llong |= *lp;
373 	    /* Work from the right edge by longs. */
374 	    for (lp = (const ulong *)(q + raster - sizeof(long)),
375 		 n = raster_longs - 1;
376 
377 		 n > right && !*lp; lp--, n--
378 		);
379 	    if (n > right)
380 		right = n, rlong = *lp;
381 	    else
382 		rlong |= *lp;
383 	}
384 
385 	/* Do binary subdivision on edge longs.  We assume that */
386 	/* sizeof(long) = 4 or 8. */
387 #if arch_sizeof_long > 8
388 	Error_longs_are_too_large();
389 #endif
390 
391 #if arch_is_big_endian
392 #  define last_bits(n) ((1L << (n)) - 1)
393 #  define shift_out_last(x,n) ((x) >>= (n))
394 #  define right_justify_last(x,n) DO_NOTHING
395 #else
396 #  define last_bits(n) (-1L << ((arch_sizeof_long * 8) - (n)))
397 #  define shift_out_last(x,n) ((x) <<= (n))
398 #  define right_justify_last(x,n) (x) >>= ((arch_sizeof_long * 8) - (n))
399 #endif
400 
401 	left <<= arch_log2_sizeof_long + 3;
402 #if arch_sizeof_long == 8
403 	if (llong & ~last_bits(32))
404 	    shift_out_last(llong, 32);
405 	else
406 	    left += 32;
407 #endif
408 	if (llong & ~last_bits(16))
409 	    shift_out_last(llong, 16);
410 	else
411 	    left += 16;
412 	if (llong & ~last_bits(8))
413 	    shift_out_last(llong, 8);
414 	else
415 	    left += 8;
416 	right_justify_last(llong, 8);
417 	if (llong & 0xf0)
418 	    left += first_1[(byte) llong >> 4];
419 	else
420 	    left += first_1[(byte) llong] + 4;
421 
422 	right <<= arch_log2_sizeof_long + 3;
423 #if arch_sizeof_long == 8
424 	if (!(rlong & last_bits(32)))
425 	    shift_out_last(rlong, 32);
426 	else
427 	    right += 32;
428 #endif
429 	if (!(rlong & last_bits(16)))
430 	    shift_out_last(rlong, 16);
431 	else
432 	    right += 16;
433 	if (!(rlong & last_bits(8)))
434 	    shift_out_last(rlong, 8);
435 	else
436 	    right += 8;
437 	right_justify_last(rlong, 8);
438 	if (!(rlong & 0xf))
439 	    right += last_1[(byte) rlong >> 4];
440 	else
441 	    right += last_1[(uint) rlong & 0xf] + 4;
442 
443 	pbox->p.x = left;
444 	pbox->q.x = right;
445     }
446 }
447 
448 /* Extract a plane from a pixmap. */
449 int
bits_extract_plane(const bits_plane_t * dest,const bits_plane_t * source,int shift,int width,int height)450 bits_extract_plane(const bits_plane_t *dest /*write*/,
451     const bits_plane_t *source /*read*/, int shift, int width, int height)
452 {
453     int source_depth = source->depth;
454     int source_bit = source->x * source_depth;
455     const byte *source_row = source->data.read + (source_bit >> 3);
456     int dest_depth = dest->depth;
457     uint plane_mask = (1 << dest_depth) - 1;
458     int dest_bit = dest->x * dest_depth;
459     byte *dest_row = dest->data.write + (dest_bit >> 3);
460     enum {
461 	EXTRACT_SLOW = 0,
462 	EXTRACT_4_TO_1,
463 	EXTRACT_32_TO_8
464     } loop_case = EXTRACT_SLOW;
465     int y;
466 
467     source_bit &= 7;
468     dest_bit &= 7;
469     /* Check for the fast CMYK cases. */
470     if (!(source_bit | dest_bit)) {
471 	switch (source_depth) {
472 	case 4:
473 	    loop_case =
474 		(dest_depth == 1 && !(source->raster & 3) &&
475 		 !(source->x & 1) ? EXTRACT_4_TO_1 :
476 		 EXTRACT_SLOW);
477 	    break;
478 	case 32:
479 	    if (dest_depth == 8 && !(shift & 7)) {
480 		loop_case = EXTRACT_32_TO_8;
481 		source_row += 3 - (shift >> 3);
482 	    }
483 	    break;
484 	}
485     }
486     for (y = 0; y < height;
487 	 ++y, source_row += source->raster, dest_row += dest->raster
488 	) {
489 	int x;
490 
491 	switch (loop_case) {
492 	case EXTRACT_4_TO_1: {
493 	    const byte *source = source_row;
494 	    byte *dest = dest_row;
495 
496 	    /* Do groups of 8 pixels. */
497 	    for (x = width; x >= 8; source += 4, x -= 8) {
498 		bits32 sword =
499 		    (*(const bits32 *)source >> shift) & 0x11111111;
500 
501 		*dest++ =
502 		    byte_acegbdfh_to_abcdefgh[(
503 #if arch_is_big_endian
504 		    (sword >> 21) | (sword >> 14) | (sword >> 7) | sword
505 #else
506 		    (sword << 3) | (sword >> 6) | (sword >> 15) | (sword >> 24)
507 #endif
508 					) & 0xff];
509 	    }
510 	    if (x) {
511 		/* Do the final 1-7 pixels. */
512 		uint test = 0x10 << shift, store = 0x80;
513 
514 		do {
515 		    *dest = (*source & test ? *dest | store : *dest & ~store);
516 		    if (test >= 0x10)
517 			test >>= 4;
518 		    else
519 			test <<= 4, ++source;
520 		    store >>= 1;
521 		} while (--x > 0);
522 	    }
523 	    break;
524 	}
525 	case EXTRACT_32_TO_8: {
526 	    const byte *source = source_row;
527 	    byte *dest = dest_row;
528 
529 	    for (x = width; x > 0; source += 4, --x)
530 		*dest++ = *source;
531 	    break;
532 	}
533 	default: {
534 	    sample_load_declare_setup(sptr, sbit, source_row, source_bit,
535 				      source_depth);
536 	    sample_store_declare_setup(dptr, dbit, dbbyte, dest_row, dest_bit,
537 				       dest_depth);
538 
539 	    sample_store_preload(dbbyte, dptr, dbit, dest_depth);
540 	    for (x = width; x > 0; --x) {
541 		gx_color_index color;
542 		uint pixel;
543 
544 		sample_load_next_any(color, sptr, sbit, source_depth);
545 		pixel = (color >> shift) & plane_mask;
546 		sample_store_next8(pixel, dptr, dbit, dest_depth, dbbyte);
547 	    }
548 	    sample_store_flush(dptr, dbit, dest_depth, dbbyte);
549 	}
550 	}
551     }
552     return 0;
553 }
554 
555 /* Expand a plane into a pixmap. */
556 int
bits_expand_plane(const bits_plane_t * dest,const bits_plane_t * source,int shift,int width,int height)557 bits_expand_plane(const bits_plane_t *dest /*write*/,
558     const bits_plane_t *source /*read*/, int shift, int width, int height)
559 {
560     /*
561      * Eventually we will optimize this just like bits_extract_plane.
562      */
563     int source_depth = source->depth;
564     int source_bit = source->x * source_depth;
565     const byte *source_row = source->data.read + (source_bit >> 3);
566     int dest_depth = dest->depth;
567     int dest_bit = dest->x * dest_depth;
568     byte *dest_row = dest->data.write + (dest_bit >> 3);
569     enum {
570 	EXPAND_SLOW = 0,
571 	EXPAND_1_TO_4,
572 	EXPAND_8_TO_32
573     } loop_case = EXPAND_SLOW;
574     int y;
575 
576     source_bit &= 7;
577     /* Check for the fast CMYK cases. */
578     if (!(source_bit || (dest_bit & 31) || (dest->raster & 3))) {
579 	switch (dest_depth) {
580 	case 4:
581 	    if (source_depth == 1)
582 		loop_case = EXPAND_1_TO_4;
583 	    break;
584 	case 32:
585 	    if (source_depth == 8 && !(shift & 7))
586 		loop_case = EXPAND_8_TO_32;
587 	    break;
588 	}
589     }
590     dest_bit &= 7;
591     switch (loop_case) {
592 
593     case EXPAND_8_TO_32: {
594 #if arch_is_big_endian
595 #  define word_shift (shift)
596 #else
597 	int word_shift = 24 - shift;
598 #endif
599 	for (y = 0; y < height;
600 	     ++y, source_row += source->raster, dest_row += dest->raster
601 	     ) {
602 	    int x;
603 	    const byte *source = source_row;
604 	    bits32 *dest = (bits32 *)dest_row;
605 
606 	    for (x = width; x > 0; --x)
607 		*dest++ = (bits32)(*source++) << word_shift;
608 	}
609 #undef word_shift
610     }
611 	break;
612 
613     case EXPAND_1_TO_4:
614     default:
615 	for (y = 0; y < height;
616 	     ++y, source_row += source->raster, dest_row += dest->raster
617 	     ) {
618 	    int x;
619 	    sample_load_declare_setup(sptr, sbit, source_row, source_bit,
620 				      source_depth);
621 	    sample_store_declare_setup(dptr, dbit, dbbyte, dest_row, dest_bit,
622 				       dest_depth);
623 
624 	    sample_store_preload(dbbyte, dptr, dbit, dest_depth);
625 	    for (x = width; x > 0; --x) {
626 		uint color;
627 		gx_color_index pixel;
628 
629 		sample_load_next8(color, sptr, sbit, source_depth);
630 		pixel = color << shift;
631 		sample_store_next_any(pixel, dptr, dbit, dest_depth, dbbyte);
632 	    }
633 	    sample_store_flush(dptr, dbit, dest_depth, dbbyte);
634 	}
635 	break;
636 
637     }
638     return 0;
639 }
640 
641 /* ---------------- Byte-oriented operations ---------------- */
642 
643 /* Fill a rectangle of bytes. */
644 void
bytes_fill_rectangle(byte * dest,uint raster,byte value,int width_bytes,int height)645 bytes_fill_rectangle(byte * dest, uint raster,
646 		     byte value, int width_bytes, int height)
647 {
648     while (height-- > 0) {
649 	memset(dest, value, width_bytes);
650 	dest += raster;
651     }
652 }
653 
654 /* Copy a rectangle of bytes. */
655 void
bytes_copy_rectangle(byte * dest,uint dest_raster,const byte * src,uint src_raster,int width_bytes,int height)656 bytes_copy_rectangle(byte * dest, uint dest_raster,
657 	     const byte * src, uint src_raster, int width_bytes, int height)
658 {
659     while (height-- > 0) {
660 	memcpy(dest, src, width_bytes);
661 	src += src_raster;
662 	dest += dest_raster;
663     }
664 }
665