Index: src/cairo-arc-private.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-arc-private.h,v
retrieving revision 1.1
diff -u -p -r1.1 cairo-arc-private.h
--- src/cairo-arc-private.h	26 Apr 2005 19:38:06 -0000	1.1
+++ src/cairo-arc-private.h	10 Aug 2005 03:22:28 -0000
@@ -54,4 +54,11 @@ _cairo_arc_path_negative (cairo_t *cr,
 			  double   angle1,
 			  double   angle2);
 
+void
+_cairo_arc_with_hands (cairo_t *cr,
+			double x0, double y0,
+			double x1, double y1,
+			double x2, double y2,
+			double radius);
+
 #endif /* CAIRO_ARC_PRIVATE_H */
Index: src/cairo-arc.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-arc.c,v
retrieving revision 1.4
diff -u -p -r1.4 cairo-arc.c
--- src/cairo-arc.c	5 Aug 2005 17:05:29 -0000	1.4
+++ src/cairo-arc.c	10 Aug 2005 03:22:28 -0000
@@ -59,7 +59,10 @@
 static double
 _arc_error_normalized (double angle)
 {
-    return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+    double sin_, cos_;
+
+    _cairo_sincos (angle / 4, &sin_, &cos_);
+    return 2.0/27.0 * pow (sin_, 6) / pow (cos_, 2);
 }
 
 static double
