Coverage Report

Created: 2025-06-10 07:17

/src/ghostpdl/base/gxclip.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
/* Implementation of (path-based) clipping */
18
#include "gx.h"
19
#include "gxdevice.h"
20
#include "gxclip.h"
21
#include "gxpath.h"
22
#include "gxcpath.h"
23
#include "gzcpath.h"
24
#include "gsutil.h"  /* For gs_next_ids */
25
26
/* Define whether to look for vertical clipping regions. */
27
#define CHECK_VERTICAL_CLIPPING
28
29
/* ------ Rectangle list clipper ------ */
30
31
/* Device for clipping with a region. */
32
/* We forward non-drawing operations, but we must be sure to intercept */
33
/* all drawing operations. */
34
static dev_proc_open_device(clip_open);
35
static dev_proc_fill_rectangle(clip_fill_rectangle);
36
static dev_proc_fill_rectangle_hl_color(clip_fill_rectangle_hl_color);
37
static dev_proc_copy_mono(clip_copy_mono);
38
static dev_proc_copy_planes(clip_copy_planes);
39
static dev_proc_copy_color(clip_copy_color);
40
static dev_proc_copy_alpha(clip_copy_alpha);
41
static dev_proc_copy_alpha_hl_color(clip_copy_alpha_hl_color);
42
static dev_proc_fill_mask(clip_fill_mask);
43
static dev_proc_strip_tile_rectangle(clip_strip_tile_rectangle);
44
static dev_proc_strip_tile_rect_devn(clip_strip_tile_rect_devn);
45
static dev_proc_strip_copy_rop2(clip_strip_copy_rop2);
46
static dev_proc_get_clipping_box(clip_get_clipping_box);
47
static dev_proc_get_bits_rectangle(clip_get_bits_rectangle);
48
static dev_proc_fill_path(clip_fill_path);
49
static dev_proc_transform_pixel_region(clip_transform_pixel_region);
50
static dev_proc_fill_stroke_path(clip_fill_stroke_path);
51
52
/* The device descriptor. */
53
static void
54
clipper_initialize_device_procs(gx_device *dev)
55
663k
{
56
663k
    set_dev_proc(dev, open_device, clip_open);
57
663k
    set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix);
58
663k
    set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
59
663k
    set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
60
663k
    set_dev_proc(dev, fill_rectangle, clip_fill_rectangle);
61
663k
    set_dev_proc(dev, copy_mono, clip_copy_mono);
62
663k
    set_dev_proc(dev, copy_color, clip_copy_color);
63
663k
    set_dev_proc(dev, get_params, gx_forward_get_params);
64
663k
    set_dev_proc(dev, put_params, gx_forward_put_params);
65
663k
    set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
66
663k
    set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
67
663k
    set_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits);
68
663k
    set_dev_proc(dev, copy_alpha, clip_copy_alpha);
69
663k
    set_dev_proc(dev, fill_path, clip_fill_path);
70
663k
    set_dev_proc(dev, fill_mask, clip_fill_mask);
71
663k
    set_dev_proc(dev, strip_tile_rectangle, clip_strip_tile_rectangle);
72
663k
    set_dev_proc(dev, get_clipping_box, clip_get_clipping_box);
73
663k
    set_dev_proc(dev, get_bits_rectangle, clip_get_bits_rectangle);
74
663k
    set_dev_proc(dev, composite, gx_forward_composite);
75
663k
    set_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params);
76
663k
    set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
77
663k
    set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
78
663k
    set_dev_proc(dev, encode_color, gx_forward_encode_color);
79
663k
    set_dev_proc(dev, decode_color, gx_forward_decode_color);
80
663k
    set_dev_proc(dev, fill_rectangle_hl_color, clip_fill_rectangle_hl_color);
81
663k
    set_dev_proc(dev, include_color_space, gx_forward_include_color_space);
82
663k
    set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors);
83
663k
    set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params);
84
663k
    set_dev_proc(dev, fillpage, gx_forward_fillpage);
85
663k
    set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op);
86
663k
    set_dev_proc(dev, copy_planes, clip_copy_planes);
87
663k
    set_dev_proc(dev, get_profile, gx_forward_get_profile);
88
663k
    set_dev_proc(dev, set_graphics_type_tag, gx_forward_set_graphics_type_tag);
89
663k
    set_dev_proc(dev, strip_copy_rop2, clip_strip_copy_rop2);
90
663k
    set_dev_proc(dev, strip_tile_rect_devn, clip_strip_tile_rect_devn);
91
663k
    set_dev_proc(dev, copy_alpha_hl_color, clip_copy_alpha_hl_color);
92
663k
    set_dev_proc(dev, transform_pixel_region, clip_transform_pixel_region);
93
663k
    set_dev_proc(dev, fill_stroke_path, clip_fill_stroke_path);
94
    /* Ideally the following defaults would be filled in for us, but that
95
     * doesn't work at the moment. */
96
663k
    set_dev_proc(dev, sync_output, gx_default_sync_output);
97
663k
    set_dev_proc(dev, output_page, gx_default_output_page);
98
663k
    set_dev_proc(dev, close_device, gx_default_close_device);
99
663k
    set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
100
663k
    set_dev_proc(dev, stroke_path, gx_default_stroke_path);
101
663k
    set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid);
102
663k
    set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram);
103
663k
    set_dev_proc(dev, fill_triangle, gx_default_fill_triangle);
104
663k
    set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
105
663k
    set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image);
106
663k
    set_dev_proc(dev, text_begin, gx_default_text_begin);
107
663k
    set_dev_proc(dev, fill_linear_color_scanline, gx_default_fill_linear_color_scanline);
108
663k
    set_dev_proc(dev, fill_linear_color_trapezoid, gx_default_fill_linear_color_trapezoid);
109
663k
    set_dev_proc(dev, fill_linear_color_triangle, gx_default_fill_linear_color_triangle);
110
663k
}
111
112
void
113
gx_device_clip_finalize(const gs_memory_t *cmem, void *vpdev)
114
54.8k
{
115
54.8k
    gx_device_clip *dev = (gx_device_clip *)vpdev;
116
117
54.8k
    if (dev->target != NULL) {
118
54.8k
        rc_decrement(dev->target, "gx_device_clip_finalize");
119
54.8k
        dev->target = NULL;
120
54.8k
    }
121
54.8k
    if (dev->rect_list != NULL) {
122
54.8k
        rc_decrement(dev->rect_list, "finalizing clipper device");
123
54.8k
        dev->rect_list = NULL;
124
54.8k
    }
125
54.8k
}
126
127
static const gx_device_clip gs_clip_device =
128
{std_device_std_body(gx_device_clip,
129
                     clipper_initialize_device_procs, "clipper",
130
                     0, 0, 1, 1)
131
};
132
133
/* Make a clipping device. */
134
void
135
gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target)
136
608k
{
137
608k
    gx_device_init_on_stack((gx_device *)dev, (const gx_device *)&gs_clip_device, target->memory);
138
608k
    dev->cpath = pcpath;
139
608k
    dev->list = *gx_cpath_list(pcpath);
140
    /* NOTE we do not count up the rect list even though we've taken a reference to it.
141
     * this is because we would then need to count it down in gx_destroy_clip_device_on_stack
142
     * and I have found at least one place where we do not call that function (!)
143
     * We should be safe though, the clip rectangle list should not disappear before we
144
     * exit the calling function at which point this device will disappear too.
145
     */
146
608k
    dev->translation.x = 0;
147
608k
    dev->translation.y = 0;
148
608k
    dev->HWResolution[0] = target->HWResolution[0];
149
608k
    dev->HWResolution[1] = target->HWResolution[1];
150
608k
    dev->sgr = target->sgr;
151
608k
    gx_device_set_target((gx_device_forward *)dev, target);
152
608k
    dev->pad = target->pad;
153
608k
    dev->log2_align_mod = target->log2_align_mod;
154
608k
    dev->num_planar_planes = target->num_planar_planes;
155
608k
    dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */
156
608k
    dev->non_strict_bounds = target->non_strict_bounds;
157
    /* There is no finalization for device on stack so no rc increment */
158
608k
    (*dev_proc(dev, open_device)) ((gx_device *)dev);
159
608k
}
160
161
void
162
gx_destroy_clip_device_on_stack(gx_device_clip * dev)
163
608k
{
164
608k
    if (dev->target != NULL)
165
608k
        rc_decrement(dev->target, "gx_destroy_clip_device_on_stack");
166
608k
    if (dev->cpath)
167
608k
        ((gx_clip_path *)dev->cpath)->cached = (dev->current == &dev->list.single ? NULL : dev->current); /* Cast away const */
168
608k
}
169
170
gx_device *
171
gx_make_clip_device_on_stack_if_needed(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, gs_fixed_rect *rect)
172
2.08k
{
173
    /* Reduce area if possible */
174
2.08k
    if (rect->p.x < pcpath->outer_box.p.x)
175
2
        rect->p.x = pcpath->outer_box.p.x;
176
2.08k
    if (rect->q.x > pcpath->outer_box.q.x)
177
21
        rect->q.x = pcpath->outer_box.q.x;
178
2.08k
    if (rect->p.y < pcpath->outer_box.p.y)
179
11
        rect->p.y = pcpath->outer_box.p.y;
180
2.08k
    if (rect->q.y > pcpath->outer_box.q.y)
181
12
        rect->q.y = pcpath->outer_box.q.y;
182
    /* Check for area being trivially clipped away. */
183
2.08k
    if (rect->p.x >= rect->q.x || rect->p.y >= rect->q.y)
184
23
        return NULL;
185
2.05k
    if (pcpath->inner_box.p.x <= rect->p.x && pcpath->inner_box.p.y <= rect->p.y &&
186
2.05k
        pcpath->inner_box.q.x >= rect->q.x && pcpath->inner_box.q.y >= rect->q.y)
187
2.05k
    {
188
        /* Area is trivially included. No need for clip. */
189
2.05k
        return target;
190
2.05k
    }
191
4
    gx_device_init_on_stack((gx_device *)dev, (const gx_device *)&gs_clip_device, target->memory);
192
4
    dev->list = *gx_cpath_list(pcpath);
193
4
    dev->translation.x = 0;
194
4
    dev->translation.y = 0;
195
4
    dev->HWResolution[0] = target->HWResolution[0];
196
4
    dev->HWResolution[1] = target->HWResolution[1];
197
4
    dev->sgr = target->sgr;
198
4
    gx_device_set_target((gx_device_forward *)dev, target);
199
4
    dev->pad = target->pad;
200
4
    dev->log2_align_mod = target->log2_align_mod;
201
4
    dev->num_planar_planes = target->num_planar_planes;
202
4
    dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */
203
4
    dev->non_strict_bounds = target->non_strict_bounds;
204
    /* There is no finalization for device on stack so no rc increment */
205
4
    (*dev_proc(dev, open_device)) ((gx_device *)dev);
206
4
    return (gx_device *)dev;
207
2.05k
}
208
void
209
gx_make_clip_device_in_heap(gx_device_clip *dev,
210
                      const gx_clip_path   *pcpath,
211
                            gx_device      *target,
212
                            gs_memory_t    *mem)
