Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-bentley-ottmann-rectilinear.c
Line
Count
Source (jump to first uncovered line)
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-boxes-private.h"
42
#include "cairo-combsort-inline.h"
43
#include "cairo-error-private.h"
44
#include "cairo-traps-private.h"
45
46
typedef struct _cairo_bo_edge cairo_bo_edge_t;
47
typedef struct _cairo_bo_trap cairo_bo_trap_t;
48
49
/* A deferred trapezoid of an edge */
50
struct _cairo_bo_trap {
51
    cairo_bo_edge_t *right;
52
    int32_t top;
53
};
54
55
struct _cairo_bo_edge {
56
    cairo_edge_t edge;
57
    cairo_bo_edge_t *prev;
58
    cairo_bo_edge_t *next;
59
    cairo_bo_trap_t deferred_trap;
60
};
61
62
typedef enum {
63
    CAIRO_BO_EVENT_TYPE_START,
64
    CAIRO_BO_EVENT_TYPE_STOP
65
} cairo_bo_event_type_t;
66
67
typedef struct _cairo_bo_event {
68
    cairo_bo_event_type_t type;
69
    cairo_point_t point;
70
    cairo_bo_edge_t *edge;
71
} cairo_bo_event_t;
72
73
typedef struct _cairo_bo_sweep_line {
74
    cairo_bo_event_t **events;
75
    cairo_bo_edge_t *head;
76
    cairo_bo_edge_t *stopped;
77
    int32_t current_y;
78
    cairo_bo_edge_t *current_edge;
79
} cairo_bo_sweep_line_t;
80
81
static inline int
82
_cairo_point_compare (const cairo_point_t *a,
83
          const cairo_point_t *b)
84
57.3k
{
85
57.3k
    int cmp;
86
87
57.3k
    cmp = a->y - b->y;
88
57.3k
    if (likely (cmp))
89
23.0k
  return cmp;
90
91
34.3k
    return a->x - b->x;
92
57.3k
}
93
94
static inline int
95
_cairo_bo_edge_compare (const cairo_bo_edge_t *a,
96
      const cairo_bo_edge_t *b)
97
5.83k
{
98
5.83k
    int cmp;
99
100
5.83k
    cmp = a->edge.line.p1.x - b->edge.line.p1.x;
101
5.83k
    if (likely (cmp))
102
2.28k
  return cmp;
103
104
3.54k
    return b->edge.bottom - a->edge.bottom;
105
5.83k
}
106
107
static inline int
108
cairo_bo_event_compare (const cairo_bo_event_t *a,
109
      const cairo_bo_event_t *b)
110
57.3k
{
111
57.3k
    int cmp;
112
113
57.3k
    cmp = _cairo_point_compare (&a->point, &b->point);
114
57.3k
    if (likely (cmp))
115
34.4k
  return cmp;
116
117
22.9k
    cmp = a->type - b->type;
118
22.9k
    if (cmp)
119
0
  return cmp;
120
121
22.9k
    return a - b;
122
22.9k
}
123
124
static inline cairo_bo_event_t *
125
_cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line)
126
27.8k
{
127
27.8k
    return *sweep_line->events++;
128
27.8k
}
129
130
CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort,
131
      cairo_bo_event_t *,
132
      cairo_bo_event_compare)
133
134
static void
135
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
136
         cairo_bo_event_t **events,
137
         int        num_events)
138
5.39k
{
139
5.39k
    _cairo_bo_event_queue_sort (events, num_events);
140
5.39k
    events[num_events] = NULL;
141
5.39k
    sweep_line->events = events;
142
143
5.39k
    sweep_line->head = NULL;
144
5.39k
    sweep_line->current_y = INT32_MIN;
145
5.39k
    sweep_line->current_edge = NULL;
146
5.39k
}
147
148
static void
149
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t  *sweep_line,
150
           cairo_bo_edge_t    *edge)
