Coverage Report

Created: 2025-11-16 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cairo/src/cairo-path-stroke-polygon.c
Line
Count
Source
1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2011 Intel Corporation
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is University of Southern
33
 * California.
34
 *
35
 * Contributor(s):
36
 *  Carl D. Worth <cworth@cworth.org>
37
 *  Chris Wilson <chris@chris-wilson.co.uk>
38
 */
39
40
#define _DEFAULT_SOURCE /* for hypot() */
41
#include "cairoint.h"
42
43
#include "cairo-box-inline.h"
44
#include "cairo-boxes-private.h"
45
#include "cairo-contour-inline.h"
46
#include "cairo-contour-private.h"
47
#include "cairo-error-private.h"
48
#include "cairo-path-fixed-private.h"
49
#include "cairo-slope-private.h"
50
51
#define DEBUG 0
52
53
struct stroker {
54
    cairo_stroke_style_t style;
55
56
#if DEBUG
57
    cairo_contour_t path;
58
#endif
59
60
    struct stroke_contour {
61
  /* Note that these are not strictly contours as they may intersect */
62
  cairo_contour_t contour;
63
    } cw, ccw;
64
    cairo_uint64_t contour_tolerance;
65
    cairo_polygon_t *polygon;
66
67
    const cairo_matrix_t *ctm;
68
    const cairo_matrix_t *ctm_inverse;
69
    double tolerance;
70
    double spline_cusp_tolerance;
71
    double half_line_width;
72
    cairo_bool_t ctm_det_positive;
73
74
    cairo_pen_t pen;
75
76
    cairo_point_t first_point;
77
78
    cairo_bool_t has_initial_sub_path;
79
80
    cairo_bool_t has_current_face;
81
    cairo_stroke_face_t current_face;
82
83
    cairo_bool_t has_first_face;
84
    cairo_stroke_face_t first_face;
85
86
    cairo_bool_t has_bounds;
87
    cairo_box_t bounds;
88
};
89
90
static inline double
91
normalize_slope (double *dx, double *dy);
92
93
static void
94
compute_face (const cairo_point_t *point,
95
        const cairo_slope_t *dev_slope,
96
        struct stroker *stroker,
97
        cairo_stroke_face_t *face);
98
99
static cairo_uint64_t
100
point_distance_sq (const cairo_point_t *p1,
101
      const cairo_point_t *p2)
102
0
{
103
0
    int32_t dx = p1->x - p2->x;
104
0
    int32_t dy = p1->y - p2->y;
105
0
    return _cairo_int32x32_64_mul (dx, dx) + _cairo_int32x32_64_mul (dy, dy);
106
0
}
107
108
static cairo_bool_t
109
within_tolerance (const cairo_point_t *p1,
110
        const cairo_point_t *p2,
111
        cairo_uint64_t tolerance)
112
1.48M
{
113
1.48M
    return FALSE;
114
0
    return _cairo_int64_lt (point_distance_sq (p1, p2), tolerance);
115
1.48M
}
116
117
static void
118
contour_add_point (struct stroker *stroker,
119
       struct stroke_contour *c,
120
       const cairo_point_t *point)
121
1.37M
{
122
1.37M
    if (! within_tolerance (point, _cairo_contour_last_point (&c->contour),
123
1.37M
      stroker->contour_tolerance))
124
1.37M
  _cairo_contour_add_point (&c->contour, point);
125
    //*_cairo_contour_last_point (&c->contour) = *point;
126
1.37M
}
127
128
static void
129
translate_point (cairo_point_t *point, const cairo_point_t *offset)
130
917k
{
131
917k
    point->x += offset->x;
132
917k
    point->y += offset->y;
133
917k
}
134
135
static int
136
slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
137
70.6k
{
138
70.6k
    double  c = (dx1 * dy2 - dx2 * dy1);
139
140
70.6k
    if (c > 0) return 1;
141
34.7k
    if (c < 0) return -1;
142
0
    return 0;
143
34.7k
}
144
145
/*
146
 * Construct a fan around the midpoint using the vertices from pen between
147
 * inpt and outpt.
148
 */
149
static void
150
add_fan (struct stroker *stroker,
151
   const cairo_slope_t *in_vector,
152
   const cairo_slope_t *out_vector,
153
   const cairo_point_t *midpt,
154
   cairo_bool_t clockwise,
155
   struct stroke_contour *c)
156
87.3k
{
157
87.3k
    cairo_pen_t *pen = &stroker->pen;
158
87.3k
    int start, stop;
159
160
87.3k
    if (stroker->has_bounds &&
161
0
  ! _cairo_box_contains_point (&stroker->bounds, midpt))
162
0
  return;
163
164
87.3k
    assert (stroker->pen.num_vertices);
165
166
87.3k
    if (clockwise) {
167
66.5k
  _cairo_pen_find_active_cw_vertices (pen,
168
66.5k
              in_vector, out_vector,
169
66.5k
              &start, &stop);
170
200k
  while (start != stop) {
171
133k
      cairo_point_t p = *midpt;
172
133k
      translate_point (&p, &pen->vertices[start].point);
173
133k
      contour_add_point (stroker, c, &p);
174
175
133k
      if (++start == pen->num_vertices)
176
16.7k
    start = 0;
177
133k
  }
178
66.5k
    } else {
179
20.8k
  _cairo_pen_find_active_ccw_vertices (pen,
180
20.8k
               in_vector, out_vector,
181
20.8k
               &start, &stop);
182
133k
  while (start != stop) {
183
112k
      cairo_point_t p = *midpt;
184
112k
      translate_point (&p, &pen->vertices[start].point);
185
112k
      contour_add_point (stroker, c, &p);
186
187
112k
      if (start-- == 0)
188
11.2k
    start += pen->num_vertices;
189
112k
  }
190
20.8k
    }
191
87.3k
}
192
193
static int
194
join_is_clockwise (const cairo_stroke_face_t *in,
195
       const cairo_stroke_face_t *out)
196
77.6k
{
197
77.6k
    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
198
77.6k
}
199
200
static void
201
inner_join (struct stroker *stroker,
202
      const cairo_stroke_face_t *in,
203
      const cairo_stroke_face_t *out,
204
      int clockwise)
