[cairo-commit] 4 commits - src/cairo-polygon.c test/horizontal-clip.c test/horizontal-clip.ref.png test/Makefile.refs
Andrea Canciani
ranma42 at kemper.freedesktop.org
Thu Jul 28 09:11:47 PDT 2011
src/cairo-polygon.c | 205 +++++++++++++++++--------------------------
test/Makefile.refs | 4
test/horizontal-clip.c | 39 ++++----
test/horizontal-clip.ref.png |binary
4 files changed, 107 insertions(+), 141 deletions(-)
New commits:
commit d7abdab931c1219314c07c0ecf21b0afef19108a
Author: Andrea Canciani <ranma42 at gmail.com>
Date: Wed Jul 27 18:58:03 2011 +0200
polygon: Fix generic case of edge clipping
The edge clipper is more complicated than it should be and contains a
subtle bug: when an edge is almost horizontal, it is always considered
as having a positive slope.
Explain what should be done and do it in a simpler way.
Fixes horizontal-clip.
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index a20e6ba..74ec9fa 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -333,97 +333,72 @@ _add_clipped_edge (cairo_polygon_t *polygon,
} else {
/* The edge and the box intersect in a generic way */
cairo_fixed_t left_y, right_y;
- int p1_y, p2_y;
- cairo_point_t p[2];
+ cairo_bool_t top_left_to_bottom_right;
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);
- p1_y = top;
- p2_y = bottom;
-
- if (left_y < right_y) {
- if (p1->x < limits->p1.x && left_y > top) {
- 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;
+ /*
+ * The edge intersects the lines corresponding to the left
+ * and right sides of the limit box at left_y and right_y,
+ * but we need to add edges for the range from top_y to
+ * bot_y.
+ *
+ * For both intersections, there are three cases:
+ *
+ * 1) It is outside the vertical range of the limit
+ * box. In this case we can simply further clip the
+ * edge we will be emitting (i.e. restrict its
+ * top/bottom limits to those of the limit box).
+ *
+ * 2) It is inside the vertical range of the limit
+ * box. In this case, we need to add the vertical edge
+ * connecting the correct vertex to the intersection,
+ * in order to preserve the winding count.
+ *
+ * 3) It is exactly on the box. In this case, do nothing.
+ *
+ * These operations restrict the active range (stored in
+ * top_y/bot_y) so that the p1-p2 edge is completely
+ * inside the box if it is clipped to this vertical range.
+ */
+
+ top_left_to_bottom_right = (p1->x < p2->x) == (p1->y < p2->y);
+
+ if (top_left_to_bottom_right) {
+ left_y = MIN (left_y, bot_y);
+ if (top_y < left_y) {
+ _add_edge (polygon, &limits->p1, &bot_left,
+ top_y, left_y, dir);
+ top_y = left_y;
}
- if (p2->x > limits->p2.x && right_y < bottom) {
- 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;
+ right_y = MAX (right_y, top_y);
+ if (bot_y > right_y) {
+ _add_edge (polygon, &top_right, &limits->p2,
+ right_y, bot_y, dir);
+ bot_y = right_y;
}
} else {
- if (p1->x > limits->p2.x && right_y > top) {
- 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;
+ right_y = MIN (right_y, bot_y);
+ if (top_y < right_y) {
+ _add_edge (polygon, &top_right, &limits->p2,
+ top_y, right_y, dir);
+ top_y = right_y;
}
- if (p2->x < limits->p1.x && left_y < bottom) {
- 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;
+ left_y = MAX (left_y, top_y);
+ if (bot_y > left_y) {
+ _add_edge (polygon, &limits->p1, &bot_left,
+ left_y, bot_y, dir);
+ bot_y = left_y;
}
}
- 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);
+ if (top_y != bot_y)
+ _add_edge (polygon, p1, p2, top_y, bot_y, dir);
}
}
}
commit 6aa6b7daa8277785f431a07fe3d8d492d62df946
Author: Andrea Canciani <ranma42 at gmail.com>
Date: Wed Jul 27 18:57:59 2011 +0200
polygon: Simplify code for edge clipping
Add some comments about what's going on and clean up the branches by
sharing common computations.
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 82a5819..a20e6ba 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -288,67 +288,53 @@ _add_clipped_edge (cairo_polygon_t *polygon,
const int top, const int bottom,
const int dir)
{
- cairo_point_t p[2];
- int top_y, bot_y;
+ cairo_point_t bot_left, top_right;
+ cairo_fixed_t top_y, bot_y;
int n;
for (n = 0; n < polygon->num_limits; n++) {
const cairo_box_t *limits = &polygon->limits[n];
+ cairo_fixed_t pleft, pright;
if (top >= limits->p2.y)
continue;
if (bottom <= limits->p1.y)
continue;
- 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;
+ bot_left.x = limits->p1.x;
+ bot_left.y = limits->p2.y;
- bot_y = bottom;
- if (bot_y > limits->p2.y)
- bot_y = limits->p2.y;
+ top_right.x = limits->p2.x;
+ top_right.y = limits->p1.y;
+
+ /* The useful region */
+ top_y = MAX (top, limits->p1.y);
+ bot_y = MIN (bottom, limits->p2.y);
+
+ /* The projection of the edge on the horizontal axis */
+ pleft = MIN (p1->x, p2->x);
+ pright = MAX (p1->x, p2->x);
+
+ if (limits->p1.x <= pleft && pright <= limits->p2.x) {
+ /* Projection of the edge completely contained in the box:
+ * clip vertically by restricting top and bottom */
_add_edge (polygon, p1, p2, top_y, bot_y, dir);
- }
- else 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
- {
- int left_y, right_y;
+ } else if (pright <= limits->p1.x) {
+ /* Projection of the edge to the left of the box:
+ * replace with the left side of the box (clipped top/bottom) */
+
+ _add_edge (polygon, &limits->p1, &bot_left, top_y, bot_y, dir);
+ } else if (limits->p2.x <= pleft) {
+ /* Projection of the edge to the right of the box:
+ * replace with the right side of the box (clipped top/bottom) */
+
+ _add_edge (polygon, &top_right, &limits->p2, top_y, bot_y, dir);
+ } else {
+ /* The edge and the box intersect in a generic way */
+ cairo_fixed_t left_y, right_y;
int p1_y, p2_y;
+ cairo_point_t p[2];
left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
limits->p1.x);
commit de25fec06bbdbb3cf458aefb4e3b9d2271022b9c
Author: Andrea Canciani <ranma42 at gmail.com>
Date: Wed Jul 27 21:50:45 2011 +0200
test: Improve horizontal-clip
The bug pointed out by this test now causes failures in xcb and xlib.
diff --git a/test/horizontal-clip.c b/test/horizontal-clip.c
index 2a5025c..93127a7 100644
--- a/test/horizontal-clip.c
+++ b/test/horizontal-clip.c
@@ -29,10 +29,11 @@
#include "cairo-test.h"
-#define WIDTH 20
-#define HEIGHT 20
+#define WIDTH 16
+#define HEIGHT 26
-#define BUG 1
+#define BUGY 1
+#define BUGX (4 * BUGY * WIDTH * 256)
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
@@ -41,28 +42,28 @@ draw (cairo_t *cr, int width, int height)
cairo_paint (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
- cairo_move_to (cr, 0-256, 4 - BUG);
- cairo_line_to (cr, WIDTH + 256, 4 + BUG);
- cairo_line_to (cr, WIDTH + 256, 2 - BUG);
- cairo_line_to (cr, 0-256, 2 + BUG);
+ cairo_move_to (cr, - BUGX, 6 - BUGY);
+ cairo_line_to (cr, + BUGX, 6 + BUGY);
+ cairo_line_to (cr, WIDTH + BUGX, 2 - BUGY);
+ cairo_line_to (cr, WIDTH - BUGX, 2 + BUGY);
cairo_fill (cr);
- cairo_move_to (cr, 0-256, 6 - BUG);
- cairo_line_to (cr, WIDTH + 256, 6 + BUG);
- cairo_line_to (cr, WIDTH + 256, 8 - BUG);
- cairo_line_to (cr, 0-256, 8 + BUG);
+ cairo_move_to (cr, WIDTH + BUGX, 8 - BUGY);
+ cairo_line_to (cr, WIDTH - BUGX, 8 + BUGY);
+ cairo_line_to (cr, - BUGX, 12 - BUGY);
+ cairo_line_to (cr, + BUGX, 12 + BUGY);
cairo_fill (cr);
- cairo_move_to (cr, WIDTH+256, 12 - BUG);
- cairo_line_to (cr, 0-256, 12 + BUG);
- cairo_line_to (cr, 0-256, 14 - BUG);
- cairo_line_to (cr, WIDTH+256, 14 + BUG);
+ cairo_move_to (cr, - BUGX, 14 - BUGY);
+ cairo_line_to (cr, + BUGX, 14 + BUGY);
+ cairo_line_to (cr, WIDTH + BUGX, 18 - BUGY);
+ cairo_line_to (cr, WIDTH - BUGX, 18 + BUGY);
cairo_fill (cr);
- cairo_move_to (cr, WIDTH+256, 18 - BUG);
- cairo_line_to (cr, 0-256, 18 + BUG);
- cairo_line_to (cr, 0-256, 16 - BUG);
- cairo_line_to (cr, WIDTH+256, 16 + BUG);
+ cairo_move_to (cr, WIDTH + BUGX, 24 - BUGY);
+ cairo_line_to (cr, WIDTH - BUGX, 24 + BUGY);
+ cairo_line_to (cr, - BUGX, 20 - BUGY);
+ cairo_line_to (cr, + BUGX, 20 + BUGY);
cairo_fill (cr);
return CAIRO_TEST_SUCCESS;
diff --git a/test/horizontal-clip.ref.png b/test/horizontal-clip.ref.png
index 51d9445..f07e035 100644
Binary files a/test/horizontal-clip.ref.png and b/test/horizontal-clip.ref.png differ
commit 80b7a1aa9b600aa3cc746d662b4090e76838f17a
Author: Andrea Canciani <ranma42 at gmail.com>
Date: Wed Jul 27 22:13:44 2011 +0200
test: Update image references
Makefile.refs was missing some images.
diff --git a/test/Makefile.refs b/test/Makefile.refs
index 1c05dea..44d8679 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -616,6 +616,7 @@ REFERENCE_IMAGES = \
halo.xlib.ref.png \
hatchings.ref.png \
hatchings.xlib.ref.png \
+ horizontal-clip.ref.png \
huge-linear.image16.ref.png \
huge-linear.pdf.ref.png \
huge-linear.ps3.ref.png \
@@ -715,6 +716,9 @@ REFERENCE_IMAGES = \
long-dashed-lines.ps3.ref.png \
long-dashed-lines.quartz.ref.png \
long-dashed-lines.ref.png \
+ map-all-to-image.ref.png \
+ map-bit-to-image.ref.png \
+ map-to-image-fill.ref.png \
mask-alpha.image16.ref.png \
mask-alpha.quartz.argb32.ref.png \
mask-alpha.ref.png \
More information about the cairo-commit
mailing list