151
11.2k
{
152
11.2k
    if (sweep_line->current_edge != NULL) {
153
5.82k
  cairo_bo_edge_t *prev, *next;
154
5.82k
  int cmp;
155
156
5.82k
  cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge);
157
5.82k
  if (cmp < 0) {
158
2.26k
      prev = sweep_line->current_edge;
159
2.26k
      next = prev->next;
160
2.26k
      while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0)
161
0
    prev = next, next = prev->next;
162
163
2.26k
      prev->next = edge;
164
2.26k
      edge->prev = prev;
165
2.26k
      edge->next = next;
166
2.26k
      if (next != NULL)
167
5
    next->prev = edge;
168
3.55k
  } else if (cmp > 0) {
169
10
      next = sweep_line->current_edge;
170
10
      prev = next->prev;
171
15
      while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0)
172
5
    next = prev, prev = next->prev;
173
174
10
      next->prev = edge;
175
10
      edge->next = next;
176
10
      edge->prev = prev;
177
10
      if (prev != NULL)
178
0
    prev->next = edge;
179
10
      else
180
10
    sweep_line->head = edge;
181
3.54k
  } else {
182
3.54k
      prev = sweep_line->current_edge;
183
3.54k
      edge->prev = prev;
184
3.54k
      edge->next = prev->next;
185
3.54k
      if (prev->next != NULL)
186
0
    prev->next->prev = edge;
187
3.54k
      prev->next = edge;
188
3.54k
  }
189
5.82k
    } else {
190
5.39k
  sweep_line->head = edge;
191
5.39k
    }
192
193
11.2k
    sweep_line->current_edge = edge;
194
11.2k
}
195
196
static void
197
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t  *sweep_line,
198
           cairo_bo_edge_t  *edge)
199
11.2k
{
200
11.2k
    if (edge->prev != NULL)
201
15
  edge->prev->next = edge->next;
202
11.2k
    else
203
11.2k
  sweep_line->head = edge->next;
204
205
11.2k
    if (edge->next != NULL)
206
5.81k
  edge->next->prev = edge->prev;
207
208
11.2k
    if (sweep_line->current_edge == edge)
209
5.39k
  sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
210
11.2k
}
211
212
static inline cairo_bool_t
213
edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
214
5.60k
{
215
5.60k
    return a->edge.line.p1.x == b->edge.line.p1.x;
216
5.60k
}
217
218
static cairo_status_t
219
_cairo_bo_edge_end_trap (cairo_bo_edge_t  *left,
220
       int32_t     bot,
221
       cairo_bool_t    do_traps,
222
       void     *container)
223
2.26k
{
224
2.26k
    cairo_bo_trap_t *trap = &left->deferred_trap;
225
2.26k
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
226
227
    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
228
2.26k
    if (likely (trap->top < bot)) {
229
2.26k
  if (do_traps) {
230
0
      _cairo_traps_add_trap (container,
231
0
           trap->top, bot,
232
0
           &left->edge.line, &trap->right->edge.line);
233
0
      status =  _cairo_traps_status ((cairo_traps_t *) container);
234
2.26k
  } else {
235
2.26k
      cairo_box_t box;
236
237
2.26k
      box.p1.x = left->edge.line.p1.x;
238
2.26k
      box.p1.y = trap->top;
239
2.26k
      box.p2.x = trap->right->edge.line.p1.x;
240
2.26k
      box.p2.y = bot;
241
2.26k
      status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box);
242
2.26k
  }
243
2.26k
    }
244
245
2.26k
    trap->right = NULL;
246
247
2.26k
    return status;
248
2.26k
}
249
250
/* Start a new trapezoid at the given top y coordinate, whose edges
251
 * are `edge' and `edge->next'. If `edge' already has a trapezoid,
252
 * then either add it to the traps in `traps', if the trapezoid's
253
 * right edge differs from `edge->next', or do nothing if the new
254
 * trapezoid would be a continuation of the existing one. */
255
static inline cairo_status_t
256
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t  *left,
257
               cairo_bo_edge_t  *right,
258
               int               top,
259
               cairo_bool_t  do_traps,
260
               void   *container)
