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
_cairo_stroker_limit(cairo_stroker_t * stroker,const cairo_path_fixed_t * path,const cairo_box_t * boxes,int num_boxes)94 _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     stroker->has_bounds = TRUE;
103     _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     _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
111 						stroker->ctm, &dx, &dy);
112 
113     fdx = _cairo_fixed_from_double (dx);
114     fdy = _cairo_fixed_from_double (dy);
115 
116     stroker->bounds.p1.x -= fdx;
117     stroker->bounds.p2.x += fdx;
118 
119     stroker->bounds.p1.y -= fdy;
120     stroker->bounds.p2.y += fdy;
121 }
122 
123 static cairo_status_t
_cairo_stroker_init(cairo_stroker_t * stroker,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,const cairo_box_t * limits,int num_limits)124 _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     stroker->style = *stroke_style;
136     stroker->ctm = ctm;
137     stroker->ctm_inverse = ctm_inverse;
138     stroker->tolerance = tolerance;
139     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     stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
149     stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
150     stroker->spline_cusp_tolerance *= 2;
151     stroker->spline_cusp_tolerance -= 1;
152 
153     stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
154     stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
155 
156     status = _cairo_pen_init (&stroker->pen,
157 			      stroker->half_line_width, tolerance, ctm);
158     if (unlikely (status))
159 	return status;
160 
161     stroker->has_current_face = FALSE;
162     stroker->has_first_face = FALSE;
163     stroker->has_initial_sub_path = FALSE;
164 
165     _cairo_stroker_dash_init (&stroker->dash, stroke_style);
166 
167     stroker->add_external_edge = NULL;
168 
169     stroker->has_bounds = FALSE;
170     if (num_limits)
171 	_cairo_stroker_limit (stroker, path, limits, num_limits);
172 
173     return CAIRO_STATUS_SUCCESS;
174 }
175 
176 static void
_cairo_stroker_fini(cairo_stroker_t * stroker)177 _cairo_stroker_fini (cairo_stroker_t *stroker)
178 {
179     _cairo_pen_fini (&stroker->pen);
180 }
181 
182 static void
_translate_point(cairo_point_t * point,const cairo_point_t * offset)183 _translate_point (cairo_point_t *point, const cairo_point_t *offset)
184 {
185     point->x += offset->x;
186     point->y += offset->y;
187 }
188 
189 static int
_cairo_stroker_join_is_clockwise(const cairo_stroke_face_t * in,const cairo_stroke_face_t * out)190 _cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in,
191 				  const cairo_stroke_face_t *out)
192 {
193     cairo_slope_t in_slope, out_slope;
194 
195     _cairo_slope_init (&in_slope, &in->point, &in->cw);
196     _cairo_slope_init (&out_slope, &out->point, &out->cw);
197 
198     return _cairo_slope_compare (&in_slope, &out_slope) < 0;
199 }
200 
201 /**
202  * _cairo_slope_compare_sgn:
203  *
204  * Return -1, 0 or 1 depending on the relative slopes of
205  * two lines.
206  **/
207 static int
_cairo_slope_compare_sgn(double dx1,double dy1,double dx2,double dy2)208 _cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
209 {
210     double  c = (dx1 * dy2 - dx2 * dy1);
211 
212     if (c > 0) return 1;
213     if (c < 0) return -1;
214     return 0;
215 }
216 
217 static inline int
_range_step(int i,int step,int max)218 _range_step (int i, int step, int max)
219 {
220     i += step;
221     if (i < 0)
222 	i = max - 1;
223     if (i >= max)
224 	i = 0;
225     return i;
226 }
227 
228 /*
229  * Construct a fan around the midpoint using the vertices from pen between
230  * inpt and outpt.
231  */
232 static cairo_status_t
_tessellate_fan(cairo_stroker_t * stroker,const cairo_slope_t * in_vector,const cairo_slope_t * out_vector,const cairo_point_t * midpt,const cairo_point_t * inpt,const cairo_point_t * outpt,cairo_bool_t clockwise)233 _tessellate_fan (cairo_stroker_t *stroker,
234 		 const cairo_slope_t *in_vector,
235 		 const cairo_slope_t *out_vector,
236 		 const cairo_point_t *midpt,
237 		 const cairo_point_t *inpt,
238 		 const cairo_point_t *outpt,
239 		 cairo_bool_t clockwise)
240 {
241     cairo_point_t stack_points[64], *points = stack_points;
242     cairo_pen_t *pen = &stroker->pen;
243     int start, stop, num_points = 0;
244     cairo_status_t status;
245 
246     if (stroker->has_bounds &&
247 	! _cairo_box_contains_point (&stroker->bounds, midpt))
248 	goto BEVEL;
249 
250     assert (stroker->pen.num_vertices);
251 
252     if (clockwise) {
253 	_cairo_pen_find_active_ccw_vertices (pen,
254 					     in_vector, out_vector,
255 					     &start, &stop);
256 	if (stroker->add_external_edge) {
257 	    cairo_point_t last;
258 	    last = *inpt;
259 	    while (start != stop) {
260 		cairo_point_t p = *midpt;
261 		_translate_point (&p, &pen->vertices[start].point);
262 
263 		status = stroker->add_external_edge (stroker->closure,
264 						     &last, &p);
265 		if (unlikely (status))
266 		    return status;
267 		last = p;
268 
269 		if (start-- == 0)
270 		    start += pen->num_vertices;
271 	    }
272 	    status = stroker->add_external_edge (stroker->closure,
273 						 &last, outpt);
274 	} else {
275 	    if (start == stop)
276 		goto BEVEL;
277 
278 	    num_points = stop - start;
279 	    if (num_points < 0)
280 		num_points += pen->num_vertices;
281 	    num_points += 2;
282 	    if (num_points > ARRAY_LENGTH(stack_points)) {
283 		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
284 		if (unlikely (points == NULL))
285 		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
286 	    }
287 
288 	    points[0] = *inpt;
289 	    num_points = 1;
290 	    while (start != stop) {
291 		points[num_points] = *midpt;
292 		_translate_point (&points[num_points], &pen->vertices[start].point);
293 		num_points++;
294 
295 		if (start-- == 0)
296 		    start += pen->num_vertices;
297 	    }
298 	    points[num_points++] = *outpt;
299 	}
300     } else {
301 	_cairo_pen_find_active_cw_vertices (pen,
302 					    in_vector, out_vector,
303 					    &start, &stop);
304 	if (stroker->add_external_edge) {
305 	    cairo_point_t last;
306 	    last = *inpt;
307 	    while (start != stop) {
308 		cairo_point_t p = *midpt;
309 		_translate_point (&p, &pen->vertices[start].point);
310 
311 		status = stroker->add_external_edge (stroker->closure,
312 						     &p, &last);
313 		if (unlikely (status))
314 		    return status;
315 		last = p;
316 
317 		if (++start == pen->num_vertices)
318 		    start = 0;
319 	    }
320 	    status = stroker->add_external_edge (stroker->closure,
321 						 outpt, &last);
322 	} else {
323 	    if (start == stop)
324 		goto BEVEL;
325 
326 	    num_points = stop - start;
327 	    if (num_points < 0)
328 		num_points += pen->num_vertices;
329 	    num_points += 2;
330 	    if (num_points > ARRAY_LENGTH(stack_points)) {
331 		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
332 		if (unlikely (points == NULL))
333 		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
334 	    }
335 
336 	    points[0] = *inpt;
337 	    num_points = 1;
338 	    while (start != stop) {
339 		points[num_points] = *midpt;
340 		_translate_point (&points[num_points], &pen->vertices[start].point);
341 		num_points++;
342 
343 		if (++start == pen->num_vertices)
344 		    start = 0;
345 	    }
346 	    points[num_points++] = *outpt;
347 	}
348     }
349 
350     if (num_points) {
351 	status = stroker->add_triangle_fan (stroker->closure,
352 					    midpt, points, num_points);
353     }
354 
355     if (points != stack_points)
356 	free (points);
357 
358     return status;
359 
360 BEVEL:
361     /* Ensure a leak free connection... */
362     if (stroker->add_external_edge != NULL) {
363 	if (clockwise)
364 	    return stroker->add_external_edge (stroker->closure, inpt, outpt);
365 	else
366 	    return stroker->add_external_edge (stroker->closure, outpt, inpt);
367     } else {
368 	stack_points[0] = *midpt;
369 	stack_points[1] = *inpt;
370 	stack_points[2] = *outpt;
371 	return stroker->add_triangle (stroker->closure, stack_points);
372     }
373 }
374 
375 static cairo_status_t
_cairo_stroker_join(cairo_stroker_t * stroker,const cairo_stroke_face_t * in,const cairo_stroke_face_t * out)376 _cairo_stroker_join (cairo_stroker_t *stroker,
377 		     const cairo_stroke_face_t *in,
378 		     const cairo_stroke_face_t *out)
379 {
380     int	 clockwise = _cairo_stroker_join_is_clockwise (out, in);
381     const cairo_point_t	*inpt, *outpt;
382     cairo_point_t points[4];
383     cairo_status_t status;
384 
385     if (in->cw.x  == out->cw.x  && in->cw.y  == out->cw.y &&
386 	in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y)
387     {
388 	return CAIRO_STATUS_SUCCESS;
389     }
390 
391     if (clockwise) {
392 	if (stroker->add_external_edge != NULL) {
393 	    status = stroker->add_external_edge (stroker->closure,
394 						 &out->cw, &in->point);
395 	    if (unlikely (status))
396 		return status;
397 
398 	    status = stroker->add_external_edge (stroker->closure,
399 						 &in->point, &in->cw);
400 	    if (unlikely (status))
401 		return status;
402 	}
403 
404 	inpt = &in->ccw;
405 	outpt = &out->ccw;
406     } else {
407 	if (stroker->add_external_edge != NULL) {
408 	    status = stroker->add_external_edge (stroker->closure,
409 						 &in->ccw, &in->point);
410 	    if (unlikely (status))
411 		return status;
412 
413 	    status = stroker->add_external_edge (stroker->closure,
414 						 &in->point, &out->ccw);
415 	    if (unlikely (status))
416 		return status;
417 	}
418 
419 	inpt = &in->cw;
420 	outpt = &out->cw;
421     }
422 
423     switch (stroker->style.line_join) {
424     case CAIRO_LINE_JOIN_ROUND:
425 	/* construct a fan around the common midpoint */
426 	return _tessellate_fan (stroker,
427 				&in->dev_vector,
428 				&out->dev_vector,
429 				&in->point, inpt, outpt,
430 				clockwise);
431 
432     case CAIRO_LINE_JOIN_MITER:
433     default: {
434 	/* dot product of incoming slope vector with outgoing slope vector */
435 	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
436 			     -in->usr_vector.y * out->usr_vector.y;
437 	double	ml = stroker->style.miter_limit;
438 
439 	/* Check the miter limit -- lines meeting at an acute angle
440 	 * can generate long miters, the limit converts them to bevel
441 	 *
442 	 * Consider the miter join formed when two line segments
443 	 * meet at an angle psi:
444 	 *
445 	 *	   /.\
446 	 *	  /. .\
447 	 *	 /./ \.\
448 	 *	/./psi\.\
449 	 *
450 	 * We can zoom in on the right half of that to see:
451 	 *
452 	 *	    |\
453 	 *	    | \ psi/2
454 	 *	    |  \
455 	 *	    |   \
456 	 *	    |    \
457 	 *	    |     \
458 	 *	  miter    \
459 	 *	 length     \
460 	 *	    |        \
461 	 *	    |        .\
462 	 *	    |    .     \
463 	 *	    |.   line   \
464 	 *	     \    width  \
465 	 *	      \           \
466 	 *
467 	 *
468 	 * The right triangle in that figure, (the line-width side is
469 	 * shown faintly with three '.' characters), gives us the
470 	 * following expression relating miter length, angle and line
471 	 * width:
472 	 *
473 	 *	1 /sin (psi/2) = miter_length / line_width
474 	 *
475 	 * The right-hand side of this relationship is the same ratio
476 	 * in which the miter limit (ml) is expressed. We want to know
477 	 * when the miter length is within the miter limit. That is
478 	 * when the following condition holds:
479 	 *
480 	 *	1/sin(psi/2) <= ml
481 	 *	1 <= ml sin(psi/2)
482 	 *	1 <= ml² sin²(psi/2)
483 	 *	2 <= ml² 2 sin²(psi/2)
484 	 *				2·sin²(psi/2) = 1-cos(psi)
485 	 *	2 <= ml² (1-cos(psi))
486 	 *
487 	 *				in · out = |in| |out| cos (psi)
488 	 *
489 	 * in and out are both unit vectors, so:
490 	 *
491 	 *				in · out = cos (psi)
492 	 *
493 	 *	2 <= ml² (1 - in · out)
494 	 *
495 	 */
496 	if (2 <= ml * ml * (1 - in_dot_out)) {
497 	    double		x1, y1, x2, y2;
498 	    double		mx, my;
499 	    double		dx1, dx2, dy1, dy2;
500 	    double		ix, iy;
501 	    double		fdx1, fdy1, fdx2, fdy2;
502 	    double		mdx, mdy;
503 
504 	    /*
505 	     * we've got the points already transformed to device
506 	     * space, but need to do some computation with them and
507 	     * also need to transform the slope from user space to
508 	     * device space
509 	     */
510 	    /* outer point of incoming line face */
511 	    x1 = _cairo_fixed_to_double (inpt->x);
512 	    y1 = _cairo_fixed_to_double (inpt->y);
513 	    dx1 = in->usr_vector.x;
514 	    dy1 = in->usr_vector.y;
515 	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
516 
517 	    /* outer point of outgoing line face */
518 	    x2 = _cairo_fixed_to_double (outpt->x);
519 	    y2 = _cairo_fixed_to_double (outpt->y);
520 	    dx2 = out->usr_vector.x;
521 	    dy2 = out->usr_vector.y;
522 	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
523 
524 	    /*
525 	     * Compute the location of the outer corner of the miter.
526 	     * That's pretty easy -- just the intersection of the two
527 	     * outer edges.  We've got slopes and points on each
528 	     * of those edges.  Compute my directly, then compute
529 	     * mx by using the edge with the larger dy; that avoids
530 	     * dividing by values close to zero.
531 	     */
532 	    my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
533 		  (dx1 * dy2 - dx2 * dy1));
534 	    if (fabs (dy1) >= fabs (dy2))
535 		mx = (my - y1) * dx1 / dy1 + x1;
536 	    else
537 		mx = (my - y2) * dx2 / dy2 + x2;
538 
539 	    /*
540 	     * When the two outer edges are nearly parallel, slight
541 	     * perturbations in the position of the outer points of the lines
542 	     * caused by representing them in fixed point form can cause the
543 	     * intersection point of the miter to move a large amount. If
544 	     * that moves the miter intersection from between the two faces,
545 	     * then draw a bevel instead.
546 	     */
547 
548 	    ix = _cairo_fixed_to_double (in->point.x);
549 	    iy = _cairo_fixed_to_double (in->point.y);
550 
551 	    /* slope of one face */
552 	    fdx1 = x1 - ix; fdy1 = y1 - iy;
553 
554 	    /* slope of the other face */
555 	    fdx2 = x2 - ix; fdy2 = y2 - iy;
556 
557 	    /* slope from the intersection to the miter point */
558 	    mdx = mx - ix; mdy = my - iy;
559 
560 	    /*
561 	     * Make sure the miter point line lies between the two
562 	     * faces by comparing the slopes
563 	     */
564 	    if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
565 		_cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy))
566 	    {
567 		if (stroker->add_external_edge != NULL) {
568 		    points[0].x = _cairo_fixed_from_double (mx);
569 		    points[0].y = _cairo_fixed_from_double (my);
570 
571 		    if (clockwise) {
572 			status = stroker->add_external_edge (stroker->closure,
573 							     inpt, &points[0]);
574 			if (unlikely (status))
575 			    return status;
576 
577 			status = stroker->add_external_edge (stroker->closure,
578 							     &points[0], outpt);
579 			if (unlikely (status))
580 			    return status;
581 		    } else {
582 			status = stroker->add_external_edge (stroker->closure,
583 							     outpt, &points[0]);
584 			if (unlikely (status))
585 			    return status;
586 
587 			status = stroker->add_external_edge (stroker->closure,
588 							     &points[0], inpt);
589 			if (unlikely (status))
590 			    return status;
591 		    }
592 
593 		    return CAIRO_STATUS_SUCCESS;
594 		} else {
595 		    points[0] = in->point;
596 		    points[1] = *inpt;
597 		    points[2].x = _cairo_fixed_from_double (mx);
598 		    points[2].y = _cairo_fixed_from_double (my);
599 		    points[3] = *outpt;
600 
601 		    return stroker->add_convex_quad (stroker->closure, points);
602 		}
603 	    }
604 	}
605     }
606 
607     /* fall through ... */
608 
609     case CAIRO_LINE_JOIN_BEVEL:
610 	if (stroker->add_external_edge != NULL) {
611 	    if (clockwise) {
612 		return stroker->add_external_edge (stroker->closure,
613 						   inpt, outpt);
614 	    } else {
615 		return stroker->add_external_edge (stroker->closure,
616 						   outpt, inpt);
617 	    }
618 	} else {
619 	    points[0] = in->point;
620 	    points[1] = *inpt;
621 	    points[2] = *outpt;
622 
623 	    return stroker->add_triangle (stroker->closure, points);
624 	}
625     }
626 }
627 
628 static cairo_status_t
_cairo_stroker_add_cap(cairo_stroker_t * stroker,const cairo_stroke_face_t * f)629 _cairo_stroker_add_cap (cairo_stroker_t *stroker,
630 			const cairo_stroke_face_t *f)
631 {
632     switch (stroker->style.line_cap) {
633     case CAIRO_LINE_CAP_ROUND: {
634 	cairo_slope_t slope;
635 
636 	slope.dx = -f->dev_vector.dx;
637 	slope.dy = -f->dev_vector.dy;
638 
639 	return _tessellate_fan (stroker,
640 				&f->dev_vector,
641 				&slope,
642 				&f->point, &f->cw, &f->ccw,
643 				FALSE);
644 
645     }
646 
647     case CAIRO_LINE_CAP_SQUARE: {
648 	double dx, dy;
649 	cairo_slope_t	fvector;
650 	cairo_point_t	quad[4];
651 
652 	dx = f->usr_vector.x;
653 	dy = f->usr_vector.y;
654 	dx *= stroker->half_line_width;
655 	dy *= stroker->half_line_width;
656 	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
657 	fvector.dx = _cairo_fixed_from_double (dx);
658 	fvector.dy = _cairo_fixed_from_double (dy);
659 
660 	quad[0] = f->ccw;
661 	quad[1].x = f->ccw.x + fvector.dx;
662 	quad[1].y = f->ccw.y + fvector.dy;
663 	quad[2].x = f->cw.x + fvector.dx;
664 	quad[2].y = f->cw.y + fvector.dy;
665 	quad[3] = f->cw;
666 
667 	if (stroker->add_external_edge != NULL) {
668 	    cairo_status_t status;
669 
670 	    status = stroker->add_external_edge (stroker->closure,
671 						 &quad[0], &quad[1]);
672 	    if (unlikely (status))
673 		return status;
674 
675 	    status = stroker->add_external_edge (stroker->closure,
676 						 &quad[1], &quad[2]);
677 	    if (unlikely (status))
678 		return status;
679 
680 	    status = stroker->add_external_edge (stroker->closure,
681 						 &quad[2], &quad[3]);
682 	    if (unlikely (status))
683 		return status;
684 
685 	    return CAIRO_STATUS_SUCCESS;
686 	} else {
687 	    return stroker->add_convex_quad (stroker->closure, quad);
688 	}
689     }
690 
691     case CAIRO_LINE_CAP_BUTT:
692     default:
693 	if (stroker->add_external_edge != NULL) {
694 	    return stroker->add_external_edge (stroker->closure,
695 					       &f->ccw, &f->cw);
696 	} else {
697 	    return CAIRO_STATUS_SUCCESS;
698 	}
699     }
700 }
701 
702 static cairo_status_t
_cairo_stroker_add_leading_cap(cairo_stroker_t * stroker,const cairo_stroke_face_t * face)703 _cairo_stroker_add_leading_cap (cairo_stroker_t     *stroker,
704 				const cairo_stroke_face_t *face)
705 {
706     cairo_stroke_face_t reversed;
707     cairo_point_t t;
708 
709     reversed = *face;
710 
711     /* The initial cap needs an outward facing vector. Reverse everything */
712     reversed.usr_vector.x = -reversed.usr_vector.x;
713     reversed.usr_vector.y = -reversed.usr_vector.y;
714     reversed.dev_vector.dx = -reversed.dev_vector.dx;
715     reversed.dev_vector.dy = -reversed.dev_vector.dy;
716     t = reversed.cw;
717     reversed.cw = reversed.ccw;
718     reversed.ccw = t;
719 
720     return _cairo_stroker_add_cap (stroker, &reversed);
721 }
722 
723 static cairo_status_t
_cairo_stroker_add_trailing_cap(cairo_stroker_t * stroker,const cairo_stroke_face_t * face)724 _cairo_stroker_add_trailing_cap (cairo_stroker_t     *stroker,
725 				 const cairo_stroke_face_t *face)
726 {
727     return _cairo_stroker_add_cap (stroker, face);
728 }
729 
730 static inline cairo_bool_t
_compute_normalized_device_slope(double * dx,double * dy,const cairo_matrix_t * ctm_inverse,double * mag_out)731 _compute_normalized_device_slope (double *dx, double *dy,
732 				  const cairo_matrix_t *ctm_inverse,
733 				  double *mag_out)
734 {
735     double dx0 = *dx, dy0 = *dy;
736     double mag;
737 
738     cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0);
739 
740     if (dx0 == 0.0 && dy0 == 0.0) {
741 	if (mag_out)
742 	    *mag_out = 0.0;
743 	return FALSE;
744     }
745 
746     if (dx0 == 0.0) {
747 	*dx = 0.0;
748 	if (dy0 > 0.0) {
749 	    mag = dy0;
750 	    *dy = 1.0;
751 	} else {
752 	    mag = -dy0;
753 	    *dy = -1.0;
754 	}
755     } else if (dy0 == 0.0) {
756 	*dy = 0.0;
757 	if (dx0 > 0.0) {
758 	    mag = dx0;
759 	    *dx = 1.0;
760 	} else {
761 	    mag = -dx0;
762 	    *dx = -1.0;
763 	}
764     } else {
765 	mag = hypot (dx0, dy0);
766 	*dx = dx0 / mag;
767 	*dy = dy0 / mag;
768     }
769 
770     if (mag_out)
771 	*mag_out = mag;
772 
773     return TRUE;
774 }
775 
776 static void
_compute_face(const cairo_point_t * point,const cairo_slope_t * dev_slope,double slope_dx,double slope_dy,cairo_stroker_t * stroker,cairo_stroke_face_t * face)777 _compute_face (const cairo_point_t *point,
778 	       const cairo_slope_t *dev_slope,
779 	       double slope_dx,
780 	       double slope_dy,
781 	       cairo_stroker_t *stroker,
782 	       cairo_stroke_face_t *face)
783 {
784     double face_dx, face_dy;
785     cairo_point_t offset_ccw, offset_cw;
786 
787     /*
788      * rotate to get a line_width/2 vector along the face, note that
789      * the vector must be rotated the right direction in device space,
790      * but by 90° in user space. So, the rotation depends on
791      * whether the ctm reflects or not, and that can be determined
792      * by looking at the determinant of the matrix.
793      */
794     if (stroker->ctm_det_positive)
795     {
796 	face_dx = - slope_dy * stroker->half_line_width;
797 	face_dy = slope_dx * stroker->half_line_width;
798     }
799     else
800     {
801 	face_dx = slope_dy * stroker->half_line_width;
802 	face_dy = - slope_dx * stroker->half_line_width;
803     }
804 
805     /* back to device space */
806     cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
807 
808     offset_ccw.x = _cairo_fixed_from_double (face_dx);
809     offset_ccw.y = _cairo_fixed_from_double (face_dy);
810     offset_cw.x = -offset_ccw.x;
811     offset_cw.y = -offset_ccw.y;
812 
813     face->ccw = *point;
814     _translate_point (&face->ccw, &offset_ccw);
815 
816     face->point = *point;
817 
818     face->cw = *point;
819     _translate_point (&face->cw, &offset_cw);
820 
821     face->usr_vector.x = slope_dx;
822     face->usr_vector.y = slope_dy;
823 
824     face->dev_vector = *dev_slope;
825 }
826 
827 static cairo_status_t
_cairo_stroker_add_caps(cairo_stroker_t * stroker)828 _cairo_stroker_add_caps (cairo_stroker_t *stroker)
829 {
830     cairo_status_t status;
831 
832     /* check for a degenerative sub_path */
833     if (stroker->has_initial_sub_path
834 	&& ! stroker->has_first_face
835 	&& ! stroker->has_current_face
836 	&& stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
837     {
838 	/* pick an arbitrary slope to use */
839 	double dx = 1.0, dy = 0.0;
840 	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
841 	cairo_stroke_face_t face;
842 
843 	_compute_normalized_device_slope (&dx, &dy,
844 					  stroker->ctm_inverse, NULL);
845 
846 	/* arbitrarily choose first_point
847 	 * first_point and current_point should be the same */
848 	_compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
849 
850 	status = _cairo_stroker_add_leading_cap (stroker, &face);
851 	if (unlikely (status))
852 	    return status;
853 
854 	status = _cairo_stroker_add_trailing_cap (stroker, &face);
855 	if (unlikely (status))
856 	    return status;
857     }
858 
859     if (stroker->has_first_face) {
860 	status = _cairo_stroker_add_leading_cap (stroker,
861 						 &stroker->first_face);
862 	if (unlikely (status))
863 	    return status;
864     }
865 
866     if (stroker->has_current_face) {
867 	status = _cairo_stroker_add_trailing_cap (stroker,
868 						  &stroker->current_face);
869 	if (unlikely (status))
870 	    return status;
871     }
872 
873     return CAIRO_STATUS_SUCCESS;
874 }
875 
876 static cairo_status_t
_cairo_stroker_add_sub_edge(cairo_stroker_t * stroker,const cairo_point_t * p1,const cairo_point_t * p2,cairo_slope_t * dev_slope,double slope_dx,double slope_dy,cairo_stroke_face_t * start,cairo_stroke_face_t * end)877 _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker,
878 			     const cairo_point_t *p1,
879 			     const cairo_point_t *p2,
880 			     cairo_slope_t *dev_slope,
881 			     double slope_dx, double slope_dy,
882 			     cairo_stroke_face_t *start,
883 			     cairo_stroke_face_t *end)
884 {
885     _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start);
886     *end = *start;
887 
888     if (p1->x == p2->x && p1->y == p2->y)
889 	return CAIRO_STATUS_SUCCESS;
890 
891     end->point = *p2;
892     end->ccw.x += p2->x - p1->x;
893     end->ccw.y += p2->y - p1->y;
894     end->cw.x += p2->x - p1->x;
895     end->cw.y += p2->y - p1->y;
896 
897     if (stroker->add_external_edge != NULL) {
898 	cairo_status_t status;
899 
900 	status = stroker->add_external_edge (stroker->closure,
901 					     &end->cw, &start->cw);
902 	if (unlikely (status))
903 	    return status;
904 
905 	status = stroker->add_external_edge (stroker->closure,
906 					     &start->ccw, &end->ccw);
907 	if (unlikely (status))
908 	    return status;
909 
910 	return CAIRO_STATUS_SUCCESS;
911     } else {
912 	cairo_point_t quad[4];
913 
914 	quad[0] = start->cw;
915 	quad[1] = end->cw;
916 	quad[2] = end->ccw;
917 	quad[3] = start->ccw;
918 
919 	return stroker->add_convex_quad (stroker->closure, quad);
920     }
921 }
922 
923 static cairo_status_t
_cairo_stroker_move_to(void * closure,const cairo_point_t * point)924 _cairo_stroker_move_to (void *closure,
925 			const cairo_point_t *point)
926 {
927     cairo_stroker_t *stroker = closure;
928     cairo_status_t status;
929 
930     /* reset the dash pattern for new sub paths */
931     _cairo_stroker_dash_start (&stroker->dash);
932 
933     /* Cap the start and end of the previous sub path as needed */
934     status = _cairo_stroker_add_caps (stroker);
935     if (unlikely (status))
936 	return status;
937 
938     stroker->first_point = *point;
939     stroker->current_point = *point;
940 
941     stroker->has_first_face = FALSE;
942     stroker->has_current_face = FALSE;
943     stroker->has_initial_sub_path = FALSE;
944 
945     return CAIRO_STATUS_SUCCESS;
946 }
947 
948 static cairo_status_t
_cairo_stroker_line_to(void * closure,const cairo_point_t * point)949 _cairo_stroker_line_to (void *closure,
950 			const cairo_point_t *point)
951 {
952     cairo_stroker_t *stroker = closure;
953     cairo_stroke_face_t start, end;
954     cairo_point_t *p1 = &stroker->current_point;
955     cairo_slope_t dev_slope;
956     double slope_dx, slope_dy;
957     cairo_status_t status;
958 
959     stroker->has_initial_sub_path = TRUE;
960 
961     if (p1->x == point->x && p1->y == point->y)
962 	return CAIRO_STATUS_SUCCESS;
963 
964     _cairo_slope_init (&dev_slope, p1, point);
965     slope_dx = _cairo_fixed_to_double (point->x - p1->x);
966     slope_dy = _cairo_fixed_to_double (point->y - p1->y);
967     _compute_normalized_device_slope (&slope_dx, &slope_dy,
968 				      stroker->ctm_inverse, NULL);
969 
970     status = _cairo_stroker_add_sub_edge (stroker,
971 					  p1, point,
972 					  &dev_slope,
973 					  slope_dx, slope_dy,
974 					  &start, &end);
975     if (unlikely (status))
976 	return status;
977 
978     if (stroker->has_current_face) {
979 	/* Join with final face from previous segment */
980 	status = _cairo_stroker_join (stroker,
981 				      &stroker->current_face,
982 				      &start);
983 	if (unlikely (status))
984 	    return status;
985     } else if (! stroker->has_first_face) {
986 	/* Save sub path's first face in case needed for closing join */
987 	stroker->first_face = start;
988 	stroker->has_first_face = TRUE;
989     }
990     stroker->current_face = end;
991     stroker->has_current_face = TRUE;
992 
993     stroker->current_point = *point;
994 
995     return CAIRO_STATUS_SUCCESS;
996 }
997 
998 static cairo_status_t
_cairo_stroker_spline_to(void * closure,const cairo_point_t * point,const cairo_slope_t * tangent)999 _cairo_stroker_spline_to (void *closure,
1000 			  const cairo_point_t *point,
1001 			  const cairo_slope_t *tangent)
1002 {
1003     cairo_stroker_t *stroker = closure;
1004     cairo_stroke_face_t new_face;
1005     double slope_dx, slope_dy;
1006     cairo_point_t points[3];
1007     cairo_point_t intersect_point;
1008 
1009     stroker->has_initial_sub_path = TRUE;
1010 
1011     if (stroker->current_point.x == point->x &&
1012 	stroker->current_point.y == point->y)
1013 	return CAIRO_STATUS_SUCCESS;
1014 
1015     slope_dx = _cairo_fixed_to_double (tangent->dx);
1016     slope_dy = _cairo_fixed_to_double (tangent->dy);
1017 
1018     if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
1019 					    stroker->ctm_inverse, NULL))
1020 	return CAIRO_STATUS_SUCCESS;
1021 
1022     _compute_face (point, tangent,
1023 		   slope_dx, slope_dy,
1024 		   stroker, &new_face);
1025 
1026     assert (stroker->has_current_face);
1027 
1028     if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x +
1029          new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) {
1030 
1031 	const cairo_point_t *inpt, *outpt;
1032 	int clockwise = _cairo_stroker_join_is_clockwise (&new_face,
1033 							  &stroker->current_face);
1034 
1035 	if (clockwise) {
1036 	    inpt = &stroker->current_face.cw;
1037 	    outpt = &new_face.cw;
1038 	} else {
1039 	    inpt = &stroker->current_face.ccw;
1040 	    outpt = &new_face.ccw;
1041 	}
1042 
1043 	_tessellate_fan (stroker,
1044 			 &stroker->current_face.dev_vector,
1045 			 &new_face.dev_vector,
1046 			 &stroker->current_face.point,
1047 			 inpt, outpt,
1048 			 clockwise);
1049     }
1050 
1051     if (_slow_segment_intersection (&stroker->current_face.cw,
1052 				    &stroker->current_face.ccw,
1053 				    &new_face.cw,
1054 				    &new_face.ccw,
1055 				    &intersect_point)) {
1056 	points[0] = stroker->current_face.ccw;
1057 	points[1] = new_face.ccw;
1058 	points[2] = intersect_point;
1059 	stroker->add_triangle (stroker->closure, points);
1060 
1061 	points[0] = stroker->current_face.cw;
1062 	points[1] = new_face.cw;
1063 	stroker->add_triangle (stroker->closure, points);
1064     } else {
1065 	points[0] = stroker->current_face.ccw;
1066 	points[1] = stroker->current_face.cw;
1067 	points[2] = new_face.cw;
1068 	stroker->add_triangle (stroker->closure, points);
1069 
1070 	points[0] = stroker->current_face.ccw;
1071 	points[1] = new_face.cw;
1072 	points[2] = new_face.ccw;
1073 	stroker->add_triangle (stroker->closure, points);
1074     }
1075 
1076     stroker->current_face = new_face;
1077     stroker->has_current_face = TRUE;
1078     stroker->current_point = *point;
1079 
1080     return CAIRO_STATUS_SUCCESS;
1081 }
1082 
1083 /*
1084  * Dashed lines.  Cap each dash end, join around turns when on
1085  */
1086 static cairo_status_t
_cairo_stroker_line_to_dashed(void * closure,const cairo_point_t * p2)1087 _cairo_stroker_line_to_dashed (void *closure,
1088 			       const cairo_point_t *p2)
1089 {
1090     cairo_stroker_t *stroker = closure;
1091     double mag, remain, step_length = 0;
1092     double slope_dx, slope_dy;
1093     double dx2, dy2;
1094     cairo_stroke_face_t sub_start, sub_end;
1095     cairo_point_t *p1 = &stroker->current_point;
1096     cairo_slope_t dev_slope;
1097     cairo_line_t segment;
1098     cairo_bool_t fully_in_bounds;
1099     cairo_status_t status;
1100 
1101     stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
1102 
1103     if (p1->x == p2->x && p1->y == p2->y)
1104 	return CAIRO_STATUS_SUCCESS;
1105 
1106     fully_in_bounds = TRUE;
1107     if (stroker->has_bounds &&
1108 	(! _cairo_box_contains_point (&stroker->bounds, p1) ||
1109 	 ! _cairo_box_contains_point (&stroker->bounds, p2)))
1110     {
1111 	fully_in_bounds = FALSE;
1112     }
1113 
1114     _cairo_slope_init (&dev_slope, p1, p2);
1115 
1116     slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
1117     slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
1118 
1119     if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
1120 					    stroker->ctm_inverse, &mag))
1121     {
1122 	return CAIRO_STATUS_SUCCESS;
1123     }
1124 
1125     remain = mag;
1126     segment.p1 = *p1;
1127     while (remain) {
1128 	step_length = MIN (stroker->dash.dash_remain, remain);
1129 	remain -= step_length;
1130 	dx2 = slope_dx * (mag - remain);
1131 	dy2 = slope_dy * (mag - remain);
1132 	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
1133 	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
1134 	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
1135 
1136 	if (stroker->dash.dash_on &&
1137 	    (fully_in_bounds ||
1138 	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
1139 	     _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
1140 	{
1141 	    status = _cairo_stroker_add_sub_edge (stroker,
1142 						  &segment.p1, &segment.p2,
1143 						  &dev_slope,
1144 						  slope_dx, slope_dy,
1145 						  &sub_start, &sub_end);
1146 	    if (unlikely (status))
1147 		return status;
1148 
1149 	    if (stroker->has_current_face)
1150 	    {
1151 		/* Join with final face from previous segment */
1152 		status = _cairo_stroker_join (stroker,
1153 					      &stroker->current_face,
1154 					      &sub_start);
1155 		if (unlikely (status))
1156 		    return status;
1157 
1158 		stroker->has_current_face = FALSE;
1159 	    }
1160 	    else if (! stroker->has_first_face &&
1161 		       stroker->dash.dash_starts_on)
1162 	    {
1163 		/* Save sub path's first face in case needed for closing join */
1164 		stroker->first_face = sub_start;
1165 		stroker->has_first_face = TRUE;
1166 	    }
1167 	    else
1168 	    {
1169 		/* Cap dash start if not connecting to a previous segment */
1170 		status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
1171 		if (unlikely (status))
1172 		    return status;
1173 	    }
1174 
1175 	    if (remain) {
1176 		/* Cap dash end if not at end of segment */
1177 		status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
1178 		if (unlikely (status))
1179 		    return status;
1180 	    } else {
1181 		stroker->current_face = sub_end;
1182 		stroker->has_current_face = TRUE;
1183 	    }
1184 	} else {
1185 	    if (stroker->has_current_face) {
1186 		/* Cap final face from previous segment */
1187 		status = _cairo_stroker_add_trailing_cap (stroker,
1188 							  &stroker->current_face);
1189 		if (unlikely (status))
1190 		    return status;
1191 
1192 		stroker->has_current_face = FALSE;
1193 	    }
1194 	}
1195 
1196 	_cairo_stroker_dash_step (&stroker->dash, step_length);
1197 	segment.p1 = segment.p2;
1198     }
1199 
1200     if (stroker->dash.dash_on && ! stroker->has_current_face) {
1201 	/* This segment ends on a transition to dash_on, compute a new face
1202 	 * and add cap for the beginning of the next dash_on step.
1203 	 *
1204 	 * Note: this will create a degenerate cap if this is not the last line
1205 	 * in the path. Whether this behaviour is desirable or not is debatable.
1206 	 * On one side these degenerate caps can not be reproduced with regular
1207 	 * path stroking.
1208 	 * On the other hand, Acroread 7 also produces the degenerate caps.
1209 	 */
1210 	_compute_face (p2, &dev_slope,
1211 		       slope_dx, slope_dy,
1212 		       stroker,
1213 		       &stroker->current_face);
1214 
1215 	status = _cairo_stroker_add_leading_cap (stroker,
1216 						 &stroker->current_face);
1217 	if (unlikely (status))
1218 	    return status;
1219 
1220 	stroker->has_current_face = TRUE;
1221     }
1222 
1223     stroker->current_point = *p2;
1224 
1225     return CAIRO_STATUS_SUCCESS;
1226 }
1227 
1228 static cairo_status_t
_cairo_stroker_curve_to(void * closure,const cairo_point_t * b,const cairo_point_t * c,const cairo_point_t * d)1229 _cairo_stroker_curve_to (void *closure,
1230 			 const cairo_point_t *b,
1231 			 const cairo_point_t *c,
1232 			 const cairo_point_t *d)
1233 {
1234     cairo_stroker_t *stroker = closure;
1235     cairo_spline_t spline;
1236     cairo_line_join_t line_join_save;
1237     cairo_stroke_face_t face;
1238     double slope_dx, slope_dy;
1239     cairo_spline_add_point_func_t line_to;
1240     cairo_spline_add_point_func_t spline_to;
1241     cairo_status_t status = CAIRO_STATUS_SUCCESS;
1242 
1243     line_to = stroker->dash.dashed ?
1244 	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
1245 	(cairo_spline_add_point_func_t) _cairo_stroker_line_to;
1246 
1247     /* spline_to is only capable of rendering non-degenerate splines. */
1248     spline_to = stroker->dash.dashed ?
1249 	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
1250 	(cairo_spline_add_point_func_t) _cairo_stroker_spline_to;
1251 
1252     if (! _cairo_spline_init (&spline,
1253 			      spline_to,
1254 			      stroker,
1255 			      &stroker->current_point, b, c, d))
1256     {
1257 	cairo_slope_t fallback_slope;
1258 	_cairo_slope_init (&fallback_slope, &stroker->current_point, d);
1259 	return line_to (closure, d, &fallback_slope);
1260     }
1261 
1262     /* If the line width is so small that the pen is reduced to a
1263        single point, then we have nothing to do. */
1264     if (stroker->pen.num_vertices <= 1)
1265 	return CAIRO_STATUS_SUCCESS;
1266 
1267     /* Compute the initial face */
1268     if (! stroker->dash.dashed || stroker->dash.dash_on) {
1269 	slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
1270 	slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
1271 	if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
1272 					      stroker->ctm_inverse, NULL))
1273 	{
1274 	    _compute_face (&stroker->current_point,
1275 			   &spline.initial_slope,
1276 			   slope_dx, slope_dy,
1277 			   stroker, &face);
1278 	}
1279 	if (stroker->has_current_face) {
1280 	    status = _cairo_stroker_join (stroker,
1281 					  &stroker->current_face, &face);
1282 	    if (unlikely (status))
1283 		return status;
1284 	} else if (! stroker->has_first_face) {
1285 	    stroker->first_face = face;
1286 	    stroker->has_first_face = TRUE;
1287 	}
1288 
1289 	stroker->current_face = face;
1290 	stroker->has_current_face = TRUE;
1291     }
1292 
1293     /* Temporarily modify the stroker to use round joins to guarantee
1294      * smooth stroked curves. */
1295     line_join_save = stroker->style.line_join;
1296     stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
1297 
1298     status = _cairo_spline_decompose (&spline, stroker->tolerance);
1299     if (unlikely (status))
1300 	return status;
1301 
1302     /* And join the final face */
1303     if (! stroker->dash.dashed || stroker->dash.dash_on) {
1304 	slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
1305 	slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
1306 	if (_compute_normalized_device_slope (&slope_dx, &slope_dy,
1307 					      stroker->ctm_inverse, NULL))
1308 	{
1309 	    _compute_face (&stroker->current_point,
1310 			   &spline.final_slope,
1311 			   slope_dx, slope_dy,
1312 			   stroker, &face);
1313 	}
1314 
1315 	status = _cairo_stroker_join (stroker, &stroker->current_face, &face);
1316 	if (unlikely (status))
1317 	    return status;
1318 
1319 	stroker->current_face = face;
1320     }
1321 
1322     stroker->style.line_join = line_join_save;
1323 
1324     return CAIRO_STATUS_SUCCESS;
1325 }
1326 
1327 static cairo_status_t
_cairo_stroker_close_path(void * closure)1328 _cairo_stroker_close_path (void *closure)
1329 {
1330     cairo_stroker_t *stroker = closure;
1331     cairo_status_t status;
1332 
1333     if (stroker->dash.dashed)
1334 	status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
1335     else
1336 	status = _cairo_stroker_line_to (stroker, &stroker->first_point);
1337     if (unlikely (status))
1338 	return status;
1339 
1340     if (stroker->has_first_face && stroker->has_current_face) {
1341 	/* Join first and final faces of sub path */
1342 	status = _cairo_stroker_join (stroker,
1343 				      &stroker->current_face,
1344 				      &stroker->first_face);
1345 	if (unlikely (status))
1346 	    return status;
1347     } else {
1348 	/* Cap the start and end of the sub path as needed */
1349 	status = _cairo_stroker_add_caps (stroker);
1350 	if (unlikely (status))
1351 	    return status;
1352     }
1353 
1354     stroker->has_initial_sub_path = FALSE;
1355     stroker->has_first_face = FALSE;
1356     stroker->has_current_face = FALSE;
1357 
1358     return CAIRO_STATUS_SUCCESS;
1359 }
1360 
1361 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)1362 _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t	*path,
1363 				    const cairo_stroke_style_t	*stroke_style,
1364 				    const cairo_matrix_t	*ctm,
1365 				    const cairo_matrix_t	*ctm_inverse,
1366 				    double		 tolerance,
1367 				    cairo_status_t (*add_triangle) (void *closure,
1368 								    const cairo_point_t triangle[3]),
1369 				    cairo_status_t (*add_triangle_fan) (void *closure,
1370 									const cairo_point_t *midpt,
1371 									const cairo_point_t *points,
1372 									int npoints),
1373 				    cairo_status_t (*add_convex_quad) (void *closure,
1374 								       const cairo_point_t quad[4]),
1375 				    void *closure)
1376 {
1377     cairo_stroker_t stroker;
1378     cairo_status_t status;
1379 
1380     status = _cairo_stroker_init (&stroker, path, stroke_style,
1381 			          ctm, ctm_inverse, tolerance,
1382 				  NULL, 0);
1383     if (unlikely (status))
1384 	return status;
1385 
1386     stroker.add_triangle = add_triangle;
1387     stroker.add_triangle_fan = add_triangle_fan;
1388     stroker.add_convex_quad = add_convex_quad;
1389     stroker.closure = closure;
1390 
1391     status = _cairo_path_fixed_interpret (path,
1392 					  _cairo_stroker_move_to,
1393 					  stroker.dash.dashed ?
1394 					  _cairo_stroker_line_to_dashed :
1395 					  _cairo_stroker_line_to,
1396 					  _cairo_stroker_curve_to,
1397 					  _cairo_stroker_close_path,
1398 					  &stroker);
1399 
1400     if (unlikely (status))
1401 	goto BAIL;
1402 
1403     /* Cap the start and end of the final sub path as needed */
1404     status = _cairo_stroker_add_caps (&stroker);
1405 
1406 BAIL:
1407     _cairo_stroker_fini (&stroker);
1408 
1409     return status;
1410 }
1411 
1412 cairo_status_t
_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)1413 _cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t	*path,
1414 					    const cairo_stroke_style_t	*stroke_style,
1415 					    const cairo_matrix_t	*ctm,
1416 					    const cairo_matrix_t	*ctm_inverse,
1417 					    double		 tolerance,
1418 					    cairo_polygon_t *polygon)
1419 {
1420     cairo_stroker_t stroker;
1421     cairo_status_t status;
1422 
1423     status = _cairo_stroker_init (&stroker, path, stroke_style,
1424 			          ctm, ctm_inverse, tolerance,
1425 				  polygon->limits, polygon->num_limits);
1426     if (unlikely (status))
1427 	return status;
1428 
1429     stroker.add_external_edge = _cairo_polygon_add_external_edge,
1430     stroker.closure = polygon;
1431 
1432     status = _cairo_path_fixed_interpret (path,
1433 					  _cairo_stroker_move_to,
1434 					  stroker.dash.dashed ?
1435 					  _cairo_stroker_line_to_dashed :
1436 					  _cairo_stroker_line_to,
1437 					  _cairo_stroker_curve_to,
1438 					  _cairo_stroker_close_path,
1439 					  &stroker);
1440 
1441     if (unlikely (status))
1442 	goto BAIL;
1443 
1444     /* Cap the start and end of the final sub path as needed */
1445     status = _cairo_stroker_add_caps (&stroker);
1446 
1447 BAIL:
1448     _cairo_stroker_fini (&stroker);
1449 
1450     return status;
1451 }
1452 
1453 cairo_int_status_t
_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)1454 _cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t	*path,
1455                                            const cairo_stroke_style_t	*stroke_style,
1456                                            const cairo_matrix_t	*ctm,
1457                                            const cairo_matrix_t	*ctm_inverse,
1458                                            double		 tolerance,
1459                                            cairo_traps_t	*traps)
1460 {
1461     cairo_int_status_t status;
1462     cairo_polygon_t polygon;
1463 
1464     _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
1465     status = _cairo_path_fixed_stroke_to_polygon (path,
1466 						  stroke_style,
1467 						  ctm,
1468 						  ctm_inverse,
1469 						  tolerance,
1470 						  &polygon);
1471     if (unlikely (status))
1472 	goto BAIL;
1473 
1474     status = _cairo_polygon_status (&polygon);
1475     if (unlikely (status))
1476 	goto BAIL;
1477 
1478     status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
1479 							CAIRO_FILL_RULE_WINDING);
1480 
1481 BAIL:
1482     _cairo_polygon_fini (&polygon);
1483 
1484     return status;
1485 }
1486