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
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *	Carl D. Worth <cworth@cworth.org>
36
 *	Chris Wilson <chris@chris-wilson.co.uk>
37
 */
38

            
39
#define _DEFAULT_SOURCE /* for hypot() */
40
#include "cairoint.h"
41

            
42
#include "cairo-box-inline.h"
43
#include "cairo-boxes-private.h"
44
#include "cairo-error-private.h"
45
#include "cairo-path-fixed-private.h"
46
#include "cairo-slope-private.h"
47
#include "cairo-stroke-dash-private.h"
48
#include "cairo-traps-private.h"
49

            
50
typedef struct cairo_stroker {
51
    cairo_stroke_style_t style;
52

            
53
    const cairo_matrix_t *ctm;
54
    const cairo_matrix_t *ctm_inverse;
55
    double half_line_width;
56
    double tolerance;
57
    double spline_cusp_tolerance;
58
    double ctm_determinant;
59
    cairo_bool_t ctm_det_positive;
60

            
61
    void *closure;
62
    cairo_status_t (*add_external_edge) (void *closure,
63
					 const cairo_point_t *p1,
64
					 const cairo_point_t *p2);
65
    cairo_status_t (*add_triangle) (void *closure,
66
				    const cairo_point_t triangle[3]);
67
    cairo_status_t (*add_triangle_fan) (void *closure,
68
					const cairo_point_t *midpt,
69
					const cairo_point_t *points,
70
					int npoints);
71
    cairo_status_t (*add_convex_quad) (void *closure,
72
				       const cairo_point_t quad[4]);
73

            
74
    cairo_pen_t	  pen;
75

            
76
    cairo_point_t current_point;
77
    cairo_point_t first_point;
78

            
79
    cairo_bool_t has_initial_sub_path;
80

            
81
    cairo_bool_t has_current_face;
82
    cairo_stroke_face_t current_face;
83

            
84
    cairo_bool_t has_first_face;
85
    cairo_stroke_face_t first_face;
86

            
87
    cairo_stroker_dash_t dash;
88

            
89
    cairo_bool_t has_bounds;
90
    cairo_box_t bounds;
91
} cairo_stroker_t;
92

            
93
static void
94
339
_cairo_stroker_limit (cairo_stroker_t *stroker,
95
		      const cairo_path_fixed_t *path,
96
		      const cairo_box_t *boxes,
97
		      int num_boxes)
98
{
99
    double dx, dy;
100
    cairo_fixed_t fdx, fdy;
101

            
102
339
    stroker->has_bounds = TRUE;
103
339
    _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
104

            
105
    /* Extend the bounds in each direction to account for the maximum area
106
     * we might generate trapezoids, to capture line segments that are outside
107
     * of the bounds but which might generate rendering that's within bounds.
108
     */
109

            
110
339
    _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
111
						stroker->ctm, &dx, &dy);
112

            
113
339
    fdx = _cairo_fixed_from_double (dx);
114
339
    fdy = _cairo_fixed_from_double (dy);
115

            
116
339
    stroker->bounds.p1.x -= fdx;
117
339
    stroker->bounds.p2.x += fdx;
118

            
119
339
    stroker->bounds.p1.y -= fdy;
120
339
    stroker->bounds.p2.y += fdy;
121
339
}
122

            
123
static cairo_status_t
124
771
_cairo_stroker_init (cairo_stroker_t		*stroker,
125
		     const cairo_path_fixed_t	*path,
126
		     const cairo_stroke_style_t	*stroke_style,
127
		     const cairo_matrix_t	*ctm,
128
		     const cairo_matrix_t	*ctm_inverse,
129
		     double			 tolerance,
130
		     const cairo_box_t		*limits,
131
		     int			 num_limits)
132
{
133
    cairo_status_t status;
134

            
135
771
    stroker->style = *stroke_style;
136
771
    stroker->ctm = ctm;
137
771
    stroker->ctm_inverse = ctm_inverse;
138
771
    stroker->tolerance = tolerance;
139
771
    stroker->half_line_width = stroke_style->line_width / 2.0;
140

            
141
    /* To test whether we need to join two segments of a spline using
142
     * a round-join or a bevel-join, we can inspect the angle between the
143
     * two segments. If the difference between the chord distance
144
     * (half-line-width times the cosine of the bisection angle) and the
145
     * half-line-width itself is greater than tolerance then we need to
146
     * inject a point.
147
     */
148
771
    stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
149
771
    stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
150
771
    stroker->spline_cusp_tolerance *= 2;
151
771
    stroker->spline_cusp_tolerance -= 1;
152

            
153
771
    stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
154
771
    stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
155

            
156
771
    status = _cairo_pen_init (&stroker->pen,
157
			      stroker->half_line_width, tolerance, ctm);
158
771
    if (unlikely (status))
159
	return status;
160

            
161
771
    stroker->has_current_face = FALSE;
162
771
    stroker->has_first_face = FALSE;
163
771
    stroker->has_initial_sub_path = FALSE;
164

            
165
    /* Coverity complains these may be unitialized. */
166
771
    memset (&stroker->current_face, 0, sizeof (cairo_stroke_face_t));
167
771
    memset (&stroker->first_face, 0, sizeof (cairo_stroke_face_t));
168

            
169
771
    _cairo_stroker_dash_init (&stroker->dash, stroke_style);
170

            
171
771
    stroker->add_external_edge = NULL;
172

            
173
771
    stroker->has_bounds = FALSE;
174
771
    if (num_limits)
175
339
	_cairo_stroker_limit (stroker, path, limits, num_limits);
176

            
177
771
    return CAIRO_STATUS_SUCCESS;
178
}
179

            
180
static void
181
771
_cairo_stroker_fini (cairo_stroker_t *stroker)
182
{
183
771
    _cairo_pen_fini (&stroker->pen);
184
771
}
185

            
186
static void
187
48339
_translate_point (cairo_point_t *point, const cairo_point_t *offset)
188
{
189
48339
    point->x += offset->x;
190
48339
    point->y += offset->y;
191
48339
}
192

            
193
static int
194
2646
_cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
195
				  const cairo_stroke_face_t *out)
