[cairo-commit] 4 commits - .gitignore src/cairo.c src/cairo.h src/cairoint.h src/cairo-path.c src/cairo-path-stroke.c src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-svg-surface.c test/.gitignore test/Makefile.am test/new-sub-path.c test/new-sub-path-ps-argb32-ref.png test/new-sub-path-ref.png test/new-sub-path-rgb24-ref.png

Carl Worth cworth at kemper.freedesktop.org
Tue Apr 18 15:24:45 PDT 2006


 .gitignore                          |    1 
 src/cairo-path-stroke.c             |   24 ++--------
 src/cairo-path.c                    |   40 +++++++++++++-----
 src/cairo-pdf-surface.c             |   48 +++++----------------
 src/cairo-ps-surface.c              |   78 +++++++++--------------------------
 src/cairo-svg-surface.c             |   17 -------
 src/cairo.c                         |   64 +++++++++++++++++++++++++----
 src/cairo.h                         |    3 +
 src/cairoint.h                      |    3 +
 test/.gitignore                     |    1 
 test/Makefile.am                    |    4 +
 test/new-sub-path-ps-argb32-ref.png |binary
 test/new-sub-path-ref.png           |binary
 test/new-sub-path-rgb24-ref.png     |binary
 test/new-sub-path.c                 |   79 ++++++++++++++++++++++++++++++++++++
 15 files changed, 217 insertions(+), 145 deletions(-)

New commits:
diff-tree eadb26a1c13da1af292f0262e108878133cbadf0 (from 448e904b2a64769aa9cfd8ea011c2b5fb6ec883b)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Apr 18 15:19:36 2006 -0700

    Add new PS-specific reference image for new-sub-path.

diff --git a/test/new-sub-path-ps-argb32-ref.png b/test/new-sub-path-ps-argb32-ref.png
new file mode 100644
index 0000000..23b7e75
Binary files /dev/null and b/test/new-sub-path-ps-argb32-ref.png differ
diff-tree 448e904b2a64769aa9cfd8ea011c2b5fb6ec883b (from parents)
Merge: cb778760cb87e727a701603bcea3a2cdc063d785 ffab2592fc5d0ccd498aff2f4e645eefe351b61b
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Apr 18 15:18:31 2006 -0700

    Merge branch 'cairo' into new-sub-path
    
    Conflicts:
    
    	src/cairo-path-stroke.c
    	src/cairo-pdf-surface.c
    	src/cairo-ps-surface.c

diff --cc src/cairo-path-stroke.c
index e817099,d6044a3..7ca6ab8
@@@ -620,7 -636,11 +633,8 @@@
      cairo_stroke_face_t start, end;
      cairo_point_t *p1 = &stroker->current_point;
      cairo_point_t *p2 = point;
+     cairo_slope_t slope;
  
 -    if (!stroker->has_current_point)
 -	return _cairo_stroker_move_to (stroker, point);
 -
      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
@@@ -667,6 -689,20 +683,17 @@@
      cairo_stroke_face_t sub_start, sub_end;
      cairo_point_t *p1 = &stroker->current_point;
      cairo_point_t *p2 = point;
+     cairo_slope_t slope;
+ 
 -    if (!stroker->has_current_point)
 -	return _cairo_stroker_move_to (stroker, point);
 -
+     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. */
+ 	return CAIRO_STATUS_SUCCESS;
+     }
+ 
+     _cairo_slope_init (&slope, p1, p2);
  
      dx = _cairo_fixed_to_double (p2->x - p1->x);
      dy = _cairo_fixed_to_double (p2->y - p1->y);
diff --cc src/cairo-pdf-surface.c
index 0c024a2,836b3ae..68c0271
@@@ -2086,3 -2037,233 +2017,229 @@@
  
      return CAIRO_STATUS_SUCCESS;
  }
