Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-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
2.97M
{
113
2.97M
    return FALSE;
114
0
    return _cairo_int64_lt (point_distance_sq (p1, p2), tolerance);
115
2.97M
}
116
117
static void
118
contour_add_point (struct stroker *stroker,
119
       struct stroke_contour *c,
120
       const cairo_point_t *point)
121
2.71M
{
122
2.71M
    if (! within_tolerance (point, _cairo_contour_last_point (&c->contour),
123
2.71M
      stroker->contour_tolerance))
124
2.71M
  _cairo_contour_add_point (&c->contour, point);
125
    //*_cairo_contour_last_point (&c->contour) = *point;
126
2.71M
}
127
128
static void
129
translate_point (cairo_point_t *point, const cairo_point_t *offset)
130
1.70M
{
131
1.70M
    point->x += offset->x;
132
1.70M
    point->y += offset->y;
133
1.70M
}
134
135
static int
136
slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
137
190k
{
138
190k
    double  c = (dx1 * dy2 - dx2 * dy1);
139
140
190k
    if (c > 0) return 1;
141
100k
    if (c < 0) return -1;
142
5.86k
    return 0;
143
100k
}
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
1.85k
{
157
1.85k
    cairo_pen_t *pen = &stroker->pen;
158
1.85k
    int start, stop;
159
160
1.85k
    if (stroker->has_bounds &&
161
1.85k
  ! _cairo_box_contains_point (&stroker->bounds, midpt))
162
1.06k
  return;
163
164
1.85k
    assert (stroker->pen.num_vertices);
165
166
798
    if (clockwise) {
167
119
  _cairo_pen_find_active_cw_vertices (pen,
168
119
              in_vector, out_vector,
169
119
              &start, &stop);
170
1.30k
  while (start != stop) {
171
1.18k
      cairo_point_t p = *midpt;
172
1.18k
      translate_point (&p, &pen->vertices[start].point);
173
1.18k
      contour_add_point (stroker, c, &p);
174
175
1.18k
      if (++start == pen->num_vertices)
176
30
    start = 0;
177
1.18k
  }
178
679
    } else {
179
679
  _cairo_pen_find_active_ccw_vertices (pen,
180
679
               in_vector, out_vector,
181
679
               &start, &stop);
182
23.7k
  while (start != stop) {
183
23.0k
      cairo_point_t p = *midpt;
184
23.0k
      translate_point (&p, &pen->vertices[start].point);
185
23.0k
      contour_add_point (stroker, c, &p);
186
187
23.0k
      if (start-- == 0)
188
299
    start += pen->num_vertices;
189
23.0k
  }
190
679
    }
191
798
}
192
193
static int
194
join_is_clockwise (const cairo_stroke_face_t *in,
195
       const cairo_stroke_face_t *out)
