Coverage Report

Created: 2025-06-10 07:15

/src/ghostpdl/base/gdevm40.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
/* 40-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 debugging statistics. */
24
/* #define COLLECT_STATS_MEM40 */
25
26
#ifdef COLLECT_STATS_MEM40
27
struct stats_mem40_s {
28
    long
29
        fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5],
30
        fprevc[257];
31
    double ftotal;
32
} stats_mem40;
33
static int prev_count = 0;
34
static gx_color_index prev_colors[256];
35
# define INCR(v) (++(stats_mem40.v))
36
#else
37
0
# define INCR(v) DO_NOTHING
38
#endif
39
40
/* ================ Standard (byte-oriented) device ================ */
41
42
#undef chunk
43
#define chunk byte
44
0
#define PIXEL_SIZE 5
45
46
/* Procedures */
47
declare_mem_procs(mem_true40_copy_mono, mem_true40_copy_color, mem_true40_fill_rectangle);
48
49
/* The device descriptor. */
50
const gx_device_memory mem_true40_device =
51
    mem_device("image40", 40, 0, mem_dev_initialize_device_procs);
52
53
const gdev_mem_functions gdev_mem_fns_40 =
54
{
55
    gx_default_rgb_map_rgb_color,
56
    gx_default_rgb_map_color_rgb,
57
    mem_true40_fill_rectangle,
58
    mem_true40_copy_mono,
59
    mem_true40_copy_color,
60
    gx_default_copy_alpha,
61
    gx_default_strip_tile_rectangle,
62
    mem_default_strip_copy_rop2,
63
    mem_get_bits_rectangle
64
};
65
66
/* Convert x coordinate to byte offset in scan line. */
67
#undef x_to_byte
68
0
#define x_to_byte(x) ((x) * PIXEL_SIZE)
69
70
/* Unpack a color into its bytes. */
71
#define declare_unpack_color(a, b, c, d, e, color)\
72
0
        byte a = (byte)((color >> 16) >> 16);\
73
0
        byte b = (byte)((uint)color >> 24);\
74
0
        byte c = (byte)((uint)color >> 16);\
75
0
        byte d = (byte)((uint)color >> 8);\
76
0
        byte e = (byte)color
