Coverage Report

Created: 2025-11-16 07:40

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