Coverage Report

Created: 2025-06-24 07:01

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