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