/src/ghostpdl/base/gsbitops.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Bitmap filling, copying, and transforming operations */ |
18 | | #include "stdio_.h" |
19 | | #include "memory_.h" |
20 | | #include "gdebug.h" |
21 | | #include "gserrors.h" |
22 | | #include "gstypes.h" |
23 | | #include "gsbittab.h" |
24 | | #include "gxbitops.h" |
25 | | #include "gxcindex.h" |
26 | | |
27 | | /* ---------------- Bit-oriented operations ---------------- */ |
28 | | |
29 | | /* Define masks for little-endian operation. */ |
30 | | /* masks[i] has the first i bits off and the rest on. */ |
31 | | #if !ARCH_IS_BIG_ENDIAN |
32 | | const bits16 mono_copy_masks[17] = { |
33 | | 0xffff, 0xff7f, 0xff3f, 0xff1f, |
34 | | 0xff0f, 0xff07, 0xff03, 0xff01, |
35 | | 0xff00, 0x7f00, 0x3f00, 0x1f00, |
36 | | 0x0f00, 0x0700, 0x0300, 0x0100, |
37 | | 0x0000 |
38 | | }; |
39 | | const bits32 mono_fill_masks[33] = { |
40 | | #define mask(n)\ |
41 | | (((bits32)~0xff | (0xff >> (n & 7))) << (n & -8)) |
42 | | mask( 0),mask( 1),mask( 2),mask( 3),mask( 4),mask( 5),mask( 6),mask( 7), |
43 | | mask( 8),mask( 9),mask(10),mask(11),mask(12),mask(13),mask(14),mask(15), |
44 | | mask(16),mask(17),mask(18),mask(19),mask(20),mask(21),mask(22),mask(23), |
45 | | mask(24),mask(25),mask(26),mask(27),mask(28),mask(29),mask(30),mask(31), |
46 | | 0 |
47 | | #undef mask |
48 | | }; |
49 | | #endif |
50 | | |
51 | | /* Fill a rectangle of bits with an 8x1 pattern. */ |
52 | | /* The pattern argument must consist of the pattern in every byte, */ |
53 | | /* e.g., if the desired pattern is 0xaa, the pattern argument must */ |
54 | | /* have the value 0xaaaa (if ints are short) or 0xaaaaaaaa. */ |
55 | | #undef chunk |
56 | 643M | #define chunk mono_fill_chunk |
57 | | #undef mono_masks |
58 | 546M | #define mono_masks mono_fill_masks |
59 | | void |
60 | | bits_fill_rectangle(byte * dest, int dest_bit, uint draster, |
61 | | mono_fill_chunk pattern, int width_bits, int height) |
62 | 272M | { |
63 | 272M | uint bit; |
64 | 272M | chunk right_mask; |
65 | 272M | int line_count = height; |
66 | 272M | chunk *ptr; |
67 | 272M | int last_bit; |
68 | | |
69 | 272M | #define FOR_EACH_LINE(stat)\ |
70 | 531M | do { stat } while ( inc_ptr(ptr, draster), --line_count ) |
71 | | |
72 | 272M | dest += (dest_bit >> 3) & -chunk_align_bytes; |
73 | 272M | ptr = (chunk *) dest; |
74 | 272M | bit = dest_bit & chunk_align_bit_mask; |
75 | 272M | last_bit = width_bits + bit - (chunk_bits + 1); |
76 | | |
77 | 272M | if (last_bit < 0) { /* <=1 chunk */ |
78 | 175M | set_mono_thin_mask(right_mask, width_bits, bit); |
79 | 175M | if (pattern == 0) |
80 | 124M | FOR_EACH_LINE(*ptr &= ~right_mask;); |
81 | 50.3M | else if (pattern == (mono_fill_chunk)(-1)) |
82 | 21.2M | FOR_EACH_LINE(*ptr |= right_mask;); |
83 | 29.1M | else |
84 | 29.1M | FOR_EACH_LINE( |
85 | 175M | *ptr = (*ptr & ~right_mask) | (pattern & right_mask); ); |
86 | 175M | } else { |
87 | 97.4M | chunk mask; |
88 | 97.4M | int last = last_bit >> chunk_log2_bits; |
89 | | |
90 | 97.4M | set_mono_left_mask(mask, bit); |
91 | 97.4M | set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1); |
92 | 97.4M | switch (last) { |
93 | 56.3M | case 0: /* 2 chunks */ |
94 | 56.3M | if (pattern == 0) |
95 | 29.7M | FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;); |
96 | 26.6M | else if (pattern == (mono_fill_chunk)(-1)) |
97 | 3.45M | FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;); |
98 | 23.1M | else |
99 | 23.1M | FOR_EACH_LINE( |
100 | 56.3M | *ptr = (*ptr & ~mask) | (pattern & mask); |
101 | 56.3M | ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); ); |
102 | 56.3M | break; |
103 | 8.37M | case 1: /* 3 chunks */ |
104 | 8.37M | if (pattern == 0) |
105 | 2.99M | FOR_EACH_LINE( *ptr &= ~mask; |
106 | 8.37M | ptr[1] = 0; |
107 | 8.37M | ptr[2] &= ~right_mask; ); |
108 | 5.38M | else if (pattern == (mono_fill_chunk)(-1)) |
109 | 392k | FOR_EACH_LINE( *ptr |= mask; |
110 | 5.38M | ptr[1] = ~(chunk) 0; |
111 | 5.38M | ptr[2] |= right_mask; ); |
112 | 4.98M | else |
113 | 4.98M | FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask); |
114 | 8.37M | ptr[1] = pattern; |
115 | 8.37M | ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); ); |
116 | 8.37M | break; |
117 | 32.7M | default:{ /* >3 chunks */ |
118 | 32.7M | uint byte_count = (last_bit >> 3) & -chunk_bytes; |
119 | | |
120 | 32.7M | if (pattern == 0) |
121 | 10.7M | FOR_EACH_LINE( *ptr &= ~mask; |
122 | 32.7M | memset(ptr + 1, 0, byte_count); |
123 | 32.7M | ptr[last + 1] &= ~right_mask; ); |
124 | 21.9M | else if (pattern == (mono_fill_chunk)(-1)) |
125 | 1.73M | FOR_EACH_LINE( *ptr |= mask; |
126 | 21.9M | memset(ptr + 1, 0xff, byte_count); |
127 | 21.9M | ptr[last + 1] |= right_mask; ); |
128 | 20.2M | else |
129 | 20.2M | FOR_EACH_LINE( |
130 | 32.7M | *ptr = (*ptr & ~mask) | (pattern & mask); |
131 | 32.7M | memset(ptr + 1, (byte) pattern, byte_count); |
132 | 32.7M | ptr[last + 1] = (ptr[last + 1] & ~right_mask) | |
133 | 32.7M | (pattern & right_mask); ); |
134 | 32.7M | } |
135 | 97.4M | } |
136 | 97.4M | } |
137 | 272M | #undef FOR_EACH_LINE |
138 | 272M | } |
139 | | |
140 | | /* |
141 | | * Similar to bits_fill_rectangle, but with an additional source mask. |
142 | | * The src_mask variable is 1 for those bits of the original that are |
143 | | * to be retained. The mask argument must consist of the requisite value |
144 | | * in every byte, in the same manner as the pattern. |
145 | | */ |
146 | | void |
147 | | bits_fill_rectangle_masked(byte * dest, int dest_bit, uint draster, |
148 | | mono_fill_chunk pattern, mono_fill_chunk src_mask, |
149 | | int width_bits, int height) |
150 | 474k | { |
151 | 474k | uint bit; |
152 | 474k | chunk right_mask; |
153 | 474k | int line_count = height; |
154 | 474k | chunk *ptr; |
155 | 474k | int last_bit; |
156 | | |
157 | 474k | #define FOR_EACH_LINE(stat)\ |
158 | 7.58M | do { stat } while ( inc_ptr(ptr, draster), --line_count ) |
159 | | |
160 | 474k | dest += (dest_bit >> 3) & -chunk_align_bytes; |
161 | 474k | ptr = (chunk *) dest; |
162 | 474k | bit = dest_bit & chunk_align_bit_mask; |
163 | 474k | last_bit = width_bits + bit - (chunk_bits + 1); |
164 | | |
165 | 474k | if (last_bit < 0) { /* <=1 chunk */ |
166 | 452k | set_mono_thin_mask(right_mask, width_bits, bit); |
167 | 452k | right_mask &= ~src_mask; |
168 | 452k | if (pattern == 0) |
169 | 61.8k | FOR_EACH_LINE(*ptr &= ~right_mask;); |
170 | 390k | else if (pattern == (mono_fill_chunk)(-1)) |
171 | 48.3k | FOR_EACH_LINE(*ptr |= right_mask;); |
172 | 342k | else |
173 | 342k | FOR_EACH_LINE( |
174 | 452k | *ptr = (*ptr & ~right_mask) | (pattern & right_mask); ); |
175 | 452k | } else { |
176 | 21.9k | chunk mask; |
177 | 21.9k | int last = last_bit >> chunk_log2_bits; |
178 | | |
179 | 21.9k | set_mono_left_mask(mask, bit); |
180 | 21.9k | set_mono_right_mask(right_mask, (last_bit & chunk_bit_mask) + 1); |
181 | 21.9k | mask &= ~src_mask; |
182 | 21.9k | right_mask &= ~src_mask; |
183 | 21.9k | switch (last) { |
184 | 4.28k | case 0: /* 2 chunks */ |
185 | 4.28k | if (pattern == 0) |
186 | 30 | FOR_EACH_LINE(*ptr &= ~mask; ptr[1] &= ~right_mask;); |
187 | 4.25k | else if (pattern == (mono_fill_chunk)(-1)) |
188 | 0 | FOR_EACH_LINE(*ptr |= mask; ptr[1] |= right_mask;); |
189 | 4.25k | else |
190 | 4.25k | FOR_EACH_LINE( |
191 | 4.28k | *ptr = (*ptr & ~mask) | (pattern & mask); |
192 | 4.28k | ptr[1] = (ptr[1] & ~right_mask) | (pattern & right_mask); ); |
193 | 4.28k | break; |
194 | 867 | case 1: /* 3 chunks */ |
195 | 867 | if (pattern == 0) |
196 | 12 | FOR_EACH_LINE( *ptr &= ~mask; |
197 | 867 | ptr[1] &= src_mask; |
198 | 867 | ptr[2] &= ~right_mask; ); |
199 | 855 | else if (pattern == (mono_fill_chunk)(-1)) |
200 | 0 | FOR_EACH_LINE( *ptr |= mask; |
201 | 855 | ptr[1] |= ~src_mask; |
202 | 855 | ptr[2] |= right_mask; ); |
203 | 855 | else |
204 | 855 | FOR_EACH_LINE( *ptr = (*ptr & ~mask) | (pattern & mask); |
205 | 867 | ptr[1] =(ptr[1] & src_mask) | pattern; |
206 | 867 | ptr[2] = (ptr[2] & ~right_mask) | (pattern & right_mask); ); |
207 | 867 | break; |
208 | 16.8k | default:{ /* >3 chunks */ |
209 | 16.8k | int i; |
210 | | |
211 | 16.8k | if (pattern == 0) |
212 | 16.8k | FOR_EACH_LINE( *ptr++ &= ~mask; |
213 | 16.8k | for (i = 0; i < last; i++) |
214 | 16.8k | *ptr++ &= src_mask; |
215 | 16.8k | *ptr &= ~right_mask; ); |
216 | 18 | else if (pattern == (mono_fill_chunk)(-1)) |
217 | 0 | FOR_EACH_LINE( *ptr++ |= mask; |
218 | 18 | for (i = 0; i < last; i++) |
219 | 18 | *ptr++ |= ~src_mask; |
220 | 18 | *ptr |= right_mask; ); |
221 | 18 | else |
222 | 18 | FOR_EACH_LINE( |
223 | | /* note: we know (pattern & ~src_mask) == pattern */ |
224 | 16.8k | *ptr = (*ptr & ~mask) | (pattern & mask); |
225 | 16.8k | ++ptr; |
226 | 16.8k | for (i = 0; i < last; i++, ptr++) |
227 | 16.8k | *ptr = (*ptr & src_mask) | pattern; |
228 | 16.8k | *ptr = (*ptr & ~right_mask) | (pattern & right_mask); ); |
229 | 16.8k | } |
230 | 21.9k | } |
231 | 21.9k | } |
232 | 474k | #undef FOR_EACH_LINE |
233 | 474k | } |
234 | | |
235 | | /* Replicate a bitmap horizontally in place. */ |
236 | | void |
237 | | bits_replicate_horizontally(byte * data, uint width, uint height, |
238 | | uint raster, uint replicated_width, uint replicated_raster) |
239 | 2.40M | { |
240 | | /* The current algorithm is extremely inefficient! */ |
241 | 2.40M | const byte *orig_row = data + (height - 1) * raster; |
242 | 2.40M | byte *tile_row = data + (height - 1) * replicated_raster; |
243 | 2.40M | uint y; |
244 | | |
245 | 2.40M | if (!(width & 7)) { |
246 | 11.5k | uint src_bytes = width >> 3; |
247 | 11.5k | uint dest_bytes = replicated_width >> 3; |
248 | | |
249 | 471k | for (y = height; y-- > 0; |
250 | 460k | orig_row -= raster, tile_row -= replicated_raster |
251 | 460k | ) { |
252 | 460k | uint move = src_bytes; |
253 | 460k | const byte *from = orig_row; |
254 | 460k | byte *to = tile_row + dest_bytes - src_bytes; |
255 | | |
256 | 460k | memmove(to, from, move); |
257 | 920k | while (to - tile_row >= move) { |
258 | 460k | from = to; |
259 | 460k | to -= move; |
260 | 460k | memmove(to, from, move); |
261 | 460k | move <<= 1; |
262 | 460k | } |
263 | 460k | if (to != tile_row) |
264 | 460k | memmove(tile_row, to, to - tile_row); |
265 | 460k | } |
266 | 2.38M | } else { |
267 | | /* |
268 | | * This algorithm is inefficient, but probably not worth improving. |
269 | | */ |
270 | 2.38M | uint bit_count = width & (uint)(-(int)width); /* lowest bit: 1, 2, or 4 */ |
271 | 2.38M | uint left_mask = (0xff00 >> bit_count) & 0xff; |
272 | | |
273 | 32.6M | for (y = height; y-- > 0; |
274 | 30.2M | orig_row -= raster, tile_row -= replicated_raster |
275 | 30.2M | ) { |
276 | 30.2M | uint sx; |
277 | | |
278 | 476M | for (sx = width; sx > 0;) { |
279 | 446M | uint bits, dx; |
280 | | |
281 | 446M | sx -= bit_count; |
282 | 446M | bits = (orig_row[sx >> 3] << (sx & 7)) & left_mask; |
283 | 28.7G | for (dx = sx + replicated_width; dx >= width;) { |
284 | 28.2G | byte *dp; |
285 | 28.2G | int dbit; |
286 | | |
287 | 28.2G | dx -= width; |
288 | 28.2G | dbit = dx & 7; |
289 | 28.2G | dp = tile_row + (dx >> 3); |
290 | 28.2G | *dp = (*dp & ~(left_mask >> dbit)) | (bits >> dbit); |
291 | 28.2G | } |
292 | 446M | } |
293 | 30.2M | } |
294 | 2.38M | } |
295 | 2.40M | } |
296 | | |
297 | | /* Replicate a bitmap vertically in place. */ |
298 | | void |
299 | | bits_replicate_vertically(byte * data, uint height, uint raster, |
300 | | uint replicated_height) |
301 | 2.46k | { |
302 | 2.46k | byte *dest = data; |
303 | 2.46k | uint h = replicated_height; |
304 | 2.46k | uint size = raster * height; |
305 | | |
306 | 4.92k | while (h > height) { |
307 | 2.46k | memcpy(dest + size, dest, size); |
308 | 2.46k | dest += size; |
309 | 2.46k | h -= height; |
310 | 2.46k | } |
311 | 2.46k | } |
312 | | |
313 | | /* Find the bounding box of a bitmap. */ |
314 | | /* Assume bits beyond the width are zero. */ |
315 | | void |
316 | | bits_bounding_box(const byte * data, uint height, uint raster, |
317 | | gs_int_rect * pbox) |
318 | 6.15M | { |
319 | 6.15M | register const ulong *lp; |
320 | 6.15M | static const byte first_1[16] = { |
321 | 6.15M | 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 |
322 | 6.15M | }; |
323 | 6.15M | static const byte last_1[16] = { |
324 | 6.15M | 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4 |
325 | 6.15M | }; |
326 | | |
327 | | /* Count trailing blank rows. */ |
328 | | /* Since the raster is a multiple of sizeof(long), */ |
329 | | /* we don't need to scan by bytes, only by longs. */ |
330 | | |
331 | 6.15M | lp = (const ulong *)(data + raster * height); |
332 | 95.1M | while ((const byte *)lp > data && !lp[-1]) |
333 | 88.9M | --lp; |
334 | 6.15M | if ((const byte *)lp == data) { |
335 | 596k | pbox->p.x = pbox->q.x = pbox->p.y = pbox->q.y = 0; |
336 | 596k | return; |
337 | 596k | } |
338 | 5.55M | pbox->q.y = height = ((const byte *)lp - data + raster - 1) / raster; |
339 | | |
340 | | /* Count leading blank rows. */ |
341 | | |
342 | 5.55M | lp = (const ulong *)data; |
343 | 88.9M | while (!*lp) |
344 | 83.3M | ++lp; |
345 | 5.55M | { |
346 | 5.55M | uint n = ((const byte *)lp - data) / raster; |
347 | | |
348 | 5.55M | pbox->p.y = n; |
349 | 5.55M | if (n) |
350 | 5.55M | height -= n, data += n * raster; |
351 | 5.55M | } |
352 | | |
353 | | /* Find the left and right edges. */ |
354 | | /* We know that the first and last rows are non-blank. */ |
355 | | |
356 | 5.55M | { |
357 | 5.55M | uint raster_longs = raster >> ARCH_LOG2_SIZEOF_LONG; |
358 | 5.55M | uint left = raster_longs - 1, right = 0; |
359 | 5.55M | ulong llong = 0, rlong = 0; |
360 | 5.55M | const byte *q; |
361 | 5.55M | uint h, n; |
362 | | |
363 | 108M | for (q = data, h = height; h-- > 0; q += raster) { /* Work from the left edge by longs. */ |
364 | 102M | for (lp = (const ulong *)q, n = 0; |
365 | 103M | n < left && !*lp; lp++, n++ |
366 | 102M | ); |
367 | 102M | if (n < left) |
368 | 302k | left = n, llong = *lp; |
369 | 102M | else |
370 | 102M | llong |= *lp; |
371 | | /* Work from the right edge by longs. */ |
372 | 102M | for (lp = (const ulong *)(q + raster - sizeof(long)), |
373 | 102M | n = raster_longs - 1; |
374 | | |
375 | 113M | n > right && !*lp; lp--, n-- |
376 | 102M | ); |
377 | 102M | if (n > right) |
378 | 88.4k | right = n, rlong = *lp; |
379 | 102M | else |
380 | 102M | rlong |= *lp; |
381 | 102M | } |
382 | | |
383 | | /* Do binary subdivision on edge longs. We assume that */ |
384 | | /* sizeof(long) = 4 or 8. */ |
385 | | #if ARCH_SIZEOF_LONG > 8 |
386 | | Error_longs_are_too_large(); |
387 | | #endif |
388 | | |
389 | | #if ARCH_IS_BIG_ENDIAN |
390 | | # define last_bits(n) ((1L << (n)) - 1) |
391 | | # define shift_out_last(x,n) ((x) >>= (n)) |
392 | | # define right_justify_last(x,n) DO_NOTHING |
393 | | #else |
394 | 33.3M | # define last_bits(n) (-1L << ((ARCH_SIZEOF_LONG * 8) - (n))) |
395 | 23.5M | # define shift_out_last(x,n) ((x) <<= (n)) |
396 | 11.1M | # define right_justify_last(x,n) (x) >>= ((ARCH_SIZEOF_LONG * 8) - (n)) |
397 | 5.55M | #endif |
398 | | |
399 | 5.55M | left <<= ARCH_LOG2_SIZEOF_LONG + 3; |
400 | 5.55M | #if ARCH_SIZEOF_LONG == 8 |
401 | 5.55M | if (llong & ~last_bits(32)) |
402 | 5.50M | shift_out_last(llong, 32); |
403 | 57.8k | else |
404 | 57.8k | left += 32; |
405 | 5.55M | #endif |
406 | 5.55M | if (llong & ~last_bits(16)) |
407 | 5.32M | shift_out_last(llong, 16); |
408 | 239k | else |
409 | 239k | left += 16; |
410 | 5.55M | if (llong & ~last_bits(8)) |
411 | 2.24M | shift_out_last(llong, 8); |
412 | 3.31M | else |
413 | 3.31M | left += 8; |
414 | 5.55M | right_justify_last(llong, 8); |
415 | 5.55M | if (llong & 0xf0) |
416 | 3.84M | left += first_1[(byte) llong >> 4]; |
417 | 1.71M | else |
418 | 1.71M | left += first_1[(byte) llong] + 4; |
419 | | |
420 | 5.55M | right <<= ARCH_LOG2_SIZEOF_LONG + 3; |
421 | 5.55M | #if ARCH_SIZEOF_LONG == 8 |
422 | 5.55M | if (!(rlong & last_bits(32))) |
423 | 5.05M | shift_out_last(rlong, 32); |
424 | 504k | else |
425 | 504k | right += 32; |
426 | 5.55M | #endif |
427 | 5.55M | if (!(rlong & last_bits(16))) |
428 | 2.48M | shift_out_last(rlong, 16); |
429 | 3.07M | else |
430 | 3.07M | right += 16; |
431 | 5.55M | if (!(rlong & last_bits(8))) |
432 | 2.94M | shift_out_last(rlong, 8); |
433 | 2.61M | else |
434 | 2.61M | right += 8; |
435 | 5.55M | right_justify_last(rlong, 8); |
436 | 5.55M | if (!(rlong & 0xf)) |
437 | 3.08M | right += last_1[(byte) rlong >> 4]; |
438 | 2.47M | else |
439 | 2.47M | right += last_1[(uint) rlong & 0xf] + 4; |
440 | | |
441 | 5.55M | pbox->p.x = left; |
442 | 5.55M | pbox->q.x = right; |
443 | 5.55M | } |
444 | 5.55M | } |
445 | | |
446 | | /* Extract a plane from a pixmap. */ |
447 | | int |
448 | | bits_extract_plane(const bits_plane_t *dest /*write*/, |
449 | | const bits_plane_t *source /*read*/, int shift, int width, int height) |
450 | 0 | { |
451 | 0 | int source_depth = source->depth; |
452 | 0 | int source_bit = source->x * source_depth; |
453 | 0 | const byte *source_row = source->data.read + (source_bit >> 3); |
454 | 0 | int dest_depth = dest->depth; |
455 | 0 | uint plane_mask = (1 << dest_depth) - 1; |
456 | 0 | int dest_bit = dest->x * dest_depth; |
457 | 0 | byte *dest_row = dest->data.write + (dest_bit >> 3); |
458 | 0 | enum { |
459 | 0 | EXTRACT_SLOW = 0, |
460 | 0 | EXTRACT_4_TO_1, |
461 | 0 | EXTRACT_32_TO_8 |
462 | 0 | } loop_case = EXTRACT_SLOW; |
463 | 0 | int y; |
464 | |
|
465 | 0 | source_bit &= 7; |
466 | 0 | dest_bit &= 7; |
467 | | /* Check for the fast CMYK cases. */ |
468 | 0 | if (!(source_bit | dest_bit)) { |
469 | 0 | switch (source_depth) { |
470 | 0 | case 4: |
471 | 0 | loop_case = |
472 | 0 | (dest_depth == 1 && !(source->raster & 3) && |
473 | 0 | !(source->x & 1) ? EXTRACT_4_TO_1 : |
474 | 0 | EXTRACT_SLOW); |
475 | 0 | break; |
476 | 0 | case 32: |
477 | 0 | if (dest_depth == 8 && !(shift & 7)) { |
478 | 0 | loop_case = EXTRACT_32_TO_8; |
479 | 0 | source_row += 3 - (shift >> 3); |
480 | 0 | } |
481 | 0 | break; |
482 | 0 | } |
483 | 0 | } |
484 | 0 | for (y = 0; y < height; |
485 | 0 | ++y, source_row += source->raster, dest_row += dest->raster |
486 | 0 | ) { |
487 | 0 | int x; |
488 | |
|
489 | 0 | switch (loop_case) { |
490 | 0 | case EXTRACT_4_TO_1: { |
491 | 0 | const byte *src = source_row; |
492 | 0 | byte *dst = dest_row; |
493 | | |
494 | | /* Do groups of 8 pixels. */ |
495 | 0 | for (x = width; x >= 8; src += 4, x -= 8) { |
496 | 0 | bits32 sword = |
497 | 0 | (*(const bits32 *)src >> shift) & 0x11111111; |
498 | |
|
499 | 0 | *dst++ = |
500 | 0 | byte_acegbdfh_to_abcdefgh[( |
501 | | #if ARCH_IS_BIG_ENDIAN |
502 | | (sword >> 21) | (sword >> 14) | (sword >> 7) | sword |
503 | | #else |
504 | 0 | (sword << 3) | (sword >> 6) | (sword >> 15) | (sword >> 24) |
505 | 0 | #endif |
506 | 0 | ) & 0xff]; |
507 | 0 | } |
508 | 0 | if (x) { |
509 | | /* Do the final 1-7 pixels. */ |
510 | 0 | uint test = 0x10 << shift, store = 0x80; |
511 | |
|
512 | 0 | do { |
513 | 0 | *dst = (*src & test ? *dst | store : *dst & ~store); |
514 | 0 | if (test >= 0x10) |
515 | 0 | test >>= 4; |
516 | 0 | else |
517 | 0 | test <<= 4, ++src; |
518 | 0 | store >>= 1; |
519 | 0 | } while (--x > 0); |
520 | 0 | } |
521 | 0 | break; |
522 | 0 | } |
523 | 0 | case EXTRACT_32_TO_8: { |
524 | 0 | const byte *src = source_row; |
525 | 0 | byte *dst = dest_row; |
526 | |
|
527 | 0 | for (x = width; x > 0; src += 4, --x) |
528 | 0 | *dst++ = *src; |
529 | 0 | break; |
530 | 0 | } |
531 | 0 | default: { |
532 | 0 | const byte *sptr = source_row; |
533 | 0 | int sbit = source_bit; |
534 | 0 | byte *dptr = dest_row; |
535 | 0 | int dbit = dest_bit; |
536 | 0 | byte dbbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0); |
537 | |
|
538 | 0 | dbbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0); |
539 | 0 | for (x = width; x > 0; --x) { |
540 | 0 | gx_color_index color; |
541 | 0 | uint pixel; |
542 | |
|
543 | 0 | if (sizeof(color) > 4) { |
544 | 0 | if (sample_load_next64((uint64_t *)&color, &sptr, &sbit, source_depth) < 0) |
545 | 0 | return_error(gs_error_rangecheck); |
546 | 0 | } |
547 | 0 | else { |
548 | 0 | if (sample_load_next32((uint32_t *)&color, &sptr, &sbit, source_depth) < 0) |
549 | 0 | return_error(gs_error_rangecheck); |
550 | 0 | } |
551 | 0 | pixel = (color >> shift) & plane_mask; |
552 | 0 | if (sample_store_next8(pixel, &dptr, &dbit, dest_depth, &dbbyte) < 0) |
553 | 0 | return_error(gs_error_rangecheck); |
554 | 0 | } |
555 | 0 | sample_store_flush(dptr, dbit, dbbyte); |
556 | 0 | } |
557 | 0 | } |
558 | 0 | } |
559 | 0 | return 0; |
560 | 0 | } |
561 | | |
562 | | /* Expand a plane into a pixmap. */ |
563 | | int |
564 | | bits_expand_plane(const bits_plane_t *dest /*write*/, |
565 | | const bits_plane_t *source /*read*/, int shift, int width, int height) |
566 | 0 | { |
567 | | /* |
568 | | * Eventually we will optimize this just like bits_extract_plane. |
569 | | */ |
570 | 0 | int source_depth = source->depth; |
571 | 0 | int source_bit = source->x * source_depth; |
572 | 0 | const byte *source_row = source->data.read + (source_bit >> 3); |
573 | 0 | int dest_depth = dest->depth; |
574 | 0 | int dest_bit = dest->x * dest_depth; |
575 | 0 | byte *dest_row = dest->data.write + (dest_bit >> 3); |
576 | 0 | enum { |
577 | 0 | EXPAND_SLOW = 0, |
578 | 0 | EXPAND_1_TO_4, |
579 | 0 | EXPAND_8_TO_32 |
580 | 0 | } loop_case = EXPAND_SLOW; |
581 | 0 | int y; |
582 | |
|
583 | 0 | source_bit &= 7; |
584 | | /* Check for the fast CMYK cases. */ |
585 | 0 | if (!(source_bit || (dest_bit & 31) || (dest->raster & 3))) { |
586 | 0 | switch (dest_depth) { |
587 | 0 | case 4: |
588 | 0 | if (source_depth == 1) |
589 | 0 | loop_case = EXPAND_1_TO_4; |
590 | 0 | break; |
591 | 0 | case 32: |
592 | 0 | if (source_depth == 8 && !(shift & 7)) |
593 | 0 | loop_case = EXPAND_8_TO_32; |
594 | 0 | break; |
595 | 0 | } |
596 | 0 | } |
597 | 0 | dest_bit &= 7; |
598 | 0 | switch (loop_case) { |
599 | | |
600 | 0 | case EXPAND_8_TO_32: { |
601 | | #if ARCH_IS_BIG_ENDIAN |
602 | | # define word_shift (shift) |
603 | | #else |
604 | 0 | int word_shift = 24 - shift; |
605 | 0 | #endif |
606 | 0 | for (y = 0; y < height; |
607 | 0 | ++y, source_row += source->raster, dest_row += dest->raster |
608 | 0 | ) { |
609 | 0 | int x; |
610 | 0 | const byte *src = source_row; |
611 | 0 | bits32 *dst = (bits32 *)dest_row; |
612 | |
|
613 | 0 | for (x = width; x > 0; --x) |
614 | 0 | *dst++ = (bits32)(*src++) << word_shift; |
615 | 0 | } |
616 | 0 | #undef word_shift |
617 | 0 | } |
618 | 0 | break; |
619 | | |
620 | 0 | case EXPAND_1_TO_4: |
621 | 0 | default: |
622 | 0 | for (y = 0; y < height; |
623 | 0 | ++y, source_row += source->raster, dest_row += dest->raster |
624 | 0 | ) { |
625 | 0 | int x; |
626 | 0 | const byte *sptr = source_row; |
627 | 0 | int sbit = source_bit; |
628 | 0 | byte *dptr = dest_row; |
629 | 0 | int dbit = dest_bit; |
630 | 0 | byte dbbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0); |
631 | |
|
632 | 0 | dbbyte = (dbit ? (byte)(*dptr & (0xff00 >> dbit)) : 0); |
633 | 0 | for (x = width; x > 0; --x) { |
634 | 0 | uint color; |
635 | 0 | gx_color_index pixel; |
636 | |
|
637 | 0 | if (sample_load_next8(&color, &sptr, &sbit, source_depth) < 0) |
638 | 0 | return_error(gs_error_rangecheck); |
639 | | |
640 | 0 | pixel = (gx_color_index)color << shift; |
641 | 0 | if (sizeof(pixel) > 4) { |
642 | 0 | if (sample_store_next64(pixel, &dptr, &dbit, dest_depth, &dbbyte) < 0) |
643 | 0 | return_error(gs_error_rangecheck); |
644 | 0 | } |
645 | 0 | else { |
646 | 0 | if (sample_store_next32(pixel, &dptr, &dbit, dest_depth, &dbbyte) < 0) |
647 | 0 | return_error(gs_error_rangecheck); |
648 | 0 | } |
649 | 0 | } |
650 | 0 | sample_store_flush(dptr, dbit, dbbyte); |
651 | 0 | } |
652 | 0 | break; |
653 | |
|
654 | 0 | } |
655 | 0 | return 0; |
656 | 0 | } |
657 | | |
658 | | /* ---------------- Byte-oriented operations ---------------- */ |
659 | | |
660 | | /* Fill a rectangle of bytes. */ |
661 | | void |
662 | | bytes_fill_rectangle(byte * dest, uint raster, |
663 | | byte value, int width_bytes, int height) |
664 | 123M | { |
665 | 310M | while (height-- > 0) { |
666 | 186M | memset(dest, value, width_bytes); |
667 | 186M | dest += raster; |
668 | 186M | } |
669 | 123M | } |
670 | | |
671 | | /* Copy a rectangle of bytes. */ |
672 | | void |
673 | | bytes_copy_rectangle(byte * dest, uint dest_raster, |
674 | | const byte * src, uint src_raster, int width_bytes, int height) |
675 | 41.7M | { |
676 | 83.5M | while (height-- > 0) { |
677 | 41.7M | memcpy(dest, src, width_bytes); |
678 | 41.7M | src += src_raster; |
679 | 41.7M | dest += dest_raster; |
680 | 41.7M | } |
681 | 41.7M | } |
682 | | |
683 | | int |
684 | | bytes_rectangle_is_const(const byte * src, uint src_raster, |
685 | | int width_bytes, int height) |
686 | 17 | { |
687 | 17 | int i; |
688 | 17 | char c; |
689 | | |
690 | 17 | if (width_bytes == 0 || height == 0) |
691 | 0 | return -1; |
692 | 17 | c = *src; |
693 | 17 | while (height-- > 0) { |
694 | 17 | const byte *s = src; |
695 | 17 | src += src_raster; |
696 | 482 | for (i = width_bytes; i > 0; i--) |
697 | 482 | if (*s++ != c) |
698 | 17 | return -1; |
699 | 17 | } |
700 | 0 | return c; |
701 | 17 | } |
702 | | |
703 | | /* Copy a rectangle of bytes zeroing any padding bytes. */ |
704 | | void |
705 | | bytes_copy_rectangle_zero_padding(byte * dest, uint dest_raster, |
706 | | const byte * src, uint src_raster, int width_bytes, int height) |
707 | 5.50M | { |
708 | 5.50M | int padlen = dest_raster; |
709 | 5.50M | if (padlen < 0) |
710 | 0 | padlen = -padlen; |
711 | 5.50M | padlen -= width_bytes; |
712 | 5.50M | if (padlen == 0) |
713 | 9.35k | { |
714 | 593k | while (height-- > 0) { |
715 | 583k | memcpy(dest, src, width_bytes); |
716 | 583k | src += src_raster; |
717 | 583k | dest += dest_raster; |
718 | 583k | } |
719 | 5.49M | } else { |
720 | 102M | while (height-- > 0) { |
721 | 97.1M | memcpy(dest, src, width_bytes); |
722 | 97.1M | memset(dest+width_bytes, 0, padlen); |
723 | 97.1M | src += src_raster; |
724 | 97.1M | dest += dest_raster; |
725 | 97.1M | } |
726 | 5.49M | } |
727 | 5.50M | } |
728 | | |
729 | | /* Copy a rectangle of bytes zeroing any padding bytes, copying |
730 | | * the last row with no padding. */ |
731 | | void |
732 | | bytes_copy_rectangle_zero_padding_last_short(byte * dest, uint dest_raster, |
733 | | const byte * src, uint src_raster, int width_bytes, int height) |
734 | 21.0M | { |
735 | 21.0M | int padlen = dest_raster; |
736 | 21.0M | if (padlen < 0) |
737 | 0 | padlen = -padlen; |
738 | 21.0M | padlen -= width_bytes; |
739 | 21.0M | if (padlen == 0) |
740 | 20.8M | { |
741 | 267M | while (height-- > 0) { |
742 | 246M | memcpy(dest, src, width_bytes); |
743 | 246M | src += src_raster; |
744 | 246M | dest += dest_raster; |
745 | 246M | } |
746 | 20.8M | } else { |
747 | 4.73M | while (--height > 0) { |
748 | 4.54M | memcpy(dest, src, width_bytes); |
749 | 4.54M | memset(dest+width_bytes, 0, padlen); |
750 | 4.54M | src += src_raster; |
751 | 4.54M | dest += dest_raster; |
752 | 4.54M | } |
753 | 189k | if (height >= 0) |
754 | 189k | memcpy(dest, src, width_bytes); |
755 | 189k | } |
756 | 21.0M | } |