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