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; }
void _cairo_contour_reset (cairo_contour_t *contour) { _cairo_contour_fini (contour); _cairo_contour_init (contour, contour->direction); }
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; }