261
5.40k
{
262
5.40k
    cairo_status_t status;
263
264
5.40k
    if (left->deferred_trap.right == right)
265
0
  return CAIRO_STATUS_SUCCESS;
266
267
5.40k
    if (left->deferred_trap.right != NULL) {
268
0
  if (right != NULL && edges_collinear (left->deferred_trap.right, right))
269
0
  {
270
      /* continuation on right, so just swap edges */
271
0
      left->deferred_trap.right = right;
272
0
      return CAIRO_STATUS_SUCCESS;
273
0
  }
274
275
0
  status = _cairo_bo_edge_end_trap (left, top, do_traps, container);
276
0
  if (unlikely (status))
277
0
      return status;
278
0
    }
279
280
5.40k
    if (right != NULL && ! edges_collinear (left, right)) {
281
2.26k
  left->deferred_trap.top = top;
282
2.26k
  left->deferred_trap.right = right;
283
2.26k
    }
284
285
5.40k
    return CAIRO_STATUS_SUCCESS;
286
5.40k
}
287
288
static inline cairo_status_t
289
_active_edges_to_traps (cairo_bo_edge_t   *left,
290
      int32_t      top,
291
      cairo_fill_rule_t  fill_rule,
292
      cairo_bool_t     do_traps,
293
      void      *container)
294
10.7k
{
295
10.7k
    cairo_bo_edge_t *right;
296
10.7k
    cairo_status_t status;
297
298
10.7k
    if (fill_rule == CAIRO_FILL_RULE_WINDING) {
299
0
  while (left != NULL) {
300
0
      int in_out;
301
302
      /* Greedily search for the closing edge, so that we generate the
303
       * maximal span width with the minimal number of trapezoids.
304
       */
305
0
      in_out = left->edge.dir;
306
307
      /* Check if there is a co-linear edge with an existing trap */
308
0
      right = left->next;
309
0
      if (left->deferred_trap.right == NULL) {
310
0
    while (right != NULL && right->deferred_trap.right == NULL)
311
0
        right = right->next;
312
313
0
    if (right != NULL && edges_collinear (left, right)) {
314
        /* continuation on left */
315
0
        left->deferred_trap = right->deferred_trap;
316
0
        right->deferred_trap.right = NULL;
317
0
    }
318
0
      }
319
320
      /* End all subsumed traps */
321
0
      right = left->next;
322
0
      while (right != NULL) {
323
0
    if (right->deferred_trap.right != NULL) {
324
0
        status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
325
0
        if (unlikely (status))
326
0
      return status;
327
0
    }
328
329
0
    in_out += right->edge.dir;
330
0
    if (in_out == 0) {
331
        /* skip co-linear edges */
332
0
        if (right->next == NULL ||
333
0
      ! edges_collinear (right, right->next))
334
0
        {
335
0
      break;
336
0
        }
337
0
    }
338
339
0
    right = right->next;
340
0
      }
341
342
0
      status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
343
0
                  do_traps, container);
344
0
      if (unlikely (status))
345
0
    return status;
346
347
0
      left = right;
348
0
      if (left != NULL)
349
0
    left = left->next;
350
0
  }
351
10.7k
    } else {
352
16.2k
  while (left != NULL) {
353
5.40k
      int in_out = 0;
354
355
5.40k
      right = left->next;
356
5.81k
      while (right != NULL) {
357
5.81k
    if (right->deferred_trap.right != NULL) {
358
0
        status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
359
0
        if (unlikely (status))
360
0
      return status;
361
0
    }
362
363
5.81k
    if ((in_out++ & 1) == 0) {
364
5.60k
        cairo_bo_edge_t *next;
365
5.60k
        cairo_bool_t skip = FALSE;
366
367
        /* skip co-linear edges */
368
5.60k
        next = right->next;
369
5.60k
        if (next != NULL)
370
205
      skip = edges_collinear (right, next);
371
372
5.60k
        if (! skip)
373
5.40k
      break;
374
5.60k
    }
375
376
410
    right = right->next;
377
410
      }
378
379
5.40k
      status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
380
5.40k
                  do_traps, container);
381
5.40k
      if (unlikely (status))
382
0
    return status;
383
384
5.40k
      left = right;
385
5.40k
      if (left != NULL)
386
5.40k
    left = left->next;
387
5.40k
  }
388
10.7k
    }
389
390
10.7k
    return CAIRO_STATUS_SUCCESS;
391
10.7k
}
392
393
static cairo_status_t
394
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t   **start_events,
395
                 int       num_events,
396
                 cairo_fill_rule_t   fill_rule,
397
                 cairo_bool_t    do_traps,
398
                 void     *container)
