[cairo-commit] 9 commits - boilerplate/.gitignore doc/public src/cairo-analysis-surface.c src/cairo.c src/cairo-gstate.c src/cairo.h src/cairoint.h src/cairo-meta-surface.c src/cairo-meta-surface-private.h src/cairo-misc.c src/cairo-paginated-surface.c src/cairo-scaled-font.c src/cairo-surface.c src/cairo-types-private.h src/cairo-unicode.c src/cairo-xlib-surface.c test/.gitignore

Behdad Esfahbod behdad at kemper.freedesktop.org
Fri Jun 27 08:18:46 PDT 2008


 boilerplate/.gitignore            |    1 
 doc/public/.gitignore             |    1 
 doc/public/cairo-sections.txt     |    3 
 doc/public/tmpl/cairo-status.sgml |    1 
 doc/public/tmpl/cairo-text.sgml   |   31 ++++++++
 src/cairo-analysis-surface.c      |   82 +++++++++++++++++++++++
 src/cairo-gstate.c                |   38 +++++++----
 src/cairo-meta-surface-private.h  |   13 ++-
 src/cairo-meta-surface.c          |  131 ++++++++++++++++++++++++++------------
 src/cairo-misc.c                  |    2 
 src/cairo-paginated-surface.c     |   60 +++++++++++++++++
 src/cairo-scaled-font.c           |   14 ++--
 src/cairo-surface.c               |  110 ++++++++++++++++++++++++++-----
 src/cairo-types-private.h         |    2 
 src/cairo-unicode.c               |   23 +++---
 src/cairo-xlib-surface.c          |   10 +-
 src/cairo.c                       |  110 ++++++++++++++++++++++++++++++-
 src/cairo.h                       |   22 ++++++
 src/cairoint.h                    |   48 ++++++++++++-
 test/.gitignore                   |    2 
 20 files changed, 602 insertions(+), 102 deletions(-)

New commits:
commit 4ffea75d908ef041fbc5aa1da9a5b725d3c24263
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 27 11:18:22 2008 -0400

    Change cairo_text_cluster_t members signed
    
    Also reject clusters with no text.

