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; }
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; }
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); }
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); }
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; }
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); }
/* 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; }
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; }