Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-bentley-ottmann-rectilinear.c
Line
Count
Source
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
36.6k
{
85
36.6k
    int cmp;
86
87
36.6k
    cmp = a->y - b->y;
88
36.6k
    if (likely (cmp))
89
13.1k
  return cmp;
90
91
23.5k
    return a->x - b->x;
92
36.6k
}
93
94
static inline int
95
_cairo_bo_edge_compare (const cairo_bo_edge_t *a,
96
      const cairo_bo_edge_t *b)
97
3.35k
{
98
3.35k
    int cmp;
99
100
3.35k
    cmp = a->edge.line.p1.x - b->edge.line.p1.x;
101
3.35k
    if (likely (cmp))
102
497
  return cmp;
103
104
2.85k
    return b->edge.bottom - a->edge.bottom;
105
3.35k
}
106
107
static inline int
108
cairo_bo_event_compare (const cairo_bo_event_t *a,
109
      const cairo_bo_event_t *b)
110
36.6k
{
111
36.6k
    int cmp;
112
113
36.6k
    cmp = _cairo_point_compare (&a->point, &b->point);
114
36.6k
    if (likely (cmp))
115
15.5k
  return cmp;
116
117
21.1k
    cmp = a->type - b->type;
118
21.1k
    if (cmp)
119
0
  return cmp;
120
121
21.1k
    return a - b;
122
21.1k
}
123
124
static inline cairo_bo_event_t *
125
_cairo_bo_event_dequeue (cairo_bo_sweep_line_t *sweep_line)
126
14.6k
{
127
14.6k
    return *sweep_line->events++;
128
14.6k
}
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
2.66k
{
139
2.66k
    _cairo_bo_event_queue_sort (events, num_events);
140
2.66k
    events[num_events] = NULL;
141
2.66k
    sweep_line->events = events;
142
143
2.66k
    sweep_line->head = NULL;
144
2.66k
    sweep_line->current_y = INT32_MIN;
145
2.66k
    sweep_line->current_edge = NULL;
146
2.66k
}
147
148
static void
149
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t  *sweep_line,
150
           cairo_bo_edge_t    *edge)
151
6.01k
{
152
6.01k
    if (sweep_line->current_edge != NULL) {
153
3.34k
  cairo_bo_edge_t *prev, *next;
154
3.34k
  int cmp;
155
156
3.34k
  cmp = _cairo_bo_edge_compare (sweep_line->current_edge, edge);
157
3.34k
  if (cmp < 0) {
158
485
      prev = sweep_line->current_edge;
159
485
      next = prev->next;
160
485
      while (next != NULL && _cairo_bo_edge_compare (next, edge) < 0)
161
0
    prev = next, next = prev->next;
162
163
485
      prev->next = edge;
164
485
      edge->prev = prev;
165
485
      edge->next = next;
166
485
      if (next != NULL)
167
3
    next->prev = edge;
168
2.86k
  } else if (cmp > 0) {
169
6
      next = sweep_line->current_edge;
170
6
      prev = next->prev;
171
9
      while (prev != NULL && _cairo_bo_edge_compare (prev, edge) > 0)
172
3
    next = prev, prev = next->prev;
173
174
6
      next->prev = edge;
175
6
      edge->next = next;
176
6
      edge->prev = prev;
177
6
      if (prev != NULL)
178
0
    prev->next = edge;
179
6
      else
180
6
    sweep_line->head = edge;
181
2.85k
  } else {
182
2.85k
      prev = sweep_line->current_edge;
183
2.85k
      edge->prev = prev;
184
2.85k
      edge->next = prev->next;
185
2.85k
      if (prev->next != NULL)
186
0
    prev->next->prev = edge;
187
2.85k
      prev->next = edge;
188
2.85k
  }
189
3.34k
    } else {
190
2.66k
  sweep_line->head = edge;
191
2.66k
    }
192
193
6.01k
    sweep_line->current_edge = edge;
194
6.01k
}
195
196
static void
197
_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t  *sweep_line,
198
           cairo_bo_edge_t  *edge)