diff --git a/src/cairo.c b/src/cairo.c
index fe68f0a..f55d78f 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -3233,17 +3233,18 @@ cairo_show_text_glyphs (cairo_t			   *cr,
 	int i;
 
 	for (i = 0; i < num_clusters; i++) {
-	    unsigned int cluster_bytes  = clusters[i].num_bytes;
-	    unsigned int cluster_glyphs = clusters[i].num_glyphs;
-
-	    /* A cluster should cover at least one byte or glyph. */
-	    if (cluster_bytes == 0 && cluster_glyphs == 0)
+	    int cluster_bytes  = clusters[i].num_bytes;
+	    int cluster_glyphs = clusters[i].num_glyphs;
+
+	    /* A cluster should cover at least one byte.
+	     * I can't see any use for a 0,0 cluster.
+	     * Zero-glyph clusters on the other hand are useful for
+	     * things like U+200C ZERO WIDTH NON-JOINER */
+	    if (cluster_bytes < 1 || cluster_glyphs < 0)
 	        goto BAD;
 
-	    /* Since utf8_len and num_glyphs are signed, but the rest of
-	     * values involved here unsigned, we can avoid overflow easily */
-	    if (cluster_bytes > (unsigned int)utf8_len || cluster_glyphs > (unsigned int)num_glyphs)
-	        goto BAD;
+	    /* Since n_bytes and n_glyphs are unsigned, but the rest of
+	     * values involved are signed, we can detect overflow easily */
 	    if (n_bytes+cluster_bytes > (unsigned int)utf8_len || n_glyphs+cluster_glyphs > (unsigned int)num_glyphs)
 	        goto BAD;
 
diff --git a/src/cairo.h b/src/cairo.h
index e8c6daf..61af650 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -827,8 +827,8 @@ typedef struct {
 } cairo_glyph_t;
 
 typedef struct {
-    unsigned int        num_bytes;
-    unsigned int        num_glyphs;
+    int        num_bytes;
+    int        num_glyphs;
 } cairo_text_cluster_t;
 
 /**
commit 4530c0b0ecdd19cfcbcb6d21b1db426ab42793d9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 17:15:42 2008 -0400

    [meta-surface] Implement show_text_glyphs; Remove show_glyphs
    
    One is enough.  The only downside is that meta-surface will consume
    32 more bytes per show_glyphs() call now.  If that's a concern,
    the show_glyphs implementation can be added back.

diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index 35957f7..bd16a5b 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -46,7 +46,7 @@ typedef enum {
     CAIRO_COMMAND_MASK,
     CAIRO_COMMAND_STROKE,
     CAIRO_COMMAND_FILL,
-    CAIRO_COMMAND_SHOW_GLYPHS,
+    CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
 
     /* Other junk. For most of these, we should be able to assert that
      * they never get called except as part of fallbacks for the 5
@@ -104,14 +104,19 @@ typedef struct _cairo_command_fill {
     cairo_antialias_t		 antialias;
 } cairo_command_fill_t;
 
-typedef struct _cairo_command_show_glyphs {
+typedef struct _cairo_command_show_text_glyphs {
     cairo_command_header_t       header;
     cairo_operator_t		 op;
     cairo_pattern_union_t	 source;
+    char			*utf8;
+    int				 utf8_len;
     cairo_glyph_t		*glyphs;
     unsigned int		 num_glyphs;
+    cairo_text_cluster_t	*clusters;
+    int				 num_clusters;
+    cairo_bool_t		 backward;
     cairo_scaled_font_t		*scaled_font;
-} cairo_command_show_glyphs_t;
+} cairo_command_show_text_glyphs_t;
 
 typedef struct _cairo_command_intersect_clip_path {
     cairo_command_header_t      header;
@@ -130,7 +135,7 @@ typedef union _cairo_command {
     cairo_command_mask_t			mask;
     cairo_command_stroke_t			stroke;
     cairo_command_fill_t			fill;
-    cairo_command_show_glyphs_t			show_glyphs;
+    cairo_command_show_text_glyphs_t		show_text_glyphs;
 
     /* The other junk. */
     cairo_command_intersect_clip_path_t		intersect_clip_path;
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 733ded4..427266b 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -39,7 +39,7 @@
 
 /* A meta surface is a surface that records all drawing operations at
  * the highest level of the surface backend interface, (that is, the
- * level of paint, mask, stroke, fill, and show_glyphs). The meta
+ * level of paint, mask, stroke, fill, and show_text_glyphs). The meta
  * surface can then be "replayed" against any target surface with:
  *
  *	_cairo_meta_surface_replay (meta, target);
@@ -157,10 +157,12 @@ _cairo_meta_surface_finish (void *abstract_surface)
 	    free (command);
 	    break;
 
-	case CAIRO_COMMAND_SHOW_GLYPHS:
-	    _cairo_pattern_fini (&command->show_glyphs.source.base);
-	    free (command->show_glyphs.glyphs);
-	    cairo_scaled_font_destroy (command->show_glyphs.scaled_font);
+	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
+	    _cairo_pattern_fini (&command->show_text_glyphs.source.base);
+	    free (command->show_text_glyphs.utf8);
+	    free (command->show_text_glyphs.glyphs);
+	    free (command->show_text_glyphs.clusters);
+	    cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
 	    free (command);
 	    break;
 
@@ -426,24 +428,34 @@ _cairo_meta_surface_fill (void			*abstract_surface,
     return status;
 }
 
+static cairo_bool_t
+_cairo_meta_surface_has_show_text_glyphs (void *abstract_surface)
+{
+    return TRUE;
+}
+
 static cairo_int_status_t
-_cairo_meta_surface_show_glyphs (void			*abstract_surface,
-				 cairo_operator_t	 op,
-				 cairo_pattern_t	*source,
-				 cairo_glyph_t		*glyphs,
-				 int			 num_glyphs,
-				 cairo_scaled_font_t	*scaled_font,
-				 int			*remaining_glyphs)
+_cairo_meta_surface_show_text_glyphs (void			    *abstract_surface,
+				      cairo_operator_t		     op,
+				      cairo_pattern_t		    *source,
+				      const char		    *utf8,
+				      int			     utf8_len,
+				      cairo_glyph_t		    *glyphs,
+				      int			     num_glyphs,
+				      const cairo_text_cluster_t    *clusters,
+				      int			     num_clusters,
+				      cairo_bool_t		     backward,
+				      cairo_scaled_font_t	    *scaled_font)
 {
     cairo_status_t status;
     cairo_meta_surface_t *meta = abstract_surface;
-    cairo_command_show_glyphs_t *command;
+    cairo_command_show_text_glyphs_t *command;
 
-    command = malloc (sizeof (cairo_command_show_glyphs_t));
+    command = malloc (sizeof (cairo_command_show_text_glyphs_t));
     if (command == NULL)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
+    command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS;
     command->header.region = CAIRO_META_REGION_ALL;
     command->op = op;
 
@@ -451,14 +463,39 @@ _cairo_meta_surface_show_glyphs (void			*abstract_surface,
     if (status)
 	goto CLEANUP_COMMAND;
 
-    command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
-    if (command->glyphs == NULL) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_SOURCE;
+    command->utf8 = NULL;
+    command->utf8_len = utf8_len;
+    command->glyphs = NULL;
+    command->num_glyphs = num_glyphs;
+    command->clusters = NULL;
+    command->num_clusters = num_clusters;
+
+    if (utf8_len) {
+	command->utf8 = malloc (utf8_len);
+	if (command->utf8 == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_ARRAYS;
+	}
+	memcpy (command->utf8, utf8, utf8_len);
+    }
+    if (num_glyphs) {
+	command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
+	if (command->glyphs == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_ARRAYS;
+	}
+	memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
+    }
+    if (num_clusters) {
+	command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
+	if (command->clusters == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_ARRAYS;
+	}
+	memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
     }
-    memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
 
-    command->num_glyphs = num_glyphs;
+    command->backward = backward;
 
     command->scaled_font = cairo_scaled_font_reference (scaled_font);
 
@@ -470,8 +507,11 @@ _cairo_meta_surface_show_glyphs (void			*abstract_surface,
 
   CLEANUP_SCALED_FONT:
     cairo_scaled_font_destroy (command->scaled_font);
+  CLEANUP_ARRAYS:
+    free (command->utf8);
     free (command->glyphs);
-  CLEANUP_SOURCE:
+    free (command->clusters);
+
     _cairo_pattern_fini (&command->source.base);
   CLEANUP_COMMAND:
     free (command);
@@ -622,15 +662,24 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
 
     /* Here are the 5 basic drawing operations, (which are in some
      * sense the only things that cairo_meta_surface should need to
-     * implement). */
+     * implement).  However, we implement the more generic show_text_glyphs
+     * instead of show_glyphs.  One or the other is eough. */
 
     _cairo_meta_surface_paint,
     _cairo_meta_surface_mask,
     _cairo_meta_surface_stroke,
     _cairo_meta_surface_fill,
-    _cairo_meta_surface_show_glyphs,
+    NULL,
+
+    _cairo_meta_surface_snapshot,
 
-    _cairo_meta_surface_snapshot
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+
+    _cairo_meta_surface_has_show_text_glyphs,
+    _cairo_meta_surface_show_text_glyphs
 };
 
 static cairo_path_fixed_t *