213
54.8k
{
214
    /* Can never fail */
215
54.8k
    (void)gx_device_init((gx_device *)dev,
216
54.8k
                         (const gx_device *)&gs_clip_device, mem, true);
217
54.8k
    dev->list = *gx_cpath_list(pcpath);
218
54.8k
    dev->rect_list = pcpath->rect_list;
219
    /* Bug #706771 we must make sure that the clip rectangle list does not
220
     * vanish while we still have a pointer to it. Do that by increasing the
221
     * reference count (obviously). We will decrement it in the device's finalize
222
     * routine.
223
     */
224
54.8k
    rc_increment(dev->rect_list);
225
54.8k
    dev->translation.x = 0;
226
54.8k
    dev->translation.y = 0;
227
54.8k
    dev->HWResolution[0] = target->HWResolution[0];
228
54.8k
    dev->HWResolution[1] = target->HWResolution[1];
229
54.8k
    dev->sgr = target->sgr;
230
54.8k
    dev->pad = target->pad;
231
54.8k
    dev->log2_align_mod = target->log2_align_mod;
232
54.8k
    dev->num_planar_planes = target->num_planar_planes;
233
54.8k
    dev->non_strict_bounds = target->non_strict_bounds;
234
54.8k
    gx_device_set_target((gx_device_forward *)dev, target);
235
54.8k
    gx_device_retain((gx_device *)dev, true); /* will free explicitly */
236
    /* Can never fail */
237
54.8k
    (void)(*dev_proc(dev, open_device)) ((gx_device *)dev);
238
54.8k
}
239
/* Define debugging statistics for the clipping loops. */
240
/* #define COLLECT_STATS_CLIP */
241
242
#ifdef COLLECT_STATS_CLIP
243
struct stats_clip_s {
244
    long
245
         loops, out, in_y, in, in1, down, up, x, no_x;
246
} stats_clip;
247
248
static const uint clip_interval = 10000;
249
250
# define INCR(v) (++(stats_clip.v))
251
# define INCR_THEN(v, e) (INCR(v), (e))
252
#else
253
38.2M
# define INCR(v) DO_NOTHING
254
28.3M
# define INCR_THEN(v, e) (e)
255
#endif
256
257
/*
258
 * Enumerate the rectangles of the x,w,y,h argument that fall within
259
 * the clipping region.
260
 * NB: if the clip list is transposed, then x, y, xe, and ye are already
261
 *     transposed and will need to be switched for the call to "process"
262
 */
263
static int
264
clip_enumerate_rest(gx_device_clip * rdev,
265
                    int x, int y, int xe, int ye,
266
                    int (*process)(clip_callback_data_t * pccd,
267
                                   int xc, int yc, int xec, int yec),
268
                    clip_callback_data_t * pccd)
269
2.69M
{
270
2.69M
    gx_clip_rect *rptr = rdev->current;   /* const within algorithm */
271
2.69M
    int yc;
272
2.69M
    int code;
273
274
#ifdef COLLECT_STATS_CLIP
275
    if (INCR(loops) % clip_interval == 0 && gs_debug_c('q')) {
276
        dmprintf5(rdev->memory,
277
                  "[q]loops=%ld out=%ld in_y=%ld in=%ld in1=%ld\n",
278
                  stats_clip.loops, stats_clip.out, stats_clip.in,
279
                  stats_clip.in_y, stats_clip.in1);
280
        dmprintf4(rdev->memory,
281
                  "[q]   down=%ld up=%ld x=%ld no_x=%ld\n",
282
                  stats_clip.down, stats_clip.up, stats_clip.x,
283
                  stats_clip.no_x);
284
    }
285
#endif
286
    /*
287
     * Warp the cursor forward or backward to the first rectangle row
288
     * that could include a given y value.  Assumes rptr is set, and
289
     * updates it.  Specifically, after this loop, either rptr == 0 (if
290
     * the y value is greater than all y values in the list), or y <
291
     * rptr->ymax and either rptr->prev == 0 or y >= rptr->prev->ymax.
292
     * Note that y <= rptr->ymin is possible.
293
     *
294
     * In the first case below, the while loop is safe because if there
295
     * is more than one rectangle, there is a 'stopper' at the end of
296
     * the list.
297
     */
298
2.69M
    if (y >= rptr->ymax) {
299
        /* Bug 706875: The 'stopper' here is a rectangle from (max_int, max_int) to
300
         * (max_int, max_int). Hence it doesn't 'stop' cases when y == max_int.
301
         * These shouldn't really happen, but let's be sure. */
302
1.15M
        if (y == max_int)
303
0
            return 0;
304
1.15M
        if ((rptr = rptr->next) != 0)
305
11.8M
            while (INCR_THEN(up, y >= rptr->ymax))
306
10.6M
                rptr = rptr->next;
307
1.15M
    } else
308
16.8M
        while (rptr->prev != 0 && y < rptr->prev->ymax)
309
15.3M
            INCR_THEN(down, rptr = rptr->prev);
310
2.69M
    if (rptr == 0 || (yc = rptr->ymin) >= ye) {
311
166k
        INCR(out);
312
166k
        if (rdev->list.count > 1)
313
166k
            rdev->current =
314
166k
                (rptr != 0 ? rptr :
315
166k
                 y >= rdev->current->ymax ? rdev->list.tail :
316
0
                 rdev->list.head);
317
166k
        return 0;
318
166k
    }
319
2.52M
    rdev->current = rptr;
320
2.52M
    if (yc < y)
321
571k
        yc = y;
322
323
2.62M
    do {
324
2.62M
        const int ymax = rptr->ymax;
325
2.62M
        int yec = min(ymax, ye);
326
327
2.62M
        if_debug2m('Q', rdev->memory, "[Q]yc=%d yec=%d\n", yc, yec);
328
3.16M
        do {
329
3.16M
            int xc = rptr->xmin;
330
3.16M
            int xec = rptr->xmax;
331
332
3.16M
            if (xc < x)
333
2.71M
                xc = x;
334
3.16M
            if (xec > xe)
335
2.19M
                xec = xe;
336
3.16M
            if (xec > xc) {
337
2.06M
                clip_rect_print('Q', "match", rptr);
338
2.06M
                if_debug2m('Q', rdev->memory, "[Q]xc=%d xec=%d\n", xc, xec);
339
2.06M
                INCR(x);
340
/*
341
 * Conditionally look ahead to detect unclipped vertical strips.  This is
342
 * really only valuable for 90 degree rotated images or (nearly-)vertical
343
 * lines with convex clipping regions; if we ever change images to use
344
 * source buffering and destination-oriented enumeration, we could probably
345
 * take out the code here with no adverse effects.
346
 */
347
2.06M
#ifdef CHECK_VERTICAL_CLIPPING
348
2.06M
                if (xec - xc == pccd->w) { /* full width */
349
                    /* Look ahead for a vertical swath. */
350
1.96M
                    while ((rptr = rptr->next) != 0 &&
351
1.96M
                           rptr->ymin == yec &&
352
1.96M
                           rptr->ymax <= ye &&
353
1.96M
                           rptr->xmin <= x &&
354
1.96M
                           rptr->xmax >= xe
355
1.91M
                           )
356
50.3k
                        yec = rptr->ymax;
357
1.91M
                } else
358
146k
                    rptr = rptr->next;
359
#else
360
                rptr = rptr->next;
361
#endif
362
2.06M
                if (rdev->list.transpose)
363
0
                    code = process(pccd, yc, xc, yec, xec);
364
2.06M
                else
365
2.06M
                    code = process(pccd, xc, yc, xec, yec);
366
2.06M
                if (code < 0)
367
0
                    return code;
368
2.06M
            } else {
369
1.10M
                INCR_THEN(no_x, rptr = rptr->next);
370
1.10M
            }
371
3.16M
            if (rptr == 0)
372
6.87k
                return 0;
373
3.16M
        }
374
3.15M
        while (rptr->ymax == ymax);
375
2.62M
    } while ((yc = rptr->ymin) < ye);
376
2.52M
    return 0;
377
2.52M
}
378
379
static int
380
clip_enumerate(gx_device_clip * rdev, int x, int y, int w, int h,
381
               int (*process)(clip_callback_data_t * pccd,
382
                              int xc, int yc, int xec, int yec),
383
               clip_callback_data_t * pccd)