399
5.39k
{
400
5.39k
    cairo_bo_sweep_line_t sweep_line;
401
5.39k
    cairo_bo_event_t *event;
402
5.39k
    cairo_status_t status;
403
404
5.39k
    _cairo_bo_sweep_line_init (&sweep_line, start_events, num_events);
405
406
27.8k
    while ((event = _cairo_bo_event_dequeue (&sweep_line))) {
407
22.4k
  if (event->point.y != sweep_line.current_y) {
408
10.7k
      status = _active_edges_to_traps (sweep_line.head,
409
10.7k
               sweep_line.current_y,
410
10.7k
               fill_rule, do_traps, container);
411
10.7k
      if (unlikely (status))
412
0
    return status;
413
414
10.7k
      sweep_line.current_y = event->point.y;
415
10.7k
  }
416
417
22.4k
  switch (event->type) {
418
11.2k
  case CAIRO_BO_EVENT_TYPE_START:
419
11.2k
      _cairo_bo_sweep_line_insert (&sweep_line, event->edge);
420
11.2k
      break;
421
422
11.2k
  case CAIRO_BO_EVENT_TYPE_STOP:
423
11.2k
      _cairo_bo_sweep_line_delete (&sweep_line, event->edge);
424
425
11.2k
      if (event->edge->deferred_trap.right != NULL) {
426
2.26k
    status = _cairo_bo_edge_end_trap (event->edge,
427
2.26k
              sweep_line.current_y,
428
2.26k
              do_traps, container);
429
2.26k
    if (unlikely (status))
430
0
        return status;
431
2.26k
      }
432
433
11.2k
      break;
434
22.4k
  }
435
22.4k
    }
436
437
5.39k
    return CAIRO_STATUS_SUCCESS;
438
5.39k
}
439
440
cairo_status_t
441
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
442
                cairo_fill_rule_t   fill_rule,
443
                cairo_boxes_t *boxes)
444
5.39k
{
445
5.39k
    cairo_status_t status;
446
5.39k
    cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
447
5.39k
    cairo_bo_event_t *events;
448
5.39k
    cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
449
5.39k
    cairo_bo_event_t **event_ptrs;
450
5.39k
    cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
451
5.39k
    cairo_bo_edge_t *edges;
452
5.39k
    int num_events;
453
5.39k
    int i, j;
454
455
5.39k
    if (unlikely (polygon->num_edges == 0))
456
1
  return CAIRO_STATUS_SUCCESS;
457
458
5.39k
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
459
5.39k
    if (unlikely (polygon->num_edges > 100000))
460
0
  return CAIRO_STATUS_SUCCESS;
461
5.39k
#endif
462
463
5.39k
    num_events = 2 * polygon->num_edges;
464
465
5.39k
    events = stack_events;
466
5.39k
    event_ptrs = stack_event_ptrs;
467
5.39k
    edges = stack_edges;
468
5.39k
    if (num_events > ARRAY_LENGTH (stack_events)) {
469
3
  events = _cairo_malloc_ab_plus_c (num_events,
470
3
            sizeof (cairo_bo_event_t) +
471
3
            sizeof (cairo_bo_edge_t) +
472
3
            sizeof (cairo_bo_event_t *),
473
3
            sizeof (cairo_bo_event_t *));
474
3
  if (unlikely (events == NULL))
475
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
476
477
3
  event_ptrs = (cairo_bo_event_t **) (events + num_events);
478
3
  edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
479
3
    }
480
481
16.6k
    for (i = j = 0; i < polygon->num_edges; i++) {
482
11.2k
  edges[i].edge = polygon->edges[i];
483
11.2k
  edges[i].deferred_trap.right = NULL;
484
11.2k
  edges[i].prev = NULL;
485
11.2k
  edges[i].next = NULL;
486
487
11.2k
  event_ptrs[j] = &events[j];
488
11.2k
  events[j].type = CAIRO_BO_EVENT_TYPE_START;
489
11.2k
  events[j].point.y = polygon->edges[i].top;
490
11.2k
  events[j].point.x = polygon->edges[i].line.p1.x;
491
11.2k
  events[j].edge = &edges[i];
492
11.2k
  j++;
493
494
11.2k
  event_ptrs[j] = &events[j];
495
11.2k
  events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
496
11.2k
  events[j].point.y = polygon->edges[i].bottom;
497
11.2k
  events[j].point.x = polygon->edges[i].line.p1.x;
498
11.2k
  events[j].edge = &edges[i];
499
11.2k
  j++;
500
11.2k
    }
501
502
5.39k
    status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
503
5.39k
                  fill_rule,
504
5.39k
                  FALSE, boxes);
