static cairo_status_t _cpf_curve_to (void *closure, cairo_point_t *p1, cairo_point_t *p2, cairo_point_t *p3) { cpf_t *cpf = closure; cairo_status_t status; cairo_spline_t spline; int i; cairo_point_t *p0 = &cpf->current_point; status = _cairo_spline_init (&spline, p0, p1, p2, p3); if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; status = _cairo_spline_decompose (&spline, cpf->tolerance); if (status) goto out; for (i=1; i < spline.num_points; i++) { status = cpf->line_to (cpf->closure, &spline.points[i]); if (status) goto out; } cpf->current_point = *p3; status = CAIRO_STATUS_SUCCESS; out: _cairo_spline_fini (&spline); return status; }
static cairo_status_t _cairo_filler_curve_to (void *closure, cairo_point_t *b, cairo_point_t *c, cairo_point_t *d) { int i; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; cairo_spline_t spline; status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; _cairo_spline_decompose (&spline, filler->tolerance); if (status) goto CLEANUP_SPLINE; for (i = 1; i < spline.num_points; i++) { status = _cairo_polygon_line_to (polygon, &spline.points[i]); if (status) break; } CLEANUP_SPLINE: _cairo_spline_fini (&spline); filler->current_point = *d; return status; }
/* We're using two different algorithms here for dashed and un-dashed * splines. The dashed algorithm uses the existing line dashing * code. It's linear in path length, but gets subtly wrong results for * self-intersecting paths (an outstanding but for self-intersecting * non-curved paths as well). The non-dashed algorithm tessellates a * single polygon for the whole curve. It handles the * self-intersecting problem, but it's (unsurprisingly) not O(n) and * more significantly, it doesn't yet handle dashes. * * The only reason we're doing split algorithms here is to * minimize the impact of fixing the splines-aren't-dashed bug for * 1.0.2. Long-term the right answer is to rewrite the whole pile * of stroking code so that the entire result is computed as a * single polygon that is tessellated, (that is, stroking can be * built on top of filling). That will solve the self-intersecting * problem. It will also increase the importance of implementing * an efficient and more robust tessellator. */ static cairo_status_t _cairo_stroker_curve_to_dashed (void *closure, cairo_point_t *b, cairo_point_t *c, cairo_point_t *d) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; cairo_spline_t spline; cairo_point_t *a = &stroker->current_point; cairo_line_join_t line_join_save; int i; status = _cairo_spline_init (&spline, a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) return _cairo_stroker_line_to_dashed (closure, d); /* 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) goto CLEANUP_SPLINE; /* Temporarily modify the stroker to use round joins to guarantee * smooth stroked curves. */ line_join_save = stroker->style->line_join; stroker->style->line_join = CAIRO_LINE_JOIN_ROUND; status = _cairo_spline_decompose (&spline, stroker->tolerance); if (status) goto CLEANUP_GSTATE; for (i = 1; i < spline.num_points; i++) { if (stroker->dashed) status = _cairo_stroker_line_to_dashed (stroker, &spline.points[i]); else status = _cairo_stroker_line_to (stroker, &spline.points[i]); if (status) break; } CLEANUP_GSTATE: stroker->style->line_join = line_join_save; CLEANUP_SPLINE: _cairo_spline_fini (&spline); return status; }
static cairo_status_t _cairo_filler_curve_to (void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { cairo_filler_t *filler = closure; cairo_spline_t spline; if (! _cairo_spline_init (&spline, _cairo_filler_line_to, filler, &filler->polygon->current_point, b, c, d)) { return _cairo_filler_line_to (closure, d); } return _cairo_spline_decompose (&spline, filler->tolerance); }
static cairo_status_t curve_to (void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { struct stroker *stroker = closure; cairo_spline_t spline; cairo_stroke_face_t face; if (stroker->has_limits) { if (! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, &stroker->limit)) return line_to (closure, d); } if (! _cairo_spline_init (&spline, spline_to, stroker, &stroker->current_face.point, b, c, d)) return line_to (closure, d); compute_face (&stroker->current_face.point, &spline.initial_slope, stroker, &face); if (stroker->has_current_face) { int clockwise = join_is_clockwise (&stroker->current_face, &face); /* Join with final face from previous segment */ outer_join (stroker, &stroker->current_face, &face, clockwise); inner_join (stroker, &stroker->current_face, &face, clockwise); } else { if (! stroker->has_first_face) { /* Save sub path's first face in case needed for closing join */ stroker->first_face = face; _cairo_tristrip_move_to (stroker->strip, &face.cw); stroker->has_first_face = TRUE; } stroker->has_current_face = TRUE; _cairo_tristrip_add_point (stroker->strip, &face.cw); _cairo_tristrip_add_point (stroker->strip, &face.ccw); } stroker->current_face = face; return _cairo_spline_decompose (&spline, stroker->tolerance); }
static cairo_status_t _cairo_in_fill_curve_to (void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { cairo_in_fill_t *in_fill = closure; cairo_spline_t spline; cairo_fixed_t top, bot, left; /* first reject based on bbox */ bot = top = in_fill->current_point.y; if (b->y < top) top = b->y; if (b->y > bot) bot = b->y; if (c->y < top) top = c->y; if (c->y > bot) bot = c->y; if (d->y < top) top = d->y; if (d->y > bot) bot = d->y; if (bot < in_fill->y || top > in_fill->y) { in_fill->current_point = *d; return CAIRO_STATUS_SUCCESS; } left = in_fill->current_point.x; if (b->x < left) left = b->x; if (c->x < left) left = c->x; if (d->x < left) left = d->x; if (left > in_fill->x) { in_fill->current_point = *d; return CAIRO_STATUS_SUCCESS; } /* XXX Investigate direct inspection of the inflections? */ if (! _cairo_spline_init (&spline, (cairo_spline_add_point_func_t)_cairo_in_fill_line_to, in_fill, &in_fill->current_point, b, c, d)) { return CAIRO_STATUS_SUCCESS; } return _cairo_spline_decompose (&spline, in_fill->tolerance); }
/* We're using two different algorithms here for dashed and un-dashed * splines. The dashed algorithm uses the existing line dashing * code. It's linear in path length, but gets subtly wrong results for * self-intersecting paths (an outstanding but for self-intersecting * non-curved paths as well). The non-dashed algorithm tessellates a * single polygon for the whole curve. It handles the * self-intersecting problem, but it's (unsurprisingly) not O(n) and * more significantly, it doesn't yet handle dashes. * * The only reason we're doing split algorithms here is to * minimize the impact of fixing the splines-aren't-dashed bug for * 1.0.2. Long-term the right answer is to rewrite the whole pile * of stroking code so that the entire result is computed as a * single polygon that is tessellated, (that is, stroking can be * built on top of filling). That will solve the self-intersecting * problem. It will also increase the importance of implementing * an efficient and more robust tessellator. */ static cairo_status_t _cairo_stroker_curve_to_dashed (void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { cairo_stroker_t *stroker = closure; cairo_spline_t spline; cairo_point_t *a = &stroker->current_point; cairo_line_join_t line_join_save; cairo_status_t status; if (! _cairo_spline_init (&spline, stroker->dashed ? _cairo_stroker_line_to_dashed : _cairo_stroker_line_to, stroker, a, b, c, d)) { return _cairo_stroker_line_to_dashed (closure, d); } /* 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; /* Temporarily modify the stroker to use round joins to guarantee * smooth stroked curves. */ line_join_save = stroker->style->line_join; stroker->style->line_join = CAIRO_LINE_JOIN_ROUND; status = _cairo_spline_decompose (&spline, stroker->tolerance); stroker->style->line_join = line_join_save; return status; }
static cairo_status_t _cpf_curve_to (void *closure, const cairo_point_t *p1, const cairo_point_t *p2, const cairo_point_t *p3) { cpf_t *cpf = closure; cairo_spline_t spline; cairo_point_t *p0 = &cpf->current_point; if (! _cairo_spline_init (&spline, cpf->line_to, cpf->closure, p0, p1, p2, p3)) { return _cpf_line_to (closure, p3); } cpf->current_point = *p3; return _cairo_spline_decompose (&spline, cpf->tolerance); }
static cairo_status_t _cairo_filler_curve_to (void *closure, const cairo_point_t *p1, const cairo_point_t *p2, const cairo_point_t *p3) { cairo_filler_t *filler = closure; cairo_spline_t spline; if (filler->has_limits) { if (! _cairo_spline_intersects (&filler->current_point, p1, p2, p3, &filler->limit)) return _cairo_filler_line_to (filler, p3, NULL); } if (! _cairo_spline_init (&spline, (cairo_spline_add_point_func_t)_cairo_filler_line_to, filler, &filler->current_point, p1, p2, p3)) { return _cairo_filler_line_to (closure, p3, NULL); } return _cairo_spline_decompose (&spline, filler->tolerance); }
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) { 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_path_fixed_line_to_func_t *line_to; cairo_status_t status = CAIRO_STATUS_SUCCESS; line_to = stroker->dash.dashed ? _cairo_stroker_line_to_dashed : _cairo_stroker_line_to; if (! _cairo_spline_init (&spline, (cairo_spline_add_point_func_t)line_to, stroker, &stroker->current_point, b, c, d)) { return line_to (closure, d); } /* 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; /* Compute the initial face */ if (! stroker->dash.dashed || stroker->dash.dash_on) { slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx); slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy); if (_compute_normalized_device_slope (&slope_dx, &slope_dy, stroker->ctm_inverse, NULL)) { _compute_face (&stroker->current_point, &spline.initial_slope, slope_dx, slope_dy, stroker, &face); } if (stroker->has_current_face) { status = _cairo_stroker_join (stroker, &stroker->current_face, &face); if (unlikely (status)) return status; } else if (! stroker->has_first_face) { stroker->first_face = face; stroker->has_first_face = TRUE; } stroker->current_face = face; stroker->has_current_face = TRUE; } /* Temporarily modify the stroker to use round joins to guarantee * smooth stroked curves. */ line_join_save = stroker->style.line_join; stroker->style.line_join = CAIRO_LINE_JOIN_ROUND; status = _cairo_spline_decompose (&spline, stroker->tolerance); if (unlikely (status)) return status; /* And join the final face */ if (! stroker->dash.dashed || stroker->dash.dash_on) { slope_dx = _cairo_fixed_to_double (spline.final_slope.dx); slope_dy = _cairo_fixed_to_double (spline.final_slope.dy); if (_compute_normalized_device_slope (&slope_dx, &slope_dy, stroker->ctm_inverse, NULL)) { _compute_face (&stroker->current_point, &spline.final_slope, slope_dx, slope_dy, stroker, &face); } status = _cairo_stroker_join (stroker, &stroker->current_face, &face); if (unlikely (status)) return status; stroker->current_face = face; } stroker->style.line_join = line_join_save; return CAIRO_STATUS_SUCCESS; }
static cairo_status_t _cairo_stroker_curve_to (void *closure, cairo_point_t *b, cairo_point_t *c, cairo_point_t *d) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; cairo_spline_t spline; cairo_pen_t pen; cairo_stroke_face_t start, end; cairo_point_t extra_points[4]; cairo_point_t *a = &stroker->current_point; double initial_slope_dx, initial_slope_dy; double final_slope_dx, final_slope_dy; status = _cairo_spline_init (&spline, a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) return _cairo_stroker_line_to (closure, d); status = _cairo_pen_init_copy (&pen, &stroker->pen); if (status) goto CLEANUP_SPLINE; initial_slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx); initial_slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy); final_slope_dx = _cairo_fixed_to_double (spline.final_slope.dx); final_slope_dy = _cairo_fixed_to_double (spline.final_slope.dy); if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy, stroker->ctm_inverse, NULL)) _compute_face (a, &spline.initial_slope, initial_slope_dx, initial_slope_dy, stroker, &start); if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy, stroker->ctm_inverse, NULL)) _compute_face (d, &spline.final_slope, final_slope_dx, final_slope_dy, stroker, &end); if (stroker->has_current_face) { status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) goto CLEANUP_PEN; } else if (!stroker->has_first_face) { stroker->first_face = start; stroker->has_first_face = TRUE; } stroker->current_face = end; stroker->has_current_face = TRUE; extra_points[0] = start.cw; extra_points[0].x -= start.point.x; extra_points[0].y -= start.point.y; extra_points[1] = start.ccw; extra_points[1].x -= start.point.x; extra_points[1].y -= start.point.y; extra_points[2] = end.cw; extra_points[2].x -= end.point.x; extra_points[2].y -= end.point.y; extra_points[3] = end.ccw; extra_points[3].x -= end.point.x; extra_points[3].y -= end.point.y; status = _cairo_pen_add_points (&pen, extra_points, 4); if (status) goto CLEANUP_PEN; status = _cairo_pen_stroke_spline (&pen, &spline, stroker->tolerance, stroker->traps); if (status) goto CLEANUP_PEN; CLEANUP_PEN: _cairo_pen_fini (&pen); CLEANUP_SPLINE: _cairo_spline_fini (&spline); stroker->current_point = *d; return status; }