Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/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
4.48M
{
113
4.48M
    return FALSE;
114
0
    return _cairo_int64_lt (point_distance_sq (p1, p2), tolerance);
115
4.48M
}
116
117
static void
118
contour_add_point (struct stroker *stroker,
119
       struct stroke_contour *c,
120
       const cairo_point_t *point)
121
4.30M
{
122
4.30M
    if (! within_tolerance (point, _cairo_contour_last_point (&c->contour),
123
4.30M
      stroker->contour_tolerance))
124
4.30M
  _cairo_contour_add_point (&c->contour, point);
125
    //*_cairo_contour_last_point (&c->contour) = *point;
126
4.30M
}
127
128
static void
129
translate_point (cairo_point_t *point, const cairo_point_t *offset)
130
2.94M
{
131
2.94M
    point->x += offset->x;
132
2.94M
    point->y += offset->y;
133
2.94M
}
134
135
static int
136
slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
137
132k
{
138
132k
    double  c = (dx1 * dy2 - dx2 * dy1);
139
140
132k
    if (c > 0) return 1;
141
71.2k
    if (c < 0) return -1;
142
6.86k
    return 0;
143
71.2k
}
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
3.29k
{
157
3.29k
    cairo_pen_t *pen = &stroker->pen;
158
3.29k
    int start, stop;
159
160
3.29k
    if (stroker->has_bounds &&
161
3.29k
  ! _cairo_box_contains_point (&stroker->bounds, midpt))
162
2.22k
  return;
163
164
3.29k
    assert (stroker->pen.num_vertices);
165
166
1.07k
    if (clockwise) {
167
383
  _cairo_pen_find_active_cw_vertices (pen,
168
383
              in_vector, out_vector,
169
383
              &start, &stop);
170
3.74k
  while (start != stop) {
171
3.36k
      cairo_point_t p = *midpt;
172
3.36k
      translate_point (&p, &pen->vertices[start].point);
173
3.36k
      contour_add_point (stroker, c, &p);
174
175
3.36k
      if (++start == pen->num_vertices)
176
76
    start = 0;
177
3.36k
  }
178
692
    } else {
179
692
  _cairo_pen_find_active_ccw_vertices (pen,
180
692
               in_vector, out_vector,
181
692
               &start, &stop);
182
14.8k
  while (start != stop) {
183
14.1k
      cairo_point_t p = *midpt;
184
14.1k
      translate_point (&p, &pen->vertices[start].point);
185
14.1k
      contour_add_point (stroker, c, &p);
186
187
14.1k
      if (start-- == 0)
188
256
    start += pen->num_vertices;
189
14.1k
  }
190
692
    }
191
1.07k
}
192
193
static int
194
join_is_clockwise (const cairo_stroke_face_t *in,
195
       const cairo_stroke_face_t *out)
196
3.23k
{
197
3.23k
    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
198
3.23k
}
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
184k
{
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
184k
    const cairo_point_t *outpt;
255
184k
    struct stroke_contour *inner;
256
257
184k
    if (clockwise) {
258
40.6k
  inner = &stroker->ccw;
259
40.6k
  outpt = &out->ccw;
260
143k
    } else {
261
143k
  inner = &stroker->cw;
262
143k
  outpt = &out->cw;
263
143k
    }
264
184k
    contour_add_point (stroker, inner, &in->point);
265
184k
    contour_add_point (stroker, inner, outpt);
266
184k
#endif
267
184k
}
268
269
static void
270
inner_close (struct stroker *stroker,
271
       const cairo_stroke_face_t *in,
272
       cairo_stroke_face_t *out)
