Coverage Report

Created: 2025-12-31 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxclip.c
Line
Count
Source
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
13.1M
{
56
13.1M
    set_dev_proc(dev, open_device, clip_open);
57
13.1M
    set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix);
58
13.1M
    set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
59
13.1M
    set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
60
13.1M
    set_dev_proc(dev, fill_rectangle, clip_fill_rectangle);
61
13.1M
    set_dev_proc(dev, copy_mono, clip_copy_mono);
62
13.1M
    set_dev_proc(dev, copy_color, clip_copy_color);
63
13.1M
    set_dev_proc(dev, get_params, gx_forward_get_params);
64
13.1M
    set_dev_proc(dev, put_params, gx_forward_put_params);
65
13.1M
    set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
66
13.1M
    set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
67
13.1M
    set_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits);
68
13.1M
    set_dev_proc(dev, copy_alpha, clip_copy_alpha);
69
13.1M
    set_dev_proc(dev, fill_path, clip_fill_path);
70
13.1M
    set_dev_proc(dev, fill_mask, clip_fill_mask);
71
13.1M
    set_dev_proc(dev, strip_tile_rectangle, clip_strip_tile_rectangle);
72
13.1M
    set_dev_proc(dev, get_clipping_box, clip_get_clipping_box);
73
13.1M
    set_dev_proc(dev, get_bits_rectangle, clip_get_bits_rectangle);
74
13.1M
    set_dev_proc(dev, composite, gx_forward_composite);
75
13.1M
    set_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params);
76
13.1M
    set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
77
13.1M
    set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
78
13.1M
    set_dev_proc(dev, encode_color, gx_forward_encode_color);
79
13.1M
    set_dev_proc(dev, decode_color, gx_forward_decode_color);
80
13.1M
    set_dev_proc(dev, fill_rectangle_hl_color, clip_fill_rectangle_hl_color);
81
13.1M
    set_dev_proc(dev, include_color_space, gx_forward_include_color_space);
82
13.1M
    set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors);
83
13.1M
    set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params);
84
13.1M
    set_dev_proc(dev, fillpage, gx_forward_fillpage);
85
13.1M
    set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op);
86
13.1M
    set_dev_proc(dev, copy_planes, clip_copy_planes);
87
13.1M
    set_dev_proc(dev, get_profile, gx_forward_get_profile);
88
13.1M
    set_dev_proc(dev, set_graphics_type_tag, gx_forward_set_graphics_type_tag);
89
13.1M
    set_dev_proc(dev, strip_copy_rop2, clip_strip_copy_rop2);
90
13.1M
    set_dev_proc(dev, strip_tile_rect_devn, clip_strip_tile_rect_devn);
91
13.1M
    set_dev_proc(dev, copy_alpha_hl_color, clip_copy_alpha_hl_color);
92
13.1M
    set_dev_proc(dev, transform_pixel_region, clip_transform_pixel_region);
93
13.1M
    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
13.1M
    set_dev_proc(dev, sync_output, gx_default_sync_output);
97
13.1M
    set_dev_proc(dev, output_page, gx_default_output_page);
98
13.1M
    set_dev_proc(dev, close_device, gx_default_close_device);
99
13.1M
    set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
100
13.1M
    set_dev_proc(dev, stroke_path, gx_default_stroke_path);
101
13.1M
    set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid);
102
13.1M
    set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram);
103
13.1M
    set_dev_proc(dev, fill_triangle, gx_default_fill_triangle);
104
13.1M
    set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line);
105
13.1M
    set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image);
106
13.1M
    set_dev_proc(dev, text_begin, gx_default_text_begin);
107
13.1M
    set_dev_proc(dev, fill_linear_color_scanline, gx_default_fill_linear_color_scanline);
108
13.1M
    set_dev_proc(dev, fill_linear_color_trapezoid, gx_default_fill_linear_color_trapezoid);
109
13.1M
    set_dev_proc(dev, fill_linear_color_triangle, gx_default_fill_linear_color_triangle);
