Coverage Report

Created: 2025-06-24 07:01

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