[cairo-commit] 3 commits - src/cairo-analysis-surface.c src/cairo-path-bounds.c src/cairo-path-fill.c src/cairo-path-fixed.c src/cairo-path-fixed-private.h src/cairo-xlib-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Tue Nov 25 04:55:54 PST 2008


 src/cairo-analysis-surface.c   |    2 
 src/cairo-path-bounds.c        |   20 +++---
 src/cairo-path-fill.c          |   85 ++++++++++++++++++++++------
 src/cairo-path-fixed-private.h |   17 +++++
 src/cairo-path-fixed.c         |  124 ++++++++++++++++++++++++++++++++++++++---
 src/cairo-xlib-surface.c       |    5 -
 6 files changed, 216 insertions(+), 37 deletions(-)

New commits:
commit 4ac38f7c2bde67cab37805cab8a2effb2a8617e4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Nov 25 11:52:01 2008 +0000

    [fill] Emit rectangles for GdkRegion
    
    Scan the path for a series of consistently wound rectangles.

diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 46046bb..a6dea08 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -150,6 +150,7 @@ _cairo_filler_close_path (void *closure)
 
 static cairo_int_status_t
 _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t	*path,
+				  cairo_fill_rule_t	 fill_rule,
 				  cairo_traps_t		*traps);
 
 cairo_status_t
@@ -163,7 +164,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
 
     /* Before we do anything else, we use a special-case filler for
      * a device-axis aligned rectangle if possible. */
-    status = _cairo_path_fixed_fill_rectangle (path, traps);
+    status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
@@ -205,27 +206,77 @@ BAIL:
  */
 static cairo_int_status_t
 _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t	*path,
+				  cairo_fill_rule_t	 fill_rule,
 				  cairo_traps_t		*traps)
 {
-    if (_cairo_path_fixed_is_box (path, NULL)) {
-	cairo_point_t *p = path->buf_head.base.points;
-	cairo_point_t *top_left, *bot_right;
-
-	top_left = &p[0];
-	bot_right = &p[2];
-	if (top_left->x > bot_right->x || top_left->y > bot_right->y) {
-	    int n;
-
-	    /* not a simple cairo_rectangle() */
-	    for (n = 0; n < 4; n++) {
-		if (p[n].x <= top_left->x && p[n].y <= top_left->y)
-		    top_left = &p[n];
-		if (p[n].x >= bot_right->x && p[n].y >= bot_right->y)
-		    bot_right = &p[n];
+    cairo_box_t box;
+
+    if (_cairo_path_fixed_is_box (path, &box)) {
+	if (box.p1.x > box.p2.x) {
+	    cairo_fixed_t t;
+
+	    t = box.p1.x;
+	    box.p1.x = box.p2.x;
+	    box.p2.x = t;
+	}
+
+	if (box.p1.y > box.p2.y) {
+	    cairo_fixed_t t;
+
+	    t = box.p1.y;
+	    box.p1.y = box.p2.y;
+	    box.p2.y = t;
+	}
+
+	return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
+    } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
+	cairo_path_fixed_iter_t iter;
+	int last_cw = -1;
+
+	/* Support a series of rectangles as can be expected to describe a
+	 * GdkRegion clip region during exposes.
+	 */
+	_cairo_path_fixed_iter_init (&iter, path);
+	while (_cairo_path_fixed_iter_is_box (&iter, &box)) {
+	    cairo_status_t status;
+	    int cw = 0;
+
+	    if (box.p1.x > box.p2.x) {
+		cairo_fixed_t t;
+
+		t = box.p1.x;
+		box.p1.x = box.p2.x;
+		box.p2.x = t;
+
+		cw = ! cw;
 	    }
+
+	    if (box.p1.y > box.p2.y) {
+		cairo_fixed_t t;
+
+		t = box.p1.y;
+		box.p1.y = box.p2.y;
+		box.p2.y = t;
+
+		cw = ! cw;
+	    }
+
+	    if (last_cw < 0) {
+		last_cw = cw;
+	    } else if (last_cw != cw) {
+		_cairo_traps_clear (traps);
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	    }
+
+	    status = _cairo_traps_tessellate_rectangle (traps,
+							&box.p1, &box.p2);
+	    if (unlikely (status))
+		return status;
 	}
+	if (_cairo_path_fixed_iter_at_end (&iter))
+	    return CAIRO_STATUS_SUCCESS;
 
-	return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right);
+	_cairo_traps_clear (traps);
     }
 
     return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index 43c33c1..c995e2a 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -88,4 +88,21 @@ cairo_private cairo_bool_t
 _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
 			 const cairo_path_fixed_t *b);
 
+typedef struct _cairo_path_fixed_iter {
+    cairo_path_buf_t *buf;
+    int n_op;
+    int n_point;
+} cairo_path_fixed_iter_t;
+
+cairo_private void
+_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
+			     cairo_path_fixed_t *path);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter,
+			       cairo_box_t *box);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
+
 #endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index b36f4d8..ffaf58c 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -1002,10 +1002,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
 	buf->points[2].y == buf->points[3].y &&
 	buf->points[3].x == buf->points[0].x)
     {
-	if (box) {
-	    box->p1 = buf->points[0];
-	    box->p2 = buf->points[2];
-	}
+	box->p1 = buf->points[0];
+	box->p2 = buf->points[2];
 	return TRUE;
     }
 