110
13.1M
}
111
112
void
113
gx_device_clip_finalize(const gs_memory_t *cmem, void *vpdev)
114
674k
{
115
674k
    gx_device_clip *dev = (gx_device_clip *)vpdev;
116
117
674k
    if (dev->target != NULL) {
118
674k
        rc_decrement(dev->target, "gx_device_clip_finalize");
119
674k
        dev->target = NULL;
120
674k
    }
121
674k
    if (dev->rect_list != NULL) {
122
674k
        rc_decrement(dev->rect_list, "finalizing clipper device");
123
674k
        dev->rect_list = NULL;
124
674k
    }
125
674k
}
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
12.4M
{
137
12.4M
    gx_device_init_on_stack((gx_device *)dev, (const gx_device *)&gs_clip_device, target->memory);
138
12.4M
    dev->cpath = pcpath;
139
12.4M
    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
12.4M
    dev->translation.x = 0;
147
12.4M
    dev->translation.y = 0;
148
12.4M
    dev->HWResolution[0] = target->HWResolution[0];
149
12.4M
    dev->HWResolution[1] = target->HWResolution[1];
150
12.4M
    dev->sgr = target->sgr;
151
12.4M
    gx_device_set_target((gx_device_forward *)dev, target);
152
12.4M
    dev->pad = target->pad;
153
12.4M
    dev->log2_align_mod = target->log2_align_mod;
154
12.4M
    dev->num_planar_planes = target->num_planar_planes;
155
12.4M
    dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */
156
12.4M
    dev->non_strict_bounds = target->non_strict_bounds;
157
    /* There is no finalization for device on stack so no rc increment */
158
12.4M
    (*dev_proc(dev, open_device)) ((gx_device *)dev);
159
12.4M
}
160
161
void
162
gx_destroy_clip_device_on_stack(gx_device_clip * dev)
163
12.4M
{
164
12.4M
    if (dev->target != NULL)
165
12.4M
        rc_decrement(dev->target, "gx_destroy_clip_device_on_stack");
166
12.4M
    if (dev->cpath)
167
12.4M
        ((gx_clip_path *)dev->cpath)->cached = (dev->current == &dev->list.single ? NULL : dev->current); /* Cast away const */
168
12.4M
}
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
1.52M
{
173
    /* Reduce area if possible */
174
1.52M
    if (rect->p.x < pcpath->outer_box.p.x)
175
9.31k
        rect->p.x = pcpath->outer_box.p.x;
176
1.52M
    if (rect->q.x > pcpath->outer_box.q.x)
177
26.0k
        rect->q.x = pcpath->outer_box.q.x;
178
1.52M
    if (rect->p.y < pcpath->outer_box.p.y)
179
52.5k
        rect->p.y = pcpath->outer_box.p.y;
180
1.52M
    if (rect->q.y > pcpath->outer_box.q.y)
181
55.0k
        rect->q.y = pcpath->outer_box.q.y;
182
    /* Check for area being trivially clipped away. */
183
1.52M
    if (rect->p.x >= rect->q.x || rect->p.y >= rect->q.y)
184
32.1k
        return NULL;
185
1.49M
    if (pcpath->inner_box.p.x <= rect->p.x && pcpath->inner_box.p.y <= rect->p.y &&
186
1.49M
        pcpath->inner_box.q.x >= rect->q.x && pcpath->inner_box.q.y >= rect->q.y)
187
1.48M
    {
188
        /* Area is trivially included. No need for clip. */
189
1.48M
        return target;
190
1.48M
    }
191
10.6k
    gx_device_init_on_stack((gx_device *)dev, (const gx_device *)&gs_clip_device, target->memory);
192
10.6k
    dev->list = *gx_cpath_list(pcpath);
193
10.6k
    dev->translation.x = 0;
194
10.6k
    dev->translation.y = 0;
195
10.6k
    dev->HWResolution[0] = target->HWResolution[0];
196
10.6k
    dev->HWResolution[1] = target->HWResolution[1];
197
10.6k
    dev->sgr = target->sgr;
198
10.6k
    gx_device_set_target((gx_device_forward *)dev, target);
199
10.6k
    dev->pad = target->pad;
200
10.6k
    dev->log2_align_mod = target->log2_align_mod;
201
10.6k
    dev->num_planar_planes = target->num_planar_planes;
202
10.6k
    dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */
203
10.6k
    dev->non_strict_bounds = target->non_strict_bounds;
204
    /* There is no finalization for device on stack so no rc increment */
205
10.6k
    (*dev_proc(dev, open_device)) ((gx_device *)dev);
206
10.6k
    return (gx_device *)dev;
207
1.49M
}
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
674k
{
214
    /* Can never fail */
215
674k
    (void)gx_device_init((gx_device *)dev,
216
674k
                         (const gx_device *)&gs_clip_device, mem, true);
217
674k
    dev->list = *gx_cpath_list(pcpath);
218
674k
    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
674k
    rc_increment(dev->rect_list);
225
674k
    dev->translation.x = 0;
226
674k
    dev->translation.y = 0;
227
674k
    dev->HWResolution[0] = target->HWResolution[0];
228
674k
    dev->HWResolution[1] = target->HWResolution[1];
229
674k
    dev->sgr = target->sgr;
230
674k
    dev->pad = target->pad;
231
674k
    dev->log2_align_mod = target->log2_align_mod;
232
674k
    dev->num_planar_planes = target->num_planar_planes;
233
674k
    dev->non_strict_bounds = target->non_strict_bounds;
234
674k
    gx_device_set_target((gx_device_forward *)dev, target);
235
674k
    gx_device_retain((gx_device *)dev, true); /* will free explicitly */
236
    /* Can never fail */
237
674k
    (void)(*dev_proc(dev, open_device)) ((gx_device *)dev);
238
674k
}
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
482M
# define INCR(v) DO_NOTHING
254
1.15G
# 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
159M
{
270
159M
    gx_clip_rect *rptr = rdev->current;   /* const within algorithm */
271
159M
    int yc;
272
159M
    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
159M
    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
58.1M
        if (y == max_int)
303
0
            return 0;
304
58.1M
        if ((rptr = rptr->next) != 0)
305
310M
            while (INCR_THEN(up, y >= rptr->ymax))
306
253M
                rptr = rptr->next;
307
58.1M
    } else
308
427M
        while (rptr->prev != 0 && y < rptr->prev->ymax)
309
325M
            INCR_THEN(down, rptr = rptr->prev);
310
159M
    if (rptr == 0 || (yc = rptr->ymin) >= ye) {
311
51.4M
        INCR(out);
312
51.4M
        if (rdev->list.count > 1)
313
37.2M
            rdev->current =
314
37.2M
                (rptr != 0 ? rptr :
315
37.2M
                 y >= rdev->current->ymax ? rdev->list.tail :
316
0
                 rdev->list.head);
317
51.4M
        return 0;
318
51.4M
    }
319
108M
    rdev->current = rptr;
320
108M
    if (yc < y)
321
23.3M
        yc = y;