205
104k
{
206
#if 0
207
    cairo_point_t last;
208
    const cairo_point_t *p, *outpt;
209
    struct stroke_contour *inner;
210
    cairo_int64_t d_p, d_last;
211
    cairo_int64_t half_line_width;
212
    cairo_bool_t negate;
213
214
    /* XXX line segments shorter than line-width */
215
216
    if (clockwise) {
217
  inner = &stroker->ccw;
218
  outpt = &out->ccw;
219
  negate = 1;
220
    } else {
221
  inner = &stroker->cw;
222
  outpt = &out->cw;
223
  negate = 0;
224
    }
225
226
    half_line_width = CAIRO_FIXED_ONE*CAIRO_FIXED_ONE/2 * stroker->style.line_width * out->length + .5;
227
228
    /* On the inside, the previous end-point is always
229
     * closer to the new face by definition.
230
     */
231
    last = *_cairo_contour_last_point (&inner->contour);
232
    d_last = distance_from_face (out, &last, negate);
233
    _cairo_contour_remove_last_point (&inner->contour);
234
235
prev:
236
    if (inner->contour.chain.num_points == 0) {
237
  contour_add_point (stroker, inner, outpt);
238
  return;
239
    }
240
    p = _cairo_contour_last_point (&inner->contour);
241
    d_p = distance_from_face (out, p, negate);
242
    if (_cairo_int64_lt (d_p, half_line_width) &&
243
  !_cairo_int64_negative (distance_along_face (out, p)))
244
    {
245
  last = *p;
246
  d_last = d_p;
247
  _cairo_contour_remove_last_point (&inner->contour);
248
  goto prev;
249
    }
250
251
    compute_inner_joint (&last, d_last, p, d_p, half_line_width);
252
    contour_add_point (stroker, inner, &last);
253
#else
254
104k
    const cairo_point_t *outpt;
255
104k
    struct stroke_contour *inner;
256
257
104k
    if (clockwise) {
258
66.5k
  inner = &stroker->ccw;
259
66.5k
  outpt = &out->ccw;
260
66.5k
    } else {
261
38.3k
  inner = &stroker->cw;
262
38.3k
  outpt = &out->cw;
263
38.3k
    }
264
104k
    contour_add_point (stroker, inner, &in->point);
265
104k
    contour_add_point (stroker, inner, outpt);
266
104k
#endif
267
104k
}
268
269
static void
270
inner_close (struct stroker *stroker,
271
       const cairo_stroke_face_t *in,
272
       cairo_stroke_face_t *out)
273
27.2k
{
274
#if 0
275
    cairo_point_t last;
276
    const cairo_point_t *p, *outpt, *inpt;
277
    struct stroke_contour *inner;
278
    struct _cairo_contour_chain *chain;
279
280
    /* XXX line segments shorter than line-width */
281
282
    if (join_is_clockwise (in, out)) {
283
  inner = &stroker->ccw;
284
  outpt = &in->ccw;
285
  inpt = &out->ccw;
286
    } else {
287
  inner = &stroker->cw;
288
  outpt = &in->cw;
289
  inpt = &out->cw;
290
    }
291
292
    if (inner->contour.chain.num_points == 0) {
293
  contour_add_point (stroker, inner, &in->point);
294
  contour_add_point (stroker, inner, inpt);
295
  *_cairo_contour_first_point (&inner->contour) =
296
      *_cairo_contour_last_point (&inner->contour);
297
  return;
298
    }
299
300
    line_width = stroker->style.line_width/2;
301
    line_width *= CAIRO_FIXED_ONE;
302
303
    d_last = sign * distance_from_face (out, outpt);
304
    last = *outpt;
305
306
    for (chain = &inner->contour.chain; chain; chain = chain->next) {
307
  for (i = 0; i < chain->num_points; i++) {
308
      p = &chain->points[i];
309
      if ((d_p = sign * distance_from_face (in, p)) >= line_width &&
310
    distance_from_edge (stroker, inpt, &last, p) < line_width)
311
      {
312
    goto out;
313
      }
314
315
      if (p->x != last.x || p->y != last.y) {
316
    last = *p;
317
    d_last = d_p;
318
      }
319
  }
320
    }
321
out:
322
323
    if (d_p != d_last) {
324
  double dot = (line_width - d_last) / (d_p - d_last);
325
  last.x += dot * (p->x - last.x);
326
  last.y += dot * (p->y - last.y);
327
    }
328
    *_cairo_contour_last_point (&inner->contour) = last;
329
330
    for (chain = &inner->contour.chain; chain; chain = chain->next) {
331
  for (i = 0; i < chain->num_points; i++) {
332
      cairo_point_t *pp = &chain->points[i];
333
      if (pp == p)
334
    return;
335
      *pp = last;
336
  }
337
    }
338
#else
339
27.2k
    const cairo_point_t *inpt;
340
27.2k
    struct stroke_contour *inner;
341
342
27.2k
    if (join_is_clockwise (in, out)) {
343
19.5k
  inner = &stroker->ccw;
344
19.5k
  inpt = &out->ccw;
345
19.5k
    } else {
346
7.71k
  inner = &stroker->cw;
347
7.71k
  inpt = &out->cw;
348
7.71k
    }
349
350
27.2k
    contour_add_point (stroker, inner, &in->point);
351
27.2k
    contour_add_point (stroker, inner, inpt);
352
27.2k
    *_cairo_contour_first_point (&inner->contour) =
353
27.2k
  *_cairo_contour_last_point (&inner->contour);
354
27.2k
#endif
355
27.2k
}
356
357
static void
358
outer_close (struct stroker *stroker,
359
       const cairo_stroke_face_t *in,
360
       const cairo_stroke_face_t *out)