199
6.01k
{
200
6.01k
    if (edge->prev != NULL)
201
9
  edge->prev->next = edge->next;
202
6.00k
    else
203
6.00k
  sweep_line->head = edge->next;
204
205
6.01k
    if (edge->next != NULL)
206
3.33k
  edge->next->prev = edge->prev;
207
208
6.01k
    if (sweep_line->current_edge == edge)
209
2.66k
  sweep_line->current_edge = edge->prev ? edge->prev : edge->next;
210
6.01k
}
211
212
static inline cairo_bool_t
213
edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
214
3.00k
{
215
3.00k
    return a->edge.line.p1.x == b->edge.line.p1.x;
216
3.00k
}
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
485
{
224
485
    cairo_bo_trap_t *trap = &left->deferred_trap;
225
485
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
226
227
    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
228
485
    if (likely (trap->top < bot)) {
229
485
  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
485
  } else {
235
485
      cairo_box_t box;
236
237
485
      box.p1.x = left->edge.line.p1.x;
238
485
      box.p1.y = trap->top;
239
485
      box.p2.x = trap->right->edge.line.p1.x;
240
485
      box.p2.y = bot;
241
485
      status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box);
242
485
  }
243
485
    }
244
245
485
    trap->right = NULL;
246
247
485
    return status;
248
485
}
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
2.67k
{
262
2.67k
    cairo_status_t status;
263
264
2.67k
    if (left->deferred_trap.right == right)
265
0
  return CAIRO_STATUS_SUCCESS;
266
267
2.67k
    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
2.67k
    if (right != NULL && ! edges_collinear (left, right)) {
281
485
  left->deferred_trap.top = top;
282
485
  left->deferred_trap.right = right;
283
485
    }
284
285
2.67k
    return CAIRO_STATUS_SUCCESS;
286
2.67k
}
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
5.34k
{
295
5.34k
    cairo_bo_edge_t *right;
296
5.34k
    cairo_status_t status;
297
298
5.34k
    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
5.34k
    } else {
352
8.01k
  while (left != NULL) {
353
2.67k
      int in_out = 0;
354
355
2.67k
      right = left->next;
356
3.33k
      while (right != NULL) {
357
3.33k
    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
3.33k
    if ((in_out++ & 1) == 0) {
364
3.00k
        cairo_bo_edge_t *next;
365
3.00k
        cairo_bool_t skip = FALSE;
366
367
        /* skip co-linear edges */
368
3.00k
        next = right->next;
369
3.00k
        if (next != NULL)
370
332
      skip = edges_collinear (right, next);
371
372
3.00k
        if (! skip)
373
2.67k
      break;
374
3.00k
    }
375
376
664
    right = right->next;
377
664
      }
378
379
2.67k
      status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
380
2.67k
                  do_traps, container);
381
2.67k
      if (unlikely (status))
382
0
    return status;
383
384
2.67k
      left = right;
385
2.67k
      if (left != NULL)
386
2.67k
    left = left->next;
387
2.67k
  }
388
5.34k
    }
389
390
5.34k
    return CAIRO_STATUS_SUCCESS;