384
71.6k
{
385
71.6k
    int xe, ye;
386
71.6k
    const gx_clip_rect *rptr = rdev->current;
387
388
71.6k
    if (w <= 0 || h <= 0)
389
0
        return 0;
390
71.6k
    pccd->tdev = rdev->target;
391
71.6k
    x += rdev->translation.x;
392
71.6k
    xe = x + w;
393
71.6k
    y += rdev->translation.y;
394
71.6k
    ye = y + h;
395
    /* pccd is non-transposed */
396
71.6k
    pccd->x = x, pccd->y = y;
397
71.6k
    pccd->w = w, pccd->h = h;
398
    /* transpose x, y, xe, ye for clip checking */
399
71.6k
    if (rdev->list.transpose) {
400
0
        x = pccd->y;
401
0
        y = pccd->x;
402
0
        xe = x + h;
403
0
        ye = y + w;
404
0
    }
405
    /* Check for the region being entirely within the current rectangle. */
406
71.6k
    if (y >= rptr->ymin && ye <= rptr->ymax &&
407
71.6k
        x >= rptr->xmin && xe <= rptr->xmax
408
71.6k
        ) {
409
64.9k
        if (rdev->list.transpose) {
410
0
            return INCR_THEN(in, process(pccd, y, x, ye, xe));
411
64.9k
        } else {
412
64.9k
            return INCR_THEN(in, process(pccd, x, y, xe, ye));
413
64.9k
        }
414
64.9k
    }
415
6.77k
    return clip_enumerate_rest(rdev, x, y, xe, ye, process, pccd);
416
71.6k
}
417
418
/* Open a clipping device */
419
static int
420
clip_open(gx_device * dev)
421
663k
{
422
663k
    gx_device_clip *const rdev = (gx_device_clip *) dev;
423
663k
    gx_device *tdev = rdev->target;
424
425
    /* Initialize the cursor. */
426
663k
    rdev->current =
427
663k
        (rdev->list.head == 0 ? &rdev->list.single : (rdev->cpath && rdev->cpath->cached ? rdev->cpath->cached : rdev->list.head));
428
663k
    rdev->color_info = tdev->color_info;
429
663k
    rdev->cached_colors = tdev->cached_colors;
430
663k
    rdev->width = tdev->width;
431
663k
    rdev->height = tdev->height;
432
663k
    gx_device_copy_color_procs(dev, tdev);
433
663k
    rdev->clipping_box_set = false;
434
663k
    rdev->memory = tdev->memory;
435
663k
    return 0;
436
663k
}
437
438
/* Fill a rectangle */
439
int
440
clip_call_fill_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
441
2.05M
{
442
2.05M
    return (*dev_proc(pccd->tdev, fill_rectangle))
443
2.05M
        (pccd->tdev, xc, yc, xec - xc, yec - yc, pccd->color[0]);
444
2.05M
}
445
static int
446
clip_fill_rectangle_t0(gx_device * dev, int x, int y, int w, int h,
447
                       gx_color_index color)
448
21.0M
{
449
21.0M
    gx_device_clip *rdev = (gx_device_clip *) dev;
450
21.0M
    clip_callback_data_t ccdata;
451
    /* We handle the fastest cases in-line here. */
452
21.0M
    gx_device *tdev = rdev->target;
453
21.0M
    /*const*/ gx_clip_rect *rptr = rdev->current;
454
21.0M
    int xe, ye;
455
456
21.0M
    if (w <= 0 || h <= 0)
457
451k
        return 0;
458
20.6M
    x += rdev->translation.x;
459
20.6M
    xe = x + w;
460
20.6M
    y += rdev->translation.y;
461
20.6M
    ye = y + h;
462
    /* ccdata is non-transposed */
463
20.6M
    ccdata.x = x, ccdata.y = y;
464
20.6M
    ccdata.w = w, ccdata.h = h;
465
    /* We open-code the most common cases here. */
466
20.6M
    if ((y >= rptr->ymin && ye <= rptr->ymax) ||
467
20.6M
        ((rptr = rptr->next) != 0 &&
468
6.30M
         y >= rptr->ymin && ye <= rptr->ymax)
469
20.6M
        ) {
470
18.0M
        rdev->current = rptr; /* may be redundant, but awkward to avoid */
471
18.0M
        INCR(in_y);
472
18.0M
        if (x >= rptr->xmin && xe <= rptr->xmax) {
473
16.5M
            INCR(in);
474
16.5M
            return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
475
16.5M
        }
476
1.55M
        else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
477
1.55M
                 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
478
1.55M
                 ) {
479
1.40M
            INCR(in1);
480
1.40M
            if (x < rptr->xmin)
481
460k
                x = rptr->xmin;
482
1.40M
            if (xe > rptr->xmax)
483
958k
                xe = rptr->xmax;
484
1.40M
            if (x >= xe)
485
1.23M
                 return 0;
486
169k
            return dev_proc(tdev, fill_rectangle)(tdev, x, y, xe - x, h, color);
487
1.40M
        }
488
18.0M
    }
489
2.68M
    ccdata.tdev = tdev;
490
2.68M
    ccdata.color[0] = color;
491
2.68M
    return clip_enumerate_rest(rdev, x, y, xe, ye, clip_call_fill_rectangle, &ccdata);
492
20.6M
}
493
494
static int
495
clip_fill_rectangle_t1(gx_device * dev, int x, int y, int w, int h,
496
                       gx_color_index color)
497
0
{
498
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
499
0
    clip_callback_data_t ccdata;
500
    /* We handle the fastest cases in-line here. */
501
0
    gx_device *tdev = rdev->target;
502
0
    /*const*/ gx_clip_rect *rptr = rdev->current;
503
0
    int xe, ye;
504
505
0
    if (w <= 0 || h <= 0)
506
0
        return 0;
507
0
    x += rdev->translation.x;
508
0
    y += rdev->translation.y;
509
    /* ccdata is non-transposed */
510
0
    ccdata.x = x, ccdata.y = y;
511
0
    ccdata.w = w, ccdata.h = h;
512
0
    x = ccdata.y;
513
0
    y = ccdata.x;
514
0
    xe = x + h;
515
0
    ye = y + w;
516
    /* We open-code the most common cases here. */
517
0
    if ((y >= rptr->ymin && ye <= rptr->ymax) ||
518
0
        ((rptr = rptr->next) != 0 &&
519
0
         y >= rptr->ymin && ye <= rptr->ymax)
520
0
        ) {
521
0
        rdev->current = rptr; /* may be redundant, but awkward to avoid */
522
0
        INCR(in_y);
523
0
        if (x >= rptr->xmin && xe <= rptr->xmax) {
524
0
            INCR(in);
525
0
            return dev_proc(tdev, fill_rectangle)(tdev, y, x, w, h, color);
526
0
        }
527
0
        else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
528
0
                 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
529
0
                 ) {
530
0
            INCR(in1);
531
0
            if (x < rptr->xmin)
532
0
                x = rptr->xmin;
533
0
            if (xe > rptr->xmax)
534
0
                xe = rptr->xmax;
535
0
            if (x >= xe)
536
0
                 return 0;
537
0
            return dev_proc(tdev, fill_rectangle)(tdev, y, x, w, xe - x, color);
538
0
        }
539
0
    }
540
0
    ccdata.tdev = tdev;
541
0
    ccdata.color[0] = color;
542
0
    return clip_enumerate_rest(rdev, x, y, xe, ye, clip_call_fill_rectangle, &ccdata);
543
0
}
544
545
static int
546
clip_fill_rectangle_s0(gx_device * dev, int x, int y, int w, int h,
547
                       gx_color_index color)
548
59.5M
{
549
59.5M
    gx_device_clip *rdev = (gx_device_clip *) dev;
550
59.5M
    gx_device *tdev = rdev->target;
551
552
59.5M
    if (w <= 0 || h <= 0)
553
46.4M
        return 0;
554
13.1M
    x += rdev->translation.x;
555
13.1M
    w += x;
556
13.1M
    y += rdev->translation.y;
557
13.1M
    h += y;
558
13.1M
    if (x < rdev->list.single.xmin)
559
615k
        x = rdev->list.single.xmin;
560
13.1M
    if (w > rdev->list.single.xmax)
561
2.10M
        w = rdev->list.single.xmax;
562
13.1M
    if (y < rdev->list.single.ymin)
563
757k
        y = rdev->list.single.ymin;
564
13.1M
    if (h > rdev->list.single.ymax)
565
422k
        h = rdev->list.single.ymax;
566
13.1M
    w -= x;
567
13.1M
    h -= y;
568
13.1M
    if (w <= 0 || h <= 0)
569
2.80M
        return 0;
570
10.2M
    return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
571
13.1M
}
572
573
static int
574
clip_fill_rectangle_s1(gx_device * dev, int x, int y, int w, int h,
575
                       gx_color_index color)
576
0
{
577
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
578
0
    gx_device *tdev = rdev->target;
579
580
0
    if (w <= 0 || h <= 0)
581
0
        return 0;
582
0
    x += rdev->translation.x;
583
0
    w += x;
584
0
    y += rdev->translation.y;
585
0
    h += y;
586
    /* Now, treat x/w as y/h and vice versa as transposed. */
587
0
    if (x < rdev->list.single.ymin)
588
0
        x = rdev->list.single.ymin;
589
0
    if (w > rdev->list.single.ymax)
590
0
        w = rdev->list.single.ymax;
591
0
    if (y < rdev->list.single.xmin)
592
0
        y = rdev->list.single.xmin;
593
0
    if (h > rdev->list.single.xmax)
594
0
        h = rdev->list.single.xmax;
595
0
    w -= x;
596
0
    h -= y;
597
0
    if (w <= 0 || h <= 0)
598
0
        return 0;
599
0
    return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
600
0
}
601
static int
602
clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
603
                    gx_color_index color)
604
11.3M
{
605
11.3M
    gx_device_clip *rdev = (gx_device_clip *) dev;
606
607
11.3M
    if (rdev->list.transpose) {
608
0
        if (rdev->list.count == 1)
609
0
            dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_s1;
610
0
        else
611
0
            dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_t1;
612
11.3M
    } else {
613
11.3M
        if (rdev->list.count == 1)
614
11.3M
            dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_s0;
615
16.8k
        else
616
16.8k
            dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_t0;
617
11.3M
    }
618
11.3M
    return dev_proc(rdev, fill_rectangle)(dev, x, y, w, h, color);
619
11.3M
}
620
621
int
622
clip_call_fill_rectangle_hl_color(clip_callback_data_t * pccd, int xc, int yc,
623
                                  int xec, int yec)
624
0
{
625
0
    gs_fixed_rect rect;
626
627
0
    rect.p.x = int2fixed(xc);
628
0
    rect.p.y = int2fixed(yc);
629
0
    rect.q.x = int2fixed(xec);
630
0
    rect.q.y = int2fixed(yec);
631
0
    return (*dev_proc(pccd->tdev, fill_rectangle_hl_color))
632
0
        (pccd->tdev, &rect, pccd->pgs, pccd->pdcolor, pccd->pcpath);
633
0
}
634
635
static int
636
clip_fill_rectangle_hl_color_t0(gx_device *dev, const gs_fixed_rect *rect,
637
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
638
    const gx_clip_path *pcpath)