@@ -73,8 +76,6 @@ _arc_max_angle_for_tolerance_normalized 
 	double angle;
 	double error;
     } table[] = {
-	{ M_PI / 1.0,   0.0185185185185185036127 },
-	{ M_PI / 2.0,   0.000272567143730179811158 },
 	{ M_PI / 3.0,   2.38647043651461047433e-05 },
 	{ M_PI / 4.0,   4.2455377443222443279e-06 },
 	{ M_PI / 5.0,   1.11281001494389081528e-06 },
@@ -162,10 +163,12 @@ _cairo_arc_segment (cairo_t *cr,
     double r_sin_B, r_cos_B;
     double h;
 
-    r_sin_A = radius * sin (angle_A);
-    r_cos_A = radius * cos (angle_A);
-    r_sin_B = radius * sin (angle_B);
-    r_cos_B = radius * cos (angle_B);
+    _cairo_sincos (angle_A, &r_sin_A, &r_cos_A);
+    _cairo_sincos (angle_B, &r_sin_B, &r_cos_B);
+    r_sin_A *= radius;
+    r_cos_A *= radius;
+    r_sin_B *= radius;
+    r_cos_B *= radius;
 
     h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
 
@@ -294,3 +297,114 @@ _cairo_arc_path_negative (cairo_t *cr,
 			     angle2, angle1,
 			     CAIRO_DIRECTION_REVERSE);
 }
+
+/**
+ * _cairo_arc_with_hands:
+ * @cr: a cairo context
+ * @x0: X position of the first position
+ * @y0: Y position of the first position
+ * @x1: X position of the corner of the joint
+ * @y1: Y position of the corner of the joint
+ * @x2: X position of the final position
+ * @y2: Y position of the final position
+ * @radius: the radius of the arc
+ * 
+ * Adds to the current path straight lines from (@x0,@y0) towards
+ * (@x1,@y1) and from there to (@x2,@y2), but connecting the two
+ * line segments by an arc of specified @radius or less if no such
+ * arc fits.
+ *
+ *
+ *	(x1,y1) + --  --  ----+------------------------+ (x0,y0)
+ *		 \       .-`
+ *		        /
+ *		   \   /     
+ *		      |       + (xc,yc)
+ *		     \|
+ *		      \
+ *		       +
+ *			\
+ *			 \
+ *		 	  \
+ *			   \
+ *			    \
+ *		    (x2,y2) +
+ **/
+void
+_cairo_arc_with_hands (cairo_t *cr,
+		       double x0, double y0,
+		       double x1, double y1,
+	  	       double x2, double y2,
+		       double radius)
+{
+    double angle0, angle1, angle2, angled;
+    double d0, d2;
+    double sin_, cos_;
+    double xc, yc, dc;
+    cairo_direction_t dir;
+
+    angle0 = atan2 (y0 - y1, x0 - x1); /* angle from (x1,y1) to (x0,y0) */
+    angle2 = atan2 (y2 - y1, x2 - x1); /* angle from (x1,y1) to (x2,y2) */
+    angle1 = (angle0 + angle2) / 2;    /* angle from (x1,y1) to (xc,yc) */
+
+    angled = angle2 - angle0;          /* the angle (x0,y0)--(x1,y1)--(x2,y2) */
+
+    /* Shall we go forward or backward?*/
+    if (angled > M_PI || (angled < 0 && angled > -M_PI)) {
+        angle1 += M_PI;
+        angled = 2 * M_PI - angled;
+        dir = CAIRO_DIRECTION_FORWARD;
+    } else {
+        double tmp;
+        tmp = angle0;
+        angle0 = angle2;
+        angle2 = tmp;
+        dir = CAIRO_DIRECTION_REVERSE;
+    }
+
+    angle0 += M_PI_2; /* angle from (xc,yc) to (x0,y0) */
+    angle2 -= M_PI_2; /* angle from (xc,yc) to (x2,y2) */
+    angled /= 2;      /* the angle (x0,y0)--(x1,y1)--(xc,yc) */
+
+
+    /* distance from (x1,y1) to (x0,y0) */
+    d0 = sqrt ((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
+    /* distance from (x2,y2) to (x0,y0) */
+    d2 = sqrt ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
+
+    dc = -1;
+    _cairo_sincos (angled, &sin_, &cos_);
+    if (fabs(cos_) >= 1e-5) { /* the arc may not fit */
+	/* min distance of end-points from corner */
+	double min_d = d0 < d2 ? d0 : d2;
+	/* max radius of an arc that fits */
+	double max_r = min_d * sin_ / cos_;
+
+	if (radius > max_r) {
+	    /* arc with requested radius doesn't fit */
+	    radius = max_r;
+	    dc = min_d / cos_; /* distance of (xc,yc) from (x1,y1) */
+	}
+    }
+
+    if (dc < 0)
+        dc = radius / sin_; /* distance of (xc,yc) from (x1,y1) */
+
+
+    /* find (cx,cy), the center of the arc */
+    _cairo_sincos (angle1, &yc, &xc);
+    xc = x1 + xc * dc;
+    yc = y1 + yc * dc;
+
+
+    /* the arc operation draws the line from current point (x0,y0)
+     * to arc center too. */
+
+    if (dir == CAIRO_DIRECTION_FORWARD)
+        cairo_arc (cr, xc, yc, radius, angle0, angle2);
+    else
+        cairo_arc_negative (cr, xc, yc, radius, angle2, angle0);
+
+    cairo_line_to (cr, x2, y2);
+}
+
Index: src/cairo-matrix.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-matrix.c,v
retrieving revision 1.30
diff -u -p -r1.30 cairo-matrix.c
--- src/cairo-matrix.c	5 Aug 2005 17:05:29 -0000	1.30
+++ src/cairo-matrix.c	10 Aug 2005 03:22:28 -0000
@@ -226,17 +226,12 @@ void
 cairo_matrix_init_rotate (cairo_matrix_t *matrix,
 			  double radians)
 {
-    double  s;
-    double  c;
-#if HAVE_SINCOS
-    sincos (radians, &s, &c);
-#else
-    s = sin (radians);
-    c = cos (radians);
-#endif
+    double  sin_, cos_;
+
+    _cairo_sincos (radians, &sin_, &cos_);
     cairo_matrix_init (matrix,
-		       c, s,
-		       -s, c,
+		       cos_, sin_,
+		       -sin_, cos_,
 		       0, 0);
 }
 slim_hidden_def(cairo_matrix_init_rotate);
Index: src/cairo-pattern.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pattern.c,v
retrieving revision 1.53
diff -u -p -r1.53 cairo-pattern.c
--- src/cairo-pattern.c	5 Aug 2005 01:44:29 -0000	1.53
+++ src/cairo-pattern.c	10 Aug 2005 03:22:29 -0000
@@ -1122,6 +1122,8 @@ _cairo_image_data_set_radial (cairo_radi
 		denumerator = -2.0 * c0_e * c0_c1;
 		
 		if (denumerator != 0.0) {
+		    double sin_, cos_;
+
 		    fraction = (c1_e * c1_e - c0_e * c0_e - c0_c1 * c0_c1) /
 			denumerator;
 
@@ -1132,8 +1134,9 @@ _cairo_image_data_set_radial (cairo_radi
 		    
 		    angle_c0 = acos (fraction);
 		    
-		    c0_y = cos (angle_c0) * c0_c1;
-		    c1_y = sin (angle_c0) * c0_c1;
+		    _cairo_sincos (angle_c0, &sin_, &cos_);
+		    c0_y = cos_ * c0_c1;
+		    c1_y = sin_ * c0_c1;
 		    
 		    y_x = sqrt (r1_2 - c1_y * c1_y);
 		    c0_x = y_x + c0_y;
Index: src/cairo-pen.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-pen.c,v
retrieving revision 1.23
diff -u -p -r1.23 cairo-pen.c
--- src/cairo-pen.c	7 Apr 2005 17:01:49 -0000	1.23
+++ src/cairo-pen.c	10 Aug 2005 03:22:29 -0000
@@ -102,8 +102,11 @@ _cairo_pen_init (cairo_pen_t *pen, doubl
      */
     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);
+	double dx, dy;
+
+	_cairo_sincos (reflect ? -theta : theta, &dx, &dy);
+	dx *= radius;
+	dy *= radius;
 	cairo_pen_vertex_t *v = &pen->vertices[i];
 	cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
 	v->point.x = _cairo_fixed_from_double (dx);
Index: src/cairo.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.c,v
retrieving revision 1.123
diff -u -p -r1.123 cairo.c
--- src/cairo.c	9 Aug 2005 01:35:22 -0000	1.123
+++ src/cairo.c	10 Aug 2005 03:22:29 -0000
@@ -1057,6 +1057,8 @@ cairo_arc (cairo_t *cr,
 	   double radius,
 	   double angle1, double angle2)
 {
+    double sin_, cos_;
+
     if (cr->status) {
 	_cairo_set_error (cr, cr->status);
 	return;
@@ -1069,9 +1071,11 @@ cairo_arc (cairo_t *cr,
     while (angle2 < angle1)
 	angle2 += 2 * M_PI;
 
+    _cairo_sincos (angle1, &sin_, &cos_);
+
     cairo_line_to (cr,
-		   xc + radius * cos (angle1),
-		   yc + radius * sin (angle1));
+		   xc + radius * cos_,
+		   yc + radius * sin_);
 
     _cairo_arc_path (cr, xc, yc, radius,
 		     angle1, angle2);
@@ -1097,6 +1101,8 @@ cairo_arc_negative (cairo_t *cr,
 		    double radius,
 		    double angle1, double angle2)
 {
+    double sin_, cos_;
+
     if (cr->status) {
 	_cairo_set_error (cr, cr->status);
 	return;
@@ -1109,30 +1115,51 @@ cairo_arc_negative (cairo_t *cr,
     while (angle2 > angle1)
 	angle2 -= 2 * M_PI;
 
+    _cairo_sincos (angle1, &sin_, &cos_);
+
     cairo_line_to (cr,
-		   xc + radius * cos (angle1),
-		   yc + radius * sin (angle1));
+		   xc + radius * cos_,
+		   yc + radius * sin_);
 
-     _cairo_arc_path_negative (cr, xc, yc, radius,
-			       angle1, angle2);
+    _cairo_arc_path_negative (cr, xc, yc, radius,
+			      angle1, angle2);
 }
 
-/* XXX: NYI
+/**
+ * cairo_arc_to:
+ * @cr: a cairo context
+ * @x1: X position of the corner of the joint
+ * @y1: Y position of the corner of the joint
+ * @x2: X position of the final position
+ * @y2: Y position of the final position
+ * @radius: the radius of the arc
+ * 
+ * Adds to the current path straight line segments from current point
+ * towards (@x1,@y1) and from there to (@x2,@y2), but connecting the two
+ * line segments by an arc of specified @radius or less if no such arc
+ * fits.
+ **/
 void
 cairo_arc_to (cairo_t *cr,
 	      double x1, double y1,
 	      double x2, double y2,
 	      double radius)
 {
+    double x0, y0;
+
     if (cr->status)
 	return;
 
-    cr->status = _cairo_gstate_arc_to (cr->gstate,
-				       x1, y1,
-				       x2, y2,
-				       radius);
+    cairo_get_current_point (cr, &x0, &y0);
+
+
+
+    _cairo_arc_with_hands (cr,
+			   x0, y0,
+			   x1, y1,
+			   x2, y2,
+			   radius);
 }
-*/
 
 void
 cairo_rel_move_to (cairo_t *cr, double dx, double dy)
Index: src/cairo.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.h,v
retrieving revision 1.146
diff -u -p -r1.146 cairo.h
--- src/cairo.h	9 Aug 2005 01:35:22 -0000	1.146
+++ src/cairo.h	10 Aug 2005 03:22:29 -0000
@@ -435,13 +435,11 @@ cairo_arc_negative (cairo_t *cr,
 		    double radius,
 		    double angle1, double angle2);
 
-/* XXX: NYI
 void
 cairo_arc_to (cairo_t *cr,
 	      double x1, double y1,
 	      double x2, double y2,
 	      double radius);
-*/
 
 void
 cairo_rel_move_to (cairo_t *cr, double dx, double dy);
Index: src/cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.188
diff -u -p -r1.188 cairoint.h
--- src/cairoint.h	9 Aug 2005 01:35:22 -0000	1.188
+++ src/cairoint.h	10 Aug 2005 03:22:29 -0000
@@ -66,6 +66,16 @@
 #include "cairo-debug.h"
 #include <pixman.h>
 
+#if HAVE_SINCOS
+# define _cairo_sincos(angle,s,c) sincos((angle), (s), (c))
+#else
+# define _cairo_sincos(angle,s,c) do { \
+	double _sincos_angle = (angle); \
+	*(s) = sin(_sincos_angle); \
+	*(c) = cos(_sincos_angle); \
+	} while (0)
+#endif
+
 #if __GNUC__ >= 3 && defined(__ELF__)
 # define slim_hidden_proto(name)	slim_hidden_proto1(name, INT_##name)
 # define slim_hidden_def(name)		slim_hidden_def1(name, INT_##name)
