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