361
27.2k
{
362
27.2k
    const cairo_point_t *inpt, *outpt;
363
27.2k
    struct stroke_contour *outer;
364
27.2k
    int clockwise;
365
366
27.2k
    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
367
135
  in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
368
135
    {
369
135
  return;
370
135
    }
371
372
27.1k
    clockwise = join_is_clockwise (in, out);
373
27.1k
    if (clockwise) {
374
19.5k
  inpt = &in->cw;
375
19.5k
  outpt = &out->cw;
376
19.5k
  outer = &stroker->cw;
377
19.5k
    } else {
378
7.58k
  inpt = &in->ccw;
379
7.58k
  outpt = &out->ccw;
380
7.58k
  outer = &stroker->ccw;
381
7.58k
    }
382
383
27.1k
    if (within_tolerance (inpt, outpt, stroker->contour_tolerance)) {
384
0
  *_cairo_contour_first_point (&outer->contour) =
385
0
      *_cairo_contour_last_point (&outer->contour);
386
0
  return;
387
0
    }
388
389
27.1k
    switch (stroker->style.line_join) {
390
18.6k
    case CAIRO_LINE_JOIN_ROUND:
391
18.6k
  if ((in->dev_slope.x * out->dev_slope.x +
392
18.6k
       in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
393
18.6k
  {
394
      /* construct a fan around the common midpoint */
395
18.6k
      add_fan (stroker,
396
18.6k
         &in->dev_vector, &out->dev_vector, &in->point,
397
18.6k
         clockwise, outer);
398
18.6k
  } /* else: bevel join */
399
18.6k
  break;
400
401
8.52k
    case CAIRO_LINE_JOIN_MITER:
402
8.52k
    default: {
403
  /* dot product of incoming slope vector with outgoing slope vector */
404
8.52k
  double  in_dot_out = in->dev_slope.x * out->dev_slope.x +
405
8.52k
           in->dev_slope.y * out->dev_slope.y;
406
8.52k
  double  ml = stroker->style.miter_limit;
407
408
  /* Check the miter limit -- lines meeting at an acute angle
409
   * can generate long miters, the limit converts them to bevel
410
   *
411
   * Consider the miter join formed when two line segments
412
   * meet at an angle psi:
413
   *
414
   *     /.\
415
   *    /. .\
416
   *   /./ \.\
417
   *  /./psi\.\
418
   *
419
   * We can zoom in on the right half of that to see:
420
   *
421
   *      |\
422
   *      | \ psi/2
423
   *      |  \
424
   *      |   \
425
   *      |    \
426
   *      |     \
427
   *    miter    \
428
   *   length     \
429
   *      |        \
430
   *      |        .\
431
   *      |    .     \
432
   *      |.   line   \
433
   *       \    width  \
434
   *        \           \
435
   *
436
   *
437
   * The right triangle in that figure, (the line-width side is
438
   * shown faintly with three '.' characters), gives us the
439
   * following expression relating miter length, angle and line
440
   * width:
441
   *
442
   *  1 /sin (psi/2) = miter_length / line_width
443
   *
444
   * The right-hand side of this relationship is the same ratio
445
   * in which the miter limit (ml) is expressed. We want to know
446
   * when the miter length is within the miter limit. That is
447
   * when the following condition holds:
448
   *
449
   *  1/sin(psi/2) <= ml
450
   *  1 <= ml sin(psi/2)
451
   *  1 <= ml² sin²(psi/2)
452
   *  2 <= ml² 2 sin²(psi/2)
453
   *        2·sin²(psi/2) = 1-cos(psi)
454
   *  2 <= ml² (1-cos(psi))
455
   *
456
   *        in · out = |in| |out| cos (psi)
457
   *
458
   * in and out are both unit vectors, so:
459
   *
460
   *        in · out = cos (psi)
461
   *
462
   *  2 <= ml² (1 - in · out)
463
   *
464
   */
465
8.52k
  if (2 <= ml * ml * (1 + in_dot_out)) {
466
8.52k
      double    x1, y1, x2, y2;
467
8.52k
      double    mx, my;
468
8.52k
      double    dx1, dx2, dy1, dy2;
469
8.52k
      double    ix, iy;
470
8.52k
      double    fdx1, fdy1, fdx2, fdy2;
471
8.52k
      double    mdx, mdy;
472
473
      /*
474
       * we've got the points already transformed to device
475
       * space, but need to do some computation with them and
476
       * also need to transform the slope from user space to
477
       * device space
478
       */
479
      /* outer point of incoming line face */
480
8.52k
      x1 = _cairo_fixed_to_double (inpt->x);
481
8.52k
      y1 = _cairo_fixed_to_double (inpt->y);
482
8.52k
      dx1 = in->dev_slope.x;
483
8.52k
      dy1 = in->dev_slope.y;
484
485
      /* outer point of outgoing line face */
486
8.52k
      x2 = _cairo_fixed_to_double (outpt->x);
487
8.52k
      y2 = _cairo_fixed_to_double (outpt->y);
488
8.52k
      dx2 = out->dev_slope.x;
489
8.52k
      dy2 = out->dev_slope.y;
490
491
      /*
492
       * Compute the location of the outer corner of the miter.
493
       * That's pretty easy -- just the intersection of the two
494
       * outer edges.  We've got slopes and points on each
495
       * of those edges.  Compute my directly, then compute
496
       * mx by using the edge with the larger dy; that avoids
497
       * dividing by values close to zero.
498
       */
499
8.52k
      my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
500
8.52k
      (dx1 * dy2 - dx2 * dy1));
501
8.52k
      if (fabs (dy1) >= fabs (dy2))
502
6.41k
    mx = (my - y1) * dx1 / dy1 + x1;
503
2.10k
      else
504
2.10k
    mx = (my - y2) * dx2 / dy2 + x2;
505
506
      /*
507
       * When the two outer edges are nearly parallel, slight
508
       * perturbations in the position of the outer points of the lines
509
       * caused by representing them in fixed point form can cause the
510
       * intersection point of the miter to move a large amount. If
511
       * that moves the miter intersection from between the two faces,
512
       * then draw a bevel instead.
513
       */
514
515
8.52k
      ix = _cairo_fixed_to_double (in->point.x);
516
8.52k
      iy = _cairo_fixed_to_double (in->point.y);
517
518
      /* slope of one face */
519
8.52k
      fdx1 = x1 - ix; fdy1 = y1 - iy;
520
521
      /* slope of the other face */
522
8.52k
      fdx2 = x2 - ix; fdy2 = y2 - iy;
523
524
      /* slope from the intersection to the miter point */
525
8.52k
      mdx = mx - ix; mdy = my - iy;
526
527
      /*
528
       * Make sure the miter point line lies between the two
529
       * faces by comparing the slopes
530
       */
531
8.52k
      if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
532
8.52k
    slope_compare_sgn (fdx2, fdy2, mdx, mdy))
533
8.48k
      {
534
8.48k
    cairo_point_t p;
535
536
8.48k
    p.x = _cairo_fixed_from_double (mx);
537
8.48k
    p.y = _cairo_fixed_from_double (my);
538
539
8.48k
    *_cairo_contour_last_point (&outer->contour) = p;
540
8.48k
    *_cairo_contour_first_point (&outer->contour) = p;
541
8.48k
    return;
542
8.48k
      }
543
8.52k
  }
544
42
  break;
545
8.52k
    }
546
547
42
    case CAIRO_LINE_JOIN_BEVEL:
548
0
  break;
549
27.1k
    }
550
18.6k
    contour_add_point (stroker, outer, outpt);
551
18.6k
}
552
553
static void
554
outer_join (struct stroker *stroker,
555
      const cairo_stroke_face_t *in,
556
      const cairo_stroke_face_t *out,
557
      int clockwise)
