Coverage Report

Created: 2025-06-24 07:01

/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
246k
{
45
246k
    set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix);
46
246k
    set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
47
246k
    set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
48
246k
    set_dev_proc(dev, fill_rectangle, tile_clip_fill_rectangle);
49
246k
    set_dev_proc(dev, copy_mono, tile_clip_copy_mono);
50
246k
    set_dev_proc(dev, copy_color, tile_clip_copy_color);
51
246k
    set_dev_proc(dev, get_params, gx_forward_get_params);
52
246k
    set_dev_proc(dev, put_params, gx_forward_put_params);
53
246k
    set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
54
246k
    set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
55
246k
    set_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits);
56
246k
    set_dev_proc(dev, copy_alpha, tile_clip_copy_alpha);
57
246k
    set_dev_proc(dev, get_clipping_box, gx_forward_get_clipping_box);
58
246k
    set_dev_proc(dev, get_bits_rectangle, gx_forward_get_bits_rectangle);
59
246k
    set_dev_proc(dev, composite, gx_no_composite);
60
246k
    set_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params);
61
246k
    set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
62
246k
    set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
63
246k
    set_dev_proc(dev, encode_color, gx_forward_encode_color);
64
246k
    set_dev_proc(dev, decode_color, gx_forward_decode_color);
65
246k
    set_dev_proc(dev, fill_rectangle_hl_color, tile_clip_fill_rectangle_hl_color);
66
246k
    set_dev_proc(dev, include_color_space, gx_forward_include_color_space);
67
246k
    set_dev_proc(dev, fill_linear_color_scanline, gx_forward_fill_linear_color_scanline);
68
246k
    set_dev_proc(dev, fill_linear_color_trapezoid, gx_forward_fill_linear_color_trapezoid);
69
246k
    set_dev_proc(dev, fill_linear_color_triangle, gx_forward_fill_linear_color_triangle);
70
246k
    set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors);
71
246k
    set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params);
72
246k
    set_dev_proc(dev, fillpage, gx_forward_fillpage);
73
246k
    set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op);
74
246k
    set_dev_proc(dev, copy_planes, tile_clip_copy_planes);
75
246k
    set_dev_proc(dev, strip_copy_rop2, tile_clip_strip_copy_rop2);
76
246k
    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
246k
    set_dev_proc(dev, open_device, gx_default_open_device);
81
246k
    set_dev_proc(dev, sync_output, gx_default_sync_output);
82
246k
    set_dev_proc(dev, output_page, gx_default_output_page);
83
246k
    set_dev_proc(dev, close_device, gx_default_close_device);
84
246k
    set_dev_proc(dev, fill_path, gx_default_fill_path);
85
246k
    set_dev_proc(dev, stroke_path, gx_default_stroke_path);
86
246k
    set_dev_proc(dev, fill_mask, gx_default_fill_mask);
87
246k
    set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid);
88
246k
    set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram);
89
246k
    set_dev_proc(dev, fill_triangle, gx_default_fill_triangle);
90
246k
    set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
91
246k
    set_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle);
92
246k
    set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image);
93
246k
    set_dev_proc(dev, text_begin, gx_default_text_begin);
94
246k
    set_dev_proc(dev, strip_tile_rect_devn, gx_default_strip_tile_rect_devn);
