[cairo-commit] 12 commits - src/cairo-bentley-ottmann.c src/cairo-compositor.c src/cairoint.h src/cairo-path-stroke.c src/cairo-path-stroke-polygon.c src/cairo-pen.c src/cairo-xlib-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Aug 26 03:44:56 PDT 2012


 src/cairo-bentley-ottmann.c     |   73 ++++---------
 src/cairo-compositor.c          |    4 
 src/cairo-path-stroke-polygon.c |  214 +++++++++++++++++++--------------------
 src/cairo-path-stroke.c         |  215 ++++++++++++++++++++++++----------------
 src/cairo-pen.c                 |  115 +++++++++++++++++----
 src/cairo-xlib-surface.c        |    4 
 src/cairoint.h                  |   17 +++
 7 files changed, 374 insertions(+), 268 deletions(-)

New commits:
commit 637659fb511824eb8ac31ef85db10406295734e6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Aug 26 00:39:43 2012 +0100

    bentley-ottmann:  hint that the insertion compare function should be inlined
    
    Albeit it too large for gcc to automatically inline, it is only used
    from within a single function. Hopefully gcc can optimise better with
    the hint.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 7820dad..4f5df2d 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -561,7 +561,7 @@ _line_equal (const cairo_line_t *a, const cairo_line_t *b)
            a->p2.x == b->p2.x && a->p2.y == b->p2.y;
 }
 
-static int
+static inline int
 _cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t	*sweep_line,
 				    const cairo_bo_edge_t	*a,
 				    const cairo_bo_edge_t	*b)
commit 3c6e4311fb3b9fe400555a8d97193fc87974899b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Aug 26 00:35:52 2012 +0100

    bentley-ottmann: Only check the pairs of coordinates for equality.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index fdb2744..7820dad 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -1329,7 +1329,7 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
      */
     if (p != 0) {
 	/* colinear if either end-point are coincident */
-	return ((p >> 1) & p) != 0;
+	return ((p >> 1) & p) & 5;
     } else if (a->edge.line.p1.y < b->edge.line.p1.y) {
 	return edge_compare_for_y_against_x (b,
 					     a->edge.line.p1.y,
commit 535b4e970cdbb459be621cecafd7f91ca4698396
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Aug 26 00:16:33 2012 +0100

    bentley-ottman: Remove a few superfluous status propagation
    
    For the traps it is simpler if we report the status at the end, and
    no-op the accumulation of the trap after hitting the error condition.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 38fe463..fdb2744 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -562,7 +562,7 @@ _line_equal (const cairo_line_t *a, const cairo_line_t *b)
 }
 
 static int
-_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t	*sweep_line,
+_cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t	*sweep_line,
 				    const cairo_bo_edge_t	*a,
 				    const cairo_bo_edge_t	*b)
 {
@@ -1118,7 +1118,7 @@ _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
     sweep_line->current_edge = NULL;
 }
 
-static cairo_status_t
+static void
 _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t	*sweep_line,
 			     cairo_bo_edge_t		*edge)
 {
@@ -1175,8 +1175,6 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t	*sweep_line,
     }
 
     sweep_line->current_edge = edge;
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -1344,7 +1342,7 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
 }
 
 /* Adds the trapezoid, if any, of the left edge to the #cairo_traps_t */
-static cairo_status_t
+static void
 _cairo_bo_edge_end_trap (cairo_bo_edge_t	*left,
 			 int32_t		 bot,
 			 cairo_traps_t	        *traps)
@@ -1376,8 +1374,6 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t	*left,
     }
 
     trap->right = NULL;
-
-    return _cairo_traps_status (traps);
 }
 
 
@@ -1386,16 +1382,14 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t	*left,
  * then either add it to the traps in `traps', if the trapezoid's
  * right edge differs from `edge->next', or do nothing if the new
  * trapezoid would be a continuation of the existing one. */
