Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gdevm24.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* 24-bit-per-pixel "memory" (stored bitmap) device */
17
#include "memory_.h"
18
#include "gx.h"
19
#include "gxdevice.h"
20
#include "gxdevmem.h"   /* semi-public definitions */
21
#include "gdevmem.h"    /* private definitions */
22
23
#define mem_true24_strip_copy_rop2 mem_gray8_rgb24_strip_copy_rop2
24
25
/*
26
 * Define whether to use the library's memset.
27
 */
28
#define USE_MEMSET
29
30
/*
31
 * Define whether to use memcpy for very wide fills.
32
 */
33
/*#define USE_MEMCPY*/
34
35
/* Define debugging statistics. */
36
/* #define COLLECT_STATS_MEM24 */
37
38
#ifdef COLLECT_STATS_MEM24
39
struct stats_mem24_s {
40
    long
41
        fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
42
        fprevc[257];
43
    double ftotal;
44
} stats_mem24;
45
static int prev_count = 0;
46
static uint prev_colors[256];
47
# define INCR(v) (++(stats_mem24.v))
48
#else
49
116M
# define INCR(v) DO_NOTHING
50
#endif
51
52
/* ================ Standard (byte-oriented) device ================ */
53
54
#undef chunk
55
#define chunk byte
56
57
/* Procedures */
58
declare_mem_procs(mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle);
59
static dev_proc_copy_alpha(mem_true24_copy_alpha);
60
61
/* The device descriptor. */
62
const gx_device_memory mem_true24_device =
63
    mem_device("image24", 24, 0, mem_dev_initialize_device_procs);
64
65
const gdev_mem_functions gdev_mem_fns_24 =
66
{
67
    gx_default_rgb_map_rgb_color,
68
    gx_default_rgb_map_color_rgb,
69
    mem_true24_fill_rectangle,
70
    mem_true24_copy_mono,
71
    mem_true24_copy_color,
72
    mem_true24_copy_alpha,
73
    gx_default_strip_tile_rectangle,
74
    mem_true24_strip_copy_rop2,
75
    mem_get_bits_rectangle
76
};
77
78
/* Convert x coordinate to byte offset in scan line. */
79
#undef x_to_byte
80
45.6M
#define x_to_byte(x) ((x) * 3)
81
82
/* Unpack a color into its bytes. */
83
#define declare_unpack_color(r, g, b, color)\
84
57.1M
        byte r = (byte)(color >> 16);\
85
57.1M
        byte g = (byte)((uint)color >> 8);\
86
57.1M
        byte b = (byte)color
87
/* Put a 24-bit color into the bitmap. */
88
#define put3(ptr, r, g, b)\
89
99.6M
        (ptr)[0] = r, (ptr)[1] = g, (ptr)[2] = b
90
/* Put 4 bytes of color into the bitmap. */
91
#define putw(ptr, wxyz)\
92
1.21G
        *(bits32 *)(ptr) = (wxyz)
93
/* Load the 3-word 24-bit-color cache. */
94
/* Free variables: [m]dev, rgbr, gbrg, brgb. */
95
#if ARCH_IS_BIG_ENDIAN
96
#  define set_color24_cache(crgb, r, g, b)\
97
        mdev->color24.rgbr = rgbr = ((bits32)(crgb) << 8) | (r),\
98
        mdev->color24.gbrg = gbrg = (rgbr << 8) | (g),\
99
        mdev->color24.brgb = brgb = (gbrg << 8) | (b),\
100
        mdev->color24.rgb = (crgb)
101
#else
102
#  define set_color24_cache(crgb, r, g, b)\
103
5.73M
        mdev->color24.rgbr = rgbr =\
104
5.73M
                ((bits32)(r) << 24) | ((bits32)(b) << 16) |\
105
5.73M
                ((bits16)(g) << 8) | (r),\
106
5.73M
        mdev->color24.brgb = brgb = (rgbr << 8) | (b),\
107
5.73M
        mdev->color24.gbrg = gbrg = (brgb << 8) | (g),\
108
5.73M
        mdev->color24.rgb = (crgb)
109
#endif
110
111
/* Fill a rectangle with a color. */
112
static int
113
mem_true24_fill_rectangle(gx_device * dev,
114
                          int x, int y, int w, int h, gx_color_index color)