273
1.26k
{
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
1.26k
    const cairo_point_t *inpt;
340
1.26k
    struct stroke_contour *inner;
341
342
1.26k
    if (join_is_clockwise (in, out)) {
343
150
  inner = &stroker->ccw;
344
150
  inpt = &out->ccw;
345
1.11k
    } else {
346
1.11k
  inner = &stroker->cw;
347
1.11k
  inpt = &out->cw;
348
1.11k
    }
349
350
1.26k
    contour_add_point (stroker, inner, &in->point);
351
1.26k
    contour_add_point (stroker, inner, inpt);
352
1.26k
    *_cairo_contour_first_point (&inner->contour) =
353
1.26k
  *_cairo_contour_last_point (&inner->contour);
354
1.26k
#endif
355
1.26k
}
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
1.26k
{
362
1.26k
    const cairo_point_t *inpt, *outpt;
363
1.26k
    struct stroke_contour *outer;
364
1.26k
    int clockwise;
365
366
1.26k
    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
367
20
  in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
368
20
    {
369
20
  return;
370
20
    }
371
372
1.24k
    clockwise = join_is_clockwise (in, out);
373
1.24k
    if (clockwise) {
374
149
  inpt = &in->cw;
375
149
  outpt = &out->cw;
376
149
  outer = &stroker->cw;
377
1.09k
    } else {
378
1.09k
  inpt = &in->ccw;
379
1.09k
  outpt = &out->ccw;
380
1.09k
  outer = &stroker->ccw;
381
1.09k
    }
382
383
1.24k
    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
1.24k
    switch (stroker->style.line_join) {
390
40
    case CAIRO_LINE_JOIN_ROUND:
391
40
  if ((in->dev_slope.x * out->dev_slope.x +
392
40
       in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
393
30
  {
394
      /* construct a fan around the common midpoint */
395
30
      add_fan (stroker,
396
30
         &in->dev_vector, &out->dev_vector, &in->point,
397
30
         clockwise, outer);
398
30
  } /* else: bevel join */
399
40
  break;
400
401
1.20k
    case CAIRO_LINE_JOIN_MITER:
402
1.20k
    default: {
403
  /* dot product of incoming slope vector with outgoing slope vector */
404
1.20k
  double  in_dot_out = in->dev_slope.x * out->dev_slope.x +
405
1.20k
           in->dev_slope.y * out->dev_slope.y;
406
1.20k
  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
1.20k
  if (2 <= ml * ml * (1 + in_dot_out)) {
466
496
      double    x1, y1, x2, y2;
467
496
      double    mx, my;
468
496
      double    dx1, dx2, dy1, dy2;
469
496
      double    ix, iy;
470
496
      double    fdx1, fdy1, fdx2, fdy2;
471
496
      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
496
      x1 = _cairo_fixed_to_double (inpt->x);
481
496
      y1 = _cairo_fixed_to_double (inpt->y);
482
496
      dx1 = in->dev_slope.x;
483
496
      dy1 = in->dev_slope.y;
484
485
      /* outer point of outgoing line face */
486
496
      x2 = _cairo_fixed_to_double (outpt->x);
487
496
      y2 = _cairo_fixed_to_double (outpt->y);
488
496
      dx2 = out->dev_slope.x;
489
496
      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
496
      my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
500
496
      (dx1 * dy2 - dx2 * dy1));
501
496
      if (fabs (dy1) >= fabs (dy2))
502
237
    mx = (my - y1) * dx1 / dy1 + x1;
503
259
      else
504
259
    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
496
      ix = _cairo_fixed_to_double (in->point.x);
516
496
      iy = _cairo_fixed_to_double (in->point.y);
517
518
      /* slope of one face */
519
496
      fdx1 = x1 - ix; fdy1 = y1 - iy;
520
521
      /* slope of the other face */
522
496
      fdx2 = x2 - ix; fdy2 = y2 - iy;
523
524
      /* slope from the intersection to the miter point */
525
496
      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
496
      if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
532
496
    slope_compare_sgn (fdx2, fdy2, mdx, mdy))
533
496
      {
534
496
    cairo_point_t p;
535
536
496
    p.x = _cairo_fixed_from_double (mx);
537
496
    p.y = _cairo_fixed_from_double (my);
538
539
496
    *_cairo_contour_last_point (&outer->contour) = p;
540
496
    *_cairo_contour_first_point (&outer->contour) = p;
541
496
    return;
542
496
      }
543
496
  }
544
704
  break;
545
1.20k
    }
546
547
704
    case CAIRO_LINE_JOIN_BEVEL:
548
0
  break;
549
1.24k
    }
550
744
    contour_add_point (stroker, outer, outpt);
551
744
}
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
184k
{
559
184k
    const cairo_point_t *inpt, *outpt;
560
184k
    struct stroke_contour *outer;
561
562
184k
    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
563
104k
  in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
564
104k
    {
565
104k
  return;
566
104k
    }
567
79.8k
    if (clockwise) {
568
24.3k
  inpt = &in->cw;
569
24.3k
  outpt = &out->cw;
570
24.3k
  outer = &stroker->cw;
571
55.4k
    } else {
572
55.4k
  inpt = &in->ccw;
573
55.4k
  outpt = &out->ccw;
574
55.4k
  outer = &stroker->ccw;
575
55.4k
    }
576
577
79.8k
    switch (stroker->style.line_join) {
578
3.99k
    case CAIRO_LINE_JOIN_ROUND:
579
3.99k
  if ((in->dev_slope.x * out->dev_slope.x +
580
3.99k
       in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
581
2.01k
  {
582
      /* construct a fan around the common midpoint */
583
2.01k
      add_fan (stroker,
584
2.01k
         &in->dev_vector, &out->dev_vector, &in->point,
585
2.01k
         clockwise, outer);
586
2.01k
  } /* else: bevel join */
587
3.99k
  break;
588
589
75.8k
    case CAIRO_LINE_JOIN_MITER:
590
75.8k
    default: {
591
  /* dot product of incoming slope vector with outgoing slope vector */
592
75.8k
  double  in_dot_out = in->dev_slope.x * out->dev_slope.x +
593
75.8k
           in->dev_slope.y * out->dev_slope.y;
594
75.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
75.8k
  if (2 <= ml * ml * (1 + in_dot_out)) {
654
65.5k
      double    x1, y1, x2, y2;
655
65.5k
      double    mx, my;
656
65.5k
      double    dx1, dx2, dy1, dy2;
657
65.5k
      double    ix, iy;
658
65.5k
      double    fdx1, fdy1, fdx2, fdy2;
659
65.5k
      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
65.5k
      x1 = _cairo_fixed_to_double (inpt->x);
669
65.5k
      y1 = _cairo_fixed_to_double (inpt->y);
670
65.5k
      dx1 = in->dev_slope.x;
671
65.5k
      dy1 = in->dev_slope.y;
672
673
      /* outer point of outgoing line face */
674
65.5k
      x2 = _cairo_fixed_to_double (outpt->x);
675
65.5k
      y2 = _cairo_fixed_to_double (outpt->y);
676
65.5k
      dx2 = out->dev_slope.x;
677
65.5k
      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
65.5k
      my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
688
65.5k
      (dx1 * dy2 - dx2 * dy1));
689
65.5k
      if (fabs (dy1) >= fabs (dy2))
690
33.2k
    mx = (my - y1) * dx1 / dy1 + x1;
691
32.2k
      else
692
32.2k
    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
65.5k
      ix = _cairo_fixed_to_double (in->point.x);
704
65.5k
      iy = _cairo_fixed_to_double (in->point.y);
705
706
      /* slope of one face */
707
65.5k
      fdx1 = x1 - ix; fdy1 = y1 - iy;
708
709
      /* slope of the other face */
710
65.5k
      fdx2 = x2 - ix; fdy2 = y2 - iy;
711
712
      /* slope from the intersection to the miter point */
713
65.5k
      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
65.5k
      if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
720
65.5k
    slope_compare_sgn (fdx2, fdy2, mdx, mdy))
721
29.7k
      {
722
29.7k
    cairo_point_t p;
723
724
29.7k
    p.x = _cairo_fixed_from_double (mx);
725
29.7k
    p.y = _cairo_fixed_from_double (my);
726
727
29.7k
    *_cairo_contour_last_point (&outer->contour) = p;
728
29.7k
    return;
729
29.7k
      }
730
65.5k
  }
731
46.0k
  break;
732
75.8k
    }
733
734
46.0k
    case CAIRO_LINE_JOIN_BEVEL:
735
0
  break;
736
79.8k
    }
737
50.0k
    contour_add_point (stroker,outer, outpt);
738
50.0k
}
739
740
static void
741
add_cap (struct stroker *stroker,
742
   const cairo_stroke_face_t *f,
743
   struct stroke_contour *c)
