static cairo_status_t
close_path (void *closure)
{
    struct stroker *stroker = closure;
    cairo_status_t status;

    status = line_to (stroker, &stroker->first_point);
    if (unlikely (status))
        return status;

    if (stroker->has_first_face && stroker->has_current_face) {
        /* Join first and final faces of sub path */
        outer_close (stroker, &stroker->current_face, &stroker->first_face);
        inner_close (stroker, &stroker->current_face, &stroker->first_face);
    } else {
        /* Cap the start and end of the sub path as needed */
        add_caps (stroker);
    }

    stroker->has_sub_path = FALSE;
    stroker->has_first_face = FALSE;
    stroker->has_current_face = FALSE;

    return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_path_fixed_stroke_to_tristrip (const cairo_path_fixed_t	*path,
                                      const cairo_stroke_style_t*style,
                                      const cairo_matrix_t	*ctm,
                                      const cairo_matrix_t	*ctm_inverse,
                                      double			 tolerance,
                                      cairo_tristrip_t		 *strip)
{
    struct stroker stroker;
    cairo_int_status_t status;
    int i;

    if (style->num_dashes)
        return CAIRO_INT_STATUS_UNSUPPORTED;

    stroker.style = *style;
    stroker.ctm = ctm;
    stroker.ctm_inverse = ctm_inverse;
    stroker.tolerance = tolerance;

    stroker.ctm_det_positive =
        _cairo_matrix_compute_determinant (ctm) >= 0.0;

    status = _cairo_pen_init (&stroker.pen,
                              style->line_width / 2.0,
                              tolerance, ctm);
    if (unlikely (status))
        return status;

    if (stroker.pen.num_vertices <= 1)
        return CAIRO_INT_STATUS_NOTHING_TO_DO;

    stroker.has_current_face = FALSE;
    stroker.has_first_face = FALSE;
    stroker.has_sub_path = FALSE;

    stroker.has_limits = strip->num_limits > 0;
    stroker.limit = strip->limits[0];
    for (i = 1; i < strip->num_limits; i++)
        _cairo_box_add_box (&stroker.limit, &strip->limits[i]);

    stroker.strip = strip;

    status = _cairo_path_fixed_interpret (path,
                                          move_to,
                                          line_to,
                                          curve_to,
                                          close_path,
                                          &stroker);
    /* Cap the start and end of the final sub path as needed */
    if (likely (status == CAIRO_INT_STATUS_SUCCESS))
        add_caps (&stroker);

    _cairo_pen_fini (&stroker.pen);

    return status;
}
static cairo_status_t
close_path (void *closure)
{
    struct stroker *stroker = closure;
    cairo_status_t status;

    status = line_to (stroker, &stroker->first_point);
    if (unlikely (status))
	return status;

    if (stroker->has_first_face && stroker->has_current_face) {
	/* Join first and final faces of sub path */
	outer_close (stroker, &stroker->current_face, &stroker->first_face);
	inner_close (stroker, &stroker->current_face, &stroker->first_face);
#if 0
	*_cairo_contour_first_point (&stroker->ccw.contour) =
	    *_cairo_contour_last_point (&stroker->ccw.contour);

	*_cairo_contour_first_point (&stroker->cw.contour) =
	    *_cairo_contour_last_point (&stroker->cw.contour);
#endif

	_cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour);
	_cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);

#if DEBUG
	{
	    FILE *file = fopen ("contours.txt", "a");
	    _cairo_debug_print_contour (file, &stroker->path);
	    _cairo_debug_print_contour (file, &stroker->cw.contour);
	    _cairo_debug_print_contour (file, &stroker->ccw.contour);
	    fclose (file);

	    _cairo_contour_reset (&stroker->path);
	}
#endif
	_cairo_contour_reset (&stroker->cw.contour);
	_cairo_contour_reset (&stroker->ccw.contour);
    } else {
	/* Cap the start and end of the sub path as needed */
	add_caps (stroker);
    }

    stroker->has_initial_sub_path = FALSE;
    stroker->has_first_face = FALSE;
    stroker->has_current_face = FALSE;

    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
