comparison mupdf-source/thirdparty/leptonica/src/roplow.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*!
28 * \file roplow.c
29 * <pre>
30 * Low level dest-only
31 * void rasteropUniLow()
32 * static void rasteropUniWordAlignedlLow()
33 * static void rasteropUniGeneralLow()
34 *
35 * Low level src and dest
36 * void rasteropLow()
37 * static void rasteropWordAlignedLow()
38 * static void rasteropVAlignedLow()
39 * static void rasteropGeneralLow()
40 *
41 * Low level in-place full height vertical block transfer
42 * void rasteropVipLow()
43 *
44 * Low level in-place full width horizontal block transfer
45 * void rasteropHipLow()
46 * static void shiftDataHorizontalLow()
47 * </pre>
48 */
49
50 #ifdef HAVE_CONFIG_H
51 #include <config_auto.h>
52 #endif /* HAVE_CONFIG_H */
53
54 #include <string.h>
55 #include "allheaders.h"
56
57 /* Static helpers */
58 static void rasteropUniWordAlignedLow(l_uint32 *datad, l_int32 dwpl, l_int32 dx,
59 l_int32 dy, l_int32 dw, l_int32 dh,
60 l_int32 op);
61 static void rasteropUniGeneralLow(l_uint32 *datad, l_int32 dwpl, l_int32 dx,
62 l_int32 dy, l_int32 dw, l_int32 dh,
63 l_int32 op);
64 static void rasteropWordAlignedLow(l_uint32 *datad, l_int32 dwpl, l_int32 dx,
65 l_int32 dy, l_int32 dw, l_int32 dh,
66 l_int32 op, l_uint32 *datas, l_int32 swpl,
67 l_int32 sx, l_int32 sy);
68 static void rasteropVAlignedLow(l_uint32 *datad, l_int32 dwpl, l_int32 dx,
69 l_int32 dy, l_int32 dw, l_int32 dh,
70 l_int32 op, l_uint32 *datas, l_int32 swpl,
71 l_int32 sx, l_int32 sy);
72 static void rasteropGeneralLow(l_uint32 *datad, l_int32 dwpl, l_int32 dx,
73 l_int32 dy, l_int32 dw, l_int32 dh,
74 l_int32 op, l_uint32 *datas, l_int32 swpl,
75 l_int32 sx, l_int32 sy);
76 static void shiftDataHorizontalLow(l_uint32 *datad, l_int32 wpld,
77 l_uint32 *datas, l_int32 wpls,
78 l_int32 shift);
79
80 #define COMBINE_PARTIAL(d, s, m) ( ((d) & ~(m)) | ((s) & (m)) )
81
82 static const l_int32 SHIFT_LEFT = 0;
83 static const l_int32 SHIFT_RIGHT = 1;
84
85 static const l_uint32 lmask32[] = {0x0,
86 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
87 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
88 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
89 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
90 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
91 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
92 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
93 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff};
94
95 static const l_uint32 rmask32[] = {0x0,
96 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
97 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
98 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
99 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
100 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
101 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
102 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
103 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
104
105
106 /*--------------------------------------------------------------------*
107 * Low-level dest-only rasterops *
108 *--------------------------------------------------------------------*/
109 /*!
110 * \brief rasteropUniLow()
111 *
112 * \param[in] datad ptr to dest image data
113 * \param[in] dpixw width of dest
114 * \param[in] dpixh height of dest
115 * \param[in] depth depth of src and dest
116 * \param[in] dwpl wpl of dest
117 * \param[in] dx x val of UL corner of dest rectangle
118 * \param[in] dy y val of UL corner of dest rectangle
119 * \param[in] dw width of dest rectangle
120 * \param[in] dh height of dest rectangle
121 * \param[in] op op code
122 * \return void
123 *
124 * Action: scales width, performs clipping, checks alignment, and
125 * dispatches for the rasterop.
126 */
127 void
128 rasteropUniLow(l_uint32 *datad,
129 l_int32 dpixw,
130 l_int32 dpixh,
131 l_int32 depth,
132 l_int32 dwpl,
133 l_int32 dx,
134 l_int32 dy,
135 l_int32 dw,
136 l_int32 dh,
137 l_int32 op)
138 {
139 l_int32 dhangw, dhangh;
140
141 /* -------------------------------------------------------*
142 * scale horizontal dimensions by depth
143 * -------------------------------------------------------*/
144 if (depth != 1) {
145 dpixw *= depth;
146 dx *= depth;
147 dw *= depth;
148 }
149
150 /* -------------------------------------------------------*
151 * clip rectangle to dest image
152 * -------------------------------------------------------*/
153 /* first, clip horizontally (dx, dw) */
154 if (dx < 0) {
155 dw += dx; /* reduce dw */
156 dx = 0;
157 }
158 dhangw = dx + dw - dpixw; /* rect ovhang dest to right */
159 if (dhangw > 0)
160 dw -= dhangw; /* reduce dw */
161
162 /* then, clip vertically (dy, dh) */
163 if (dy < 0) {
164 dh += dy; /* reduce dh */
165 dy = 0;
166 }
167 dhangh = dy + dh - dpixh; /* rect ovhang dest below */
168 if (dhangh > 0)
169 dh -= dhangh; /* reduce dh */
170
171 /* if clipped entirely, quit */
172 if ((dw <= 0) || (dh <= 0))
173 return;
174
175 /* -------------------------------------------------------*
176 * dispatch to aligned or non-aligned blitters
177 * -------------------------------------------------------*/
178 if ((dx & 31) == 0)
179 rasteropUniWordAlignedLow(datad, dwpl, dx, dy, dw, dh, op);
180 else
181 rasteropUniGeneralLow(datad, dwpl, dx, dy, dw, dh, op);
182 }
183
184
185
186 /*--------------------------------------------------------------------*
187 * Static low-level uni rasterop with word alignment *
188 *--------------------------------------------------------------------*/
189 /*!
190 * \brief rasteropUniWordAlignedLow()
191 *
192 * \param[in] datad ptr to dest image data
193 * \param[in] dwpl wpl of dest
194 * \param[in] dx x val of UL corner of dest rectangle
195 * \param[in] dy y val of UL corner of dest rectangle
196 * \param[in] dw width of dest rectangle
197 * \param[in] dh height of dest rectangle
198 * \param[in] op op code
199 * \return void
200 *
201 * This is called when the dest rect is left aligned
202 * on 32-bit word boundaries. That is: dx & 31 == 0.
203 *
204 * We make an optimized implementation of this because
205 * it is a common case: e.g., operating on a full dest image.
206 */
207 static void
208 rasteropUniWordAlignedLow(l_uint32 *datad,
209 l_int32 dwpl,
210 l_int32 dx,
211 l_int32 dy,
212 l_int32 dw,
213 l_int32 dh,
214 l_int32 op)
215 {
216 l_int32 nfullw; /* number of full words */
217 l_uint32 *pfword; /* ptr to first word */
218 l_int32 lwbits; /* number of ovrhang bits in last partial word */
219 l_uint32 lwmask; /* mask for last partial word */
220 l_uint32 *lined;
221 l_int32 i, j;
222
223 /*--------------------------------------------------------*
224 * Preliminary calculations *
225 *--------------------------------------------------------*/
226 nfullw = dw >> 5;
227 lwbits = dw & 31;
228 if (lwbits)
229 lwmask = lmask32[lwbits];
230 pfword = datad + dwpl * dy + (dx >> 5);
231
232
233 /*--------------------------------------------------------*
234 * Now we're ready to do the ops *
235 *--------------------------------------------------------*/
236 switch (op)
237 {
238 case PIX_CLR:
239 for (i = 0; i < dh; i++) {
240 lined = pfword + i * dwpl;
241 for (j = 0; j < nfullw; j++)
242 *lined++ = 0x0;
243 if (lwbits)
244 *lined = COMBINE_PARTIAL(*lined, 0x0, lwmask);
245 }
246 break;
247 case PIX_SET:
248 for (i = 0; i < dh; i++) {
249 lined = pfword + i * dwpl;
250 for (j = 0; j < nfullw; j++)
251 *lined++ = 0xffffffff;
252 if (lwbits)
253 *lined = COMBINE_PARTIAL(*lined, 0xffffffff, lwmask);
254 }
255 break;
256 case PIX_NOT(PIX_DST):
257 for (i = 0; i < dh; i++) {
258 lined = pfword + i * dwpl;
259 for (j = 0; j < nfullw; j++) {
260 *lined = ~(*lined);
261 lined++;
262 }
263 if (lwbits)
264 *lined = COMBINE_PARTIAL(*lined, ~(*lined), lwmask);
265 }
266 break;
267 default:
268 lept_stderr("Operation %d not permitted here!\n", op);
269 }
270 }
271
272
273 /*--------------------------------------------------------------------*
274 * Static low-level uni rasterop without word alignment *
275 *--------------------------------------------------------------------*/
276 /*!
277 * \brief rasteropUniGeneralLow()
278 *
279 * \param[in] datad ptr to dest image data
280 * \param[in] dwpl wpl of dest
281 * \param[in] dx x val of UL corner of dest rectangle
282 * \param[in] dy y val of UL corner of dest rectangle
283 * \param[in] dw width of dest rectangle
284 * \param[in] dh height of dest rectangle
285 * \param[in] op op code
286 * \return void
287 */
288 static void
289 rasteropUniGeneralLow(l_uint32 *datad,
290 l_int32 dwpl,
291 l_int32 dx,
292 l_int32 dy,
293 l_int32 dw,
294 l_int32 dh,
295 l_int32 op)
296 {
297 l_int32 dfwpartb; /* boolean (1, 0) if first dest word is partial */
298 l_int32 dfwpart2b; /* boolean (1, 0) if first dest word is doubly partial */
299 l_uint32 dfwmask; /* mask for first partial dest word */
300 l_int32 dfwbits; /* first word dest bits in ovrhang */
301 l_uint32 *pdfwpart = NULL; /* ptr to first partial dest word */
302 l_int32 dfwfullb; /* boolean (1, 0) if there exists a full dest word */
303 l_int32 dnfullw; /* number of full words in dest */
304 l_uint32 *pdfwfull = NULL; /* ptr to first full dest word */
305 l_int32 dlwpartb; /* boolean (1, 0) if last dest word is partial */
306 l_uint32 dlwmask; /* mask for last partial dest word */
307 l_int32 dlwbits; /* last word dest bits in ovrhang */
308 l_uint32 *pdlwpart = NULL; /* ptr to last partial dest word */
309 l_int32 i, j;
310
311
312 /*--------------------------------------------------------*
313 * Preliminary calculations *
314 *--------------------------------------------------------*/
315 /* is the first word partial? */
316 dfwmask = 0;
317 if ((dx & 31) == 0) { /* if not */
318 dfwpartb = 0;
319 dfwbits = 0;
320 } else { /* if so */
321 dfwpartb = 1;
322 dfwbits = 32 - (dx & 31);
323 dfwmask = rmask32[dfwbits];
324 pdfwpart = datad + dwpl * dy + (dx >> 5);
325 }
326
327 /* is the first word doubly partial? */
328 if (dw >= dfwbits) { /* if not */
329 dfwpart2b = 0;
330 } else { /* if so */
331 dfwpart2b = 1;
332 dfwmask &= lmask32[32 - dfwbits + dw];
333 }
334
335 /* is there a full dest word? */
336 if (dfwpart2b == 1) { /* not */
337 dfwfullb = 0;
338 dnfullw = 0;
339 } else {
340 dnfullw = (dw - dfwbits) >> 5;
341 if (dnfullw == 0) { /* if not */
342 dfwfullb = 0;
343 } else { /* if so */
344 dfwfullb = 1;
345 if (dfwpartb)
346 pdfwfull = pdfwpart + 1;
347 else
348 pdfwfull = datad + dwpl * dy + (dx >> 5);
349 }
350 }
351
352 /* is the last word partial? */
353 dlwbits = (dx + dw) & 31;
354 if (dfwpart2b == 1 || dlwbits == 0) { /* if not */
355 dlwpartb = 0;
356 } else {
357 dlwpartb = 1;
358 dlwmask = lmask32[dlwbits];
359 if (dfwpartb)
360 pdlwpart = pdfwpart + 1 + dnfullw;
361 else
362 pdlwpart = datad + dwpl * dy + (dx >> 5) + dnfullw;
363 }
364
365
366 /*--------------------------------------------------------*
367 * Now we're ready to do the ops *
368 *--------------------------------------------------------*/
369 switch (op)
370 {
371 case PIX_CLR:
372 /* do the first partial word */
373 if (dfwpartb) {
374 for (i = 0; i < dh; i++) {
375 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, 0x0, dfwmask);
376 pdfwpart += dwpl;
377 }
378 }
379
380 /* do the full words */
381 if (dfwfullb) {
382 for (i = 0; i < dh; i++) {
383 for (j = 0; j < dnfullw; j++)
384 *(pdfwfull + j) = 0x0;
385 pdfwfull += dwpl;
386 }
387 }
388
389 /* do the last partial word */
390 if (dlwpartb) {
391 for (i = 0; i < dh; i++) {
392 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, 0x0, dlwmask);
393 pdlwpart += dwpl;
394 }
395 }
396 break;
397 case PIX_SET:
398 /* do the first partial word */
399 if (dfwpartb) {
400 for (i = 0; i < dh; i++) {
401 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, 0xffffffff, dfwmask);
402 pdfwpart += dwpl;
403 }
404 }
405
406 /* do the full words */
407 if (dfwfullb) {
408 for (i = 0; i < dh; i++) {
409 for (j = 0; j < dnfullw; j++)
410 *(pdfwfull + j) = 0xffffffff;
411 pdfwfull += dwpl;
412 }
413 }
414
415 /* do the last partial word */
416 if (dlwpartb) {
417 for (i = 0; i < dh; i++) {
418 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, 0xffffffff, dlwmask);
419 pdlwpart += dwpl;
420 }
421 }
422 break;
423 case PIX_NOT(PIX_DST):
424 /* do the first partial word */
425 if (dfwpartb) {
426 for (i = 0; i < dh; i++) {
427 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, ~(*pdfwpart), dfwmask);
428 pdfwpart += dwpl;
429 }
430 }
431
432 /* do the full words */
433 if (dfwfullb) {
434 for (i = 0; i < dh; i++) {
435 for (j = 0; j < dnfullw; j++)
436 *(pdfwfull + j) = ~(*(pdfwfull + j));
437 pdfwfull += dwpl;
438 }
439 }
440
441 /* do the last partial word */
442 if (dlwpartb) {
443 for (i = 0; i < dh; i++) {
444 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, ~(*pdlwpart), dlwmask);
445 pdlwpart += dwpl;
446 }
447 }
448 break;
449 default:
450 lept_stderr("Operation %d not permitted here!\n", op);
451 }
452 }
453
454
455 /*--------------------------------------------------------------------*
456 * Low-level src and dest rasterops *
457 *--------------------------------------------------------------------*/
458 /*!
459 * \brief rasteropLow()
460 *
461 * \param[in] datad ptr to dest image data
462 * \param[in] dpixw width of dest
463 * \param[in] dpixh height of dest
464 * \param[in] depth depth of src and dest
465 * \param[in] dwpl wpl of dest
466 * \param[in] dx x val of UL corner of dest rectangle
467 * \param[in] dy y val of UL corner of dest rectangle
468 * \param[in] dw width of dest rectangle
469 * \param[in] dh height of dest rectangle
470 * \param[in] op op code
471 * \param[in] datas ptr to src image data
472 * \param[in] spixw width of src
473 * \param[in] spixh height of src
474 * \param[in] swpl wpl of src
475 * \param[in] sx x val of UL corner of src rectangle
476 * \param[in] sy y val of UL corner of src rectangle
477 * \return void
478 *
479 * Action: Scales width, performs clipping, checks alignment and
480 * dispatches for the rasterop.
481 *
482 * Warning: the two images must have equal depth. This is not checked.
483 */
484 void
485 rasteropLow(l_uint32 *datad,
486 l_int32 dpixw,
487 l_int32 dpixh,
488 l_int32 depth,
489 l_int32 dwpl,
490 l_int32 dx,
491 l_int32 dy,
492 l_int32 dw,
493 l_int32 dh,
494 l_int32 op,
495 l_uint32 *datas,
496 l_int32 spixw,
497 l_int32 spixh,
498 l_int32 swpl,
499 l_int32 sx,
500 l_int32 sy)
501 {
502 l_int32 dhangw, shangw, dhangh, shangh;
503
504 /* -------------------------------------------------------*
505 * Scale horizontal dimensions by depth *
506 * -------------------------------------------------------*/
507 if (depth != 1) {
508 dpixw *= depth;
509 dx *= depth;
510 dw *= depth;
511 spixw *= depth;
512 sx *= depth;
513 }
514
515 /* -------------------------------------------------------*
516 * Clip to max rectangle within both src and dest *
517 * -------------------------------------------------------*/
518 /* Clip horizontally (sx, dx, dw) */
519 if (dx < 0) {
520 sx -= dx; /* increase sx */
521 dw += dx; /* reduce dw */
522 dx = 0;
523 }
524 if (sx < 0) {
525 dx -= sx; /* increase dx */
526 dw += sx; /* reduce dw */
527 sx = 0;
528 }
529 dhangw = dx + dw - dpixw; /* rect ovhang dest to right */
530 if (dhangw > 0)
531 dw -= dhangw; /* reduce dw */
532 shangw = sx + dw - spixw; /* rect ovhang src to right */
533 if (shangw > 0)
534 dw -= shangw; /* reduce dw */
535
536 /* Clip vertically (sy, dy, dh) */
537 if (dy < 0) {
538 sy -= dy; /* increase sy */
539 dh += dy; /* reduce dh */
540 dy = 0;
541 }
542 if (sy < 0) {
543 dy -= sy; /* increase dy */
544 dh += sy; /* reduce dh */
545 sy = 0;
546 }
547 dhangh = dy + dh - dpixh; /* rect ovhang dest below */
548 if (dhangh > 0)
549 dh -= dhangh; /* reduce dh */
550 shangh = sy + dh - spixh; /* rect ovhang src below */
551 if (shangh > 0)
552 dh -= shangh; /* reduce dh */
553
554 /* If clipped entirely, quit */
555 if ((dw <= 0) || (dh <= 0))
556 return;
557
558 #if 0
559 lept_stderr("dx = %d, dy = %d, dw = %d, dh = %d, sx = %d, sy = %d\n",
560 dx, dy, dw, dh, sx, sy);
561 #endif
562
563 /* -------------------------------------------------------*
564 * Dispatch to aligned or non-aligned blitters *
565 * -------------------------------------------------------*/
566 if (((dx & 31) == 0) && ((sx & 31) == 0))
567 rasteropWordAlignedLow(datad, dwpl, dx, dy, dw, dh, op,
568 datas, swpl, sx, sy);
569 else if ((dx & 31) == (sx & 31))
570 rasteropVAlignedLow(datad, dwpl, dx, dy, dw, dh, op,
571 datas, swpl, sx, sy);
572 else
573 rasteropGeneralLow(datad, dwpl, dx, dy, dw, dh, op,
574 datas, swpl, sx, sy);
575 }
576
577
578 /*--------------------------------------------------------------------*
579 * Static low-level rasterop with vertical word alignment *
580 *--------------------------------------------------------------------*/
581 /*!
582 * \brief rasteropWordAlignedLow()
583 *
584 * \param[in] datad ptr to dest image data
585 * \param[in] dwpl wpl of dest
586 * \param[in] dx x val of UL corner of dest rectangle
587 * \param[in] dy y val of UL corner of dest rectangle
588 * \param[in] dw width of dest rectangle
589 * \param[in] dh height of dest rectangle
590 * \param[in] op op code
591 * \param[in] datas ptr to src image data
592 * \param[in] swpl wpl of src
593 * \param[in] sx x val of UL corner of src rectangle
594 * \param[in] sy y val of UL corner of src rectangle
595 * \return void
596 *
597 * This is called when both the src and dest rects
598 * are left aligned on 32-bit word boundaries.
599 * That is: dx & 31 == 0 and sx & 31 == 0
600 *
601 * We make an optimized implementation of this because
602 * it is a common case: e.g., two images are rasterop'd
603 * starting from their UL corners 0,0.
604 */
605 static void
606 rasteropWordAlignedLow(l_uint32 *datad,
607 l_int32 dwpl,
608 l_int32 dx,
609 l_int32 dy,
610 l_int32 dw,
611 l_int32 dh,
612 l_int32 op,
613 l_uint32 *datas,
614 l_int32 swpl,
615 l_int32 sx,
616 l_int32 sy)
617 {
618 l_int32 nfullw; /* number of full words */
619 l_uint32 *psfword; /* ptr to first src word */
620 l_uint32 *pdfword; /* ptr to first dest word */
621 l_int32 lwbits; /* number of ovrhang bits in last partial word */
622 l_uint32 lwmask; /* mask for last partial word */
623 l_uint32 *lines, *lined;
624 l_int32 i, j;
625
626
627 /*--------------------------------------------------------*
628 * Preliminary calculations *
629 *--------------------------------------------------------*/
630 nfullw = dw >> 5;
631 lwbits = dw & 31;
632 if (lwbits)
633 lwmask = lmask32[lwbits];
634 psfword = datas + swpl * sy + (sx >> 5);
635 pdfword = datad + dwpl * dy + (dx >> 5);
636
637 /*--------------------------------------------------------*
638 * Now we're ready to do the ops *
639 *--------------------------------------------------------*/
640 switch (op)
641 {
642 case PIX_SRC:
643 for (i = 0; i < dh; i++) {
644 lines = psfword + i * swpl;
645 lined = pdfword + i * dwpl;
646 for (j = 0; j < nfullw; j++) {
647 *lined = *lines;
648 lined++;
649 lines++;
650 }
651 if (lwbits)
652 *lined = COMBINE_PARTIAL(*lined, *lines, lwmask);
653 }
654 break;
655 case PIX_NOT(PIX_SRC):
656 for (i = 0; i < dh; i++) {
657 lines = psfword + i * swpl;
658 lined = pdfword + i * dwpl;
659 for (j = 0; j < nfullw; j++) {
660 *lined = ~(*lines);
661 lined++;
662 lines++;
663 }
664 if (lwbits)
665 *lined = COMBINE_PARTIAL(*lined, ~(*lines), lwmask);
666 }
667 break;
668 case (PIX_SRC | PIX_DST):
669 for (i = 0; i < dh; i++) {
670 lines = psfword + i * swpl;
671 lined = pdfword + i * dwpl;
672 for (j = 0; j < nfullw; j++) {
673 *lined = (*lines | *lined);
674 lined++;
675 lines++;
676 }
677 if (lwbits)
678 *lined = COMBINE_PARTIAL(*lined, (*lines | *lined), lwmask);
679 }
680 break;
681 case (PIX_SRC & PIX_DST):
682 for (i = 0; i < dh; i++) {
683 lines = psfword + i * swpl;
684 lined = pdfword + i * dwpl;
685 for (j = 0; j < nfullw; j++) {
686 *lined = (*lines & *lined);
687 lined++;
688 lines++;
689 }
690 if (lwbits)
691 *lined = COMBINE_PARTIAL(*lined, (*lines & *lined), lwmask);
692 }
693 break;
694 case (PIX_SRC ^ PIX_DST):
695 for (i = 0; i < dh; i++) {
696 lines = psfword + i * swpl;
697 lined = pdfword + i * dwpl;
698 for (j = 0; j < nfullw; j++) {
699 *lined = (*lines ^ *lined);
700 lined++;
701 lines++;
702 }
703 if (lwbits)
704 *lined = COMBINE_PARTIAL(*lined, (*lines ^ *lined), lwmask);
705 }
706 break;
707 case (PIX_NOT(PIX_SRC) | PIX_DST):
708 for (i = 0; i < dh; i++) {
709 lines = psfword + i * swpl;
710 lined = pdfword + i * dwpl;
711 for (j = 0; j < nfullw; j++) {
712 *lined = (~(*lines) | *lined);
713 lined++;
714 lines++;
715 }
716 if (lwbits)
717 *lined = COMBINE_PARTIAL(*lined, (~(*lines) | *lined), lwmask);
718 }
719 break;
720 case (PIX_NOT(PIX_SRC) & PIX_DST):
721 for (i = 0; i < dh; i++) {
722 lines = psfword + i * swpl;
723 lined = pdfword + i * dwpl;
724 for (j = 0; j < nfullw; j++) {
725 *lined = (~(*lines) & *lined);
726 lined++;
727 lines++;
728 }
729 if (lwbits)
730 *lined = COMBINE_PARTIAL(*lined, (~(*lines) & *lined), lwmask);
731 }
732 break;
733 case (PIX_SRC | PIX_NOT(PIX_DST)):
734 for (i = 0; i < dh; i++) {
735 lines = psfword + i * swpl;
736 lined = pdfword + i * dwpl;
737 for (j = 0; j < nfullw; j++) {
738 *lined = (*lines | ~(*lined));
739 lined++;
740 lines++;
741 }
742 if (lwbits)
743 *lined = COMBINE_PARTIAL(*lined, (*lines | ~(*lined)), lwmask);
744 }
745 break;
746 case (PIX_SRC & PIX_NOT(PIX_DST)):
747 for (i = 0; i < dh; i++) {
748 lines = psfword + i * swpl;
749 lined = pdfword + i * dwpl;
750 for (j = 0; j < nfullw; j++) {
751 *lined = (*lines & ~(*lined));
752 lined++;
753 lines++;
754 }
755 if (lwbits)
756 *lined = COMBINE_PARTIAL(*lined, (*lines & ~(*lined)), lwmask);
757 }
758 break;
759 case (PIX_NOT(PIX_SRC | PIX_DST)):
760 for (i = 0; i < dh; i++) {
761 lines = psfword + i * swpl;
762 lined = pdfword + i * dwpl;
763 for (j = 0; j < nfullw; j++) {
764 *lined = ~(*lines | *lined);
765 lined++;
766 lines++;
767 }
768 if (lwbits)
769 *lined = COMBINE_PARTIAL(*lined, ~(*lines | *lined), lwmask);
770 }
771 break;
772 case (PIX_NOT(PIX_SRC & PIX_DST)):
773 for (i = 0; i < dh; i++) {
774 lines = psfword + i * swpl;
775 lined = pdfword + i * dwpl;
776 for (j = 0; j < nfullw; j++) {
777 *lined = ~(*lines & *lined);
778 lined++;
779 lines++;
780 }
781 if (lwbits)
782 *lined = COMBINE_PARTIAL(*lined, ~(*lines & *lined), lwmask);
783 }
784 break;
785 /* this is three cases: ~(s ^ d), ~s ^ d, s ^ ~d */
786 case (PIX_NOT(PIX_SRC ^ PIX_DST)):
787 for (i = 0; i < dh; i++) {
788 lines = psfword + i * swpl;
789 lined = pdfword + i * dwpl;
790 for (j = 0; j < nfullw; j++) {
791 *lined = ~(*lines ^ *lined);
792 lined++;
793 lines++;
794 }
795 if (lwbits)
796 *lined = COMBINE_PARTIAL(*lined, ~(*lines ^ *lined), lwmask);
797 }
798 break;
799 default:
800 lept_stderr("Operation %d invalid\n", op);
801 }
802 }
803
804
805
806 /*--------------------------------------------------------------------*
807 * Static low-level rasterop with vertical word alignment *
808 *--------------------------------------------------------------------*/
809 /*!
810 * \brief rasteropVAlignedLow()
811 *
812 * \param[in] datad ptr to dest image data
813 * \param[in] dwpl wpl of dest
814 * \param[in] dx x val of UL corner of dest rectangle
815 * \param[in] dy y val of UL corner of dest rectangle
816 * \param[in] dw width of dest rectangle
817 * \param[in] dh height of dest rectangle
818 * \param[in] op op code
819 * \param[in] datas ptr to src image data
820 * \param[in] swpl wpl of src
821 * \param[in] sx x val of UL corner of src rectangle
822 * \param[in] sy y val of UL corner of src rectangle
823 * \return void
824 *
825 * This is called when the left side of the src and dest
826 * rects have the same alignment relative to 32-bit word
827 * boundaries; i.e., dx & 31) == (sx & 31
828 */
829 static void
830 rasteropVAlignedLow(l_uint32 *datad,
831 l_int32 dwpl,
832 l_int32 dx,
833 l_int32 dy,
834 l_int32 dw,
835 l_int32 dh,
836 l_int32 op,
837 l_uint32 *datas,
838 l_int32 swpl,
839 l_int32 sx,
840 l_int32 sy)
841 {
842 l_int32 dfwpartb; /* boolean (1, 0) if first dest word is partial */
843 l_int32 dfwpart2b; /* boolean (1, 0) if first dest word is doubly partial */
844 l_uint32 dfwmask; /* mask for first partial dest word */
845 l_int32 dfwbits; /* first word dest bits in ovrhang */
846 l_uint32 *pdfwpart = NULL; /* ptr to first partial dest word */
847 l_uint32 *psfwpart = NULL; /* ptr to first partial src word */
848 l_int32 dfwfullb; /* boolean (1, 0) if there exists a full dest word */
849 l_int32 dnfullw; /* number of full words in dest */
850 l_uint32 *pdfwfull = NULL; /* ptr to first full dest word */
851 l_uint32 *psfwfull = NULL; /* ptr to first full src word */
852 l_int32 dlwpartb; /* boolean (1, 0) if last dest word is partial */
853 l_uint32 dlwmask; /* mask for last partial dest word */
854 l_int32 dlwbits; /* last word dest bits in ovrhang */
855 l_uint32 *pdlwpart = NULL; /* ptr to last partial dest word */
856 l_uint32 *pslwpart = NULL; /* ptr to last partial src word */
857 l_int32 i, j;
858
859
860 /*--------------------------------------------------------*
861 * Preliminary calculations *
862 *--------------------------------------------------------*/
863 /* is the first word partial? */
864 dfwmask = 0;
865 if ((dx & 31) == 0) { /* if not */
866 dfwpartb = 0;
867 dfwbits = 0;
868 } else { /* if so */
869 dfwpartb = 1;
870 dfwbits = 32 - (dx & 31);
871 dfwmask = rmask32[dfwbits];
872 pdfwpart = datad + dwpl * dy + (dx >> 5);
873 psfwpart = datas + swpl * sy + (sx >> 5);
874 }
875
876 /* is the first word doubly partial? */
877 if (dw >= dfwbits) { /* if not */
878 dfwpart2b = 0;
879 } else { /* if so */
880 dfwpart2b = 1;
881 dfwmask &= lmask32[32 - dfwbits + dw];
882 }
883
884 /* is there a full dest word? */
885 if (dfwpart2b == 1) { /* not */
886 dfwfullb = 0;
887 dnfullw = 0;
888 } else {
889 dnfullw = (dw - dfwbits) >> 5;
890 if (dnfullw == 0) { /* if not */
891 dfwfullb = 0;
892 } else { /* if so */
893 dfwfullb = 1;
894 if (dfwpartb) {
895 pdfwfull = pdfwpart + 1;
896 psfwfull = psfwpart + 1;
897 } else {
898 pdfwfull = datad + dwpl * dy + (dx >> 5);
899 psfwfull = datas + swpl * sy + (sx >> 5);
900 }
901 }
902 }
903
904 /* is the last word partial? */
905 dlwbits = (dx + dw) & 31;
906 if (dfwpart2b == 1 || dlwbits == 0) { /* if not */
907 dlwpartb = 0;
908 } else {
909 dlwpartb = 1;
910 dlwmask = lmask32[dlwbits];
911 if (dfwpartb) {
912 pdlwpart = pdfwpart + 1 + dnfullw;
913 pslwpart = psfwpart + 1 + dnfullw;
914 } else {
915 pdlwpart = datad + dwpl * dy + (dx >> 5) + dnfullw;
916 pslwpart = datas + swpl * sy + (sx >> 5) + dnfullw;
917 }
918 }
919
920
921 /*--------------------------------------------------------*
922 * Now we're ready to do the ops *
923 *--------------------------------------------------------*/
924 switch (op)
925 {
926 case PIX_SRC:
927 /* do the first partial word */
928 if (dfwpartb) {
929 for (i = 0; i < dh; i++) {
930 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, *psfwpart, dfwmask);
931 pdfwpart += dwpl;
932 psfwpart += swpl;
933 }
934 }
935
936 /* do the full words */
937 if (dfwfullb) {
938 for (i = 0; i < dh; i++) {
939 for (j = 0; j < dnfullw; j++)
940 *(pdfwfull + j) = *(psfwfull + j);
941 pdfwfull += dwpl;
942 psfwfull += swpl;
943 }
944 }
945
946 /* do the last partial word */
947 if (dlwpartb) {
948 for (i = 0; i < dh; i++) {
949 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, *pslwpart, dlwmask);
950 pdlwpart += dwpl;
951 pslwpart += swpl;
952 }
953 }
954 break;
955 case PIX_NOT(PIX_SRC):
956 /* do the first partial word */
957 if (dfwpartb) {
958 for (i = 0; i < dh; i++) {
959 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, ~(*psfwpart), dfwmask);
960 pdfwpart += dwpl;
961 psfwpart += swpl;
962 }
963 }
964
965 /* do the full words */
966 if (dfwfullb) {
967 for (i = 0; i < dh; i++) {
968 for (j = 0; j < dnfullw; j++)
969 *(pdfwfull + j) = ~(*(psfwfull + j));
970 pdfwfull += dwpl;
971 psfwfull += swpl;
972 }
973 }
974
975 /* do the last partial word */
976 if (dlwpartb) {
977 for (i = 0; i < dh; i++) {
978 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, ~(*pslwpart), dlwmask);
979 pdlwpart += dwpl;
980 pslwpart += swpl;
981 }
982 }
983 break;
984 case (PIX_SRC | PIX_DST):
985 /* do the first partial word */
986 if (dfwpartb) {
987 for (i = 0; i < dh; i++) {
988 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
989 (*psfwpart | *pdfwpart), dfwmask);
990 pdfwpart += dwpl;
991 psfwpart += swpl;
992 }
993 }
994
995 /* do the full words */
996 if (dfwfullb) {
997 for (i = 0; i < dh; i++) {
998 for (j = 0; j < dnfullw; j++)
999 *(pdfwfull + j) |= *(psfwfull + j);
1000 pdfwfull += dwpl;
1001 psfwfull += swpl;
1002 }
1003 }
1004
1005 /* do the last partial word */
1006 if (dlwpartb) {
1007 for (i = 0; i < dh; i++) {
1008 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1009 (*pslwpart | *pdlwpart), dlwmask);
1010 pdlwpart += dwpl;
1011 pslwpart += swpl;
1012 }
1013 }
1014 break;
1015 case (PIX_SRC & PIX_DST):
1016 /* do the first partial word */
1017 if (dfwpartb) {
1018 for (i = 0; i < dh; i++) {
1019 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1020 (*psfwpart & *pdfwpart), dfwmask);
1021 pdfwpart += dwpl;
1022 psfwpart += swpl;
1023 }
1024 }
1025
1026 /* do the full words */
1027 if (dfwfullb) {
1028 for (i = 0; i < dh; i++) {
1029 for (j = 0; j < dnfullw; j++)
1030 *(pdfwfull + j) &= *(psfwfull + j);
1031 pdfwfull += dwpl;
1032 psfwfull += swpl;
1033 }
1034 }
1035
1036 /* do the last partial word */
1037 if (dlwpartb) {
1038 for (i = 0; i < dh; i++) {
1039 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1040 (*pslwpart & *pdlwpart), dlwmask);
1041 pdlwpart += dwpl;
1042 pslwpart += swpl;
1043 }
1044 }
1045 break;
1046 case (PIX_SRC ^ PIX_DST):
1047 /* do the first partial word */
1048 if (dfwpartb) {
1049 for (i = 0; i < dh; i++) {
1050 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1051 (*psfwpart ^ *pdfwpart), dfwmask);
1052 pdfwpart += dwpl;
1053 psfwpart += swpl;
1054 }
1055 }
1056
1057 /* do the full words */
1058 if (dfwfullb) {
1059 for (i = 0; i < dh; i++) {
1060 for (j = 0; j < dnfullw; j++)
1061 *(pdfwfull + j) ^= *(psfwfull + j);
1062 pdfwfull += dwpl;
1063 psfwfull += swpl;
1064 }
1065 }
1066
1067 /* do the last partial word */
1068 if (dlwpartb) {
1069 for (i = 0; i < dh; i++) {
1070 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1071 (*pslwpart ^ *pdlwpart), dlwmask);
1072 pdlwpart += dwpl;
1073 pslwpart += swpl;
1074 }
1075 }
1076 break;
1077 case (PIX_NOT(PIX_SRC) | PIX_DST):
1078 /* do the first partial word */
1079 if (dfwpartb) {
1080 for (i = 0; i < dh; i++) {
1081 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1082 (~(*psfwpart) | *pdfwpart), dfwmask);
1083 pdfwpart += dwpl;
1084 psfwpart += swpl;
1085 }
1086 }
1087
1088 /* do the full words */
1089 if (dfwfullb) {
1090 for (i = 0; i < dh; i++) {
1091 for (j = 0; j < dnfullw; j++)
1092 *(pdfwfull + j) |= ~(*(psfwfull + j));
1093 pdfwfull += dwpl;
1094 psfwfull += swpl;
1095 }
1096 }
1097
1098 /* do the last partial word */
1099 if (dlwpartb) {
1100 for (i = 0; i < dh; i++) {
1101 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1102 (~(*pslwpart) | *pdlwpart), dlwmask);
1103 pdlwpart += dwpl;
1104 pslwpart += swpl;
1105 }
1106 }
1107 break;
1108 case (PIX_NOT(PIX_SRC) & PIX_DST):
1109 /* do the first partial word */
1110 if (dfwpartb) {
1111 for (i = 0; i < dh; i++) {
1112 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1113 (~(*psfwpart) & *pdfwpart), dfwmask);
1114 pdfwpart += dwpl;
1115 psfwpart += swpl;
1116 }
1117 }
1118
1119 /* do the full words */
1120 if (dfwfullb) {
1121 for (i = 0; i < dh; i++) {
1122 for (j = 0; j < dnfullw; j++)
1123 *(pdfwfull + j) &= ~(*(psfwfull + j));
1124 pdfwfull += dwpl;
1125 psfwfull += swpl;
1126 }
1127 }
1128
1129 /* do the last partial word */
1130 if (dlwpartb) {
1131 for (i = 0; i < dh; i++) {
1132 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1133 (~(*pslwpart) & *pdlwpart), dlwmask);
1134 pdlwpart += dwpl;
1135 pslwpart += swpl;
1136 }
1137 }
1138 break;
1139 case (PIX_SRC | PIX_NOT(PIX_DST)):
1140 /* do the first partial word */
1141 if (dfwpartb) {
1142 for (i = 0; i < dh; i++) {
1143 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1144 (*psfwpart | ~(*pdfwpart)), dfwmask);
1145 pdfwpart += dwpl;
1146 psfwpart += swpl;
1147 }
1148 }
1149
1150 /* do the full words */
1151 if (dfwfullb) {
1152 for (i = 0; i < dh; i++) {
1153 for (j = 0; j < dnfullw; j++)
1154 *(pdfwfull + j) = *(psfwfull + j) | ~(*(pdfwfull + j));
1155 pdfwfull += dwpl;
1156 psfwfull += swpl;
1157 }
1158 }
1159
1160 /* do the last partial word */
1161 if (dlwpartb) {
1162 for (i = 0; i < dh; i++) {
1163 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1164 (*pslwpart | ~(*pdlwpart)), dlwmask);
1165 pdlwpart += dwpl;
1166 pslwpart += swpl;
1167 }
1168 }
1169 break;
1170 case (PIX_SRC & PIX_NOT(PIX_DST)):
1171 /* do the first partial word */
1172 if (dfwpartb) {
1173 for (i = 0; i < dh; i++) {
1174 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1175 (*psfwpart & ~(*pdfwpart)), dfwmask);
1176 pdfwpart += dwpl;
1177 psfwpart += swpl;
1178 }
1179 }
1180
1181 /* do the full words */
1182 if (dfwfullb) {
1183 for (i = 0; i < dh; i++) {
1184 for (j = 0; j < dnfullw; j++)
1185 *(pdfwfull + j) = *(psfwfull + j) & ~(*(pdfwfull + j));
1186 pdfwfull += dwpl;
1187 psfwfull += swpl;
1188 }
1189 }
1190
1191 /* do the last partial word */
1192 if (dlwpartb) {
1193 for (i = 0; i < dh; i++) {
1194 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1195 (*pslwpart & ~(*pdlwpart)), dlwmask);
1196 pdlwpart += dwpl;
1197 pslwpart += swpl;
1198 }
1199 }
1200 break;
1201 case (PIX_NOT(PIX_SRC | PIX_DST)):
1202 /* do the first partial word */
1203 if (dfwpartb) {
1204 for (i = 0; i < dh; i++) {
1205 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1206 ~(*psfwpart | *pdfwpart), dfwmask);
1207 pdfwpart += dwpl;
1208 psfwpart += swpl;
1209 }
1210 }
1211
1212 /* do the full words */
1213 if (dfwfullb) {
1214 for (i = 0; i < dh; i++) {
1215 for (j = 0; j < dnfullw; j++)
1216 *(pdfwfull + j) = ~(*(psfwfull + j) | *(pdfwfull + j));
1217 pdfwfull += dwpl;
1218 psfwfull += swpl;
1219 }
1220 }
1221
1222 /* do the last partial word */
1223 if (dlwpartb) {
1224 for (i = 0; i < dh; i++) {
1225 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1226 ~(*pslwpart | *pdlwpart), dlwmask);
1227 pdlwpart += dwpl;
1228 pslwpart += swpl;
1229 }
1230 }
1231 break;
1232 case (PIX_NOT(PIX_SRC & PIX_DST)):
1233 /* do the first partial word */
1234 if (dfwpartb) {
1235 for (i = 0; i < dh; i++) {
1236 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1237 ~(*psfwpart & *pdfwpart), dfwmask);
1238 pdfwpart += dwpl;
1239 psfwpart += swpl;
1240 }
1241 }
1242
1243 /* do the full words */
1244 if (dfwfullb) {
1245 for (i = 0; i < dh; i++) {
1246 for (j = 0; j < dnfullw; j++)
1247 *(pdfwfull + j) = ~(*(psfwfull + j) & *(pdfwfull + j));
1248 pdfwfull += dwpl;
1249 psfwfull += swpl;
1250 }
1251 }
1252
1253 /* do the last partial word */
1254 if (dlwpartb) {
1255 for (i = 0; i < dh; i++) {
1256 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1257 ~(*pslwpart & *pdlwpart), dlwmask);
1258 pdlwpart += dwpl;
1259 pslwpart += swpl;
1260 }
1261 }
1262 break;
1263 /* this is three cases: ~(s ^ d), ~s ^ d, s ^ ~d */
1264 case (PIX_NOT(PIX_SRC ^ PIX_DST)):
1265 /* do the first partial word */
1266 if (dfwpartb) {
1267 for (i = 0; i < dh; i++) {
1268 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1269 ~(*psfwpart ^ *pdfwpart), dfwmask);
1270 pdfwpart += dwpl;
1271 psfwpart += swpl;
1272 }
1273 }
1274
1275 /* do the full words */
1276 if (dfwfullb) {
1277 for (i = 0; i < dh; i++) {
1278 for (j = 0; j < dnfullw; j++)
1279 *(pdfwfull + j) = ~(*(psfwfull + j) ^ *(pdfwfull + j));
1280 pdfwfull += dwpl;
1281 psfwfull += swpl;
1282 }
1283 }
1284
1285 /* do the last partial word */
1286 if (dlwpartb) {
1287 for (i = 0; i < dh; i++) {
1288 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1289 ~(*pslwpart ^ *pdlwpart), dlwmask);
1290 pdlwpart += dwpl;
1291 pslwpart += swpl;
1292 }
1293 }
1294 break;
1295 default:
1296 lept_stderr("Operation %x invalid\n", op);
1297 }
1298 }
1299
1300
1301 /*--------------------------------------------------------------------*
1302 * Static low-level rasterop without vertical word alignment *
1303 *--------------------------------------------------------------------*/
1304 /*!
1305 * \brief rasteropGeneralLow()
1306 *
1307 * \param[in] datad ptr to dest image data
1308 * \param[in] dwpl wpl of dest
1309 * \param[in] dx x val of UL corner of dest rectangle
1310 * \param[in] dy y val of UL corner of dest rectangle
1311 * \param[in] dw width of dest rectangle
1312 * \param[in] dh height of dest rectangle
1313 * \param[in] op op code
1314 * \param[in] datas ptr to src image data
1315 * \param[in] swpl wpl of src
1316 * \param[in] sx x val of UL corner of src rectangle
1317 * \param[in] sy y val of UL corner of src rectangle
1318 * \return void
1319 *
1320 * This is called when the src and dest rects are
1321 * do not have the same 32-bit word alignment.
1322 *
1323 * The method is a generalization of rasteropVAlignLow.
1324 * There, the src image pieces were directly merged
1325 * with the dest. Here, we shift the source bits
1326 * to fill words that are aligned with the dest, and
1327 * then use those "source words" exactly in place
1328 * of the source words that were used in rasteropVAlignLow.
1329 *
1330 * The critical parameter is thus the shift required
1331 * for the src. Consider the left edge of the rectangle.
1332 * The overhang into the src and dest words are found,
1333 * and the difference is exactly this shift. There are
1334 * two separate cases, depending on whether the src pixels
1335 * are shifted left or right. If the src overhang is
1336 * larger than the dest overhang, the src is shifted to
1337 * the right, and a number of pixels equal to the shift are
1338 * left over for filling the next dest word, if necessary.
1339 *
1340 * But if the dest overhang is larger than the src overhang,
1341 * the src is shifted to the left, and depending on the width of
1342 * transferred pixels, it may also be necessary to shift pixels
1343 * in from the next src word, in order to fill the dest word.
1344 * An interesting case is where the src overhang equals the width,
1345 * dw, of the block. Then all the pixels necessary to fill the first
1346 * dest word can be taken from the first src word, up to the last
1347 * src pixel in the word, and no pixels from the next src word are
1348 * required. Consider this simple example, where a single pixel from
1349 * the src is transferred to the dest:
1350 * pix1 = pixCreate(32, 1, 1);
1351 * pix2 = pixCreate(32, 1, 1);
1352 * pixRasterop(pix1, 30, 0, 1, 1, PIX_SRC, pix2, 31, 0);
1353 * Here, the pixel at the right end of the src image (sx = 31)
1354 * is shifted one bit to the left (to dx = 30). The width (1) equals
1355 * the src overhang (1), and no pixels from the next word are required.
1356 * (This must be true because there is only one src word.)
1357 */
1358 static void
1359 rasteropGeneralLow(l_uint32 *datad,
1360 l_int32 dwpl,
1361 l_int32 dx,
1362 l_int32 dy,
1363 l_int32 dw,
1364 l_int32 dh,
1365 l_int32 op,
1366 l_uint32 *datas,
1367 l_int32 swpl,
1368 l_int32 sx,
1369 l_int32 sy)
1370 {
1371 l_int32 dfwpartb; /* boolean (1, 0) if first dest word is partial */
1372 l_int32 dfwpart2b; /* boolean (1, 0) if 1st dest word is doubly partial */
1373 l_uint32 dfwmask; /* mask for first partial dest word */
1374 l_int32 dfwbits; /* first word dest bits in overhang; 0-31 */
1375 l_int32 dhang; /* dest overhang in first partial word, */
1376 /* or 0 if dest is word aligned (same as dfwbits) */
1377 l_uint32 *pdfwpart = NULL; /* ptr to first partial dest word */
1378 l_uint32 *psfwpart = NULL; /* ptr to first partial src word */
1379 l_int32 dfwfullb; /* boolean (1, 0) if there exists a full dest word */
1380 l_int32 dnfullw; /* number of full words in dest */
1381 l_uint32 *pdfwfull = NULL; /* ptr to first full dest word */
1382 l_uint32 *psfwfull = NULL; /* ptr to first full src word */
1383 l_int32 dlwpartb; /* boolean (1, 0) if last dest word is partial */
1384 l_uint32 dlwmask; /* mask for last partial dest word */
1385 l_int32 dlwbits; /* last word dest bits in ovrhang */
1386 l_uint32 *pdlwpart = NULL; /* ptr to last partial dest word */
1387 l_uint32 *pslwpart = NULL; /* ptr to last partial src word */
1388 l_uint32 sword; /* compose src word aligned with the dest words */
1389 l_int32 sfwbits; /* first word src bits in overhang (1-32), */
1390 /* or 32 if src is word aligned */
1391 l_int32 shang; /* source overhang in the first partial word, */
1392 /* or 0 if src is word aligned (not same as sfwbits) */
1393 l_int32 sleftshift; /* bits to shift left for source word to align */
1394 /* with the dest. Also the number of bits that */
1395 /* get shifted to the right to align with the dest. */
1396 l_int32 srightshift; /* bits to shift right for source word to align */
1397 /* with dest. Also, the number of bits that get */
1398 /* shifted left to align with the dest. */
1399 l_int32 srightmask; /* mask for selecting sleftshift bits that have */
1400 /* been shifted right by srightshift bits */
1401 l_int32 sfwshiftdir; /* either SHIFT_LEFT or SHIFT_RIGHT */
1402 l_int32 sfwaddb; /* boolean: do we need an additional sfw right shift? */
1403 l_int32 slwaddb; /* boolean: do we need an additional slw right shift? */
1404 l_int32 i, j;
1405
1406
1407 /*--------------------------------------------------------*
1408 * Preliminary calculations *
1409 *--------------------------------------------------------*/
1410 /* To get alignment of src with dst (e.g., in the
1411 * full words) the src must do a left shift of its
1412 * relative overhang in the current src word,
1413 * and OR that with a right shift of
1414 * (31 - relative overhang) from the next src word.
1415 * We find the absolute overhangs, the relative overhangs,
1416 * the required shifts and the src mask */
1417 if ((sx & 31) == 0)
1418 shang = 0;
1419 else
1420 shang = 32 - (sx & 31);
1421 if ((dx & 31) == 0)
1422 dhang = 0;
1423 else
1424 dhang = 32 - (dx & 31);
1425 #if 0
1426 lept_stderr("shang = %d, dhang = %d\n", shang, dhang);
1427 #endif
1428
1429 if (shang == 0 && dhang == 0) { /* this should be treated by an
1430 aligned operation, not by
1431 this general rasterop! */
1432 sleftshift = 0;
1433 srightshift = 0;
1434 srightmask = rmask32[0];
1435 } else {
1436 if (dhang > shang)
1437 sleftshift = dhang - shang;
1438 else
1439 sleftshift = 32 - (shang - dhang);
1440 srightshift = 32 - sleftshift;
1441 srightmask = rmask32[sleftshift];
1442 }
1443
1444 #if 0
1445 lept_stderr("sleftshift = %d, srightshift = %d\n", sleftshift, srightshift);
1446 #endif
1447
1448 /* Is the first dest word partial? */
1449 dfwmask = 0;
1450 if ((dx & 31) == 0) { /* if not */
1451 dfwpartb = 0;
1452 dfwbits = 0;
1453 } else { /* if so */
1454 dfwpartb = 1;
1455 dfwbits = 32 - (dx & 31);
1456 dfwmask = rmask32[dfwbits];
1457 pdfwpart = datad + dwpl * dy + (dx >> 5);
1458 psfwpart = datas + swpl * sy + (sx >> 5);
1459 sfwbits = 32 - (sx & 31);
1460 if (dfwbits > sfwbits) {
1461 sfwshiftdir = SHIFT_LEFT; /* shift by sleftshift */
1462 /* Do we have enough bits from the current src word? */
1463 if (dw <= shang)
1464 sfwaddb = 0; /* yes: we have enough bits */
1465 else
1466 sfwaddb = 1; /* no: rshift in next src word by srightshift */
1467 } else {
1468 sfwshiftdir = SHIFT_RIGHT; /* shift by srightshift */
1469 }
1470 }
1471
1472 /* Is the first dest word doubly partial? */
1473 if (dw >= dfwbits) { /* if not */
1474 dfwpart2b = 0;
1475 } else { /* if so */
1476 dfwpart2b = 1;
1477 dfwmask &= lmask32[32 - dfwbits + dw];
1478 }
1479
1480 /* Is there a full dest word? */
1481 if (dfwpart2b == 1) { /* not */
1482 dfwfullb = 0;
1483 dnfullw = 0;
1484 } else {
1485 dnfullw = (dw - dfwbits) >> 5;
1486 if (dnfullw == 0) { /* if not */
1487 dfwfullb = 0;
1488 } else { /* if so */
1489 dfwfullb = 1;
1490 pdfwfull = datad + dwpl * dy + ((dx + dhang) >> 5);
1491 psfwfull = datas + swpl * sy + ((sx + dhang) >> 5); /* yes, dhang */
1492 }
1493 }
1494
1495 /* Is the last dest word partial? */
1496 dlwbits = (dx + dw) & 31;
1497 if (dfwpart2b == 1 || dlwbits == 0) { /* if not */
1498 dlwpartb = 0;
1499 } else {
1500 dlwpartb = 1;
1501 dlwmask = lmask32[dlwbits];
1502 pdlwpart = datad + dwpl * dy + ((dx + dhang) >> 5) + dnfullw;
1503 pslwpart = datas + swpl * sy + ((sx + dhang) >> 5) + dnfullw;
1504 if (dlwbits <= srightshift) /* must be <= here !!! */
1505 slwaddb = 0; /* we got enough bits from current src word */
1506 else
1507 slwaddb = 1; /* must rshift in next src word by srightshift */
1508 }
1509
1510
1511 /*--------------------------------------------------------*
1512 * Now we're ready to do the ops *
1513 *--------------------------------------------------------*/
1514 switch (op)
1515 {
1516 case PIX_SRC:
1517 /* do the first partial word */
1518 if (dfwpartb) {
1519 for (i = 0; i < dh; i++)
1520 {
1521 if (sfwshiftdir == SHIFT_LEFT) {
1522 sword = *psfwpart << sleftshift;
1523 if (sfwaddb)
1524 sword = COMBINE_PARTIAL(sword,
1525 *(psfwpart + 1) >> srightshift,
1526 srightmask);
1527 } else { /* shift right */
1528 sword = *psfwpart >> srightshift;
1529 }
1530
1531 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, sword, dfwmask);
1532 pdfwpart += dwpl;
1533 psfwpart += swpl;
1534 }
1535 }
1536
1537 /* do the full words */
1538 if (dfwfullb) {
1539 for (i = 0; i < dh; i++) {
1540 for (j = 0; j < dnfullw; j++) {
1541 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1542 *(psfwfull + j + 1) >> srightshift,
1543 srightmask);
1544 *(pdfwfull + j) = sword;
1545 }
1546 pdfwfull += dwpl;
1547 psfwfull += swpl;
1548 }
1549 }
1550
1551 /* do the last partial word */
1552 if (dlwpartb) {
1553 for (i = 0; i < dh; i++) {
1554 sword = *pslwpart << sleftshift;
1555 if (slwaddb)
1556 sword = COMBINE_PARTIAL(sword,
1557 *(pslwpart + 1) >> srightshift,
1558 srightmask);
1559
1560 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, sword, dlwmask);
1561 pdlwpart += dwpl;
1562 pslwpart += swpl;
1563 }
1564 }
1565 break;
1566 case PIX_NOT(PIX_SRC):
1567 /* do the first partial word */
1568 if (dfwpartb) {
1569 for (i = 0; i < dh; i++)
1570 {
1571 if (sfwshiftdir == SHIFT_LEFT) {
1572 sword = *psfwpart << sleftshift;
1573 if (sfwaddb)
1574 sword = COMBINE_PARTIAL(sword,
1575 *(psfwpart + 1) >> srightshift,
1576 srightmask);
1577 } else { /* shift right */
1578 sword = *psfwpart >> srightshift;
1579 }
1580
1581 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, ~sword, dfwmask);
1582 pdfwpart += dwpl;
1583 psfwpart += swpl;
1584 }
1585 }
1586
1587 /* do the full words */
1588 if (dfwfullb) {
1589 for (i = 0; i < dh; i++) {
1590 for (j = 0; j < dnfullw; j++) {
1591 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1592 *(psfwfull + j + 1) >> srightshift,
1593 srightmask);
1594 *(pdfwfull + j) = ~sword;
1595 }
1596 pdfwfull += dwpl;
1597 psfwfull += swpl;
1598 }
1599 }
1600
1601 /* do the last partial word */
1602 if (dlwpartb) {
1603 for (i = 0; i < dh; i++) {
1604 sword = *pslwpart << sleftshift;
1605 if (slwaddb)
1606 sword = COMBINE_PARTIAL(sword,
1607 *(pslwpart + 1) >> srightshift,
1608 srightmask);
1609
1610 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, ~sword, dlwmask);
1611 pdlwpart += dwpl;
1612 pslwpart += swpl;
1613 }
1614 }
1615 break;
1616 case (PIX_SRC | PIX_DST):
1617 /* do the first partial word */
1618 if (dfwpartb) {
1619 for (i = 0; i < dh; i++)
1620 {
1621 if (sfwshiftdir == SHIFT_LEFT) {
1622 sword = *psfwpart << sleftshift;
1623 if (sfwaddb)
1624 sword = COMBINE_PARTIAL(sword,
1625 *(psfwpart + 1) >> srightshift,
1626 srightmask);
1627 } else { /* shift right */
1628 sword = *psfwpart >> srightshift;
1629 }
1630
1631 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1632 (sword | *pdfwpart), dfwmask);
1633 pdfwpart += dwpl;
1634 psfwpart += swpl;
1635 }
1636 }
1637
1638 /* do the full words */
1639 if (dfwfullb) {
1640 for (i = 0; i < dh; i++) {
1641 for (j = 0; j < dnfullw; j++) {
1642 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1643 *(psfwfull + j + 1) >> srightshift,
1644 srightmask);
1645 *(pdfwfull + j) |= sword;
1646 }
1647 pdfwfull += dwpl;
1648 psfwfull += swpl;
1649 }
1650 }
1651
1652 /* do the last partial word */
1653 if (dlwpartb) {
1654 for (i = 0; i < dh; i++) {
1655 sword = *pslwpart << sleftshift;
1656 if (slwaddb)
1657 sword = COMBINE_PARTIAL(sword,
1658 *(pslwpart + 1) >> srightshift,
1659 srightmask);
1660
1661 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1662 (sword | *pdlwpart), dlwmask);
1663 pdlwpart += dwpl;
1664 pslwpart += swpl;
1665 }
1666 }
1667 break;
1668 case (PIX_SRC & PIX_DST):
1669 /* do the first partial word */
1670 if (dfwpartb) {
1671 for (i = 0; i < dh; i++)
1672 {
1673 if (sfwshiftdir == SHIFT_LEFT) {
1674 sword = *psfwpart << sleftshift;
1675 if (sfwaddb)
1676 sword = COMBINE_PARTIAL(sword,
1677 *(psfwpart + 1) >> srightshift,
1678 srightmask);
1679 } else { /* shift right */
1680 sword = *psfwpart >> srightshift;
1681 }
1682
1683 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1684 (sword & *pdfwpart), dfwmask);
1685 pdfwpart += dwpl;
1686 psfwpart += swpl;
1687 }
1688 }
1689
1690 /* do the full words */
1691 if (dfwfullb) {
1692 for (i = 0; i < dh; i++) {
1693 for (j = 0; j < dnfullw; j++) {
1694 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1695 *(psfwfull + j + 1) >> srightshift,
1696 srightmask);
1697 *(pdfwfull + j) &= sword;
1698 }
1699 pdfwfull += dwpl;
1700 psfwfull += swpl;
1701 }
1702 }
1703
1704 /* do the last partial word */
1705 if (dlwpartb) {
1706 for (i = 0; i < dh; i++) {
1707 sword = *pslwpart << sleftshift;
1708 if (slwaddb)
1709 sword = COMBINE_PARTIAL(sword,
1710 *(pslwpart + 1) >> srightshift,
1711 srightmask);
1712
1713 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1714 (sword & *pdlwpart), dlwmask);
1715 pdlwpart += dwpl;
1716 pslwpart += swpl;
1717 }
1718 }
1719 break;
1720 case (PIX_SRC ^ PIX_DST):
1721 /* do the first partial word */
1722 if (dfwpartb) {
1723 for (i = 0; i < dh; i++)
1724 {
1725 if (sfwshiftdir == SHIFT_LEFT) {
1726 sword = *psfwpart << sleftshift;
1727 if (sfwaddb)
1728 sword = COMBINE_PARTIAL(sword,
1729 *(psfwpart + 1) >> srightshift,
1730 srightmask);
1731 } else { /* shift right */
1732 sword = *psfwpart >> srightshift;
1733 }
1734
1735 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1736 (sword ^ *pdfwpart), dfwmask);
1737 pdfwpart += dwpl;
1738 psfwpart += swpl;
1739 }
1740 }
1741
1742 /* do the full words */
1743 if (dfwfullb) {
1744 for (i = 0; i < dh; i++) {
1745 for (j = 0; j < dnfullw; j++) {
1746 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1747 *(psfwfull + j + 1) >> srightshift,
1748 srightmask);
1749 *(pdfwfull + j) ^= sword;
1750 }
1751 pdfwfull += dwpl;
1752 psfwfull += swpl;
1753 }
1754 }
1755
1756 /* do the last partial word */
1757 if (dlwpartb) {
1758 for (i = 0; i < dh; i++) {
1759 sword = *pslwpart << sleftshift;
1760 if (slwaddb)
1761 sword = COMBINE_PARTIAL(sword,
1762 *(pslwpart + 1) >> srightshift,
1763 srightmask);
1764
1765 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1766 (sword ^ *pdlwpart), dlwmask);
1767 pdlwpart += dwpl;
1768 pslwpart += swpl;
1769 }
1770 }
1771 break;
1772 case (PIX_NOT(PIX_SRC) | PIX_DST):
1773 /* do the first partial word */
1774 if (dfwpartb) {
1775 for (i = 0; i < dh; i++)
1776 {
1777 if (sfwshiftdir == SHIFT_LEFT) {
1778 sword = *psfwpart << sleftshift;
1779 if (sfwaddb)
1780 sword = COMBINE_PARTIAL(sword,
1781 *(psfwpart + 1) >> srightshift,
1782 srightmask);
1783 } else { /* shift right */
1784 sword = *psfwpart >> srightshift;
1785 }
1786
1787 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1788 (~sword | *pdfwpart), dfwmask);
1789 pdfwpart += dwpl;
1790 psfwpart += swpl;
1791 }
1792 }
1793
1794 /* do the full words */
1795 if (dfwfullb) {
1796 for (i = 0; i < dh; i++) {
1797 for (j = 0; j < dnfullw; j++) {
1798 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1799 *(psfwfull + j + 1) >> srightshift,
1800 srightmask);
1801 *(pdfwfull + j) |= ~sword;
1802 }
1803 pdfwfull += dwpl;
1804 psfwfull += swpl;
1805 }
1806 }
1807
1808 /* do the last partial word */
1809 if (dlwpartb) {
1810 for (i = 0; i < dh; i++) {
1811 sword = *pslwpart << sleftshift;
1812 if (slwaddb)
1813 sword = COMBINE_PARTIAL(sword,
1814 *(pslwpart + 1) >> srightshift,
1815 srightmask);
1816
1817 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1818 (~sword | *pdlwpart), dlwmask);
1819 pdlwpart += dwpl;
1820 pslwpart += swpl;
1821 }
1822 }
1823 break;
1824 case (PIX_NOT(PIX_SRC) & PIX_DST):
1825 /* do the first partial word */
1826 if (dfwpartb) {
1827 for (i = 0; i < dh; i++)
1828 {
1829 if (sfwshiftdir == SHIFT_LEFT) {
1830 sword = *psfwpart << sleftshift;
1831 if (sfwaddb)
1832 sword = COMBINE_PARTIAL(sword,
1833 *(psfwpart + 1) >> srightshift,
1834 srightmask);
1835 } else { /* shift right */
1836 sword = *psfwpart >> srightshift;
1837 }
1838
1839 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1840 (~sword & *pdfwpart), dfwmask);
1841 pdfwpart += dwpl;
1842 psfwpart += swpl;
1843 }
1844 }
1845
1846 /* do the full words */
1847 if (dfwfullb) {
1848 for (i = 0; i < dh; i++) {
1849 for (j = 0; j < dnfullw; j++) {
1850 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1851 *(psfwfull + j + 1) >> srightshift,
1852 srightmask);
1853 *(pdfwfull + j) &= ~sword;
1854 }
1855 pdfwfull += dwpl;
1856 psfwfull += swpl;
1857 }
1858 }
1859
1860 /* do the last partial word */
1861 if (dlwpartb) {
1862 for (i = 0; i < dh; i++) {
1863 sword = *pslwpart << sleftshift;
1864 if (slwaddb)
1865 sword = COMBINE_PARTIAL(sword,
1866 *(pslwpart + 1) >> srightshift,
1867 srightmask);
1868
1869 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1870 (~sword & *pdlwpart), dlwmask);
1871 pdlwpart += dwpl;
1872 pslwpart += swpl;
1873 }
1874 }
1875 break;
1876 case (PIX_SRC | PIX_NOT(PIX_DST)):
1877 /* do the first partial word */
1878 if (dfwpartb) {
1879 for (i = 0; i < dh; i++)
1880 {
1881 if (sfwshiftdir == SHIFT_LEFT) {
1882 sword = *psfwpart << sleftshift;
1883 if (sfwaddb)
1884 sword = COMBINE_PARTIAL(sword,
1885 *(psfwpart + 1) >> srightshift,
1886 srightmask);
1887 } else { /* shift right */
1888 sword = *psfwpart >> srightshift;
1889 }
1890
1891 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1892 (sword | ~(*pdfwpart)), dfwmask);
1893 pdfwpart += dwpl;
1894 psfwpart += swpl;
1895 }
1896 }
1897
1898 /* do the full words */
1899 if (dfwfullb) {
1900 for (i = 0; i < dh; i++) {
1901 for (j = 0; j < dnfullw; j++) {
1902 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1903 *(psfwfull + j + 1) >> srightshift,
1904 srightmask);
1905 *(pdfwfull + j) = sword | ~(*(pdfwfull + j));
1906 }
1907 pdfwfull += dwpl;
1908 psfwfull += swpl;
1909 }
1910 }
1911
1912 /* do the last partial word */
1913 if (dlwpartb) {
1914 for (i = 0; i < dh; i++) {
1915 sword = *pslwpart << sleftshift;
1916 if (slwaddb)
1917 sword = COMBINE_PARTIAL(sword,
1918 *(pslwpart + 1) >> srightshift,
1919 srightmask);
1920
1921 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1922 (sword | ~(*pdlwpart)), dlwmask);
1923 pdlwpart += dwpl;
1924 pslwpart += swpl;
1925 }
1926 }
1927 break;
1928 case (PIX_SRC & PIX_NOT(PIX_DST)):
1929 /* do the first partial word */
1930 if (dfwpartb) {
1931 for (i = 0; i < dh; i++)
1932 {
1933 if (sfwshiftdir == SHIFT_LEFT) {
1934 sword = *psfwpart << sleftshift;
1935 if (sfwaddb)
1936 sword = COMBINE_PARTIAL(sword,
1937 *(psfwpart + 1) >> srightshift,
1938 srightmask);
1939 } else { /* shift right */
1940 sword = *psfwpart >> srightshift;
1941 }
1942
1943 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1944 (sword & ~(*pdfwpart)), dfwmask);
1945 pdfwpart += dwpl;
1946 psfwpart += swpl;
1947 }
1948 }
1949
1950 /* do the full words */
1951 if (dfwfullb) {
1952 for (i = 0; i < dh; i++) {
1953 for (j = 0; j < dnfullw; j++) {
1954 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
1955 *(psfwfull + j + 1) >> srightshift,
1956 srightmask);
1957 *(pdfwfull + j) = sword & ~(*(pdfwfull + j));
1958 }
1959 pdfwfull += dwpl;
1960 psfwfull += swpl;
1961 }
1962 }
1963
1964 /* do the last partial word */
1965 if (dlwpartb) {
1966 for (i = 0; i < dh; i++) {
1967 sword = *pslwpart << sleftshift;
1968 if (slwaddb)
1969 sword = COMBINE_PARTIAL(sword,
1970 *(pslwpart + 1) >> srightshift,
1971 srightmask);
1972
1973 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
1974 (sword & ~(*pdlwpart)), dlwmask);
1975 pdlwpart += dwpl;
1976 pslwpart += swpl;
1977 }
1978 }
1979 break;
1980 case (PIX_NOT(PIX_SRC | PIX_DST)):
1981 /* do the first partial word */
1982 if (dfwpartb) {
1983 for (i = 0; i < dh; i++)
1984 {
1985 if (sfwshiftdir == SHIFT_LEFT) {
1986 sword = *psfwpart << sleftshift;
1987 if (sfwaddb)
1988 sword = COMBINE_PARTIAL(sword,
1989 *(psfwpart + 1) >> srightshift,
1990 srightmask);
1991 } else { /* shift right */
1992 sword = *psfwpart >> srightshift;
1993 }
1994
1995 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
1996 ~(sword | *pdfwpart), dfwmask);
1997 pdfwpart += dwpl;
1998 psfwpart += swpl;
1999 }
2000 }
2001
2002 /* do the full words */
2003 if (dfwfullb) {
2004 for (i = 0; i < dh; i++) {
2005 for (j = 0; j < dnfullw; j++) {
2006 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
2007 *(psfwfull + j + 1) >> srightshift,
2008 srightmask);
2009 *(pdfwfull + j) = ~(sword | *(pdfwfull + j));
2010 }
2011 pdfwfull += dwpl;
2012 psfwfull += swpl;
2013 }
2014 }
2015
2016 /* do the last partial word */
2017 if (dlwpartb) {
2018 for (i = 0; i < dh; i++) {
2019 sword = *pslwpart << sleftshift;
2020 if (slwaddb)
2021 sword = COMBINE_PARTIAL(sword,
2022 *(pslwpart + 1) >> srightshift,
2023 srightmask);
2024
2025 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
2026 ~(sword | *pdlwpart), dlwmask);
2027 pdlwpart += dwpl;
2028 pslwpart += swpl;
2029 }
2030 }
2031 break;
2032 case (PIX_NOT(PIX_SRC & PIX_DST)):
2033 /* do the first partial word */
2034 if (dfwpartb) {
2035 for (i = 0; i < dh; i++)
2036 {
2037 if (sfwshiftdir == SHIFT_LEFT) {
2038 sword = *psfwpart << sleftshift;
2039 if (sfwaddb)
2040 sword = COMBINE_PARTIAL(sword,
2041 *(psfwpart + 1) >> srightshift,
2042 srightmask);
2043 } else { /* shift right */
2044 sword = *psfwpart >> srightshift;
2045 }
2046
2047 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
2048 ~(sword & *pdfwpart), dfwmask);
2049 pdfwpart += dwpl;
2050 psfwpart += swpl;
2051 }
2052 }
2053
2054 /* do the full words */
2055 if (dfwfullb) {
2056 for (i = 0; i < dh; i++) {
2057 for (j = 0; j < dnfullw; j++) {
2058 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
2059 *(psfwfull + j + 1) >> srightshift,
2060 srightmask);
2061 *(pdfwfull + j) = ~(sword & *(pdfwfull + j));
2062 }
2063 pdfwfull += dwpl;
2064 psfwfull += swpl;
2065 }
2066 }
2067
2068 /* do the last partial word */
2069 if (dlwpartb) {
2070 for (i = 0; i < dh; i++) {
2071 sword = *pslwpart << sleftshift;
2072 if (slwaddb)
2073 sword = COMBINE_PARTIAL(sword,
2074 *(pslwpart + 1) >> srightshift,
2075 srightmask);
2076
2077 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
2078 ~(sword & *pdlwpart), dlwmask);
2079 pdlwpart += dwpl;
2080 pslwpart += swpl;
2081 }
2082 }
2083 break;
2084 /* this is three cases: ~(s ^ d), ~s ^ d, s ^ ~d */
2085 case (PIX_NOT(PIX_SRC ^ PIX_DST)):
2086 /* do the first partial word */
2087 if (dfwpartb) {
2088 for (i = 0; i < dh; i++)
2089 {
2090 if (sfwshiftdir == SHIFT_LEFT) {
2091 sword = *psfwpart << sleftshift;
2092 if (sfwaddb)
2093 sword = COMBINE_PARTIAL(sword,
2094 *(psfwpart + 1) >> srightshift,
2095 srightmask);
2096 } else { /* shift right */
2097 sword = *psfwpart >> srightshift;
2098 }
2099
2100 *pdfwpart = COMBINE_PARTIAL(*pdfwpart,
2101 ~(sword ^ *pdfwpart), dfwmask);
2102 pdfwpart += dwpl;
2103 psfwpart += swpl;
2104 }
2105 }
2106
2107 /* do the full words */
2108 if (dfwfullb) {
2109 for (i = 0; i < dh; i++) {
2110 for (j = 0; j < dnfullw; j++) {
2111 sword = COMBINE_PARTIAL(*(psfwfull + j) << sleftshift,
2112 *(psfwfull + j + 1) >> srightshift,
2113 srightmask);
2114 *(pdfwfull + j) = ~(sword ^ *(pdfwfull + j));
2115 }
2116 pdfwfull += dwpl;
2117 psfwfull += swpl;
2118 }
2119 }
2120
2121 /* do the last partial word */
2122 if (dlwpartb) {
2123 for (i = 0; i < dh; i++) {
2124 sword = *pslwpart << sleftshift;
2125 if (slwaddb)
2126 sword = COMBINE_PARTIAL(sword,
2127 *(pslwpart + 1) >> srightshift,
2128 srightmask);
2129
2130 *pdlwpart = COMBINE_PARTIAL(*pdlwpart,
2131 ~(sword ^ *pdlwpart), dlwmask);
2132 pdlwpart += dwpl;
2133 pslwpart += swpl;
2134 }
2135 }
2136 break;
2137 default:
2138 lept_stderr("Operation %x invalid\n", op);
2139 }
2140 }
2141
2142
2143 /*--------------------------------------------------------------------*
2144 * Low level in-place full height vertical block transfer *
2145 *--------------------------------------------------------------------*/
2146 /*!
2147 * \brief rasteropVipLow()
2148 *
2149 * \param[in] data ptr to image data
2150 * \param[in] pixw width
2151 * \param[in] pixh height
2152 * \param[in] depth depth
2153 * \param[in] wpl wpl
2154 * \param[in] x x val of UL corner of rectangle
2155 * \param[in] w width of rectangle
2156 * \param[in] shift + shifts data downward in vertical column
2157 * \return 0 if OK; 1 on error.
2158 *
2159 * <pre>
2160 * Notes:
2161 * (1) This clears the pixels that are left exposed after the
2162 * translation. You can consider them as pixels that are
2163 * shifted in from outside the image. This can be later
2164 * overridden by the incolor parameter in higher-level functions
2165 * that call this. For example, for images with depth > 1,
2166 * these pixels are cleared to black; to be white they
2167 * must later be SET to white. See, e.g., pixRasteropVip().
2168 * (2) This function scales the width to accommodate any depth,
2169 * performs clipping, and then does the in-place rasterop.
2170 * </pre>
2171 */
2172 void
2173 rasteropVipLow(l_uint32 *data,
2174 l_int32 pixw,
2175 l_int32 pixh,
2176 l_int32 depth,
2177 l_int32 wpl,
2178 l_int32 x,
2179 l_int32 w,
2180 l_int32 shift)
2181 {
2182 l_int32 fwpartb; /* boolean (1, 0) if first word is partial */
2183 l_int32 fwpart2b; /* boolean (1, 0) if first word is doubly partial */
2184 l_uint32 fwmask; /* mask for first partial word */
2185 l_int32 fwbits; /* first word bits in ovrhang */
2186 l_uint32 *pdfwpart = NULL; /* ptr to first partial dest word */
2187 l_uint32 *psfwpart = NULL; /* ptr to first partial src word */
2188 l_int32 fwfullb; /* boolean (1, 0) if there exists a full word */
2189 l_int32 nfullw; /* number of full words */
2190 l_uint32 *pdfwfull = NULL; /* ptr to first full dest word */
2191 l_uint32 *psfwfull = NULL; /* ptr to first full src word */
2192 l_int32 lwpartb; /* boolean (1, 0) if last word is partial */
2193 l_uint32 lwmask; /* mask for last partial word */
2194 l_int32 lwbits; /* last word bits in ovrhang */
2195 l_uint32 *pdlwpart = NULL; /* ptr to last partial dest word */
2196 l_uint32 *pslwpart = NULL; /* ptr to last partial src word */
2197 l_int32 dirwpl; /* directed wpl (-wpl * sign(shift)) */
2198 l_int32 absshift; /* absolute value of shift; for use in iterator */
2199 l_int32 vlimit; /* vertical limit value for iterations */
2200 l_int32 i, j;
2201
2202
2203 /*--------------------------------------------------------*
2204 * Scale horizontal dimensions by depth *
2205 *--------------------------------------------------------*/
2206 if (depth != 1) {
2207 pixw *= depth;
2208 x *= depth;
2209 w *= depth;
2210 }
2211
2212
2213 /*--------------------------------------------------------*
2214 * Clip horizontally *
2215 *--------------------------------------------------------*/
2216 if (x < 0) {
2217 w += x; /* reduce w */
2218 x = 0; /* clip to x = 0 */
2219 }
2220 if (x >= pixw || w <= 0) /* no part of vertical slice is in the image */
2221 return;
2222
2223 if (x + w > pixw)
2224 w = pixw - x; /* clip to x + w = pixw */
2225
2226 /*--------------------------------------------------------*
2227 * Preliminary calculations *
2228 *--------------------------------------------------------*/
2229 /* is the first word partial? */
2230 if ((x & 31) == 0) { /* if not */
2231 fwpartb = 0;
2232 fwbits = 0;
2233 } else { /* if so */
2234 fwpartb = 1;
2235 fwbits = 32 - (x & 31);
2236 fwmask = rmask32[fwbits];
2237 if (shift >= 0) { /* go up from bottom */
2238 pdfwpart = data + wpl * (pixh - 1) + (x >> 5);
2239 psfwpart = data + wpl * (pixh - 1 - shift) + (x >> 5);
2240 } else { /* go down from top */
2241 pdfwpart = data + (x >> 5);
2242 psfwpart = data - wpl * shift + (x >> 5);
2243 }
2244 }
2245
2246 /* is the first word doubly partial? */
2247 if (w >= fwbits) { /* if not */
2248 fwpart2b = 0;
2249 } else { /* if so */
2250 fwpart2b = 1;
2251 fwmask &= lmask32[32 - fwbits + w];
2252 }
2253
2254 /* is there a full dest word? */
2255 if (fwpart2b == 1) { /* not */
2256 fwfullb = 0;
2257 nfullw = 0;
2258 } else {
2259 nfullw = (w - fwbits) >> 5;
2260 if (nfullw == 0) { /* if not */
2261 fwfullb = 0;
2262 } else { /* if so */
2263 fwfullb = 1;
2264 if (fwpartb) {
2265 pdfwfull = pdfwpart + 1;
2266 psfwfull = psfwpart + 1;
2267 } else if (shift >= 0) { /* go up from bottom */
2268 pdfwfull = data + wpl * (pixh - 1) + (x >> 5);
2269 psfwfull = data + wpl * (pixh - 1 - shift) + (x >> 5);
2270 } else { /* go down from top */
2271 pdfwfull = data + (x >> 5);
2272 psfwfull = data - wpl * shift + (x >> 5);
2273 }
2274 }
2275 }
2276
2277 /* is the last word partial? */
2278 lwbits = (x + w) & 31;
2279 if (fwpart2b == 1 || lwbits == 0) { /* if not */
2280 lwpartb = 0;
2281 } else {
2282 lwpartb = 1;
2283 lwmask = lmask32[lwbits];
2284 if (fwpartb) {
2285 pdlwpart = pdfwpart + 1 + nfullw;
2286 pslwpart = psfwpart + 1 + nfullw;
2287 } else if (shift >= 0) { /* go up from bottom */
2288 pdlwpart = data + wpl * (pixh - 1) + (x >> 5) + nfullw;
2289 pslwpart = data + wpl * (pixh - 1 - shift) + (x >> 5) + nfullw;
2290 } else { /* go down from top */
2291 pdlwpart = data + (x >> 5) + nfullw;
2292 pslwpart = data - wpl * shift + (x >> 5) + nfullw;
2293 }
2294 }
2295
2296 /* determine the direction of flow from the shift
2297 * If the shift >= 0, data flows downard from src
2298 * to dest, starting at the bottom and working up.
2299 * If shift < 0, data flows upward from src to
2300 * dest, starting at the top and working down. */
2301 dirwpl = (shift >= 0) ? -wpl : wpl;
2302 absshift = L_ABS(shift);
2303 vlimit = L_MAX(0, pixh - absshift);
2304
2305
2306 /*--------------------------------------------------------*
2307 * Now we're ready to do the ops *
2308 *--------------------------------------------------------*/
2309
2310 /* Do the first partial word */
2311 if (fwpartb) {
2312 for (i = 0; i < vlimit; i++) {
2313 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, *psfwpart, fwmask);
2314 pdfwpart += dirwpl;
2315 psfwpart += dirwpl;
2316 }
2317
2318 /* Clear the incoming pixels */
2319 for (i = vlimit; i < pixh; i++) {
2320 *pdfwpart = COMBINE_PARTIAL(*pdfwpart, 0x0, fwmask);
2321 pdfwpart += dirwpl;
2322 }
2323 }
2324
2325 /* Do the full words */
2326 if (fwfullb) {
2327 for (i = 0; i < vlimit; i++) {
2328 for (j = 0; j < nfullw; j++)
2329 *(pdfwfull + j) = *(psfwfull + j);
2330 pdfwfull += dirwpl;
2331 psfwfull += dirwpl;
2332 }
2333
2334 /* Clear the incoming pixels */
2335 for (i = vlimit; i < pixh; i++) {
2336 for (j = 0; j < nfullw; j++)
2337 *(pdfwfull + j) = 0x0;
2338 pdfwfull += dirwpl;
2339 }
2340 }
2341
2342 /* Do the last partial word */
2343 if (lwpartb) {
2344 for (i = 0; i < vlimit; i++) {
2345 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, *pslwpart, lwmask);
2346 pdlwpart += dirwpl;
2347 pslwpart += dirwpl;
2348 }
2349
2350 /* Clear the incoming pixels */
2351 for (i = vlimit; i < pixh; i++) {
2352 *pdlwpart = COMBINE_PARTIAL(*pdlwpart, 0x0, lwmask);
2353 pdlwpart += dirwpl;
2354 }
2355 }
2356 }
2357
2358
2359
2360 /*--------------------------------------------------------------------*
2361 * Low level in-place full width horizontal block transfer *
2362 *--------------------------------------------------------------------*/
2363 /*!
2364 * \brief rasteropHipLow()
2365 *
2366 * \param[in] data ptr to image data
2367 * \param[in] pixh height
2368 * \param[in] depth depth
2369 * \param[in] wpl wpl
2370 * \param[in] y y val of UL corner of rectangle
2371 * \param[in] h height of rectangle
2372 * \param[in] shift + shifts data to the left in a horizontal column
2373 * \return 0 if OK; 1 on error.
2374 *
2375 * <pre>
2376 * Notes:
2377 * (1) This clears the pixels that are left exposed after the rasterop.
2378 * Therefore, for Pix with depth > 1, these pixels become black,
2379 * and must be subsequently SET if they are to be white.
2380 * For example, see pixRasteropHip().
2381 * (2) This function performs clipping and calls shiftDataHorizontalLow()
2382 * to do the in-place rasterop on each line.
2383 * </pre>
2384 */
2385 void
2386 rasteropHipLow(l_uint32 *data,
2387 l_int32 pixh,
2388 l_int32 depth,
2389 l_int32 wpl,
2390 l_int32 y,
2391 l_int32 h,
2392 l_int32 shift)
2393 {
2394 l_int32 i;
2395 l_uint32 *line;
2396
2397 /* clip band if necessary */
2398 if (y < 0) {
2399 h += y; /* reduce h */
2400 y = 0; /* clip to y = 0 */
2401 }
2402 if (h <= 0 || y > pixh) /* no part of horizontal slice is in the image */
2403 return;
2404
2405 if (y + h > pixh)
2406 h = pixh - y; /* clip to y + h = pixh */
2407
2408 for (i = y; i < y + h; i++) {
2409 line = data + i * wpl;
2410 shiftDataHorizontalLow(line, wpl, line, wpl, shift * depth);
2411 }
2412 }
2413
2414
2415 /*!
2416 * \brief shiftDataHorizontalLow()
2417 *
2418 * \param[in] datad ptr to beginning of dest line
2419 * \param[in] wpld wpl of dest
2420 * \param[in] datas ptr to beginning of src line
2421 * \param[in] wpls wpl of src
2422 * \param[in] shift horizontal shift of block; >0 is to right
2423 * \return void
2424 *
2425 * <pre>
2426 * Notes:
2427 * (1) This can also be used for in-place operation; see, e.g.,
2428 * rasteropHipLow().
2429 * (2) We are clearing the pixels that are shifted in from
2430 * outside the image. This can be overridden by the
2431 * incolor parameter in higher-level functions that call this.
2432 * </pre>
2433 */
2434 static void
2435 shiftDataHorizontalLow(l_uint32 *datad,
2436 l_int32 wpld,
2437 l_uint32 *datas,
2438 l_int32 wpls,
2439 l_int32 shift)
2440 {
2441 l_int32 j, firstdw, wpl, rshift, lshift;
2442 l_uint32 *lined, *lines;
2443
2444 lined = datad;
2445 lines = datas;
2446
2447 if (shift >= 0) { /* src shift to right; data flows to
2448 * right, starting at right edge and
2449 * progressing leftward. */
2450 firstdw = shift / 32;
2451 wpl = L_MIN(wpls, wpld - firstdw);
2452 lined += firstdw + wpl - 1;
2453 lines += wpl - 1;
2454 rshift = shift & 31;
2455 if (rshift == 0) {
2456 for (j = 0; j < wpl; j++)
2457 *lined-- = *lines--;
2458
2459 /* clear out the rest to the left edge */
2460 for (j = 0; j < firstdw; j++)
2461 *lined-- = 0;
2462 } else {
2463 lshift = 32 - rshift;
2464 for (j = 1; j < wpl; j++) {
2465 *lined-- = *(lines - 1) << lshift | *lines >> rshift;
2466 lines--;
2467 }
2468 *lined = *lines >> rshift; /* partial first */
2469
2470 /* clear out the rest to the left edge */
2471 *lined &= ~lmask32[rshift];
2472 lined--;
2473 for (j = 0; j < firstdw; j++)
2474 *lined-- = 0;
2475 }
2476 } else { /* src shift to left; data flows to left, starting
2477 * at left edge and progressing rightward. */
2478 firstdw = (-shift) / 32;
2479 wpl = L_MIN(wpls - firstdw, wpld);
2480 lines += firstdw;
2481 lshift = (-shift) & 31;
2482 if (lshift == 0) {
2483 for (j = 0; j < wpl; j++)
2484 *lined++ = *lines++;
2485
2486 /* clear out the rest to the right edge */
2487 for (j = 0; j < firstdw; j++)
2488 *lined++ = 0;
2489 } else {
2490 rshift = 32 - lshift;
2491 for (j = 1; j < wpl; j++) {
2492 *lined++ = *lines << lshift | *(lines + 1) >> rshift;
2493 lines++;
2494 }
2495 *lined = *lines << lshift; /* partial last */
2496
2497 /* clear out the rest to the right edge */
2498 /* first clear the lshift pixels of this partial word */
2499 *lined &= ~rmask32[lshift];
2500 lined++;
2501 /* then the remaining words to the right edge */
2502 for (j = 0; j < firstdw; j++)
2503 *lined++ = 0;
2504 }
2505 }
2506 }