744
723k
{
745
723k
    switch (stroker->style.line_cap) {
746
542
    case CAIRO_LINE_CAP_ROUND: {
747
542
  cairo_slope_t slope;
748
749
542
  slope.dx = -f->dev_vector.dx;
750
542
  slope.dy = -f->dev_vector.dy;
751
752
542
  add_fan (stroker, &f->dev_vector, &slope, &f->point, FALSE, c);
753
542
  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
722k
    case CAIRO_LINE_CAP_BUTT:
779
722k
    default:
780
722k
  break;
781
723k
    }
782
723k
    contour_add_point (stroker, c, &f->cw);
783
723k
}
784
785
static void
786
add_leading_cap (struct stroker *stroker,
787
     const cairo_stroke_face_t *face,
788
     struct stroke_contour *c)
789
361k
{
790
361k
    cairo_stroke_face_t reversed;
791
361k
    cairo_point_t t;
792
793
361k
    reversed = *face;
794
795
    /* The initial cap needs an outward facing vector. Reverse everything */
796
361k
    reversed.usr_vector.x = -reversed.usr_vector.x;
797
361k
    reversed.usr_vector.y = -reversed.usr_vector.y;
798
361k
    reversed.dev_vector.dx = -reversed.dev_vector.dx;
799
361k
    reversed.dev_vector.dy = -reversed.dev_vector.dy;
800
801
361k
    t = reversed.cw;
802
361k
    reversed.cw = reversed.ccw;
803
361k
    reversed.ccw = t;
804
805
361k
    add_cap (stroker, &reversed, c);
806
361k
}
807
808
static void
809
add_trailing_cap (struct stroker *stroker,
810
      const cairo_stroke_face_t *face,
811
      struct stroke_contour *c)
812
361k
{
813
361k
    add_cap (stroker, face, c);
814
361k
}
815
816
static inline double
817
normalize_slope (double *dx, double *dy)
818
2.92M
{
819
2.92M
    double dx0 = *dx, dy0 = *dy;
820
2.92M
    double mag;
821
822
2.92M
    assert (dx0 != 0.0 || dy0 != 0.0);
823
824
2.92M
    if (dx0 == 0.0) {
825
550k
  *dx = 0.0;
826
550k
  if (dy0 > 0.0) {
827
360k
      mag = dy0;
828
360k
      *dy = 1.0;
829
360k
  } else {
830
190k
      mag = -dy0;
831
190k
      *dy = -1.0;
832
190k
  }
833
2.37M
    } else if (dy0 == 0.0) {
834
546k
  *dy = 0.0;
835
546k
  if (dx0 > 0.0) {
836
192k
      mag = dx0;
837
192k
      *dx = 1.0;
838
354k
  } else {
839
354k
      mag = -dx0;
840
354k
      *dx = -1.0;
841
354k
  }
842
1.82M
    } else {
843
1.82M
  mag = hypot (dx0, dy0);
844
1.82M
  *dx = dx0 / mag;
845
1.82M
  *dy = dy0 / mag;
846
1.82M
    }
847
848
2.92M
    return mag;
849
2.92M
}
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
1.46M
{
857
1.46M
    double face_dx, face_dy;
858
1.46M
    cairo_point_t offset_ccw, offset_cw;
859
1.46M
    double slope_dx, slope_dy;
860
861
1.46M
    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
862
1.46M
    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
863
1.46M
    face->length = normalize_slope (&slope_dx, &slope_dy);
864
1.46M
    face->dev_slope.x = slope_dx;
865
1.46M
    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
1.46M
    if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) {
875
  /* Normalize the matrix! */
876
1.46M
  cairo_matrix_transform_distance (stroker->ctm_inverse,
877
1.46M
           &slope_dx, &slope_dy);
878
1.46M
  normalize_slope (&slope_dx, &slope_dy);
879
880
1.46M
  if (stroker->ctm_det_positive) {
881
1.46M
      face_dx = - slope_dy * stroker->half_line_width;
882
1.46M
      face_dy = slope_dx * stroker->half_line_width;
883
1.46M
  } else {
884
24
      face_dx = slope_dy * stroker->half_line_width;
885
24
      face_dy = - slope_dx * stroker->half_line_width;
886
24
  }
887
888
  /* back to device space */
889
1.46M
  cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
890
1.46M
    } else {
891
0
  face_dx = - slope_dy * stroker->half_line_width;
892
0
  face_dy = slope_dx * stroker->half_line_width;
893
0
    }
894
895
1.46M
    offset_ccw.x = _cairo_fixed_from_double (face_dx);
896
1.46M
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
897
1.46M
    offset_cw.x = -offset_ccw.x;
898
1.46M
    offset_cw.y = -offset_ccw.y;
899
900
1.46M
    face->ccw = *point;
901
1.46M
    translate_point (&face->ccw, &offset_ccw);
902
903
1.46M
    face->point = *point;
904
905
1.46M
    face->cw = *point;
906
1.46M
    translate_point (&face->cw, &offset_cw);
907
908
1.46M
    face->usr_vector.x = slope_dx;
909
1.46M
    face->usr_vector.y = slope_dy;
910
911
1.46M
    face->dev_vector = *dev_slope;
912
1.46M
}
913
914
static void
915
add_caps (struct stroker *stroker)
916
461k
{
917
    /* check for a degenerative sub_path */
918
461k
    if (stroker->has_initial_sub_path &&
919
111k
  ! stroker->has_first_face &&
920
6.11k
  ! stroker->has_current_face &&
921
6.11k
  stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
922
213
    {
923
  /* pick an arbitrary slope to use */
924
213
  cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
925
213
  cairo_stroke_face_t face;
926
927
  /* arbitrarily choose first_point */
928
213
  compute_face (&stroker->first_point, &slope, stroker, &face);
929
930
213
  add_leading_cap (stroker, &face, &stroker->ccw);
931
213
  add_trailing_cap (stroker, &face, &stroker->ccw);
932
933
  /* ensure the circle is complete */
934
213
  _cairo_contour_add_point (&stroker->ccw.contour,
935
213
          _cairo_contour_first_point (&stroker->ccw.contour));
936
937
213
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
938
213
  _cairo_contour_reset (&stroker->ccw.contour);
939
461k
    } else {
940
461k
  if (stroker->has_current_face)
941
361k
      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
461k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
955
461k
  _cairo_contour_reset (&stroker->ccw.contour);
956
957
461k
  if (stroker->has_first_face) {
958
361k
      _cairo_contour_add_point (&stroker->ccw.contour,
959
361k
              &stroker->first_face.cw);
960
361k
      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
361k
      _cairo_polygon_add_contour (stroker->polygon,
970
361k
          &stroker->ccw.contour);
971
361k
      _cairo_contour_reset (&stroker->ccw.contour);
972
361k
  }
973
974
461k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
975
461k
  _cairo_contour_reset (&stroker->cw.contour);
976
461k
    }
977
461k
}
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
369k
{
986
369k
    struct stroker *stroker = closure;
987
988
    /* Cap the start and end of the previous sub path as needed */
989
369k
    add_caps (stroker);
990
991
369k
    stroker->has_first_face = FALSE;
992
369k
    stroker->has_current_face = FALSE;
993
369k
    stroker->has_initial_sub_path = FALSE;
994
995
369k
    stroker->first_point = *point;
996
997
#if DEBUG
998
    _cairo_contour_add_point (&stroker->path, point);
999
#endif
1000
1001
369k
    stroker->current_face.point = *point;
1002
1003
369k
    return CAIRO_STATUS_SUCCESS;
1004
369k
}
1005
1006
static cairo_status_t
1007
line_to (void *closure,
1008
   const cairo_point_t *point)
1009
297k
{
1010
297k
    struct stroker *stroker = closure;
1011
297k
    cairo_stroke_face_t start;
1012
297k
    cairo_point_t *p1 = &stroker->current_face.point;
1013
297k
    cairo_slope_t dev_slope;
1014
1015
297k
    stroker->has_initial_sub_path = TRUE;
1016
1017
297k
    if (p1->x == point->x && p1->y == point->y)
1018
6.13k
  return CAIRO_STATUS_SUCCESS;
1019
1020
#if DEBUG
1021
    _cairo_contour_add_point (&stroker->path, point);
1022
#endif
1023
1024
290k
    _cairo_slope_init (&dev_slope, p1, point);
1025
290k
    compute_face (p1, &dev_slope, stroker, &start);
1026
1027
290k
    if (stroker->has_current_face) {
1028
184k
  int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
1029
184k
                &start.dev_vector);
1030
184k
  if (clockwise) {
1031
184k
      clockwise = clockwise < 0;
1032
      /* Join with final face from previous segment */
1033
184k
      if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
1034
184k
            stroker->contour_tolerance) ||
1035
0
    ! within_tolerance (&stroker->current_face.cw, &start.cw,
1036
0
            stroker->contour_tolerance))
1037
184k
      {
1038
184k
    outer_join (stroker, &stroker->current_face, &start, clockwise);
1039
184k
    inner_join (stroker, &stroker->current_face, &start, clockwise);
1040
184k
      }
1041
184k
  }