196
{
197
    cairo_slope_t in_slope, out_slope;
198

            
199
2646
    _cairo_slope_init (&in_slope, &in->point, &in->cw);
200
2646
    _cairo_slope_init (&out_slope, &out->point, &out->cw);
201

            
202
2646
    return _cairo_slope_compare (&in_slope, &out_slope) < 0;
203
}
204

            
205
/**
206
 * _cairo_slope_compare_sgn:
207
 *
208
 * Return -1, 0 or 1 depending on the relative slopes of
209
 * two lines.
210
 **/
211
static int
212
498
_cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
213
{
214
498
    double  c = (dx1 * dy2 - dx2 * dy1);
215

            
216
498
    if (c > 0) return 1;
217
252
    if (c < 0) return -1;
218
    return 0;
219
}
220

            
221
/*
222
 * Construct a fan around the midpoint using the vertices from pen between
223
 * inpt and outpt.
224
 */
225
static cairo_status_t
226
5127
_tessellate_fan (cairo_stroker_t *stroker,
227
		 const cairo_slope_t *in_vector,
228
		 const cairo_slope_t *out_vector,
229
		 const cairo_point_t *midpt,
230
		 const cairo_point_t *inpt,
231
		 const cairo_point_t *outpt,
232
		 cairo_bool_t clockwise)
233
{
234
5127
    cairo_point_t stack_points[64], *points = stack_points;
235
5127
    cairo_pen_t *pen = &stroker->pen;
236
5127
    int start, stop, num_points = 0;
237
    cairo_status_t status;
238

            
239
8433
    if (stroker->has_bounds &&
240
3306
	! _cairo_box_contains_point (&stroker->bounds, midpt))
241
132
	goto BEVEL;
242

            
243
4995
    assert (stroker->pen.num_vertices);
244

            
245
4995
    if (clockwise) {
246
1497
	_cairo_pen_find_active_ccw_vertices (pen,
247
					     in_vector, out_vector,
248
					     &start, &stop);
249
1497
	if (stroker->add_external_edge) {
250
	    cairo_point_t last;
251
1497
	    last = *inpt;
252
3288
	    while (start != stop) {
253
1791
		cairo_point_t p = *midpt;
254
1791
		_translate_point (&p, &pen->vertices[start].point);
255

            
256
1791
		status = stroker->add_external_edge (stroker->closure,
257
						     &last, &p);
258
1791
		if (unlikely (status))
259
		    return status;
260
1791
		last = p;
261

            
262
1791
		if (start-- == 0)
263
12
		    start += pen->num_vertices;
264
	    }
265
1497
	    status = stroker->add_external_edge (stroker->closure,
266
						 &last, outpt);
267
	} else {
268
	    if (start == stop)
269
		goto BEVEL;
270

            
271
	    num_points = stop - start;
272
	    if (num_points < 0)
273
		num_points += pen->num_vertices;
274
	    num_points += 2;
275
	    if (num_points > ARRAY_LENGTH(stack_points)) {
276
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
277
		if (unlikely (points == NULL))
278
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
279
	    }
280

            
281
	    points[0] = *inpt;
282
	    num_points = 1;
283
	    while (start != stop) {
284
		points[num_points] = *midpt;
285
		_translate_point (&points[num_points], &pen->vertices[start].point);
286
		num_points++;
287

            
288
		if (start-- == 0)
289
		    start += pen->num_vertices;
290
	    }
291
	    points[num_points++] = *outpt;
292
	}
293
    } else {
294
3498
	_cairo_pen_find_active_cw_vertices (pen,
295
					    in_vector, out_vector,
296
					    &start, &stop);
297
3498
	if (stroker->add_external_edge) {
298
	    cairo_point_t last;
299
3498
	    last = *inpt;
300
38448
	    while (start != stop) {
301
34950
		cairo_point_t p = *midpt;
302
34950
		_translate_point (&p, &pen->vertices[start].point);
303

            
304
34950
		status = stroker->add_external_edge (stroker->closure,
305
						     &p, &last);
306
34950
		if (unlikely (status))
307
		    return status;
308
34950
		last = p;
309

            
310
34950
		if (++start == pen->num_vertices)
311
1503
		    start = 0;
312
	    }
313
3498
	    status = stroker->add_external_edge (stroker->closure,
314
						 outpt, &last);
315
	} else {
316
	    if (start == stop)
317
		goto BEVEL;
318

            
319
	    num_points = stop - start;
320
	    if (num_points < 0)
321
		num_points += pen->num_vertices;
322
	    num_points += 2;
323
	    if (num_points > ARRAY_LENGTH(stack_points)) {
324
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
325
		if (unlikely (points == NULL))
326
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
327
	    }
328

            
329
	    points[0] = *inpt;
330
	    num_points = 1;
331
	    while (start != stop) {
332
		points[num_points] = *midpt;
333
		_translate_point (&points[num_points], &pen->vertices[start].point);
334
		num_points++;
335

            
336
		if (++start == pen->num_vertices)
337
		    start = 0;
338
	    }
339
	    points[num_points++] = *outpt;
340
	}
341
    }
342

            
343
4995
    if (num_points) {
344
	status = stroker->add_triangle_fan (stroker->closure,
345
					    midpt, points, num_points);
346
    }
347

            
348
4995
    if (points != stack_points)
349
	free (points);
350

            
351
4995
    return status;
352

            
353
132
BEVEL:
354
    /* Ensure a leak free connection... */
355
132
    if (stroker->add_external_edge != NULL) {
356
132
	if (clockwise)
357
	    return stroker->add_external_edge (stroker->closure, inpt, outpt);
358
	else
359
132
	    return stroker->add_external_edge (stroker->closure, outpt, inpt);
360
    } else {
361
	stack_points[0] = *midpt;
362
	stack_points[1] = *inpt;
363
	stack_points[2] = *outpt;
364
	return stroker->add_triangle (stroker->closure, stack_points);
365
    }
366
}
367

            
368
static cairo_status_t
369
2646
_cairo_stroker_join (cairo_stroker_t *stroker,
370
		     const cairo_stroke_face_t *in,
371
		     const cairo_stroke_face_t *out)
