Coverage Report

Created: 2026-04-01 07:17

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