196
2.60k
{
197
2.60k
    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
198
2.60k
}
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
252k
{
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
252k
    const cairo_point_t *outpt;
255
252k
    struct stroke_contour *inner;
256
257
252k
    if (clockwise) {
258
60.0k
  inner = &stroker->ccw;
259
60.0k
  outpt = &out->ccw;
260
192k
    } else {
261
192k
  inner = &stroker->cw;
262
192k
  outpt = &out->cw;
263
192k
    }
264
252k
    contour_add_point (stroker, inner, &in->point);
265
252k
    contour_add_point (stroker, inner, outpt);
266
252k
#endif
267
252k
}
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.27k
{
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.27k
    const cairo_point_t *inpt;
340
1.27k
    struct stroke_contour *inner;
341
342
1.27k
    if (join_is_clockwise (in, out)) {
343
127
  inner = &stroker->ccw;
344
127
  inpt = &out->ccw;
345
1.14k
    } else {
346
1.14k
  inner = &stroker->cw;
347
1.14k
  inpt = &out->cw;
348
1.14k
    }
349
350
1.27k
    contour_add_point (stroker, inner, &in->point);
351
1.27k
    contour_add_point (stroker, inner, inpt);
352
1.27k
    *_cairo_contour_first_point (&inner->contour) =
353
1.27k
  *_cairo_contour_last_point (&inner->contour);
354
1.27k
#endif
355
1.27k
}
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.27k
{
362
1.27k
    const cairo_point_t *inpt, *outpt;
363
1.27k
    struct stroke_contour *outer;
364
1.27k
    int clockwise;
365
366
1.27k
    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
367
5
  in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
368
5
    {
369
5
  return;
370
5
    }
371
372
1.26k
    clockwise = join_is_clockwise (in, out);
373
1.26k
    if (clockwise) {
374
127
  inpt = &in->cw;
375
127
  outpt = &out->cw;
376
127
  outer = &stroker->cw;
377
1.14k
    } else {
378
1.14k
  inpt = &in->ccw;
379
1.14k
  outpt = &out->ccw;
380
1.14k
  outer = &stroker->ccw;
381
1.14k
    }
382
383
1.26k
    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.26k
    switch (stroker->style.line_join) {
390
18
    case CAIRO_LINE_JOIN_ROUND:
391
18
  if ((in->dev_slope.x * out->dev_slope.x +
392
18
       in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
393
15
  {
394
      /* construct a fan around the common midpoint */
395
15
      add_fan (stroker,
396
15
         &in->dev_vector, &out->dev_vector, &in->point,
397
15
         clockwise, outer);
398
15
  } /* else: bevel join */
399
18
  break;
400
401
1.25k
    case CAIRO_LINE_JOIN_MITER:
402
1.25k
    default: {
403
  /* dot product of incoming slope vector with outgoing slope vector */
404
1.25k
  double  in_dot_out = in->dev_slope.x * out->dev_slope.x +
405
1.25k
           in->dev_slope.y * out->dev_slope.y;
406
1.25k
  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.25k
  if (2 <= ml * ml * (1 + in_dot_out)) {
466
521
      double    x1, y1, x2, y2;
467
521
      double    mx, my;
468
521
      double    dx1, dx2, dy1, dy2;
469
521
      double    ix, iy;
470
521
      double    fdx1, fdy1, fdx2, fdy2;
471
521
      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
521
      x1 = _cairo_fixed_to_double (inpt->x);
481
521
      y1 = _cairo_fixed_to_double (inpt->y);
482
521
      dx1 = in->dev_slope.x;
483
521
      dy1 = in->dev_slope.y;
484
485
      /* outer point of outgoing line face */
486
521
      x2 = _cairo_fixed_to_double (outpt->x);
487
521
      y2 = _cairo_fixed_to_double (outpt->y);
488
521
      dx2 = out->dev_slope.x;
489
521
      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
521
      my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
500
521
      (dx1 * dy2 - dx2 * dy1));
501
521
      if (fabs (dy1) >= fabs (dy2))
502
258
    mx = (my - y1) * dx1 / dy1 + x1;
503
263
      else
504
263
    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
521
      ix = _cairo_fixed_to_double (in->point.x);
516
521
      iy = _cairo_fixed_to_double (in->point.y);
517
518
      /* slope of one face */
519
521
      fdx1 = x1 - ix; fdy1 = y1 - iy;
520
521
      /* slope of the other face */
522
521
      fdx2 = x2 - ix; fdy2 = y2 - iy;
523
524
      /* slope from the intersection to the miter point */
525
521
      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
521
      if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
532
521
    slope_compare_sgn (fdx2, fdy2, mdx, mdy))
533
520
      {
534
520
    cairo_point_t p;
535
536
520
    p.x = _cairo_fixed_from_double (mx);
537
520
    p.y = _cairo_fixed_from_double (my);
538
539
520
    *_cairo_contour_last_point (&outer->contour) = p;
540
520
    *_cairo_contour_first_point (&outer->contour) = p;
541
520
    return;
542
520
      }
543
521
  }
544
730
  break;
545
1.25k
    }
546
547
730
    case CAIRO_LINE_JOIN_BEVEL:
548
0
  break;
549
1.26k
    }
550
748
    contour_add_point (stroker, outer, outpt);
551
748
}
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
252k
{
559
252k
    const cairo_point_t *inpt, *outpt;
560
252k
    struct stroke_contour *outer;
561
562
252k
    if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
563
140k
  in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
564
140k
    {
565
140k
  return;
566
140k
    }
567
111k
    if (clockwise) {
568
34.1k
  inpt = &in->cw;
569
34.1k
  outpt = &out->cw;
570
34.1k
  outer = &stroker->cw;
571
77.3k
    } else {
572
77.3k
  inpt = &in->ccw;
573
77.3k
  outpt = &out->ccw;
574
77.3k
  outer = &stroker->ccw;
575
77.3k
    }
576
577
111k
    switch (stroker->style.line_join) {
578
1.78k
    case CAIRO_LINE_JOIN_ROUND:
579
1.78k
  if ((in->dev_slope.x * out->dev_slope.x +
580
1.78k
       in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
581
1.03k
  {
582
      /* construct a fan around the common midpoint */
583
1.03k
      add_fan (stroker,
584
1.03k
         &in->dev_vector, &out->dev_vector, &in->point,
585
1.03k
         clockwise, outer);
586
1.03k
  } /* else: bevel join */
587
1.78k
  break;
588
589
109k
    case CAIRO_LINE_JOIN_MITER:
590
109k
    default: {
591
  /* dot product of incoming slope vector with outgoing slope vector */
592
109k
  double  in_dot_out = in->dev_slope.x * out->dev_slope.x +
593
109k
           in->dev_slope.y * out->dev_slope.y;
594
109k
  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
109k
  if (2 <= ml * ml * (1 + in_dot_out)) {
654
94.5k
      double    x1, y1, x2, y2;
655
94.5k
      double    mx, my;
656
94.5k
      double    dx1, dx2, dy1, dy2;
657
94.5k
      double    ix, iy;
658
94.5k
      double    fdx1, fdy1, fdx2, fdy2;
659
94.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
94.5k
      x1 = _cairo_fixed_to_double (inpt->x);
669
94.5k
      y1 = _cairo_fixed_to_double (inpt->y);
670
94.5k
      dx1 = in->dev_slope.x;
671
94.5k
      dy1 = in->dev_slope.y;
672
673
      /* outer point of outgoing line face */
674
94.5k
      x2 = _cairo_fixed_to_double (outpt->x);
675
94.5k
      y2 = _cairo_fixed_to_double (outpt->y);
676
94.5k
      dx2 = out->dev_slope.x;
677
94.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
94.5k
      my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
688
94.5k
      (dx1 * dy2 - dx2 * dy1));
689
94.5k
      if (fabs (dy1) >= fabs (dy2))
690
48.1k
    mx = (my - y1) * dx1 / dy1 + x1;
691
46.3k
      else
692
46.3k
    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
94.5k
      ix = _cairo_fixed_to_double (in->point.x);
704
94.5k
      iy = _cairo_fixed_to_double (in->point.y);
705
706
      /* slope of one face */
707
94.5k
      fdx1 = x1 - ix; fdy1 = y1 - iy;
708
709
      /* slope of the other face */
710
94.5k
      fdx2 = x2 - ix; fdy2 = y2 - iy;
711
712
      /* slope from the intersection to the miter point */
713
94.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
94.5k
      if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
720
94.5k
    slope_compare_sgn (fdx2, fdy2, mdx, mdy))
721
36.5k
      {
722
36.5k
    cairo_point_t p;
723
724
36.5k
    p.x = _cairo_fixed_from_double (mx);
725
36.5k
    p.y = _cairo_fixed_from_double (my);
726
727
36.5k
    *_cairo_contour_last_point (&outer->contour) = p;
728
36.5k
    return;
729
36.5k
      }
730
94.5k
  }
731
73.1k
  break;
732
109k
    }
733
734
73.1k
    case CAIRO_LINE_JOIN_BEVEL:
735
0
  break;
736
111k
    }
737
74.9k
    contour_add_point (stroker,outer, outpt);
738
74.9k
}
739
740
static void
741
add_cap (struct stroker *stroker,
742
   const cairo_stroke_face_t *f,
743
   struct stroke_contour *c)
