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 }