Coverage Report

Created: 2025-06-10 07:26

/src/ghostpdl/base/gxoprect.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
17
/* generic (very slow) overprint fill rectangle implementation */
18
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsutil.h"             /* for gs_next_ids */
23
#include "gxdevice.h"
24
#include "gsdevice.h"
25
#include "gxgetbit.h"
26
#include "gxoprect.h"
27
#include "gsbitops.h"
28
29
/*
30
 * Unpack a scanline for a depth < 8. In this case we know the depth is
31
 * divisor of 8 and thus a power of 2, which implies that 8 / depth is
32
 * also a power of 2.
33
 */
34
static void
35
unpack_scanline_lt8(
36
    gx_color_index *    destp,
37
    const byte *        srcp,
38
    int                 src_offset,
39
    int                 width,
40
    int                 depth )
41
0
{
42
0
    byte                buff = 0;
43
0
    int                 i = 0, shift = 8 - depth, p_per_byte = 8 / depth;
44
45
    /* exit early if nothing to do */
46
0
    if (width == 0)
47
0
        return;
48
49
    /* skip over src_offset */
50
0
    if (src_offset >= p_per_byte) {
51
0
        srcp += src_offset / p_per_byte;
52
0
        src_offset &= (p_per_byte - 1);
53
0
    }
54
0
    if (src_offset > 0) {
55
0
        buff = *srcp++ << (src_offset * depth);
56
0
        i = src_offset;
57
0
        width += src_offset;
58
0
    }
59
60
    /* process the interesting part of the scanline */
61
0
    for (; i < width; i++, buff <<= depth) {
62
0
        if ((i & (p_per_byte - 1)) == 0)
63
0
            buff = *srcp++;
64
0
        *destp++ = buff >> shift;
65
0
    }
66
0
}
67
68
/*
69
 * Pack a scanline for a depth of < 8. Note that data prior to dest_offset
70
 * and any data beyond the width must be left undisturbed.
71
 */
72
static void
73
pack_scanline_lt8(
74
    const gx_color_index *  srcp,
75
    byte *                  destp,
76
    int                     dest_offset,
77
    int                     width,
78
    int                     depth )
79
0
{
80
0
    byte                    buff = 0;
81
0
    int                     i = 0, p_per_byte = 8 / depth;
82
83
    /* exit early if nothing to do */
84
0
    if (width == 0)
85
0
        return;
86
87
    /* skip over dest_offset */
88
0
    if (dest_offset >= p_per_byte) {
89
0
        destp += dest_offset / p_per_byte;
90
0
        dest_offset &= (p_per_byte - 1);
91
0
    }
92
0
    if (dest_offset > 0) {
93
0
        buff = *destp++ >> (8 - dest_offset * depth);
94
0
        i = dest_offset;
95
0
        width += dest_offset;
96
0
    }
97
98
    /* process the interesting part of the scanline */
99
0
    for (; i < width; i++) {
100
0
        buff = (buff << depth) | *srcp++;
101
0
        if ((i & (p_per_byte - 1)) == p_per_byte - 1)
102
0
            *destp++ = buff;
103
0
    }
104
0
    if ((i &= (p_per_byte - 1)) != 0) {
105
0
        int     shift = depth * (p_per_byte - i);
106
0
        int     mask = (1 << shift) - 1;
107
108
0
        *destp = (*destp & mask) | (buff << shift);
109
0
    }
110
0
}
111
112
/*
113
 * Unpack a scanline for a depth >= 8. In this case, the depth must be
114
 * a multiple of 8.
115
 */
116
static void
117
unpack_scanline_ge8(
118
    gx_color_index *    destp,
119
    const byte *        srcp,
120
    int                 src_offset,
121
    int                 width,
122
    int                 depth )
