Coverage Report

Created: 2025-06-10 07:26

/src/ghostpdl/base/gxclip2.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
/* Mask clipping for patterns */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gpcheck.h"
21
#include "gserrors.h"
22
#include "gsstruct.h"
23
#include "gxdevice.h"
24
#include "gxdevmem.h"
25
#include "gxclip2.h"
26
#include "gxdcolor.h"
27
#include "gdevmpla.h"
28
29
private_st_device_tile_clip();
30
31
/* Device procedures */
32
static dev_proc_fill_rectangle(tile_clip_fill_rectangle);
33
static dev_proc_fill_rectangle_hl_color(tile_clip_fill_rectangle_hl_color);
34
static dev_proc_copy_mono(tile_clip_copy_mono);
35
static dev_proc_copy_color(tile_clip_copy_color);
36
static dev_proc_copy_planes(tile_clip_copy_planes);
37
static dev_proc_copy_alpha(tile_clip_copy_alpha);
38
static dev_proc_copy_alpha_hl_color(tile_clip_copy_alpha_hl_color);
39
static dev_proc_strip_copy_rop2(tile_clip_strip_copy_rop2);
40
41
/* The device descriptor. */
42
static void
43
tile_clipper_initialize_device_procs(gx_device *dev)
44
32.2k
{
45
32.2k
    set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix);
46
32.2k
    set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
47
32.2k
    set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
48
32.2k
    set_dev_proc(dev, fill_rectangle, tile_clip_fill_rectangle);
49
32.2k
    set_dev_proc(dev, copy_mono, tile_clip_copy_mono);
50
32.2k
    set_dev_proc(dev, copy_color, tile_clip_copy_color);
51
32.2k
    set_dev_proc(dev, get_params, gx_forward_get_params);
52
32.2k
    set_dev_proc(dev, put_params, gx_forward_put_params);
53
32.2k
    set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
54
32.2k
    set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
55
32.2k
    set_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits);
56
32.2k
    set_dev_proc(dev, copy_alpha, tile_clip_copy_alpha);
57
32.2k
    set_dev_proc(dev, get_clipping_box, gx_forward_get_clipping_box);
58
32.2k
    set_dev_proc(dev, get_bits_rectangle, gx_forward_get_bits_rectangle);
59
32.2k
    set_dev_proc(dev, composite, gx_no_composite);
60
32.2k
    set_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params);
61
32.2k
    set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
62
32.2k
    set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
63
32.2k
    set_dev_proc(dev, encode_color, gx_forward_encode_color);
64
32.2k
    set_dev_proc(dev, decode_color, gx_forward_decode_color);
65
32.2k
    set_dev_proc(dev, fill_rectangle_hl_color, tile_clip_fill_rectangle_hl_color);
66
32.2k
    set_dev_proc(dev, include_color_space, gx_forward_include_color_space);
67
32.2k
    set_dev_proc(dev, fill_linear_color_scanline, gx_forward_fill_linear_color_scanline);
68
32.2k
    set_dev_proc(dev, fill_linear_color_trapezoid, gx_forward_fill_linear_color_trapezoid);
69
32.2k
    set_dev_proc(dev, fill_linear_color_triangle, gx_forward_fill_linear_color_triangle);
70
32.2k
    set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors);
71
32.2k
    set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params);
72
32.2k
    set_dev_proc(dev, fillpage, gx_forward_fillpage);
73
32.2k
    set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op);
74
32.2k
    set_dev_proc(dev, copy_planes, tile_clip_copy_planes);
75
32.2k
    set_dev_proc(dev, strip_copy_rop2, tile_clip_strip_copy_rop2);
76
32.2k
    set_dev_proc(dev, copy_alpha_hl_color, tile_clip_copy_alpha_hl_color);
77
78
    /* Ideally the following defaults would be set up for us, but this
79
     * does not currently work. */
80
32.2k
    set_dev_proc(dev, open_device, gx_default_open_device);
81
32.2k
    set_dev_proc(dev, sync_output, gx_default_sync_output);
82
32.2k
    set_dev_proc(dev, output_page, gx_default_output_page);
83
32.2k
    set_dev_proc(dev, close_device, gx_default_close_device);
84
32.2k
    set_dev_proc(dev, fill_path, gx_default_fill_path);
85
32.2k
    set_dev_proc(dev, stroke_path, gx_default_stroke_path);
86
32.2k
    set_dev_proc(dev, fill_mask, gx_default_fill_mask);
87
32.2k
    set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid);
88
32.2k
    set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram);
89
32.2k
    set_dev_proc(dev, fill_triangle, gx_default_fill_triangle);
90
32.2k
    set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
91
32.2k
    set_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle);
92
32.2k
    set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image);