-static inline cairo_status_t
+static inline void
 _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t	*left,
 				       cairo_bo_edge_t  *right,
 				       int               top,
 				       cairo_traps_t	*traps)
 {
-    cairo_status_t status;
-
     if (left->deferred_trap.right == right)
-	return CAIRO_STATUS_SUCCESS;
+	return;
 
     assert (right);
     if (left->deferred_trap.right != NULL) {
@@ -1403,12 +1397,10 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t	*left,
 	{
 	    /* continuation on right, so just swap edges */
 	    left->deferred_trap.right = right;
-	    return CAIRO_STATUS_SUCCESS;
+	    return;
 	}
 
-	status = _cairo_bo_edge_end_trap (left, top, traps);
-	if (unlikely (status))
-	    return status;
+	_cairo_bo_edge_end_trap (left, top, traps);
     }
 
     if (! edges_colinear (left, right)) {
@@ -1422,18 +1414,15 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t	*left,
 		   top);
 #endif
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static inline cairo_status_t
+static inline void
 _active_edges_to_traps (cairo_bo_edge_t	*pos,
 			int32_t		 top,
 			unsigned	 mask,
 			cairo_traps_t        *traps)
 {
     cairo_bo_edge_t *left;
-    cairo_status_t status;
     int in_out;
 
 
@@ -1457,9 +1446,7 @@ _active_edges_to_traps (cairo_bo_edge_t	*pos,
 	    }
 	    else
 	    {
-		status = _cairo_bo_edge_end_trap (pos, top, traps);
-		if (unlikely (status))
-		    return status;
+		_cairo_bo_edge_end_trap (pos, top, traps);
 	    }
 	}
 
@@ -1467,22 +1454,15 @@ _active_edges_to_traps (cairo_bo_edge_t	*pos,
 	if ((in_out & mask) == 0) {
 	    /* skip co-linear edges */
 	    if (pos->next == NULL || ! edges_colinear (pos, pos->next)) {
-		status = _cairo_bo_edge_start_or_continue_trap (left, pos,
-								top, traps);
-		if (unlikely (status))
-		    return status;
-
+		_cairo_bo_edge_start_or_continue_trap (left, pos, top, traps);
 		left = pos->next;
 	    }
 	}
 
 	pos = pos->next;
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
-
 /* Execute a single pass of the Bentley-Ottmann algorithm on edges,
  * generating trapezoids according to the fill_rule and appending them
  * to traps. */
@@ -1493,7 +1473,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
 					    cairo_traps_t	*traps,
 					    int			*num_intersections)
 {
-    cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */
+    cairo_status_t status;
     int intersection_count = 0;
     cairo_bo_event_queue_t event_queue;
     cairo_bo_sweep_line_t sweep_line;
@@ -1534,20 +1514,16 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
 	if (event->point.y != sweep_line.current_y) {
 	    for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
 		if (e1->deferred_trap.right != NULL) {
-		    status = _cairo_bo_edge_end_trap (e1,
-						      e1->edge.bottom,
-						      traps);
-		    if (unlikely (status))
-			goto unwind;
+		    _cairo_bo_edge_end_trap (e1,
+					     e1->edge.bottom,
+					     traps);
 		}
 	    }
 	    sweep_line.stopped = NULL;
 
-	    status = _active_edges_to_traps (sweep_line.head,
-					     sweep_line.current_y,
-					     fill_rule, traps);
-	    if (unlikely (status))
-		goto unwind;
+	    _active_edges_to_traps (sweep_line.head,
+				    sweep_line.current_y,
+				    fill_rule, traps);
 
 	    sweep_line.current_y = event->point.y;
 	}
@@ -1565,9 +1541,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
 	case CAIRO_BO_EVENT_TYPE_START:
 	    e1 = &((cairo_bo_start_event_t *) event)->edge;
 
-	    status = _cairo_bo_sweep_line_insert (&sweep_line, e1);
-	    if (unlikely (status))
-		goto unwind;
+	    _cairo_bo_sweep_line_insert (&sweep_line, e1);
 
 	    status = _cairo_bo_event_queue_insert_stop (&event_queue, e1);
 	    if (unlikely (status))
@@ -1670,11 +1644,10 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t   **start_events,
     *num_intersections = intersection_count;
     for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
 	if (e1->deferred_trap.right != NULL) {
-	    status = _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
-	    if (unlikely (status))
-		break;
+	    _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
 	}
     }
+    status = traps->status;
  unwind:
     _cairo_bo_event_queue_fini (&event_queue);
 