@@ -1014,10 +1012,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
 	buf->points[2].x == buf->points[3].x &&
 	buf->points[3].y == buf->points[0].y)
     {
-	if (box) {
-	    box->p1 = buf->points[0];
-	    box->p2 = buf->points[2];
-	}
+	box->p1 = buf->points[0];
+	box->p2 = buf->points[2];
 	return TRUE;
     }
 
@@ -1049,3 +1045,115 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
 
     return FALSE;
 }
+
+void
+_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
+			     cairo_path_fixed_t *path)
+{
+    iter->buf = &path->buf_head.base;
+    iter->n_op = 0;
+    iter->n_point = 0;
+}
+
+static cairo_bool_t
+_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
+{
+    if (++iter->n_op == iter->buf->num_ops) {
+	iter->buf = iter->buf->next;
+	iter->n_op = 0;
+	iter->n_point = 0;
+    }
+
+    return iter->buf != NULL;
+}
+
+cairo_bool_t
+_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter,
+			       cairo_box_t *box)
+{
+    cairo_point_t points[5];
+    cairo_path_fixed_iter_t iter;
+
+    if (_iter->buf == NULL)
+	return FALSE;
+
+    iter = *_iter;
+
+    /* Check whether the ops are those that would be used for a rectangle */
+    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO)
+	return FALSE;
+    points[0] = iter.buf->points[iter.n_point++];
+    if (! _cairo_path_fixed_iter_next_op (&iter))
+	return FALSE;
+
+    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+	return FALSE;
+    points[1] = iter.buf->points[iter.n_point++];
+    if (! _cairo_path_fixed_iter_next_op (&iter))
+	return FALSE;
+
+    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+	return FALSE;
+    points[2] = iter.buf->points[iter.n_point++];
+    if (! _cairo_path_fixed_iter_next_op (&iter))
+	return FALSE;
+
+    if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+	return FALSE;
+    points[3] = iter.buf->points[iter.n_point++];
+    if (! _cairo_path_fixed_iter_next_op (&iter))
+	return FALSE;
+
+    /* Now, there are choices. The rectangle might end with a LINE_TO
+     * (to the original point), but this isn't required. If it
+     * doesn't, then it must end with a CLOSE_PATH. */
+    if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) {
+	points[4] = iter.buf->points[iter.n_point++];
+	if (points[4].x != points[0].x || points[4].y != points[0].y)
+	    return FALSE;
+    } else if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_CLOSE_PATH) {
+	return FALSE;
+    }
+    if (! _cairo_path_fixed_iter_next_op (&iter))
+	return FALSE;
+
+    /* Ok, we may have a box, if the points line up */
+    if (points[0].y == points[1].y &&
+	points[1].x == points[2].x &&
+	points[2].y == points[3].y &&
+	points[3].x == points[0].x)
+    {
+	box->p1 = points[0];
+	box->p2 = points[2];
+	*_iter = iter;
+	return TRUE;
+    }
+
+    if (points[0].x == points[1].x &&
+	points[1].y == points[2].y &&
+	points[2].x == points[3].x &&
+	points[3].y == points[0].y)
+    {
+	box->p1 = points[0];
+	box->p2 = points[2];
+	*_iter = iter;
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+cairo_bool_t
+_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
+{
+    if (iter->buf == NULL)
+	return TRUE;
+
+    if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO &&
+	iter->buf->num_ops == iter->n_op + 1)
+    {
+	return TRUE;
+    }
+
+    return FALSE;
+}
commit 23df74e5ffd6be876f3c19ee9d71683f5a0ed6f4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Nov 25 11:45:30 2008 +0000

    [xlib] Cosmetic tweak.
    
    Tightly scope the local rects.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 2ae727f..136e554 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1924,8 +1924,6 @@ _cairo_xlib_surface_fill_rectangles (void		     *abstract_surface,
 {
     cairo_xlib_surface_t *surface = abstract_surface;
     XRenderColor render_color;
-    XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
-    XRectangle *xrects = static_xrects;
     int i;
 
     _cairo_xlib_display_notify (surface->display);
@@ -1961,6 +1959,9 @@ _cairo_xlib_surface_fill_rectangles (void		     *abstract_surface,
 			      rects->width,
 			      rects->height);
     } else {
+	XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+	XRectangle *xrects = static_xrects;
+
 	if (num_rects > ARRAY_LENGTH (static_xrects)) {
 	    xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
 	    if (xrects == NULL)
commit 06fabd6cbd0ad187f5f9f155d6b7962f76ec5dda
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Nov 25 12:05:26 2008 +0000

    [path] Fix up extents.
    
    Forgot to round the box to the integer rectangle and missed why only
    testing on image. Very naughty.

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 431f98e..3109dee 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -290,7 +290,7 @@ _cairo_analysis_surface_intersect_clip_path (void		*abstract_surface,
 	surface->current_clip.width  = surface->width;
 	surface->current_clip.height = surface->height;
     } else {
-	cairo_rectangle_int_t   extent;
+	cairo_rectangle_int_t extent;
 	cairo_bool_t is_empty;
 
 	_cairo_path_fixed_approximate_extents (path, &extent);
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 54df5bf..6245cd2 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -172,18 +172,20 @@ _cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
     _cairo_path_bounder_init (&bounder);
 
     status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
-					       _cairo_path_bounder_move_to,
-					       _cairo_path_bounder_line_to,
-					       _cairo_path_bounder_curve_to,
-					       _cairo_path_bounder_close_path,
-					       &bounder);
+					  _cairo_path_bounder_move_to,
+					  _cairo_path_bounder_line_to,
+					  _cairo_path_bounder_curve_to,
+					  _cairo_path_bounder_close_path,
+					  &bounder);
     assert (status == CAIRO_STATUS_SUCCESS);
 
     if (bounder.has_point) {
-	extents->x = bounder.min_x;
-	extents->y = bounder.min_y;
-	extents->width = bounder.max_x - extents->x;
-	extents->height = bounder.max_y - extents->y;
+	extents->x = _cairo_fixed_integer_floor (bounder.min_x);
+	extents->y = _cairo_fixed_integer_floor (bounder.min_y);
+	extents->width =
+	    _cairo_fixed_integer_ceil (bounder.max_x) - extents->x;
+	extents->height =
+	    _cairo_fixed_integer_ceil (bounder.max_y) - extents->y;
     } else {
 	extents->x = extents->y = 0;
 	extents->width = extents->height = 0;


More information about the cairo-commit mailing list