391
5.34k
}
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
2.66k
{
400
2.66k
    cairo_bo_sweep_line_t sweep_line;
401
2.66k
    cairo_bo_event_t *event;
402
2.66k
    cairo_status_t status;
403
404
2.66k
    _cairo_bo_sweep_line_init (&sweep_line, start_events, num_events);
405
406
14.6k
    while ((event = _cairo_bo_event_dequeue (&sweep_line))) {
407
12.0k
  if (event->point.y != sweep_line.current_y) {
408
5.34k
      status = _active_edges_to_traps (sweep_line.head,
409
5.34k
               sweep_line.current_y,
410
5.34k
               fill_rule, do_traps, container);
411
5.34k
      if (unlikely (status))
412
0
    return status;
413
414
5.34k
      sweep_line.current_y = event->point.y;
415
5.34k
  }
416
417
12.0k
  switch (event->type) {
418
6.01k
  case CAIRO_BO_EVENT_TYPE_START:
419
6.01k
      _cairo_bo_sweep_line_insert (&sweep_line, event->edge);
420
6.01k
      break;
421
422
6.01k
  case CAIRO_BO_EVENT_TYPE_STOP:
423
6.01k
      _cairo_bo_sweep_line_delete (&sweep_line, event->edge);
424
425
6.01k
      if (event->edge->deferred_trap.right != NULL) {
426
485
    status = _cairo_bo_edge_end_trap (event->edge,
427
485
              sweep_line.current_y,
428
485
              do_traps, container);
429
485
    if (unlikely (status))
430
0
        return status;
431
485
      }
432
433
6.01k
      break;
434
12.0k
  }
435
12.0k
    }
436
437
2.66k
    return CAIRO_STATUS_SUCCESS;
438
2.66k
}
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
2.67k
{
445
2.67k
    cairo_status_t status;
446
2.67k
    cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
447
2.67k
    cairo_bo_event_t *events;
448
2.67k
    cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
449
2.67k
    cairo_bo_event_t **event_ptrs;
450
2.67k
    cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
451
2.67k
    cairo_bo_edge_t *edges;
452
2.67k
    int num_events;
453
2.67k
    int i, j;
454
455
2.67k
    if (unlikely (polygon->num_edges == 0))
456
7
  return CAIRO_STATUS_SUCCESS;
457
458
2.66k
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
459
2.66k
    if (unlikely (polygon->num_edges > 100000))
460
0
  return CAIRO_STATUS_SUCCESS;
461
2.66k
#endif
462
463
2.66k
    num_events = 2 * polygon->num_edges;
464
465
2.66k
    events = stack_events;
466
2.66k
    event_ptrs = stack_event_ptrs;
467
2.66k
    edges = stack_edges;
468
2.66k
    if (num_events > ARRAY_LENGTH (stack_events)) {
469
1
  events = _cairo_malloc_ab_plus_c (num_events,
470
1
            sizeof (cairo_bo_event_t) +
471
1
            sizeof (cairo_bo_edge_t) +
472
1
            sizeof (cairo_bo_event_t *),
473
1
            sizeof (cairo_bo_event_t *));
474
1
  if (unlikely (events == NULL))
475
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
476
477
1
  event_ptrs = (cairo_bo_event_t **) (events + num_events);
478
1
  edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
479
1
    }
480
481
8.68k
    for (i = j = 0; i < polygon->num_edges; i++) {
482
6.01k
  edges[i].edge = polygon->edges[i];
483
6.01k
  edges[i].deferred_trap.right = NULL;
484
6.01k
  edges[i].prev = NULL;
485
6.01k
  edges[i].next = NULL;
486
487
6.01k
  event_ptrs[j] = &events[j];
488
6.01k
  events[j].type = CAIRO_BO_EVENT_TYPE_START;
489
6.01k
  events[j].point.y = polygon->edges[i].top;
490
6.01k
  events[j].point.x = polygon->edges[i].line.p1.x;
491
6.01k
  events[j].edge = &edges[i];
492
6.01k
  j++;
493
494
6.01k
  event_ptrs[j] = &events[j];
495
6.01k
  events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
496
6.01k
  events[j].point.y = polygon->edges[i].bottom;
497
6.01k
  events[j].point.x = polygon->edges[i].line.p1.x;
498
6.01k
  events[j].edge = &edges[i];
499
6.01k
  j++;
500
6.01k
    }
501
502
2.66k
    status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
503
2.66k
                  fill_rule,
504
2.66k
                  FALSE, boxes);
505
2.66k
    if (events != stack_events)
506
1
  free (events);
507
508
2.66k
    return status;
509
2.66k
}
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
}