[cairo-commit] 2 commits - src/cairo-path-fixed.c

Chris Wilson ickle at kemper.freedesktop.org
Fri Oct 30 01:10:49 PDT 2009


 src/cairo-path-fixed.c |  108 ++++++++++++++++++++++++++-----------------------
 1 file changed, 59 insertions(+), 49 deletions(-)

New commits:
commit 19c411a5b8b84d31516d9c85642ad55ef5d29aba
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 30 07:58:45 2009 +0000

    path: Skip any secondary degenerate line-to segments.
    
    Only the very first line-to following a move-to can have any
    significance if degenerate whilst stroking, so skip all others.
    In other words,
    
      0 0 m 0 0 l stroke
    
    produces a capped degenerate path (i.e a dot),
    
      0 0 m 0 0 l 0 0 l stroke
    
    produces the same degenerate stroke, and
    
      0 0 m 0 0 l 1 0 l stroke
    
    produce a horizontal line.

diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index db0e493..42172c6 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -446,6 +446,16 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
     if (! path->has_current_point)
 	return _cairo_path_fixed_move_to (path, point.x, point.y);
 
+    /* If the previous op was but the initial MOVE_TO and this segment
+     * is degenerate, then we can simply skip this point. Note that
+     * a move-to followed by a degenerate line-to is a valid path for
+     * stroking, but at all other times is simply a degenerate segment.
+     */
+    if (_cairo_path_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
+	if (x == path->current_point.x && y == path->current_point.y)
+	    return CAIRO_STATUS_SUCCESS;
+    }
+
     /* If the previous op was also a LINE_TO with the same gradient,
      * then just change its end-point rather than adding a new op.
      */
@@ -453,9 +463,6 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
 	cairo_path_buf_t *buf;
 	const cairo_point_t *p;
 
-	if (x == path->current_point.x && y == path->current_point.y)
-	    return CAIRO_STATUS_SUCCESS;
-
 	buf = cairo_path_tail (path);
 	if (likely (buf->num_points >= 2)) {
 	    p = &buf->points[buf->num_points-2];
commit 23bcf91748c4bb04c16e503b913da3bfc237463f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 30 07:49:56 2009 +0000

    path: Misclassification of rectilinear after degenerate line-to
    
    Malte Nuhn reported hitting an assertion:
    
      cairo-path-stroke.c:1816: _cairo_rectilinear_stroker_line_to: Assertion `a->x == b->x || a->y == b->y' failed.
      http://bugs.freedesktop.org/show_bug.cgi?id=24797
    
    when stroking an apparently simple path:
    
      0 8.626485 m
      0 8.626485 l
      5.208333 2.5 l
      10.416667 2.5 l
      15.625 2.5 l
      20.833333 2.5 l
      26.041667 2.5 l
      31.25 2.5 l
      36.458333 2.5 l
      41.666667 2.5 l
      46.875 2.5 l
      52.083333 2.5 l
      57.291667 2.5 l
      62.5 2.5 l
      67.708333 2.5 l
      72.916667 2.5 l
      78.125 2.5 l
      83.333333 2.5 l
      88.541667 2.5 l
      93.75 2.5 l
      98.958333 2.5 l
      104.166667 2.5 l
      109.375 2.5 l
      114.583333 2.5 l
      119.791667 2.5 l
      125 2.5 l
      stroke
    
    which upon reduction becomes:
    
      0.000000 8.625000 m 5.207031 2.500000 l 125.000000 2.500000 l stroke
    
    The bug is that after spotting a repeated line-to we move the previous
    end-point without reclassifying the path, hence we miss the
    non-rectilinear step.

diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 4a2ce01..db0e493 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -443,61 +443,64 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
      * explicitly calling into _cairo_path_fixed_move_to to ensure
      * that the last_move_point state is updated properly.
      */
-    if (! path->has_current_point) {
-	status = _cairo_path_fixed_move_to (path, point.x, point.y);
-    } else {
-	/* If the previous op was also a LINE_TO with the same gradient,
-	 * then just change its end-point rather than adding a new op.
-	 */
-	if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
-	    if (x == path->current_point.x &&
-		y == path->current_point.y)
-	    {
-		return CAIRO_STATUS_SUCCESS;
-	    }
-	    else
-	    {
-		cairo_path_buf_t *buf;
-		cairo_point_t *p;
-		cairo_slope_t prev, self;
-
-		buf = cairo_path_tail (path);
-		if (likely (buf->num_points >= 2)) {
-		    p = &buf->points[buf->num_points-2];
-		} else {
-		    cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
-		    p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
-		}
-
-		_cairo_slope_init (&prev, p, &path->current_point);
-		_cairo_slope_init (&self, &path->current_point, &point);
-		if (_cairo_slope_equal (&prev, &self)) {
-		    buf->points[buf->num_points - 1] = point;
-		    path->current_point = point;
-		    return CAIRO_STATUS_SUCCESS;
-		}
-	    }
-	}
+    if (! path->has_current_point)
+	return _cairo_path_fixed_move_to (path, point.x, point.y);
 
-	status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
-	if (path->is_rectilinear) {
-	    path->is_rectilinear = path->current_point.x == x ||
-		path->current_point.y == y;
-	    path->maybe_fill_region &= path->is_rectilinear;
-	}
-	if (path->maybe_fill_region) {
-	    path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
-		_cairo_fixed_is_integer (y);
+    /* If the previous op was also a LINE_TO with the same gradient,
+     * then just change its end-point rather than adding a new op.
+     */
+    if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
+	cairo_path_buf_t *buf;
+	const cairo_point_t *p;
+
+	if (x == path->current_point.x && y == path->current_point.y)
+	    return CAIRO_STATUS_SUCCESS;
+
+	buf = cairo_path_tail (path);
+	if (likely (buf->num_points >= 2)) {
+	    p = &buf->points[buf->num_points-2];
+	} else {
+	    cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
+	    p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
 	}
-	if (path->is_empty_fill) {
-	    path->is_empty_fill = path->current_point.x == x &&
-		path->current_point.y == y;
+
+	if (p->x == path->current_point.x && p->y == path->current_point.y) {
+	    /* previous line element was degenerate, replace */
+	    buf->points[buf->num_points - 1] = point;
+	    goto FLAGS;
+	} else {
+	    cairo_slope_t prev, self;
+
+	    _cairo_slope_init (&prev, p, &path->current_point);
+	    _cairo_slope_init (&self, &path->current_point, &point);
+	    if (_cairo_slope_equal (&prev, &self)) {
+		buf->points[buf->num_points - 1] = point;
+		goto FLAGS;
+	    }
 	}
+    }
+
+    status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
+    if (unlikely (status))
+	return status;
 
-	path->current_point = point;
+  FLAGS:
+    if (path->is_rectilinear) {
+	path->is_rectilinear = path->current_point.x == x ||
+			       path->current_point.y == y;
+	path->maybe_fill_region &= path->is_rectilinear;
+    }
+    if (path->maybe_fill_region) {
+	path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
+				  _cairo_fixed_is_integer (y);
+    }
+    if (path->is_empty_fill) {
+	path->is_empty_fill = path->current_point.x == x &&
+			      path->current_point.y == y;
     }
 
-    return status;
+    path->current_point = point;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t


More information about the cairo-commit mailing list