93
32.2k
    set_dev_proc(dev, text_begin, gx_default_text_begin);
94
32.2k
    set_dev_proc(dev, strip_tile_rect_devn, gx_default_strip_tile_rect_devn);
95
32.2k
}
96
97
static const gx_device_tile_clip gs_tile_clip_device =
98
{std_device_std_body_open(gx_device_tile_clip,
99
                          tile_clipper_initialize_device_procs,
100
                          "tile clipper",
101
                          0, 0, 1, 1)
102
};
103
104
/* Initialize a tile clipping device from a mask. */
105
int
106
tile_clip_initialize(gx_device_tile_clip * cdev, const gx_strip_bitmap * tiles,
107
                     gx_device * tdev, int px, int py)
108
32.2k
{
109
32.2k
    int code =
110
32.2k
    gx_mask_clip_initialize(cdev, &gs_tile_clip_device,
111
32.2k
                            (const gx_bitmap *)tiles,
112
32.2k
                            tdev, 0, 0, NULL);  /* phase will be reset */
113
114
32.2k
    if (code >= 0) {
115
32.2k
        cdev->tiles = *tiles;
116
32.2k
        tile_clip_set_phase(cdev, px, py);
117
32.2k
    }
118
32.2k
    return code;
119
32.2k
}
120
121
void
122
tile_clip_free(gx_device_tile_clip *cdev)
123
32.2k
{
124
    /* release the target reference */
125
32.2k
    if(cdev->finalize)
126
32.2k
        cdev->finalize((gx_device *)cdev);  /* this also sets the target to NULL */
127
32.2k
    gs_free_object(cdev->memory, cdev, "tile_clip_free(cdev)");
128
32.2k
}
129
130
/* Set the phase of the tile. */
131
void
132
tile_clip_set_phase(gx_device_tile_clip * cdev, int px, int py)
133
553k
{
134
553k
    cdev->phase.x = px;
135
553k
    cdev->phase.y = py;
136
553k
}
137
138
/* Fill a rectangle with high level devn color by tiling with the mask. */
139
static int
140
tile_clip_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
141
                const gs_gstate *pgs, const gx_drawing_color *pdcolor,
142
                const gx_clip_path *pcpath)
143
0
{
144
0
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
145
0
    gx_device *tdev = cdev->target;
146
0
    int x, y, w, h;
147
0
    gx_device_color dcolor0, dcolor1;
148
0
    int k;
149
150
    /* Have to pack the no color index into the pure device type */
151
0
    dcolor0.type = gx_dc_type_pure;
152
0
    dcolor0.colors.pure = gx_no_color_index;
153
    /* Have to set the dcolor1 to a non mask type */
154
0
    dcolor1.type = gx_dc_type_devn;
155
0
    for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
156
0
        dcolor1.colors.devn.values[k] = pdcolor->colors.devn.values[k];
157
0
    }
158
0
    x = fixed2int(rect->p.x);
159
0
    y = fixed2int(rect->p.y);
160
0
    w = fixed2int(rect->q.x) - x;
161
0
    h = fixed2int(rect->q.y) - y;
162
0
    return (*dev_proc(tdev, strip_tile_rect_devn))(tdev, &cdev->tiles,
163
0
                                                    x, y, w, h, &dcolor0, &dcolor1,
164
0
                                                    cdev->phase.x, cdev->phase.y);
165
0
}
166
167
/* Fill a rectangle by tiling with the mask. */
168
static int
169
tile_clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
170
                         gx_color_index color)
171
9.33k
{
172
9.33k
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
173
9.33k
    gx_device *tdev = cdev->target;
174
175
9.33k
    return (*dev_proc(tdev, strip_tile_rectangle)) (tdev, &cdev->tiles,
176
9.33k
                                                    x, y, w, h,
177
9.33k
                    gx_no_color_index, color, cdev->phase.x, cdev->phase.y);
178
9.33k
}
179
180
/* Calculate the X offset corresponding to a given Y, taking the phase */
181
/* and shift into account. */
182
#define x_offset(ty, cdev)\
183
848k
  ((cdev)->phase.x + (((ty) + (cdev)->phase.y) / (cdev)->tiles.rep_height) *\
184
848k
   (cdev)->tiles.rep_shift)
185
186
/* Copy a monochrome bitmap.  We divide it up into maximal chunks */
187
/* that line up with a single tile, and then do the obvious Boolean */
188
/* combination of the tile mask and the source. */
189
static int
190
tile_clip_copy_mono(gx_device * dev,
191
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
192
                    int x, int y, int w, int h,
193
                    gx_color_index color0, gx_color_index color1)