115
56.2M
{
116
56.2M
    gx_device_memory * const mdev = (gx_device_memory *)dev;
117
56.2M
    declare_unpack_color(r, g, b, color);
118
56.2M
    declare_scan_ptr(dest);
119
120
56.2M
    if_debug4m('b', dev->memory,
121
56.2M
               "[b]device y=%d h=%d x=%d w=%d\n", y + mdev->band_y, h, x, w);
122
    /*
123
     * In order to avoid testing w > 0 and h > 0 twice, we defer
124
     * executing setup_rect, and use fit_fill_xywh instead of
125
     * fit_fill.
126
     */
127
56.2M
    fit_fill_xywh(dev, x, y, w, h);
128
56.2M
    INCR(fill);
129
#ifdef COLLECT_STATS_MEM24
130
    stats_mem24.ftotal += w;
131
#endif
132
56.2M
    if (w >= 5) {
133
10.5M
        if (h <= 0)
134
293k
            return 0;
135
10.5M
        INCR(fwide);
136
10.2M
        setup_rect(dest);
137
10.2M
        if (r == g && r == b) {
138
#ifndef USE_MEMSET
139
            /* We think we can do better than the library's memset.... */
140
            int bcntm7 = w * 3 - 7;
141
            register bits32 cword = color | (color << 24);
142
143
            INCR(fgray[min(w, 100)]);
144
            while (h-- > 0) {
145
                register byte *pptr = dest;
146
                byte *limit = pptr + bcntm7;
147
148
                /* We want to store full words, but we have to */
149
                /* guarantee that they are word-aligned. */
150
                switch (x & 3) {
151
                    case 3:
152
                        *pptr++ = (byte) cword;
153
                    case 2:
154
                        *pptr++ = (byte) cword;
155
                    case 1:
156
                        *pptr++ = (byte) cword;
157
                    case 0:;
158
                }
159
                /* Even with w = 5, we always store at least */
160
                /* 3 full words, regardless of the starting x. */
161
                *(bits32 *) pptr =
162
                    ((bits32 *) pptr)[1] =
163
                    ((bits32 *) pptr)[2] = cword;
164
                pptr += 12;
165
                while (pptr < limit) {
166
                    *(bits32 *) pptr =
167
                        ((bits32 *) pptr)[1] = cword;
168
                    pptr += 8;
169
                }
170
                switch ((int)(pptr - limit)) {
171
                    case 0:
172
                        pptr[6] = (byte) cword;
173
                    case 1:
174
                        pptr[5] = (byte) cword;
175
                    case 2:
176
                        pptr[4] = (byte) cword;
177
                    case 3:
178
                        *(bits32 *) pptr = cword;
179
                        break;
180
                    case 4:
181
                        pptr[2] = (byte) cword;
182
                    case 5:
183
                        pptr[1] = (byte) cword;
184
                    case 6:
185
                        pptr[0] = (byte) cword;
186
                    case 7:;
187
                }
188
                inc_ptr(dest, draster);
189
            }
190
#else
191
3.75M
            int bcnt = w * 3;
192
193
3.75M
            INCR(fgray[min(w, 100)]);
194
39.4M
            while (h-- > 0) {
195
35.6M
                memset(dest, r, bcnt);
196
35.6M
                inc_ptr(dest, draster);
197
35.6M
            }
198
3.75M
#endif
199
6.49M
        } else {
200
6.49M
            int x3 = -x & 3, ww = w - x3; /* we know ww >= 2 */
201
6.49M
            bits32 rgbr, gbrg, brgb;
202
203
6.49M
            if (mdev->color24.rgb == color) {
204
755k
                rgbr = mdev->color24.rgbr;
205
755k
                gbrg = mdev->color24.gbrg;
206
755k
                brgb = mdev->color24.brgb;
207
5.73M
            } else {
208
5.73M
                INCR(fsetc);
209
5.73M
                set_color24_cache(color, r, g, b);
210
5.73M
            }
211
#ifdef COLLECT_STATS_MEM24
212
            {
213
                int ci;
214
                for (ci = 0; ci < prev_count; ++ci)
215
                    if (prev_colors[ci] == color)
216
                        break;
217
                INCR(fprevc[ci]);
218
                if (ci == prev_count) {
219
                    if (ci < countof(prev_colors))
220
                        ++prev_count;
221
                    else
222
                        --ci;
223
                }
224
                if (ci)
225
                    memmove(&prev_colors[1], &prev_colors[0],
226
                            ci * sizeof(prev_colors[0]));
227
                prev_colors[0] = color;
228
            }
229
#endif
230
6.49M
            INCR(fcolor[min(w, 100)]);
231
14.7M
            while (h-- > 0) {
232
8.23M
                register byte *pptr = dest;
233
8.23M
                int w1 = ww;
234
235
8.23M
                switch (x3) {
236
1.88M
                    case 1:
237
1.88M
                        put3(pptr, r, g, b);
238
1.88M
                        pptr += 3;
239
1.88M
                        break;
240
1.71M
                    case 2:
241
1.71M
                        pptr[0] = r;
242
1.71M
                        pptr[1] = g;
243
1.71M
                        putw(pptr + 2, brgb);
244
1.71M
                        pptr += 6;
245
1.71M
                        break;
246
2.07M
                    case 3:
247
2.07M
                        pptr[0] = r;
248
2.07M
                        putw(pptr + 1, gbrg);
249
2.07M
                        putw(pptr + 5, brgb);
250
2.07M
                        pptr += 9;
251
2.07M
                        break;
252
2.56M
                    case 0:
253
2.56M
                        ;
254
8.23M
                }
255
#ifdef USE_MEMCPY
256
                /*
257
                 * For very wide fills, it's most efficient to fill a few
258
                 * pixels and then use memcpy to fill the rest.
259
                 */
260
                if (w1 > 16) {
261
#define PUTW4(ptr, w)\
262
  BEGIN\
263
    putw(ptr, w); putw((ptr)+12, w); putw((ptr)+24, w); putw((ptr)+36, w);\
264
  END
265
                    PUTW4(pptr, rgbr);
266
                    PUTW4(pptr + 4, gbrg);
267
                    PUTW4(pptr + 8, brgb);
268
#undef PUTW4
269
                    if (w1 > 64) {
270
                        memcpy(pptr + 48, pptr, 48);
271
                        memcpy(pptr + 96, pptr, 96);
272
                        for (pptr += 192; (w1 -= 64) >= 64; pptr += 192)
273
                            memcpy(pptr, pptr - 192, 192);
274
                    } else
275
                        pptr += 48;
276
                    for (; (w1 -= 16) >= 16; pptr += 48)
277
                        memcpy(pptr, pptr - 48, 48);
278
                }
279
#endif
280
410M
                while (w1 >= 4) {
281
401M
                    putw(pptr, rgbr);
282
401M
                    putw(pptr + 4, gbrg);
283
401M
                    putw(pptr + 8, brgb);
284
401M
                    pptr += 12;
285
401M
                    w1 -= 4;
286
401M
                }
287
8.23M
                switch (w1) {
288
1.74M
                    case 1:
289
1.74M
                        put3(pptr, r, g, b);
290
1.74M
                        break;
291
1.72M
                    case 2:
292
1.72M
                        putw(pptr, rgbr);
293
1.72M
                        pptr[4] = g;
294
1.72M
                        pptr[5] = b;
295
1.72M
                        break;
296
2.53M
                    case 3:
297
2.53M
                        putw(pptr, rgbr);
298
2.53M
                        putw(pptr + 4, gbrg);
299
2.53M
                        pptr[8] = b;
300
2.53M
                        break;
301
2.23M
                    case 0:
302
2.23M
                        ;
303
8.23M
                }
304
8.23M
                inc_ptr(dest, draster);
305
8.23M
            }
306
6.49M
        }
307
45.6M
    } else if (h > 0) {   /* w < 5 */
308
33.9M
        INCR(fnarrow[max(w, 0)]);
309
33.9M
        setup_rect(dest);
310
33.9M
        switch (w) {
311
1.77M
            case 4:
312
2.38M
                do {
313
2.38M
                    dest[9] = dest[6] = dest[3] = dest[0] = r;
314
2.38M
                    dest[10] = dest[7] = dest[4] = dest[1] = g;
315
2.38M
                    dest[11] = dest[8] = dest[5] = dest[2] = b;
316
2.38M
                    inc_ptr(dest, draster);
317
2.38M
                }
318
2.38M
                while (--h);
319
1.77M
                break;
320
3.29M
            case 3:
321
5.91M
                do {
322
5.91M
                    dest[6] = dest[3] = dest[0] = r;
323
5.91M
                    dest[7] = dest[4] = dest[1] = g;
324
5.91M
                    dest[8] = dest[5] = dest[2] = b;
325
5.91M
                    inc_ptr(dest, draster);
326
5.91M
                }
327
5.91M
                while (--h);
328
3.29M
                break;
329
4.33M
            case 2:
330
6.21M
                do {
331
6.21M
                    dest[3] = dest[0] = r;
332
6.21M
                    dest[4] = dest[1] = g;
333
6.21M
                    dest[5] = dest[2] = b;
334
6.21M
                    inc_ptr(dest, draster);
335
6.21M
                }
336
6.21M
                while (--h);
337
4.33M
                break;
338
23.2M
            case 1:
339
25.1M
                do {
340
25.1M
                    dest[0] = r, dest[1] = g, dest[2] = b;
341
25.1M
                    inc_ptr(dest, draster);
342
25.1M
                }
343
25.1M
                while (--h);
344
23.2M
                break;
345
65.3k
            case 0:
346
1.27M
            default:
347
1.27M
                ;
348
33.9M
        }
349
33.9M
    }
350
55.9M
    return 0;
351
56.2M
}
352
353
/* Copy a monochrome bitmap. */
354
static int
355
mem_true24_copy_mono(gx_device * dev,
356
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
357
        int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
358
872k
{
359
872k
    gx_device_memory * const mdev = (gx_device_memory *)dev;
360
872k
    const byte *line;
361
872k
    int sbit;
362
872k
    int first_bit;
363
364
872k
    declare_scan_ptr(dest);
365
366
872k
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
367
869k
    setup_rect(dest);
368
869k
    line = base + (sourcex >> 3);
369
869k
    sbit = sourcex & 7;
370
869k
    first_bit = 0x80 >> sbit;
371
869k
    if (zero != gx_no_color_index) { /* Loop for halftones or inverted masks */
372
        /* (never used). */
373
37.9k
        declare_unpack_color(r0, g0, b0, zero);
374
37.9k
        declare_unpack_color(r1, g1, b1, one);
375
75.8k
        while (h-- > 0) {
376
37.9k
            register byte *pptr = dest;
377
37.9k
            const byte *sptr = line;
378
37.9k
            register int sbyte = *sptr++;
379
37.9k
            register int bit = first_bit;
380
37.9k
            int count = w;
381
382
26.6M
            do {
383
26.6M
                if (sbyte & bit) {
384
8.93M
                    if (one != gx_no_color_index) {
385
6.98M
                        put3(pptr, r1, g1, b1);
386
6.98M
                    }
387
17.7M
                } else {
388
17.7M
                    put3(pptr, r0, g0, b0);
389
17.7M
                }
390
391
26.6M
                pptr += 3;
392
26.6M
                count--;
393
394
26.6M
                if (count == 0)
395
37.9k
                    break;
396
397
26.6M
                if ((bit >>= 1) == 0) {
398
3.31M
                    bit = 0x80;
399
3.31M
                    sbyte = *sptr++;
400
3.31M
                }
401
402
26.6M
            } while (true);
403
404
0
            line += sraster;
405
37.9k
            inc_ptr(dest, draster);
406
37.9k
        }
407
831k
    } else if (one != gx_no_color_index) { /* Loop for character and pattern masks. */
408
        /* This is used heavily. */
409
831k
        declare_unpack_color(r1, g1, b1, one);
410
831k
        int first_mask = first_bit << 1;
411
831k
        int first_count, first_skip;
412
413
831k
        if (sbit + w > 8)
414
644k
            first_mask -= 1,
415
644k
                first_count = 8 - sbit;
416
187k
        else
417
187k
            first_mask -= first_mask >> w,
418
187k
                first_count = w;
419
831k
        first_skip = first_count * 3;
420
10.8M
        while (h-- > 0) {
421
10.0M
            register byte *pptr = dest;
422
10.0M
            const byte *sptr = line;
423
10.0M
            register int sbyte = *sptr++ & first_mask;
424
10.0M
            int count = w - first_count;
425
426
10.0M
            if (sbyte) {
427
6.88M
                register int bit = first_bit;
428
429
51.8M
                do {
430
51.8M
                    if (sbyte & bit)
431
19.0M
                        put3(pptr, r1, g1, b1);
432
51.8M
                    pptr += 3;
433
51.8M
                }
434
51.8M
                while ((bit >>= 1) & first_mask);
435
6.88M
            } else
436
3.16M
                pptr += first_skip;
437
24.7M
            while (count >= 8) {
438
14.6M
                sbyte = *sptr++;
439
14.6M
                if (sbyte & 0xf0) {
440
6.64M
                    if (sbyte & 0x80)
441
5.35M
                        put3(pptr, r1, g1, b1);
442
6.64M
                    if (sbyte & 0x40)
443
5.19M
                        put3(pptr + 3, r1, g1, b1);
444
6.64M
                    if (sbyte & 0x20)
445
5.03M
                        put3(pptr + 6, r1, g1, b1);
446
6.64M
                    if (sbyte & 0x10)
447
4.99M
                        put3(pptr + 9, r1, g1, b1);
448
6.64M
                }
449
14.6M
                if (sbyte & 0xf) {
450
6.79M
                    if (sbyte & 8)
451
5.01M
                        put3(pptr + 12, r1, g1, b1);
452
6.79M
                    if (sbyte & 4)
453
5.16M
                        put3(pptr + 15, r1, g1, b1);
454
6.79M
                    if (sbyte & 2)
455
5.30M
                        put3(pptr + 18, r1, g1, b1);
456
6.79M
                    if (sbyte & 1)
457
5.21M
                        put3(pptr + 21, r1, g1, b1);
458
6.79M
                }
459
14.6M
                pptr += 24;
460
14.6M
                count -= 8;
461
14.6M
            }
462
10.0M
            if (count > 0) {
463
7.05M
                register int bit = 0x80;
464
465
7.05M
                sbyte = *sptr++;
466
27.1M
                do {
467
27.1M
                    if (sbyte & bit)
468
11.0M
                        put3(pptr, r1, g1, b1);
469
27.1M
                    pptr += 3;
470
27.1M
                    bit >>= 1;
471
27.1M
                }
472
27.1M
                while (--count > 0);
473
7.05M
            }
474
10.0M
            line += sraster;
475
10.0M
            inc_ptr(dest, draster);
476
10.0M
        }
477
831k
    }
478
869k
    return 0;
479
872k
}
480
481
/* Copy a color bitmap. */
482
static int
483
mem_true24_copy_color(gx_device * dev,
484
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
485
                      int x, int y, int w, int h)
486
359k
{
487
359k
    gx_device_memory * const mdev = (gx_device_memory *)dev;
488
489
359k
    if_debug1m('w', dev->memory, "[w]device y=%d:\n",
490
359k
               y + mdev->band_y); /* See siscale.c about 'w'. */
491
359k
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
492
195k
    mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
493
195k
    return 0;
494
359k
}
495
496
/* Copy an alpha map. */
497
static int
498
mem_true24_copy_alpha(gx_device * dev, const byte * base, int sourcex,
499
                   int sraster, gx_bitmap_id id, int x, int y, int w, int h,
500
                      gx_color_index color, int depth)
501
0
{
502
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
503
0
    const byte *line;
504
505
0
    declare_scan_ptr(dest);
506
0
    declare_unpack_color(r, g, b, color);
507
508
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
509
0
    setup_rect(dest);
510
0
    line = base;
511
0
    while (h-- > 0) {
512
0
        register byte *pptr = dest;
513
0
        int sx;
514
515
0
        for (sx = sourcex; sx < sourcex + w; ++sx, pptr += 3) {
516
0
            int alpha2, alpha;
517
518
0
            switch(depth)
519
0
            {
520
0
            case 2: /* map 0 - 3 to 0 - 255 */
521
0
                alpha =
522
0
                    ((line[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 85;
523
0
                break;
524
0
            case 4:
525
0
                alpha2 = line[sx >> 1];
526
0
                alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4) * 17;
527
0
                break;
528
0
            case 8:
529
0
                alpha = line[sx];
530
0
                break;
531
0
            default:
532
0
                return_error(gs_error_rangecheck);
533
0
            }
534
0
            if (alpha == 255) { /* Just write the new color. */
535
0
                put3(pptr, r, g, b);
536
0
            } else if (alpha != 0) { /* Blend RGB values. */
537
0
                alpha += alpha>>7;
538
0
#define make_shade(old, clr, alpha) \
539
0
  ((((old)<<8) + ((int)(clr) - (int)(old)) * (alpha))>>8)
540
0
                pptr[0] = make_shade(pptr[0], r, alpha);
541
0
                pptr[1] = make_shade(pptr[1], g, alpha);
542
0
                pptr[2] = make_shade(pptr[2], b, alpha);
543
0
#undef make_shade
544
0
            }
545
0
        }
546
0
        line += sraster;
547
0
        inc_ptr(dest, draster);
548
0
    }
549
0
    return 0;
550
0
}
551
552
/* ================ "Word"-oriented device ================ */
553
554
/* Note that on a big-endian machine, this is the same as the */
555
/* standard byte-oriented-device. */
556
557
#if !ARCH_IS_BIG_ENDIAN
558
559
/* Procedures */
560
declare_mem_procs(mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle);
561
562
/* Here is the device descriptor. */
563
const gx_device_memory mem_true24_word_device =
564
    mem_device("image24w", 24, 0, mem_word_dev_initialize_device_procs);
565
566
const gdev_mem_functions gdev_mem_fns_24w =
567
{
568
    gx_default_rgb_map_rgb_color,
569
    gx_default_rgb_map_color_rgb,
570
    mem24_word_fill_rectangle,
571
    mem24_word_copy_mono,
572
    mem24_word_copy_color,
573
    gx_default_copy_alpha,
574
    gx_default_strip_tile_rectangle,
575
    gx_no_strip_copy_rop2,
576
    mem_word_get_bits_rectangle
577
};
578
579
/* Fill a rectangle with a color. */
580
static int
581
mem24_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
582
                          gx_color_index color)
583
0
{
584
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
585
0
    byte *base;
586
0
    size_t raster;
587
588
0
    fit_fill(dev, x, y, w, h);
589
0
    base = scan_line_base(mdev, y);
590
0
    raster = mdev->raster;
591
0
    mem_swap_byte_rect(base, raster, x * 24, w * 24, h, true);
592
0
    mem_true24_fill_rectangle(dev, x, y, w, h, color);
593
0
    mem_swap_byte_rect(base, raster, x * 24, w * 24, h, false);
594
0
    return 0;
595
0
}
596
597
/* Copy a bitmap. */
598
static int
599
mem24_word_copy_mono(gx_device * dev,
600
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
601
        int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
602
0
{
603
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
604
0
    byte *row;
605
0
    size_t raster;
606
0
    bool store;
607
608
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
609
0
    row = scan_line_base(mdev, y);
610
0
    raster = mdev->raster;
611
0
    store = (zero != gx_no_color_index && one != gx_no_color_index);
612
0
    mem_swap_byte_rect(row, raster, x * 24, w * 24, h, store);
613
0
    mem_true24_copy_mono(dev, base, sourcex, sraster, id,
614
0
                         x, y, w, h, zero, one);
615
0
    mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false);
616
0
    return 0;
617
0
}
618
619
/* Copy a color bitmap. */
620
static int
621
mem24_word_copy_color(gx_device * dev,
622
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
623
                      int x, int y, int w, int h)
624
0
{
625
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
626
0
    byte *row;
627
0
    size_t raster;
628
629
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
630
0
    row = scan_line_base(mdev, y);
631
0
    raster = mdev->raster;
632
0
    mem_swap_byte_rect(row, raster, x * 24, w * 24, h, true);
633
0
    bytes_copy_rectangle(row + x * 3, raster, base + sourcex * 3, sraster,
634
0
                         w * 3, h);
635
0
    mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false);
636
0
    return 0;
637
0
}
638
639
#endif /* !ARCH_IS_BIG_ENDIAN */