123
0
{
124
0
    gx_color_index      buff = 0;
125
0
    int                 i, j, bytes_per_p = depth >> 3;
126
127
    /* skip over src_offset */
128
0
    srcp += src_offset * bytes_per_p;
129
130
    /* process the interesting part of the scanline */
131
0
    width *= bytes_per_p;
132
0
    for (i = 0, j = 0; i < width; i++) {
133
0
        buff = (buff << 8) | *srcp++;
134
0
        if (++j == bytes_per_p) {
135
0
            *destp++ = buff;
136
0
            buff = 0;
137
0
            j = 0;
138
0
        }
139
0
    }
140
0
}
141
142
/*
143
 * Pack a scanline for depth >= 8.
144
 */
145
static void
146
pack_scanline_ge8(
147
    const gx_color_index *  srcp,
148
    byte *                  destp,
149
    int                     dest_offset,
150
    int                     width,
151
    int                     depth )
152
0
{
153
0
    gx_color_index          buff = 0;
154
0
    int                     i, j, bytes_per_p = depth >> 3;
155
0
    int                     shift = depth - 8;
156
157
    /* skip over dest_offset */
158
0
    destp += dest_offset;
159
160
    /* process the interesting part of the scanline */
161
0
    width *= bytes_per_p;
162
0
    for (i = 0, j = bytes_per_p - 1; i < width; i++, buff <<= 8) {
163
0
        if (++j == bytes_per_p) {
164
0
            buff = *srcp++;
165
0
            j = 0;
166
0
        }
167
0
        *destp++ = buff >> shift;
168
0
    }
169
0
}
170
171
/*
172
 * Perform the fill rectangle operation for a non-separable color encoding
173
 * that requires overprint support. This situation requires that colors be
174
 * decoded, modified, and re-encoded. These steps must be performed per
175
 * output pixel, so there is no hope of achieving good performance.
176
 * Consequently, only minimal performance optimizations are applied below.
177
 *
178
 * The overprint device structure is known only in gsovr.c, and thus is not
179
 * available here. The required information from the overprint device is,
180
 * therefore, provided via explicit operands.  The device operand points to
181
 * the target of the overprint compositor device, not the compositor device
182
 * itself. The drawn_comps bit array and the memory descriptor pointer are
183
 * also provided explicitly as operands.
184
 *
185
 * Returns 0 on success, < 0 in the event of an error.
186
 */
187
int
188
gx_overprint_generic_fill_rectangle(
189
    gx_device *             tdev,
190
    gx_color_index          drawn_comps,
191
    int                     x,
192
    int                     y,
193
    int                     w,
194
    int                     h,
195
    gx_color_index          color,
196
    gs_memory_t *           mem )