639
0
{
640
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
641
0
    clip_callback_data_t ccdata;
642
0
    gx_device *tdev = rdev->target;
643
0
    gx_clip_rect *rptr = rdev->current;
644
0
    int xe, ye;
645
0
    int w, h, x, y;
646
0
    gs_fixed_rect newrect;
647
648
0
    x = fixed2int(rect->p.x);
649
0
    y = fixed2int(rect->p.y);
650
0
    w = fixed2int(rect->q.x) - x;
651
0
    h = fixed2int(rect->q.y) - y;
652
653
0
    if (w <= 0 || h <= 0)
654
0
        return 0;
655
0
    x += rdev->translation.x;
656
0
    xe = x + w;
657
0
    y += rdev->translation.y;
658
0
    ye = y + h;
659
    /* ccdata is non-transposed */
660
0
    ccdata.x = x, ccdata.y = y;
661
0
    ccdata.w = w, ccdata.h = h;
662
    /* We open-code the most common cases here. */
663
0
    if ((y >= rptr->ymin && ye <= rptr->ymax) ||
664
0
        ((rptr = rptr->next) != 0 &&
665
0
         y >= rptr->ymin && ye <= rptr->ymax)
666
0
        ) {
667
0
        rdev->current = rptr; /* may be redundant, but awkward to avoid */
668
0
        INCR(in_y);
669
0
        if (x >= rptr->xmin && xe <= rptr->xmax) {
670
0
            INCR(in);
671
0
            newrect.p.x = int2fixed(x);
672
0
            newrect.p.y = int2fixed(y);
673
0
            newrect.q.x = int2fixed(x + w);
674
0
            newrect.q.y = int2fixed(y + h);
675
0
            return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
676
0
                                                           pdcolor, pcpath);
677
0
        }
678
0
        else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
679
0
                 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
680
0
                 ) {
681
0
            INCR(in1);
682
0
            if (x < rptr->xmin)
683
0
                x = rptr->xmin;
684
0
            if (xe > rptr->xmax)
685
0
                xe = rptr->xmax;
686
0
            if (x >= xe)
687
0
                return 0;
688
0
            else {
689
0
                newrect.p.x = int2fixed(x);
690
0
                newrect.p.y = int2fixed(y);
691
0
                newrect.q.x = int2fixed(xe);
692
0
                newrect.q.y = int2fixed(y + h);
693
0
                return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
694
0
                                                               pdcolor, pcpath);
695
0
            }
696
0
        }
697
0
    }
698
0
    ccdata.tdev = tdev;
699
0
    ccdata.pdcolor = pdcolor;
700
0
    ccdata.pgs = pgs;
701
0
    ccdata.pcpath = pcpath;
702
0
    return clip_enumerate_rest(rdev, x, y, xe, ye,
703
0
                               clip_call_fill_rectangle_hl_color, &ccdata);
704
0
}
705
706
static int
707
clip_fill_rectangle_hl_color_t1(gx_device *dev, const gs_fixed_rect *rect,
708
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
709
    const gx_clip_path *pcpath)
710
0
{
711
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
712
0
    clip_callback_data_t ccdata;
713
0
    gx_device *tdev = rdev->target;
714
0
    gx_clip_rect *rptr = rdev->current;
715
0
    int xe, ye;
716
0
    int w, h, x, y;
717
0
    gs_fixed_rect newrect;
718
719
0
    x = fixed2int(rect->p.x);
720
0
    y = fixed2int(rect->p.y);
721
0
    w = fixed2int(rect->q.x) - x;
722
0
    h = fixed2int(rect->q.y) - y;
723
724
0
    if (w <= 0 || h <= 0)
725
0
        return 0;
726
0
    x += rdev->translation.x;
727
0
    y += rdev->translation.y;
728
    /* ccdata is non-transposed */
729
0
    ccdata.x = x, ccdata.y = y;
730
0
    ccdata.w = w, ccdata.h = h;
731
    /* transpose x, y, xe, ye for clip checking */
732
0
    x = ccdata.y;
733
0
    y = ccdata.x;
734
0
    xe = x + h;
735
0
    ye = y + w;
736
    /* We open-code the most common cases here. */
737
0
    if ((y >= rptr->ymin && ye <= rptr->ymax) ||
738
0
        ((rptr = rptr->next) != 0 &&
739
0
         y >= rptr->ymin && ye <= rptr->ymax)
740
0
        ) {
741
0
        rdev->current = rptr; /* may be redundant, but awkward to avoid */
742
0
        INCR(in_y);
743
0
        if (x >= rptr->xmin && xe <= rptr->xmax) {
744
0
            INCR(in);
745
0
            newrect.p.x = int2fixed(y);
746
0
            newrect.p.y = int2fixed(x);
747
0
            newrect.q.x = int2fixed(y + h);
748
0
            newrect.q.y = int2fixed(x + w);
749
0
            return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
750
0
                                                           pdcolor, pcpath);
751
0
        }
752
0
        else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
753
0
                 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
754
0
                 ) {
755
0
            INCR(in1);
756
0
            if (x < rptr->xmin)
757
0
                x = rptr->xmin;
758
0
            if (xe > rptr->xmax)
759
0
                xe = rptr->xmax;
760
0
            if (x >= xe)
761
0
                return 0;
762
0
            else {
763
0
                newrect.p.x = int2fixed(y);
764
0
                newrect.p.y = int2fixed(x);
765
0
                newrect.q.x = int2fixed(y+h);
766
0
                newrect.q.y = int2fixed(xe);
767
0
                return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
768
0
                                                               pdcolor, pcpath);
769
0
            }
770
0
        }
771
0
    }
772
0
    ccdata.tdev = tdev;
773
0
    ccdata.pdcolor = pdcolor;
774
0
    ccdata.pgs = pgs;
775
0
    ccdata.pcpath = pcpath;
776
0
    return clip_enumerate_rest(rdev, x, y, xe, ye,
777
0
                               clip_call_fill_rectangle_hl_color, &ccdata);
778
0
}
779
780
static int
781
clip_fill_rectangle_hl_color_s0(gx_device *dev, const gs_fixed_rect *rect,
782
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
783
    const gx_clip_path *pcpath)
784
0
{
785
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
786
0
    gx_device *tdev = rdev->target;
787
0
    int w, h, x, y;
788
0
    gs_fixed_rect newrect;
789
790
0
    x = fixed2int(rect->p.x);
791
0
    y = fixed2int(rect->p.y);
792
0
    w = fixed2int(rect->q.x) - x;
793
0
    h = fixed2int(rect->q.y) - y;
794
795
0
    if (w <= 0 || h <= 0)
796
0
        return 0;
797
0
    x += rdev->translation.x;
798
0
    w += x;
799
0
    y += rdev->translation.y;
800
0
    h += y;
801
0
    if (x < rdev->list.single.xmin)
802
0
        x = rdev->list.single.xmin;
803
0
    if (w > rdev->list.single.xmax)
804
0
        w = rdev->list.single.xmax;
805
0
    if (y < rdev->list.single.ymin)
806
0
        y = rdev->list.single.ymin;
807
0
    if (h > rdev->list.single.ymax)
808
0
        h = rdev->list.single.ymax;
809
0
    w -= x;
810
0
    h -= y;
811
0
    if (w <= 0 || h <= 0)
812
0
        return 0;
813
0
    newrect.p.x = int2fixed(x);
814
0
    newrect.p.y = int2fixed(y);
815
0
    newrect.q.x = int2fixed(x + w);
816
0
    newrect.q.y = int2fixed(y + h);
817
0
    return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
818
0
                                                   pdcolor, pcpath);
819
0
}
820
821
static int
822
clip_fill_rectangle_hl_color_s1(gx_device *dev, const gs_fixed_rect *rect,
823
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
824
    const gx_clip_path *pcpath)
825
0
{
826
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
827
0
    gx_device *tdev = rdev->target;
828
0
    int w, h, x, y;
829
0
    gs_fixed_rect newrect;
830
831
0
    x = fixed2int(rect->p.x);
832
0
    y = fixed2int(rect->p.y);
833
0
    w = fixed2int(rect->q.x) - x;
834
0
    h = fixed2int(rect->q.y) - y;
835
836
0
    if (w <= 0 || h <= 0)
837
0
        return 0;
838
0
    x += rdev->translation.x;
839
0
    w += x;
840
0
    y += rdev->translation.y;
841
0
    h += y;
842
    /* Now, treat x/w as y/h and vice versa as transposed. */
843
0
    if (x < rdev->list.single.ymin)
844
0
        x = rdev->list.single.ymin;
845
0
    if (w > rdev->list.single.ymax)
846
0
        w = rdev->list.single.ymax;
847
0
    if (y < rdev->list.single.xmin)
848
0
        y = rdev->list.single.xmin;
849
0
    if (h > rdev->list.single.xmax)
850
0
        h = rdev->list.single.xmax;
851
0
    w -= x;
852
0
    h -= y;
853
0
    if (w <= 0 || h <= 0)
854
0
        return 0;
855
0
    newrect.p.x = int2fixed(y);
856
0
    newrect.p.y = int2fixed(x);
857
0
    newrect.q.x = int2fixed(y + h);
858
0
    newrect.q.y = int2fixed(x + w);
859
0
    return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
860
0
                                                   pdcolor, pcpath);
861
0
}
862
863
static int
864
clip_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
865
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
866
    const gx_clip_path *pcpath)
867
0
{
868
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
869
870
0
    if (rdev->list.transpose) {
871
0
        if (rdev->list.count == 1)
872
0
            dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_s1;
873
0
        else
874
0
            dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_t1;
875
0
    } else {
876
0
        if (rdev->list.count == 1)
877
0
            dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_s0;
878
0
        else
879
0
            dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_t0;
880
0
    }
881
0
    return dev_proc(rdev, fill_rectangle_hl_color)(dev, rect, pgs, pdcolor, pcpath);
882
0
}
883
884
/* Copy a monochrome rectangle */
885
int
886
clip_call_copy_mono(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
887
5.51k
{
888
5.51k
    return (*dev_proc(pccd->tdev, copy_mono))
889
5.51k
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
890
5.51k
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
891
5.51k
         xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->color[1]);
892
5.51k
}
893
static int
894
clip_copy_mono_t0(gx_device * dev,
895
                  const byte * data, int sourcex, int raster, gx_bitmap_id id,
896
                  int x, int y, int w, int h,
897
                  gx_color_index color0, gx_color_index color1)