194
0
{
195
0
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
196
0
    gx_color_index color, mcolor0, mcolor1;
197
0
    int ty, ny;
198
0
    int code;
199
200
0
    setup_mask_copy_mono(cdev, color, mcolor0, mcolor1);
201
0
    for (ty = y; ty < y + h; ty += ny) {
202
0
        int tx, nx;
203
0
        int cy;
204
0
        int xoff;
205
206
0
        if (cdev->tiles.rep_height == 0 || cdev->tiles.rep_width == 0)
207
0
            return 0;
208
209
0
        cy = (ty + cdev->phase.y) % cdev->tiles.rep_height;
210
0
        xoff = x_offset(ty, cdev);
211
212
0
        ny = min(y + h - ty, cdev->tiles.size.y - cy);
213
0
        if (ny > cdev->mdev.height)
214
0
            ny = cdev->mdev.height;
215
0
        for (tx = x; tx < x + w; tx += nx) {
216
0
            int cx = (tx + xoff) % cdev->tiles.rep_width;
217
218
0
            nx = min(x + w - tx, cdev->tiles.size.x - cx);
219
            /* Copy a tile slice to the memory device buffer. */
220
0
            memcpy(cdev->buffer.bytes,
221
0
                   cdev->tiles.data + cy * cdev->tiles.raster,
222
0
                   (size_t)cdev->tiles.raster * ny);
223
            /* Intersect the tile with the source data. */
224
            /* mcolor0 and mcolor1 invert the data if needed. */
225
            /* This call can't fail. */
226
0
            (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev,
227
0
                                 data + (ty - y) * raster, sourcex + tx - x,
228
0
                                                 raster, gx_no_bitmap_id,
229
0
                                           cx, 0, nx, ny, mcolor0, mcolor1);
230
            /* Now copy the color through the double mask. */
231
0
            code = (*dev_proc(cdev->target, copy_mono)) (cdev->target,
232
0
                                 cdev->buffer.bytes, cx, cdev->tiles.raster,
233
0
                                                         gx_no_bitmap_id,
234
0
                                  tx, ty, nx, ny, gx_no_color_index, color);
235
0
            if (code < 0)
236
0
                return code;
237
0
        }
238
0
    }
239
0
    return 0;
240
0
}
241
242
/*
243
 * Define the skeleton for the other copying operations.  We can't use the
244
 * BitBlt tricks: we have to scan for runs of 1s.  There are many obvious
245
 * ways to speed this up; we'll implement some if we need to.  The schema
246
 * is:
247
 *      FOR_RUNS(data_row, tx1, tx, ty) {
248
 *        ... process the run ([tx1,tx),ty) ...
249
 *      } END_FOR_RUNS();
250
 * Free variables: cdev, data, sourcex, raster, x, y, w, h.
251
 */
252
#define t_next(tx)\
253
741M
  BEGIN {\
254
741M
    if ( ++cx == cdev->tiles.size.x )\
255
741M
      cx = 0, tp = tile_row, tbit = 0x80;\
256
741M
    else if ( (tbit >>= 1) == 0 )\
257
376M
      tp++, tbit = 0x80;\
258
741M
    tx++;\
259
741M
  } END
260
#define FOR_RUNS(data_row, tx1, tx, ty)\
261
509k
        const byte *data_row = data;\
262
509k
        int cy;\
263
509k
        byte *tile_row;\
264
509k
         int ty;\
265
509k
\
266
509k
        if (cdev->tiles.rep_height == 0 || cdev->tiles.rep_width == 0)\
267
509k
            return 0;\
268
509k
        cy = imod(y + cdev->phase.y, cdev->tiles.rep_height);\
269
509k
        tile_row = cdev->tiles.data + cy * cdev->tiles.raster;\
270
509k
\
271
1.35M
        for ( ty = y; ty < y + h; ty++, data_row += raster ) {\
272
848k
          int cx = imod(x + x_offset(ty, cdev), cdev->tiles.rep_width);\
273
848k
          const byte *tp = tile_row + (cx >> 3);\
274
848k
          byte tbit = 0x80 >> (cx & 7);\
275
848k
          int tx;\
276
848k
\
277
1.00M
          for ( tx = x; tx < x + w; ) {\
278
969k
            int tx1;\
279
969k
\
280
969k
            /* Skip a run of 0s. */\
281
365M
            while ( tx < x + w && (*tp & tbit) == 0 )\
282
969k
              t_next(tx);\
283
969k
            if ( tx == x + w )\
284
969k
              break;\
285
969k
            /* Scan a run of 1s. */\
286
969k
            tx1 = tx;\
287
13.0M
            do {\
288
13.0M
              t_next(tx);\
289
13.0M
            } while ( tx < x + w && (*tp & tbit) != 0 );\
290
509k
            if_debug3m('T', cdev->memory, "[T]run x=(%d,%d), y=%d\n", tx1, tx, ty);
291
/* (body goes here) */
292
#define END_FOR_RUNS()\
293
155k
          }\
294
1.35M
          if ( ++cy == cdev->tiles.size.y )\
295
848k
            cy = 0, tile_row = cdev->tiles.data;\
296
848k
          else\
297
848k
            tile_row += cdev->tiles.raster;\
298
848k
        }