558
104k
{
559
104k
    const cairo_point_t *inpt, *outpt;
560
104k
    struct stroke_contour *outer;
561
562
104k
    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
563
18.7k
  in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
564
18.7k
    {
565
18.7k
  return;
566
18.7k
    }
567
86.1k
    if (clockwise) {
568
64.1k
  inpt = &in->cw;
569
64.1k
  outpt = &out->cw;
570
64.1k
  outer = &stroker->cw;
571
64.1k
    } else {
572
21.9k
  inpt = &in->ccw;
573
21.9k
  outpt = &out->ccw;
574
21.9k
  outer = &stroker->ccw;
575
21.9k
    }
576
577
86.1k
    switch (stroker->style.line_join) {
578
59.3k
    case CAIRO_LINE_JOIN_ROUND:
579
59.3k
  if ((in->dev_slope.x * out->dev_slope.x +
580
59.3k
       in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
581
57.1k
  {
582
      /* construct a fan around the common midpoint */
583
57.1k
      add_fan (stroker,
584
57.1k
         &in->dev_vector, &out->dev_vector, &in->point,
585
57.1k
         clockwise, outer);
586
57.1k
  } /* else: bevel join */
587
59.3k
  break;
588
589
26.8k
    case CAIRO_LINE_JOIN_MITER:
590
26.8k
    default: {
591
  /* dot product of incoming slope vector with outgoing slope vector */
592
26.8k
  double  in_dot_out = in->dev_slope.x * out->dev_slope.x +
593
26.8k
           in->dev_slope.y * out->dev_slope.y;
594
26.8k
  double  ml = stroker->style.miter_limit;
595
596
  /* Check the miter limit -- lines meeting at an acute angle
597
   * can generate long miters, the limit converts them to bevel
598
   *
599
   * Consider the miter join formed when two line segments
600
   * meet at an angle psi:
601
   *
602
   *     /.\
603
   *    /. .\
604
   *   /./ \.\
605
   *  /./psi\.\
606
   *
607
   * We can zoom in on the right half of that to see:
608
   *
609
   *      |\
610
   *      | \ psi/2
611
   *      |  \
612
   *      |   \
613
   *      |    \
614
   *      |     \
615
   *    miter    \
616
   *   length     \
617
   *      |        \
618
   *      |        .\
619
   *      |    .     \
620
   *      |.   line   \
621
   *       \    width  \
622
   *        \           \
623
   *
624
   *
625
   * The right triangle in that figure, (the line-width side is
626
   * shown faintly with three '.' characters), gives us the
627
   * following expression relating miter length, angle and line
628
   * width:
629
   *
630
   *  1 /sin (psi/2) = miter_length / line_width
631
   *
632
   * The right-hand side of this relationship is the same ratio
633
   * in which the miter limit (ml) is expressed. We want to know
634
   * when the miter length is within the miter limit. That is
635
   * when the following condition holds:
636
   *
637
   *  1/sin(psi/2) <= ml
638
   *  1 <= ml sin(psi/2)
639
   *  1 <= ml² sin²(psi/2)
640
   *  2 <= ml² 2 sin²(psi/2)
641
   *        2·sin²(psi/2) = 1-cos(psi)
642
   *  2 <= ml² (1-cos(psi))
643
   *
644
   *        in · out = |in| |out| cos (psi)
645
   *
646
   * in and out are both unit vectors, so:
647
   *
648
   *        in · out = cos (psi)
649
   *
650
   *  2 <= ml² (1 - in · out)
651
   *
652
   */
653
26.8k
  if (2 <= ml * ml * (1 + in_dot_out)) {
654
26.8k
      double    x1, y1, x2, y2;
655
26.8k
      double    mx, my;
656
26.8k
      double    dx1, dx2, dy1, dy2;
657
26.8k
      double    ix, iy;
658
26.8k
      double    fdx1, fdy1, fdx2, fdy2;
659
26.8k
      double    mdx, mdy;
660
661
      /*
662
       * we've got the points already transformed to device
663
       * space, but need to do some computation with them and
664
       * also need to transform the slope from user space to
665
       * device space
666
       */
667
      /* outer point of incoming line face */
668
26.8k
      x1 = _cairo_fixed_to_double (inpt->x);
669
26.8k
      y1 = _cairo_fixed_to_double (inpt->y);
670
26.8k
      dx1 = in->dev_slope.x;
671
26.8k
      dy1 = in->dev_slope.y;
672
673
      /* outer point of outgoing line face */
674
26.8k
      x2 = _cairo_fixed_to_double (outpt->x);
675
26.8k
      y2 = _cairo_fixed_to_double (outpt->y);
676
26.8k
      dx2 = out->dev_slope.x;
677
26.8k
      dy2 = out->dev_slope.y;
678
679
      /*
680
       * Compute the location of the outer corner of the miter.
681
       * That's pretty easy -- just the intersection of the two
682
       * outer edges.  We've got slopes and points on each
683
       * of those edges.  Compute my directly, then compute
684
       * mx by using the edge with the larger dy; that avoids
685
       * dividing by values close to zero.
686
       */
687
26.8k
      my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
688
26.8k
      (dx1 * dy2 - dx2 * dy1));
689
26.8k
      if (fabs (dy1) >= fabs (dy2))
690
11.3k
    mx = (my - y1) * dx1 / dy1 + x1;
691
15.4k
      else
692
15.4k
    mx = (my - y2) * dx2 / dy2 + x2;
693
694
      /*
695
       * When the two outer edges are nearly parallel, slight
696
       * perturbations in the position of the outer points of the lines
697
       * caused by representing them in fixed point form can cause the
698
       * intersection point of the miter to move a large amount. If
699
       * that moves the miter intersection from between the two faces,
700
       * then draw a bevel instead.
701
       */
702
703
26.8k
      ix = _cairo_fixed_to_double (in->point.x);
704
26.8k
      iy = _cairo_fixed_to_double (in->point.y);
705
706
      /* slope of one face */
707
26.8k
      fdx1 = x1 - ix; fdy1 = y1 - iy;
708
709
      /* slope of the other face */
710
26.8k
      fdx2 = x2 - ix; fdy2 = y2 - iy;
711
712
      /* slope from the intersection to the miter point */
713
26.8k
      mdx = mx - ix; mdy = my - iy;
714
715
      /*
716
       * Make sure the miter point line lies between the two
717
       * faces by comparing the slopes
718
       */
719
26.8k
      if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
720
26.8k
    slope_compare_sgn (fdx2, fdy2, mdx, mdy))
721
22.9k
      {
722
22.9k
    cairo_point_t p;
723
724
22.9k
    p.x = _cairo_fixed_from_double (mx);
725
22.9k
    p.y = _cairo_fixed_from_double (my);
726
727
22.9k
    *_cairo_contour_last_point (&outer->contour) = p;
728
22.9k
    return;
729
22.9k
      }
730
26.8k
  }
731
3.82k
  break;
732
26.8k
    }
733
734
3.82k
    case CAIRO_LINE_JOIN_BEVEL:
735
0
  break;
736
86.1k
    }
737
63.1k
    contour_add_point (stroker,outer, outpt);
738
63.1k
}
739
740
static void
741
add_cap (struct stroker *stroker,
742
   const cairo_stroke_face_t *f,
743
   struct stroke_contour *c)
