Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gdevm4.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
/* 4-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
/* ================ Standard (byte-oriented) device ================ */
24
25
#undef chunk
26
#define chunk byte
27
#define fpat(byt) mono_fill_make_pattern(byt)
28
29
/* Procedures */
30
declare_mem_procs(mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle);
31
32
/* The device descriptor. */
33
const gx_device_memory mem_mapped4_device =
34
    mem_device("image4", 3, 1, mem_dev_initialize_device_procs);
35
36
const gdev_mem_functions gdev_mem_fns_4 =
37
{
38
    mem_mapped_map_rgb_color,
39
    mem_mapped_map_color_rgb,
40
    mem_mapped4_fill_rectangle,
41
    mem_mapped4_copy_mono,
42
    mem_mapped4_copy_color,
43
    gx_default_copy_alpha,
44
    gx_default_strip_tile_rectangle,
45
    mem_gray_strip_copy_rop2,
46
    mem_get_bits_rectangle
47
};
48
49
/* Convert x coordinate to byte offset in scan line. */
50
#undef x_to_byte
51
61.5M
#define x_to_byte(x) ((x) >> 1)
52
53
/* Define the 4-bit fill patterns. */
54
static const mono_fill_chunk tile_patterns[16] =
55
{fpat(0x00), fpat(0x11), fpat(0x22), fpat(0x33),
56
 fpat(0x44), fpat(0x55), fpat(0x66), fpat(0x77),
57
 fpat(0x88), fpat(0x99), fpat(0xaa), fpat(0xbb),
58
 fpat(0xcc), fpat(0xdd), fpat(0xee), fpat(0xff)
59
};
60
61
/* Fill a rectangle with a color. */
62
static int
63
mem_mapped4_fill_rectangle(gx_device * dev,
64
                           int x, int y, int w, int h, gx_color_index color)