322
323
129M
    do {
324
129M
        const int ymax = rptr->ymax;
325
129M
        int yec = min(ymax, ye);
326
327
129M
        if_debug2m('Q', rdev->memory, "[Q]yc=%d yec=%d\n", yc, yec);
328
523M
        do {
329
523M
            int xc = rptr->xmin;
330
523M
            int xec = rptr->xmax;
331
332
523M
            if (xc < x)
333
244M
                xc = x;
334
523M
            if (xec > xe)
335
304M
                xec = xe;
336
523M
            if (xec > xc) {
337
102M
                clip_rect_print('Q', "match", rptr);
338
102M
                if_debug2m('Q', rdev->memory, "[Q]xc=%d xec=%d\n", xc, xec);
339
102M
                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
102M
#ifdef CHECK_VERTICAL_CLIPPING
348
102M
                if (xec - xc == pccd->w) { /* full width */
349
                    /* Look ahead for a vertical swath. */
350
70.4M
                    while ((rptr = rptr->next) != 0 &&
351
70.4M
                           rptr->ymin == yec &&
352
61.3M
                           rptr->ymax <= ye &&
353
10.3M
                           rptr->xmin <= x &&
354
10.2M
                           rptr->xmax >= xe
355
60.3M
                           )
356
10.0M
                        yec = rptr->ymax;
357
60.3M
                } else
358
42.3M
                    rptr = rptr->next;
359
#else
360
                rptr = rptr->next;
361
#endif
362
102M
                if (rdev->list.transpose)
363
0
                    code = process(pccd, yc, xc, yec, xec);
364
102M
                else
365
102M
                    code = process(pccd, xc, yc, xec, yec);
366
102M
                if (code < 0)
367
0
                    return code;
368
421M
            } else {
369
421M
                INCR_THEN(no_x, rptr = rptr->next);
370
421M
            }
371
523M
            if (rptr == 0)
372
1.71M
                return 0;
373
523M
        }
374
522M
        while (rptr->ymax == ymax);
375
129M
    } while ((yc = rptr->ymin) < ye);
376
106M
    return 0;
377
108M
}
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
205M
{
385
205M
    int xe, ye;
386
205M
    const gx_clip_rect *rptr = rdev->current;
387
388
205M
    if (w <= 0 || h <= 0)
389
0
        return 0;
390
205M
    pccd->tdev = rdev->target;
391
205M
    x += rdev->translation.x;
392
205M
    xe = x + w;
393
205M
    y += rdev->translation.y;
394
205M
    ye = y + h;
395
    /* pccd is non-transposed */
396
205M
    pccd->x = x, pccd->y = y;
397
205M
    pccd->w = w, pccd->h = h;
398
    /* transpose x, y, xe, ye for clip checking */
399
205M
    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
205M
    if (y >= rptr->ymin && ye <= rptr->ymax &&
407
109M
        x >= rptr->xmin && xe <= rptr->xmax
408
205M
        ) {
409
94.1M
        if (rdev->list.transpose) {
410
0
            return INCR_THEN(in, process(pccd, y, x, ye, xe));
411
94.1M
        } else {
412
94.1M
            return INCR_THEN(in, process(pccd, x, y, xe, ye));
413
94.1M
        }
414
94.1M
    }
415
111M
    return clip_enumerate_rest(rdev, x, y, xe, ye, process, pccd);
416
205M
}
417
418
/* Open a clipping device */
419
static int
420
clip_open(gx_device * dev)
421
13.1M
{
422
13.1M
    gx_device_clip *const rdev = (gx_device_clip *) dev;
423
13.1M
    gx_device *tdev = rdev->target;
424
425
    /* Initialize the cursor. */
426
13.1M
    rdev->current =
427
13.1M
        (rdev->list.head == 0 ? &rdev->list.single : (rdev->cpath && rdev->cpath->cached ? rdev->cpath->cached : rdev->list.head));
428
13.1M
    rdev->color_info = tdev->color_info;
429
13.1M
    rdev->cached_colors = tdev->cached_colors;
430
13.1M
    rdev->width = tdev->width;
431
13.1M
    rdev->height = tdev->height;
432
13.1M
    gx_device_copy_color_procs(dev, tdev);
433
13.1M
    rdev->clipping_box_set = false;
434
13.1M
    rdev->memory = tdev->memory;
435
13.1M
    return 0;
436
13.1M
}
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
34.9M
{
442
34.9M
    return (*dev_proc(pccd->tdev, fill_rectangle))
443
34.9M
        (pccd->tdev, xc, yc, xec - xc, yec - yc, pccd->color[0]);
444
34.9M
}
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
230M
{
449
230M
    gx_device_clip *rdev = (gx_device_clip *) dev;
450
230M
    clip_callback_data_t ccdata;
451
    /* We handle the fastest cases in-line here. */
452
230M
    gx_device *tdev = rdev->target;
453
230M
    /*const*/ gx_clip_rect *rptr = rdev->current;
454
230M
    int xe, ye;
455
456
230M
    if (w <= 0 || h <= 0)
457
52.7M
        return 0;
458
177M
    x += rdev->translation.x;
459
177M
    xe = x + w;
460
177M
    y += rdev->translation.y;
461
177M
    ye = y + h;
462
    /* ccdata is non-transposed */
463
177M
    ccdata.x = x, ccdata.y = y;
464
177M
    ccdata.w = w, ccdata.h = h;
465
    /* We open-code the most common cases here. */
466
177M
    if ((y >= rptr->ymin && ye <= rptr->ymax) ||
467
72.1M
        ((rptr = rptr->next) != 0 &&
468
68.0M
         y >= rptr->ymin && ye <= rptr->ymax)
469
177M
        ) {
470
138M
        rdev->current = rptr; /* may be redundant, but awkward to avoid */
471
138M
        INCR(in_y);
472
138M
        if (x >= rptr->xmin && xe <= rptr->xmax) {
473
112M
            INCR(in);
474
112M
            return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
475
112M
        }
476
26.8M
        else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
477
26.8M
                 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
478
26.8M
                 ) {
479
21.1M
            INCR(in1);
480
21.1M
            if (x < rptr->xmin)
481
8.38M
                x = rptr->xmin;
482
21.1M
            if (xe > rptr->xmax)
483
13.3M
                xe = rptr->xmax;
484
21.1M
            if (x >= xe)
485
18.3M
                 return 0;
486
2.86M
            return dev_proc(tdev, fill_rectangle)(tdev, x, y, xe - x, h, color);
487
21.1M
        }
488
138M
    }
489
44.0M
    ccdata.tdev = tdev;
490
44.0M
    ccdata.color[0] = color;
491
44.0M
    return clip_enumerate_rest(rdev, x, y, xe, ye, clip_call_fill_rectangle, &ccdata);