1042
184k
    } else {
1043
106k
  if (! stroker->has_first_face) {
1044
      /* Save sub path's first face in case needed for closing join */
1045
106k
      stroker->first_face = start;
1046
106k
      stroker->has_first_face = TRUE;
1047
106k
  }
1048
106k
  stroker->has_current_face = TRUE;
1049
1050
106k
  contour_add_point (stroker, &stroker->cw, &start.cw);
1051
106k
  contour_add_point (stroker, &stroker->ccw, &start.ccw);
1052
106k
    }
1053
1054
290k
    stroker->current_face = start;
1055
290k
    stroker->current_face.point = *point;
1056
290k
    stroker->current_face.ccw.x += dev_slope.dx;
1057
290k
    stroker->current_face.ccw.y += dev_slope.dy;
1058
290k
    stroker->current_face.cw.x += dev_slope.dx;
1059
290k
    stroker->current_face.cw.y += dev_slope.dy;
1060
1061
290k
    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
1062
290k
    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
1063
1064
290k
    return CAIRO_STATUS_SUCCESS;
1065
297k
}
1066
1067
static cairo_status_t
1068
spline_to (void *closure,
1069
     const cairo_point_t *point,
1070
     const cairo_slope_t *tangent)
1071
916k
{
1072
916k
    struct stroker *stroker = closure;
1073
916k
    cairo_stroke_face_t face;
1074
1075
#if DEBUG
1076
    _cairo_contour_add_point (&stroker->path, point);
1077
#endif
1078
916k
    if ((tangent->dx | tangent->dy) == 0) {
1079
34
  struct stroke_contour *outer;
1080
34
  cairo_point_t t;
1081
34
  int clockwise;
1082
1083
34
  face = stroker->current_face;
1084
1085
34
  face.usr_vector.x = -face.usr_vector.x;
1086
34
  face.usr_vector.y = -face.usr_vector.y;
1087
34
  face.dev_vector.dx = -face.dev_vector.dx;
1088
34
  face.dev_vector.dy = -face.dev_vector.dy;
1089
1090
34
  t = face.cw;
1091
34
  face.cw = face.ccw;
1092
34
  face.ccw = t;
1093
1094
34
  clockwise = join_is_clockwise (&stroker->current_face, &face);
1095
34
  if (clockwise) {
1096
8
      outer = &stroker->cw;
1097
26
  } else {
1098
26
      outer = &stroker->ccw;
1099
26
  }
1100
1101
34
  add_fan (stroker,
1102
34
     &stroker->current_face.dev_vector,
1103
34
     &face.dev_vector,
1104
34
     &stroker->current_face.point,
1105
34
     clockwise, outer);
1106
916k
    } else {
1107
916k
  compute_face (point, tangent, stroker, &face);
1108
1109
916k
  if ((face.dev_slope.x * stroker->current_face.dev_slope.x +
1110
916k
       face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance)
1111
678
  {
1112
678
      struct stroke_contour *outer;
1113
678
      int clockwise = join_is_clockwise (&stroker->current_face, &face);
1114
1115
678
      stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
1116
678
      stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
1117
678
      contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
1118
1119
678
      stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
1120
678
      stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
1121
678
      contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
1122
1123
678
      if (clockwise) {
1124
374
    outer = &stroker->cw;
1125
374
      } else {
1126
304
    outer = &stroker->ccw;
1127
304
      }
1128
678
      add_fan (stroker,
1129
678
         &stroker->current_face.dev_vector,
1130
678
         &face.dev_vector,
1131
678
         &stroker->current_face.point,
1132
678
         clockwise, outer);
1133
678
  }
1134
1135
916k
  contour_add_point (stroker, &stroker->cw, &face.cw);
1136
916k
  contour_add_point (stroker, &stroker->ccw, &face.ccw);
1137
916k
    }
1138
1139
916k
    stroker->current_face = face;
1140
1141
916k
    return CAIRO_STATUS_SUCCESS;
1142
916k
}
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
264k
{
1150
264k
    struct stroker *stroker = closure;
1151
264k
    cairo_spline_t spline;
1152
264k
    cairo_stroke_face_t face;
1153
1154
264k
    if (stroker->has_bounds &&
1155
264k
  ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
1156
264k
            &stroker->bounds))
1157
8.41k
  return line_to (closure, d);
1158
1159
255k
    if (! _cairo_spline_init (&spline, spline_to, stroker,
1160
255k
            &stroker->current_face.point, b, c, d))
1161
96
  return line_to (closure, d);
1162
1163
255k
    compute_face (&stroker->current_face.point, &spline.initial_slope,
1164
255k
      stroker, &face);
1165
1166
255k
    if (stroker->has_current_face) {
1167
24
  int clockwise = join_is_clockwise (&stroker->current_face, &face);
1168
  /* Join with final face from previous segment */
1169
24
  outer_join (stroker, &stroker->current_face, &face, clockwise);
1170
24
  inner_join (stroker, &stroker->current_face, &face, clockwise);
1171
255k
    } else {
1172
255k
  if (! stroker->has_first_face) {
1173
      /* Save sub path's first face in case needed for closing join */
1174
255k
      stroker->first_face = face;
1175
255k
      stroker->has_first_face = TRUE;
1176
255k
  }
1177
255k
  stroker->has_current_face = TRUE;
1178
1179
255k
  contour_add_point (stroker, &stroker->cw, &face.cw);
1180
255k
  contour_add_point (stroker, &stroker->ccw, &face.ccw);
1181
255k
    }
1182
255k
    stroker->current_face = face;
1183
1184
255k
    return _cairo_spline_decompose (&spline, stroker->tolerance);
1185
255k
}
1186
1187
static cairo_status_t
1188
close_path (void *closure)
1189
2.76k
{
1190
2.76k
    struct stroker *stroker = closure;
1191
2.76k
    cairo_status_t status;
1192
1193
2.76k
    status = line_to (stroker, &stroker->first_point);
1194
2.76k
    if (unlikely (status))
1195
0
  return status;
1196
1197
2.76k
    if (stroker->has_first_face && stroker->has_current_face) {
1198
  /* Join first and final faces of sub path */
1199
1.26k
  outer_close (stroker, &stroker->current_face, &stroker->first_face);
1200
1.26k
  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
1.26k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
1210
1.26k
  _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
1.26k
  _cairo_contour_reset (&stroker->cw.contour);
1224
1.26k
  _cairo_contour_reset (&stroker->ccw.contour);
1225
1.50k
    } else {
1226
  /* Cap the start and end of the sub path as needed */
1227
1.50k
  add_caps (stroker);
1228
1.50k
    }
1229
1230
2.76k
    stroker->has_initial_sub_path = FALSE;
1231
2.76k
    stroker->has_first_face = FALSE;
1232
2.76k
    stroker->has_current_face = FALSE;
1233
1234
2.76k
    return CAIRO_STATUS_SUCCESS;
1235
2.76k
}
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
91.0k
{
1245
91.0k
    struct stroker stroker;
1246
91.0k
    cairo_status_t status;
1247
1248
91.0k
    if (style->num_dashes) {
1249
0
  return _cairo_path_fixed_stroke_dashed_to_polygon (path,
1250
0
                 style,
1251
0
                 ctm,
1252
0
                 ctm_inverse,
1253
0
                 tolerance,
1254
0
                 polygon);
1255
0
    }
1256
1257
91.0k
    stroker.has_bounds = polygon->num_limits;
1258
91.0k
    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
91.0k
  double dx, dy;
1265
91.0k
  cairo_fixed_t fdx, fdy;
1266
91.0k
  int i;
1267
1268
91.0k
  stroker.bounds = polygon->limits[0];
1269
91.0k
  for (i = 1; i < polygon->num_limits; i++)
1270
0
       _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);