@@ -639,7 +688,7 @@ _cairo_command_get_path (cairo_command_t *command)
     switch (command->header.type) {
     case CAIRO_COMMAND_PAINT:
     case CAIRO_COMMAND_MASK:
-    case CAIRO_COMMAND_SHOW_GLYPHS:
+    case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
 	return NULL;
     case CAIRO_COMMAND_STROKE:
 	return &command->stroke.path;
@@ -705,14 +754,15 @@ _cairo_meta_surface_get_path (cairo_surface_t	 *surface,
 	    status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD);
 	    break;
 	}
-	case CAIRO_COMMAND_SHOW_GLYPHS:
+	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
 	{
-	    status = _cairo_scaled_font_glyph_path (command->show_glyphs.scaled_font,
-						    command->show_glyphs.glyphs,
-						    command->show_glyphs.num_glyphs,
+	    status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
+						    command->show_text_glyphs.glyphs,
+						    command->show_text_glyphs.num_glyphs,
 						    path);
 	    break;
 	}
+
 	default:
 	    ASSERT_NOT_REACHED;
 	}
@@ -873,13 +923,13 @@ _cairo_meta_surface_replay_internal (cairo_surface_t	     *surface,
 					      command->fill.antialias);
 	    break;
 	}
-	case CAIRO_COMMAND_SHOW_GLYPHS:
+	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
 	{
-	    cairo_glyph_t *glyphs = command->show_glyphs.glyphs;
+	    cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
 	    cairo_glyph_t *dev_glyphs;
-	    int i, num_glyphs = command->show_glyphs.num_glyphs;
+	    int i, num_glyphs = command->show_text_glyphs.num_glyphs;
 
-            /* show_glyphs is special because _cairo_surface_show_glyphs is allowed
+            /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
 	     * to modify the glyph array that's passed in.  We must always
 	     * copy the array before handing it to the backend.
 	     */
@@ -900,11 +950,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t	     *surface,
 		memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
 	    }
 
-	    status = _cairo_surface_show_glyphs	(target,
-						 command->show_glyphs.op,
-						 &command->show_glyphs.source.base,
-						 dev_glyphs, num_glyphs,
-						 command->show_glyphs.scaled_font);
+	    status = _cairo_surface_show_text_glyphs	(target,
+							 command->show_text_glyphs.op,
+							 &command->show_text_glyphs.source.base,
+							 command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
+							 dev_glyphs, num_glyphs,
+							 command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
+							 command->show_text_glyphs.backward,
+							 command->show_text_glyphs.scaled_font);
 
 	    free (dev_glyphs);
 	    break;
commit 93c3eebc6ec740317650e8ec166ae5311c12f0d7
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 16:45:09 2008 -0400

    [paginated-surface] Implement show_text_glyphs

diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index dc622ed..f25e792 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -632,6 +632,58 @@ _cairo_paginated_surface_show_glyphs (void			*abstract_surface,
     return status;
 }
 
+static cairo_bool_t
+_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
+{
+    cairo_paginated_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_has_show_text_glyphs (surface->target);
+}
+
+static cairo_int_status_t
+_cairo_paginated_surface_show_text_glyphs (void			    *abstract_surface,
+					  cairo_operator_t	     op,
+					  cairo_pattern_t	    *source,
+					  const char		    *utf8,
+					  int			     utf8_len,
+					  cairo_glyph_t		    *glyphs,
+					  int			     num_glyphs,
+					  const cairo_text_cluster_t *clusters,
+					  int			     num_clusters,
+					  cairo_bool_t		     backward,
+					  cairo_scaled_font_t	    *scaled_font)
+{
+    cairo_paginated_surface_t *surface = abstract_surface;
+    cairo_int_status_t status;
+
+    /* Optimize away erasing of nothing. */
+    if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+	return CAIRO_STATUS_SUCCESS;
+
+    surface->page_is_blank = FALSE;
+
+    /* Since this is a "wrapping" surface, we're calling back into
+     * _cairo_surface_show_glyphs from within a call to the same.
+     * Since _cairo_surface_show_glyphs acquires a mutex, we release
+     * and re-acquire the mutex around this nested call.
+     *
+     * Yes, this is ugly, but we consider it pragmatic as compared to
+     * adding locking code to all 18 surface-backend-specific
+     * show_glyphs functions, (which would get less testing and likely
+     * lead to bugs).
+     */
+    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+    status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
+					      utf8, utf8_len,
+					      glyphs, num_glyphs,
+					      clusters, num_clusters,
+					      backward,
+					      scaled_font);
+    CAIRO_MUTEX_LOCK (scaled_font->mutex);
+
+    return status;
+}
+
 static cairo_surface_t *
 _cairo_paginated_surface_snapshot (void *abstract_other)
 {
@@ -668,5 +720,11 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
     _cairo_paginated_surface_stroke,
     _cairo_paginated_surface_fill,
     _cairo_paginated_surface_show_glyphs,
-    _cairo_paginated_surface_snapshot
+    _cairo_paginated_surface_snapshot,
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+    _cairo_paginated_surface_has_show_text_glyphs,
+    _cairo_paginated_surface_show_text_glyphs
 };
commit 8f02cadf3dc0ed4aedfafad4644a5fdc9d3e8168
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 16:44:59 2008 -0400

    [analysis-surface] Implement show_text_glyphs

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 0ac37f0..12115a6 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -607,6 +607,77 @@ _cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
     return status;
 }
 
