1 /* Copyright (C) 2001-2006 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gxclip.c 10200 2009-10-21 03:50:46Z mvrhel $ */
15 /* Implementation of (path-based) clipping */
16 #include "gx.h"
17 #include "gxdevice.h"
18 #include "gxclip.h"
19 #include "gxpath.h"
20 #include "gxcpath.h"
21
22 /* Define whether to look for vertical clipping regions. */
23 #define CHECK_VERTICAL_CLIPPING
24
25 /* ------ Rectangle list clipper ------ */
26
27 /* Device for clipping with a region. */
28 /* We forward non-drawing operations, but we must be sure to intercept */
29 /* all drawing operations. */
30 static dev_proc_open_device(clip_open);
31 static dev_proc_fill_rectangle(clip_fill_rectangle);
32 static dev_proc_copy_mono(clip_copy_mono);
33 static dev_proc_copy_color(clip_copy_color);
34 static dev_proc_copy_alpha(clip_copy_alpha);
35 static dev_proc_fill_mask(clip_fill_mask);
36 static dev_proc_strip_tile_rectangle(clip_strip_tile_rectangle);
37 static dev_proc_strip_copy_rop(clip_strip_copy_rop);
38 static dev_proc_get_clipping_box(clip_get_clipping_box);
39 static dev_proc_get_bits_rectangle(clip_get_bits_rectangle);
40
41 /* The device descriptor. */
42 static const gx_device_clip gs_clip_device =
43 {std_device_std_body(gx_device_clip, 0, "clipper",
44 0, 0, 1, 1),
45 {clip_open,
46 gx_forward_get_initial_matrix,
47 gx_default_sync_output,
48 gx_default_output_page,
49 gx_default_close_device,
50 gx_forward_map_rgb_color,
51 gx_forward_map_color_rgb,
52 clip_fill_rectangle,
53 gx_default_tile_rectangle,
54 clip_copy_mono,
55 clip_copy_color,
56 gx_default_draw_line,
57 gx_default_get_bits,
58 gx_forward_get_params,
59 gx_forward_put_params,
60 gx_forward_map_cmyk_color,
61 gx_forward_get_xfont_procs,
62 gx_forward_get_xfont_device,
63 gx_forward_map_rgb_alpha_color,
64 gx_forward_get_page_device,
65 gx_forward_get_alpha_bits,
66 clip_copy_alpha,
67 gx_forward_get_band,
68 gx_default_copy_rop,
69 gx_default_fill_path,
70 gx_default_stroke_path,
71 clip_fill_mask,
72 gx_default_fill_trapezoid,
73 gx_default_fill_parallelogram,
74 gx_default_fill_triangle,
75 gx_default_draw_thin_line,
76 gx_default_begin_image,
77 gx_default_image_data,
78 gx_default_end_image,
79 clip_strip_tile_rectangle,
80 clip_strip_copy_rop,
81 clip_get_clipping_box,
82 gx_default_begin_typed_image,
83 clip_get_bits_rectangle,
84 gx_forward_map_color_rgb_alpha,
85 gx_no_create_compositor,
86 gx_forward_get_hardware_params,
87 gx_default_text_begin,
88 gx_default_finish_copydevice,
89 NULL, /* begin_transparency_group */
90 NULL, /* end_transparency_group */
91 NULL, /* begin_transparency_mask */
92 NULL, /* end_transparency_mask */
93 NULL, /* discard_transparency_layer */
94 gx_forward_get_color_mapping_procs,
95 gx_forward_get_color_comp_index,
96 gx_forward_encode_color,
97 gx_forward_decode_color,
98 gx_forward_pattern_manage,
99 gx_forward_fill_rectangle_hl_color,
100 gx_forward_include_color_space,
101 gx_default_fill_linear_color_scanline,
102 gx_default_fill_linear_color_trapezoid,
103 gx_default_fill_linear_color_triangle,
104 gx_forward_update_spot_equivalent_colors,
105 gx_forward_ret_devn_params,
106 gx_forward_fillpage,
107 NULL, /* push_transparency_state */
108 NULL /* pop_transparency_state */
109 }
110 };
111
112 /* Make a clipping device. */
113 void
gx_make_clip_device_on_stack(gx_device_clip * dev,const gx_clip_path * pcpath,gx_device * target)114 gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target)
115 {
116 gx_device_init((gx_device *)dev, (const gx_device *)&gs_clip_device, NULL, true);
117 dev->list = *gx_cpath_list(pcpath);
118 dev->translation.x = 0;
119 dev->translation.y = 0;
120 dev->HWResolution[0] = target->HWResolution[0];
121 dev->HWResolution[1] = target->HWResolution[1];
122 dev->sgr = target->sgr;
123 dev->target = target;
124 (*dev_proc(dev, open_device)) ((gx_device *)dev);
125 }
126 void
gx_make_clip_device_in_heap(gx_device_clip * dev,const gx_clip_path * pcpath,gx_device * target,gs_memory_t * mem)127 gx_make_clip_device_in_heap(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target,
128 gs_memory_t *mem)
129 {
130 gx_device_init((gx_device *)dev, (const gx_device *)&gs_clip_device, mem, true);
131 dev->list = *gx_cpath_list(pcpath);
132 dev->translation.x = 0;
133 dev->translation.y = 0;
134 dev->HWResolution[0] = target->HWResolution[0];
135 dev->HWResolution[1] = target->HWResolution[1];
136 dev->sgr = target->sgr;
137 gx_device_set_target((gx_device_forward *)dev, target);
138 gx_device_retain((gx_device *)dev, true); /* will free explicitly */
139 (*dev_proc(dev, open_device)) ((gx_device *)dev);
140 }
141 /* Define debugging statistics for the clipping loops. */
142 #ifdef DEBUG
143 struct stats_clip_s {
144 long
145 loops, out, in_y, in, in1, down, up, x, no_x;
146 } stats_clip;
147
148 static const uint clip_interval = 10000;
149
150 # define INCR(v) (++(stats_clip.v))
151 # define INCR_THEN(v, e) (INCR(v), (e))
152 #else
153 # define INCR(v) DO_NOTHING
154 # define INCR_THEN(v, e) (e)
155 #endif
156
157 /*
158 * Enumerate the rectangles of the x,w,y,h argument that fall within
159 * the clipping region.
160 */
161 static int
clip_enumerate_rest(gx_device_clip * rdev,int x,int y,int xe,int ye,int (* process)(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec),clip_callback_data_t * pccd)162 clip_enumerate_rest(gx_device_clip * rdev,
163 int x, int y, int xe, int ye,
164 int (*process)(clip_callback_data_t * pccd,
165 int xc, int yc, int xec, int yec),
166 clip_callback_data_t * pccd)
167 {
168 gx_clip_rect *rptr = rdev->current; /* const within algorithm */
169 int yc;
170 int code;
171
172 #ifdef DEBUG
173 if (INCR(loops) % clip_interval == 0 && gs_debug_c('q')) {
174 dprintf5("[q]loops=%ld out=%ld in_y=%ld in=%ld in1=%ld\n",
175 stats_clip.loops, stats_clip.out, stats_clip.in,
176 stats_clip.in_y, stats_clip.in1);
177 dprintf4("[q] down=%ld up=%ld x=%ld no_x=%ld\n",
178 stats_clip.down, stats_clip.up, stats_clip.x,
179 stats_clip.no_x);
180 }
181 #endif
182 pccd->x = x, pccd->y = y;
183 pccd->w = xe - x, pccd->h = ye - y;
184 /*
185 * Warp the cursor forward or backward to the first rectangle row
186 * that could include a given y value. Assumes rptr is set, and
187 * updates it. Specifically, after this loop, either rptr == 0 (if
188 * the y value is greater than all y values in the list), or y <
189 * rptr->ymax and either rptr->prev == 0 or y >= rptr->prev->ymax.
190 * Note that y <= rptr->ymin is possible.
191 *
192 * In the first case below, the while loop is safe because if there
193 * is more than one rectangle, there is a 'stopper' at the end of
194 * the list.
195 */
196 if (y >= rptr->ymax) {
197 if ((rptr = rptr->next) != 0)
198 while (INCR_THEN(up, y >= rptr->ymax))
199 rptr = rptr->next;
200 } else
201 while (rptr->prev != 0 && y < rptr->prev->ymax)
202 INCR_THEN(down, rptr = rptr->prev);
203 if (rptr == 0 || (yc = rptr->ymin) >= ye) {
204 INCR(out);
205 if (rdev->list.count > 1)
206 rdev->current =
207 (rptr != 0 ? rptr :
208 y >= rdev->current->ymax ? rdev->list.tail :
209 rdev->list.head);
210 return 0;
211 }
212 rdev->current = rptr;
213 if (yc < y)
214 yc = y;
215
216 do {
217 const int ymax = rptr->ymax;
218 int yec = min(ymax, ye);
219
220 if_debug2('Q', "[Q]yc=%d yec=%d\n", yc, yec);
221 do {
222 int xc = rptr->xmin;
223 int xec = rptr->xmax;
224
225 if (xc < x)
226 xc = x;
227 if (xec > xe)
228 xec = xe;
229 if (xec > xc) {
230 clip_rect_print('Q', "match", rptr);
231 if_debug2('Q', "[Q]xc=%d xec=%d\n", xc, xec);
232 INCR(x);
233 /*
234 * Conditionally look ahead to detect unclipped vertical strips. This is
235 * really only valuable for 90 degree rotated images or (nearly-)vertical
236 * lines with convex clipping regions; if we ever change images to use
237 * source buffering and destination-oriented enumeration, we could probably
238 * take out the code here with no adverse effects.
239 */
240 #ifdef CHECK_VERTICAL_CLIPPING
241 if (xec - xc == pccd->w) { /* full width */
242 /* Look ahead for a vertical swath. */
243 while ((rptr = rptr->next) != 0 &&
244 rptr->ymin == yec &&
245 rptr->ymax <= ye &&
246 rptr->xmin <= x &&
247 rptr->xmax >= xe
248 )
249 yec = rptr->ymax;
250 } else
251 rptr = rptr->next;
252 #else
253 rptr = rptr->next;
254 #endif
255 code = process(pccd, xc, yc, xec, yec);
256 if (code < 0)
257 return code;
258 } else {
259 INCR_THEN(no_x, rptr = rptr->next);
260 }
261 if (rptr == 0)
262 return 0;
263 }
264 while (rptr->ymax == ymax);
265 } while ((yc = rptr->ymin) < ye);
266 return 0;
267 }
268
269 static int
clip_enumerate(gx_device_clip * rdev,int x,int y,int w,int h,int (* process)(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec),clip_callback_data_t * pccd)270 clip_enumerate(gx_device_clip * rdev, int x, int y, int w, int h,
271 int (*process)(clip_callback_data_t * pccd,
272 int xc, int yc, int xec, int yec),
273 clip_callback_data_t * pccd)
274 {
275 int xe, ye;
276 const gx_clip_rect *rptr = rdev->current;
277
278 if (w <= 0 || h <= 0)
279 return 0;
280 pccd->tdev = rdev->target;
281 x += rdev->translation.x;
282 xe = x + w;
283 y += rdev->translation.y;
284 ye = y + h;
285 /* Check for the region being entirely within the current rectangle. */
286 if (y >= rptr->ymin && ye <= rptr->ymax &&
287 x >= rptr->xmin && xe <= rptr->xmax
288 ) {
289 pccd->x = x, pccd->y = y, pccd->w = w, pccd->h = h;
290 return INCR_THEN(in, process(pccd, x, y, xe, ye));
291 }
292 return clip_enumerate_rest(rdev, x, y, xe, ye, process, pccd);
293 }
294
295 /* Open a clipping device */
296 static int
clip_open(gx_device * dev)297 clip_open(gx_device * dev)
298 {
299 gx_device_clip *const rdev = (gx_device_clip *) dev;
300 gx_device *tdev = rdev->target;
301
302 /* Initialize the cursor. */
303 rdev->current =
304 (rdev->list.head == 0 ? &rdev->list.single : rdev->list.head);
305 rdev->color_info = tdev->color_info;
306 rdev->cached_colors = tdev->cached_colors;
307 rdev->width = tdev->width;
308 rdev->height = tdev->height;
309 gx_device_copy_color_procs(dev, tdev);
310 rdev->clipping_box_set = false;
311 rdev->memory = tdev->memory;
312 return 0;
313 }
314
315 /* Fill a rectangle */
316 int
clip_call_fill_rectangle(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)317 clip_call_fill_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
318 {
319 return (*dev_proc(pccd->tdev, fill_rectangle))
320 (pccd->tdev, xc, yc, xec - xc, yec - yc, pccd->color[0]);
321 }
322 static int
clip_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)323 clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
324 gx_color_index color)
325 {
326 gx_device_clip *rdev = (gx_device_clip *) dev;
327 clip_callback_data_t ccdata;
328 /* We handle the fastest cases in-line here. */
329 gx_device *tdev = rdev->target;
330 /*const*/ gx_clip_rect *rptr = rdev->current;
331 int xe, ye;
332
333 if (w <= 0 || h <= 0)
334 return 0;
335 x += rdev->translation.x;
336 xe = x + w;
337 y += rdev->translation.y;
338 ye = y + h;
339 /* We open-code the most common cases here. */
340 if ((y >= rptr->ymin && ye <= rptr->ymax) ||
341 ((rptr = rptr->next) != 0 &&
342 y >= rptr->ymin && ye <= rptr->ymax)
343 ) {
344 rdev->current = rptr; /* may be redundant, but awkward to avoid */
345 INCR(in_y);
346 if (x >= rptr->xmin && xe <= rptr->xmax) {
347 INCR(in);
348 return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
349 }
350 else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
351 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
352 ) {
353 INCR(in1);
354 if (x < rptr->xmin)
355 x = rptr->xmin;
356 if (xe > rptr->xmax)
357 xe = rptr->xmax;
358 return
359 (x >= xe ? 0 :
360 dev_proc(tdev, fill_rectangle)(tdev, x, y, xe - x, h, color));
361 }
362 }
363 ccdata.tdev = tdev;
364 ccdata.color[0] = color;
365 return clip_enumerate_rest(rdev, x, y, xe, ye,
366 clip_call_fill_rectangle, &ccdata);
367 }
368
369 /* Copy a monochrome rectangle */
370 int
clip_call_copy_mono(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)371 clip_call_copy_mono(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
372 {
373 return (*dev_proc(pccd->tdev, copy_mono))
374 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
375 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
376 xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->color[1]);
377 }
378 static int
clip_copy_mono(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)379 clip_copy_mono(gx_device * dev,
380 const byte * data, int sourcex, int raster, gx_bitmap_id id,
381 int x, int y, int w, int h,
382 gx_color_index color0, gx_color_index color1)
383 {
384 gx_device_clip *rdev = (gx_device_clip *) dev;
385 clip_callback_data_t ccdata;
386 /* We handle the fastest case in-line here. */
387 gx_device *tdev = rdev->target;
388 const gx_clip_rect *rptr = rdev->current;
389 int xe, ye;
390
391 if (w <= 0 || h <= 0)
392 return 0;
393 x += rdev->translation.x;
394 xe = x + w;
395 y += rdev->translation.y;
396 ye = y + h;
397 if (y >= rptr->ymin && ye <= rptr->ymax) {
398 INCR(in_y);
399 if (x >= rptr->xmin && xe <= rptr->xmax) {
400 INCR(in);
401 return dev_proc(tdev, copy_mono)
402 (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
403 }
404 }
405 ccdata.tdev = tdev;
406 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
407 ccdata.color[0] = color0, ccdata.color[1] = color1;
408 return clip_enumerate_rest(rdev, x, y, xe, ye,
409 clip_call_copy_mono, &ccdata);
410 }
411
412 /* Copy a color rectangle */
413 int
clip_call_copy_color(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)414 clip_call_copy_color(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
415 {
416 return (*dev_proc(pccd->tdev, copy_color))
417 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
418 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
419 xc, yc, xec - xc, yec - yc);
420 }
421 static int
clip_copy_color(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)422 clip_copy_color(gx_device * dev,
423 const byte * data, int sourcex, int raster, gx_bitmap_id id,
424 int x, int y, int w, int h)
425 {
426 gx_device_clip *rdev = (gx_device_clip *) dev;
427 clip_callback_data_t ccdata;
428
429 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
430 return clip_enumerate(rdev, x, y, w, h, clip_call_copy_color, &ccdata);
431 }
432
433 /* Copy a rectangle with alpha */
434 int
clip_call_copy_alpha(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)435 clip_call_copy_alpha(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
436 {
437 return (*dev_proc(pccd->tdev, copy_alpha))
438 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
439 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
440 xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->depth);
441 }
442 static int
clip_copy_alpha(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color,int depth)443 clip_copy_alpha(gx_device * dev,
444 const byte * data, int sourcex, int raster, gx_bitmap_id id,
445 int x, int y, int w, int h,
446 gx_color_index color, int depth)
447 {
448 gx_device_clip *rdev = (gx_device_clip *) dev;
449 clip_callback_data_t ccdata;
450
451 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
452 ccdata.color[0] = color, ccdata.depth = depth;
453 return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha, &ccdata);
454 }
455
456 /* Fill a region defined by a mask. */
457 int
clip_call_fill_mask(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)458 clip_call_fill_mask(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
459 {
460 return (*dev_proc(pccd->tdev, fill_mask))
461 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
462 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
463 xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth,
464 pccd->lop, NULL);
465 }
466 static int
clip_fill_mask(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)467 clip_fill_mask(gx_device * dev,
468 const byte * data, int sourcex, int raster, gx_bitmap_id id,
469 int x, int y, int w, int h,
470 const gx_drawing_color * pdcolor, int depth,
471 gs_logical_operation_t lop, const gx_clip_path * pcpath)
472 {
473 gx_device_clip *rdev = (gx_device_clip *) dev;
474 clip_callback_data_t ccdata;
475
476 if (pcpath != 0)
477 return gx_default_fill_mask(dev, data, sourcex, raster, id,
478 x, y, w, h, pdcolor, depth, lop,
479 pcpath);
480 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
481 ccdata.pdcolor = pdcolor, ccdata.depth = depth, ccdata.lop = lop;
482 return clip_enumerate(rdev, x, y, w, h, clip_call_fill_mask, &ccdata);
483 }
484
485 /* Strip-tile a rectangle. */
486 int
clip_call_strip_tile_rectangle(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)487 clip_call_strip_tile_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
488 {
489 return (*dev_proc(pccd->tdev, strip_tile_rectangle))
490 (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
491 pccd->color[0], pccd->color[1], pccd->phase.x, pccd->phase.y);
492 }
493 static int
clip_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1,int phase_x,int phase_y)494 clip_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
495 int x, int y, int w, int h,
496 gx_color_index color0, gx_color_index color1, int phase_x, int phase_y)
497 {
498 gx_device_clip *rdev = (gx_device_clip *) dev;
499 clip_callback_data_t ccdata;
500
501 ccdata.tiles = tiles;
502 ccdata.color[0] = color0, ccdata.color[1] = color1;
503 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
504 return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rectangle, &ccdata);
505 }
506
507 /* Copy a rectangle with RasterOp and strip texture. */
508 int
clip_call_strip_copy_rop(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)509 clip_call_strip_copy_rop(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
510 {
511 return (*dev_proc(pccd->tdev, strip_copy_rop))
512 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
513 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
514 pccd->scolors, pccd->textures, pccd->tcolors,
515 xc, yc, xec - xc, yec - yc, pccd->phase.x, pccd->phase.y,
516 pccd->lop);
517 }
518 static int
clip_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint raster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int w,int h,int phase_x,int phase_y,gs_logical_operation_t lop)519 clip_strip_copy_rop(gx_device * dev,
520 const byte * sdata, int sourcex, uint raster, gx_bitmap_id id,
521 const gx_color_index * scolors,
522 const gx_strip_bitmap * textures, const gx_color_index * tcolors,
523 int x, int y, int w, int h,
524 int phase_x, int phase_y, gs_logical_operation_t lop)
525 {
526 gx_device_clip *rdev = (gx_device_clip *) dev;
527 clip_callback_data_t ccdata;
528
529 ccdata.data = sdata, ccdata.sourcex = sourcex, ccdata.raster = raster;
530 ccdata.scolors = scolors, ccdata.textures = textures,
531 ccdata.tcolors = tcolors;
532 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
533 return clip_enumerate(rdev, x, y, w, h, clip_call_strip_copy_rop, &ccdata);
534 }
535
536 /* Get the (outer) clipping box, in client coordinates. */
537 static void
clip_get_clipping_box(gx_device * dev,gs_fixed_rect * pbox)538 clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
539 {
540 gx_device_clip *const rdev = (gx_device_clip *) dev;
541
542 if (!rdev->clipping_box_set) {
543 gx_device *tdev = rdev->target;
544 gs_fixed_rect tbox;
545
546 (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
547 if (rdev->list.count != 0) {
548 gs_fixed_rect cbox;
549
550 if (rdev->list.count == 1) {
551 cbox.p.x = int2fixed(rdev->list.single.xmin);
552 cbox.p.y = int2fixed(rdev->list.single.ymin);
553 cbox.q.x = int2fixed(rdev->list.single.xmax);
554 cbox.q.y = int2fixed(rdev->list.single.ymax);
555 } else {
556 /* The head and tail elements are dummies.... */
557 cbox.p.x = int2fixed(rdev->list.xmin);
558 cbox.p.y = int2fixed(rdev->list.head->next->ymin);
559 cbox.q.x = int2fixed(rdev->list.xmax);
560 cbox.q.y = int2fixed(rdev->list.tail->prev->ymax);
561 }
562 rect_intersect(tbox, cbox);
563 }
564 if (rdev->translation.x | rdev->translation.y) {
565 fixed tx = int2fixed(rdev->translation.x),
566 ty = int2fixed(rdev->translation.y);
567
568 if (tbox.p.x != min_fixed)
569 tbox.p.x -= tx;
570 if (tbox.p.y != min_fixed)
571 tbox.p.y -= ty;
572 if (tbox.q.x != max_fixed)
573 tbox.q.x -= tx;
574 if (tbox.q.y != max_fixed)
575 tbox.q.y -= ty;
576 }
577 rdev->clipping_box = tbox;
578 rdev->clipping_box_set = true;
579 }
580 *pbox = rdev->clipping_box;
581 }
582
583 /* Get bits back from the device. */
584 static int
clip_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)585 clip_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
586 gs_get_bits_params_t * params, gs_int_rect ** unread)
587 {
588 gx_device_clip *rdev = (gx_device_clip *) dev;
589 gx_device *tdev = rdev->target;
590 int tx = rdev->translation.x, ty = rdev->translation.y;
591 gs_int_rect rect;
592 int code;
593
594 rect.p.x = prect->p.x - tx, rect.p.y = prect->p.y - ty;
595 rect.q.x = prect->q.x - tx, rect.q.y = prect->q.y - ty;
596 code = (*dev_proc(tdev, get_bits_rectangle))
597 (tdev, &rect, params, unread);
598 if (code > 0) {
599 /* Adjust unread rectangle coordinates */
600 gs_int_rect *list = *unread;
601 int i;
602
603 for (i = 0; i < code; ++list, ++i) {
604 list->p.x += tx, list->p.y += ty;
605 list->q.x += tx, list->q.y += ty;
606 }
607 }
608 return code;
609 }
610