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; }