Index: docs/pango-sections.txt
===================================================================
--- docs/pango-sections.txt	(revision 2241)
+++ docs/pango-sections.txt	(working copy)
@@ -831,6 +831,9 @@ pango_cairo_context_set_resolution
 pango_cairo_context_get_resolution
 pango_cairo_context_set_font_options
 pango_cairo_context_get_font_options
+PangoCairoShapeRendererFunc
+pango_cairo_context_set_shape_renderer
+pango_cairo_context_get_shape_renderer
 pango_cairo_update_context
 pango_cairo_create_layout
 pango_cairo_update_layout
Index: docs/tmpl/pangocairo.sgml
===================================================================
--- docs/tmpl/pangocairo.sgml	(revision 2241)
+++ docs/tmpl/pangocairo.sgml	(working copy)
@@ -230,6 +230,43 @@ int main (int argc, char **argv)
 @Returns: 
 
 
+<!-- ##### USER_FUNCTION PangoCairoShapeRendererFunc ##### -->
+<para>
+Function type for rendering attributes of type %PANGO_ATTR_SHAPE
+with Pango's Cairo renderer.
+</para>
+
+@cr: a Cairo context with current point set to where the shape should
+     be rendered
+@attr: the %PANGO_ATTR_SHAPE to render
+@do_path: whether only the shape path should be appended to current
+          path of @cr and no filling/stroking done.  This will be set
+	  to %TRUE when called from pango_cairo_layout_path() and
+	  pango_cairo_layout_line_path() rendering functions.
+@data: user data passed to pango_cairo_context_set_shape_renderer()
+
+
+<!-- ##### FUNCTION pango_cairo_context_set_shape_renderer ##### -->
+<para>
+
+</para>
+
+@context: 
+@func: 
+@data: 
+@dnotify: 
+
+
+<!-- ##### FUNCTION pango_cairo_context_get_shape_renderer ##### -->
+<para>
+
+</para>
+
+@context: 
+@data: 
+@Returns: 
+
+
 <!-- ##### FUNCTION pango_cairo_update_context ##### -->
 <para>
 