65
162M
{
66
162M
    gx_device_memory * const mdev = (gx_device_memory *)dev;
67
68
162M
    fit_fill(dev, x, y, w, h);
69
137M
    bits_fill_rectangle(scan_line_base(mdev, y), x << 2, mdev->raster,
70
137M
                        tile_patterns[color], w << 2, h);
71
137M
    return 0;
72
162M
}
73
74
/* Copy a bitmap. */
75
static int
76
mem_mapped4_copy_mono(gx_device * dev,
77
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
78
        int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
79
61.5M
{
80
61.5M
    gx_device_memory * const mdev = (gx_device_memory *)dev;
81
61.5M
    const byte *line;
82
61.5M
    declare_scan_ptr(dest);
83
61.5M
    byte invert, bb;
84
85
61.5M
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
86
61.5M
    setup_rect(dest);
87
61.5M
    line = base + (sourcex >> 3);
88
    /* Divide into opaque and masked cases. */
89
61.5M
    if (one == gx_no_color_index) {
90
20.4k
        if (zero == gx_no_color_index)
91
0
            return 0;   /* nothing to do */
92
20.4k
        invert = 0xff;
93
20.4k
        bb = ((byte) zero << 4) | (byte) zero;
94
61.5M
    } else if (zero == gx_no_color_index) {
95
6.22M
        invert = 0;
96
6.22M
        bb = ((byte) one << 4) | (byte) one;
97
55.2M
    } else {
98
        /* Opaque case. */
99
55.2M
        int shift = ~(sourcex ^ x) & 1;
100
55.2M
        byte oz[4];
101
102
55.2M
        oz[0] = (byte)((zero << 4) | zero);
103
55.2M
        oz[1] = (byte)((zero << 4) | one);
104
55.2M
        oz[2] = (byte)((one << 4) | zero);
105
55.2M
        oz[3] = (byte)((one << 4) | one);
106
69.0M
        do {
107
69.0M
            register byte *dptr = (byte *) dest;
108
69.0M
            const byte *sptr = line;
109
69.0M
            register uint sbyte = *sptr++;
110
69.0M
            register int sbit = ~sourcex & 7;
111
69.0M
            int count = w;
112
113
            /*
114
             * If the first source bit corresponds to an odd X in the
115
             * destination, process it now.
116
             */
117
69.0M
            if (x & 1) {
118
30.0M
                *dptr = (*dptr & 0xf0) |
119
30.0M
                    ((sbyte >> sbit) & 1 ? one : zero);
120
30.0M
                --count;  /* may now be 0 */
121
30.0M
                if (--sbit < 0)
122
2.59M
                    sbit = 7, sbyte = *sptr++;
123
30.0M
                ++dptr;
124
30.0M
            }
125
            /*
126
             * Now we know the next destination X is even.  We want to
127
             * process 2 source bits at a time from now on, so set things up
128
             * properly depending on whether the next source X (bit) is even
129
             * or odd.  In both even and odd cases, the active source bits
130
             * are in bits 8..1 of sbyte.
131
             */
132
69.0M
            sbyte <<= shift;
133
69.0M
            sbit += shift - 1;
134
            /*
135
             * Now bit # sbit+1 is the most significant unprocessed bit
136
             * in sbyte.  -1 <= sbit <= 7; sbit is odd.
137
             * Note that if sbit = -1, all of sbyte has been processed.
138
             *
139
             * Continue processing pairs of bits in the first source byte.
140
             */
141
200M
            while (count >= 2 && sbit >= 0) {
142
131M
                *dptr++ = oz[(sbyte >> sbit) & 3];
143
131M
                sbit -= 2, count -= 2;
144
131M
            }
145
            /*
146
             * Now sbit = -1 iff we have processed the entire first source
147
             * byte.
148
             *
149
             * Process full source bytes.
150
             */
151
69.0M
            if (shift) {
152
47.4M
                sbyte >>= 1;  /* in case count < 8 */
153
525M
                for (; count >= 8; dptr += 4, count -= 8) {
154
477M
                    sbyte = *sptr++;
155
477M
                    dptr[0] = oz[sbyte >> 6];
156
477M
                    dptr[1] = oz[(sbyte >> 4) & 3];
157
477M
                    dptr[2] = oz[(sbyte >> 2) & 3];
158
477M
                    dptr[3] = oz[sbyte & 3];
159
477M
                }
160
47.4M
                sbyte <<= 1;
161
47.4M
            } else {
162
193M
                for (; count >= 8; dptr += 4, count -= 8) {
163
171M
                    sbyte = (sbyte << 8) | *sptr++;
164
171M
                    dptr[0] = oz[(sbyte >> 7) & 3];
165
171M
                    dptr[1] = oz[(sbyte >> 5) & 3];
166
171M
                    dptr[2] = oz[(sbyte >> 3) & 3];
167
171M
                    dptr[3] = oz[(sbyte >> 1) & 3];
168
171M
                }
169
21.6M
            }
170
69.0M
            if (!count)
171
22.4M
                continue;
172
            /*
173
             * Process pairs of bits in the final source byte.  Note that
174
             * if sbit > 0, this is still the first source byte (the
175
             * full-byte loop wasn't executed).
176
             */
177
46.5M
            if (sbit < 0) {
178
35.3M
                sbyte = (sbyte << 8) | (*sptr << shift);
179
35.3M
                sbit = 7;
180
35.3M
            }
181
102M
            while (count >= 2) {
182
56.1M
                *dptr++ = oz[(sbyte >> sbit) & 3];
183
56.1M
                sbit -= 2, count -= 2;
184
56.1M
            }
185
            /*
186
             * If the final source bit corresponds to an even X value,
187
             * process it now.
188
             */
189
46.5M
            if (count) {
190
31.2M
                *dptr = (*dptr & 0x0f) |
191
31.2M
                    (((sbyte >> sbit) & 2 ? one : zero) << 4);
192
31.2M
            }
193
69.0M
        } while ((line += sraster, inc_ptr(dest, draster), --h) > 0);
194
0
        return 0;
195
55.2M
    }
196
    /* Masked case. */
197
93.1M
    do {
198
93.1M
        register byte *dptr = (byte *) dest;
199
93.1M
        const byte *sptr = line;
200
93.1M
        register int sbyte = *sptr++ ^ invert;
201
93.1M
        register int sbit = 0x80 >> (sourcex & 7);
202
93.1M
        register byte mask = (x & 1 ? 0x0f : 0xf0);
203
93.1M
        int count = w;
204
205
1.54G
        do {
206
1.54G
            if (sbyte & sbit)
207
498M
                *dptr = (*dptr & ~mask) | (bb & mask);
208
1.54G
            if ((sbit >>= 1) == 0)
209
158M
                sbit = 0x80, sbyte = *sptr++ ^ invert;
210
1.54G
            dptr += (mask = ~mask) >> 7;
211
1.54G
        } while (--count > 0);
212
93.1M
        line += sraster;
213
93.1M
        inc_ptr(dest, draster);
214
93.1M
    } while (--h > 0);
215
6.24M
    return 0;
216
61.5M
}
217
218
/* Copy a color bitmap. */
219
static int
220
mem_mapped4_copy_color(gx_device * dev,
221
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
222
                       int x, int y, int w, int h)
223
202M
{
224
    /* Use monobit copy_mono. */
225
202M
    int code;
226
227
    /* Patch the width in the device temporarily. */
228
202M
    dev->width <<= 2;
229
202M
    code = mem_mono_copy_mono(dev, base, sourcex << 2, sraster, id,
230
202M
                              x << 2, y, w << 2, h,
231
202M
                              (gx_color_index) 0, (gx_color_index) 1);
232
    /* Restore the correct width. */
233
202M
    dev->width >>= 2;
234
202M
    return code;
235
202M
}
236
237
/* ================ "Word"-oriented device ================ */
238
239
/* Note that on a big-endian machine, this is the same as the */
240
/* standard byte-oriented-device. */
241
242
#if !ARCH_IS_BIG_ENDIAN
243
244
/* Procedures */
245
declare_mem_procs(mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle);
246
247
/* Here is the device descriptor. */
248
const gx_device_memory mem_mapped4_word_device =
249
    mem_device("image4w", 4, 0, mem_word_dev_initialize_device_procs);
250
251
const gdev_mem_functions gdev_mem_fns_4w =
252
{
253
    mem_mapped_map_rgb_color,
254
    mem_mapped_map_color_rgb,
255
    mem4_word_fill_rectangle,
256
    mem4_word_copy_mono,
257
    mem4_word_copy_color,
258
    gx_default_copy_alpha,
259
    gx_default_strip_tile_rectangle,
260
    gx_no_strip_copy_rop2,
261
    mem_word_get_bits_rectangle
262
};
263
264
/* Fill a rectangle with a color. */
265
static int
266
mem4_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
267
                         gx_color_index color)
