xref: /plan9/sys/src/cmd/gs/src/gsbitops.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gsbitops.c,v 1.8 2002/10/07 08:28:56 ghostgum Exp $ */
187dd7cddfSDavid du Colombier /* Bitmap filling, copying, and transforming operations */
197dd7cddfSDavid du Colombier #include "stdio_.h"
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "gdebug.h"
227dd7cddfSDavid du Colombier #include "gserror.h"
237dd7cddfSDavid du Colombier #include "gserrors.h"
247dd7cddfSDavid du Colombier #include "gstypes.h"
257dd7cddfSDavid du Colombier #include "gsbittab.h"
267dd7cddfSDavid du Colombier #include "gxbitops.h"
27*593dc095SDavid du Colombier #include "gxcindex.h"
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /* ---------------- Bit-oriented operations ---------------- */
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /* Define masks for little-endian operation. */
327dd7cddfSDavid du Colombier /* masks[i] has the first i bits off and the rest on. */
337dd7cddfSDavid du Colombier #if !arch_is_big_endian
347dd7cddfSDavid du Colombier const bits16 mono_copy_masks[17] = {
357dd7cddfSDavid du Colombier     0xffff, 0xff7f, 0xff3f, 0xff1f,
367dd7cddfSDavid du Colombier     0xff0f, 0xff07, 0xff03, 0xff01,
377dd7cddfSDavid du Colombier     0xff00, 0x7f00, 0x3f00, 0x1f00,
387dd7cddfSDavid du Colombier     0x0f00, 0x0700, 0x0300, 0x0100,
397dd7cddfSDavid du Colombier     0x0000
407dd7cddfSDavid du Colombier };
417dd7cddfSDavid du Colombier const bits32 mono_fill_masks[33] = {
427dd7cddfSDavid du Colombier #define mask(n)\
437dd7cddfSDavid du Colombier   ((~0xff | (0xff >> (n & 7))) << (n & -8))
447dd7cddfSDavid du Colombier     mask( 0),mask( 1),mask( 2),mask( 3),mask( 4),mask( 5),mask( 6),mask( 7),
457dd7cddfSDavid du Colombier     mask( 8),mask( 9),mask(10),mask(11),mask(12),mask(13),mask(14),mask(15),
467dd7cddfSDavid du Colombier     mask(16),mask(17),mask(18),mask(19),mask(20),mask(21),mask(22),mask(23),
477dd7cddfSDavid du Colombier     mask(24),mask(25),mask(26),mask(27),mask(28),mask(29),mask(30),mask(31),
487dd7cddfSDavid du Colombier     0
497dd7cddfSDavid du Colombier #undef mask
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier #endif
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier /* Fill a rectangle of bits with an 8x1 pattern. */
547dd7cddfSDavid du Colombier /* The pattern argument must consist of the pattern in every byte, */
557dd7cddfSDavid du Colombier /* e.g., if the desired pattern is 0xaa, the pattern argument must */
567dd7cddfSDavid du Colombier /* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */
577dd7cddfSDavid du Colombier #undef chunk
587dd7cddfSDavid du Colombier #define chunk mono_fill_chunk
597dd7cddfSDavid du Colombier #undef mono_masks
607dd7cddfSDavid du Colombier #define mono_masks mono_fill_masks
617dd7cddfSDavid du Colombier void
bits_fill_rectangle(byte * dest,int dest_bit,uint draster,mono_fill_chunk pattern,int width_bits,int height)627dd7cddfSDavid du Colombier bits_fill_rectangle(byte * dest, int dest_bit, uint draster,
637dd7cddfSDavid du Colombier 		    mono_fill_chunk pattern, int width_bits, int height)
647dd7cddfSDavid du Colombier {
657dd7cddfSDavid du Colombier     uint bit;
667dd7cddfSDavid du Colombier     chunk right_mask;
677dd7cddfSDavid du Colombier     int line_count = height;
687dd7cddfSDavid du Colombier     chunk *ptr;
697dd7cddfSDavid du Colombier     int last_bit;
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier #define FOR_EACH_LINE(stat)\
727dd7cddfSDavid du Colombier 	do { stat } while ( inc_ptr(ptr, draster), --line_count )
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier     dest += (dest_bit >> 3) & -chunk_align_bytes;
757dd7cddfSDavid du Colombier     ptr = (chunk *) dest;
767dd7cddfSDavid du Colombier     bit = dest_bit & chunk_align_bit_mask;
777dd7cddfSDavid du Colombier     last_bit = width_bits + bit - (chunk_bits + 1);
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier     if (last_bit < 0) {		/* <=1 chunk */
807dd7cddfSDavid du Colombier 	set_mono_thin_mask(right_mask, width_bits, bit);
81*593dc095SDavid du Colombier 	if (pattern == 0)
82*593dc095SDavid du Colombier 	    FOR_EACH_LINE(*ptr &= ~right_mask;);
83*593dc095SDavid du Colombier 	else if (pattern == (mono_fill_chunk)(-1))
84*593dc095SDavid du Colombier 	    FOR_EACH_LINE(*ptr |= right_mask;);
85*593dc095SDavid du Colombier 	else
867dd7cddfSDavid du Colombier 	    FOR_EACH_LINE(
87*593dc095SDavid du Colombier 		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
887dd7cddfSDavid du Colombier     } else {
897dd7cddfSDavid du Colombier 	chunk mask;
907dd7cddfSDavid du Colombier 	int last = last_bit >> chunk_log2_bits;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	set_mono_left_mask(mask, bit);
937dd7cddfSDavid du Colombier 	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
947dd7cddfSDavid du Colombier 	switch (last) {
957dd7cddfSDavid du Colombier 	    case 0:		/* 2 chunks */
96*593dc095SDavid du Colombier 		if (pattern == 0)
97*593dc095SDavid du Colombier 		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
98*593dc095SDavid du Colombier 		else if (pattern == (mono_fill_chunk)(-1))
99*593dc095SDavid du Colombier 		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
100*593dc095SDavid du Colombier 		else
1017dd7cddfSDavid du Colombier 		    FOR_EACH_LINE(
1027dd7cddfSDavid du Colombier 		        *ptr = (*ptr & ~mask) | (pattern & mask);
103*593dc095SDavid du Colombier 			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
1047dd7cddfSDavid du Colombier 		break;
1057dd7cddfSDavid du Colombier 	    case 1:		/* 3 chunks */
106*593dc095SDavid du Colombier 		if (pattern == 0)
107*593dc095SDavid du Colombier 		    FOR_EACH_LINE( *ptr &= ~mask;
1087dd7cddfSDavid du Colombier 				   ptr[1] = 0;
109*593dc095SDavid du Colombier 				   ptr[2] &= ~right_mask; );
110*593dc095SDavid du Colombier 		else if (pattern == (mono_fill_chunk)(-1))
111*593dc095SDavid du Colombier 		    FOR_EACH_LINE( *ptr |= mask;
1127dd7cddfSDavid du Colombier 				   ptr[1] = ~(chunk) 0;
113*593dc095SDavid du Colombier 				   ptr[2] |= right_mask; );
114*593dc095SDavid du Colombier 		else
115*593dc095SDavid du Colombier 		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
1167dd7cddfSDavid du Colombier 				    ptr[1] = pattern;
117*593dc095SDavid du Colombier 				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
1187dd7cddfSDavid du Colombier 		break;
1197dd7cddfSDavid du Colombier 	    default:{		/* >3 chunks */
1207dd7cddfSDavid du Colombier 		    uint byte_count = (last_bit >> 3) & -chunk_bytes;
1217dd7cddfSDavid du Colombier 
122*593dc095SDavid du Colombier 		    if (pattern == 0)
123*593dc095SDavid du Colombier 			FOR_EACH_LINE( *ptr &= ~mask;
1247dd7cddfSDavid du Colombier 				       memset(ptr + 1, 0, byte_count);
125*593dc095SDavid du Colombier 				       ptr[last + 1] &= ~right_mask; );
126*593dc095SDavid du Colombier 		    else if (pattern == (mono_fill_chunk)(-1))
127*593dc095SDavid du Colombier 			FOR_EACH_LINE( *ptr |= mask;
1287dd7cddfSDavid du Colombier 				       memset(ptr + 1, 0xff, byte_count);
129*593dc095SDavid du Colombier 				       ptr[last + 1] |= right_mask; );
130*593dc095SDavid du Colombier 		    else
1317dd7cddfSDavid du Colombier 			FOR_EACH_LINE(
1327dd7cddfSDavid du Colombier 				*ptr = (*ptr & ~mask) | (pattern & mask);
1337dd7cddfSDavid du Colombier 				memset(ptr + 1, (byte) pattern, byte_count);
134*593dc095SDavid du Colombier 				ptr[last + 1] = (ptr[last + 1] & ~right_mask) |
135*593dc095SDavid du Colombier 					        (pattern & right_mask); 	);
1367dd7cddfSDavid du Colombier 		}
1377dd7cddfSDavid du Colombier 	}
1387dd7cddfSDavid du Colombier     }
139*593dc095SDavid du Colombier #undef FOR_EACH_LINE
140*593dc095SDavid du Colombier }
141*593dc095SDavid du Colombier 
142*593dc095SDavid du Colombier /*
143*593dc095SDavid du Colombier  * Similar to bits_fill_rectangle, but with an additional source mask.
144*593dc095SDavid du Colombier  * The src_mask variable is 1 for those bits of the original that are
145*593dc095SDavid du Colombier  * to be retained. The mask argument must consist of the requisite value
146*593dc095SDavid du Colombier  * in every byte, in the same manner as the pattern.
147*593dc095SDavid du Colombier  */
148*593dc095SDavid du Colombier 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*593dc095SDavid du Colombier bits_fill_rectangle_masked(byte * dest, int dest_bit, uint draster,
150*593dc095SDavid du Colombier 		    mono_fill_chunk pattern, mono_fill_chunk src_mask,
151*593dc095SDavid du Colombier 		    int width_bits, int height)
152*593dc095SDavid du Colombier {
153*593dc095SDavid du Colombier     uint bit;
154*593dc095SDavid du Colombier     chunk right_mask;
155*593dc095SDavid du Colombier     int line_count = height;
156*593dc095SDavid du Colombier     chunk *ptr;
157*593dc095SDavid du Colombier     int last_bit;
158*593dc095SDavid du Colombier 
159*593dc095SDavid du Colombier #define FOR_EACH_LINE(stat)\
160*593dc095SDavid du Colombier 	do { stat } while ( inc_ptr(ptr, draster), --line_count )
161*593dc095SDavid du Colombier 
162*593dc095SDavid du Colombier     dest += (dest_bit >> 3) & -chunk_align_bytes;
163*593dc095SDavid du Colombier     ptr = (chunk *) dest;
164*593dc095SDavid du Colombier     bit = dest_bit & chunk_align_bit_mask;
165*593dc095SDavid du Colombier     last_bit = width_bits + bit - (chunk_bits + 1);
166*593dc095SDavid du Colombier 
167*593dc095SDavid du Colombier     if (last_bit < 0) {		/* <=1 chunk */
168*593dc095SDavid du Colombier 	set_mono_thin_mask(right_mask, width_bits, bit);
169*593dc095SDavid du Colombier 	right_mask &= ~src_mask;
170*593dc095SDavid du Colombier 	if (pattern == 0)
171*593dc095SDavid du Colombier 	    FOR_EACH_LINE(*ptr &= ~right_mask;);
172*593dc095SDavid du Colombier 	else if (pattern == (mono_fill_chunk)(-1))
173*593dc095SDavid du Colombier 	    FOR_EACH_LINE(*ptr |= right_mask;);
174*593dc095SDavid du Colombier 	else
175*593dc095SDavid du Colombier 	    FOR_EACH_LINE(
176*593dc095SDavid du Colombier 		*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
177*593dc095SDavid du Colombier     } else {
178*593dc095SDavid du Colombier 	chunk mask;
179*593dc095SDavid du Colombier 	int last = last_bit >> chunk_log2_bits;
180*593dc095SDavid du Colombier 
181*593dc095SDavid du Colombier 	set_mono_left_mask(mask, bit);
182*593dc095SDavid du Colombier 	set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1);
183*593dc095SDavid du Colombier 	mask &= ~src_mask;
184*593dc095SDavid du Colombier 	right_mask &= ~src_mask;
185*593dc095SDavid du Colombier 	switch (last) {
186*593dc095SDavid du Colombier 	    case 0:		/* 2 chunks */
187*593dc095SDavid du Colombier 		if (pattern == 0)
188*593dc095SDavid du Colombier 		    FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;);
189*593dc095SDavid du Colombier 		else if (pattern == (mono_fill_chunk)(-1))
190*593dc095SDavid du Colombier 		    FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;);
191*593dc095SDavid du Colombier 		else
192*593dc095SDavid du Colombier 		    FOR_EACH_LINE(
193*593dc095SDavid du Colombier 		        *ptr = (*ptr & ~mask) | (pattern & mask);
194*593dc095SDavid du Colombier 			ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); );
195*593dc095SDavid du Colombier 		break;
196*593dc095SDavid du Colombier 	    case 1:		/* 3 chunks */
197*593dc095SDavid du Colombier 		if (pattern == 0)
198*593dc095SDavid du Colombier 		    FOR_EACH_LINE( *ptr &= ~mask;
199*593dc095SDavid du Colombier 				   ptr[1] &= src_mask;
200*593dc095SDavid du Colombier 				   ptr[2] &= ~right_mask; );
201*593dc095SDavid du Colombier 		else if (pattern == (mono_fill_chunk)(-1))
202*593dc095SDavid du Colombier 		    FOR_EACH_LINE( *ptr |= mask;
203*593dc095SDavid du Colombier 				   ptr[1] |= ~src_mask;
204*593dc095SDavid du Colombier 				   ptr[2] |= right_mask; );
205*593dc095SDavid du Colombier 		else
206*593dc095SDavid du Colombier 		    FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask);
207*593dc095SDavid du Colombier 				    ptr[1] =(ptr[1] & src_mask) | pattern;
208*593dc095SDavid du Colombier 				    ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); );
209*593dc095SDavid du Colombier 		break;
210*593dc095SDavid du Colombier 	    default:{		/* >3 chunks */
211*593dc095SDavid du Colombier                     int     i;
212*593dc095SDavid du Colombier 
213*593dc095SDavid du Colombier 		    if (pattern == 0)
214*593dc095SDavid du Colombier 			FOR_EACH_LINE( *ptr++ &= ~mask;
215*593dc095SDavid du Colombier 				       for (i = 0; i < last; i++)
216*593dc095SDavid du Colombier 					   *ptr++ &= src_mask;
217*593dc095SDavid du Colombier 				       *ptr &= ~right_mask; );
218*593dc095SDavid du Colombier 		    else if (pattern == (mono_fill_chunk)(-1))
219*593dc095SDavid du Colombier 			FOR_EACH_LINE( *ptr++ |= mask;
220*593dc095SDavid du Colombier 				       for (i = 0; i < last; i++)
221*593dc095SDavid du Colombier 					   *ptr++ |= ~src_mask;
222*593dc095SDavid du Colombier 					*ptr |= right_mask; );
223*593dc095SDavid du Colombier 		    else
224*593dc095SDavid du Colombier 			FOR_EACH_LINE(
225*593dc095SDavid du Colombier 			    /* note: we know (pattern & ~src_mask) == pattern */
226*593dc095SDavid du Colombier 			    *ptr = (*ptr & ~mask) | (pattern & mask);
227*593dc095SDavid du Colombier 			    ++ptr;
228*593dc095SDavid du Colombier 			    for (i = 0; i < last; i++, ptr++)
229*593dc095SDavid du Colombier                                 *ptr = (*ptr & src_mask) | pattern;
230*593dc095SDavid du Colombier 				*ptr = (*ptr & ~right_mask) | (pattern & right_mask); );
231*593dc095SDavid du Colombier 		}
232*593dc095SDavid du Colombier 	}
2337dd7cddfSDavid du Colombier     }
2347dd7cddfSDavid du Colombier #undef FOR_EACH_LINE
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier /* Replicate a bitmap horizontally in place. */
2387dd7cddfSDavid du Colombier void
bits_replicate_horizontally(byte * data,uint width,uint height,uint raster,uint replicated_width,uint replicated_raster)2397dd7cddfSDavid du Colombier bits_replicate_horizontally(byte * data, uint width, uint height,
2407dd7cddfSDavid du Colombier 		 uint raster, uint replicated_width, uint replicated_raster)
2417dd7cddfSDavid du Colombier {
2427dd7cddfSDavid du Colombier     /* The current algorithm is extremely inefficient! */
2437dd7cddfSDavid du Colombier     const byte *orig_row = data + (height - 1) * raster;
2447dd7cddfSDavid du Colombier     byte *tile_row = data + (height - 1) * replicated_raster;
2457dd7cddfSDavid du Colombier     uint y;
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier     if (!(width & 7)) {
2487dd7cddfSDavid du Colombier 	uint src_bytes = width >> 3;
2497dd7cddfSDavid du Colombier 	uint dest_bytes = replicated_width >> 3;
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	for (y = height; y-- > 0;
2527dd7cddfSDavid du Colombier 	     orig_row -= raster, tile_row -= replicated_raster
2537dd7cddfSDavid du Colombier 	     ) {
2547dd7cddfSDavid du Colombier 	    uint move = src_bytes;
2557dd7cddfSDavid du Colombier 	    const byte *from = orig_row;
2567dd7cddfSDavid du Colombier 	    byte *to = tile_row + dest_bytes - src_bytes;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	    memmove(to, from, move);
2597dd7cddfSDavid du Colombier 	    while (to - tile_row >= move) {
2607dd7cddfSDavid du Colombier 		from = to;
2617dd7cddfSDavid du Colombier 		to -= move;
2627dd7cddfSDavid du Colombier 		memmove(to, from, move);
2637dd7cddfSDavid du Colombier 		move <<= 1;
2647dd7cddfSDavid du Colombier 	    }
2657dd7cddfSDavid du Colombier 	    if (to != tile_row)
2667dd7cddfSDavid du Colombier 		memmove(tile_row, to, to - tile_row);
2677dd7cddfSDavid du Colombier 	}
2687dd7cddfSDavid du Colombier     } else {
2697dd7cddfSDavid du Colombier 	/*
2707dd7cddfSDavid du Colombier 	 * This algorithm is inefficient, but probably not worth improving.
2717dd7cddfSDavid du Colombier 	 */
272*593dc095SDavid du Colombier 	uint bit_count = width & (uint)(-(int)width);  /* lowest bit: 1, 2, or 4 */
2737dd7cddfSDavid du Colombier 	uint left_mask = (0xff00 >> bit_count) & 0xff;
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier 	for (y = height; y-- > 0;
2767dd7cddfSDavid du Colombier 	     orig_row -= raster, tile_row -= replicated_raster
2777dd7cddfSDavid du Colombier 	     ) {
2787dd7cddfSDavid du Colombier 	    uint sx;
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 	    for (sx = width; sx > 0;) {
2817dd7cddfSDavid du Colombier 		uint bits, dx;
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier 		sx -= bit_count;
2847dd7cddfSDavid du Colombier 		bits = (orig_row[sx >> 3] << (sx & 7)) & left_mask;
2857dd7cddfSDavid du Colombier 		for (dx = sx + replicated_width; dx >= width;) {
2867dd7cddfSDavid du Colombier 		    byte *dp;
2877dd7cddfSDavid du Colombier 		    int dbit;
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier 		    dx -= width;
2907dd7cddfSDavid du Colombier 		    dbit = dx & 7;
2917dd7cddfSDavid du Colombier 		    dp = tile_row + (dx >> 3);
2927dd7cddfSDavid du Colombier 		    *dp = (*dp & ~(left_mask >> dbit)) | (bits >> dbit);
2937dd7cddfSDavid du Colombier 		}
2947dd7cddfSDavid du Colombier 	    }
2957dd7cddfSDavid du Colombier 	}
2967dd7cddfSDavid du Colombier     }
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier /* Replicate a bitmap vertically in place. */
3007dd7cddfSDavid du Colombier void
bits_replicate_vertically(byte * data,uint height,uint raster,uint replicated_height)3017dd7cddfSDavid du Colombier bits_replicate_vertically(byte * data, uint height, uint raster,
3027dd7cddfSDavid du Colombier 			  uint replicated_height)
3037dd7cddfSDavid du Colombier {
3047dd7cddfSDavid du Colombier     byte *dest = data;
3057dd7cddfSDavid du Colombier     uint h = replicated_height;
3067dd7cddfSDavid du Colombier     uint size = raster * height;
3077dd7cddfSDavid du Colombier 
3087dd7cddfSDavid du Colombier     while (h > height) {
3097dd7cddfSDavid du Colombier 	memcpy(dest + size, dest, size);
3107dd7cddfSDavid du Colombier 	dest += size;
3117dd7cddfSDavid du Colombier 	h -= height;
3127dd7cddfSDavid du Colombier     }
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier 
3157dd7cddfSDavid du Colombier /* Find the bounding box of a bitmap. */
3167dd7cddfSDavid du Colombier /* Assume bits beyond the width are zero. */
3177dd7cddfSDavid du Colombier void
bits_bounding_box(const byte * data,uint height,uint raster,gs_int_rect * pbox)3187dd7cddfSDavid du Colombier bits_bounding_box(const byte * data, uint height, uint raster,
3197dd7cddfSDavid du Colombier 		  gs_int_rect * pbox)
3207dd7cddfSDavid du Colombier {
3217dd7cddfSDavid du Colombier     register const ulong *lp;
3227dd7cddfSDavid du Colombier     static const byte first_1[16] = {
3237dd7cddfSDavid du Colombier 	4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
3247dd7cddfSDavid du Colombier     };
3257dd7cddfSDavid du Colombier     static const byte last_1[16] = {
3267dd7cddfSDavid du Colombier 	0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4
3277dd7cddfSDavid du Colombier     };
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier     /* Count trailing blank rows. */
3307dd7cddfSDavid du Colombier     /* Since the raster is a multiple of sizeof(long), */
3317dd7cddfSDavid du Colombier     /* we don't need to scan by bytes, only by longs. */
3327dd7cddfSDavid du Colombier 
3337dd7cddfSDavid du Colombier     lp = (const ulong *)(data + raster * height);
3347dd7cddfSDavid du Colombier     while ((const byte *)lp > data && !lp[-1])
3357dd7cddfSDavid du Colombier 	--lp;
3367dd7cddfSDavid du Colombier     if ((const byte *)lp == data) {
3377dd7cddfSDavid du Colombier 	pbox->p.x = pbox->q.x = pbox->p.y = pbox->q.y = 0;
3387dd7cddfSDavid du Colombier 	return;
3397dd7cddfSDavid du Colombier     }
3407dd7cddfSDavid du Colombier     pbox->q.y = height = ((const byte *)lp - data + raster - 1) / raster;
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier     /* Count leading blank rows. */
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier     lp = (const ulong *)data;
3457dd7cddfSDavid du Colombier     while (!*lp)
3467dd7cddfSDavid du Colombier 	++lp;
3477dd7cddfSDavid du Colombier     {
3487dd7cddfSDavid du Colombier 	uint n = ((const byte *)lp - data) / raster;
3497dd7cddfSDavid du Colombier 
3507dd7cddfSDavid du Colombier 	pbox->p.y = n;
3517dd7cddfSDavid du Colombier 	if (n)
3527dd7cddfSDavid du Colombier 	    height -= n, data += n * raster;
3537dd7cddfSDavid du Colombier     }
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier     /* Find the left and right edges. */
3567dd7cddfSDavid du Colombier     /* We know that the first and last rows are non-blank. */
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier     {
3597dd7cddfSDavid du Colombier 	uint raster_longs = raster >> arch_log2_sizeof_long;
3607dd7cddfSDavid du Colombier 	uint left = raster_longs - 1, right = 0;
3617dd7cddfSDavid du Colombier 	ulong llong = 0, rlong = 0;
3627dd7cddfSDavid du Colombier 	const byte *q;
3637dd7cddfSDavid du Colombier 	uint h, n;
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 	for (q = data, h = height; h-- > 0; q += raster) {	/* Work from the left edge by longs. */
3667dd7cddfSDavid du Colombier 	    for (lp = (const ulong *)q, n = 0;
3677dd7cddfSDavid du Colombier 		 n < left && !*lp; lp++, n++
3687dd7cddfSDavid du Colombier 		);
3697dd7cddfSDavid du Colombier 	    if (n < left)
3707dd7cddfSDavid du Colombier 		left = n, llong = *lp;
3717dd7cddfSDavid du Colombier 	    else
3727dd7cddfSDavid du Colombier 		llong |= *lp;
3737dd7cddfSDavid du Colombier 	    /* Work from the right edge by longs. */
3747dd7cddfSDavid du Colombier 	    for (lp = (const ulong *)(q + raster - sizeof(long)),
3757dd7cddfSDavid du Colombier 		 n = raster_longs - 1;
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 		 n > right && !*lp; lp--, n--
3787dd7cddfSDavid du Colombier 		);
3797dd7cddfSDavid du Colombier 	    if (n > right)
3807dd7cddfSDavid du Colombier 		right = n, rlong = *lp;
3817dd7cddfSDavid du Colombier 	    else
3827dd7cddfSDavid du Colombier 		rlong |= *lp;
3837dd7cddfSDavid du Colombier 	}
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier 	/* Do binary subdivision on edge longs.  We assume that */
3867dd7cddfSDavid du Colombier 	/* sizeof(long) = 4 or 8. */
3877dd7cddfSDavid du Colombier #if arch_sizeof_long > 8
3887dd7cddfSDavid du Colombier 	Error_longs_are_too_large();
3897dd7cddfSDavid du Colombier #endif
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier #if arch_is_big_endian
3927dd7cddfSDavid du Colombier #  define last_bits(n) ((1L << (n)) - 1)
3937dd7cddfSDavid du Colombier #  define shift_out_last(x,n) ((x) >>= (n))
3947dd7cddfSDavid du Colombier #  define right_justify_last(x,n) DO_NOTHING
3957dd7cddfSDavid du Colombier #else
3967dd7cddfSDavid du Colombier #  define last_bits(n) (-1L << ((arch_sizeof_long * 8) - (n)))
3977dd7cddfSDavid du Colombier #  define shift_out_last(x,n) ((x) <<= (n))
3987dd7cddfSDavid du Colombier #  define right_justify_last(x,n) (x) >>= ((arch_sizeof_long * 8) - (n))
3997dd7cddfSDavid du Colombier #endif
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	left <<= arch_log2_sizeof_long + 3;
4027dd7cddfSDavid du Colombier #if arch_sizeof_long == 8
4037dd7cddfSDavid du Colombier 	if (llong & ~last_bits(32))
4047dd7cddfSDavid du Colombier 	    shift_out_last(llong, 32);
4057dd7cddfSDavid du Colombier 	else
4067dd7cddfSDavid du Colombier 	    left += 32;
4077dd7cddfSDavid du Colombier #endif
4087dd7cddfSDavid du Colombier 	if (llong & ~last_bits(16))
4097dd7cddfSDavid du Colombier 	    shift_out_last(llong, 16);
4107dd7cddfSDavid du Colombier 	else
4117dd7cddfSDavid du Colombier 	    left += 16;
4127dd7cddfSDavid du Colombier 	if (llong & ~last_bits(8))
4137dd7cddfSDavid du Colombier 	    shift_out_last(llong, 8);
4147dd7cddfSDavid du Colombier 	else
4157dd7cddfSDavid du Colombier 	    left += 8;
4167dd7cddfSDavid du Colombier 	right_justify_last(llong, 8);
4177dd7cddfSDavid du Colombier 	if (llong & 0xf0)
4187dd7cddfSDavid du Colombier 	    left += first_1[(byte) llong >> 4];
4197dd7cddfSDavid du Colombier 	else
4207dd7cddfSDavid du Colombier 	    left += first_1[(byte) llong] + 4;
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	right <<= arch_log2_sizeof_long + 3;
4237dd7cddfSDavid du Colombier #if arch_sizeof_long == 8
4247dd7cddfSDavid du Colombier 	if (!(rlong & last_bits(32)))
4257dd7cddfSDavid du Colombier 	    shift_out_last(rlong, 32);
4267dd7cddfSDavid du Colombier 	else
4277dd7cddfSDavid du Colombier 	    right += 32;
4287dd7cddfSDavid du Colombier #endif
4297dd7cddfSDavid du Colombier 	if (!(rlong & last_bits(16)))
4307dd7cddfSDavid du Colombier 	    shift_out_last(rlong, 16);
4317dd7cddfSDavid du Colombier 	else
4327dd7cddfSDavid du Colombier 	    right += 16;
4337dd7cddfSDavid du Colombier 	if (!(rlong & last_bits(8)))
4347dd7cddfSDavid du Colombier 	    shift_out_last(rlong, 8);
4357dd7cddfSDavid du Colombier 	else
4367dd7cddfSDavid du Colombier 	    right += 8;
4377dd7cddfSDavid du Colombier 	right_justify_last(rlong, 8);
4387dd7cddfSDavid du Colombier 	if (!(rlong & 0xf))
4397dd7cddfSDavid du Colombier 	    right += last_1[(byte) rlong >> 4];
4407dd7cddfSDavid du Colombier 	else
4417dd7cddfSDavid du Colombier 	    right += last_1[(uint) rlong & 0xf] + 4;
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	pbox->p.x = left;
4447dd7cddfSDavid du Colombier 	pbox->q.x = right;
4457dd7cddfSDavid du Colombier     }
4467dd7cddfSDavid du Colombier }
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier /* Extract a plane from a pixmap. */
4497dd7cddfSDavid du Colombier int
bits_extract_plane(const bits_plane_t * dest,const bits_plane_t * source,int shift,int width,int height)4507dd7cddfSDavid du Colombier bits_extract_plane(const bits_plane_t *dest /*write*/,
4517dd7cddfSDavid du Colombier     const bits_plane_t *source /*read*/, int shift, int width, int height)
4527dd7cddfSDavid du Colombier {
4537dd7cddfSDavid du Colombier     int source_depth = source->depth;
4547dd7cddfSDavid du Colombier     int source_bit = source->x * source_depth;
4557dd7cddfSDavid du Colombier     const byte *source_row = source->data.read + (source_bit >> 3);
4567dd7cddfSDavid du Colombier     int dest_depth = dest->depth;
4577dd7cddfSDavid du Colombier     uint plane_mask = (1 << dest_depth) - 1;
4587dd7cddfSDavid du Colombier     int dest_bit = dest->x * dest_depth;
4597dd7cddfSDavid du Colombier     byte *dest_row = dest->data.write + (dest_bit >> 3);
4607dd7cddfSDavid du Colombier     enum {
4617dd7cddfSDavid du Colombier 	EXTRACT_SLOW = 0,
4627dd7cddfSDavid du Colombier 	EXTRACT_4_TO_1,
4637dd7cddfSDavid du Colombier 	EXTRACT_32_TO_8
4647dd7cddfSDavid du Colombier     } loop_case = EXTRACT_SLOW;
4657dd7cddfSDavid du Colombier     int y;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier     source_bit &= 7;
4687dd7cddfSDavid du Colombier     dest_bit &= 7;
4697dd7cddfSDavid du Colombier     /* Check for the fast CMYK cases. */
4707dd7cddfSDavid du Colombier     if (!(source_bit | dest_bit)) {
4717dd7cddfSDavid du Colombier 	switch (source_depth) {
4727dd7cddfSDavid du Colombier 	case 4:
4737dd7cddfSDavid du Colombier 	    loop_case =
4747dd7cddfSDavid du Colombier 		(dest_depth == 1 && !(source->raster & 3) &&
4757dd7cddfSDavid du Colombier 		 !(source->x & 1) ? EXTRACT_4_TO_1 :
4767dd7cddfSDavid du Colombier 		 EXTRACT_SLOW);
4777dd7cddfSDavid du Colombier 	    break;
4787dd7cddfSDavid du Colombier 	case 32:
4797dd7cddfSDavid du Colombier 	    if (dest_depth == 8 && !(shift & 7)) {
4807dd7cddfSDavid du Colombier 		loop_case = EXTRACT_32_TO_8;
4817dd7cddfSDavid du Colombier 		source_row += 3 - (shift >> 3);
4827dd7cddfSDavid du Colombier 	    }
4837dd7cddfSDavid du Colombier 	    break;
4847dd7cddfSDavid du Colombier 	}
4857dd7cddfSDavid du Colombier     }
4867dd7cddfSDavid du Colombier     for (y = 0; y < height;
4877dd7cddfSDavid du Colombier 	 ++y, source_row += source->raster, dest_row += dest->raster
4887dd7cddfSDavid du Colombier 	) {
4897dd7cddfSDavid du Colombier 	int x;
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier 	switch (loop_case) {
4927dd7cddfSDavid du Colombier 	case EXTRACT_4_TO_1: {
4937dd7cddfSDavid du Colombier 	    const byte *source = source_row;
4947dd7cddfSDavid du Colombier 	    byte *dest = dest_row;
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	    /* Do groups of 8 pixels. */
4977dd7cddfSDavid du Colombier 	    for (x = width; x >= 8; source += 4, x -= 8) {
4987dd7cddfSDavid du Colombier 		bits32 sword =
4997dd7cddfSDavid du Colombier 		    (*(const bits32 *)source >> shift) & 0x11111111;
5007dd7cddfSDavid du Colombier 
5017dd7cddfSDavid du Colombier 		*dest++ =
5027dd7cddfSDavid du Colombier 		    byte_acegbdfh_to_abcdefgh[(
5037dd7cddfSDavid du Colombier #if arch_is_big_endian
5047dd7cddfSDavid du Colombier 		    (sword >> 21) | (sword >> 14) | (sword >> 7) | sword
5057dd7cddfSDavid du Colombier #else
5067dd7cddfSDavid du Colombier 		    (sword << 3) | (sword >> 6) | (sword >> 15) | (sword >> 24)
5077dd7cddfSDavid du Colombier #endif
5087dd7cddfSDavid du Colombier 					) & 0xff];
5097dd7cddfSDavid du Colombier 	    }
5107dd7cddfSDavid du Colombier 	    if (x) {
5117dd7cddfSDavid du Colombier 		/* Do the final 1-7 pixels. */
5127dd7cddfSDavid du Colombier 		uint test = 0x10 << shift, store = 0x80;
5137dd7cddfSDavid du Colombier 
5147dd7cddfSDavid du Colombier 		do {
5157dd7cddfSDavid du Colombier 		    *dest = (*source & test ? *dest | store : *dest & ~store);
5167dd7cddfSDavid du Colombier 		    if (test >= 0x10)
5177dd7cddfSDavid du Colombier 			test >>= 4;
5187dd7cddfSDavid du Colombier 		    else
5197dd7cddfSDavid du Colombier 			test <<= 4, ++source;
5207dd7cddfSDavid du Colombier 		    store >>= 1;
5217dd7cddfSDavid du Colombier 		} while (--x > 0);
5227dd7cddfSDavid du Colombier 	    }
5237dd7cddfSDavid du Colombier 	    break;
5247dd7cddfSDavid du Colombier 	}
5257dd7cddfSDavid du Colombier 	case EXTRACT_32_TO_8: {
5267dd7cddfSDavid du Colombier 	    const byte *source = source_row;
5277dd7cddfSDavid du Colombier 	    byte *dest = dest_row;
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier 	    for (x = width; x > 0; source += 4, --x)
5307dd7cddfSDavid du Colombier 		*dest++ = *source;
5317dd7cddfSDavid du Colombier 	    break;
5327dd7cddfSDavid du Colombier 	}
5337dd7cddfSDavid du Colombier 	default: {
5347dd7cddfSDavid du Colombier 	    sample_load_declare_setup(sptr, sbit, source_row, source_bit,
5357dd7cddfSDavid du Colombier 				      source_depth);
5367dd7cddfSDavid du Colombier 	    sample_store_declare_setup(dptr, dbit, dbbyte, dest_row, dest_bit,
5377dd7cddfSDavid du Colombier 				       dest_depth);
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier 	    sample_store_preload(dbbyte, dptr, dbit, dest_depth);
5407dd7cddfSDavid du Colombier 	    for (x = width; x > 0; --x) {
541*593dc095SDavid du Colombier 		gx_color_index color;
5427dd7cddfSDavid du Colombier 		uint pixel;
5437dd7cddfSDavid du Colombier 
544*593dc095SDavid du Colombier 		sample_load_next_any(color, sptr, sbit, source_depth);
5457dd7cddfSDavid du Colombier 		pixel = (color >> shift) & plane_mask;
5467dd7cddfSDavid du Colombier 		sample_store_next8(pixel, dptr, dbit, dest_depth, dbbyte);
5477dd7cddfSDavid du Colombier 	    }
5487dd7cddfSDavid du Colombier 	    sample_store_flush(dptr, dbit, dest_depth, dbbyte);
5497dd7cddfSDavid du Colombier 	}
5507dd7cddfSDavid du Colombier 	}
5517dd7cddfSDavid du Colombier     }
5527dd7cddfSDavid du Colombier     return 0;
5537dd7cddfSDavid du Colombier }
5547dd7cddfSDavid du Colombier 
5557dd7cddfSDavid du Colombier /* Expand a plane into a pixmap. */
5567dd7cddfSDavid du Colombier int
bits_expand_plane(const bits_plane_t * dest,const bits_plane_t * source,int shift,int width,int height)5577dd7cddfSDavid du Colombier bits_expand_plane(const bits_plane_t *dest /*write*/,
5587dd7cddfSDavid du Colombier     const bits_plane_t *source /*read*/, int shift, int width, int height)
5597dd7cddfSDavid du Colombier {
5607dd7cddfSDavid du Colombier     /*
5617dd7cddfSDavid du Colombier      * Eventually we will optimize this just like bits_extract_plane.
5627dd7cddfSDavid du Colombier      */
5637dd7cddfSDavid du Colombier     int source_depth = source->depth;
5647dd7cddfSDavid du Colombier     int source_bit = source->x * source_depth;
5657dd7cddfSDavid du Colombier     const byte *source_row = source->data.read + (source_bit >> 3);
5667dd7cddfSDavid du Colombier     int dest_depth = dest->depth;
5677dd7cddfSDavid du Colombier     int dest_bit = dest->x * dest_depth;
5687dd7cddfSDavid du Colombier     byte *dest_row = dest->data.write + (dest_bit >> 3);
5697dd7cddfSDavid du Colombier     enum {
5707dd7cddfSDavid du Colombier 	EXPAND_SLOW = 0,
5717dd7cddfSDavid du Colombier 	EXPAND_1_TO_4,
5727dd7cddfSDavid du Colombier 	EXPAND_8_TO_32
5737dd7cddfSDavid du Colombier     } loop_case = EXPAND_SLOW;
5747dd7cddfSDavid du Colombier     int y;
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier     source_bit &= 7;
5777dd7cddfSDavid du Colombier     /* Check for the fast CMYK cases. */
5787dd7cddfSDavid du Colombier     if (!(source_bit || (dest_bit & 31) || (dest->raster & 3))) {
5797dd7cddfSDavid du Colombier 	switch (dest_depth) {
5807dd7cddfSDavid du Colombier 	case 4:
5817dd7cddfSDavid du Colombier 	    if (source_depth == 1)
5827dd7cddfSDavid du Colombier 		loop_case = EXPAND_1_TO_4;
5837dd7cddfSDavid du Colombier 	    break;
5847dd7cddfSDavid du Colombier 	case 32:
5857dd7cddfSDavid du Colombier 	    if (source_depth == 8 && !(shift & 7))
5867dd7cddfSDavid du Colombier 		loop_case = EXPAND_8_TO_32;
5877dd7cddfSDavid du Colombier 	    break;
5887dd7cddfSDavid du Colombier 	}
5897dd7cddfSDavid du Colombier     }
5907dd7cddfSDavid du Colombier     dest_bit &= 7;
5917dd7cddfSDavid du Colombier     switch (loop_case) {
5927dd7cddfSDavid du Colombier 
5937dd7cddfSDavid du Colombier     case EXPAND_8_TO_32: {
5947dd7cddfSDavid du Colombier #if arch_is_big_endian
5957dd7cddfSDavid du Colombier #  define word_shift (shift)
5967dd7cddfSDavid du Colombier #else
5977dd7cddfSDavid du Colombier 	int word_shift = 24 - shift;
5987dd7cddfSDavid du Colombier #endif
5997dd7cddfSDavid du Colombier 	for (y = 0; y < height;
6007dd7cddfSDavid du Colombier 	     ++y, source_row += source->raster, dest_row += dest->raster
6017dd7cddfSDavid du Colombier 	     ) {
6027dd7cddfSDavid du Colombier 	    int x;
6037dd7cddfSDavid du Colombier 	    const byte *source = source_row;
6047dd7cddfSDavid du Colombier 	    bits32 *dest = (bits32 *)dest_row;
6057dd7cddfSDavid du Colombier 
6067dd7cddfSDavid du Colombier 	    for (x = width; x > 0; --x)
6077dd7cddfSDavid du Colombier 		*dest++ = (bits32)(*source++) << word_shift;
6087dd7cddfSDavid du Colombier 	}
6097dd7cddfSDavid du Colombier #undef word_shift
6107dd7cddfSDavid du Colombier     }
6117dd7cddfSDavid du Colombier 	break;
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier     case EXPAND_1_TO_4:
6147dd7cddfSDavid du Colombier     default:
6157dd7cddfSDavid du Colombier 	for (y = 0; y < height;
6167dd7cddfSDavid du Colombier 	     ++y, source_row += source->raster, dest_row += dest->raster
6177dd7cddfSDavid du Colombier 	     ) {
6187dd7cddfSDavid du Colombier 	    int x;
6197dd7cddfSDavid du Colombier 	    sample_load_declare_setup(sptr, sbit, source_row, source_bit,
6207dd7cddfSDavid du Colombier 				      source_depth);
6217dd7cddfSDavid du Colombier 	    sample_store_declare_setup(dptr, dbit, dbbyte, dest_row, dest_bit,
6227dd7cddfSDavid du Colombier 				       dest_depth);
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier 	    sample_store_preload(dbbyte, dptr, dbit, dest_depth);
6257dd7cddfSDavid du Colombier 	    for (x = width; x > 0; --x) {
6267dd7cddfSDavid du Colombier 		uint color;
627*593dc095SDavid du Colombier 		gx_color_index pixel;
6287dd7cddfSDavid du Colombier 
6297dd7cddfSDavid du Colombier 		sample_load_next8(color, sptr, sbit, source_depth);
6307dd7cddfSDavid du Colombier 		pixel = color << shift;
631*593dc095SDavid du Colombier 		sample_store_next_any(pixel, dptr, dbit, dest_depth, dbbyte);
6327dd7cddfSDavid du Colombier 	    }
6337dd7cddfSDavid du Colombier 	    sample_store_flush(dptr, dbit, dest_depth, dbbyte);
6347dd7cddfSDavid du Colombier 	}
6357dd7cddfSDavid du Colombier 	break;
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier     }
6387dd7cddfSDavid du Colombier     return 0;
6397dd7cddfSDavid du Colombier }
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier /* ---------------- Byte-oriented operations ---------------- */
6427dd7cddfSDavid du Colombier 
6437dd7cddfSDavid du Colombier /* Fill a rectangle of bytes. */
6447dd7cddfSDavid du Colombier void
bytes_fill_rectangle(byte * dest,uint raster,byte value,int width_bytes,int height)6457dd7cddfSDavid du Colombier bytes_fill_rectangle(byte * dest, uint raster,
6467dd7cddfSDavid du Colombier 		     byte value, int width_bytes, int height)
6477dd7cddfSDavid du Colombier {
6487dd7cddfSDavid du Colombier     while (height-- > 0) {
6497dd7cddfSDavid du Colombier 	memset(dest, value, width_bytes);
6507dd7cddfSDavid du Colombier 	dest += raster;
6517dd7cddfSDavid du Colombier     }
6527dd7cddfSDavid du Colombier }
6537dd7cddfSDavid du Colombier 
6547dd7cddfSDavid du Colombier /* Copy a rectangle of bytes. */
6557dd7cddfSDavid du Colombier void
bytes_copy_rectangle(byte * dest,uint dest_raster,const byte * src,uint src_raster,int width_bytes,int height)6567dd7cddfSDavid du Colombier bytes_copy_rectangle(byte * dest, uint dest_raster,
6577dd7cddfSDavid du Colombier 	     const byte * src, uint src_raster, int width_bytes, int height)
6587dd7cddfSDavid du Colombier {
6597dd7cddfSDavid du Colombier     while (height-- > 0) {
6607dd7cddfSDavid du Colombier 	memcpy(dest, src, width_bytes);
6617dd7cddfSDavid du Colombier 	src += src_raster;
6627dd7cddfSDavid du Colombier 	dest += dest_raster;
6637dd7cddfSDavid du Colombier     }
6647dd7cddfSDavid du Colombier }
665