Coverage Report

Created: 2025-11-16 09:57

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