492
177M
}
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
724M
{
549
724M
    gx_device_clip *rdev = (gx_device_clip *) dev;
550
724M
    gx_device *tdev = rdev->target;
551
552
724M
    if (w <= 0 || h <= 0)
553
18.6M
        return 0;
554
705M
    x += rdev->translation.x;
555
705M
    w += x;
556
705M
    y += rdev->translation.y;
557
705M
    h += y;
558
705M
    if (x < rdev->list.single.xmin)
559
42.8M
        x = rdev->list.single.xmin;
560
705M
    if (w > rdev->list.single.xmax)
561
169M
        w = rdev->list.single.xmax;
562
705M
    if (y < rdev->list.single.ymin)
563
40.6M
        y = rdev->list.single.ymin;
564
705M
    if (h > rdev->list.single.ymax)
565
49.1M
        h = rdev->list.single.ymax;
566
705M
    w -= x;
567
705M
    h -= y;
568
705M
    if (w <= 0 || h <= 0)
569
186M
        return 0;
570
519M
    return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
571
705M
}
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
147M
{
605
147M
    gx_device_clip *rdev = (gx_device_clip *) dev;
606
607
147M
    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
147M
    } else {
613
147M
        if (rdev->list.count == 1)
614
146M
            dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_s0;
615
782k
        else
616
782k
            dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_t0;
617
147M
    }
618
147M
    return dev_proc(rdev, fill_rectangle)(dev, x, y, w, h, color);
619
147M
}
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
2.55M
{
625
2.55M
    gs_fixed_rect rect;
626
627
2.55M
    rect.p.x = int2fixed(xc);
628
2.55M
    rect.p.y = int2fixed(yc);
629
2.55M
    rect.q.x = int2fixed(xec);
630
2.55M
    rect.q.y = int2fixed(yec);
631
2.55M
    return (*dev_proc(pccd->tdev, fill_rectangle_hl_color))
632
2.55M
        (pccd->tdev, &rect, pccd->pgs, pccd->pdcolor, pccd->pcpath);
633
2.55M
}
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
31.9M
{
640
31.9M
    gx_device_clip *rdev = (gx_device_clip *) dev;
641
31.9M
    clip_callback_data_t ccdata;
642
31.9M
    gx_device *tdev = rdev->target;
643
31.9M
    gx_clip_rect *rptr = rdev->current;
644
31.9M
    int xe, ye;
645
31.9M
    int w, h, x, y;
646
31.9M
    gs_fixed_rect newrect;
647
648
31.9M
    x = fixed2int(rect->p.x);
649
31.9M
    y = fixed2int(rect->p.y);
650
31.9M
    w = fixed2int(rect->q.x) - x;
651
31.9M
    h = fixed2int(rect->q.y) - y;
652
653
31.9M
    if (w <= 0 || h <= 0)
654
649k
        return 0;
655
31.3M
    x += rdev->translation.x;
656
31.3M
    xe = x + w;
657
31.3M
    y += rdev->translation.y;
658
31.3M
    ye = y + h;
659
    /* ccdata is non-transposed */
660
31.3M
    ccdata.x = x, ccdata.y = y;
661
31.3M
    ccdata.w = w, ccdata.h = h;
662
    /* We open-code the most common cases here. */
663
31.3M
    if ((y >= rptr->ymin && ye <= rptr->ymax) ||
664
6.70M
        ((rptr = rptr->next) != 0 &&
665
6.70M
         y >= rptr->ymin && ye <= rptr->ymax)
666
31.3M
        ) {
667
29.3M
        rdev->current = rptr; /* may be redundant, but awkward to avoid */
668
29.3M
        INCR(in_y);
669
29.3M
        if (x >= rptr->xmin && xe <= rptr->xmax) {
670
23.1M
            INCR(in);
671
23.1M
            newrect.p.x = int2fixed(x);
672
23.1M
            newrect.p.y = int2fixed(y);
673
23.1M
            newrect.q.x = int2fixed(x + w);
674
23.1M
            newrect.q.y = int2fixed(y + h);
675
23.1M
            return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
676
23.1M
                                                           pdcolor, pcpath);
677
23.1M
        }
678
6.18M
        else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
679
6.18M
                 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
680
6.18M
                 ) {
681
4.01M
            INCR(in1);
682
4.01M
            if (x < rptr->xmin)
683
2.19M
                x = rptr->xmin;
684
4.01M
            if (xe > rptr->xmax)
685
1.81M
                xe = rptr->xmax;
686
4.01M
            if (x >= xe)
687
3.92M
                return 0;
688
81.3k
            else {
689
81.3k
                newrect.p.x = int2fixed(x);
690
81.3k
                newrect.p.y = int2fixed(y);
691
81.3k
                newrect.q.x = int2fixed(xe);
692
81.3k
                newrect.q.y = int2fixed(y + h);
693
81.3k
                return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
694
81.3k
                                                               pdcolor, pcpath);
695
81.3k
            }
696
4.01M
        }
697
29.3M
    }
698
4.17M
    ccdata.tdev = tdev;
699
4.17M
    ccdata.pdcolor = pdcolor;
700
4.17M
    ccdata.pgs = pgs;
701
4.17M
    ccdata.pcpath = pcpath;
702
4.17M
    return clip_enumerate_rest(rdev, x, y, xe, ye,
703
4.17M
                               clip_call_fill_rectangle_hl_color, &ccdata);