268
0
{
269
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
270
0
    byte *base;
271
0
    size_t raster;
272
273
0
    fit_fill(dev, x, y, w, h);
274
0
    base = scan_line_base(mdev, y);
275
0
    raster = mdev->raster;
276
0
    mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
277
0
    bits_fill_rectangle(base, x << 2, raster,
278
0
                        tile_patterns[color], w << 2, h);
279
0
    mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true);
280
0
    return 0;
281
0
}
282
283
/* Copy a bitmap. */
284
static int
285
mem4_word_copy_mono(gx_device * dev,
286
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
287
        int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
288
0
{
289
0
    gx_device_memory * const mdev = (gx_device_memory *)dev;
290
0
    byte *row;
291
0
    size_t raster;
292
0
    bool store;
293
294
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
295
0
    row = scan_line_base(mdev, y);
296
0
    raster = mdev->raster;
297
0
    store = (zero != gx_no_color_index && one != gx_no_color_index);
298
0
    mem_swap_byte_rect(row, raster, x << 2, w << 2, h, store);
299
0
    mem_mapped4_copy_mono(dev, base, sourcex, sraster, id,
300
0
                          x, y, w, h, zero, one);
301
0
    mem_swap_byte_rect(row, raster, x << 2, w << 2, h, false);
302
0
    return 0;
303
0
}
304
305
/* Copy a color bitmap. */
306
static int
307
mem4_word_copy_color(gx_device * dev,
308
               const byte * base, int sourcex, int sraster, gx_bitmap_id id,
309
                     int x, int y, int w, int h)
310
0
{
311
0
    int code;
312
313
0
    fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
314
    /* Use monobit copy_mono. */
315
    /* Patch the width in the device temporarily. */
316
0
    dev->width <<= 2;
317
0
    code = gdev_mem_word_functions_for_bits(1)->copy_mono
318
0
        (dev, base, sourcex << 2, sraster, id,
319
0
         x << 2, y, w << 2, h, (gx_color_index) 0, (gx_color_index) 1);
320
    /* Restore the correct width. */
321
0
    dev->width >>= 2;
322
0
    return code;
323
0
}
324
325
#endif /* !ARCH_IS_BIG_ENDIAN */