898
3.89k
{
899
3.89k
    gx_device_clip *rdev = (gx_device_clip *) dev;
900
3.89k
    clip_callback_data_t ccdata;
901
    /* We handle the fastest case in-line here. */
902
3.89k
    gx_device *tdev = rdev->target;
903
3.89k
    const gx_clip_rect *rptr = rdev->current;
904
3.89k
    int xe, ye;
905
906
3.89k
    if (w <= 0 || h <= 0)
907
0
        return 0;
908
3.89k
    x += rdev->translation.x;
909
3.89k
    xe = x + w;
910
3.89k
    y += rdev->translation.y;
911
3.89k
    ye = y + h;
912
    /* ccdata is non-transposed */
913
3.89k
    ccdata.x = x, ccdata.y = y;
914
3.89k
    ccdata.w = w, ccdata.h = h;
915
3.89k
    if (y >= rptr->ymin && ye <= rptr->ymax) {
916
103
        INCR(in_y);
917
103
        if (x >= rptr->xmin && xe <= rptr->xmax) {
918
0
            INCR(in);
919
0
            return dev_proc(tdev, copy_mono)
920
0
                    (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
921
0
        }
922
103
    }
923
3.89k
    ccdata.tdev = tdev;
924
3.89k
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
925
3.89k
    ccdata.color[0] = color0, ccdata.color[1] = color1;
926
3.89k
    return clip_enumerate_rest(rdev, x, y, xe, ye,
927
3.89k
                               clip_call_copy_mono, &ccdata);
928
3.89k
}
929
static int
930
clip_copy_mono_t1(gx_device * dev,
931
                  const byte * data, int sourcex, int raster, gx_bitmap_id id,
932
                  int x, int y, int w, int h,
933
                  gx_color_index color0, gx_color_index color1)
934
0
{
935
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
936
0
    clip_callback_data_t ccdata;
937
    /* We handle the fastest case in-line here. */
938
0
    gx_device *tdev = rdev->target;
939
0
    const gx_clip_rect *rptr = rdev->current;
940
0
    int xe, ye;
941
942
0
    if (w <= 0 || h <= 0)
943
0
        return 0;
944
0
    x += rdev->translation.x;
945
0
    y += rdev->translation.y;
946
    /* ccdata is non-transposed */
947
0
    ccdata.x = x, ccdata.y = y;
948
0
    ccdata.w = w, ccdata.h = h;
949
0
    x = ccdata.y;
950
0
    y = ccdata.x;
951
0
    xe = x + h;
952
0
    ye = y + w;
953
0
    if (y >= rptr->ymin && ye <= rptr->ymax) {
954
0
        INCR(in_y);
955
0
        if (x >= rptr->xmin && xe <= rptr->xmax) {
956
0
            INCR(in);
957
            /* Untranspose coords here. */
958
0
            return dev_proc(tdev, copy_mono)
959
0
                    (tdev, data, sourcex, raster, id, y, x, w, h, color0, color1);
960
0
        }
961
0
    }
962
0
    ccdata.tdev = tdev;
963
0
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
964
0
    ccdata.color[0] = color0, ccdata.color[1] = color1;
965
    /* Coords are passed in transposed here, but will appear untransposed at the end. */
966
0
    return clip_enumerate_rest(rdev, x, y, xe, ye,
967
0
                               clip_call_copy_mono, &ccdata);
968
0
}
969
static int
970
clip_copy_mono_s0(gx_device * dev,
971
                  const byte * data, int sourcex, int raster, gx_bitmap_id id,
972
                  int x, int y, int w, int h,
973
                  gx_color_index color0, gx_color_index color1)
974
347k
{
975
347k
    gx_device_clip *rdev = (gx_device_clip *) dev;
976
347k
    gx_device *tdev = rdev->target;
977
978
347k
    if (w <= 0 || h <= 0)
979
24
        return 0;
980
347k
    x += rdev->translation.x;
981
347k
    w += x;
982
347k
    y += rdev->translation.y;
983
347k
    h += y;
984
347k
    if (x < rdev->list.single.xmin)
985
169
    {
986
169
        sourcex += (rdev->list.single.xmin - x);
987
169
        x = rdev->list.single.xmin;
988
169
    }
989
347k
    if (w > rdev->list.single.xmax)
990
16.2k
        w = rdev->list.single.xmax;
991
347k
    if (y < rdev->list.single.ymin)
992
194k
    {
993
194k
        data += (rdev->list.single.ymin - y) * raster;
994
194k
        y = rdev->list.single.ymin;
995
194k
    }
996
347k
    if (h > rdev->list.single.ymax)
997
193k
        h = rdev->list.single.ymax;
998
347k
    w -= x;
999
347k
    h -= y;
1000
347k
    if (w <= 0 || h <= 0)
1001
11.9k
        return 0;
1002
335k
    return dev_proc(tdev, copy_mono)
1003
335k
                    (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
1004
347k
}
1005
static int
1006
clip_copy_mono_s1(gx_device * dev,
1007
                  const byte * data, int sourcex, int raster, gx_bitmap_id id,
1008
                  int x, int y, int w, int h,
1009
                  gx_color_index color0, gx_color_index color1)
1010
0
{
1011
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1012
0
    gx_device *tdev = rdev->target;
1013
1014
0
    if (w <= 0 || h <= 0)
1015
0
        return 0;
1016
0
    x += rdev->translation.x;
1017
0
    w += x;
1018
0
    y += rdev->translation.y;
1019
0
    h += y;
1020
    /* Now, treat x/w as y/h and vice versa as transposed. */
1021
0
    if (x < rdev->list.single.ymin)
1022
0
    {
1023
0
        data += (rdev->list.single.ymin - x) * raster;
1024
0
        x = rdev->list.single.ymin;
1025
0
    }
1026
0
    if (w > rdev->list.single.ymax)
1027
0
        w = rdev->list.single.ymax;
1028
0
    if (y < rdev->list.single.xmin)
1029
0
    {
1030
0
        sourcex += (rdev->list.single.xmin - y);
1031
0
        y = rdev->list.single.xmin;
1032
0
    }
1033
0
    if (h > rdev->list.single.xmax)
1034
0
        h = rdev->list.single.xmax;
1035
0
    w -= x;
1036
0
    h -= y;
1037
0
    if (w <= 0 || h <= 0)
1038
0
        return 0;
1039
0
    return dev_proc(tdev, copy_mono)
1040
0
                    (tdev, data, sourcex, raster, id, y, x, h, w, color0, color1);
1041
0
}
1042
static int
1043
clip_copy_mono(gx_device * dev,
1044
               const byte * data, int sourcex, int raster, gx_bitmap_id id,
1045
               int x, int y, int w, int h,
1046
               gx_color_index color0, gx_color_index color1)
1047
335k
{
1048
335k
    gx_device_clip *rdev = (gx_device_clip *) dev;
1049
1050
335k
    if (rdev->list.transpose) {
1051
0
        if (rdev->list.count == 1)
1052
0
            dev_proc(rdev, copy_mono) = clip_copy_mono_s1;
1053
0
        else
1054
0
            dev_proc(rdev, copy_mono) = clip_copy_mono_t1;
1055
335k
    } else {
1056
335k
        if (rdev->list.count == 1)
1057
331k
            dev_proc(rdev, copy_mono) = clip_copy_mono_s0;
1058
3.89k
        else
1059
3.89k
            dev_proc(rdev, copy_mono) = clip_copy_mono_t0;
1060
335k
    }
1061
335k
    return dev_proc(rdev, copy_mono)(dev, data, sourcex, raster, id, x, y, w, h, color0, color1);
1062
335k
}
1063
1064
/* Copy a plane */
1065
int
1066
clip_call_copy_planes(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1067
0
{
1068
0
    return (*dev_proc(pccd->tdev, copy_planes))
1069
0
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1070
0
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1071
0
         xc, yc, xec - xc, yec - yc, pccd->plane_height);
1072
0
}
1073
static int
1074
clip_copy_planes_t0(gx_device * dev,
1075
                    const byte * data, int sourcex, int raster, gx_bitmap_id id,
1076
                    int x, int y, int w, int h, int plane_height)
1077
0
{
1078
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1079
0
    clip_callback_data_t ccdata;
1080
    /* We handle the fastest case in-line here. */
1081
0
    gx_device *tdev = rdev->target;
1082
0
    const gx_clip_rect *rptr = rdev->current;
1083
0
    int xe, ye;
1084
1085
0
    if (w <= 0 || h <= 0)
1086
0
        return 0;
1087
0
    x += rdev->translation.x;
1088
0
    xe = x + w;
1089
0
    y += rdev->translation.y;
1090
0
    ye = y + h;
1091
    /* ccdata is non-transposed */
1092
0
    ccdata.x = x, ccdata.y = y;
1093
0
    ccdata.w = w, ccdata.h = h;
1094
0
    if (y >= rptr->ymin && ye <= rptr->ymax) {
1095
0
        INCR(in_y);
1096
0
        if (x >= rptr->xmin && xe <= rptr->xmax) {
1097
0
            INCR(in);
1098
0
            return dev_proc(tdev, copy_planes)
1099
0
                    (tdev, data, sourcex, raster, id, x, y, w, h, plane_height);
1100
0
        }
1101
0
    }
1102
0
    ccdata.tdev = tdev;
1103
0
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1104
0
    ccdata.plane_height = plane_height;
1105
0
    return clip_enumerate_rest(rdev, x, y, xe, ye,
1106
0
                               clip_call_copy_planes, &ccdata);
1107
0
}
1108
static int
1109
clip_copy_planes_t1(gx_device * dev,
1110
                    const byte * data, int sourcex, int raster, gx_bitmap_id id,
1111
                    int x, int y, int w, int h, int plane_height)
1112
0
{
1113
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1114
0
    clip_callback_data_t ccdata;
1115
    /* We handle the fastest case in-line here. */
1116
0
    gx_device *tdev = rdev->target;
1117
0
    const gx_clip_rect *rptr = rdev->current;
1118
0
    int xe, ye;
1119
1120
0
    if (w <= 0 || h <= 0)
1121
0
        return 0;
1122
0
    x += rdev->translation.x;
1123
0
    y += rdev->translation.y;
1124
    /* ccdata is non-transposed */
1125
0
    ccdata.x = x, ccdata.y = y;
1126
0
    ccdata.w = w, ccdata.h = h;
1127
    /* transpose x, y, xe, ye for clip checking */
1128
0
    x = ccdata.y;
1129
0
    y = ccdata.x;
1130
0
    xe = x + h;
1131
0
    ye = y + w;
1132
0
    if (y >= rptr->ymin && ye <= rptr->ymax) {
1133
0
        INCR(in_y);
1134
0
        if (x >= rptr->xmin && xe <= rptr->xmax) {
1135
0
            INCR(in);
1136
0
            return dev_proc(tdev, copy_planes)
1137
0
                    (tdev, data, sourcex, raster, id, y, x, h, w, plane_height);
1138
0
        }
1139
0
    }
1140
0
    ccdata.tdev = tdev;
1141
0
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1142
0
    ccdata.plane_height = plane_height;
1143
0
    return clip_enumerate_rest(rdev, x, y, xe, ye,
1144
0
                               clip_call_copy_planes, &ccdata);
1145
0
}
1146
static int
1147
clip_copy_planes_s0(gx_device * dev,
1148
                    const byte * data, int sourcex, int raster, gx_bitmap_id id,
1149
                    int x, int y, int w, int h, int plane_height)
1150
0
{
1151
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1152
0
    gx_device *tdev = rdev->target;
1153
1154
0
    x += rdev->translation.x;
1155
0
    w += x;
1156
0
    y += rdev->translation.y;
1157
0
    h += y;
1158
0
    if (x < rdev->list.single.xmin)
1159
0
    {
1160
0
        sourcex += rdev->list.single.xmin - x;
1161
0
        x = rdev->list.single.xmin;
1162
0
    }
1163
0
    if (w > rdev->list.single.xmax)
1164
0
        w = rdev->list.single.xmax;
1165
0
    if (y < rdev->list.single.ymin)
1166
0
    {
1167
0
        data += (rdev->list.single.ymin - y) * raster;
1168
0
        y = rdev->list.single.ymin;
1169
0
    }
1170
0
    if (h > rdev->list.single.ymax)
1171
0
        h = rdev->list.single.ymax;
1172
0
    w -= x;
1173
0
    h -= y;
1174
0
    if (w <= 0 || h <= 0)
1175
0
        return 0;
1176
0
    return dev_proc(tdev, copy_planes)
1177
0
                    (tdev, data, sourcex, raster, id, x, y, w, h, plane_height);
1178
0
}
1179
static int
1180
clip_copy_planes_s1(gx_device * dev,
1181
                    const byte * data, int sourcex, int raster, gx_bitmap_id id,
1182
                    int x, int y, int w, int h, int plane_height)
1183
0
{
1184
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1185
0
    gx_device *tdev = rdev->target;
1186
1187
0
    x += rdev->translation.x;
1188
0
    w += x;
1189
0
    y += rdev->translation.y;
1190
0
    h += y;
1191
    /* Now, treat x/w as y/h and vice versa as transposed. */
1192
0
    if (x < rdev->list.single.ymin)
1193
0
    {
1194
0
        data += (rdev->list.single.ymin - x) * raster;
1195
0
        x = rdev->list.single.ymin;
1196
0
    }
1197
0
    if (w > rdev->list.single.ymax)
1198
0
        w = rdev->list.single.ymax;
1199
0
    if (y < rdev->list.single.xmin)
1200
0
    {
1201
0
        sourcex += rdev->list.single.xmin - y;
1202
0
        y = rdev->list.single.xmin;
1203
0
    }
1204
0
    if (h > rdev->list.single.xmax)
1205
0
        h = rdev->list.single.xmax;
1206
0
    w -= x;
1207
0
    h -= y;
1208
0
    if (w <= 0 || h <= 0)
1209
0
        return 0;
1210
0
    return dev_proc(tdev, copy_planes)
1211
0
                    (tdev, data, sourcex, raster, id, y, x, h, w, plane_height);
1212
0
}
1213
static int
1214
clip_copy_planes(gx_device * dev,
1215
                 const byte * data, int sourcex, int raster, gx_bitmap_id id,
1216
                 int x, int y, int w, int h, int plane_height)
1217
0
{
1218
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1219
1220
0
    if (rdev->list.transpose) {
1221
0
        if (rdev->list.count == 1)
1222
0
            dev_proc(rdev, copy_planes) = clip_copy_planes_s1;
1223
0
        else
1224
0
            dev_proc(rdev, copy_planes) = clip_copy_planes_t1;
1225
0
    } else {
1226
0
        if (rdev->list.count == 1)
1227
0
            dev_proc(rdev, copy_planes) = clip_copy_planes_s0;
1228
0
        else
1229
0
            dev_proc(rdev, copy_planes) = clip_copy_planes_t0;
1230
0
    }
1231
0
    return dev_proc(rdev, copy_planes)(dev, data, sourcex, raster, id, x, y, w, h, plane_height);
1232
0
}
1233
1234
/* Copy a color rectangle */
1235
int
1236
clip_call_copy_color(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1237
27.0k
{
1238
27.0k
    return (*dev_proc(pccd->tdev, copy_color))
1239
27.0k
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1240
27.0k
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1241
27.0k
         xc, yc, xec - xc, yec - yc);
1242
27.0k
}
1243
static int
1244
clip_copy_color(gx_device * dev,
1245
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
1246
                int x, int y, int w, int h)
1247
25.4k
{
1248
25.4k
    gx_device_clip *rdev = (gx_device_clip *) dev;
1249
25.4k
    clip_callback_data_t ccdata;
1250
1251
25.4k
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1252
25.4k
    return clip_enumerate(rdev, x, y, w, h, clip_call_copy_color, &ccdata);
1253
25.4k
}
1254
1255
/* Copy a rectangle with alpha */
1256
int
1257
clip_call_copy_alpha(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1258
0
{
1259
0
    return (*dev_proc(pccd->tdev, copy_alpha))
1260
0
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1261
0
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1262
0
         xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->depth);
1263
0
}
1264
static int
1265
clip_copy_alpha(gx_device * dev,
1266
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
1267
                int x, int y, int w, int h,
1268
                gx_color_index color, int depth)
1269
0
{
1270
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1271
0
    clip_callback_data_t ccdata;
1272
1273
0
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1274
0
    ccdata.color[0] = color, ccdata.depth = depth;
1275
0
    return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha, &ccdata);
1276
0
}
1277
1278
int
1279
clip_call_copy_alpha_hl_color(clip_callback_data_t * pccd, int xc, int yc,
1280
                              int xec, int yec)
1281
0
{
1282
0
    return (*dev_proc(pccd->tdev, copy_alpha_hl_color))
1283
0
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1284
0
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1285
0
         xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth);
1286
0
}
1287
1288
static int
1289
clip_copy_alpha_hl_color(gx_device * dev,
1290
                const byte * data, int sourcex, int raster, gx_bitmap_id id,
1291
                int x, int y, int w, int h,
1292
                const gx_drawing_color *pdcolor, int depth)