+static cairo_bool_t
+_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
+{
+    cairo_analysis_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_has_show_text_glyphs (surface->target);
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
+					  cairo_operator_t	     op,
+					  cairo_pattern_t	    *source,
+					  const char		    *utf8,
+					  int			     utf8_len,
+					  cairo_glyph_t		    *glyphs,
+					  int			     num_glyphs,
+					  const cairo_text_cluster_t *clusters,
+					  int			     num_clusters,
+					  cairo_bool_t		     backward,
+					  cairo_scaled_font_t	    *scaled_font)
+{
+    cairo_analysis_surface_t *surface = abstract_surface;
+    cairo_status_t	     status, backend_status;
+    cairo_rectangle_int_t    extents, glyph_extents;
+
+    if (!surface->target->backend->show_text_glyphs)
+	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
+    else
+	backend_status = (*surface->target->backend->show_text_glyphs) (surface->target, op,
+									source,
+									utf8, utf8_len,
+									glyphs, num_glyphs,
+									clusters, num_clusters,
+									backward,
+									scaled_font);
+
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
+    status = _cairo_surface_get_extents (&surface->base, &extents);
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
+    }
+
+    _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+    if (_cairo_operator_bounded_by_mask (op)) {
+	status = _cairo_scaled_font_glyph_device_extents (scaled_font,
+							  glyphs,
+							  num_glyphs,
+							  &glyph_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &glyph_extents);
+    }
+
+    status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
+    return status;
+}
+
 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
     NULL, /* create_similar */
@@ -639,6 +710,9 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     NULL, /* is_similar */
     NULL, /* reset */
     NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+    _cairo_analysis_surface_has_show_text_glyphs,
+    _cairo_analysis_surface_show_text_glyphs
 };
 
 cairo_surface_t *
@@ -832,7 +906,13 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
     (_stroke_func) _return_success,	    /* stroke */
     (_fill_func) _return_success,	    /* fill */
     (_show_glyphs_func) _return_success,    /* show_glyphs */
-    NULL  /* snapshot */
+    NULL, /* snapshot */
+    NULL, /* is_similar */
+    NULL, /* reset */
+    NULL, /* fill_stroke */
+    NULL, /* create_solid_pattern_surface */
+    NULL, /* has_show_text_glyphs */
+    NULL  /* show_text_glyphs */
 };
 
 cairo_surface_t *
commit 047566fd526f7936a49b630ed47c570dd70e837f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 16:15:12 2008 -0400

    Add cairo_show_text_glyphs API
    
    New public API:
    
    	cairo_text_cluster_t
    	cairo_has_show_text_glyphs()
    	cairo_show_text_glyphs()
    
    Add accompanying gstate and surface functions, and surface backend methods.
    No backends implement them just yet.

diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index c958638..7e60882 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -387,6 +387,7 @@ cairo_path_extents
 cairo_glyph_t
 cairo_font_slant_t
 cairo_font_weight_t
+cairo_text_cluster_t
 cairo_select_font_face
 cairo_set_font_size
 cairo_set_font_matrix
@@ -399,6 +400,8 @@ cairo_set_scaled_font
 cairo_get_scaled_font
 cairo_show_text
 cairo_show_glyphs
+cairo_has_show_text_glyphs
+cairo_show_text_glyphs
 cairo_font_extents
 cairo_text_extents
 cairo_glyph_extents
diff --git a/doc/public/tmpl/cairo-status.sgml b/doc/public/tmpl/cairo-status.sgml
index f88befe..37b5898 100644
--- a/doc/public/tmpl/cairo-status.sgml
+++ b/doc/public/tmpl/cairo-status.sgml
@@ -67,6 +67,7 @@ code is required before or after each individual cairo function call.
 @CAIRO_STATUS_USER_FONT_IMMUTABLE: 
 @CAIRO_STATUS_USER_FONT_ERROR: 
 @CAIRO_STATUS_NEGATIVE_COUNT: 
+ at CAIRO_STATUS_INVALID_CLUSTERS: 
 
 <!-- ##### FUNCTION cairo_status_to_string ##### -->
 <para>
diff --git a/doc/public/tmpl/cairo-text.sgml b/doc/public/tmpl/cairo-text.sgml
index 8de82ad..925d29b 100644
--- a/doc/public/tmpl/cairo-text.sgml
+++ b/doc/public/tmpl/cairo-text.sgml
@@ -70,6 +70,14 @@ Cairo has two sets of text rendering capabilities:
 @CAIRO_FONT_WEIGHT_NORMAL: 
 @CAIRO_FONT_WEIGHT_BOLD: 
 
+<!-- ##### STRUCT cairo_text_cluster_t ##### -->
+<para>
+
+</para>
+
+ at num_bytes: 
+ at num_glyphs: 
+
 <!-- ##### FUNCTION cairo_select_font_face ##### -->
 <para>
 
@@ -181,6 +189,29 @@ Cairo has two sets of text rendering capabilities:
 @num_glyphs: 
 
 
+<!-- ##### FUNCTION cairo_has_show_text_glyphs ##### -->
+<para>
+
+</para>
+
+ at cr: 
+
+
+<!-- ##### FUNCTION cairo_show_text_glyphs ##### -->
+<para>
+
+</para>
+
+ at cr: 
+ at utf8: 
+ at utf8_len: 
+ at glyphs: 
+ at num_glyphs: 
+ at clusters: 
+ at num_clusters: 
+ at backward: 
+
+
 <!-- ##### FUNCTION cairo_font_extents ##### -->
 <para>
 
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 2579de7..0eb6e7d 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1497,10 +1497,21 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
     return cairo_scaled_font_status (gstate->scaled_font);
 }
 
+cairo_bool_t
+_cairo_gstate_has_show_text_glyphs (cairo_gstate_t *gstate)
+{
+    return _cairo_surface_has_show_text_glyphs (gstate->target);
+}
+
 cairo_status_t
