summaryrefslogtreecommitdiff
path: root/src/cairo-polygon.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-08-28 10:05:52 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-08-29 08:08:33 +0100
commit3f12d9ec5db1ac372742c3c03408bdaeaffdc1e4 (patch)
treea46be582bac6364db75df1c5c32ef79ab2538e2f /src/cairo-polygon.c
parent2457c4bedef0447f7bff9b54dba96126010917ac (diff)
downloadcairo-3f12d9ec5db1ac372742c3c03408bdaeaffdc1e4.tar.gz
[clip] Use geometric clipping for unaligned clips
For the simple cases where the clip is an unaligned box (or boxes), apply the clip directly to the geometry and avoid having to use an intermediate clip-mask.
Diffstat (limited to 'src/cairo-polygon.c')
-rw-r--r--src/cairo-polygon.c329
1 files changed, 182 insertions, 147 deletions
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index a8addff2e..fdc5c92d3 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -50,7 +50,7 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->has_current_point = FALSE;
polygon->has_current_edge = FALSE;
- polygon->has_limits = FALSE;
+ polygon->num_limits = 0;
polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;
@@ -58,10 +58,11 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
void
_cairo_polygon_limit (cairo_polygon_t *polygon,
- const cairo_box_t *limits)
+ const cairo_box_t *limits,
+ int num_limits)
{
- polygon->has_limits = TRUE;
- polygon->limits = *limits;
+ polygon->limits = limits;
+ polygon->num_limits = num_limits;
}
void
@@ -159,156 +160,163 @@ static void
_add_clipped_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2,
- int dir)
+ const int top, const int bottom,
+ const int dir)
{
cairo_point_t p[2];
int top_y, bot_y;
+ int n;
- if (p1->x <= polygon->limits.p1.x && p2->x <= polygon->limits.p1.x)
- {
- p[0].x = polygon->limits.p1.x;
- p[0].y = polygon->limits.p1.y;
- top_y = p1->y;
- if (top_y < p[0].y)
- top_y = p[0].y;
-
- p[1].x = polygon->limits.p1.x;
- p[1].y = polygon->limits.p2.y;
- bot_y = p2->y;
- if (bot_y > p[1].y)
- bot_y = p[1].y;
-
- _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
- }
- else if (p1->x >= polygon->limits.p2.x && p2->x >= polygon->limits.p2.x)
- {
- p[0].x = polygon->limits.p2.x;
- p[0].y = polygon->limits.p1.y;
- top_y = p1->y;
- if (top_y < p[0].y)
- top_y = p[0].y;
-
- p[1].x = polygon->limits.p2.x;
- p[1].y = polygon->limits.p2.y;
- bot_y = p2->y;
- if (bot_y > p[1].y)
- bot_y = p[1].y;
-
- _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
- }
- else if (p1->x >= polygon->limits.p1.x && p2->x >= polygon->limits.p1.x &&
- p1->x <= polygon->limits.p2.x && p2->x <= polygon->limits.p2.x)
- {
- top_y = p1->y;
- if (top_y < polygon->limits.p1.y)
- top_y = polygon->limits.p1.y;
-
- bot_y = p2->y;
- if (bot_y > polygon->limits.p2.y)
- bot_y = polygon->limits.p2.y;
-
- _add_edge (polygon, p1, p2, top_y, bot_y, dir);
- }
- else
- {
- int left_y, right_y;
- int p1_y, p2_y;
+ for (n = 0; n < polygon->num_limits; n++) {
+ const cairo_box_t *limits = &polygon->limits[n];
- left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
- polygon->limits.p1.x);
- right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
- polygon->limits.p2.x);
+ if (top >= limits->p2.y)
+ continue;
+ if (bottom <= limits->p1.y)
+ continue;
- if (left_y == right_y) /* horizontal within bounds */
- return;
+ if (p1->x <= limits->p1.x && p2->x <= limits->p1.x)
+ {
+ p[0].x = limits->p1.x;
+ p[0].y = limits->p1.y;
+ top_y = top;
+ if (top_y < p[0].y)
+ top_y = p[0].y;
+
+ p[1].x = limits->p1.x;
+ p[1].y = limits->p2.y;
+ bot_y = bottom;
+ if (bot_y > p[1].y)
+ bot_y = p[1].y;
+
+ _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
+ }
+ else if (p1->x >= limits->p2.x && p2->x >= limits->p2.x)
+ {
+ p[0].x = limits->p2.x;
+ p[0].y = limits->p1.y;
+ top_y = top;
+ if (top_y < p[0].y)
+ top_y = p[0].y;
+
+ p[1].x = limits->p2.x;
+ p[1].y = limits->p2.y;
+ bot_y = bottom;
+ if (bot_y > p[1].y)
+ bot_y = p[1].y;
+
+ _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
+ }
+ else if (p1->x >= limits->p1.x && p2->x >= limits->p1.x &&
+ p1->x <= limits->p2.x && p2->x <= limits->p2.x)
+ {
+ top_y = top;
+ if (top_y < limits->p1.y)
+ top_y = limits->p1.y;
- p1_y = p1->y;
- p2_y = p2->y;
-
- if (left_y < right_y) {
- if (p1->x < polygon->limits.p1.x && left_y > polygon->limits.p1.y)
- {
- p[0].x = polygon->limits.p1.x;
- p[0].y = polygon->limits.p1.y;
- top_y = p1_y;
- if (top_y < p[0].y)
- top_y = p[0].y;
-
- p[1].x = polygon->limits.p1.x;
- p[1].y = polygon->limits.p2.y;
- bot_y = left_y;
- if (bot_y > p[1].y)
- bot_y = p[1].y;
-
- if (bot_y > top_y)
- _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
- p1_y = bot_y;
- }
+ bot_y = bottom;
+ if (bot_y > limits->p2.y)
+ bot_y = limits->p2.y;
- if (p2->x > polygon->limits.p2.x && right_y < polygon->limits.p2.y)
- {
- p[0].x = polygon->limits.p2.x;
- p[0].y = polygon->limits.p1.y;
- top_y = right_y;
- if (top_y < p[0].y)
- top_y = p[0].y;
-
- p[1].x = polygon->limits.p2.x;
- p[1].y = polygon->limits.p2.y;
- bot_y = p2_y;
- if (bot_y > p[1].y)
- bot_y = p[1].y;
-
- if (bot_y > top_y)
- _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
- p2_y = top_y;
- }
- } else {
- if (p1->x > polygon->limits.p2.x && right_y > polygon->limits.p1.y)
- {
- p[0].x = polygon->limits.p2.x;
- p[0].y = polygon->limits.p1.y;
- top_y = p1_y;
- if (top_y < p[0].y)
- top_y = p[0].y;
-
- p[1].x = polygon->limits.p2.x;
- p[1].y = polygon->limits.p2.y;
- bot_y = right_y;
- if (bot_y > p[1].y)
- bot_y = p[1].y;
-
- if (bot_y > top_y)
- _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
- p1_y = bot_y;
- }
+ _add_edge (polygon, p1, p2, top_y, bot_y, dir);
+ }
+ else
+ {
+ int left_y, right_y;
+ int p1_y, p2_y;
- if (p2->x < polygon->limits.p1.x && left_y < polygon->limits.p2.y)
- {
- p[0].x = polygon->limits.p1.x;
- p[0].y = polygon->limits.p1.y;
- top_y = left_y;
- if (top_y < p[0].y)
- top_y = p[0].y;
-
- p[1].x = polygon->limits.p1.x;
- p[1].y = polygon->limits.p2.y;
- bot_y = p2_y;
- if (bot_y > p[1].y)
- bot_y = p[1].y;
-
- if (bot_y > top_y)
- _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
- p2_y = top_y;
+ left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+ limits->p1.x);
+ right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+ limits->p2.x);
+
+ if (left_y == right_y) /* horizontal within bounds */
+ return;
+
+ p1_y = top;
+ p2_y = bottom;
+
+ if (left_y < right_y) {
+ if (p1->x < limits->p1.x && left_y > limits->p1.y) {
+ p[0].x = limits->p1.x;
+ p[0].y = limits->p1.y;
+ top_y = p1_y;
+ if (top_y < p[0].y)
+ top_y = p[0].y;
+
+ p[1].x = limits->p1.x;
+ p[1].y = limits->p2.y;
+ bot_y = left_y;
+ if (bot_y > p[1].y)
+ bot_y = p[1].y;
+
+ if (bot_y > top_y)
+ _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
+ p1_y = bot_y;
+ }
+
+ if (p2->x > limits->p2.x && right_y < limits->p2.y) {
+ p[0].x = limits->p2.x;
+ p[0].y = limits->p1.y;
+ top_y = right_y;
+ if (top_y < p[0].y)
+ top_y = p[0].y;
+
+ p[1].x = limits->p2.x;
+ p[1].y = limits->p2.y;
+ bot_y = p2_y;
+ if (bot_y > p[1].y)
+ bot_y = p[1].y;
+
+ if (bot_y > top_y)
+ _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
+ p2_y = top_y;
+ }
+ } else {
+ if (p1->x > limits->p2.x && right_y > limits->p1.y) {
+ p[0].x = limits->p2.x;
+ p[0].y = limits->p1.y;
+ top_y = p1_y;
+ if (top_y < p[0].y)
+ top_y = p[0].y;
+
+ p[1].x = limits->p2.x;
+ p[1].y = limits->p2.y;
+ bot_y = right_y;
+ if (bot_y > p[1].y)
+ bot_y = p[1].y;
+
+ if (bot_y > top_y)
+ _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
+ p1_y = bot_y;
+ }
+
+ if (p2->x < limits->p1.x && left_y < limits->p2.y) {
+ p[0].x = limits->p1.x;
+ p[0].y = limits->p1.y;
+ top_y = left_y;
+ if (top_y < p[0].y)
+ top_y = p[0].y;
+
+ p[1].x = limits->p1.x;
+ p[1].y = limits->p2.y;
+ bot_y = p2_y;
+ if (bot_y > p[1].y)
+ bot_y = p[1].y;
+
+ if (bot_y > top_y)
+ _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
+ p2_y = top_y;
+ }
}
- }
- if (p1_y < polygon->limits.p1.y)
- p1_y = polygon->limits.p1.y;
- if (p2_y > polygon->limits.p2.y)
- p2_y = polygon->limits.p2.y;
- if (p2_y > p1_y)
- _add_edge (polygon, p1, p2, p1_y, p2_y, dir);
+ if (p1_y < limits->p1.y)
+ p1_y = limits->p1.y;
+ if (p2_y > limits->p2.y)
+ p2_y = limits->p2.y;
+ if (p2_y > p1_y)
+ _add_edge (polygon, p1, p2, p1_y, p2_y, dir);
+ }
}
}
@@ -331,14 +339,14 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon,
dir = -1;
}
- if (polygon->has_limits) {
- if (p2->y <= polygon->limits.p1.y)
+ if (polygon->num_limits) {
+ if (p2->y <= polygon->limits[0].p1.y)
return;
- if (p1->y >= polygon->limits.p2.y)
+ if (p1->y >= polygon->limits[polygon->num_limits-1].p2.y)
return;
- _add_clipped_edge (polygon, p1, p2, dir);
+ _add_clipped_edge (polygon, p1, p2, p1->y, p2->y, dir);
} else
_add_edge (polygon, p1, p2, p1->y, p2->y, dir);
}
@@ -352,6 +360,33 @@ _cairo_polygon_add_external_edge (void *polygon,
return _cairo_polygon_status (polygon);
}
+cairo_status_t
+_cairo_polygon_add_line (cairo_polygon_t *polygon,
+ const cairo_line_t *line,
+ int top, int bottom,
+ int dir)
+{
+ /* drop horizontal edges */
+ if (line->p1.y == line->p2.y)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (bottom <= top)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (polygon->num_limits) {
+ if (line->p2.y <= polygon->limits[0].p1.y)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (line->p1.y >= polygon->limits[polygon->num_limits-1].p2.y)
+ return CAIRO_STATUS_SUCCESS;
+
+ _add_clipped_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
+ } else
+ _add_edge (polygon, &line->p1, &line->p2, top, bottom, dir);
+
+ return _cairo_polygon_status (polygon);
+}
+
/* flattened path operations */
void