Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-path-fill.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
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 University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *  Carl D. Worth <cworth@cworth.org>
36
 */
37
38
#include "cairoint.h"
39
#include "cairo-boxes-private.h"
40
#include "cairo-error-private.h"
41
#include "cairo-path-fixed-private.h"
42
#include "cairo-region-private.h"
43
#include "cairo-traps-private.h"
44
45
typedef struct cairo_filler {
46
    cairo_polygon_t *polygon;
47
    double tolerance;
48
49
    cairo_box_t limit;
50
    cairo_bool_t has_limits;
51
52
    cairo_point_t current_point;
53
    cairo_point_t last_move_to;
54
} cairo_filler_t;
55
56
static cairo_status_t
57
_cairo_filler_line_to (void *closure,
58
           const cairo_point_t *point)
59
55.4M
{
60
55.4M
    cairo_filler_t *filler = closure;
61
55.4M
    cairo_status_t status;
62
63
55.4M
    status = _cairo_polygon_add_external_edge (filler->polygon,
64
55.4M
                 &filler->current_point,
65
55.4M
                 point);
66
67
55.4M
    filler->current_point = *point;
68
69
55.4M
    return status;
70
55.4M
}
71
72
static cairo_status_t
73
_cairo_filler_add_point (void *closure,
74
       const cairo_point_t *point,
75
       const cairo_slope_t *tangent)
76
15.9M
{
77
15.9M
    return _cairo_filler_line_to (closure, point);
78
15.9M
};
79
80
static cairo_status_t
81
_cairo_filler_close (void *closure)
82
101k
{
83
101k
    cairo_filler_t *filler = closure;
84
85
    /* close the subpath */
86
101k
    return _cairo_filler_line_to (closure, &filler->last_move_to);
87
101k
}
88
89
static cairo_status_t
90
_cairo_filler_move_to (void *closure,
91
           const cairo_point_t *point)
92
50.7k
{
93
50.7k
    cairo_filler_t *filler = closure;
94
50.7k
    cairo_status_t status;
95
96
    /* close current subpath */
97
50.7k
    status = _cairo_filler_close (closure);
98
50.7k
    if (unlikely (status))
99
0
  return status;
100
101
        /* make sure that the closure represents a degenerate path */
102
50.7k
    filler->current_point = *point;
103
50.7k
    filler->last_move_to = *point;
104
105
50.7k
    return CAIRO_STATUS_SUCCESS;
106
50.7k
}
107
108
static cairo_status_t
109
_cairo_filler_curve_to (void    *closure,
110
      const cairo_point_t *p1,
111
      const cairo_point_t *p2,
112
      const cairo_point_t *p3)
113
41.0k
{
114
41.0k
    cairo_filler_t *filler = closure;
115
41.0k
    cairo_spline_t spline;
116
117
41.0k
    if (filler->has_limits) {
118
40.4k
  if (! _cairo_spline_intersects (&filler->current_point, p1, p2, p3,
119
40.4k
          &filler->limit))
120
28.7k
      return _cairo_filler_line_to (filler, p3);
121
40.4k
    }
122
123
12.3k
    if (! _cairo_spline_init (&spline,
124
12.3k
            _cairo_filler_add_point, filler,
125
12.3k
            &filler->current_point, p1, p2, p3))
126
537
    {
127
537
  return _cairo_filler_line_to (closure, p3);
128
537
    }
129
130
11.8k
    return _cairo_spline_decompose (&spline, filler->tolerance);
131
12.3k
}
132
133
cairo_status_t
134
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
135
           double tolerance,
136
           cairo_polygon_t *polygon)