197
0
{
198
0
    gx_color_value          src_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
199
0
    gx_color_index *        pcolor_buff = 0;
200
0
    byte *                  gb_buff = 0;
201
0
    gs_get_bits_params_t    gb_params;
202
0
    gs_int_rect             gb_rect;
203
0
    int                     depth = tdev->color_info.depth;
204
0
    int                     bit_x, start_x, end_x, raster, code;
205
0
    void                    (*unpack_proc)( gx_color_index *,
206
0
                                            const byte *,
207
0
                                            int, int, int );
208
0
    void                    (*pack_proc)( const gx_color_index *,
209
0
                                          byte *,
210
0
                                          int, int, int );
211
212
0
    fit_fill(tdev, x, y, w, h);
213
0
    bit_x = x * depth;
214
0
    start_x = bit_x & ~(8 * align_bitmap_mod - 1);
215
0
    end_x = bit_x + w * depth;
216
217
    /* select the appropriate pack/unpack routines */
218
0
    if (depth >= 8) {
219
0
        unpack_proc = unpack_scanline_ge8;
220
0
        pack_proc = pack_scanline_ge8;
221
0
    } else {
222
0
        unpack_proc = unpack_scanline_lt8;
223
0
        pack_proc = pack_scanline_lt8;
224
0
    }
225
226
    /* decode the source color */
227
0
    if ((code = dev_proc(tdev, decode_color)(tdev, color, src_cvals)) < 0)
228
0
        return code;
229
230
    /* allocate space for a scanline of color indices */
231
0
    pcolor_buff = (gx_color_index *)
232
0
                      gs_alloc_bytes( mem,
233
0
                                      w *  ARCH_SIZEOF_COLOR_INDEX,
234
0
                                      "overprint generic fill rectangle" );
235
0
    if (pcolor_buff == 0)
236
0
        return gs_note_error(gs_error_VMerror);
237
238
    /* allocate a buffer for the returned data */
239
0
    raster = bitmap_raster(end_x - start_x);
240
0
    gb_buff = gs_alloc_bytes(mem, raster, "overprint generic fill rectangle");
241
0
    if (gb_buff == 0) {
242
0
        gs_free_object( mem,
243
0
                        pcolor_buff,
244
0
                        "overprint generic fill rectangle" );
245
0
        return gs_note_error(gs_error_VMerror);
246
0
    }
247
248
    /*
249
     * Initialize the get_bits parameters. The selection of options is
250
     * based on the following logic:
251
     *
252
     *  - Overprint is only defined with respect to components of the
253
     *    process color model, so the retrieved information must be kept
254
     *    in that color model. The gx_bitmap_format_t bitfield regards
255
     *    this as the native color space.
256
     *
257
     *  - Overprinting and alpha compositing don't mix, so there is no
258
     *    reason to retrieve the alpha information.
259
     *
260
     *  - Data should be returned in the depth of the process color
261
     *    model. Though this depth could be specified explicitly, there
262
     *    is little reason to do so.
263
     *
264
     *  - Though overprint is much more easily implemented with planar
265
     *    data, there is no planar version of the copy_color method to
266
     *    send the modified data back to device. Hence, we must retrieve
267
     *    data in chunky form.
268
     *
269
     *  - It is not possible to modify the raster data "in place", as
270
     *    doing so would bypass any other forwarding devices currently
271
     *    in the device "stack" (e.g.: a bounding box device). Hence,
272
     *    we must work with a copy of the data, which is passed to the
273
     *    copy_color method at the end of fill_rectangle operation.
274
     *
275
     *  - Though we only require data for those planes that will not be
276
     *    modified, there is no benefit to returning less than the full
277
     *    data for each pixel if the color encoding is not separable.
278
     *    Since this routine will be used only for encodings that are
279
     *    not separable, we might as well ask for full information.
280
     *
281
     *  - Though no particular alignment and offset are required, it is
282
     *    useful to make the copy operation as fast as possible. Ideally
283
     *    we would calculate an offset so that the data achieves optimal
284
     *    alignment. Alas, some of the devices work much more slowly if
285
     *    anything but GB_OFFSET_0 is specified, so that is what we use.
286
     */
287
0
    gb_params.options =  GB_COLORS_NATIVE
288
0
                       | GB_ALPHA_NONE
289
0
                       | GB_DEPTH_ALL
290
0
                       | GB_PACKING_CHUNKY
291
0
                       | GB_RETURN_COPY
292
0
                       | GB_ALIGN_STANDARD
293
0
                       | GB_OFFSET_0
294
0
                       | GB_RASTER_STANDARD;
295
0
    gb_params.x_offset = 0;     /* for consistency */
296
0
    gb_params.data[0] = gb_buff;
297
0
    gb_params.raster = raster;
298
299
0
    gb_rect.p.x = x;
300
0
    gb_rect.q.x = x + w;
301
302
    /* process each scanline separately */
303
0
    while (h-- > 0 && code >= 0) {
304
0
        gx_color_index *    cp = pcolor_buff;
305
0
        int                 i;
306
307
0
        gb_rect.p.y = y++;
308
0
        gb_rect.q.y = y;
309
0
        code = dev_proc(tdev, get_bits_rectangle)( tdev,
310
0
                                                   &gb_rect,
311
0
                                                   &gb_params );
312
0
        if (code < 0)
313
0
            break;
314
0
        unpack_proc(pcolor_buff, gb_buff, 0, w, depth);
315
0
        for (i = 0; i < w; i++, cp++) {
316
0
            gx_color_index  comps;
317
0
            int             j;
318
0
            gx_color_value  dest_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
319
320
0
            if ((code = dev_proc(tdev, decode_color)(tdev, *cp, dest_cvals)) < 0)
321
0
                break;
322
0
            for (j = 0, comps = drawn_comps; comps != 0; ++j, comps >>= 1) {
323
0
                    if ((comps & 0x1) != 0)
324
0
                        dest_cvals[j] = src_cvals[j];
325
0
            }
326
0
            *cp = dev_proc(tdev, encode_color)(tdev, dest_cvals);
327
0
        }
328
0
        pack_proc(pcolor_buff, gb_buff, 0, w, depth);
329
0
        code = dev_proc(tdev, copy_color)( tdev,
330
0
                                           gb_buff,
331
0
                                           0,
332
0
                                           raster,
333
0
                                           gs_no_bitmap_id,
334
0
                                           x, y - 1, w, 1 );
335
0
    }
336
337
0
    gs_free_object( mem,
338
0
                    gb_buff,
339
0
                    "overprint generic fill rectangle" );
340
0
    gs_free_object( mem,
341
0
                    pcolor_buff,
342
0
                    "overprint generic fill rectangle" );
343
344
0
    return code;
345
0
}
346
347
/*
348
 * Replication of 2 and 4 bit patterns to fill a mem_mono_chunk.
349
 */