744
334k
{
745
334k
    switch (stroker->style.line_cap) {
746
764
    case CAIRO_LINE_CAP_ROUND: {
747
764
  cairo_slope_t slope;
748
749
764
  slope.dx = -f->dev_vector.dx;
750
764
  slope.dy = -f->dev_vector.dy;
751
752
764
  add_fan (stroker, &f->dev_vector, &slope, &f->point, FALSE, c);
753
764
  break;
754
0
    }
755
756
10
    case CAIRO_LINE_CAP_SQUARE: {
757
10
  cairo_slope_t fvector;
758
10
  cairo_point_t p;
759
10
  double dx, dy;
760
761
10
  dx = f->usr_vector.x;
762
10
  dy = f->usr_vector.y;
763
10
  dx *= stroker->half_line_width;
764
10
  dy *= stroker->half_line_width;
765
10
  cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
766
10
  fvector.dx = _cairo_fixed_from_double (dx);
767
10
  fvector.dy = _cairo_fixed_from_double (dy);
768
769
10
  p.x = f->ccw.x + fvector.dx;
770
10
  p.y = f->ccw.y + fvector.dy;
771
10
  contour_add_point (stroker, c, &p);
772
773
10
  p.x = f->cw.x + fvector.dx;
774
10
  p.y = f->cw.y + fvector.dy;
775
10
  contour_add_point (stroker, c, &p);
776
10
    }
777
778
333k
    case CAIRO_LINE_CAP_BUTT:
779
333k
    default:
780
333k
  break;
781
334k
    }
782
334k
    contour_add_point (stroker, c, &f->cw);
783
334k
}
784
785
static void
786
add_leading_cap (struct stroker *stroker,
787
     const cairo_stroke_face_t *face,
788
     struct stroke_contour *c)
