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

       1                 : /*
       2                 :  * Copyright © 2004 Carl Worth
       3                 :  * Copyright © 2006 Red Hat, Inc.
       4                 :  * Copyright © 2008 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-error-private.h"
      42                 : #include "cairo-freelist-private.h"
      43                 : #include "cairo-combsort-private.h"
      44                 : 
      45                 : #define DEBUG_PRINT_STATE 0
      46                 : #define DEBUG_EVENTS 0
      47                 : #define DEBUG_TRAPS 0
      48                 : 
      49                 : typedef cairo_point_t cairo_bo_point32_t;
      50                 : 
      51                 : typedef struct _cairo_bo_intersect_ordinate {
      52                 :     int32_t ordinate;
      53                 :     enum { EXACT, INEXACT } exactness;
      54                 : } cairo_bo_intersect_ordinate_t;
      55                 : 
      56                 : typedef struct _cairo_bo_intersect_point {
      57                 :     cairo_bo_intersect_ordinate_t x;
      58                 :     cairo_bo_intersect_ordinate_t y;
      59                 : } cairo_bo_intersect_point_t;
      60                 : 
      61                 : typedef struct _cairo_bo_edge cairo_bo_edge_t;
      62                 : typedef struct _cairo_bo_trap cairo_bo_trap_t;
      63                 : 
      64                 : /* A deferred trapezoid of an edge */
      65                 : struct _cairo_bo_trap {
      66                 :     cairo_bo_edge_t *right;
      67                 :     int32_t top;
      68                 : };
      69                 : 
      70                 : struct _cairo_bo_edge {
      71                 :     cairo_edge_t edge;
      72                 :     cairo_bo_edge_t *prev;
      73                 :     cairo_bo_edge_t *next;
      74                 :     cairo_bo_trap_t deferred_trap;
      75                 : };
      76                 : 
      77                 : /* the parent is always given by index/2 */
      78                 : #define PQ_PARENT_INDEX(i) ((i) >> 1)
      79                 : #define PQ_FIRST_ENTRY 1
      80                 : 
      81                 : /* left and right children are index * 2 and (index * 2) +1 respectively */
      82                 : #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
      83                 : 
      84                 : typedef enum {
      85                 :     CAIRO_BO_EVENT_TYPE_STOP,
      86                 :     CAIRO_BO_EVENT_TYPE_INTERSECTION,
      87                 :     CAIRO_BO_EVENT_TYPE_START
      88                 : } cairo_bo_event_type_t;
      89                 : 
      90                 : typedef struct _cairo_bo_event {
      91                 :     cairo_bo_event_type_t type;
      92                 :     cairo_point_t point;
      93                 : } cairo_bo_event_t;
      94                 : 
      95                 : typedef struct _cairo_bo_start_event {
      96                 :     cairo_bo_event_type_t type;
      97                 :     cairo_point_t point;
      98                 :     cairo_bo_edge_t edge;
      99                 : } cairo_bo_start_event_t;
     100                 : 
     101                 : typedef struct _cairo_bo_queue_event {
     102                 :     cairo_bo_event_type_t type;
     103                 :     cairo_point_t point;
     104                 :     cairo_bo_edge_t *e1;
     105                 :     cairo_bo_edge_t *e2;
     106                 : } cairo_bo_queue_event_t;
     107                 : 
     108                 : typedef struct _pqueue {
     109                 :     int size, max_size;
     110                 : 
     111                 :     cairo_bo_event_t **elements;
     112                 :     cairo_bo_event_t *elements_embedded[1024];
     113                 : } pqueue_t;
     114                 : 
     115                 : typedef struct _cairo_bo_event_queue {
     116                 :     cairo_freepool_t pool;
     117                 :     pqueue_t pqueue;
     118                 :     cairo_bo_event_t **start_events;
     119                 : } cairo_bo_event_queue_t;
     120                 : 
     121                 : typedef struct _cairo_bo_sweep_line {
     122                 :     cairo_bo_edge_t *head;
     123                 :     cairo_bo_edge_t *stopped;
     124                 :     int32_t current_y;
     125                 :     cairo_bo_edge_t *current_edge;
     126                 : } cairo_bo_sweep_line_t;
     127                 : 
     128                 : #if DEBUG_TRAPS
     129                 : static void
     130                 : dump_traps (cairo_traps_t *traps, const char *filename)
     131                 : {
     132                 :     FILE *file;
     133                 :     cairo_box_t extents;
     134                 :     int n;
     135                 : 
     136                 :     if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
     137                 :         return;
     138                 : 
     139                 : #if 0
     140                 :     if (traps->has_limits) {
     141                 :         printf ("%s: limits=(%d, %d, %d, %d)\n",
     142                 :                 filename,
     143                 :                 traps->limits.p1.x, traps->limits.p1.y,
     144                 :                 traps->limits.p2.x, traps->limits.p2.y);
     145                 :     }
     146                 : #endif
     147                 :     _cairo_traps_extents (traps, &extents);
     148                 :     printf ("%s: extents=(%d, %d, %d, %d)\n",
     149                 :             filename,
     150                 :             extents.p1.x, extents.p1.y,
     151                 :             extents.p2.x, extents.p2.y);
     152                 : 
     153                 :     file = fopen (filename, "a");
     154                 :     if (file != NULL) {
     155                 :         for (n = 0; n < traps->num_traps; n++) {
     156                 :             fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n",
     157                 :                      traps->traps[n].top,
     158                 :                      traps->traps[n].bottom,
     159                 :                      traps->traps[n].left.p1.x,
     160                 :                      traps->traps[n].left.p1.y,
     161                 :                      traps->traps[n].left.p2.x,
     162                 :                      traps->traps[n].left.p2.y,
     163                 :                      traps->traps[n].right.p1.x,
     164                 :                      traps->traps[n].right.p1.y,
     165                 :                      traps->traps[n].right.p2.x,
     166                 :                      traps->traps[n].right.p2.y);
     167                 :         }
     168                 :         fprintf (file, "\n");
     169                 :         fclose (file);
     170                 :     }
     171                 : }
     172                 : 
     173                 : static void
     174                 : dump_edges (cairo_bo_start_event_t *events,
     175                 :             int num_edges,
     176                 :             const char *filename)
     177                 : {
     178                 :     FILE *file;
     179                 :     int n;
     180                 : 
     181                 :     if (getenv ("CAIRO_DEBUG_TRAPS") == NULL)
     182                 :         return;
     183                 : 
     184                 :     file = fopen (filename, "a");
     185                 :     if (file != NULL) {
     186                 :         for (n = 0; n < num_edges; n++) {
     187                 :             fprintf (file, "(%d, %d), (%d, %d) %d %d %d\n",
     188                 :                      events[n].edge.edge.line.p1.x,
     189                 :                      events[n].edge.edge.line.p1.y,
     190                 :                      events[n].edge.edge.line.p2.x,
     191                 :                      events[n].edge.edge.line.p2.y,
     192                 :                      events[n].edge.edge.top,
     193                 :                      events[n].edge.edge.bottom,
     194                 :                      events[n].edge.edge.dir);
     195                 :         }
     196                 :         fprintf (file, "\n");
     197                 :         fclose (file);
     198                 :     }
     199                 : }
     200                 : #endif
     201                 : 
     202                 : static cairo_fixed_t
     203               0 : _line_compute_intersection_x_for_y (const cairo_line_t *line,
     204                 :                                     cairo_fixed_t y)
     205                 : {
     206                 :     cairo_fixed_t x, dy;
     207                 : 
     208               0 :     if (y == line->p1.y)
     209               0 :         return line->p1.x;
     210               0 :     if (y == line->p2.y)
     211               0 :         return line->p2.x;
     212                 : 
     213               0 :     x = line->p1.x;
     214               0 :     dy = line->p2.y - line->p1.y;
     215               0 :     if (dy != 0) {
     216               0 :         x += _cairo_fixed_mul_div_floor (y - line->p1.y,
     217               0 :                                          line->p2.x - line->p1.x,
     218                 :                                          dy);
     219                 :     }
     220                 : 
     221               0 :     return x;
     222                 : }
     223                 : 
     224                 : static inline int
     225               0 : _cairo_bo_point32_compare (cairo_bo_point32_t const *a,
     226                 :                            cairo_bo_point32_t const *b)
     227                 : {
     228                 :     int cmp;
     229                 : 
     230               0 :     cmp = a->y - b->y;
     231               0 :     if (cmp)
     232               0 :         return cmp;
     233                 : 
     234               0 :     return a->x - b->x;
     235                 : }
     236                 : 
     237                 : /* Compare the slope of a to the slope of b, returning 1, 0, -1 if the
     238                 :  * slope a is respectively greater than, equal to, or less than the
     239                 :  * slope of b.
     240                 :  *
     241                 :  * For each edge, consider the direction vector formed from:
     242                 :  *
     243                 :  *      top -> bottom
     244                 :  *
     245                 :  * which is:
     246                 :  *
     247                 :  *      (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y)
     248                 :  *
     249                 :  * We then define the slope of each edge as dx/dy, (which is the
     250                 :  * inverse of the slope typically used in math instruction). We never
     251                 :  * compute a slope directly as the value approaches infinity, but we
     252                 :  * can derive a slope comparison without division as follows, (where
     253                 :  * the ? represents our compare operator).
     254                 :  *
     255                 :  * 1.      slope(a) ? slope(b)
     256                 :  * 2.       adx/ady ? bdx/bdy
     257                 :  * 3.   (adx * bdy) ? (bdx * ady)
     258                 :  *
     259                 :  * Note that from step 2 to step 3 there is no change needed in the
     260                 :  * sign of the result since both ady and bdy are guaranteed to be
     261                 :  * greater than or equal to 0.
     262                 :  *
     263                 :  * When using this slope comparison to sort edges, some care is needed
     264                 :  * when interpreting the results. Since the slope compare operates on
     265                 :  * distance vectors from top to bottom it gives a correct left to
     266                 :  * right sort for edges that have a common top point, (such as two
     267                 :  * edges with start events at the same location). On the other hand,
     268                 :  * the sense of the result will be exactly reversed for two edges that
     269                 :  * have a common stop point.
     270                 :  */
     271                 : static inline int
     272               0 : _slope_compare (const cairo_bo_edge_t *a,
     273                 :                 const cairo_bo_edge_t *b)
     274                 : {
     275                 :     /* XXX: We're assuming here that dx and dy will still fit in 32
     276                 :      * bits. That's not true in general as there could be overflow. We
     277                 :      * should prevent that before the tessellation algorithm
     278                 :      * begins.
     279                 :      */
     280               0 :     int32_t adx = a->edge.line.p2.x - a->edge.line.p1.x;
     281               0 :     int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x;
     282                 : 
     283                 :     /* Since the dy's are all positive by construction we can fast
     284                 :      * path several common cases.
     285                 :      */
     286                 : 
     287                 :     /* First check for vertical lines. */
     288               0 :     if (adx == 0)
     289               0 :         return -bdx;
     290               0 :     if (bdx == 0)
     291               0 :         return adx;
     292                 : 
     293                 :     /* Then where the two edges point in different directions wrt x. */
     294               0 :     if ((adx ^ bdx) < 0)
     295               0 :         return adx;
     296                 : 
     297                 :     /* Finally we actually need to do the general comparison. */
     298                 :     {
     299               0 :         int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y;
     300               0 :         int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y;
     301               0 :         cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
     302               0 :         cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
     303                 : 
     304               0 :         return _cairo_int64_cmp (adx_bdy, bdx_ady);
     305                 :     }
     306                 : }
     307                 : 
     308                 : /*
     309                 :  * We need to compare the x-coordinates of a pair of lines for a particular y,
     310                 :  * without loss of precision.
     311                 :  *
     312                 :  * The x-coordinate along an edge for a given y is:
     313                 :  *   X = A_x + (Y - A_y) * A_dx / A_dy
     314                 :  *
     315                 :  * So the inequality we wish to test is:
     316                 :  *   A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy,
     317                 :  * where ∘ is our inequality operator.
     318                 :  *
     319                 :  * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are
     320                 :  * all positive, so we can rearrange it thus without causing a sign change:
     321                 :  *   A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy
     322                 :  *                                 - (Y - A_y) * A_dx * B_dy
     323                 :  *
     324                 :  * Given the assumption that all the deltas fit within 32 bits, we can compute
     325                 :  * this comparison directly using 128 bit arithmetic. For certain, but common,
     326                 :  * input we can reduce this down to a single 32 bit compare by inspecting the
     327                 :  * deltas.
     328                 :  *
     329                 :  * (And put the burden of the work on developing fast 128 bit ops, which are
     330                 :  * required throughout the tessellator.)
     331                 :  *
     332                 :  * See the similar discussion for _slope_compare().
     333                 :  */
     334                 : static int
     335               0 : edges_compare_x_for_y_general (const cairo_bo_edge_t *a,
     336                 :                                const cairo_bo_edge_t *b,
     337                 :                                int32_t y)
     338                 : {
     339                 :     /* XXX: We're assuming here that dx and dy will still fit in 32
     340                 :      * bits. That's not true in general as there could be overflow. We
     341                 :      * should prevent that before the tessellation algorithm
     342                 :      * begins.
     343                 :      */
     344                 :     int32_t dx;
     345                 :     int32_t adx, ady;
     346                 :     int32_t bdx, bdy;
     347                 :     enum {
     348                 :        HAVE_NONE    = 0x0,
     349                 :        HAVE_DX      = 0x1,
     350                 :        HAVE_ADX     = 0x2,
     351                 :        HAVE_DX_ADX  = HAVE_DX | HAVE_ADX,
     352                 :        HAVE_BDX     = 0x4,
     353                 :        HAVE_DX_BDX  = HAVE_DX | HAVE_BDX,
     354                 :        HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX,
     355                 :        HAVE_ALL     = HAVE_DX | HAVE_ADX | HAVE_BDX
     356               0 :     } have_dx_adx_bdx = HAVE_ALL;
     357                 : 
     358                 :     /* don't bother solving for abscissa if the edges' bounding boxes
     359                 :      * can be used to order them. */
     360                 :     {
     361                 :            int32_t amin, amax;
     362                 :            int32_t bmin, bmax;
     363               0 :            if (a->edge.line.p1.x < a->edge.line.p2.x) {
     364               0 :                    amin = a->edge.line.p1.x;
     365               0 :                    amax = a->edge.line.p2.x;
     366                 :            } else {
     367               0 :                    amin = a->edge.line.p2.x;
     368               0 :                    amax = a->edge.line.p1.x;
     369                 :            }
     370               0 :            if (b->edge.line.p1.x < b->edge.line.p2.x) {
     371               0 :                    bmin = b->edge.line.p1.x;
     372               0 :                    bmax = b->edge.line.p2.x;
     373                 :            } else {
     374               0 :                    bmin = b->edge.line.p2.x;
     375               0 :                    bmax = b->edge.line.p1.x;
     376                 :            }
     377               0 :            if (amax < bmin) return -1;
     378               0 :            if (amin > bmax) return +1;
     379                 :     }
     380                 : 
     381               0 :     ady = a->edge.line.p2.y - a->edge.line.p1.y;
     382               0 :     adx = a->edge.line.p2.x - a->edge.line.p1.x;
     383               0 :     if (adx == 0)
     384               0 :         have_dx_adx_bdx &= ~HAVE_ADX;
     385                 : 
     386               0 :     bdy = b->edge.line.p2.y - b->edge.line.p1.y;
     387               0 :     bdx = b->edge.line.p2.x - b->edge.line.p1.x;
     388               0 :     if (bdx == 0)
     389               0 :         have_dx_adx_bdx &= ~HAVE_BDX;
     390                 : 
     391               0 :     dx = a->edge.line.p1.x - b->edge.line.p1.x;
     392               0 :     if (dx == 0)
     393               0 :         have_dx_adx_bdx &= ~HAVE_DX;
     394                 : 
     395                 : #define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx)
     396                 : #define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y)
     397                 : #define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y)
     398               0 :     switch (have_dx_adx_bdx) {
     399                 :     default:
     400                 :     case HAVE_NONE:
     401               0 :         return 0;
     402                 :     case HAVE_DX:
     403                 :         /* A_dy * B_dy * (A_x - B_x) ∘ 0 */
     404               0 :         return dx; /* ady * bdy is positive definite */
     405                 :     case HAVE_ADX:
     406                 :         /* 0 ∘  - (Y - A_y) * A_dx * B_dy */
     407               0 :         return adx; /* bdy * (y - a->top.y) is positive definite */
     408                 :     case HAVE_BDX:
     409                 :         /* 0 ∘ (Y - B_y) * B_dx * A_dy */
     410               0 :         return -bdx; /* ady * (y - b->top.y) is positive definite */
     411                 :     case HAVE_ADX_BDX:
     412                 :         /*  0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */
     413               0 :         if ((adx ^ bdx) < 0) {
     414               0 :             return adx;
     415               0 :         } else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */
     416                 :             cairo_int64_t adx_bdy, bdx_ady;
     417                 : 
     418                 :             /* ∴ A_dx * B_dy ∘ B_dx * A_dy */
     419                 : 
     420               0 :             adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
     421               0 :             bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
     422                 : 
     423               0 :             return _cairo_int64_cmp (adx_bdy, bdx_ady);
     424                 :         } else
     425               0 :             return _cairo_int128_cmp (A, B);
     426                 :     case HAVE_DX_ADX:
     427                 :         /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */
     428               0 :         if ((-adx ^ dx) < 0) {
     429               0 :             return dx;
     430                 :         } else {
     431                 :             cairo_int64_t ady_dx, dy_adx;
     432                 : 
     433               0 :             ady_dx = _cairo_int32x32_64_mul (ady, dx);
     434               0 :             dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx);
     435                 : 
     436               0 :             return _cairo_int64_cmp (ady_dx, dy_adx);
     437                 :         }
     438                 :     case HAVE_DX_BDX:
     439                 :         /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */
     440               0 :         if ((bdx ^ dx) < 0) {
     441               0 :             return dx;
     442                 :         } else {
     443                 :             cairo_int64_t bdy_dx, dy_bdx;
     444                 : 
     445               0 :             bdy_dx = _cairo_int32x32_64_mul (bdy, dx);
     446               0 :             dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx);
     447                 : 
     448               0 :             return _cairo_int64_cmp (bdy_dx, dy_bdx);
     449                 :         }
     450                 :     case HAVE_ALL:
     451                 :         /* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */
     452               0 :         return _cairo_int128_cmp (L, _cairo_int128_sub (B, A));
     453                 :     }
     454                 : #undef B
     455                 : #undef A
     456                 : #undef L
     457                 : }
     458                 : 
     459                 : /*
     460                 :  * We need to compare the x-coordinate of a line for a particular y wrt to a
     461                 :  * given x, without loss of precision.
     462                 :  *
     463                 :  * The x-coordinate along an edge for a given y is:
     464                 :  *   X = A_x + (Y - A_y) * A_dx / A_dy
     465                 :  *
     466                 :  * So the inequality we wish to test is:
     467                 :  *   A_x + (Y - A_y) * A_dx / A_dy ∘ X
     468                 :  * where ∘ is our inequality operator.
     469                 :  *
     470                 :  * By construction, we know that A_dy (and (Y - A_y)) are
     471                 :  * all positive, so we can rearrange it thus without causing a sign change:
     472                 :  *   (Y - A_y) * A_dx ∘ (X - A_x) * A_dy
     473                 :  *
     474                 :  * Given the assumption that all the deltas fit within 32 bits, we can compute
     475                 :  * this comparison directly using 64 bit arithmetic.
     476                 :  *
     477                 :  * See the similar discussion for _slope_compare() and
     478                 :  * edges_compare_x_for_y_general().
     479                 :  */
     480                 : static int
     481               0 : edge_compare_for_y_against_x (const cairo_bo_edge_t *a,
     482                 :                               int32_t y,
     483                 :                               int32_t x)
     484                 : {
     485                 :     int32_t adx, ady;
     486                 :     int32_t dx, dy;
     487                 :     cairo_int64_t L, R;
     488                 : 
     489               0 :     if (x < a->edge.line.p1.x && x < a->edge.line.p2.x)
     490               0 :         return 1;
     491               0 :     if (x > a->edge.line.p1.x && x > a->edge.line.p2.x)
     492               0 :         return -1;
     493                 : 
     494               0 :     adx = a->edge.line.p2.x - a->edge.line.p1.x;
     495               0 :     dx = x - a->edge.line.p1.x;
     496                 : 
     497               0 :     if (adx == 0)
     498               0 :         return -dx;
     499               0 :     if (dx == 0 || (adx ^ dx) < 0)
     500               0 :         return adx;
     501                 : 
     502               0 :     dy = y - a->edge.line.p1.y;
     503               0 :     ady = a->edge.line.p2.y - a->edge.line.p1.y;
     504                 : 
     505               0 :     L = _cairo_int32x32_64_mul (dy, adx);
     506               0 :     R = _cairo_int32x32_64_mul (dx, ady);
     507                 : 
     508               0 :     return _cairo_int64_cmp (L, R);
     509                 : }
     510                 : 
     511                 : static int
     512               0 : edges_compare_x_for_y (const cairo_bo_edge_t *a,
     513                 :                        const cairo_bo_edge_t *b,
     514                 :                        int32_t y)
     515                 : {
     516                 :     /* If the sweep-line is currently on an end-point of a line,
     517                 :      * then we know its precise x value (and considering that we often need to
     518                 :      * compare events at end-points, this happens frequently enough to warrant
     519                 :      * special casing).
     520                 :      */
     521                 :     enum {
     522                 :        HAVE_NEITHER = 0x0,
     523                 :        HAVE_AX      = 0x1,
     524                 :        HAVE_BX      = 0x2,
     525                 :        HAVE_BOTH    = HAVE_AX | HAVE_BX
     526               0 :     } have_ax_bx = HAVE_BOTH;
     527                 :     int32_t ax, bx;
     528                 : 
     529               0 :     if (y == a->edge.line.p1.y)
     530               0 :         ax = a->edge.line.p1.x;
     531               0 :     else if (y == a->edge.line.p2.y)
     532               0 :         ax = a->edge.line.p2.x;
     533                 :     else
     534               0 :         have_ax_bx &= ~HAVE_AX;
     535                 : 
     536               0 :     if (y == b->edge.line.p1.y)
     537               0 :         bx = b->edge.line.p1.x;
     538               0 :     else if (y == b->edge.line.p2.y)
     539               0 :         bx = b->edge.line.p2.x;
     540                 :     else
     541               0 :         have_ax_bx &= ~HAVE_BX;
     542                 : 
     543               0 :     switch (have_ax_bx) {
     544                 :     default:
     545                 :     case HAVE_NEITHER:
     546               0 :         return edges_compare_x_for_y_general (a, b, y);
     547                 :     case HAVE_AX:
     548               0 :         return -edge_compare_for_y_against_x (b, y, ax);
     549                 :     case HAVE_BX:
     550               0 :         return edge_compare_for_y_against_x (a, y, bx);
     551                 :     case HAVE_BOTH:
     552               0 :         return ax - bx;
     553                 :     }
     554                 : }
     555                 : 
     556                 : static inline int
     557               0 : _line_equal (const cairo_line_t *a, const cairo_line_t *b)
     558                 : {
     559               0 :     return a->p1.x == b->p1.x && a->p1.y == b->p1.y &&
     560               0 :            a->p2.x == b->p2.x && a->p2.y == b->p2.y;
     561                 : }
     562                 : 
     563                 : static int
     564               0 : _cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t       *sweep_line,
     565                 :                                     const cairo_bo_edge_t       *a,
     566                 :                                     const cairo_bo_edge_t       *b)
     567                 : {
     568                 :     int cmp;
     569                 : 
     570                 :     /* compare the edges if not identical */
     571               0 :     if (! _line_equal (&a->edge.line, &b->edge.line)) {
     572               0 :         cmp = edges_compare_x_for_y (a, b, sweep_line->current_y);
     573               0 :         if (cmp)
     574               0 :             return cmp;
     575                 : 
     576                 :         /* The two edges intersect exactly at y, so fall back on slope
     577                 :          * comparison. We know that this compare_edges function will be
     578                 :          * called only when starting a new edge, (not when stopping an
     579                 :          * edge), so we don't have to worry about conditionally inverting
     580                 :          * the sense of _slope_compare. */
     581               0 :         cmp = _slope_compare (a, b);
     582               0 :         if (cmp)
     583               0 :             return cmp;
     584                 :     }
     585                 : 
     586                 :     /* We've got two collinear edges now. */
     587               0 :     return b->edge.bottom - a->edge.bottom;
     588                 : }
     589                 : 
     590                 : static inline cairo_int64_t
     591               0 : det32_64 (int32_t a, int32_t b,
     592                 :           int32_t c, int32_t d)
     593                 : {
     594                 :     /* det = a * d - b * c */
     595               0 :     return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
     596                 :                              _cairo_int32x32_64_mul (b, c));
     597                 : }
     598                 : 
     599                 : static inline cairo_int128_t
     600               0 : det64x32_128 (cairo_int64_t a, int32_t       b,
     601                 :               cairo_int64_t c, int32_t       d)
     602                 : {
     603                 :     /* det = a * d - b * c */
     604               0 :     return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d),
     605                 :                               _cairo_int64x32_128_mul (c, b));
     606                 : }
     607                 : 
     608                 : /* Compute the intersection of two lines as defined by two edges. The
     609                 :  * result is provided as a coordinate pair of 128-bit integers.
     610                 :  *
     611                 :  * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
     612                 :  * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
     613                 :  */
     614                 : static cairo_bool_t
     615               0 : intersect_lines (cairo_bo_edge_t                *a,
     616                 :                  cairo_bo_edge_t                *b,
     617                 :                  cairo_bo_intersect_point_t     *intersection)
     618                 : {
     619                 :     cairo_int64_t a_det, b_det;
     620                 : 
     621                 :     /* XXX: We're assuming here that dx and dy will still fit in 32
     622                 :      * bits. That's not true in general as there could be overflow. We
     623                 :      * should prevent that before the tessellation algorithm begins.
     624                 :      * What we're doing to mitigate this is to perform clamping in
     625                 :      * cairo_bo_tessellate_polygon().
     626                 :      */
     627               0 :     int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x;
     628               0 :     int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y;
     629                 : 
     630               0 :     int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x;
     631               0 :     int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y;
     632                 : 
     633                 :     cairo_int64_t den_det;
     634                 :     cairo_int64_t R;
     635                 :     cairo_quorem64_t qr;
     636                 : 
     637               0 :     den_det = det32_64 (dx1, dy1, dx2, dy2);
     638                 : 
     639                 :      /* Q: Can we determine that the lines do not intersect (within range)
     640                 :       * much more cheaply than computing the intersection point i.e. by
     641                 :       * avoiding the division?
     642                 :       *
     643                 :       *   X = ax + t * adx = bx + s * bdx;
     644                 :       *   Y = ay + t * ady = by + s * bdy;
     645                 :       *   ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx)
     646                 :       *   => t * L = R
     647                 :       *
     648                 :       * Therefore we can reject any intersection (under the criteria for
     649                 :       * valid intersection events) if:
     650                 :       *   L^R < 0 => t < 0, or
     651                 :       *   L<R => t > 1
     652                 :       *
     653                 :       * (where top/bottom must at least extend to the line endpoints).
     654                 :       *
     655                 :       * A similar substitution can be performed for s, yielding:
     656                 :       *   s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by)
     657                 :       */
     658               0 :     R = det32_64 (dx2, dy2,
     659               0 :                   b->edge.line.p1.x - a->edge.line.p1.x,
     660               0 :                   b->edge.line.p1.y - a->edge.line.p1.y);
     661               0 :     if (_cairo_int64_negative (den_det)) {
     662               0 :         if (_cairo_int64_ge (den_det, R))
     663               0 :             return FALSE;
     664                 :     } else {
     665               0 :         if (_cairo_int64_le (den_det, R))
     666               0 :             return FALSE;
     667                 :     }
     668                 : 
     669               0 :     R = det32_64 (dy1, dx1,
     670               0 :                   a->edge.line.p1.y - b->edge.line.p1.y,
     671               0 :                   a->edge.line.p1.x - b->edge.line.p1.x);
     672               0 :     if (_cairo_int64_negative (den_det)) {
     673               0 :         if (_cairo_int64_ge (den_det, R))
     674               0 :             return FALSE;
     675                 :     } else {
     676               0 :         if (_cairo_int64_le (den_det, R))
     677               0 :             return FALSE;
     678                 :     }
     679                 : 
     680                 :     /* We now know that the two lines should intersect within range. */
     681                 : 
     682               0 :     a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y,
     683                 :                       a->edge.line.p2.x, a->edge.line.p2.y);
     684               0 :     b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y,
     685                 :                       b->edge.line.p2.x, b->edge.line.p2.y);
     686                 : 
     687                 :     /* x = det (a_det, dx1, b_det, dx2) / den_det */
     688               0 :     qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1,
     689                 :                                                        b_det, dx2),
     690                 :                                          den_det);
     691               0 :     if (_cairo_int64_eq (qr.rem, den_det))
     692               0 :         return FALSE;
     693                 : #if 0
     694                 :     intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
     695                 : #else
     696               0 :     intersection->x.exactness = EXACT;
     697               0 :     if (! _cairo_int64_is_zero (qr.rem)) {
     698               0 :         if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
     699               0 :             qr.rem = _cairo_int64_negate (qr.rem);
     700               0 :         qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
     701               0 :         if (_cairo_int64_ge (qr.rem, den_det)) {
     702               0 :             qr.quo = _cairo_int64_add (qr.quo,
     703                 :                                        _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
     704                 :         } else
     705               0 :             intersection->x.exactness = INEXACT;
     706                 :     }
     707                 : #endif
     708               0 :     intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo);
     709                 : 
     710                 :     /* y = det (a_det, dy1, b_det, dy2) / den_det */
     711               0 :     qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1,
     712                 :                                                        b_det, dy2),
     713                 :                                          den_det);
     714               0 :     if (_cairo_int64_eq (qr.rem, den_det))
     715               0 :         return FALSE;
     716                 : #if 0
     717                 :     intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
     718                 : #else
     719               0 :     intersection->y.exactness = EXACT;
     720               0 :     if (! _cairo_int64_is_zero (qr.rem)) {
     721               0 :         if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
     722               0 :             qr.rem = _cairo_int64_negate (qr.rem);
     723               0 :         qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
     724               0 :         if (_cairo_int64_ge (qr.rem, den_det)) {
     725               0 :             qr.quo = _cairo_int64_add (qr.quo,
     726                 :                                        _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
     727                 :         } else
     728               0 :             intersection->y.exactness = INEXACT;
     729                 :     }
     730                 : #endif
     731               0 :     intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo);
     732                 : 
     733               0 :     return TRUE;
     734                 : }
     735                 : 
     736                 : static int
     737               0 : _cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t  a,
     738                 :                                          int32_t                        b)
     739                 : {
     740                 :     /* First compare the quotient */
     741               0 :     if (a.ordinate > b)
     742               0 :         return +1;
     743               0 :     if (a.ordinate < b)
     744               0 :         return -1;
     745                 :     /* With quotient identical, if remainder is 0 then compare equal */
     746                 :     /* Otherwise, the non-zero remainder makes a > b */
     747               0 :     return INEXACT == a.exactness;
     748                 : }
     749                 : 
     750                 : /* Does the given edge contain the given point. The point must already
     751                 :  * be known to be contained within the line determined by the edge,
     752                 :  * (most likely the point results from an intersection of this edge
     753                 :  * with another).
     754                 :  *
     755                 :  * If we had exact arithmetic, then this function would simply be a
     756                 :  * matter of examining whether the y value of the point lies within
     757                 :  * the range of y values of the edge. But since intersection points
     758                 :  * are not exact due to being rounded to the nearest integer within
     759                 :  * the available precision, we must also examine the x value of the
     760                 :  * point.
     761                 :  *
     762                 :  * The definition of "contains" here is that the given intersection
     763                 :  * point will be seen by the sweep line after the start event for the
     764                 :  * given edge and before the stop event for the edge. See the comments
     765                 :  * in the implementation for more details.
     766                 :  */
     767                 : static cairo_bool_t
     768               0 : _cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t                *edge,
     769                 :                                          cairo_bo_intersect_point_t     *point)
     770                 : {
     771                 :     int cmp_top, cmp_bottom;
     772                 : 
     773                 :     /* XXX: When running the actual algorithm, we don't actually need to
     774                 :      * compare against edge->top at all here, since any intersection above
     775                 :      * top is eliminated early via a slope comparison. We're leaving these
     776                 :      * here for now only for the sake of the quadratic-time intersection
     777                 :      * finder which needs them.
     778                 :      */
     779                 : 
     780               0 :     cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y,
     781                 :                                                        edge->edge.top);
     782               0 :     cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y,
     783                 :                                                           edge->edge.bottom);
     784                 : 
     785               0 :     if (cmp_top < 0 || cmp_bottom > 0)
     786                 :     {
     787               0 :         return FALSE;
     788                 :     }
     789                 : 
     790               0 :     if (cmp_top > 0 && cmp_bottom < 0)
     791                 :     {
     792               0 :         return TRUE;
     793                 :     }
     794                 : 
     795                 :     /* At this stage, the point lies on the same y value as either
     796                 :      * edge->top or edge->bottom, so we have to examine the x value in
     797                 :      * order to properly determine containment. */
     798                 : 
     799                 :     /* If the y value of the point is the same as the y value of the
     800                 :      * top of the edge, then the x value of the point must be greater
     801                 :      * to be considered as inside the edge. Similarly, if the y value
     802                 :      * of the point is the same as the y value of the bottom of the
     803                 :      * edge, then the x value of the point must be less to be
     804                 :      * considered as inside. */
     805                 : 
     806               0 :     if (cmp_top == 0) {
     807                 :         cairo_fixed_t top_x;
     808                 : 
     809               0 :         top_x = _line_compute_intersection_x_for_y (&edge->edge.line,
     810                 :                                                     edge->edge.top);
     811               0 :         return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0;
     812                 :     } else { /* cmp_bottom == 0 */
     813                 :         cairo_fixed_t bot_x;
     814                 : 
     815               0 :         bot_x = _line_compute_intersection_x_for_y (&edge->edge.line,
     816                 :                                                     edge->edge.bottom);
     817               0 :         return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0;
     818                 :     }
     819                 : }
     820                 : 
     821                 : /* Compute the intersection of two edges. The result is provided as a
     822                 :  * coordinate pair of 128-bit integers.
     823                 :  *
     824                 :  * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection
     825                 :  * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the
     826                 :  * intersection of the lines defined by the edges occurs outside of
     827                 :  * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges
     828                 :  * are exactly parallel.
     829                 :  *
     830                 :  * Note that when determining if a candidate intersection is "inside"
     831                 :  * an edge, we consider both the infinitesimal shortening and the
     832                 :  * infinitesimal tilt rules described by John Hobby. Specifically, if
     833                 :  * the intersection is exactly the same as an edge point, it is
     834                 :  * effectively outside (no intersection is returned). Also, if the
     835                 :  * intersection point has the same
     836                 :  */
     837                 : static cairo_bool_t
     838               0 : _cairo_bo_edge_intersect (cairo_bo_edge_t       *a,
     839                 :                           cairo_bo_edge_t       *b,
     840                 :                           cairo_bo_point32_t    *intersection)
     841                 : {
     842                 :     cairo_bo_intersect_point_t quorem;
     843                 : 
     844               0 :     if (! intersect_lines (a, b, &quorem))
     845               0 :         return FALSE;
     846                 : 
     847               0 :     if (! _cairo_bo_edge_contains_intersect_point (a, &quorem))
     848               0 :         return FALSE;
     849                 : 
     850               0 :     if (! _cairo_bo_edge_contains_intersect_point (b, &quorem))
     851               0 :         return FALSE;
     852                 : 
     853                 :     /* Now that we've correctly compared the intersection point and
     854                 :      * determined that it lies within the edge, then we know that we
     855                 :      * no longer need any more bits of storage for the intersection
     856                 :      * than we do for our edge coordinates. We also no longer need the
     857                 :      * remainder from the division. */
     858               0 :     intersection->x = quorem.x.ordinate;
     859               0 :     intersection->y = quorem.y.ordinate;
     860                 : 
     861               0 :     return TRUE;
     862                 : }
     863                 : 
     864                 : static inline int
     865               0 : cairo_bo_event_compare (const cairo_bo_event_t *a,
     866                 :                         const cairo_bo_event_t *b)
     867                 : {
     868                 :     int cmp;
     869                 : 
     870               0 :     cmp = _cairo_bo_point32_compare (&a->point, &b->point);
     871               0 :     if (cmp)
     872               0 :         return cmp;
     873                 : 
     874               0 :     cmp = a->type - b->type;
     875               0 :     if (cmp)
     876               0 :         return cmp;
     877                 : 
     878               0 :     return a - b;
     879                 : }
     880                 : 
     881                 : static inline void
     882               0 : _pqueue_init (pqueue_t *pq)
     883                 : {
     884               0 :     pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
     885               0 :     pq->size = 0;
     886                 : 
     887               0 :     pq->elements = pq->elements_embedded;
     888               0 : }
     889                 : 
     890                 : static inline void
     891               0 : _pqueue_fini (pqueue_t *pq)
     892                 : {
     893               0 :     if (pq->elements != pq->elements_embedded)
     894               0 :         free (pq->elements);
     895               0 : }
     896                 : 
     897                 : static cairo_status_t
     898               0 : _pqueue_grow (pqueue_t *pq)
     899                 : {
     900                 :     cairo_bo_event_t **new_elements;
     901               0 :     pq->max_size *= 2;
     902                 : 
     903               0 :     if (pq->elements == pq->elements_embedded) {
     904               0 :         new_elements = _cairo_malloc_ab (pq->max_size,
     905                 :                                          sizeof (cairo_bo_event_t *));
     906               0 :         if (unlikely (new_elements == NULL))
     907               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     908                 : 
     909               0 :         memcpy (new_elements, pq->elements_embedded,
     910                 :                 sizeof (pq->elements_embedded));
     911                 :     } else {
     912               0 :         new_elements = _cairo_realloc_ab (pq->elements,
     913                 :                                           pq->max_size,
     914                 :                                           sizeof (cairo_bo_event_t *));
     915               0 :         if (unlikely (new_elements == NULL))
     916               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     917                 :     }
     918                 : 
     919               0 :     pq->elements = new_elements;
     920               0 :     return CAIRO_STATUS_SUCCESS;
     921                 : }
     922                 : 
     923                 : static inline cairo_status_t
     924               0 : _pqueue_push (pqueue_t *pq, cairo_bo_event_t *event)
     925                 : {
     926                 :     cairo_bo_event_t **elements;
     927                 :     int i, parent;
     928                 : 
     929               0 :     if (unlikely (pq->size + 1 == pq->max_size)) {
     930                 :         cairo_status_t status;
     931                 : 
     932               0 :         status = _pqueue_grow (pq);
     933               0 :         if (unlikely (status))
     934               0 :             return status;
     935                 :     }
     936                 : 
     937               0 :     elements = pq->elements;
     938                 : 
     939               0 :     for (i = ++pq->size;
     940               0 :          i != PQ_FIRST_ENTRY &&
     941               0 :          cairo_bo_event_compare (event,
     942               0 :                                  elements[parent = PQ_PARENT_INDEX (i)]) < 0;
     943               0 :          i = parent)
     944                 :     {
     945               0 :         elements[i] = elements[parent];
     946                 :     }
     947                 : 
     948               0 :     elements[i] = event;
     949                 : 
     950               0 :     return CAIRO_STATUS_SUCCESS;
     951                 : }
     952                 : 
     953                 : static inline void
     954               0 : _pqueue_pop (pqueue_t *pq)
     955                 : {
     956               0 :     cairo_bo_event_t **elements = pq->elements;
     957                 :     cairo_bo_event_t *tail;
     958                 :     int child, i;
     959                 : 
     960               0 :     tail = elements[pq->size--];
     961               0 :     if (pq->size == 0) {
     962               0 :         elements[PQ_FIRST_ENTRY] = NULL;
     963               0 :         return;
     964                 :     }
     965                 : 
     966               0 :     for (i = PQ_FIRST_ENTRY;
     967               0 :          (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
     968               0 :          i = child)
     969                 :     {
     970               0 :         if (child != pq->size &&
     971               0 :             cairo_bo_event_compare (elements[child+1],
     972               0 :                                     elements[child]) < 0)
     973                 :         {
     974               0 :             child++;
     975                 :         }
     976                 : 
     977               0 :         if (cairo_bo_event_compare (elements[child], tail) >= 0)
     978               0 :             break;
     979                 : 
     980               0 :         elements[i] = elements[child];
     981                 :     }
     982               0 :     elements[i] = tail;
     983                 : }
     984                 : 
     985                 : static inline cairo_status_t
     986               0 : _cairo_bo_event_queue_insert (cairo_bo_event_queue_t    *queue,
     987                 :                               cairo_bo_event_type_t      type,
     988                 :                               cairo_bo_edge_t           *e1,
     989                 :                               cairo_bo_edge_t           *e2,
     990                 :                               const cairo_point_t        *point)
     991                 : {
     992                 :     cairo_bo_queue_event_t *event;
     993                 : 
     994               0 :     event = _cairo_freepool_alloc (&queue->pool);
     995               0 :     if (unlikely (event == NULL))
     996               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     997                 : 
     998               0 :     event->type = type;
     999               0 :     event->e1 = e1;
    1000               0 :     event->e2 = e2;
    1001               0 :     event->point = *point;
    1002                 : 
    1003               0 :     return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event);
    1004                 : }
    1005                 : 
    1006                 : static void
    1007               0 : _cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue,
    1008                 :                               cairo_bo_event_t       *event)
    1009                 : {
    1010               0 :     _cairo_freepool_free (&queue->pool, event);
    1011               0 : }
    1012                 : 
    1013                 : static cairo_bo_event_t *
    1014               0 : _cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue)
    1015                 : {
    1016                 :     cairo_bo_event_t *event, *cmp;
    1017                 : 
    1018               0 :     event = event_queue->pqueue.elements[PQ_FIRST_ENTRY];
    1019               0 :     cmp = *event_queue->start_events;
    1020               0 :     if (event == NULL ||
    1021               0 :         (cmp != NULL && cairo_bo_event_compare (cmp, event) < 0))
    1022                 :     {
    1023               0 :         event = cmp;
    1024               0 :         event_queue->start_events++;
    1025                 :     }
    1026                 :     else
    1027                 :     {
    1028               0 :         _pqueue_pop (&event_queue->pqueue);
    1029                 :     }
    1030                 : 
    1031               0 :     return event;
    1032                 : }
    1033                 : 
    1034               0 : CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
    1035                 :                         cairo_bo_event_t *,
    1036                 :                         cairo_bo_event_compare)
    1037                 : 
    1038                 : static void
    1039               0 : _cairo_bo_event_queue_init (cairo_bo_event_queue_t       *event_queue,
    1040                 :                             cairo_bo_event_t            **start_events,
    1041                 :                             int                           num_events)
    1042                 : {
    1043               0 :     _cairo_bo_event_queue_sort (start_events, num_events);
    1044               0 :     start_events[num_events] = NULL;
    1045                 : 
    1046               0 :     event_queue->start_events = start_events;
    1047                 : 
    1048               0 :     _cairo_freepool_init (&event_queue->pool,
    1049                 :                           sizeof (cairo_bo_queue_event_t));
    1050               0 :     _pqueue_init (&event_queue->pqueue);
    1051               0 :     event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL;
    1052               0 : }
    1053                 : 
    1054                 : static cairo_status_t
    1055               0 : _cairo_bo_event_queue_insert_stop (cairo_bo_event_queue_t       *event_queue,
    1056                 :                                    cairo_bo_edge_t              *edge)
    1057                 : {
    1058                 :     cairo_bo_point32_t point;
    1059                 : 
    1060               0 :     point.y = edge->edge.bottom;
    1061               0 :     point.x = _line_compute_intersection_x_for_y (&edge->edge.line,
    1062                 :                                                   point.y);
    1063               0 :     return _cairo_bo_event_queue_insert (event_queue,
    1064                 :                                          CAIRO_BO_EVENT_TYPE_STOP,
    1065                 :                                          edge, NULL,
    1066                 :                                          &point);
    1067                 : }
    1068                 : 
    1069                 : static void
    1070               0 : _cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue)
    1071                 : {
    1072               0 :     _pqueue_fini (&event_queue->pqueue);
    1073               0 :     _cairo_freepool_fini (&event_queue->pool);
    1074               0 : }
    1075                 : 
    1076                 : static inline cairo_status_t
    1077               0 : _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t       *event_queue,
    1078                 :                                                            cairo_bo_edge_t      *left,
    1079                 :                                                            cairo_bo_edge_t *right)
    1080                 : {
    1081                 :     cairo_bo_point32_t intersection;
    1082                 : 
    1083               0 :     if (_line_equal (&left->edge.line, &right->edge.line))
    1084               0 :         return CAIRO_STATUS_SUCCESS;
    1085                 : 
    1086                 :     /* The names "left" and "right" here are correct descriptions of
    1087                 :      * the order of the two edges within the active edge list. So if a
    1088                 :      * slope comparison also puts left less than right, then we know
    1089                 :      * that the intersection of these two segments has already
    1090                 :      * occurred before the current sweep line position. */
    1091               0 :     if (_slope_compare (left, right) <= 0)
    1092               0 :         return CAIRO_STATUS_SUCCESS;
    1093                 : 
    1094               0 :     if (! _cairo_bo_edge_intersect (left, right, &intersection))
    1095               0 :         return CAIRO_STATUS_SUCCESS;
    1096                 : 
    1097               0 :     return _cairo_bo_event_queue_insert (event_queue,
    1098                 :                                          CAIRO_BO_EVENT_TYPE_INTERSECTION,
    1099                 :                                          left, right,
    1100                 :                                          &intersection);
    1101                 : }
    1102                 : 
    1103                 : static void
    1104               0 : _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
    1105                 : {
    1106               0 :     sweep_line->head = NULL;
    1107               0 :     sweep_line->stopped = NULL;
    1108               0 :     sweep_line->current_y = INT32_MIN;
    1109               0 :     sweep_line->current_edge = NULL;
    1110               0 : }
    1111                 : 
    1112                 : static cairo_status_t
    1113               0 : _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t      *sweep_line,
    1114                 :                              cairo_bo_edge_t            *edge)
    1115                 : {
    1116               0 :     if (sweep_line->current_edge != NULL) {
    1117                 :         cairo_bo_edge_t *prev, *next;
    1118                 :         int cmp;
    1119                 : 
    1120               0 :         cmp = _cairo_bo_sweep_line_compare_edges (sweep_line,
    1121               0 :                                                   sweep_line->current_edge,
    1122                 :                                                   edge);
    1123               0 :         if (cmp < 0) {
    1124               0 :             prev = sweep_line->current_edge;
    1125               0 :             next = prev->next;
    1126               0 :             while (next != NULL &&
    1127               0 :                    _cairo_bo_sweep_line_compare_edges (sweep_line,
    1128                 :                                                        next, edge) < 0)
    1129                 :             {
    1130               0 :                 prev = next, next = prev->next;
    1131                 :             }
    1132                 : 
    1133               0 :             prev->next = edge;
    1134               0 :             edge->prev = prev;
    1135               0 :             edge->next = next;
    1136               0 :             if (next != NULL)
    1137               0 :                 next->prev = edge;
    1138               0 :         } else if (cmp > 0) {
    1139               0 :             next = sweep_line->current_edge;
    1140               0 :             prev = next->prev;
    1141               0 :             while (prev != NULL &&
    1142               0 :                    _cairo_bo_sweep_line_compare_edges (sweep_line,
    1143                 :                                                        prev, edge) > 0)
    1144                 :             {
    1145               0 :                 next = prev, prev = next->prev;
    1146                 :             }
    1147                 : 
    1148               0 :             next->prev = edge;
    1149               0 :             edge->next = next;
    1150               0 :             edge->prev = prev;
    1151               0 :             if (prev != NULL)
    1152               0 :                 prev->next = edge;
    1153                 :             else
    1154               0 :                 sweep_line->head = edge;
    1155                 :         } else {
    1156               0 :             prev = sweep_line->current_edge;
    1157               0 :             edge->prev = prev;
    1158               0 :             edge->next = prev->next;
    1159               0 :             if (prev->next != NULL)
    1160               0 :                 prev->next->prev = edge;
    1161               0 :             prev->next = edge;
    1162                 :         }
    1163                 :     } else {
    1164               0 :         sweep_line->head = edge;
    1165                 :     }
    1166                 : 
    1167               0 :     sweep_line->current_edge = edge;
    1168                 : 
    1169               0 :     return CAIRO_STATUS_SUCCESS;
    1170                 : }
    1171                 : 
    1172                 : static void
    1173               0 : _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t      *sweep_line,
    1174                 :                              cairo_bo_edge_t    *edge)
    1175                 : {
    1176               0 :     if (edge->prev != NULL)
    1177               0 :         edge->prev->next = edge->next;
    1178                 :     else
    1179               0 :         sweep_line->head = edge->next;
    1180                 : 
    1181               0 :     if (edge->next != NULL)
    1182               0 :         edge->next->prev = edge->prev;
    1183                 : 
    1184               0 :     if (sweep_line->current_edge == edge)
    1185               0 :         sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
    1186               0 : }
    1187                 : 
    1188                 : static void
    1189               0 : _cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t        *sweep_line,
    1190                 :                            cairo_bo_edge_t              *left,
    1191                 :                            cairo_bo_edge_t              *right)
    1192                 : {
    1193               0 :     if (left->prev != NULL)
    1194               0 :         left->prev->next = right;
    1195                 :     else
    1196               0 :         sweep_line->head = right;
    1197                 : 
    1198               0 :     if (right->next != NULL)
    1199               0 :         right->next->prev = left;
    1200                 : 
    1201               0 :     left->next = right->next;
    1202               0 :     right->next = left;
    1203                 : 
    1204               0 :     right->prev = left->prev;
    1205               0 :     left->prev = right;
    1206               0 : }
    1207                 : 
    1208                 : #if DEBUG_PRINT_STATE
    1209                 : static void
    1210                 : _cairo_bo_edge_print (cairo_bo_edge_t *edge)
    1211                 : {
    1212                 :     printf ("(0x%x, 0x%x)-(0x%x, 0x%x)",
    1213                 :             edge->edge.line.p1.x, edge->edge.line.p1.y,
    1214                 :             edge->edge.line.p2.x, edge->edge.line.p2.y);
    1215                 : }
    1216                 : 
    1217                 : static void
    1218                 : _cairo_bo_event_print (cairo_bo_event_t *event)
    1219                 : {
    1220                 :     switch (event->type) {
    1221                 :     case CAIRO_BO_EVENT_TYPE_START:
    1222                 :         printf ("Start: ");
    1223                 :         break;
    1224                 :     case CAIRO_BO_EVENT_TYPE_STOP:
    1225                 :         printf ("Stop: ");
    1226                 :         break;
    1227                 :     case CAIRO_BO_EVENT_TYPE_INTERSECTION:
    1228                 :         printf ("Intersection: ");
    1229                 :         break;
    1230                 :     }
    1231                 :     printf ("(%d, %d)\t", event->point.x, event->point.y);
    1232                 :     _cairo_bo_edge_print (event->e1);
    1233                 :     if (event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) {
    1234                 :         printf (" X ");
    1235                 :         _cairo_bo_edge_print (event->e2);
    1236                 :     }
    1237                 :     printf ("\n");
    1238                 : }
    1239                 : 
    1240                 : static void
    1241                 : _cairo_bo_event_queue_print (cairo_bo_event_queue_t *event_queue)
    1242                 : {
    1243                 :     /* XXX: fixme to print the start/stop array too. */
    1244                 :     printf ("Event queue:\n");
    1245                 : }
    1246                 : 
    1247                 : static void
    1248                 : _cairo_bo_sweep_line_print (cairo_bo_sweep_line_t *sweep_line)
    1249                 : {
    1250                 :     cairo_bool_t first = TRUE;
    1251                 :     cairo_bo_edge_t *edge;
    1252                 : 
    1253                 :     printf ("Sweep line from edge list: ");
    1254                 :     first = TRUE;
    1255                 :     for (edge = sweep_line->head;
    1256                 :          edge;
    1257                 :          edge = edge->next)
    1258                 :     {
    1259                 :         if (!first)
    1260                 :             printf (", ");
    1261                 :         _cairo_bo_edge_print (edge);
    1262                 :         first = FALSE;
    1263                 :     }
    1264                 :     printf ("\n");
    1265                 : }
    1266                 : 
    1267                 : static void
    1268                 : print_state (const char                 *msg,
    1269                 :              cairo_bo_event_t           *event,
    1270                 :              cairo_bo_event_queue_t     *event_queue,
    1271                 :              cairo_bo_sweep_line_t      *sweep_line)
    1272                 : {
    1273                 :     printf ("%s ", msg);
    1274                 :     _cairo_bo_event_print (event);
    1275                 :     _cairo_bo_event_queue_print (event_queue);
    1276                 :     _cairo_bo_sweep_line_print (sweep_line);
    1277                 :     printf ("\n");
    1278                 : }
    1279                 : #endif
    1280                 : 
    1281                 : #if DEBUG_EVENTS
    1282                 : static void CAIRO_PRINTF_FORMAT (1, 2)
    1283                 : event_log (const char *fmt, ...)
    1284                 : {
    1285                 :     FILE *file;
    1286                 : 
    1287                 :     if (getenv ("CAIRO_DEBUG_EVENTS") == NULL)
    1288                 :         return;
    1289                 : 
    1290                 :     file = fopen ("bo-events.txt", "a");
    1291                 :     if (file != NULL) {
    1292                 :         va_list ap;
    1293                 : 
    1294                 :         va_start (ap, fmt);
    1295                 :         vfprintf (file, fmt, ap);
    1296                 :         va_end (ap);
    1297                 : 
    1298                 :         fclose (file);
    1299                 :     }
    1300                 : }
    1301                 : #endif
    1302                 : 
    1303                 : static inline cairo_bool_t
    1304               0 : edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
    1305                 : {
    1306               0 :     if (_line_equal (&a->edge.line, &b->edge.line))
    1307               0 :         return TRUE;
    1308                 : 
    1309               0 :     if (_slope_compare (a, b))
    1310               0 :         return FALSE;
    1311                 : 
    1312                 :     /* The choice of y is not truly arbitrary since we must guarantee that it
    1313                 :      * is greater than the start of either line.
    1314                 :      */
    1315               0 :     if (a->edge.line.p1.y == b->edge.line.p1.y) {
    1316               0 :         return a->edge.line.p1.x == b->edge.line.p1.x;
    1317               0 :     } else if (a->edge.line.p1.y < b->edge.line.p1.y) {
    1318               0 :         return edge_compare_for_y_against_x (b,
    1319                 :                                              a->edge.line.p1.y,
    1320                 :                                              a->edge.line.p1.x) == 0;
    1321                 :     } else {
    1322               0 :         return edge_compare_for_y_against_x (a,
    1323                 :                                              b->edge.line.p1.y,
    1324                 :                                              b->edge.line.p1.x) == 0;
    1325                 :     }
    1326                 : }
    1327                 : 
    1328                 : /* Adds the trapezoid, if any, of the left edge to the #cairo_traps_t */
    1329                 : static cairo_status_t
    1330               0 : _cairo_bo_edge_end_trap (cairo_bo_edge_t        *left,
    1331                 :                          int32_t                 bot,
    1332                 :                          cairo_traps_t          *traps)
    1333                 : {
    1334               0 :     cairo_bo_trap_t *trap = &left->deferred_trap;
    1335                 : 
    1336                 :     /* Only emit (trivial) non-degenerate trapezoids with positive height. */
    1337               0 :     if (likely (trap->top < bot)) {
    1338               0 :         _cairo_traps_add_trap (traps,
    1339                 :                                trap->top, bot,
    1340               0 :                                &left->edge.line, &trap->right->edge.line);
    1341                 : 
    1342                 : #if DEBUG_PRINT_STATE
    1343                 :         printf ("Deferred trap: left=(%x, %x)-(%x,%x) "
    1344                 :                 "right=(%x,%x)-(%x,%x) top=%x, bot=%x\n",
    1345                 :                 left->edge.line.p1.x, left->edge.line.p1.y,
    1346                 :                 left->edge.line.p2.x, left->edge.line.p2.y,
    1347                 :                 trap->right->edge.line.p1.x, trap->right->edge.line.p1.y,
    1348                 :                 trap->right->edge.line.p2.x, trap->right->edge.line.p2.y,
    1349                 :                 trap->top, bot);
    1350                 : #endif
    1351                 : #if DEBUG_EVENTS
    1352                 :         event_log ("end trap: %lu %lu %d %d\n",
    1353                 :                    (long) left,
    1354                 :                    (long) trap->right,
    1355                 :                    trap->top,
    1356                 :                    bot);
    1357                 : #endif
    1358                 :     }
    1359                 : 
    1360               0 :     trap->right = NULL;
    1361                 : 
    1362               0 :     return _cairo_traps_status (traps);
    1363                 : }
    1364                 : 
    1365                 : 
    1366                 : /* Start a new trapezoid at the given top y coordinate, whose edges
    1367                 :  * are `edge' and `edge->next'. If `edge' already has a trapezoid,
    1368                 :  * then either add it to the traps in `traps', if the trapezoid's
    1369                 :  * right edge differs from `edge->next', or do nothing if the new
    1370                 :  * trapezoid would be a continuation of the existing one. */
    1371                 : static inline cairo_status_t
    1372               0 : _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t  *left,
    1373                 :                                        cairo_bo_edge_t  *right,
    1374                 :                                        int               top,
    1375                 :                                        cairo_traps_t    *traps)
    1376                 : {
    1377                 :     cairo_status_t status;
    1378                 : 
    1379               0 :     if (left->deferred_trap.right == right)
    1380               0 :         return CAIRO_STATUS_SUCCESS;
    1381                 : 
    1382               0 :     if (left->deferred_trap.right != NULL) {
    1383               0 :         if (right != NULL && edges_colinear (left->deferred_trap.right, right))
    1384                 :         {
    1385                 :             /* continuation on right, so just swap edges */
    1386               0 :             left->deferred_trap.right = right;
    1387               0 :             return CAIRO_STATUS_SUCCESS;
    1388                 :         }
    1389                 : 
    1390               0 :         status = _cairo_bo_edge_end_trap (left, top, traps);
    1391               0 :         if (unlikely (status))
    1392               0 :             return status;
    1393                 :     }
    1394                 : 
    1395               0 :     if (right != NULL && ! edges_colinear (left, right)) {
    1396               0 :         left->deferred_trap.top = top;
    1397               0 :         left->deferred_trap.right = right;
    1398                 : 
    1399                 : #if DEBUG_EVENTS
    1400                 :         event_log ("begin trap: %lu %lu %d\n",
    1401                 :                    (long) left,
    1402                 :                    (long) right,
    1403                 :                    top);
    1404                 : #endif
    1405                 :     }
    1406                 : 
    1407               0 :     return CAIRO_STATUS_SUCCESS;
    1408                 : }
    1409                 : 
    1410                 : static inline cairo_status_t
    1411               0 : _active_edges_to_traps (cairo_bo_edge_t         *left,
    1412                 :                         int32_t                  top,
    1413                 :                         cairo_fill_rule_t        fill_rule,
    1414                 :                         cairo_traps_t           *traps)
    1415                 : {
    1416                 :     cairo_bo_edge_t *right;
    1417                 :     cairo_status_t status;
    1418                 : 
    1419                 : #if DEBUG_PRINT_STATE
    1420                 :     printf ("Processing active edges for %x\n", top);
    1421                 : #endif
    1422                 : 
    1423               0 :     if (fill_rule == CAIRO_FILL_RULE_WINDING) {
    1424               0 :         while (left != NULL) {
    1425                 :             int in_out;
    1426                 : 
    1427                 :             /* Greedily search for the closing edge, so that we generate the
    1428                 :              * maximal span width with the minimal number of trapezoids.
    1429                 :              */
    1430               0 :             in_out = left->edge.dir;
    1431                 : 
    1432                 :             /* Check if there is a co-linear edge with an existing trap */
    1433               0 :             right = left->next;
    1434               0 :             if (left->deferred_trap.right == NULL) {
    1435               0 :                 while (right != NULL && right->deferred_trap.right == NULL)
    1436               0 :                     right = right->next;
    1437                 : 
    1438               0 :                 if (right != NULL && edges_colinear (left, right)) {
    1439                 :                     /* continuation on left */
    1440               0 :                     left->deferred_trap = right->deferred_trap;
    1441               0 :                     right->deferred_trap.right = NULL;
    1442                 :                 }
    1443                 :             }
    1444                 : 
    1445                 :             /* End all subsumed traps */
    1446               0 :             right = left->next;
    1447               0 :             while (right != NULL) {
    1448               0 :                 if (right->deferred_trap.right != NULL) {
    1449               0 :                     status = _cairo_bo_edge_end_trap (right, top, traps);
    1450               0 :                     if (unlikely (status))
    1451               0 :                         return status;
    1452                 :                 }
    1453                 : 
    1454               0 :                 in_out += right->edge.dir;
    1455               0 :                 if (in_out == 0) {
    1456                 :                     cairo_bo_edge_t *next;
    1457               0 :                     cairo_bool_t skip = FALSE;
    1458                 : 
    1459                 :                     /* skip co-linear edges */
    1460               0 :                     next = right->next;
    1461               0 :                     if (next != NULL)
    1462               0 :                         skip = edges_colinear (right, next);
    1463                 : 
    1464               0 :                     if (! skip)
    1465               0 :                         break;
    1466                 :                 }
    1467                 : 
    1468               0 :                 right = right->next;
    1469                 :             }
    1470                 : 
    1471               0 :             status = _cairo_bo_edge_start_or_continue_trap (left, right,
    1472                 :                                                             top, traps);
    1473               0 :             if (unlikely (status))
    1474               0 :                 return status;
    1475                 : 
    1476               0 :             left = right;
    1477               0 :             if (left != NULL)
    1478               0 :                 left = left->next;
    1479                 :         }
    1480                 :     } else {
    1481               0 :         while (left != NULL) {
    1482               0 :             int in_out = 0;
    1483                 : 
    1484               0 :             right = left->next;
    1485               0 :             while (right != NULL) {
    1486               0 :                 if (right->deferred_trap.right != NULL) {
    1487               0 :                     status = _cairo_bo_edge_end_trap (right, top, traps);
    1488               0 :                     if (unlikely (status))
    1489               0 :                         return status;
    1490                 :                 }
    1491                 : 
    1492               0 :                 if ((in_out++ & 1) == 0) {
    1493                 :                     cairo_bo_edge_t *next;
    1494               0 :                     cairo_bool_t skip = FALSE;
    1495                 : 
    1496                 :                     /* skip co-linear edges */
    1497               0 :                     next = right->next;
    1498               0 :                     if (next != NULL)
    1499               0 :                         skip = edges_colinear (right, next);
    1500                 : 
    1501               0 :                     if (! skip)
    1502               0 :                         break;
    1503                 :                 }
    1504                 : 
    1505               0 :                 right = right->next;
    1506                 :             }
    1507                 : 
    1508               0 :             status = _cairo_bo_edge_start_or_continue_trap (left, right,
    1509                 :                                                             top, traps);
    1510               0 :             if (unlikely (status))
    1511               0 :                 return status;
    1512                 : 
    1513               0 :             left = right;
    1514               0 :             if (left != NULL)
    1515               0 :                 left = left->next;
    1516                 :         }
    1517                 :     }
    1518                 : 
    1519               0 :     return CAIRO_STATUS_SUCCESS;
    1520                 : }
    1521                 : 
    1522                 : 
    1523                 : /* Execute a single pass of the Bentley-Ottmann algorithm on edges,
    1524                 :  * generating trapezoids according to the fill_rule and appending them
    1525                 :  * to traps. */
    1526                 : static cairo_status_t
    1527               0 : _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
    1528                 :                                             int                  num_events,
    1529                 :                                             cairo_fill_rule_t    fill_rule,
    1530                 :                                             cairo_traps_t       *traps,
    1531                 :                                             int                 *num_intersections)
    1532                 : {
    1533               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */
    1534               0 :     int intersection_count = 0;
    1535                 :     cairo_bo_event_queue_t event_queue;
    1536                 :     cairo_bo_sweep_line_t sweep_line;
    1537                 :     cairo_bo_event_t *event;
    1538                 :     cairo_bo_edge_t *left, *right;
    1539                 :     cairo_bo_edge_t *e1, *e2;
    1540                 : 
    1541                 : #if DEBUG_EVENTS
    1542                 :     {
    1543                 :         int i;
    1544                 : 
    1545                 :         for (i = 0; i < num_events; i++) {
    1546                 :             cairo_bo_start_event_t *event =
    1547                 :                 ((cairo_bo_start_event_t **) start_events)[i];
    1548                 :             event_log ("edge: %lu (%d, %d) (%d, %d) (%d, %d) %d\n",
    1549                 :                        (long) &events[i].edge,
    1550                 :                        event->edge.edge.line.p1.x,
    1551                 :                        event->edge.edge.line.p1.y,
    1552                 :                        event->edge.edge.line.p2.x,
    1553                 :                        event->edge.edge.line.p2.y,
    1554                 :                        event->edge.top,
    1555                 :                        event->edge.bottom,
    1556                 :                        event->edge.edge.dir);
    1557                 :         }
    1558                 :     }
    1559                 : #endif
    1560                 : 
    1561               0 :     _cairo_bo_event_queue_init (&event_queue, start_events, num_events);
    1562               0 :     _cairo_bo_sweep_line_init (&sweep_line);
    1563                 : 
    1564               0 :     while ((event = _cairo_bo_event_dequeue (&event_queue))) {
    1565               0 :         if (event->point.y != sweep_line.current_y) {
    1566               0 :             for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
    1567               0 :                 if (e1->deferred_trap.right != NULL) {
    1568               0 :                     status = _cairo_bo_edge_end_trap (e1,
    1569                 :                                                       e1->edge.bottom,
    1570                 :                                                       traps);
    1571               0 :                     if (unlikely (status))
    1572               0 :                         goto unwind;
    1573                 :                 }
    1574                 :             }
    1575               0 :             sweep_line.stopped = NULL;
    1576                 : 
    1577               0 :             status = _active_edges_to_traps (sweep_line.head,
    1578                 :                                              sweep_line.current_y,
    1579                 :                                              fill_rule, traps);
    1580               0 :             if (unlikely (status))
    1581               0 :                 goto unwind;
    1582                 : 
    1583               0 :             sweep_line.current_y = event->point.y;
    1584                 :         }
    1585                 : 
    1586                 : #if DEBUG_EVENTS
    1587                 :         event_log ("event: %d (%ld, %ld) %lu, %lu\n",
    1588                 :                    event->type,
    1589                 :                    (long) event->point.x,
    1590                 :                    (long) event->point.y,
    1591                 :                    (long) event->e1,
    1592                 :                    (long) event->e2);
    1593                 : #endif
    1594                 : 
    1595               0 :         switch (event->type) {
    1596                 :         case CAIRO_BO_EVENT_TYPE_START:
    1597               0 :             e1 = &((cairo_bo_start_event_t *) event)->edge;
    1598                 : 
    1599               0 :             status = _cairo_bo_sweep_line_insert (&sweep_line, e1);
    1600               0 :             if (unlikely (status))
    1601               0 :                 goto unwind;
    1602                 : 
    1603               0 :             status = _cairo_bo_event_queue_insert_stop (&event_queue, e1);
    1604               0 :             if (unlikely (status))
    1605               0 :                 goto unwind;
    1606                 : 
    1607                 :             /* check to see if this is a continuation of a stopped edge */
    1608                 :             /* XXX change to an infinitesimal lengthening rule */
    1609               0 :             for (left = sweep_line.stopped; left; left = left->next) {
    1610               0 :                 if (e1->edge.top <= left->edge.bottom &&
    1611               0 :                     edges_colinear (e1, left))
    1612                 :                 {
    1613               0 :                     e1->deferred_trap = left->deferred_trap;
    1614               0 :                     if (left->prev != NULL)
    1615               0 :                         left->prev = left->next;
    1616                 :                     else
    1617               0 :                         sweep_line.stopped = left->next;
    1618               0 :                     if (left->next != NULL)
    1619               0 :                         left->next->prev = left->prev;
    1620               0 :                     break;
    1621                 :                 }
    1622                 :             }
    1623                 : 
    1624               0 :             left = e1->prev;
    1625               0 :             right = e1->next;
    1626                 : 
    1627               0 :             if (left != NULL) {
    1628               0 :                 status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1);
    1629               0 :                 if (unlikely (status))
    1630               0 :                     goto unwind;
    1631                 :             }
    1632                 : 
    1633               0 :             if (right != NULL) {
    1634               0 :                 status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
    1635               0 :                 if (unlikely (status))
    1636               0 :                     goto unwind;
    1637                 :             }
    1638                 : 
    1639               0 :             break;
    1640                 : 
    1641                 :         case CAIRO_BO_EVENT_TYPE_STOP:
    1642               0 :             e1 = ((cairo_bo_queue_event_t *) event)->e1;
    1643               0 :             _cairo_bo_event_queue_delete (&event_queue, event);
    1644                 : 
    1645               0 :             left = e1->prev;
    1646               0 :             right = e1->next;
    1647                 : 
    1648               0 :             _cairo_bo_sweep_line_delete (&sweep_line, e1);
    1649                 : 
    1650                 :             /* first, check to see if we have a continuation via a fresh edge */
    1651               0 :             if (e1->deferred_trap.right != NULL) {
    1652               0 :                 e1->next = sweep_line.stopped;
    1653               0 :                 if (sweep_line.stopped != NULL)
    1654               0 :                     sweep_line.stopped->prev = e1;
    1655               0 :                 sweep_line.stopped = e1;
    1656               0 :                 e1->prev = NULL;
    1657                 :             }
    1658                 : 
    1659               0 :             if (left != NULL && right != NULL) {
    1660               0 :                 status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right);
    1661               0 :                 if (unlikely (status))
    1662               0 :                     goto unwind;
    1663                 :             }
    1664                 : 
    1665               0 :             break;
    1666                 : 
    1667                 :         case CAIRO_BO_EVENT_TYPE_INTERSECTION:
    1668               0 :             e1 = ((cairo_bo_queue_event_t *) event)->e1;
    1669               0 :             e2 = ((cairo_bo_queue_event_t *) event)->e2;
    1670               0 :             _cairo_bo_event_queue_delete (&event_queue, event);
    1671                 : 
    1672                 :             /* skip this intersection if its edges are not adjacent */
    1673               0 :             if (e2 != e1->next)
    1674               0 :                 break;
    1675                 : 
    1676               0 :             intersection_count++;
    1677                 : 
    1678               0 :             left = e1->prev;
    1679               0 :             right = e2->next;
    1680                 : 
    1681               0 :             _cairo_bo_sweep_line_swap (&sweep_line, e1, e2);
    1682                 : 
    1683                 :             /* after the swap e2 is left of e1 */
    1684                 : 
    1685               0 :             if (left != NULL) {
    1686               0 :                 status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2);
    1687               0 :                 if (unlikely (status))
    1688               0 :                     goto unwind;
    1689                 :             }
    1690                 : 
    1691               0 :             if (right != NULL) {
    1692               0 :                 status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right);
    1693               0 :                 if (unlikely (status))
    1694               0 :                     goto unwind;
    1695                 :             }
    1696                 : 
    1697               0 :             break;
    1698                 :         }
    1699                 :     }
    1700                 : 
    1701               0 :     *num_intersections = intersection_count;
    1702               0 :     for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
    1703               0 :         if (e1->deferred_trap.right != NULL) {
    1704               0 :             status = _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
    1705               0 :             if (unlikely (status))
    1706               0 :                 break;
    1707                 :         }
    1708                 :     }
    1709                 :  unwind:
    1710               0 :     _cairo_bo_event_queue_fini (&event_queue);
    1711                 : 
    1712                 : #if DEBUG_EVENTS
    1713                 :     event_log ("\n");
    1714                 : #endif
    1715                 : 
    1716               0 :     return status;
    1717                 : }
    1718                 : 
    1719                 : cairo_status_t
    1720               0 : _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t         *traps,
    1721                 :                                            const cairo_polygon_t *polygon,
    1722                 :                                            cairo_fill_rule_t      fill_rule)
    1723                 : {
    1724                 :     int intersections;
    1725                 :     cairo_status_t status;
    1726                 :     cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
    1727                 :     cairo_bo_start_event_t *events;
    1728                 :     cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
    1729                 :     cairo_bo_event_t **event_ptrs;
    1730                 :     int num_events;
    1731                 :     int i;
    1732                 : 
    1733               0 :     num_events = polygon->num_edges;
    1734               0 :     if (unlikely (0 == num_events))
    1735               0 :         return CAIRO_STATUS_SUCCESS;
    1736                 : 
    1737               0 :     events = stack_events;
    1738               0 :     event_ptrs = stack_event_ptrs;
    1739               0 :     if (num_events > ARRAY_LENGTH (stack_events)) {
    1740               0 :         events = _cairo_malloc_ab_plus_c (num_events,
    1741                 :                                           sizeof (cairo_bo_start_event_t) +
    1742                 :                                           sizeof (cairo_bo_event_t *),
    1743                 :                                           sizeof (cairo_bo_event_t *));
    1744               0 :         if (unlikely (events == NULL))
    1745               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1746                 : 
    1747               0 :         event_ptrs = (cairo_bo_event_t **) (events + num_events);
    1748                 :     }
    1749                 : 
    1750               0 :     for (i = 0; i < num_events; i++) {
    1751               0 :         event_ptrs[i] = (cairo_bo_event_t *) &events[i];
    1752                 : 
    1753               0 :         events[i].type = CAIRO_BO_EVENT_TYPE_START;
    1754               0 :         events[i].point.y = polygon->edges[i].top;
    1755               0 :         events[i].point.x =
    1756               0 :             _line_compute_intersection_x_for_y (&polygon->edges[i].line,
    1757               0 :                                                 events[i].point.y);
    1758                 : 
    1759               0 :         events[i].edge.edge = polygon->edges[i];
    1760               0 :         events[i].edge.deferred_trap.right = NULL;
    1761               0 :         events[i].edge.prev = NULL;
    1762               0 :         events[i].edge.next = NULL;
    1763                 :     }
    1764                 : 
    1765                 : #if DEBUG_TRAPS
    1766                 :     dump_edges (events, num_events, "bo-polygon-edges.txt");
    1767                 : #endif
    1768                 : 
    1769                 :     /* XXX: This would be the convenient place to throw in multiple
    1770                 :      * passes of the Bentley-Ottmann algorithm. It would merely
    1771                 :      * require storing the results of each pass into a temporary
    1772                 :      * cairo_traps_t. */
    1773               0 :     status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs,
    1774                 :                                                          num_events,
    1775                 :                                                          fill_rule, traps,
    1776                 :                                                          &intersections);
    1777                 : #if DEBUG_TRAPS
    1778                 :     dump_traps (traps, "bo-polygon-out.txt");
    1779                 : #endif
    1780                 : 
    1781               0 :     if (events != stack_events)
    1782               0 :         free (events);
    1783                 : 
    1784               0 :     return status;
    1785                 : }
    1786                 : 
    1787                 : cairo_status_t
    1788               0 : _cairo_bentley_ottmann_tessellate_traps (cairo_traps_t *traps,
    1789                 :                                          cairo_fill_rule_t fill_rule)
    1790                 : {
    1791                 :     cairo_status_t status;
    1792                 :     cairo_polygon_t polygon;
    1793                 :     int i;
    1794                 : 
    1795               0 :     if (unlikely (0 == traps->num_traps))
    1796               0 :         return CAIRO_STATUS_SUCCESS;
    1797                 : 
    1798                 : #if DEBUG_TRAPS
    1799                 :     dump_traps (traps, "bo-traps-in.txt");
    1800                 : #endif
    1801                 : 
    1802               0 :     _cairo_polygon_init (&polygon);
    1803               0 :     _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
    1804                 : 
    1805               0 :     for (i = 0; i < traps->num_traps; i++) {
    1806               0 :         status = _cairo_polygon_add_line (&polygon,
    1807               0 :                                           &traps->traps[i].left,
    1808               0 :                                           traps->traps[i].top,
    1809               0 :                                           traps->traps[i].bottom,
    1810                 :                                           1);
    1811               0 :         if (unlikely (status))
    1812               0 :             goto CLEANUP;
    1813                 : 
    1814               0 :         status = _cairo_polygon_add_line (&polygon,
    1815               0 :                                           &traps->traps[i].right,
    1816               0 :                                           traps->traps[i].top,
    1817               0 :                                           traps->traps[i].bottom,
    1818                 :                                           -1);
    1819               0 :         if (unlikely (status))
    1820               0 :             goto CLEANUP;
    1821                 :     }
    1822                 : 
    1823               0 :     _cairo_traps_clear (traps);
    1824               0 :     status = _cairo_bentley_ottmann_tessellate_polygon (traps,
    1825                 :                                                         &polygon,
    1826                 :                                                         fill_rule);
    1827                 : 
    1828                 : #if DEBUG_TRAPS
    1829                 :     dump_traps (traps, "bo-traps-out.txt");
    1830                 : #endif
    1831                 : 
    1832                 :   CLEANUP:
    1833               0 :     _cairo_polygon_fini (&polygon);
    1834                 : 
    1835               0 :     return status;
    1836                 : }
    1837                 : 
    1838                 : #if 0
    1839                 : static cairo_bool_t
    1840                 : edges_have_an_intersection_quadratic (cairo_bo_edge_t   *edges,
    1841                 :                                       int                num_edges)
    1842                 : 
    1843                 : {
    1844                 :     int i, j;
    1845                 :     cairo_bo_edge_t *a, *b;
    1846                 :     cairo_bo_point32_t intersection;
    1847                 : 
    1848                 :     /* We must not be given any upside-down edges. */
    1849                 :     for (i = 0; i < num_edges; i++) {
    1850                 :         assert (_cairo_bo_point32_compare (&edges[i].top, &edges[i].bottom) < 0);
    1851                 :         edges[i].line.p1.x <<= CAIRO_BO_GUARD_BITS;
    1852                 :         edges[i].line.p1.y <<= CAIRO_BO_GUARD_BITS;
    1853                 :         edges[i].line.p2.x <<= CAIRO_BO_GUARD_BITS;
    1854                 :         edges[i].line.p2.y <<= CAIRO_BO_GUARD_BITS;
    1855                 :     }
    1856                 : 
    1857                 :     for (i = 0; i < num_edges; i++) {
    1858                 :         for (j = 0; j < num_edges; j++) {
    1859                 :             if (i == j)
    1860                 :                 continue;
    1861                 : 
    1862                 :             a = &edges[i];
    1863                 :             b = &edges[j];
    1864                 : 
    1865                 :             if (! _cairo_bo_edge_intersect (a, b, &intersection))
    1866                 :                 continue;
    1867                 : 
    1868                 :             printf ("Found intersection (%d,%d) between (%d,%d)-(%d,%d) and (%d,%d)-(%d,%d)\n",
    1869                 :                     intersection.x,
    1870                 :                     intersection.y,
    1871                 :                     a->line.p1.x, a->line.p1.y,
    1872                 :                     a->line.p2.x, a->line.p2.y,
    1873                 :                     b->line.p1.x, b->line.p1.y,
    1874                 :                     b->line.p2.x, b->line.p2.y);
    1875                 : 
    1876                 :             return TRUE;
    1877                 :         }
    1878                 :     }
    1879                 :     return FALSE;
    1880                 : }
    1881                 : 
    1882                 : #define TEST_MAX_EDGES 10
    1883                 : 
    1884                 : typedef struct test {
    1885                 :     const char *name;
    1886                 :     const char *description;
    1887                 :     int num_edges;
    1888                 :     cairo_bo_edge_t edges[TEST_MAX_EDGES];
    1889                 : } test_t;
    1890                 : 
    1891                 : static test_t
    1892                 : tests[] = {
    1893                 :     {
    1894                 :         "3 near misses",
    1895                 :         "3 edges all intersecting very close to each other",
    1896                 :         3,
    1897                 :         {
    1898                 :             { { 4, 2}, {0, 0}, { 9, 9}, NULL, NULL },
    1899                 :             { { 7, 2}, {0, 0}, { 2, 3}, NULL, NULL },
    1900                 :             { { 5, 2}, {0, 0}, { 1, 7}, NULL, NULL }
    1901                 :         }
    1902                 :     },
    1903                 :     {
    1904                 :         "inconsistent data",
    1905                 :         "Derived from random testing---was leading to skip list and edge list disagreeing.",
    1906                 :         2,
    1907                 :         {
    1908                 :             { { 2, 3}, {0, 0}, { 8, 9}, NULL, NULL },
    1909                 :             { { 2, 3}, {0, 0}, { 6, 7}, NULL, NULL }
    1910                 :         }
    1911                 :     },
    1912                 :     {
    1913                 :         "failed sort",
    1914                 :         "A test derived from random testing that leads to an inconsistent sort --- looks like we just can't attempt to validate the sweep line with edge_compare?",
    1915                 :         3,
    1916                 :         {
    1917                 :             { { 6, 2}, {0, 0}, { 6, 5}, NULL, NULL },
    1918                 :             { { 3, 5}, {0, 0}, { 5, 6}, NULL, NULL },
    1919                 :             { { 9, 2}, {0, 0}, { 5, 6}, NULL, NULL },
    1920                 :         }
    1921                 :     },
    1922                 :     {
    1923                 :         "minimal-intersection",
    1924                 :         "Intersection of a two from among the smallest possible edges.",
    1925                 :         2,
    1926                 :         {
    1927                 :             { { 0, 0}, {0, 0}, { 1, 1}, NULL, NULL },
    1928                 :             { { 1, 0}, {0, 0}, { 0, 1}, NULL, NULL }
    1929                 :         }
    1930                 :     },
    1931                 :     {
    1932                 :         "simple",
    1933                 :         "A simple intersection of two edges at an integer (2,2).",
    1934                 :         2,
    1935                 :         {
    1936                 :             { { 1, 1}, {0, 0}, { 3, 3}, NULL, NULL },
    1937                 :             { { 2, 1}, {0, 0}, { 2, 3}, NULL, NULL }
    1938                 :         }
    1939                 :     },
    1940                 :     {
    1941                 :         "bend-to-horizontal",
    1942                 :         "With intersection truncation one edge bends to horizontal",
    1943                 :         2,
    1944                 :         {
    1945                 :             { { 9, 1}, {0, 0}, {3, 7}, NULL, NULL },
    1946                 :             { { 3, 5}, {0, 0}, {9, 9}, NULL, NULL }
    1947                 :         }
    1948                 :     }
    1949                 : };
    1950                 : 
    1951                 : /*
    1952                 :     {
    1953                 :         "endpoint",
    1954                 :         "An intersection that occurs at the endpoint of a segment.",
    1955                 :         {
    1956                 :             { { 4, 6}, { 5, 6}, NULL, { { NULL }} },
    1957                 :             { { 4, 5}, { 5, 7}, NULL, { { NULL }} },
    1958                 :             { { 0, 0}, { 0, 0}, NULL, { { NULL }} },
    1959                 :         }
    1960                 :     }
    1961                 :     {
    1962                 :         name = "overlapping",
    1963                 :         desc = "Parallel segments that share an endpoint, with different slopes.",
    1964                 :         edges = {
    1965                 :             { top = { x = 2, y = 0}, bottom = { x = 1, y = 1}},
    1966                 :             { top = { x = 2, y = 0}, bottom = { x = 0, y = 2}},
    1967                 :             { top = { x = 0, y = 3}, bottom = { x = 1, y = 3}},
    1968                 :             { top = { x = 0, y = 3}, bottom = { x = 2, y = 3}},
    1969                 :             { top = { x = 0, y = 4}, bottom = { x = 0, y = 6}},
    1970                 :             { top = { x = 0, y = 5}, bottom = { x = 0, y = 6}}
    1971                 :         }
    1972                 :     },
    1973                 :     {
    1974                 :         name = "hobby_stage_3",
    1975                 :         desc = "A particularly tricky part of the 3rd stage of the 'hobby' test below.",
    1976                 :         edges = {
    1977                 :             { top = { x = -1, y = -2}, bottom = { x =  4, y = 2}},
    1978                 :             { top = { x =  5, y =  3}, bottom = { x =  9, y = 5}},
    1979                 :             { top = { x =  5, y =  3}, bottom = { x =  6, y = 3}},
    1980                 :         }
    1981                 :     },
    1982                 :     {
    1983                 :         name = "hobby",
    1984                 :         desc = "Example from John Hobby's paper. Requires 3 passes of the iterative algorithm.",
    1985                 :         edges = {
    1986                 :             { top = { x =   0, y =   0}, bottom = { x =   9, y =   5}},
    1987                 :             { top = { x =   0, y =   0}, bottom = { x =  13, y =   6}},
    1988                 :             { top = { x =  -1, y =  -2}, bottom = { x =   9, y =   5}}
    1989                 :         }
    1990                 :     },
    1991                 :     {
    1992                 :         name = "slope",
    1993                 :         desc = "Edges with same start/stop points but different slopes",
    1994                 :         edges = {
    1995                 :             { top = { x = 4, y = 1}, bottom = { x = 6, y = 3}},
    1996                 :             { top = { x = 4, y = 1}, bottom = { x = 2, y = 3}},
    1997                 :             { top = { x = 2, y = 4}, bottom = { x = 4, y = 6}},
    1998                 :             { top = { x = 6, y = 4}, bottom = { x = 4, y = 6}}
    1999                 :         }
    2000                 :     },
    2001                 :     {
    2002                 :         name = "horizontal",
    2003                 :         desc = "Test of a horizontal edge",
    2004                 :         edges = {
    2005                 :             { top = { x = 1, y = 1}, bottom = { x = 6, y = 6}},
    2006                 :             { top = { x = 2, y = 3}, bottom = { x = 5, y = 3}}
    2007                 :         }
    2008                 :     },
    2009                 :     {
    2010                 :         name = "vertical",
    2011                 :         desc = "Test of a vertical edge",
    2012                 :         edges = {
    2013                 :             { top = { x = 5, y = 1}, bottom = { x = 5, y = 7}},
    2014                 :             { top = { x = 2, y = 4}, bottom = { x = 8, y = 5}}
    2015                 :         }
    2016                 :     },
    2017                 :     {
    2018                 :         name = "congruent",
    2019                 :         desc = "Two overlapping edges with the same slope",
    2020                 :         edges = {
    2021                 :             { top = { x = 5, y = 1}, bottom = { x = 5, y = 7}},
    2022                 :             { top = { x = 5, y = 2}, bottom = { x = 5, y = 6}},
    2023                 :             { top = { x = 2, y = 4}, bottom = { x = 8, y = 5}}
    2024                 :         }
    2025                 :     },
    2026                 :     {
    2027                 :         name = "multi",
    2028                 :         desc = "Several segments with a common intersection point",
    2029                 :         edges = {
    2030                 :             { top = { x = 1, y = 2}, bottom = { x = 5, y = 4} },
    2031                 :             { top = { x = 1, y = 1}, bottom = { x = 5, y = 5} },
    2032                 :             { top = { x = 2, y = 1}, bottom = { x = 4, y = 5} },
    2033                 :             { top = { x = 4, y = 1}, bottom = { x = 2, y = 5} },
    2034                 :             { top = { x = 5, y = 1}, bottom = { x = 1, y = 5} },
    2035                 :             { top = { x = 5, y = 2}, bottom = { x = 1, y = 4} }
    2036                 :         }
    2037                 :     }
    2038                 : };
    2039                 : */
    2040                 : 
    2041                 : static int
    2042                 : run_test (const char            *test_name,
    2043                 :           cairo_bo_edge_t       *test_edges,
    2044                 :           int                    num_edges)
    2045                 : {
    2046                 :     int i, intersections, passes;
    2047                 :     cairo_bo_edge_t *edges;
    2048                 :     cairo_array_t intersected_edges;
    2049                 : 
    2050                 :     printf ("Testing: %s\n", test_name);
    2051                 : 
    2052                 :     _cairo_array_init (&intersected_edges, sizeof (cairo_bo_edge_t));
    2053                 : 
    2054                 :     intersections = _cairo_bentley_ottmann_intersect_edges (test_edges, num_edges, &intersected_edges);
    2055                 :     if (intersections)
    2056                 :         printf ("Pass 1 found %d intersections:\n", intersections);
    2057                 : 
    2058                 : 
    2059                 :     /* XXX: Multi-pass Bentley-Ottmmann. Preferable would be to add a
    2060                 :      * pass of Hobby's tolerance-square algorithm instead. */
    2061                 :     passes = 1;
    2062                 :     while (intersections) {
    2063                 :         int num_edges = _cairo_array_num_elements (&intersected_edges);
    2064                 :         passes++;
    2065                 :         edges = _cairo_malloc_ab (num_edges, sizeof (cairo_bo_edge_t));
    2066                 :         assert (edges != NULL);
    2067                 :         memcpy (edges, _cairo_array_index (&intersected_edges, 0), num_edges * sizeof (cairo_bo_edge_t));
    2068                 :         _cairo_array_fini (&intersected_edges);
    2069                 :         _cairo_array_init (&intersected_edges, sizeof (cairo_bo_edge_t));
    2070                 :         intersections = _cairo_bentley_ottmann_intersect_edges (edges, num_edges, &intersected_edges);
    2071                 :         free (edges);
    2072                 : 
    2073                 :         if (intersections){
    2074                 :             printf ("Pass %d found %d remaining intersections:\n", passes, intersections);
    2075                 :         } else {
    2076                 :             if (passes > 3)
    2077                 :                 for (i = 0; i < passes; i++)
    2078                 :                     printf ("*");
    2079                 :             printf ("No remainining intersections found after pass %d\n", passes);
    2080                 :         }
    2081                 :     }
    2082                 : 
    2083                 :     if (edges_have_an_intersection_quadratic (_cairo_array_index (&intersected_edges, 0),
    2084                 :                                               _cairo_array_num_elements (&intersected_edges)))
    2085                 :         printf ("*** FAIL ***\n");
    2086                 :     else
    2087                 :         printf ("PASS\n");
    2088                 : 
    2089                 :     _cairo_array_fini (&intersected_edges);
    2090                 : 
    2091                 :     return 0;
    2092                 : }
    2093                 : 
    2094                 : #define MAX_RANDOM 300
    2095                 : 
    2096                 : int
    2097                 : main (void)
    2098                 : {
    2099                 :     char random_name[] = "random-XX";
    2100                 :     cairo_bo_edge_t random_edges[MAX_RANDOM], *edge;
    2101                 :     unsigned int i, num_random;
    2102                 :     test_t *test;
    2103                 : 
    2104                 :     for (i = 0; i < ARRAY_LENGTH (tests); i++) {
    2105                 :         test = &tests[i];
    2106                 :         run_test (test->name, test->edges, test->num_edges);
    2107                 :     }
    2108                 : 
    2109                 :     for (num_random = 0; num_random < MAX_RANDOM; num_random++) {
    2110                 :         srand (0);
    2111                 :         for (i = 0; i < num_random; i++) {
    2112                 :             do {
    2113                 :                 edge = &random_edges[i];
    2114                 :                 edge->line.p1.x = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
    2115                 :                 edge->line.p1.y = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
    2116                 :                 edge->line.p2.x = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
    2117                 :                 edge->line.p2.y = (int32_t) (10.0 * (rand() / (RAND_MAX + 1.0)));
    2118                 :                 if (edge->line.p1.y > edge->line.p2.y) {
    2119                 :                     int32_t tmp = edge->line.p1.y;
    2120                 :                     edge->line.p1.y = edge->line.p2.y;
    2121                 :                     edge->line.p2.y = tmp;
    2122                 :                 }
    2123                 :             } while (edge->line.p1.y == edge->line.p2.y);
    2124                 :         }
    2125                 : 
    2126                 :         sprintf (random_name, "random-%02d", num_random);
    2127                 : 
    2128                 :         run_test (random_name, random_edges, num_random);
    2129                 :     }
    2130                 : 
    2131                 :     return 0;
    2132                 : }
    2133                 : #endif

Generated by: LCOV version 1.7