744
60.3k
{
745
60.3k
    switch (stroker->style.line_cap) {
746
11.6k
    case CAIRO_LINE_CAP_ROUND: {
747
11.6k
  cairo_slope_t slope;
748
749
11.6k
  slope.dx = -f->dev_vector.dx;
750
11.6k
  slope.dy = -f->dev_vector.dy;
751
752
11.6k
  add_fan (stroker, &f->dev_vector, &slope, &f->point, FALSE, c);
753
11.6k
  break;
754
0
    }
755
756
0
    case CAIRO_LINE_CAP_SQUARE: {
757
0
  cairo_slope_t fvector;
758
0
  cairo_point_t p;
759
0
  double dx, dy;
760
761
0
  dx = f->usr_vector.x;
762
0
  dy = f->usr_vector.y;
763
0
  dx *= stroker->half_line_width;
764
0
  dy *= stroker->half_line_width;
765
0
  cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
766
0
  fvector.dx = _cairo_fixed_from_double (dx);
767
0
  fvector.dy = _cairo_fixed_from_double (dy);
768
769
0
  p.x = f->ccw.x + fvector.dx;
770
0
  p.y = f->ccw.y + fvector.dy;
771
0
  contour_add_point (stroker, c, &p);
772
773
0
  p.x = f->cw.x + fvector.dx;
774
0
  p.y = f->cw.y + fvector.dy;
775
0
  contour_add_point (stroker, c, &p);
776
0
    }
777
778
48.7k
    case CAIRO_LINE_CAP_BUTT:
779
48.7k
    default:
780
48.7k
  break;
781
60.3k
    }
782
60.3k
    contour_add_point (stroker, c, &f->cw);
783
60.3k
}
784
785
static void
786
add_leading_cap (struct stroker *stroker,
787
     const cairo_stroke_face_t *face,
788
     struct stroke_contour *c)
789
30.1k
{
790
30.1k
    cairo_stroke_face_t reversed;
791
30.1k
    cairo_point_t t;
792
793
30.1k
    reversed = *face;
794
795
    /* The initial cap needs an outward facing vector. Reverse everything */
796
30.1k
    reversed.usr_vector.x = -reversed.usr_vector.x;
797
30.1k
    reversed.usr_vector.y = -reversed.usr_vector.y;
798
30.1k
    reversed.dev_vector.dx = -reversed.dev_vector.dx;
799
30.1k
    reversed.dev_vector.dy = -reversed.dev_vector.dy;
800
801
30.1k
    t = reversed.cw;
802
30.1k
    reversed.cw = reversed.ccw;
803
30.1k
    reversed.ccw = t;
804
805
30.1k
    add_cap (stroker, &reversed, c);
806
30.1k
}
807
808
static void
809
add_trailing_cap (struct stroker *stroker,
810
      const cairo_stroke_face_t *face,
811
      struct stroke_contour *c)
812
30.1k
{
813
30.1k
    add_cap (stroker, face, c);
814
30.1k
}
815
816
static inline double
817
normalize_slope (double *dx, double *dy)
818
659k
{
819
659k
    double dx0 = *dx, dy0 = *dy;
820
659k
    double mag;
821
822
659k
    assert (dx0 != 0.0 || dy0 != 0.0);
823
824
659k
    if (dx0 == 0.0) {
825
132k
  *dx = 0.0;
826
132k
  if (dy0 > 0.0) {
827
68.8k
      mag = dy0;
828
68.8k
      *dy = 1.0;
829
68.8k
  } else {
830
63.7k
      mag = -dy0;
831
63.7k
      *dy = -1.0;
832
63.7k
  }
833
526k
    } else if (dy0 == 0.0) {
834
138k
  *dy = 0.0;
835
138k
  if (dx0 > 0.0) {
836
77.9k
      mag = dx0;
837
77.9k
      *dx = 1.0;
838
77.9k
  } else {
839
60.5k
      mag = -dx0;
840
60.5k
      *dx = -1.0;
841
60.5k
  }
842
388k
    } else {
843
388k
  mag = hypot (dx0, dy0);
844
388k
  *dx = dx0 / mag;
845
388k
  *dy = dy0 / mag;
846
388k
    }
847
848
659k
    return mag;
849
659k
}
850
851
static void
852
compute_face (const cairo_point_t *point,
853
        const cairo_slope_t *dev_slope,
854
        struct stroker *stroker,
855
        cairo_stroke_face_t *face)
856
335k
{
857
335k
    double face_dx, face_dy;
858
335k
    cairo_point_t offset_ccw, offset_cw;
859
335k
    double slope_dx, slope_dy;
860
861
335k
    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
862
335k
    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
863
335k
    face->length = normalize_slope (&slope_dx, &slope_dy);
864
335k
    face->dev_slope.x = slope_dx;
865
335k
    face->dev_slope.y = slope_dy;
866
867
    /*
868
     * rotate to get a line_width/2 vector along the face, note that
869
     * the vector must be rotated the right direction in device space,
870
     * but by 90° in user space. So, the rotation depends on
871
     * whether the ctm reflects or not, and that can be determined
872
     * by looking at the determinant of the matrix.
873
     */
874
335k
    if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) {
875
  /* Normalize the matrix! */
876
323k
  cairo_matrix_transform_distance (stroker->ctm_inverse,
877
323k
           &slope_dx, &slope_dy);
878
323k
  normalize_slope (&slope_dx, &slope_dy);
879
880
323k
  if (stroker->ctm_det_positive) {
881
305k
      face_dx = - slope_dy * stroker->half_line_width;
882
305k
      face_dy = slope_dx * stroker->half_line_width;
883
305k
  } else {
884
18.7k
      face_dx = slope_dy * stroker->half_line_width;
885
18.7k
      face_dy = - slope_dx * stroker->half_line_width;
886
18.7k
  }
887
888
  /* back to device space */
889
323k
  cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
890
323k
    } else {
891
11.9k
  face_dx = - slope_dy * stroker->half_line_width;
892
11.9k
  face_dy = slope_dx * stroker->half_line_width;
893
11.9k
    }
894
895
335k
    offset_ccw.x = _cairo_fixed_from_double (face_dx);
896
335k
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
897
335k
    offset_cw.x = -offset_ccw.x;
898
335k
    offset_cw.y = -offset_ccw.y;
899
900
335k
    face->ccw = *point;
901
335k
    translate_point (&face->ccw, &offset_ccw);
902
903
335k
    face->point = *point;
904
905
335k
    face->cw = *point;
906
335k
    translate_point (&face->cw, &offset_cw);
907
908
335k
    face->usr_vector.x = slope_dx;
909
335k
    face->usr_vector.y = slope_dy;
910
911
335k
    face->dev_vector = *dev_slope;