789
167k
{
790
167k
    cairo_stroke_face_t reversed;
791
167k
    cairo_point_t t;
792
793
167k
    reversed = *face;
794
795
    /* The initial cap needs an outward facing vector. Reverse everything */
796
167k
    reversed.usr_vector.x = -reversed.usr_vector.x;
797
167k
    reversed.usr_vector.y = -reversed.usr_vector.y;
798
167k
    reversed.dev_vector.dx = -reversed.dev_vector.dx;
799
167k
    reversed.dev_vector.dy = -reversed.dev_vector.dy;
800
801
167k
    t = reversed.cw;
802
167k
    reversed.cw = reversed.ccw;
803
167k
    reversed.ccw = t;
804
805
167k
    add_cap (stroker, &reversed, c);
806
167k
}
807
808
static void
809
add_trailing_cap (struct stroker *stroker,
810
      const cairo_stroke_face_t *face,
811
      struct stroke_contour *c)
812
167k
{
813
167k
    add_cap (stroker, face, c);
814
167k
}
815
816
static inline double
817
normalize_slope (double *dx, double *dy)
818
1.67M
{
819
1.67M
    double dx0 = *dx, dy0 = *dy;
820
1.67M
    double mag;
821
822
1.67M
    assert (dx0 != 0.0 || dy0 != 0.0);
823
824
1.67M
    if (dx0 == 0.0) {
825
290k
  *dx = 0.0;
826
290k
  if (dy0 > 0.0) {
827
186k
      mag = dy0;
828
186k
      *dy = 1.0;
829
186k
  } else {
830
103k
      mag = -dy0;
831
103k
      *dy = -1.0;
832
103k
  }
833
1.38M
    } else if (dy0 == 0.0) {
834
274k
  *dy = 0.0;
835
274k
  if (dx0 > 0.0) {
836
102k
      mag = dx0;
837
102k
      *dx = 1.0;
838
172k
  } else {
839
172k
      mag = -dx0;
840
172k
      *dx = -1.0;
841
172k
  }
842
1.11M
    } else {
843
1.11M
  mag = hypot (dx0, dy0);
844
1.11M
  *dx = dx0 / mag;
845
1.11M
  *dy = dy0 / mag;
846
1.11M
    }
847
848
1.67M
    return mag;
849
1.67M
}
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
838k
{
857
838k
    double face_dx, face_dy;
858
838k
    cairo_point_t offset_ccw, offset_cw;
859
838k
    double slope_dx, slope_dy;
860
861
838k
    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
862
838k
    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
863
838k
    face->length = normalize_slope (&slope_dx, &slope_dy);
864
838k
    face->dev_slope.x = slope_dx;
865
838k
    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
838k
    if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) {
875
  /* Normalize the matrix! */
876
838k
  cairo_matrix_transform_distance (stroker->ctm_inverse,
877
838k
           &slope_dx, &slope_dy);
878
838k
  normalize_slope (&slope_dx, &slope_dy);
879
880
838k
  if (stroker->ctm_det_positive) {
881
838k
      face_dx = - slope_dy * stroker->half_line_width;
882
838k
      face_dy = slope_dx * stroker->half_line_width;
883
838k
  } 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
838k
  cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
890
838k
    } 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
838k
    offset_ccw.x = _cairo_fixed_from_double (face_dx);
896
838k
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
897
838k
    offset_cw.x = -offset_ccw.x;
898
838k
    offset_cw.y = -offset_ccw.y;
899
900
838k
    face->ccw = *point;
901
838k
    translate_point (&face->ccw, &offset_ccw);
902
903
838k
    face->point = *point;
904
905
838k
    face->cw = *point;
906
838k
    translate_point (&face->cw, &offset_cw);
907
908
838k
    face->usr_vector.x = slope_dx;
909
838k
    face->usr_vector.y = slope_dy;
910
911
838k
    face->dev_vector = *dev_slope;