+ 
+ static cairo_bool_t
+ _surface_pattern_supported (const cairo_surface_pattern_t *pattern)
+ {
+     if (pattern->surface->backend->acquire_source_image != NULL)
+ 	return TRUE;
+ 
+     return FALSE;
+ }
+ 
+ static cairo_bool_t
+ _pattern_supported (const cairo_pattern_t *pattern)
+ {
+     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ 	return TRUE;
+ 
+     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+ 	return _surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
+ 	
+     return FALSE;
+ }
+ 
+ static cairo_int_status_t
+ _operation_supported (cairo_pdf_surface_t *surface,
+ 		      cairo_operator_t op,
+ 		      const cairo_pattern_t *pattern)
+ {
+     if (! _pattern_supported (pattern))
+ 	return FALSE;
+ 
+     if (_cairo_operator_always_opaque (op))
+ 	return TRUE;
+ 
+     if (_cairo_operator_always_translucent (op))
+ 	return FALSE;
+ 
+     return _cairo_pattern_is_opaque (pattern);
+ }
+ 
+ static cairo_int_status_t
+ _analyze_operation (cairo_pdf_surface_t *surface,
+ 		    cairo_operator_t op,
+ 		    const cairo_pattern_t *pattern)
+ {
+     if (_operation_supported (surface, op, pattern))
+ 	return CAIRO_STATUS_SUCCESS;
+     else
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_pdf_surface_paint (void			*abstract_surface,
+ 			  cairo_operator_t	 op,
+ 			  cairo_pattern_t	*source)
+ {
+     cairo_pdf_surface_t *surface = abstract_surface;
+ 
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     /* One would think that since we analyzed this away as unsupported
+      * that it would never be called after analyzing. But in fact,
+      * paint is called to paint the actual fallback surface. So we
+      * must not ASSERT_NOT_REACHED as we do for the other drawing
+      * operations. */
+ 
+     return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_pdf_surface_mask	(void			*abstract_surface,
+ 			 cairo_operator_t	 op,
+ 			 cairo_pattern_t	*source,
+ 			 cairo_pattern_t	*mask)
+ {
+     cairo_pdf_surface_t *surface = abstract_surface;
+ 
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     ASSERT_NOT_REACHED;
+ 
+     return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_pdf_surface_stroke (void			*abstract_surface,
+ 			   cairo_operator_t	 op,
+ 			   cairo_pattern_t	*source,
+ 			   cairo_path_fixed_t	*path,
+ 			   cairo_stroke_style_t	*style,
+ 			   cairo_matrix_t	*ctm,
+ 			   cairo_matrix_t	*ctm_inverse,
+ 			   double		 tolerance,
+ 			   cairo_antialias_t	 antialias)
+ {
+     cairo_pdf_surface_t *surface = abstract_surface;
+ 
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     ASSERT_NOT_REACHED;
+ 
+     return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_pdf_surface_fill (void			*abstract_surface,
+ 			 cairo_operator_t	 op,
+ 			 cairo_pattern_t	*source,
+ 			 cairo_path_fixed_t	*path,
+ 			 cairo_fill_rule_t	 fill_rule,
+ 			 double			 tolerance,
+ 			 cairo_antialias_t	 antialias)
+ {
+     cairo_pdf_surface_t *surface = abstract_surface;
+     cairo_pdf_document_t *document = surface->document;
+     const char *pdf_operator;
+     cairo_status_t status;
 -    pdf_path_info_t info;
+ 
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return _analyze_operation (surface, op, source);
+ 
+     assert (_operation_supported (surface, op, source));
+ 
+     status = emit_pattern (surface, source);
+     if (status)
+ 	return status;
+ 
+     /* After emitting the pattern the current stream should belong to
+      * this surface, so no need to _cairo_pdf_surface_ensure_stream()
+      */
+     assert (document->current_stream != NULL &&
+ 	    document->current_stream == surface->current_stream);
+ 
 -    info.output_stream = document->output_stream;
 -    info.has_current_point = FALSE;
 -
+     status = _cairo_path_fixed_interpret (path,
+ 					  CAIRO_DIRECTION_FORWARD,
+ 					  _cairo_pdf_path_move_to,
+ 					  _cairo_pdf_path_line_to,
+ 					  _cairo_pdf_path_curve_to,
+ 					  _cairo_pdf_path_close_path,
 -					  &info);
++					  document->output_stream);
+ 
+     switch (fill_rule) {
+     case CAIRO_FILL_RULE_WINDING:
+ 	pdf_operator = "f";
+ 	break;
+     case CAIRO_FILL_RULE_EVEN_ODD:
+ 	pdf_operator = "f*";
+ 	break;
+     default:
+ 	ASSERT_NOT_REACHED;
+     }
+ 
+     _cairo_output_stream_printf (document->output_stream,
+ 				 "%s\r\n",
+ 				 pdf_operator);
+ 
+     return status;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
+ 				cairo_operator_t	 op,
+ 				cairo_pattern_t		*source,
+ 				const cairo_glyph_t	*glyphs,
+ 				int			 num_glyphs,
+ 				cairo_scaled_font_t	*scaled_font)
+ {
+     cairo_pdf_surface_t *surface = abstract_surface;
+ 
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     ASSERT_NOT_REACHED;
+ 
+     return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ 
+ static void
+ _cairo_pdf_surface_set_paginated_mode (void			*abstract_surface,
+ 				       cairo_paginated_mode_t	 paginated_mode)
+ {
+     cairo_pdf_surface_t *surface = abstract_surface;
+ 
+     surface->paginated_mode = paginated_mode;
+ }
+ 
+ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
+     CAIRO_SURFACE_TYPE_PDF,
+     _cairo_pdf_surface_create_similar,
+     _cairo_pdf_surface_finish,
+     NULL, /* acquire_source_image */
+     NULL, /* release_source_image */
+     NULL, /* acquire_dest_image */
+     NULL, /* release_dest_image */
+     NULL, /* clone_similar */
+     _cairo_pdf_surface_composite,
+     _cairo_pdf_surface_fill_rectangles,
+     _cairo_pdf_surface_composite_trapezoids,
+     _cairo_pdf_surface_copy_page,
+     _cairo_pdf_surface_show_page,
+     NULL, /* set_clip_region */
+     _cairo_pdf_surface_intersect_clip_path,
+     _cairo_pdf_surface_get_extents,
+     _cairo_pdf_surface_old_show_glyphs,
+     _cairo_pdf_surface_get_font_options,
+     NULL, /* flush */
+     NULL, /* mark_dirty_rectangle */
+     NULL, /* scaled_font_fini */
+     NULL, /* scaled_glyph_fini */
+ 
+     /* Here are the drawing functions */
+ 
+     _cairo_pdf_surface_paint,
+     _cairo_pdf_surface_mask,
+     _cairo_pdf_surface_stroke,
+     _cairo_pdf_surface_fill,
+     _cairo_pdf_surface_show_glyphs,
+     NULL, /* snapshot */
+ };
+ 
+ static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
+     NULL, /* start_page */
+     _cairo_pdf_surface_set_paginated_mode
+ };
diff --cc src/cairo-ps-surface.c
index 37053e9,19a835b..29b6882
@@@ -78,10 -107,79 +107,62 @@@
  
  #define PS_SURFACE_DPI_DEFAULT 300.0
  
- #if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- static cairo_int_status_t
- _cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface);
- #endif
 -typedef struct
 -{
 -    cairo_output_stream_t *output_stream;
 -    cairo_bool_t has_current_point;
 -} cairo_ps_surface_path_info_t;
 -
+ static cairo_status_t
+ _cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
+ {
 -    cairo_ps_surface_path_info_t *info = closure;
++    cairo_output_stream_t *output_stream = closure;
+ 
 -    _cairo_output_stream_printf (info->output_stream,
 -				 "%f %f M ",
++    _cairo_output_stream_printf (output_stream,
++				 "%f %f moveto ",
+ 				 _cairo_fixed_to_double (point->x),
+ 				 _cairo_fixed_to_double (point->y));
 -    info->has_current_point = TRUE;
+     
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
+ {
 -    cairo_ps_surface_path_info_t *info = closure;
 -    const char *ps_operator;
++    cairo_output_stream_t *output_stream = closure;
+ 
 -    if (info->has_current_point)
 -	ps_operator = "L";
 -    else
 -	ps_operator = "M";
 -    
 -    _cairo_output_stream_printf (info->output_stream,
 -				 "%f %f %s ",
++    _cairo_output_stream_printf (output_stream,
++				 "%f %f lineto ",
+ 				 _cairo_fixed_to_double (point->x),
 -				 _cairo_fixed_to_double (point->y),
 -				 ps_operator);
 -    info->has_current_point = TRUE;
++				 _cairo_fixed_to_double (point->y));
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_ps_surface_path_curve_to (void          *closure,
 -			  cairo_point_t *b,
 -			  cairo_point_t *c,
 -			  cairo_point_t *d)
++				 cairo_point_t *b,
++				 cairo_point_t *c,
++				 cairo_point_t *d)
+ {
 -    cairo_ps_surface_path_info_t *info = closure;
++    cairo_output_stream_t *output_stream = closure;
+ 
 -    _cairo_output_stream_printf (info->output_stream,
 -				 "%f %f %f %f %f %f C ",
++    _cairo_output_stream_printf (output_stream,
++				 "%f %f %f %f %f %f curveto ",
+ 				 _cairo_fixed_to_double (b->x),
+ 				 _cairo_fixed_to_double (b->y),
+ 				 _cairo_fixed_to_double (c->x),
+ 				 _cairo_fixed_to_double (c->y),
+ 				 _cairo_fixed_to_double (d->x),
+ 				 _cairo_fixed_to_double (d->y));
+     
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_ps_surface_path_close_path (void *closure)
+ {
 -    cairo_ps_surface_path_info_t *info = closure;
++    cairo_output_stream_t *output_stream = closure;
+     
 -    if (info->has_current_point)
 -        _cairo_output_stream_printf (info->output_stream,
 -				     "P\n");
 -    info->has_current_point = FALSE;
++    _cairo_output_stream_printf (output_stream,
++				 "closepath\n");
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
  
  static void
  _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
@@@ -101,13 -200,325 +183,321 @@@
  				 surface->width,
  				 surface->height);
  
-     /* The "/FlateDecode filter" currently used is a feature of
-      * LanguageLevel 3 */
-     _cairo_output_stream_printf (surface->stream,
- 				 "%%%%DocumentData: Binary\n"
- 				 "%%%%LanguageLevel: 3\n"
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "%%%%DocumentData: Clean7Bit\n"
+ 				 "%%%%LanguageLevel: 2\n"
  				 "%%%%Orientation: Portrait\n"
  				 "%%%%EndComments\n");
+ 
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "%%%%BeginProlog\n"
+ 				 "/C{curveto}bind def\n"
+ 				 "/F{fill}bind def\n"
+ 				 "/G{setgray}bind def\n"
+ 				 "/L{lineto}bind def\n"
+ 				 "/M{moveto}bind def\n"
+ 				 "/P{closepath}bind def\n"
+ 				 "/R{setrgbcolor}bind def\n"
+ 				 "/S{show}bind def\n"
+ 				 "%%%%EndProlog\n");
+ }
+ 
+ static cairo_bool_t
+ _cairo_ps_glyph_equal (const void *key_a, const void *key_b)
+ {
+     const cairo_ps_glyph_t   *ps_glyph_a = key_a;
+     const cairo_ps_glyph_t   *ps_glyph_b = key_b;
+ 
+     return ps_glyph_a->base.hash == ps_glyph_b->base.hash;
+ }
+ 
+ static void
+ _cairo_ps_glyph_key_init (cairo_ps_glyph_t  *ps_glyph,
+ 			  unsigned long	    index)
+ {
+     ps_glyph->base.hash = index;
+ }
+ 
+ static cairo_ps_glyph_t *
+ _cairo_ps_glyph_create (cairo_ps_font_t *ps_font,
+ 			unsigned long index)
+ {
+     cairo_ps_glyph_t	*ps_glyph = malloc (sizeof (cairo_ps_glyph_t));
+ 
+     if (!ps_glyph)
+ 	return NULL;
+     _cairo_ps_glyph_key_init (ps_glyph, index);
+     ps_glyph->output_glyph = ps_font->max_glyph++;
+     return ps_glyph;
+ }
+ 
+ static void
+ _cairo_ps_glyph_destroy (cairo_ps_glyph_t *ps_glyph)
+ {
+     free (ps_glyph);
+ }
+ 
+ static cairo_status_t
+ _cairo_ps_glyph_find (cairo_ps_font_t	    *font,
+ 		      cairo_scaled_font_t   *scaled_font,
+ 		      unsigned long	    index,
+ 		      cairo_ps_glyph_t	    **result)
+ {
+     cairo_ps_glyph_t	key;
+     cairo_ps_glyph_t	*ps_glyph;
+     cairo_status_t	status;
+ 
+     _cairo_ps_glyph_key_init (&key, index);
+     if (!_cairo_hash_table_lookup (font->glyphs, 
+ 				   &key.base, 
+ 				   (cairo_hash_entry_t **) &ps_glyph)) {
+ 	ps_glyph = _cairo_ps_glyph_create (font, index);
+ 	if (!ps_glyph)
+ 	    return CAIRO_STATUS_NO_MEMORY;
+ 	status = _cairo_hash_table_insert (font->glyphs, &ps_glyph->base);
+ 	if (status)
+ 	    return status;
+     }
+     *result = ps_glyph;
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_bool_t
+ _cairo_ps_font_equal (const void *key_a, const void *key_b)
+ {
+     const cairo_ps_font_t   *ps_font_a = key_a;
+     const cairo_ps_font_t   *ps_font_b = key_b;
+ 
+     return ps_font_a->scaled_font == ps_font_b->scaled_font;
+ }
+ 
+ static void
+ _cairo_ps_font_key_init (cairo_ps_font_t	*ps_font,
+ 			 cairo_scaled_font_t	*scaled_font)
+ {
+     ps_font->base.hash = (unsigned long) scaled_font;
+     ps_font->scaled_font = scaled_font;
+ }
+ 
+ static cairo_ps_font_t *
+ _cairo_ps_font_create (cairo_ps_surface_t   *surface,
+ 		       cairo_scaled_font_t  *scaled_font)
+ {
+     cairo_ps_font_t *ps_font = malloc (sizeof (cairo_ps_font_t));
+     if (!ps_font)
+ 	return NULL;
+     _cairo_ps_font_key_init (ps_font, scaled_font);
+     ps_font->glyphs = _cairo_hash_table_create (_cairo_ps_glyph_equal);
+     if (!ps_font->glyphs) {
+ 	free (ps_font);
+ 	return NULL;
+     }
+     ps_font->max_glyph = 0;
+     ps_font->output_font = surface->max_font++;
+     cairo_scaled_font_reference (ps_font->scaled_font);
+     return ps_font;
+ }
+ 
+ static void
+ _cairo_ps_font_destroy_glyph (void *entry, void *closure)
+ {
+     cairo_ps_glyph_t	*ps_glyph = entry;
+     cairo_ps_font_t	*ps_font = closure;
+     
+     _cairo_hash_table_remove (ps_font->glyphs, &ps_glyph->base);
+     _cairo_ps_glyph_destroy (ps_glyph);
+ }
+ 
+ static void
+ _cairo_ps_font_destroy (cairo_ps_font_t *ps_font)
+ {
+     _cairo_hash_table_foreach (ps_font->glyphs,
+ 			       _cairo_ps_font_destroy_glyph,
+ 			       ps_font);
+     _cairo_hash_table_destroy (ps_font->glyphs);
+     cairo_scaled_font_destroy (ps_font->scaled_font);
+     free (ps_font);
+ }
+ 
+ static void
+ _cairo_ps_surface_destroy_font (cairo_ps_surface_t *surface,
+ 				cairo_ps_font_t *ps_font)
+ {
+     _cairo_hash_table_remove (surface->fonts, &ps_font->base);
+     _cairo_ps_font_destroy (ps_font);
+ }
+ 
+ static cairo_status_t
+ _cairo_ps_font_find (cairo_ps_surface_t	    *surface,
+ 		     cairo_scaled_font_t    *scaled_font,
+ 		     cairo_ps_font_t	    **result)
+ {
+     cairo_ps_font_t	key;
+     cairo_ps_font_t	*ps_font;
+     cairo_status_t	status;
+ 
+     _cairo_ps_font_key_init (&key, scaled_font);
+     if (!_cairo_hash_table_lookup (surface->fonts, &key.base,
+ 				   (cairo_hash_entry_t **) &ps_font)) 
+     {
+ 	ps_font = _cairo_ps_font_create (surface, scaled_font);
+ 	if (!ps_font)
+ 	    return CAIRO_STATUS_NO_MEMORY;
+ 	status = _cairo_hash_table_insert (surface->fonts,
+ 					   &ps_font->base);
+ 	if (status)
+ 	    return status;
+     }
+     *result = ps_font;
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ typedef struct _cairo_ps_font_glyph_select {
+     cairo_ps_glyph_t	**glyphs;
+     int			subfont;
+     int			numglyph;
+ } cairo_ps_font_glyph_select_t;
+ 
+ static void
+ _cairo_ps_font_select_glyphs (void *entry, void *closure)
+ {
+     cairo_ps_glyph_t		    *ps_glyph = entry;
+     cairo_ps_font_glyph_select_t    *ps_glyph_select = closure;
+ 
+     if (ps_glyph->output_glyph >> 8 == ps_glyph_select->subfont) {
+ 	unsigned long	sub_glyph = ps_glyph->output_glyph & 0xff;
+ 	ps_glyph_select->glyphs[sub_glyph] = ps_glyph;
+ 	if (sub_glyph >= ps_glyph_select->numglyph)
+ 	    ps_glyph_select->numglyph = sub_glyph + 1;
+     }
+ }
+ 
+ static cairo_status_t
+ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
+ 			      cairo_ps_font_t *ps_font,
+ 			      cairo_ps_glyph_t *ps_glyph)
+ {
+     cairo_scaled_glyph_t    *scaled_glyph;
+     cairo_status_t	    status;
 -    cairo_ps_surface_path_info_t info;
+     
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "\t\t{ %% %d\n", ps_glyph->output_glyph);
+     status = _cairo_scaled_glyph_lookup (ps_font->scaled_font,
+ 					 ps_glyph->base.hash,
+ 					 CAIRO_SCALED_GLYPH_INFO_METRICS|
+ 					 CAIRO_SCALED_GLYPH_INFO_PATH,
+ 					 &scaled_glyph);
+     /*
+      * If that fails, try again but ask for an image instead
+      */
+     if (status)
+ 	status = _cairo_scaled_glyph_lookup (ps_font->scaled_font,
+ 					     ps_glyph->base.hash,
+ 					     CAIRO_SCALED_GLYPH_INFO_METRICS|
+ 					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ 					     &scaled_glyph);
+     if (status) {
+ 	_cairo_output_stream_printf (surface->final_stream, "\t\t}\n");
+ 	return status;
+     }
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "%f %f %f %f 0 0 setcachedevice\n",
+ 				 _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
+ 				 -_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
+ 				 _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
+ 				 -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
+     
 -    info.output_stream = surface->final_stream;
 -    info.has_current_point = FALSE;
 -
+     status = _cairo_path_fixed_interpret (scaled_glyph->path,
+ 					  CAIRO_DIRECTION_FORWARD,
+ 					  _cairo_ps_surface_path_move_to,
+ 					  _cairo_ps_surface_path_line_to,
+ 					  _cairo_ps_surface_path_curve_to,
+ 					  _cairo_ps_surface_path_close_path,
 -					  &info);
++					  surface->final_stream);
+     
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "F\n");
+     
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "\t\t}\n");
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static void
+ _cairo_ps_surface_emit_font (void *entry, void *closure)
+ {
+     cairo_ps_font_t *ps_font = entry;
+     cairo_ps_surface_t *surface = closure;
+     cairo_ps_font_glyph_select_t glyph_select;
+     cairo_ps_glyph_t *ps_glyphs[256], *ps_glyph;
+     int glyph, numglyph;
+     int subfont, nsubfont;
+ 
+     _cairo_output_stream_printf (surface->final_stream,
+ 				 "%% _cairo_ps_surface_emit_font\n");
+     nsubfont = (ps_font->max_glyph >> 8) + 1;
+     for (subfont = 0; subfont < nsubfont; subfont++) {
+ 	_cairo_output_stream_printf (surface->final_stream,
+ 				     "/CairoFont-%d-%d <<\n",
+ 				     ps_font->output_font,
+ 				     subfont);
+ 	memset (ps_glyphs, '\0', sizeof (ps_glyphs));
+         glyph_select.glyphs = ps_glyphs;
+ 	glyph_select.numglyph = 0;
+ 	glyph_select.subfont = subfont;
+ 	_cairo_hash_table_foreach (ps_font->glyphs, 
+ 				   _cairo_ps_font_select_glyphs,
+ 				   &glyph_select);
+ 	_cairo_output_stream_printf (surface->final_stream,
+ 				     "\t/FontType\t3\n"
+ 				     "\t/FontMatrix\t[1 0 0 1 0 0]\n"
+ 				     "\t/Encoding\t[0]\n"
+ 				     "\t/FontBBox\t[0 0 10 10]\n"
+ 				     "\t/Glyphs [\n");
+ 	numglyph = glyph_select.numglyph;
+ 	for (glyph = 0; glyph < numglyph; glyph++) {
+ 	    ps_glyph = ps_glyphs[glyph];
+ 	    if (ps_glyph) {
+ 		_cairo_ps_surface_emit_glyph (surface,
+ 					      ps_font,
+ 					      ps_glyph);
+ 	    } else {
+ 		_cairo_output_stream_printf (surface->final_stream,
+ 					     "\t\t{ } %% %d\n", glyph);
+ 	    }
+ 	    _cairo_ps_font_destroy_glyph (ps_glyph, ps_font);
+ 	}
+ 	_cairo_output_stream_printf (surface->final_stream,
+ 				     "\t]\n"
+ 				     "\t/BuildChar {\n"
+ 				     "\t\texch /Glyphs get\n"
+ 				     "\t\texch get exec\n"
+ 				     "\t}\n"
+ 				     ">> definefont pop\n");
+     }
+     _cairo_ps_surface_destroy_font (surface, ps_font);
+ }
+ 
+ 
+ static void
+ _cairo_ps_surface_emit_fonts (cairo_ps_surface_t *surface)
+ {
+     _cairo_hash_table_foreach (surface->fonts, 
+ 			       _cairo_ps_surface_emit_font,
+ 			       surface);
+     _cairo_hash_table_destroy (surface->fonts);
+     surface->fonts = NULL;
+ }
+ 
+ static void
+ _cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
+ {
+     char    buf[4096];
+     int	    n;
+     
+     rewind (surface->tmpfile);
+     while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
+ 	_cairo_output_stream_write (surface->final_stream, buf, n);
  }
  
  static void
@@@ -1117,8 -1315,12 +1294,11 @@@
      cairo_ps_surface_t *surface = abstract_surface;
      cairo_output_stream_t *stream = surface->stream;
      cairo_status_t status;
 -    cairo_ps_surface_path_info_t info;
      const char *ps_operator;
  
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return CAIRO_STATUS_SUCCESS;
+ 
      _cairo_output_stream_printf (stream,
  				 "%% _cairo_ps_surface_intersect_clip_path\n");
  
@@@ -1189,64 -1384,146 +1359,137 @@@
  {
      cairo_ps_surface_t *surface = abstract_surface;
      cairo_output_stream_t *stream = surface->stream;
-     cairo_font_subset_t *subset;
-     int i, subset_index;
 -    cairo_ps_surface_path_info_t info;
  
-     if (surface->fallback)
- 	return CAIRO_STATUS_SUCCESS;
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return _analyze_operation (surface, op, source);
  
-     if (surface->need_start_page)
- 	_cairo_ps_surface_start_page (surface);
+     /* XXX: It would be nice to be able to assert this condition
+      * here. But, we actually allow one 'cheat' that is used when
+      * painting the final image-based fallbacks. The final fallbacks
+      * do have alpha which we support by blending with white. This is
+      * possible only because there is nothing between the fallback
+      * images and the paper, nor is anything painted above. */
+     /*
+     assert (pattern_operation_supported (op, source));
+     */
+     
+     _cairo_output_stream_printf (stream,
+ 				 "%% _cairo_ps_surface_paint\n");
  
-     /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
-     if (! _cairo_scaled_font_is_ft (scaled_font))
- 	return CAIRO_INT_STATUS_UNSUPPORTED;
+     emit_pattern (surface, source);
  
-     if (surface->fallback)
- 	return CAIRO_STATUS_SUCCESS;
 -    info.output_stream = stream;
 -    info.has_current_point = FALSE;
 -
+     _cairo_output_stream_printf (stream, "0 0 M\n");
+     _cairo_output_stream_printf (stream, "%f 0 L\n", surface->width);
+     _cairo_output_stream_printf (stream, "%f %f L\n",
+ 				 surface->width, surface->height);
+     _cairo_output_stream_printf (stream, "0 %f L\n", surface->height);
+     _cairo_output_stream_printf (stream, "P F\n");
+     return CAIRO_STATUS_SUCCESS;
+ }
  
-     if (pattern_operation_needs_fallback (op, pattern))
- 	return _cairo_ps_surface_add_fallback_area (surface, dest_x, dest_y, width, height);
+ static int
+ _cairo_ps_line_cap (cairo_line_cap_t cap)
+ {
+     switch (cap) {
+     case CAIRO_LINE_CAP_BUTT:
+ 	return 0;
+     case CAIRO_LINE_CAP_ROUND:
+ 	return 1;
+     case CAIRO_LINE_CAP_SQUARE:
+ 	return 2;
+     default:
+ 	ASSERT_NOT_REACHED;
+ 	return 0;
+     }
+ }
  
-     _cairo_output_stream_printf (stream,
- 				 "%% _cairo_ps_surface_old_show_glyphs\n");
+ static int
+ _cairo_ps_line_join (cairo_line_join_t join)
+ {
+     switch (join) {
+     case CAIRO_LINE_JOIN_MITER:
+ 	return 0;
+     case CAIRO_LINE_JOIN_ROUND:
+ 	return 1;
+     case CAIRO_LINE_JOIN_BEVEL:
+ 	return 2;
+     default:
+ 	ASSERT_NOT_REACHED;
+ 	return 0;
+     }
+ }
  
-     emit_pattern (surface, pattern);
+ static cairo_int_status_t
+ _cairo_ps_surface_stroke (void			*abstract_surface,
+ 			  cairo_operator_t	 op,
+ 			  cairo_pattern_t	*source,
+ 			  cairo_path_fixed_t	*path,
+ 			  cairo_stroke_style_t	*style,
+ 			  cairo_matrix_t	*ctm,
+ 			  cairo_matrix_t	*ctm_inverse,
+ 			  double		 tolerance,
+ 			  cairo_antialias_t	 antialias)
+ {
+     cairo_ps_surface_t *surface = abstract_surface;
+     cairo_output_stream_t *stream = surface->stream;
+     cairo_int_status_t status;
 -    cairo_ps_surface_path_info_t info;
  
-     /* FIXME: Need to optimize this so we only do this sequence if the
-      * font isn't already set. */
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return _analyze_operation (surface, op, source);
  
-     subset = _cairo_ps_surface_get_font (surface, scaled_font);
+     assert (operation_supported (surface, op, source));
+     
      _cairo_output_stream_printf (stream,
- 				 "/f%d findfont\n"
- 				 "[ %f %f %f %f 0 0 ] makefont\n"
- 				 "setfont\n",
- 				 subset->font_id,
- 				 scaled_font->scale.xx,
- 				 scaled_font->scale.yx,
- 				 scaled_font->scale.xy,
- 				 -scaled_font->scale.yy);
- 
-     /* FIXME: Need to optimize per glyph code.  Should detect when
-      * glyphs share the same baseline and when the spacing corresponds
-      * to the glyph widths. */
+ 				 "%% _cairo_ps_surface_stroke\n");
  
-     for (i = 0; i < num_glyphs; i++) {
- 	subset_index = _cairo_font_subset_use_glyph (subset, glyphs[i].index);
- 	_cairo_output_stream_printf (stream,
- 				     "%f %f moveto (\\%o) show\n",
- 				     glyphs[i].x,
- 				     glyphs[i].y,
- 				     subset_index);
- 	
-     }
+     emit_pattern (surface, source);
  
-     return CAIRO_STATUS_SUCCESS;
 -    
 -    info.output_stream = stream;
 -    info.has_current_point = FALSE;
 -
+     _cairo_output_stream_printf (stream,
+ 				 "gsave\n");
+     status = _cairo_path_fixed_interpret (path,
+ 					  CAIRO_DIRECTION_FORWARD,
+ 					  _cairo_ps_surface_path_move_to,
+ 					  _cairo_ps_surface_path_line_to,
+ 					  _cairo_ps_surface_path_curve_to,
+ 					  _cairo_ps_surface_path_close_path,
 -					  &info);
++					  stream);
+ 
+     /*
+      * Switch to user space to set line parameters
+      */
+     _cairo_output_stream_printf (stream,
+ 				 "[%f %f %f %f 0 0] concat\n",
+ 				 ctm->xx, ctm->yx, ctm->xy, ctm->yy);
+     /* line width */
+     _cairo_output_stream_printf (stream, "%f setlinewidth\n",
+ 				 style->line_width);
+     /* line cap */
+     _cairo_output_stream_printf (stream, "%d setlinecap\n",
+ 				 _cairo_ps_line_cap (style->line_cap));
+     /* line join */
+     _cairo_output_stream_printf (stream, "%d setlinejoin\n",
+ 				 _cairo_ps_line_join (style->line_join));
+     /* dashes */
+     if (style->num_dashes) {
+ 	int d;
+ 	_cairo_output_stream_printf (stream, "[");
+ 	for (d = 0; d < style->num_dashes; d++)
+ 	    _cairo_output_stream_printf (stream, " %f", style->dash[d]);
+ 	_cairo_output_stream_printf (stream, "] %f setdash\n",
+ 				     style->dash_offset);
+     }
+     /* miter limit */
+     _cairo_output_stream_printf (stream, "%f setmiterlimit\n",
+ 				 style->miter_limit);
+     _cairo_output_stream_printf (stream,
+ 				 "stroke\n");
+     _cairo_output_stream_printf (stream,
+ 				 "grestore\n");
+     return status;
  }