912
335k
}
913
914
static void
915
add_caps (struct stroker *stroker)
916
108k
{
917
    /* check for a degenerative sub_path */
918
108k
    if (stroker->has_initial_sub_path &&
919
23.3k
  ! stroker->has_first_face &&
920
1.16k
  ! stroker->has_current_face &&
921
1.16k
  stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
922
1.12k
    {
923
  /* pick an arbitrary slope to use */
924
1.12k
  cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
925
1.12k
  cairo_stroke_face_t face;
926
927
  /* arbitrarily choose first_point */
928
1.12k
  compute_face (&stroker->first_point, &slope, stroker, &face);
929
930
1.12k
  add_leading_cap (stroker, &face, &stroker->ccw);
931
1.12k
  add_trailing_cap (stroker, &face, &stroker->ccw);
932
933
  /* ensure the circle is complete */
934
1.12k
  _cairo_contour_add_point (&stroker->ccw.contour,
935
1.12k
          _cairo_contour_first_point (&stroker->ccw.contour));
936
937
1.12k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
938
1.12k
  _cairo_contour_reset (&stroker->ccw.contour);
939
107k
    } else {
940
107k
  if (stroker->has_current_face)
941
29.0k
      add_trailing_cap (stroker, &stroker->current_face, &stroker->ccw);
942
943
#if DEBUG
944
  {
945
      FILE *file = fopen ("contours.txt", "a");
946
      _cairo_debug_print_contour (file, &stroker->path);
947
      _cairo_debug_print_contour (file, &stroker->cw.contour);
948
      _cairo_debug_print_contour (file, &stroker->ccw.contour);
949
      fclose (file);
950
      _cairo_contour_reset (&stroker->path);
951
  }
952
#endif
953
954
107k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
955
107k
  _cairo_contour_reset (&stroker->ccw.contour);
956
957
107k
  if (stroker->has_first_face) {
958
29.0k
      _cairo_contour_add_point (&stroker->ccw.contour,
959
29.0k
              &stroker->first_face.cw);
960
29.0k
      add_leading_cap (stroker, &stroker->first_face, &stroker->ccw);
961
#if DEBUG
962
      {
963
    FILE *file = fopen ("contours.txt", "a");
964
    _cairo_debug_print_contour (file, &stroker->ccw.contour);
965
    fclose (file);
966
      }
967
#endif
968
969
29.0k
      _cairo_polygon_add_contour (stroker->polygon,
970
29.0k
          &stroker->ccw.contour);
971
29.0k
      _cairo_contour_reset (&stroker->ccw.contour);
972
29.0k
  }
973
974
107k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
975
107k
  _cairo_contour_reset (&stroker->cw.contour);
976
107k
    }
977
108k
}
978
979
static cairo_status_t
980
close_path (void *closure);
981
982
static cairo_status_t
983
move_to (void *closure,
984
   const cairo_point_t *point)
985
73.0k
{
986
73.0k
    struct stroker *stroker = closure;
987
988
    /* Cap the start and end of the previous sub path as needed */
989
73.0k
    add_caps (stroker);
990
991
73.0k
    stroker->has_first_face = FALSE;
992
73.0k
    stroker->has_current_face = FALSE;
993
73.0k
    stroker->has_initial_sub_path = FALSE;
994
995
73.0k
    stroker->first_point = *point;
996
997
#if DEBUG
998
    _cairo_contour_add_point (&stroker->path, point);
999
#endif
1000
1001
73.0k
    stroker->current_face.point = *point;
1002
1003
73.0k
    return CAIRO_STATUS_SUCCESS;
1004
73.0k
}
1005
1006
static cairo_status_t
1007
line_to (void *closure,
1008
   const cairo_point_t *point)
1009
134k
{
1010
134k
    struct stroker *stroker = closure;
1011
134k
    cairo_stroke_face_t start;
1012
134k
    cairo_point_t *p1 = &stroker->current_face.point;
1013
134k
    cairo_slope_t dev_slope;
1014
1015
134k
    stroker->has_initial_sub_path = TRUE;
1016
1017
134k
    if (p1->x == point->x && p1->y == point->y)
1018
1.22k
  return CAIRO_STATUS_SUCCESS;
1019
1020
#if DEBUG
1021
    _cairo_contour_add_point (&stroker->path, point);
1022
#endif
1023
1024
132k
    _cairo_slope_init (&dev_slope, p1, point);
1025
132k
    compute_face (p1, &dev_slope, stroker, &start);
1026
1027
132k
    if (stroker->has_current_face) {
1028
83.5k
  int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
1029
83.5k
                &start.dev_vector);
1030
83.5k
  if (clockwise) {
1031
81.6k
      clockwise = clockwise < 0;
1032
      /* Join with final face from previous segment */
1033
81.6k
      if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
1034
81.6k
            stroker->contour_tolerance) ||
1035
0
    ! within_tolerance (&stroker->current_face.cw, &start.cw,
1036
0
            stroker->contour_tolerance))
1037
81.6k
      {
1038
81.6k
    outer_join (stroker, &stroker->current_face, &start, clockwise);
1039
81.6k
    inner_join (stroker, &stroker->current_face, &start, clockwise);
1040
81.6k
      }
1041
81.6k
  }
1042
83.5k
    } else {
1043
49.3k
  if (! stroker->has_first_face) {
1044
      /* Save sub path's first face in case needed for closing join */
1045
49.3k
      stroker->first_face = start;
1046
49.3k
      stroker->has_first_face = TRUE;
1047
49.3k
  }
1048
49.3k
  stroker->has_current_face = TRUE;
1049
1050
49.3k
  contour_add_point (stroker, &stroker->cw, &start.cw);
1051
49.3k
  contour_add_point (stroker, &stroker->ccw, &start.ccw);
1052
49.3k
    }
1053
1054
132k
    stroker->current_face = start;
1055
132k
    stroker->current_face.point = *point;
1056
132k
    stroker->current_face.ccw.x += dev_slope.dx;
1057
132k
    stroker->current_face.ccw.y += dev_slope.dy;
1058
132k
    stroker->current_face.cw.x += dev_slope.dx;
1059
132k
    stroker->current_face.cw.y += dev_slope.dy;
1060
1061
132k
    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
1062
132k
    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
1063
1064
132k
    return CAIRO_STATUS_SUCCESS;
1065
134k
}
1066
1067
static cairo_status_t
1068
spline_to (void *closure,
1069
     const cairo_point_t *point,
1070
     const cairo_slope_t *tangent)