912
838k
}
913
914
static void
915
add_caps (struct stroker *stroker)
916
217k
{
917
    /* check for a degenerative sub_path */
918
217k
    if (stroker->has_initial_sub_path &&
919
52.6k
  ! stroker->has_first_face &&
920
3.18k
  ! stroker->has_current_face &&
921
3.18k
  stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
922
292
    {
923
  /* pick an arbitrary slope to use */
924
292
  cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
925
292
  cairo_stroke_face_t face;
926
927
  /* arbitrarily choose first_point */
928
292
  compute_face (&stroker->first_point, &slope, stroker, &face);
929
930
292
  add_leading_cap (stroker, &face, &stroker->ccw);
931
292
  add_trailing_cap (stroker, &face, &stroker->ccw);
932
933
  /* ensure the circle is complete */
934
292
  _cairo_contour_add_point (&stroker->ccw.contour,
935
292
          _cairo_contour_first_point (&stroker->ccw.contour));
936
937
292
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
938
292
  _cairo_contour_reset (&stroker->ccw.contour);
939
217k
    } else {
940
217k
  if (stroker->has_current_face)
941
166k
      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
217k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
955
217k
  _cairo_contour_reset (&stroker->ccw.contour);
956
957
217k
  if (stroker->has_first_face) {
958
166k
      _cairo_contour_add_point (&stroker->ccw.contour,
959
166k
              &stroker->first_face.cw);
960
166k
      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
166k
      _cairo_polygon_add_contour (stroker->polygon,
970
166k
          &stroker->ccw.contour);
971
166k
      _cairo_contour_reset (&stroker->ccw.contour);
972
166k
  }
973
974
217k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
975
217k
  _cairo_contour_reset (&stroker->cw.contour);
976
217k
    }
977
217k
}
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
171k
{
986
171k
    struct stroker *stroker = closure;
987
988
    /* Cap the start and end of the previous sub path as needed */
989
171k
    add_caps (stroker);
990
991
171k
    stroker->has_first_face = FALSE;
992
171k
    stroker->has_current_face = FALSE;
993
171k
    stroker->has_initial_sub_path = FALSE;
994
995
171k
    stroker->first_point = *point;
996
997
#if DEBUG
998
    _cairo_contour_add_point (&stroker->path, point);
999
#endif
1000
1001
171k
    stroker->current_face.point = *point;
1002
1003
171k
    return CAIRO_STATUS_SUCCESS;
1004
171k
}
1005
1006
static cairo_status_t
1007
line_to (void *closure,
1008
   const cairo_point_t *point)
1009
306k
{
1010
306k
    struct stroker *stroker = closure;
1011
306k
    cairo_stroke_face_t start;
1012
306k
    cairo_point_t *p1 = &stroker->current_face.point;
1013
306k
    cairo_slope_t dev_slope;
1014
1015
306k
    stroker->has_initial_sub_path = TRUE;
1016
1017
306k
    if (p1->x == point->x && p1->y == point->y)
1018
3.19k
  return CAIRO_STATUS_SUCCESS;
1019
1020
#if DEBUG
1021
    _cairo_contour_add_point (&stroker->path, point);
1022
#endif
1023
1024
303k
    _cairo_slope_init (&dev_slope, p1, point);
1025
303k
    compute_face (p1, &dev_slope, stroker, &start);
1026
1027
303k
    if (stroker->has_current_face) {
1028
252k
  int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
1029
252k
                &start.dev_vector);
1030
252k
  if (clockwise) {
1031
252k
      clockwise = clockwise < 0;
1032
      /* Join with final face from previous segment */
1033
252k
      if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
1034
252k
            stroker->contour_tolerance) ||
1035
0
    ! within_tolerance (&stroker->current_face.cw, &start.cw,
1036
0
            stroker->contour_tolerance))
1037
252k
      {
1038
252k
    outer_join (stroker, &stroker->current_face, &start, clockwise);
1039
252k
    inner_join (stroker, &stroker->current_face, &start, clockwise);
1040
252k
      }
1041
252k
  }
1042
252k
    } else {
1043
50.7k
  if (! stroker->has_first_face) {
1044
      /* Save sub path's first face in case needed for closing join */
1045
50.7k
      stroker->first_face = start;
1046
50.7k
      stroker->has_first_face = TRUE;
1047
50.7k
  }
1048
50.7k
  stroker->has_current_face = TRUE;
1049
1050
50.7k
  contour_add_point (stroker, &stroker->cw, &start.cw);
1051
50.7k
  contour_add_point (stroker, &stroker->ccw, &start.ccw);
1052
50.7k
    }
1053
1054
303k
    stroker->current_face = start;
1055
303k
    stroker->current_face.point = *point;
1056
303k
    stroker->current_face.ccw.x += dev_slope.dx;
1057
303k
    stroker->current_face.ccw.y += dev_slope.dy;