372
{
373
2646
    int	 clockwise = _cairo_stroker_join_is_clockwise (out, in);
374
    const cairo_point_t	*inpt, *outpt;
375
    cairo_point_t points[4];
376
    cairo_status_t status;
377

            
378
2646
    if (in->cw.x  == out->cw.x  && in->cw.y  == out->cw.y &&
379
78
	in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
380
    {
381
78
	return CAIRO_STATUS_SUCCESS;
382
    }
383

            
384
2568
    if (clockwise) {
385
1719
	if (stroker->add_external_edge != NULL) {
386
1719
	    status = stroker->add_external_edge (stroker->closure,
387
						 &out->cw, &in->point);
388
1719
	    if (unlikely (status))
389
		return status;
390

            
391
1719
	    status = stroker->add_external_edge (stroker->closure,
392
						 &in->point, &in->cw);
393
1719
	    if (unlikely (status))
394
		return status;
395
	}
396

            
397
1719
	inpt = &in->ccw;
398
1719
	outpt = &out->ccw;
399
    } else {
400
849
	if (stroker->add_external_edge != NULL) {
401
849
	    status = stroker->add_external_edge (stroker->closure,
402
						 &in->ccw, &in->point);
403
849
	    if (unlikely (status))
404
		return status;
405

            
406
849
	    status = stroker->add_external_edge (stroker->closure,
407
						 &in->point, &out->ccw);
408
849
	    if (unlikely (status))
409
		return status;
410
	}
411

            
412
849
	inpt = &in->cw;
413
849
	outpt = &out->cw;
414
    }
415

            
416
2568
    switch (stroker->style.line_join) {
417
2241
    case CAIRO_LINE_JOIN_ROUND:
418
	/* construct a fan around the common midpoint */
419
2241
	return _tessellate_fan (stroker,
420
				&in->dev_vector,
421
				&out->dev_vector,
422
				&in->point, inpt, outpt,
423
				clockwise);
424

            
425
249
    case CAIRO_LINE_JOIN_MITER:
426
    default: {
427
	/* dot product of incoming slope vector with outgoing slope vector */
428
249
	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
429
249
			     -in->usr_vector.y * out->usr_vector.y;
430
249
	double	ml = stroker->style.miter_limit;
431

            
432
	/* Check the miter limit -- lines meeting at an acute angle
433
	 * can generate long miters, the limit converts them to bevel
434
	 *
435
	 * Consider the miter join formed when two line segments
436
	 * meet at an angle psi:
437
	 *
438
	 *	   /.\
439
	 *	  /. .\
440
	 *	 /./ \.\
441
	 *	/./psi\.\
442
	 *
443
	 * We can zoom in on the right half of that to see:
444
	 *
445
	 *	    |\
446
	 *	    | \ psi/2
447
	 *	    |  \
448
	 *	    |   \
449
	 *	    |    \
450
	 *	    |     \
451
	 *	  miter    \
452
	 *	 length     \
453
	 *	    |        \
454
	 *	    |        .\
455
	 *	    |    .     \
456
	 *	    |.   line   \
457
	 *	     \    width  \
458
	 *	      \           \
459
	 *
460
	 *
461
	 * The right triangle in that figure, (the line-width side is
462
	 * shown faintly with three '.' characters), gives us the
463
	 * following expression relating miter length, angle and line
464
	 * width:
465
	 *
466
	 *	1 /sin (psi/2) = miter_length / line_width
467
	 *
468
	 * The right-hand side of this relationship is the same ratio
469
	 * in which the miter limit (ml) is expressed. We want to know
470
	 * when the miter length is within the miter limit. That is
471
	 * when the following condition holds:
472
	 *
473
	 *	1/sin(psi/2) <= ml
474
	 *	1 <= ml sin(psi/2)
475
	 *	1 <= ml² sin²(psi/2)
476
	 *	2 <= ml² 2 sin²(psi/2)
477
	 *				2·sin²(psi/2) = 1-cos(psi)
478
	 *	2 <= ml² (1-cos(psi))
479
	 *
480
	 *				in · out = |in| |out| cos (psi)
481
	 *
482
	 * in and out are both unit vectors, so:
483
	 *
484
	 *				in · out = cos (psi)
485
	 *
486
	 *	2 <= ml² (1 - in · out)
487
	 *
488
	 */
489
249
	if (2 <= ml * ml * (1 - in_dot_out)) {
490
	    double		x1, y1, x2, y2;
491
	    double		mx, my;
492
	    double		dx1, dx2, dy1, dy2;
493
	    double		ix, iy;
494
	    double		fdx1, fdy1, fdx2, fdy2;
495
	    double		mdx, mdy;
496

            
497
	    /*
498
	     * we've got the points already transformed to device
499
	     * space, but need to do some computation with them and
500
	     * also need to transform the slope from user space to
501
	     * device space
502
	     */
503
	    /* outer point of incoming line face */
504
249
	    x1 = _cairo_fixed_to_double (inpt->x);
505
249
	    y1 = _cairo_fixed_to_double (inpt->y);
506
249
	    dx1 = in->usr_vector.x;
507
249
	    dy1 = in->usr_vector.y;
508
249
	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
509

            
510
	    /* outer point of outgoing line face */
511
249
	    x2 = _cairo_fixed_to_double (outpt->x);
512
249
	    y2 = _cairo_fixed_to_double (outpt->y);
513
249
	    dx2 = out->usr_vector.x;
514
249
	    dy2 = out->usr_vector.y;
515
249
	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
516

            
517
	    /*
518
	     * Compute the location of the outer corner of the miter.
519
	     * That's pretty easy -- just the intersection of the two
520
	     * outer edges.  We've got slopes and points on each
521
	     * of those edges.  Compute my directly, then compute
522
	     * mx by using the edge with the larger dy; that avoids
523
	     * dividing by values close to zero.
524
	     */
525
249
	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
526
249
		  (dx1 * dy2 - dx2 * dy1));
527
249
	    if (fabs (dy1) >= fabs (dy2))
528
156
		mx = (my - y1) * dx1 / dy1 + x1;
529
	    else
530
93
		mx = (my - y2) * dx2 / dy2 + x2;
531

            
532
	    /*
533
	     * When the two outer edges are nearly parallel, slight
534
	     * perturbations in the position of the outer points of the lines
535
	     * caused by representing them in fixed point form can cause the
536
	     * intersection point of the miter to move a large amount. If
537
	     * that moves the miter intersection from between the two faces,
538
	     * then draw a bevel instead.
539
	     */
540

            
541
249
	    ix = _cairo_fixed_to_double (in->point.x);
542
249
	    iy = _cairo_fixed_to_double (in->point.y);
543

            
544
	    /* slope of one face */
545
249
	    fdx1 = x1 - ix; fdy1 = y1 - iy;
546

            
547
	    /* slope of the other face */
548
249
	    fdx2 = x2 - ix; fdy2 = y2 - iy;
549

            
550
	    /* slope from the intersection to the miter point */
551
249
	    mdx = mx - ix; mdy = my - iy;
552

            
553
	    /*
554
	     * Make sure the miter point line lies between the two
555
	     * faces by comparing the slopes
556
	     */
557
498
	    if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
558
249
		_cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
559
	    {
560
222
		if (stroker->add_external_edge != NULL) {
561
222
		    points[0].x = _cairo_fixed_from_double (mx);
562
222
		    points[0].y = _cairo_fixed_from_double (my);
563

            
564
222
		    if (clockwise) {
565
177
			status = stroker->add_external_edge (stroker->closure,
566
							     inpt, &points[0]);
567
177
			if (unlikely (status))
568
222
			    return status;
569

            
570
177
			status = stroker->add_external_edge (stroker->closure,
571
							     &points[0], outpt);
572
177
			if (unlikely (status))
573
			    return status;
574
		    } else {
575
45
			status = stroker->add_external_edge (stroker->closure,
576
							     outpt, &points[0]);
577
45
			if (unlikely (status))
578
			    return status;
579

            
580
45
			status = stroker->add_external_edge (stroker->closure,
581
							     &points[0], inpt);
582
45
			if (unlikely (status))
583
			    return status;
584
		    }
585

            
586
222
		    return CAIRO_STATUS_SUCCESS;
587
		} else {
588
		    points[0] = in->point;
589
		    points[1] = *inpt;
590
		    points[2].x = _cairo_fixed_from_double (mx);
591
		    points[2].y = _cairo_fixed_from_double (my);
592
		    points[3] = *outpt;
593

            
594
		    return stroker->add_convex_quad (stroker->closure, points);
595
		}
596
	    }
597
	}
598
    }
599

            
600
    /* fall through ... */
601

            
602
    case CAIRO_LINE_JOIN_BEVEL:
603
105
	if (stroker->add_external_edge != NULL) {
604
105
	    if (clockwise) {
605
45
		return stroker->add_external_edge (stroker->closure,
606
						   inpt, outpt);
607
	    } else {
608
60
		return stroker->add_external_edge (stroker->closure,
609
						   outpt, inpt);
610
	    }
611
	} else {
612
	    points[0] = in->point;
613
	    points[1] = *inpt;
614
	    points[2] = *outpt;
615

            
616
	    return stroker->add_triangle (stroker->closure, points);
617
	}
618
    }
619
}
620

            
621
static cairo_status_t
622
6306
_cairo_stroker_add_cap (cairo_stroker_t *stroker,
623
			const cairo_stroke_face_t *f)