1071
171k
{
1072
171k
    struct stroker *stroker = closure;
1073
171k
    cairo_stroke_face_t face;
1074
1075
#if DEBUG
1076
    _cairo_contour_add_point (&stroker->path, point);
1077
#endif
1078
171k
    if ((tangent->dx | tangent->dy) == 0) {
1079
0
  struct stroke_contour *outer;
1080
0
  cairo_point_t t;
1081
0
  int clockwise;
1082
1083
0
  face = stroker->current_face;
1084
1085
0
  face.usr_vector.x = -face.usr_vector.x;
1086
0
  face.usr_vector.y = -face.usr_vector.y;
1087
0
  face.dev_vector.dx = -face.dev_vector.dx;
1088
0
  face.dev_vector.dy = -face.dev_vector.dy;
1089
1090
0
  t = face.cw;
1091
0
  face.cw = face.ccw;
1092
0
  face.ccw = t;
1093
1094
0
  clockwise = join_is_clockwise (&stroker->current_face, &face);
1095
0
  if (clockwise) {
1096
0
      outer = &stroker->cw;
1097
0
  } else {
1098
0
      outer = &stroker->ccw;
1099
0
  }
1100
1101
0
  add_fan (stroker,
1102
0
     &stroker->current_face.dev_vector,
1103
0
     &face.dev_vector,
1104
0
     &stroker->current_face.point,
1105
0
     clockwise, outer);
1106
171k
    } else {
1107
171k
  compute_face (point, tangent, stroker, &face);
1108
1109
171k
  if ((face.dev_slope.x * stroker->current_face.dev_slope.x +
1110
171k
       face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance)
1111
3
  {
1112
3
      struct stroke_contour *outer;
1113
3
      int clockwise = join_is_clockwise (&stroker->current_face, &face);
1114
1115
3
      stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
1116
3
      stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
1117
3
      contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
1118
1119
3
      stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
1120
3
      stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
1121
3
      contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
1122
1123
3
      if (clockwise) {
1124
3
    outer = &stroker->cw;
1125
3
      } else {
1126
0
    outer = &stroker->ccw;
1127
0
      }
1128
3
      add_fan (stroker,
1129
3
         &stroker->current_face.dev_vector,
1130
3
         &face.dev_vector,
1131
3
         &stroker->current_face.point,
1132
3
         clockwise, outer);
1133
3
  }
1134
1135
171k
  contour_add_point (stroker, &stroker->cw, &face.cw);
1136
171k
  contour_add_point (stroker, &stroker->ccw, &face.ccw);
1137
171k
    }
1138
1139
171k
    stroker->current_face = face;
1140
1141
171k
    return CAIRO_STATUS_SUCCESS;
1142
171k
}
1143
1144
static cairo_status_t
1145
curve_to (void *closure,
1146
    const cairo_point_t *b,
1147
    const cairo_point_t *c,
1148
    const cairo_point_t *d)
1149
30.3k
{
1150
30.3k
    struct stroker *stroker = closure;
1151
30.3k
    cairo_spline_t spline;
1152
30.3k
    cairo_stroke_face_t face;
1153
1154
30.3k
    if (stroker->has_bounds &&
1155
0
  ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
1156
0
            &stroker->bounds))
1157
0
  return line_to (closure, d);
1158
1159
30.3k
    if (! _cairo_spline_init (&spline, spline_to, stroker,
1160
30.3k
            &stroker->current_face.point, b, c, d))
1161
168
  return line_to (closure, d);
1162
1163
30.2k
    compute_face (&stroker->current_face.point, &spline.initial_slope,
1164
30.2k
      stroker, &face);
1165
1166
30.2k
    if (stroker->has_current_face) {
1167
23.2k
  int clockwise = join_is_clockwise (&stroker->current_face, &face);
1168
  /* Join with final face from previous segment */
1169
23.2k
  outer_join (stroker, &stroker->current_face, &face, clockwise);
1170
23.2k
  inner_join (stroker, &stroker->current_face, &face, clockwise);
1171
23.2k
    } else {
1172
6.95k
  if (! stroker->has_first_face) {
1173
      /* Save sub path's first face in case needed for closing join */
1174
6.95k
      stroker->first_face = face;
1175
6.95k
      stroker->has_first_face = TRUE;
1176
6.95k
  }
1177
6.95k
  stroker->has_current_face = TRUE;
1178
1179
6.95k
  contour_add_point (stroker, &stroker->cw, &face.cw);
1180
6.95k
  contour_add_point (stroker, &stroker->ccw, &face.ccw);
1181
6.95k
    }
1182
30.2k
    stroker->current_face = face;
1183
1184
30.2k
    return _cairo_spline_decompose (&spline, stroker->tolerance);
1185
30.3k
}
1186
1187
static cairo_status_t
1188
close_path (void *closure)
1189
28.4k
{
1190
28.4k
    struct stroker *stroker = closure;
1191
28.4k
    cairo_status_t status;
1192
1193
28.4k
    status = line_to (stroker, &stroker->first_point);
1194
28.4k
    if (unlikely (status))
1195
0
  return status;
1196
1197
28.4k
    if (stroker->has_first_face && stroker->has_current_face) {
1198
  /* Join first and final faces of sub path */
1199
27.2k
  outer_close (stroker, &stroker->current_face, &stroker->first_face);
1200
27.2k
  inner_close (stroker, &stroker->current_face, &stroker->first_face);
1201
#if 0
1202
  *_cairo_contour_first_point (&stroker->ccw.contour) =
1203
      *_cairo_contour_last_point (&stroker->ccw.contour);
1204
1205
  *_cairo_contour_first_point (&stroker->cw.contour) =
1206
      *_cairo_contour_last_point (&stroker->cw.contour);
1207
#endif
1208
1209
27.2k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
1210
27.2k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
1211
1212
#if DEBUG
1213
  {
1214
      FILE *file = fopen ("contours.txt", "a");
1215
      _cairo_debug_print_contour (file, &stroker->path);
1216
      _cairo_debug_print_contour (file, &stroker->cw.contour);
1217
      _cairo_debug_print_contour (file, &stroker->ccw.contour);
1218
      fclose (file);
1219
1220
      _cairo_contour_reset (&stroker->path);
1221
  }
1222
#endif
1223
27.2k
  _cairo_contour_reset (&stroker->cw.contour);
1224
27.2k
  _cairo_contour_reset (&stroker->ccw.contour);
1225
27.2k
    } else {
1226
  /* Cap the start and end of the sub path as needed */
1227
1.16k
  add_caps (stroker);
1228
1.16k
    }
1229
1230
28.4k
    stroker->has_initial_sub_path = FALSE;
1231
28.4k
    stroker->has_first_face = FALSE;
1232
28.4k
    stroker->has_current_face = FALSE;
1233
1234
28.4k
    return CAIRO_STATUS_SUCCESS;
1235
28.4k
}
1236
1237
cairo_status_t
1238
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
1239
             const cairo_stroke_style_t *style,
1240
             const cairo_matrix_t *ctm,
1241
             const cairo_matrix_t *ctm_inverse,
1242
             double    tolerance,
1243
             cairo_polygon_t *polygon)
1244
35.9k
{
1245
35.9k
    struct stroker stroker;
1246
35.9k
    cairo_status_t status;
1247
1248
35.9k
    if (style->num_dashes) {
1249
1.34k
  return _cairo_path_fixed_stroke_dashed_to_polygon (path,
1250
1.34k
                 style,
1251
1.34k
                 ctm,
1252
1.34k
                 ctm_inverse,
1253
1.34k
                 tolerance,
1254
1.34k
                 polygon);
1255
1.34k
    }
1256
1257
34.5k
    stroker.has_bounds = polygon->num_limits;
1258
34.5k
    if (stroker.has_bounds) {
1259
  /* Extend the bounds in each direction to account for the maximum area
1260
   * we might generate trapezoids, to capture line segments that are
1261
   * outside of the bounds but which might generate rendering that's
1262
   * within bounds.
1263
   */
1264
0
  double dx, dy;
1265
0
  cairo_fixed_t fdx, fdy;
1266
0
  int i;
1267
1268
0
  stroker.bounds = polygon->limits[0];
1269
0
  for (i = 1; i < polygon->num_limits; i++)
1270
0
       _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);
1271
1272
0
  _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
1273
0
  fdx = _cairo_fixed_from_double (dx);
1274
0
  fdy = _cairo_fixed_from_double (dy);
1275
1276
0
  stroker.bounds.p1.x -= fdx;
1277
0
  stroker.bounds.p2.x += fdx;
1278
0
  stroker.bounds.p1.y -= fdy;
1279
0
  stroker.bounds.p2.y += fdy;
1280
0
    }