-_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
-			   const cairo_glyph_t *glyphs,
-			   int num_glyphs)
+_cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
+				const char		   *utf8,
+				int			    utf8_len,
+				const cairo_glyph_t	   *glyphs,
+				int			    num_glyphs,
+				const cairo_text_cluster_t *clusters,
+				int			    num_clusters,
+				cairo_bool_t		    backward)
 {
     cairo_status_t status;
     cairo_pattern_union_t source_pattern;
@@ -1543,14 +1554,19 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
      * rasterizer is something like ten times slower than freetype's for huge
      * sizes.  So, no win just yet.  For now, do it for insanely-huge sizes,
      * just to make sure we don't make anyone unhappy.  When we get a really
-     * fast rasterizer in cairo, we may want to readjust this. */
-    if (_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
-	status = _cairo_surface_show_glyphs (gstate->target,
-					     gstate->op,
-					     &source_pattern.base,
-					     transformed_glyphs,
-					     num_glyphs,
-					     gstate->scaled_font);
+     * fast rasterizer in cairo, we may want to readjust this.
+     *
+     * Needless to say, do this only if show_text_glyphs is not available. */
+    if (_cairo_gstate_has_show_text_glyphs (gstate) ||
+	_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
+	status = _cairo_surface_show_text_glyphs (gstate->target,
+						  gstate->op,
+						  &source_pattern.base,
+						  utf8, utf8_len,
+						  transformed_glyphs, num_glyphs,
+						  clusters, num_clusters,
+						  backward,
+						  gstate->scaled_font);
     } else {
 	cairo_path_fixed_t path;
 
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 30686a0..71338bf 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -111,6 +111,8 @@ cairo_status_to_string (cairo_status_t status)
 	return "error occurred in a user-font callback function";
     case CAIRO_STATUS_NEGATIVE_COUNT:
 	return "negative number used where it is not allowed";
+    case CAIRO_STATUS_INVALID_CLUSTERS:
+	return "input clusters do not represent the accompanying text and glyph arrays";
     }
 
     return "<unknown error status>";
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 31ff7cf..f244984 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1277,20 +1277,26 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
     cairo_status_t status;
     cairo_scaled_glyph_t *scaled_glyph;
 
+    *num_glyphs = 0;
+    *glyphs = NULL;
+
     status = scaled_font->status;
     if (status)
 	return status;
 
-    if (utf8[0] == '\0') {
-	*num_glyphs = 0;
-	*glyphs = NULL;
+    if (utf8[0] == '\0')
 	return CAIRO_STATUS_SUCCESS;
-    }
 
     CAIRO_MUTEX_LOCK (scaled_font->mutex);
     _cairo_scaled_font_freeze_cache (scaled_font);
 
     if (scaled_font->backend->text_to_glyphs) {
+
+	/* validate input so backend does not have to */
+	status = _cairo_utf8_to_ucs4 (utf8, -1, NULL, NULL);
+	if (status)
+	    goto DONE;
+
 	status = scaled_font->backend->text_to_glyphs (scaled_font,
 						       x, y, utf8,
 						       glyphs, num_glyphs);
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index c186dd9..6e6f7fc 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2135,13 +2135,41 @@ _cairo_surface_get_extents (cairo_surface_t         *surface,
     return status;
 }
 
+cairo_status_t
+_cairo_surface_show_glyphs (cairo_surface_t	*surface,
+			    cairo_operator_t	 op,
+			    cairo_pattern_t	*source,
+			    cairo_glyph_t	*glyphs,
+			    int			 num_glyphs,
+			    cairo_scaled_font_t	*scaled_font)
+{
+    return _cairo_surface_show_text_glyphs (surface,
+					    op,
+					    source,
+					    NULL, 0,
+					    glyphs, num_glyphs,
+					    NULL, 0,
+					    FALSE,
+					    scaled_font);
+}
+
+cairo_bool_t
+_cairo_surface_has_show_text_glyphs (cairo_surface_t	    *surface)
+{
+    if (surface->backend->has_show_text_glyphs)
+	return surface->backend->has_show_text_glyphs (surface);
+    else
+	return surface->backend->show_text_glyphs != NULL;
+}
+
 /* Note: the backends may modify the contents of the glyph array as long as
  * they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to
  * avoid copying the array again and again, and edit it in-place.
  * Backends are in fact free to use the array as a generic buffer as they
  * see fit.
  *
- * When they do return UNSUPPORTED, they may adjust remaining_glyphs to notify
+ * For show_glyphs backend method, and NOT for show_text_glyphs method,
+ * when they do return UNSUPPORTED, they may adjust remaining_glyphs to notify
  * that they have successfully rendered some of the glyphs (from the beginning
  * of the array), but not all.  If they don't touch remaining_glyphs, it
  * defaults to all glyphs.
@@ -2150,12 +2178,17 @@ _cairo_surface_get_extents (cairo_surface_t         *surface,
  * 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale.
  */
 cairo_status_t
-_cairo_surface_show_glyphs (cairo_surface_t	*surface,
-			    cairo_operator_t	 op,
-			    cairo_pattern_t	*source,
-			    cairo_glyph_t	*glyphs,
-			    int			 num_glyphs,
-			    cairo_scaled_font_t	*scaled_font)
+_cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
+				 cairo_operator_t	     op,
+				 cairo_pattern_t	    *source,
+				 const char		    *utf8,
+				 int			     utf8_len,
+				 cairo_glyph_t		    *glyphs,
+				 int			     num_glyphs,
+				 const cairo_text_cluster_t *clusters,
+				 int			     num_clusters,
+				 cairo_bool_t		     backward,
+				 cairo_scaled_font_t	    *scaled_font)
 {
     cairo_status_t status;
     cairo_scaled_font_t *dev_scaled_font = scaled_font;
@@ -2166,7 +2199,7 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
     if (surface->status)
 	return surface->status;
 
-    if (!num_glyphs)
+    if (!num_glyphs && !utf8_len)
 	return CAIRO_STATUS_SUCCESS;
 
     status = _cairo_surface_copy_pattern_for_destination (source,
@@ -2200,16 +2233,56 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 
     status = CAIRO_INT_STATUS_UNSUPPORTED;
 
-    if (surface->backend->show_glyphs) {
-	int remaining_glyphs = num_glyphs;
-	status = surface->backend->show_glyphs (surface, op, dev_source,
-						glyphs, num_glyphs,
-                                                dev_scaled_font,
-						&remaining_glyphs);
-	glyphs += num_glyphs - remaining_glyphs;
-	num_glyphs = remaining_glyphs;
-	if (remaining_glyphs == 0)
-	    status = CAIRO_STATUS_SUCCESS;
+    if (clusters) {
+	/* A real show_text_glyphs call.  Try show_text_glyphs backend
+	 * method first */
+	if (surface->backend->show_text_glyphs) {
+	    status = surface->backend->show_text_glyphs (surface, op, dev_source,
+							 utf8, utf8_len,
+							 glyphs, num_glyphs,
+							 clusters, num_clusters,
+							 backward,
+							 dev_scaled_font);
+	}
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) {
+	    int remaining_glyphs = num_glyphs;
+	    status = surface->backend->show_glyphs (surface, op, dev_source,
+						    glyphs, num_glyphs,
+						    dev_scaled_font,
+						    &remaining_glyphs);
+	    glyphs += num_glyphs - remaining_glyphs;
+	    num_glyphs = remaining_glyphs;
+	    if (remaining_glyphs == 0)
+		status = CAIRO_STATUS_SUCCESS;
+	}
+    } else {
+	/* A mere show_glyphs call.  Try show_glyphs backend method first */
+	if (surface->backend->show_glyphs) {
+	    int remaining_glyphs = num_glyphs;
+	    status = surface->backend->show_glyphs (surface, op, dev_source,
+						    glyphs, num_glyphs,
+						    dev_scaled_font,
+						    &remaining_glyphs);
+	    glyphs += num_glyphs - remaining_glyphs;
+	    num_glyphs = remaining_glyphs;
+	    if (remaining_glyphs == 0)
+		status = CAIRO_STATUS_SUCCESS;
+	} else if (surface->backend->show_text_glyphs) {
+	    /* Intentionally only try show_text_glyphs method for show_glyphs
+	     * calls if backend does not have show_glyphs.  If backend has
+	     * both methods implemented, we don't fallback from show_glyphs to
+	     * show_text_glyphs, and hence the backend an assume in its
+	     * show_text_glyphs call that clusters is not NULL (which also
+	     * implies that UTF-8 is not NULL, unless the text is
+	     * zero-length).
+	     */
+	    status = surface->backend->show_text_glyphs (surface, op, dev_source,
+							 utf8, utf8_len,
+							 glyphs, num_glyphs,
+							 clusters, num_clusters,
+							 backward,
+							 dev_scaled_font);
+	}
     }
 
     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
@@ -2581,6 +2654,7 @@ _cairo_surface_create_in_error (cairo_status_t status)
     case CAIRO_STATUS_USER_FONT_IMMUTABLE:
     case CAIRO_STATUS_USER_FONT_ERROR:
     case CAIRO_STATUS_NEGATIVE_COUNT:
+    case CAIRO_STATUS_INVALID_CLUSTERS:
     default:
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_surface_t *) &_cairo_surface_nil;
diff --git a/src/cairo.c b/src/cairo.c
index afc076d..fe68f0a 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -3109,15 +3109,19 @@ cairo_show_text (cairo_t *cr, const char *utf8)
     cairo_get_current_point (cr, &x, &y);
 
     status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
-					       x, y,
-					       &glyphs, &num_glyphs);
+					   x, y,
+					   &glyphs, &num_glyphs);
     if (status)
 	goto BAIL;
 
     if (num_glyphs == 0)
 	return;
 
-    status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
+    status = _cairo_gstate_show_text_glyphs (cr->gstate,
+					     NULL, 0,
+					     glyphs, num_glyphs,
+					     NULL, 0,
+					     FALSE);
     if (status)
 	goto BAIL;
 
@@ -3171,7 +3175,104 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
 	return;
     }
 
