static void
edge_end_box (sweep_line_t *sweep_line, edge_t *left, int32_t bot)
{
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
    if (likely (left->top < bot)) {
	if (sweep_line->do_traps) {
	    cairo_line_t _left = {
		{ left->x, left->top },
		{ left->x, bot },
	    }, _right = {
		{ left->right->x, left->top },
		{ left->right->x, bot },
	    };
	    _cairo_traps_add_trap (sweep_line->container, left->top, bot, &_left, &_right);
	    status = _cairo_traps_status ((cairo_traps_t *) sweep_line->container);
	} else {
	    cairo_box_t box;

	    box.p1.x = left->x;
	    box.p1.y = left->top;
	    box.p2.x = left->right->x;
	    box.p2.y = bot;

	    status = _cairo_boxes_add (sweep_line->container,
				       CAIRO_ANTIALIAS_DEFAULT,
				       &box);
	}
    }
    if (unlikely (status))
	longjmp (sweep_line->unwind, status);

    left->right = NULL;
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t	*left,
			 int32_t		 bot,
			 cairo_bool_t		 do_traps,
			 void			*container)
{
    cairo_bo_trap_t *trap = &left->deferred_trap;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
    if (likely (trap->top < bot)) {
	if (do_traps) {
	    _cairo_traps_add_trap (container,
				   trap->top, bot,
				   &left->edge.line, &trap->right->edge.line);
	    status =  _cairo_traps_status ((cairo_traps_t *) container);
	} else {
	    cairo_box_t box;

	    box.p1.x = left->edge.line.p1.x;
	    box.p1.y = trap->top;
	    box.p2.x = trap->right->edge.line.p1.x;
	    box.p2.y = bot;
	    status = _cairo_boxes_add (container, CAIRO_ANTIALIAS_DEFAULT, &box);
	}
    }

    trap->right = NULL;

    return status;
}
Esempio n. 3
0
static cairo_status_t
span_to_traps (void *abstract_renderer, int y, int h,
	       const cairo_half_open_span_t *spans, unsigned num_spans)
{
    struct cairo_trap_renderer *r = abstract_renderer;
    cairo_fixed_t top, bot;

    if (num_spans == 0)
	return CAIRO_STATUS_SUCCESS;

    top = _cairo_fixed_from_int (y);
    bot = _cairo_fixed_from_int (y + h);
    do {
	if (spans[0].coverage) {
	    cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x);
	    cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x);
	    cairo_line_t left = { { x0, top }, { x0, bot } },
			 right = { { x1, top }, { x1, bot } };
	    _cairo_traps_add_trap (r->traps, top, bot, &left, &right);
	}
	spans++;
    } while (--num_spans > 1);

    return CAIRO_STATUS_SUCCESS;
}
Esempio n. 4
0
static cairo_status_t
_cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
				   cairo_point_t left_p1, cairo_point_t left_p2,
				   cairo_point_t right_p1, cairo_point_t right_p2)
{
    cairo_line_t left;
    cairo_line_t right;

    left.p1 = left_p1;
    left.p2 = left_p2;

    right.p1 = right_p1;
    right.p2 = right_p2;

    return _cairo_traps_add_trap (traps, top, bottom, &left, &right);
}
Esempio n. 5
0
cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
				   const cairo_point_t *top_left,
				   const cairo_point_t *bottom_right)
{
    cairo_line_t left;
    cairo_line_t right;

     left.p1.x =  left.p2.x = top_left->x;
     left.p1.y = right.p1.y = top_left->y;
    right.p1.x = right.p2.x = bottom_right->x;
     left.p2.y = right.p2.y = bottom_right->y;

    _cairo_traps_add_trap (traps, top_left->y, bottom_right->y, &left, &right);

    return traps->status;
}
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t	*left,
			 int32_t		 bot,
			 cairo_traps_t	        *traps)
{
    cairo_bo_trap_t *trap = &left->deferred_trap;

    /* Only emit (trivial) non-degenerate trapezoids with positive height. */
    if (likely (trap->top < bot)) {
	_cairo_traps_add_trap (traps,
			       trap->top, bot,
			       &left->edge.line, &trap->right->edge.line);
    }

    trap->right = NULL;

    return _cairo_traps_status (traps);
}
Esempio n. 7
0
cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
				   const cairo_point_t *top_left,
				   const cairo_point_t *bottom_right)
{
    cairo_line_t left;
    cairo_line_t right;
    cairo_fixed_t top, bottom;

    if (top_left->y == bottom_right->y)
	return CAIRO_STATUS_SUCCESS;

    if (top_left->x == bottom_right->x)
	return CAIRO_STATUS_SUCCESS;

     left.p1.x =  left.p2.x = top_left->x;
     left.p1.y = right.p1.y = top_left->y;
    right.p1.x = right.p2.x = bottom_right->x;
     left.p2.y = right.p2.y = bottom_right->y;

     top = top_left->y;
     bottom = bottom_right->y;

    if (traps->num_limits) {
	cairo_bool_t reversed;
	int n;

	if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
	    return CAIRO_STATUS_SUCCESS;

	/* support counter-clockwise winding for rectangular tessellation */
	reversed = top_left->x > bottom_right->x;
	if (reversed) {
	    right.p1.x = right.p2.x = top_left->x;
	    left.p1.x = left.p2.x = bottom_right->x;
	}

	if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
	    return CAIRO_STATUS_SUCCESS;

	for (n = 0; n < traps->num_limits; n++) {
	    const cairo_box_t *limits = &traps->limits[n];
	    cairo_line_t _left, _right;
	    cairo_fixed_t _top, _bottom;

	    if (top >= limits->p2.y)
		continue;
	    if (bottom <= limits->p1.y)
		continue;

	    /* Trivially reject if trapezoid is entirely to the right or
	     * to the left of the limits. */
	    if (left.p1.x >= limits->p2.x)
		continue;
	    if (right.p1.x <= limits->p1.x)
		continue;

	    /* Otherwise, clip the trapezoid to the limits. */
	    _top = top;
	    if (_top < limits->p1.y)
		_top = limits->p1.y;

	    _bottom = bottom;
	    if (_bottom > limits->p2.y)
		_bottom = limits->p2.y;

	    if (_bottom <= _top)
		continue;

	    _left = left;
	    if (_left.p1.x < limits->p1.x) {
		_left.p1.x = limits->p1.x;
		_left.p1.y = limits->p1.y;
		_left.p2.x = limits->p1.x;
		_left.p2.y = limits->p2.y;
	    }

	    _right = right;
	    if (_right.p1.x > limits->p2.x) {
		_right.p1.x = limits->p2.x;
		_right.p1.y = limits->p1.y;
		_right.p2.x = limits->p2.x;
		_right.p2.y = limits->p2.y;
	    }

	    if (left.p1.x >= right.p1.x)
		continue;

	    if (reversed)
		_cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left);
	    else
		_cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right);
	}
    } else {
	_cairo_traps_add_trap (traps, top, bottom, &left, &right);
    }

    return traps->status;
}
Esempio n. 8
0
static void
_cairo_traps_add_clipped_trap (cairo_traps_t *traps,
			       cairo_fixed_t _top, cairo_fixed_t _bottom,
			       const cairo_line_t *_left,
			       const cairo_line_t *_right)
{
    /* Note: With the goofy trapezoid specification, (where an
     * arbitrary two points on the lines can specified for the left
     * and right edges), these limit checks would not work in
     * general. For example, one can imagine a trapezoid entirely
     * within the limits, but with two points used to specify the left
     * edge entirely to the right of the limits.  Fortunately, for our
     * purposes, cairo will never generate such a crazy
     * trapezoid. Instead, cairo always uses for its points the
     * extreme positions of the edge that are visible on at least some
     * trapezoid. With this constraint, it's impossible for both
     * points to be outside the limits while the relevant edge is
     * entirely inside the limits.
     */
    if (traps->num_limits) {
	const cairo_box_t *b = &traps->bounds;
	cairo_fixed_t top = _top, bottom = _bottom;
	cairo_line_t left = *_left, right = *_right;

	/* Trivially reject if trapezoid is entirely to the right or
	 * to the left of the limits. */
	if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
	    return;

	if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
	    return;

	/* And reject if the trapezoid is entirely above or below */
	if (top >= b->p2.y || bottom <= b->p1.y)
	    return;

	/* Otherwise, clip the trapezoid to the limits. We only clip
	 * where an edge is entirely outside the limits. If we wanted
	 * to be more clever, we could handle cases where a trapezoid
	 * edge intersects the edge of the limits, but that would
	 * require slicing this trapezoid into multiple trapezoids,
	 * and I'm not sure the effort would be worth it. */
	if (top < b->p1.y)
	    top = b->p1.y;

	if (bottom > b->p2.y)
	    bottom = b->p2.y;

	if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
	    left.p1.x = left.p2.x = b->p1.x;

	if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
	    right.p1.x = right.p2.x = b->p2.x;

	/* Trivial discards for empty trapezoids that are likely to
	 * be produced by our tessellators (most notably convex_quad
	 * when given a simple rectangle).
	 */
	if (top >= bottom)
	    return;

	/* cheap colinearity check */
	if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
	    right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
	    return;

	_cairo_traps_add_trap (traps, top, bottom, &left, &right);
    } else
	_cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
}
Esempio n. 9
0
/* The algorithm here is pretty simple:

   inactive = [edges]
   y = min_p1_y (inactive)

   while (num_active || num_inactive) {
   	active = all edges containing y

	next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )

	fill_traps (active, y, next_y, fill_rule)

	y = next_y
   }

   The invariants that hold during fill_traps are:

   	All edges in active contain both y and next_y
	No edges in active intersect within y and next_y

   These invariants mean that fill_traps is as simple as sorting the
   active edges, forming a trapezoid between each adjacent pair. Then,
   either the even-odd or winding rule is used to determine whether to
   emit each of these trapezoids.

   Warning: This function obliterates the edges of the polygon provided.
*/
cairo_status_t
_cairo_traps_tessellate_polygon (cairo_traps_t		*traps,
				 cairo_polygon_t	*poly,
				 cairo_fill_rule_t	fill_rule)
{
    cairo_status_t	status;
    int 		i, active, inactive;
    cairo_fixed_t	y, y_next, intersect;
    int			in_out, num_edges = poly->num_edges;
    cairo_edge_t	*edges = poly->edges;

    if (num_edges == 0)
	return CAIRO_STATUS_SUCCESS;

    qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
    
    y = edges[0].edge.p1.y;
    active = 0;
    inactive = 0;
    while (active < num_edges) {
	while (inactive < num_edges && edges[inactive].edge.p1.y <= y)
	    inactive++;

	for (i = active; i < inactive; i++)
	    edges[i].current_x = _compute_x (&edges[i].edge, y);

	qsort (&edges[active], inactive - active,
	       sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);

	/* find next inflection point */
	y_next = edges[active].edge.p2.y;

	for (i = active; i < inactive; i++) {
	    if (edges[i].edge.p2.y < y_next)
		y_next = edges[i].edge.p2.y;
	    /* check intersect */
	    if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)
		if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,
					       &intersect))
		    if (intersect > y && intersect < y_next)
			y_next = intersect;
	}
	/* check next inactive point */
	if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)
	    y_next = edges[inactive].edge.p1.y;

	/* walk the active edges generating trapezoids */
	in_out = 0;
	for (i = active; i < inactive - 1; i++) {
	    if (fill_rule == CAIRO_FILL_RULE_WINDING) {
		if (edges[i].clockWise)
		    in_out++;
		else
		    in_out--;
		if (in_out == 0)
		    continue;
	    } else {
		in_out++;
		if ((in_out & 1) == 0)
		    continue;
	    }
	    status = _cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);
	    if (status)
		return status;
	}

	/* delete inactive edges */
	for (i = active; i < inactive; i++) {
	    if (edges[i].edge.p2.y <= y_next) {
		memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));
		active++;
	    }
	}

	y = y_next;
    }
    return CAIRO_STATUS_SUCCESS;
}
Esempio n. 10
0
cairo_status_t
_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_trap (traps, q[a].y, q[b].y, &left, &right);
	    left.p1  = q[b]; left.p2  = q[c];
	    _cairo_traps_add_trap (traps, q[b].y, q[c].y, &left, &right);
	    left.p1  = q[c]; left.p2  = q[d];
	    _cairo_traps_add_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_trap (traps, q[a].y, q[b].y, &left, &right);
	    right.p1 = q[b]; right.p2 = q[c];
	    _cairo_traps_add_trap (traps, q[b].y, q[c].y, &left, &right);
	    right.p1 = q[c]; right.p2 = q[d];
	    _cairo_traps_add_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_trap (traps, q[a].y, q[b].y, &left, &right);
	    left.p1  = q[b]; left.p2  = q[c];
	    _cairo_traps_add_trap (traps, q[b].y, q[d].y, &left, &right);
	    right.p1 = q[d]; right.p2 = q[c];
	    _cairo_traps_add_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_trap (traps, q[a].y, q[b].y, &left, &right);
	    right.p1 = q[b]; right.p2 = q[c];
	    _cairo_traps_add_trap (traps, q[b].y, q[d].y, &left, &right);
	    left.p1  = q[d]; left.p2  = q[c];
	    _cairo_traps_add_trap (traps, q[d].y, q[c].y, &left, &right);
	}
    }

    return traps->status;
}