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

       1                 : /*
       2                 :  * Copyright © 2004 Carl Worth
       3                 :  * Copyright © 2006 Red Hat, Inc.
       4                 :  * Copyright © 2009 Chris Wilson
       5                 :  *
       6                 :  * This library is free software; you can redistribute it and/or
       7                 :  * modify it either under the terms of the GNU Lesser General Public
       8                 :  * License version 2.1 as published by the Free Software Foundation
       9                 :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      10                 :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      11                 :  * notice, a recipient may use your version of this file under either
      12                 :  * the MPL or the LGPL.
      13                 :  *
      14                 :  * You should have received a copy of the LGPL along with this library
      15                 :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      16                 :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      17                 :  * You should have received a copy of the MPL along with this library
      18                 :  * in the file COPYING-MPL-1.1
      19                 :  *
      20                 :  * The contents of this file are subject to the Mozilla Public License
      21                 :  * Version 1.1 (the "License"); you may not use this file except in
      22                 :  * compliance with the License. You may obtain a copy of the License at
      23                 :  * http://www.mozilla.org/MPL/
      24                 :  *
      25                 :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      26                 :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      27                 :  * the specific language governing rights and limitations.
      28                 :  *
      29                 :  * The Original Code is the cairo graphics library.
      30                 :  *
      31                 :  * The Initial Developer of the Original Code is Carl Worth
      32                 :  *
      33                 :  * Contributor(s):
      34                 :  *      Carl D. Worth <cworth@cworth.org>
      35                 :  *      Chris Wilson <chris@chris-wilson.co.uk>
      36                 :  */
      37                 : 
      38                 : /* Provide definitions for standalone compilation */
      39                 : #include "cairoint.h"
      40                 : 
      41                 : #include "cairo-boxes-private.h"
      42                 : #include "cairo-error-private.h"
      43                 : #include "cairo-combsort-private.h"
      44                 : #include "cairo-list-private.h"
      45                 : 
      46                 : #include <setjmp.h>
      47                 : 
      48                 : typedef struct _rectangle rectangle_t;
      49                 : typedef struct _edge edge_t;
      50                 : 
      51                 : struct _edge {
      52                 :     edge_t *next, *prev;
      53                 :     edge_t *right;
      54                 :     cairo_fixed_t x, top;
      55                 :     int dir;
      56                 : };
      57                 : 
      58                 : struct _rectangle {
      59                 :     edge_t left, right;
      60                 :     int32_t top, bottom;
      61                 : };
      62                 : 
      63                 : #define UNROLL3(x) x x x
      64                 : 
      65                 : /* the parent is always given by index/2 */
      66                 : #define PQ_PARENT_INDEX(i) ((i) >> 1)
      67                 : #define PQ_FIRST_ENTRY 1
      68                 : 
      69                 : /* left and right children are index * 2 and (index * 2) +1 respectively */
      70                 : #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
      71                 : 
      72                 : typedef struct _pqueue {
      73                 :     int size, max_size;
      74                 : 
      75                 :     rectangle_t **elements;
      76                 :     rectangle_t *elements_embedded[1024];
      77                 : } pqueue_t;
      78                 : 
      79                 : typedef struct _sweep_line {
      80                 :     rectangle_t **rectangles;
      81                 :     pqueue_t pq;
      82                 :     edge_t head, tail;
      83                 :     edge_t *insert_left, *insert_right;
      84                 :     int32_t current_y;
      85                 :     int32_t last_y;
      86                 : 
      87                 :     cairo_fill_rule_t fill_rule;
      88                 : 
      89                 :     jmp_buf unwind;
      90                 : } sweep_line_t;
      91                 : 
      92                 : #define DEBUG_TRAPS 0
      93                 : 
      94                 : #if DEBUG_TRAPS
      95                 : static void
      96                 : dump_traps (cairo_traps_t *traps, const char *filename)
      97                 : {
      98                 :     FILE *file;
      99                 :     int n;
     100                 : 
     101                 :     if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
     102                 :         return;
     103                 : 
     104                 :     file = fopen (filename, "a");
     105                 :     if (file != NULL) {
     106                 :         for (n = 0; n < traps->num_traps; n++) {
     107                 :             fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
     108                 :                      traps->traps[n].top,
     109                 :                      traps->traps[n].bottom,
     110                 :                      traps->traps[n].left.p1.x,
     111                 :                      traps->traps[n].left.p1.y,
     112                 :                      traps->traps[n].left.p2.x,
     113                 :                      traps->traps[n].left.p2.y,
     114                 :                      traps->traps[n].right.p1.x,
     115                 :                      traps->traps[n].right.p1.y,
     116                 :                      traps->traps[n].right.p2.x,
     117                 :                      traps->traps[n].right.p2.y);
     118                 :         }
     119                 :         fprintf (file, "\n");
     120                 :         fclose (file);
     121                 :     }
     122                 : }
     123                 : #else
     124                 : #define dump_traps(traps, filename)
     125                 : #endif
     126                 : 
     127                 : static inline int
     128               0 : rectangle_compare_start (const rectangle_t *a,
     129                 :                          const rectangle_t *b)
     130                 : {
     131               0 :     return a->top - b->top;
     132                 : }
     133                 : 
     134                 : static inline int
     135               0 : rectangle_compare_stop (const rectangle_t *a,
     136                 :                          const rectangle_t *b)
     137                 : {
     138               0 :     return a->bottom - b->bottom;
     139                 : }
     140                 : 
     141                 : static inline void
     142               0 : pqueue_init (pqueue_t *pq)
     143                 : {
     144               0 :     pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
     145               0 :     pq->size = 0;
     146                 : 
     147               0 :     pq->elements = pq->elements_embedded;
     148               0 :     pq->elements[PQ_FIRST_ENTRY] = NULL;
     149               0 : }
     150                 : 
     151                 : static inline void
     152               0 : pqueue_fini (pqueue_t *pq)
     153                 : {
     154               0 :     if (pq->elements != pq->elements_embedded)
     155               0 :         free (pq->elements);
     156               0 : }
     157                 : 
     158                 : static cairo_bool_t
     159               0 : pqueue_grow (pqueue_t *pq)
     160                 : {
     161                 :     rectangle_t **new_elements;
     162               0 :     pq->max_size *= 2;
     163                 : 
     164               0 :     if (pq->elements == pq->elements_embedded) {
     165               0 :         new_elements = _cairo_malloc_ab (pq->max_size,
     166                 :                                          sizeof (rectangle_t *));
     167               0 :         if (unlikely (new_elements == NULL))
     168               0 :             return FALSE;
     169                 : 
     170               0 :         memcpy (new_elements, pq->elements_embedded,
     171                 :                 sizeof (pq->elements_embedded));
     172                 :     } else {
     173               0 :         new_elements = _cairo_realloc_ab (pq->elements,
     174                 :                                           pq->max_size,
     175                 :                                           sizeof (rectangle_t *));
     176               0 :         if (unlikely (new_elements == NULL))
     177               0 :             return FALSE;
     178                 :     }
     179                 : 
     180               0 :     pq->elements = new_elements;
     181               0 :     return TRUE;
     182                 : }
     183                 : 
     184                 : static inline void
     185               0 : pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
     186                 : {
     187                 :     rectangle_t **elements;
     188                 :     int i, parent;
     189                 : 
     190               0 :     if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) {
     191               0 :         if (unlikely (! pqueue_grow (&sweep->pq))) {
     192               0 :             longjmp (sweep->unwind,
     193               0 :                      _cairo_error (CAIRO_STATUS_NO_MEMORY));
     194                 :         }
     195                 :     }
     196                 : 
     197               0 :     elements = sweep->pq.elements;
     198               0 :     for (i = ++sweep->pq.size;
     199               0 :          i != PQ_FIRST_ENTRY &&
     200               0 :          rectangle_compare_stop (rectangle,
     201               0 :                                  elements[parent = PQ_PARENT_INDEX (i)]) < 0;
     202               0 :          i = parent)
     203                 :     {
     204               0 :         elements[i] = elements[parent];
     205                 :     }
     206                 : 
     207               0 :     elements[i] = rectangle;
     208               0 : }
     209                 : 
     210                 : static inline void
     211               0 : pqueue_pop (pqueue_t *pq)
     212                 : {
     213               0 :     rectangle_t **elements = pq->elements;
     214                 :     rectangle_t *tail;
     215                 :     int child, i;
     216                 : 
     217               0 :     tail = elements[pq->size--];
     218               0 :     if (pq->size == 0) {
     219               0 :         elements[PQ_FIRST_ENTRY] = NULL;
     220               0 :         return;
     221                 :     }
     222                 : 
     223               0 :     for (i = PQ_FIRST_ENTRY;
     224               0 :          (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
     225               0 :          i = child)
     226                 :     {
     227               0 :         if (child != pq->size &&
     228               0 :             rectangle_compare_stop (elements[child+1],
     229               0 :                                     elements[child]) < 0)
     230                 :         {
     231               0 :             child++;
     232                 :         }
     233                 : 
     234               0 :         if (rectangle_compare_stop (elements[child], tail) >= 0)
     235               0 :             break;
     236                 : 
     237               0 :         elements[i] = elements[child];
     238                 :     }
     239               0 :     elements[i] = tail;
     240                 : }
     241                 : 
     242                 : static inline rectangle_t *
     243               0 : rectangle_pop_start (sweep_line_t *sweep_line)
     244                 : {
     245               0 :     return *sweep_line->rectangles++;
     246                 : }
     247                 : 
     248                 : static inline rectangle_t *
     249               0 : rectangle_peek_stop (sweep_line_t *sweep_line)
     250                 : {
     251               0 :     return sweep_line->pq.elements[PQ_FIRST_ENTRY];
     252                 : }
     253                 : 
     254               0 : CAIRO_COMBSORT_DECLARE (_rectangle_sort,
     255                 :                         rectangle_t *,
     256                 :                         rectangle_compare_start)
     257                 : 
     258                 : static void
     259               0 : sweep_line_init (sweep_line_t    *sweep_line,
     260                 :                  rectangle_t    **rectangles,
     261                 :                  int              num_rectangles,
     262                 :                  cairo_fill_rule_t fill_rule)
     263                 : {
     264               0 :     _rectangle_sort (rectangles, num_rectangles);
     265               0 :     rectangles[num_rectangles] = NULL;
     266               0 :     sweep_line->rectangles = rectangles;
     267                 : 
     268               0 :     sweep_line->head.x = INT32_MIN;
     269               0 :     sweep_line->head.right = NULL;
     270               0 :     sweep_line->head.dir = 0;
     271               0 :     sweep_line->head.next = &sweep_line->tail;
     272                 :     /* we need to initialize prev so that we can check
     273                 :      * if this edge is the left most and make sure
     274                 :      * we always insert to the right of it, even if
     275                 :      * our x coordinate matches */
     276               0 :     sweep_line->head.prev = NULL;
     277                 : 
     278               0 :     sweep_line->tail.x = INT32_MAX;
     279               0 :     sweep_line->tail.right = NULL;
     280               0 :     sweep_line->tail.dir = 0;
     281               0 :     sweep_line->tail.prev = &sweep_line->head;
     282               0 :     sweep_line->tail.next = NULL;
     283                 : 
     284               0 :     sweep_line->insert_left = &sweep_line->tail;
     285               0 :     sweep_line->insert_right = &sweep_line->tail;
     286                 : 
     287               0 :     sweep_line->current_y = INT32_MIN;
     288               0 :     sweep_line->last_y = INT32_MIN;
     289                 : 
     290               0 :     sweep_line->fill_rule = fill_rule;
     291                 : 
     292               0 :     pqueue_init (&sweep_line->pq);
     293               0 : }
     294                 : 
     295                 : static void
     296               0 : sweep_line_fini (sweep_line_t *sweep_line)
     297                 : {
     298               0 :     pqueue_fini (&sweep_line->pq);
     299               0 : }
     300                 : 
     301                 : static void
     302               0 : edge_end_box (sweep_line_t *sweep_line,
     303                 :               edge_t    *left,
     304                 :               int32_t            bot,
     305                 :               cairo_bool_t       do_traps,
     306                 :               void              *container)
     307                 : {
     308               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     309                 : 
     310                 :     /* Only emit (trivial) non-degenerate trapezoids with positive height. */
     311               0 :     if (likely (left->top < bot)) {
     312               0 :         if (do_traps) {
     313               0 :             cairo_line_t _left = {
     314               0 :                 { left->x, left->top },
     315               0 :                 { left->x, bot },
     316               0 :             }, _right = {
     317               0 :                 { left->right->x, left->top },
     318               0 :                 { left->right->x, bot },
     319                 :             };
     320               0 :             _cairo_traps_add_trap (container, left->top, bot, &_left, &_right);
     321               0 :             status = _cairo_traps_status ((cairo_traps_t *) container);
     322                 :         } else {
     323                 :             cairo_box_t box;
     324                 : 
     325               0 :             box.p1.x = left->x;
     326               0 :             box.p1.y = left->top;
     327               0 :             box.p2.x = left->right->x;
     328               0 :             box.p2.y = bot;
     329                 : 
     330               0 :             status = _cairo_boxes_add (container, &box);
     331                 :         }
     332                 :     }
     333               0 :     if (unlikely (status))
     334               0 :         longjmp (sweep_line->unwind, status);
     335                 : 
     336               0 :     left->right = NULL;
     337               0 : }
     338                 : 
     339                 : /* Start a new trapezoid at the given top y coordinate, whose edges
     340                 :  * are `edge' and `edge->next'. If `edge' already has a trapezoid,
     341                 :  * then either add it to the traps in `traps', if the trapezoid's
     342                 :  * right edge differs from `edge->next', or do nothing if the new
     343                 :  * trapezoid would be a continuation of the existing one. */
     344                 : static inline void
     345               0 : edge_start_or_continue_box (sweep_line_t *sweep_line,
     346                 :                             edge_t      *left,
     347                 :                             edge_t      *right,
     348                 :                             int          top,
     349                 :                             cairo_bool_t         do_traps,
     350                 :                             void                *container)
     351                 : {
     352               0 :     if (left->right == right)
     353               0 :         return;
     354                 : 
     355               0 :     if (left->right != NULL) {
     356               0 :         if (right != NULL && left->right->x == right->x) {
     357                 :             /* continuation on right, so just swap edges */
     358               0 :             left->right = right;
     359               0 :             return;
     360                 :         }
     361                 : 
     362               0 :         edge_end_box (sweep_line,
     363                 :                       left, top, do_traps, container);
     364                 :     }
     365                 : 
     366               0 :     if (right != NULL && left->x != right->x) {
     367               0 :         left->top = top;
     368               0 :         left->right = right;
     369                 :     }
     370                 : }
     371                 : 
     372                 : static inline void
     373               0 : active_edges_to_traps (sweep_line_t     *sweep,
     374                 :                        cairo_bool_t      do_traps,
     375                 :                        void             *container)
     376                 : {
     377               0 :     int top = sweep->current_y;
     378                 :     edge_t *pos;
     379                 : 
     380               0 :     if (sweep->last_y == sweep->current_y)
     381               0 :         return;
     382                 : 
     383               0 :     pos = sweep->head.next;
     384               0 :     if (pos == &sweep->tail)
     385               0 :         return;
     386                 : 
     387               0 :     if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING) {
     388                 :         do {
     389                 :             edge_t *left, *right;
     390                 :             int winding;
     391                 : 
     392               0 :             left = pos;
     393               0 :             winding = left->dir;
     394                 : 
     395               0 :             right = left->next;
     396                 : 
     397                 :             /* Check if there is a co-linear edge with an existing trap */
     398               0 :             if (left->right == NULL) {
     399               0 :                 while (unlikely (right->x == left->x)) {
     400               0 :                     winding += right->dir;
     401               0 :                     if (right->right != NULL) {
     402                 :                         /* continuation on left */
     403               0 :                         left->top = right->top;
     404               0 :                         left->right = right->right;
     405               0 :                         right->right = NULL;
     406               0 :                         winding -= right->dir;
     407               0 :                         break;
     408                 :                     }
     409                 : 
     410               0 :                     right = right->next;
     411                 :                 }
     412                 : 
     413               0 :                 if (winding == 0) {
     414               0 :                     pos = right;
     415               0 :                     continue;
     416                 :                 }
     417                 :             }
     418                 : 
     419                 :             /* Greedily search for the closing edge, so that we generate the
     420                 :              * maximal span width with the minimal number of trapezoids.
     421                 :              */
     422                 : 
     423                 :             do {
     424                 :                 /* End all subsumed traps */
     425               0 :                 if (unlikely (right->right != NULL)) {
     426               0 :                     edge_end_box (sweep,
     427                 :                                   right, top, do_traps, container);
     428                 :                 }
     429                 : 
     430               0 :                 winding += right->dir;
     431               0 :                 if (winding == 0) {
     432                 :                     /* skip co-linear edges */
     433               0 :                     if (likely (right->x != right->next->x))
     434                 :                         break;
     435                 :                 }
     436                 : 
     437               0 :                 right = right->next;
     438               0 :             } while (TRUE);
     439                 : 
     440               0 :             edge_start_or_continue_box (sweep,
     441                 :                                         left, right, top,
     442                 :                                         do_traps, container);
     443                 : 
     444               0 :             pos = right->next;
     445               0 :         } while (pos != &sweep->tail);
     446                 :     } else {
     447                 :         do {
     448               0 :             edge_t *right = pos->next;
     449               0 :             int count = 0;
     450                 : 
     451                 :             do {
     452                 :                 /* End all subsumed traps */
     453               0 :                 if (unlikely (right->right != NULL)) {
     454               0 :                     edge_end_box (sweep,
     455                 :                                   right, top, do_traps, container);
     456                 :                 }
     457                 : 
     458               0 :                 if (++count & 1) {
     459                 :                     /* skip co-linear edges */
     460               0 :                     if (likely (right->x != right->next->x))
     461                 :                         break;
     462                 :                 }
     463                 : 
     464               0 :                 right = right->next;
     465               0 :             } while (TRUE);
     466                 : 
     467               0 :             edge_start_or_continue_box (sweep,
     468                 :                                         pos, right, top,
     469                 :                                         do_traps, container);
     470                 : 
     471               0 :             pos = right->next;
     472               0 :         } while (pos != &sweep->tail);
     473                 :     }
     474                 : 
     475               0 :     sweep->last_y = sweep->current_y;
     476                 : }
     477                 : 
     478                 : static inline void
     479               0 : sweep_line_delete_edge (sweep_line_t *sweep_line,
     480                 :                         edge_t *edge,
     481                 :                         cairo_bool_t do_traps,
     482                 :                         void *container)
     483                 : {
     484               0 :     if (edge->right != NULL) {
     485               0 :         edge_t *next = edge->next;
     486               0 :         if (next->x == edge->x) {
     487               0 :             next->top = edge->top;
     488               0 :             next->right = edge->right;
     489                 :         } else {
     490               0 :             edge_end_box (sweep_line,
     491                 :                           edge,
     492                 :                           sweep_line->current_y,
     493                 :                           do_traps, container);
     494                 :         }
     495                 :     }
     496                 : 
     497               0 :     if (sweep_line->insert_left == edge)
     498               0 :         sweep_line->insert_left = edge->next;
     499               0 :     if (sweep_line->insert_right == edge)
     500               0 :         sweep_line->insert_right = edge->next;
     501                 : 
     502               0 :     edge->prev->next = edge->next;
     503               0 :     edge->next->prev = edge->prev;
     504               0 : }
     505                 : 
     506                 : static inline cairo_bool_t
     507               0 : sweep_line_delete (sweep_line_t *sweep,
     508                 :                    rectangle_t  *rectangle,
     509                 :                    cairo_bool_t          do_traps,
     510                 :                    void                 *container)
     511                 : {
     512                 :     cairo_bool_t update;
     513                 : 
     514               0 :     update = TRUE;
     515               0 :     if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
     516               0 :         rectangle->left.prev->dir == rectangle->left.dir)
     517                 :     {
     518               0 :         update = rectangle->left.next != &rectangle->right;
     519                 :     }
     520                 : 
     521               0 :     sweep_line_delete_edge (sweep,
     522                 :                             &rectangle->left,
     523                 :                             do_traps, container);
     524                 : 
     525               0 :     sweep_line_delete_edge (sweep,
     526                 :                             &rectangle->right,
     527                 :                             do_traps, container);
     528                 : 
     529               0 :     pqueue_pop (&sweep->pq);
     530               0 :     return update;
     531                 : }
     532                 : 
     533                 : static inline void
     534               0 : insert_edge (edge_t *edge, edge_t *pos)
     535                 : {
     536               0 :     if (pos->x != edge->x) {
     537               0 :         if (pos->x > edge->x) {
     538                 :             do {
     539               0 :                 UNROLL3({
     540                 :                     if (pos->prev->x <= edge->x)
     541                 :                         break;
     542                 :                     pos = pos->prev;
     543                 :                 })
     544               0 :             } while (TRUE);
     545                 :         } else {
     546                 :             do {
     547               0 :                 UNROLL3({
     548                 :                     pos = pos->next;
     549                 :                     if (pos->x >= edge->x)
     550                 :                         break;
     551                 :                 })
     552               0 :             } while (TRUE);
     553                 :         }
     554                 :     }
     555               0 :     if (pos->prev) {
     556               0 :         pos->prev->next = edge;
     557               0 :         edge->prev = pos->prev;
     558               0 :         edge->next = pos;
     559               0 :         pos->prev = edge;
     560                 :     } else {
     561                 :         /* we have edge that shares an x coordinate with the left most sentinal.
     562                 :          * instead of inserting before pos and ruining our sentinal we insert after pos. */
     563               0 :         pos->next->prev = edge;
     564               0 :         edge->next = pos->next;
     565               0 :         edge->prev = pos;
     566               0 :         pos->next = edge;
     567                 :     }
     568               0 : }
     569                 : 
     570                 : static inline cairo_bool_t
     571               0 : sweep_line_insert (sweep_line_t *sweep,
     572                 :                    rectangle_t  *rectangle)
     573                 : {
     574                 :     edge_t *pos;
     575                 : 
     576                 :     /* right edge */
     577               0 :     pos = sweep->insert_right;
     578               0 :     insert_edge (&rectangle->right, pos);
     579               0 :     sweep->insert_right = &rectangle->right;
     580                 : 
     581                 :     /* left edge */
     582               0 :     pos = sweep->insert_left;
     583               0 :     if (pos->x > sweep->insert_right->x)
     584               0 :         pos = sweep->insert_right->prev;
     585               0 :     insert_edge (&rectangle->left, pos);
     586               0 :     sweep->insert_left = &rectangle->left;
     587                 : 
     588               0 :     pqueue_push (sweep, rectangle);
     589                 : 
     590               0 :     if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
     591               0 :         rectangle->left.prev->dir == rectangle->left.dir)
     592                 :     {
     593               0 :         return rectangle->left.next != &rectangle->right;
     594                 :     }
     595                 : 
     596               0 :     return TRUE;
     597                 : }
     598                 : 
     599                 : static cairo_status_t
     600               0 : _cairo_bentley_ottmann_tessellate_rectangular (rectangle_t      **rectangles,
     601                 :                                                int                        num_rectangles,
     602                 :                                                cairo_fill_rule_t          fill_rule,
     603                 :                                                cairo_bool_t              do_traps,
     604                 :                                                void                     *container)
     605                 : {
     606                 :     sweep_line_t sweep_line;
     607                 :     rectangle_t *rectangle;
     608                 :     cairo_status_t status;
     609               0 :     cairo_bool_t update = FALSE;
     610                 : 
     611               0 :     sweep_line_init (&sweep_line, rectangles, num_rectangles, fill_rule);
     612               0 :     if ((status = setjmp (sweep_line.unwind)))
     613               0 :         goto unwind;
     614                 : 
     615               0 :     rectangle = rectangle_pop_start (&sweep_line);
     616                 :     do {
     617               0 :         if (rectangle->top != sweep_line.current_y) {
     618                 :             rectangle_t *stop;
     619                 : 
     620               0 :             stop = rectangle_peek_stop (&sweep_line);
     621               0 :             while (stop != NULL && stop->bottom < rectangle->top) {
     622               0 :                 if (stop->bottom != sweep_line.current_y) {
     623               0 :                     if (update) {
     624               0 :                         active_edges_to_traps (&sweep_line,
     625                 :                                                do_traps, container);
     626               0 :                         update = FALSE;
     627                 :                     }
     628                 : 
     629               0 :                     sweep_line.current_y = stop->bottom;
     630                 :                 }
     631                 : 
     632               0 :                 update |= sweep_line_delete (&sweep_line, stop, do_traps, container);
     633                 : 
     634               0 :                 stop = rectangle_peek_stop (&sweep_line);
     635                 :             }
     636                 : 
     637               0 :             if (update) {
     638               0 :                 active_edges_to_traps (&sweep_line, do_traps, container);
     639               0 :                 update = FALSE;
     640                 :             }
     641                 : 
     642               0 :             sweep_line.current_y = rectangle->top;
     643                 :         }
     644                 : 
     645               0 :         update |= sweep_line_insert (&sweep_line, rectangle);
     646               0 :     } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL);
     647                 : 
     648               0 :     while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) {
     649               0 :         if (rectangle->bottom != sweep_line.current_y) {
     650               0 :             if (update) {
     651               0 :                 active_edges_to_traps (&sweep_line, do_traps, container);
     652               0 :                 update = FALSE;
     653                 :             }
     654                 : 
     655               0 :             sweep_line.current_y = rectangle->bottom;
     656                 :         }
     657                 : 
     658               0 :         update |= sweep_line_delete (&sweep_line, rectangle, do_traps, container);
     659                 :     }
     660                 : 
     661                 : unwind:
     662               0 :     sweep_line_fini (&sweep_line);
     663               0 :     return status;
     664                 : }
     665                 : 
     666                 : cairo_status_t
     667               0 : _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
     668                 :                                                      cairo_fill_rule_t fill_rule)
     669                 : {
     670                 :     rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
     671                 :     rectangle_t *rectangles;
     672                 :     rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
     673                 :     rectangle_t **rectangles_ptrs;
     674                 :     cairo_status_t status;
     675                 :     int i;
     676                 : 
     677               0 :     if (unlikely (traps->num_traps <= 1))
     678               0 :         return CAIRO_STATUS_SUCCESS;
     679                 : 
     680               0 :     assert (traps->is_rectangular);
     681                 : 
     682                 :     dump_traps (traps, "bo-rects-traps-in.txt");
     683                 : 
     684               0 :     rectangles = stack_rectangles;
     685               0 :     rectangles_ptrs = stack_rectangles_ptrs;
     686               0 :     if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) {
     687               0 :         rectangles = _cairo_malloc_ab_plus_c (traps->num_traps,
     688                 :                                           sizeof (rectangle_t) +
     689                 :                                           sizeof (rectangle_t *),
     690                 :                                           sizeof (rectangle_t *));
     691               0 :         if (unlikely (rectangles == NULL))
     692               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     693                 : 
     694               0 :         rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps);
     695                 :     }
     696                 : 
     697               0 :     for (i = 0; i < traps->num_traps; i++) {
     698               0 :         if (traps->traps[i].left.p1.x < traps->traps[i].right.p1.x) {
     699               0 :             rectangles[i].left.x = traps->traps[i].left.p1.x;
     700               0 :             rectangles[i].left.dir = 1;
     701                 : 
     702               0 :             rectangles[i].right.x = traps->traps[i].right.p1.x;
     703               0 :             rectangles[i].right.dir = -1;
     704                 :         } else {
     705               0 :             rectangles[i].right.x = traps->traps[i].left.p1.x;
     706               0 :             rectangles[i].right.dir = 1;
     707                 : 
     708               0 :             rectangles[i].left.x = traps->traps[i].right.p1.x;
     709               0 :             rectangles[i].left.dir = -1;
     710                 :         }
     711                 : 
     712               0 :         rectangles[i].left.right = NULL;
     713               0 :         rectangles[i].right.right = NULL;
     714                 : 
     715               0 :         rectangles[i].top = traps->traps[i].top;
     716               0 :         rectangles[i].bottom = traps->traps[i].bottom;
     717                 : 
     718               0 :         rectangles_ptrs[i] = &rectangles[i];
     719                 :     }
     720                 : 
     721               0 :     _cairo_traps_clear (traps);
     722               0 :     status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i,
     723                 :                                                             fill_rule,
     724                 :                                                             TRUE, traps);
     725               0 :     traps->is_rectilinear = TRUE;
     726               0 :     traps->is_rectangular = TRUE;
     727                 : 
     728               0 :     if (rectangles != stack_rectangles)
     729               0 :         free (rectangles);
     730                 : 
     731                 :     dump_traps (traps, "bo-rects-traps-out.txt");
     732                 : 
     733               0 :     return status;
     734                 : }
     735                 : 
     736                 : cairo_status_t
     737               0 : _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
     738                 :                                          cairo_fill_rule_t fill_rule,
     739                 :                                          cairo_boxes_t *out)
     740                 : {
     741                 :     rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
     742                 :     rectangle_t *rectangles;
     743                 :     rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
     744                 :     rectangle_t **rectangles_ptrs;
     745                 :     const struct _cairo_boxes_chunk *chunk;
     746                 :     cairo_status_t status;
     747                 :     int i, j;
     748                 : 
     749               0 :     if (unlikely (in->num_boxes <= 1))
     750               0 :         return CAIRO_STATUS_SUCCESS;
     751                 : 
     752               0 :     rectangles = stack_rectangles;
     753               0 :     rectangles_ptrs = stack_rectangles_ptrs;
     754               0 :     if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) {
     755               0 :         rectangles = _cairo_malloc_ab_plus_c (in->num_boxes,
     756                 :                                           sizeof (rectangle_t) +
     757                 :                                           sizeof (rectangle_t *),
     758                 :                                           sizeof (rectangle_t *));
     759               0 :         if (unlikely (rectangles == NULL))
     760               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     761                 : 
     762               0 :         rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes);
     763                 :     }
     764                 : 
     765               0 :     j = 0;
     766               0 :     for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
     767               0 :         const cairo_box_t *box = chunk->base;
     768               0 :         for (i = 0; i < chunk->count; i++) {
     769               0 :             if (box[i].p1.x < box[i].p2.x) {
     770               0 :                 rectangles[j].left.x = box[i].p1.x;
     771               0 :                 rectangles[j].left.dir = 1;
     772                 : 
     773               0 :                 rectangles[j].right.x = box[i].p2.x;
     774               0 :                 rectangles[j].right.dir = -1;
     775                 :             } else {
     776               0 :                 rectangles[j].right.x = box[i].p1.x;
     777               0 :                 rectangles[j].right.dir = 1;
     778                 : 
     779               0 :                 rectangles[j].left.x = box[i].p2.x;
     780               0 :                 rectangles[j].left.dir = -1;
     781                 :             }
     782                 : 
     783               0 :             rectangles[j].left.right = NULL;
     784               0 :             rectangles[j].right.right = NULL;
     785                 : 
     786               0 :             rectangles[j].top = box[i].p1.y;
     787               0 :             rectangles[j].bottom = box[i].p2.y;
     788                 : 
     789               0 :             rectangles_ptrs[j] = &rectangles[j];
     790               0 :             j++;
     791                 :         }
     792                 :     }
     793                 : 
     794               0 :     _cairo_boxes_clear (out);
     795               0 :     status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, j,
     796                 :                                                             fill_rule,
     797                 :                                                             FALSE, out);
     798               0 :     if (rectangles != stack_rectangles)
     799               0 :         free (rectangles);
     800                 : 
     801               0 :     return status;
     802                 : }

Generated by: LCOV version 1.7