624
{
625
6306
    switch (stroker->style.line_cap) {
626
2886
    case CAIRO_LINE_CAP_ROUND: {
627
	cairo_slope_t slope;
628

            
629
2886
	slope.dx = -f->dev_vector.dx;
630
2886
	slope.dy = -f->dev_vector.dy;
631

            
632
2886
	return _tessellate_fan (stroker,
633
				&f->dev_vector,
634
				&slope,
635
				&f->point, &f->cw, &f->ccw,
636
				FALSE);
637

            
638
    }
639

            
640
390
    case CAIRO_LINE_CAP_SQUARE: {
641
	double dx, dy;
642
	cairo_slope_t	fvector;
643
	cairo_point_t	quad[4];
644

            
645
390
	dx = f->usr_vector.x;
646
390
	dy = f->usr_vector.y;
647
390
	dx *= stroker->half_line_width;
648
390
	dy *= stroker->half_line_width;
649
390
	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
650
390
	fvector.dx = _cairo_fixed_from_double (dx);
651
390
	fvector.dy = _cairo_fixed_from_double (dy);
652

            
653
390
	quad[0] = f->ccw;
654
390
	quad[1].x = f->ccw.x + fvector.dx;
655
390
	quad[1].y = f->ccw.y + fvector.dy;
656
390
	quad[2].x = f->cw.x + fvector.dx;
657
390
	quad[2].y = f->cw.y + fvector.dy;
658
390
	quad[3] = f->cw;
659

            
660
390
	if (stroker->add_external_edge != NULL) {
661
	    cairo_status_t status;
662

            
663
390
	    status = stroker->add_external_edge (stroker->closure,
664
						 &quad[0], &quad[1]);
665
390
	    if (unlikely (status))
666
		return status;
667

            
668
390
	    status = stroker->add_external_edge (stroker->closure,
669
						 &quad[1], &quad[2]);
670
390
	    if (unlikely (status))
671
		return status;
672

            
673
390
	    status = stroker->add_external_edge (stroker->closure,
674
						 &quad[2], &quad[3]);
675
390
	    if (unlikely (status))
676
		return status;
677

            
678
390
	    return CAIRO_STATUS_SUCCESS;
679
	} else {
680
	    return stroker->add_convex_quad (stroker->closure, quad);
681
	}
682
    }
683

            
684
3030
    case CAIRO_LINE_CAP_BUTT:
685
    default:
686
3030
	if (stroker->add_external_edge != NULL) {
687
3030
	    return stroker->add_external_edge (stroker->closure,
688
					       &f->ccw, &f->cw);
689
	} else {
690
	    return CAIRO_STATUS_SUCCESS;
691
	}
692
    }
693
}
694

            
695
static cairo_status_t
696
3153
_cairo_stroker_add_leading_cap (cairo_stroker_t     *stroker,
697
				const cairo_stroke_face_t *face)
698
{
699
    cairo_stroke_face_t reversed;
700
    cairo_point_t t;
701

            
702
3153
    reversed = *face;
703

            
704
    /* The initial cap needs an outward facing vector. Reverse everything */
705
3153
    reversed.usr_vector.x = -reversed.usr_vector.x;
706
3153
    reversed.usr_vector.y = -reversed.usr_vector.y;
707
3153
    reversed.dev_vector.dx = -reversed.dev_vector.dx;
708
3153
    reversed.dev_vector.dy = -reversed.dev_vector.dy;
709
3153
    t = reversed.cw;
710
3153
    reversed.cw = reversed.ccw;
711
3153
    reversed.ccw = t;
712

            
713
3153
    return _cairo_stroker_add_cap (stroker, &reversed);
714
}
715

            
716
static cairo_status_t
717
3153
_cairo_stroker_add_trailing_cap (cairo_stroker_t     *stroker,
718
				 const cairo_stroke_face_t *face)