1058
303k
    stroker->current_face.cw.x += dev_slope.dx;
1059
303k
    stroker->current_face.cw.y += dev_slope.dy;
1060
1061
303k
    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
1062
303k
    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
1063
1064
303k
    return CAIRO_STATUS_SUCCESS;
1065
306k
}
1066
1067
static cairo_status_t
1068
spline_to (void *closure,
1069
     const cairo_point_t *point,
1070
     const cairo_slope_t *tangent)
1071
417k
{
1072
417k
    struct stroker *stroker = closure;
1073
417k
    cairo_stroke_face_t face;
1074
1075
#if DEBUG
1076
    _cairo_contour_add_point (&stroker->path, point);
1077
#endif
1078
417k
    if ((tangent->dx | tangent->dy) == 0) {
1079
2
  struct stroke_contour *outer;
1080
2
  cairo_point_t t;
1081
2
  int clockwise;
1082
1083
2
  face = stroker->current_face;
1084
1085
2
  face.usr_vector.x = -face.usr_vector.x;
1086
2
  face.usr_vector.y = -face.usr_vector.y;
1087
2
  face.dev_vector.dx = -face.dev_vector.dx;
1088
2
  face.dev_vector.dy = -face.dev_vector.dy;
1089
1090
2
  t = face.cw;
1091
2
  face.cw = face.ccw;
1092
2
  face.ccw = t;
1093
1094
2
  clockwise = join_is_clockwise (&stroker->current_face, &face);
1095
2
  if (clockwise) {
1096
0
      outer = &stroker->cw;
1097
2
  } else {
1098
2
      outer = &stroker->ccw;
1099
2
  }
1100
1101
2
  add_fan (stroker,
1102
2
     &stroker->current_face.dev_vector,
1103
2
     &face.dev_vector,
1104
2
     &stroker->current_face.point,
1105
2
     clockwise, outer);
1106
417k
    } else {
1107
417k
  compute_face (point, tangent, stroker, &face);
1108
1109
417k
  if ((face.dev_slope.x * stroker->current_face.dev_slope.x +
1110
417k
       face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance)
1111
38
  {
1112
38
      struct stroke_contour *outer;
1113
38
      int clockwise = join_is_clockwise (&stroker->current_face, &face);
1114
1115
38
      stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
1116
38
      stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
1117
38
      contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
1118
1119
38
      stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
1120
38
      stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
1121
38
      contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
1122
1123
38
      if (clockwise) {
1124
26
    outer = &stroker->cw;
1125
26
      } else {
1126
12
    outer = &stroker->ccw;
1127
12
      }
1128
38
      add_fan (stroker,
1129
38
         &stroker->current_face.dev_vector,
1130
38
         &face.dev_vector,
1131
38
         &stroker->current_face.point,
1132
38
         clockwise, outer);
1133
38
  }
1134
1135
417k
  contour_add_point (stroker, &stroker->cw, &face.cw);
1136
417k
  contour_add_point (stroker, &stroker->ccw, &face.ccw);
1137
417k
    }
1138
1139
417k
    stroker->current_face = face;
1140
1141
417k
    return CAIRO_STATUS_SUCCESS;
1142
417k
}
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
120k
{
1150
120k
    struct stroker *stroker = closure;
1151
120k
    cairo_spline_t spline;
1152
120k
    cairo_stroke_face_t face;
1153
1154
120k
    if (stroker->has_bounds &&
1155
120k
  ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
1156
120k
            &stroker->bounds))
1157
3.03k
  return line_to (closure, d);
1158
1159
117k
    if (! _cairo_spline_init (&spline, spline_to, stroker,
1160
117k
            &stroker->current_face.point, b, c, d))
1161
6
  return line_to (closure, d);
1162
1163
117k
    compute_face (&stroker->current_face.point, &spline.initial_slope,
1164
117k
      stroker, &face);
1165
1166
117k
    if (stroker->has_current_face) {
1167
20
  int clockwise = join_is_clockwise (&stroker->current_face, &face);
1168
  /* Join with final face from previous segment */
1169
20
  outer_join (stroker, &stroker->current_face, &face, clockwise);
1170
20
  inner_join (stroker, &stroker->current_face, &face, clockwise);
1171
117k
    } else {
1172
117k
  if (! stroker->has_first_face) {
1173
      /* Save sub path's first face in case needed for closing join */
1174
117k
      stroker->first_face = face;
1175
117k
      stroker->has_first_face = TRUE;
1176
117k
  }
1177
117k
  stroker->has_current_face = TRUE;
1178
1179
117k
  contour_add_point (stroker, &stroker->cw, &face.cw);
1180
117k
  contour_add_point (stroker, &stroker->ccw, &face.ccw);
1181
117k
    }
1182
117k
    stroker->current_face = face;
1183
1184
117k
    return _cairo_spline_decompose (&spline, stroker->tolerance);
1185
117k
}
1186
1187
static cairo_status_t
1188
close_path (void *closure)
1189
2.84k
{
1190
2.84k
    struct stroker *stroker = closure;
1191
2.84k
    cairo_status_t status;
1192
1193
2.84k
    status = line_to (stroker, &stroker->first_point);
1194
2.84k
    if (unlikely (status))
1195
0
  return status;
1196
1197
2.84k
    if (stroker->has_first_face && stroker->has_current_face) {
1198
  /* Join first and final faces of sub path */
1199
1.27k
  outer_close (stroker, &stroker->current_face, &stroker->first_face);
1200
1.27k
  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.27k
  _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
1210
1.27k
  _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.27k
  _cairo_contour_reset (&stroker->cw.contour);
1224
1.27k
  _cairo_contour_reset (&stroker->ccw.contour);
1225
1.56k
    } else {
1226
  /* Cap the start and end of the sub path as needed */
1227
1.56k
  add_caps (stroker);
1228
1.56k
    }
1229
1230
2.84k
    stroker->has_initial_sub_path = FALSE;
1231
2.84k
    stroker->has_first_face = FALSE;
1232
2.84k
    stroker->has_current_face = FALSE;
1233
1234
2.84k
    return CAIRO_STATUS_SUCCESS;
1235
2.84k
}
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
44.5k
{
1245
44.5k
    struct stroker stroker;
1246
44.5k
    cairo_status_t status;
1247
1248
44.5k
    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
44.5k
    stroker.has_bounds = polygon->num_limits;
1258
44.5k
    if (stroker.has_bounds) {
1259
  /* Extend the bounds in each direction to account for the maximum area
1260
   * we might generate trapezoids, to capture line segments that are
1261
   * outside of the bounds but which might generate rendering that's
1262
   * within bounds.
1263
   */
1264
44.5k
  double dx, dy;
1265
44.5k
  cairo_fixed_t fdx, fdy;
1266
44.5k
  int i;
1267
1268
44.5k
  stroker.bounds = polygon->limits[0];
1269
44.5k
  for (i = 1; i < polygon->num_limits; i++)
1270
0
       _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);
1271
1272
44.5k
  _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
1273
44.5k
  fdx = _cairo_fixed_from_double (dx);
1274
44.5k
  fdy = _cairo_fixed_from_double (dy);
1275
1276
44.5k
  stroker.bounds.p1.x -= fdx;
1277
44.5k
  stroker.bounds.p2.x += fdx;
1278
44.5k
  stroker.bounds.p1.y -= fdy;
1279
44.5k
  stroker.bounds.p2.y += fdy;
1280
44.5k
    }