-    status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
+    status = _cairo_gstate_show_text_glyphs (cr->gstate,
+					     NULL, 0,
+					     glyphs, num_glyphs,
+					     NULL, 0,
+					     FALSE);
+    if (status)
+	_cairo_set_error (cr, status);
+}
+
+cairo_bool_t
+cairo_has_show_text_glyphs (cairo_t			   *cr)
+{
+    return _cairo_gstate_has_show_text_glyphs (cr->gstate);
+}
+
+void
+cairo_show_text_glyphs (cairo_t			   *cr,
+			const char		   *utf8,
+			int			    utf8_len,
+			const cairo_glyph_t	   *glyphs,
+			int			    num_glyphs,
+			const cairo_text_cluster_t *clusters,
+			int			    num_clusters,
+			cairo_bool_t		    backward)
+{
+    cairo_status_t status;
+
+    if (cr->status)
+	return;
+
+    /* A slew of sanity checks */
+
+    /* A -1 for utf8_len means NUL-terminated */
+    if (utf8_len == -1)
+	utf8_len = strlen (utf8);
+
+    /* Apart from that, no negatives */
+    if (num_glyphs < 0 || utf8_len < 0 || num_clusters < 0) {
+	_cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT);
+	return;
+    }
+
+    /* And no NULLs for non-zeros */
+    if ((num_glyphs   && glyphs   == NULL) ||
+	(utf8_len     && utf8     == NULL) ||
+	(num_clusters && clusters == NULL)) {
+	_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
+	return;
+    }
+
+    /* Make sure clusters cover the entire glyphs and utf8 arrays,
+     * and that cluster boundaries are UTF-8 boundaries. */
+    {
+	unsigned int n_bytes  = 0;
+	unsigned int n_glyphs = 0;
+	int i;
+
+	for (i = 0; i < num_clusters; i++) {
+	    unsigned int cluster_bytes  = clusters[i].num_bytes;
+	    unsigned int cluster_glyphs = clusters[i].num_glyphs;
+
+	    /* A cluster should cover at least one byte or glyph. */
+	    if (cluster_bytes == 0 && cluster_glyphs == 0)
+	        goto BAD;
+
+	    /* Since utf8_len and num_glyphs are signed, but the rest of
+	     * values involved here unsigned, we can avoid overflow easily */
+	    if (cluster_bytes > (unsigned int)utf8_len || cluster_glyphs > (unsigned int)num_glyphs)
+	        goto BAD;
+	    if (n_bytes+cluster_bytes > (unsigned int)utf8_len || n_glyphs+cluster_glyphs > (unsigned int)num_glyphs)
+	        goto BAD;
+
+	    /* Make sure we've got valid UTF-8 for the cluster */
+	    status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL);
+	    if (status) {
+		_cairo_set_error (cr, status);
+		return;
+	    }
+
+	    n_bytes  += cluster_bytes ;
+	    n_glyphs += cluster_glyphs;
+	}
+
+	if (n_bytes != (unsigned int)utf8_len || n_glyphs != (unsigned int)num_glyphs) {
+	  BAD:
+	    _cairo_set_error (cr, CAIRO_STATUS_INVALID_CLUSTERS);
+	    return;
+	}
+    }
+
+    if (num_glyphs == 0 && utf8_len == 0)
+	return;
+
+    status = _cairo_gstate_show_text_glyphs (cr->gstate,
+					     utf8, utf8_len,
+					     glyphs, num_glyphs,
+					     clusters, num_clusters,
+					     !!backward);
     if (status)
 	_cairo_set_error (cr, status);
 }