1281
1282
34.5k
    stroker.style = *style;
1283
34.5k
    stroker.ctm = ctm;
1284
34.5k
    stroker.ctm_inverse = ctm_inverse;
1285
34.5k
    stroker.tolerance = tolerance;
1286
34.5k
    stroker.half_line_width = style->line_width / 2.;
1287
1288
    /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height`
1289
     * is greater than `tolerance` then two segments are joined with
1290
     * round-join, otherwise bevel-join is used.
1291
     *
1292
     * (See https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225
1293
     *  for an illustration.)
1294
     *
1295
     * `Arc height` is the distance from the center of arc's chord to
1296
     * the center of the arc. It is also the difference of arc's radius
1297
     * and the "distance from a point where segments are joined to the
1298
     * chord" (distance to the chord). Arc's radius is the half of a line
1299
     * width and the "distance to the chord" is equal to "half of a line width"
1300
     * times `cos(half the angle between segment vectors)`. So
1301
     *
1302
     *     arc_height = w/2 - w/2 * cos(phi/2),
1303
     *
1304
     * where `w/2` is the "half of a line width".
1305
     *
1306
     * Using the double angle cosine formula we can express the `cos(phi/2)`
1307
     * with just `cos(phi)` which is also the dot product of segments'
1308
     * unit vectors.
1309
     *
1310
     *     cos(phi/2) = sqrt ( (1 + cos(phi)) / 2 );
1311
     *     cos(phi/2) is in [0; 1] range, cannot be negative;
1312
     *
1313
     *     cos(phi) = a . b  = (ax * bx + ay * by),
1314
     *
1315
     * where `a` and `b` are unit vectors of the segments to be joined.
1316
     *
1317
     * Since `arc height` should be greater than the `tolerance` to produce
1318
     * a round-join we can write
1319
     *
1320
     *     w/2 * (1 - cos(phi/2))  >  tolerance;
1321
     *     1 - tolerance / (w/2)  >  cos(phi/2);    [!]
1322
     *
1323
     * which can be rewritten with the above double angle formula to
1324
     *
1325
     *     cos(phi)  <  2 * ( 1 - tolerance / (w/2) )^2 - 1,
1326
     *
1327
     * [!] Note that `w/2` is in [tolerance; +inf] range, since `cos(phi/2)`
1328
     * cannot be negative. The left part of the above inequality is the
1329
     * dot product and the right part is the `spline_cusp_tolerance`:
1330
     *
1331
     *     (ax * bx + ay * by) < spline_cusp_tolerance.
1332
     *
1333
     * In the code below only the `spline_cusp_tolerance` is calculated.
1334
     * The dot product is calculated later, in the condition expression
1335
     * itself. "Half of a line width" must be scaled with CTM for tolerance
1336
     * condition to be properly met. Also, since `arch height` cannot exceed
1337
     * the "half of a line width" and since `cos(phi/2)` cannot be negative,
1338
     * when `tolerance` is greater than the "half of a line width" the
1339
     * bevel-join should be produced.
1340
     */
1341
34.5k
    double scaled_hlw = hypot(stroker.half_line_width * ctm->xx,
1342
34.5k
            stroker.half_line_width * ctm->yx);
1343
1344
34.5k
    if (scaled_hlw <= tolerance) {
1345
0
  stroker.spline_cusp_tolerance = -1.0;
1346
34.5k
    } else {
1347
34.5k
  stroker.spline_cusp_tolerance = 1 - tolerance / scaled_hlw;
1348
34.5k
  stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
1349
34.5k
  stroker.spline_cusp_tolerance *= 2;
1350
34.5k
  stroker.spline_cusp_tolerance -= 1;
1351
34.5k
    }
1352
1353
34.5k
    stroker.ctm_det_positive =
1354
34.5k
  _cairo_matrix_compute_determinant (ctm) >= 0.0;
1355
1356
34.5k
    stroker.pen.num_vertices = 0;
1357
34.5k
    if (path->has_curve_to ||
1358
25.9k
  style->line_join == CAIRO_LINE_JOIN_ROUND ||
1359
23.0k
  style->line_cap == CAIRO_LINE_CAP_ROUND) {
1360
23.0k
  status = _cairo_pen_init (&stroker.pen,
1361
23.0k
          stroker.half_line_width,
1362
23.0k
          tolerance, ctm);
1363
23.0k
  if (unlikely (status))
1364
0
      return status;
1365
1366
  /* If the line width is so small that the pen is reduced to a
1367
     single point, then we have nothing to do. */
1368
23.0k
  if (stroker.pen.num_vertices <= 1)
1369
0
      return CAIRO_STATUS_SUCCESS;
1370
23.0k
    }
1371
1372
34.5k
    stroker.has_current_face = FALSE;
1373
34.5k
    stroker.has_first_face = FALSE;
1374
34.5k
    stroker.has_initial_sub_path = FALSE;
1375
1376
#if DEBUG
1377
    remove ("contours.txt");
1378
    remove ("polygons.txt");
1379
    _cairo_contour_init (&stroker.path, 0);
1380
#endif
1381
34.5k
    _cairo_contour_init (&stroker.cw.contour, 1);
1382
34.5k
    _cairo_contour_init (&stroker.ccw.contour, -1);
1383
34.5k
    tolerance *= CAIRO_FIXED_ONE;
1384
34.5k
    tolerance *= tolerance;
1385
34.5k
    stroker.contour_tolerance = tolerance;
1386
34.5k
    stroker.polygon = polygon;
1387
1388
34.5k
    status = _cairo_path_fixed_interpret (path,
1389
34.5k
            move_to,
1390
34.5k
            line_to,
1391
34.5k
            curve_to,
1392
34.5k
            close_path,
1393
34.5k
            &stroker);
1394
    /* Cap the start and end of the final sub path as needed */
1395
34.5k
    if (likely (status == CAIRO_STATUS_SUCCESS))
1396
34.5k
  add_caps (&stroker);
1397
1398
34.5k
    _cairo_contour_fini (&stroker.cw.contour);
1399
34.5k
    _cairo_contour_fini (&stroker.ccw.contour);
1400
34.5k
    if (stroker.pen.num_vertices)
1401
23.0k
  _cairo_pen_fini (&stroker.pen);
1402
1403
#if DEBUG
1404
    {
1405
  FILE *file = fopen ("polygons.txt", "a");
1406
  _cairo_debug_print_polygon (file, polygon);
1407
  fclose (file);
1408
    }
1409
#endif
1410
1411
34.5k
    return status;
1412
34.5k
}