move_to (void *closure,
         const cairo_point_t *point)
{
    struct stroker *stroker = closure;

    /* Cap the start and end of the previous sub path as needed */
    add_caps (stroker);

    stroker->has_first_face = FALSE;
    stroker->has_current_face = FALSE;
    stroker->has_sub_path = FALSE;

    stroker->first_point = *point;

    stroker->current_face.point = *point;

    return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
				     const cairo_stroke_style_t	*style,
				     const cairo_matrix_t	*ctm,
				     const cairo_matrix_t	*ctm_inverse,
				     double		 tolerance,
				     cairo_polygon_t *polygon)
{
    struct stroker stroker;
    cairo_status_t status;

    if (style->num_dashes) {
	return _cairo_path_fixed_stroke_dashed_to_polygon (path,
							   style,
							   ctm,
							   ctm_inverse,
							   tolerance,
							   polygon);
    }

    stroker.has_bounds = polygon->num_limits;
    if (stroker.has_bounds) {
	/* Extend the bounds in each direction to account for the maximum area
	 * we might generate trapezoids, to capture line segments that are
	 * outside of the bounds but which might generate rendering that's
	 * within bounds.
	 */
	double dx, dy;
	cairo_fixed_t fdx, fdy;
	int i;

	stroker.bounds = polygon->limits[0];
	for (i = 1; i < polygon->num_limits; i++)
	     _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);

	_cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
	fdx = _cairo_fixed_from_double (dx);
	fdy = _cairo_fixed_from_double (dy);

	stroker.bounds.p1.x -= fdx;
	stroker.bounds.p2.x += fdx;
	stroker.bounds.p1.y -= fdy;
	stroker.bounds.p2.y += fdy;
    }

    stroker.style = *style;
    stroker.ctm = ctm;
    stroker.ctm_inverse = ctm_inverse;
    stroker.tolerance = tolerance;
    stroker.half_line_width = style->line_width / 2.;
    /* To test whether we need to join two segments of a spline using
     * a round-join or a bevel-join, we can inspect the angle between the
     * two segments. If the difference between the chord distance
     * (half-line-width times the cosine of the bisection angle) and the
     * half-line-width itself is greater than tolerance then we need to
     * inject a point.
     */
    stroker.spline_cusp_tolerance = 1 - tolerance / stroker.half_line_width;
    stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
    stroker.spline_cusp_tolerance *= 2;
    stroker.spline_cusp_tolerance -= 1;
    stroker.ctm_det_positive =
	_cairo_matrix_compute_determinant (ctm) >= 0.0;

    stroker.pen.num_vertices = 0;
    if (path->has_curve_to ||
	style->line_join == CAIRO_LINE_JOIN_ROUND ||
	style->line_cap == CAIRO_LINE_CAP_ROUND) {
	status = _cairo_pen_init (&stroker.pen,
				  stroker.half_line_width,
				  tolerance, ctm);
	if (unlikely (status))
	    return status;

	/* If the line width is so small that the pen is reduced to a
	   single point, then we have nothing to do. */
	if (stroker.pen.num_vertices <= 1)
	    return CAIRO_STATUS_SUCCESS;
    }

    stroker.has_current_face = FALSE;
    stroker.has_first_face = FALSE;
    stroker.has_initial_sub_path = FALSE;

#if DEBUG
    remove ("contours.txt");
    remove ("polygons.txt");
    _cairo_contour_init (&stroker.path, 0);
#endif
    _cairo_contour_init (&stroker.cw.contour, 1);
    _cairo_contour_init (&stroker.ccw.contour, -1);
    tolerance *= CAIRO_FIXED_ONE;
    tolerance *= tolerance;
    stroker.contour_tolerance = tolerance;
    stroker.polygon = polygon;

    status = _cairo_path_fixed_interpret (path,
					  move_to,
					  line_to,
					  curve_to,
					  close_path,
					  &stroker);
    /* Cap the start and end of the final sub path as needed */
    if (likely (status == CAIRO_STATUS_SUCCESS))
	add_caps (&stroker);

    _cairo_contour_fini (&stroker.cw.contour);
    _cairo_contour_fini (&stroker.ccw.contour);
    if (stroker.pen.num_vertices)
	_cairo_pen_fini (&stroker.pen);

#if DEBUG
    {
	FILE *file = fopen ("polygons.txt", "a");
	_cairo_debug_print_polygon (file, polygon);
	fclose (file);
    }
#endif

    return status;
}
cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
				     const cairo_stroke_style_t	*style,
				     const cairo_matrix_t	*ctm,
				     const cairo_matrix_t	*ctm_inverse,
				     double		 tolerance,
				     cairo_polygon_t *polygon)
{
    struct stroker stroker;
    cairo_status_t status;

    if (style->num_dashes) {
	return _cairo_path_fixed_stroke_dashed_to_polygon (path,
							   style,
							   ctm,
							   ctm_inverse,
							   tolerance,
							   polygon);
    }

    stroker.style = *style;
    stroker.ctm = ctm;
    stroker.ctm_inverse = ctm_inverse;
    stroker.tolerance = tolerance;

    stroker.ctm_det_positive =
	_cairo_matrix_compute_determinant (ctm) >= 0.0;

    stroker.pen.num_vertices = 0;
    if (path->has_curve_to ||
	style->line_join == CAIRO_LINE_JOIN_ROUND ||
	style->line_cap == CAIRO_LINE_CAP_ROUND) {
	status = _cairo_pen_init (&stroker.pen,
				  style->line_width / 2.0,
				  tolerance, ctm);
	if (unlikely (status))
	    return status;

	/* If the line width is so small that the pen is reduced to a
	   single point, then we have nothing to do. */
	if (stroker.pen.num_vertices <= 1)
	    return CAIRO_STATUS_SUCCESS;
    }

    stroker.has_current_face = FALSE;
    stroker.has_first_face = FALSE;
    stroker.has_initial_sub_path = FALSE;

#if DEBUG
    remove ("contours.txt");
    remove ("polygons.txt");
    _cairo_contour_init (&stroker.path, 0);
#endif
    _cairo_contour_init (&stroker.cw.contour, 1);
    _cairo_contour_init (&stroker.ccw.contour, -1);
    tolerance *= CAIRO_FIXED_ONE;
    tolerance *= tolerance;
    stroker.contour_tolerance = tolerance;
    stroker.polygon = polygon;

    status = _cairo_path_fixed_interpret (path,
					  move_to,
					  line_to,
					  curve_to,
					  close_path,
					  &stroker);
    /* Cap the start and end of the final sub path as needed */
    if (likely (status == CAIRO_STATUS_SUCCESS))
	add_caps (&stroker);

    _cairo_contour_fini (&stroker.cw.contour);
    _cairo_contour_fini (&stroker.ccw.contour);
    if (stroker.pen.num_vertices)
	_cairo_pen_fini (&stroker.pen);

#if DEBUG
    {
	FILE *file = fopen ("polygons.txt", "a");
	_cairo_debug_print_polygon (file, polygon);
	fclose (file);
    }
#endif

    return status;
}