350
static mono_fill_chunk fill_pat_2[4] = {
351
    mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x55),
352
    mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xff)
353
};
354
355
static mono_fill_chunk fill_pat_4[16] = {
356
    mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x11),
357
    mono_fill_make_pattern(0x22), mono_fill_make_pattern(0x33),
358
    mono_fill_make_pattern(0x44), mono_fill_make_pattern(0x55),
359
    mono_fill_make_pattern(0x66), mono_fill_make_pattern(0x77),
360
    mono_fill_make_pattern(0x88), mono_fill_make_pattern(0x99),
361
    mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xbb),
362
    mono_fill_make_pattern(0xcc), mono_fill_make_pattern(0xdd),
363
    mono_fill_make_pattern(0xee), mono_fill_make_pattern(0xff)
364
};
365
366
/*
367
 * Replicate a color or mask as required to fill a mem_mono_fill_chunk.
368
 * This is possible if (8 * sizeof(mono_fill_chunk)) % depth == 0.
369
 * Since sizeof(mono_fill_chunk) is a power of 2, this will be the case
370
 * if depth is a power of 2 and depth <= 8 * sizeof(mono_fill_chunk).
371
 */
372
static mono_fill_chunk
373
replicate_color(int depth, mono_fill_chunk color)
374
0
{
375
0
    switch (depth) {
376
377
0
      case 1:
378
0
        color = (mono_fill_chunk)(-(int)color); break;
379
380
0
      case 2:
381
0
        color = fill_pat_2[color]; break;
382
383
0
      case 4:
384
0
        color = fill_pat_4[color]; break;
385
386
0
      case 8:
387
0
        color= mono_fill_make_pattern(color); break;
388
389
0
#if mono_fill_chunk_bytes > 2
390
0
      case 16:
391
0
        color = (color << 16) | color;
392
        /* fall through */
393
0
#endif
394
#if mono_fill_chunk_bytes > 4
395
      case 32:
396
        color = (color << 32) | color;
397
        break;
398
#endif
399
0
    }
400
401
0
    return color;
402
0
}
403
404
/*
405
 * Perform the fill rectangle operation for a separable color encoding
406
 * that requires overprint support.
407
 *
408
 * This is handled via two separate cases. If
409
 *
410
 *    (8 * sizeof(mono_fill_chunk)) % tdev->color_info.depth = 0,
411
 *
412
 * then is possible to work via the masked analog of the bits_fill_rectangle
413
 * procedure, bits_fill_rectangle_masked. This requires that both the
414
 * color and component mask be replicated sufficiently to fill the
415
 * mono_fill_chunk. The somewhat elaborate set-up aside, the resulting
416
 * algorithm is about as efficient as can be achieved when using
417
 * get_bits_rectangle. More efficient algorithms require overprint to be
418
 * implemented in the target device itself.
419
 *
420
 * If the condition is not satisfied, a simple byte-wise algorithm is
421
 * used. This requires minimal setup but is not efficient, as it works in
422
 * units that are too small. More efficient methods are possible in this
423
 * case, but the required setup for a general depth is excessive (even
424
 * with the restriction that depth % 8 = 0). Hence, efficiency for these
425
 * cases is better addressed by direct implementation of overprint for
426
 * memory devices.
427
 *
428
 * For both cases, the color and retain_mask values passed to this
429
 * procedure are expected to be already swapped as required for a byte-
430
 * oriented bitmap. This consideration affects only little-endian
431
 * machines. For those machines, if depth > 9 the color passed to these
432
 * two procedures will not be the same as that passed to
433
 * gx_overprint_generic_fill_rectangle.
434
 *
435
 * Returns 0 on success, < 0 in the event of an error.
436
 */
