Coverage Report

Created: 2026-05-24 06:25

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