95
246k
}
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
246k
{
109
246k
    int code =
110
246k
    gx_mask_clip_initialize(cdev, &gs_tile_clip_device,
111
246k
                            (const gx_bitmap *)tiles,
112
246k
                            tdev, 0, 0, NULL);  /* phase will be reset */
113
114
246k
    if (code >= 0) {
115
246k
        cdev->tiles = *tiles;
116
246k
        tile_clip_set_phase(cdev, px, py);
117
246k
    }
118
246k
    return code;
119
246k
}
120
121
void
122
tile_clip_free(gx_device_tile_clip *cdev)
123
246k
{
124
    /* release the target reference */
125
246k
    if(cdev->finalize)
126
246k
        cdev->finalize((gx_device *)cdev);  /* this also sets the target to NULL */
127
246k
    gs_free_object(cdev->memory, cdev, "tile_clip_free(cdev)");
128
246k
}
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
4.50M
{
134
4.50M
    cdev->phase.x = px;
135
4.50M
    cdev->phase.y = py;
136
4.50M
}
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
5.83k
{
144
5.83k
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
145
5.83k
    gx_device *tdev = cdev->target;
146
5.83k
    int x, y, w, h;
147
5.83k
    gx_device_color dcolor0, dcolor1;
148
5.83k
    int k;
149
150
    /* Have to pack the no color index into the pure device type */
151
5.83k
    dcolor0.type = gx_dc_type_pure;
152
5.83k
    dcolor0.colors.pure = gx_no_color_index;
153
    /* Have to set the dcolor1 to a non mask type */
154
5.83k
    dcolor1.type = gx_dc_type_devn;
155
379k
    for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
156
373k
        dcolor1.colors.devn.values[k] = pdcolor->colors.devn.values[k];
157
373k
    }
158
5.83k
    x = fixed2int(rect->p.x);
159
5.83k
    y = fixed2int(rect->p.y);
160
5.83k
    w = fixed2int(rect->q.x) - x;
161
5.83k
    h = fixed2int(rect->q.y) - y;
162
5.83k
    return (*dev_proc(tdev, strip_tile_rect_devn))(tdev, &cdev->tiles,
163
5.83k
                                                    x, y, w, h, &dcolor0, &dcolor1,
164
5.83k
                                                    cdev->phase.x, cdev->phase.y);