437
int
438
gx_overprint_sep_fill_rectangle_1(
439
    gx_device *             tdev,
440
    gx_color_index          retain_mask,    /* already swapped */
441
    int                     x,
442
    int                     y,
443
    int                     w,
444
    int                     h,
445
    gx_color_index          color,          /* already swapped */
446
    gs_memory_t *           mem )
447
0
{
448
0
    byte *                  gb_buff = 0;
449
0
    gs_get_bits_params_t    gb_params;
450
0
    gs_int_rect             gb_rect;
451
0
    int                     code = 0, bit_w, depth = tdev->color_info.depth;
452
0
    int                     raster;
453
0
    mono_fill_chunk         rep_color, rep_mask;
454
455
0
    fit_fill(tdev, x, y, w, h);
456
0
    bit_w = w * depth;
457
458
    /* set up replicated color and retain mask */
459
0
    if (depth < 8 * sizeof(mono_fill_chunk)) {
460
0
        rep_color = replicate_color(depth, (mono_fill_chunk)color);
461
0
        rep_mask = replicate_color(depth, (mono_fill_chunk)retain_mask);
462
0
    } else {
463
0
        rep_color = (mono_fill_chunk)color;
464
0
        rep_mask = (mono_fill_chunk)retain_mask;
465
0
    }
466
467
    /* allocate a buffer for the returned data */
468
0
    raster = bitmap_raster(w * depth);
469
0
    gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 1");
470
0
    if (gb_buff == 0)
471
0
        return gs_note_error(gs_error_VMerror);
472
473
    /*
474
     * Initialize the get_bits parameters. The selection of options is
475
     * the same as that for gx_overprint_generic_fill_rectangle (above).
476
     */
477
0
    gb_params.options =  GB_COLORS_NATIVE
478
0
                       | GB_ALPHA_NONE
479
0
                       | GB_DEPTH_ALL
480
0
                       | GB_PACKING_CHUNKY
481
0
                       | GB_RETURN_COPY
482
0
                       | GB_ALIGN_STANDARD
483
0
                       | GB_OFFSET_0
484
0
                       | GB_RASTER_STANDARD;
485
0
    gb_params.x_offset = 0;     /* for consistency */
486
0
    gb_params.data[0] = gb_buff;
487
0
    gb_params.raster = raster;
488
489
0
    gb_rect.p.x = x;
490
0
    gb_rect.q.x = x + w;
491
492
    /* process each scanline separately */
493
0
    while (h-- > 0 && code >= 0) {
494
0
        gb_rect.p.y = y++;
495
0
        gb_rect.q.y = y;
496
0
        code = dev_proc(tdev, get_bits_rectangle)( tdev,
497
0
                                                   &gb_rect,
498
0
                                                   &gb_params );
499
0
        if (code < 0)
500
0
            break;
501
0
        bits_fill_rectangle_masked( gb_buff,
502
0
                                    0,
503
0
                                    raster,
504
0
                                    rep_color,
505
0
                                    rep_mask,
506
0
                                    bit_w,
507
0
                                    1 );
508
0
        code = dev_proc(tdev, copy_color)( tdev,
509
0
                                           gb_buff,
510
0
                                           0,
511
0
                                           raster,
512
0
                                           gs_no_bitmap_id,
513
0
                                           x, y - 1, w, 1 );
514
0
    }
515
516
0
    gs_free_object( mem,
517
0
                    gb_buff,
518
0
                    "overprint generic fill rectangle" );
519
520
0
    return code;
521
0
}
522
523
int
524
gx_overprint_sep_fill_rectangle_2(
525
    gx_device *             tdev,
526
    gx_color_index          retain_mask,    /* already swapped */
527
    int                     x,
528
    int                     y,
529
    int                     w,
530
    int                     h,
531
    gx_color_index          color,          /* already swapped */
532
    gs_memory_t *           mem )