719
{
720
3153
    return _cairo_stroker_add_cap (stroker, face);
721
}
722

            
723
static inline cairo_bool_t
724
6009
_compute_normalized_device_slope (double *dx, double *dy,
725
				  const cairo_matrix_t *ctm_inverse,
726
				  double *mag_out)
727
{
728
6009
    double dx0 = *dx, dy0 = *dy;
729
    double mag;
730

            
731
6009
    cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
732

            
733
6009
    if (dx0 == 0.0 && dy0 == 0.0) {
734
	if (mag_out)
735
	    *mag_out = 0.0;
736
	return FALSE;
737
    }
738

            
739
6009
    if (dx0 == 0.0) {
740
600
	*dx = 0.0;
741
600
	if (dy0 > 0.0) {
742
561
	    mag = dy0;
743
561
	    *dy = 1.0;
744
	} else {
745
39
	    mag = -dy0;
746
39
	    *dy = -1.0;
747
	}
748
5409
    } else if (dy0 == 0.0) {
749
678
	*dy = 0.0;
750
678
	if (dx0 > 0.0) {
751
636
	    mag = dx0;
752
636
	    *dx = 1.0;
753
	} else {
754
42
	    mag = -dx0;
755
42
	    *dx = -1.0;
756
	}
757
    } else {
758
4731
	mag = hypot (dx0, dy0);
759
4731
	*dx = dx0 / mag;
760
4731
	*dy = dy0 / mag;
761
    }
762

            
763
6009
    if (mag_out)
764
5559
	*mag_out = mag;
765

            
766
6009
    return TRUE;
767
}
768

            
769
static void
770
5799
_compute_face (const cairo_point_t *point,
771
	       const cairo_slope_t *dev_slope,
772
	       double slope_dx,
773
	       double slope_dy,
774
	       cairo_stroker_t *stroker,
775
	       cairo_stroke_face_t *face)
776
{
777
    double face_dx, face_dy;
778
    cairo_point_t offset_ccw, offset_cw;
779

            
780
    /*
781
     * rotate to get a line_width/2 vector along the face, note that
782
     * the vector must be rotated the right direction in device space,
783
     * but by 90° in user space. So, the rotation depends on
784
     * whether the ctm reflects or not, and that can be determined
785
     * by looking at the determinant of the matrix.
786
     */
787
5799
    if (stroker->ctm_det_positive)
788
    {
789
5559
	face_dx = - slope_dy * stroker->half_line_width;
790
5559
	face_dy = slope_dx * stroker->half_line_width;
791
    }
792
    else
793
    {
794
240
	face_dx = slope_dy * stroker->half_line_width;
795
240
	face_dy = - slope_dx * stroker->half_line_width;
796
    }
797

            
798
    /* back to device space */
799
5799
    cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
800

            
801
5799
    offset_ccw.x = _cairo_fixed_from_double (face_dx);
802
5799
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
803
5799
    offset_cw.x = -offset_ccw.x;
804
5799
    offset_cw.y = -offset_ccw.y;
805

            
806
5799
    face->ccw = *point;
807
5799
    _translate_point (&face->ccw, &offset_ccw);
808

            
809
5799
    face->point = *point;
810

            
811
5799
    face->cw = *point;
812
5799
    _translate_point (&face->cw, &offset_cw);
813

            
814
5799
    face->usr_vector.x = slope_dx;
815
5799
    face->usr_vector.y = slope_dy;
816

            
817
5799
    face->dev_vector = *dev_slope;
818
5799
}
819

            
820
static cairo_status_t
821
1641
_cairo_stroker_add_caps (cairo_stroker_t *stroker)
822
{
823
    cairo_status_t status;
824

            
825
    /* check for a degenerative sub_path */
826
1641
    if (stroker->has_initial_sub_path
827
450
	&& ! stroker->has_first_face
828
18
	&& ! stroker->has_current_face
829
18
	&& stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
830
    {
831
	/* pick an arbitrary slope to use */
832
18
	double dx = 1.0, dy = 0.0;
833
18
	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
834
	cairo_stroke_face_t face;
835

            
836
18
	_compute_normalized_device_slope (&dx, &dy,
837
					  stroker->ctm_inverse, NULL);
838

            
839
	/* arbitrarily choose first_point
840
	 * first_point and current_point should be the same */
841
18
	_compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
842

            
843
18
	status = _cairo_stroker_add_leading_cap (stroker, &face);
844
18
	if (unlikely (status))
845
	    return status;
846

            
847
18
	status = _cairo_stroker_add_trailing_cap (stroker, &face);
848
18
	if (unlikely (status))
849
	    return status;
850
    }
851

            
852
1641
    if (stroker->has_first_face) {
853
432
	status = _cairo_stroker_add_leading_cap (stroker,
854
432
						 &stroker->first_face);
855
432
	if (unlikely (status))
856
	    return status;
857
    }
858

            
859
1641
    if (stroker->has_current_face) {
860
498
	status = _cairo_stroker_add_trailing_cap (stroker,
861
498
						  &stroker->current_face);
862
498
	if (unlikely (status))
863
	    return status;
864
    }
865

            
866
1641
    return CAIRO_STATUS_SUCCESS;
867
}
868

            
869
static cairo_status_t
870
4971
_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker,
871
			     const cairo_point_t *p1,
872
			     const cairo_point_t *p2,
873
			     cairo_slope_t *dev_slope,
874
			     double slope_dx, double slope_dy,
875
			     cairo_stroke_face_t *start,
876
			     cairo_stroke_face_t *end)
