Пример #1
0
static cairo_status_t
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
{
    int i, j, k;
    cairo_slope_t slope_ij, slope_jk;

    i = 0;
    j = _cairo_hull_next_valid (hull, num_hull, i);
    k = _cairo_hull_next_valid (hull, num_hull, j);

    do {
	_cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
	_cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);

	/* Is the angle formed by ij and jk concave? */
	if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
	    if (i == k)
		return CAIRO_STATUS_SUCCESS;
	    hull[j].discard = 1;
	    j = i;
	    i = _cairo_hull_prev_valid (hull, num_hull, j);
	} else {
	    i = j;
	    j = k;
	    k = _cairo_hull_next_valid (hull, num_hull, j);
	}
    } while (j != 0);

    return CAIRO_STATUS_SUCCESS;
}
Пример #2
0
static int
_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
{
    cairo_slope_t in_slope, out_slope;

    _cairo_slope_init (&in_slope, &in->point, &in->cw);
    _cairo_slope_init (&out_slope, &out->point, &out->cw);

    return _cairo_slope_compare (&in_slope, &out_slope) < 0;
}
Пример #3
0
static void
_cairo_hull_init (cairo_hull_t			*hull,
	          cairo_pen_vertex_t		*vertices,
		  int				 num_vertices)
{
    cairo_point_t *p, *extremum, tmp;
    int i;

    extremum = &vertices[0].point;
    for (i = 1; i < num_vertices; i++) {
	p = &vertices[i].point;
	if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
	    extremum = p;
    }
    /* Put the extremal point at the beginning of the array */
    tmp = *extremum;
    *extremum = vertices[0].point;
    vertices[0].point = tmp;

    for (i = 0; i < num_vertices; i++) {
	hull[i].point = vertices[i].point;
	_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);

        /* give each point a unique id for later comparison */
        hull[i].id = i;

        /* Don't discard by default */
        hull[i].discard = 0;

	/* Discard all points coincident with the extremal point */
	if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
	    hull[i].discard = 1;
    }
}
Пример #4
0
static cairo_status_t
line_to (void *closure,
	 const cairo_point_t *point)
{
    struct stroker *stroker = closure;
    cairo_stroke_face_t start;
    cairo_point_t *p1 = &stroker->current_face.point;
    cairo_slope_t dev_slope;

    stroker->has_initial_sub_path = TRUE;

    if (p1->x == point->x && p1->y == point->y)
	return CAIRO_STATUS_SUCCESS;

#if DEBUG
    _cairo_contour_add_point (&stroker->path, point);
#endif

    _cairo_slope_init (&dev_slope, p1, point);
    compute_face (p1, &dev_slope, stroker, &start);

    if (stroker->has_current_face) {
	int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
					      &start.dev_vector);
	if (clockwise) {
	    clockwise = clockwise < 0;
	    /* Join with final face from previous segment */
	    if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
				    stroker->contour_tolerance) ||
		! within_tolerance (&stroker->current_face.cw, &start.cw,
				    stroker->contour_tolerance))
	    {
		outer_join (stroker, &stroker->current_face, &start, clockwise);
		inner_join (stroker, &stroker->current_face, &start, clockwise);
	    }
	}
    } else {
	if (! stroker->has_first_face) {
	    /* Save sub path's first face in case needed for closing join */
	    stroker->first_face = start;
	    stroker->has_first_face = TRUE;
	}
	stroker->has_current_face = TRUE;

	contour_add_point (stroker, &stroker->cw, &start.cw);
	contour_add_point (stroker, &stroker->ccw, &start.ccw);
    }

    stroker->current_face = start;
    stroker->current_face.point = *point;
    stroker->current_face.ccw.x += dev_slope.dx;
    stroker->current_face.ccw.y += dev_slope.dy;
    stroker->current_face.cw.x += dev_slope.dx;
    stroker->current_face.cw.y += dev_slope.dy;

    contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
    contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);

    return CAIRO_STATUS_SUCCESS;
}
Пример #5
0
static cairo_status_t
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
			       cairo_spline_t *spline,
			       cairo_direction_t dir,
			       cairo_polygon_t *polygon)
{
    int i;
    cairo_status_t status;
    int start, stop, step;
    int active = 0;
    cairo_point_t hull_point;
    cairo_slope_t slope, initial_slope, final_slope;
    cairo_point_t *point = spline->points;
    int num_points = spline->num_points;

    if (dir == CAIRO_DIRECTION_FORWARD) {
	start = 0;
	stop = num_points;
	step = 1;
	initial_slope = spline->initial_slope;
	final_slope = spline->final_slope;
    } else {
	start = num_points - 1;
	stop = -1;
	step = -1;
	initial_slope = spline->final_slope;
	initial_slope.dx = -initial_slope.dx;
	initial_slope.dy = -initial_slope.dy;
	final_slope = spline->initial_slope;
	final_slope.dx = -final_slope.dx; 
	final_slope.dy = -final_slope.dy; 
    }

    _cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);

    i = start;
    while (i != stop) {
	hull_point.x = point[i].x + pen->vertices[active].point.x;
	hull_point.y = point[i].y + pen->vertices[active].point.y;
	status = _cairo_polygon_line_to (polygon, &hull_point);
	if (status)
	    return status;

	if (i + step == stop)
	    slope = final_slope;
	else
	    _cairo_slope_init (&slope, &point[i], &point[i+step]);
	if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
	    if (++active == pen->num_vertices)
		active = 0;
	} else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
	    if (--active == -1)
		active = pen->num_vertices - 1;
	} else {
	    i += step;
	}
    }

    return CAIRO_STATUS_SUCCESS;
}
Пример #6
0
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen)
{
    int i, i_prev;
    cairo_pen_vertex_t *prev, *v, *next;

    for (i=0, i_prev = pen->num_vertices - 1;
	 i < pen->num_vertices;
	 i_prev = i++) {
	prev = &pen->vertices[i_prev];
	v = &pen->vertices[i];
	next = &pen->vertices[(i + 1) % pen->num_vertices];

	_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
	_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
    }
}
Пример #7
0
cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon,
			const cairo_point_t *point)
{
    /* squash collinear edges */
    if (polygon->has_current_edge) {
	if (polygon->current_point.x != point->x ||
	    polygon->current_point.y != point->y)
	{
	    cairo_slope_t this;

	    _cairo_slope_init (&this, &polygon->current_point, point);
	    if (_cairo_slope_equal (&polygon->current_edge, &this)) {
		polygon->current_point = *point;
		return CAIRO_STATUS_SUCCESS;
	    }

	    _cairo_polygon_add_edge (polygon,
				     &polygon->last_point,
				     &polygon->current_point);

	    polygon->last_point = polygon->current_point;
	    polygon->current_edge = this;
	}
    } else if (polygon->has_current_point) {
	if (polygon->current_point.x != point->x ||
	    polygon->current_point.y != point->y)
	{
	    polygon->last_point = polygon->current_point;
	    _cairo_slope_init (&polygon->current_edge,
			       &polygon->last_point,
			       point);
	    polygon->has_current_edge = TRUE;
	}
    } else {
	polygon->first_point = *point;
	polygon->has_current_point = TRUE;
    }

    polygon->current_point = *point;
    return polygon->status;
}
Пример #8
0
cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
		    cairo_spline_add_point_func_t add_point_func,
		    void *closure,
		    const cairo_point_t *a, const cairo_point_t *b,
		    const cairo_point_t *c, const cairo_point_t *d)
{
    spline->add_point_func = add_point_func;
    spline->closure = closure;

    spline->knots.a = *a;
    spline->knots.b = *b;
    spline->knots.c = *c;
    spline->knots.d = *d;

    if (a->x != b->x || a->y != b->y)
	_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.b);
    else if (a->x != c->x || a->y != c->y)
	_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.c);
    else if (a->x != d->x || a->y != d->y)
	_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d);
    else
	return FALSE;

    if (c->x != d->x || c->y != d->y)
	_cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d);
    else if (b->x != d->x || b->y != d->y)
	_cairo_slope_init (&spline->final_slope, &spline->knots.b, &spline->knots.d);
    else
	_cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d);

    return TRUE;
}
Пример #9
0
cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
		    cairo_spline_add_point_func_t add_point_func,
		    void *closure,
		    const cairo_point_t *a, const cairo_point_t *b,
		    const cairo_point_t *c, const cairo_point_t *d)
{
    /* If both tangents are zero, this is just a straight line */
    if (a->x == b->x && a->y == b->y && c->x == d->x && c->y == d->y)
	return FALSE;

    spline->add_point_func = add_point_func;
    spline->closure = closure;

    spline->knots.a = *a;
    spline->knots.b = *b;
    spline->knots.c = *c;
    spline->knots.d = *d;

    if (a->x != b->x || a->y != b->y)
	_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.b);
    else if (a->x != c->x || a->y != c->y)
	_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.c);
    else if (a->x != d->x || a->y != d->y)
	_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d);
    else
	return FALSE;

    if (c->x != d->x || c->y != d->y)
	_cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d);
    else if (b->x != d->x || b->y != d->y)
	_cairo_slope_init (&spline->final_slope, &spline->knots.b, &spline->knots.d);
    else
	return FALSE; /* just treat this as a straight-line from a -> d */

    /* XXX if the initial, final and vector are all equal, this is just a line */

    return TRUE;
}
Пример #10
0
static cairo_status_t
_cairo_stroker_line_to (void *closure,
			const cairo_point_t *point)
{
    cairo_stroker_t *stroker = closure;
    cairo_stroke_face_t start, end;
    cairo_point_t *p1 = &stroker->current_point;
    cairo_slope_t dev_slope;
    double slope_dx, slope_dy;
    cairo_status_t status;

    stroker->has_initial_sub_path = TRUE;

    if (p1->x == point->x && p1->y == point->y)
	return CAIRO_STATUS_SUCCESS;

    _cairo_slope_init (&dev_slope, p1, point);
    slope_dx = _cairo_fixed_to_double (point->x - p1->x);
    slope_dy = _cairo_fixed_to_double (point->y - p1->y);
    _compute_normalized_device_slope (&slope_dx, &slope_dy,
				      stroker->ctm_inverse, NULL);

    status = _cairo_stroker_add_sub_edge (stroker,
					  p1, point,
					  &dev_slope,
					  slope_dx, slope_dy,
					  &start, &end);
    if (unlikely (status))
	return status;

    if (stroker->has_current_face) {
	/* Join with final face from previous segment */
	status = _cairo_stroker_join (stroker,
				      &stroker->current_face,
				      &start);
	if (unlikely (status))
	    return status;
    } else if (! stroker->has_first_face) {
	/* Save sub path's first face in case needed for closing join */
	stroker->first_face = start;
	stroker->has_first_face = TRUE;
    }
    stroker->current_face = end;
    stroker->has_current_face = TRUE;

    stroker->current_point = *point;

    return CAIRO_STATUS_SUCCESS;
}
Пример #11
0
static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
    cairo_slope_t slope_left, slope_pt, slope_right;

    if (t->top > pt->y)
	return FALSE;
    if (t->bottom < pt->y)
	return FALSE;

    _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
    _cairo_slope_init (&slope_pt, &t->left.p1, pt);

    if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
	return FALSE;

    _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
    _cairo_slope_init (&slope_pt, &t->right.p1, pt);

    if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
	return FALSE;

    return TRUE;
}
Пример #12
0
static cairo_status_t
line_to (void *closure,
         const cairo_point_t *point)
{
    struct stroker *stroker = closure;
    cairo_stroke_face_t start;
    cairo_point_t *p1 = &stroker->current_face.point;
    cairo_slope_t dev_slope;

    stroker->has_sub_path = TRUE;

    if (p1->x == point->x && p1->y == point->y)
        return CAIRO_STATUS_SUCCESS;

    _cairo_slope_init (&dev_slope, p1, point);
    compute_face (p1, &dev_slope, stroker, &start);

    if (stroker->has_current_face) {
        int clockwise = join_is_clockwise (&stroker->current_face, &start);
        /* Join with final face from previous segment */
        outer_join (stroker, &stroker->current_face, &start, clockwise);
        inner_join (stroker, &stroker->current_face, &start, clockwise);
    } else {
        if (! stroker->has_first_face) {
            /* Save sub path's first face in case needed for closing join */
            stroker->first_face = start;
            _cairo_tristrip_move_to (stroker->strip, &start.cw);
            stroker->has_first_face = TRUE;
        }
        stroker->has_current_face = TRUE;

        _cairo_tristrip_add_point (stroker->strip, &start.cw);
        _cairo_tristrip_add_point (stroker->strip, &start.ccw);
    }

    stroker->current_face = start;
    stroker->current_face.point = *point;
    stroker->current_face.ccw.x += dev_slope.dx;
    stroker->current_face.ccw.y += dev_slope.dy;
    stroker->current_face.cw.x += dev_slope.dx;
    stroker->current_face.cw.y += dev_slope.dy;

    _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.cw);
    _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.ccw);

    return CAIRO_STATUS_SUCCESS;
}
Пример #13
0
static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline,
			 const cairo_point_t *point,
			 const cairo_point_t *knot)
{
    cairo_point_t *prev;
    cairo_slope_t slope;

    prev = &spline->last_point;
    if (prev->x == point->x && prev->y == point->y)
	return CAIRO_STATUS_SUCCESS;

    _cairo_slope_init (&slope, point, knot);

    spline->last_point = *point;
    return spline->add_point_func (spline->closure, point, &slope);
}
Пример #14
0
void
_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
				     const cairo_point_t q[4])
{
    int a, b, c, d;
    int i;
    cairo_slope_t ab, ad;
    cairo_bool_t b_left_of_d;
    cairo_line_t left;
    cairo_line_t right;

    /* Choose a as a point with minimal y */
    a = 0;
    for (i = 1; i < 4; i++)
	if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
	    a = i;

    /* b and d are adjacent to a, while c is opposite */
    b = (a + 1) % 4;
    c = (a + 2) % 4;
    d = (a + 3) % 4;

    /* Choose between b and d so that b.y is less than d.y */
    if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
	b = (a + 3) % 4;
	d = (a + 1) % 4;
    }

    /* Without freedom left to choose anything else, we have four
     * cases to tessellate.
     *
     * First, we have to determine the Y-axis sort of the four
     * vertices, (either abcd or abdc). After that we need to detemine
     * which edges will be "left" and which will be "right" in the
     * resulting trapezoids. This can be determined by computing a
     * slope comparison of ab and ad to determine if b is left of d or
     * not.
     *
     * Note that "left of" here is in the sense of which edges should
     * be the left vs. right edges of the trapezoid. In particular, b
     * left of d does *not* mean that b.x is less than d.x.
     *
     * This should hopefully be made clear in the lame ASCII art
     * below. Since the same slope comparison is used in all cases, we
     * compute it before testing for the Y-value sort. */

    /* Note: If a == b then the ab slope doesn't give us any
     * information. In that case, we can replace it with the ac (or
     * equivalenly the bc) slope which gives us exactly the same
     * information we need. At worst the names of the identifiers ab
     * and b_left_of_d are inaccurate in this case, (would be ac, and
     * c_left_of_d). */
    if (q[a].x == q[b].x && q[a].y == q[b].y)
	_cairo_slope_init (&ab, &q[a], &q[c]);
    else
	_cairo_slope_init (&ab, &q[a], &q[b]);

    _cairo_slope_init (&ad, &q[a], &q[d]);

    b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;

    if (q[c].y <= q[d].y) {
	if (b_left_of_d) {
	    /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
	     *
	     *                      top bot left right
	     *        _a  a  a
	     *      / /  /|  |\      a.y b.y  ab   ad
	     *     b /  b |  b \
	     *    / /   | |   \ \    b.y c.y  bc   ad
	     *   c /    c |    c \
	     *  | /      \|     \ \  c.y d.y  cd   ad
	     *  d         d       d
	     */
	    left.p1  = q[a]; left.p2  = q[b];
	    right.p1 = q[a]; right.p2 = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    left.p1  = q[b]; left.p2  = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
	    left.p1  = q[c]; left.p2  = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
	} else {
	    /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
	     *
	     *       a  a  a_
	     *      /|  |\  \ \     a.y b.y  ad  ab
	     *     / b  | b  \ b
	     *    / /   | |   \ \   b.y c.y  ad  bc
	     *   / c    | c    \ c
	     *  / /     |/      \ | c.y d.y  ad  cd
	     *  d       d         d
	     */
	    left.p1  = q[a]; left.p2  = q[d];
	    right.p1 = q[a]; right.p2 = q[b];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    right.p1 = q[b]; right.p2 = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
	    right.p1 = q[c]; right.p2 = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
	}
    } else {
	if (b_left_of_d) {
	    /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
	     *
	     *        a   a     a
	     *       //  / \    |\     a.y b.y  ab  ad
	     *     /b/  b   \   b \
	     *    / /    \   \   \ \   b.y d.y  bc  ad
	     *   /d/      \   d   \ d
	     *  //         \ /     \|  d.y c.y  bc  dc
	     *  c           c       c
	     */
	    left.p1  = q[a]; left.p2  = q[b];
	    right.p1 = q[a]; right.p2 = q[d];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    left.p1  = q[b]; left.p2  = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
	    right.p1 = q[d]; right.p2 = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
	} else {
	    /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
	     *
	     *      a     a   a
	     *     /|    / \  \\       a.y b.y  ad  ab
	     *    / b   /   b  \b\
	     *   / /   /   /    \ \    b.y d.y  ad  bc
	     *  d /   d   /	 \d\
	     *  |/     \ /         \\  d.y c.y  dc  bc
	     *  c       c	   c
	     */
	    left.p1  = q[a]; left.p2  = q[d];
	    right.p1 = q[a]; right.p2 = q[b];
	    _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
	    right.p1 = q[b]; right.p2 = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
	    left.p1  = q[d]; left.p2  = q[c];
	    _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
	}
    }
}
Пример #15
0
static void
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
			       cairo_spline_t *spline,
			       cairo_direction_t dir,
			       cairo_polygon_t *polygon)
{
    int i;
    int start, stop, step;
    int active = 0;
    cairo_point_t hull_point;
    cairo_slope_t slope, initial_slope, final_slope;
    cairo_point_t *point = spline->points;
    int num_points = spline->num_points;

    if (dir == CAIRO_DIRECTION_FORWARD) {
	start = 0;
	stop = num_points;
	step = 1;
	initial_slope = spline->initial_slope;
	final_slope = spline->final_slope;
    } else {
	start = num_points - 1;
	stop = -1;
	step = -1;
	initial_slope = spline->final_slope;
	initial_slope.dx = -initial_slope.dx;
	initial_slope.dy = -initial_slope.dy;
	final_slope = spline->initial_slope;
	final_slope.dx = -final_slope.dx;
	final_slope.dy = -final_slope.dy;
    }

    _cairo_pen_find_active_cw_vertex_index (pen,
	                                    &initial_slope,
					    &active);

    i = start;
    while (i != stop) {
	hull_point.x = point[i].x + pen->vertices[active].point.x;
	hull_point.y = point[i].y + pen->vertices[active].point.y;

	_cairo_polygon_line_to (polygon, &hull_point);

	if (i + step == stop)
	    slope = final_slope;
	else
	    _cairo_slope_init (&slope, &point[i], &point[i+step]);

	/* The strict inequalities here ensure that if a spline slope
	 * compares identically with either of the slopes of the
	 * active vertex, then it remains the active vertex. This is
	 * very important since otherwise we can trigger an infinite
	 * loop in the case of a degenerate pen, (a line), where
	 * neither vertex considers itself active for the slope---one
	 * will consider it as equal and reject, and the other will
	 * consider it unequal and reject. This is due to the inherent
	 * ambiguity when comparing slopes that differ by exactly
	 * pi. */
	if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_ccw) > 0) {
	    if (++active == pen->num_vertices)
		active = 0;
	} else if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_cw) < 0) {
	    if (--active == -1)
		active = pen->num_vertices - 1;
	} else {
	    i += step;
	}
    }
}
Пример #16
0
/*
 * Dashed lines.  Cap each dash end, join around turns when on
 */