165
5.83k
}
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
45.0k
{
172
45.0k
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
173
45.0k
    gx_device *tdev = cdev->target;
174
175
45.0k
    return (*dev_proc(tdev, strip_tile_rectangle)) (tdev, &cdev->tiles,
176
45.0k
                                                    x, y, w, h,
177
45.0k
                    gx_no_color_index, color, cdev->phase.x, cdev->phase.y);
178
45.0k
}
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
6.91M
  ((cdev)->phase.x + (((ty) + (cdev)->phase.y) / (cdev)->tiles.rep_height) *\
184
6.91M
   (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
229
{
195
229
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
196
229
    gx_color_index color, mcolor0, mcolor1;
197
229
    int ty, ny;
198
229
    int code;
199
200
229
    setup_mask_copy_mono(cdev, color, mcolor0, mcolor1);
201
458
    for (ty = y; ty < y + h; ty += ny) {
202
229
        int tx, nx;
203
229
        int cy;
204
229
        int xoff;
205
206
229
        if (cdev->tiles.rep_height == 0 || cdev->tiles.rep_width == 0)
207
0
            return 0;
208
209
229
        cy = (ty + cdev->phase.y) % cdev->tiles.rep_height;
210
229
        xoff = x_offset(ty, cdev);
211
212
229
        ny = min(y + h - ty, cdev->tiles.size.y - cy);
213
229
        if (ny > cdev->mdev.height)
214
0
            ny = cdev->mdev.height;
215
458
        for (tx = x; tx < x + w; tx += nx) {
216
229
            int cx = (tx + xoff) % cdev->tiles.rep_width;
217
218
229
            nx = min(x + w - tx, cdev->tiles.size.x - cx);
219
            /* Copy a tile slice to the memory device buffer. */
220
229
            memcpy(cdev->buffer.bytes,
221
229
                   cdev->tiles.data + cy * cdev->tiles.raster,
222
229
                   (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
229
            (*dev_proc(&cdev->mdev, copy_mono)) ((gx_device *) & cdev->mdev,
227
229
                                 data + (ty - y) * raster, sourcex + tx - x,
228
229
                                                 raster, gx_no_bitmap_id,
229
229
                                           cx, 0, nx, ny, mcolor0, mcolor1);
230
            /* Now copy the color through the double mask. */
231
229
            code = (*dev_proc(cdev->target, copy_mono)) (cdev->target,
232
229
                                 cdev->buffer.bytes, cx, cdev->tiles.raster,
233
229
                                                         gx_no_bitmap_id,
234
229
                                  tx, ty, nx, ny, gx_no_color_index, color);
235
229
            if (code < 0)
236
0
                return code;
237
229
        }
238
229
    }
239
229
    return 0;
240
229
}
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
5.89G
  BEGIN {\
254
5.89G
    if ( ++cx == cdev->tiles.size.x )\
255
5.89G
      cx = 0, tp = tile_row, tbit = 0x80;\
256
5.89G
    else if ( (tbit >>= 1) == 0 )\
257
2.99G
      tp++, tbit = 0x80;\
258
5.89G
    tx++;\
259
5.89G
  } END
260
#define FOR_RUNS(data_row, tx1, tx, ty)\
261
4.20M
        const byte *data_row = data;\
262
4.20M
        int cy;\
263
4.20M
        byte *tile_row;\
264
4.20M
         int ty;\
265
4.20M
\
266
4.20M
        if (cdev->tiles.rep_height == 0 || cdev->tiles.rep_width == 0)\
267
4.20M
            return 0;\
268
4.20M
        cy = imod(y + cdev->phase.y, cdev->tiles.rep_height);\
269
4.20M
        tile_row = cdev->tiles.data + cy * cdev->tiles.raster;\
270
4.20M
\
271
11.1M
        for ( ty = y; ty < y + h; ty++, data_row += raster ) {\
272
6.91M
          int cx = imod(x + x_offset(ty, cdev), cdev->tiles.rep_width);\
273
6.91M
          const byte *tp = tile_row + (cx >> 3);\
274
6.91M
          byte tbit = 0x80 >> (cx & 7);\
275
6.91M
          int tx;\
276
6.91M
\
277
8.35M
          for ( tx = x; tx < x + w; ) {\
278
7.89M
            int tx1;\
279
7.89M
\
280
7.89M
            /* Skip a run of 0s. */\
281
2.90G
            while ( tx < x + w && (*tp & tbit) == 0 )\
282
7.89M
              t_next(tx);\
283
7.89M
            if ( tx == x + w )\
284
7.89M
              break;\
285
7.89M
            /* Scan a run of 1s. */\
286
7.89M
            tx1 = tx;\
287
93.7M
            do {\
288
93.7M
              t_next(tx);\
289
93.7M
            } while ( tx < x + w && (*tp & tbit) != 0 );\
290
4.20M
            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
1.43M
          }\
294
11.1M
          if ( ++cy == cdev->tiles.size.y )\
295
6.91M
            cy = 0, tile_row = cdev->tiles.data;\
296
6.91M
          else\
297
6.91M
            tile_row += cdev->tiles.raster;\
298
6.91M
        }
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
3.48M
{
306
3.48M
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
307
308
3.48M
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
309
3.42M
    {
310
13.5M
        FOR_RUNS(data_row, txrun, tx, ty) {
311
            /* Copy the run. */
312
13.5M
            int code = (*dev_proc(cdev->target, copy_color))
313
13.5M
            (cdev->target, data_row, sourcex + txrun - x, raster,
314
13.5M
             gx_no_bitmap_id, txrun, ty, tx - txrun, 1);
315
316
13.5M
            if (code < 0)
317
0
                return code;
318
13.5M
        }
319
13.5M
        END_FOR_RUNS();
320
3.42M
    }
321
0
    return 0;
322
3.42M
}
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
781k
{
330
781k
    gx_device_tile_clip *cdev = (gx_device_tile_clip *) dev;
331
332
781k
    fit_copy(dev, data, sourcex, raster, id, x, y, w, h);
333
774k
    {
334
2.68M
        FOR_RUNS(data_row, txrun, tx, ty) {
335
            /* Copy the run. */
336
2.68M
            int code = (*dev_proc(cdev->target, copy_planes))
337
2.68M
            (cdev->target, data_row, sourcex + txrun - x, raster,
338
2.68M
             gx_no_bitmap_id, txrun, ty, tx - txrun, 1, plane_height);
339
340
2.68M
            if (code < 0)
341
0
                return code;
342
2.68M
        }
343
2.68M
        END_FOR_RUNS();
344
774k
    }
345
0
    return 0;
346
774k
}
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
}