diff --git a/src/cairo.h b/src/cairo.h
index 3954159..e8c6daf 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -207,6 +207,7 @@ typedef struct _cairo_user_data_key {
  * @CAIRO_STATUS_USER_FONT_IMMUTABLE: the user-font is immutable (Since 1.8)
  * @CAIRO_STATUS_USER_FONT_ERROR: error occurred in a user-font callback function (Since 1.8)
  * @CAIRO_STATUS_NEGATIVE_COUNT: negative number used where it is not allowed (Since 1.8)
+ * @CAIRO_STATUS_INVALID_CLUSTERS: input clusters do not represent the accompanying text and glyph array (Since 1.8)
  *
  * #cairo_status_t is used to indicate errors that can occur when
  * using Cairo. In some cases it is returned directly by functions.
@@ -245,7 +246,8 @@ typedef enum _cairo_status {
     CAIRO_STATUS_FONT_TYPE_MISMATCH,
     CAIRO_STATUS_USER_FONT_IMMUTABLE,
     CAIRO_STATUS_USER_FONT_ERROR,
-    CAIRO_STATUS_NEGATIVE_COUNT
+    CAIRO_STATUS_NEGATIVE_COUNT,
+    CAIRO_STATUS_INVALID_CLUSTERS,
     /* after adding a new error: update CAIRO_STATUS_LAST_STATUS in cairoint.h */
 } cairo_status_t;
 
@@ -824,6 +826,11 @@ typedef struct {
     double               y;
 } cairo_glyph_t;
 
+typedef struct {
+    unsigned int        num_bytes;
+    unsigned int        num_glyphs;
+} cairo_text_cluster_t;
+
 /**
  * cairo_text_extents_t:
  * @x_bearing: the horizontal distance from the origin to the
@@ -1124,6 +1131,19 @@ cairo_show_text (cairo_t *cr, const char *utf8);
 cairo_public void
 cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
 
+cairo_public cairo_bool_t
+cairo_has_show_text_glyphs (cairo_t *cr);
+
+cairo_public void
+cairo_show_text_glyphs (cairo_t			   *cr,
+			const char		   *utf8,
+			int			    utf8_len,
+			const cairo_glyph_t	   *glyphs,
+			int			    num_glyphs,
+			const cairo_text_cluster_t *clusters,
+			int			    num_clusters,
+			cairo_bool_t		    backward);
+
 cairo_public void
 cairo_text_path  (cairo_t *cr, const char *utf8);
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 9e5c38c..50f5681 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -110,7 +110,7 @@ _cairo_win32_tmpfile (void);
  * a bit of a pain, but it should be easy to always catch as long as
  * one adds a new test case to test a trigger of the new status value.
  */
-#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_NEGATIVE_COUNT
+#define CAIRO_STATUS_LAST_STATUS CAIRO_STATUS_INVALID_CLUSTERS
 
 
 /* Size in bytes of buffer to use off the stack per functions.
@@ -751,6 +751,22 @@ struct _cairo_surface_backend {
     (*create_solid_pattern_surface)
 			        (void			*surface,
 				 cairo_solid_pattern_t  *solid_pattern);
+
+    cairo_bool_t
+    (*has_show_text_glyphs)	(void			    *surface);
+
+    cairo_warn cairo_int_status_t
+    (*show_text_glyphs)		(void			    *surface,
+				 cairo_operator_t	     op,
+				 cairo_pattern_t	    *source,
+				 const char		    *utf8,
+				 int			     utf8_len,
+				 cairo_glyph_t		    *glyphs,
+				 int			     num_glyphs,
+				 const cairo_text_cluster_t *clusters,
+				 int			     num_clusters,
+				 cairo_bool_t		     backward,
+				 cairo_scaled_font_t	    *scaled_font);
 };
 
 #include "cairo-surface-private.h"
@@ -1214,10 +1230,18 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
 			     int num_glyphs,
 			     cairo_text_extents_t *extents);
 
+cairo_private cairo_bool_t
+_cairo_gstate_has_show_text_glyphs (cairo_gstate_t *gstate);
+
 cairo_private cairo_status_t
-_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
-			   const cairo_glyph_t *glyphs,
-			   int num_glyphs);
+_cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
+				const char		   *utf8,
+				int			    utf8_len,
+				const cairo_glyph_t	   *glyphs,
+				int			    num_glyphs,
+				const cairo_text_cluster_t *clusters,
+				int			    num_clusters,
+				cairo_bool_t		    backward);
 
 cairo_private cairo_status_t
 _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
@@ -1729,6 +1753,22 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 			    int			 num_glyphs,
 			    cairo_scaled_font_t	*scaled_font);
 
+cairo_private cairo_bool_t
+_cairo_surface_has_show_text_glyphs (cairo_surface_t	    *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
+				 cairo_operator_t	     op,
+				 cairo_pattern_t	    *source,
+				 const char		    *utf8,
+				 int			     utf8_len,
+				 cairo_glyph_t		    *glyphs,
+				 int			     num_glyphs,
+				 const cairo_text_cluster_t *clusters,
+				 int			     num_clusters,
+				 cairo_bool_t		     backward,
+				 cairo_scaled_font_t	    *scaled_font);
+
 cairo_private cairo_status_t
 _cairo_surface_composite_trapezoids (cairo_operator_t	op,
 				     cairo_pattern_t	*pattern,
commit dff0dd0c63e530e21471531299a8f260cf88f001
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 15:58:06 2008 -0400

    Allow NULL output in _cairo_utf8_to_ucs4()
    
    The function can be used to validate UTF-8 text now.

diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
index caa4727..c4873d5 100644
--- a/src/cairo-unicode.c
+++ b/src/cairo-unicode.c
@@ -202,7 +202,7 @@ _utf8_get_char_extended (const unsigned char *p,
  *   If @len is supplied and the string has an embedded nul
  *   byte, only the portion before the nul byte is converted.
  * @result: location to store a pointer to a newly allocated UTF-32
- *   string (always native endian). Free with free(). A 0
+ *   string (always native endian), or %NULL. Free with free(). A 0
  *   word will be written after the last character.
  * @items_written: location to store number of 32-bit words
  *   written. (Not including the trailing 0)
@@ -241,18 +241,21 @@ _cairo_utf8_to_ucs4 (const char *str,
 	in = UTF8_NEXT_CHAR (in);
     }
 
-    str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
-    if (!str32)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (result) {
+	str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
+	if (!str32)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    in = ustr;
-    for (i=0; i < n_chars; i++) {
-	str32[i] = _utf8_get_char (in);
-	in = UTF8_NEXT_CHAR (in);
+	in = ustr;
+	for (i=0; i < n_chars; i++) {
+	    str32[i] = _utf8_get_char (in);
+	    in = UTF8_NEXT_CHAR (in);
+	}
+	str32[i] = 0;
+
+	*result = str32;
     }
-    str32[i] = 0;
 
-    *result = str32;
     if (items_written)
 	*items_written = n_chars;
 
commit 883c972a9bc0aafb817a02c7b4a8c6f250796405
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 16:08:39 2008 -0400

    [cairo-types] fix doc syntax

diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 36661e4..1baab26 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -132,7 +132,7 @@ typedef enum _cairo_paginated_mode {
 /* Sure wish C had a real enum type so that this would be distinct
  * from #cairo_status_t. Oh well, without that, I'll use this bogus 100
  * offset.  We want to keep it fit in int8_t as the compiler may choose
- * that for cairo_status_t */
+ * that for #cairo_status_t */
 typedef enum _cairo_int_status {
     CAIRO_INT_STATUS_UNSUPPORTED = 100,
     CAIRO_INT_STATUS_DEGENERATE,
commit 787fb135663ebd9ab4a8d38da8fafc5e82d47ec5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 16:08:21 2008 -0400

    [xlib] Use _cairo_xlib_surface_create_internal() directly

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index a3d3851..b7ede3a 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1191,10 +1191,12 @@ _cairo_xlib_surface_create_solid_pattern_surface (void                  *abstrac
 			    other->depth);
 
     surface = (cairo_xlib_surface_t *)
-	      cairo_xlib_surface_create (other->dpy,
-					 pixmap,
-					 other->visual,
-					 image->width, image->height);
+	      _cairo_xlib_surface_create_internal (other->dpy,
+						   pixmap,
+						   other->screen, other->visual,
+						   NULL,
+						   image->width, image->height,
+						   0);
     status = surface->base.status;
     if (status)
 	goto BAIL;
commit ba62d2d30a960d921f6efe84e2d6dc93d0de6e39
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 26 16:20:47 2008 -0400

    Update .gitignore files

diff --git a/boilerplate/.gitignore b/boilerplate/.gitignore
index c132572..49c76a3 100644
--- a/boilerplate/.gitignore
+++ b/boilerplate/.gitignore
@@ -1,3 +1,4 @@
+TAGS
 *.lo
 *.la
 *.exe
diff --git a/doc/public/.gitignore b/doc/public/.gitignore
index fa0e847..493a241 100644
--- a/doc/public/.gitignore
+++ b/doc/public/.gitignore
@@ -4,6 +4,7 @@ Makefile.in
 cairo-decl-list.txt
 cairo-decl.txt
 cairo-docs.sgml
+cairo-undeclared.txt
 cairo-undocumented.txt
 cairo-unused.txt
 cairo.hierarchy
diff --git a/test/.gitignore b/test/.gitignore
index 8fddf60..4a72553 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,3 +1,4 @@
+TAGS
 .deps
 .libs
 Makefile
@@ -204,6 +205,7 @@ unantialiased-shapes
 unbounded-operator
 user-data
 user-font
+user-font-proxy
 xlib-expose-event
 xlib-surface
 xlib-surface-source


More information about the cairo-commit mailing list