Index: pango/pango-layout.c
===================================================================
--- pango/pango-layout.c	(revision 2257)
+++ pango/pango-layout.c	(working copy)
@@ -525,6 +525,7 @@ pango_layout_get_spacing (PangoLayout *l
  * @attrs: a #PangoAttrList
  *
  * Sets the text attributes for a layout object.
+ * References @attrs, so the caller can unref its reference.
  **/
 void
 pango_layout_set_attributes (PangoLayout   *layout,
Index: pango/pangocairo-render.c
===================================================================
--- pango/pangocairo-render.c	(revision 2241)
+++ pango/pangocairo-render.c	(working copy)
@@ -36,6 +36,8 @@ struct _PangoCairoRenderer
   cairo_t *cr;
   gboolean do_path;
   double x_offset, y_offset;
+  PangoCairoShapeRendererFunc shape_renderer;
+  gpointer                    shape_renderer_data;
 };
 
 struct _PangoCairoRendererClass
@@ -69,7 +71,6 @@ _pango_cairo_renderer_draw_frame (PangoC
 {
   if (crenderer->do_path)
     {
-      cairo_t *cr = crenderer->cr;
       double d2 = line_width * .5, d = line_width;
 
       /* we draw an outer box in one winding direction and an inner one in the
@@ -406,6 +407,31 @@ pango_cairo_renderer_draw_error_underlin
 }
 
 static void
+pango_cairo_renderer_draw_shape (PangoRenderer  *renderer,
+				 PangoAttrShape *attr,
+				 int             x,
+				 int             y)
+{
+  PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
+  cairo_t *cr = crenderer->cr;
+  double base_x = crenderer->x_offset + (double)x / PANGO_SCALE;
+  double base_y = crenderer->y_offset + (double)y / PANGO_SCALE;
+
+  if (!crenderer->shape_renderer)
+    return;
+
+  cairo_save (cr);
+  if (!crenderer->do_path)
+    set_color (crenderer, PANGO_RENDER_PART_FOREGROUND);
+
+  cairo_move_to (cr, base_x, base_y);
+
+  crenderer->shape_renderer (cr, attr, crenderer->do_path, crenderer->shape_renderer_data);
+
+  cairo_restore (cr);
+}
+
+static void
 pango_cairo_renderer_init (PangoCairoRenderer *renderer)
 {
 }
@@ -418,6 +444,7 @@ pango_cairo_renderer_class_init (PangoCa
   renderer_class->draw_glyphs = pango_cairo_renderer_draw_glyphs;
   renderer_class->draw_rectangle = pango_cairo_renderer_draw_rectangle;
   renderer_class->draw_error_underline = pango_cairo_renderer_draw_error_underline;
+  renderer_class->draw_shape = pango_cairo_renderer_draw_shape;
 }
 
 static PangoCairoRenderer *cached_renderer = NULL;
@@ -454,6 +481,8 @@ release_renderer (PangoCairoRenderer *re
     {
       renderer->cr = NULL;
       renderer->do_path = FALSE;
+      renderer->shape_renderer = NULL;
+      renderer->shape_renderer_data = NULL;
       renderer->x_offset = 0.;
       renderer->y_offset = 0.;
 
@@ -516,6 +545,8 @@ _pango_cairo_do_layout_line (cairo_t    
 
   crenderer->cr = cr;
   crenderer->do_path = do_path;
+  crenderer->shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (line->layout),
+								      &crenderer->shape_renderer_data);
   cairo_get_current_point (cr, &crenderer->x_offset, &crenderer->y_offset);
 
   pango_renderer_draw_layout_line (renderer, line, 0, 0);
@@ -534,6 +565,8 @@ _pango_cairo_do_layout (cairo_t     *cr,
 
   crenderer->cr = cr;
   crenderer->do_path = do_path;
+  crenderer->shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout),
+								      &crenderer->shape_renderer_data);
   cairo_get_current_point (cr, &crenderer->x_offset, &crenderer->y_offset);
 
   pango_renderer_draw_layout (renderer, layout, 0, 0);
Index: pango/pangocairo-context.c
===================================================================
--- pango/pangocairo-context.c	(revision 2260)
+++ pango/pangocairo-context.c	(working copy)
@@ -34,6 +34,10 @@ struct _PangoCairoContextInfo
   cairo_font_options_t *set_options;
   cairo_font_options_t *surface_options;
   cairo_font_options_t *merged_options;
+
+  PangoCairoShapeRendererFunc shape_renderer_func;
+  gpointer                    shape_renderer_data;
+  GDestroyNotify              shape_renderer_notify;
 };
 
 static void
@@ -46,6 +50,9 @@ free_context_info (PangoCairoContextInfo
   if (info->merged_options)
     cairo_font_options_destroy (info->merged_options);
 
+  if (info->shape_renderer_notify)
+    info->shape_renderer_notify (info->shape_renderer_data);
+
   g_slice_free (PangoCairoContextInfo, info);
 }
 
@@ -63,11 +70,8 @@ get_context_info (PangoContext *context,
 
   if (G_UNLIKELY (!info) && create)
     {
-      info = g_slice_new (PangoCairoContextInfo);
+      info = g_slice_new0 (PangoCairoContextInfo);
       info->dpi = -1.0;
-      info->set_options = NULL;
-      info->surface_options = NULL;
-      info->merged_options = NULL;
 
       g_object_set_qdata_full (G_OBJECT (context), context_info_quark,
 			       info, (GDestroyNotify)free_context_info);
@@ -262,6 +266,83 @@ _pango_cairo_context_get_merged_font_opt
 }
 
 /**
+ * pango_cairo_context_set_shape_renderer:
+ * @context: a #PangoContext, from pango_cairo_font_map_create_context()
+ * @func: Callback function for rendering attributes of type
+ * %PANGO_ATTR_SHAPE, or %NULL to disable shape rendering.
+ * @data: User data that will be passed to @func.
+ * @dnotify: Callback that will be called when the
+ *           context is freed to release @data, or %NULL.
+ *
+ * Sets callback function for context to use for rendering attributes
+ * of type %PANGO_ATTR_SHAPE.  See #PangoCairoShapeRendererFunc for
+ * details.
+ *
+ * Since: 1.18
+ */
+void
+pango_cairo_context_set_shape_renderer (PangoContext                *context,
+					PangoCairoShapeRendererFunc  func,
+					gpointer                     data,
+					GDestroyNotify               dnotify)
+{
+  PangoCairoContextInfo *info;
+
+  g_return_if_fail (PANGO_IS_CONTEXT (context));
+
+  info  = get_context_info (context, TRUE);
+
+  if (info->shape_renderer_notify)
+    info->shape_renderer_notify (info->shape_renderer_data);
+
+  info->shape_renderer_func   = func;
+  info->shape_renderer_data   = data;
+  info->shape_renderer_notify = dnotify;
+}
+
+/**
+ * pango_cairo_context_get_shape_renderer:
+ * @context: a #PangoContext, from pango_cairo_font_map_create_context()
+ * @data: Pointer to #gpointer to return user data
+ *
+ * Sets callback function for context to use for rendering attributes
+ * of type %PANGO_ATTR_SHAPE.  See #PangoCairoShapeRendererFunc for
+ * details.
+ *
+ * Retrieves callback function and associated user data for rendering
+ * attributes of type %PANGO_ATTR_SHAPE as set by
+ * pango_cairo_context_set_shape_renderer(), if any.
+ *
+ * Return value: the shape rendering callback previously set on the context, or %NULL
+ *   if no shape rendering callback have been set.
+ *
+ * Since: 1.18
+ */
+PangoCairoShapeRendererFunc
+pango_cairo_context_get_shape_renderer (PangoContext                *context,
+					gpointer                    *data)
+{
+  PangoCairoContextInfo *info;
+
+  g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL);
+
+  info = get_context_info (context, FALSE);
+
+  if (info)
+    {
+      if (data)
+        *data = info->shape_renderer_data;
+      return info->shape_renderer_func;
+    }
+  else
+    {
+      if (data)
+        *data = NULL;
+      return NULL;
+    }
+}
+
+/**
  * pango_cairo_create_layout:
  * @cr: a Cairo context
  *
Index: pango/pangocairo.h
===================================================================
--- pango/pangocairo.h	(revision 2241)
+++ pango/pangocairo.h	(working copy)
@@ -44,6 +44,11 @@ G_BEGIN_DECLS
 
 typedef struct _PangoCairoFontMap      PangoCairoFontMap;
 
+typedef void (* PangoCairoShapeRendererFunc) (cairo_t        *cr,
+					      PangoAttrShape *attr,
+					      gboolean        do_path,
+					      gpointer        data);
+
 /*
  * PangoCairoFontMap
  */
@@ -70,6 +75,13 @@ void               pango_cairo_context_s
 							   double              dpi);
 double             pango_cairo_context_get_resolution     (PangoContext       *context);
 
+void                        pango_cairo_context_set_shape_renderer (PangoContext                *context,
+								    PangoCairoShapeRendererFunc  func,
+								    gpointer                     data,
+								    GDestroyNotify               dnotify);
+PangoCairoShapeRendererFunc pango_cairo_context_get_shape_renderer (PangoContext                *context,
+								    gpointer                    *data);
+
 /* Convenience
  */
 PangoLayout *pango_cairo_create_layout (cairo_t     *cr);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2260)
+++ ChangeLog	(working copy)
@@ -1,5 +1,20 @@
 2007-05-04  Behdad Esfahbod  <behdad@gnome.org>
 
+	* pango/pangocairo.h:
+	* pango/pangocairo-context.c:
+	* pango/pangocairo-render.c:
+	New API
+
+		PangoCairoShapeRendererFunc and
+		pango_cairo_context_[sg]et_shape_renderer() 
+
+	* docs/pango-sections.txt, docs/tmpl/pangocairo.sgml: Document new API.
+
+	* examples/Makefile.am, examples/cairoshape.c: New example to show off
+	new API/feature.
+
+2007-05-04  Behdad Esfahbod  <behdad@gnome.org>
+
 	* pango/Makefile.am:
 	* pango/pangocairo-context.c:
 	* pango/pangocairo-fontmap.c:
Index: examples/cairoshape.c
===================================================================
--- examples/cairoshape.c	(revision 0)
+++ examples/cairoshape.c	(revision 0)
@@ -0,0 +1,209 @@
+/* example to use pangocairo to render arbitrary shapes inside a text layout */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <pango/pangocairo.h>
+
+#define BULLET "•"
+
+const char text[] =
+"The GNOME project provides two things:\n"
+"\n"
+"  • The GNOME desktop environment\n"
+"  • The GNOME development platform\n"
+"  • Planet GNOME";
+
+typedef struct {
+  double width, height;
+  const char *path;
+} MiniSvg;
+
+static MiniSvg GnomeFootLogo = {
+  96.2152, 118.26,
+  "M 86.068,1 C 61.466,0 56.851,35.041 70.691,35.041 C 84.529,35.041 110.671,0 86.068,0 z "
+  "M 45.217,30.699 C 52.586,31.149 60.671,2.577 46.821,4.374 C 32.976,6.171 37.845,30.249 45.217,30.699 z "
+  "M 11.445,48.453 C 16.686,46.146 12.12,23.581 3.208,29.735 C -5.7,35.89 6.204,50.759 11.445,48.453 z "
+  "M 26.212,36.642 C 32.451,35.37 32.793,9.778 21.667,14.369 C 10.539,18.961 19.978,37.916 26.212,36.642 L 26.212,36.642 z "
+  "M 58.791,93.913 C 59.898,102.367 52.589,106.542 45.431,101.092 C 22.644,83.743 83.16,75.088 79.171,51.386 C 75.86,31.712 15.495,37.769 8.621,68.553 C 3.968,89.374 27.774,118.26 52.614,118.26 C 64.834,118.26 78.929,107.226 81.566,93.248 C 83.58,82.589 57.867,86.86 58.791,93.913 L 58.791,93.913 z "
+  "\0"
+};
+
+static void
+mini_svg_render (MiniSvg  *shape,
+		 cairo_t  *cr,
+		 gboolean  do_path)
+{
+  double x, y;
+  const char *p;
+  char op[2];
+  int items, len;
+
+  cairo_get_current_point (cr, &x, &y);
+  cairo_translate (cr, x, y);
+
+  for (p = shape->path; (items = sscanf (p, "%1s %n", op, &len)), p += len, *p;)
+    switch (*op)
+    {
+      case 'M':
+        {
+	  sscanf (p, "%lf,%lf %n", &x, &y, &len); p += len;
+	  cairo_move_to (cr, x, y);
+	  break;
+	}
+      case 'L':
+        {
+	  sscanf (p, "%lf,%lf %n", &x, &y, &len); p += len;
+	  cairo_line_to (cr, x, y);
+	  break;
+	}
+      case 'C':
+        {
+	  double x1, y1, x2, y2, x3, y3;
+	  sscanf (p, "%lf,%lf %lf,%lf %lf,%lf %n", &x1, &y1, &x2, &y2, &x3, &y3, &len); p += len;
+	  cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
+	  break;
+	}
+      case 'z':
+        {
+	  cairo_close_path (cr);
+	  break;
+	}
+      default: 
+        {
+	  g_warning ("Invalid MiniSvg operation '%c'", *op);
+	  break;
+	}
+    }
+
+  if (!do_path)
+    cairo_fill (cr);
+}
+
+static void
+mini_svg_shape_renderer (cairo_t        *cr,
+			 PangoAttrShape *attr,
+			 gboolean        do_path,
+			 gpointer        data)
+{
+  MiniSvg *shape = (MiniSvg *) attr->data;
+  double scale_x, scale_y;
+
+  scale_x = (double) attr->ink_rect.width  / (PANGO_SCALE * shape->width );
+  scale_y = (double) attr->ink_rect.height / (PANGO_SCALE * shape->height);
+
+  cairo_rel_move_to (cr,
+		     (double) attr->ink_rect.x / PANGO_SCALE,
+		     (double) attr->ink_rect.y / PANGO_SCALE);
+  cairo_scale (cr, scale_x, scale_y);
+
+  mini_svg_render (shape, cr, do_path);
+}
+
+
+static PangoLayout *
+get_layout (cairo_t *cr)
+{
+  PangoLayout *layout;
+  PangoAttrList *attrs;
+  PangoRectangle ink_rect     = {1 * PANGO_SCALE, -11 * PANGO_SCALE,  8 * PANGO_SCALE, 10 * PANGO_SCALE};
+  PangoRectangle logical_rect = {0 * PANGO_SCALE, -12 * PANGO_SCALE, 10 * PANGO_SCALE, 12 * PANGO_SCALE};
+  const char *p;
+
+  /* Create a PangoLayout, set the font and text */
+  layout = pango_cairo_create_layout (cr);
+
+  pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
+					  mini_svg_shape_renderer, NULL, NULL);
+
+  pango_layout_set_text (layout, text, -1);
+
+  attrs = pango_attr_list_new ();
+
+  /* set gnome shape attributes for bullets */
+  for (p = text; (p = strstr (p, BULLET)); p += strlen (BULLET))
+    {
+      PangoAttribute *attr;
+      
+      attr = pango_attr_shape_new_with_data (&ink_rect,
+					     &logical_rect,
+					     &GnomeFootLogo,
+					     NULL, NULL);
+
+      attr->start_index = p - text;
+      attr->end_index = attr->start_index + strlen (BULLET);
+
+      pango_attr_list_insert (attrs, attr);
+    }
+
+  pango_layout_set_attributes (layout, attrs);
+  pango_attr_list_unref (attrs);
+
+  return layout;
+}
+
+static void
+draw_text (cairo_t *cr, int *width, int *height)
+{
+
+  PangoLayout *layout = get_layout (cr);
+
+  if (width || height)
+    {
+      pango_layout_get_pixel_size (layout, width, height);
+      if (width)
+        *width += 20;
+      if (height)
+        *height += 20;
+    }
+
+  cairo_move_to (cr, 10, 10);
+  pango_cairo_show_layout (cr, layout);
+
+  g_object_unref (layout);
+}
+
+int main (int argc, char **argv)
+{
+  cairo_t *cr;
+  char *filename;
+  cairo_status_t status;
+  cairo_surface_t *surface;
+  int width, height;
+
+  if (argc != 2)
+    {
+      g_printerr ("Usage: cairoshape OUTPUT_FILENAME\n");
+      return 1;
+    }
+
+  filename = argv[1];
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					0, 0);
+  cr = cairo_create (surface);
+  draw_text (cr, &width, &height);
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					width, height);
+  cr = cairo_create (surface);
+
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  cairo_paint (cr);
+  cairo_set_source_rgb (cr, 0.0, 0.0, 0.5);
+  draw_text (cr, NULL, NULL);
+  cairo_destroy (cr);
+
+  status = cairo_surface_write_to_png (surface, filename);
+  cairo_surface_destroy (surface);
+
+  if (status != CAIRO_STATUS_SUCCESS)
+    {
+      g_printerr ("Could not save png to '%s'\n", filename);
+      return 1;
+    }
+
+  return 0;
+}
Index: examples/cairotwisted.c
===================================================================
--- examples/cairotwisted.c	(revision 2241)
+++ examples/cairotwisted.c	(working copy)
@@ -1,4 +1,5 @@
-#include <config.h>
+/* example to use pangocairo to render text projected on a path */
+
 #include <math.h>
 #include <stdlib.h>
 #include <pango/pangocairo.h>
Index: examples/cairosimple.c
===================================================================
--- examples/cairosimple.c	(revision 2241)
+++ examples/cairosimple.c	(working copy)
@@ -1,4 +1,5 @@
-#include <config.h>
+/* simple example to use pangocairo to render rotated text */
+
 #include <math.h>
 #include <pango/pangocairo.h>
 
Index: examples/Makefile.am
===================================================================
--- examples/Makefile.am	(revision 2241)
+++ examples/Makefile.am	(working copy)
@@ -15,7 +15,7 @@ INCLUDES =				\
 noinst_PROGRAMS =
 
 if HAVE_CAIRO_PNG
-noinst_PROGRAMS += cairosimple cairotwisted
+noinst_PROGRAMS += cairosimple cairotwisted cairoshape
 
 cairosimple_LDADD =					\
 	../pango/libpango-$(PANGO_API_VERSION).la	\
@@ -27,4 +27,5 @@ cairosimple_LDADD +=					\
 	../pango/libpangoft2-$(PANGO_API_VERSION).la
 endif
 cairotwisted_LDADD = $(cairosimple_LDADD)
+cairoshape_LDADD   = $(cairosimple_LDADD)
 endif