533
0
{
534
0
    byte *                  gb_buff = 0;
535
0
    gs_get_bits_params_t    gb_params;
536
0
    gs_int_rect             gb_rect;
537
0
    int                     code = 0, byte_w, raster;
538
0
    int                     byte_depth = tdev->color_info.depth >> 3;
539
0
    byte *                  pcolor;
540
0
    byte *                  pmask;
541
542
0
    fit_fill(tdev, x, y, w, h);
543
0
    byte_w = w * byte_depth;
544
545
    /* set up color and retain mask pointers */
546
0
    pcolor = (byte *)&color;
547
0
    pmask = (byte *)&retain_mask;
548
#if ARCH_IS_BIG_ENDIAN
549
    pcolor += ARCH_SIZEOF_COLOR_INDEX - byte_depth;
550
    pmask += ARCH_SIZEOF_COLOR_INDEX - byte_depth;
551
#endif
552
553
    /* allocate a buffer for the returned data */
554
0
    raster = bitmap_raster(w * (byte_depth << 3));
555
0
    gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 2");
556
0
    if (gb_buff == 0)
557
0
        return gs_note_error(gs_error_VMerror);
558
559
    /*
560
     * Initialize the get_bits parameters. The selection of options is
561
     * the same as that for gx_overprint_generic_fill_rectangle (above).
562
     */
563
0
    gb_params.options =  GB_COLORS_NATIVE
564
0
                       | GB_ALPHA_NONE
565
0
                       | GB_DEPTH_ALL
566
0
                       | GB_PACKING_CHUNKY
567
0
                       | GB_RETURN_COPY
568
0
                       | GB_ALIGN_STANDARD
569
0
                       | GB_OFFSET_0
570
0
                       | GB_RASTER_STANDARD;
571
0
    gb_params.x_offset = 0;     /* for consistency */
572
0
    gb_params.data[0] = gb_buff;
573
0
    gb_params.raster = raster;
574
575
0
    gb_rect.p.x = x;
576
0
    gb_rect.q.x = x + w;
577
578
    /* process each scanline separately */
579
0
    while (h-- > 0 && code >= 0) {
580
0
        int     i, j;
581
0
        byte *  cp = gb_buff;
582
583
0
        gb_rect.p.y = y++;
584
0
        gb_rect.q.y = y;
585
0
        code = dev_proc(tdev, get_bits_rectangle)( tdev,
586
0
                                                   &gb_rect,
587
0
                                                   &gb_params );
588
0
        if (code < 0)
589
0
            break;
590
0
        for (i = 0, j = 0; i < byte_w; i++, cp++) {
591
0
            *cp = (*cp & pmask[j]) | pcolor[j];
592
0
            if (++j == byte_depth)
593
0
                j = 0;
594
0
        }
595
0
        code = dev_proc(tdev, copy_color)( tdev,
596
0
                                           gb_buff,
597
0
                                           0,
598
0
                                           raster,
599
0
                                           gs_no_bitmap_id,
600
0
                                           x, y - 1, w, 1 );
601
0
    }
602
603
0
    gs_free_object( mem,
604
0
                    gb_buff,
605
0
                    "overprint generic fill rectangle" );
606
607
0
    return code;
608
0
}