@@ -1691,7 +1664,6 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t	 *traps,
 					   cairo_fill_rule_t	  fill_rule)
 {
     int intersections;
-    cairo_status_t status;
     cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
     cairo_bo_start_event_t *events;
     cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
@@ -1699,6 +1671,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t	 *traps,
     cairo_bo_start_event_t *stack_event_y[64];
     cairo_bo_start_event_t **event_y = NULL;
     int i, num_events, y, ymin, ymax;
+    cairo_status_t status;
 
     num_events = polygon->num_edges;
     if (unlikely (0 == num_events))
commit b66065537cec5f03b33f7513f06e26630c28b5f1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Aug 26 10:21:22 2012 +0100

    stroke: Compute bounds for fallback stroker (typically dashing)
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 8f9fa92..5ef212c 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -90,10 +90,13 @@ typedef struct cairo_stroker {
 
 static cairo_status_t
 _cairo_stroker_init (cairo_stroker_t		*stroker,
+		     const cairo_path_fixed_t	*path,
 		     const cairo_stroke_style_t	*stroke_style,
 		     const cairo_matrix_t	*ctm,
 		     const cairo_matrix_t	*ctm_inverse,
-		     double			 tolerance)
+		     double			 tolerance,
+		     const cairo_box_t		*limits,
+		     int			 num_limits)
 {
     cairo_status_t status;
 
@@ -111,8 +114,6 @@ _cairo_stroker_init (cairo_stroker_t		*stroker,
     if (unlikely (status))
 	return status;
 
-    stroker->has_bounds = FALSE;
-
     stroker->has_current_face = FALSE;
     stroker->has_first_face = FALSE;
     stroker->has_initial_sub_path = FALSE;
@@ -121,6 +122,31 @@ _cairo_stroker_init (cairo_stroker_t		*stroker,
 
     stroker->add_external_edge = NULL;
 
+    stroker->has_bounds = num_limits;
+    if (stroker->has_bounds) {
+	/* Extend the bounds in each direction to account for the maximum area
+	 * we might generate trapezoids, to capture line segments that are
+	 * outside of the bounds but which might generate rendering that's
+	 * within bounds.
+	 */
+	double dx, dy;
+	cairo_fixed_t fdx, fdy;
+	int i;
+
+	stroker->bounds = limits[0];
+	for (i = 1; i < num_limits; i++)
+	     _cairo_box_add_box (&stroker->bounds, &limits[i]);
+
+	_cairo_stroke_style_max_distance_from_path (stroke_style, path, ctm, &dx, &dy);
+	fdx = _cairo_fixed_from_double (dx);
+	fdy = _cairo_fixed_from_double (dy);
+
+	stroker->bounds.p1.x -= fdx;
+	stroker->bounds.p2.x += fdx;
+	stroker->bounds.p1.y -= fdy;
+	stroker->bounds.p2.y += fdy;
+    }
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1261,8 +1287,9 @@ _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t	*path,
     cairo_stroker_t stroker;
     cairo_status_t status;
 
-    status = _cairo_stroker_init (&stroker, stroke_style,
-			          ctm, ctm_inverse, tolerance);
+    status = _cairo_stroker_init (&stroker, path, stroke_style,
+			          ctm, ctm_inverse, tolerance,
+				  NULL, 0);
     if (unlikely (status))
 	return status;
 
@@ -1303,8 +1330,9 @@ _cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t	*path,
     cairo_stroker_t stroker;
     cairo_status_t status;
 
-    status = _cairo_stroker_init (&stroker, stroke_style,
-			          ctm, ctm_inverse, tolerance);
+    status = _cairo_stroker_init (&stroker, path, stroke_style,
+			          ctm, ctm_inverse, tolerance,
+				  polygon->limits, polygon->num_limits);
     if (unlikely (status))
 	return status;
 
commit 99593538a9d054aa1bb9fa620fced8c8b8ccdc9d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Aug 26 10:50:50 2012 +0100

    stroke: Convert fallback stroker to new pen vertex finder
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index bae66dc..8f9fa92 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -220,100 +220,117 @@ _tessellate_fan (cairo_stroker_t *stroker,
 		 cairo_bool_t clockwise)
 {
     cairo_point_t stack_points[64], *points = stack_points;
-    int start, stop, step, i, npoints;
+    cairo_pen_t *pen = &stroker->pen;
+    int start, stop, num_points = 0;
     cairo_status_t status;
 
+    if (stroker->has_bounds &&
+	! _cairo_box_contains_point (&stroker->bounds, midpt))
+	goto BEVEL;
+
+    assert (stroker->pen.num_vertices);
+
     if (clockwise) {
-	step  = -1;
-
-	start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
-							 in_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
-				  in_vector) < 0)
-	    start = _range_step (start, -1, stroker->pen.num_vertices);
-
-	stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
-							 out_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
-				  out_vector) > 0)
-	{
-	    stop = _range_step (stop, 1, stroker->pen.num_vertices);
-	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
-				      in_vector) < 0)
-	    {
-		goto BEVEL;
-	    }
-	}
+	_cairo_pen_find_active_ccw_vertices (pen,
+					     in_vector, out_vector,
+					     &start, &stop);
+	if (stroker->add_external_edge) {
+	    cairo_point_t last;
+	    last = *inpt;
+	    while (start != stop) {
+		cairo_point_t p = *midpt;
+		_translate_point (&p, &pen->vertices[start].point);
 
-	npoints = start - stop;
-    } else {
-	step  = 1;
-
-	start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
-							in_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
-				  in_vector) < 0)
-	    start = _range_step (start, 1, stroker->pen.num_vertices);
-
-	stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
-							out_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
-				  out_vector) > 0)
-	{
-	    stop = _range_step (stop, -1, stroker->pen.num_vertices);
-	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
-				      in_vector) < 0)
-	    {
+		status = stroker->add_external_edge (stroker->closure,
+						     &last, &p);
+		if (unlikely (status))
+		    return status;
+		last = p;
+
+		if (start-- == 0)
+		    start += pen->num_vertices;
+	    }
+	    status = stroker->add_external_edge (stroker->closure,
+						 &last, outpt);
+	} else {
+	    if (start == stop)
 		goto BEVEL;
+
+	    num_points = stop - start;
+	    if (num_points < 0)
+		num_points += pen->num_vertices;
+	    num_points += 2;
+	    if (num_points > ARRAY_LENGTH(stack_points)) {
+		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
+		if (unlikely (points == NULL))
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    }
-	}
 