704
31.3M
}
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
43.6M
{
785
43.6M
    gx_device_clip *rdev = (gx_device_clip *) dev;
786
43.6M
    gx_device *tdev = rdev->target;
787
43.6M
    int w, h, x, y;
788
43.6M
    gs_fixed_rect newrect;
789
790
43.6M
    x = fixed2int(rect->p.x);
791
43.6M
    y = fixed2int(rect->p.y);
792
43.6M
    w = fixed2int(rect->q.x) - x;
793
43.6M
    h = fixed2int(rect->q.y) - y;
794
795
43.6M
    if (w <= 0 || h <= 0)
796
354k
        return 0;
797
43.2M
    x += rdev->translation.x;
798
43.2M
    w += x;
799
43.2M
    y += rdev->translation.y;
800
43.2M
    h += y;
801
43.2M
    if (x < rdev->list.single.xmin)
802
44.6k
        x = rdev->list.single.xmin;
803
43.2M
    if (w > rdev->list.single.xmax)
804
241k
        w = rdev->list.single.xmax;
805
43.2M
    if (y < rdev->list.single.ymin)
806
722k
        y = rdev->list.single.ymin;
807
43.2M
    if (h > rdev->list.single.ymax)
808
893k
        h = rdev->list.single.ymax;
809
43.2M
    w -= x;
810
43.2M
    h -= y;
811
43.2M
    if (w <= 0 || h <= 0)
812
939k
        return 0;
813
42.3M
    newrect.p.x = int2fixed(x);
814
42.3M
    newrect.p.y = int2fixed(y);
815
42.3M
    newrect.q.x = int2fixed(x + w);
816
42.3M
    newrect.q.y = int2fixed(y + h);
817
42.3M
    return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs,
818
42.3M
                                                   pdcolor, pcpath);
819
43.2M
}
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
223k
{
868
223k
    gx_device_clip *rdev = (gx_device_clip *) dev;
869
870
223k
    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
223k
    } else {
876
223k
        if (rdev->list.count == 1)
877
201k
            dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_s0;
878
22.4k
        else
879
22.4k
            dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_t0;
880
223k
    }
881
223k
    return dev_proc(rdev, fill_rectangle_hl_color)(dev, rect, pgs, pdcolor, pcpath);
882
223k
}
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
164k
{
888
164k
    return (*dev_proc(pccd->tdev, copy_mono))
889
164k
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
890
164k
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
891
164k
         xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->color[1]);
892
164k
}
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
118k
{
899
118k
    gx_device_clip *rdev = (gx_device_clip *) dev;
900
118k
    clip_callback_data_t ccdata;
901
    /* We handle the fastest case in-line here. */
902
118k
    gx_device *tdev = rdev->target;
903
118k
    const gx_clip_rect *rptr = rdev->current;
904
118k
    int xe, ye;
905
906
118k
    if (w <= 0 || h <= 0)
907
2.23k
        return 0;
908
115k
    x += rdev->translation.x;
909
115k
    xe = x + w;
910
115k
    y += rdev->translation.y;
911
115k
    ye = y + h;
912
    /* ccdata is non-transposed */
913
115k
    ccdata.x = x, ccdata.y = y;
914
115k
    ccdata.w = w, ccdata.h = h;
915
115k
    if (y >= rptr->ymin && ye <= rptr->ymax) {
916
11.4k
        INCR(in_y);
917
11.4k
        if (x >= rptr->xmin && xe <= rptr->xmax) {
918
6.43k
            INCR(in);
919
6.43k
            return dev_proc(tdev, copy_mono)
920
6.43k
                    (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
921
6.43k
        }
922
11.4k
    }
923
109k
    ccdata.tdev = tdev;
924
109k
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
925
109k
    ccdata.color[0] = color0, ccdata.color[1] = color1;
926
109k
    return clip_enumerate_rest(rdev, x, y, xe, ye,
927
109k
                               clip_call_copy_mono, &ccdata);
928
115k
}
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
9.25M
{
975
9.25M
    gx_device_clip *rdev = (gx_device_clip *) dev;
976
9.25M
    gx_device *tdev = rdev->target;
977
978
9.25M
    if (w <= 0 || h <= 0)
979
291
        return 0;
980
9.25M
    x += rdev->translation.x;
981
9.25M
    w += x;
982
9.25M
    y += rdev->translation.y;
983
9.25M
    h += y;
984
9.25M
    if (x < rdev->list.single.xmin)
985
3.50M
    {
986
3.50M
        sourcex += (rdev->list.single.xmin - x);
987
3.50M
        x = rdev->list.single.xmin;
988
3.50M
    }
989
9.25M
    if (w > rdev->list.single.xmax)
990
2.81M
        w = rdev->list.single.xmax;
991
9.25M
    if (y < rdev->list.single.ymin)
992
5.09M
    {
993
5.09M
        data += (rdev->list.single.ymin - y) * raster;
994
5.09M
        y = rdev->list.single.ymin;
995
5.09M
    }
996
9.25M
    if (h > rdev->list.single.ymax)
997
3.28M
        h = rdev->list.single.ymax;
998
9.25M
    w -= x;
999
9.25M
    h -= y;
1000
9.25M
    if (w <= 0 || h <= 0)
1001
4.01M
        return 0;
1002
5.24M
    return dev_proc(tdev, copy_mono)
1003
5.24M
                    (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
1004
9.25M
}
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
4.05M
{
1048
4.05M
    gx_device_clip *rdev = (gx_device_clip *) dev;
1049
1050
4.05M
    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
4.05M
    } else {
1056
4.05M
        if (rdev->list.count == 1)
1057
3.94M
            dev_proc(rdev, copy_mono) = clip_copy_mono_s0;
1058
116k
        else
1059
116k
            dev_proc(rdev, copy_mono) = clip_copy_mono_t0;
1060
4.05M
    }
1061
4.05M
    return dev_proc(rdev, copy_mono)(dev, data, sourcex, raster, id, x, y, w, h, color0, color1);
1062
4.05M
}
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
294
{
1068
294
    return (*dev_proc(pccd->tdev, copy_planes))
1069
294
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1070
294
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1071
294
         xc, yc, xec - xc, yec - yc, pccd->plane_height);
1072
294
}
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
386
{
1078
386
    gx_device_clip *rdev = (gx_device_clip *) dev;
1079
386
    clip_callback_data_t ccdata;
1080
    /* We handle the fastest case in-line here. */
1081
386
    gx_device *tdev = rdev->target;
1082
386
    const gx_clip_rect *rptr = rdev->current;
1083
386
    int xe, ye;
1084
1085
386
    if (w <= 0 || h <= 0)
1086
0
        return 0;
1087
386
    x += rdev->translation.x;
1088
386
    xe = x + w;
1089
386
    y += rdev->translation.y;
1090
386
    ye = y + h;
1091
    /* ccdata is non-transposed */
1092
386
    ccdata.x = x, ccdata.y = y;
1093
386
    ccdata.w = w, ccdata.h = h;
1094
386
    if (y >= rptr->ymin && ye <= rptr->ymax) {
1095
28
        INCR(in_y);
1096
28
        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
28
    }
1102
386
    ccdata.tdev = tdev;
1103
386
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1104
386
    ccdata.plane_height = plane_height;
1105
386
    return clip_enumerate_rest(rdev, x, y, xe, ye,
1106
386
                               clip_call_copy_planes, &ccdata);
1107
386
}
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
194k
{
1151
194k
    gx_device_clip *rdev = (gx_device_clip *) dev;
1152
194k
    gx_device *tdev = rdev->target;
1153
1154
194k
    x += rdev->translation.x;
1155
194k
    w += x;
1156
194k
    y += rdev->translation.y;
1157
194k
    h += y;
1158
194k
    if (x < rdev->list.single.xmin)
1159
346
    {
1160
346
        sourcex += rdev->list.single.xmin - x;
1161
346
        x = rdev->list.single.xmin;
1162
346
    }
1163
194k
    if (w > rdev->list.single.xmax)
1164
694
        w = rdev->list.single.xmax;
1165
194k
    if (y < rdev->list.single.ymin)
1166
2
    {
1167
2
        data += (rdev->list.single.ymin - y) * raster;
1168
2
        y = rdev->list.single.ymin;
1169
2
    }
1170
194k
    if (h > rdev->list.single.ymax)
1171
5
        h = rdev->list.single.ymax;
1172
194k
    w -= x;
1173
194k
    h -= y;
1174
194k
    if (w <= 0 || h <= 0)
1175
723
        return 0;
1176
193k
    return dev_proc(tdev, copy_planes)
1177
193k
                    (tdev, data, sourcex, raster, id, x, y, w, h, plane_height);
1178
194k
}
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
323
{
1218
323
    gx_device_clip *rdev = (gx_device_clip *) dev;
1219
1220
323
    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
323
    } else {
1226
323
        if (rdev->list.count == 1)
1227
295
            dev_proc(rdev, copy_planes) = clip_copy_planes_s0;
1228
28
        else
1229
28
            dev_proc(rdev, copy_planes) = clip_copy_planes_t0;
1230
323
    }
