Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
/* Compute outline of a given spline using the pen.
   The trapezoids needed to fill that outline will be added to traps
*/
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t		*pen,
			  cairo_spline_t	*spline,
			  double		tolerance,
			  cairo_traps_t		*traps)
{
    cairo_status_t status;
    cairo_polygon_t polygon;

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

    _cairo_polygon_init (&polygon);

    status = _cairo_spline_decompose (spline, tolerance);
    if (status)
	return status;

    status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
    if (status)
	return status;

    status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
    if (status)
	return status;

    _cairo_polygon_close (&polygon);
    _cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
    _cairo_polygon_fini (&polygon);
    
    return CAIRO_STATUS_SUCCESS;
}
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;
}
Exemplo n.º 4
0
/* 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);
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
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);
}
Exemplo n.º 8
0
/* 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;
}
Exemplo n.º 9
0
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);
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
0
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;
}