877
{
878
4971
    _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
879
4971
    *end = *start;
880

            
881
4971
    if (p1->x == p2->x && p1->y == p2->y)
882
12
	return CAIRO_STATUS_SUCCESS;
883

            
884
4959
    end->point = *p2;
885
4959
    end->ccw.x += p2->x - p1->x;
886
4959
    end->ccw.y += p2->y - p1->y;
887
4959
    end->cw.x += p2->x - p1->x;
888
4959
    end->cw.y += p2->y - p1->y;
889

            
890
4959
    if (stroker->add_external_edge != NULL) {
891
	cairo_status_t status;
892

            
893
4959
	status = stroker->add_external_edge (stroker->closure,
894
4959
					     &end->cw, &start->cw);
895
4959
	if (unlikely (status))
896
	    return status;
897

            
898
4959
	status = stroker->add_external_edge (stroker->closure,
899
4959
					     &start->ccw, &end->ccw);
900
4959
	if (unlikely (status))
901
	    return status;
902

            
903
4959
	return CAIRO_STATUS_SUCCESS;
904
    } else {
905
	cairo_point_t quad[4];
906

            
907
	quad[0] = start->cw;
908
	quad[1] = end->cw;
909
	quad[2] = end->ccw;
910
	quad[3] = start->ccw;
911

            
912
	return stroker->add_convex_quad (stroker->closure, quad);
913
    }
914
}
915

            
916
static cairo_status_t
917
855
_cairo_stroker_move_to (void *closure,
918
			const cairo_point_t *point)
919
{
920
855
    cairo_stroker_t *stroker = closure;
921
    cairo_status_t status;
922

            
923
    /* reset the dash pattern for new sub paths */
924
855
    _cairo_stroker_dash_start (&stroker->dash);
925

            
926
    /* Cap the start and end of the previous sub path as needed */
927
855
    status = _cairo_stroker_add_caps (stroker);
928
855
    if (unlikely (status))
929
	return status;
930

            
931
855
    stroker->first_point = *point;
932
855
    stroker->current_point = *point;
933

            
934
855
    stroker->has_first_face = FALSE;
935
855
    stroker->has_current_face = FALSE;
936
855
    stroker->has_initial_sub_path = FALSE;
937

            
938
855
    return CAIRO_STATUS_SUCCESS;
939
}
940

            
941
static cairo_status_t
942
_cairo_stroker_line_to (void *closure,
943
			const cairo_point_t *point)
944
{
945
    cairo_stroker_t *stroker = closure;
946
    cairo_stroke_face_t start, end;
947
    cairo_point_t *p1 = &stroker->current_point;
948
    cairo_slope_t dev_slope;
949
    double slope_dx, slope_dy;
950
    cairo_status_t status;
951

            
952
    stroker->has_initial_sub_path = TRUE;
953

            
954
    if (p1->x == point->x && p1->y == point->y)
955
	return CAIRO_STATUS_SUCCESS;
956

            
957
    _cairo_slope_init (&dev_slope, p1, point);
958
    slope_dx = _cairo_fixed_to_double (point->x - p1->x);
959
    slope_dy = _cairo_fixed_to_double (point->y - p1->y);
960
    _compute_normalized_device_slope (&slope_dx, &slope_dy,
961
				      stroker->ctm_inverse, NULL);
962

            
963
    status = _cairo_stroker_add_sub_edge (stroker,
964
					  p1, point,
965
					  &dev_slope,
966
					  slope_dx, slope_dy,
967
					  &start, &end);
968
    if (unlikely (status))
969
	return status;
970

            
971
    if (stroker->has_current_face) {
972
	/* Join with final face from previous segment */
973
	status = _cairo_stroker_join (stroker,
974
				      &stroker->current_face,
975
				      &start);
976
	if (unlikely (status))
977
	    return status;
978
    } else if (! stroker->has_first_face) {
979
	/* Save sub path's first face in case needed for closing join */
980
	stroker->first_face = start;
981
	stroker->has_first_face = TRUE;
982
    }
983
    stroker->current_face = end;
984
    stroker->has_current_face = TRUE;
985

            
986
    stroker->current_point = *point;
987

            
988
    return CAIRO_STATUS_SUCCESS;
989
}
990

            
991
static cairo_status_t
992
_cairo_stroker_add_point_line_to (void *closure,
993
				  const cairo_point_t *point,
994
				  const cairo_slope_t *tangent)
995
{
996
    return _cairo_stroker_line_to (closure, point);
997
};
998

            
999
static cairo_status_t
_cairo_stroker_spline_to (void *closure,
			  const cairo_point_t *point,
			  const cairo_slope_t *tangent)
{
    cairo_stroker_t *stroker = closure;
    cairo_stroke_face_t new_face;
    double slope_dx, slope_dy;
    cairo_point_t points[3];
    cairo_point_t intersect_point;
    stroker->has_initial_sub_path = TRUE;
    if (stroker->current_point.x == point->x &&
	stroker->current_point.y == point->y)
	return CAIRO_STATUS_SUCCESS;
    slope_dx = _cairo_fixed_to_double (tangent->dx);
    slope_dy = _cairo_fixed_to_double (tangent->dy);
    if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
					    stroker->ctm_inverse, NULL))
	return CAIRO_STATUS_SUCCESS;
    _compute_face (point, tangent,
		   slope_dx, slope_dy,
		   stroker, &new_face);
    assert (stroker->has_current_face);
    if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x +
         new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) {
	const cairo_point_t *inpt, *outpt;
	int clockwise = _cairo_stroker_join_is_clockwise (&new_face,
							  &stroker->current_face);
	if (clockwise) {
	    inpt = &stroker->current_face.cw;
	    outpt = &new_face.cw;
	} else {
	    inpt = &stroker->current_face.ccw;
	    outpt = &new_face.ccw;
	}
	_tessellate_fan (stroker,
			 &stroker->current_face.dev_vector,
			 &new_face.dev_vector,
			 &stroker->current_face.point,
			 inpt, outpt,
			 clockwise);
    }
    if (_slow_segment_intersection (&stroker->current_face.cw,
				    &stroker->current_face.ccw,
				    &new_face.cw,
				    &new_face.ccw,
				    &intersect_point)) {
	points[0] = stroker->current_face.ccw;
	points[1] = new_face.ccw;
	points[2] = intersect_point;
	stroker->add_triangle (stroker->closure, points);
	points[0] = stroker->current_face.cw;
	points[1] = new_face.cw;
	stroker->add_triangle (stroker->closure, points);
    } else {
	points[0] = stroker->current_face.ccw;
	points[1] = stroker->current_face.cw;
	points[2] = new_face.cw;
	stroker->add_triangle (stroker->closure, points);
	points[0] = stroker->current_face.ccw;
	points[1] = new_face.cw;
	points[2] = new_face.ccw;
	stroker->add_triangle (stroker->closure, points);
    }
    stroker->current_face = new_face;
    stroker->has_current_face = TRUE;
    stroker->current_point = *point;
    return CAIRO_STATUS_SUCCESS;
}
/*
 * Dashed lines.  Cap each dash end, join around turns when on
 */