1231
323
    return dev_proc(rdev, copy_planes)(dev, data, sourcex, raster, id, x, y, w, h, plane_height);
1232
323
}
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
63.6M
{
1238
63.6M
    return (*dev_proc(pccd->tdev, copy_color))
1239
63.6M
        (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
1240
63.6M
         pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
1241
63.6M
         xc, yc, xec - xc, yec - yc);
1242
63.6M
}
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
68.7M
{
1248
68.7M
    gx_device_clip *rdev = (gx_device_clip *) dev;
1249
68.7M
    clip_callback_data_t ccdata;
1250
1251
68.7M
    ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
1252
68.7M
    return clip_enumerate(rdev, x, y, w, h, clip_call_copy_color, &ccdata);
1253
68.7M
}
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
94.6M
{
1360
94.6M
    return (*dev_proc(pccd->tdev, strip_tile_rectangle))
1361
94.6M
        (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
1362
94.6M
         pccd->color[0], pccd->color[1], pccd->phase.x, pccd->phase.y);
1363
94.6M
}
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
135M
{
1369
135M
    gx_device_clip *rdev = (gx_device_clip *) dev;
1370
135M
    clip_callback_data_t ccdata;
1371
1372
135M
    ccdata.tiles = tiles;
1373
135M
    ccdata.color[0] = color0, ccdata.color[1] = color1;
1374
135M
    ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
1375
135M
    return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rectangle, &ccdata);