137
36.3k
{
138
36.3k
    cairo_filler_t filler;
139
36.3k
    cairo_status_t status;
140
141
36.3k
    filler.polygon = polygon;
142
36.3k
    filler.tolerance = tolerance;
143
144
36.3k
    filler.has_limits = FALSE;
145
36.3k
    if (polygon->num_limits) {
146
36.2k
  filler.has_limits = TRUE;
147
36.2k
  filler.limit = polygon->limit;
148
36.2k
    }
149
150
    /* make sure that the closure represents a degenerate path */
151
36.3k
    filler.current_point.x = 0;
152
36.3k
    filler.current_point.y = 0;
153
36.3k
    filler.last_move_to = filler.current_point;
154
155
36.3k
    status = _cairo_path_fixed_interpret (path,
156
36.3k
            _cairo_filler_move_to,
157
36.3k
            _cairo_filler_line_to,
158
36.3k
            _cairo_filler_curve_to,
159
36.3k
            _cairo_filler_close,
160
36.3k
            &filler);
161
36.3k
    if (unlikely (status))
162
0
  return status;
163
164
36.3k
    return _cairo_filler_close (&filler);
165
36.3k
}
166
167
typedef struct cairo_filler_rectilinear_aligned {
168
    cairo_polygon_t *polygon;
169
170
    cairo_point_t current_point;
171
    cairo_point_t last_move_to;
172
} cairo_filler_ra_t;
173
174
static cairo_status_t
175
_cairo_filler_ra_line_to (void *closure,
176
        const cairo_point_t *point)
177
52.2k
{
178
52.2k
    cairo_filler_ra_t *filler = closure;
179
52.2k
    cairo_status_t status;
180
52.2k
    cairo_point_t p;
181
182
52.2k
    p.x = _cairo_fixed_round_down (point->x);
183
52.2k
    p.y = _cairo_fixed_round_down (point->y);
184
185
52.2k
    status = _cairo_polygon_add_external_edge (filler->polygon,
186
52.2k
                 &filler->current_point,
187
52.2k
                 &p);
188
189
52.2k
    filler->current_point = p;
190
191
52.2k
    return status;
192
52.2k
}
193
194
static cairo_status_t
195
_cairo_filler_ra_close (void *closure)
196
21.8k
{
197
21.8k
    cairo_filler_ra_t *filler = closure;
198
21.8k
    return _cairo_filler_ra_line_to (closure, &filler->last_move_to);
199
21.8k
}
200
201
static cairo_status_t
202
_cairo_filler_ra_move_to (void *closure,
203
        const cairo_point_t *point)
204
12.1k
{
205
12.1k
    cairo_filler_ra_t *filler = closure;
206
12.1k
    cairo_status_t status;
207
12.1k
    cairo_point_t p;
208
209
    /* close current subpath */
210
12.1k
    status = _cairo_filler_ra_close (closure);
211
12.1k
    if (unlikely (status))
212
0
  return status;
213
214
12.1k
    p.x = _cairo_fixed_round_down (point->x);
215
12.1k
    p.y = _cairo_fixed_round_down (point->y);
216
217
    /* make sure that the closure represents a degenerate path */
218
12.1k
    filler->current_point = p;
219
12.1k
    filler->last_move_to = p;
220
221
12.1k
    return CAIRO_STATUS_SUCCESS;
222
12.1k
}
223
224
cairo_status_t
225
_cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path,
226
                 cairo_antialias_t antialias,
227
                 cairo_polygon_t *polygon)
228
5.39k
{
229
5.39k
    cairo_filler_ra_t filler;
230
5.39k
    cairo_status_t status;
231
232
5.39k
    if (antialias != CAIRO_ANTIALIAS_NONE)
233
5
  return _cairo_path_fixed_fill_to_polygon (path, 0., polygon);
234
235
5.39k
    filler.polygon = polygon;
236
237
    /* make sure that the closure represents a degenerate path */
238
5.39k
    filler.current_point.x = 0;
239
5.39k
    filler.current_point.y = 0;
240
5.39k
    filler.last_move_to = filler.current_point;
241
242
5.39k
    status = _cairo_path_fixed_interpret_flat (path,
243
5.39k
                 _cairo_filler_ra_move_to,
244
5.39k
                 _cairo_filler_ra_line_to,
245
5.39k
                 _cairo_filler_ra_close,
246
5.39k
                 &filler,
247
5.39k
                 0.);
248
5.39k
    if (unlikely (status))
249
0
  return status;
250
251
5.39k
    return _cairo_filler_ra_close (&filler);
252
5.39k
}
253
254
cairo_status_t
255
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
256
         cairo_fill_rule_t fill_rule,