static cairo_status_t
5595
_cairo_stroker_line_to_dashed (void *closure,
			       const cairo_point_t *p2)
{
5595
    cairo_stroker_t *stroker = closure;
5595
    double mag, remain, step_length = 0;
    double slope_dx, slope_dy;
    double dx2, dy2;
    cairo_stroke_face_t sub_start, sub_end;
5595
    cairo_point_t *p1 = &stroker->current_point;
    cairo_slope_t dev_slope;
    cairo_line_t segment;
    cairo_bool_t fully_in_bounds;
    cairo_status_t status;
5595
    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
5595
    if (p1->x == p2->x && p1->y == p2->y)
36
	return CAIRO_STATUS_SUCCESS;
5559
    fully_in_bounds = TRUE;
9888
    if (stroker->has_bounds &&
8400
	(! _cairo_box_contains_point (&stroker->bounds, p1) ||
4071
	 ! _cairo_box_contains_point (&stroker->bounds, p2)))
    {
261
	fully_in_bounds = FALSE;
    }
5559
    _cairo_slope_init (&dev_slope, p1, p2);
5559
    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
5559
    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
5559
    if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
					    stroker->ctm_inverse, &mag))
    {
	return CAIRO_STATUS_SUCCESS;
    }
5559
    remain = mag;
5559
    segment.p1 = *p1;
20379
    while (remain) {
14820
	step_length = MIN (stroker->dash.dash_remain, remain);
14820
	remain -= step_length;
14820
	dx2 = slope_dx * (mag - remain);
14820
	dy2 = slope_dy * (mag - remain);
14820
	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
14820
	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
14820
	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
14820
	if (stroker->dash.dash_on &&
2595
	    (fully_in_bounds ||
2595
	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
2577
	     _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
	{
4971
	    status = _cairo_stroker_add_sub_edge (stroker,
						  &segment.p1, &segment.p2,
						  &dev_slope,
						  slope_dx, slope_dy,
						  &sub_start, &sub_end);
4971
	    if (unlikely (status))
		return status;
4971
	    if (stroker->has_current_face)
	    {
		/* Join with final face from previous segment */
2304
		status = _cairo_stroker_join (stroker,
2304
					      &stroker->current_face,
					      &sub_start);
2304
		if (unlikely (status))
		    return status;
2304
		stroker->has_current_face = FALSE;
	    }
2667
	    else if (! stroker->has_first_face &&
618
		       stroker->dash.dash_starts_on)
	    {
		/* Save sub path's first face in case needed for closing join */
342
		stroker->first_face = sub_start;
342
		stroker->has_first_face = TRUE;
	    }
	    else
	    {
		/* Cap dash start if not connecting to a previous segment */
2325
		status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
2325
		if (unlikely (status))
		    return status;
	    }
4971
	    if (remain) {
		/* Cap dash end if not at end of segment */
2460
		status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
2460
		if (unlikely (status))
		    return status;
	    } else {
2511
		stroker->current_face = sub_end;
2511
		stroker->has_current_face = TRUE;
	    }
	} else {
9849
	    if (stroker->has_current_face) {
		/* Cap final face from previous segment */
177
		status = _cairo_stroker_add_trailing_cap (stroker,
177
							  &stroker->current_face);
177
		if (unlikely (status))
		    return status;
177
		stroker->has_current_face = FALSE;
	    }
	}
14820
	_cairo_stroker_dash_step (&stroker->dash, step_length);
14820
	segment.p1 = segment.p2;
    }
5559
    if (stroker->dash.dash_on && ! stroker->has_current_face) {
	/* This segment ends on a transition to dash_on, compute a new face
	 * and add cap for the beginning of the next dash_on step.
	 *
	 * Note: this will create a degenerate cap if this is not the last line
	 * in the path. Whether this behaviour is desirable or not is debatable.
	 * On one side these degenerate caps can not be reproduced with regular
	 * path stroking.
	 * On the other hand, Acroread 7 also produces the degenerate caps.
	 */
378
	_compute_face (p2, &dev_slope,
		       slope_dx, slope_dy,
		       stroker,
		       &stroker->current_face);
378
	status = _cairo_stroker_add_leading_cap (stroker,
378
						 &stroker->current_face);
378
	if (unlikely (status))
	    return status;
378
	stroker->has_current_face = TRUE;
    }
5559
    stroker->current_point = *p2;
5559
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
4380
_cairo_stroker_add_point_line_to_dashed (void *closure,
					 const cairo_point_t *point,
					 const cairo_slope_t *tangent)
{
4380
    return _cairo_stroker_line_to_dashed (closure, point);
};
static cairo_status_t
486
_cairo_stroker_curve_to (void *closure,
			 const cairo_point_t *b,
			 const cairo_point_t *c,
			 const cairo_point_t *d)
{
486
    cairo_stroker_t *stroker = closure;
    cairo_spline_t spline;
    cairo_line_join_t line_join_save;
    cairo_stroke_face_t face;
    double slope_dx, slope_dy;
    cairo_spline_add_point_func_t line_to;
    cairo_spline_add_point_func_t spline_to;
486
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
486
    line_to = stroker->dash.dashed ?
	_cairo_stroker_add_point_line_to_dashed :
	_cairo_stroker_add_point_line_to;
    /* spline_to is only capable of rendering non-degenerate splines. */
486
    spline_to = stroker->dash.dashed ?
	_cairo_stroker_add_point_line_to_dashed :
	_cairo_stroker_spline_to;
486
    if (! _cairo_spline_init (&spline,
			      spline_to,
			      stroker,
486
			      &stroker->current_point, b, c, d))
    {
	cairo_slope_t fallback_slope;
48
	_cairo_slope_init (&fallback_slope, &stroker->current_point, d);
48
	return line_to (closure, d, &fallback_slope);
    }
    /* If the line width is so small that the pen is reduced to a
       single point, then we have nothing to do. */
438
    if (stroker->pen.num_vertices <= 1)
	return CAIRO_STATUS_SUCCESS;
    /* Compute the initial face */
438
    if (! stroker->dash.dashed || stroker->dash.dash_on) {
228
	slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
228
	slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
228
	if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
					      stroker->ctm_inverse, NULL))
	{
228
	    _compute_face (&stroker->current_point,
			   &spline.initial_slope,
			   slope_dx, slope_dy,
			   stroker, &face);
	}
228
	if (stroker->has_current_face) {
69
	    status = _cairo_stroker_join (stroker,
69
					  &stroker->current_face, &face);
69
	    if (unlikely (status))
		return status;
159
	} else if (! stroker->has_first_face) {
159
	    stroker->first_face = face;
159
	    stroker->has_first_face = TRUE;
	}
228
	stroker->current_face = face;
228
	stroker->has_current_face = TRUE;
    }
    /* Temporarily modify the stroker to use round joins to guarantee
     * smooth stroked curves. */
438
    line_join_save = stroker->style.line_join;
438
    stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
438
    status = _cairo_spline_decompose (&spline, stroker->tolerance);
438
    if (unlikely (status))
	return status;
    /* And join the final face */
438
    if (! stroker->dash.dashed || stroker->dash.dash_on) {
204
	slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
204
	slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
204
	if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
					      stroker->ctm_inverse, NULL))
	{
204
	    _compute_face (&stroker->current_point,
			   &spline.final_slope,
			   slope_dx, slope_dy,
			   stroker, &face);
	}
