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