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