/work/workdir/UnpackedTarball/cairo/src/cairo-path-fill.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 | | #include "cairo-boxes-private.h" |
40 | | #include "cairo-error-private.h" |
41 | | #include "cairo-path-fixed-private.h" |
42 | | #include "cairo-region-private.h" |
43 | | #include "cairo-traps-private.h" |
44 | | |
45 | | typedef struct cairo_filler { |
46 | | cairo_polygon_t *polygon; |
47 | | double tolerance; |
48 | | |
49 | | cairo_box_t limit; |
50 | | cairo_bool_t has_limits; |
51 | | |
52 | | cairo_point_t current_point; |
53 | | cairo_point_t last_move_to; |
54 | | } cairo_filler_t; |
55 | | |
56 | | static cairo_status_t |
57 | | _cairo_filler_line_to (void *closure, |
58 | | const cairo_point_t *point) |
59 | 55.4M | { |
60 | 55.4M | cairo_filler_t *filler = closure; |
61 | 55.4M | cairo_status_t status; |
62 | | |
63 | 55.4M | status = _cairo_polygon_add_external_edge (filler->polygon, |
64 | 55.4M | &filler->current_point, |
65 | 55.4M | point); |
66 | | |
67 | 55.4M | filler->current_point = *point; |
68 | | |
69 | 55.4M | return status; |
70 | 55.4M | } |
71 | | |
72 | | static cairo_status_t |
73 | | _cairo_filler_add_point (void *closure, |
74 | | const cairo_point_t *point, |
75 | | const cairo_slope_t *tangent) |
76 | 15.9M | { |
77 | 15.9M | return _cairo_filler_line_to (closure, point); |
78 | 15.9M | }; |
79 | | |
80 | | static cairo_status_t |
81 | | _cairo_filler_close (void *closure) |
82 | 101k | { |
83 | 101k | cairo_filler_t *filler = closure; |
84 | | |
85 | | /* close the subpath */ |
86 | 101k | return _cairo_filler_line_to (closure, &filler->last_move_to); |
87 | 101k | } |
88 | | |
89 | | static cairo_status_t |
90 | | _cairo_filler_move_to (void *closure, |
91 | | const cairo_point_t *point) |
92 | 50.7k | { |
93 | 50.7k | cairo_filler_t *filler = closure; |
94 | 50.7k | cairo_status_t status; |
95 | | |
96 | | /* close current subpath */ |
97 | 50.7k | status = _cairo_filler_close (closure); |
98 | 50.7k | if (unlikely (status)) |
99 | 0 | return status; |
100 | | |
101 | | /* make sure that the closure represents a degenerate path */ |
102 | 50.7k | filler->current_point = *point; |
103 | 50.7k | filler->last_move_to = *point; |
104 | | |
105 | 50.7k | return CAIRO_STATUS_SUCCESS; |
106 | 50.7k | } |
107 | | |
108 | | static cairo_status_t |
109 | | _cairo_filler_curve_to (void *closure, |
110 | | const cairo_point_t *p1, |
111 | | const cairo_point_t *p2, |
112 | | const cairo_point_t *p3) |
113 | 41.0k | { |
114 | 41.0k | cairo_filler_t *filler = closure; |
115 | 41.0k | cairo_spline_t spline; |
116 | | |
117 | 41.0k | if (filler->has_limits) { |
118 | 40.4k | if (! _cairo_spline_intersects (&filler->current_point, p1, p2, p3, |
119 | 40.4k | &filler->limit)) |
120 | 28.7k | return _cairo_filler_line_to (filler, p3); |
121 | 40.4k | } |
122 | | |
123 | 12.3k | if (! _cairo_spline_init (&spline, |
124 | 12.3k | _cairo_filler_add_point, filler, |
125 | 12.3k | &filler->current_point, p1, p2, p3)) |
126 | 537 | { |
127 | 537 | return _cairo_filler_line_to (closure, p3); |
128 | 537 | } |
129 | | |
130 | 11.8k | return _cairo_spline_decompose (&spline, filler->tolerance); |
131 | 12.3k | } |
132 | | |
133 | | cairo_status_t |
134 | | _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path, |
135 | | double tolerance, |
136 | | cairo_polygon_t *polygon) |
137 | 36.3k | { |
138 | 36.3k | cairo_filler_t filler; |
139 | 36.3k | cairo_status_t status; |
140 | | |
141 | 36.3k | filler.polygon = polygon; |
142 | 36.3k | filler.tolerance = tolerance; |
143 | | |
144 | 36.3k | filler.has_limits = FALSE; |
145 | 36.3k | if (polygon->num_limits) { |
146 | 36.2k | filler.has_limits = TRUE; |
147 | 36.2k | filler.limit = polygon->limit; |
148 | 36.2k | } |
149 | | |
150 | | /* make sure that the closure represents a degenerate path */ |
151 | 36.3k | filler.current_point.x = 0; |
152 | 36.3k | filler.current_point.y = 0; |
153 | 36.3k | filler.last_move_to = filler.current_point; |
154 | | |
155 | 36.3k | status = _cairo_path_fixed_interpret (path, |
156 | 36.3k | _cairo_filler_move_to, |
157 | 36.3k | _cairo_filler_line_to, |
158 | 36.3k | _cairo_filler_curve_to, |
159 | 36.3k | _cairo_filler_close, |
160 | 36.3k | &filler); |
161 | 36.3k | if (unlikely (status)) |
162 | 0 | return status; |
163 | | |
164 | 36.3k | return _cairo_filler_close (&filler); |
165 | 36.3k | } |
166 | | |
167 | | typedef struct cairo_filler_rectilinear_aligned { |
168 | | cairo_polygon_t *polygon; |
169 | | |
170 | | cairo_point_t current_point; |
171 | | cairo_point_t last_move_to; |
172 | | } cairo_filler_ra_t; |
173 | | |
174 | | static cairo_status_t |
175 | | _cairo_filler_ra_line_to (void *closure, |
176 | | const cairo_point_t *point) |
177 | 52.2k | { |
178 | 52.2k | cairo_filler_ra_t *filler = closure; |
179 | 52.2k | cairo_status_t status; |
180 | 52.2k | cairo_point_t p; |
181 | | |
182 | 52.2k | p.x = _cairo_fixed_round_down (point->x); |
183 | 52.2k | p.y = _cairo_fixed_round_down (point->y); |
184 | | |
185 | 52.2k | status = _cairo_polygon_add_external_edge (filler->polygon, |
186 | 52.2k | &filler->current_point, |
187 | 52.2k | &p); |
188 | | |
189 | 52.2k | filler->current_point = p; |
190 | | |
191 | 52.2k | return status; |
192 | 52.2k | } |
193 | | |
194 | | static cairo_status_t |
195 | | _cairo_filler_ra_close (void *closure) |
196 | 21.8k | { |
197 | 21.8k | cairo_filler_ra_t *filler = closure; |
198 | 21.8k | return _cairo_filler_ra_line_to (closure, &filler->last_move_to); |
199 | 21.8k | } |
200 | | |
201 | | static cairo_status_t |
202 | | _cairo_filler_ra_move_to (void *closure, |
203 | | const cairo_point_t *point) |
204 | 12.1k | { |
205 | 12.1k | cairo_filler_ra_t *filler = closure; |
206 | 12.1k | cairo_status_t status; |
207 | 12.1k | cairo_point_t p; |
208 | | |
209 | | /* close current subpath */ |
210 | 12.1k | status = _cairo_filler_ra_close (closure); |
211 | 12.1k | if (unlikely (status)) |
212 | 0 | return status; |
213 | | |
214 | 12.1k | p.x = _cairo_fixed_round_down (point->x); |
215 | 12.1k | p.y = _cairo_fixed_round_down (point->y); |
216 | | |
217 | | /* make sure that the closure represents a degenerate path */ |
218 | 12.1k | filler->current_point = p; |
219 | 12.1k | filler->last_move_to = p; |
220 | | |
221 | 12.1k | return CAIRO_STATUS_SUCCESS; |
222 | 12.1k | } |
223 | | |
224 | | cairo_status_t |
225 | | _cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path, |
226 | | cairo_antialias_t antialias, |
227 | | cairo_polygon_t *polygon) |
228 | 5.39k | { |
229 | 5.39k | cairo_filler_ra_t filler; |
230 | 5.39k | cairo_status_t status; |
231 | | |
232 | 5.39k | if (antialias != CAIRO_ANTIALIAS_NONE) |
233 | 5 | return _cairo_path_fixed_fill_to_polygon (path, 0., polygon); |
234 | | |
235 | 5.39k | filler.polygon = polygon; |
236 | | |
237 | | /* make sure that the closure represents a degenerate path */ |
238 | 5.39k | filler.current_point.x = 0; |
239 | 5.39k | filler.current_point.y = 0; |
240 | 5.39k | filler.last_move_to = filler.current_point; |
241 | | |
242 | 5.39k | status = _cairo_path_fixed_interpret_flat (path, |
243 | 5.39k | _cairo_filler_ra_move_to, |
244 | 5.39k | _cairo_filler_ra_line_to, |
245 | 5.39k | _cairo_filler_ra_close, |
246 | 5.39k | &filler, |
247 | 5.39k | 0.); |
248 | 5.39k | if (unlikely (status)) |
249 | 0 | return status; |
250 | | |
251 | 5.39k | return _cairo_filler_ra_close (&filler); |
252 | 5.39k | } |
253 | | |
254 | | cairo_status_t |
255 | | _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, |
256 | | cairo_fill_rule_t fill_rule, |
257 | | double tolerance, |
258 | | cairo_traps_t *traps) |
259 | 0 | { |
260 | 0 | cairo_polygon_t polygon; |
261 | 0 | cairo_status_t status; |
262 | |
|
263 | 0 | if (_cairo_path_fixed_fill_is_empty (path)) |
264 | 0 | return CAIRO_STATUS_SUCCESS; |
265 | | |
266 | 0 | _cairo_polygon_init (&polygon, traps->limits, traps->num_limits); |
267 | 0 | status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); |
268 | 0 | if (unlikely (status || polygon.num_edges == 0)) |
269 | 0 | goto CLEANUP; |
270 | | |
271 | 0 | status = _cairo_bentley_ottmann_tessellate_polygon (traps, |
272 | 0 | &polygon, fill_rule); |
273 | |
|
274 | 0 | CLEANUP: |
275 | 0 | _cairo_polygon_fini (&polygon); |
276 | 0 | return status; |
277 | 0 | } |
278 | | |
279 | | static cairo_status_t |
280 | | _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path, |
281 | | cairo_fill_rule_t fill_rule, |
282 | | cairo_antialias_t antialias, |
283 | | cairo_boxes_t *boxes) |
284 | 5.39k | { |
285 | 5.39k | cairo_polygon_t polygon; |
286 | 5.39k | cairo_status_t status; |
287 | | |
288 | 5.39k | _cairo_polygon_init (&polygon, boxes->limits, boxes->num_limits); |
289 | 5.39k | boxes->num_limits = 0; |
290 | | |
291 | | /* tolerance will be ignored as the path is rectilinear */ |
292 | 5.39k | status = _cairo_path_fixed_fill_rectilinear_to_polygon (path, antialias, &polygon); |
293 | 5.39k | if (likely (status == CAIRO_STATUS_SUCCESS)) { |
294 | 5.39k | status = |
295 | 5.39k | _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon, |
296 | 5.39k | fill_rule, |
297 | 5.39k | boxes); |
298 | 5.39k | } |
299 | | |
300 | 5.39k | _cairo_polygon_fini (&polygon); |
301 | | |
302 | 5.39k | return status; |
303 | 5.39k | } |
304 | | |
305 | | cairo_status_t |
306 | | _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, |
307 | | cairo_fill_rule_t fill_rule, |
308 | | cairo_antialias_t antialias, |
309 | | cairo_boxes_t *boxes) |
310 | 514k | { |
311 | 514k | cairo_path_fixed_iter_t iter; |
312 | 514k | cairo_status_t status; |
313 | 514k | cairo_box_t box; |
314 | | |
315 | 514k | if (_cairo_path_fixed_is_box (path, &box)) |
316 | 507k | return _cairo_boxes_add (boxes, antialias, &box); |
317 | | |
318 | 6.87k | _cairo_path_fixed_iter_init (&iter, path); |
319 | 164k | while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { |
320 | 157k | if (box.p1.y == box.p2.y || box.p1.x == box.p2.x) |
321 | 9.71k | continue; |
322 | | |
323 | 148k | if (box.p1.y > box.p2.y) { |
324 | 76.9k | cairo_fixed_t t; |
325 | | |
326 | 76.9k | t = box.p1.y; |
327 | 76.9k | box.p1.y = box.p2.y; |
328 | 76.9k | box.p2.y = t; |
329 | | |
330 | 76.9k | t = box.p1.x; |
331 | 76.9k | box.p1.x = box.p2.x; |
332 | 76.9k | box.p2.x = t; |
333 | 76.9k | } |
334 | | |
335 | 148k | status = _cairo_boxes_add (boxes, antialias, &box); |
336 | 148k | if (unlikely (status)) |
337 | 0 | return status; |
338 | 148k | } |
339 | | |
340 | 6.87k | if (_cairo_path_fixed_iter_at_end (&iter)) |
341 | 1.47k | return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes); |
342 | | |
343 | | /* path is not rectangular, try extracting clipped rectilinear edges */ |
344 | 5.39k | _cairo_boxes_clear (boxes); |
345 | 5.39k | return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path, |
346 | 5.39k | fill_rule, |
347 | 5.39k | antialias, |
348 | 5.39k | boxes); |
349 | 6.87k | } |