1376
135M
}
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
34.3M
{
1413
34.3M
    gx_device_clip *const rdev = (gx_device_clip *) dev;
1414
1415
34.3M
    if (!rdev->clipping_box_set) {
1416
669k
        gx_device *tdev = rdev->target;
1417
669k
        gs_fixed_rect tbox;
1418
1419
669k
        (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
1420
669k
        if (rdev->list.count != 0) {
1421
669k
            gs_fixed_rect cbox;
1422
1423
669k
            if (rdev->list.count == 1) {
1424
425k
                cbox.p.x = int2fixed(rdev->list.single.xmin);
1425
425k
                cbox.p.y = int2fixed(rdev->list.single.ymin);
1426
425k
                cbox.q.x = int2fixed(rdev->list.single.xmax);
1427
425k
                cbox.q.y = int2fixed(rdev->list.single.ymax);
1428
425k
            } else {
1429
                /* The head and tail elements are dummies.... */
1430
244k
                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
244k
                cbox.p.x = cbox.p.y = max_int;
1435
244k
                cbox.q.x = cbox.q.y = min_int;
1436
                /* scan the list for the outer bbox */
1437
27.6M
                while (curr->next != NULL) { /* stop before tail */
1438
27.4M
                    if (curr->xmin < cbox.p.x)
1439
4.70M
                        cbox.p.x = curr->xmin;
1440
27.4M
                    if (curr->xmax > cbox.q.x)
1441
4.53M
                        cbox.q.x = curr->xmax;
1442
27.4M
                    if (curr->ymin < cbox.p.y)
1443
244k
                        cbox.p.y = curr->ymin;
1444
27.4M
                    if (curr->ymax > cbox.q.y)
1445
14.4M
                        cbox.q.y = curr->ymax;
1446
27.4M
                    curr = curr->next;
1447
27.4M
                }
1448
                /* Clamp the values so they won't overflow when converting to fixed. */
1449
977k
#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
244k
                SAFE_CONVERT2FIXED(cbox.p.x);
1451
244k
                SAFE_CONVERT2FIXED(cbox.p.y);
1452
244k
                SAFE_CONVERT2FIXED(cbox.q.x);
1453
244k
                SAFE_CONVERT2FIXED(cbox.q.y);
1454
244k
#undef SAFE_CONVERT2FIXED
1455
244k
            }
1456
669k
            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
669k
            rect_intersect(tbox, cbox);
1466
669k
        }
1467
669k
        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
669k
        rdev->clipping_box = tbox;
1481
669k
        rdev->clipping_box_set = true;
1482
669k
    }
1483
34.3M
    *pbox = rdev->clipping_box;
1484
34.3M
}
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
242k
{
1504
242k
    int transpose = list->transpose;
1505
242k
    int code = 0;
1506
242k
    int yc;
1507
    /* Start at the last place we succeeded, to try to exploit
1508
     * locality of reference. */
1509
242k
    gx_clip_rect *rptr = pccd->last_clip_rect;
1510
1511
    /* If this is the first time through, start at the head. */
1512
242k
    if (rptr == NULL)
1513
242k
        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
242k
    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
242k
        while (rptr->prev != NULL && y < rptr->prev->ymax)
1538
0
            rptr = rptr->prev;
1539
    /* If we've run out, bale! */
1540
242k
    if (rptr == NULL || (yc = rptr->ymin) >= ye)
1541
0
        return 0;
1542
242k
    if (yc < y)
1543
0
        yc = y;
1544
1545
242k
    do {
1546
242k
        const int ymax = rptr->ymax;
1547
242k
        int yec = min(ymax, ye);
1548
1549
242k
        do {
1550
242k
            int xc = rptr->xmin;
1551
242k
            int xec = rptr->xmax;
1552
1553
242k
            if (xc < x)
1554
0
                xc = x;
1555
242k
            if (xec > xe)
1556
0
                xec = xe;
1557
242k
            if (xec > xc) {
1558
242k
                if (transpose)
1559
0
                    code = process(pccd, yc, xc, yec, xec);
1560
242k
                else
1561
242k
                    code = process(pccd, xc, yc, xec, yec);
1562
242k
                if (code < 0)
1563
0
                    return code;
1564
242k
            }
1565
242k
            pccd->last_clip_rect = rptr;
1566
242k
            rptr = rptr->next;
1567
242k
            if (rptr == NULL)
1568
242k
                return 0;
1569
242k
        }
1570
242k
        while (rptr->ymax == ymax);
1571
242k
    } while ((yc = rptr->ymin) < ye);
1572
0
    return 0;
1573
242k
}
1574
1575
static int
1576
do_clip_call_fill_path(clip_callback_data_t *pccd, int xc, int yc, int xec, int yec)
1577
1.34M
{
1578
1.34M
    gx_device *tdev = pccd->tdev;
1579
1.34M
    gs_fixed_rect rect;
1580
1.34M
    dev_proc_fill_path((*proc));
1581
1582
1.34M
    rect.p.x = int2fixed(xc);
1583
1.34M
    rect.p.y = int2fixed(yc);
1584
1.34M
    rect.q.x = int2fixed(xec);
1585
1.34M
    rect.q.y = int2fixed(yec);
1586
1587
1.34M
    if (pccd->id_pool_len == 0) {
1588
1.22M
        pccd->id_pool = gs_next_ids(pccd->tdev->memory, 100);
1589
1.22M
        pccd->id_pool_len = 100;
1590
1.22M
    }
1591
1.34M
    gx_cpath_init_local_rectangle(pccd->rect_cpath, &rect, pccd->id_pool++);
1592
1.34M
    pccd->id_pool_len--;
1593
1.34M
    proc = dev_proc(tdev, fill_path);
1594
1.34M
    if (proc == NULL)
1595
0
        proc = gx_default_fill_path;
1596
1.34M
    return (*proc)(pccd->tdev, pccd->pgs, pccd->ppath, pccd->params,
1597
1.34M
                   pccd->pdcolor, pccd->rect_cpath);
1598
1.34M
}
1599
1600
static int
1601
clip_call_fill_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1602
1.34M
{
1603
1.34M
    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
1.34M
    if (pcpath != NULL && pcpath->rect_list->list.count != 0)
1610
242k
        return clip_list_enumerate_intersections(&pcpath->rect_list->list, do_clip_call_fill_path, pccd,  xc, yc, xec, yec);
1611
1612
1.10M
    return do_clip_call_fill_path(pccd, xc, yc, xec, yec);
1613
1.34M
}
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
1.22M
{
1620
1.22M
    gx_device_clip *rdev = (gx_device_clip *) dev;
1621
1.22M
    clip_callback_data_t ccdata;
1622
1.22M
    gs_fixed_rect box;
1623
1.22M
    gx_clip_path cpath;
1624
1625
1.22M
    ccdata.id_pool_len = 0;
1626
1.22M
    gx_cpath_preinit_local_rectangle(&cpath, ppath->memory);
1627
1.22M
    ccdata.rect_cpath = &cpath;
1628
1.22M
    ccdata.pgs = pgs;
1629
1.22M
    ccdata.ppath = ppath;
1630
1.22M
    ccdata.params = params;
1631
1.22M
    ccdata.pdcolor = pdcolor;
1632
1.22M
    ccdata.pcpath = pcpath;
1633
1.22M
    ccdata.last_clip_rect = NULL;
1634
1.22M
    clip_get_clipping_box(dev, &box);
1635
1.22M
    return clip_enumerate(rdev,
1636
1.22M
                          fixed2int(box.p.x),
1637
1.22M
                          fixed2int(box.p.y),
1638
1.22M
                          fixed2int(box.q.x - box.p.x),
1639
1.22M
                          fixed2int(box.q.y - box.p.y),
1640
1.22M
                          clip_call_fill_path, &ccdata);
1641
1.22M
}
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
2.14M
{
1651
2.14M
    clip_transform_pixel_region_data *state = (clip_transform_pixel_region_data *)data->state;
1652
2.14M
    gx_device_clip *cdev = (gx_device_clip *)dev;
1653
2.14M
    transform_pixel_region_data local_data;
1654
2.14M
    gs_int_rect local_clip;
1655
2.14M
    int ret;
1656
1657
2.14M
    if (reason == transform_pixel_region_begin) {
1658
27.2k
        int skewed = 1;
1659
27.2k
        if (data->u.init.pixels->y.step.dQ == 0 && data->u.init.pixels->y.step.dR == 0 &&
1660
27.2k
            data->u.init.rows->x.step.dQ == 0 && data->u.init.rows->x.step.dR == 0)
1661
27.1k
            skewed = 0;
1662
149
        else if (data->u.init.pixels->x.step.dQ == 0 && data->u.init.pixels->x.step.dR == 0 &&
1663
15
                 data->u.init.rows->y.step.dQ == 0 && data->u.init.rows->y.step.dR == 0)
1664
3
            skewed = 0;
1665
27.2k
        state = (clip_transform_pixel_region_data *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(*state), "clip_transform_pixel_region_data");
1666
27.2k
        if (state == NULL)
1667
0
            return gs_error_VMerror;
1668
27.2k
        local_data = *data;
1669
27.2k
        if (cdev->list.count == 1 && skewed == 0) {
1670
            /* Single unskewed rectangle - we can use the underlying device direct */
1671
26.3k
            local_data.u.init.clip = &local_clip;
1672
26.3k
            local_clip = *data->u.init.clip;
1673
26.3k
            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
26.3k
            } else {
1683
26.3k
                if (local_clip.p.x < cdev->current->xmin)
1684
0
                    local_clip.p.x = cdev->current->xmin;
1685
26.3k
                if (local_clip.q.x > cdev->current->xmax)
1686
13
                    local_clip.q.x = cdev->current->xmax;
1687
26.3k
                if (local_clip.p.y < cdev->current->ymin)
1688
0
                    local_clip.p.y = cdev->current->ymin;
1689
26.3k
                if (local_clip.q.y > cdev->current->ymax)
1690
18
                    local_clip.q.y = cdev->current->ymax;
1691
26.3k
            }
1692
26.3k
            state->use_default = 0;
1693
26.3k
            ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, &local_data);
1694
26.3k
        } else {
1695
            /* Multiple rectangles - we need to use the default */
1696
940
            state->use_default = 1;
1697
940
            ret = gx_default_transform_pixel_region(dev, reason, &local_data);
1698
940
        }
1699
27.2k
        state->child_state = local_data.state;
1700
27.2k
        data->state = state;
1701
27.2k
        return ret;
1702
27.2k
    }