1271
1272
91.0k
  _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
1273
91.0k
  fdx = _cairo_fixed_from_double (dx);
1274
91.0k
  fdy = _cairo_fixed_from_double (dy);
1275
1276
91.0k
  stroker.bounds.p1.x -= fdx;
1277
91.0k
  stroker.bounds.p2.x += fdx;
1278
91.0k
  stroker.bounds.p1.y -= fdy;
1279
91.0k
  stroker.bounds.p2.y += fdy;
1280
91.0k
    }
1281
1282
91.0k
    stroker.style = *style;
1283
91.0k
    stroker.ctm = ctm;
1284
91.0k
    stroker.ctm_inverse = ctm_inverse;
1285
91.0k
    stroker.tolerance = tolerance;
1286
91.0k
    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
91.0k
    double scaled_hlw = hypot(stroker.half_line_width * ctm->xx,
1342
91.0k
            stroker.half_line_width * ctm->yx);
1343
1344
91.0k
    if (scaled_hlw <= tolerance) {
1345
2
  stroker.spline_cusp_tolerance = -1.0;
1346
91.0k
    } else {
1347
91.0k
  stroker.spline_cusp_tolerance = 1 - tolerance / scaled_hlw;
1348
91.0k
  stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
1349
91.0k
  stroker.spline_cusp_tolerance *= 2;
1350
91.0k
  stroker.spline_cusp_tolerance -= 1;
1351
91.0k
    }
