1 /* Copyright (C) 2001-2012 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, 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_rop(clip_strip_copy_rop);
45 static dev_proc_strip_copy_rop2(clip_strip_copy_rop2);
46 static dev_proc_get_clipping_box(clip_get_clipping_box);
47 static dev_proc_get_bits_rectangle(clip_get_bits_rectangle);
48 static dev_proc_fill_path(clip_fill_path);
49
50 /* The device descriptor. */
51 static const gx_device_clip gs_clip_device =
52 {std_device_std_body(gx_device_clip, 0, "clipper",
53 0, 0, 1, 1),
54 {clip_open,
55 gx_forward_get_initial_matrix,
56 gx_default_sync_output,
57 gx_default_output_page,
58 gx_default_close_device,
59 gx_forward_map_rgb_color,
60 gx_forward_map_color_rgb,
61 clip_fill_rectangle,
62 gx_default_tile_rectangle,
63 clip_copy_mono,
64 clip_copy_color,
65 gx_default_draw_line,
66 gx_default_get_bits,
67 gx_forward_get_params,
68 gx_forward_put_params,
69 gx_forward_map_cmyk_color,
70 gx_forward_get_xfont_procs,
71 gx_forward_get_xfont_device,
72 gx_forward_map_rgb_alpha_color,
73 gx_forward_get_page_device,
74 gx_forward_get_alpha_bits,
75 clip_copy_alpha,
76 gx_forward_get_band,
77 gx_default_copy_rop,
78 clip_fill_path,
79 gx_default_stroke_path,
80 clip_fill_mask,
81 gx_default_fill_trapezoid,
82 gx_default_fill_parallelogram,
83 gx_default_fill_triangle,
84 gx_default_draw_thin_line,
85 gx_default_begin_image,
86 gx_default_image_data,
87 gx_default_end_image,
88 clip_strip_tile_rectangle,
89 clip_strip_copy_rop,
90 clip_get_clipping_box,
91 gx_default_begin_typed_image,
92 clip_get_bits_rectangle,
93 gx_forward_map_color_rgb_alpha,
94 gx_forward_create_compositor,
95 gx_forward_get_hardware_params,
96 gx_default_text_begin,
97 gx_default_finish_copydevice,
98 NULL, /* begin_transparency_group */
99 NULL, /* end_transparency_group */
100 NULL, /* begin_transparency_mask */
101 NULL, /* end_transparency_mask */
102 NULL, /* discard_transparency_layer */
103 gx_forward_get_color_mapping_procs,
104 gx_forward_get_color_comp_index,
105 gx_forward_encode_color,
106 gx_forward_decode_color,
107 NULL,
108 clip_fill_rectangle_hl_color,
109 gx_forward_include_color_space,
110 gx_default_fill_linear_color_scanline,
111 gx_default_fill_linear_color_trapezoid,
112 gx_default_fill_linear_color_triangle,
113 gx_forward_update_spot_equivalent_colors,
114 gx_forward_ret_devn_params,
115 gx_forward_fillpage,
116 NULL, /* push_transparency_state */
117 NULL, /* pop_transparency_state */
118 NULL, /* put_image */
119 gx_forward_dev_spec_op,
120 clip_copy_planes, /* copy planes */
121 gx_forward_get_profile,
122 gx_forward_set_graphics_type_tag,
123 clip_strip_copy_rop2,
124 clip_strip_tile_rect_devn,
125 clip_copy_alpha_hl_color
126 }
127 };
128
129 /* Make a clipping device. */
130 void
gx_make_clip_device_on_stack(gx_device_clip * dev,const gx_clip_path * pcpath,gx_device * target)131 gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target)
132 {
133 gx_device_init((gx_device *)dev, (const gx_device *)&gs_clip_device, NULL, true);
134 dev->list = *gx_cpath_list(pcpath);
135 dev->translation.x = 0;
136 dev->translation.y = 0;
137 dev->HWResolution[0] = target->HWResolution[0];
138 dev->HWResolution[1] = target->HWResolution[1];
139 dev->sgr = target->sgr;
140 dev->target = target;
141 dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */
142 /* There is no finalization for device on stack so no rc increment */
143 (*dev_proc(dev, open_device)) ((gx_device *)dev);
144 }
145
146 gx_device *
gx_make_clip_device_on_stack_if_needed(gx_device_clip * dev,const gx_clip_path * pcpath,gx_device * target,gs_fixed_rect * rect)147 gx_make_clip_device_on_stack_if_needed(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, gs_fixed_rect *rect)
148 {
149 /* Reduce area if possible */
150 if (rect->p.x < pcpath->outer_box.p.x)
151 rect->p.x = pcpath->outer_box.p.x;
152 if (rect->q.x > pcpath->outer_box.q.x)
153 rect->q.x = pcpath->outer_box.q.x;
154 if (rect->p.y < pcpath->outer_box.p.y)
155 rect->p.y = pcpath->outer_box.p.y;
156 if (rect->q.y > pcpath->outer_box.q.y)
157 rect->q.y = pcpath->outer_box.q.y;
158 if (pcpath->inner_box.p.x <= rect->p.x && pcpath->inner_box.p.y <= rect->p.y &&
159 pcpath->inner_box.q.x >= rect->q.x && pcpath->inner_box.q.y >= rect->q.y)
160 {
161 /* Area is trivially included. No need for clip. */
162 return target;
163 }
164 else
165 {
166 /* Check for area being trivially clipped away. */
167 if (rect->p.x >= rect->q.x || rect->p.y >= rect->q.y)
168 return NULL;
169 }
170 gx_device_init((gx_device *)dev, (const gx_device *)&gs_clip_device, NULL, true);
171 dev->list = *gx_cpath_list(pcpath);
172 dev->translation.x = 0;
173 dev->translation.y = 0;
174 dev->HWResolution[0] = target->HWResolution[0];
175 dev->HWResolution[1] = target->HWResolution[1];
176 dev->sgr = target->sgr;
177 dev->target = target;
178 dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */
179 /* There is no finalization for device on stack so no rc increment */
180 (*dev_proc(dev, open_device)) ((gx_device *)dev);
181 return (gx_device *)dev;
182 }
183 void
gx_make_clip_device_in_heap(gx_device_clip * dev,const gx_clip_path * pcpath,gx_device * target,gs_memory_t * mem)184 gx_make_clip_device_in_heap(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target,
185 gs_memory_t *mem)
186 {
187 gx_device_init((gx_device *)dev, (const gx_device *)&gs_clip_device, mem, true);
188 dev->list = *gx_cpath_list(pcpath);
189 dev->translation.x = 0;
190 dev->translation.y = 0;
191 dev->HWResolution[0] = target->HWResolution[0];
192 dev->HWResolution[1] = target->HWResolution[1];
193 dev->sgr = target->sgr;
194 gx_device_set_target((gx_device_forward *)dev, target);
195 gx_device_retain((gx_device *)dev, true); /* will free explicitly */
196 (*dev_proc(dev, open_device)) ((gx_device *)dev);
197 }
198 /* Define debugging statistics for the clipping loops. */
199 #ifdef DEBUG
200 struct stats_clip_s {
201 long
202 loops, out, in_y, in, in1, down, up, x, no_x;
203 } stats_clip;
204
205 static const uint clip_interval = 10000;
206
207 # define INCR(v) (++(stats_clip.v))
208 # define INCR_THEN(v, e) (INCR(v), (e))
209 #else
210 # define INCR(v) DO_NOTHING
211 # define INCR_THEN(v, e) (e)
212 #endif
213
214 /*
215 * Enumerate the rectangles of the x,w,y,h argument that fall within
216 * the clipping region.
217 */
218 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)219 clip_enumerate_rest(gx_device_clip * rdev,
220 int x, int y, int xe, int ye,
221 int (*process)(clip_callback_data_t * pccd,
222 int xc, int yc, int xec, int yec),
223 clip_callback_data_t * pccd)
224 {
225 gx_clip_rect *rptr = rdev->current; /* const within algorithm */
226 int yc;
227 int code;
228
229 #ifdef DEBUG
230 if (INCR(loops) % clip_interval == 0 && gs_debug_c('q')) {
231 dprintf5("[q]loops=%ld out=%ld in_y=%ld in=%ld in1=%ld\n",
232 stats_clip.loops, stats_clip.out, stats_clip.in,
233 stats_clip.in_y, stats_clip.in1);
234 dprintf4("[q] down=%ld up=%ld x=%ld no_x=%ld\n",
235 stats_clip.down, stats_clip.up, stats_clip.x,
236 stats_clip.no_x);
237 }
238 #endif
239 pccd->x = x, pccd->y = y;
240 pccd->w = xe - x, pccd->h = ye - y;
241 /*
242 * Warp the cursor forward or backward to the first rectangle row
243 * that could include a given y value. Assumes rptr is set, and
244 * updates it. Specifically, after this loop, either rptr == 0 (if
245 * the y value is greater than all y values in the list), or y <
246 * rptr->ymax and either rptr->prev == 0 or y >= rptr->prev->ymax.
247 * Note that y <= rptr->ymin is possible.
248 *
249 * In the first case below, the while loop is safe because if there
250 * is more than one rectangle, there is a 'stopper' at the end of
251 * the list.
252 */
253 if (y >= rptr->ymax) {
254 if ((rptr = rptr->next) != 0)
255 while (INCR_THEN(up, y >= rptr->ymax))
256 rptr = rptr->next;
257 } else
258 while (rptr->prev != 0 && y < rptr->prev->ymax)
259 INCR_THEN(down, rptr = rptr->prev);
260 if (rptr == 0 || (yc = rptr->ymin) >= ye) {
261 INCR(out);
262 if (rdev->list.count > 1)
263 rdev->current =
264 (rptr != 0 ? rptr :
265 y >= rdev->current->ymax ? rdev->list.tail :
266 rdev->list.head);
267 return 0;
268 }
269 rdev->current = rptr;
270 if (yc < y)
271 yc = y;
272
273 do {
274 const int ymax = rptr->ymax;
275 int yec = min(ymax, ye);
276
277 if_debug2('Q', "[Q]yc=%d yec=%d\n", yc, yec);
278 do {
279 int xc = rptr->xmin;
280 int xec = rptr->xmax;
281
282 if (xc < x)
283 xc = x;
284 if (xec > xe)
285 xec = xe;
286 if (xec > xc) {
287 clip_rect_print('Q', "match", rptr);
288 if_debug2('Q', "[Q]xc=%d xec=%d\n", xc, xec);
289 INCR(x);
290 /*
291 * Conditionally look ahead to detect unclipped vertical strips. This is
292 * really only valuable for 90 degree rotated images or (nearly-)vertical
293 * lines with convex clipping regions; if we ever change images to use
294 * source buffering and destination-oriented enumeration, we could probably
295 * take out the code here with no adverse effects.
296 */
297 #ifdef CHECK_VERTICAL_CLIPPING
298 if (xec - xc == pccd->w) { /* full width */
299 /* Look ahead for a vertical swath. */
300 while ((rptr = rptr->next) != 0 &&
301 rptr->ymin == yec &&
302 rptr->ymax <= ye &&
303 rptr->xmin <= x &&
304 rptr->xmax >= xe
305 )
306 yec = rptr->ymax;
307 } else
308 rptr = rptr->next;
309 #else
310 rptr = rptr->next;
311 #endif
312 code = process(pccd, xc, yc, xec, yec);
313 if (code < 0)
314 return code;
315 } else {
316 INCR_THEN(no_x, rptr = rptr->next);
317 }
318 if (rptr == 0)
319 return 0;
320 }
321 while (rptr->ymax == ymax);
322 } while ((yc = rptr->ymin) < ye);
323 return 0;
324 }
325
326 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)327 clip_enumerate(gx_device_clip * rdev, int x, int y, int w, int h,
328 int (*process)(clip_callback_data_t * pccd,
329 int xc, int yc, int xec, int yec),
330 clip_callback_data_t * pccd)
331 {
332 int xe, ye;
333 const gx_clip_rect *rptr = rdev->current;
334
335 if (w <= 0 || h <= 0)
336 return 0;
337 pccd->tdev = rdev->target;
338 x += rdev->translation.x;
339 xe = x + w;
340 y += rdev->translation.y;
341 ye = y + h;
342 /* Check for the region being entirely within the current rectangle. */
343 if (y >= rptr->ymin && ye <= rptr->ymax &&
344 x >= rptr->xmin && xe <= rptr->xmax
345 ) {
346 pccd->x = x, pccd->y = y, pccd->w = w, pccd->h = h;
347 return INCR_THEN(in, process(pccd, x, y, xe, ye));
348 }
349 return clip_enumerate_rest(rdev, x, y, xe, ye, process, pccd);
350 }
351
352 /* Open a clipping device */
353 static int
clip_open(gx_device * dev)354 clip_open(gx_device * dev)
355 {
356 gx_device_clip *const rdev = (gx_device_clip *) dev;
357 gx_device *tdev = rdev->target;
358
359 /* Initialize the cursor. */
360 rdev->current =
361 (rdev->list.head == 0 ? &rdev->list.single : rdev->list.head);
362 rdev->color_info = tdev->color_info;
363 rdev->cached_colors = tdev->cached_colors;
364 rdev->width = tdev->width;
365 rdev->height = tdev->height;
366 gx_device_copy_color_procs(dev, tdev);
367 rdev->clipping_box_set = false;
368 rdev->memory = tdev->memory;
369 return 0;
370 }
371
372 /* Fill a rectangle */
373 int
clip_call_fill_rectangle(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)374 clip_call_fill_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
375 {
376 return (*dev_proc(pccd->tdev, fill_rectangle))
377 (pccd->tdev, xc, yc, xec - xc, yec - yc, pccd->color[0]);
378 }
379 static int
clip_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)380 clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
381 gx_color_index color)
382 {
383 gx_device_clip *rdev = (gx_device_clip *) dev;
384 clip_callback_data_t ccdata;
385 /* We handle the fastest cases in-line here. */
386 gx_device *tdev = rdev->target;
387 /*const*/ gx_clip_rect *rptr = rdev->current;
388 int xe, ye;
389
390 if (w <= 0 || h <= 0)
391 return 0;
392 x += rdev->translation.x;
393 xe = x + w;
394 y += rdev->translation.y;
395 ye = y + h;
396 /* We open-code the most common cases here. */
397 if ((y >= rptr->ymin && ye <= rptr->ymax) ||
398 ((rptr = rptr->next) != 0 &&
399 y >= rptr->ymin && ye <= rptr->ymax)
400 ) {
401 rdev->current = rptr; /* may be redundant, but awkward to avoid */
402 INCR(in_y);
403 if (x >= rptr->xmin && xe <= rptr->xmax) {
404 INCR(in);
405 return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color);
406 }
407 else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
408 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
409 ) {
410 INCR(in1);
411 if (x < rptr->xmin)
412 x = rptr->xmin;
413 if (xe > rptr->xmax)
414 xe = rptr->xmax;
415 return
416 (x >= xe ? 0 :
417 dev_proc(tdev, fill_rectangle)(tdev, x, y, xe - x, h, color));
418 }
419 }
420 ccdata.tdev = tdev;
421 ccdata.color[0] = color;
422 return clip_enumerate_rest(rdev, x, y, xe, ye,
423 clip_call_fill_rectangle, &ccdata);
424 }
425
426 int
clip_call_fill_rectangle_hl_color(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)427 clip_call_fill_rectangle_hl_color(clip_callback_data_t * pccd, int xc, int yc,
428 int xec, int yec)
429 {
430 gs_fixed_rect rect;
431
432 rect.p.x = xc;
433 rect.p.y = yc;
434 rect.q.x = xec;
435 rect.q.y = yec;
436 return (*dev_proc(pccd->tdev, fill_rectangle_hl_color))
437 (pccd->tdev, &rect, pccd->pis, pccd->pdcolor, pccd->pcpath);
438 }
439
440 static int
clip_fill_rectangle_hl_color(gx_device * dev,const gs_fixed_rect * rect,const gs_imager_state * pis,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)441 clip_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
442 const gs_imager_state *pis, const gx_drawing_color *pdcolor,
443 const gx_clip_path *pcpath)
444 {
445 gx_device_clip *rdev = (gx_device_clip *) dev;
446 clip_callback_data_t ccdata;
447 gx_device *tdev = rdev->target;
448 gx_clip_rect *rptr = rdev->current;
449 int xe, ye;
450 int w, h, x, y;
451 gs_fixed_rect newrect;
452
453 x = rect->p.x;
454 y = rect->p.y;
455 w = rect->q.x - rect->p.x;
456 h = rect->q.y - rect->p.y;
457
458 if (w <= 0 || h <= 0)
459 return 0;
460 x += rdev->translation.x;
461 xe = x + w;
462 y += rdev->translation.y;
463 ye = y + h;
464 /* We open-code the most common cases here. */
465 if ((y >= rptr->ymin && ye <= rptr->ymax) ||
466 ((rptr = rptr->next) != 0 &&
467 y >= rptr->ymin && ye <= rptr->ymax)
468 ) {
469 rdev->current = rptr; /* may be redundant, but awkward to avoid */
470 INCR(in_y);
471 if (x >= rptr->xmin && xe <= rptr->xmax) {
472 INCR(in);
473 newrect.p.x = x;
474 newrect.p.y = y;
475 newrect.q.x = x + w;
476 newrect.q.y = y + h;
477 return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pis,
478 pdcolor, pcpath);
479 }
480 else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) &&
481 (rptr->next == 0 || rptr->next->ymax != rptr->ymax)
482 ) {
483 INCR(in1);
484 if (x < rptr->xmin)
485 x = rptr->xmin;
486 if (xe > rptr->xmax)
487 xe = rptr->xmax;
488 if (x >= xe)
489 return 0;
490 else {
491 newrect.p.x = x;
492 newrect.p.y = y;
493 newrect.q.x = xe;
494 newrect.q.y = y + h;
495 return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pis,
496 pdcolor, pcpath);
497 }
498 }
499 }
500 ccdata.tdev = tdev;
501 ccdata.pdcolor = pdcolor;
502 ccdata.pis = pis;
503 ccdata.pcpath = pcpath;
504 return clip_enumerate_rest(rdev, x, y, xe, ye,
505 clip_call_fill_rectangle_hl_color, &ccdata);
506 }
507
508 /* Copy a monochrome rectangle */
509 int
clip_call_copy_mono(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)510 clip_call_copy_mono(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
511 {
512 return (*dev_proc(pccd->tdev, copy_mono))
513 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
514 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
515 xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->color[1]);
516 }
517 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)518 clip_copy_mono(gx_device * dev,
519 const byte * data, int sourcex, int raster, gx_bitmap_id id,
520 int x, int y, int w, int h,
521 gx_color_index color0, gx_color_index color1)
522 {
523 gx_device_clip *rdev = (gx_device_clip *) dev;
524 clip_callback_data_t ccdata;
525 /* We handle the fastest case in-line here. */
526 gx_device *tdev = rdev->target;
527 const gx_clip_rect *rptr = rdev->current;
528 int xe, ye;
529
530 if (w <= 0 || h <= 0)
531 return 0;
532 x += rdev->translation.x;
533 xe = x + w;
534 y += rdev->translation.y;
535 ye = y + h;
536 if (y >= rptr->ymin && ye <= rptr->ymax) {
537 INCR(in_y);
538 if (x >= rptr->xmin && xe <= rptr->xmax) {
539 INCR(in);
540 return dev_proc(tdev, copy_mono)
541 (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1);
542 }
543 }
544 ccdata.tdev = tdev;
545 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
546 ccdata.color[0] = color0, ccdata.color[1] = color1;
547 return clip_enumerate_rest(rdev, x, y, xe, ye,
548 clip_call_copy_mono, &ccdata);
549 }
550
551 /* Copy a plane */
552 int
clip_call_copy_planes(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)553 clip_call_copy_planes(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
554 {
555 return (*dev_proc(pccd->tdev, copy_planes))
556 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
557 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
558 xc, yc, xec - xc, yec - yc, pccd->plane_height);
559 }
560 static int
clip_copy_planes(gx_device * dev,const byte * data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,int plane_height)561 clip_copy_planes(gx_device * dev,
562 const byte * data, int sourcex, int raster, gx_bitmap_id id,
563 int x, int y, int w, int h, int plane_height)
564 {
565 gx_device_clip *rdev = (gx_device_clip *) dev;
566 clip_callback_data_t ccdata;
567 /* We handle the fastest case in-line here. */
568 gx_device *tdev = rdev->target;
569 const gx_clip_rect *rptr = rdev->current;
570 int xe, ye;
571
572 if (w <= 0 || h <= 0)
573 return 0;
574 x += rdev->translation.x;
575 xe = x + w;
576 y += rdev->translation.y;
577 ye = y + h;
578 if (y >= rptr->ymin && ye <= rptr->ymax) {
579 INCR(in_y);
580 if (x >= rptr->xmin && xe <= rptr->xmax) {
581 INCR(in);
582 return dev_proc(tdev, copy_planes)
583 (tdev, data, sourcex, raster, id, x, y, w, h, plane_height);
584 }
585 }
586 ccdata.tdev = tdev;
587 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
588 ccdata.plane_height = plane_height;
589 return clip_enumerate_rest(rdev, x, y, xe, ye,
590 clip_call_copy_planes, &ccdata);
591 }
592
593 /* Copy a color rectangle */
594 int
clip_call_copy_color(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)595 clip_call_copy_color(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
596 {
597 return (*dev_proc(pccd->tdev, copy_color))
598 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
599 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
600 xc, yc, xec - xc, yec - yc);
601 }
602 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)603 clip_copy_color(gx_device * dev,
604 const byte * data, int sourcex, int raster, gx_bitmap_id id,
605 int x, int y, int w, int h)
606 {
607 gx_device_clip *rdev = (gx_device_clip *) dev;
608 clip_callback_data_t ccdata;
609
610 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
611 return clip_enumerate(rdev, x, y, w, h, clip_call_copy_color, &ccdata);
612 }
613
614 /* Copy a rectangle with alpha */
615 int
clip_call_copy_alpha(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)616 clip_call_copy_alpha(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
617 {
618 return (*dev_proc(pccd->tdev, copy_alpha))
619 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
620 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
621 xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->depth);
622 }
623 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)624 clip_copy_alpha(gx_device * dev,
625 const byte * data, int sourcex, int raster, gx_bitmap_id id,
626 int x, int y, int w, int h,
627 gx_color_index color, int depth)
628 {
629 gx_device_clip *rdev = (gx_device_clip *) dev;
630 clip_callback_data_t ccdata;
631
632 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
633 ccdata.color[0] = color, ccdata.depth = depth;
634 return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha, &ccdata);
635 }
636
637 int
clip_call_copy_alpha_hl_color(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)638 clip_call_copy_alpha_hl_color(clip_callback_data_t * pccd, int xc, int yc,
639 int xec, int yec)
640 {
641 return (*dev_proc(pccd->tdev, copy_alpha_hl_color))
642 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
643 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
644 xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth);
645 }
646
647 static int
clip_copy_alpha_hl_color(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)648 clip_copy_alpha_hl_color(gx_device * dev,
649 const byte * data, int sourcex, int raster, gx_bitmap_id id,
650 int x, int y, int w, int h,
651 const gx_drawing_color *pdcolor, int depth)
652 {
653 gx_device_clip *rdev = (gx_device_clip *) dev;
654 clip_callback_data_t ccdata;
655
656 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
657 ccdata.pdcolor = pdcolor, ccdata.depth = depth;
658 return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha_hl_color, &ccdata);
659 }
660
661 /* Fill a region defined by a mask. */
662 int
clip_call_fill_mask(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)663 clip_call_fill_mask(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
664 {
665 return (*dev_proc(pccd->tdev, fill_mask))
666 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
667 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
668 xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth,
669 pccd->lop, NULL);
670 }
671 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)672 clip_fill_mask(gx_device * dev,
673 const byte * data, int sourcex, int raster, gx_bitmap_id id,
674 int x, int y, int w, int h,
675 const gx_drawing_color * pdcolor, int depth,
676 gs_logical_operation_t lop, const gx_clip_path * pcpath)
677 {
678 gx_device_clip *rdev = (gx_device_clip *) dev;
679 clip_callback_data_t ccdata;
680
681 if (pcpath != 0)
682 return gx_default_fill_mask(dev, data, sourcex, raster, id,
683 x, y, w, h, pdcolor, depth, lop,
684 pcpath);
685 ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster;
686 ccdata.pdcolor = pdcolor, ccdata.depth = depth, ccdata.lop = lop;
687 return clip_enumerate(rdev, x, y, w, h, clip_call_fill_mask, &ccdata);
688 }
689
690 /* Strip-tile a rectangle with devn colors. */
691 int
clip_call_strip_tile_rect_devn(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)692 clip_call_strip_tile_rect_devn(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
693 {
694 return (*dev_proc(pccd->tdev, strip_tile_rect_devn))
695 (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
696 pccd->pdc[0], pccd->pdc[1], pccd->phase.x, pccd->phase.y);
697 }
698 static int
clip_strip_tile_rect_devn(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int w,int h,const gx_drawing_color * pdcolor0,const gx_drawing_color * pdcolor1,int phase_x,int phase_y)699 clip_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tiles,
700 int x, int y, int w, int h,
701 const gx_drawing_color *pdcolor0,
702 const gx_drawing_color *pdcolor1, int phase_x,
703 int phase_y)
704 {
705 gx_device_clip *rdev = (gx_device_clip *) dev;
706 clip_callback_data_t ccdata;
707
708 ccdata.tiles = tiles;
709 ccdata.pdc[0] = pdcolor0;
710 ccdata.pdc[1] = pdcolor1;
711 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
712 return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rect_devn, &ccdata);
713 }
714
715 /* Strip-tile a rectangle. */
716 int
clip_call_strip_tile_rectangle(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)717 clip_call_strip_tile_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
718 {
719 return (*dev_proc(pccd->tdev, strip_tile_rectangle))
720 (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc,
721 pccd->color[0], pccd->color[1], pccd->phase.x, pccd->phase.y);
722 }
723 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)724 clip_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
725 int x, int y, int w, int h,
726 gx_color_index color0, gx_color_index color1, int phase_x, int phase_y)
727 {
728 gx_device_clip *rdev = (gx_device_clip *) dev;
729 clip_callback_data_t ccdata;
730
731 ccdata.tiles = tiles;
732 ccdata.color[0] = color0, ccdata.color[1] = color1;
733 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y;
734 return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rectangle, &ccdata);
735 }
736
737 /* Copy a rectangle with RasterOp and strip texture. */
738 int
clip_call_strip_copy_rop(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)739 clip_call_strip_copy_rop(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
740 {
741 return (*dev_proc(pccd->tdev, strip_copy_rop))
742 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
743 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
744 pccd->scolors, pccd->textures, pccd->tcolors,
745 xc, yc, xec - xc, yec - yc, pccd->phase.x, pccd->phase.y,
746 pccd->lop);
747 }
748 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)749 clip_strip_copy_rop(gx_device * dev,
750 const byte * sdata, int sourcex, uint raster, gx_bitmap_id id,
751 const gx_color_index * scolors,
752 const gx_strip_bitmap * textures, const gx_color_index * tcolors,
753 int x, int y, int w, int h,
754 int phase_x, int phase_y, gs_logical_operation_t lop)
755 {
756 gx_device_clip *rdev = (gx_device_clip *) dev;
757 clip_callback_data_t ccdata;
758
759 ccdata.data = sdata, ccdata.sourcex = sourcex, ccdata.raster = raster;
760 ccdata.scolors = scolors, ccdata.textures = textures,
761 ccdata.tcolors = tcolors;
762 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
763 return clip_enumerate(rdev, x, y, w, h, clip_call_strip_copy_rop, &ccdata);
764 }
765
766 /* Copy a rectangle with RasterOp and strip texture. */
767 int
clip_call_strip_copy_rop2(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)768 clip_call_strip_copy_rop2(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
769 {
770 return (*dev_proc(pccd->tdev, strip_copy_rop2))
771 (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster,
772 pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id,
773 pccd->scolors, pccd->textures, pccd->tcolors,
774 xc, yc, xec - xc, yec - yc, pccd->phase.x, pccd->phase.y,
775 pccd->lop, pccd->plane_height);
776 }
777 static int
clip_strip_copy_rop2(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,uint planar_height)778 clip_strip_copy_rop2(gx_device * dev,
779 const byte * sdata, int sourcex, uint raster, gx_bitmap_id id,
780 const gx_color_index * scolors,
781 const gx_strip_bitmap * textures, const gx_color_index * tcolors,
782 int x, int y, int w, int h,
783 int phase_x, int phase_y, gs_logical_operation_t lop,
784 uint planar_height)
785 {
786 gx_device_clip *rdev = (gx_device_clip *) dev;
787 clip_callback_data_t ccdata;
788
789 ccdata.data = sdata, ccdata.sourcex = sourcex, ccdata.raster = raster;
790 ccdata.scolors = scolors, ccdata.textures = textures,
791 ccdata.tcolors = tcolors;
792 ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop;
793 ccdata.plane_height = planar_height;
794 return clip_enumerate(rdev, x, y, w, h, clip_call_strip_copy_rop2, &ccdata);
795 }
796
797 /* Get the (outer) clipping box, in client coordinates. */
798 static void
clip_get_clipping_box(gx_device * dev,gs_fixed_rect * pbox)799 clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox)
800 {
801 gx_device_clip *const rdev = (gx_device_clip *) dev;
802
803 if (!rdev->clipping_box_set) {
804 gx_device *tdev = rdev->target;
805 gs_fixed_rect tbox;
806
807 (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox);
808 if (rdev->list.count != 0) {
809 gs_fixed_rect cbox;
810
811 if (rdev->list.count == 1) {
812 cbox.p.x = int2fixed(rdev->list.single.xmin);
813 cbox.p.y = int2fixed(rdev->list.single.ymin);
814 cbox.q.x = int2fixed(rdev->list.single.xmax);
815 cbox.q.y = int2fixed(rdev->list.single.ymax);
816 } else {
817 /* The head and tail elements are dummies.... */
818 cbox.p.x = int2fixed(rdev->list.xmin);
819 cbox.p.y = int2fixed(rdev->list.head->next->ymin);
820 cbox.q.x = int2fixed(rdev->list.xmax);
821 cbox.q.y = int2fixed(rdev->list.tail->prev->ymax);
822 }
823 rect_intersect(tbox, cbox);
824 }
825 if (rdev->translation.x | rdev->translation.y) {
826 fixed tx = int2fixed(rdev->translation.x),
827 ty = int2fixed(rdev->translation.y);
828
829 if (tbox.p.x != min_fixed)
830 tbox.p.x -= tx;
831 if (tbox.p.y != min_fixed)
832 tbox.p.y -= ty;
833 if (tbox.q.x != max_fixed)
834 tbox.q.x -= tx;
835 if (tbox.q.y != max_fixed)
836 tbox.q.y -= ty;
837 }
838 rdev->clipping_box = tbox;
839 rdev->clipping_box_set = true;
840 }
841 *pbox = rdev->clipping_box;
842 }
843
844 /* Get bits back from the device. */
845 static int
clip_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)846 clip_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
847 gs_get_bits_params_t * params, gs_int_rect ** unread)
848 {
849 gx_device_clip *rdev = (gx_device_clip *) dev;
850 gx_device *tdev = rdev->target;
851 int tx = rdev->translation.x, ty = rdev->translation.y;
852 gs_int_rect rect;
853 int code;
854
855 rect.p.x = prect->p.x - tx, rect.p.y = prect->p.y - ty;
856 rect.q.x = prect->q.x - tx, rect.q.y = prect->q.y - ty;
857 code = (*dev_proc(tdev, get_bits_rectangle))
858 (tdev, &rect, params, unread);
859 if (code > 0) {
860 /* Adjust unread rectangle coordinates */
861 gs_int_rect *list = *unread;
862 int i;
863
864 for (i = 0; i < code; ++list, ++i) {
865 list->p.x += tx, list->p.y += ty;
866 list->q.x += tx, list->q.y += ty;
867 }
868 }
869 return code;
870 }
871
872 static int
clip_call_fill_path(clip_callback_data_t * pccd,int xc,int yc,int xec,int yec)873 clip_call_fill_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec)
874 {
875 gx_device *tdev = pccd->tdev;
876 dev_proc_fill_path((*proc));
877 int code;
878 gx_clip_path cpath_intersection;
879 gx_clip_path *pcpath = pccd->pcpath;
880
881 if (pcpath != NULL) {
882 gx_path rect_path;
883 code = gx_cpath_init_local_shared(&cpath_intersection, pcpath, pccd->ppath->memory);
884 if (code < 0)
885 return code;
886 gx_path_init_local(&rect_path, pccd->ppath->memory);
887 gx_path_add_rectangle(&rect_path, int2fixed(xc), int2fixed(yc), int2fixed(xec), int2fixed(yec));
888 code = gx_cpath_intersect(&cpath_intersection, &rect_path,
889 gx_rule_winding_number, pccd->pis);
890 gx_path_free(&rect_path, "clip_call_fill_path");
891 } else {
892 gs_fixed_rect clip_box;
893 clip_box.p.x = int2fixed(xc);
894 clip_box.p.y = int2fixed(yc);
895 clip_box.q.x = int2fixed(xec);
896 clip_box.q.y = int2fixed(yec);
897 gx_cpath_init_local(&cpath_intersection, pccd->ppath->memory);
898 code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box);
899 }
900 if (code < 0)
901 return code;
902 proc = dev_proc(tdev, fill_path);
903 if (proc == NULL)
904 proc = gx_default_fill_path;
905 code = (*proc)(pccd->tdev, pccd->pis, pccd->ppath, pccd->params,
906 pccd->pdcolor, &cpath_intersection);
907 gx_cpath_free(&cpath_intersection, "clip_call_fill_path");
908 return code;
909 }
910 static int
clip_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)911 clip_fill_path(gx_device * dev, const gs_imager_state * pis,
912 gx_path * ppath, const gx_fill_params * params,
913 const gx_drawing_color * pdcolor,
914 const gx_clip_path * pcpath)
915 {
916 gx_device_clip *rdev = (gx_device_clip *) dev;
917 clip_callback_data_t ccdata;
918 gs_fixed_rect box;
919
920 ccdata.pis = pis;
921 ccdata.ppath = ppath;
922 ccdata.params = params;
923 ccdata.pdcolor = pdcolor;
924 ccdata.pcpath = pcpath;
925 clip_get_clipping_box(dev, &box);
926 return clip_enumerate(rdev,
927 fixed2int(box.p.x),
928 fixed2int(box.p.y),
929 fixed2int(box.q.x - box.p.x),
930 fixed2int(box.q.y - box.p.y),
931 clip_call_fill_path, &ccdata);
932 }