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