-	npoints = stop - start;
-    }
-    stop = _range_step (stop, step, stroker->pen.num_vertices);
+	    points[0] = *inpt;
+	    num_points = 1;
+	    while (start != stop) {
+		points[num_points] = *midpt;
+		_translate_point (&points[num_points], &pen->vertices[start].point);
+		num_points++;
 
-    if (npoints < 0)
-	npoints += stroker->pen.num_vertices;
-    npoints += 3;
+		if (start-- == 0)
+		    start += pen->num_vertices;
+	    }
+	    points[num_points++] = *outpt;
+	}
+    } else {
+	_cairo_pen_find_active_cw_vertices (pen,
+					    in_vector, out_vector,
+					    &start, &stop);
+	if (stroker->add_external_edge) {
+	    cairo_point_t last;
+	    last = *inpt;
+	    while (start != stop) {
+		cairo_point_t p = *midpt;
+		_translate_point (&p, &pen->vertices[start].point);
 
-    if (npoints <= 1)
-	goto BEVEL;
+		status = stroker->add_external_edge (stroker->closure,
+						     &p, &last);
+		if (unlikely (status))
+		    return status;
+		last = p;
 
-    if (npoints > ARRAY_LENGTH (stack_points)) {
-	points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
-	if (unlikely (points == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
+		if (++start == pen->num_vertices)
+		    start = 0;
+	    }
+	    status = stroker->add_external_edge (stroker->closure,
+						 outpt, &last);
+	} else {
+	    if (start == stop)
+		goto BEVEL;
 
+	    num_points = stop - start;
+	    if (num_points < 0)
+		num_points += pen->num_vertices;
+	    num_points += 2;
+	    if (num_points > ARRAY_LENGTH(stack_points)) {
+		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
+		if (unlikely (points == NULL))
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    }
 
-    /* Construct the fan. */
-    npoints = 0;
-    points[npoints++] = *inpt;
-    for (i = start;
-	 i != stop;
-	i = _range_step (i, step, stroker->pen.num_vertices))
-    {
-	points[npoints] = *midpt;
-	_translate_point (&points[npoints], &stroker->pen.vertices[i].point);
-	npoints++;
-    }
-    points[npoints++] = *outpt;
+	    points[0] = *inpt;
+	    num_points = 1;
+	    while (start != stop) {
+		points[num_points] = *midpt;
+		_translate_point (&points[num_points], &pen->vertices[start].point);
+		num_points++;
 
-    if (stroker->add_external_edge != NULL) {
-	for (i = 0; i < npoints - 1; i++) {
-	    if (clockwise) {
-		status = stroker->add_external_edge (stroker->closure,
-						     &points[i], &points[i+1]);
-	    } else {
-		status = stroker->add_external_edge (stroker->closure,
-						     &points[i+1], &points[i]);
+		if (++start == pen->num_vertices)
+		    start = 0;
 	    }
-	    if (unlikely (status))
-		break;
+	    points[num_points++] = *outpt;
 	}
-    } else {
+    }
+
+    if (num_points) {
 	status = stroker->add_triangle_fan (stroker->closure,
-					    midpt, points, npoints);
+					    midpt, points, num_points);
     }
 
     if (points != stack_points)
commit 4eb8e9f8618c5c5c002b7fd72c0370451ae1f511
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 25 23:57:56 2012 +0100

    stroke: Convert a very small round-join into a miter
    
    Avoid adding a bevel join if the miter point is within tolerance.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 350e436..f6e81e0 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -406,8 +406,8 @@ outer_close (struct stroker *stroker,
 	    add_fan (stroker,
 		     &in->dev_vector, &out->dev_vector, &in->point,
 		     clockwise, outer);
+	    break;
 	}
-	break;
 
     case CAIRO_LINE_JOIN_MITER:
     default: {
commit fa93fc63b652f04bcf7d5340a13023819ecf2140
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 25 23:54:36 2012 +0100

    stroke: Precompute the line half-width
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 61a782b..350e436 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -68,6 +68,7 @@ struct stroker {
     const cairo_matrix_t *ctm_inverse;
     double tolerance;
     double spline_cusp_tolerance;
+    double half_line_width;
     cairo_bool_t ctm_det_positive;
 
     cairo_pen_t pen;
@@ -378,6 +379,7 @@ outer_close (struct stroker *stroker,
     {
 	return;
     }
+
     clockwise = join_is_clockwise (in, out);
     if (clockwise) {
 	inpt = &in->cw;
@@ -410,8 +412,8 @@ outer_close (struct stroker *stroker,
     case CAIRO_LINE_JOIN_MITER:
     default: {
 	/* dot product of incoming slope vector with outgoing slope vector */
-	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
-			     -in->usr_vector.y * out->usr_vector.y;
+	double	in_dot_out = in->dev_slope.x * out->dev_slope.x +
+			     in->dev_slope.y * out->dev_slope.y;
 	double	ml = stroker->style.miter_limit;
 
 	/* Check the miter limit -- lines meeting at an acute angle
@@ -471,7 +473,7 @@ outer_close (struct stroker *stroker,
 	 *	2 <= ml² (1 - in · out)
 	 *
 	 */
-	if (2 <= ml * ml * (1 - in_dot_out)) {
+	if (2 <= ml * ml * (1 + in_dot_out)) {
 	    double		x1, y1, x2, y2;
 	    double		mx, my;
 	    double		dx1, dx2, dy1, dy2;
@@ -488,16 +490,14 @@ outer_close (struct stroker *stroker,
 	    /* outer point of incoming line face */
 	    x1 = _cairo_fixed_to_double (inpt->x);
 	    y1 = _cairo_fixed_to_double (inpt->y);
-	    dx1 = in->usr_vector.x;
-	    dy1 = in->usr_vector.y;
-	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+	    dx1 = in->dev_slope.x;
+	    dy1 = in->dev_slope.y;
 
 	    /* outer point of outgoing line face */
 	    x2 = _cairo_fixed_to_double (outpt->x);
 	    y2 = _cairo_fixed_to_double (outpt->y);
-	    dx2 = out->usr_vector.x;
-	    dy2 = out->usr_vector.y;
-	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+	    dx2 = out->dev_slope.x;
+	    dy2 = out->dev_slope.y;
 
 	    /*
 	     * Compute the location of the outer corner of the miter.
@@ -596,8 +596,8 @@ outer_join (struct stroker *stroker,
     case CAIRO_LINE_JOIN_MITER:
     default: {
 	/* dot product of incoming slope vector with outgoing slope vector */
-	double	in_dot_out = -in->usr_vector.x * out->usr_vector.x +
-			     -in->usr_vector.y * out->usr_vector.y;
+	double	in_dot_out = in->dev_slope.x * out->dev_slope.x +
+			     in->dev_slope.y * out->dev_slope.y;
 	double	ml = stroker->style.miter_limit;
 
 	/* Check the miter limit -- lines meeting at an acute angle
@@ -657,7 +657,7 @@ outer_join (struct stroker *stroker,
 	 *	2 <= ml² (1 - in · out)
 	 *
 	 */
-	if (2 <= ml * ml * (1 - in_dot_out)) {
+	if (2 <= ml * ml * (1 + in_dot_out)) {
 	    double		x1, y1, x2, y2;
 	    double		mx, my;
 	    double		dx1, dx2, dy1, dy2;
@@ -674,16 +674,14 @@ outer_join (struct stroker *stroker,
 	    /* outer point of incoming line face */
 	    x1 = _cairo_fixed_to_double (inpt->x);
 	    y1 = _cairo_fixed_to_double (inpt->y);
-	    dx1 = in->usr_vector.x;
-	    dy1 = in->usr_vector.y;
-	    cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+	    dx1 = in->dev_slope.x;
+	    dy1 = in->dev_slope.y;
 
 	    /* outer point of outgoing line face */
 	    x2 = _cairo_fixed_to_double (outpt->x);
 	    y2 = _cairo_fixed_to_double (outpt->y);
-	    dx2 = out->usr_vector.x;
-	    dy2 = out->usr_vector.y;
-	    cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+	    dx2 = out->dev_slope.x;
+	    dy2 = out->dev_slope.y;
 
 	    /*
 	     * Compute the location of the outer corner of the miter.
@@ -763,27 +761,25 @@ add_cap (struct stroker *stroker,
     }
 
     case CAIRO_LINE_CAP_SQUARE: {
+	cairo_slope_t fvector;
+	cairo_point_t p;
 	double dx, dy;
-	cairo_slope_t	fvector;
-	cairo_point_t	quad[4];
 
 	dx = f->usr_vector.x;
 	dy = f->usr_vector.y;
-	dx *= stroker->style.line_width / 2.0;
-	dy *= stroker->style.line_width / 2.0;
+	dx *= stroker->half_line_width;
+	dy *= stroker->half_line_width;
 	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
 	fvector.dx = _cairo_fixed_from_double (dx);
 	fvector.dy = _cairo_fixed_from_double (dy);
 
-	quad[0] = f->ccw;
-	quad[1].x = f->ccw.x + fvector.dx;
-	quad[1].y = f->ccw.y + fvector.dy;
-	quad[2].x = f->cw.x + fvector.dx;
-	quad[2].y = f->cw.y + fvector.dy;
-	quad[3] = f->cw;
+	p.x = f->ccw.x + fvector.dx;
+	p.y = f->ccw.y + fvector.dy;
+	contour_add_point (stroker, c, &p);
 
-	contour_add_point (stroker, c, &quad[1]);
-	contour_add_point (stroker, c, &quad[2]);
+	p.x = f->cw.x + fvector.dx;
+	p.y = f->cw.y + fvector.dy;
+	contour_add_point (stroker, c, &p);
     }
 
     case CAIRO_LINE_CAP_BUTT:
@@ -888,22 +884,19 @@ compute_face (const cairo_point_t *point,
 					 &slope_dx, &slope_dy);
 	normalize_slope (&slope_dx, &slope_dy);
 
-	if (stroker->ctm_det_positive)
-	{
-	    face_dx = - slope_dy * (stroker->style.line_width / 2.0);
-	    face_dy = slope_dx * (stroker->style.line_width / 2.0);
-	}
-	else
-	{
-	    face_dx = slope_dy * (stroker->style.line_width / 2.0);
-	    face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+	if (stroker->ctm_det_positive) {
+	    face_dx = - slope_dy * stroker->half_line_width;
+	    face_dy = slope_dx * stroker->half_line_width;
+	} else {
+	    face_dx = slope_dy * stroker->half_line_width;
+	    face_dy = - slope_dx * stroker->half_line_width;
 	}
 
 	/* back to device space */
 	cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
     } else {
-	face_dx = - slope_dy * (stroker->style.line_width / 2.0);
-	face_dy = slope_dx * (stroker->style.line_width / 2.0);
+	face_dx = - slope_dy * stroker->half_line_width;
+	face_dy = slope_dx * stroker->half_line_width;
     }
 
     offset_ccw.x = _cairo_fixed_from_double (face_dx);
@@ -1089,7 +1082,7 @@ spline_to (void *closure,
 #if DEBUG
     _cairo_contour_add_point (&stroker->path, point);
 #endif
-    if (tangent->dx == 0 && tangent->dy == 0) {
+    if ((tangent->dx | tangent->dy) == 0) {
 	const cairo_point_t *inpt, *outpt;
 	struct stroke_contour *outer;
 	cairo_point_t t;
@@ -1307,6 +1300,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
     stroker.ctm = ctm;
     stroker.ctm_inverse = ctm_inverse;
     stroker.tolerance = tolerance;
+    stroker.half_line_width = style->line_width / 2.;
     /* To test whether we need to join two segments of a spline using
      * a round-join or a bevel-join, we can inspect the angle between the
      * two segments. If the difference between the chord distance
@@ -1314,7 +1308,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
      * half-line-width itself is greater than tolerance then we need to
      * inject a point.
      */
-    stroker.spline_cusp_tolerance = 1 - 2 * tolerance / style->line_width;
+    stroker.spline_cusp_tolerance = 1 - tolerance / stroker.half_line_width;
     stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
     stroker.spline_cusp_tolerance *= 2;
     stroker.spline_cusp_tolerance -= 1;
@@ -1326,7 +1320,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
 	style->line_join == CAIRO_LINE_JOIN_ROUND ||
 	style->line_cap == CAIRO_LINE_CAP_ROUND) {
 	status = _cairo_pen_init (&stroker.pen,
-				  style->line_width / 2.0,
+				  stroker.half_line_width,
 				  tolerance, ctm);
 	if (unlikely (status))
 	    return status;
commit 3cf6551ac71bac4d0ae1d0938bc0205dfc03f65c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 25 23:42:45 2012 +0100

    stroke: Use new pen vertex range finders
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 242fb24..61a782b 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -161,12 +161,11 @@ add_fan (struct stroker *stroker,
 	 const cairo_slope_t *in_vector,
 	 const cairo_slope_t *out_vector,
 	 const cairo_point_t *midpt,
-	 const cairo_point_t *inpt,
-	 const cairo_point_t *outpt,
 	 cairo_bool_t clockwise,
 	 struct stroke_contour *c)
 {
-    int start, stop, step, i, npoints;
+    cairo_pen_t *pen = &stroker->pen;
+    int start, stop;
 
     if (stroker->has_bounds &&
 	! _cairo_box_contains_point (&stroker->bounds, midpt))
@@ -175,61 +174,29 @@ add_fan (struct stroker *stroker,
     assert (stroker->pen.num_vertices);
 
     if (clockwise) {
-	step  = 1;
-
-	start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
-							in_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
-				  in_vector) < 0)
-	    start = range_step (start, 1, stroker->pen.num_vertices);
-
-	stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
-							out_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
-				  out_vector) > 0)
-	{
-	    stop = range_step (stop, -1, stroker->pen.num_vertices);
-	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
-				      in_vector) < 0)
-		return;
+	_cairo_pen_find_active_cw_vertices (pen,
+					    in_vector, out_vector,
+					    &start, &stop);
+	while (start != stop) {
+	    cairo_point_t p = *midpt;
+	    translate_point (&p, &pen->vertices[start].point);
+	    contour_add_point (stroker, c, &p);
+
+	    if (++start == pen->num_vertices)
+		start = 0;
 	}
-
-	npoints = stop - start;
     } else {
-	step  = -1;
-
-	start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
-							 in_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
-				  in_vector) < 0)
-	    start = range_step (start, -1, stroker->pen.num_vertices);
-
-	stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
-							 out_vector);
-	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
-				  out_vector) > 0)
-	{
-	    stop = range_step (stop, 1, stroker->pen.num_vertices);
-	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
-				      in_vector) < 0)
-		return;
+	_cairo_pen_find_active_ccw_vertices (pen,
+					     in_vector, out_vector,
+					     &start, &stop);
+	while (start != stop) {
+	    cairo_point_t p = *midpt;
+	    translate_point (&p, &pen->vertices[start].point);
+	    contour_add_point (stroker, c, &p);
+
+	    if (start-- == 0)
+		start += pen->num_vertices;
 	}
-
-	npoints = start - stop;
-    }
-    stop = range_step (stop, step, stroker->pen.num_vertices);
-    if (npoints < 0)
-	npoints += stroker->pen.num_vertices;
-    if (npoints <= 1)
-	return;
-
-    for (i = start;
-	 i != stop;
-	i = range_step (i, step, stroker->pen.num_vertices))
-    {
-	cairo_point_t p = *midpt;
-	translate_point (&p, &stroker->pen.vertices[i].point);
-	contour_add_point (stroker, c, &p);
     }
 }
 
@@ -435,9 +402,7 @@ outer_close (struct stroker *stroker,
 	     in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
 	{
 	    add_fan (stroker,
-		     &in->dev_vector,
-		     &out->dev_vector,
-		     &in->point, inpt, outpt,
+		     &in->dev_vector, &out->dev_vector, &in->point,
 		     clockwise, outer);
 	}
 	break;
@@ -624,9 +589,7 @@ outer_join (struct stroker *stroker,
     case CAIRO_LINE_JOIN_ROUND:
 	/* construct a fan around the common midpoint */
 	add_fan (stroker,
-		 &in->dev_vector,
-		 &out->dev_vector,
-		 &in->point, inpt, outpt,
+		 &in->dev_vector, &out->dev_vector, &in->point,
 		 clockwise, outer);
 	break;
 
@@ -795,9 +758,7 @@ add_cap (struct stroker *stroker,
 	slope.dx = -f->dev_vector.dx;
 	slope.dy = -f->dev_vector.dy;
 
-	add_fan (stroker, &f->dev_vector, &slope,
-		 &f->point, &f->ccw, &f->cw,
-		 FALSE, c);
+	add_fan (stroker, &f->dev_vector, &slope, &f->point, FALSE, c);
 	break;
     }
 
@@ -1159,7 +1120,7 @@ spline_to (void *closure,
 	add_fan (stroker,
 		 &stroker->current_face.dev_vector,
 		 &face.dev_vector,
-		 &stroker->current_face.point, inpt, outpt,
+		 &stroker->current_face.point,
 		 clockwise, outer);
     } else {
 	compute_face (point, tangent, stroker, &face);
@@ -1191,7 +1152,7 @@ spline_to (void *closure,
 	    add_fan (stroker,
 		     &stroker->current_face.dev_vector,
 		     &face.dev_vector,
-		     &stroker->current_face.point, inpt, outpt,
+		     &stroker->current_face.point,
 		     clockwise, outer);
 	}
 
commit 74e9ae8cdff31e9a039b17f7dbe6e80f98e2c047
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 25 23:29:21 2012 +0100

    pen: Use bisection to speed up vertex finding
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index d70a064..cf441c4 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -388,3 +388,84 @@ _cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
 
     return i;
 }
+
+void
+_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
+				    const cairo_slope_t *in,
+				    const cairo_slope_t *out,
+				    int *start, int *stop)
+{
+
+    int lo = 0, hi = pen->num_vertices;
+    int i;
+
+    i = (lo + hi) >> 1;
+    do {
+	if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
+	    lo = i;
+	else
+	    hi = i;
+	i = (lo + hi) >> 1;
+    } while (hi - lo > 1);
+    if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
+	if (++i == pen->num_vertices)
+	    i = 0;
+    *start = i;
+
+    lo = i;
+    hi = i + pen->num_vertices;
+    i = (lo + hi) >> 1;
+    do {
+	int j = i;
+	if (j >= pen->num_vertices)
+	    j -= pen->num_vertices;
+	if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
+	    hi = i;
+	else
+	    lo = i;
+	i = (lo + hi) >> 1;
+    } while (hi - lo > 1);
+    if (i >= pen->num_vertices)
+	i -= pen->num_vertices;
+    *stop = i;
+}
+
+void
+_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
+				     const cairo_slope_t *in,
+				     const cairo_slope_t *out,
+				     int *start, int *stop)
+{
+    int lo = 0, hi = pen->num_vertices;
+    int i;
+
+    i = (lo + hi) >> 1;
+    do {
+	if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0)
+	    lo = i;
+	else
+	    hi = i;
+	i = (lo + hi) >> 1;
+    } while (hi - lo > 1);
+    if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0)
+	if (++i == pen->num_vertices)
+	    i = 0;
+    *start = i;
+
+    lo = i;
+    hi = i + pen->num_vertices;
+    i = (lo + hi) >> 1;
+    do {
+	int j = i;
+	if (j >= pen->num_vertices)
+	    j -= pen->num_vertices;
+	if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
+	    hi = i;
+	else
+	    lo = i;
+	i = (lo + hi) >> 1;
+    } while (hi - lo > 1);
+    if (i >= pen->num_vertices)
+	i -= pen->num_vertices;
+    *stop = i;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 68b25be..7463595 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1555,6 +1555,18 @@ cairo_private int
 _cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
 					 const cairo_slope_t *slope);
 
+cairo_private void
+_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
+				     const cairo_slope_t *in,
+				     const cairo_slope_t *out,
+				     int *start, int *stop);
+
+cairo_private void
+_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
+				     const cairo_slope_t *in,
+				     const cairo_slope_t *out,
+				     int *start, int *stop);
+
 /* cairo-polygon.c */
 cairo_private void
 _cairo_polygon_init (cairo_polygon_t   *polygon,
commit aeb039b16dc302192113a7f10c4b86e7d13eb221
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 25 12:57:01 2012 +0100

    stroke: Skip spline evaluation when stroking to a polygon
    
    If the spline is wholly outside the clip region, accounting for the
    stroke width and additional rendering, then we can simplify that spline
    with a straight line.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index b7c18b7..242fb24 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -81,6 +81,9 @@ struct stroker {
 
     cairo_bool_t has_first_face;
     cairo_stroke_face_t first_face;
+
+    cairo_bool_t has_bounds;
+    cairo_box_t bounds;
 };
 
 static inline double
@@ -165,6 +168,10 @@ add_fan (struct stroker *stroker,
 {
     int start, stop, step, i, npoints;
 
+    if (stroker->has_bounds &&
+	! _cairo_box_contains_point (&stroker->bounds, midpt))
+	return;
+
     assert (stroker->pen.num_vertices);
 
     if (clockwise) {
@@ -1207,6 +1214,11 @@ curve_to (void *closure,
     cairo_spline_t spline;
     cairo_stroke_face_t face;
 
+    if (stroker->has_bounds &&
+	! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+				    &stroker->bounds))
+	return line_to (closure, d);
+
     if (! _cairo_spline_init (&spline, spline_to, stroker,
 			      &stroker->current_face.point, b, c, d))
 	return line_to (closure, d);
@@ -1305,6 +1317,31 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
 							   polygon);
     }
 
+    stroker.has_bounds = polygon->num_limits;
+    if (stroker.has_bounds) {
+	/* Extend the bounds in each direction to account for the maximum area
+	 * we might generate trapezoids, to capture line segments that are
+	 * outside of the bounds but which might generate rendering that's
+	 * within bounds.
+	 */
+	double dx, dy;
+	cairo_fixed_t fdx, fdy;
+	int i;
+
+	stroker.bounds = polygon->limits[0];
+	for (i = 1; i < polygon->num_limits; i++)
+	     _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);
+
+	_cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
+	fdx = _cairo_fixed_from_double (dx);
+	fdy = _cairo_fixed_from_double (dy);
+
+	stroker.bounds.p1.x -= fdx;
+	stroker.bounds.p2.x += fdx;
+	stroker.bounds.p1.y -= fdy;
+	stroker.bounds.p2.y += fdy;
+    }
+
     stroker.style = *style;
     stroker.ctm = ctm;
     stroker.ctm_inverse = ctm_inverse;
commit bdf83008f4b2c723fd8e65e2a92bc47a2e7bc442
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Aug 25 08:39:30 2012 +0100

    compositor: Skip invisible strokes
    
    If the pen is reduced to a single point, it is effectively invisible
    when rasterised, so skip the stroke composition.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-compositor.c b/src/cairo-compositor.c
index a633aa2..b31413b 100644
--- a/src/cairo-compositor.c
+++ b/src/cairo-compositor.c
@@ -139,6 +139,10 @@ _cairo_compositor_stroke (const cairo_compositor_t	*compositor,
     cairo_int_status_t status;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
+
+    if (_cairo_pen_vertices_needed (tolerance, style->line_width/2, ctm) <= 1)
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
     status = _cairo_composite_rectangles_init_for_stroke (&extents, surface,
 							  op, source,
 							  path, style, ctm,
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index e71f7b5..d70a064 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -41,11 +41,6 @@
 #include "cairo-error-private.h"
 #include "cairo-slope-private.h"
 
-static int
-_cairo_pen_vertices_needed (double tolerance,
-			    double radius,
-			    const cairo_matrix_t *matrix);
-
 static void
 _cairo_pen_compute_slopes (cairo_pen_t *pen);
 
@@ -88,10 +83,12 @@ _cairo_pen_init (cairo_pen_t	*pen,
      * is reflecting
      */
     for (i=0; i < pen->num_vertices; i++) {
-	double theta = 2 * M_PI * i / (double) pen->num_vertices;
-	double dx = radius * cos (reflect ? -theta : theta);
-	double dy = radius * sin (reflect ? -theta : theta);
 	cairo_pen_vertex_t *v = &pen->vertices[i];
+	double theta = 2 * M_PI * i / (double) pen->num_vertices, dx, dy;
+	if (reflect)
+	    theta = -theta;
+	dx = radius * cos (theta);
+	dy = radius * sin (theta);
 	cairo_matrix_transform_distance (ctm, &dx, &dy);
 	v->point.x = _cairo_fixed_from_double (dx);
 	v->point.y = _cairo_fixed_from_double (dy);
@@ -273,7 +270,7 @@ Note that this also equation works for M == m (a circle) as it
 doesn't matter where on the circle the error is computed.
 */
 
-static int
+int
 _cairo_pen_vertices_needed (double	    tolerance,
 			    double	    radius,
 			    const cairo_matrix_t  *matrix)
@@ -283,21 +280,16 @@ _cairo_pen_vertices_needed (double	    tolerance,
      * compute major axis length for a pen with the specified radius.
      * we don't need the minor axis length.
      */
+    double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix,
+								     radius);
+    int num_vertices;
 
-    double  major_axis = _cairo_matrix_transformed_circle_major_axis (matrix,
-								      radius);
-
-    /*
-     * compute number of vertices needed
-     */
-    int	    num_vertices;
-
-    /* Where tolerance / M is > 1, we use 4 points */
-    if (tolerance >= major_axis) {
+    if (tolerance >= 2*major_axis) {
+	num_vertices = 1;
+    } else if (tolerance >= major_axis) {
 	num_vertices = 4;
     } else {
-	double delta = acos (1 - tolerance / major_axis);
-	num_vertices = ceil (M_PI / delta);
+	num_vertices = ceil (2*M_PI / acos (1 - tolerance / major_axis));
 
 	/* number of vertices must be even */
 	if (num_vertices % 2)
diff --git a/src/cairoint.h b/src/cairoint.h
index 26a8de1..68b25be 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1524,6 +1524,11 @@ cairo_private cairo_image_color_t
 _cairo_image_analyze_color (cairo_image_surface_t      *image);
 
 /* cairo-pen.c */
+cairo_private int
+_cairo_pen_vertices_needed (double	    tolerance,
+			    double	    radius,
+			    const cairo_matrix_t  *matrix);
+
 cairo_private cairo_status_t
 _cairo_pen_init (cairo_pen_t	*pen,
 		 double		 radius,
commit fc38d7375d4f0342ece91596d71f0ce56aa2c975
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Aug 24 17:39:08 2012 +0100

    xlib/shm: Add missing release of the display after GetImage
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 6127e07..a35ea43 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -779,8 +779,10 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 				    AllPlanes);
 	    XSetErrorHandler (old_handler);
 
-	    if (success)
+	    if (success) {
+		cairo_device_release (&display->base);
 		return &image->base;
+	    }
 
 	    cairo_surface_destroy (&image->base);
 	}


More information about the cairo-commit mailing list