1293
0
{
1294
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1295
0
    clip_callback_data_t ccdata;
1296
1297
0
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1298
0
    ccdata.pdcolor = pdcolor, ccdata.depth = depth;
1299
0
    return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha_hl_color, &ccdata);
1300
0
}
1301
1302
/* Fill a region defined by a mask. */
1303
int
1304
clip_call_fill_mask(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1305
0
{
1306
0
    return (*dev_proc(pccd->tdev, fill_mask))
1307
0
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1308
0
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1309
0
         xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth,
1310
0
         pccd->lop, NULL);
1311
0
}
1312
static int
1313
clip_fill_mask(gx_device * dev,
1314
               const byte * data, int sourcex, int raster, gx_bitmap_id id,
1315
               int x, int y, int w, int h,
1316
               const gx_drawing_color * pdcolor, int depth,
1317
               gs_logical_operation_t lop, const gx_clip_path * pcpath)
1318
0
{
1319
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1320
0
    clip_callback_data_t ccdata;
1321
1322
0
    if (pcpath != 0)
1323
0
        return gx_default_fill_mask(dev, data, sourcex, raster, id,
1324
0
                                    x, y, w, h, pdcolor, depth, lop,
1325
0
                                    pcpath);
1326
0
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1327
0
    ccdata.pdcolor = pdcolor, ccdata.depth = depth, ccdata.lop = lop;
1328
0
    return clip_enumerate(rdev, x, y, w, h, clip_call_fill_mask, &ccdata);
1329
0
}
1330
1331
/* Strip-tile a rectangle with devn colors. */
1332
int
1333
clip_call_strip_tile_rect_devn(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1334
0
{
1335
0
    return (*dev_proc(pccd->tdev, strip_tile_rect_devn))
1336
0
        (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
1337
0
         pccd->pdc[0], pccd->pdc[1], pccd->phase.x, pccd->phase.y);
1338
0
}
1339
static int
1340
clip_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tiles,
1341
                                int x, int y, int w, int h,
1342
                                const gx_drawing_color *pdcolor0,
1343
                                const gx_drawing_color *pdcolor1, int phase_x,
1344
                                int phase_y)
1345
0
{
1346
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1347
0
    clip_callback_data_t ccdata;
1348
1349
0
    ccdata.tiles = tiles;
1350
0
    ccdata.pdc[0] = pdcolor0;
1351
0
    ccdata.pdc[1] = pdcolor1;
1352
0
    ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
1353
0
    return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rect_devn, &ccdata);
1354
0
}
1355
1356
/* Strip-tile a rectangle. */
1357
int
1358
clip_call_strip_tile_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1359
1.79k
{
1360
1.79k
    return (*dev_proc(pccd->tdev, strip_tile_rectangle))
1361
1.79k
        (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
1362
1.79k
         pccd->color[0], pccd->color[1], pccd->phase.x, pccd->phase.y);
1363
1.79k
}
1364
static int
1365
clip_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
1366
                          int x, int y, int w, int h,
1367
     gx_color_index color0, gx_color_index color1, int phase_x, int phase_y)
1368
1.84k
{
1369
1.84k
    gx_device_clip *rdev = (gx_device_clip *) dev;
1370
1.84k
    clip_callback_data_t ccdata;
1371
1372
1.84k
    ccdata.tiles = tiles;
1373
1.84k
    ccdata.color[0] = color0, ccdata.color[1] = color1;
1374
1.84k
    ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
1375
1.84k
    return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rectangle, &ccdata);
1376
1.84k
}
1377
1378
/* Copy a rectangle with RasterOp and strip texture. */
1379
int
1380
clip_call_strip_copy_rop2(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1381
0
{
1382
0
    return (*dev_proc(pccd->tdev, strip_copy_rop2))
1383
0
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1384
0
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1385
0
         pccd->scolors, pccd->textures, pccd->tcolors,
1386
0
         xc, yc, xec - xc, yec - yc, pccd->phase.x, pccd->phase.y,
1387
0
         pccd->lop, pccd->plane_height);
1388
0
}
1389
static int
1390
clip_strip_copy_rop2(gx_device * dev,
1391
              const byte * sdata, int sourcex, uint raster, gx_bitmap_id id,
1392
                    const gx_color_index * scolors,
1393
           const gx_strip_bitmap * textures, const gx_color_index * tcolors,
1394
                    int x, int y, int w, int h,
1395
                    int phase_x, int phase_y, gs_logical_operation_t lop,
1396
                    uint planar_height)