- #endif
  
  static cairo_int_status_t
- _cairo_ps_surface_fill (void			*abstract_surface,
+ _cairo_ps_surface_fill (void		*abstract_surface,
  		 cairo_operator_t	 op,
  		 cairo_pattern_t	*source,
  		 cairo_path_fixed_t	*path,
@@@ -1257,17 -1534,14 +1500,13 @@@
      cairo_ps_surface_t *surface = abstract_surface;
      cairo_output_stream_t *stream = surface->stream;
      cairo_int_status_t status;
 -    cairo_ps_surface_path_info_t info;
      const char *ps_operator;
  
-     if (pattern_operation_needs_fallback (op, source))
- 	return _cairo_ps_surface_add_fallback_area (surface,
- 					     0, 0,
- 					     surface->width,
- 					     surface->height);
- 
-     if (surface->need_start_page)
- 	_cairo_ps_surface_start_page (surface);
+     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ 	return _analyze_operation (surface, op, source);
  
+     assert (operation_supported (surface, op, source));
+     
      _cairo_output_stream_printf (stream,
  				 "%% _cairo_ps_surface_fill\n");
  
diff-tree cb778760cb87e727a701603bcea3a2cdc063d785 (from 1dc1b57b4eaa55b7a5cafe39f818f7c87352ea6d)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Feb 23 22:07:13 2006 -0800

    cairo_close_path: Document that there will be a current point after
    cairo_close_path.

diff --git a/src/cairo.c b/src/cairo.c
index 6a94d0f..3319e2b 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1417,7 +1417,8 @@ cairo_stroke_to_path (cairo_t *cr)
  * 
  * 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.
+ * cairo_move_to()), and closes this subpath. After this call the
+ * current point will be at the joined endpoint of the subpath.
  *
  * The behavior of cairo_close_path() is distinct from simply calling
  * cairo_line_to() with the equivalent coordinate in the case of
@@ -1425,7 +1426,8 @@ cairo_stroke_to_path (cairo_t *cr)
  * the ends of the subpath. Instead, there is a line join connecting
  * the final and initial segments of the subpath.
  *
- * If there is no current point, this function will have no effect.
+ * If there is no current point before the call to cairo_close_path,
+ * this function will have no effect.
  **/
 void
 cairo_close_path (cairo_t *cr)
diff-tree 1dc1b57b4eaa55b7a5cafe39f818f7c87352ea6d (from 0354956a09cf5a45feed256c1d880bbb9b7c7c42)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Feb 23 22:01:07 2006 -0800

    cairo_new_sub_path: Making cairo_arc easier to use and more.
    
    This adds a new function which has as its only effect the elimination
    of
    the current point. This makes it much easier to use the various
    cairo_arc calls when the initial line_to is not actually desired.
    
    This function also unifies and generalizes the long-existing behavior
    of cairo_line_to being treated as cairo_move_to when there is no
    current point. With the addition of cairo_new_sub_path this becomes a
    documented feature with similar behavior in cairo_curve_to as well.

diff --git a/.gitignore b/.gitignore
index aaa9f03..73e1e4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ stamp-h
 stamp-h1
 stamp-h.in
 *~
+*.orig
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 96664ce..e817099 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -47,7 +47,6 @@ typedef struct cairo_stroker {
 
     cairo_pen_t	  pen;
 
-    cairo_bool_t has_current_point;
     cairo_point_t current_point;
     cairo_point_t first_point;
 
@@ -159,7 +158,6 @@ _cairo_stroker_init (cairo_stroker_t		*s
 		     stroke_style->line_width / 2.0,
 		     tolerance, ctm);
     
-    stroker->has_current_point = FALSE;
     stroker->has_current_face = FALSE;
     stroker->has_first_face = FALSE;
 
@@ -607,7 +605,6 @@ _cairo_stroker_move_to (void *closure, c
 
     stroker->first_point = *point;
     stroker->current_point = *point;
-    stroker->has_current_point = 1;
 
     stroker->has_first_face = 0;
     stroker->has_current_face = 0;
@@ -624,9 +621,6 @@ _cairo_stroker_line_to (void *closure, c
     cairo_point_t *p1 = &stroker->current_point;
     cairo_point_t *p2 = point;
 
-    if (!stroker->has_current_point)
-	return _cairo_stroker_move_to (stroker, point);
-
     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
@@ -674,9 +668,6 @@ _cairo_stroker_line_to_dashed (void *clo
     cairo_point_t *p1 = &stroker->current_point;
     cairo_point_t *p2 = point;
 
-    if (!stroker->has_current_point)
-	return _cairo_stroker_move_to (stroker, point);
-    
     dx = _cairo_fixed_to_double (p2->x - p1->x);
     dy = _cairo_fixed_to_double (p2->y - p1->y);
 
@@ -914,14 +905,12 @@ _cairo_stroker_close_path (void *closure
     cairo_status_t status;
     cairo_stroker_t *stroker = closure;
 
-    if (stroker->has_current_point) {
-	if (stroker->dashed)
-	    status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
-	else
-	    status = _cairo_stroker_line_to (stroker, &stroker->first_point);
-	if (status)
-	    return status;
-    }
+    if (stroker->dashed)
+	status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
+    else
+	status = _cairo_stroker_line_to (stroker, &stroker->first_point);
+    if (status)
+	return status;
 
     if (stroker->has_first_face && stroker->has_current_face) {
 	status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
@@ -931,7 +920,6 @@ _cairo_stroker_close_path (void *closure
 
     stroker->has_first_face = 0;
     stroker->has_current_face = 0;
-    stroker->has_current_point = 0;
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 669e587..7358bee 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -87,7 +87,7 @@ _cairo_path_fixed_init (cairo_path_fixed
 
     path->current_point.x = 0;
     path->current_point.y = 0;
-    path->has_current_point = 0;
+    path->has_current_point = FALSE;
     path->last_move_point = path->current_point;
 }
 
@@ -163,7 +163,7 @@ _cairo_path_fixed_fini (cairo_path_fixed
     }
     path->arg_buf_tail = NULL;
 
-    path->has_current_point = 0;
+    path->has_current_point = FALSE;
 }
 
 void
@@ -189,12 +189,18 @@ _cairo_path_fixed_move_to (cairo_path_fi
 	return status;
 
     path->current_point = point;
-    path->has_current_point = 1;
+    path->has_current_point = TRUE;
     path->last_move_point = path->current_point;
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+void
+_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
+{
+    path->has_current_point = FALSE;
+}
+
 cairo_status_t
 _cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
 			       cairo_fixed_t	   dx,
@@ -202,7 +208,7 @@ _cairo_path_fixed_rel_move_to (cairo_pat
 {
     cairo_fixed_t x, y;
 
-    if (!path->has_current_point)
+    if (! path->has_current_point)
 	return CAIRO_STATUS_NO_CURRENT_POINT;
 
     x = path->current_point.x + dx;
@@ -222,12 +228,16 @@ _cairo_path_fixed_line_to (cairo_path_fi
     point.x = x;
     point.y = y;
 
-    status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
+    if (! path->has_current_point)
+	status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
+    else
+	status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
+
     if (status)
 	return status;
 
     path->current_point = point;
-    path->has_current_point = 1;
+    path->has_current_point = TRUE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -239,7 +249,7 @@ _cairo_path_fixed_rel_line_to (cairo_pat
 {
     cairo_fixed_t x, y;
 
-    if (!path->has_current_point)
+    if (! path->has_current_point)
 	return CAIRO_STATUS_NO_CURRENT_POINT;
 
     x = path->current_point.x + dx;
@@ -261,12 +271,19 @@ _cairo_path_fixed_curve_to (cairo_path_f
     point[1].x = x1; point[1].y = y1;
     point[2].x = x2; point[2].y = y2;
 
+    if (! path->has_current_point) {
+	status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO,
+					&point[0], 1);
+	if (status)
+	    return status;
+    }
+
     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
     if (status)
 	return status;
 
     path->current_point = point[2];
-    path->has_current_point = 1;
+    path->has_current_point = TRUE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -281,7 +298,7 @@ _cairo_path_fixed_rel_curve_to (cairo_pa
     cairo_fixed_t x1, y1;
     cairo_fixed_t x2, y2;
 
-    if (!path->has_current_point)
+    if (! path->has_current_point)
 	return CAIRO_STATUS_NO_CURRENT_POINT;
 
     x0 = path->current_point.x + dx0;
@@ -304,13 +321,16 @@ _cairo_path_fixed_close_path (cairo_path
 {
     cairo_status_t status;
 
+    if (! path->has_current_point)
+	return CAIRO_STATUS_SUCCESS;
+
     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
     if (status)
 	return status;
 
     path->current_point.x = path->last_move_point.x;
     path->current_point.y = path->last_move_point.y;
-    path->has_current_point = 1;
+    path->has_current_point = TRUE;
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index ee5c482..0c024a2 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1263,22 +1263,15 @@ intersect (cairo_line_t *line, cairo_fix
 	_cairo_fixed_to_double (line->p2.y - line->p1.y);
 }
 
-typedef struct
-{
-    cairo_output_stream_t *output_stream;
-    cairo_bool_t has_current_point;
-} pdf_path_info_t;
-
 static cairo_status_t
 _cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
 {
-    pdf_path_info_t *info = closure;
+    cairo_output_stream_t *output_stream = closure;
 
-    _cairo_output_stream_printf (info->output_stream,
+    _cairo_output_stream_printf (output_stream,
 				 "%f %f m ",
 				 _cairo_fixed_to_double (point->x),
 				 _cairo_fixed_to_double (point->y));
-    info->has_current_point = TRUE;
     
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1286,20 +1279,12 @@ _cairo_pdf_path_move_to (void *closure, 
 static cairo_status_t
 _cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
 {
-    pdf_path_info_t *info = closure;
-    const char *pdf_operator;
-
-    if (info->has_current_point)
-	pdf_operator = "l";
-    else
-	pdf_operator = "m";
+    cairo_output_stream_t *output_stream = closure;
     
-    _cairo_output_stream_printf (info->output_stream,
-				 "%f %f %s ",
+    _cairo_output_stream_printf (output_stream,
+				 "%f %f l ",
 				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y),
-				 pdf_operator);
-    info->has_current_point = TRUE;
+				 _cairo_fixed_to_double (point->y));
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1310,9 +1295,9 @@ _cairo_pdf_path_curve_to (void          
 			  cairo_point_t *c,
 			  cairo_point_t *d)
 {
-    pdf_path_info_t *info = closure;
+    cairo_output_stream_t *output_stream = closure;
 
-    _cairo_output_stream_printf (info->output_stream,
+    _cairo_output_stream_printf (output_stream,
 				 "%f %f %f %f %f %f c ",
 				 _cairo_fixed_to_double (b->x),
 				 _cairo_fixed_to_double (b->y),
@@ -1327,11 +1312,10 @@ _cairo_pdf_path_curve_to (void          
 static cairo_status_t
 _cairo_pdf_path_close_path (void *closure)
 {
-    pdf_path_info_t *info = closure;
+    cairo_output_stream_t *output_stream = closure;
     
-    _cairo_output_stream_printf (info->output_stream,
+    _cairo_output_stream_printf (output_stream,
 				 "h\r\n");
-    info->has_current_point = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1349,7 +1333,6 @@ _cairo_pdf_surface_fill (void			*abstrac
     cairo_pdf_document_t *document = surface->document;
     const char *pdf_operator;
     cairo_status_t status;
-    pdf_path_info_t info;
 
     status = emit_pattern (surface, pattern);
     if (status)
@@ -1360,16 +1343,13 @@ _cairo_pdf_surface_fill (void			*abstrac
     assert (document->current_stream != NULL &&
 	    document->current_stream == surface->current_stream);
 
-    info.output_stream = document->output_stream;
-    info.has_current_point = FALSE;
-
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_pdf_path_move_to,
 					  _cairo_pdf_path_line_to,
 					  _cairo_pdf_path_curve_to,
 					  _cairo_pdf_path_close_path,
-					  &info);
+					  document->output_stream);
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
@@ -1600,7 +1580,6 @@ _cairo_pdf_surface_intersect_clip_path (
     cairo_pdf_document_t *document = surface->document;
     cairo_output_stream_t *output = document->output_stream;
     cairo_status_t status;
-    pdf_path_info_t info;
     const char *pdf_operator;
 
     _cairo_pdf_surface_ensure_stream (surface);
@@ -1617,16 +1596,13 @@ _cairo_pdf_surface_intersect_clip_path (
 	surface->has_clip = TRUE;
     }
 
-    info.output_stream = document->output_stream;
-    info.has_current_point = FALSE;
-
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_pdf_path_move_to,
 					  _cairo_pdf_path_line_to,
 					  _cairo_pdf_path_curve_to,
 					  _cairo_pdf_path_close_path,
-					  &info);
+					  document->output_stream);
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 6cf8621..37053e9 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1049,22 +1049,16 @@ _cairo_ps_surface_composite_trapezoids (
     return CAIRO_STATUS_SUCCESS;
 }
 
-typedef struct
-{
-    cairo_output_stream_t *output_stream;
-    cairo_bool_t has_current_point;
-} cairo_ps_surface_path_info_t;
 
 static cairo_status_t
 _cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
 {
-    cairo_ps_surface_path_info_t *info = closure;
+    cairo_output_stream_t *output_stream = closure;
 
-    _cairo_output_stream_printf (info->output_stream,
+    _cairo_output_stream_printf (output_stream,
 				 "%f %f moveto ",
 				 _cairo_fixed_to_double (point->x),
 				 _cairo_fixed_to_double (point->y));
-    info->has_current_point = TRUE;
     
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1072,33 +1066,25 @@ _cairo_ps_surface_path_move_to (void *cl
 static cairo_status_t
 _cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
 {
-    cairo_ps_surface_path_info_t *info = closure;
-    const char *ps_operator;
+    cairo_output_stream_t *output_stream = closure;
 
-    if (info->has_current_point)
-	ps_operator = "lineto";
-    else
-	ps_operator = "moveto";
-    
-    _cairo_output_stream_printf (info->output_stream,
-				 "%f %f %s ",
+    _cairo_output_stream_printf (output_stream,
+				 "%f %f lineto ",
 				 _cairo_fixed_to_double (point->x),
-				 _cairo_fixed_to_double (point->y),
-				 ps_operator);
-    info->has_current_point = TRUE;
+				 _cairo_fixed_to_double (point->y));
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 _cairo_ps_surface_path_curve_to (void          *closure,
-			  cairo_point_t *b,
-			  cairo_point_t *c,
-			  cairo_point_t *d)
+				 cairo_point_t *b,
+				 cairo_point_t *c,
+				 cairo_point_t *d)
 {
-    cairo_ps_surface_path_info_t *info = closure;
+    cairo_output_stream_t *output_stream = closure;
 
-    _cairo_output_stream_printf (info->output_stream,
+    _cairo_output_stream_printf (output_stream,
 				 "%f %f %f %f %f %f curveto ",
 				 _cairo_fixed_to_double (b->x),
 				 _cairo_fixed_to_double (b->y),
@@ -1113,11 +1099,10 @@ _cairo_ps_surface_path_curve_to (void   
 static cairo_status_t
 _cairo_ps_surface_path_close_path (void *closure)
 {
-    cairo_ps_surface_path_info_t *info = closure;
+    cairo_output_stream_t *output_stream = closure;
     
-    _cairo_output_stream_printf (info->output_stream,
+    _cairo_output_stream_printf (output_stream,
 				 "closepath\n");
-    info->has_current_point = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1132,7 +1117,6 @@ _cairo_ps_surface_intersect_clip_path (v
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_status_t status;
-    cairo_ps_surface_path_info_t info;
     const char *ps_operator;
 
     _cairo_output_stream_printf (stream,
@@ -1143,16 +1127,13 @@ _cairo_ps_surface_intersect_clip_path (v
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    info.output_stream = stream;
-    info.has_current_point = FALSE;
-
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_ps_surface_path_move_to,
 					  _cairo_ps_surface_path_line_to,
 					  _cairo_ps_surface_path_curve_to,
 					  _cairo_ps_surface_path_close_path,
-					  &info);
+					  stream);
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
@@ -1276,7 +1257,6 @@ _cairo_ps_surface_fill (void			*abstract
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_int_status_t status;
-    cairo_ps_surface_path_info_t info;
     const char *ps_operator;
 
     if (pattern_operation_needs_fallback (op, source))
@@ -1293,16 +1273,13 @@ _cairo_ps_surface_fill (void			*abstract
 
     emit_pattern (surface, source);
 
-    info.output_stream = stream;
-    info.has_current_point = FALSE;
-
     status = _cairo_path_fixed_interpret (path,
 					  CAIRO_DIRECTION_FORWARD,
 					  _cairo_ps_surface_path_move_to,
 					  _cairo_ps_surface_path_line_to,
 					  _cairo_ps_surface_path_curve_to,
 					  _cairo_ps_surface_path_close_path,
-					  &info);
+					  stream);
 
     switch (fill_rule) {
     case CAIRO_FILL_RULE_WINDING:
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 5a2c92f..9297005 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -783,7 +783,6 @@ emit_pattern (cairo_svg_surface_t *surfa
 typedef struct
 {
     cairo_svg_document_t *document;
-    cairo_bool_t has_current_point;
     xmlBufferPtr path;
 } svg_path_info_t;
 
@@ -801,7 +800,6 @@ _cairo_svg_path_move_to (void *closure, 
     _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->y));
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
-    info->has_current_point = TRUE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -813,10 +811,7 @@ _cairo_svg_path_line_to (void *closure, 
     xmlBufferPtr path = info->path;
     char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
 
-    if (info->has_current_point)
-	xmlBufferCat (path, CC2XML ("L "));
-    else
-	xmlBufferCat (path, CC2XML ("M "));
+    xmlBufferCat (path, CC2XML ("L "));
 
     _cairo_dtostr (buffer, sizeof buffer, _cairo_fixed_to_double (point->x));
     xmlBufferCat (path, CC2XML (buffer));
@@ -825,8 +820,6 @@ _cairo_svg_path_line_to (void *closure, 
     xmlBufferCat (path, CC2XML (buffer));
     xmlBufferCat (path, CC2XML (" "));
 
-    info->has_current_point = TRUE;
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -868,10 +861,7 @@ _cairo_svg_path_close_path (void *closur
 {
     svg_path_info_t *info = closure;
 
-    if (info->has_current_point)
-	    xmlBufferCat (info->path, CC2XML ("Z "));
-
-    info->has_current_point = FALSE;
+    xmlBufferCat (info->path, CC2XML ("Z "));
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -893,7 +883,6 @@ _cairo_svg_surface_fill (void			*abstrac
     xmlBufferPtr style;
 
     info.document = document;
-    info.has_current_point = FALSE;
     info.path = xmlBufferCreate ();
     
     style = xmlBufferCreate ();
@@ -1035,7 +1024,6 @@ _cairo_svg_surface_stroke (void			*abstr
     char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
     
     info.document = document;
-    info.has_current_point = FALSE;
     info.path = xmlBufferCreate ();
 
     rx = ry = stroke_style->line_width;
@@ -1176,7 +1164,6 @@ _cairo_svg_surface_intersect_clip_path (
 
     if (path != NULL) {
 	info.document = document;
-	info.has_current_point = FALSE;
 	info.path = xmlBufferCreate ();
 
 	group = xmlNewChild (surface->xml_node, NULL, CC2XML ("g"), NULL);
diff --git a/src/cairo.c b/src/cairo.c
index 96cd504..6a94d0f 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -957,8 +957,8 @@ cairo_device_to_user_distance (cairo_t *
  * cairo_new_path:
  * @cr: a cairo context
  *
- * Clears the current path. After this call there will be no current
- * point.
+ * Clears the current path. After this call there will be no path and
+ * no current point.
  **/
 void
 cairo_new_path (cairo_t *cr)
@@ -976,8 +976,8 @@ slim_hidden_def(cairo_new_path);
  * @x: the X coordinate of the new position
  * @y: the Y coordinate of the new position
  *
- * If the current subpath is not empty, begin a new subpath. After
- * this call the current point will be (@x, @y).
+ * Begin a new subpath. After this call the current point will be (@x,
+ * @y).
  **/
 void
 cairo_move_to (cairo_t *cr, double x, double y)
@@ -998,6 +998,31 @@ cairo_move_to (cairo_t *cr, double x, do
 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
+ * affected. After this call there will be no current point.
+ *
+ * In many cases, this call is not needed since new subpaths 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
+ * makes things easier as it is no longer necessary to manually
+ * compute the arc's initial coordinates for a call to
+ * cairo_move_to().
+ **/
+void
+cairo_new_sub_path (cairo_t *cr)
+{
+    if (cr->status)
+	return;
+
+    _cairo_path_fixed_new_sub_path (&cr->path);
+}
+
+/**
  * cairo_line_to:
  * @cr: a cairo context
  * @x: the X coordinate of the end of the new line
@@ -1006,6 +1031,9 @@ slim_hidden_def(cairo_move_to);
  * Adds a line to the path from the current point to position (@x, @y)
  * in user-space coordinates. After this call the current point
  * will be (@x, @y).
+ *
+ * If there is no current point before the call to cairo_line_to()
+ * this function will behave as cairo_move_to (@cr, @x, @y).
  **/
 void
 cairo_line_to (cairo_t *cr, double x, double y)
@@ -1038,6 +1066,10 @@ cairo_line_to (cairo_t *cr, double x, do
  * position (@x3, @y3) in user-space coordinates, using (@x1, @y1) and
  * (@x2, @y2) as the control points. After this call the current point
  * will be (@x3, @y3).
+ *
+ * If there is no current point before the call to cairo_curve_to()
+ * this function will behave as if preceded by a call to
+ * cairo_move_to (@cr, @x1, @y1).
  **/
 void
 cairo_curve_to (cairo_t *cr,
@@ -1208,11 +1240,15 @@ cairo_arc_to (cairo_t *cr,
  * @dx: the X offset
  * @dy: the Y offset
  *
- * If the current subpath is not empty, begin a new subpath. After
- * this call the current point will offset by (@x, @y).
+ * Begin a new subpath. 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)
  * is logically equivalent to cairo_move_to (@cr, x + @dx, y + @dy).
+ *
+ * It is an error to call this function with no current point. Doing
+ * so will cause @cr to shutdown with a status of
+ * CAIRO_STATUS_NO_CURRENT_POINT.
  **/
 void
 cairo_rel_move_to (cairo_t *cr, double dx, double dy)
@@ -1244,6 +1280,10 @@ cairo_rel_move_to (cairo_t *cr, double d
  *
  * Given a current point of (x, y), cairo_rel_line_to(@cr, @dx, @dy)
  * is logically equivalent to cairo_line_to (@cr, x + @dx, y + @dy).
+ *
+ * It is an error to call this function with no current point. Doing
+ * so will cause @cr to shutdown with a status of
+ * CAIRO_STATUS_NO_CURRENT_POINT.
  **/
 void
 cairo_rel_line_to (cairo_t *cr, double dx, double dy)
@@ -1284,6 +1324,10 @@ slim_hidden_def(cairo_rel_line_to);
  * @dy1, @dx2, @dy2, @dx3, @dy3) is logically equivalent to
  * cairo_curve_to (@cr, x + @dx1, y + @dy1, x + @dx2, y + @dy2, x +
  * @dx3, y + @dy3).
+ *
+ * It is an error to call this function with no current point. Doing
+ * so will cause @cr to shutdown with a status of
+ * CAIRO_STATUS_NO_CURRENT_POINT.
  **/
 void
 cairo_rel_curve_to (cairo_t *cr,
@@ -1378,8 +1422,10 @@ cairo_stroke_to_path (cairo_t *cr)
  * 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, their is a line join connecting
+ * the ends of the subpath. Instead, there is a line join connecting
  * the final and initial segments of the subpath.
+ *
+ * If there is no current point, this function will have no effect.
  **/
 void
 cairo_close_path (cairo_t *cr)
diff --git a/src/cairo.h b/src/cairo.h
index fbb3620..6dd2742 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -436,6 +436,9 @@ cairo_public void
 cairo_move_to (cairo_t *cr, double x, double y);
 
 cairo_public void
+cairo_new_sub_path (cairo_t *cr);
+
+cairo_public void
 cairo_line_to (cairo_t *cr, double x, double y);
 
 cairo_public void
diff --git a/src/cairoint.h b/src/cairoint.h
index 88fccae..d51b994 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1394,6 +1394,9 @@ _cairo_path_fixed_move_to (cairo_path_fi
 			   cairo_fixed_t	x,
 			   cairo_fixed_t	y);
 
+cairo_private void
+_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path);
+
 cairo_private cairo_status_t
 _cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
 			       cairo_fixed_t	   dx,
diff --git a/test/.gitignore b/test/.gitignore
index 5173349..1a12122 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -37,6 +37,7 @@ move-to-show-surface
 multi-page
 multi-page.pdf
 multi-page.ps
+new-sub-path
 nil-surface
 operator-clear
 operator-source
diff --git a/test/Makefile.am b/test/Makefile.am
index 0da8b5a..0ea0624 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -29,6 +29,7 @@ mask				\
 mask-ctm			\
 mask-surface-ctm		\
 move-to-show-surface		\
+new-sub-path			\
 nil-surface			\
 operator-clear			\
 operator-source			\
@@ -143,6 +144,8 @@ mask-surface-ctm-ref.png				\
 mask-surface-ctm-rgb24-ref.png				\
 move-to-show-surface-ref.png				\
 move-to-show-surface-rgb24-ref.png			\
+new-sub-path-ref.png					\
+new-sub-path-rgb24-ref.png				\
 nil-surface-ref.png					\
 nil-surface-rgb24-ref.png				\
 operator-clear-ref.png					\
@@ -311,6 +314,7 @@ mask_ctm_LDADD = $(LDADDS)
 mask_surface_ctm_LDADD = $(LDADDS)
 multi_page_LDADD = $(LDADDS)
 move_to_show_surface_LDADD = $(LDADDS)
+new_sub_path_LDADD = $(LDADDS)
 nil_surface_LDADD = $(LDADDS)
 operator_clear_LDADD = $(LDADDS)
 operator_source_LDADD = $(LDADDS)
diff --git a/test/new-sub-path-ref.png b/test/new-sub-path-ref.png
new file mode 100644
index 0000000..7319ab3
Binary files /dev/null and b/test/new-sub-path-ref.png differ
diff --git a/test/new-sub-path-rgb24-ref.png b/test/new-sub-path-rgb24-ref.png
new file mode 100644
index 0000000..8cbc731
Binary files /dev/null and b/test/new-sub-path-rgb24-ref.png differ
diff --git a/test/new-sub-path.c b/test/new-sub-path.c
new file mode 100644
index 0000000..90e0c73
--- /dev/null
+++ b/test/new-sub-path.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Carl D. Worth <cworth at cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 10
+
+cairo_test_t test = {
+    "new-sub-path",
+    "Test the cairo_new_sub_path call",
+    8 * SIZE,
+    3 * SIZE
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */
+
+    /* Test cairo_new_sub_path followed by several different
+     * path-modification functions in turn...
+     */
+
+    /* ... cairo_move_to */
+    cairo_new_sub_path (cr);
+    cairo_move_to (cr, SIZE, SIZE);
+    cairo_line_to (cr, SIZE, 2 * SIZE);
+
+    /* ... cairo_line_to */
+    cairo_new_sub_path (cr);
+    cairo_line_to (cr, 2 * SIZE, 1.5 * SIZE);
+    cairo_line_to (cr, 3 * SIZE, 1.5 * SIZE);
+
+    /* ... cairo_curve_to */
+    cairo_new_sub_path (cr);
+    cairo_curve_to (cr,
+		    4.0 * SIZE, 1.5 * SIZE,
+		    4.5 * SIZE, 1.0 * SIZE,
+		    5.0 * SIZE, 1.5 * SIZE);
+
+    /* ... cairo_arc */
+    cairo_new_sub_path (cr);
+    cairo_arc (cr,
+	       6.5 * SIZE, 1.5 * SIZE,
+	       0.5 * SIZE,
+	       0.0, 2.0 * M_PI);
+
+    cairo_stroke (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test, draw);
+}


More information about the cairo-commit mailing list