static cairo_status_t
_cairo_stroker_line_to_dashed (void *closure,
			       const cairo_point_t *p2)
{
    cairo_stroker_t *stroker = closure;
    double mag, remain, step_length = 0;
    double slope_dx, slope_dy;
    double dx2, dy2;
    cairo_stroke_face_t sub_start, sub_end;
    cairo_point_t *p1 = &stroker->current_point;
    cairo_slope_t dev_slope;
    cairo_line_t segment;
    cairo_bool_t fully_in_bounds;
    cairo_status_t status;

    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;

    if (p1->x == p2->x && p1->y == p2->y)
	return CAIRO_STATUS_SUCCESS;

    fully_in_bounds = TRUE;
    if (stroker->has_bounds &&
	(! _cairo_box_contains_point (&stroker->bounds, p1) ||
	 ! _cairo_box_contains_point (&stroker->bounds, p2)))
    {
	fully_in_bounds = FALSE;
    }

    _cairo_slope_init (&dev_slope, p1, p2);

    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);

    if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
					    stroker->ctm_inverse, &mag))
    {
	return CAIRO_STATUS_SUCCESS;
    }

    remain = mag;
    segment.p1 = *p1;
    while (remain) {
	step_length = MIN (stroker->dash.dash_remain, remain);
	remain -= step_length;
	dx2 = slope_dx * (mag - remain);
	dy2 = slope_dy * (mag - remain);
	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;

	if (stroker->dash.dash_on &&
	    (fully_in_bounds ||
	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
	     _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
	{
	    status = _cairo_stroker_add_sub_edge (stroker,
						  &segment.p1, &segment.p2,
						  &dev_slope,
						  slope_dx, slope_dy,
						  &sub_start, &sub_end);
	    if (unlikely (status))
		return status;

	    if (stroker->has_current_face)
	    {
		/* Join with final face from previous segment */
		status = _cairo_stroker_join (stroker,
					      &stroker->current_face,
					      &sub_start);
		if (unlikely (status))
		    return status;

		stroker->has_current_face = FALSE;
	    }
	    else if (! stroker->has_first_face &&
		       stroker->dash.dash_starts_on)
	    {
		/* Save sub path's first face in case needed for closing join */
		stroker->first_face = sub_start;
		stroker->has_first_face = TRUE;
	    }
	    else
	    {
		/* Cap dash start if not connecting to a previous segment */
		status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
		if (unlikely (status))
		    return status;
	    }

	    if (remain) {
		/* Cap dash end if not at end of segment */
		status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
		if (unlikely (status))
		    return status;
	    } else {
		stroker->current_face = sub_end;
		stroker->has_current_face = TRUE;
	    }
	} else {
	    if (stroker->has_current_face) {
		/* Cap final face from previous segment */
		status = _cairo_stroker_add_trailing_cap (stroker,
							  &stroker->current_face);
		if (unlikely (status))
		    return status;

		stroker->has_current_face = FALSE;
	    }
	}

	_cairo_stroker_dash_step (&stroker->dash, step_length);
	segment.p1 = segment.p2;
    }

    if (stroker->dash.dash_on && ! stroker->has_current_face) {
	/* This segment ends on a transition to dash_on, compute a new face
	 * and add cap for the beginning of the next dash_on step.
	 *
	 * Note: this will create a degenerate cap if this is not the last line
	 * in the path. Whether this behaviour is desirable or not is debatable.
	 * On one side these degenerate caps can not be reproduced with regular
	 * path stroking.
	 * On the other hand, Acroread 7 also produces the degenerate caps.
	 */
	_compute_face (p2, &dev_slope,
		       slope_dx, slope_dy,
		       stroker,
		       &stroker->current_face);

	status = _cairo_stroker_add_leading_cap (stroker,
						 &stroker->current_face);
	if (unlikely (status))
	    return status;

	stroker->has_current_face = TRUE;
    }

    stroker->current_point = *p2;

    return CAIRO_STATUS_SUCCESS;
}
Пример #17
0
static cairo_status_t
_cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker)
{
    cairo_status_t status;
    cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
    cairo_fixed_t half_line_width = stroker->half_line_width;
    int i;

    for (i = 0; i < stroker->num_segments; i++) {
	cairo_point_t *a, *b;
	cairo_bool_t is_horizontal;

	a = &stroker->segments[i].p1;
	b = &stroker->segments[i].p2;

	is_horizontal = stroker->segments[i].is_horizontal;

	/* Handle the joins for a potentially degenerate segment. */
	if (line_cap == CAIRO_LINE_CAP_BUTT &&
	    stroker->segments[i].has_join &&
	    (i != stroker->num_segments - 1 ||
	     (! stroker->open_sub_path && stroker->dash.dash_starts_on)))
	{
	    cairo_point_t p1 = stroker->segments[i].p1;
	    cairo_point_t p2 = stroker->segments[i].p2;
	    cairo_slope_t out_slope;
	    int j = (i + 1) % stroker->num_segments;

	    _cairo_slope_init (&out_slope,
			       &stroker->segments[j].p1,
			       &stroker->segments[j].p2);

	    if (is_horizontal) {
		if (p1.x <= p2.x) {
		    p1.x = p2.x;
		    p2.x += half_line_width;
		} else {
		    p1.x = p2.x - half_line_width;
		}
		if (out_slope.dy >= 0)
		    p1.y -= half_line_width;
		if (out_slope.dy <= 0)
		    p2.y += half_line_width;
	    } else {
		if (p1.y <= p2.y) {
		    p1.y = p2.y;
		    p2.y += half_line_width;
		} else {
		    p1.y = p2.y - half_line_width;
		}
		if (out_slope.dx >= 0)
		    p1.x -= half_line_width;
		if (out_slope.dx <= 0)
		    p2.x += half_line_width;
	    }

	    status = _cairo_traps_tessellate_rectangle (stroker->traps,
							&p1, &p2);
	    if (unlikely (status))
		return status;
	}

	/* Perform the adjustments of the endpoints. */
	if (is_horizontal) {
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
		if (a->x <= b->x) {
		    a->x -= half_line_width;
		    b->x += half_line_width;
		} else {
		    a->x += half_line_width;
		    b->x -= half_line_width;
		}
	    }

	    if (a->x > b->x) {
		cairo_point_t *t;

		t = a;
		a = b;
		b = t;
	    }

	    a->y -= half_line_width;
	    b->y += half_line_width;
	} else {
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
		if (a->y <= b->y) {
		    a->y -= half_line_width;
		    b->y += half_line_width;
		} else {
		    a->y += half_line_width;
		    b->y -= half_line_width;
		}
	    }

	    if (a->y > b->y) {
		cairo_point_t *t;

		t = a;
		a = b;
		b = t;
	    }

	    a->x -= half_line_width;
	    b->x += half_line_width;
	}

	if (a->x == b->x && a->y == b->y)
	    continue;

	status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b);
	if (unlikely (status))
	    return status;
    }

    stroker->num_segments = 0;

    return CAIRO_STATUS_SUCCESS;
}
Пример #18
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_spline_add_point_func_t line_to;
    cairo_spline_add_point_func_t spline_to;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    line_to = stroker->dash.dashed ?
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to;

    /* spline_to is only capable of rendering non-degenerate splines. */
    spline_to = stroker->dash.dashed ?
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
	(cairo_spline_add_point_func_t) _cairo_stroker_spline_to;

    if (! _cairo_spline_init (&spline,
			      spline_to,
			      stroker,
			      &stroker->current_point, b, c, d))
    {
	cairo_slope_t fallback_slope;
	_cairo_slope_init (&fallback_slope, &stroker->current_point, d);
	return line_to (closure, d, &fallback_slope);
    }

    /* 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;
}
Пример #19
0
static cairo_status_t
_cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker)
{
    cairo_status_t status;
    cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
    cairo_fixed_t half_line_x = stroker->half_line_x;
    cairo_fixed_t half_line_y = stroker->half_line_y;
    int i;

    for (i = 0; i < stroker->num_segments; i++) {
	cairo_point_t *a, *b;
	cairo_bool_t is_horizontal;
	cairo_box_t box;

	a = &stroker->segments[i].p1;
	b = &stroker->segments[i].p2;

	is_horizontal = stroker->segments[i].flags & HORIZONTAL;

	/* Handle the joins for a potentially degenerate segment. */
	if (line_cap == CAIRO_LINE_CAP_BUTT &&
	    stroker->segments[i].flags & JOIN &&
	    (i != stroker->num_segments - 1 ||
	     (! stroker->open_sub_path && stroker->dash.dash_starts_on)))
	{
	    cairo_slope_t out_slope;
	    int j = (i + 1) % stroker->num_segments;
	    cairo_bool_t forwards = !!(stroker->segments[i].flags & FORWARDS);

	    _cairo_slope_init (&out_slope,
			       &stroker->segments[j].p1,
			       &stroker->segments[j].p2);
	    box.p2 = box.p1 = stroker->segments[i].p2;

	    if (is_horizontal) {
		if (forwards)
		    box.p2.x += half_line_x;
		else
		    box.p1.x -= half_line_x;

		if (out_slope.dy > 0)
		    box.p1.y -= half_line_y;
		else
		    box.p2.y += half_line_y;
	    } else {
		if (forwards)
		    box.p2.y += half_line_y;
		else
		    box.p1.y -= half_line_y;

		if (out_slope.dx > 0)
		    box.p1.x -= half_line_x;
		else
		    box.p2.x += half_line_x;
	    }

	    status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box);
	    if (unlikely (status))
		return status;
	}

	/* Perform the adjustments of the endpoints. */
	if (is_horizontal) {
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
		if (a->x <= b->x) {
		    a->x -= half_line_x;
		    b->x += half_line_x;
		} else {
		    a->x += half_line_x;
		    b->x -= half_line_x;
		}
	    }

	    a->y += half_line_y;
	    b->y -= half_line_y;
	} else {
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
		if (a->y <= b->y) {
		    a->y -= half_line_y;
		    b->y += half_line_y;
		} else {
		    a->y += half_line_y;
		    b->y -= half_line_y;
		}
	    }

	    a->x += half_line_x;
	    b->x -= half_line_x;
	}

	if (a->x == b->x && a->y == b->y)
	    continue;

	if (a->x < b->x) {
	    box.p1.x = a->x;
	    box.p2.x = b->x;
	} else {
	    box.p1.x = b->x;
	    box.p2.x = a->x;
	}
	if (a->y < b->y) {
	    box.p1.y = a->y;
	    box.p2.y = b->y;
	} else {
	    box.p1.y = b->y;
	    box.p2.y = a->y;
	}

	status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box);
	if (unlikely (status))
	    return status;
    }

    stroker->num_segments = 0;

    return CAIRO_STATUS_SUCCESS;
}