[cairo-commit] 9 commits - ROADMAP src/cairo.c src/cairo-path-stroke.c src/cairo-ps-surface.c test/degenerate-path.c test/degenerate-path-ref.png test/degenerate-path-rgb24-ref.png test/Makefile.am

Carl Worth cworth at kemper.freedesktop.org
Tue Jun 27 06:43:49 PDT 2006


 ROADMAP                            |    2 
 src/cairo-path-stroke.c            |   76 +++++++++++++++++++++----------------
 src/cairo-ps-surface.c             |    7 +++
 src/cairo.c                        |   50 ++++++++++++++++++------
 test/Makefile.am                   |    4 +
 test/degenerate-path-ref.png       |binary
 test/degenerate-path-rgb24-ref.png |binary
 test/degenerate-path.c             |   68 +++++++++++++++++++++++++++++++++
 8 files changed, 163 insertions(+), 44 deletions(-)

New commits:
diff-tree 34f24d2aad90d4a737b513ac6858ed879316e132 (from 988a28e259924e7ce50f4d3119bcef7a3b18c931)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Jun 27 15:38:45 2006 +0200

    ROADMAP: Note that degenerate path stuff has been pushed out now.

diff --git a/ROADMAP b/ROADMAP
index eccbd46..6d21090 100644
--- a/ROADMAP
+++ b/ROADMAP
@@ -61,7 +61,7 @@ cairo 1.2.0 plans
     ✓	   PS emit_glyph function needs to support bitmapped glyphs
     ✓	   SVG emit_glyph function needs to support bitmapped glyphs
     ✓	   PDF: minefield page one is falling back unnecessarily
-	   should be possible to draw caps with degenerate paths
+    ✓	   should be possible to draw caps with degenerate paths
 
  Fix memory leaks
      1. Ensure 'make check-valgrind' passes with no leaks
diff-tree 988a28e259924e7ce50f4d3119bcef7a3b18c931 (from parents)
Merge: 973c9abd53df4e6d6583de045514e003827bc7b9 ce2b9e1b5cc816e4a6a4345daab539cc58e2d043
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Jun 27 15:37:58 2006 +0200

    Merge branch 'degenerate-path' into cairo

diff-tree 973c9abd53df4e6d6583de045514e003827bc7b9 (from 5d60ceb9b85a6b39865bc760ef7467c10f2ec7b6)
Author: Jeff Muizelaar <jeff at infidigm.net>
Date:   Tue Jun 27 15:33:47 2006 +0200

    PS: Workaround to avoid splitting final ~> terminating sequence.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index ced69e2..d72c3c0 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1336,6 +1336,13 @@ _string_array_stream_write (cairo_output
 	    stream->column++;
 	    stream->string_size++;
 	    break;
+	/* Have to also be careful to never split the final ~> sequence. */
+	case '~':
+	    _cairo_output_stream_write (stream->output, &c, 1);
+	    stream->column++;
+	    stream->string_size++;
+	    c = *data++;
+	    break;
 	}
 	_cairo_output_stream_write (stream->output, &c, 1);
 	stream->column++;
diff-tree ce2b9e1b5cc816e4a6a4345daab539cc58e2d043 (from 58a60ed9fdd53a4cf29d33624b866bf6ccd637ae)
Author: Carl Worth <cworth at cworth.org>
Date:   Sun Jun 25 16:57:59 2006 +0200

    Prefer TRUE and FALSE over 1 and 0 for assigning cairo_bool_t values

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 92152e8..4ba321e 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -670,11 +670,11 @@ _cairo_stroker_line_to (void *closure, c
     } else {
 	if (!stroker->has_first_face) {
 	    stroker->first_face = start;
-	    stroker->has_first_face = 1;
+	    stroker->has_first_face = TRUE;
 	}
     }
     stroker->current_face = end;
-    stroker->has_current_face = 1;
+    stroker->has_current_face = TRUE;
 
     stroker->current_point = *point;
 