1281
1282
44.5k
    stroker.style = *style;
1283
44.5k
    stroker.ctm = ctm;
1284
44.5k
    stroker.ctm_inverse = ctm_inverse;
1285
44.5k
    stroker.tolerance = tolerance;
1286
44.5k
    stroker.half_line_width = style->line_width / 2.;
1287
1288
    /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height`
1289
     * is greater than `tolerance` then two segments are joined with
1290
     * round-join, otherwise bevel-join is used.
1291
     *
1292
     * (See https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225
1293
     *  for an illustration.)
1294
     *
1295
     * `Arc height` is the distance from the center of arc's chord to
1296
     * the center of the arc. It is also the difference of arc's radius
1297
     * and the "distance from a point where segments are joined to the
1298
     * chord" (distance to the chord). Arc's radius is the half of a line
1299
     * width and the "distance to the chord" is equal to "half of a line width"
1300
     * times `cos(half the angle between segment vectors)`. So
1301
     *
1302
     *     arc_height = w/2 - w/2 * cos(phi/2),
1303
     *
1304
     * where `w/2` is the "half of a line width".
1305
     *
1306
     * Using the double angle cosine formula we can express the `cos(phi/2)`
1307
     * with just `cos(phi)` which is also the dot product of segments'
1308
     * unit vectors.
1309
     *
1310
     *     cos(phi/2) = sqrt ( (1 + cos(phi)) / 2 );
1311
     *     cos(phi/2) is in [0; 1] range, cannot be negative;
1312
     *
1313
     *     cos(phi) = a . b  = (ax * bx + ay * by),
1314
     *
1315
     * where `a` and `b` are unit vectors of the segments to be joined.
1316
     *
1317
     * Since `arc height` should be greater than the `tolerance` to produce
1318
     * a round-join we can write
1319
     *
1320
     *     w/2 * (1 - cos(phi/2))  >  tolerance;
1321
     *     1 - tolerance / (w/2)  >  cos(phi/2);    [!]
1322
     *
1323
     * which can be rewritten with the above double angle formula to
1324
     *
1325
     *     cos(phi)  <  2 * ( 1 - tolerance / (w/2) )^2 - 1,
1326
     *
1327
     * [!] Note that `w/2` is in [tolerance; +inf] range, since `cos(phi/2)`
1328
     * cannot be negative. The left part of the above inequality is the
1329
     * dot product and the right part is the `spline_cusp_tolerance`:
1330
     *
1331
     *     (ax * bx + ay * by) < spline_cusp_tolerance.
1332
     *
1333
     * In the code below only the `spline_cusp_tolerance` is calculated.
1334
     * The dot product is calculated later, in the condition expression
1335
     * itself. "Half of a line width" must be scaled with CTM for tolerance
1336
     * condition to be properly met. Also, since `arch height` cannot exceed
1337
     * the "half of a line width" and since `cos(phi/2)` cannot be negative,
1338
     * when `tolerance` is greater than the "half of a line width" the
1339
     * bevel-join should be produced.
1340
     */
1341
44.5k
    double scaled_hlw = hypot(stroker.half_line_width * ctm->xx,
1342
44.5k
            stroker.half_line_width * ctm->yx);
1343
1344
44.5k
    if (scaled_hlw <= tolerance) {
1345
2
  stroker.spline_cusp_tolerance = -1.0;
1346
44.5k
    } else {
1347
44.5k
  stroker.spline_cusp_tolerance = 1 - tolerance / scaled_hlw;
1348
44.5k
  stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
1349
44.5k
  stroker.spline_cusp_tolerance *= 2;
1350
44.5k
  stroker.spline_cusp_tolerance -= 1;
1351
44.5k
    }
1352
1353
44.5k
    stroker.ctm_det_positive =
1354
44.5k
  _cairo_matrix_compute_determinant (ctm) >= 0.0;
1355
1356
44.5k
    stroker.pen.num_vertices = 0;
1357
44.5k
    if (path->has_curve_to ||
1358
4.80k
  style->line_join == CAIRO_LINE_JOIN_ROUND ||
1359
39.7k
  style->line_cap == CAIRO_LINE_CAP_ROUND) {
1360
39.7k
  status = _cairo_pen_init (&stroker.pen,
1361
39.7k
          stroker.half_line_width,
1362
39.7k
          tolerance, ctm);
1363
39.7k
  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
39.7k
  if (stroker.pen.num_vertices <= 1)
1369
0
      return CAIRO_STATUS_SUCCESS;
1370
39.7k
    }
1371
1372
44.5k
    stroker.has_current_face = FALSE;
1373
44.5k
    stroker.has_first_face = FALSE;
1374
44.5k
    stroker.has_initial_sub_path = FALSE;
1375
1376
#if DEBUG
1377
    remove ("contours.txt");
1378
    remove ("polygons.txt");
1379
    _cairo_contour_init (&stroker.path, 0);
1380
#endif
1381
44.5k
    _cairo_contour_init (&stroker.cw.contour, 1);
1382
44.5k
    _cairo_contour_init (&stroker.ccw.contour, -1);
1383
44.5k
    tolerance *= CAIRO_FIXED_ONE;
1384
44.5k
    tolerance *= tolerance;
1385
44.5k
    stroker.contour_tolerance = tolerance;
1386
44.5k
    stroker.polygon = polygon;
1387
1388
44.5k
    status = _cairo_path_fixed_interpret (path,
1389
44.5k
            move_to,
1390
44.5k
            line_to,
1391
44.5k
            curve_to,
1392
44.5k
            close_path,
1393
44.5k
            &stroker);
1394
    /* Cap the start and end of the final sub path as needed */
1395
44.5k
    if (likely (status == CAIRO_STATUS_SUCCESS))
1396
44.5k
  add_caps (&stroker);
1397
1398
44.5k
    _cairo_contour_fini (&stroker.cw.contour);
1399
44.5k
    _cairo_contour_fini (&stroker.ccw.contour);
1400
44.5k
    if (stroker.pen.num_vertices)
1401
39.7k
  _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
44.5k
    return status;
1412
44.5k
}