/work/workdir/UnpackedTarball/cairo/src/cairo-mono-scan-converter.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* |
3 | | * Copyright (c) 2011 Intel Corporation |
4 | | * |
5 | | * Permission is hereby granted, free of charge, to any person |
6 | | * obtaining a copy of this software and associated documentation |
7 | | * files (the "Software"), to deal in the Software without |
8 | | * restriction, including without limitation the rights to use, |
9 | | * copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | | * copies of the Software, and to permit persons to whom the |
11 | | * Software is furnished to do so, subject to the following |
12 | | * conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be |
15 | | * included in all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
19 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
21 | | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
22 | | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
23 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
24 | | * OTHER DEALINGS IN THE SOFTWARE. |
25 | | */ |
26 | | #include "cairoint.h" |
27 | | #include "cairo-spans-private.h" |
28 | | #include "cairo-error-private.h" |
29 | | |
30 | | #include <stdlib.h> |
31 | | #include <string.h> |
32 | | #include <limits.h> |
33 | | |
34 | | struct quorem { |
35 | | int32_t quo; |
36 | | int32_t rem; |
37 | | }; |
38 | | |
39 | | struct edge { |
40 | | struct edge *next, *prev; |
41 | | |
42 | | int32_t height_left; |
43 | | int32_t dir; |
44 | | int32_t vertical; |
45 | | |
46 | | int32_t dy; |
47 | | struct quorem x; |
48 | | struct quorem dxdy; |
49 | | }; |
50 | | |
51 | | /* A collection of sorted and vertically clipped edges of the polygon. |
52 | | * Edges are moved from the polygon to an active list while scan |
53 | | * converting. */ |
54 | | struct polygon { |
55 | | /* The vertical clip extents. */ |
56 | | int32_t ymin, ymax; |
57 | | |
58 | | int num_edges; |
59 | | struct edge *edges; |
60 | | |
61 | | /* Array of edges all starting in the same bucket. An edge is put |
62 | | * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when |
63 | | * it is added to the polygon. */ |
64 | | struct edge **y_buckets; |
65 | | |
66 | | struct edge *y_buckets_embedded[64]; |
67 | | struct edge edges_embedded[32]; |
68 | | }; |
69 | | |
70 | | struct mono_scan_converter { |
71 | | struct polygon polygon[1]; |
72 | | |
73 | | /* Leftmost edge on the current scan line. */ |
74 | | struct edge head, tail; |
75 | | int is_vertical; |
76 | | |
77 | | cairo_half_open_span_t *spans; |
78 | | cairo_half_open_span_t spans_embedded[64]; |
79 | | int num_spans; |
80 | | |
81 | | /* Clip box. */ |
82 | | int32_t xmin, xmax; |
83 | | int32_t ymin, ymax; |
84 | | }; |
85 | | |
86 | 978k | #define I(x) _cairo_fixed_integer_round_down(x) |
87 | | |
88 | | /* Compute the floored division a/b. Assumes / and % perform symmetric |
89 | | * division. */ |
90 | | inline static struct quorem |
91 | | floored_divrem(int a, int b) |
92 | 0 | { |
93 | 0 | struct quorem qr; |
94 | 0 | qr.quo = a/b; |
95 | 0 | qr.rem = a%b; |
96 | 0 | if ((a^b)<0 && qr.rem) { |
97 | 0 | qr.quo -= 1; |
98 | 0 | qr.rem += b; |
99 | 0 | } |
100 | 0 | return qr; |
101 | 0 | } |
102 | | |
103 | | /* Compute the floored division (x*a)/b. Assumes / and % perform symmetric |
104 | | * division. */ |
105 | | static struct quorem |
106 | | floored_muldivrem(int x, int a, int b) |
107 | 23.9k | { |
108 | 23.9k | struct quorem qr; |
109 | 23.9k | long long xa = (long long)x*a; |
110 | 23.9k | qr.quo = xa/b; |
111 | 23.9k | qr.rem = xa%b; |
112 | 23.9k | if ((xa>=0) != (b>=0) && qr.rem) { |
113 | 6.20k | qr.quo -= 1; |
114 | 6.20k | qr.rem += b; |
115 | 6.20k | } |
116 | 23.9k | return qr; |
117 | 23.9k | } |
118 | | |
119 | | static cairo_status_t |
120 | | polygon_init (struct polygon *polygon, int ymin, int ymax) |
121 | 20.3k | { |
122 | 20.3k | unsigned h = ymax - ymin + 1; |
123 | | |
124 | 20.3k | polygon->y_buckets = polygon->y_buckets_embedded; |
125 | 20.3k | if (h > ARRAY_LENGTH (polygon->y_buckets_embedded)) { |
126 | 0 | polygon->y_buckets = _cairo_malloc_ab (h, sizeof (struct edge *)); |
127 | 0 | if (unlikely (NULL == polygon->y_buckets)) |
128 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
129 | 0 | } |
130 | 20.3k | memset (polygon->y_buckets, 0, h * sizeof (struct edge *)); |
131 | 20.3k | polygon->y_buckets[h-1] = (void *)-1; |
132 | | |
133 | 20.3k | polygon->ymin = ymin; |
134 | 20.3k | polygon->ymax = ymax; |
135 | 20.3k | return CAIRO_STATUS_SUCCESS; |
136 | 20.3k | } |
137 | | |
138 | | static void |
139 | | polygon_fini (struct polygon *polygon) |
140 | 20.3k | { |
141 | 20.3k | if (polygon->y_buckets != polygon->y_buckets_embedded) |
142 | 0 | free (polygon->y_buckets); |
143 | | |
144 | 20.3k | if (polygon->edges != polygon->edges_embedded) |
145 | 600 | free (polygon->edges); |
146 | 20.3k | } |
147 | | |
148 | | static void |
149 | | _polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, |
150 | | struct edge *e, |
151 | | int y) |
152 | 267k | { |
153 | 267k | struct edge **ptail = &polygon->y_buckets[y - polygon->ymin]; |
154 | 267k | if (*ptail) |
155 | 247k | (*ptail)->prev = e; |
156 | 267k | e->next = *ptail; |
157 | 267k | e->prev = NULL; |
158 | 267k | *ptail = e; |
159 | 267k | } |
160 | | |
161 | | inline static void |
162 | | polygon_add_edge (struct polygon *polygon, |
163 | | const cairo_edge_t *edge) |
164 | 320k | { |
165 | 320k | struct edge *e; |
166 | 320k | cairo_fixed_t dx; |
167 | 320k | cairo_fixed_t dy; |
168 | 320k | int y, ytop, ybot; |
169 | 320k | int ymin = polygon->ymin; |
170 | 320k | int ymax = polygon->ymax; |
171 | | |
172 | 320k | y = I(edge->top); |
173 | 320k | ytop = MAX(y, ymin); |
174 | | |
175 | 320k | y = I(edge->bottom); |
176 | 320k | ybot = MIN(y, ymax); |
177 | | |
178 | 320k | if (ybot <= ytop) |
179 | 52.9k | return; |
180 | | |
181 | 267k | e = polygon->edges + polygon->num_edges++; |
182 | 267k | e->height_left = ybot - ytop; |
183 | 267k | e->dir = edge->dir; |
184 | | |
185 | 267k | dx = edge->line.p2.x - edge->line.p1.x; |
186 | 267k | dy = edge->line.p2.y - edge->line.p1.y; |
187 | | |
188 | 267k | if (dx == 0) { |
189 | 255k | e->vertical = TRUE; |
190 | 255k | e->x.quo = edge->line.p1.x; |
191 | 255k | e->x.rem = 0; |
192 | 255k | e->dxdy.quo = 0; |
193 | 255k | e->dxdy.rem = 0; |
194 | 255k | e->dy = 0; |
195 | 255k | } else { |
196 | 11.9k | e->vertical = FALSE; |
197 | 11.9k | e->dxdy = floored_muldivrem (dx, CAIRO_FIXED_ONE, dy); |
198 | 11.9k | e->dy = dy; |
199 | | |
200 | 11.9k | e->x = floored_muldivrem (ytop * CAIRO_FIXED_ONE + CAIRO_FIXED_FRAC_MASK/2 - edge->line.p1.y, |
201 | 11.9k | dx, dy); |
202 | 11.9k | e->x.quo += edge->line.p1.x; |
203 | 11.9k | } |
204 | 267k | e->x.rem -= dy; |
205 | | |
206 | 267k | _polygon_insert_edge_into_its_y_bucket (polygon, e, ytop); |
207 | 267k | } |
208 | | |
209 | | static struct edge * |
210 | | merge_sorted_edges (struct edge *head_a, struct edge *head_b) |
211 | 133k | { |
212 | 133k | struct edge *head, **next, *prev; |
213 | 133k | int32_t x; |
214 | | |
215 | 133k | prev = head_a->prev; |
216 | 133k | next = &head; |
217 | 133k | if (head_a->x.quo <= head_b->x.quo) { |
218 | 94.6k | head = head_a; |
219 | 94.6k | } else { |
220 | 39.1k | head = head_b; |
221 | 39.1k | head_b->prev = prev; |
222 | 39.1k | goto start_with_b; |
223 | 39.1k | } |
224 | | |
225 | 120k | do { |
226 | 120k | x = head_b->x.quo; |
227 | 797k | while (head_a != NULL && head_a->x.quo <= x) { |
228 | 676k | prev = head_a; |
229 | 676k | next = &head_a->next; |
230 | 676k | head_a = head_a->next; |
231 | 676k | } |
232 | | |
233 | 120k | head_b->prev = prev; |
234 | 120k | *next = head_b; |
235 | 120k | if (head_a == NULL) |
236 | 51.8k | return head; |
237 | | |
238 | 107k | start_with_b: |
239 | 107k | x = head_a->x.quo; |
240 | 979k | while (head_b != NULL && head_b->x.quo <= x) { |
241 | 871k | prev = head_b; |
242 | 871k | next = &head_b->next; |
243 | 871k | head_b = head_b->next; |
244 | 871k | } |
245 | | |
246 | 107k | head_a->prev = prev; |
247 | 107k | *next = head_a; |
248 | 107k | if (head_b == NULL) |
249 | 81.8k | return head; |
250 | 107k | } while (1); |
251 | 94.6k | } |
252 | | |
253 | | static struct edge * |
254 | | sort_edges (struct edge *list, |
255 | | unsigned int level, |
256 | | struct edge **head_out) |
257 | 133k | { |
258 | 133k | struct edge *head_other, *remaining; |
259 | 133k | unsigned int i; |
260 | | |
261 | 133k | head_other = list->next; |
262 | | |
263 | 133k | if (head_other == NULL) { |
264 | 0 | *head_out = list; |
265 | 0 | return NULL; |
266 | 0 | } |
267 | | |
268 | 133k | remaining = head_other->next; |
269 | 133k | if (list->x.quo <= head_other->x.quo) { |
270 | 96.9k | *head_out = list; |
271 | 96.9k | head_other->next = NULL; |
272 | 96.9k | } else { |
273 | 36.7k | *head_out = head_other; |
274 | 36.7k | head_other->prev = list->prev; |
275 | 36.7k | head_other->next = list; |
276 | 36.7k | list->prev = head_other; |
277 | 36.7k | list->next = NULL; |
278 | 36.7k | } |
279 | | |
280 | 247k | for (i = 0; i < level && remaining; i++) { |
281 | 113k | remaining = sort_edges (remaining, i, &head_other); |
282 | 113k | *head_out = merge_sorted_edges (*head_out, head_other); |
283 | 113k | } |
284 | | |
285 | 133k | return remaining; |
286 | 133k | } |
287 | | |
288 | | static struct edge * |
289 | | merge_unsorted_edges (struct edge *head, struct edge *unsorted) |
290 | 20.3k | { |
291 | 20.3k | sort_edges (unsorted, UINT_MAX, &unsorted); |
292 | 20.3k | return merge_sorted_edges (head, unsorted); |
293 | 20.3k | } |
294 | | |
295 | | inline static void |
296 | | active_list_merge_edges (struct mono_scan_converter *c, struct edge *edges) |
297 | 20.3k | { |
298 | 20.3k | struct edge *e; |
299 | | |
300 | 145k | for (e = edges; c->is_vertical && e; e = e->next) |
301 | 125k | c->is_vertical = e->vertical; |
302 | | |
303 | 20.3k | c->head.next = merge_unsorted_edges (c->head.next, edges); |
304 | 20.3k | } |
305 | | |
306 | | inline static void |
307 | | add_span (struct mono_scan_converter *c, int x1, int x2) |
308 | 20.3k | { |
309 | 20.3k | int n; |
310 | | |
311 | 20.3k | if (x1 < c->xmin) |
312 | 0 | x1 = c->xmin; |
313 | 20.3k | if (x2 > c->xmax) |
314 | 6 | x2 = c->xmax; |
315 | 20.3k | if (x2 <= x1) |
316 | 830 | return; |
317 | | |
318 | 19.4k | n = c->num_spans++; |
319 | 19.4k | c->spans[n].x = x1; |
320 | 19.4k | c->spans[n].coverage = 255; |
321 | | |
322 | 19.4k | n = c->num_spans++; |
323 | 19.4k | c->spans[n].x = x2; |
324 | 19.4k | c->spans[n].coverage = 0; |
325 | 19.4k | } |
326 | | |
327 | | inline static void |
328 | | row (struct mono_scan_converter *c, unsigned int mask) |
329 | 20.3k | { |
330 | 20.3k | struct edge *edge = c->head.next; |
331 | 20.3k | int xstart = INT_MIN, prev_x = INT_MIN; |
332 | 20.3k | int winding = 0; |
333 | | |
334 | 20.3k | c->num_spans = 0; |
335 | 287k | while (&c->tail != edge) { |
336 | 267k | struct edge *next = edge->next; |
337 | 267k | int xend = I(edge->x.quo); |
338 | | |
339 | 267k | if (--edge->height_left) { |
340 | 0 | if (!edge->vertical) { |
341 | 0 | edge->x.quo += edge->dxdy.quo; |
342 | 0 | edge->x.rem += edge->dxdy.rem; |
343 | 0 | if (edge->x.rem >= 0) { |
344 | 0 | ++edge->x.quo; |
345 | 0 | edge->x.rem -= edge->dy; |
346 | 0 | } |
347 | 0 | } |
348 | |
|
349 | 0 | if (edge->x.quo < prev_x) { |
350 | 0 | struct edge *pos = edge->prev; |
351 | 0 | pos->next = next; |
352 | 0 | next->prev = pos; |
353 | 0 | do { |
354 | 0 | pos = pos->prev; |
355 | 0 | } while (edge->x.quo < pos->x.quo); |
356 | 0 | pos->next->prev = edge; |
357 | 0 | edge->next = pos->next; |
358 | 0 | edge->prev = pos; |
359 | 0 | pos->next = edge; |
360 | 0 | } else |
361 | 0 | prev_x = edge->x.quo; |
362 | 267k | } else { |
363 | 267k | edge->prev->next = next; |
364 | 267k | next->prev = edge->prev; |
365 | 267k | } |
366 | | |
367 | 267k | winding += edge->dir; |
368 | 267k | if ((winding & mask) == 0) { |
369 | 70.6k | if (I(next->x.quo) > xend + 1) { |
370 | 20.3k | add_span (c, xstart, xend); |
371 | 20.3k | xstart = INT_MIN; |
372 | 20.3k | } |
373 | 196k | } else if (xstart == INT_MIN) |
374 | 20.3k | xstart = xend; |
375 | | |
376 | 267k | edge = next; |
377 | 267k | } |
378 | 20.3k | } |
379 | | |
380 | | inline static void dec (struct edge *e, int h) |
381 | 0 | { |
382 | 0 | e->height_left -= h; |
383 | 0 | if (e->height_left == 0) { |
384 | 0 | e->prev->next = e->next; |
385 | 0 | e->next->prev = e->prev; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | | static cairo_status_t |
390 | | _mono_scan_converter_init(struct mono_scan_converter *c, |
391 | | int xmin, int ymin, |
392 | | int xmax, int ymax) |
393 | 20.3k | { |
394 | 20.3k | cairo_status_t status; |
395 | 20.3k | int max_num_spans; |
396 | | |
397 | 20.3k | status = polygon_init (c->polygon, ymin, ymax); |
398 | 20.3k | if (unlikely (status)) |
399 | 0 | return status; |
400 | | |
401 | 20.3k | max_num_spans = xmax - xmin + 1; |
402 | 20.3k | if (max_num_spans > ARRAY_LENGTH(c->spans_embedded)) { |
403 | 0 | c->spans = _cairo_malloc_ab (max_num_spans, |
404 | 0 | sizeof (cairo_half_open_span_t)); |
405 | 0 | if (unlikely (c->spans == NULL)) { |
406 | 0 | polygon_fini (c->polygon); |
407 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
408 | 0 | } |
409 | 0 | } else |
410 | 20.3k | c->spans = c->spans_embedded; |
411 | | |
412 | 20.3k | c->xmin = xmin; |
413 | 20.3k | c->xmax = xmax; |
414 | 20.3k | c->ymin = ymin; |
415 | 20.3k | c->ymax = ymax; |
416 | | |
417 | 20.3k | c->head.vertical = 1; |
418 | 20.3k | c->head.height_left = INT_MAX; |
419 | 20.3k | c->head.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MIN)); |
420 | 20.3k | c->head.prev = NULL; |
421 | 20.3k | c->head.next = &c->tail; |
422 | 20.3k | c->tail.prev = &c->head; |
423 | 20.3k | c->tail.next = NULL; |
424 | 20.3k | c->tail.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MAX)); |
425 | 20.3k | c->tail.height_left = INT_MAX; |
426 | 20.3k | c->tail.vertical = 1; |
427 | | |
428 | 20.3k | c->is_vertical = 1; |
429 | 20.3k | return CAIRO_STATUS_SUCCESS; |
430 | 20.3k | } |
431 | | |
432 | | static void |
433 | | _mono_scan_converter_fini(struct mono_scan_converter *self) |
434 | 20.3k | { |
435 | 20.3k | if (self->spans != self->spans_embedded) |
436 | 0 | free (self->spans); |
437 | | |
438 | 20.3k | polygon_fini(self->polygon); |
439 | 20.3k | } |
440 | | |
441 | | static cairo_status_t |
442 | | mono_scan_converter_allocate_edges(struct mono_scan_converter *c, |
443 | | int num_edges) |
444 | | |
445 | 20.3k | { |
446 | 20.3k | c->polygon->num_edges = 0; |
447 | 20.3k | c->polygon->edges = c->polygon->edges_embedded; |
448 | 20.3k | if (num_edges > ARRAY_LENGTH (c->polygon->edges_embedded)) { |
449 | 600 | c->polygon->edges = _cairo_malloc_ab (num_edges, sizeof (struct edge)); |
450 | 600 | if (unlikely (c->polygon->edges == NULL)) |
451 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
452 | 600 | } |
453 | | |
454 | 20.3k | return CAIRO_STATUS_SUCCESS; |
455 | 20.3k | } |
456 | | |
457 | | static void |
458 | | mono_scan_converter_add_edge (struct mono_scan_converter *c, |
459 | | const cairo_edge_t *edge) |
460 | 320k | { |
461 | 320k | polygon_add_edge (c->polygon, edge); |
462 | 320k | } |
463 | | |
464 | | static void |
465 | | step_edges (struct mono_scan_converter *c, int count) |
466 | 0 | { |
467 | 0 | struct edge *edge; |
468 | |
|
469 | 0 | for (edge = c->head.next; edge != &c->tail; edge = edge->next) { |
470 | 0 | edge->height_left -= count; |
471 | 0 | if (! edge->height_left) { |
472 | 0 | edge->prev->next = edge->next; |
473 | 0 | edge->next->prev = edge->prev; |
474 | 0 | } |
475 | 0 | } |
476 | 0 | } |
477 | | |
478 | | static cairo_status_t |
479 | | mono_scan_converter_render(struct mono_scan_converter *c, |
480 | | unsigned int winding_mask, |
481 | | cairo_span_renderer_t *renderer) |
482 | 20.3k | { |
483 | 20.3k | struct polygon *polygon = c->polygon; |
484 | 20.3k | int i, j, h = c->ymax - c->ymin; |
485 | 20.3k | cairo_status_t status; |
486 | | |
487 | 40.6k | for (i = 0; i < h; i = j) { |
488 | 20.3k | j = i + 1; |
489 | | |
490 | 20.3k | if (polygon->y_buckets[i]) |
491 | 20.3k | active_list_merge_edges (c, polygon->y_buckets[i]); |
492 | | |
493 | 20.3k | if (c->is_vertical) { |
494 | 18.4k | int min_height; |
495 | 18.4k | struct edge *e; |
496 | | |
497 | 18.4k | e = c->head.next; |
498 | 18.4k | min_height = e->height_left; |
499 | 123k | while (e != &c->tail) { |
500 | 104k | if (e->height_left < min_height) |
501 | 0 | min_height = e->height_left; |
502 | 104k | e = e->next; |
503 | 104k | } |
504 | | |
505 | 18.4k | while (--min_height >= 1 && polygon->y_buckets[j] == NULL) |
506 | 0 | j++; |
507 | 18.4k | if (j != i + 1) |
508 | 0 | step_edges (c, j - (i + 1)); |
509 | 18.4k | } |
510 | | |
511 | 20.3k | row (c, winding_mask); |
512 | 20.3k | if (c->num_spans) { |
513 | 19.4k | status = renderer->render_rows (renderer, c->ymin+i, j-i, |
514 | 19.4k | c->spans, c->num_spans); |
515 | 19.4k | if (unlikely (status)) |
516 | 0 | return status; |
517 | 19.4k | } |
518 | | |
519 | | /* XXX recompute after dropping edges? */ |
520 | 20.3k | if (c->head.next == &c->tail) |
521 | 20.3k | c->is_vertical = 1; |
522 | 20.3k | } |
523 | | |
524 | 20.3k | return CAIRO_STATUS_SUCCESS; |
525 | 20.3k | } |
526 | | |
527 | | struct _cairo_mono_scan_converter { |
528 | | cairo_scan_converter_t base; |
529 | | |
530 | | struct mono_scan_converter converter[1]; |
531 | | cairo_fill_rule_t fill_rule; |
532 | | }; |
533 | | |
534 | | typedef struct _cairo_mono_scan_converter cairo_mono_scan_converter_t; |
535 | | |
536 | | static void |
537 | | _cairo_mono_scan_converter_destroy (void *converter) |
538 | 20.3k | { |
539 | 20.3k | cairo_mono_scan_converter_t *self = converter; |
540 | 20.3k | _mono_scan_converter_fini (self->converter); |
541 | 20.3k | free(self); |
542 | 20.3k | } |
543 | | |
544 | | cairo_status_t |
545 | | _cairo_mono_scan_converter_add_polygon (void *converter, |
546 | | const cairo_polygon_t *polygon) |
547 | 20.3k | { |
548 | 20.3k | cairo_mono_scan_converter_t *self = converter; |
549 | 20.3k | cairo_status_t status; |
550 | 20.3k | int i; |
551 | | |
552 | | #if 0 |
553 | | FILE *file = fopen ("polygon.txt", "w"); |
554 | | _cairo_debug_print_polygon (file, polygon); |
555 | | fclose (file); |
556 | | #endif |
557 | | |
558 | 20.3k | status = mono_scan_converter_allocate_edges (self->converter, |
559 | 20.3k | polygon->num_edges); |
560 | 20.3k | if (unlikely (status)) |
561 | 0 | return status; |
562 | | |
563 | 340k | for (i = 0; i < polygon->num_edges; i++) |
564 | 320k | mono_scan_converter_add_edge (self->converter, &polygon->edges[i]); |
565 | | |
566 | 20.3k | return CAIRO_STATUS_SUCCESS; |
567 | 20.3k | } |
568 | | |
569 | | static cairo_status_t |
570 | | _cairo_mono_scan_converter_generate (void *converter, |
571 | | cairo_span_renderer_t *renderer) |
572 | 20.3k | { |
573 | 20.3k | cairo_mono_scan_converter_t *self = converter; |
574 | | |
575 | 20.3k | return mono_scan_converter_render (self->converter, |
576 | 20.3k | self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1, |
577 | 20.3k | renderer); |
578 | 20.3k | } |
579 | | |
580 | | cairo_scan_converter_t * |
581 | | _cairo_mono_scan_converter_create (int xmin, |
582 | | int ymin, |
583 | | int xmax, |
584 | | int ymax, |
585 | | cairo_fill_rule_t fill_rule) |
586 | 20.3k | { |
587 | 20.3k | cairo_mono_scan_converter_t *self; |
588 | 20.3k | cairo_status_t status; |
589 | | |
590 | 20.3k | self = _cairo_malloc (sizeof(struct _cairo_mono_scan_converter)); |
591 | 20.3k | if (unlikely (self == NULL)) { |
592 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
593 | 0 | goto bail_nomem; |
594 | 0 | } |
595 | | |
596 | 20.3k | self->base.destroy = _cairo_mono_scan_converter_destroy; |
597 | 20.3k | self->base.generate = _cairo_mono_scan_converter_generate; |
598 | | |
599 | 20.3k | status = _mono_scan_converter_init (self->converter, |
600 | 20.3k | xmin, ymin, xmax, ymax); |
601 | 20.3k | if (unlikely (status)) |
602 | 0 | goto bail; |
603 | | |
604 | 20.3k | self->fill_rule = fill_rule; |
605 | | |
606 | 20.3k | return &self->base; |
607 | | |
608 | 0 | bail: |
609 | 0 | self->base.destroy(&self->base); |
610 | 0 | bail_nomem: |
611 | 0 | return _cairo_scan_converter_create_in_error (status); |
612 | 0 | } |