1703
1704
2.11M
    data->state = state->child_state;
1705
2.11M
    if (state->use_default)
1706
20.9k
        ret = gx_default_transform_pixel_region(dev, reason, data);
1707
2.09M
    else
1708
2.09M
        ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, data);
1709
1710
2.11M
    if (reason == transform_pixel_region_end) {
1711
27.2k
        gs_free_object(dev->memory->non_gc_memory, state, "clip_transform_pixel_region_data");
1712
27.2k
        state = NULL;
1713
27.2k
    }
1714
2.11M
    data->state = state;
1715
1716
2.11M
    return ret;
1717
2.14M
}
1718
1719
static int
1720
clip_call_fill_stroke_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
1721
109
{
1722
109
    gx_device *tdev = pccd->tdev;
1723
109
    dev_proc_fill_stroke_path((*proc));
1724
109
    int code;
1725
109
    gx_clip_path cpath_intersection;
1726
109
    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
109
    if (pcpath != NULL && pcpath->rect_list->list.count != 0) {
1733
109
        gx_path rect_path;
1734
109
        code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, pccd->ppath->memory, 1);
1735
109
        if (code < 0)
1736
0
            return code;
1737
109
        gx_path_init_local(&rect_path, pccd->ppath->memory);
1738
109
        code = gx_path_add_rectangle(&rect_path, int2fixed(xc), int2fixed(yc), int2fixed(xec), int2fixed(yec));
1739
109
        if (code < 0)
1740
0
            return code;
1741
109
        code = gx_cpath_intersect(&cpath_intersection, &rect_path,
1742
109
                                  gx_rule_winding_number, (gs_gstate *)(pccd->pgs));
1743
109
        gx_path_free(&rect_path, "clip_call_fill_stroke_path");
1744
109
    } 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
109
    if (code < 0)
1754
0
        return code;
1755
109
    proc = dev_proc(tdev, fill_stroke_path);
1756
109
    if (proc == NULL)
1757
0
        proc = gx_default_fill_stroke_path;
1758
109
    code = (*proc)(pccd->tdev, pccd->pgs, pccd->ppath, pccd->params,
1759
109
                   pccd->pdcolor, pccd->stroke_params, pccd->pstroke_dcolor,
1760
109
                   &cpath_intersection);
1761
109
    gx_cpath_free(&cpath_intersection, "clip_call_fill_stroke_path");
1762
109
    return code;
1763
109
}
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
109
{
1774
109
    gx_device_clip *rdev = (gx_device_clip *) dev;
1775
109
    clip_callback_data_t ccdata;
1776
109
    gs_fixed_rect box;
1777
1778
109
    ccdata.pgs = pgs;
1779
109
    ccdata.ppath = ppath;
1780
109
    ccdata.params = params;
1781
109
    ccdata.pdcolor = pdcolor;
1782
109
    ccdata.stroke_params = stroke_params;
1783
109
    ccdata.pstroke_dcolor = pstroke_dcolor;
1784
109
    ccdata.pcpath = pcpath;
1785
109
    clip_get_clipping_box(dev, &box);
1786
109
    return clip_enumerate(rdev,
1787
109
                          fixed2int(box.p.x),
1788
109
                          fixed2int(box.p.y),
1789
109
                          fixed2int(box.q.x - box.p.x),
1790
109
                          fixed2int(box.q.y - box.p.y),
1791
109
                          clip_call_fill_stroke_path, &ccdata);
1792
109
}