1397
0
{
1398
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1399
0
    clip_callback_data_t ccdata;
1400
1401
0
    ccdata.data = sdata, ccdata.sourcex = sourcex, ccdata.raster = raster;
1402
0
    ccdata.scolors = scolors, ccdata.textures = textures,
1403
0
        ccdata.tcolors = tcolors;
1404
0
    ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
1405
0
    ccdata.plane_height = planar_height;
1406
0
    return clip_enumerate(rdev, x, y, w, h, clip_call_strip_copy_rop2, &ccdata);
1407
0
}
1408
1409
/* Get the (outer) clipping box, in client coordinates. */
1410
static void
1411
clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
1412
52.2k
{
1413
52.2k
    gx_device_clip *const rdev = (gx_device_clip *) dev;
1414
1415
52.2k
    if (!rdev->clipping_box_set) {
1416
7.35k
        gx_device *tdev = rdev->target;
1417
7.35k
        gs_fixed_rect tbox;
1418
1419
7.35k
        (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
1420
7.35k
        if (rdev->list.count != 0) {
1421
7.35k
            gs_fixed_rect cbox;
1422
1423
7.35k
            if (rdev->list.count == 1) {
1424
5.20k
                cbox.p.x = int2fixed(rdev->list.single.xmin);
1425
5.20k
                cbox.p.y = int2fixed(rdev->list.single.ymin);
1426
5.20k
                cbox.q.x = int2fixed(rdev->list.single.xmax);
1427
5.20k
                cbox.q.y = int2fixed(rdev->list.single.ymax);
1428
5.20k
            } else {
1429
                /* The head and tail elements are dummies.... */
1430
2.14k
                gx_clip_rect *curr = rdev->list.head->next;
1431
1432
                /* Our initial scan is done as ints, but we'll convert to
1433
                 * fixed later. */
1434
2.14k
                cbox.p.x = cbox.p.y = max_int;
1435
2.14k
                cbox.q.x = cbox.q.y = min_int;
1436
                /* scan the list for the outer bbox */
1437
132k
                while (curr->next != NULL) { /* stop before tail */
1438
130k
                    if (curr->xmin < cbox.p.x)
1439
34.3k
                        cbox.p.x = curr->xmin;
1440
130k
                    if (curr->xmax > cbox.q.x)
1441
42.4k
                        cbox.q.x = curr->xmax;
1442
130k
                    if (curr->ymin < cbox.p.y)
1443
2.14k
                        cbox.p.y = curr->ymin;
1444
130k
                    if (curr->ymax > cbox.q.y)
1445
102k
                        cbox.q.y = curr->ymax;
1446
130k
                    curr = curr->next;
1447
130k
                }
1448
                /* Clamp the values so they won't overflow when converting to fixed. */
1449
8.59k
#define SAFE_CONVERT2FIXED(x)  if (x < fixed2int(min_int)) x = fixed2int(min_int); else if (x > fixed2int(max_int)) x = fixed2int(max_int); else x = int2fixed(x);
1450
2.14k
                SAFE_CONVERT2FIXED(cbox.p.x);
1451
2.14k
                SAFE_CONVERT2FIXED(cbox.p.y);
1452
2.14k
                SAFE_CONVERT2FIXED(cbox.q.x);
1453
2.14k
                SAFE_CONVERT2FIXED(cbox.q.y);
1454
2.14k
#undef SAFE_CONVERT2FIXED
1455
2.14k
            }
1456
7.35k
            if (rdev->list.transpose) {
1457
0
                fixed temp = cbox.p.x;
1458
1459
0
                cbox.p.x = cbox.p.y;
1460
0
                cbox.p.y = temp;
1461
0
                temp = cbox.q.x;
1462
0
                cbox.q.x = cbox.q.y;
1463
0
                cbox.q.y = temp;
1464
0
            }
1465
7.35k
            rect_intersect(tbox, cbox);
1466
7.35k
        }
1467
7.35k
        if (rdev->translation.x | rdev->translation.y) {
1468
0
            fixed tx = int2fixed(rdev->translation.x),
1469
0
                ty = int2fixed(rdev->translation.y);
1470
1471
0
            if (tbox.p.x != min_fixed)
1472
0
                tbox.p.x -= tx;
1473
0
            if (tbox.p.y != min_fixed)
1474
0
                tbox.p.y -= ty;
1475
0
            if (tbox.q.x != max_fixed)
1476
0
                tbox.q.x -= tx;
1477
0
            if (tbox.q.y != max_fixed)
1478
0
                tbox.q.y -= ty;
1479
0
        }
1480
7.35k
        rdev->clipping_box = tbox;
1481
7.35k
        rdev->clipping_box_set = true;
1482
7.35k
    }
1483
52.2k
    *pbox = rdev->clipping_box;
1484
52.2k
}
1485
1486
/* Get bits back from the device. */
1487
static int
1488
clip_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
1489
                        gs_get_bits_params_t * params)
1490
0
{
1491
0
    gx_device_clip *rdev = (gx_device_clip *) dev;
1492
0
    gx_device *tdev = rdev->target;
1493
0
    int tx = rdev->translation.x, ty = rdev->translation.y;
1494
0
    gs_int_rect rect;
1495
1496
0
    rect.p.x = prect->p.x - tx, rect.p.y = prect->p.y - ty;
1497
0
    rect.q.x = prect->q.x - tx, rect.q.y = prect->q.y - ty;
1498
0
    return (*dev_proc(tdev, get_bits_rectangle))
1499
0
                     (tdev, &rect, params);
1500
0
}
1501
1502
static int clip_list_enumerate_intersections(gx_clip_list *list, int (*process)(clip_callback_data_t *, int, int, int, int), clip_callback_data_t *pccd, int x, int y, int xe, int ye)
1503
15.8k
{
1504
15.8k
    int transpose = list->transpose;
1505
15.8k
    int code = 0;
1506
15.8k
    int yc;
1507
    /* Start at the last place we succeeded, to try to exploit
1508
     * locality of reference. */
1509
15.8k
    gx_clip_rect *rptr = pccd->last_clip_rect;
1510
1511
    /* If this is the first time through, start at the head. */
1512
15.8k
    if (rptr == NULL)
1513
15.8k
        rptr = (list->head == NULL ? &list->single : list->head);
1514
1515
    /*
1516
     * Warp the cursor forwards or backward to the first rectangle row
1517
     * that could include a given y value.  Assumes rptr is set, and
1518
     * updates it.  Specifically, after this loop, either rptr == 0 (if
1519
     * the y value is greater than all y values in the list), or y <
1520
     * rptr->ymax and either rptr->prev == 0 or y >= rptr->prev->ymax.
1521
     * Note that y <= rptr->ymin is possible.
1522
     *
1523
     * In the first case below, the while loop is safe because if there
1524
     * is more than one rectangle, there is a 'stopper' at the end of
1525
     * the list.
1526
     */
1527
15.8k
    if (y >= rptr->ymax) {
1528
        /* Bug 706875: The 'stopper' here is a rectangle from (max_int, max_int) to
1529
         * (max_int, max_int). Hence it doesn't 'stop' cases when y == max_int.
1530
         * These shouldn't really happen, but let's be sure. */
1531
0
        if (y == max_int)
1532
0
            return 0;
1533
0
        if ((rptr = rptr->next) != NULL)
1534
0
            while (y >= rptr->ymax)
1535
0
                rptr = rptr->next;
1536
0
    } else
1537
15.8k
        while (rptr->prev != NULL && y < rptr->prev->ymax)
1538
0
            rptr = rptr->prev;
1539
    /* If we've run out, bale! */
1540
15.8k
    if (rptr == NULL || (yc = rptr->ymin) >= ye)
1541
0
        return 0;
1542
15.8k
    if (yc < y)
1543
0
        yc = y;
1544
1545
15.8k
    do {
1546
15.8k
        const int ymax = rptr->ymax;
1547
15.8k
        int yec = min(ymax, ye);
1548
1549
15.8k
        do {
1550
15.8k
            int xc = rptr->xmin;
1551
15.8k
            int xec = rptr->xmax;
1552
1553
15.8k
            if (xc < x)
1554
0
                xc = x;
1555
15.8k
            if (xec > xe)
1556
0
                xec = xe;
1557
15.8k
            if (xec > xc) {
1558
15.8k
                if (transpose)
1559
0
                    code = process(pccd, yc, xc, yec, xec);
1560
15.8k
                else
1561
15.8k
                    code = process(pccd, xc, yc, xec, yec);
1562
15.8k
                if (code < 0)
1563
0
                    return code;
1564
15.8k
            }
1565
15.8k
            pccd->last_clip_rect = rptr;
1566
15.8k
            rptr = rptr->next;
1567
15.8k
            if (rptr == NULL)
1568
15.8k
                return 0;
1569
15.8k
        }
1570
15.8k
        while (rptr->ymax == ymax);
1571
15.8k
    } while ((yc = rptr->ymin) < ye);
1572
0
    return 0;
1573
15.8k
}
1574
1575
static int
1576
do_clip_call_fill_path(clip_callback_data_t *pccd, int xc, int yc, int xec, int yec)
1577
44.4k
{
1578
44.4k
    gx_device *tdev = pccd->tdev;
1579
44.4k
    gs_fixed_rect rect;
1580
44.4k
    dev_proc_fill_path((*proc));
1581
1582
44.4k
    rect.p.x = int2fixed(xc);
1583
44.4k
    rect.p.y = int2fixed(yc);
1584
44.4k
    rect.q.x = int2fixed(xec);
1585
44.4k
    rect.q.y = int2fixed(yec);
1586
1587
44.4k
    if (pccd->id_pool_len == 0) {
1588
44.4k
        pccd->id_pool = gs_next_ids(pccd->tdev->memory, 100);
1589
44.4k
        pccd->id_pool_len = 100;
1590
44.4k
    }
1591
44.4k
    gx_cpath_init_local_rectangle(pccd->rect_cpath, &rect, pccd->id_pool++);
1592
44.4k
    pccd->id_pool_len--;
1593
44.4k
    proc = dev_proc(tdev, fill_path);
1594
44.4k
    if (proc == NULL)
1595
0
        proc = gx_default_fill_path;
1596
44.4k
    return (*proc)(pccd->tdev, pccd->pgs, pccd->ppath, pccd->params,
1597
44.4k
                   pccd->pdcolor, pccd->rect_cpath);
1598
44.4k
}
1599
1600
static int
1601
clip_call_fill_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1602
44.4k
{
1603
44.4k
    gx_clip_path *pcpath = (gx_clip_path *)pccd->pcpath;
1604
1605
    /* Previously the code here tested for pcpath != NULL, but
1606
     * we can commonly (such as from clist_playback_band) be
1607
     * called with a non-NULL, but still invalid clip path.
1608
     * Detect this by the list having at least one entry in it. */
1609
44.4k
    if (pcpath != NULL && pcpath->rect_list->list.count != 0)
1610
15.8k
        return clip_list_enumerate_intersections(&pcpath->rect_list->list, do_clip_call_fill_path, pccd,  xc, yc, xec, yec);
1611
1612
28.5k
    return do_clip_call_fill_path(pccd, xc, yc, xec, yec);
1613
44.4k
}
1614
static int
1615
clip_fill_path(gx_device * dev, const gs_gstate * pgs,
1616
               gx_path * ppath, const gx_fill_params * params,
1617
               const gx_drawing_color * pdcolor,
1618
               const gx_clip_path * pcpath)