77
/* Put a 40-bit color into the bitmap. */
78
#define put5(ptr, a, b, c, d, e)\
79
0
        (ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e
80
/* Put 4 bytes of color into the bitmap. */
81
#define putw(ptr, wxyz)\
82
0
        *(bits32 *)(ptr) = (wxyz)
83
/* Load the 5-word 40-bit-color cache. */
84
/* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */
85
#if ARCH_IS_BIG_ENDIAN
86
#  define set_color40_cache(color, a, b, c, d, e)\
87
        mdev->color40.abcd = abcd = (color) >> 8, \
88
        mdev->color40.bcde = bcde = (abcd << 8) | (e),\
89
        mdev->color40.cdea = cdea = (bcde << 8) | (a),\
90
        mdev->color40.deab = deab = (cdea << 8) | (b),\
91
        mdev->color40.eabc = eabc = (deab << 8) | (c),\
92
        mdev->color40.abcde = (color)
93
#else
94
#  define set_color40_cache(color, a, b, c, d, e)\
95
0
        mdev->color40.abcd = abcd =\
96
0
                ((bits32)(d) << 24) | ((bits32)(c) << 16) |\
97
0
                ((bits16)(b) << 8) | (a),\
98
0
        mdev->color40.eabc = eabc = (abcd << 8) | (e),\
99
0
        mdev->color40.deab = deab = (eabc << 8) | (d),\
100
0
        mdev->color40.cdea = cdea = (deab << 8) | (c),\
101
0
        mdev->color40.bcde = bcde = (cdea << 8) | (b),\
102
0
        mdev->color40.abcde = (color)
103
#endif
104
105
/* Fill a rectangle with a color. */
106
static int
107
mem_true40_fill_rectangle(gx_device * dev,
108
                          int x, int y, int w, int h, gx_color_index color)
109
0
{
110
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
111
0
    declare_unpack_color(a, b, c, d, e, color);
112
0
    declare_scan_ptr(dest);
113
114
    /*
115
     * In order to avoid testing w > 0 and h > 0 twice, we defer
116
     * executing setup_rect, and use fit_fill_xywh instead of
117
     * fit_fill.
118
     */
119
0
    fit_fill_xywh(dev, x, y, w, h);
120
0
    INCR(fill);
121
#ifdef COLLECT_STATS_MEM40
122
    stats_mem40.ftotal += w;
123
#endif
124
0
    if (w >= 5) {
125
0
        if (h <= 0)
126
0
            return 0;
127
0
        INCR(fwide);
128
0
        setup_rect(dest);
129
0
        if (a == b && b == c && c == d && d == e) {
130
0
            int bcnt = w * PIXEL_SIZE;
131
132
0
            INCR(fgray[min(w, 100)]);
133
0
            while (h-- > 0) {
134
0
                memset(dest, a, bcnt);
135
0
                inc_ptr(dest, draster);
136
0
            }
137
0
        } else {
138
0
            int x3 = -x & 3, ww = w - x3; /* we know ww >= 2 */
139
0
            bits32 abcd, bcde, cdea, deab, eabc;
140
141
0
            if (mdev->color40.abcde == color) {
142
0
                abcd = mdev->color40.abcd;
143
0
                bcde = mdev->color40.bcde;
144
0
                cdea = mdev->color40.cdea;
145
0
                deab = mdev->color40.deab;
146
0
                eabc = mdev->color40.eabc;
147
0
            } else {
148
0
                INCR(fsetc);
149
0
                set_color40_cache(color, a, b, c, d, e);
150
0
            }
151
#ifdef COLLECT_STATS_MEM40
152
            {
153
                int ci;
154
                for (ci = 0; ci < prev_count; ++ci)
155
                    if (prev_colors[ci] == color)
156
                        break;
157
                INCR(fprevc[ci]);
158
                if (ci == prev_count) {
159
                    if (ci < countof(prev_colors))
160
                        ++prev_count;
161
                    else
162
                        --ci;
163
                }
164
                if (ci) {
165
                    memmove(&prev_colors[1], &prev_colors[0],
166
                            ci * sizeof(prev_colors[0]));
167
                    prev_colors[0] = color;
168
                }
169
            }
170
#endif
171
0
            INCR(fcolor[min(w, 100)]);
172
0
            while (h-- > 0) {
173
0
                register byte *pptr = dest;
174
0
                int w1 = ww;
175
176
0
                switch (x3) {
177
0
                    case 1:
178
0
                        pptr[0] = a;
179
0
                        putw(pptr + 1, bcde);
180
0
                        pptr += PIXEL_SIZE;
181
0
                        break;
182
0
                    case 2:
183
0
                        pptr[0] = a;
184
0
                        pptr[1] = b;
185
0
                        putw(pptr + 2, cdea);
186
0
                        putw(pptr + 6, bcde);
187
0
                        pptr += 2 * PIXEL_SIZE;
188
0
                        break;
189
0
                    case 3:
190
0
                        pptr[0] = a;
191
0
                        pptr[1] = b;
192
0
                        pptr[2] = c;
193
0
                        putw(pptr + 3, deab);
194
0
                        putw(pptr + 7, cdea);
195
0
                        putw(pptr + 11, bcde);
196
0
                        pptr += 3 * PIXEL_SIZE;
197
0
                        break;
198
0
                    case 0:
199
0
                        ;
200
0
                }
201
0
                while (w1 >= 4) {
202
0
                    putw(pptr, abcd);
203
0
                    putw(pptr + 4, eabc);
204
0
                    putw(pptr + 8, deab);
205
0
                    putw(pptr + 12, cdea);
206
0
                    putw(pptr + 16, bcde);
207
0
                    pptr += 4 * PIXEL_SIZE;
208
0
                    w1 -= 4;
209
0
                }
210
0
                switch (w1) {
211
0
                    case 1:
212
0
                        putw(pptr, abcd);
213
0
                        pptr[4] = e;
214
0
                        break;
215
0
                    case 2:
216
0
                        putw(pptr, abcd);
217
0
                        putw(pptr + 4, eabc);
218
0
                        pptr[8] = d;
219
0
                        pptr[9] = e;
220
0
                        break;
221
0
                    case 3:
222
0
                        putw(pptr, abcd);
223
0
                        putw(pptr + 4, eabc);
224
0
                        putw(pptr + 8, deab);
225
0
                        pptr[12] = c;
226
0
                        pptr[13] = d;
227
0
                        pptr[14] = e;
228
0
                        break;
229
0
                    case 0:
230
0
                        ;
231
0
                }
232
0
                inc_ptr(dest, draster);
233
0
            }
234
0
        }
235
0
    } else if (h > 0) {   /* w < 5 */
236
0
        INCR(fnarrow[max(w, 0)]);
237
0
        setup_rect(dest);
238
0
        switch (w) {
239
0
            case 4:
240
0
                do {
241
0
                    dest[15] = dest[10] = dest[5] = dest[0] = a;
242
0
                    dest[16] = dest[11] = dest[6] = dest[1] = b;
243
0
                    dest[17] = dest[12] = dest[7] = dest[2] = c;
244
0
                    dest[18] = dest[13] = dest[8] = dest[3] = d;
245
0
                    dest[19] = dest[14] = dest[9] = dest[4] = e;
246
0
                    inc_ptr(dest, draster);
247
0
                }
248
0
                while (--h);
249
0
                break;
250
0
            case 3:
251
0
                do {
252
0
                    dest[10] = dest[5] = dest[0] = a;
253
0
                    dest[11] = dest[6] = dest[1] = b;
254
0
                    dest[12] = dest[7] = dest[2] = c;
255
0
                    dest[13] = dest[8] = dest[3] = d;
256
0
                    dest[14] = dest[9] = dest[4] = e;
257
0
                    inc_ptr(dest, draster);
258
0
                }
259
0
                while (--h);
260
0
                break;
261
0
            case 2:
262
0
                do {
263
0
                    dest[5] = dest[0] = a;
264
0
                    dest[6] = dest[1] = b;
265
0
                    dest[7] = dest[2] = c;
266
0
                    dest[8] = dest[3] = d;
267
0
                    dest[9] = dest[4] = e;
268
0
                    inc_ptr(dest, draster);
269
0
                }
270
0
                while (--h);
271
0
                break;
272
0
            case 1:
273
0
                do {
274
0
                    dest[0] = a; dest[1] = b; dest[2] = c; dest[3] = d; dest[4] = e;
275
0
                    inc_ptr(dest, draster);
276
0
                }
277
0
                while (--h);
278
0
                break;
279
0
            case 0:
280
0
            default:
281
0
                ;
282
0
        }
283
0
    }
284
0
    return 0;
285
0
}
286
287
/* Copy a monochrome bitmap. */
288
static int
289
mem_true40_copy_mono(gx_device * dev,
290
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
291
        int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
292
0
{
293
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
294
0
    const byte *line;
295
0
    int sbit;
296
0
    int first_bit;
297
298
0
    declare_scan_ptr(dest);
299
300
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
301
0
    setup_rect(dest);
302
0
    line = base + (sourcex >> 3);
303
0
    sbit = sourcex & 7;
304
0
    first_bit = 0x80 >> sbit;
305
0
    if (zero != gx_no_color_index) { /* Loop for halftones or inverted masks */
306
        /* (never used). */
307
0
        declare_unpack_color(a0, b0, c0, d0, e0, zero);
308
0
        declare_unpack_color(a1, b1, c1, d1, e1, one);
309
0
        while (h-- > 0) {
310
0
            register byte *pptr = dest;
311
0
            const byte *sptr = line;
312
0
            register int sbyte = *sptr++;
313
0
            register int bit = first_bit;
314
0
            int count = w;
315
316
0
            do {
317
0
                if (sbyte & bit) {
318
0
                    if (one != gx_no_color_index)
319
0
                        put5(pptr, a1, b1, c1, d1, e1);
320
0
                } else
321
0
                    put5(pptr, a0, b0, c0, d0, e0);
322
0
                pptr += PIXEL_SIZE;
323
0
                if ((bit >>= 1) == 0)
324
0
                    bit = 0x80, sbyte = *sptr++;
325
0
            }
326
0
            while (--count > 0);
327
0
            line += sraster;
328
0
            inc_ptr(dest, draster);
329
0
        }
330
0
    } else if (one != gx_no_color_index) { /* Loop for character and pattern masks. */
331
        /* This is used heavily. */
332
0
        declare_unpack_color(a1, b1, c1, d1, e1, one);
333
0
        int first_mask = first_bit << 1;
334
0
        int first_count, first_skip;
335
336
0
        if (sbit + w > 8)
337
0
            first_mask -= 1,
338
0
                first_count = 8 - sbit;
339
0
        else
340
0
            first_mask -= first_mask >> w,
341
0
                first_count = w;
342
0
        first_skip = first_count * PIXEL_SIZE;
343
0
        while (h-- > 0) {
344
0
            register byte *pptr = dest;
345
0
            const byte *sptr = line;
346
0
            register int sbyte = *sptr++ & first_mask;
347
0
            int count = w - first_count;
348
349
0
            if (sbyte) {
350
0
                register int bit = first_bit;
351
352
0
                do {
353
0
                    if (sbyte & bit)
354
0
                        put5(pptr, a1, b1, c1, d1, e1);
355
0
                    pptr += PIXEL_SIZE;
356
0
                }
357
0
                while ((bit >>= 1) & first_mask);
358
0
            } else
359
0
                pptr += first_skip;
360
0
            while (count >= 8) {
361
0
                sbyte = *sptr++;
362
0
                if (sbyte & 0xf0) {
363
0
                    if (sbyte & 0x80)
364
0
                        put5(pptr, a1, b1, c1, d1, e1);
365
0
                    if (sbyte & 0x40)
366
0
                        put5(pptr + 5, a1, b1, c1, d1, e1);
367
0
                    if (sbyte & 0x20)
368
0
                        put5(pptr + 10, a1, b1, c1, d1, e1);
369
0
                    if (sbyte & 0x10)
370
0
                        put5(pptr + 15, a1, b1, c1, d1, e1);
371
0
                }
372
0
                if (sbyte & 0xf) {
373
0
                    if (sbyte & 8)
374
0
                        put5(pptr + 20, a1, b1, c1, d1, e1);
375
0
                    if (sbyte & 4)
376
0
                        put5(pptr + 25, a1, b1, c1, d1, e1);
377
0
                    if (sbyte & 2)
378
0
                        put5(pptr + 30, a1, b1, c1, d1, e1);
379
0
                    if (sbyte & 1)
380
0
                        put5(pptr + 35, a1, b1, c1, d1, e1);
381
0
                }
382
0
                pptr += 8 * PIXEL_SIZE;
383
0
                count -= 8;
384
0
            }
385
0
            if (count > 0) {
386
0
                register int bit = 0x80;
387
388
0
                sbyte = *sptr++;
389
0
                do {
390
0
                    if (sbyte & bit)
391
0
                        put5(pptr, a1, b1, c1, d1, e1);
392
0
                    pptr += PIXEL_SIZE;
393
0
                    bit >>= 1;
394
0
                }
395
0
                while (--count > 0);
396
0
            }
397
0
            line += sraster;
398
0
            inc_ptr(dest, draster);
399
0
        }
400
0
    }
401
0
    return 0;
402
0
}
403
404
/* Copy a color bitmap. */
405
static int
406
mem_true40_copy_color(gx_device * dev,
407
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
408
                      int x, int y, int w, int h)
409
0
{
410
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
411
412
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
413
0
    mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h);
414
0
    return 0;
415
0
}
416
417
/* ================ "Word"-oriented device ================ */
418
419
/* Note that on a big-endian machine, this is the same as the */
420
/* standard byte-oriented-device. */
421
422
#if !ARCH_IS_BIG_ENDIAN
423
424
/* Procedures */
425
declare_mem_procs(mem40_word_copy_mono, mem40_word_copy_color, mem40_word_fill_rectangle);
426
427
/* Here is the device descriptor. */
428
const gx_device_memory mem_true40_word_device =
429
    mem_device("image40w", 40, 0, mem_word_dev_initialize_device_procs);
430
431
const gdev_mem_functions gdev_mem_fns_40w =
432
{
433
    gx_default_rgb_map_rgb_color,
434
    gx_default_rgb_map_color_rgb,
435
    mem40_word_fill_rectangle,
436
    mem40_word_copy_mono,
437
    mem40_word_copy_color,
438
    gx_default_copy_alpha,
439
    gx_default_strip_tile_rectangle,
440
    gx_no_strip_copy_rop2,
441
    mem_word_get_bits_rectangle
442
};
443
444
/* Fill a rectangle with a color. */
445
static int
446
mem40_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
447
                          gx_color_index color)
