LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-rectangular-scan-converter.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 335 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13