505
5.39k
    if (events != stack_events)
506
3
  free (events);
507
508
5.39k
    return status;
509
5.39k
}
510
511
cairo_status_t
512
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
513
                 cairo_fill_rule_t fill_rule)
514
0
{
515
0
    cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
516
0
    cairo_bo_event_t *events;
517
0
    cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
518
0
    cairo_bo_event_t **event_ptrs;
519
0
    cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
520
0
    cairo_bo_edge_t *edges;
521
0
    cairo_status_t status;
522
0
    int i, j, k;
523
524
0
    if (unlikely (traps->num_traps == 0))
525
0
  return CAIRO_STATUS_SUCCESS;
526
527
0
    assert (traps->is_rectilinear);
528
529
0
    i = 4 * traps->num_traps;
530
531
0
    events = stack_events;
532
0
    event_ptrs = stack_event_ptrs;
533
0
    edges = stack_edges;
534
0
    if (i > ARRAY_LENGTH (stack_events)) {
535
0
  events = _cairo_malloc_ab_plus_c (i,
536
0
            sizeof (cairo_bo_event_t) +
537
0
            sizeof (cairo_bo_edge_t) +
538
0
            sizeof (cairo_bo_event_t *),
539
0
            sizeof (cairo_bo_event_t *));
540
0
  if (unlikely (events == NULL))
541
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
542
543
0
  event_ptrs = (cairo_bo_event_t **) (events + i);
544
0
  edges = (cairo_bo_edge_t *) (event_ptrs + i + 1);
545
0
    }
546
547
0
    for (i = j = k = 0; i < traps->num_traps; i++) {
548
0
  edges[k].edge.top = traps->traps[i].top;
549
0
  edges[k].edge.bottom = traps->traps[i].bottom;
550
0
  edges[k].edge.line = traps->traps[i].left;
551
0
  edges[k].edge.dir = 1;
552
0
  edges[k].deferred_trap.right = NULL;
553
0
  edges[k].prev = NULL;
554
0
  edges[k].next = NULL;
555
556
0
  event_ptrs[j] = &events[j];
557
0
  events[j].type = CAIRO_BO_EVENT_TYPE_START;
558
0
  events[j].point.y = traps->traps[i].top;
559
0
  events[j].point.x = traps->traps[i].left.p1.x;
560
0
  events[j].edge = &edges[k];
561
0
  j++;
562
563
0
  event_ptrs[j] = &events[j];
564
0
  events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
565
0
  events[j].point.y = traps->traps[i].bottom;
566
0
  events[j].point.x = traps->traps[i].left.p1.x;
567
0
  events[j].edge = &edges[k];
568
0
  j++;
569
0
  k++;
570
571
0
  edges[k].edge.top = traps->traps[i].top;
572
0
  edges[k].edge.bottom = traps->traps[i].bottom;
573
0
  edges[k].edge.line = traps->traps[i].right;
574
0
  edges[k].edge.dir = -1;
575
0
  edges[k].deferred_trap.right = NULL;
576
0
  edges[k].prev = NULL;
577
0
  edges[k].next = NULL;
578
579
0
  event_ptrs[j] = &events[j];
580
0
  events[j].type = CAIRO_BO_EVENT_TYPE_START;
581
0
  events[j].point.y = traps->traps[i].top;
582
0
  events[j].point.x = traps->traps[i].right.p1.x;
583
0
  events[j].edge = &edges[k];
584
0
  j++;
585
586
0
  event_ptrs[j] = &events[j];
587
0
  events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
588
0
  events[j].point.y = traps->traps[i].bottom;
589
0
  events[j].point.x = traps->traps[i].right.p1.x;
590
0
  events[j].edge = &edges[k];
591
0
  j++;
592
0
  k++;
593
0
    }
594
595
0
    _cairo_traps_clear (traps);
596
0
    status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
597
0
                  fill_rule,
598
0
                  TRUE, traps);
599
0
    traps->is_rectilinear = TRUE;
600
601
0
    if (events != stack_events)
602
0
  free (events);
603
604
0
    return status;
605
0
}