448
0
{
449
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
450
0
    byte *base;
451
0
    size_t raster;
452
453
0
    fit_fill(dev, x, y, w, h);
454
0
    base = scan_line_base(mdev, y);
455
0
    raster = mdev->raster;
456
0
    mem_swap_byte_rect(base, raster, x * 40, w * 40, h, true);
457
0
    mem_true40_fill_rectangle(dev, x, y, w, h, color);
458
0
    mem_swap_byte_rect(base, raster, x * 40, w * 40, h, false);
459
0
    return 0;
460
0
}
461
462
/* Copy a bitmap. */
463
static int
464
mem40_word_copy_mono(gx_device * dev,
465
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
466
        int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
467
0
{
468
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
469
0
    byte *row;
470
0
    size_t raster;
471
0
    bool store;
472
473
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
474
0
    row = scan_line_base(mdev, y);
475
0
    raster = mdev->raster;
476
0
    store = (zero != gx_no_color_index && one != gx_no_color_index);
477
0
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, store);
478
0
    mem_true40_copy_mono(dev, base, sourcex, sraster, id,
479
0
                         x, y, w, h, zero, one);
480
0
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, false);
481
0
    return 0;
482
0
}
483
484
/* Copy a color bitmap. */
485
static int
486
mem40_word_copy_color(gx_device * dev,
487
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
488
                      int x, int y, int w, int h)
489
0
{
490
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
491
0
    byte *row;
492
0
    size_t raster;
493
494
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
495
0
    row = scan_line_base(mdev, y);
496
0
    raster = mdev->raster;
497
0
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, true);
498
0
    bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE,
499
0
                                sraster, w * PIXEL_SIZE, h);
500
0
    mem_swap_byte_rect(row, raster, x * 40, w * 40, h, false);
501
0
    return 0;
502
0
}
503
504
#endif /* !ARCH_IS_BIG_ENDIAN */