204
	status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
204
	if (unlikely (status))
	    return status;
204
	stroker->current_face = face;
    }
438
    stroker->style.line_join = line_join_save;
438
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
84
_cairo_stroker_close_path (void *closure)
{
84
    cairo_stroker_t *stroker = closure;
    cairo_status_t status;
84
    if (stroker->dash.dashed)
84
	status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
    else
	status = _cairo_stroker_line_to (stroker, &stroker->first_point);
84
    if (unlikely (status))
	return status;
84
    if (stroker->has_first_face && stroker->has_current_face) {
	/* Join first and final faces of sub path */
69
	status = _cairo_stroker_join (stroker,
69
				      &stroker->current_face,
69
				      &stroker->first_face);
69
	if (unlikely (status))
	    return status;
    } else {
	/* Cap the start and end of the sub path as needed */
15
	status = _cairo_stroker_add_caps (stroker);
15
	if (unlikely (status))
	    return status;
    }
84
    stroker->has_initial_sub_path = FALSE;
84
    stroker->has_first_face = FALSE;
84
    stroker->has_current_face = FALSE;
84
    return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t	*path,
				    const cairo_stroke_style_t	*stroke_style,
				    const cairo_matrix_t	*ctm,
				    const cairo_matrix_t	*ctm_inverse,
				    double		 tolerance,
				    cairo_status_t (*add_triangle) (void *closure,
								    const cairo_point_t triangle[3]),
				    cairo_status_t (*add_triangle_fan) (void *closure,
									const cairo_point_t *midpt,
									const cairo_point_t *points,
									int npoints),
				    cairo_status_t (*add_convex_quad) (void *closure,
								       const cairo_point_t quad[4]),
				    void *closure)
{
    cairo_stroker_t stroker;
    cairo_status_t status;
    status = _cairo_stroker_init (&stroker, path, stroke_style,
			          ctm, ctm_inverse, tolerance,
				  NULL, 0);
    if (unlikely (status))
	return status;
    stroker.add_triangle = add_triangle;
    stroker.add_triangle_fan = add_triangle_fan;
    stroker.add_convex_quad = add_convex_quad;
    stroker.closure = closure;
    status = _cairo_path_fixed_interpret (path,
					  _cairo_stroker_move_to,
					  stroker.dash.dashed ?
					  _cairo_stroker_line_to_dashed :
					  _cairo_stroker_line_to,
					  _cairo_stroker_curve_to,
					  _cairo_stroker_close_path,
					  &stroker);
    if (unlikely (status))
	goto BAIL;
    /* Cap the start and end of the final sub path as needed */
    status = _cairo_stroker_add_caps (&stroker);
BAIL:
    _cairo_stroker_fini (&stroker);
    return status;
}
cairo_status_t
771
_cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t	*path,
					    const cairo_stroke_style_t	*stroke_style,
					    const cairo_matrix_t	*ctm,
					    const cairo_matrix_t	*ctm_inverse,
					    double		 tolerance,
					    cairo_polygon_t *polygon)
{
    cairo_stroker_t stroker;
    cairo_status_t status;
771
    status = _cairo_stroker_init (&stroker, path, stroke_style,
			          ctm, ctm_inverse, tolerance,
				  polygon->limits, polygon->num_limits);
771
    if (unlikely (status))
	return status;
771
    stroker.add_external_edge = _cairo_polygon_add_external_edge,
771
    stroker.closure = polygon;
771
    status = _cairo_path_fixed_interpret (path,
					  _cairo_stroker_move_to,
771
					  stroker.dash.dashed ?
					  _cairo_stroker_line_to_dashed :
					  _cairo_stroker_line_to,
					  _cairo_stroker_curve_to,
					  _cairo_stroker_close_path,
					  &stroker);
771
    if (unlikely (status))
	goto BAIL;
    /* Cap the start and end of the final sub path as needed */
771
    status = _cairo_stroker_add_caps (&stroker);
771
BAIL:
771
    _cairo_stroker_fini (&stroker);
771
    return status;
}
cairo_int_status_t
216
_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t	*path,
                                           const cairo_stroke_style_t	*stroke_style,
                                           const cairo_matrix_t	*ctm,
                                           const cairo_matrix_t	*ctm_inverse,
                                           double		 tolerance,
                                           cairo_traps_t	*traps)
{
    cairo_int_status_t status;
    cairo_polygon_t polygon;
216
    _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
216
    status = _cairo_path_fixed_stroke_to_polygon (path,
						  stroke_style,
						  ctm,
						  ctm_inverse,
						  tolerance,
						  &polygon);
216
    if (unlikely (status))
	goto BAIL;
216
    status = _cairo_polygon_status (&polygon);
216
    if (unlikely (status))
	goto BAIL;
216
    status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
							CAIRO_FILL_RULE_WINDING);
216
BAIL:
216
    _cairo_polygon_fini (&polygon);
216
    return status;
}