1619
44.4k
{
1620
44.4k
    gx_device_clip *rdev = (gx_device_clip *) dev;
1621
44.4k
    clip_callback_data_t ccdata;
1622
44.4k
    gs_fixed_rect box;
1623
44.4k
    gx_clip_path cpath;
1624
1625
44.4k
    ccdata.id_pool_len = 0;
1626
44.4k
    gx_cpath_preinit_local_rectangle(&cpath, ppath->memory);
1627
44.4k
    ccdata.rect_cpath = &cpath;
1628
44.4k
    ccdata.pgs = pgs;
1629
44.4k
    ccdata.ppath = ppath;
1630
44.4k
    ccdata.params = params;
1631
44.4k
    ccdata.pdcolor = pdcolor;
1632
44.4k
    ccdata.pcpath = pcpath;
1633
44.4k
    ccdata.last_clip_rect = NULL;
1634
44.4k
    clip_get_clipping_box(dev, &box);
1635
44.4k
    return clip_enumerate(rdev,
1636
44.4k
                          fixed2int(box.p.x),
1637
44.4k
                          fixed2int(box.p.y),
1638
44.4k
                          fixed2int(box.q.x - box.p.x),
1639
44.4k
                          fixed2int(box.q.y - box.p.y),
1640
44.4k
                          clip_call_fill_path, &ccdata);
1641
44.4k
}
1642
1643
typedef struct  {
1644
    int use_default;
1645
    void *child_state;
1646
} clip_transform_pixel_region_data;
1647
1648
static int
1649
clip_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
1650
367k
{
1651
367k
    clip_transform_pixel_region_data *state = (clip_transform_pixel_region_data *)data->state;
1652
367k
    gx_device_clip *cdev = (gx_device_clip *)dev;
1653
367k
    transform_pixel_region_data local_data;
1654
367k
    gs_int_rect local_clip;
1655
367k
    int ret;
1656
1657
367k
    if (reason == transform_pixel_region_begin) {
1658
7.84k
        int skewed = 1;
1659
7.84k
        if (data->u.init.pixels->y.step.dQ == 0 && data->u.init.pixels->y.step.dR == 0 &&
1660
7.84k
            data->u.init.rows->x.step.dQ == 0 && data->u.init.rows->x.step.dR == 0)
1661
7.82k
            skewed = 0;
1662
14
        else if (data->u.init.pixels->x.step.dQ == 0 && data->u.init.pixels->x.step.dR == 0 &&
1663
14
                 data->u.init.rows->y.step.dQ == 0 && data->u.init.rows->y.step.dR == 0)
1664
0
            skewed = 0;
1665
7.84k
        state = (clip_transform_pixel_region_data *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(*state), "clip_transform_pixel_region_data");
1666
7.84k
        if (state == NULL)
1667
0
            return gs_error_VMerror;
1668
7.84k
        local_data = *data;
1669
7.84k
        if (cdev->list.count == 1 && skewed == 0) {
1670
            /* Single unskewed rectangle - we can use the underlying device direct */
1671
7.62k
            local_data.u.init.clip = &local_clip;
1672
7.62k
            local_clip = *data->u.init.clip;
1673
7.62k
            if (cdev->list.transpose) {
1674
0
                if (local_clip.p.x < cdev->current->ymin)
1675
0
                    local_clip.p.x = cdev->current->ymin;
1676
0
                if (local_clip.q.x > cdev->current->ymax)
1677
0
                    local_clip.q.x = cdev->current->ymax;
1678
0
                if (local_clip.p.y < cdev->current->xmin)
1679
0
                    local_clip.p.y = cdev->current->xmin;
1680
0
                if (local_clip.q.y > cdev->current->xmax)
1681
0
                    local_clip.q.y = cdev->current->xmax;
1682
7.62k
            } else {
1683
7.62k
                if (local_clip.p.x < cdev->current->xmin)
1684
0
                    local_clip.p.x = cdev->current->xmin;
1685
7.62k
                if (local_clip.q.x > cdev->current->xmax)
1686
1
                    local_clip.q.x = cdev->current->xmax;
1687
7.62k
                if (local_clip.p.y < cdev->current->ymin)
1688
0
                    local_clip.p.y = cdev->current->ymin;
1689
7.62k
                if (local_clip.q.y > cdev->current->ymax)
1690
1
                    local_clip.q.y = cdev->current->ymax;
1691
7.62k
            }
1692
7.62k
            state->use_default = 0;
1693
7.62k
            ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, &local_data);
1694
7.62k
        } else {
1695
            /* Multiple rectangles - we need to use the default */
1696
222
            state->use_default = 1;
1697
222
            ret = gx_default_transform_pixel_region(dev, reason, &local_data);
1698
222
        }
1699
7.84k
        state->child_state = local_data.state;
1700
7.84k
        data->state = state;
1701
7.84k
        return ret;
1702
7.84k
    }
1703
1704
360k
    data->state = state->child_state;
1705
360k
    if (state->use_default)
1706
6.22k
        ret = gx_default_transform_pixel_region(dev, reason, data);
1707
353k
    else
1708
353k
        ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, data);
1709
1710
360k
    if (reason == transform_pixel_region_end) {
1711
7.84k
        gs_free_object(dev->memory->non_gc_memory, state, "clip_transform_pixel_region_data");
1712
7.84k
        state = NULL;
1713
7.84k
    }
1714
360k
    data->state = state;
1715
1716
360k
    return ret;
1717
367k
}
1718
1719
static int
1720
clip_call_fill_stroke_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1721
1
{
1722
1
    gx_device *tdev = pccd->tdev;
1723
1
    dev_proc_fill_stroke_path((*proc));
1724
1
    int code;
1725
1
    gx_clip_path cpath_intersection;
1726
1
    gx_clip_path *pcpath = (gx_clip_path *)pccd->pcpath;
1727
1728
    /* Previously the code here tested for pcpath != NULL, but
1729
     * we can commonly (such as from clist_playback_band) be
1730
     * called with a non-NULL, but still invalid clip path.
1731
     * Detect this by the list having at least one entry in it. */
1732
1
    if (pcpath != NULL && pcpath->rect_list->list.count != 0) {
1733
1
        gx_path rect_path;
1734
1
        code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, pccd->ppath->memory, 1);
1735
1
        if (code < 0)
1736
0
            return code;
1737
1
        gx_path_init_local(&rect_path, pccd->ppath->memory);
1738
1
        code = gx_path_add_rectangle(&rect_path, int2fixed(xc), int2fixed(yc), int2fixed(xec), int2fixed(yec));
1739
1
        if (code < 0)
1740
0
            return code;
1741
1
        code = gx_cpath_intersect(&cpath_intersection, &rect_path,
1742
1
                                  gx_rule_winding_number, (gs_gstate *)(pccd->pgs));
1743
1
        gx_path_free(&rect_path, "clip_call_fill_stroke_path");
1744
1
    } else {
1745
0
        gs_fixed_rect clip_box;
1746
0
        clip_box.p.x = int2fixed(xc);
1747
0
        clip_box.p.y = int2fixed(yc);
1748
0
        clip_box.q.x = int2fixed(xec);
1749
0
        clip_box.q.y = int2fixed(yec);
1750
0
        gx_cpath_init_local(&cpath_intersection, pccd->ppath->memory);
1751
0
        code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box);
1752
0
    }
1753
1
    if (code < 0)
1754
0
        return code;
1755
1
    proc = dev_proc(tdev, fill_stroke_path);
1756
1
    if (proc == NULL)
1757
0
        proc = gx_default_fill_stroke_path;
1758
1
    code = (*proc)(pccd->tdev, pccd->pgs, pccd->ppath, pccd->params,
1759
1
                   pccd->pdcolor, pccd->stroke_params, pccd->pstroke_dcolor,
1760
1
                   &cpath_intersection);
1761
1
    gx_cpath_free(&cpath_intersection, "clip_call_fill_stroke_path");
1762
1
    return code;
1763
1
}
1764
1765
static int
1766
clip_fill_stroke_path(gx_device *dev, const gs_gstate *pgs,
1767
               gx_path *ppath,
1768
               const gx_fill_params *params,
1769
               const gx_drawing_color *pdcolor,
1770
               const gx_stroke_params *stroke_params,
1771
               const gx_drawing_color *pstroke_dcolor,
1772
               const gx_clip_path *pcpath)
1773
1
{
1774
1
    gx_device_clip *rdev = (gx_device_clip *) dev;
1775
1
    clip_callback_data_t ccdata;
1776
1
    gs_fixed_rect box;
1777
1778
1
    ccdata.pgs = pgs;
1779
1
    ccdata.ppath = ppath;
1780
1
    ccdata.params = params;
1781
1
    ccdata.pdcolor = pdcolor;
1782
1
    ccdata.stroke_params = stroke_params;
1783
1
    ccdata.pstroke_dcolor = pstroke_dcolor;
1784
1
    ccdata.pcpath = pcpath;
1785
1
    clip_get_clipping_box(dev, &box);
1786
1
    return clip_enumerate(rdev,
1787
1
                          fixed2int(box.p.x),
1788
1
                          fixed2int(box.p.y),
1789
1
                          fixed2int(box.q.x - box.p.x),
1790
1
                          fixed2int(box.q.y - box.p.y),
1791
1
                          clip_call_fill_stroke_path, &ccdata);
1792
1
}