/work/workdir/UnpackedTarball/cairo/src/cairo-polygon.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2002 University of Southern California |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it either under the terms of the GNU Lesser General Public |
8 | | * License version 2.1 as published by the Free Software Foundation |
9 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
10 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
11 | | * notice, a recipient may use your version of this file under either |
12 | | * the MPL or the LGPL. |
13 | | * |
14 | | * You should have received a copy of the LGPL along with this library |
15 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
17 | | * You should have received a copy of the MPL along with this library |
18 | | * in the file COPYING-MPL-1.1 |
19 | | * |
20 | | * The contents of this file are subject to the Mozilla Public License |
21 | | * Version 1.1 (the "License"); you may not use this file except in |
22 | | * compliance with the License. You may obtain a copy of the License at |
23 | | * http://www.mozilla.org/MPL/ |
24 | | * |
25 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
26 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
27 | | * the specific language governing rights and limitations. |
28 | | * |
29 | | * The Original Code is the cairo graphics library. |
30 | | * |
31 | | * The Initial Developer of the Original Code is University of Southern |
32 | | * California. |
33 | | * |
34 | | * Contributor(s): |
35 | | * Carl D. Worth <cworth@cworth.org> |
36 | | */ |
37 | | |
38 | | #include "cairoint.h" |
39 | | |
40 | | #include "cairo-boxes-private.h" |
41 | | #include "cairo-contour-private.h" |
42 | | #include "cairo-error-private.h" |
43 | | |
44 | | #define DEBUG_POLYGON 0 |
45 | | |
46 | | #if DEBUG_POLYGON && !NDEBUG |
47 | | static void |
48 | | assert_last_edge_is_valid(cairo_polygon_t *polygon, |
49 | | const cairo_box_t *limit) |
50 | | { |
51 | | cairo_edge_t *edge; |
52 | | cairo_fixed_t x; |
53 | | |
54 | | edge = &polygon->edges[polygon->num_edges-1]; |
55 | | |
56 | | assert (edge->bottom > edge->top); |
57 | | assert (edge->top >= limit->p1.y); |
58 | | assert (edge->bottom <= limit->p2.y); |
59 | | |
60 | | x = _cairo_edge_compute_intersection_x_for_y (&edge->line.p1, |
61 | | &edge->line.p2, |
62 | | edge->top); |
63 | | assert (x >= limit->p1.x); |
64 | | assert (x <= limit->p2.x); |
65 | | |
66 | | x = _cairo_edge_compute_intersection_x_for_y (&edge->line.p1, |
67 | | &edge->line.p2, |
68 | | edge->bottom); |
69 | | assert (x >= limit->p1.x); |
70 | | assert (x <= limit->p2.x); |
71 | | } |
72 | | #else |
73 | | #define assert_last_edge_is_valid(p, l) |
74 | | #endif |
75 | | |
76 | | static void |
77 | | _cairo_polygon_add_edge (cairo_polygon_t *polygon, |
78 | | const cairo_point_t *p1, |
79 | | const cairo_point_t *p2, |
80 | | int dir); |
81 | | |
82 | | void |
83 | | _cairo_polygon_limit (cairo_polygon_t *polygon, |
84 | | const cairo_box_t *limits, |
85 | | int num_limits) |
86 | 45.9k | { |
87 | 45.9k | int n; |
88 | | |
89 | 45.9k | polygon->limits = limits; |
90 | 45.9k | polygon->num_limits = num_limits; |
91 | | |
92 | 45.9k | if (polygon->num_limits) { |
93 | 45.8k | polygon->limit = limits[0]; |
94 | 45.8k | for (n = 1; n < num_limits; n++) { |
95 | 0 | if (limits[n].p1.x < polygon->limit.p1.x) |
96 | 0 | polygon->limit.p1.x = limits[n].p1.x; |
97 | |
|
98 | 0 | if (limits[n].p1.y < polygon->limit.p1.y) |
99 | 0 | polygon->limit.p1.y = limits[n].p1.y; |
100 | |
|
101 | 0 | if (limits[n].p2.x > polygon->limit.p2.x) |
102 | 0 | polygon->limit.p2.x = limits[n].p2.x; |
103 | |
|
104 | 0 | if (limits[n].p2.y > polygon->limit.p2.y) |
105 | 0 | polygon->limit.p2.y = limits[n].p2.y; |
106 | 0 | } |
107 | 45.8k | } |
108 | 45.9k | } |
109 | | |
110 | | void |
111 | | _cairo_polygon_limit_to_clip (cairo_polygon_t *polygon, |
112 | | const cairo_clip_t *clip) |
113 | 0 | { |
114 | 0 | if (clip) |
115 | 0 | _cairo_polygon_limit (polygon, clip->boxes, clip->num_boxes); |
116 | 0 | else |
117 | 0 | _cairo_polygon_limit (polygon, 0, 0); |
118 | 0 | } |
119 | | |
120 | | void |
121 | | _cairo_polygon_init (cairo_polygon_t *polygon, |
122 | | const cairo_box_t *limits, |
123 | | int num_limits) |
124 | 45.9k | { |
125 | 45.9k | VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); |
126 | | |
127 | 45.9k | polygon->status = CAIRO_STATUS_SUCCESS; |
128 | | |
129 | 45.9k | polygon->num_edges = 0; |
130 | | |
131 | 45.9k | polygon->edges = polygon->edges_embedded; |
132 | 45.9k | polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); |
133 | | |
134 | 45.9k | polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; |
135 | 45.9k | polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; |
136 | | |
137 | 45.9k | _cairo_polygon_limit (polygon, limits, num_limits); |
138 | 45.9k | } |
139 | | |
140 | | void |
141 | | _cairo_polygon_init_with_clip (cairo_polygon_t *polygon, |
142 | | const cairo_clip_t *clip) |
143 | 0 | { |
144 | 0 | if (clip) |
145 | 0 | _cairo_polygon_init (polygon, clip->boxes, clip->num_boxes); |
146 | 0 | else |
147 | 0 | _cairo_polygon_init (polygon, 0, 0); |
148 | 0 | } |
149 | | |
150 | | cairo_status_t |
151 | | _cairo_polygon_init_boxes (cairo_polygon_t *polygon, |
152 | | const cairo_boxes_t *boxes) |
153 | 0 | { |
154 | 0 | const struct _cairo_boxes_chunk *chunk; |
155 | 0 | int i; |
156 | |
|
157 | 0 | VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); |
158 | |
|
159 | 0 | polygon->status = CAIRO_STATUS_SUCCESS; |
160 | |
|
161 | 0 | polygon->num_edges = 0; |
162 | |
|
163 | 0 | polygon->edges = polygon->edges_embedded; |
164 | 0 | polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); |
165 | 0 | if (boxes->num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { |
166 | 0 | polygon->edges_size = 2 * boxes->num_boxes; |
167 | 0 | polygon->edges = _cairo_malloc_ab (polygon->edges_size, |
168 | 0 | 2*sizeof(cairo_edge_t)); |
169 | 0 | if (unlikely (polygon->edges == NULL)) |
170 | 0 | return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
171 | 0 | } |
172 | | |
173 | 0 | polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; |
174 | 0 | polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; |
175 | |
|
176 | 0 | polygon->limits = NULL; |
177 | 0 | polygon->num_limits = 0; |
178 | |
|
179 | 0 | for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { |
180 | 0 | for (i = 0; i < chunk->count; i++) { |
181 | 0 | cairo_point_t p1, p2; |
182 | |
|
183 | 0 | p1 = chunk->base[i].p1; |
184 | 0 | p2.x = p1.x; |
185 | 0 | p2.y = chunk->base[i].p2.y; |
186 | 0 | _cairo_polygon_add_edge (polygon, &p1, &p2, 1); |
187 | |
|
188 | 0 | p1 = chunk->base[i].p2; |
189 | 0 | p2.x = p1.x; |
190 | 0 | p2.y = chunk->base[i].p1.y; |
191 | 0 | _cairo_polygon_add_edge (polygon, &p1, &p2, 1); |
192 | 0 | } |
193 | 0 | } |
194 | |
|
195 | 0 | return polygon->status; |
196 | 0 | } |
197 | | |
198 | | cairo_status_t |
199 | | _cairo_polygon_init_box_array (cairo_polygon_t *polygon, |
200 | | cairo_box_t *boxes, |
201 | | int num_boxes) |
202 | 0 | { |
203 | 0 | int i; |
204 | |
|
205 | 0 | VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); |
206 | |
|
207 | 0 | polygon->status = CAIRO_STATUS_SUCCESS; |
208 | |
|
209 | 0 | polygon->num_edges = 0; |
210 | |
|
211 | 0 | polygon->edges = polygon->edges_embedded; |
212 | 0 | polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); |
213 | 0 | if (num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { |
214 | 0 | polygon->edges_size = 2 * num_boxes; |
215 | 0 | polygon->edges = _cairo_malloc_ab (polygon->edges_size, |
216 | 0 | 2*sizeof(cairo_edge_t)); |
217 | 0 | if (unlikely (polygon->edges == NULL)) |
218 | 0 | return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
219 | 0 | } |
220 | | |
221 | 0 | polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; |
222 | 0 | polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; |
223 | |
|
224 | 0 | polygon->limits = NULL; |
225 | 0 | polygon->num_limits = 0; |
226 | |
|
227 | 0 | for (i = 0; i < num_boxes; i++) { |
228 | 0 | cairo_point_t p1, p2; |
229 | |
|
230 | 0 | p1 = boxes[i].p1; |
231 | 0 | p2.x = p1.x; |
232 | 0 | p2.y = boxes[i].p2.y; |
233 | 0 | _cairo_polygon_add_edge (polygon, &p1, &p2, 1); |
234 | |
|
235 | 0 | p1 = boxes[i].p2; |
236 | 0 | p2.x = p1.x; |
237 | 0 | p2.y = boxes[i].p1.y; |
238 | 0 | _cairo_polygon_add_edge (polygon, &p1, &p2, 1); |
239 | 0 | } |
240 | |
|
241 | 0 | return polygon->status; |
242 | 0 | } |
243 | | |
244 | | |
245 | | void |
246 | | _cairo_polygon_fini (cairo_polygon_t *polygon) |
247 | 45.9k | { |
248 | 45.9k | if (polygon->edges != polygon->edges_embedded) |
249 | 615 | free (polygon->edges); |
250 | | |
251 | 45.9k | VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); |
252 | 45.9k | } |
253 | | |
254 | | /* make room for at least one more edge */ |
255 | | static cairo_bool_t |
256 | | _cairo_polygon_grow (cairo_polygon_t *polygon) |
257 | 1.03k | { |
258 | 1.03k | cairo_edge_t *new_edges; |
259 | 1.03k | int old_size = polygon->edges_size; |
260 | 1.03k | int new_size = 4 * old_size; |
261 | | |
262 | 1.03k | if (CAIRO_INJECT_FAULT ()) { |
263 | 0 | polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
264 | 0 | return FALSE; |
265 | 0 | } |
266 | | |
267 | 1.03k | if (polygon->edges == polygon->edges_embedded) { |
268 | 615 | new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t)); |
269 | 615 | if (new_edges != NULL) |
270 | 615 | memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t)); |
271 | 615 | } else { |
272 | 416 | new_edges = _cairo_realloc_ab (polygon->edges, |
273 | 416 | new_size, sizeof (cairo_edge_t)); |
274 | 416 | } |
275 | | |
276 | 1.03k | if (unlikely (new_edges == NULL)) { |
277 | 0 | polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
278 | 0 | return FALSE; |
279 | 0 | } |
280 | | |
281 | 1.03k | polygon->edges = new_edges; |
282 | 1.03k | polygon->edges_size = new_size; |
283 | | |
284 | 1.03k | return TRUE; |
285 | 1.03k | } |
286 | | |
287 | | static void |
288 | | _add_edge (cairo_polygon_t *polygon, |
289 | | const cairo_point_t *p1, |
290 | | const cairo_point_t *p2, |
291 | | int top, int bottom, |
292 | | int dir) |
293 | 378k | { |
294 | 378k | cairo_edge_t *edge; |
295 | | |
296 | 378k | assert (top < bottom); |
297 | | |
298 | 378k | if (unlikely (polygon->num_edges == polygon->edges_size)) { |
299 | 1.03k | if (! _cairo_polygon_grow (polygon)) |
300 | 0 | return; |
301 | 1.03k | } |
302 | | |
303 | 378k | edge = &polygon->edges[polygon->num_edges++]; |
304 | 378k | edge->line.p1 = *p1; |
305 | 378k | edge->line.p2 = *p2; |
306 | 378k | edge->top = top; |
307 | 378k | edge->bottom = bottom; |
308 | 378k | edge->dir = dir; |
309 | | |
310 | 378k | if (top < polygon->extents.p1.y) |
311 | 46.3k | polygon->extents.p1.y = top; |
312 | 378k | if (bottom > polygon->extents.p2.y) |
313 | 45.7k | polygon->extents.p2.y = bottom; |
314 | | |
315 | 378k | if (p1->x < polygon->extents.p1.x || p1->x > polygon->extents.p2.x) { |
316 | 72.2k | cairo_fixed_t x = p1->x; |
317 | 72.2k | if (top != p1->y) |
318 | 7.60k | x = _cairo_edge_compute_intersection_x_for_y (p1, p2, top); |
319 | 72.2k | if (x < polygon->extents.p1.x) |
320 | 57.1k | polygon->extents.p1.x = x; |
321 | 72.2k | if (x > polygon->extents.p2.x) |
322 | 56.3k | polygon->extents.p2.x = x; |
323 | 72.2k | } |
324 | | |
325 | 378k | if (p2->x < polygon->extents.p1.x || p2->x > polygon->extents.p2.x) { |
326 | 12.5k | cairo_fixed_t x = p2->x; |
327 | 12.5k | if (bottom != p2->y) |
328 | 12.0k | x = _cairo_edge_compute_intersection_x_for_y (p1, p2, bottom); |
329 | 12.5k | if (x < polygon->extents.p1.x) |
330 | 601 | polygon->extents.p1.x = x; |
331 | 12.5k | if (x > polygon->extents.p2.x) |
332 | 539 | polygon->extents.p2.x = x; |
333 | 12.5k | } |
334 | 378k | } |
335 | | |
336 | | static void |
337 | | _add_clipped_edge (cairo_polygon_t *polygon, |
338 | | const cairo_point_t *p1, |
339 | | const cairo_point_t *p2, |
340 | | const int top, const int bottom, |
341 | | const int dir) |
342 | 368k | { |
343 | 368k | cairo_point_t bot_left, top_right; |
344 | 368k | cairo_fixed_t top_y, bot_y; |
345 | 368k | int n; |
346 | | |
347 | 737k | for (n = 0; n < polygon->num_limits; n++) { |
348 | 368k | const cairo_box_t *limits = &polygon->limits[n]; |
349 | 368k | cairo_fixed_t pleft, pright; |
350 | | |
351 | 368k | if (top >= limits->p2.y) |
352 | 0 | continue; |
353 | 368k | if (bottom <= limits->p1.y) |
354 | 0 | continue; |
355 | | |
356 | 368k | bot_left.x = limits->p1.x; |
357 | 368k | bot_left.y = limits->p2.y; |
358 | | |
359 | 368k | top_right.x = limits->p2.x; |
360 | 368k | top_right.y = limits->p1.y; |
361 | | |
362 | | /* The useful region */ |
363 | 368k | top_y = MAX (top, limits->p1.y); |
364 | 368k | bot_y = MIN (bottom, limits->p2.y); |
365 | | |
366 | | /* The projection of the edge on the horizontal axis */ |
367 | 368k | pleft = MIN (p1->x, p2->x); |
368 | 368k | pright = MAX (p1->x, p2->x); |
369 | | |
370 | 368k | if (limits->p1.x <= pleft && pright <= limits->p2.x) { |
371 | | /* Projection of the edge completely contained in the box: |
372 | | * clip vertically by restricting top and bottom */ |
373 | | |
374 | 79.9k | _add_edge (polygon, p1, p2, top_y, bot_y, dir); |
375 | 79.9k | assert_last_edge_is_valid (polygon, limits); |
376 | 288k | } else if (pright <= limits->p1.x) { |
377 | | /* Projection of the edge to the left of the box: |
378 | | * replace with the left side of the box (clipped top/bottom) */ |
379 | | |
380 | 79.1k | _add_edge (polygon, &limits->p1, &bot_left, top_y, bot_y, dir); |
381 | 79.1k | assert_last_edge_is_valid (polygon, limits); |
382 | 209k | } else if (limits->p2.x <= pleft) { |
383 | | /* Projection of the edge to the right of the box: |
384 | | * replace with the right side of the box (clipped top/bottom) */ |
385 | | |
386 | 134k | _add_edge (polygon, &top_right, &limits->p2, top_y, bot_y, dir); |
387 | 134k | assert_last_edge_is_valid (polygon, limits); |
388 | 134k | } else { |
389 | | /* The edge and the box intersect in a generic way */ |
390 | 74.8k | cairo_fixed_t left_y, right_y; |
391 | 74.8k | cairo_bool_t top_left_to_bottom_right; |
392 | | |
393 | | /* |
394 | | * The edge intersects the lines corresponding to the left |
395 | | * and right sides of the limit box at left_y and right_y, |
396 | | * but we need to add edges for the range from top_y to |
397 | | * bot_y. |
398 | | * |
399 | | * For both intersections, there are three cases: |
400 | | * |
401 | | * 1) It is outside the vertical range of the limit |
402 | | * box. In this case we can simply further clip the |
403 | | * edge we will be emitting (i.e. restrict its |
404 | | * top/bottom limits to those of the limit box). |
405 | | * |
406 | | * 2) It is inside the vertical range of the limit |
407 | | * box. In this case, we need to add the vertical edge |
408 | | * connecting the correct vertex to the intersection, |
409 | | * in order to preserve the winding count. |
410 | | * |
411 | | * 3) It is exactly on the box. In this case, do nothing. |
412 | | * |
413 | | * These operations restrict the active range (stored in |
414 | | * top_y/bot_y) so that the p1-p2 edge is completely |
415 | | * inside the box if it is clipped to this vertical range. |
416 | | */ |
417 | | |
418 | 74.8k | top_left_to_bottom_right = (p1->x <= p2->x) == (p1->y <= p2->y); |
419 | 74.8k | if (top_left_to_bottom_right) { |
420 | 40.0k | if (pleft >= limits->p1.x) { |
421 | 11.0k | left_y = top_y; |
422 | 28.9k | } else { |
423 | 28.9k | left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, |
424 | 28.9k | limits->p1.x); |
425 | 28.9k | if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x) |
426 | 23.5k | left_y++; |
427 | 28.9k | } |
428 | | |
429 | 40.0k | left_y = MIN (left_y, bot_y); |
430 | 40.0k | if (top_y < left_y) { |
431 | 16.2k | _add_edge (polygon, &limits->p1, &bot_left, |
432 | 16.2k | top_y, left_y, dir); |
433 | 16.2k | assert_last_edge_is_valid (polygon, limits); |
434 | 16.2k | top_y = left_y; |
435 | 16.2k | } |
436 | | |
437 | 40.0k | if (pright <= limits->p2.x) { |
438 | 2.11k | right_y = bot_y; |
439 | 37.9k | } else { |
440 | 37.9k | right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, |
441 | 37.9k | limits->p2.x); |
442 | 37.9k | if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x) |
443 | 3.72k | right_y--; |
444 | 37.9k | } |
445 | | |
446 | 40.0k | right_y = MAX (right_y, top_y); |
447 | 40.0k | if (bot_y > right_y) { |
448 | 20.6k | _add_edge (polygon, &top_right, &limits->p2, |
449 | 20.6k | right_y, bot_y, dir); |
450 | 20.6k | assert_last_edge_is_valid (polygon, limits); |
451 | 20.6k | bot_y = right_y; |
452 | 20.6k | } |
453 | 40.0k | } else { |
454 | 34.7k | if (pright <= limits->p2.x) { |
455 | 2.21k | right_y = top_y; |
456 | 32.5k | } else { |
457 | 32.5k | right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, |
458 | 32.5k | limits->p2.x); |
459 | 32.5k | if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x) |
460 | 25.5k | right_y++; |
461 | 32.5k | } |
462 | | |
463 | 34.7k | right_y = MIN (right_y, bot_y); |
464 | 34.7k | if (top_y < right_y) { |
465 | 22.4k | _add_edge (polygon, &top_right, &limits->p2, |
466 | 22.4k | top_y, right_y, dir); |
467 | 22.4k | assert_last_edge_is_valid (polygon, limits); |
468 | 22.4k | top_y = right_y; |
469 | 22.4k | } |
470 | | |
471 | 34.7k | if (pleft >= limits->p1.x) { |
472 | 11.9k | left_y = bot_y; |
473 | 22.7k | } else { |
474 | 22.7k | left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, |
475 | 22.7k | limits->p1.x); |
476 | 22.7k | if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x) |
477 | 4.39k | left_y--; |
478 | 22.7k | } |
479 | | |
480 | 34.7k | left_y = MAX (left_y, top_y); |
481 | 34.7k | if (bot_y > left_y) { |
482 | 11.6k | _add_edge (polygon, &limits->p1, &bot_left, |
483 | 11.6k | left_y, bot_y, dir); |
484 | 11.6k | assert_last_edge_is_valid (polygon, limits); |
485 | 11.6k | bot_y = left_y; |
486 | 11.6k | } |
487 | 34.7k | } |
488 | | |
489 | 74.8k | if (top_y != bot_y) { |
490 | 12.7k | _add_edge (polygon, p1, p2, top_y, bot_y, dir); |
491 | 12.7k | assert_last_edge_is_valid (polygon, limits); |
492 | 12.7k | } |
493 | 74.8k | } |
494 | 368k | } |
495 | 368k | } |
496 | | |
497 | | static void |
498 | | _cairo_polygon_add_edge (cairo_polygon_t *polygon, |
499 | | const cairo_point_t *p1, |
500 | | const cairo_point_t *p2, |
501 | | int dir) |
502 | 91.6M | { |
503 | | /* drop horizontal edges */ |
504 | 91.6M | if (p1->y == p2->y) |
505 | 677k | return; |
506 | | |
507 | 90.9M | if (p1->y > p2->y) { |
508 | 45.5M | const cairo_point_t *t; |
509 | 45.5M | t = p1, p1 = p2, p2 = t; |
510 | 45.5M | dir = -dir; |
511 | 45.5M | } |
512 | | |
513 | 90.9M | if (polygon->num_limits) { |
514 | 90.9M | if (p2->y <= polygon->limit.p1.y) |
515 | 38.5M | return; |
516 | | |
517 | 52.3M | if (p1->y >= polygon->limit.p2.y) |
518 | 51.9M | return; |
519 | | |
520 | 368k | _add_clipped_edge (polygon, p1, p2, p1->y, p2->y, dir); |
521 | 368k | } else |
522 | 1.22k | _add_edge (polygon, p1, p2, p1->y, p2->y, dir); |
523 | 90.9M | } |
524 | | |
525 | | cairo_status_t |
526 | | _cairo_polygon_add_external_edge (void *polygon, |
527 | | const cairo_point_t *p1, |
528 | | const cairo_point_t *p2) |
529 | 55.5M | { |
530 | 55.5M | _cairo_polygon_add_edge (polygon, p1, p2, 1); |
531 | 55.5M | return _cairo_polygon_status (polygon); |
532 | 55.5M | } |
533 | | |
534 | | cairo_status_t |
535 | | _cairo_polygon_add_line (cairo_polygon_t *polygon, |
536 | | const cairo_line_t *line, |
537 | | int top, int bottom, |
538 | | int dir) |
539 | 0 | { |
540 | | /* drop horizontal edges */ |
541 | 0 | if (line->p1.y == line->p2.y) |
542 | 0 | return CAIRO_STATUS_SUCCESS; |
543 | | |
544 | 0 | if (bottom <= top) |
545 | 0 | return CAIRO_STATUS_SUCCESS; |
546 | | |
547 | 0 | if (polygon->num_limits) { |
548 | 0 | if (line->p2.y <= polygon->limit.p1.y) |
549 | 0 | return CAIRO_STATUS_SUCCESS; |
550 | | |
551 | 0 | if (line->p1.y >= polygon->limit.p2.y) |
552 | 0 | return CAIRO_STATUS_SUCCESS; |
553 | | |
554 | 0 | _add_clipped_edge (polygon, &line->p1, &line->p2, top, bottom, dir); |
555 | 0 | } else |
556 | 0 | _add_edge (polygon, &line->p1, &line->p2, top, bottom, dir); |
557 | | |
558 | 0 | return polygon->status; |
559 | 0 | } |
560 | | |
561 | | cairo_status_t |
562 | | _cairo_polygon_add_contour (cairo_polygon_t *polygon, |
563 | | const cairo_contour_t *contour) |
564 | 50.5k | { |
565 | 50.5k | const struct _cairo_contour_chain *chain; |
566 | 50.5k | const cairo_point_t *prev = NULL; |
567 | 50.5k | int i; |
568 | | |
569 | 50.5k | if (contour->chain.num_points <= 1) |
570 | 20.7k | return CAIRO_INT_STATUS_SUCCESS; |
571 | | |
572 | 29.7k | prev = &contour->chain.points[0]; |
573 | 69.6k | for (chain = &contour->chain; chain; chain = chain->next) { |
574 | 36.1M | for (i = 0; i < chain->num_points; i++) { |
575 | 36.0M | _cairo_polygon_add_edge (polygon, prev, &chain->points[i], |
576 | 36.0M | contour->direction); |
577 | 36.0M | prev = &chain->points[i]; |
578 | 36.0M | } |
579 | 39.8k | } |
580 | | |
581 | 29.7k | return polygon->status; |
582 | 50.5k | } |
583 | | |
584 | | void |
585 | | _cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy) |
586 | 0 | { |
587 | 0 | int n; |
588 | |
|
589 | 0 | dx = _cairo_fixed_from_int (dx); |
590 | 0 | dy = _cairo_fixed_from_int (dy); |
591 | |
|
592 | 0 | polygon->extents.p1.x += dx; |
593 | 0 | polygon->extents.p2.x += dx; |
594 | 0 | polygon->extents.p1.y += dy; |
595 | 0 | polygon->extents.p2.y += dy; |
596 | |
|
597 | 0 | for (n = 0; n < polygon->num_edges; n++) { |
598 | 0 | cairo_edge_t *e = &polygon->edges[n]; |
599 | |
|
600 | 0 | e->top += dy; |
601 | 0 | e->bottom += dy; |
602 | |
|
603 | 0 | e->line.p1.x += dx; |
604 | 0 | e->line.p2.x += dx; |
605 | 0 | e->line.p1.y += dy; |
606 | 0 | e->line.p2.y += dy; |
607 | 0 | } |
608 | 0 | } |