Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2009 Intel Corporation
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it either under the terms of the GNU Lesser General Public
7 : * License version 2.1 as published by the Free Software Foundation
8 : * (the "LGPL") or, at your option, under the terms of the Mozilla
9 : * Public License Version 1.1 (the "MPL"). If you do not alter this
10 : * notice, a recipient may use your version of this file under either
11 : * the MPL or the LGPL.
12 : *
13 : * You should have received a copy of the LGPL along with this library
14 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 : * You should have received a copy of the MPL along with this library
17 : * in the file COPYING-MPL-1.1
18 : *
19 : * The contents of this file are subject to the Mozilla Public License
20 : * Version 1.1 (the "License"); you may not use this file except in
21 : * compliance with the License. You may obtain a copy of the License at
22 : * http://www.mozilla.org/MPL/
23 : *
24 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 : * the specific language governing rights and limitations.
27 : *
28 : * The Original Code is the cairo graphics library.
29 : *
30 : * Contributor(s):
31 : * Chris Wilson <chris@chris-wilson.co.uk>
32 : */
33 :
34 : #include "cairoint.h"
35 :
36 : #include "cairo-combsort-private.h"
37 : #include "cairo-error-private.h"
38 : #include "cairo-freelist-private.h"
39 : #include "cairo-list-private.h"
40 : #include "cairo-spans-private.h"
41 :
42 : #include <setjmp.h>
43 :
44 : typedef struct _rectangle {
45 : struct _rectangle *next, *prev;
46 : cairo_fixed_t left, right;
47 : cairo_fixed_t top, bottom;
48 : int32_t top_y, bottom_y;
49 : int dir;
50 : } rectangle_t;
51 :
52 : #define UNROLL3(x) x x x
53 :
54 : /* the parent is always given by index/2 */
55 : #define PQ_PARENT_INDEX(i) ((i) >> 1)
56 : #define PQ_FIRST_ENTRY 1
57 :
58 : /* left and right children are index * 2 and (index * 2) +1 respectively */
59 : #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
60 :
61 : typedef struct _pqueue {
62 : int size, max_size;
63 :
64 : rectangle_t **elements;
65 : rectangle_t *elements_embedded[1024];
66 : } pqueue_t;
67 :
68 : typedef struct {
69 : rectangle_t **start;
70 : pqueue_t stop;
71 : rectangle_t head, tail;
72 : rectangle_t *insert_cursor;
73 : int32_t current_y;
74 : int32_t xmin, xmax;
75 :
76 : struct coverage {
77 : struct cell {
78 : struct cell *prev, *next;
79 : int x, covered, uncovered;
80 : } head, tail, *cursor;
81 : unsigned int count;
82 : cairo_freepool_t pool;
83 : } coverage;
84 :
85 : cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)];
86 : cairo_half_open_span_t *spans;
87 : unsigned int num_spans;
88 : unsigned int size_spans;
89 :
90 : jmp_buf jmpbuf;
91 : } sweep_line_t;
92 :
93 : static inline int
94 0 : rectangle_compare_start (const rectangle_t *a,
95 : const rectangle_t *b)
96 : {
97 : int cmp;
98 :
99 0 : cmp = a->top_y - b->top_y;
100 0 : if (cmp)
101 0 : return cmp;
102 :
103 0 : return a->left - b->left;
104 : }
105 :
106 : static inline int
107 0 : rectangle_compare_stop (const rectangle_t *a,
108 : const rectangle_t *b)
109 : {
110 0 : return a->bottom_y - b->bottom_y;
111 : }
112 :
113 : static inline void
114 0 : pqueue_init (pqueue_t *pq)
115 : {
116 0 : pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
117 0 : pq->size = 0;
118 :
119 0 : pq->elements = pq->elements_embedded;
120 0 : pq->elements[PQ_FIRST_ENTRY] = NULL;
121 0 : }
122 :
123 : static inline void
124 0 : pqueue_fini (pqueue_t *pq)
125 : {
126 0 : if (pq->elements != pq->elements_embedded)
127 0 : free (pq->elements);
128 0 : }
129 :
130 : static cairo_bool_t
131 0 : pqueue_grow (pqueue_t *pq)
132 : {
133 : rectangle_t **new_elements;
134 0 : pq->max_size *= 2;
135 :
136 0 : if (pq->elements == pq->elements_embedded) {
137 0 : new_elements = _cairo_malloc_ab (pq->max_size,
138 : sizeof (rectangle_t *));
139 0 : if (unlikely (new_elements == NULL))
140 0 : return FALSE;
141 :
142 0 : memcpy (new_elements, pq->elements_embedded,
143 : sizeof (pq->elements_embedded));
144 : } else {
145 0 : new_elements = _cairo_realloc_ab (pq->elements,
146 : pq->max_size,
147 : sizeof (rectangle_t *));
148 0 : if (unlikely (new_elements == NULL))
149 0 : return FALSE;
150 : }
151 :
152 0 : pq->elements = new_elements;
153 0 : return TRUE;
154 : }
155 :
156 : static inline void
157 0 : pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
158 : {
159 : rectangle_t **elements;
160 : int i, parent;
161 :
162 0 : if (unlikely (sweep->stop.size + 1 == sweep->stop.max_size)) {
163 0 : if (unlikely (! pqueue_grow (&sweep->stop)))
164 0 : longjmp (sweep->jmpbuf,
165 0 : _cairo_error (CAIRO_STATUS_NO_MEMORY));
166 : }
167 :
168 0 : elements = sweep->stop.elements;
169 0 : for (i = ++sweep->stop.size;
170 0 : i != PQ_FIRST_ENTRY &&
171 0 : rectangle_compare_stop (rectangle,
172 0 : elements[parent = PQ_PARENT_INDEX (i)]) < 0;
173 0 : i = parent)
174 : {
175 0 : elements[i] = elements[parent];
176 : }
177 :
178 0 : elements[i] = rectangle;
179 0 : }
180 :
181 : static inline void
182 0 : pqueue_pop (pqueue_t *pq)
183 : {
184 0 : rectangle_t **elements = pq->elements;
185 : rectangle_t *tail;
186 : int child, i;
187 :
188 0 : tail = elements[pq->size--];
189 0 : if (pq->size == 0) {
190 0 : elements[PQ_FIRST_ENTRY] = NULL;
191 0 : return;
192 : }
193 :
194 0 : for (i = PQ_FIRST_ENTRY;
195 0 : (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
196 0 : i = child)
197 : {
198 0 : if (child != pq->size &&
199 0 : rectangle_compare_stop (elements[child+1],
200 0 : elements[child]) < 0)
201 : {
202 0 : child++;
203 : }
204 :
205 0 : if (rectangle_compare_stop (elements[child], tail) >= 0)
206 0 : break;
207 :
208 0 : elements[i] = elements[child];
209 : }
210 0 : elements[i] = tail;
211 : }
212 :
213 : static inline rectangle_t *
214 0 : peek_stop (sweep_line_t *sweep)
215 : {
216 0 : return sweep->stop.elements[PQ_FIRST_ENTRY];
217 : }
218 :
219 0 : CAIRO_COMBSORT_DECLARE (rectangle_sort, rectangle_t *, rectangle_compare_start)
220 :
221 : static void
222 0 : sweep_line_init (sweep_line_t *sweep)
223 : {
224 0 : sweep->head.left = INT_MIN;
225 0 : sweep->head.next = &sweep->tail;
226 0 : sweep->tail.left = INT_MAX;
227 0 : sweep->tail.prev = &sweep->head;
228 0 : sweep->insert_cursor = &sweep->tail;
229 :
230 0 : _cairo_freepool_init (&sweep->coverage.pool, sizeof (struct cell));
231 :
232 0 : sweep->spans = sweep->spans_stack;
233 0 : sweep->size_spans = ARRAY_LENGTH (sweep->spans_stack);
234 :
235 0 : sweep->coverage.head.prev = NULL;
236 0 : sweep->coverage.head.x = INT_MIN;
237 0 : sweep->coverage.tail.next = NULL;
238 0 : sweep->coverage.tail.x = INT_MAX;
239 :
240 0 : pqueue_init (&sweep->stop);
241 0 : }
242 :
243 : static void
244 0 : sweep_line_fini (sweep_line_t *sweep)
245 : {
246 0 : _cairo_freepool_fini (&sweep->coverage.pool);
247 0 : pqueue_fini (&sweep->stop);
248 :
249 0 : if (sweep->spans != sweep->spans_stack)
250 0 : free (sweep->spans);
251 0 : }
252 :
253 : static inline void
254 0 : add_cell (sweep_line_t *sweep, int x, int covered, int uncovered)
255 : {
256 : struct cell *cell;
257 :
258 0 : cell = sweep->coverage.cursor;
259 0 : if (cell->x > x) {
260 : do {
261 0 : UNROLL3({
262 : if (cell->prev->x < x)
263 : break;
264 : cell = cell->prev;
265 : })
266 : } while (TRUE);
267 : } else {
268 0 : if (cell->x == x)
269 0 : goto found;
270 :
271 : do {
272 0 : UNROLL3({
273 : cell = cell->next;
274 : if (cell->x >= x)
275 : break;
276 : })
277 : } while (TRUE);
278 : }
279 :
280 0 : if (x != cell->x) {
281 : struct cell *c;
282 :
283 0 : sweep->coverage.count++;
284 :
285 0 : c = _cairo_freepool_alloc (&sweep->coverage.pool);
286 0 : if (unlikely (c == NULL)) {
287 0 : longjmp (sweep->jmpbuf,
288 0 : _cairo_error (CAIRO_STATUS_NO_MEMORY));
289 : }
290 :
291 0 : cell->prev->next = c;
292 0 : c->prev = cell->prev;
293 0 : c->next = cell;
294 0 : cell->prev = c;
295 :
296 0 : c->x = x;
297 0 : c->covered = 0;
298 0 : c->uncovered = 0;
299 :
300 0 : cell = c;
301 : }
302 :
303 : found:
304 0 : cell->covered += covered;
305 0 : cell->uncovered += uncovered;
306 0 : sweep->coverage.cursor = cell;
307 0 : }
308 :
309 : static inline void
310 0 : _active_edges_to_spans (sweep_line_t *sweep)
311 : {
312 0 : int32_t y = sweep->current_y;
313 : rectangle_t *rectangle;
314 : int coverage, prev_coverage;
315 : int prev_x;
316 : struct cell *cell;
317 :
318 0 : sweep->num_spans = 0;
319 0 : if (sweep->head.next == &sweep->tail)
320 0 : return;
321 :
322 0 : sweep->coverage.head.next = &sweep->coverage.tail;
323 0 : sweep->coverage.tail.prev = &sweep->coverage.head;
324 0 : sweep->coverage.cursor = &sweep->coverage.tail;
325 0 : sweep->coverage.count = 0;
326 :
327 : /* XXX cell coverage only changes when a rectangle appears or
328 : * disappears. Try only modifying coverage at such times.
329 : */
330 0 : for (rectangle = sweep->head.next;
331 0 : rectangle != &sweep->tail;
332 0 : rectangle = rectangle->next)
333 : {
334 : int height;
335 : int frac, i;
336 :
337 0 : if (y == rectangle->bottom_y) {
338 0 : height = rectangle->bottom & CAIRO_FIXED_FRAC_MASK;
339 0 : if (height == 0)
340 0 : continue;
341 : } else
342 0 : height = CAIRO_FIXED_ONE;
343 0 : if (y == rectangle->top_y)
344 0 : height -= rectangle->top & CAIRO_FIXED_FRAC_MASK;
345 0 : height *= rectangle->dir;
346 :
347 0 : i = _cairo_fixed_integer_part (rectangle->left),
348 0 : frac = _cairo_fixed_fractional_part (rectangle->left);
349 0 : add_cell (sweep, i,
350 0 : (CAIRO_FIXED_ONE-frac) * height,
351 : frac * height);
352 :
353 0 : i = _cairo_fixed_integer_part (rectangle->right),
354 0 : frac = _cairo_fixed_fractional_part (rectangle->right);
355 0 : add_cell (sweep, i,
356 0 : -(CAIRO_FIXED_ONE-frac) * height,
357 0 : -frac * height);
358 : }
359 :
360 0 : if (2*sweep->coverage.count >= sweep->size_spans) {
361 : unsigned size;
362 :
363 0 : size = sweep->size_spans;
364 0 : while (size <= 2*sweep->coverage.count)
365 0 : size <<= 1;
366 :
367 0 : if (sweep->spans != sweep->spans_stack)
368 0 : free (sweep->spans);
369 :
370 0 : sweep->spans = _cairo_malloc_ab (size, sizeof (cairo_half_open_span_t));
371 0 : if (unlikely (sweep->spans == NULL))
372 0 : longjmp (sweep->jmpbuf, _cairo_error (CAIRO_STATUS_NO_MEMORY));
373 :
374 0 : sweep->size_spans = size;
375 : }
376 :
377 0 : prev_coverage = coverage = 0;
378 0 : prev_x = INT_MIN;
379 0 : for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) {
380 0 : if (cell->x != prev_x && coverage != prev_coverage) {
381 0 : int n = sweep->num_spans++;
382 0 : sweep->spans[n].x = prev_x;
383 0 : sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
384 0 : sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
385 0 : prev_coverage = coverage;
386 : }
387 :
388 0 : coverage += cell->covered;
389 0 : if (coverage != prev_coverage) {
390 0 : int n = sweep->num_spans++;
391 0 : sweep->spans[n].x = cell->x;
392 0 : sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
393 0 : sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
394 0 : prev_coverage = coverage;
395 : }
396 0 : coverage += cell->uncovered;
397 0 : prev_x = cell->x + 1;
398 : }
399 0 : _cairo_freepool_reset (&sweep->coverage.pool);
400 :
401 0 : if (sweep->num_spans) {
402 0 : if (prev_x <= sweep->xmax) {
403 0 : int n = sweep->num_spans++;
404 0 : sweep->spans[n].x = prev_x;
405 0 : sweep->spans[n].coverage = coverage;
406 : }
407 :
408 0 : if (coverage && prev_x < sweep->xmax) {
409 0 : int n = sweep->num_spans++;
410 0 : sweep->spans[n].x = sweep->xmax;
411 0 : sweep->spans[n].coverage = 0;
412 : }
413 : }
414 : }
415 :
416 : static inline void
417 0 : sweep_line_delete (sweep_line_t *sweep,
418 : rectangle_t *rectangle)
419 : {
420 0 : if (sweep->insert_cursor == rectangle)
421 0 : sweep->insert_cursor = rectangle->next;
422 :
423 0 : rectangle->prev->next = rectangle->next;
424 0 : rectangle->next->prev = rectangle->prev;
425 :
426 0 : pqueue_pop (&sweep->stop);
427 0 : }
428 :
429 : static inline void
430 0 : sweep_line_insert (sweep_line_t *sweep,
431 : rectangle_t *rectangle)
432 : {
433 : rectangle_t *pos;
434 :
435 0 : pos = sweep->insert_cursor;
436 0 : if (pos->left != rectangle->left) {
437 0 : if (pos->left > rectangle->left) {
438 : do {
439 0 : UNROLL3({
440 : if (pos->prev->left < rectangle->left)
441 : break;
442 : pos = pos->prev;
443 : })
444 : } while (TRUE);
445 : } else {
446 : do {
447 0 : UNROLL3({
448 : pos = pos->next;
449 : if (pos->left >= rectangle->left)
450 : break;
451 : });
452 : } while (TRUE);
453 : }
454 : }
455 :
456 0 : pos->prev->next = rectangle;
457 0 : rectangle->prev = pos->prev;
458 0 : rectangle->next = pos;
459 0 : pos->prev = rectangle;
460 0 : sweep->insert_cursor = rectangle;
461 :
462 0 : pqueue_push (sweep, rectangle);
463 0 : }
464 :
465 : static void
466 0 : render_rows (sweep_line_t *sweep_line,
467 : cairo_span_renderer_t *renderer,
468 : int height)
469 : {
470 : cairo_status_t status;
471 :
472 0 : _active_edges_to_spans (sweep_line);
473 :
474 0 : status = renderer->render_rows (renderer,
475 : sweep_line->current_y, height,
476 0 : sweep_line->spans,
477 : sweep_line->num_spans);
478 0 : if (unlikely (status))
479 0 : longjmp (sweep_line->jmpbuf, status);
480 0 : }
481 :
482 : static cairo_status_t
483 0 : generate (cairo_rectangular_scan_converter_t *self,
484 : cairo_span_renderer_t *renderer,
485 : rectangle_t **rectangles)
486 : {
487 : sweep_line_t sweep_line;
488 : rectangle_t *start, *stop;
489 : cairo_status_t status;
490 :
491 0 : sweep_line_init (&sweep_line);
492 0 : sweep_line.xmin = self->xmin;
493 0 : sweep_line.xmax = self->xmax;
494 0 : sweep_line.start = rectangles;
495 0 : if ((status = setjmp (sweep_line.jmpbuf)))
496 0 : goto BAIL;
497 :
498 0 : sweep_line.current_y = self->ymin;
499 0 : start = *sweep_line.start++;
500 : do {
501 0 : if (start->top_y != sweep_line.current_y) {
502 0 : render_rows (&sweep_line, renderer,
503 0 : start->top_y - sweep_line.current_y);
504 0 : sweep_line.current_y = start->top_y;
505 : }
506 :
507 : do {
508 0 : sweep_line_insert (&sweep_line, start);
509 0 : start = *sweep_line.start++;
510 0 : if (start == NULL)
511 0 : goto end;
512 0 : if (start->top_y != sweep_line.current_y)
513 0 : break;
514 : } while (TRUE);
515 :
516 0 : render_rows (&sweep_line, renderer, 1);
517 :
518 0 : stop = peek_stop (&sweep_line);
519 0 : while (stop->bottom_y == sweep_line.current_y) {
520 0 : sweep_line_delete (&sweep_line, stop);
521 0 : stop = peek_stop (&sweep_line);
522 0 : if (stop == NULL)
523 0 : break;
524 : }
525 :
526 0 : sweep_line.current_y++;
527 :
528 0 : while (stop != NULL && stop->bottom_y < start->top_y) {
529 0 : if (stop->bottom_y != sweep_line.current_y) {
530 0 : render_rows (&sweep_line, renderer,
531 0 : stop->bottom_y - sweep_line.current_y);
532 0 : sweep_line.current_y = stop->bottom_y;
533 : }
534 :
535 0 : render_rows (&sweep_line, renderer, 1);
536 :
537 : do {
538 0 : sweep_line_delete (&sweep_line, stop);
539 0 : stop = peek_stop (&sweep_line);
540 0 : } while (stop != NULL && stop->bottom_y == sweep_line.current_y);
541 :
542 0 : sweep_line.current_y++;
543 : }
544 : } while (TRUE);
545 :
546 : end:
547 0 : render_rows (&sweep_line, renderer, 1);
548 :
549 0 : stop = peek_stop (&sweep_line);
550 0 : while (stop->bottom_y == sweep_line.current_y) {
551 0 : sweep_line_delete (&sweep_line, stop);
552 0 : stop = peek_stop (&sweep_line);
553 0 : if (stop == NULL)
554 0 : goto out;
555 : }
556 :
557 0 : sweep_line.current_y++;
558 :
559 : do {
560 0 : if (stop->bottom_y != sweep_line.current_y) {
561 0 : render_rows (&sweep_line, renderer,
562 0 : stop->bottom_y - sweep_line.current_y);
563 0 : sweep_line.current_y = stop->bottom_y;
564 : }
565 :
566 0 : render_rows (&sweep_line, renderer, 1);
567 :
568 : do {
569 0 : sweep_line_delete (&sweep_line, stop);
570 0 : stop = peek_stop (&sweep_line);
571 0 : if (stop == NULL)
572 0 : goto out;
573 0 : } while (stop->bottom_y == sweep_line.current_y);
574 :
575 0 : sweep_line.current_y++;
576 : } while (TRUE);
577 :
578 : out:
579 0 : status = renderer->render_rows (renderer,
580 : sweep_line.current_y,
581 0 : self->ymax - sweep_line.current_y,
582 : NULL, 0);
583 :
584 : BAIL:
585 0 : sweep_line_fini (&sweep_line);
586 :
587 0 : return status;
588 : }
589 :
590 : static cairo_status_t
591 0 : _cairo_rectangular_scan_converter_generate (void *converter,
592 : cairo_span_renderer_t *renderer)
593 : {
594 0 : cairo_rectangular_scan_converter_t *self = converter;
595 : rectangle_t *rectangles_stack[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *)];
596 : rectangle_t **rectangles;
597 : struct _cairo_rectangular_scan_converter_chunk *chunk;
598 : cairo_status_t status;
599 : int i, j;
600 :
601 0 : if (unlikely (self->num_rectangles == 0)) {
602 0 : return renderer->render_rows (renderer,
603 0 : self->ymin, self->ymax - self->ymin,
604 : NULL, 0);
605 : }
606 :
607 0 : rectangles = rectangles_stack;
608 0 : if (unlikely (self->num_rectangles >= ARRAY_LENGTH (rectangles_stack))) {
609 0 : rectangles = _cairo_malloc_ab (self->num_rectangles + 1,
610 : sizeof (rectangle_t *));
611 0 : if (unlikely (rectangles == NULL))
612 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
613 : }
614 :
615 0 : j = 0;
616 0 : for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) {
617 : rectangle_t *rectangle;
618 :
619 0 : rectangle = chunk->base;
620 0 : for (i = 0; i < chunk->count; i++)
621 0 : rectangles[j++] = &rectangle[i];
622 : }
623 0 : rectangle_sort (rectangles, j);
624 0 : rectangles[j] = NULL;
625 :
626 0 : status = generate (self, renderer, rectangles);
627 :
628 0 : if (rectangles != rectangles_stack)
629 0 : free (rectangles);
630 :
631 0 : return status;
632 : }
633 :
634 : static rectangle_t *
635 0 : _allocate_rectangle (cairo_rectangular_scan_converter_t *self)
636 : {
637 : rectangle_t *rectangle;
638 : struct _cairo_rectangular_scan_converter_chunk *chunk;
639 :
640 0 : chunk = self->tail;
641 0 : if (chunk->count == chunk->size) {
642 : int size;
643 :
644 0 : size = chunk->size * 2;
645 0 : chunk->next = _cairo_malloc_ab_plus_c (size,
646 : sizeof (rectangle_t),
647 : sizeof (struct _cairo_rectangular_scan_converter_chunk));
648 :
649 0 : if (unlikely (chunk->next == NULL))
650 0 : return NULL;
651 :
652 0 : chunk = chunk->next;
653 0 : chunk->next = NULL;
654 0 : chunk->count = 0;
655 0 : chunk->size = size;
656 0 : chunk->base = chunk + 1;
657 0 : self->tail = chunk;
658 : }
659 :
660 0 : rectangle = chunk->base;
661 0 : return rectangle + chunk->count++;
662 : }
663 :
664 : cairo_status_t
665 0 : _cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self,
666 : const cairo_box_t *box,
667 : int dir)
668 : {
669 : rectangle_t *rectangle;
670 :
671 0 : rectangle = _allocate_rectangle (self);
672 0 : if (unlikely (rectangle == NULL))
673 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
674 :
675 0 : rectangle->left = box->p1.x;
676 0 : rectangle->right = box->p2.x;
677 0 : rectangle->dir = dir;
678 :
679 0 : rectangle->top = box->p1.y;
680 0 : rectangle->top_y = _cairo_fixed_integer_floor (box->p1.y);
681 0 : rectangle->bottom = box->p2.y;
682 0 : rectangle->bottom_y = _cairo_fixed_integer_floor (box->p2.y);
683 0 : assert (rectangle->bottom_y >= rectangle->top_y);
684 :
685 0 : self->num_rectangles++;
686 :
687 0 : return CAIRO_STATUS_SUCCESS;
688 : }
689 :
690 : static void
691 0 : _cairo_rectangular_scan_converter_destroy (void *converter)
692 : {
693 0 : cairo_rectangular_scan_converter_t *self = converter;
694 : struct _cairo_rectangular_scan_converter_chunk *chunk, *next;
695 :
696 0 : for (chunk = self->chunks.next; chunk != NULL; chunk = next) {
697 0 : next = chunk->next;
698 0 : free (chunk);
699 : }
700 0 : }
701 :
702 : void
703 0 : _cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self,
704 : const cairo_rectangle_int_t *extents)
705 : {
706 0 : self->base.destroy = _cairo_rectangular_scan_converter_destroy;
707 0 : self->base.add_edge = NULL;
708 0 : self->base.add_polygon = NULL;
709 0 : self->base.generate = _cairo_rectangular_scan_converter_generate;
710 :
711 0 : self->xmin = extents->x;
712 0 : self->xmax = extents->x + extents->width;
713 0 : self->ymin = extents->y;
714 0 : self->ymax = extents->y + extents->height;
715 :
716 0 : self->chunks.base = self->buf;
717 0 : self->chunks.next = NULL;
718 0 : self->chunks.count = 0;
719 0 : self->chunks.size = sizeof (self->buf) / sizeof (rectangle_t);
720 0 : self->tail = &self->chunks;
721 :
722 0 : self->num_rectangles = 0;
723 0 : }
|