/src/ghostpdl/base/gxclip.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 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., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, 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_rop2(clip_strip_copy_rop2); |
45 | | static dev_proc_get_clipping_box(clip_get_clipping_box); |
46 | | static dev_proc_get_bits_rectangle(clip_get_bits_rectangle); |
47 | | static dev_proc_fill_path(clip_fill_path); |
48 | | static dev_proc_transform_pixel_region(clip_transform_pixel_region); |
49 | | static dev_proc_fill_stroke_path(clip_fill_stroke_path); |
50 | | |
51 | | /* The device descriptor. */ |
52 | | static void |
53 | | clipper_initialize_device_procs(gx_device *dev) |
54 | 3.31M | { |
55 | 3.31M | set_dev_proc(dev, open_device, clip_open); |
56 | 3.31M | set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix); |
57 | 3.31M | set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color); |
58 | 3.31M | set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb); |
59 | 3.31M | set_dev_proc(dev, fill_rectangle, clip_fill_rectangle); |
60 | 3.31M | set_dev_proc(dev, copy_mono, clip_copy_mono); |
61 | 3.31M | set_dev_proc(dev, copy_color, clip_copy_color); |
62 | 3.31M | set_dev_proc(dev, get_params, gx_forward_get_params); |
63 | 3.31M | set_dev_proc(dev, put_params, gx_forward_put_params); |
64 | 3.31M | set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color); |
65 | 3.31M | set_dev_proc(dev, get_page_device, gx_forward_get_page_device); |
66 | 3.31M | set_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits); |
67 | 3.31M | set_dev_proc(dev, copy_alpha, clip_copy_alpha); |
68 | 3.31M | set_dev_proc(dev, fill_path, clip_fill_path); |
69 | 3.31M | set_dev_proc(dev, fill_mask, clip_fill_mask); |
70 | 3.31M | set_dev_proc(dev, strip_tile_rectangle, clip_strip_tile_rectangle); |
71 | 3.31M | set_dev_proc(dev, get_clipping_box, clip_get_clipping_box); |
72 | 3.31M | set_dev_proc(dev, get_bits_rectangle, clip_get_bits_rectangle); |
73 | 3.31M | set_dev_proc(dev, composite, gx_forward_composite); |
74 | 3.31M | set_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params); |
75 | 3.31M | set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs); |
76 | 3.31M | set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index); |
77 | 3.31M | set_dev_proc(dev, encode_color, gx_forward_encode_color); |
78 | 3.31M | set_dev_proc(dev, decode_color, gx_forward_decode_color); |
79 | 3.31M | set_dev_proc(dev, fill_rectangle_hl_color, clip_fill_rectangle_hl_color); |
80 | 3.31M | set_dev_proc(dev, include_color_space, gx_forward_include_color_space); |
81 | 3.31M | set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); |
82 | 3.31M | set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); |
83 | 3.31M | set_dev_proc(dev, fillpage, gx_forward_fillpage); |
84 | 3.31M | set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op); |
85 | 3.31M | set_dev_proc(dev, copy_planes, clip_copy_planes); |
86 | 3.31M | set_dev_proc(dev, get_profile, gx_forward_get_profile); |
87 | 3.31M | set_dev_proc(dev, set_graphics_type_tag, gx_forward_set_graphics_type_tag); |
88 | 3.31M | set_dev_proc(dev, strip_copy_rop2, clip_strip_copy_rop2); |
89 | 3.31M | set_dev_proc(dev, strip_tile_rect_devn, clip_strip_tile_rect_devn); |
90 | 3.31M | set_dev_proc(dev, copy_alpha_hl_color, clip_copy_alpha_hl_color); |
91 | 3.31M | set_dev_proc(dev, transform_pixel_region, clip_transform_pixel_region); |
92 | 3.31M | set_dev_proc(dev, fill_stroke_path, clip_fill_stroke_path); |
93 | | /* Ideally the following defaults would be filled in for us, but that |
94 | | * doesn't work at the moment. */ |
95 | 3.31M | set_dev_proc(dev, sync_output, gx_default_sync_output); |
96 | 3.31M | set_dev_proc(dev, output_page, gx_default_output_page); |
97 | 3.31M | set_dev_proc(dev, close_device, gx_default_close_device); |
98 | 3.31M | set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line); |
99 | 3.31M | set_dev_proc(dev, stroke_path, gx_default_stroke_path); |
100 | 3.31M | set_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid); |
101 | 3.31M | set_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram); |
102 | 3.31M | set_dev_proc(dev, fill_triangle, gx_default_fill_triangle); |
103 | 3.31M | set_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line); |
104 | 3.31M | set_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image); |
105 | 3.31M | set_dev_proc(dev, text_begin, gx_default_text_begin); |
106 | 3.31M | set_dev_proc(dev, fill_linear_color_scanline, gx_default_fill_linear_color_scanline); |
107 | 3.31M | set_dev_proc(dev, fill_linear_color_trapezoid, gx_default_fill_linear_color_trapezoid); |
108 | 3.31M | set_dev_proc(dev, fill_linear_color_triangle, gx_default_fill_linear_color_triangle); |
109 | 3.31M | } |
110 | | static const gx_device_clip gs_clip_device = |
111 | | {std_device_std_body(gx_device_clip, |
112 | | clipper_initialize_device_procs, "clipper", |
113 | | 0, 0, 1, 1) |
114 | | }; |
115 | | |
116 | | /* Make a clipping device. */ |
117 | | void |
118 | | gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target) |
119 | 3.23M | { |
120 | 3.23M | gx_device_init_on_stack((gx_device *)dev, (const gx_device *)&gs_clip_device, target->memory); |
121 | 3.23M | dev->cpath = pcpath; |
122 | 3.23M | dev->list = *gx_cpath_list(pcpath); |
123 | 3.23M | dev->translation.x = 0; |
124 | 3.23M | dev->translation.y = 0; |
125 | 3.23M | dev->HWResolution[0] = target->HWResolution[0]; |
126 | 3.23M | dev->HWResolution[1] = target->HWResolution[1]; |
127 | 3.23M | dev->sgr = target->sgr; |
128 | 3.23M | dev->target = target; |
129 | 3.23M | dev->pad = target->pad; |
130 | 3.23M | dev->log2_align_mod = target->log2_align_mod; |
131 | 3.23M | dev->is_planar = target->is_planar; |
132 | 3.23M | dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */ |
133 | | /* There is no finalization for device on stack so no rc increment */ |
134 | 3.23M | (*dev_proc(dev, open_device)) ((gx_device *)dev); |
135 | 3.23M | } |
136 | | |
137 | | void |
138 | | gx_destroy_clip_device_on_stack(gx_device_clip * dev) |
139 | 0 | { |
140 | 0 | if (dev->cpath) |
141 | 0 | ((gx_clip_path *)dev->cpath)->cached = (dev->current == &dev->list.single ? NULL : dev->current); /* Cast away const */ |
142 | 0 | } |
143 | | |
144 | | gx_device * |
145 | | gx_make_clip_device_on_stack_if_needed(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, gs_fixed_rect *rect) |
146 | 575k | { |
147 | | /* Reduce area if possible */ |
148 | 575k | if (rect->p.x < pcpath->outer_box.p.x) |
149 | 680 | rect->p.x = pcpath->outer_box.p.x; |
150 | 575k | if (rect->q.x > pcpath->outer_box.q.x) |
151 | 706 | rect->q.x = pcpath->outer_box.q.x; |
152 | 575k | if (rect->p.y < pcpath->outer_box.p.y) |
153 | 4.12k | rect->p.y = pcpath->outer_box.p.y; |
154 | 575k | if (rect->q.y > pcpath->outer_box.q.y) |
155 | 3.38k | rect->q.y = pcpath->outer_box.q.y; |
156 | | /* Check for area being trivially clipped away. */ |
157 | 575k | if (rect->p.x >= rect->q.x || rect->p.y >= rect->q.y) |
158 | 746 | return NULL; |
159 | 574k | if (pcpath->inner_box.p.x <= rect->p.x && pcpath->inner_box.p.y <= rect->p.y && |
160 | 574k | pcpath->inner_box.q.x >= rect->q.x && pcpath->inner_box.q.y >= rect->q.y) |
161 | 573k | { |
162 | | /* Area is trivially included. No need for clip. */ |
163 | 573k | return target; |
164 | 573k | } |
165 | 1.77k | gx_device_init_on_stack((gx_device *)dev, (const gx_device *)&gs_clip_device, target->memory); |
166 | 1.77k | dev->list = *gx_cpath_list(pcpath); |
167 | 1.77k | dev->translation.x = 0; |
168 | 1.77k | dev->translation.y = 0; |
169 | 1.77k | dev->HWResolution[0] = target->HWResolution[0]; |
170 | 1.77k | dev->HWResolution[1] = target->HWResolution[1]; |
171 | 1.77k | dev->sgr = target->sgr; |
172 | 1.77k | dev->target = target; |
173 | 1.77k | dev->pad = target->pad; |
174 | 1.77k | dev->log2_align_mod = target->log2_align_mod; |
175 | 1.77k | dev->is_planar = target->is_planar; |
176 | 1.77k | dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */ |
177 | | /* There is no finalization for device on stack so no rc increment */ |
178 | 1.77k | (*dev_proc(dev, open_device)) ((gx_device *)dev); |
179 | 1.77k | return (gx_device *)dev; |
180 | 574k | } |
181 | | void |
182 | | gx_make_clip_device_in_heap(gx_device_clip *dev, |
183 | | const gx_clip_path *pcpath, |
184 | | gx_device *target, |
185 | | gs_memory_t *mem) |
186 | 72.2k | { |
187 | | /* Can never fail */ |
188 | 72.2k | (void)gx_device_init((gx_device *)dev, |
189 | 72.2k | (const gx_device *)&gs_clip_device, mem, true); |
190 | 72.2k | dev->list = *gx_cpath_list(pcpath); |
191 | 72.2k | dev->translation.x = 0; |
192 | 72.2k | dev->translation.y = 0; |
193 | 72.2k | dev->HWResolution[0] = target->HWResolution[0]; |
194 | 72.2k | dev->HWResolution[1] = target->HWResolution[1]; |
195 | 72.2k | dev->sgr = target->sgr; |
196 | 72.2k | dev->pad = target->pad; |
197 | 72.2k | dev->log2_align_mod = target->log2_align_mod; |
198 | 72.2k | dev->is_planar = target->is_planar; |
199 | 72.2k | gx_device_set_target((gx_device_forward *)dev, target); |
200 | 72.2k | gx_device_retain((gx_device *)dev, true); /* will free explicitly */ |
201 | | /* Can never fail */ |
202 | 72.2k | (void)(*dev_proc(dev, open_device)) ((gx_device *)dev); |
203 | 72.2k | } |
204 | | /* Define debugging statistics for the clipping loops. */ |
205 | | /* #define COLLECT_STATS_CLIP */ |
206 | | |
207 | | #ifdef COLLECT_STATS_CLIP |
208 | | struct stats_clip_s { |
209 | | long |
210 | | loops, out, in_y, in, in1, down, up, x, no_x; |
211 | | } stats_clip; |
212 | | |
213 | | static const uint clip_interval = 10000; |
214 | | |
215 | | # define INCR(v) (++(stats_clip.v)) |
216 | | # define INCR_THEN(v, e) (INCR(v), (e)) |
217 | | #else |
218 | 76.5M | # define INCR(v) DO_NOTHING |
219 | 261M | # define INCR_THEN(v, e) (e) |
220 | | #endif |
221 | | |
222 | | /* |
223 | | * Enumerate the rectangles of the x,w,y,h argument that fall within |
224 | | * the clipping region. |
225 | | * NB: if the clip list is transposed, then x, y, xe, and ye are already |
226 | | * transposed and will need to be switched for the call to "process" |
227 | | */ |
228 | | static int |
229 | | clip_enumerate_rest(gx_device_clip * rdev, |
230 | | int x, int y, int xe, int ye, |
231 | | int (*process)(clip_callback_data_t * pccd, |
232 | | int xc, int yc, int xec, int yec), |
233 | | clip_callback_data_t * pccd) |
234 | 40.8M | { |
235 | 40.8M | gx_clip_rect *rptr = rdev->current; /* const within algorithm */ |
236 | 40.8M | int yc; |
237 | 40.8M | int code; |
238 | | |
239 | | #ifdef COLLECT_STATS_CLIP |
240 | | if (INCR(loops) % clip_interval == 0 && gs_debug_c('q')) { |
241 | | dmprintf5(rdev->memory, |
242 | | "[q]loops=%ld out=%ld in_y=%ld in=%ld in1=%ld\n", |
243 | | stats_clip.loops, stats_clip.out, stats_clip.in, |
244 | | stats_clip.in_y, stats_clip.in1); |
245 | | dmprintf4(rdev->memory, |
246 | | "[q] down=%ld up=%ld x=%ld no_x=%ld\n", |
247 | | stats_clip.down, stats_clip.up, stats_clip.x, |
248 | | stats_clip.no_x); |
249 | | } |
250 | | #endif |
251 | | /* |
252 | | * Warp the cursor forward or backward to the first rectangle row |
253 | | * that could include a given y value. Assumes rptr is set, and |
254 | | * updates it. Specifically, after this loop, either rptr == 0 (if |
255 | | * the y value is greater than all y values in the list), or y < |
256 | | * rptr->ymax and either rptr->prev == 0 or y >= rptr->prev->ymax. |
257 | | * Note that y <= rptr->ymin is possible. |
258 | | * |
259 | | * In the first case below, the while loop is safe because if there |
260 | | * is more than one rectangle, there is a 'stopper' at the end of |
261 | | * the list. |
262 | | */ |
263 | 40.8M | if (y >= rptr->ymax) { |
264 | 15.3M | if ((rptr = rptr->next) != 0) |
265 | 77.6M | while (INCR_THEN(up, y >= rptr->ymax)) |
266 | 62.6M | rptr = rptr->next; |
267 | 15.3M | } else |
268 | 95.8M | while (rptr->prev != 0 && y < rptr->prev->ymax) |
269 | 70.4M | INCR_THEN(down, rptr = rptr->prev); |
270 | 40.8M | if (rptr == 0 || (yc = rptr->ymin) >= ye) { |
271 | 16.5M | INCR(out); |
272 | 16.5M | if (rdev->list.count > 1) |
273 | 8.53M | rdev->current = |
274 | 8.53M | (rptr != 0 ? rptr : |
275 | 8.53M | y >= rdev->current->ymax ? rdev->list.tail : |
276 | 0 | rdev->list.head); |
277 | 16.5M | return 0; |
278 | 16.5M | } |
279 | 24.2M | rdev->current = rptr; |
280 | 24.2M | if (yc < y) |
281 | 5.53M | yc = y; |
282 | | |
283 | 26.8M | do { |
284 | 26.8M | const int ymax = rptr->ymax; |
285 | 26.8M | int yec = min(ymax, ye); |
286 | | |
287 | 26.8M | if_debug2m('Q', rdev->memory, "[Q]yc=%d yec=%d\n", yc, yec); |
288 | 111M | do { |
289 | 111M | int xc = rptr->xmin; |
290 | 111M | int xec = rptr->xmax; |
291 | | |
292 | 111M | if (xc < x) |
293 | 54.3M | xc = x; |
294 | 111M | if (xec > xe) |
295 | 63.4M | xec = xe; |
296 | 111M | if (xec > xc) { |
297 | 20.3M | clip_rect_print('Q', "match", rptr); |
298 | 20.3M | if_debug2m('Q', rdev->memory, "[Q]xc=%d xec=%d\n", xc, xec); |
299 | 20.3M | INCR(x); |
300 | | /* |
301 | | * Conditionally look ahead to detect unclipped vertical strips. This is |
302 | | * really only valuable for 90 degree rotated images or (nearly-)vertical |
303 | | * lines with convex clipping regions; if we ever change images to use |
304 | | * source buffering and destination-oriented enumeration, we could probably |
305 | | * take out the code here with no adverse effects. |
306 | | */ |
307 | 20.3M | #ifdef CHECK_VERTICAL_CLIPPING |
308 | 20.3M | if (xec - xc == pccd->w) { /* full width */ |
309 | | /* Look ahead for a vertical swath. */ |
310 | 14.8M | while ((rptr = rptr->next) != 0 && |
311 | 14.8M | rptr->ymin == yec && |
312 | 14.8M | rptr->ymax <= ye && |
313 | 14.8M | rptr->xmin <= x && |
314 | 14.8M | rptr->xmax >= xe |
315 | 12.3M | ) |
316 | 2.52M | yec = rptr->ymax; |
317 | 12.3M | } else |
318 | 8.02M | rptr = rptr->next; |
319 | | #else |
320 | | rptr = rptr->next; |
321 | | #endif |
322 | 20.3M | if (rdev->list.transpose) |
323 | 0 | code = process(pccd, yc, xc, yec, xec); |
324 | 20.3M | else |
325 | 20.3M | code = process(pccd, xc, yc, xec, yec); |
326 | 20.3M | if (code < 0) |
327 | 0 | return code; |
328 | 91.1M | } else { |
329 | 91.1M | INCR_THEN(no_x, rptr = rptr->next); |
330 | 91.1M | } |
331 | 111M | if (rptr == 0) |
332 | 178k | return 0; |
333 | 111M | } |
334 | 111M | while (rptr->ymax == ymax); |
335 | 26.8M | } while ((yc = rptr->ymin) < ye); |
336 | 24.0M | return 0; |
337 | 24.2M | } |
338 | | |
339 | | static int |
340 | | clip_enumerate(gx_device_clip * rdev, int x, int y, int w, int h, |
341 | | int (*process)(clip_callback_data_t * pccd, |
342 | | int xc, int yc, int xec, int yec), |
343 | | clip_callback_data_t * pccd) |
344 | 56.4M | { |
345 | 56.4M | int xe, ye; |
346 | 56.4M | const gx_clip_rect *rptr = rdev->current; |
347 | | |
348 | 56.4M | if (w <= 0 || h <= 0) |
349 | 0 | return 0; |
350 | 56.4M | pccd->tdev = rdev->target; |
351 | 56.4M | x += rdev->translation.x; |
352 | 56.4M | xe = x + w; |
353 | 56.4M | y += rdev->translation.y; |
354 | 56.4M | ye = y + h; |
355 | | /* pccd is non-transposed */ |
356 | 56.4M | pccd->x = x, pccd->y = y; |
357 | 56.4M | pccd->w = w, pccd->h = h; |
358 | | /* transpose x, y, xe, ye for clip checking */ |
359 | 56.4M | if (rdev->list.transpose) { |
360 | 0 | x = pccd->y; |
361 | 0 | y = pccd->x; |
362 | 0 | xe = x + h; |
363 | 0 | ye = y + w; |
364 | 0 | } |
365 | | /* Check for the region being entirely within the current rectangle. */ |
366 | 56.4M | if (y >= rptr->ymin && ye <= rptr->ymax && |
367 | 56.4M | x >= rptr->xmin && xe <= rptr->xmax |
368 | 56.4M | ) { |
369 | 21.8M | if (rdev->list.transpose) { |
370 | 0 | return INCR_THEN(in, process(pccd, y, x, ye, xe)); |
371 | 21.8M | } else { |
372 | 21.8M | return INCR_THEN(in, process(pccd, x, y, xe, ye)); |
373 | 21.8M | } |
374 | 21.8M | } |
375 | 34.5M | return clip_enumerate_rest(rdev, x, y, xe, ye, process, pccd); |
376 | 56.4M | } |
377 | | |
378 | | /* Open a clipping device */ |
379 | | static int |
380 | | clip_open(gx_device * dev) |
381 | 3.31M | { |
382 | 3.31M | gx_device_clip *const rdev = (gx_device_clip *) dev; |
383 | 3.31M | gx_device *tdev = rdev->target; |
384 | | |
385 | | /* Initialize the cursor. */ |
386 | 3.31M | rdev->current = |
387 | 3.31M | (rdev->list.head == 0 ? &rdev->list.single : (rdev->cpath && rdev->cpath->cached ? rdev->cpath->cached : rdev->list.head)); |
388 | 3.31M | rdev->color_info = tdev->color_info; |
389 | 3.31M | rdev->cached_colors = tdev->cached_colors; |
390 | 3.31M | rdev->width = tdev->width; |
391 | 3.31M | rdev->height = tdev->height; |
392 | 3.31M | gx_device_copy_color_procs(dev, tdev); |
393 | 3.31M | rdev->clipping_box_set = false; |
394 | 3.31M | rdev->memory = tdev->memory; |
395 | 3.31M | return 0; |
396 | 3.31M | } |
397 | | |
398 | | /* Fill a rectangle */ |
399 | | int |
400 | | clip_call_fill_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
401 | 3.05M | { |
402 | 3.05M | return (*dev_proc(pccd->tdev, fill_rectangle)) |
403 | 3.05M | (pccd->tdev, xc, yc, xec - xc, yec - yc, pccd->color[0]); |
404 | 3.05M | } |
405 | | static int |
406 | | clip_fill_rectangle_t0(gx_device * dev, int x, int y, int w, int h, |
407 | | gx_color_index color) |
408 | 32.5M | { |
409 | 32.5M | gx_device_clip *rdev = (gx_device_clip *) dev; |
410 | 32.5M | clip_callback_data_t ccdata; |
411 | | /* We handle the fastest cases in-line here. */ |
412 | 32.5M | gx_device *tdev = rdev->target; |
413 | 32.5M | /*const*/ gx_clip_rect *rptr = rdev->current; |
414 | 32.5M | int xe, ye; |
415 | | |
416 | 32.5M | if (w <= 0 || h <= 0) |
417 | 13.3M | return 0; |
418 | 19.1M | x += rdev->translation.x; |
419 | 19.1M | xe = x + w; |
420 | 19.1M | y += rdev->translation.y; |
421 | 19.1M | ye = y + h; |
422 | | /* ccdata is non-transposed */ |
423 | 19.1M | ccdata.x = x, ccdata.y = y; |
424 | 19.1M | ccdata.w = w, ccdata.h = h; |
425 | | /* We open-code the most common cases here. */ |
426 | 19.1M | if ((y >= rptr->ymin && ye <= rptr->ymax) || |
427 | 19.1M | ((rptr = rptr->next) != 0 && |
428 | 8.17M | y >= rptr->ymin && ye <= rptr->ymax) |
429 | 19.1M | ) { |
430 | 14.8M | rdev->current = rptr; /* may be redundant, but awkward to avoid */ |
431 | 14.8M | INCR(in_y); |
432 | 14.8M | if (x >= rptr->xmin && xe <= rptr->xmax) { |
433 | 12.1M | INCR(in); |
434 | 12.1M | return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color); |
435 | 12.1M | } |
436 | 2.79M | else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) && |
437 | 2.79M | (rptr->next == 0 || rptr->next->ymax != rptr->ymax) |
438 | 2.79M | ) { |
439 | 1.81M | INCR(in1); |
440 | 1.81M | if (x < rptr->xmin) |
441 | 721k | x = rptr->xmin; |
442 | 1.81M | if (xe > rptr->xmax) |
443 | 1.11M | xe = rptr->xmax; |
444 | 1.81M | if (x >= xe) |
445 | 1.52M | return 0; |
446 | 286k | return dev_proc(tdev, fill_rectangle)(tdev, x, y, xe - x, h, color); |
447 | 1.81M | } |
448 | 14.8M | } |
449 | 5.21M | ccdata.tdev = tdev; |
450 | 5.21M | ccdata.color[0] = color; |
451 | 5.21M | return clip_enumerate_rest(rdev, x, y, xe, ye, clip_call_fill_rectangle, &ccdata); |
452 | 19.1M | } |
453 | | |
454 | | static int |
455 | | clip_fill_rectangle_t1(gx_device * dev, int x, int y, int w, int h, |
456 | | gx_color_index color) |
457 | 0 | { |
458 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
459 | 0 | clip_callback_data_t ccdata; |
460 | | /* We handle the fastest cases in-line here. */ |
461 | 0 | gx_device *tdev = rdev->target; |
462 | 0 | /*const*/ gx_clip_rect *rptr = rdev->current; |
463 | 0 | int xe, ye; |
464 | |
|
465 | 0 | if (w <= 0 || h <= 0) |
466 | 0 | return 0; |
467 | 0 | x += rdev->translation.x; |
468 | 0 | y += rdev->translation.y; |
469 | | /* ccdata is non-transposed */ |
470 | 0 | ccdata.x = x, ccdata.y = y; |
471 | 0 | ccdata.w = w, ccdata.h = h; |
472 | 0 | x = ccdata.y; |
473 | 0 | y = ccdata.x; |
474 | 0 | xe = x + h; |
475 | 0 | ye = y + w; |
476 | | /* We open-code the most common cases here. */ |
477 | 0 | if ((y >= rptr->ymin && ye <= rptr->ymax) || |
478 | 0 | ((rptr = rptr->next) != 0 && |
479 | 0 | y >= rptr->ymin && ye <= rptr->ymax) |
480 | 0 | ) { |
481 | 0 | rdev->current = rptr; /* may be redundant, but awkward to avoid */ |
482 | 0 | INCR(in_y); |
483 | 0 | if (x >= rptr->xmin && xe <= rptr->xmax) { |
484 | 0 | INCR(in); |
485 | 0 | return dev_proc(tdev, fill_rectangle)(tdev, y, x, w, h, color); |
486 | 0 | } |
487 | 0 | else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) && |
488 | 0 | (rptr->next == 0 || rptr->next->ymax != rptr->ymax) |
489 | 0 | ) { |
490 | 0 | INCR(in1); |
491 | 0 | if (x < rptr->xmin) |
492 | 0 | x = rptr->xmin; |
493 | 0 | if (xe > rptr->xmax) |
494 | 0 | xe = rptr->xmax; |
495 | 0 | if (x >= xe) |
496 | 0 | return 0; |
497 | 0 | return dev_proc(tdev, fill_rectangle)(tdev, y, x, w, xe - x, color); |
498 | 0 | } |
499 | 0 | } |
500 | 0 | ccdata.tdev = tdev; |
501 | 0 | ccdata.color[0] = color; |
502 | 0 | return clip_enumerate_rest(rdev, x, y, xe, ye, clip_call_fill_rectangle, &ccdata); |
503 | 0 | } |
504 | | |
505 | | static int |
506 | | clip_fill_rectangle_s0(gx_device * dev, int x, int y, int w, int h, |
507 | | gx_color_index color) |
508 | 136M | { |
509 | 136M | gx_device_clip *rdev = (gx_device_clip *) dev; |
510 | 136M | gx_device *tdev = rdev->target; |
511 | | |
512 | 136M | if (w <= 0 || h <= 0) |
513 | 3.20M | return 0; |
514 | 133M | x += rdev->translation.x; |
515 | 133M | w += x; |
516 | 133M | y += rdev->translation.y; |
517 | 133M | h += y; |
518 | 133M | if (x < rdev->list.single.xmin) |
519 | 31.7M | x = rdev->list.single.xmin; |
520 | 133M | if (w > rdev->list.single.xmax) |
521 | 38.0M | w = rdev->list.single.xmax; |
522 | 133M | if (y < rdev->list.single.ymin) |
523 | 5.77M | y = rdev->list.single.ymin; |
524 | 133M | if (h > rdev->list.single.ymax) |
525 | 3.44M | h = rdev->list.single.ymax; |
526 | 133M | w -= x; |
527 | 133M | h -= y; |
528 | 133M | if (w <= 0 || h <= 0) |
529 | 71.6M | return 0; |
530 | 61.5M | return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color); |
531 | 133M | } |
532 | | |
533 | | static int |
534 | | clip_fill_rectangle_s1(gx_device * dev, int x, int y, int w, int h, |
535 | | gx_color_index color) |
536 | 0 | { |
537 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
538 | 0 | gx_device *tdev = rdev->target; |
539 | |
|
540 | 0 | if (w <= 0 || h <= 0) |
541 | 0 | return 0; |
542 | 0 | x += rdev->translation.x; |
543 | 0 | w += x; |
544 | 0 | y += rdev->translation.y; |
545 | 0 | h += y; |
546 | | /* Now, treat x/w as y/h and vice versa as transposed. */ |
547 | 0 | if (x < rdev->list.single.ymin) |
548 | 0 | x = rdev->list.single.ymin; |
549 | 0 | if (w > rdev->list.single.ymax) |
550 | 0 | w = rdev->list.single.ymax; |
551 | 0 | if (y < rdev->list.single.xmin) |
552 | 0 | y = rdev->list.single.xmin; |
553 | 0 | if (h > rdev->list.single.xmax) |
554 | 0 | h = rdev->list.single.xmax; |
555 | 0 | w -= x; |
556 | 0 | h -= y; |
557 | 0 | if (w <= 0 || h <= 0) |
558 | 0 | return 0; |
559 | 0 | return dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color); |
560 | 0 | } |
561 | | static int |
562 | | clip_fill_rectangle(gx_device * dev, int x, int y, int w, int h, |
563 | | gx_color_index color) |
564 | 26.5M | { |
565 | 26.5M | gx_device_clip *rdev = (gx_device_clip *) dev; |
566 | | |
567 | 26.5M | if (rdev->list.transpose) { |
568 | 0 | if (rdev->list.count == 1) |
569 | 0 | dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_s1; |
570 | 0 | else |
571 | 0 | dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_t1; |
572 | 26.5M | } else { |
573 | 26.5M | if (rdev->list.count == 1) |
574 | 26.4M | dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_s0; |
575 | 110k | else |
576 | 110k | dev_proc(rdev, fill_rectangle) = clip_fill_rectangle_t0; |
577 | 26.5M | } |
578 | 26.5M | return dev_proc(rdev, fill_rectangle)(dev, x, y, w, h, color); |
579 | 26.5M | } |
580 | | |
581 | | int |
582 | | clip_call_fill_rectangle_hl_color(clip_callback_data_t * pccd, int xc, int yc, |
583 | | int xec, int yec) |
584 | 485k | { |
585 | 485k | gs_fixed_rect rect; |
586 | | |
587 | 485k | rect.p.x = int2fixed(xc); |
588 | 485k | rect.p.y = int2fixed(yc); |
589 | 485k | rect.q.x = int2fixed(xec); |
590 | 485k | rect.q.y = int2fixed(yec); |
591 | 485k | return (*dev_proc(pccd->tdev, fill_rectangle_hl_color)) |
592 | 485k | (pccd->tdev, &rect, pccd->pgs, pccd->pdcolor, pccd->pcpath); |
593 | 485k | } |
594 | | |
595 | | static int |
596 | | clip_fill_rectangle_hl_color_t0(gx_device *dev, const gs_fixed_rect *rect, |
597 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, |
598 | | const gx_clip_path *pcpath) |
599 | 6.20M | { |
600 | 6.20M | gx_device_clip *rdev = (gx_device_clip *) dev; |
601 | 6.20M | clip_callback_data_t ccdata; |
602 | 6.20M | gx_device *tdev = rdev->target; |
603 | 6.20M | gx_clip_rect *rptr = rdev->current; |
604 | 6.20M | int xe, ye; |
605 | 6.20M | int w, h, x, y; |
606 | 6.20M | gs_fixed_rect newrect; |
607 | | |
608 | 6.20M | x = fixed2int(rect->p.x); |
609 | 6.20M | y = fixed2int(rect->p.y); |
610 | 6.20M | w = fixed2int(rect->q.x) - x; |
611 | 6.20M | h = fixed2int(rect->q.y) - y; |
612 | | |
613 | 6.20M | if (w <= 0 || h <= 0) |
614 | 47.5k | return 0; |
615 | 6.15M | x += rdev->translation.x; |
616 | 6.15M | xe = x + w; |
617 | 6.15M | y += rdev->translation.y; |
618 | 6.15M | ye = y + h; |
619 | | /* ccdata is non-transposed */ |
620 | 6.15M | ccdata.x = x, ccdata.y = y; |
621 | 6.15M | ccdata.w = w, ccdata.h = h; |
622 | | /* We open-code the most common cases here. */ |
623 | 6.15M | if ((y >= rptr->ymin && ye <= rptr->ymax) || |
624 | 6.15M | ((rptr = rptr->next) != 0 && |
625 | 966k | y >= rptr->ymin && ye <= rptr->ymax) |
626 | 6.15M | ) { |
627 | 5.75M | rdev->current = rptr; /* may be redundant, but awkward to avoid */ |
628 | 5.75M | INCR(in_y); |
629 | 5.75M | if (x >= rptr->xmin && xe <= rptr->xmax) { |
630 | 4.17M | INCR(in); |
631 | 4.17M | newrect.p.x = int2fixed(x); |
632 | 4.17M | newrect.p.y = int2fixed(y); |
633 | 4.17M | newrect.q.x = int2fixed(x + w); |
634 | 4.17M | newrect.q.y = int2fixed(y + h); |
635 | 4.17M | return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs, |
636 | 4.17M | pdcolor, pcpath); |
637 | 4.17M | } |
638 | 1.58M | else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) && |
639 | 1.58M | (rptr->next == 0 || rptr->next->ymax != rptr->ymax) |
640 | 1.58M | ) { |
641 | 911k | INCR(in1); |
642 | 911k | if (x < rptr->xmin) |
643 | 367k | x = rptr->xmin; |
644 | 911k | if (xe > rptr->xmax) |
645 | 544k | xe = rptr->xmax; |
646 | 911k | if (x >= xe) |
647 | 902k | return 0; |
648 | 8.50k | else { |
649 | 8.50k | newrect.p.x = int2fixed(x); |
650 | 8.50k | newrect.p.y = int2fixed(y); |
651 | 8.50k | newrect.q.x = int2fixed(xe); |
652 | 8.50k | newrect.q.y = int2fixed(y + h); |
653 | 8.50k | return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs, |
654 | 8.50k | pdcolor, pcpath); |
655 | 8.50k | } |
656 | 911k | } |
657 | 5.75M | } |
658 | 1.06M | ccdata.tdev = tdev; |
659 | 1.06M | ccdata.pdcolor = pdcolor; |
660 | 1.06M | ccdata.pgs = pgs; |
661 | 1.06M | ccdata.pcpath = pcpath; |
662 | 1.06M | return clip_enumerate_rest(rdev, x, y, xe, ye, |
663 | 1.06M | clip_call_fill_rectangle_hl_color, &ccdata); |
664 | 6.15M | } |
665 | | |
666 | | static int |
667 | | clip_fill_rectangle_hl_color_t1(gx_device *dev, const gs_fixed_rect *rect, |
668 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, |
669 | | const gx_clip_path *pcpath) |
670 | 0 | { |
671 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
672 | 0 | clip_callback_data_t ccdata; |
673 | 0 | gx_device *tdev = rdev->target; |
674 | 0 | gx_clip_rect *rptr = rdev->current; |
675 | 0 | int xe, ye; |
676 | 0 | int w, h, x, y; |
677 | 0 | gs_fixed_rect newrect; |
678 | |
|
679 | 0 | x = fixed2int(rect->p.x); |
680 | 0 | y = fixed2int(rect->p.y); |
681 | 0 | w = fixed2int(rect->q.x) - x; |
682 | 0 | h = fixed2int(rect->q.y) - y; |
683 | |
|
684 | 0 | if (w <= 0 || h <= 0) |
685 | 0 | return 0; |
686 | 0 | x += rdev->translation.x; |
687 | 0 | y += rdev->translation.y; |
688 | | /* ccdata is non-transposed */ |
689 | 0 | ccdata.x = x, ccdata.y = y; |
690 | 0 | ccdata.w = w, ccdata.h = h; |
691 | | /* transpose x, y, xe, ye for clip checking */ |
692 | 0 | x = ccdata.y; |
693 | 0 | y = ccdata.x; |
694 | 0 | xe = x + h; |
695 | 0 | ye = y + w; |
696 | | /* We open-code the most common cases here. */ |
697 | 0 | if ((y >= rptr->ymin && ye <= rptr->ymax) || |
698 | 0 | ((rptr = rptr->next) != 0 && |
699 | 0 | y >= rptr->ymin && ye <= rptr->ymax) |
700 | 0 | ) { |
701 | 0 | rdev->current = rptr; /* may be redundant, but awkward to avoid */ |
702 | 0 | INCR(in_y); |
703 | 0 | if (x >= rptr->xmin && xe <= rptr->xmax) { |
704 | 0 | INCR(in); |
705 | 0 | newrect.p.x = int2fixed(y); |
706 | 0 | newrect.p.y = int2fixed(x); |
707 | 0 | newrect.q.x = int2fixed(y + h); |
708 | 0 | newrect.q.y = int2fixed(x + w); |
709 | 0 | return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs, |
710 | 0 | pdcolor, pcpath); |
711 | 0 | } |
712 | 0 | else if ((rptr->prev == 0 || rptr->prev->ymax != rptr->ymax) && |
713 | 0 | (rptr->next == 0 || rptr->next->ymax != rptr->ymax) |
714 | 0 | ) { |
715 | 0 | INCR(in1); |
716 | 0 | if (x < rptr->xmin) |
717 | 0 | x = rptr->xmin; |
718 | 0 | if (xe > rptr->xmax) |
719 | 0 | xe = rptr->xmax; |
720 | 0 | if (x >= xe) |
721 | 0 | return 0; |
722 | 0 | else { |
723 | 0 | newrect.p.x = int2fixed(y); |
724 | 0 | newrect.p.y = int2fixed(x); |
725 | 0 | newrect.q.x = int2fixed(y+h); |
726 | 0 | newrect.q.y = int2fixed(xe); |
727 | 0 | return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs, |
728 | 0 | pdcolor, pcpath); |
729 | 0 | } |
730 | 0 | } |
731 | 0 | } |
732 | 0 | ccdata.tdev = tdev; |
733 | 0 | ccdata.pdcolor = pdcolor; |
734 | 0 | ccdata.pgs = pgs; |
735 | 0 | ccdata.pcpath = pcpath; |
736 | 0 | return clip_enumerate_rest(rdev, x, y, xe, ye, |
737 | 0 | clip_call_fill_rectangle_hl_color, &ccdata); |
738 | 0 | } |
739 | | |
740 | | static int |
741 | | clip_fill_rectangle_hl_color_s0(gx_device *dev, const gs_fixed_rect *rect, |
742 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, |
743 | | const gx_clip_path *pcpath) |
744 | 10.0M | { |
745 | 10.0M | gx_device_clip *rdev = (gx_device_clip *) dev; |
746 | 10.0M | gx_device *tdev = rdev->target; |
747 | 10.0M | int w, h, x, y; |
748 | 10.0M | gs_fixed_rect newrect; |
749 | | |
750 | 10.0M | x = fixed2int(rect->p.x); |
751 | 10.0M | y = fixed2int(rect->p.y); |
752 | 10.0M | w = fixed2int(rect->q.x) - x; |
753 | 10.0M | h = fixed2int(rect->q.y) - y; |
754 | | |
755 | 10.0M | if (w <= 0 || h <= 0) |
756 | 7.05k | return 0; |
757 | 10.0M | x += rdev->translation.x; |
758 | 10.0M | w += x; |
759 | 10.0M | y += rdev->translation.y; |
760 | 10.0M | h += y; |
761 | 10.0M | if (x < rdev->list.single.xmin) |
762 | 4.61k | x = rdev->list.single.xmin; |
763 | 10.0M | if (w > rdev->list.single.xmax) |
764 | 11.0k | w = rdev->list.single.xmax; |
765 | 10.0M | if (y < rdev->list.single.ymin) |
766 | 176k | y = rdev->list.single.ymin; |
767 | 10.0M | if (h > rdev->list.single.ymax) |
768 | 208k | h = rdev->list.single.ymax; |
769 | 10.0M | w -= x; |
770 | 10.0M | h -= y; |
771 | 10.0M | if (w <= 0 || h <= 0) |
772 | 180k | return 0; |
773 | 9.85M | newrect.p.x = int2fixed(x); |
774 | 9.85M | newrect.p.y = int2fixed(y); |
775 | 9.85M | newrect.q.x = int2fixed(x + w); |
776 | 9.85M | newrect.q.y = int2fixed(y + h); |
777 | 9.85M | return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs, |
778 | 9.85M | pdcolor, pcpath); |
779 | 10.0M | } |
780 | | |
781 | | static int |
782 | | clip_fill_rectangle_hl_color_s1(gx_device *dev, const gs_fixed_rect *rect, |
783 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, |
784 | | const gx_clip_path *pcpath) |
785 | 0 | { |
786 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
787 | 0 | gx_device *tdev = rdev->target; |
788 | 0 | int w, h, x, y; |
789 | 0 | gs_fixed_rect newrect; |
790 | |
|
791 | 0 | x = fixed2int(rect->p.x); |
792 | 0 | y = fixed2int(rect->p.y); |
793 | 0 | w = fixed2int(rect->q.x) - x; |
794 | 0 | h = fixed2int(rect->q.y) - y; |
795 | |
|
796 | 0 | if (w <= 0 || h <= 0) |
797 | 0 | return 0; |
798 | 0 | x += rdev->translation.x; |
799 | 0 | w += x; |
800 | 0 | y += rdev->translation.y; |
801 | 0 | h += y; |
802 | | /* Now, treat x/w as y/h and vice versa as transposed. */ |
803 | 0 | if (x < rdev->list.single.ymin) |
804 | 0 | x = rdev->list.single.ymin; |
805 | 0 | if (w > rdev->list.single.ymax) |
806 | 0 | w = rdev->list.single.ymax; |
807 | 0 | if (y < rdev->list.single.xmin) |
808 | 0 | y = rdev->list.single.xmin; |
809 | 0 | if (h > rdev->list.single.xmax) |
810 | 0 | h = rdev->list.single.xmax; |
811 | 0 | w -= x; |
812 | 0 | h -= y; |
813 | 0 | if (w <= 0 || h <= 0) |
814 | 0 | return 0; |
815 | 0 | newrect.p.x = int2fixed(y); |
816 | 0 | newrect.p.y = int2fixed(x); |
817 | 0 | newrect.q.x = int2fixed(y + h); |
818 | 0 | newrect.q.y = int2fixed(x + w); |
819 | 0 | return dev_proc(tdev, fill_rectangle_hl_color)(tdev, &newrect, pgs, |
820 | 0 | pdcolor, pcpath); |
821 | 0 | } |
822 | | |
823 | | static int |
824 | | clip_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect, |
825 | | const gs_gstate *pgs, const gx_drawing_color *pdcolor, |
826 | | const gx_clip_path *pcpath) |
827 | 69.6k | { |
828 | 69.6k | gx_device_clip *rdev = (gx_device_clip *) dev; |
829 | | |
830 | 69.6k | if (rdev->list.transpose) { |
831 | 0 | if (rdev->list.count == 1) |
832 | 0 | dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_s1; |
833 | 0 | else |
834 | 0 | dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_t1; |
835 | 69.6k | } else { |
836 | 69.6k | if (rdev->list.count == 1) |
837 | 68.8k | dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_s0; |
838 | 821 | else |
839 | 821 | dev_proc(rdev, fill_rectangle_hl_color) = clip_fill_rectangle_hl_color_t0; |
840 | 69.6k | } |
841 | 69.6k | return dev_proc(rdev, fill_rectangle_hl_color)(dev, rect, pgs, pdcolor, pcpath); |
842 | 69.6k | } |
843 | | |
844 | | /* Copy a monochrome rectangle */ |
845 | | int |
846 | | clip_call_copy_mono(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
847 | 30.2k | { |
848 | 30.2k | return (*dev_proc(pccd->tdev, copy_mono)) |
849 | 30.2k | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
850 | 30.2k | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
851 | 30.2k | xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->color[1]); |
852 | 30.2k | } |
853 | | static int |
854 | | clip_copy_mono_t0(gx_device * dev, |
855 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
856 | | int x, int y, int w, int h, |
857 | | gx_color_index color0, gx_color_index color1) |
858 | 19.5k | { |
859 | 19.5k | gx_device_clip *rdev = (gx_device_clip *) dev; |
860 | 19.5k | clip_callback_data_t ccdata; |
861 | | /* We handle the fastest case in-line here. */ |
862 | 19.5k | gx_device *tdev = rdev->target; |
863 | 19.5k | const gx_clip_rect *rptr = rdev->current; |
864 | 19.5k | int xe, ye; |
865 | | |
866 | 19.5k | if (w <= 0 || h <= 0) |
867 | 83 | return 0; |
868 | 19.4k | x += rdev->translation.x; |
869 | 19.4k | xe = x + w; |
870 | 19.4k | y += rdev->translation.y; |
871 | 19.4k | ye = y + h; |
872 | | /* ccdata is non-transposed */ |
873 | 19.4k | ccdata.x = x, ccdata.y = y; |
874 | 19.4k | ccdata.w = w, ccdata.h = h; |
875 | 19.4k | if (y >= rptr->ymin && ye <= rptr->ymax) { |
876 | 294 | INCR(in_y); |
877 | 294 | if (x >= rptr->xmin && xe <= rptr->xmax) { |
878 | 0 | INCR(in); |
879 | 0 | return dev_proc(tdev, copy_mono) |
880 | 0 | (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1); |
881 | 0 | } |
882 | 294 | } |
883 | 19.4k | ccdata.tdev = tdev; |
884 | 19.4k | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
885 | 19.4k | ccdata.color[0] = color0, ccdata.color[1] = color1; |
886 | 19.4k | return clip_enumerate_rest(rdev, x, y, xe, ye, |
887 | 19.4k | clip_call_copy_mono, &ccdata); |
888 | 19.4k | } |
889 | | static int |
890 | | clip_copy_mono_t1(gx_device * dev, |
891 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
892 | | int x, int y, int w, int h, |
893 | | gx_color_index color0, gx_color_index color1) |
894 | 0 | { |
895 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
896 | 0 | clip_callback_data_t ccdata; |
897 | | /* We handle the fastest case in-line here. */ |
898 | 0 | gx_device *tdev = rdev->target; |
899 | 0 | const gx_clip_rect *rptr = rdev->current; |
900 | 0 | int xe, ye; |
901 | |
|
902 | 0 | if (w <= 0 || h <= 0) |
903 | 0 | return 0; |
904 | 0 | x += rdev->translation.x; |
905 | 0 | y += rdev->translation.y; |
906 | | /* ccdata is non-transposed */ |
907 | 0 | ccdata.x = x, ccdata.y = y; |
908 | 0 | ccdata.w = w, ccdata.h = h; |
909 | 0 | x = ccdata.y; |
910 | 0 | y = ccdata.x; |
911 | 0 | xe = x + h; |
912 | 0 | ye = y + w; |
913 | 0 | if (y >= rptr->ymin && ye <= rptr->ymax) { |
914 | 0 | INCR(in_y); |
915 | 0 | if (x >= rptr->xmin && xe <= rptr->xmax) { |
916 | 0 | INCR(in); |
917 | 0 | return dev_proc(tdev, copy_mono) |
918 | 0 | (tdev, data, sourcex, raster, id, y, x, h, w, color0, color1); |
919 | 0 | } |
920 | 0 | } |
921 | 0 | ccdata.tdev = tdev; |
922 | 0 | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
923 | 0 | ccdata.color[0] = color0, ccdata.color[1] = color1; |
924 | 0 | return clip_enumerate_rest(rdev, x, y, xe, ye, |
925 | 0 | clip_call_copy_mono, &ccdata); |
926 | 0 | } |
927 | | static int |
928 | | clip_copy_mono_s0(gx_device * dev, |
929 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
930 | | int x, int y, int w, int h, |
931 | | gx_color_index color0, gx_color_index color1) |
932 | 1.04M | { |
933 | 1.04M | gx_device_clip *rdev = (gx_device_clip *) dev; |
934 | 1.04M | gx_device *tdev = rdev->target; |
935 | | |
936 | 1.04M | if (w <= 0 || h <= 0) |
937 | 23 | return 0; |
938 | 1.04M | x += rdev->translation.x; |
939 | 1.04M | w += x; |
940 | 1.04M | y += rdev->translation.y; |
941 | 1.04M | h += y; |
942 | 1.04M | if (x < rdev->list.single.xmin) |
943 | 1.00k | { |
944 | 1.00k | sourcex += (rdev->list.single.xmin - x); |
945 | 1.00k | x = rdev->list.single.xmin; |
946 | 1.00k | } |
947 | 1.04M | if (w > rdev->list.single.xmax) |
948 | 6.26k | w = rdev->list.single.xmax; |
949 | 1.04M | if (y < rdev->list.single.ymin) |
950 | 402k | { |
951 | 402k | data += (rdev->list.single.ymin - y) * raster; |
952 | 402k | y = rdev->list.single.ymin; |
953 | 402k | } |
954 | 1.04M | if (h > rdev->list.single.ymax) |
955 | 403k | h = rdev->list.single.ymax; |
956 | 1.04M | w -= x; |
957 | 1.04M | h -= y; |
958 | 1.04M | if (w <= 0 || h <= 0) |
959 | 841 | return 0; |
960 | 1.04M | return dev_proc(tdev, copy_mono) |
961 | 1.04M | (tdev, data, sourcex, raster, id, x, y, w, h, color0, color1); |
962 | 1.04M | } |
963 | | static int |
964 | | clip_copy_mono_s1(gx_device * dev, |
965 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
966 | | int x, int y, int w, int h, |
967 | | gx_color_index color0, gx_color_index color1) |
968 | 0 | { |
969 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
970 | 0 | gx_device *tdev = rdev->target; |
971 | |
|
972 | 0 | if (w <= 0 || h <= 0) |
973 | 0 | return 0; |
974 | 0 | x += rdev->translation.x; |
975 | 0 | w += x; |
976 | 0 | y += rdev->translation.y; |
977 | 0 | h += y; |
978 | | /* Now, treat x/w as y/h and vice versa as transposed. */ |
979 | 0 | if (x < rdev->list.single.ymin) |
980 | 0 | { |
981 | 0 | data += (rdev->list.single.ymin - x) * raster; |
982 | 0 | x = rdev->list.single.ymin; |
983 | 0 | } |
984 | 0 | if (w > rdev->list.single.ymax) |
985 | 0 | w = rdev->list.single.ymax; |
986 | 0 | if (y < rdev->list.single.xmin) |
987 | 0 | { |
988 | 0 | sourcex += (rdev->list.single.xmin - y); |
989 | 0 | y = rdev->list.single.xmin; |
990 | 0 | } |
991 | 0 | if (h > rdev->list.single.xmax) |
992 | 0 | h = rdev->list.single.xmax; |
993 | 0 | w -= x; |
994 | 0 | h -= y; |
995 | 0 | if (w <= 0 || h <= 0) |
996 | 0 | return 0; |
997 | 0 | return dev_proc(tdev, copy_mono) |
998 | 0 | (tdev, data, sourcex, raster, id, y, x, h, w, color0, color1); |
999 | 0 | } |
1000 | | static int |
1001 | | clip_copy_mono(gx_device * dev, |
1002 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1003 | | int x, int y, int w, int h, |
1004 | | gx_color_index color0, gx_color_index color1) |
1005 | 775k | { |
1006 | 775k | gx_device_clip *rdev = (gx_device_clip *) dev; |
1007 | | |
1008 | 775k | if (rdev->list.transpose) { |
1009 | 0 | if (rdev->list.count == 1) |
1010 | 0 | dev_proc(rdev, copy_mono) = clip_copy_mono_s1; |
1011 | 0 | else |
1012 | 0 | dev_proc(rdev, copy_mono) = clip_copy_mono_t1; |
1013 | 775k | } else { |
1014 | 775k | if (rdev->list.count == 1) |
1015 | 756k | dev_proc(rdev, copy_mono) = clip_copy_mono_s0; |
1016 | 19.5k | else |
1017 | 19.5k | dev_proc(rdev, copy_mono) = clip_copy_mono_t0; |
1018 | 775k | } |
1019 | 775k | return dev_proc(rdev, copy_mono)(dev, data, sourcex, raster, id, x, y, w, h, color0, color1); |
1020 | 775k | } |
1021 | | |
1022 | | /* Copy a plane */ |
1023 | | int |
1024 | | clip_call_copy_planes(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1025 | 0 | { |
1026 | 0 | return (*dev_proc(pccd->tdev, copy_planes)) |
1027 | 0 | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
1028 | 0 | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
1029 | 0 | xc, yc, xec - xc, yec - yc, pccd->plane_height); |
1030 | 0 | } |
1031 | | static int |
1032 | | clip_copy_planes_t0(gx_device * dev, |
1033 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1034 | | int x, int y, int w, int h, int plane_height) |
1035 | 0 | { |
1036 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1037 | 0 | clip_callback_data_t ccdata; |
1038 | | /* We handle the fastest case in-line here. */ |
1039 | 0 | gx_device *tdev = rdev->target; |
1040 | 0 | const gx_clip_rect *rptr = rdev->current; |
1041 | 0 | int xe, ye; |
1042 | |
|
1043 | 0 | if (w <= 0 || h <= 0) |
1044 | 0 | return 0; |
1045 | 0 | x += rdev->translation.x; |
1046 | 0 | xe = x + w; |
1047 | 0 | y += rdev->translation.y; |
1048 | 0 | ye = y + h; |
1049 | | /* ccdata is non-transposed */ |
1050 | 0 | ccdata.x = x, ccdata.y = y; |
1051 | 0 | ccdata.w = w, ccdata.h = h; |
1052 | 0 | if (y >= rptr->ymin && ye <= rptr->ymax) { |
1053 | 0 | INCR(in_y); |
1054 | 0 | if (x >= rptr->xmin && xe <= rptr->xmax) { |
1055 | 0 | INCR(in); |
1056 | 0 | return dev_proc(tdev, copy_planes) |
1057 | 0 | (tdev, data, sourcex, raster, id, x, y, w, h, plane_height); |
1058 | 0 | } |
1059 | 0 | } |
1060 | 0 | ccdata.tdev = tdev; |
1061 | 0 | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1062 | 0 | ccdata.plane_height = plane_height; |
1063 | 0 | return clip_enumerate_rest(rdev, x, y, xe, ye, |
1064 | 0 | clip_call_copy_planes, &ccdata); |
1065 | 0 | } |
1066 | | static int |
1067 | | clip_copy_planes_t1(gx_device * dev, |
1068 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1069 | | int x, int y, int w, int h, int plane_height) |
1070 | 0 | { |
1071 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1072 | 0 | clip_callback_data_t ccdata; |
1073 | | /* We handle the fastest case in-line here. */ |
1074 | 0 | gx_device *tdev = rdev->target; |
1075 | 0 | const gx_clip_rect *rptr = rdev->current; |
1076 | 0 | int xe, ye; |
1077 | |
|
1078 | 0 | if (w <= 0 || h <= 0) |
1079 | 0 | return 0; |
1080 | 0 | x += rdev->translation.x; |
1081 | 0 | y += rdev->translation.y; |
1082 | | /* ccdata is non-transposed */ |
1083 | 0 | ccdata.x = x, ccdata.y = y; |
1084 | 0 | ccdata.w = w, ccdata.h = h; |
1085 | | /* transpose x, y, xe, ye for clip checking */ |
1086 | 0 | x = ccdata.y; |
1087 | 0 | y = ccdata.x; |
1088 | 0 | xe = x + h; |
1089 | 0 | ye = y + w; |
1090 | 0 | if (y >= rptr->ymin && ye <= rptr->ymax) { |
1091 | 0 | INCR(in_y); |
1092 | 0 | if (x >= rptr->xmin && xe <= rptr->xmax) { |
1093 | 0 | INCR(in); |
1094 | 0 | return dev_proc(tdev, copy_planes) |
1095 | 0 | (tdev, data, sourcex, raster, id, y, x, h, w, plane_height); |
1096 | 0 | } |
1097 | 0 | } |
1098 | 0 | ccdata.tdev = tdev; |
1099 | 0 | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1100 | 0 | ccdata.plane_height = plane_height; |
1101 | 0 | return clip_enumerate_rest(rdev, x, y, xe, ye, |
1102 | 0 | clip_call_copy_planes, &ccdata); |
1103 | 0 | } |
1104 | | static int |
1105 | | clip_copy_planes_s0(gx_device * dev, |
1106 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1107 | | int x, int y, int w, int h, int plane_height) |
1108 | 3.47k | { |
1109 | 3.47k | gx_device_clip *rdev = (gx_device_clip *) dev; |
1110 | 3.47k | gx_device *tdev = rdev->target; |
1111 | | |
1112 | 3.47k | x += rdev->translation.x; |
1113 | 3.47k | w += x; |
1114 | 3.47k | y += rdev->translation.y; |
1115 | 3.47k | h += y; |
1116 | 3.47k | if (x < rdev->list.single.xmin) |
1117 | 0 | { |
1118 | 0 | sourcex += rdev->list.single.xmin - x; |
1119 | 0 | x = rdev->list.single.xmin; |
1120 | 0 | } |
1121 | 3.47k | if (w > rdev->list.single.xmax) |
1122 | 0 | w = rdev->list.single.xmax; |
1123 | 3.47k | if (y < rdev->list.single.ymin) |
1124 | 0 | { |
1125 | 0 | data += (rdev->list.single.ymin - y) * raster; |
1126 | 0 | y = rdev->list.single.ymin; |
1127 | 0 | } |
1128 | 3.47k | if (h > rdev->list.single.ymax) |
1129 | 0 | h = rdev->list.single.ymax; |
1130 | 3.47k | w -= x; |
1131 | 3.47k | h -= y; |
1132 | 3.47k | if (w <= 0 || h <= 0) |
1133 | 0 | return 0; |
1134 | 3.47k | return dev_proc(tdev, copy_planes) |
1135 | 3.47k | (tdev, data, sourcex, raster, id, x, y, w, h, plane_height); |
1136 | 3.47k | } |
1137 | | static int |
1138 | | clip_copy_planes_s1(gx_device * dev, |
1139 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1140 | | int x, int y, int w, int h, int plane_height) |
1141 | 0 | { |
1142 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1143 | 0 | gx_device *tdev = rdev->target; |
1144 | |
|
1145 | 0 | x += rdev->translation.x; |
1146 | 0 | w += x; |
1147 | 0 | y += rdev->translation.y; |
1148 | 0 | h += y; |
1149 | | /* Now, treat x/w as y/h and vice versa as transposed. */ |
1150 | 0 | if (x < rdev->list.single.ymin) |
1151 | 0 | { |
1152 | 0 | data += (rdev->list.single.ymin - x) * raster; |
1153 | 0 | x = rdev->list.single.ymin; |
1154 | 0 | } |
1155 | 0 | if (w > rdev->list.single.ymax) |
1156 | 0 | w = rdev->list.single.ymax; |
1157 | 0 | if (y < rdev->list.single.xmin) |
1158 | 0 | { |
1159 | 0 | sourcex += rdev->list.single.xmin - y; |
1160 | 0 | y = rdev->list.single.xmin; |
1161 | 0 | } |
1162 | 0 | if (h > rdev->list.single.xmax) |
1163 | 0 | h = rdev->list.single.xmax; |
1164 | 0 | w -= x; |
1165 | 0 | h -= y; |
1166 | 0 | if (w <= 0 || h <= 0) |
1167 | 0 | return 0; |
1168 | 0 | return dev_proc(tdev, copy_planes) |
1169 | 0 | (tdev, data, sourcex, raster, id, y, x, h, w, plane_height); |
1170 | 0 | } |
1171 | | static int |
1172 | | clip_copy_planes(gx_device * dev, |
1173 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1174 | | int x, int y, int w, int h, int plane_height) |
1175 | 2 | { |
1176 | 2 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1177 | | |
1178 | 2 | if (rdev->list.transpose) { |
1179 | 0 | if (rdev->list.count == 1) |
1180 | 0 | dev_proc(rdev, copy_planes) = clip_copy_planes_s1; |
1181 | 0 | else |
1182 | 0 | dev_proc(rdev, copy_planes) = clip_copy_planes_t1; |
1183 | 2 | } else { |
1184 | 2 | if (rdev->list.count == 1) |
1185 | 2 | dev_proc(rdev, copy_planes) = clip_copy_planes_s0; |
1186 | 0 | else |
1187 | 0 | dev_proc(rdev, copy_planes) = clip_copy_planes_t0; |
1188 | 2 | } |
1189 | 2 | return dev_proc(rdev, copy_planes)(dev, data, sourcex, raster, id, x, y, w, h, plane_height); |
1190 | 2 | } |
1191 | | |
1192 | | /* Copy a color rectangle */ |
1193 | | int |
1194 | | clip_call_copy_color(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1195 | 19.9M | { |
1196 | 19.9M | return (*dev_proc(pccd->tdev, copy_color)) |
1197 | 19.9M | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
1198 | 19.9M | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
1199 | 19.9M | xc, yc, xec - xc, yec - yc); |
1200 | 19.9M | } |
1201 | | static int |
1202 | | clip_copy_color(gx_device * dev, |
1203 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1204 | | int x, int y, int w, int h) |
1205 | 24.6M | { |
1206 | 24.6M | gx_device_clip *rdev = (gx_device_clip *) dev; |
1207 | 24.6M | clip_callback_data_t ccdata; |
1208 | | |
1209 | 24.6M | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1210 | 24.6M | return clip_enumerate(rdev, x, y, w, h, clip_call_copy_color, &ccdata); |
1211 | 24.6M | } |
1212 | | |
1213 | | /* Copy a rectangle with alpha */ |
1214 | | int |
1215 | | clip_call_copy_alpha(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1216 | 0 | { |
1217 | 0 | return (*dev_proc(pccd->tdev, copy_alpha)) |
1218 | 0 | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
1219 | 0 | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
1220 | 0 | xc, yc, xec - xc, yec - yc, pccd->color[0], pccd->depth); |
1221 | 0 | } |
1222 | | static int |
1223 | | clip_copy_alpha(gx_device * dev, |
1224 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1225 | | int x, int y, int w, int h, |
1226 | | gx_color_index color, int depth) |
1227 | 0 | { |
1228 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1229 | 0 | clip_callback_data_t ccdata; |
1230 | |
|
1231 | 0 | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1232 | 0 | ccdata.color[0] = color, ccdata.depth = depth; |
1233 | 0 | return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha, &ccdata); |
1234 | 0 | } |
1235 | | |
1236 | | int |
1237 | | clip_call_copy_alpha_hl_color(clip_callback_data_t * pccd, int xc, int yc, |
1238 | | int xec, int yec) |
1239 | 0 | { |
1240 | 0 | return (*dev_proc(pccd->tdev, copy_alpha_hl_color)) |
1241 | 0 | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
1242 | 0 | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
1243 | 0 | xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth); |
1244 | 0 | } |
1245 | | |
1246 | | static int |
1247 | | clip_copy_alpha_hl_color(gx_device * dev, |
1248 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1249 | | int x, int y, int w, int h, |
1250 | | const gx_drawing_color *pdcolor, int depth) |
1251 | 0 | { |
1252 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1253 | 0 | clip_callback_data_t ccdata; |
1254 | |
|
1255 | 0 | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1256 | 0 | ccdata.pdcolor = pdcolor, ccdata.depth = depth; |
1257 | 0 | return clip_enumerate(rdev, x, y, w, h, clip_call_copy_alpha_hl_color, &ccdata); |
1258 | 0 | } |
1259 | | |
1260 | | /* Fill a region defined by a mask. */ |
1261 | | int |
1262 | | clip_call_fill_mask(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1263 | 0 | { |
1264 | 0 | return (*dev_proc(pccd->tdev, fill_mask)) |
1265 | 0 | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
1266 | 0 | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
1267 | 0 | xc, yc, xec - xc, yec - yc, pccd->pdcolor, pccd->depth, |
1268 | 0 | pccd->lop, NULL); |
1269 | 0 | } |
1270 | | static int |
1271 | | clip_fill_mask(gx_device * dev, |
1272 | | const byte * data, int sourcex, int raster, gx_bitmap_id id, |
1273 | | int x, int y, int w, int h, |
1274 | | const gx_drawing_color * pdcolor, int depth, |
1275 | | gs_logical_operation_t lop, const gx_clip_path * pcpath) |
1276 | 28 | { |
1277 | 28 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1278 | 28 | clip_callback_data_t ccdata; |
1279 | | |
1280 | 28 | if (pcpath != 0) |
1281 | 0 | return gx_default_fill_mask(dev, data, sourcex, raster, id, |
1282 | 0 | x, y, w, h, pdcolor, depth, lop, |
1283 | 0 | pcpath); |
1284 | 28 | ccdata.data = data, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1285 | 28 | ccdata.pdcolor = pdcolor, ccdata.depth = depth, ccdata.lop = lop; |
1286 | 28 | return clip_enumerate(rdev, x, y, w, h, clip_call_fill_mask, &ccdata); |
1287 | 28 | } |
1288 | | |
1289 | | /* Strip-tile a rectangle with devn colors. */ |
1290 | | int |
1291 | | clip_call_strip_tile_rect_devn(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1292 | 0 | { |
1293 | 0 | return (*dev_proc(pccd->tdev, strip_tile_rect_devn)) |
1294 | 0 | (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc, |
1295 | 0 | pccd->pdc[0], pccd->pdc[1], pccd->phase.x, pccd->phase.y); |
1296 | 0 | } |
1297 | | static int |
1298 | | clip_strip_tile_rect_devn(gx_device * dev, const gx_strip_bitmap * tiles, |
1299 | | int x, int y, int w, int h, |
1300 | | const gx_drawing_color *pdcolor0, |
1301 | | const gx_drawing_color *pdcolor1, int phase_x, |
1302 | | int phase_y) |
1303 | 0 | { |
1304 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1305 | 0 | clip_callback_data_t ccdata; |
1306 | |
|
1307 | 0 | ccdata.tiles = tiles; |
1308 | 0 | ccdata.pdc[0] = pdcolor0; |
1309 | 0 | ccdata.pdc[1] = pdcolor1; |
1310 | 0 | ccdata.phase.x = phase_x, ccdata.phase.y = phase_y; |
1311 | 0 | return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rect_devn, &ccdata); |
1312 | 0 | } |
1313 | | |
1314 | | /* Strip-tile a rectangle. */ |
1315 | | int |
1316 | | clip_call_strip_tile_rectangle(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1317 | 18.7M | { |
1318 | 18.7M | return (*dev_proc(pccd->tdev, strip_tile_rectangle)) |
1319 | 18.7M | (pccd->tdev, pccd->tiles, xc, yc, xec - xc, yec - yc, |
1320 | 18.7M | pccd->color[0], pccd->color[1], pccd->phase.x, pccd->phase.y); |
1321 | 18.7M | } |
1322 | | static int |
1323 | | clip_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles, |
1324 | | int x, int y, int w, int h, |
1325 | | gx_color_index color0, gx_color_index color1, int phase_x, int phase_y) |
1326 | 31.6M | { |
1327 | 31.6M | gx_device_clip *rdev = (gx_device_clip *) dev; |
1328 | 31.6M | clip_callback_data_t ccdata; |
1329 | | |
1330 | 31.6M | ccdata.tiles = tiles; |
1331 | 31.6M | ccdata.color[0] = color0, ccdata.color[1] = color1; |
1332 | 31.6M | ccdata.phase.x = phase_x, ccdata.phase.y = phase_y; |
1333 | 31.6M | return clip_enumerate(rdev, x, y, w, h, clip_call_strip_tile_rectangle, &ccdata); |
1334 | 31.6M | } |
1335 | | |
1336 | | /* Copy a rectangle with RasterOp and strip texture. */ |
1337 | | int |
1338 | | clip_call_strip_copy_rop2(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1339 | 0 | { |
1340 | 0 | return (*dev_proc(pccd->tdev, strip_copy_rop2)) |
1341 | 0 | (pccd->tdev, pccd->data + (yc - pccd->y) * pccd->raster, |
1342 | 0 | pccd->sourcex + xc - pccd->x, pccd->raster, gx_no_bitmap_id, |
1343 | 0 | pccd->scolors, pccd->textures, pccd->tcolors, |
1344 | 0 | xc, yc, xec - xc, yec - yc, pccd->phase.x, pccd->phase.y, |
1345 | 0 | pccd->lop, pccd->plane_height); |
1346 | 0 | } |
1347 | | static int |
1348 | | clip_strip_copy_rop2(gx_device * dev, |
1349 | | const byte * sdata, int sourcex, uint raster, gx_bitmap_id id, |
1350 | | const gx_color_index * scolors, |
1351 | | const gx_strip_bitmap * textures, const gx_color_index * tcolors, |
1352 | | int x, int y, int w, int h, |
1353 | | int phase_x, int phase_y, gs_logical_operation_t lop, |
1354 | | uint planar_height) |
1355 | 0 | { |
1356 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1357 | 0 | clip_callback_data_t ccdata; |
1358 | |
|
1359 | 0 | ccdata.data = sdata, ccdata.sourcex = sourcex, ccdata.raster = raster; |
1360 | 0 | ccdata.scolors = scolors, ccdata.textures = textures, |
1361 | 0 | ccdata.tcolors = tcolors; |
1362 | 0 | ccdata.phase.x = phase_x, ccdata.phase.y = phase_y, ccdata.lop = lop; |
1363 | 0 | ccdata.plane_height = planar_height; |
1364 | 0 | return clip_enumerate(rdev, x, y, w, h, clip_call_strip_copy_rop2, &ccdata); |
1365 | 0 | } |
1366 | | |
1367 | | /* Get the (outer) clipping box, in client coordinates. */ |
1368 | | static void |
1369 | | clip_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox) |
1370 | 6.90M | { |
1371 | 6.90M | gx_device_clip *const rdev = (gx_device_clip *) dev; |
1372 | | |
1373 | 6.90M | if (!rdev->clipping_box_set) { |
1374 | 280k | gx_device *tdev = rdev->target; |
1375 | 280k | gs_fixed_rect tbox; |
1376 | | |
1377 | 280k | (*dev_proc(tdev, get_clipping_box)) (tdev, &tbox); |
1378 | 280k | if (rdev->list.count != 0) { |
1379 | 279k | gs_fixed_rect cbox; |
1380 | | |
1381 | 279k | if (rdev->list.count == 1) { |
1382 | 258k | cbox.p.x = int2fixed(rdev->list.single.xmin); |
1383 | 258k | cbox.p.y = int2fixed(rdev->list.single.ymin); |
1384 | 258k | cbox.q.x = int2fixed(rdev->list.single.xmax); |
1385 | 258k | cbox.q.y = int2fixed(rdev->list.single.ymax); |
1386 | 258k | } else { |
1387 | | /* The head and tail elements are dummies.... */ |
1388 | 21.4k | gx_clip_rect *curr = rdev->list.head->next; |
1389 | | |
1390 | 21.4k | cbox.p.x = cbox.p.y = max_int; |
1391 | 21.4k | cbox.q.x = cbox.q.y = min_int; |
1392 | | /* scan the list for the outer bbox */ |
1393 | 4.88M | while (curr->next != NULL) { /* stop before tail */ |
1394 | 4.86M | if (curr->xmin < cbox.p.x) |
1395 | 377k | cbox.p.x = curr->xmin; |
1396 | 4.86M | if (curr->xmax > cbox.q.x) |
1397 | 299k | cbox.q.x = curr->xmax; |
1398 | 4.86M | if (curr->ymin < cbox.p.y) |
1399 | 21.4k | cbox.p.y = curr->ymin; |
1400 | 4.86M | if (curr->ymax > cbox.q.y) |
1401 | 1.24M | cbox.q.y = curr->ymax; |
1402 | 4.86M | curr = curr->next; |
1403 | 4.86M | } |
1404 | 21.4k | cbox.p.x = int2fixed(cbox.p.x); |
1405 | 21.4k | cbox.q.x = int2fixed(cbox.q.x); |
1406 | 21.4k | cbox.p.y = int2fixed(cbox.p.y); |
1407 | 21.4k | cbox.q.y = int2fixed(cbox.q.y); |
1408 | 21.4k | } |
1409 | 279k | if (rdev->list.transpose) { |
1410 | 0 | fixed temp = cbox.p.x; |
1411 | |
|
1412 | 0 | cbox.p.x = cbox.p.y; |
1413 | 0 | cbox.p.y = temp; |
1414 | 0 | temp = cbox.q.x; |
1415 | 0 | cbox.q.x = cbox.q.y; |
1416 | 0 | cbox.q.y = temp; |
1417 | 0 | } |
1418 | 279k | rect_intersect(tbox, cbox); |
1419 | 279k | } |
1420 | 280k | if (rdev->translation.x | rdev->translation.y) { |
1421 | 0 | fixed tx = int2fixed(rdev->translation.x), |
1422 | 0 | ty = int2fixed(rdev->translation.y); |
1423 | |
|
1424 | 0 | if (tbox.p.x != min_fixed) |
1425 | 0 | tbox.p.x -= tx; |
1426 | 0 | if (tbox.p.y != min_fixed) |
1427 | 0 | tbox.p.y -= ty; |
1428 | 0 | if (tbox.q.x != max_fixed) |
1429 | 0 | tbox.q.x -= tx; |
1430 | 0 | if (tbox.q.y != max_fixed) |
1431 | 0 | tbox.q.y -= ty; |
1432 | 0 | } |
1433 | 280k | rdev->clipping_box = tbox; |
1434 | 280k | rdev->clipping_box_set = true; |
1435 | 280k | } |
1436 | 6.90M | *pbox = rdev->clipping_box; |
1437 | 6.90M | } |
1438 | | |
1439 | | /* Get bits back from the device. */ |
1440 | | static int |
1441 | | clip_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, |
1442 | | gs_get_bits_params_t * params) |
1443 | 0 | { |
1444 | 0 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1445 | 0 | gx_device *tdev = rdev->target; |
1446 | 0 | int tx = rdev->translation.x, ty = rdev->translation.y; |
1447 | 0 | gs_int_rect rect; |
1448 | |
|
1449 | 0 | rect.p.x = prect->p.x - tx, rect.p.y = prect->p.y - ty; |
1450 | 0 | rect.q.x = prect->q.x - tx, rect.q.y = prect->q.y - ty; |
1451 | 0 | return (*dev_proc(tdev, get_bits_rectangle)) |
1452 | 0 | (tdev, &rect, params); |
1453 | 0 | } |
1454 | | |
1455 | | static int |
1456 | | clip_call_fill_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1457 | 20.5k | { |
1458 | 20.5k | gx_device *tdev = pccd->tdev; |
1459 | 20.5k | dev_proc_fill_path((*proc)); |
1460 | 20.5k | int code; |
1461 | 20.5k | gx_clip_path cpath_intersection; |
1462 | 20.5k | gx_clip_path *pcpath = (gx_clip_path *)pccd->pcpath; |
1463 | | |
1464 | | /* Previously the code here tested for pcpath != NULL, but |
1465 | | * we can commonly (such as from clist_playback_band) be |
1466 | | * called with a non-NULL, but still invalid clip path. |
1467 | | * Detect this by the list having at least one entry in it. */ |
1468 | 20.5k | if (pcpath != NULL && pcpath->rect_list->list.count != 0) { |
1469 | 20.4k | gx_path rect_path; |
1470 | 20.4k | code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, pccd->ppath->memory, 1); |
1471 | 20.4k | if (code < 0) |
1472 | 0 | return code; |
1473 | 20.4k | gx_path_init_local(&rect_path, pccd->ppath->memory); |
1474 | 20.4k | code = gx_path_add_rectangle(&rect_path, int2fixed(xc), int2fixed(yc), int2fixed(xec), int2fixed(yec)); |
1475 | 20.4k | if (code < 0) |
1476 | 0 | return code; |
1477 | 20.4k | code = gx_cpath_intersect(&cpath_intersection, &rect_path, |
1478 | 20.4k | gx_rule_winding_number, (gs_gstate *)(pccd->pgs)); |
1479 | 20.4k | gx_path_free(&rect_path, "clip_call_fill_path"); |
1480 | 20.4k | } else { |
1481 | 59 | gs_fixed_rect clip_box; |
1482 | 59 | clip_box.p.x = int2fixed(xc); |
1483 | 59 | clip_box.p.y = int2fixed(yc); |
1484 | 59 | clip_box.q.x = int2fixed(xec); |
1485 | 59 | clip_box.q.y = int2fixed(yec); |
1486 | 59 | gx_cpath_init_local(&cpath_intersection, pccd->ppath->memory); |
1487 | 59 | code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box); |
1488 | 59 | } |
1489 | 20.5k | if (code < 0) |
1490 | 0 | return code; |
1491 | 20.5k | proc = dev_proc(tdev, fill_path); |
1492 | 20.5k | if (proc == NULL) |
1493 | 0 | proc = gx_default_fill_path; |
1494 | 20.5k | code = (*proc)(pccd->tdev, pccd->pgs, pccd->ppath, pccd->params, |
1495 | 20.5k | pccd->pdcolor, &cpath_intersection); |
1496 | 20.5k | gx_cpath_free(&cpath_intersection, "clip_call_fill_path"); |
1497 | 20.5k | return code; |
1498 | 20.5k | } |
1499 | | static int |
1500 | | clip_fill_path(gx_device * dev, const gs_gstate * pgs, |
1501 | | gx_path * ppath, const gx_fill_params * params, |
1502 | | const gx_drawing_color * pdcolor, |
1503 | | const gx_clip_path * pcpath) |
1504 | 20.5k | { |
1505 | 20.5k | gx_device_clip *rdev = (gx_device_clip *) dev; |
1506 | 20.5k | clip_callback_data_t ccdata; |
1507 | 20.5k | gs_fixed_rect box; |
1508 | | |
1509 | 20.5k | ccdata.pgs = pgs; |
1510 | 20.5k | ccdata.ppath = ppath; |
1511 | 20.5k | ccdata.params = params; |
1512 | 20.5k | ccdata.pdcolor = pdcolor; |
1513 | 20.5k | ccdata.pcpath = pcpath; |
1514 | 20.5k | clip_get_clipping_box(dev, &box); |
1515 | 20.5k | return clip_enumerate(rdev, |
1516 | 20.5k | fixed2int(box.p.x), |
1517 | 20.5k | fixed2int(box.p.y), |
1518 | 20.5k | fixed2int(box.q.x - box.p.x), |
1519 | 20.5k | fixed2int(box.q.y - box.p.y), |
1520 | 20.5k | clip_call_fill_path, &ccdata); |
1521 | 20.5k | } |
1522 | | |
1523 | | typedef struct { |
1524 | | int use_default; |
1525 | | void *child_state; |
1526 | | } clip_transform_pixel_region_data; |
1527 | | |
1528 | | static int |
1529 | | clip_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data) |
1530 | 1.49M | { |
1531 | 1.49M | clip_transform_pixel_region_data *state = (clip_transform_pixel_region_data *)data->state; |
1532 | 1.49M | gx_device_clip *cdev = (gx_device_clip *)dev; |
1533 | 1.49M | transform_pixel_region_data local_data; |
1534 | 1.49M | gs_int_rect local_clip; |
1535 | 1.49M | int ret; |
1536 | | |
1537 | 1.49M | if (reason == transform_pixel_region_begin) { |
1538 | 28.9k | int skewed = 1; |
1539 | 28.9k | if (data->u.init.pixels->y.step.dQ == 0 && data->u.init.pixels->y.step.dR == 0 && |
1540 | 28.9k | data->u.init.rows->x.step.dQ == 0 && data->u.init.rows->x.step.dR == 0) |
1541 | 28.9k | skewed = 0; |
1542 | 32 | else if (data->u.init.pixels->x.step.dQ == 0 && data->u.init.pixels->x.step.dR == 0 && |
1543 | 32 | data->u.init.rows->y.step.dQ == 0 && data->u.init.rows->y.step.dR == 0) |
1544 | 0 | skewed = 0; |
1545 | 28.9k | state = (clip_transform_pixel_region_data *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(*state), "clip_transform_pixel_region_data"); |
1546 | 28.9k | if (state == NULL) |
1547 | 0 | return gs_error_VMerror; |
1548 | 28.9k | local_data = *data; |
1549 | 28.9k | if (cdev->list.count == 1 && skewed == 0) { |
1550 | | /* Single unskewed rectangle - we can use the underlying device direct */ |
1551 | 28.2k | local_data.u.init.clip = &local_clip; |
1552 | 28.2k | local_clip = *data->u.init.clip; |
1553 | 28.2k | if (cdev->list.transpose) { |
1554 | 0 | if (local_clip.p.x < cdev->current->ymin) |
1555 | 0 | local_clip.p.x = cdev->current->ymin; |
1556 | 0 | if (local_clip.q.x > cdev->current->ymax) |
1557 | 0 | local_clip.q.x = cdev->current->ymax; |
1558 | 0 | if (local_clip.p.y < cdev->current->xmin) |
1559 | 0 | local_clip.p.y = cdev->current->xmin; |
1560 | 0 | if (local_clip.q.y > cdev->current->xmax) |
1561 | 0 | local_clip.q.y = cdev->current->xmax; |
1562 | 28.2k | } else { |
1563 | 28.2k | if (local_clip.p.x < cdev->current->xmin) |
1564 | 0 | local_clip.p.x = cdev->current->xmin; |
1565 | 28.2k | if (local_clip.q.x > cdev->current->xmax) |
1566 | 20 | local_clip.q.x = cdev->current->xmax; |
1567 | 28.2k | if (local_clip.p.y < cdev->current->ymin) |
1568 | 0 | local_clip.p.y = cdev->current->ymin; |
1569 | 28.2k | if (local_clip.q.y > cdev->current->ymax) |
1570 | 45 | local_clip.q.y = cdev->current->ymax; |
1571 | 28.2k | } |
1572 | 28.2k | state->use_default = 0; |
1573 | 28.2k | ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, &local_data); |
1574 | 28.2k | } else { |
1575 | | /* Multiple rectangles - we need to use the default */ |
1576 | 686 | state->use_default = 1; |
1577 | 686 | ret = gx_default_transform_pixel_region(dev, reason, &local_data); |
1578 | 686 | } |
1579 | 28.9k | state->child_state = local_data.state; |
1580 | 28.9k | data->state = state; |
1581 | 28.9k | return ret; |
1582 | 28.9k | } |
1583 | | |
1584 | 1.46M | data->state = state->child_state; |
1585 | 1.46M | if (state->use_default) |
1586 | 12.3k | ret = gx_default_transform_pixel_region(dev, reason, data); |
1587 | 1.45M | else |
1588 | 1.45M | ret = dev_proc(cdev->target, transform_pixel_region)(cdev->target, reason, data); |
1589 | | |
1590 | 1.46M | if (reason == transform_pixel_region_end) { |
1591 | 28.9k | gs_free_object(dev->memory->non_gc_memory, state, "clip_transform_pixel_region_data"); |
1592 | 28.9k | state = NULL; |
1593 | 28.9k | } |
1594 | 1.46M | data->state = state; |
1595 | | |
1596 | 1.46M | return ret; |
1597 | 1.49M | } |
1598 | | |
1599 | | static int |
1600 | | clip_call_fill_stroke_path(clip_callback_data_t * pccd, int xc, int yc, int xec, int yec) |
1601 | 3 | { |
1602 | 3 | gx_device *tdev = pccd->tdev; |
1603 | 3 | dev_proc_fill_stroke_path((*proc)); |
1604 | 3 | int code; |
1605 | 3 | gx_clip_path cpath_intersection; |
1606 | 3 | gx_clip_path *pcpath = (gx_clip_path *)pccd->pcpath; |
1607 | | |
1608 | | /* Previously the code here tested for pcpath != NULL, but |
1609 | | * we can commonly (such as from clist_playback_band) be |
1610 | | * called with a non-NULL, but still invalid clip path. |
1611 | | * Detect this by the list having at least one entry in it. */ |
1612 | 3 | if (pcpath != NULL && pcpath->rect_list->list.count != 0) { |
1613 | 3 | gx_path rect_path; |
1614 | 3 | code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, pccd->ppath->memory, 1); |
1615 | 3 | if (code < 0) |
1616 | 0 | return code; |
1617 | 3 | gx_path_init_local(&rect_path, pccd->ppath->memory); |
1618 | 3 | code = gx_path_add_rectangle(&rect_path, int2fixed(xc), int2fixed(yc), int2fixed(xec), int2fixed(yec)); |
1619 | 3 | if (code < 0) |
1620 | 0 | return code; |
1621 | 3 | code = gx_cpath_intersect(&cpath_intersection, &rect_path, |
1622 | 3 | gx_rule_winding_number, (gs_gstate *)(pccd->pgs)); |
1623 | 3 | gx_path_free(&rect_path, "clip_call_fill_stroke_path"); |
1624 | 3 | } else { |
1625 | 0 | gs_fixed_rect clip_box; |
1626 | 0 | clip_box.p.x = int2fixed(xc); |
1627 | 0 | clip_box.p.y = int2fixed(yc); |
1628 | 0 | clip_box.q.x = int2fixed(xec); |
1629 | 0 | clip_box.q.y = int2fixed(yec); |
1630 | 0 | gx_cpath_init_local(&cpath_intersection, pccd->ppath->memory); |
1631 | 0 | code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box); |
1632 | 0 | } |
1633 | 3 | if (code < 0) |
1634 | 0 | return code; |
1635 | 3 | proc = dev_proc(tdev, fill_stroke_path); |
1636 | 3 | if (proc == NULL) |
1637 | 0 | proc = gx_default_fill_stroke_path; |
1638 | 3 | code = (*proc)(pccd->tdev, pccd->pgs, pccd->ppath, pccd->params, |
1639 | 3 | pccd->pdcolor, pccd->stroke_params, pccd->pstroke_dcolor, |
1640 | 3 | &cpath_intersection); |
1641 | 3 | gx_cpath_free(&cpath_intersection, "clip_call_fill_stroke_path"); |
1642 | 3 | return code; |
1643 | 3 | } |
1644 | | |
1645 | | static int |
1646 | | clip_fill_stroke_path(gx_device *dev, const gs_gstate *pgs, |
1647 | | gx_path *ppath, |
1648 | | const gx_fill_params *params, |
1649 | | const gx_drawing_color *pdcolor, |
1650 | | const gx_stroke_params *stroke_params, |
1651 | | const gx_drawing_color *pstroke_dcolor, |
1652 | | const gx_clip_path *pcpath) |
1653 | 3 | { |
1654 | 3 | gx_device_clip *rdev = (gx_device_clip *) dev; |
1655 | 3 | clip_callback_data_t ccdata; |
1656 | 3 | gs_fixed_rect box; |
1657 | | |
1658 | 3 | ccdata.pgs = pgs; |
1659 | 3 | ccdata.ppath = ppath; |
1660 | 3 | ccdata.params = params; |
1661 | 3 | ccdata.pdcolor = pdcolor; |
1662 | 3 | ccdata.stroke_params = stroke_params; |
1663 | 3 | ccdata.pstroke_dcolor = pstroke_dcolor; |
1664 | 3 | ccdata.pcpath = pcpath; |
1665 | 3 | clip_get_clipping_box(dev, &box); |
1666 | 3 | return clip_enumerate(rdev, |
1667 | 3 | fixed2int(box.p.x), |
1668 | 3 | fixed2int(box.p.y), |
1669 | 3 | fixed2int(box.q.x - box.p.x), |
1670 | 3 | fixed2int(box.q.y - box.p.y), |
1671 | 3 | clip_call_fill_stroke_path, &ccdata); |
1672 | 3 | } |