@@ -693,7 +693,7 @@ _cairo_stroker_line_to_dashed (void *clo
     double dx, dy;
     double dx2, dy2;
     cairo_point_t fd1, fd2;
-    int first = 1;
+    cairo_bool_t first = TRUE;
     cairo_stroke_face_t sub_start, sub_end;
     cairo_point_t *p1 = &stroker->current_point;
     cairo_point_t *p2 = point;
@@ -751,7 +751,7 @@ _cairo_stroker_line_to_dashed (void *clo
 		} else {
 		    if (!stroker->has_first_face) {
 			stroker->first_face = sub_start;
-			stroker->has_first_face = 1;
+			stroker->has_first_face = TRUE;
 		    } else {
 			status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
 			if (status)
@@ -772,7 +772,7 @@ _cairo_stroker_line_to_dashed (void *clo
 		 * through
 		 */
 		stroker->current_face = sub_end;
-		stroker->has_current_face = 1;
+		stroker->has_current_face = TRUE;
 	    }
 	} else {
 	    /*
@@ -787,11 +787,11 @@ _cairo_stroker_line_to_dashed (void *clo
 		}
 	    }
 	    if (!remain)
-		stroker->has_current_face = 0;
+		stroker->has_current_face = FALSE;
 	}
 	_cairo_stroker_step_dash (stroker, tmp);
 	fd1 = fd2;
-	first = 0;
+	first = FALSE;
     }
 
     stroker->current_point = *point;
@@ -831,11 +831,11 @@ _cairo_stroker_curve_to (void *closure,
     } else {
 	if (!stroker->has_first_face) {
 	    stroker->first_face = start;
-	    stroker->has_first_face = 1;
+	    stroker->has_first_face = TRUE;
 	}
     }
     stroker->current_face = end;
-    stroker->has_current_face = 1;
+    stroker->has_current_face = TRUE;
 
     extra_points[0] = start.cw;
     extra_points[0].x -= start.point.x;
@@ -958,9 +958,9 @@ _cairo_stroker_close_path (void *closure
 	    return status;
     }
 
-    stroker->has_sub_path = 0;
-    stroker->has_first_face = 0;
-    stroker->has_current_face = 0;
+    stroker->has_sub_path = FALSE;
+    stroker->has_first_face = FALSE;
+    stroker->has_current_face = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
diff-tree 58a60ed9fdd53a4cf29d33624b866bf6ccd637ae (from 773cb6475b68199e5ef0839cd22c9f3445d7d5d3)
Author: Carl Worth <cworth at cworth.org>
Date:   Sun Jun 25 16:53:13 2006 +0200

    Prefer sub-path over subpath in documentation.

diff --git a/src/cairo.c b/src/cairo.c
index d00a5f6..9b4154a 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1183,7 +1183,7 @@ slim_hidden_def(cairo_new_path);
  * @x: the X coordinate of the new position
  * @y: the Y coordinate of the new position
  *
- * Begin a new subpath. After this call the current point will be (@x,
+ * Begin a new sub-path. After this call the current point will be (@x,
  * @y).
  **/
 void
@@ -1208,14 +1208,14 @@ slim_hidden_def(cairo_move_to);
  * cairo_new_sub_path:
  * @cr: a cairo context
  *
- * Begin a new subpath. Note that the existing path is not
+ * Begin a new sub-path. Note that the existing path is not
  * affected. After this call there will be no current point.
  *
- * In many cases, this call is not needed since new subpaths are
+ * In many cases, this call is not needed since new sub-paths are
  * frequently started with cairo_move_to().
  *
  * A call to cairo_new_sub_path() is particularly useful when
- * beginning a new subpath with one of the cairo_arc() calls. This
+ * beginning a new sub-path with one of the cairo_arc() calls. This
  * makes things easier as it is no longer necessary to manually
  * compute the arc's initial coordinates for a call to
  * cairo_move_to().
@@ -1447,7 +1447,7 @@ cairo_arc_to (cairo_t *cr,
  * @dx: the X offset
  * @dy: the Y offset
  *
- * Begin a new subpath. After this call the current point will offset
+ * Begin a new sub-path. After this call the current point will offset
  * by (@x, @y).
  *
  * Given a current point of (x, y), cairo_rel_move_to(@cr, @dx, @dy)
@@ -1578,7 +1578,7 @@ cairo_rel_curve_to (cairo_t *cr,
  * @width: the width of the rectangle
  * @height: the height of the rectangle
  *
- * Adds a closed-subpath rectangle of the given size to the current
+ * Adds a closed sub-path rectangle of the given size to the current
  * path at position (@x, @y) in user-space coordinates.
  *
  * This function is logically equivalent to:
@@ -1623,15 +1623,15 @@ cairo_stroke_to_path (cairo_t *cr)
  * @cr: a cairo context
  *
  * Adds a line segment to the path from the current point to the
- * beginning of the current subpath, (the most recent point passed to
- * cairo_move_to()), and closes this subpath. After this call the
- * current point will be at the joined endpoint of the subpath.
+ * beginning of the current sub-path, (the most recent point passed to
+ * cairo_move_to()), and closes this sub-path. After this call the
+ * current point will be at the joined endpoint of the sub-path.
  *
  * The behavior of cairo_close_path() is distinct from simply calling
  * cairo_line_to() with the equivalent coordinate in the case of
- * stroking. When a closed subpath is stroked, there are no caps on
- * the ends of the subpath. Instead, there is a line join connecting
- * the final and initial segments of the subpath.
+ * stroking. When a closed sub-path is stroked, there are no caps on
+ * the ends of the sub-path. Instead, there is a line join connecting
+ * the final and initial segments of the sub-path.
  *
  * If there is no current point before the call to cairo_close_path,
  * this function will have no effect.
diff-tree 773cb6475b68199e5ef0839cd22c9f3445d7d5d3 (from 8f0dd658b1fff3f4e9225b8fb23884f0bbcdb822)
Author: Carl Worth <cworth at cworth.org>
Date:   Sun Jun 25 16:51:25 2006 +0200

    Prefer sub_path over subpath in identifiers.

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 3fc078c..92152e8 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -50,7 +50,7 @@ typedef struct cairo_stroker {
     cairo_point_t current_point;
     cairo_point_t first_point;
 
-    cairo_bool_t has_subpath;
+    cairo_bool_t has_sub_path;
 
     cairo_bool_t has_current_face;
     cairo_stroke_face_t current_face;
@@ -166,7 +166,7 @@ _cairo_stroker_init (cairo_stroker_t		*s
 
     stroker->has_current_face = FALSE;
     stroker->has_first_face = FALSE;
-    stroker->has_subpath = FALSE;
+    stroker->has_sub_path = FALSE;
 
     if (stroker->style->dash)
 	_cairo_stroker_start_dash (stroker);
@@ -470,8 +470,8 @@ static cairo_status_t
 _cairo_stroker_add_caps (cairo_stroker_t *stroker)
 {
     cairo_status_t status;
-    /* check for a degenerative subpath */
-    if (stroker->has_subpath
+    /* check for a degenerative sub_path */
+    if (stroker->has_sub_path
 	&& !stroker->has_first_face
 	&& !stroker->has_current_face
 	&& stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND)
@@ -627,7 +627,7 @@ _cairo_stroker_move_to (void *closure, c
 
     stroker->has_first_face = FALSE;
     stroker->has_current_face = FALSE;
-    stroker->has_subpath = FALSE;
+    stroker->has_sub_path = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -652,7 +652,7 @@ _cairo_stroker_line_to (void *closure, c
     cairo_point_t *p2 = point;
     cairo_slope_t slope;
 
-    stroker->has_subpath = TRUE;
+    stroker->has_sub_path = TRUE;
 
     if (p1->x == p2->x && p1->y == p2->y)
 	return CAIRO_STATUS_SUCCESS;
@@ -958,7 +958,7 @@ _cairo_stroker_close_path (void *closure
 	    return status;
     }
 
-    stroker->has_subpath = 0;
+    stroker->has_sub_path = 0;
     stroker->has_first_face = 0;
     stroker->has_current_face = 0;
 
diff-tree 8f0dd658b1fff3f4e9225b8fb23884f0bbcdb822 (from 15caa88c6416ce8e0c4c026e76f84ccaf7a3c840)
Author: Carl Worth <cworth at cworth.org>
Date:   Sun Jun 25 16:49:45 2006 +0200

    Add documentation for how degenerate segments and sub-paths are treated.

diff --git a/src/cairo.c b/src/cairo.c
index 7d6d4bc..d00a5f6 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -900,6 +900,11 @@ cairo_set_line_join (cairo_t *cr, cairo_
  * stroke. The @offset specifies an offset into the pattern at which
  * the stroke begins.
  *
+ * Each "on" segment will have caps applied as if the segment were a
+ * separate sub-path. In particular, it is valid to use an "on" length
+ * of 0.0 with CAIRO_LINE_CAP_ROUND or CAIRO_LINE_CAP_SQUARE in order
+ * to distributed dots or squares along a path.
+ *
  * Note: The length values are in user-space units as evaluated at the
  * time of stroking. This is not necessarily the same as the user
  * space at the time of cairo_set_dash().
@@ -1776,6 +1781,27 @@ cairo_mask_surface (cairo_t         *cr,
  * context. See cairo_set_line_width(), cairo_set_line_join(),
  * cairo_set_line_cap(), cairo_set_dash(), and
  * cairo_stroke_preserve().
+ *
+ * Note: Degenerate segments and sub-paths are treated specially and
+ * provide a useful result. These can result in two different
+ * situations:
+ *
+ * 1. Zero-length "on" segments set in cairo_set_dash(). If the cap
+ * style is CAIRO_LINE_CAP_ROUND or CAIRO_LINE_CAP_SQUARE then these
+ * segments will be drawn as circular dots or squares respectively. In
+ * the case of CAIRO_LINE_CAP_SQUARE, the orientation of the squares
+ * is determined by the direction of the underlying path.
+ *
+ * 2. A sub-path created by cairo_move_to() followed by either a
+ * cairo_close_path() or one or more calls to cairo_line_to() to the
+ * same coordinate as the cairo_move_to(). If the cap style is
+ * CAIRO_LINE_CAP_ROUND then these sub-paths will be drawn as circular
+ * dots. Note that in the case of CAIRO_LINE_CAP_SQUARE a degenerate
+ * sub-path will not be drawn at all, (since the correct orientation
+ * is indeterminate).
+ *
+ * In no case will a cap style of CAIRO_LINE_CAP_BUTT cause anything
+ * to be drawn in the case of either degenerate segments or sub-paths.
  **/
 void
 cairo_stroke (cairo_t *cr)
diff-tree 15caa88c6416ce8e0c4c026e76f84ccaf7a3c840 (from 20df4af12617ad6459dcb234dfd98954282710f5)
Author: Jeff Muizelaar <jeff at infidigm.net>
Date:   Sun Jun 25 16:12:38 2006 +0200

    Initial support for degenerate-path stroking
    
    This follows the PDF and SVG specifications which only draw degenerate paths when
    round caps are in effect.
    
    With this commit, the degenerate-path test passes with the image, xlib, and pdf
    backends, (but still fails with ps and svg backends).

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 2f89314..3fc078c 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -50,6 +50,8 @@ typedef struct cairo_stroker {
     cairo_point_t current_point;
     cairo_point_t first_point;
 
+    cairo_bool_t has_subpath;
+
     cairo_bool_t has_current_face;
     cairo_stroke_face_t current_face;
 
@@ -164,6 +166,7 @@ _cairo_stroker_init (cairo_stroker_t		*s
 
     stroker->has_current_face = FALSE;
     stroker->has_first_face = FALSE;
+    stroker->has_subpath = FALSE;
 
     if (stroker->style->dash)
 	_cairo_stroker_start_dash (stroker);
@@ -205,7 +208,8 @@ _cairo_stroker_join (cairo_stroker_t *st
     if (in->cw.x == out->cw.x
 	&& in->cw.y == out->cw.y
 	&& in->ccw.x == out->ccw.x
-	&& in->ccw.y == out->ccw.y) {
+	&& in->ccw.y == out->ccw.y)
+    {
 	return CAIRO_STATUS_SUCCESS;
     }
 
@@ -459,10 +463,26 @@ _cairo_stroker_add_trailing_cap (cairo_s
     return _cairo_stroker_add_cap (stroker, face);
 }
 
+static void
+_compute_face (cairo_point_t *point, cairo_slope_t *slope, cairo_stroker_t *stroker, cairo_stroke_face_t *face);
+
 static cairo_status_t
 _cairo_stroker_add_caps (cairo_stroker_t *stroker)
 {
     cairo_status_t status;
+    /* check for a degenerative subpath */
+    if (stroker->has_subpath
+	&& !stroker->has_first_face
+	&& !stroker->has_current_face
+	&& stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND)
+    {
+	/* pick an arbitrary slope to use */
+	cairo_slope_t slope = {1, 0};
+	_compute_face (&stroker->first_point, &slope, stroker, &stroker->first_face);
+
+	stroker->has_first_face = stroker->has_current_face = TRUE;
+	stroker->current_face = stroker->first_face;
+    }
 
     if (stroker->has_first_face) {
 	status = _cairo_stroker_add_leading_cap (stroker, &stroker->first_face);
@@ -563,12 +583,8 @@ _cairo_stroker_add_sub_edge (cairo_strok
        fields from start. */
     _compute_face (p2, slope, stroker, end);
 
-    if (p1->x == p2->x && p1->y == p2->y) {
-	/* XXX: Need to rethink how this case should be handled, (both
-           here and in _compute_face). The key behavior is that
-           degenerate paths should draw as much as possible. */
+    if (p1->x == p2->x && p1->y == p2->y)
 	return CAIRO_STATUS_SUCCESS;
-    }
 
     /* XXX: I should really check the return value of the
        move_to/line_to functions here to catch out of memory
@@ -609,8 +625,9 @@ _cairo_stroker_move_to (void *closure, c
     stroker->first_point = *point;
     stroker->current_point = *point;
 
-    stroker->has_first_face = 0;
-    stroker->has_current_face = 0;
+    stroker->has_first_face = FALSE;
+    stroker->has_current_face = FALSE;
+    stroker->has_subpath = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -635,13 +652,10 @@ _cairo_stroker_line_to (void *closure, c
     cairo_point_t *p2 = point;
     cairo_slope_t slope;
 
-    if (p1->x == p2->x && p1->y == p2->y) {
-	/* XXX: Need to rethink how this case should be handled, (both
-           here and in cairo_stroker_add_sub_edge and in _compute_face). The
-           key behavior is that degenerate paths should draw as much
-           as possible. */
+    stroker->has_subpath = TRUE;
+
+    if (p1->x == p2->x && p1->y == p2->y)
 	return CAIRO_STATUS_SUCCESS;
-    }
 
     _cairo_slope_init (&slope, p1, p2);
 
@@ -685,13 +699,8 @@ _cairo_stroker_line_to_dashed (void *clo
     cairo_point_t *p2 = point;
     cairo_slope_t slope;
 
-    if (p1->x == p2->x && p1->y == p2->y) {
-	/* XXX: Need to rethink how this case should be handled, (both
-           here and in cairo_stroker_add_sub_edge and in _compute_face). The
-           key behavior is that degenerate paths should draw as much
-           as possible. */
+    if (p1->x == p2->x && p1->y == p2->y)
 	return CAIRO_STATUS_SUCCESS;
-    }
 
     _cairo_slope_init (&slope, p1, p2);
 
@@ -943,8 +952,13 @@ _cairo_stroker_close_path (void *closure
 	status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
 	if (status)
 	    return status;
+    } else {
+	status = _cairo_stroker_add_caps (stroker);
+	if (status)
+	    return status;
     }
 
+    stroker->has_subpath = 0;
     stroker->has_first_face = 0;
     stroker->has_current_face = 0;
 
diff-tree 20df4af12617ad6459dcb234dfd98954282710f5 (from e747bbd350e9630c18849dd7975036d1260264be)
Author: Jeff Muizelaar <jeff at infidigm.net>
Date:   Sun Jun 25 15:48:48 2006 +0200

    Add new test case degenerate-path to show current 'bug'

diff --git a/test/Makefile.am b/test/Makefile.am
index dcaa67e..4da7ed4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -20,6 +20,7 @@ dash-caps-joins			\
 dash-scale			\
 dash-offset-negative		\
 dash-zero-length		\
+degenerate-path			\
 device-offset			\
 device-offset-positive		\
 extend-reflect			\
@@ -178,6 +179,9 @@ dash-offset-negative-ps-argb32-ref.png		
 dash-zero-length-ref.png				\
 dash-zero-length-rgb24-ref.png				\
 dash-zero-length-ps-argb32-ref.png			\
+degenerate-path-ref.png					\
+degenerate-path-rgb24-ref.png				\
+degenerate-path-ps-argb32-ref.png			\
 device-offset-ref.png					\
 device-offset-positive-ref.png				\
 fill-and-stroke-ref.png					\
diff --git a/test/degenerate-path-ref.png b/test/degenerate-path-ref.png
new file mode 100644
index 0000000..1b07de4
Binary files /dev/null and b/test/degenerate-path-ref.png differ
diff --git a/test/degenerate-path-rgb24-ref.png b/test/degenerate-path-rgb24-ref.png
new file mode 100644
index 0000000..29f4089
Binary files /dev/null and b/test/degenerate-path-rgb24-ref.png differ
diff --git a/test/degenerate-path.c b/test/degenerate-path.c
new file mode 100644
index 0000000..1329bdf
--- /dev/null
+++ b/test/degenerate-path.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2006 Jeff Muizelaar
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Jeff Muizelaar not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Jeff Muizelaar makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL JEFF MUIZELAAR BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jeff Muizelaar <jeff at infidigm.net>
+ */
+
+#include "cairo-test.h"
+
+#define IMAGE_WIDTH 40
+#define IMAGE_HEIGHT 22
+
+cairo_test_t test = {
+    "degenerate-path",
+    "Tests the behaviour of degenerate paths with different cap types",
+    IMAGE_WIDTH, IMAGE_HEIGHT
+};
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    const cairo_line_cap_t cap[] = { CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_SQUARE, CAIRO_LINE_CAP_BUTT };
+    int i;
+
+    cairo_set_source_rgb (cr, 1, 0, 0);
+
+    for (i=0; i<ARRAY_SIZE(cap); i++) {
+	cairo_set_line_cap (cr, cap[i]);
+
+	cairo_set_line_width (cr, 6);
+	cairo_move_to (cr, 6, 6);
+	cairo_line_to (cr, 6, 6);
+	cairo_stroke (cr);
+
+	cairo_move_to (cr, 6, 15);
+	cairo_close_path (cr);
+	cairo_stroke (cr);
+
+	cairo_translate (cr, 12, 0);
+    }
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test, draw);
+}


More information about the cairo-commit mailing list