LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-rectangular-scan-converter.c (source / functions) Found Hit Coverage
Test: app.info Lines: 341 0 0.0 %
Date: 2012-06-02 Functions: 22 0 0.0 %

       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               0 :         } 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               0 :         } 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               0 :             } while (TRUE);
     445                 :         } else {
     446                 :             do {
     447               0 :                 UNROLL3({
     448                 :                     pos = pos->next;
     449                 :                     if (pos->left >= rectangle->left)
     450                 :                         break;
     451                 :                 });
     452               0 :             } 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                 :                 break;
     514               0 :         } 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               0 :     } 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               0 :     } 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.7