299
300
/* Copy a color rectangle. */
301
static int
302
tile_clip_copy_color(gx_device * dev,
303
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
304
                     int x, int y, int w, int h)
305
516k
{
306
516k
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
307
308
516k
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
309
509k
    {
310
1.97M
        FOR_RUNS(data_row, txrun, tx, ty) {
311
            /* Copy the run. */
312
1.97M
            int code = (*dev_proc(cdev->target, copy_color))
313
1.97M
            (cdev->target, data_row, sourcex + txrun - x, raster,
314
1.97M
             gx_no_bitmap_id, txrun, ty, tx - txrun, 1);
315
316
1.97M
            if (code < 0)
317
0
                return code;
318
1.97M
        }
319
1.97M
        END_FOR_RUNS();
320
509k
    }
321
0
    return 0;
322
509k
}
323
324
/* Copy a color rectangle. */
325
static int
326
tile_clip_copy_planes(gx_device * dev,
327
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
328
                     int x, int y, int w, int h, int plane_height)
329
0
{
330
0
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
331
332
0
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
333
0
    {
334
0
        FOR_RUNS(data_row, txrun, tx, ty) {
335
            /* Copy the run. */
336
0
            int code = (*dev_proc(cdev->target, copy_planes))
337
0
            (cdev->target, data_row, sourcex + txrun - x, raster,
338
0
             gx_no_bitmap_id, txrun, ty, tx - txrun, 1, plane_height);
339
340
0
            if (code < 0)
341
0
                return code;
342
0
        }
343
0
        END_FOR_RUNS();
344
0
    }
345
0
    return 0;
346
0
}
347
348
349
/* Copy an alpha rectangle similarly. */
350
static int
351
tile_clip_copy_alpha(gx_device * dev,
352
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
353
                int x, int y, int w, int h, gx_color_index color, int depth)
354
0
{
355
0
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
356
357
0
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
358
0
    {
359
0
        FOR_RUNS(data_row, txrun, tx, ty) {
360
            /* Copy the run. */
361
0
            int code = (*dev_proc(cdev->target, copy_alpha))
362
0
            (cdev->target, data_row, sourcex + txrun - x, raster,
363
0
             gx_no_bitmap_id, txrun, ty, tx - txrun, 1, color, depth);
364
365
0
            if (code < 0)
366
0
                return code;
367
0
        }
368
0
        END_FOR_RUNS();
369
0
    }
370
0
    return 0;
371
0
}
372
373
static int
374
tile_clip_copy_alpha_hl_color(gx_device * dev,
375
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
376
                int x, int y, int w, int h, const gx_drawing_color *pdcolor,
377
                int depth)
378
0
{
379
0
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
380
381
0
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
382
0
    {
383
0
        FOR_RUNS(data_row, txrun, tx, ty) {
384
            /* Copy the run. */
385
0
            int code = (*dev_proc(cdev->target, copy_alpha_hl_color))
386
0
            (cdev->target, data_row, sourcex + txrun - x, raster,
387
0
             gx_no_bitmap_id, txrun, ty, tx - txrun, 1, pdcolor, depth);
388
389
0
            if (code < 0)
390
0
                return code;
391
0
        }
392
0
        END_FOR_RUNS();
393
0
    }
394
0
    return 0;
395
0
}
396
397
static int
398
tile_clip_strip_copy_rop2(gx_device * dev,
399
               const byte * data, int sourcex, uint raster, gx_bitmap_id id,
400
                         const gx_color_index * scolors,
401
           const gx_strip_bitmap * textures, const gx_color_index * tcolors,
402
                         int x, int y, int w, int h,
403
                       int phase_x, int phase_y, gs_logical_operation_t lop,
404
                       uint planar_height)
405
0
{
406
0
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
407
408
0
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
409
0
    {
410
0
        FOR_RUNS(data_row, txrun, tx, ty) {
411
            /* Copy the run. */
412
0
            int code = (*dev_proc(cdev->target, strip_copy_rop2))
413
0
            (cdev->target, data_row, sourcex + txrun - x, raster,
414
0
             gx_no_bitmap_id, scolors, textures, tcolors,
415
0
             txrun, ty, tx - txrun, 1, phase_x, phase_y, lop,
416
0
             planar_height);
417
418
0
            if (code < 0)
419
0
                return code;
420
0
        }
421
0
        END_FOR_RUNS();
422
0
    }
423
0
    return 0;
424
0
}