Ejemplo n.º 1
0
static cairo_status_t
_cairo_rectilinear_stroker_close_path (void *closure)
{
    cairo_rectilinear_stroker_t *stroker = closure;
    cairo_status_t status;

    /* We don't draw anything for degenerate paths. */
    if (! stroker->open_sub_path)
	return CAIRO_STATUS_SUCCESS;

    if (stroker->dash.dashed) {
	status = _cairo_rectilinear_stroker_line_to_dashed (stroker,
							    &stroker->first_point);
    } else {
	status = _cairo_rectilinear_stroker_line_to (stroker,
						     &stroker->first_point);
    }
    if (unlikely (status))
	return status;

    stroker->open_sub_path = FALSE;

    if (stroker->dash.dashed)
	status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
    else
	status = _cairo_rectilinear_stroker_emit_segments (stroker);
    if (unlikely (status))
	return status;

    return CAIRO_STATUS_SUCCESS;
}
Ejemplo n.º 2
0
static cairo_status_t
_cairo_rectilinear_stroker_move_to (void		*closure,
				    cairo_point_t	*point)
{
    cairo_rectilinear_stroker_t *stroker = closure;
    cairo_status_t status;

    status = _cairo_rectilinear_stroker_emit_segments (stroker);
    if (status)
	return status;

    stroker->current_point = *point;
    stroker->first_point = *point;

    return CAIRO_STATUS_SUCCESS;
}
Ejemplo n.º 3
0
static cairo_status_t
_cairo_rectilinear_stroker_move_to (void		*closure,
				    const cairo_point_t	*point)
{
    cairo_rectilinear_stroker_t *stroker = closure;
    cairo_status_t status;

    if (stroker->dash.dashed)
	status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
    else
	status = _cairo_rectilinear_stroker_emit_segments (stroker);
    if (unlikely (status))
	return status;

    /* reset the dash pattern for new sub paths */
    _cairo_stroker_dash_start (&stroker->dash);

    stroker->current_point = *point;
    stroker->first_point = *point;

    return CAIRO_STATUS_SUCCESS;
}
Ejemplo n.º 4
0
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
					       const cairo_stroke_style_t	*stroke_style,
					       const cairo_matrix_t	*ctm,
					       cairo_antialias_t	 antialias,
					       cairo_boxes_t		*boxes)
{
    cairo_rectilinear_stroker_t rectilinear_stroker;
    cairo_int_status_t status;
    cairo_box_t box;

    assert (_cairo_path_fixed_stroke_is_rectilinear (path));

    if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
					   stroke_style, ctm, antialias,
					   boxes))
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    if (! rectilinear_stroker.dash.dashed &&
	_cairo_path_fixed_is_stroke_box (path, &box) &&
	/* if the segments overlap we need to feed them into the tessellator */
	box.p2.x - box.p1.x > 2* rectilinear_stroker.half_line_x &&
	box.p2.y - box.p1.y > 2* rectilinear_stroker.half_line_y)
    {
	cairo_box_t b;

	/* top */
	b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p1.y - rectilinear_stroker.half_line_y;
	b.p2.y = box.p1.y + rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	/* left  (excluding top/bottom) */
	b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p1.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p1.y + rectilinear_stroker.half_line_y;
	b.p2.y = box.p2.y - rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	/* right  (excluding top/bottom) */
	b.p1.x = box.p2.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p1.y + rectilinear_stroker.half_line_y;
	b.p2.y = box.p2.y - rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	/* bottom */
	b.p1.x = box.p1.x - rectilinear_stroker.half_line_x;
	b.p2.x = box.p2.x + rectilinear_stroker.half_line_x;
	b.p1.y = box.p2.y - rectilinear_stroker.half_line_y;
	b.p2.y = box.p2.y + rectilinear_stroker.half_line_y;
	status = (cairo_int_status_t)_cairo_boxes_add (boxes, antialias, &b);
	assert (status == CAIRO_INT_STATUS_SUCCESS);

	goto done;
    }

    if (boxes->num_limits) {
	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
					  boxes->limits,
					  boxes->num_limits);
    }

    status = (cairo_int_status_t)_cairo_path_fixed_interpret (path,
					  _cairo_rectilinear_stroker_move_to,
					  rectilinear_stroker.dash.dashed ?
					  _cairo_rectilinear_stroker_line_to_dashed :
					  _cairo_rectilinear_stroker_line_to,
					  NULL,
					  _cairo_rectilinear_stroker_close_path,
					  &rectilinear_stroker);
    if (unlikely (status))
	goto BAIL;

    if (rectilinear_stroker.dash.dashed)
	status = (cairo_int_status_t)_cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
    else
	status = (cairo_int_status_t)_cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
    if (unlikely (status))
	goto BAIL;

    /* As we incrementally tessellate, we do not eliminate self-intersections */
    status = (cairo_int_status_t)_cairo_bentley_ottmann_tessellate_boxes (boxes,
						      CAIRO_FILL_RULE_WINDING,
						      boxes);
    if (unlikely (status))
	goto BAIL;

done:
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;

BAIL:
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
    _cairo_boxes_clear (boxes);
    return status;
}
Ejemplo n.º 5
0
static cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t	*path,
				      cairo_stroke_style_t	*stroke_style,
				      const cairo_matrix_t	*ctm,
				      cairo_traps_t		*traps)
{
    cairo_rectilinear_stroker_t rectilinear_stroker;
    cairo_int_status_t status;

    /* This special-case rectilinear stroker only supports
     * miter-joined lines (not curves) and a translation-only matrix
     * (though it could probably be extended to support a matrix with
     * uniform, integer scaling).
     *
     * It also only supports horizontal and vertical line_to
     * elements. But we don't catch that here, but instead return
     * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
     * non-rectilinear line_to is encountered.
     */
    if (path->has_curve_to)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    if (stroke_style->line_join	!= CAIRO_LINE_JOIN_MITER)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    /* If the miter limit turns right angles into bevels, then we
     * can't use this optimization. Remember, the ratio is
     * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2,
     * which we round for safety. */
    if (stroke_style->miter_limit < M_SQRT2)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
	   stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }
    if (! (_cairo_matrix_is_identity (ctm) ||
	   _cairo_matrix_is_translation (ctm)))
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    _cairo_rectilinear_stroker_init (&rectilinear_stroker,
				     stroke_style,
				     ctm,
				     traps);
    if (traps->has_limits) {
	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
					  &traps->limits);
    }

    status = _cairo_path_fixed_interpret (path,
					  CAIRO_DIRECTION_FORWARD,
					  _cairo_rectilinear_stroker_move_to,
					  rectilinear_stroker.dash.dashed ?
					  _cairo_rectilinear_stroker_line_to_dashed :
					  _cairo_rectilinear_stroker_line_to,
					  NULL,
					  _cairo_rectilinear_stroker_close_path,
					  &rectilinear_stroker);
    if (unlikely (status))
	goto BAIL;

    if (rectilinear_stroker.dash.dashed)
	status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
    else
	status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);

BAIL:
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);

    if (unlikely (status))
	_cairo_traps_clear (traps);

    return status;
}