Coverage Report

Created: 2022-10-31 07:00

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