257
         double tolerance,
258
         cairo_traps_t *traps)
259
0
{
260
0
    cairo_polygon_t polygon;
261
0
    cairo_status_t status;
262
263
0
    if (_cairo_path_fixed_fill_is_empty (path))
264
0
  return CAIRO_STATUS_SUCCESS;
265
266
0
    _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
267
0
    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
268
0
    if (unlikely (status || polygon.num_edges == 0))
269
0
  goto CLEANUP;
270
271
0
    status = _cairo_bentley_ottmann_tessellate_polygon (traps,
272
0
              &polygon, fill_rule);
273
274
0
  CLEANUP:
275
0
    _cairo_polygon_fini (&polygon);
276
0
    return status;
277
0
}
278
279
static cairo_status_t
280
_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
281
              cairo_fill_rule_t fill_rule,
282
              cairo_antialias_t antialias,
283
              cairo_boxes_t *boxes)
284
5.39k
{
285
5.39k
    cairo_polygon_t polygon;
286
5.39k
    cairo_status_t status;
287
288
5.39k
    _cairo_polygon_init (&polygon, boxes->limits, boxes->num_limits);
289
5.39k
    boxes->num_limits = 0;
290
291
    /* tolerance will be ignored as the path is rectilinear */
292
5.39k
    status = _cairo_path_fixed_fill_rectilinear_to_polygon (path, antialias, &polygon);
293
5.39k
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
294
5.39k
  status =
295
5.39k
      _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
296
5.39k
                      fill_rule,
297
5.39k
                      boxes);
298
5.39k
    }
299
300
5.39k
    _cairo_polygon_fini (&polygon);
301
302
5.39k
    return status;
303
5.39k
}
304
305
cairo_status_t
306
_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
307
               cairo_fill_rule_t fill_rule,
308
               cairo_antialias_t antialias,
309
               cairo_boxes_t *boxes)
310
514k
{
311
514k
    cairo_path_fixed_iter_t iter;
312
514k
    cairo_status_t status;
313
514k
    cairo_box_t box;
314
315
514k
    if (_cairo_path_fixed_is_box (path, &box))
316
507k
  return _cairo_boxes_add (boxes, antialias, &box);
317
318
6.87k
    _cairo_path_fixed_iter_init (&iter, path);
319
164k
    while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
320
157k
  if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
321
9.71k
      continue;
322
323
148k
  if (box.p1.y > box.p2.y) {
324
76.9k
      cairo_fixed_t t;
325
326
76.9k
      t = box.p1.y;
327
76.9k
      box.p1.y = box.p2.y;
328
76.9k
      box.p2.y = t;
329
330
76.9k
      t = box.p1.x;
331
76.9k
      box.p1.x = box.p2.x;
332
76.9k
      box.p2.x = t;
333
76.9k
  }
334
335
148k
  status = _cairo_boxes_add (boxes, antialias, &box);
336
148k
  if (unlikely (status))
337
0
      return status;
338
148k
    }
339
340
6.87k
    if (_cairo_path_fixed_iter_at_end (&iter))
341
1.47k
  return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
342
343
    /* path is not rectangular, try extracting clipped rectilinear edges */
344
5.39k
    _cairo_boxes_clear (boxes);
345
5.39k
    return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
346
5.39k
                   fill_rule,
347
5.39k
                   antialias,
348
5.39k
                   boxes);
349
6.87k
}