1352
1353
91.0k
    stroker.ctm_det_positive =
1354
91.0k
  _cairo_matrix_compute_determinant (ctm) >= 0.0;
1355
1356
91.0k
    stroker.pen.num_vertices = 0;
1357
91.0k
    if (path->has_curve_to ||
1358
3.78k
  style->line_join == CAIRO_LINE_JOIN_ROUND ||
1359
87.3k
  style->line_cap == CAIRO_LINE_CAP_ROUND) {
1360
87.3k
  status = _cairo_pen_init (&stroker.pen,
1361
87.3k
          stroker.half_line_width,
1362
87.3k
          tolerance, ctm);
1363
87.3k
  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
87.3k
  if (stroker.pen.num_vertices <= 1)
1369
0
      return CAIRO_STATUS_SUCCESS;
1370
87.3k
    }
1371
1372
91.0k
    stroker.has_current_face = FALSE;
1373
91.0k
    stroker.has_first_face = FALSE;
1374
91.0k
    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
91.0k
    _cairo_contour_init (&stroker.cw.contour, 1);
1382
91.0k
    _cairo_contour_init (&stroker.ccw.contour, -1);
1383
91.0k
    tolerance *= CAIRO_FIXED_ONE;
1384
91.0k
    tolerance *= tolerance;
1385
91.0k
    stroker.contour_tolerance = tolerance;
1386
91.0k
    stroker.polygon = polygon;
1387
1388
91.0k
    status = _cairo_path_fixed_interpret (path,
1389
91.0k
            move_to,
1390
91.0k
            line_to,
1391
91.0k
            curve_to,
1392
91.0k
            close_path,
1393
91.0k
            &stroker);
1394
    /* Cap the start and end of the final sub path as needed */
1395
91.0k
    if (likely (status == CAIRO_STATUS_SUCCESS))
1396
91.0k
  add_caps (&stroker);
1397
1398
91.0k
    _cairo_contour_fini (&stroker.cw.contour);
1399
91.0k
    _cairo_contour_fini (&stroker.ccw.contour);
1400
91.0k
    if (stroker.pen.num_vertices)
1401
87.3k
  _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
91.0k
    return status;
1412
91.0k
}