summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog21
-rw-r--r--TODO52
-rw-r--r--configure.in2
-rw-r--r--src/cairo-font.c11
-rw-r--r--src/cairo-gstate.c268
-rw-r--r--src/cairo.c47
-rw-r--r--src/cairo.h20
-rw-r--r--src/cairo_font.c11
-rw-r--r--src/cairo_gstate.c268
-rw-r--r--src/cairoint.h12
10 files changed, 698 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 0721dd35..824d661f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,23 @@
-2003-09-27 Carl Worth <cworth@isi.edu>
+2003-09-29 Carl Worth <cworth@isi.edu>
+
+ * configure.in (CAIRO_VERSION): Bumpred version to 0.1.6 to
+ indicate new cairo_arc and cairo_arc_negative.
+
+ * src/cairo_gstate.c (_arc_error_normalized):
+ (_arc_max_angle_for_tolerance_normalized):
+ (_cairo_gstate_arc_segments_needed):
+ (_cairo_gstate_arc_segment):
+ (_cairo_gstate_arc_dir):
+ (_cairo_gstate_arc):
+ (_cairo_gstate_arc_negative): Several new functions to implement
+ arc support.
+
+ * src/cairo.h: Added cairo_arc and cairo_arc_negative.
+
+ * src/cairo.c (cairo_arc):
+ (cairo_arc_negative): Added new arc support.
+
+2003-09-27 Carl Worth <cworth@isi.edu>
* src/cairoint.h: Fixed several enum symbols that had been
mistakenly converted to lowercase at some point.
diff --git a/TODO b/TODO
index fc1f9373..0ac2e234 100644
--- a/TODO
+++ b/TODO
@@ -11,12 +11,13 @@ compiled conditionally.
* Verification, profiling, optimization.
-
Some notes on arc support
--------------------------
+=========================
-"Approximation of circular arcs by cubic poynomials", Michael Goldapp,
-Computer Aided Geometric Design 8 (1991) 227-238.
+Some general notions
+--------------------
+This is from "Approximation of circular arcs by cubic poynomials",
+Michael Goldapp, Computer Aided Geometric Design 8 (1991) 227-238.
To draw a unit arc from 0 to A with 0 < A < pi/2:
@@ -37,9 +38,14 @@ A simpler error function to work with is:
e(t) = x^2(t) + y^2(t) - 1
-And from Dokken[cite]: e(t) ~ 2 abs( rho(t) )
+And from "Good approximation of circles by curvature-continuous Bezier
+curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
+Design 8 (1990) 22-41, we learn:
+
+ e(t) ~ 2 abs( rho(t) )
-A single cubic Bezier spline approximation must have the 4 control points:
+Continuing with Goldapp's analysis, a single cubic Bezier spline
+approximation must have the 4 control points:
(1, 0)
(1, h)
@@ -55,7 +61,38 @@ From which we can determine the maximum error:
abs( max(e(t)) ) = 4/27 * (sin^6 (A/4)) / (cos^2 (A/4))
t in [0,1]
-
+
+-----
+
+Now, for Cairo we want to draw an arc of radius R from an angle A to
+an angle B, (where B > A). So the equations above have trivial
+modifications:
+
+The spline control points become
+
+ (R * cos(A), R * sin(A))
+ (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
+ (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
+ (R * cos(B), R * sin(B))
+
+where h = 4/3 * R * tan ((B-A)/4)
+
+And the maximum deviation in radius is approximately:
+
+ 2/27 * (sin^6 ((B-A)/4) / cos^2 ((B-A)/4))
+
+So now we can get down to writing some C code:
+
+double
+_arc_error_normalized (double angle)
+{
+ return 2/27 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+}
+
+And for accurate drawing the following must hold in device space:
+
+ tolerance/radius >= _arc_error_normalized (B-A)
+
A comparison with PostScript
============================
@@ -190,4 +227,3 @@ Operators, Rational,Boolean,and Bitwise Operators, Control Operators,
Type,Attribute,and Conversion Operators, File Operators, Resource
Operators, Virtual Memory Operators, Miscellaneous Operators,
Interpreter Parameter Operators, Errors
-
diff --git a/configure.in b/configure.in
index 00507343..4ad94a08 100644
--- a/configure.in
+++ b/configure.in
@@ -3,7 +3,7 @@ AC_INIT(src/cairo.h)
dnl ===========================================================================
# Package version number, (as distinct from shared library version)
-CAIRO_VERSION=0.1.5
+CAIRO_VERSION=0.1.6
# libtool shared library version
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 4f43f813..0494995b 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -142,7 +142,16 @@ _cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFon
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
- for non-uniform X/Y scaling? */
+ for non-uniform X/Y scaling?
+
+ XXX: Actually, the reasoning above is bogus. A transformation
+ such as scale (N, 1/N) will give an expansion_factor of 1. So,
+ with the code below we'll end up with font_size == 1 instead of
+ N, (so the hinting will be all wrong). I think we want to use
+ the maximum eigen value rather than the square root of the
+ determinant.
+
+ */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index b874db49..7d1cdfc3 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -707,6 +707,272 @@ _cairo_gstate_curve_to (cairo_gstate_t *gstate,
return status;
}
+/* Spline deviation from the circle in radius would be given by:
+
+ error = sqrt (x**2 + y**2) - 1
+
+ A simpler error function to work with is:
+
+ e = x**2 + y**2 - 1
+
+ From "Good approximation of circles by curvature-continuous Bezier
+ curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
+ Design 8 (1990) 22-41, we learn:
+
+ abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
+
+ and
+ abs (error) =~ 1/2 * e
+
+ Of course, this error value applies only for the particular spline
+ approximation that is used in _cairo_gstate_arc_segment.
+*/
+static double
+_arc_error_normalized (double angle)
+{
+ return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+}
+
+static double
+_arc_max_angle_for_tolerance_normalized (double tolerance)
+{
+ double angle, error;
+ int i;
+
+ /* Use table lookup to reduce search time in most cases. */
+ struct {
+ 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 },
+ { M_PI / 6.0, 3.72662000942734705475e-07 },
+ { M_PI / 7.0, 1.47783685574284411325e-07 },
+ { M_PI / 8.0, 6.63240432022601149057e-08 },
+ { M_PI / 9.0, 3.2715520137536980553e-08 },
+ { M_PI / 10.0, 1.73863223499021216974e-08 },
+ { M_PI / 11.0, 9.81410988043554039085e-09 },
+ };
+ int table_size = (sizeof (table) / sizeof (table[0]));
+
+ for (i = 0; i < table_size; i++)
+ if (table[i].error < tolerance)
+ return table[i].angle;
+
+ ++i;
+ do {
+ angle = M_PI / i++;
+ error = _arc_error_normalized (angle);
+ } while (error > tolerance);
+
+ return angle;
+}
+
+static int
+_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
+ double angle,
+ double radius)
+{
+ double l1, l2, lmax;
+ double max_angle;
+
+ _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
+
+ l1 = fabs (l1);
+ l2 = fabs (l2);
+ if (l1 > l2)
+ lmax = l1;
+ else
+ lmax = l2;
+
+ max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
+
+ return (int) ceil (angle / max_angle);
+}
+
+/* We want to draw a single spline approximating a circular arc radius
+ R from angle A to angle B. Since we want a symmetric spline that
+ matches the endpoints of the arc in position and slope, we know
+ that the spline control points must be:
+
+ (R * cos(A), R * sin(A))
+ (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
+ (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
+ (R * cos(B), R * sin(B))
+
+ for some value of h.
+
+ "Approximation of circular arcs by cubic poynomials", Michael
+ Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
+ various values of h along with error analysis for each.
+
+ From that paper, a very practical value of h is:
+
+ h = 4/3 * tan(angle/4)
+
+ This value does not give the spline with minimal error, but it does
+ provide a very good approximation, (6th-order convergence), and the
+ error expression is quite simple, (see the comment for
+ _arc_error_normalized).
+*/
+static cairo_status_t
+_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle_A, double angle_B)
+{
+ cairo_status_t status;
+ double r_sin_A, r_cos_A;
+ 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);
+
+ h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
+
+ status = _cairo_gstate_curve_to (gstate,
+ xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
+ xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
+ xc + r_cos_B, yc + r_sin_B);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle_min,
+ double angle_max,
+ cairo_direction_t dir)
+{
+ cairo_status_t status;
+
+ while (angle_max - angle_min > 4 * M_PI)
+ angle_max -= 2 * M_PI;
+
+ /* Recurse if drawing arc larger than pi */
+ if (angle_max - angle_min > M_PI) {
+ /* XXX: Something tells me this block could be condensed. */
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min, angle_min + M_PI, dir);
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min + M_PI, angle_max, dir);
+ if (status)
+ return status;
+ } else {
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min + M_PI, angle_max, dir);
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min, angle_min + M_PI, dir);
+ if (status)
+ return status;
+ }
+ } else {
+ int i, segments;
+ double angle, angle_step;
+
+ segments = _cairo_gstate_arc_segments_needed (gstate,
+ angle_max - angle_min,
+ radius);
+ angle_step = (angle_max - angle_min) / (double) segments;
+
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ angle = angle_min;
+ } else {
+ angle = angle_max;
+ angle_step = - angle_step;
+ }
+
+ for (i = 0; i < segments; i++, angle += angle_step) {
+ _cairo_gstate_arc_segment (gstate,
+ xc, yc,
+ radius,
+ angle,
+ angle + angle_step);
+ }
+
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_arc (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ cairo_status_t status;
+
+ while (angle2 < angle1)
+ angle2 += 2 * M_PI;
+
+ status = _cairo_gstate_line_to (gstate,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle1, angle2, CAIRO_DIRECTION_FORWARD);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ cairo_status_t status;
+
+ while (angle2 > angle1)
+ angle2 -= 2 * M_PI;
+
+ status = _cairo_gstate_line_to (gstate,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle2, angle1, CAIRO_DIRECTION_REVERSE);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* XXX: NYI
+cairo_status_t
+_cairo_gstate_arc_to (cairo_gstate_t *gstate,
+ double x1, double y1,
+ double x2, double y2,
+ double radius)
+{
+
+}
+*/
+
cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
{
@@ -775,7 +1041,7 @@ _cairo_gstate_stroke_path (cairo_gstate_t *gstate)
{
cairo_status_t status;
- _cairo_pen_init (&gstate
+ _cairo_pen_init (&gstate);
return CAIRO_STATUS_SUCCESS;
}
*/
diff --git a/src/cairo.c b/src/cairo.c
index b1043ccd..909529c5 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -478,6 +478,53 @@ cairo_curve_to (cairo_t *cr,
}
void
+cairo_arc (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_arc (cr->gstate,
+ xc, yc,
+ radius,
+ angle1, angle2);
+}
+
+void
+cairo_arc_negative (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_arc_negative (cr->gstate,
+ xc, yc,
+ radius,
+ angle1, angle2);
+}
+
+/* XXX: NYI
+void
+cairo_arc_to (cairo_t *cr,
+ double x1, double y1,
+ double x2, double y2,
+ double radius)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_arc_to (cr->gstate,
+ x1, y1,
+ x2, y2,
+ radius);
+}
+*/
+
+void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
if (cr->status)
diff --git a/src/cairo.h b/src/cairo.h
index 171565d1..9a375f0e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -261,6 +261,26 @@ cairo_curve_to (cairo_t *cr,
double x3, double y3);
extern void __external_linkage
+cairo_arc (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+extern void __external_linkage
+cairo_arc_negative (cairo_t *cr,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+/* XXX: NYI
+extern void __external_linkage
+cairo_arc_to (cairo_t *cr,
+ double x1, double y1,
+ double x2, double y2,
+ double radius);
+*/
+
+extern void __external_linkage
cairo_rel_move_to (cairo_t *cr, double dx, double dy);
extern void __external_linkage
diff --git a/src/cairo_font.c b/src/cairo_font.c
index 4f43f813..0494995b 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -142,7 +142,16 @@ _cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFon
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
- for non-uniform X/Y scaling? */
+ for non-uniform X/Y scaling?
+
+ XXX: Actually, the reasoning above is bogus. A transformation
+ such as scale (N, 1/N) will give an expansion_factor of 1. So,
+ with the code below we'll end up with font_size == 1 instead of
+ N, (so the hinting will be all wrong). I think we want to use
+ the maximum eigen value rather than the square root of the
+ determinant.
+
+ */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index b874db49..7d1cdfc3 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -707,6 +707,272 @@ _cairo_gstate_curve_to (cairo_gstate_t *gstate,
return status;
}
+/* Spline deviation from the circle in radius would be given by:
+
+ error = sqrt (x**2 + y**2) - 1
+
+ A simpler error function to work with is:
+
+ e = x**2 + y**2 - 1
+
+ From "Good approximation of circles by curvature-continuous Bezier
+ curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
+ Design 8 (1990) 22-41, we learn:
+
+ abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
+
+ and
+ abs (error) =~ 1/2 * e
+
+ Of course, this error value applies only for the particular spline
+ approximation that is used in _cairo_gstate_arc_segment.
+*/
+static double
+_arc_error_normalized (double angle)
+{
+ return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+}
+
+static double
+_arc_max_angle_for_tolerance_normalized (double tolerance)
+{
+ double angle, error;
+ int i;
+
+ /* Use table lookup to reduce search time in most cases. */
+ struct {
+ 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 },
+ { M_PI / 6.0, 3.72662000942734705475e-07 },
+ { M_PI / 7.0, 1.47783685574284411325e-07 },
+ { M_PI / 8.0, 6.63240432022601149057e-08 },
+ { M_PI / 9.0, 3.2715520137536980553e-08 },
+ { M_PI / 10.0, 1.73863223499021216974e-08 },
+ { M_PI / 11.0, 9.81410988043554039085e-09 },
+ };
+ int table_size = (sizeof (table) / sizeof (table[0]));
+
+ for (i = 0; i < table_size; i++)
+ if (table[i].error < tolerance)
+ return table[i].angle;
+
+ ++i;
+ do {
+ angle = M_PI / i++;
+ error = _arc_error_normalized (angle);
+ } while (error > tolerance);
+
+ return angle;
+}
+
+static int
+_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
+ double angle,
+ double radius)
+{
+ double l1, l2, lmax;
+ double max_angle;
+
+ _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
+
+ l1 = fabs (l1);
+ l2 = fabs (l2);
+ if (l1 > l2)
+ lmax = l1;
+ else
+ lmax = l2;
+
+ max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
+
+ return (int) ceil (angle / max_angle);
+}
+
+/* We want to draw a single spline approximating a circular arc radius
+ R from angle A to angle B. Since we want a symmetric spline that
+ matches the endpoints of the arc in position and slope, we know
+ that the spline control points must be:
+
+ (R * cos(A), R * sin(A))
+ (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
+ (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
+ (R * cos(B), R * sin(B))
+
+ for some value of h.
+
+ "Approximation of circular arcs by cubic poynomials", Michael
+ Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
+ various values of h along with error analysis for each.
+
+ From that paper, a very practical value of h is:
+
+ h = 4/3 * tan(angle/4)
+
+ This value does not give the spline with minimal error, but it does
+ provide a very good approximation, (6th-order convergence), and the
+ error expression is quite simple, (see the comment for
+ _arc_error_normalized).
+*/
+static cairo_status_t
+_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle_A, double angle_B)
+{
+ cairo_status_t status;
+ double r_sin_A, r_cos_A;
+ 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);
+
+ h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
+
+ status = _cairo_gstate_curve_to (gstate,
+ xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
+ xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
+ xc + r_cos_B, yc + r_sin_B);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle_min,
+ double angle_max,
+ cairo_direction_t dir)
+{
+ cairo_status_t status;
+
+ while (angle_max - angle_min > 4 * M_PI)
+ angle_max -= 2 * M_PI;
+
+ /* Recurse if drawing arc larger than pi */
+ if (angle_max - angle_min > M_PI) {
+ /* XXX: Something tells me this block could be condensed. */
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min, angle_min + M_PI, dir);
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min + M_PI, angle_max, dir);
+ if (status)
+ return status;
+ } else {
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min + M_PI, angle_max, dir);
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle_min, angle_min + M_PI, dir);
+ if (status)
+ return status;
+ }
+ } else {
+ int i, segments;
+ double angle, angle_step;
+
+ segments = _cairo_gstate_arc_segments_needed (gstate,
+ angle_max - angle_min,
+ radius);
+ angle_step = (angle_max - angle_min) / (double) segments;
+
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ angle = angle_min;
+ } else {
+ angle = angle_max;
+ angle_step = - angle_step;
+ }
+
+ for (i = 0; i < segments; i++, angle += angle_step) {
+ _cairo_gstate_arc_segment (gstate,
+ xc, yc,
+ radius,
+ angle,
+ angle + angle_step);
+ }
+
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_arc (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ cairo_status_t status;
+
+ while (angle2 < angle1)
+ angle2 += 2 * M_PI;
+
+ status = _cairo_gstate_line_to (gstate,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle1, angle2, CAIRO_DIRECTION_FORWARD);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2)
+{
+ cairo_status_t status;
+
+ while (angle2 > angle1)
+ angle2 -= 2 * M_PI;
+
+ status = _cairo_gstate_line_to (gstate,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+ if (status)
+ return status;
+
+ status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
+ angle2, angle1, CAIRO_DIRECTION_REVERSE);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* XXX: NYI
+cairo_status_t
+_cairo_gstate_arc_to (cairo_gstate_t *gstate,
+ double x1, double y1,
+ double x2, double y2,
+ double radius)
+{
+
+}
+*/
+
cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
{
@@ -775,7 +1041,7 @@ _cairo_gstate_stroke_path (cairo_gstate_t *gstate)
{
cairo_status_t status;
- _cairo_pen_init (&gstate
+ _cairo_pen_init (&gstate);
return CAIRO_STATUS_SUCCESS;
}
*/
diff --git a/src/cairoint.h b/src/cairoint.h
index cd4ec4cd..307b9703 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -544,6 +544,18 @@ _cairo_gstate_curve_to (cairo_gstate_t *gstate,
double x3, double y3);
extern cairo_status_t __internal_linkage
+_cairo_gstate_arc (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+extern cairo_status_t __internal_linkage
+_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
+ double xc, double yc,
+ double radius,
+ double angle1, double angle2);
+
+extern cairo_status_t __internal_linkage
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
extern cairo_status_t __internal_linkage