[cairo-commit] cairo/src Makefile.am, 1.26, 1.27 cairo.c, 1.42, 1.43 cairo_cache.c, NONE, 1.1 cairo_font.c, 1.25, 1.26 cairo_ft_font.c, 1.23, 1.24 cairo_glitz_surface.c, 1.8, 1.9 cairo_gstate.c, 1.60, 1.61 cairo_image_surface.c, 1.16, 1.17 cairo_png_surface.c, 1.8, 1.9 cairo_ps_surface.c, 1.13, 1.14 cairo_xcb_surface.c, 1.11, 1.12 cairo_xlib_surface.c, 1.24, 1.25 cairoint.h, 1.69, 1.70

Graydon Hoare commit at pdx.freedesktop.org
Fri Oct 8 12:09:54 PDT 2004


Committed by: graydon

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv9655/src

Modified Files:
	Makefile.am cairo.c cairo_font.c cairo_ft_font.c 
	cairo_glitz_surface.c cairo_gstate.c cairo_image_surface.c 
	cairo_png_surface.c cairo_ps_surface.c cairo_xcb_surface.c 
	cairo_xlib_surface.c cairoint.h 
Added Files:
	cairo_cache.c 
Log Message:
2004-10-07  Graydon Hoare  <graydon at redhat.com>

	* src/Makefile.am (libcairo_la_SOURCES): Add cairo_cache.c

	* src/cairo.c
	(cairo_text_extents)
	(cairo_show_text)
	(cairo_text_path): Rewrite using temporary glyph arrays

	* src/cairo_cache.c: New file.

	* src/cairo_font.c (_cairo_glyph_cache_create)
	(_cairo_glyph_cache_destroy)
	(_cairo_glyph_cache_reference)
	(_cairo_glyph_cache_pop_last)
	(_cairo_glyph_surface_init)
	(_cairo_font_lookup_glyph): Remove old glyph cache code.
	(_cairo_font_scale)
	(_cairo_font_transform): Remove font-transforming code.
	(_cairo_font_text_extents)
	(_cairo_font_text_bbox)
	(_cairo_font_show_text)
	(_cairo_font_text_path): Remove text-API code.
	(_cairo_font_cache_key_t): New structure type.
	(_font_cache_hash)
	(_font_cache_keys_equal)
	(_font_cache_create_entry)
	(_font_cache_destroy_entry)
	(_font_cache_destroy_cache): New font cache code.
	(_global_font_cache)
	(_lock_global_font_cache)
	(_unlock_global_font_cache)
	(_get_global_font_cache): New global font cache.
	(_cairo_font_text_to_glyphs)
	(_cairo_glyph_cache_hash)
	(_cairo_glyph_cache_keys_equal)
	(_image_glyph_cache_create_entry)
	(_image_glyph_cache_destroy_entry)		
	(_image_glyph_cache_destroy_cache): New glyph cache code.
	(_global_image_glyph_cache)
	(_cairo_lock_global_image_glyph_cache)
	(_cairo_unlock_global_image_glyph_cache)
	(_cairo_get_global_image_glyph_cache): New global glyph cache.
	(_cairo_font_cache_backend): New structure.
	(_cairo_image_cache_backend): Likewise.
	(_cairo_font_create): Reimplement in terms of font cache.
	(_cairo_font_init): Remove matrix and glyph cache related code.
	(_cairo_font_copy): Likewise.
	(_cairo_font_show_glyphs): Delegate to surface when possible.
	(_cairo_font_glyph_extents)
	(_cairo_font_glyph_bbox)
	(_cairo_font_glyph_path)
	(_cairo_font_font_extents)
	(_cairo_font_show_glyphs): Rename to as cairo_unscaled_font_XXX,
	and add scale parameter.

	* src/cairo_ft_font.c
	(ft_cache_t)
	(ft_font_val_t)
	(cairo_ft_cache_key_t)
	(cairo_ft_cache_entry_t): New structure types.
	(_create_from_face)
	(_reference_font_val)
	(_destroy_font_val)
	(_create_from_library_and_pattern): New functions.
	(_ft_font_cache_hash)
	(_ft_font_cache_keys_equal)
	(_ft_font_cache_create_entry)
	(_ft_font_cache_destroy_entry)	
	(_ft_font_cache_destroy_cache): New ft font cache code.
	(_global_ft_cache)
	(_lock_global_ft_cache)
	(_unlock_global_ft_cache)
	(_get_global_ft_cache): New global ft font cache.
	(_ft_font_cache_backend): New structure.
	(_cairo_ft_font_create): Rewrite to use cache.
	(_cairo_ft_font_destroy): Likewise.
	(_cairo_ft_font_copy): Remove.
	(_install_font_matrix): Rename as _install_font_scale.
	(_utf8_to_glyphs): Rename as _cairo_ft_font_text_to_glyphs.
	(_cairo_ft_font_text_to_glyphs): Use cache for metrics.
	(_cairo_ft_font_extents): Accept size, use scaled metrics.
	(_cairo_ft_font_glyph_extents)
	(_cairo_ft_font_glyph_bbox)
	(_cairo_ft_font_show_glyphs)
	(_cairo_ft_font_glyph_path): Modify to use size, cache. 
	(_cairo_ft_font_text_extents)
	(_cairo_ft_font_text_bbox)
	(_cairo_ft_font_show_text)		
	(_cairo_ft_font_text_path): Remove text-API code.
	(cairo_ft_font_create)
	(cairo_ft_font_create_for_ft_face)
	(cairo_ft_font_face)
	(cairo_ft_font_pattern): Rewrite using ft_font_val_t.

	* src/cairo_gstate.c (cairo_gstate_init_copy): Just reference font.
	(_cairo_gstate_fini): Finalize font matrix.
	(_cairo_gstate_default_matrix): Initialize font matrix.
	(_cairo_gstate_clip): Re-enable clipping rectangle.
	(_cairo_gstate_select_font)
	(_cairo_gstate_set_font): Set font matrix to identity.
	(_cairo_gstate_scale_font): Scale font matrix, not font.
	(_cairo_gstate_transform_font): Transform font matrix, not font.
	(_cairo_gstate_set_font_transform): Install as font matrix, not in font.
	(_build_font_scale): New helper function.
	(_cairo_gstate_text_to_glyphs): New function.
	(_cairo_gstate_current_font_extents)
	(_cairo_gstate_glyph_extents)
	(_cairo_gstate_show_glyphs)
	(_cairo_gstate_glyph_path): Rewrite using font matrix and size.
	(_cairo_gstate_text_path
	(_cairo_gstate_text_extents)
	(_cairo_gstate_show_text): Remove text-API code.

	* src/cairo_xlib_surface.c 
	(_cairo_xlib_surface_set_clip_region): Minor bug fix.
	(_cairo_xlib_surface_show_glyphs): New function.
	(_cairo_xlib_surface_backend): Add reference to new function.
	(glyphset_cache_t)
	(glyphset_cache_entry_t): New structure types.	
	(_next_xlib_glyph): New helper function.
	(_xlib_glyphset_cache_create_value)
	(_xlib_glyphset_cache_destroy_cache)
	(_xlib_glyphset_cache_destroy_value)
	(_xlib_glyphset_cache_backend): New  glyphset cache code.
	(_xlib_glyphset_caches)
	(_lock_xlib_glyphset_caches)
	(_unlock_xlib_glyphset_caches)
	(_get_glyphset_cache): New global glyphset cache.

	* src/cairo_glitz_surface.c (cairo_glitz_surface_backend):
	Add NULL entry for show_glyphs. 

	* src/cairo_image_surface.c (cairo_image_surface_backend):
	Add NULL entry for show_glyphs. 

	* src/cairo_ps_surface.c (cairo_ps_surface_backend):
	Add NULL entry for show_glyphs. 

	* src/cairo_png_surface.c (cairo_png_surface_backend):
	Add NULL entry for show_glyphs. 

	* src/cairo_xcb_surface.c (cairo_xcb_surface_backend):
	Add NULL entry for show_glyphs. 

	* src/cairoint.h (cairo_cache_backend_t): New structure type.
	(cairo_cache_entry_base_t)
	(cairo_cache_arrangement_t)
	(cairo_cache_t): New structure types.
	(_cairo_cache_init)
	(_cairo_cache_reference)
	(_cairo_cache_destroy)
	(_cairo_cache_lookup)
	(_cairo_hash_string): New cache functions.
	(CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT)
	(CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT)
	(CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT)
	(CAIRO_FT_CACHE_NUM_FONTS_DEFAULT): New constants.
	(cairo_font_scale_t)
	(cairo_glyph_cache_key_t)
	(cairo_image_glyph_cache_entry_t): New structure types.
	(_cairo_lock_global_image_glyph_cache)
	(_cairo_unlock_global_image_glyph_cache)
	(_cairo_get_global_image_glyph_cache)
	(_cairo_glyph_cache_hash)
	(_cairo_glyph_cache_keys_equal): New functions for glyph caches.
	(cairo_font_backend_t): Remove text-API calls, add scale params,
	remove copy call.
	(cairo_surface_backend_t): Add show_glyphs entry.
	(cairo_glyph_surface_t)
	(cairo_glyph_surface_node_t): Remove old glyph cache structures.
	(cairo_unscaled_font_t): New structure type.
	(cairo_font): Remove glyph cache member, add pointer to unscaled.
	(cairo_gstate): Add font_matrix member, change to hold unscaled.
	(_cairo_gstate_set_font_transform)
	(_cairo_gstate_current_font_transform)
	(_cairo_gstate_text_to_glyphs): New functions.
	(_cairo_gstate_text_path
	(_cairo_gstate_text_extents)
	(_cairo_gstate_show_text)
	(_cairo_font_text_extents)
	(_cairo_font_text_bbox)
	(_cairo_font_show_text)
	(_cairo_font_text_path): Remove text-API code.
	(_cairo_font_glyph_extents)
	(_cairo_font_glyph_bbox)
	(_cairo_font_glyph_path)
	(_cairo_font_font_extents)
	(_cairo_font_show_glyphs): Add scale parameter.



Index: Makefile.am
===================================================================
RCS file: /cvs/cairo/cairo/src/Makefile.am,v
retrieving revision 1.26
retrieving revision 1.27
diff -C2 -d -r1.26 -r1.27
*** Makefile.am	11 Sep 2004 11:23:18 -0000	1.26
--- Makefile.am	8 Oct 2004 19:09:51 -0000	1.27
***************
*** 32,35 ****
--- 32,36 ----
  	cairo.c			\
  	cairo.h			\
+ 	cairo_cache.c		\
  	cairo_color.c		\
  	cairo_fixed.c		\

Index: cairo.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -C2 -d -r1.42 -r1.43
*** cairo.c	4 Sep 2004 13:38:34 -0000	1.42
--- cairo.c	8 Oct 2004 19:09:51 -0000	1.43
***************
*** 901,910 ****
  		    cairo_text_extents_t   *extents)
  {
      CAIRO_CHECK_SANITY (cr);
      if (cr->status)
  	return;
!     
!     cr->status = _cairo_gstate_text_extents (cr->gstate, utf8, extents);
      CAIRO_CHECK_SANITY (cr);
  }
  
--- 901,925 ----
  		    cairo_text_extents_t   *extents)
  {
+     cairo_glyph_t *glyphs = NULL;
+     int nglyphs;
+ 
      CAIRO_CHECK_SANITY (cr);
      if (cr->status)
  	return;
! 
!     cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
      CAIRO_CHECK_SANITY (cr);
+ 
+     if (cr->status) {
+ 	if (glyphs)
+ 	    free (glyphs);
+ 	return;
+     }
+ 	
+     cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, nglyphs, extents);
+     CAIRO_CHECK_SANITY (cr);
+     
+     if (glyphs)
+ 	free (glyphs);
  }
  
***************
*** 927,930 ****
--- 942,948 ----
  cairo_show_text (cairo_t *cr, const unsigned char *utf8)
  {
+     cairo_glyph_t *glyphs = NULL;
+     int nglyphs;
+ 
      CAIRO_CHECK_SANITY (cr);
      if (cr->status)
***************
*** 934,939 ****
  	return;
  
!     cr->status = _cairo_gstate_show_text (cr->gstate, utf8);
      CAIRO_CHECK_SANITY (cr);
  }
  
--- 952,969 ----
  	return;
  
!     cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
      CAIRO_CHECK_SANITY (cr);
+ 
+     if (cr->status) {
+ 	if (glyphs)
+ 	    free (glyphs);
+ 	return;
+     }
+ 
+     cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, nglyphs);
+     CAIRO_CHECK_SANITY (cr);
+ 
+     if (glyphs)
+ 	free (glyphs);
  }
  
***************
*** 952,961 ****
  cairo_text_path  (cairo_t *cr, const unsigned char *utf8)
  {
      CAIRO_CHECK_SANITY (cr);
      if (cr->status)
  	return;
  
!     cr->status = _cairo_gstate_text_path (cr->gstate, utf8);
      CAIRO_CHECK_SANITY (cr);
  }
  
--- 982,1006 ----
  cairo_text_path  (cairo_t *cr, const unsigned char *utf8)
  {
+     cairo_glyph_t *glyphs = NULL;
+     int nglyphs;
+ 
      CAIRO_CHECK_SANITY (cr);
      if (cr->status)
  	return;
  
!     cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
      CAIRO_CHECK_SANITY (cr);
+ 
+     if (cr->status) {
+ 	if (glyphs)
+ 	    free (glyphs);
+ 	return;
+     }
+ 
+     cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, nglyphs);
+     CAIRO_CHECK_SANITY (cr);
+ 
+     if (glyphs)
+ 	free (glyphs);
  }
  

--- NEW FILE: cairo_cache.c ---
(This appears to be a binary file; contents omitted.)

Index: cairo_font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_font.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -C2 -d -r1.25 -r1.26
*** cairo_font.c	4 Sep 2004 13:38:34 -0000	1.25
--- cairo_font.c	8 Oct 2004 19:09:51 -0000	1.26
***************
*** 37,54 ****
  #include "cairoint.h"
  
- static cairo_glyph_cache_t *
- _cairo_glyph_cache_create (void);
  
! static void
! _cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache);
  
! static void
! _cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache);
  
! cairo_font_t *
! _cairo_font_create (const char           *family, 
! 		    cairo_font_slant_t   slant, 
! 		    cairo_font_weight_t  weight)
  {
      const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
  
--- 37,94 ----
  #include "cairoint.h"
  
  
! /* First we implement a global font cache for named fonts. */
  
! typedef struct {
!     cairo_cache_entry_base_t base;
!     const char *family;
!     cairo_font_slant_t slant;
!     cairo_font_weight_t weight;    
! } cairo_font_cache_key_t;
  
! typedef struct {
!     cairo_font_cache_key_t key;
!     cairo_unscaled_font_t *unscaled;
! } cairo_font_cache_entry_t;
! 
! static unsigned long
! _font_cache_hash (void *cache, void *key)
! {
!     cairo_font_cache_key_t *in;
!     in = (cairo_font_cache_key_t *) key;
!     unsigned long hash;
! 
!     /* 1607 and 1451 are just a couple random primes. */
!     hash = _cairo_hash_string (in->family);
!     hash += ((unsigned long) in->slant) * 1607;
!     hash += ((unsigned long) in->weight) * 1451;
!     return hash;
! }
! 
! 
! static int
! _font_cache_keys_equal (void *cache,
! 			void *k1,
! 			void *k2)
  {
+     cairo_font_cache_key_t *a, *b;
+     a = (cairo_font_cache_key_t *) k1;
+     b = (cairo_font_cache_key_t *) k2;
+     
+     return (strcmp (a->family, b->family) == 0) 
+ 	&& (a->weight == b->weight)
+ 	&& (a->slant == b->slant);
+ }
+ 
+ 
+ static cairo_status_t
+ _font_cache_create_entry (void *cache,
+ 			  void *key,
+ 			  void **return_value)
+ {
+     cairo_font_cache_key_t *k;
+     cairo_font_cache_entry_t *entry;
+     k = (cairo_font_cache_key_t *) key;
+ 
      const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
  
***************
*** 59,422 ****
       * ugly one if necessary). */
  
!     return backend->create (family, slant, weight);
  }
  
! cairo_status_t
! _cairo_font_init (cairo_font_t *font, 
! 		  const struct cairo_font_backend *backend)
  {
!     cairo_matrix_set_identity (&font->matrix);
!     font->refcount = 1;
!     font->backend = backend;
!     font->glyph_cache = _cairo_glyph_cache_create ();
!     if (font->glyph_cache == NULL)
! 	return CAIRO_STATUS_NO_MEMORY;
      
!     return CAIRO_STATUS_SUCCESS;
  }
  
! cairo_font_t *
! _cairo_font_copy (cairo_font_t *font)
  {
!     cairo_font_t *newfont = NULL;
!     char *tmp = NULL;
  
!     if (font == NULL || font->backend->copy == NULL)
! 	return NULL;
!     
!     newfont = font->backend->copy (font);
!     if (newfont == NULL) {
! 	free (tmp);
! 	return NULL;
!     }
  
-     newfont->refcount = 1;
-     cairo_matrix_copy(&newfont->matrix, &font->matrix);
-     newfont->backend = font->backend;
  
!     if (newfont->glyph_cache)
! 	_cairo_glyph_cache_destroy (newfont->glyph_cache);
!     
!     newfont->glyph_cache = font->glyph_cache;
!     _cairo_glyph_cache_reference (font->glyph_cache);
!     
!     return newfont;
  }
  
! cairo_status_t
! _cairo_font_scale (cairo_font_t *font, double scale)
  {
!     return cairo_matrix_scale (&font->matrix, scale, scale);
  }
  
! cairo_status_t
! _cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix)
  {
!     return cairo_matrix_multiply (&font->matrix, matrix, &font->matrix);
  }
  
  
! cairo_status_t
! _cairo_font_text_extents (cairo_font_t *font,
! 			  const unsigned char *utf8,
! 			  cairo_text_extents_t *extents)
  {
!     return font->backend->text_extents(font, utf8, extents);
  }
  
! cairo_status_t
! _cairo_font_glyph_extents (cairo_font_t *font,
!                            cairo_glyph_t *glyphs,
!                            int num_glyphs,
! 			   cairo_text_extents_t *extents)
  {
!     return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
  }
  
  cairo_status_t
! _cairo_font_text_bbox (cairo_font_t             *font,
!                        cairo_surface_t          *surface,
!                        double                   x,
!                        double                   y,
!                        const unsigned char      *utf8,
! 		       cairo_box_t		*bbox)
  {
!     return font->backend->text_bbox (font, surface, x, y, utf8, bbox);
  }
  
  cairo_status_t
! _cairo_font_glyph_bbox (cairo_font_t            *font,
! 			cairo_surface_t         *surface,
! 			cairo_glyph_t           *glyphs,
! 			int                     num_glyphs,
! 			cairo_box_t		*bbox)
  {
!     return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox);
  }
  
  cairo_status_t
! _cairo_font_show_text (cairo_font_t		*font,
! 		       cairo_operator_t		operator,
! 		       cairo_surface_t		*source,
! 		       cairo_surface_t		*surface,
! 		       int                      source_x,
! 		       int                      source_y,
! 		       double			x,
! 		       double			y,
! 		       const unsigned char	*utf8)
  {
!     return font->backend->show_text(font, operator, source, 
! 				    surface, source_x, source_y, x, y, utf8);
  }
  
  cairo_status_t
! _cairo_font_show_glyphs (cairo_font_t           *font,
!                          cairo_operator_t       operator,
!                          cairo_surface_t        *source,
!                          cairo_surface_t        *surface,
! 			 int                    source_x,
! 			 int                    source_y,
!                          cairo_glyph_t          *glyphs,
!                          int                    num_glyphs)
  {
!     return font->backend->show_glyphs(font, operator, source, 
! 				      surface, source_x, source_y,
! 				      glyphs, num_glyphs);
  }
  
  cairo_status_t
! _cairo_font_text_path (cairo_font_t             *font,
! 		       double			x,
! 		       double			y,
!                        const unsigned char      *utf8,
!                        cairo_path_t             *path)
  {
!     return font->backend->text_path(font, x, y, utf8, path);
  }
  
  cairo_status_t
! _cairo_font_glyph_path (cairo_font_t            *font,
!                         cairo_glyph_t           *glyphs, 
!                         int                     num_glyphs,
!                         cairo_path_t            *path)
  {
!     return font->backend->glyph_path(font, glyphs, num_glyphs, path);
  }
  
  cairo_status_t
! _cairo_font_font_extents (cairo_font_t *font,
! 			  cairo_font_extents_t *extents)
  {
!     return font->backend->font_extents(font, extents);
  }
  
! static void
! _cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache)
  {
!     if (glyph_cache->last) {
! 	cairo_glyph_surface_node_t *remove = glyph_cache->last;
! 	
! 	cairo_surface_destroy (remove->s.surface);
! 	glyph_cache->last = remove->prev;
! 	if (glyph_cache->last)
! 	    glyph_cache->last->next = NULL;
  
! 	free (remove);
! 	glyph_cache->n_nodes--;
!     }
  }
  
- static cairo_glyph_cache_t *
- _cairo_glyph_cache_create (void)
- {
-     cairo_glyph_cache_t *glyph_cache;
- 	
-     glyph_cache = malloc (sizeof (cairo_glyph_cache_t));
-     if (glyph_cache == NULL)
- 	return NULL;
-     
-     glyph_cache->n_nodes = 0;
-     glyph_cache->first = NULL;
-     glyph_cache->last = NULL;
-     glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT;
-     glyph_cache->ref_count = 1;
  
!     return glyph_cache;
  }
  
! static void
! _cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache)
  {
!     if (glyph_cache == NULL)
  	return;
  
!     glyph_cache->ref_count++;
  }
  
! static void
! _cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache)
  {
!     if (glyph_cache == NULL)
! 	return;
  
!     glyph_cache->ref_count--;
!     if (glyph_cache->ref_count)
! 	return;
  
-     while (glyph_cache->last)
- 	_cairo_glyph_cache_pop_last (glyph_cache);
  
!     free (glyph_cache);
! }
  
! static void
! _cairo_glyph_surface_init (cairo_font_t *font,
! 			   cairo_surface_t *surface,
! 			   const cairo_glyph_t *glyph,
! 			   cairo_glyph_surface_t *glyph_surface)
  {
!     cairo_surface_t *image;
!     
!     glyph_surface->surface = NULL;
!     glyph_surface->index = glyph->index;
!     glyph_surface->matrix[0][0] = font->matrix.m[0][0];
!     glyph_surface->matrix[0][1] = font->matrix.m[0][1];
!     glyph_surface->matrix[1][0] = font->matrix.m[1][0];
!     glyph_surface->matrix[1][1] = font->matrix.m[1][1];
  
!     image = font->backend->create_glyph (font, glyph, &glyph_surface->size);
!     if (image == NULL)
! 	return;
!     
!     if (surface->backend != image->backend) {
! 	cairo_status_t status;
! 	
! 	glyph_surface->surface =
! 	    _cairo_surface_create_similar_scratch (surface,
! 						   CAIRO_FORMAT_A8, 0,
! 						   glyph_surface->size.width,
! 						   glyph_surface->size.height);
! 	if (glyph_surface->surface == NULL) {
! 	    glyph_surface->surface = image;
! 	    return;
! 	}
! 	    
! 	status = _cairo_surface_set_image (glyph_surface->surface,
! 					   (cairo_image_surface_t *) image);
! 	if (status) {
! 	    cairo_surface_destroy (glyph_surface->surface);
! 	    glyph_surface->surface = NULL;
! 	}
! 	cairo_surface_destroy (image);
!     } else
! 	glyph_surface->surface = image;
  }
  
! cairo_surface_t *
! _cairo_font_lookup_glyph (cairo_font_t *font,
! 			  cairo_surface_t *surface,
! 			  const cairo_glyph_t *glyph,
! 			  cairo_glyph_size_t *return_size)
  {
!     cairo_glyph_surface_t glyph_surface;
!     cairo_glyph_cache_t *cache = font->glyph_cache;
!     cairo_glyph_surface_node_t *node;
! 	
!     for (node = cache->first; node != NULL; node = node->next) {
! 	cairo_glyph_surface_t *s = &node->s;
  
! 	if ((s->surface == NULL || s->surface->backend == surface->backend) &&
! 	    s->index == glyph->index &&
! 	    s->matrix[0][0] == font->matrix.m[0][0] &&
! 	    s->matrix[0][1] == font->matrix.m[0][1] &&
! 	    s->matrix[1][0] == font->matrix.m[1][0] &&
! 	    s->matrix[1][1] == font->matrix.m[1][1]) {
  
! 	    /* move node first in cache */
! 	    if (node->prev) {
! 		if (node->next == NULL) {    
! 		    cache->last = node->prev;
! 		    node->prev->next = NULL;
! 		} else {
! 		    node->prev->next = node->next;
! 		    node->next->prev = node->prev;
! 		}
  
! 		node->prev = NULL;
! 		node->next = cache->first;
! 		cache->first = node;
! 		if (node->next)
! 		    node->next->prev = node;
! 		else
! 		    cache->last = node;
! 	    }
! 	    
! 	    cairo_surface_reference (s->surface);
! 	    *return_size = s->size;
! 	    
! 	    return s->surface;
! 	}
      }
-     
-     _cairo_glyph_surface_init (font, surface, glyph, &glyph_surface);
  
!     *return_size = glyph_surface.size;
!     
!     if (cache->cache_size > 0) {
! 	if (cache->n_nodes == cache->cache_size)
! 	    _cairo_glyph_cache_pop_last (cache);
  
! 	node = malloc (sizeof (cairo_glyph_surface_node_t));
! 	if (node) {
! 	    cairo_surface_reference (glyph_surface.surface);
! 	    
! 	    /* insert node first in cache */
! 	    node->s = glyph_surface;
! 	    node->prev = NULL;
! 	    node->next = cache->first;
! 	    cache->first = node;
! 	    if (node->next)
! 		node->next->prev = node;
! 	    else
! 		cache->last = node;
  
! 	    cache->n_nodes++;
! 	}
!     }
!     
!     return glyph_surface.surface;
  }
  
- /* public font interface follows */
  
! void
! cairo_font_reference (cairo_font_t *font)
  {
!     font->refcount++;
  }
  
! void
! cairo_font_destroy (cairo_font_t *font)
  {
!     if (--(font->refcount) > 0)
! 	return;
  
!     _cairo_glyph_cache_destroy (font->glyph_cache);
  
-     if (font->backend->destroy)
- 	font->backend->destroy (font);
- }
  
  void
! cairo_font_set_transform (cairo_font_t *font, 
! 			  cairo_matrix_t *matrix)
  {
!     cairo_matrix_copy (&(font->matrix), matrix);
  }
  
  void
! cairo_font_current_transform (cairo_font_t *font, 
! 			      cairo_matrix_t *matrix)
  {
!     cairo_matrix_copy (matrix, &(font->matrix));
  }
--- 99,525 ----
       * ugly one if necessary). */
  
!     entry = malloc (sizeof (cairo_font_cache_entry_t));
!     if (entry == NULL)
! 	goto FAIL;
! 
!     entry->key.slant = k->slant;
!     entry->key.weight = k->weight;
!     entry->key.family = strdup(k->family);
!     if (entry->key.family == NULL)
! 	goto FREE_ENTRY;
! 
!     entry->unscaled = backend->create (k->family, k->slant, k->weight);
!     if (entry->unscaled == NULL)
! 	goto FREE_FAMILY;
!     
!     /* Not sure how to measure backend font mem; use a simple count for now.*/
!     entry->key.base.memory = 1;
!     *return_value = entry;
!     return CAIRO_STATUS_SUCCESS;
!     
!  FREE_FAMILY:
!     free ((void *) entry->key.family);
! 
!  FREE_ENTRY:
!     free (entry);
!    
!  FAIL:
!     return CAIRO_STATUS_NO_MEMORY;
  }
  
! static void
! _font_cache_destroy_entry (void *cache,
! 			   void *entry)
  {
!     cairo_font_cache_entry_t *e;
      
!     e = (cairo_font_cache_entry_t *) entry;
!     _cairo_unscaled_font_destroy (e->unscaled);
!     free ((void *) e->key.family);
!     free (e);
  }
  
! static void 
! _font_cache_destroy_cache (void *cache)
  {
!     free (cache);
! }
  
! const struct cairo_cache_backend cairo_font_cache_backend = {
!     _font_cache_hash,
!     _font_cache_keys_equal,
!     _font_cache_create_entry,
!     _font_cache_destroy_entry,
!     _font_cache_destroy_cache
! };
  
  
! static void
! _lock_global_font_cache (void)
! {
!     /* FIXME: implement locking. */
  }
  
! static void
! _unlock_global_font_cache (void)
  {
!     /* FIXME: implement locking. */
  }
  
! static cairo_cache_t *
! _global_font_cache = NULL;
! 
! static cairo_cache_t *
! _get_global_font_cache (void)
  {
!     if (_global_font_cache == NULL) {
! 	_global_font_cache = malloc (sizeof (cairo_cache_t));
! 	
! 	if (_global_font_cache == NULL)
! 	    goto FAIL;
! 	
! 	if (_cairo_cache_init (_global_font_cache,
! 			       &cairo_font_cache_backend,
! 			       CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT))
! 	    goto FAIL;
!     }
! 
!     return _global_font_cache;
!     
!  FAIL:
!     if (_global_font_cache)
! 	free (_global_font_cache);
!     _global_font_cache = NULL;
!     return NULL;
  }
  
  
! /* Now the internal "unscaled + scale" font API */
! 
! cairo_unscaled_font_t *
! _cairo_unscaled_font_create (const char           *family, 
! 			     cairo_font_slant_t   slant, 
! 			     cairo_font_weight_t  weight)
  {
!     cairo_cache_t * cache;
!     cairo_font_cache_key_t key;
!     cairo_font_cache_entry_t *font;
!     cairo_status_t status;
! 
!     _lock_global_font_cache ();
!     cache = _get_global_font_cache ();
!     if (cache == NULL) {
! 	_unlock_global_font_cache ();
! 	return NULL;
!     }
! 
!     key.family = family;
!     key.slant = slant;
!     key.weight = weight;
!     
!     status = _cairo_cache_lookup (cache, &key, (void **) &font);
!     if (status) {
! 	_unlock_global_font_cache ();
! 	return NULL;
!     }
! 
!     _cairo_unscaled_font_reference (font->unscaled);
!     _unlock_global_font_cache ();
!     return font->unscaled;
  }
  
! void
! _cairo_font_init (cairo_font_t *scaled, 
! 		  cairo_font_scale_t *scale, 
! 		  cairo_unscaled_font_t *unscaled)
  {
!     scaled->scale = *scale;
!     scaled->unscaled = unscaled;
!     scaled->refcount = 1;
  }
  
  cairo_status_t
! _cairo_unscaled_font_init (cairo_unscaled_font_t 		*font, 
! 			   const struct cairo_font_backend	*backend)
  {
!     font->refcount = 1;
!     font->backend = backend;
!     return CAIRO_STATUS_SUCCESS;
  }
  
+ 
  cairo_status_t
! _cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t 	*font,
! 				     cairo_font_scale_t 	*scale,
! 				     const unsigned char 	*utf8, 
! 				     cairo_glyph_t 		**glyphs, 
! 				     int 			*num_glyphs)
  {
!     return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
  }
  
  cairo_status_t
! _cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t	*font,
! 				    cairo_font_scale_t 		*scale,			   
! 				    cairo_glyph_t 		*glyphs,
! 				    int 			num_glyphs,
! 				    cairo_text_extents_t 	*extents)
  {
!     return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents);
  }
  
+ 
  cairo_status_t
! _cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t	*font,
! 				 cairo_font_scale_t	*scale,
! 				 cairo_glyph_t          *glyphs,
! 				 int                    num_glyphs,
! 				 cairo_box_t		*bbox)
  {
!     return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
  }
  
  cairo_status_t
! _cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t	*font,
! 				  cairo_font_scale_t	*scale,
! 				  cairo_operator_t       operator,
! 				  cairo_surface_t        *source,
! 				  cairo_surface_t        *surface,
! 				  int                    source_x,
! 				  int                    source_y,
! 				  cairo_glyph_t          *glyphs,
! 				  int                    num_glyphs)
  {
!     cairo_status_t status;
!     if (surface->backend->show_glyphs != NULL) {
! 	status = surface->backend->show_glyphs (font, scale, operator, source, 
! 						surface, source_x, source_y,
! 						glyphs, num_glyphs);
! 	if (status == CAIRO_STATUS_SUCCESS)
! 	    return status;
!     }
! 
!     /* Surface display routine either does not exist or failed. */
!     return font->backend->show_glyphs (font, scale, operator, source, 
! 				       surface, source_x, source_y,
! 				       glyphs, num_glyphs);
  }
  
  cairo_status_t
! _cairo_unscaled_font_glyph_path (cairo_unscaled_font_t	*font,
! 				 cairo_font_scale_t 	*scale,
! 				 cairo_glyph_t		*glyphs, 
! 				 int			num_glyphs,
! 				 cairo_path_t        	*path)
  {
!     return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
  }
  
  cairo_status_t
! _cairo_unscaled_font_font_extents (cairo_unscaled_font_t	*font,
! 				   cairo_font_scale_t		*scale,
! 				   cairo_font_extents_t		*extents)
  {
!     return font->backend->font_extents(font, scale, extents);
  }
  
! void
! _cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
  {
!     font->refcount++;
! }
  
! void
! _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
! {    
!     if (--(font->refcount) > 0)
! 	return;
! 
!     if (font->backend)
! 	font->backend->destroy (font);
  }
  
  
! 
! /* Public font API follows. */
! 
! void
! cairo_font_reference (cairo_font_t *font)
! {
!     font->refcount++;
  }
  
! void
! cairo_font_destroy (cairo_font_t *font)
  {
!     if (--(font->refcount) > 0)
  	return;
  
!     if (font->unscaled)
! 	_cairo_unscaled_font_destroy (font->unscaled);
! 
!     free (font);
  }
  
! void
! cairo_font_set_transform (cairo_font_t *font, 
! 			  cairo_matrix_t *matrix)
  {
!     double dummy;
!     cairo_matrix_get_affine (matrix,
! 			     &font->scale.matrix[0][0],
! 			     &font->scale.matrix[0][1],
! 			     &font->scale.matrix[1][0],
! 			     &font->scale.matrix[1][1],
! 			     &dummy, &dummy);    
! }
  
! void
! cairo_font_current_transform (cairo_font_t *font, 
! 			      cairo_matrix_t *matrix)
! {
!     cairo_matrix_set_affine (matrix,
! 			     font->scale.matrix[0][0],
! 			     font->scale.matrix[0][1],
! 			     font->scale.matrix[1][0],
! 			     font->scale.matrix[1][1],
! 			     0, 0);
! }
  
  
! /* Now we implement functions to access a default global image & metrics
!  * cache. 
!  */
  
! unsigned long
! _cairo_glyph_cache_hash (void *cache, void *key)
  {
!     cairo_glyph_cache_key_t *in;
!     in = (cairo_glyph_cache_key_t *) key;
!     return 
! 	((unsigned long) in->unscaled) 
! 	^ ((unsigned long) in->scale.matrix[0][0]) 
! 	^ ((unsigned long) in->scale.matrix[0][1]) 
! 	^ ((unsigned long) in->scale.matrix[1][0]) 
! 	^ ((unsigned long) in->scale.matrix[1][1]) 
! 	^ in->index;
! }
  
! int
! _cairo_glyph_cache_keys_equal (void *cache,
! 			       void *k1,
! 			       void *k2)
! {
!     cairo_glyph_cache_key_t *a, *b;
!     a = (cairo_glyph_cache_key_t *) k1;
!     b = (cairo_glyph_cache_key_t *) k2;
!     return (a->index == b->index)
! 	&& (a->unscaled == b->unscaled)
! 	&& (a->scale.matrix[0][0] == b->scale.matrix[0][0])
! 	&& (a->scale.matrix[0][1] == b->scale.matrix[0][1])
! 	&& (a->scale.matrix[1][0] == b->scale.matrix[1][0])
! 	&& (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
  }
  
! 
! static cairo_status_t
! _image_glyph_cache_create_entry (void *cache,
! 				 void *key,
! 				 void **return_value)
  {
!     cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
!     cairo_image_glyph_cache_entry_t *im;
!     cairo_status_t status;
  
!     im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
!     if (im == NULL)
! 	return CAIRO_STATUS_NO_MEMORY;
  
!     im->key = *k;    
!     status = im->key.unscaled->backend->create_glyph (im);
  
!     if (status != CAIRO_STATUS_SUCCESS) {
! 	free (im);
! 	return status;
      }
  
!     _cairo_unscaled_font_reference (im->key.unscaled);
  
!     im->key.base.memory = 
! 	sizeof (cairo_image_glyph_cache_entry_t) 
! 	+ (im->image ? 
! 	   sizeof (cairo_image_surface_t) 
! 	   + 28 * sizeof (int) /* rough guess at size of pixman image structure */
! 	   + (im->image->height * im->image->stride) : 0);
  
!     *return_value = im;
! 
!     return CAIRO_STATUS_SUCCESS;
  }
  
  
! static void
! _image_glyph_cache_destroy_entry (void *cache,
! 				  void *value)
  {
!     cairo_image_glyph_cache_entry_t *im;
! 
!     im = (cairo_image_glyph_cache_entry_t *) value;
!     _cairo_unscaled_font_destroy (im->key.unscaled);
!     cairo_surface_destroy (&(im->image->base));
!     free (im); 
  }
  
! static void 
! _image_glyph_cache_destroy_cache (void *cache)
  {
!     free (cache);
! }
  
! const cairo_cache_backend_t cairo_image_cache_backend = {
!     _cairo_glyph_cache_hash,
!     _cairo_glyph_cache_keys_equal,
!     _image_glyph_cache_create_entry,
!     _image_glyph_cache_destroy_entry,
!     _image_glyph_cache_destroy_cache
! };
  
  
  void
! _cairo_lock_global_image_glyph_cache()
  {
!     /* FIXME: implement locking. */
  }
  
  void
! _cairo_unlock_global_image_glyph_cache()
  {
!     /* FIXME: implement locking. */
! }
! 
! static cairo_cache_t *
! _global_image_glyph_cache = NULL;
! 
! cairo_cache_t *
! _cairo_get_global_image_glyph_cache ()
! {
!     if (_global_image_glyph_cache == NULL) {
! 	_global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
! 	
! 	if (_global_image_glyph_cache == NULL)
! 	    goto FAIL;
! 	
! 	if (_cairo_cache_init (_global_image_glyph_cache,
! 			       &cairo_image_cache_backend,
! 			       CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT))
! 	    goto FAIL;
!     }
! 
!     return _global_image_glyph_cache;
!     
!  FAIL:
!     if (_global_image_glyph_cache)
! 	free (_global_image_glyph_cache);
!     _global_image_glyph_cache = NULL;
!     return NULL;
  }

Index: cairo_ft_font.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_ft_font.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -C2 -d -r1.23 -r1.24
*** cairo_ft_font.c	24 May 2004 09:28:05 -0000	1.23
--- cairo_ft_font.c	8 Oct 2004 19:09:51 -0000	1.24
***************
*** 32,74 ****
  #include FT_IMAGE_H
  
! typedef struct {
!     cairo_font_t base;
  
!     FT_Library ft_library;
!     int owns_ft_library;
  
      FT_Face face;
      int owns_face;
[...1512 lines suppressed...]
+ cairo_ft_font_face (cairo_font_t *abstract_font)
+ {
+     cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled;
+ 
+     if (font == NULL || font->val == NULL)
+         return NULL;
+ 
+     return font->val->face;
+ }
+ 
+ FcPattern *
+ cairo_ft_font_pattern (cairo_font_t *abstract_font)
+ {
+     cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled;
+ 
+     if (font == NULL)
+         return NULL;
+ 
+     return font->pattern;
+ }

Index: cairo_glitz_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_glitz_surface.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** cairo_glitz_surface.c	4 Oct 2004 11:55:46 -0000	1.8
--- cairo_glitz_surface.c	8 Oct 2004 19:09:51 -0000	1.9
***************
*** 901,905 ****
      _cairo_glitz_surface_show_page,
      _cairo_glitz_surface_set_clip_region,
!     _cairo_glitz_surface_create_pattern
  };
  
--- 901,906 ----
      _cairo_glitz_surface_show_page,
      _cairo_glitz_surface_set_clip_region,
!     _cairo_glitz_surface_create_pattern,
!     NULL /* show_glyphs */
  };
  

Index: cairo_gstate.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_gstate.c,v
retrieving revision 1.60
retrieving revision 1.61
diff -C2 -d -r1.60 -r1.61
*** cairo_gstate.c	4 Sep 2004 13:38:34 -0000	1.60
--- cairo_gstate.c	8 Oct 2004 19:09:51 -0000	1.61
***************
*** 78,84 ****
      gstate->dash_offset = 0.0;
  
!     gstate->font = _cairo_font_create (CAIRO_FONT_FAMILY_DEFAULT,
! 				       CAIRO_FONT_SLANT_DEFAULT,
! 				       CAIRO_FONT_WEIGHT_DEFAULT);
  
      gstate->surface = NULL;
--- 78,84 ----
      gstate->dash_offset = 0.0;
  
!     gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT,
! 						CAIRO_FONT_SLANT_DEFAULT,
! 						CAIRO_FONT_WEIGHT_DEFAULT);
  
      gstate->surface = NULL;
***************
*** 120,128 ****
  
      if (other->font) {
! 	gstate->font = _cairo_font_copy (other->font);
! 	if (!gstate->font) {
! 	    status = CAIRO_STATUS_NO_MEMORY;
! 	    goto CLEANUP_DASHES;
! 	}
      }
  
--- 120,125 ----
  
      if (other->font) {
! 	gstate->font = other->font;
! 	_cairo_unscaled_font_reference (gstate->font);
      }
  
***************
*** 150,156 ****
    CLEANUP_PATH:
      _cairo_path_fini (&gstate->path);
    CLEANUP_FONT:
!     cairo_font_destroy (gstate->font);
!   CLEANUP_DASHES:
      free (gstate->dash);
      gstate->dash = NULL;
--- 147,154 ----
    CLEANUP_PATH:
      _cairo_path_fini (&gstate->path);
+ 
    CLEANUP_FONT:
!     _cairo_unscaled_font_destroy (gstate->font);
! 
      free (gstate->dash);
      gstate->dash = NULL;
***************
*** 162,166 ****
  _cairo_gstate_fini (cairo_gstate_t *gstate)
  {
!     cairo_font_destroy (gstate->font);
  
      if (gstate->surface)
--- 160,164 ----
  _cairo_gstate_fini (cairo_gstate_t *gstate)
  {
!     _cairo_unscaled_font_destroy (gstate->font);
  
      if (gstate->surface)
***************
*** 178,181 ****
--- 176,181 ----
      cairo_pattern_destroy (gstate->pattern);
  
+     _cairo_matrix_fini (&gstate->font_matrix);
+ 
      _cairo_matrix_fini (&gstate->ctm);
      _cairo_matrix_fini (&gstate->ctm_inverse);
***************
*** 628,631 ****
--- 628,633 ----
  	scale = 1;
  
+     cairo_matrix_set_identity (&gstate->font_matrix);
+ 
      cairo_matrix_set_identity (&gstate->ctm);
      cairo_matrix_scale (&gstate->ctm, scale, scale);
***************
*** 1677,1689 ****
      cairo_status_t st;
  
-     /* XXX: Something in the rectangle-based clipping support is
-      * broken. See cairo_snippets/xxx_clip_rectangle which
-      * demonstrates no clipping at all.
-      *
-      * For now, I'm am disabling this optimization completely until it
-      * can be fixed.
-      */
-     return 0;
- 
      st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);    
      if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
--- 1679,1682 ----
***************
*** 1993,1996 ****
--- 1986,1990 ----
  }
  
+ 
  cairo_status_t
  _cairo_gstate_select_font (cairo_gstate_t       *gstate, 
***************
*** 1999,2006 ****
  			   cairo_font_weight_t  weight)
  {
!     if (gstate->font != NULL)
! 	cairo_font_destroy (gstate->font);
  
!     gstate->font = _cairo_font_create (family, slant, weight);
    
      return CAIRO_STATUS_SUCCESS;
--- 1993,2011 ----
  			   cairo_font_weight_t  weight)
  {
!     cairo_unscaled_font_t *tmp;
  
!     tmp = _cairo_unscaled_font_create (family, slant, weight);
! 
!     if (tmp == NULL)
! 	return CAIRO_STATUS_NO_MEMORY;
! 
!     if (gstate->font != tmp)
!     {
! 	if (gstate->font != NULL)
! 	    _cairo_unscaled_font_destroy (gstate->font);
! 
! 	cairo_matrix_set_identity (&gstate->font_matrix);
! 	gstate->font = tmp;
!     }
    
      return CAIRO_STATUS_SUCCESS;
***************
*** 2011,2015 ****
  			  double scale)
  {
!     return _cairo_font_scale (gstate->font, scale);
  }
  
--- 2016,2020 ----
  			  double scale)
  {
!     return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
  }
  
***************
*** 2018,2116 ****
  			      cairo_matrix_t *matrix)
  {
!     return _cairo_font_transform (gstate->font, matrix);    
  }
  
  cairo_status_t
  _cairo_gstate_current_font (cairo_gstate_t *gstate, 
  			    cairo_font_t **font)
  {
!     *font = gstate->font;
  
      return CAIRO_STATUS_SUCCESS;
  }
  
! cairo_status_t
! _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, 
! 				    cairo_font_extents_t *extents)
  {
!     cairo_int_status_t status;
!     cairo_matrix_t saved_font_matrix;
!     
!     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
!     cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
!     
!     status = _cairo_font_font_extents (gstate->font, extents);
! 
!     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);    
  
!     return status;
  }
  
  
! cairo_status_t
! _cairo_gstate_set_font (cairo_gstate_t *gstate, 
! 			cairo_font_t *font)
  {
!     if (gstate->font != NULL)    
! 	cairo_font_destroy (gstate->font);
!     gstate->font = font;
!     cairo_font_reference (gstate->font);
!     return CAIRO_STATUS_SUCCESS;
  }
  
  cairo_status_t
! _cairo_gstate_text_extents (cairo_gstate_t *gstate,
! 			    const unsigned char *utf8,
! 			    cairo_text_extents_t *extents)
  {
!     cairo_matrix_t saved_font_matrix;
!     cairo_status_t status;
!     double scale_x, scale_y;
! 
!     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
!     _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
!     cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
! 
!     status = _cairo_font_text_extents (gstate->font,
! 				       utf8, extents);
! 
!     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
  
!     extents->x_bearing /= scale_x;
!     extents->y_bearing /= scale_y;
!     extents->width  /= scale_x;
!     extents->height /= scale_y;
!     extents->x_advance /= scale_x;
!     extents->y_advance /= scale_y;
  
!     return status;
! }
  
! cairo_status_t
! _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
! 			     cairo_glyph_t *glyphs, 
! 			     int num_glyphs,
! 			     cairo_text_extents_t *extents)
! {
!     cairo_status_t status;
!     cairo_matrix_t saved_font_matrix;
!     double scale_x, scale_y;
  
!     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
!     _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
!     cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
  
!     status = _cairo_font_glyph_extents (gstate->font,
! 					glyphs, num_glyphs,
! 					extents);
  
!     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
  
!     extents->x_bearing /= scale_x;
!     extents->y_bearing /= scale_y;
!     extents->width  /= scale_x;
!     extents->height /= scale_y;
!     extents->x_advance /= scale_x;
!     extents->y_advance /= scale_y;
  
      return status;
--- 2023,2198 ----
  			      cairo_matrix_t *matrix)
  {
!     cairo_matrix_t tmp;
!     double a, b, c, d, tx, ty;
!     cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
!     cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
!     return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
  }
  
+ 
  cairo_status_t
  _cairo_gstate_current_font (cairo_gstate_t *gstate, 
  			    cairo_font_t **font)
  {
!     cairo_font_scale_t scale;
!     cairo_font_t *scaled;
!     double dummy;
! 
!     scaled = malloc (sizeof (cairo_font_t));
!     if (scaled == NULL)
! 	return CAIRO_STATUS_NO_MEMORY;
! 
!     cairo_matrix_get_affine (&gstate->font_matrix,
! 			     &scale.matrix[0][0],
! 			     &scale.matrix[0][1],
! 			     &scale.matrix[1][0],
! 			     &scale.matrix[1][1],
! 			     &dummy, &dummy);
! 
!     _cairo_font_init (scaled, &scale, gstate->font);
!     _cairo_unscaled_font_reference (gstate->font);
! 
!     *font = scaled;
  
      return CAIRO_STATUS_SUCCESS;
  }
  
! void
! _cairo_gstate_set_font_transform (cairo_gstate_t *gstate, 
! 				  cairo_matrix_t *matrix)
  {
!     cairo_matrix_copy (&gstate->font_matrix, matrix);
! }
  
! void
! _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
! 				      cairo_matrix_t *matrix)
! {
!     cairo_matrix_copy (matrix, &gstate->font_matrix);
  }
  
+ /* 
+  * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
+  * it is easy to get confused about what's going on.
+  *
+  * The user's view
+  * ---------------
+  *
+  * Users ask for things in user space. When cairo starts, a user space unit
+  * is about 1/96 inch, which is similar to (but importantly different from)
+  * the normal "point" units most users think in terms of. When a user
+  * selects a font, its scale is set to "one user unit". The user can then
+  * independently scale the user coordinate system *or* the font matrix, in
+  * order to adjust the rendered size of the font.
+  *
+  * If the user asks for a permanent reference to "a font", they are given a
+  * handle to a structure holding a scale matrix and an unscaled font. This
+  * effectively decouples the font from further changes to user space. Even
+  * if the user then "sets" the current cairo_t font to the handle they were
+  * passed, further changes to the cairo_t CTM will not affect externally
+  * held references to the font.
+  *
+  *
+  * The font's view
+  * ---------------
+  *
+  * Fonts are designed and stored (in say .ttf files) in "font space", which
+  * describes an "EM Square" (a design tile) and has some abstract number
+  * such as 1000, 1024, or 2048 units per "EM". This is basically an
+  * uninteresting space for us, but we need to remember that it exists.
+  *
+  * Font resources (from libraries or operating systems) render themselves
+  * to a particular device. Since they do not want to make most programmers
+  * worry about the font design space, the scaling API is simplified to
+  * involve just telling the font the required pixel size of the EM square
+  * (that is, in device space).
+  *
+  *
+  * Cairo's gstate view
+  * -------------------
+  *
+  * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
+  * called the "font matrix" which describes the user's most recent
+  * font-scaling or font-transforming request. This is kept in terms of an
+  * abstract scale factor, composed with the CTM and used to set the font's
+  * pixel size. So if the user asks to "scale the font by 12", the matrix
+  * is:
+  *
+  *   [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
+  *
+  * It is an affine matrix, like all cairo matrices, but its tx and ty
+  * components are always set to zero; we don't permit "nudging" fonts
+  * around.
+  *
+  * In order to perform any action on a font, we must build an object
+  * called a cairo_font_scale_t; this contains the central 2x2 matrix 
+  * resulting from "font matrix * CTM".
+  *  
+  * We pass this to the font when making requests of it, which causes it to
+  * reply for a particular [user request, device] combination, under the CTM
+  * (to accomodate the "zoom in" == "bigger fonts" issue above).
+  *
+  * The other terms in our communication with the font are therefore in
+  * device space. When we ask it to perform text->glyph conversion, it will
+  * produce a glyph string in device space. Glyph vectors we pass to it for
+  * measuring or rendering should be in device space. The metrics which we
+  * get back from the font will be in device space. The contents of the
+  * global glyph image cache will be in device space.
+  *
+  *
+  * Cairo's public view
+  * -------------------
+  *
+  * Since the values entering and leaving via public API calls are in user
+  * space, the gstate functions typically need to multiply argumens by the
+  * CTM (for user-input glyph vectors), and return values by the CTM inverse
+  * (for font responses such as metrics or glyph vectors).
+  *
+  */
  
! static void
! _build_font_scale (cairo_gstate_t *gstate,
! 		   cairo_font_scale_t *sc)
  {
!     cairo_matrix_t tmp;
!     double dummy;
!     cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
!     cairo_matrix_get_affine (&tmp,
! 			     &sc->matrix[0][0],
! 			     &sc->matrix[0][1],
! 			     &sc->matrix[1][0],
! 			     &sc->matrix[1][1],
! 			     &dummy, &dummy);
  }
  
  cairo_status_t
! _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, 
! 				    cairo_font_extents_t *extents)
  {
!     cairo_int_status_t status;
!     cairo_font_scale_t sc;
!     double dummy = 0.0;
  
!     _build_font_scale (gstate, &sc);
  
!     status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
  
!     /* The font responded in device space; convert to user space. */
  
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &dummy,
! 				     &extents->ascent);
  
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &dummy,
! 				     &extents->descent);
  
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &dummy,
! 				     &extents->height);
  
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &extents->max_x_advance,
! 				     &extents->max_y_advance);
  
      return status;
***************
*** 2118,2220 ****
  
  cairo_status_t
! _cairo_gstate_show_text (cairo_gstate_t *gstate, 
! 			 const unsigned char *utf8)
  {
      cairo_status_t status;
!     cairo_point_t point;
!     double x, y;
!     cairo_matrix_t saved_font_matrix;
!     cairo_pattern_t pattern;
!     cairo_box_t bbox;
  
      status = _cairo_path_current_point (&gstate->path, &point);
      if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
! 	x = 0;
! 	y = 0;
! 	cairo_matrix_transform_point (&gstate->ctm, &x, &y);
      } else {
! 	x = _cairo_fixed_to_double (point.x);
! 	y = _cairo_fixed_to_double (point.y);
      }
-     
-     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
-     cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
  
!     _cairo_pattern_init_copy (&pattern, gstate->pattern);
!     
!     status = _cairo_font_text_bbox (gstate->font, gstate->surface,
!  				    x, y, utf8, &bbox);
!     if (status)
! 	return status;
!     
!     status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
!     if (status)
  	return status;
-     
-     if (gstate->clip.surface)
-     {
- 	cairo_surface_t *intermediate;
- 	cairo_color_t empty_color;
  
! 	_cairo_color_init (&empty_color);
! 	_cairo_color_set_alpha (&empty_color, .0);
! 	intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
! 							    CAIRO_FORMAT_A8,
! 							    gstate->clip.width,
! 							    gstate->clip.height,
! 							    &empty_color);
  
! 	status = _cairo_font_show_text (gstate->font,
! 					CAIRO_OPERATOR_ADD, pattern.source,
! 					intermediate,
! 					gstate->clip.x - pattern.source_offset.x,
! 					gstate->clip.y - pattern.source_offset.y,
! 					x - gstate->clip.x, 
! 					y - gstate->clip.y, utf8);
  
! 	if (status)
! 	    goto BAIL;
! 	
! 	status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
! 					   gstate->clip.surface,
! 					   NULL,
! 					   intermediate,
! 					   0, 0, 
! 					   0, 0,
! 					   0, 0,
! 					   gstate->clip.width, 
! 					   gstate->clip.height);
  
! 	if (status)
! 	    goto BAIL;
  
! 	status = _cairo_surface_composite (gstate->operator,
! 					   pattern.source,
! 					   intermediate,
! 					   gstate->surface,
! 					   0, 0, 
! 					   0, 0,
! 					   gstate->clip.x, 
! 					   gstate->clip.y,
! 					   gstate->clip.width, 
! 					   gstate->clip.height);
  
!     BAIL:
! 	cairo_surface_destroy (intermediate);
! 	
!     }
!     else
      {
! 	status = _cairo_font_show_text (gstate->font,
! 					gstate->operator, pattern.source,
! 					gstate->surface,
! 					-pattern.source_offset.x,
! 					-pattern.source_offset.y,
! 					x, y, utf8);
      }
-     
-     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
  
!     _cairo_pattern_fini (&pattern);
  
      return status;
--- 2200,2307 ----
  
  cairo_status_t
! _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, 
! 			      const unsigned char *utf8,
! 			      cairo_glyph_t **glyphs,
! 			      int *nglyphs)
  {
      cairo_status_t status;
!     cairo_font_scale_t sc;
! 
!     cairo_point_t point; 
!     double dev_x, dev_y;
!     int i;
! 
!     _build_font_scale (gstate, &sc);
  
      status = _cairo_path_current_point (&gstate->path, &point);
      if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
! 	dev_x = 0.0;
! 	dev_y = 0.0;
      } else {
! 	dev_x = _cairo_fixed_to_double (point.x);
! 	dev_y = _cairo_fixed_to_double (point.y);
      }
  
!     status = _cairo_unscaled_font_text_to_glyphs (gstate->font, 
! 						  &sc, utf8, glyphs, nglyphs);
! 
!     if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
  	return status;
  
!     /* The font responded in device space, starting from (0,0); add any
!        current point offset in device space, and convert to user space. */
  
!     for (i = 0; i < *nglyphs; ++i) {
!  	(*glyphs)[i].x += dev_x; 
!  	(*glyphs)[i].y += dev_y; 
!  	cairo_matrix_transform_point (&gstate->ctm_inverse,  
!  				      &((*glyphs)[i].x),  
!  				      &((*glyphs)[i].y)); 
!     }
!     
!     return CAIRO_STATUS_SUCCESS;
! }
  
! cairo_status_t
! _cairo_gstate_set_font (cairo_gstate_t *gstate, 
! 			cairo_font_t *font)
! {
!     if (gstate->font != NULL)    
! 	_cairo_unscaled_font_destroy (gstate->font);
!     gstate->font = font->unscaled;
!     _cairo_unscaled_font_reference (gstate->font);
!     cairo_matrix_set_affine (&gstate->font_matrix,
! 			     font->scale.matrix[0][0],
! 			     font->scale.matrix[0][1],
! 			     font->scale.matrix[1][0],
! 			     font->scale.matrix[1][1],
! 			     0, 0);
!     return CAIRO_STATUS_SUCCESS;
! }
  
! cairo_status_t
! _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
! 			     cairo_glyph_t *glyphs, 
! 			     int num_glyphs,
! 			     cairo_text_extents_t *extents)
! {
!     cairo_status_t status;
!     cairo_glyph_t *transformed_glyphs;
!     cairo_font_scale_t sc;
!     int i;
  
!     _build_font_scale (gstate, &sc);
  
!     transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
!     if (transformed_glyphs == NULL)
! 	return CAIRO_STATUS_NO_MEMORY;
! 
!     for (i = 0; i < num_glyphs; ++i)
      {
! 	transformed_glyphs[i] = glyphs[i];
! 	cairo_matrix_transform_point (&gstate->ctm, 
! 				      &transformed_glyphs[i].x, 
! 				      &transformed_glyphs[i].y);
      }
  
!     status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc, 
! 						 transformed_glyphs, num_glyphs, 
! 						 extents);
! 
!     /* The font responded in device space; convert to user space. */
! 
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &extents->x_bearing,
! 				     &extents->y_bearing);
! 
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &extents->width,
! 				     &extents->height);
! 
!     cairo_matrix_transform_distance (&gstate->ctm_inverse, 
! 				     &extents->x_advance,
! 				     &extents->y_advance);
! 
!     free (transformed_glyphs);
  
      return status;
***************
*** 2227,2236 ****
  {
      cairo_status_t status;
-     cairo_matrix_t saved_font_matrix;
      int i;
      cairo_glyph_t *transformed_glyphs = NULL;
      cairo_pattern_t pattern;
      cairo_box_t bbox;
  
      transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
      if (transformed_glyphs == NULL)
--- 2314,2325 ----
  {
      cairo_status_t status;
      int i;
      cairo_glyph_t *transformed_glyphs = NULL;
+     cairo_font_scale_t sc;
      cairo_pattern_t pattern;
      cairo_box_t bbox;
  
+     _build_font_scale (gstate, &sc);
+ 
      transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
      if (transformed_glyphs == NULL)
***************
*** 2241,2254 ****
  	transformed_glyphs[i] = glyphs[i];
  	cairo_matrix_transform_point (&gstate->ctm, 
! 				      &(transformed_glyphs[i].x), 
! 				      &(transformed_glyphs[i].y));
      }
      
-     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
-     cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
- 
      _cairo_pattern_init_copy (&pattern, gstate->pattern);
!     status = _cairo_font_glyph_bbox (gstate->font, gstate->surface,
!  				     transformed_glyphs, num_glyphs, &bbox);
      if (status)
  	return status;
--- 2330,2341 ----
  	transformed_glyphs[i] = glyphs[i];
  	cairo_matrix_transform_point (&gstate->ctm, 
! 				      &transformed_glyphs[i].x, 
! 				      &transformed_glyphs[i].y);
      }
      
      _cairo_pattern_init_copy (&pattern, gstate->pattern);
!     status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc, 
! 					      transformed_glyphs, num_glyphs, 
! 					      &bbox);
      if (status)
  	return status;
***************
*** 2278,2287 ****
  	}
  
! 	status = _cairo_font_show_glyphs (gstate->font, 
! 					  CAIRO_OPERATOR_ADD, 
! 					  pattern.source, intermediate,
! 					  gstate->clip.x - pattern.source_offset.x,
! 					  gstate->clip.y - pattern.source_offset.y,
! 					  transformed_glyphs, num_glyphs);
  
  	if (status)
--- 2365,2375 ----
  	}
  
! 	status = _cairo_unscaled_font_show_glyphs (gstate->font, 
! 						   &sc,
! 						   CAIRO_OPERATOR_ADD, 
! 						   pattern.source, intermediate,
! 						   gstate->clip.x - pattern.source_offset.x,
! 						   gstate->clip.y - pattern.source_offset.y,
! 						   transformed_glyphs, num_glyphs);
  
  	if (status)
***************
*** 2318,2331 ****
      else
      {
! 	status = _cairo_font_show_glyphs (gstate->font, 
! 					  gstate->operator, pattern.source,
! 					  gstate->surface,
! 					  -pattern.source_offset.x,
! 					  -pattern.source_offset.y,
! 					  transformed_glyphs, num_glyphs);
      }
      
-     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
- 
      _cairo_pattern_fini (&pattern);
  
--- 2406,2418 ----
      else
      {
! 	status = _cairo_unscaled_font_show_glyphs (gstate->font, 
! 						   &sc,
! 						   gstate->operator, pattern.source,
! 						   gstate->surface,
! 						   -pattern.source_offset.x,
! 						   -pattern.source_offset.y,
! 						   transformed_glyphs, num_glyphs);
      }
      
      _cairo_pattern_fini (&pattern);
  
***************
*** 2335,2372 ****
  }
  
- 
- cairo_status_t
- _cairo_gstate_text_path (cairo_gstate_t *gstate, 
- 			 const unsigned char *utf8)
- {
-     cairo_status_t status;
-     cairo_matrix_t saved_font_matrix;
-     cairo_point_t point;
-     double x, y;
- 
-     status = _cairo_path_current_point (&gstate->path, &point);
-     if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- 	x = 0;
- 	y = 0;
- 	cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-     } else {
- 	x = _cairo_fixed_to_double (point.x);
- 	y = _cairo_fixed_to_double (point.y);
-     }
- 
-     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
-     cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
- 
-     status = _cairo_font_text_path (gstate->font, 
- 				    x, y,
- 				    utf8,
- 				    &gstate->path);
- 
-     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
- 
-     return status;
- }
- 
- 
  cairo_status_t
  _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
--- 2422,2425 ----
***************
*** 2377,2381 ****
      int i;
      cairo_glyph_t *transformed_glyphs = NULL;
!     cairo_matrix_t saved_font_matrix;
  
      transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
--- 2430,2436 ----
      int i;
      cairo_glyph_t *transformed_glyphs = NULL;
!     cairo_font_scale_t sc;
! 
!     _build_font_scale (gstate, &sc);
  
      transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
***************
*** 2391,2402 ****
      }
  
!     cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
!     cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
! 
!     status = _cairo_font_glyph_path (gstate->font, 
! 				     transformed_glyphs, num_glyphs,
! 				     &gstate->path);
! 
!     cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
  
      free (transformed_glyphs);
--- 2446,2452 ----
      }
  
!     status = _cairo_unscaled_font_glyph_path (gstate->font, &sc,
! 					      transformed_glyphs, num_glyphs,
! 					      &gstate->path);
  
      free (transformed_glyphs);

Index: cairo_image_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_image_surface.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -d -r1.16 -r1.17
*** cairo_image_surface.c	4 Sep 2004 13:38:34 -0000	1.16
--- cairo_image_surface.c	8 Oct 2004 19:09:51 -0000	1.17
***************
*** 526,529 ****
      _cairo_image_surface_show_page,
      _cairo_image_abstract_surface_set_clip_region,
!     _cairo_image_abstract_surface_create_pattern
  };
--- 526,530 ----
      _cairo_image_surface_show_page,
      _cairo_image_abstract_surface_set_clip_region,
!     _cairo_image_abstract_surface_create_pattern,
!     NULL /* show_glyphs */
  };

Index: cairo_png_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_png_surface.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** cairo_png_surface.c	28 May 2004 19:37:15 -0000	1.8
--- cairo_png_surface.c	8 Oct 2004 19:09:51 -0000	1.9
***************
*** 383,386 ****
      _cairo_png_surface_show_page,
      _cairo_png_surface_set_clip_region,
!     _cairo_png_surface_create_pattern
  };
--- 383,387 ----
      _cairo_png_surface_show_page,
      _cairo_png_surface_set_clip_region,
!     _cairo_png_surface_create_pattern,
!     NULL /* show_glyphs */
  };

Index: cairo_ps_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_ps_surface.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** cairo_ps_surface.c	4 Sep 2004 13:38:35 -0000	1.13
--- cairo_ps_surface.c	8 Oct 2004 19:09:51 -0000	1.14
***************
*** 437,440 ****
      _cairo_ps_surface_show_page,
      _cairo_ps_surface_set_clip_region,
!     _cairo_ps_surface_create_pattern
  };
--- 437,441 ----
      _cairo_ps_surface_show_page,
      _cairo_ps_surface_set_clip_region,
!     _cairo_ps_surface_create_pattern,
!     NULL /* show_glyphs */
  };

Index: cairo_xcb_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_xcb_surface.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** cairo_xcb_surface.c	30 Sep 2004 20:34:19 -0000	1.11
--- cairo_xcb_surface.c	8 Oct 2004 19:09:51 -0000	1.12
***************
*** 746,750 ****
      _cairo_xcb_surface_show_page,
      _cairo_xcb_surface_set_clip_region,
!     _cairo_xcb_surface_create_pattern
  };
  
--- 746,751 ----
      _cairo_xcb_surface_show_page,
      _cairo_xcb_surface_set_clip_region,
!     _cairo_xcb_surface_create_pattern,
!     NULL /* show_glyphs */
  };
  

Index: cairo_xlib_surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo_xlib_surface.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -C2 -d -r1.24 -r1.25
*** cairo_xlib_surface.c	4 Sep 2004 13:38:35 -0000	1.24
--- cairo_xlib_surface.c	8 Oct 2004 19:09:51 -0000	1.25
***************
*** 632,635 ****
--- 632,637 ----
  	XUnionRectWithRegion (&xr, xregion, xregion);
  	rects = malloc(sizeof(XRectangle));
+ 	if (rects == NULL)
+ 	    return CAIRO_STATUS_NO_MEMORY;
  	rects[0] = xr;
  	m = 1;
***************
*** 642,645 ****
--- 644,649 ----
  	    return CAIRO_STATUS_SUCCESS;
  	rects = malloc(sizeof(XRectangle) * n);
+ 	if (rects == NULL)
+ 	    return CAIRO_STATUS_NO_MEMORY;
  	box = pixman_region_rects (region);
  	xregion = XCreateRegion();
***************
*** 662,666 ****
      free(rects);
      if (surf->picture)
!     XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
      XDestroyRegion(xregion);
      XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
--- 666,670 ----
      free(rects);
      if (surf->picture)
! 	XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
      XDestroyRegion(xregion);
      XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
***************
*** 676,679 ****
--- 680,694 ----
  }
  
+ static cairo_status_t
+ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t  *font,
+ 				 cairo_font_scale_t	*scale,
+ 				 cairo_operator_t       operator,
+ 				 cairo_surface_t        *source,
+ 				 cairo_surface_t        *surface,
+ 				 int                    source_x,
+ 				 int                    source_y,
+ 				 const cairo_glyph_t    *glyphs,
+ 				 int                    num_glyphs);
+ 
  static const struct cairo_surface_backend cairo_xlib_surface_backend = {
      _cairo_xlib_surface_create_similar,
***************
*** 691,695 ****
      _cairo_xlib_surface_show_page,
      _cairo_xlib_surface_set_clip_region,
!     _cairo_xlib_surface_create_pattern
  };
  
--- 706,711 ----
      _cairo_xlib_surface_show_page,
      _cairo_xlib_surface_set_clip_region,
!     _cairo_xlib_surface_create_pattern,
!     _cairo_xlib_surface_show_glyphs
  };
  
***************
*** 762,763 ****
--- 778,1288 ----
  }
  DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
+ 
+ 
+ /* RENDER glyphset cache code */
+ 
+ typedef struct glyphset_cache {
+     cairo_cache_t base;
+     struct glyphset_cache *next;
+     Display *display;
+     XRenderPictFormat *a8_pict_format;
+     GlyphSet glyphset;
+     Glyph counter;
+ } glyphset_cache_t;
+ 
+ typedef struct {
+     cairo_glyph_cache_key_t key;
+     Glyph glyph;
+     XGlyphInfo info;
+ } glyphset_cache_entry_t;
+ 
+ static Glyph
+ _next_xlib_glyph (glyphset_cache_t *cache)
+ {
+     return ++(cache->counter);
+ }
+ 
+ 
+ static cairo_status_t 
+ _xlib_glyphset_cache_create_entry (void *cache,
+ 				   void *key,
+ 				   void **return_entry)
+ {
+     glyphset_cache_t *g = (glyphset_cache_t *) cache;
+     cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key;
+     glyphset_cache_entry_t *v;
+ 
+     cairo_status_t status;
+ 
+     cairo_cache_t *im_cache;
+     cairo_image_glyph_cache_entry_t *im;
+ 
+     v = malloc (sizeof (glyphset_cache_entry_t));
+     _cairo_lock_global_image_glyph_cache ();
+     im_cache = _cairo_get_global_image_glyph_cache ();
+ 
+     if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) {
+ 	_cairo_unlock_global_image_glyph_cache ();
+ 	return CAIRO_STATUS_NO_MEMORY;
+     }
+ 
+     status = _cairo_cache_lookup (im_cache, key, (void **) (&im));
+     if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
+ 	_cairo_unlock_global_image_glyph_cache ();
+ 	return CAIRO_STATUS_NO_MEMORY;
+     }
+ 
+     v->key = *k;
+     _cairo_unscaled_font_reference (v->key.unscaled);
+ 
+     v->glyph = _next_xlib_glyph (g);
+ 
+     v->info.width = im->image ? im->image->stride : im->size.width;
+     v->info.height = im->size.height;
+     v->info.x = - im->extents.x_bearing;
+     v->info.y = im->extents.y_bearing;
+     v->info.xOff = 0;
+     v->info.yOff = 0;
+ 
+     XRenderAddGlyphs (g->display, g->glyphset,
+ 		      &(v->glyph), &(v->info), 1,
+ 		      im->image ? im->image->data : NULL,
+ 		      im->image ? v->info.height * v->info.width : 0);
+ 
+     v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
+     *return_entry = v;
+     _cairo_unlock_global_image_glyph_cache ();
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static void 
+ _xlib_glyphset_cache_destroy_cache (void *cache)
+ {
+     /* FIXME: will we ever release glyphset caches? */
+ }
+ 
+ static void 
+ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
+ {
+     glyphset_cache_t *g;
+     glyphset_cache_entry_t *v;
+ 
+     g = (glyphset_cache_t *) cache;
+     v = (glyphset_cache_entry_t *) entry;
+ 
+     _cairo_unscaled_font_destroy (v->key.unscaled);
+     XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
+     free (v);	
+ }
+ 
+ const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
+     _cairo_glyph_cache_hash,
+     _cairo_glyph_cache_keys_equal,
+     _xlib_glyphset_cache_create_entry,
+     _xlib_glyphset_cache_destroy_entry,
+     _xlib_glyphset_cache_destroy_cache
+ };
+ 
+ 
+ static glyphset_cache_t *
+ _xlib_glyphset_caches = NULL;
+ 
+ static void
+ _lock_xlib_glyphset_caches (void)
+ {
+     /* FIXME: implement locking */
+ }
+ 
+ static void
+ _unlock_xlib_glyphset_caches (void)
+ {
+     /* FIXME: implement locking */
+ }
+ 
+ static glyphset_cache_t *
+ _get_glyphset_cache (Display *d)
+ {
+     /* 
+      * There should usually only be one, or a very small number, of
+      * displays. So we just do a linear scan. 
+      */
+ 
+     glyphset_cache_t *g;
+ 
+     for (g = _xlib_glyphset_caches; g != NULL; g = g->next) {
+ 	if (g->display == d)
+ 	    return g;
+     }
+ 
+     g = malloc (sizeof (glyphset_cache_t));
+     if (g == NULL) 
+ 	goto ERR;
+ 
+     g->counter = 0;
+     g->display = d;
+     g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8);
+     if (g->a8_pict_format == NULL)
+ 	goto ERR;
+     
+     if (_cairo_cache_init (&g->base,
+ 			   &_xlib_glyphset_cache_backend,
+ 			   CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT))
+ 	goto FREE_GLYPHSET_CACHE;
+     
+     g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format);
+     g->next = _xlib_glyphset_caches;
+     _xlib_glyphset_caches = g;
+     return g;
+     
+  FREE_GLYPHSET_CACHE:
+     free (g);
+     
+  ERR:
+     return NULL;
+ }
+ 
+ #define N_STACK_BUF 1024
+ 
+ static cairo_status_t
+ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t  *font,
+ 				   cairo_font_scale_t	  *scale,
+ 				   cairo_operator_t       operator,
+ 				   glyphset_cache_t 	  *g,
+ 				   cairo_glyph_cache_key_t *key,
+ 				   cairo_xlib_surface_t   *src,
+ 				   cairo_xlib_surface_t   *self,
+ 				   int                    source_x,
+ 				   int                    source_y,
+ 				   const cairo_glyph_t    *glyphs,
+ 				   glyphset_cache_entry_t **entries,
+ 				   int                    num_glyphs)
+ {
+     XGlyphElt32 *elts = NULL;
+     XGlyphElt32 stack_elts [N_STACK_BUF];
+ 
+     unsigned int *chars = NULL;
+     unsigned int stack_chars [N_STACK_BUF];
+ 
+     int i;    
+     int lastX = 0, lastY = 0;
+ 
+     /* Acquire arrays of suitable sizes. */
+     if (num_glyphs < N_STACK_BUF) {
+ 	elts = stack_elts;
+ 	chars = stack_chars;
+ 
+     } else {
+ 	elts = malloc (num_glyphs * sizeof (XGlyphElt32));
+ 	if (elts == NULL)
+ 	    goto FAIL;
+ 
+ 	chars = malloc (num_glyphs * sizeof (unsigned int));
+ 	if (chars == NULL)
+ 	    goto FREE_ELTS;
+ 
+     }
+ 
+     for (i = 0; i < num_glyphs; ++i) {
+ 	chars[i] = entries[i]->glyph;
+ 	elts[i].chars = &(chars[i]);
+ 	elts[i].nchars = 1;
+ 	elts[i].glyphset = g->glyphset;
+ 	elts[i].xOff = glyphs[i].x - lastX;
+ 	elts[i].yOff = glyphs[i].y - lastY;
+ 	lastX = glyphs[i].x;
+ 	lastY = glyphs[i].y;
+     }
+ 
+     XRenderCompositeText32 (self->dpy,
+ 			    _render_operator (operator),
+ 			    src->picture,
+ 			    self->picture,
+ 			    g->a8_pict_format,
+ 			    source_x, source_y,
+ 			    0, 0,
+ 			    elts, num_glyphs);
+ 
+     if (num_glyphs >= N_STACK_BUF) {
+ 	free (chars);
+ 	free (elts); 
+     }
+     
+     return CAIRO_STATUS_SUCCESS;
+     
+  FREE_ELTS:
+     if (num_glyphs >= N_STACK_BUF)
+ 	free (elts); 
+ 
+  FAIL:
+     return CAIRO_STATUS_NO_MEMORY;
+ }
+ 
+ 
+ static cairo_status_t
+ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t  *font,
+ 				   cairo_font_scale_t	  *scale,
+ 				   cairo_operator_t       operator,
+ 				   glyphset_cache_t 	  *g,
+ 				   cairo_glyph_cache_key_t *key,
+ 				   cairo_xlib_surface_t   *src,
+ 				   cairo_xlib_surface_t   *self,
+ 				   int                    source_x,
+ 				   int                    source_y,
+ 				   const cairo_glyph_t    *glyphs,
+ 				   glyphset_cache_entry_t **entries,
+ 				   int                    num_glyphs)
+ {
+     XGlyphElt16 *elts = NULL;
+     XGlyphElt16 stack_elts [N_STACK_BUF];
+ 
+     unsigned short *chars = NULL;
+     unsigned short stack_chars [N_STACK_BUF];
+ 
+     int i;
+     int lastX = 0, lastY = 0;
+ 
+     /* Acquire arrays of suitable sizes. */
+     if (num_glyphs < N_STACK_BUF) {
+ 	elts = stack_elts;
+ 	chars = stack_chars;
+ 
+     } else {
+ 	elts = malloc (num_glyphs * sizeof (XGlyphElt16));
+ 	if (elts == NULL)
+ 	    goto FAIL;
+ 
+ 	chars = malloc (num_glyphs * sizeof (unsigned short));
+ 	if (chars == NULL)
+ 	    goto FREE_ELTS;
+ 
+     }
+ 
+     for (i = 0; i < num_glyphs; ++i) {
+ 	chars[i] = entries[i]->glyph;
+ 	elts[i].chars = &(chars[i]);
+ 	elts[i].nchars = 1;
+ 	elts[i].glyphset = g->glyphset;
+ 	elts[i].xOff = glyphs[i].x - lastX;
+ 	elts[i].yOff = glyphs[i].y - lastY;
+ 	lastX = glyphs[i].x;
+ 	lastY = glyphs[i].y;
+     }
+ 
+     XRenderCompositeText16 (self->dpy,
+ 			    _render_operator (operator),
+ 			    src->picture,
+ 			    self->picture,
+ 			    g->a8_pict_format,
+ 			    source_x, source_y,
+ 			    0, 0,
+ 			    elts, num_glyphs);
+ 
+     if (num_glyphs >= N_STACK_BUF) {
+ 	free (chars);
+ 	free (elts); 
+     }
+     
+     return CAIRO_STATUS_SUCCESS;
+ 
+  FREE_ELTS:
+     if (num_glyphs >= N_STACK_BUF)
+ 	free (elts); 
+ 
+  FAIL:
+     return CAIRO_STATUS_NO_MEMORY;
+ }
+ 
+ static cairo_status_t
+ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t  *font,
+ 				  cairo_font_scale_t	  *scale,
+ 				  cairo_operator_t       operator,
+ 				  glyphset_cache_t 	  *g,
+ 				  cairo_glyph_cache_key_t *key,
+ 				  cairo_xlib_surface_t   *src,
+ 				  cairo_xlib_surface_t   *self,
+ 				  int                    source_x,
+ 				  int                    source_y,
+ 				  const cairo_glyph_t    *glyphs,
+ 				  glyphset_cache_entry_t **entries,
+ 				  int                    num_glyphs)
+ {
+     XGlyphElt8 *elts = NULL;
+     XGlyphElt8 stack_elts [N_STACK_BUF];
+ 
+     char *chars = NULL;
+     char stack_chars [N_STACK_BUF];
+ 
+     int i;
+     int lastX = 0, lastY = 0;
+ 
+     /* Acquire arrays of suitable sizes. */
+     if (num_glyphs < N_STACK_BUF) {
+ 	elts = stack_elts;
+ 	chars = stack_chars;
+ 
+     } else {
+ 	elts = malloc (num_glyphs * sizeof (XGlyphElt8));
+ 	if (elts == NULL)
+ 	    goto FAIL;
+ 
+ 	chars = malloc (num_glyphs * sizeof (char));
+ 	if (chars == NULL)
+ 	    goto FREE_ELTS;
+ 
+     }
+ 
+     for (i = 0; i < num_glyphs; ++i) {
+ 	chars[i] = entries[i]->glyph;
+ 	elts[i].chars = &(chars[i]);
+ 	elts[i].nchars = 1;
+ 	elts[i].glyphset = g->glyphset;
+ 	elts[i].xOff = glyphs[i].x - lastX;
+ 	elts[i].yOff = glyphs[i].y - lastY;
+ 	lastX = glyphs[i].x;
+ 	lastY = glyphs[i].y;
+     }
+ 
+     XRenderCompositeText8 (self->dpy,
+ 			   _render_operator (operator),
+ 			   src->picture,
+ 			   self->picture,
+ 			   g->a8_pict_format,
+ 			   source_x, source_y,
+ 			   0, 0,
+ 			   elts, num_glyphs);
+     
+     if (num_glyphs >= N_STACK_BUF) {
+ 	free (chars);
+ 	free (elts); 
+     }
+     
+     return CAIRO_STATUS_SUCCESS;
+     
+  FREE_ELTS:
+     if (num_glyphs >= N_STACK_BUF)
+ 	free (elts); 
+ 
+  FAIL:
+     return CAIRO_STATUS_NO_MEMORY;
+ }
+ 
+ 
+ static cairo_status_t
+ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t  *font,
+ 				 cairo_font_scale_t	*scale,
+ 				 cairo_operator_t       operator,
+ 				 cairo_surface_t        *source,
+ 				 cairo_surface_t        *surface,
+ 				 int                    source_x,
+ 				 int                    source_y,
+ 				 const cairo_glyph_t    *glyphs,
+ 				 int                    num_glyphs)
+ {
+     unsigned int elt_size;
+     cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
+     cairo_image_surface_t *tmp = NULL;
+     cairo_xlib_surface_t *src = NULL;
+     glyphset_cache_t *g;
+     cairo_status_t status;
+     cairo_glyph_cache_key_t key;
+     glyphset_cache_entry_t **entries;
+     glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
+     int i;
+ 
+     /* Acquire an entry array of suitable size. */
+     if (num_glyphs < N_STACK_BUF) {
+ 	entries = stack_entries;
+ 
+     } else {
+ 	entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *));
+ 	if (entries == NULL)
+ 	    goto FAIL;
+     }
+ 
+     /* prep the source surface. */
+     if (source->backend == surface->backend) {
+ 	src = (cairo_xlib_surface_t *) source;
+ 
+     } else {
+ 	tmp = _cairo_surface_get_image (source);
+ 	if (tmp == NULL)
+ 	    goto FREE_ENTRIES;
+ 
+ 	src = (cairo_xlib_surface_t *) 
+ 	    _cairo_surface_create_similar_scratch (surface, self->format, 1,
+ 						   tmp->width, tmp->height);
+ 
+ 	if (src == NULL)
+ 	    goto FREE_TMP;
+ 
+ 	if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS)
+ 	    goto FREE_SRC;	    
+     }
+ 
+     _lock_xlib_glyphset_caches ();
+     g = _get_glyphset_cache (self->dpy);
+     if (g == NULL)
+ 	goto UNLOCK;
+ 
+     /* Work out the index size to use. */
+     elt_size = 8;
+     key.scale = *scale;
+     key.unscaled = font;
+ 
+     for (i = 0; i < num_glyphs; ++i) {
+ 	key.index = glyphs[i].index;
+ 	status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]));
+ 	if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) 
+ 	    goto UNLOCK;
+ 
+ 	if (elt_size == 8 && entries[i]->glyph > 0xff)
+ 	    elt_size = 16;
+ 	if (elt_size == 16 && entries[i]->glyph > 0xffff) {
+ 	    elt_size = 32;
+ 	    break;
+ 	}
+     }
+ 
+     /* Call the appropriate sub-function. */
+ 
+     if (elt_size == 8)
+ 	status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self,
+ 						    source_x, source_y, 
+ 						   glyphs, entries, num_glyphs);
+     else if (elt_size == 16)
+ 	status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self,
+ 						    source_x, source_y, 
+ 						    glyphs, entries, num_glyphs);
+     else 
+ 	status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self,
+ 						    source_x, source_y, 
+ 						    glyphs, entries, num_glyphs);
+ 
+     _unlock_xlib_glyphset_caches ();
+ 
+     if (tmp != NULL) {
+ 	cairo_surface_destroy (&(src->base));
+ 	cairo_surface_destroy (&(tmp->base));
+     }
+ 
+     if (num_glyphs >= N_STACK_BUF)
+ 	free (entries); 
+ 
+     return status;
+ 
+  UNLOCK:
+     _unlock_xlib_glyphset_caches ();
+ 
+  FREE_SRC:
+     cairo_surface_destroy (&(src->base));
+ 
+  FREE_TMP:
+     cairo_surface_destroy (&(tmp->base));
+ 
+  FREE_ENTRIES:
+     if (num_glyphs >= N_STACK_BUF)
+ 	free (entries); 
+ 
+  FAIL:
+     return CAIRO_STATUS_NO_MEMORY;
+ }

Index: cairoint.h
===================================================================
RCS file: /cvs/cairo/cairo/src/cairoint.h,v
retrieving revision 1.69
retrieving revision 1.70
diff -C2 -d -r1.69 -r1.70
*** cairoint.h	4 Sep 2004 13:38:35 -0000	1.69
--- cairoint.h	8 Oct 2004 19:09:51 -0000	1.70
***************
*** 50,54 ****
  #endif
  
- #include <assert.h>
  #include <stdlib.h>
  #include <string.h>
--- 50,53 ----
***************
*** 254,303 ****
  
  typedef struct cairo_color cairo_color_t;
  
  typedef struct cairo_font_backend {
!     cairo_font_t *(*create)          (const char		*family,
  				      cairo_font_slant_t	slant,
  				      cairo_font_weight_t	weight);
  				    
-     cairo_font_t *(*copy)            (void			*font);
- 
      void (*destroy)		     (void			*font);
  
      cairo_status_t (*font_extents)   (void			*font,
  				      cairo_font_extents_t	*extents);
  
!     cairo_status_t (*text_extents)   (void			*font,
  				      const unsigned char	*utf8,
! 				      cairo_text_extents_t	*extents);
!   
      cairo_status_t (*glyph_extents)  (void			*font,
  				      cairo_glyph_t		*glyphs, 
  				      int			num_glyphs,
  				      cairo_text_extents_t	*extents);
  
-     cairo_status_t (*text_bbox)      (void			*font,
- 				      cairo_surface_t		*surface,
- 				      double			x,
- 				      double			y,
- 				      const unsigned char	*utf8,
- 				      cairo_box_t		*bbox);
- 
      cairo_status_t (*glyph_bbox)    (void			*font,
! 				     cairo_surface_t     	*surface,
  				     const cairo_glyph_t	*glyphs,
  				     int			num_glyphs,
  				     cairo_box_t		*bbox);
    
-     cairo_status_t (*show_text)      (void			*font,
- 				      cairo_operator_t		operator,
- 				      cairo_surface_t		*source,
- 				      cairo_surface_t		*surface,
- 				      int                       source_x,
- 				      int                       source_y,
- 				      double			x,
- 				      double			y,
- 				      const unsigned char	*utf8);
- 
      cairo_status_t (*show_glyphs)    (void			*font,
  				      cairo_operator_t		operator,
  				      cairo_surface_t		*source,
--- 253,454 ----
  
  typedef struct cairo_color cairo_color_t;
+ typedef struct cairo_image_surface cairo_image_surface_t;
+ 
+ /* cairo_cache.c structures and functions */ 
+ 
+ typedef struct cairo_cache_backend {
+ 
+     unsigned long	(*hash)			(void *cache,
+ 						 void *key);
+ 
+     int			(*keys_equal)		(void *cache,
+ 						 void *k1, 
+ 						 void *k2);
+     
+     cairo_status_t	(*create_entry)		(void *cache,
+ 						 void *key,
+ 						 void **entry_return);
+ 
+     void		(*destroy_entry)	(void *cache,
+ 						 void *entry);
+ 
+     void		(*destroy_cache)	(void *cache);
+ 
+ } cairo_cache_backend_t;
+ 
+ 
+ /* 
+  * The cairo_cache system makes the following assumptions about
+  * entries in its cache:
+  *
+  *  - a pointer to an entry can be cast to a cairo_cache_entry_base_t.
+  *  - a pointer to an entry can also be cast to the "key type".
+  *
+  * The practical effect of this is that your entries must be laid
+  * out this way:
+  *
+  *    struct my_entry { 
+  *      cairo_cache_entry_base_t;
+  *      my_key_value_1;
+  *      my_key_value_2;
+  *      ...
+  *      my_value;
+  *    };
+  */
+ 
+ typedef struct {
+     unsigned long memory;
+     unsigned long hashcode;
+ } cairo_cache_entry_base_t;
+ 
+ typedef struct {
+     unsigned long high_water_mark;
+     unsigned long size;
+     unsigned long rehash;
+ } cairo_cache_arrangement_t;
+ 
+ #undef CAIRO_MEASURE_CACHE_PERFORMANCE
+ 
+ typedef struct {
+     unsigned long refcount;
+     const cairo_cache_backend_t *backend;
+     cairo_cache_arrangement_t *arrangement;
+     cairo_cache_entry_base_t **entries;
+ 
+     unsigned long max_memory;
+     unsigned long used_memory;
+     unsigned long live_entries;
+ 
+ #ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
+     unsigned long hits;
+     unsigned long misses;
+     unsigned long probes;
+ #endif
+ } cairo_cache_t;
+ 
+ extern cairo_status_t __internal_linkage
+ _cairo_cache_init (cairo_cache_t *cache,
+ 		   const cairo_cache_backend_t *backend,
+ 		   unsigned long max_memory);
+ 
+ extern void __internal_linkage
+ _cairo_cache_reference (cairo_cache_t *cache);
+ 
+ extern void __internal_linkage
+ _cairo_cache_destroy (cairo_cache_t *cache);
+ 
+ extern cairo_status_t __internal_linkage
+ _cairo_cache_lookup (cairo_cache_t *cache,
+ 		     void *key,
+ 		     void **entry_return);
+ 
+ extern unsigned long __internal_linkage
+ _cairo_hash_string (const char *c);
+ 
+ #define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
+ #define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
+ #define CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT 20
+ #define CAIRO_FT_CACHE_NUM_FONTS_DEFAULT 20
+ 
+ typedef struct {
+     double matrix[2][2];
+ } cairo_font_scale_t;
+ 
+ struct cairo_font_backend;
+ 
+ typedef struct {
+     int refcount;
+     const struct cairo_font_backend *backend;
+ } cairo_unscaled_font_t;
+ 
+ /* 
+  * A cairo_font contains a pointer to a cairo_sizeless_font_t and a scale
+  * matrix. These are the things the user holds references to.
+  */
+ 
+ struct cairo_font {
+     int refcount;
+     cairo_font_scale_t scale;
+     cairo_unscaled_font_t *unscaled;
+ };
+ 
+ 
+ /* cairo_font.c is responsible for two global caches: 
+  *  
+  *   - font entries:  [[[base], name, weight, slant], cairo_unscaled_font_t ]
+  *   - glyph entries: [[[base], cairo_font_t, index], image, size, extents  ]
+  *
+  * Surfaces may build their own glyph caches if they have surface-specific
+  * glyph resources to maintain; those caches can feed off of the global
+  * caches if need be (eg. cairo_xlib_surface.c does this).
+  */
+ 
+ typedef struct {
+     cairo_cache_entry_base_t base;
+     cairo_unscaled_font_t *unscaled;
+     cairo_font_scale_t scale;
+     unsigned long index;
+ } cairo_glyph_cache_key_t;
+ 
+ typedef struct {
+     cairo_glyph_cache_key_t key;
+     cairo_image_surface_t *image;
+     cairo_glyph_size_t size;    
+     cairo_text_extents_t extents;
+ } cairo_image_glyph_cache_entry_t;
+ 
+ extern void __internal_linkage
+ _cairo_lock_global_image_glyph_cache (void);
+ 
+ extern void __internal_linkage
+ _cairo_unlock_global_image_glyph_cache (void);
+ 
+ extern cairo_cache_t * __internal_linkage
+ _cairo_get_global_image_glyph_cache (void);
+ 
+ /* Some glyph cache functions you can reuse. */
+ 
+ extern unsigned long __internal_linkage
+ _cairo_glyph_cache_hash (void *cache, void *key);
+ 
+ extern int __internal_linkage
+ _cairo_glyph_cache_keys_equal (void *cache,
+ 			       void *k1,
+ 			       void *k2);
+ 
+ 
+ /* the font backend interface */
  
  typedef struct cairo_font_backend {
!     cairo_unscaled_font_t *(*create) (const char		*family,
  				      cairo_font_slant_t	slant,
  				      cairo_font_weight_t	weight);
  				    
      void (*destroy)		     (void			*font);
  
      cairo_status_t (*font_extents)   (void			*font,
+ 				      cairo_font_scale_t	*scale,
  				      cairo_font_extents_t	*extents);
  
!     cairo_status_t (*text_to_glyphs) (void                      *font,
! 				      cairo_font_scale_t	*scale,
  				      const unsigned char	*utf8,
! 				      cairo_glyph_t		**glyphs, 
! 				      int			*num_glyphs);
! 
      cairo_status_t (*glyph_extents)  (void			*font,
+ 				      cairo_font_scale_t	*scale,
  				      cairo_glyph_t		*glyphs, 
  				      int			num_glyphs,
  				      cairo_text_extents_t	*extents);
  
      cairo_status_t (*glyph_bbox)    (void			*font,
! 				     cairo_font_scale_t		*scale,
  				     const cairo_glyph_t	*glyphs,
  				     int			num_glyphs,
  				     cairo_box_t		*bbox);
    
      cairo_status_t (*show_glyphs)    (void			*font,
+ 				      cairo_font_scale_t	*scale,
  				      cairo_operator_t		operator,
  				      cairo_surface_t		*source,
***************
*** 308,324 ****
  				      int			num_glyphs);
    
-     cairo_status_t (*text_path)      (void			*font,
- 				      double			x,
- 				      double			y,
- 				      const unsigned char	*utf8,
- 				      cairo_path_t		*path);
- 
      cairo_status_t (*glyph_path)     (void			*font,
  				      cairo_glyph_t		*glyphs, 
  				      int			num_glyphs,
  				      cairo_path_t		*path);
!     cairo_surface_t *(*create_glyph) (void			*font,
! 				      const cairo_glyph_t	*glyph,
! 				      cairo_glyph_size_t        *return_size);
  } cairo_font_backend_t;
  
--- 459,470 ----
  				      int			num_glyphs);
    
      cairo_status_t (*glyph_path)     (void			*font,
+ 				      cairo_font_scale_t	*scale,
  				      cairo_glyph_t		*glyphs, 
  				      int			num_glyphs,
  				      cairo_path_t		*path);
! 
!     cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry);
! 
  } cairo_font_backend_t;
  
***************
*** 326,330 ****
  extern const struct cairo_font_backend cairo_ft_font_backend;
  
- typedef struct cairo_image_surface cairo_image_surface_t;
  
  typedef struct cairo_surface_backend {
--- 472,475 ----
***************
*** 411,414 ****
--- 556,576 ----
  				 cairo_pattern_t	*pattern,
  				 cairo_box_t		*extents);
+ 
+     /* 
+      * This is an optional entry to let the surface manage its own glyph
+      * resources. If null, the font will be asked to render against this
+      * surface, using image surfaces as glyphs. 
+      */    
+     cairo_status_t 
+     (*show_glyphs)		(cairo_unscaled_font_t		*font,
+ 				 cairo_font_scale_t		*scale,
+ 				 cairo_operator_t		operator,
+ 				 cairo_surface_t		*source,
+ 				 cairo_surface_t		*surface,
+ 				 int				source_x,
+ 				 int				source_y,
+ 				 const cairo_glyph_t		*glyphs,
+ 				 int				num_glyphs);
+ 
  } cairo_surface_backend_t;
  
***************
*** 548,585 ****
  #define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
  
- #define CAIRO_FONT_CACHE_SIZE_DEFAULT 256
- 
- typedef struct {
-     unsigned long index;
-     double matrix[2][2];
-     
-     unsigned int time;
-     
-     cairo_surface_t *surface;
-     cairo_glyph_size_t size;
- } cairo_glyph_surface_t;
- 
- typedef struct cairo_glyph_surface_node {
-     struct cairo_glyph_surface_node *next;
-     struct cairo_glyph_surface_node *prev;
-     
-     cairo_glyph_surface_t s;
- } cairo_glyph_surface_node_t;
- 
- typedef struct {
-     cairo_glyph_surface_node_t *first;
-     cairo_glyph_surface_node_t *last;
-     unsigned int n_nodes;
-     
-     unsigned int ref_count;
-     unsigned int cache_size;
- } cairo_glyph_cache_t;
- 
- struct cairo_font {
-     int refcount;
-     cairo_matrix_t matrix;
-     cairo_glyph_cache_t *glyph_cache;
-     const struct cairo_font_backend *backend;
- };
  
  #define CAIRO_GSTATE_OPERATOR_DEFAULT	CAIRO_OPERATOR_OVER
--- 710,713 ----
***************
*** 619,623 ****
      double dash_offset;
  
!     cairo_font_t *font;
  
      cairo_surface_t *surface;
--- 747,751 ----
      double dash_offset;
  
!     cairo_unscaled_font_t *font;
  
      cairo_surface_t *surface;
***************
*** 629,632 ****
--- 757,763 ----
  
      double pixels_per_inch;
+ 
+     cairo_matrix_t font_matrix;
+ 
      cairo_matrix_t ctm;
      cairo_matrix_t ctm_inverse;
***************
*** 936,939 ****
--- 1067,1078 ----
  			    cairo_font_t **font);
  
+ extern void __internal_linkage
+ _cairo_gstate_set_font_transform (cairo_gstate_t *gstate, 
+ 				  cairo_matrix_t *matrix);
+ 
+ extern void __internal_linkage
+ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
+ 				      cairo_matrix_t *matrix);
+ 
  extern cairo_status_t __internal_linkage
  _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, 
***************
*** 944,952 ****
  			cairo_font_t *font);
  
- 
  extern cairo_status_t __internal_linkage
! _cairo_gstate_text_extents (cairo_gstate_t *gstate,
! 			    const unsigned char *utf8,
! 			    cairo_text_extents_t *extents);
  
  extern cairo_status_t __internal_linkage
--- 1083,1091 ----
  			cairo_font_t *font);
  
  extern cairo_status_t __internal_linkage
! _cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
! 			      const unsigned char *utf8, 
! 			      cairo_glyph_t **glyphs, 
! 			      int *num_glyphs);
  
  extern cairo_status_t __internal_linkage
***************
*** 957,964 ****
  
  extern cairo_status_t __internal_linkage
- _cairo_gstate_show_text (cairo_gstate_t *gstate, 
- 			 const unsigned char *utf8);
- 
- extern cairo_status_t __internal_linkage
  _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, 
  			   cairo_glyph_t *glyphs, 
--- 1096,1099 ----
***************
*** 966,973 ****
  
  extern cairo_status_t __internal_linkage
- _cairo_gstate_text_path (cairo_gstate_t *gstate, 
- 			 const unsigned char *utf8);
- 
- extern cairo_status_t __internal_linkage
  _cairo_gstate_glyph_path (cairo_gstate_t *gstate, 
  			  cairo_glyph_t *glyphs, 
--- 1101,1104 ----
***************
*** 993,1085 ****
  /* cairo_font.c */
  
! extern cairo_font_t * __internal_linkage
! _cairo_font_create (const char           *family, 
! 		    cairo_font_slant_t   slant, 
! 		    cairo_font_weight_t  weight);
! 
! extern cairo_status_t __internal_linkage
! _cairo_font_init (cairo_font_t *font, 
! 		  const struct cairo_font_backend *backend);
! 
! extern cairo_font_t * __internal_linkage
! _cairo_font_copy (cairo_font_t *font);
! 
! extern cairo_status_t __internal_linkage
! _cairo_font_scale (cairo_font_t *font, double scale);
  
! extern cairo_status_t __internal_linkage
! _cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix);
  
  extern cairo_status_t __internal_linkage
! _cairo_font_font_extents (cairo_font_t *font, 
! 			  cairo_font_extents_t *extents);
  
! extern cairo_status_t __internal_linkage
! _cairo_font_text_extents (cairo_font_t *font,
!                           const unsigned char *utf8,
! 			  cairo_text_extents_t *extents);
  
! extern cairo_status_t __internal_linkage
! _cairo_font_glyph_extents (cairo_font_t *font,
!                            cairo_glyph_t *glyphs,
!                            int num_glyphs,
! 			   cairo_text_extents_t *extents);
  
  extern cairo_status_t __internal_linkage
! _cairo_font_text_bbox (cairo_font_t             *font,
!                        cairo_surface_t          *surface,
!                        double                   x,
!                        double                   y,
!                        const unsigned char      *utf8,
! 		       cairo_box_t		*bbox);
  
  extern cairo_status_t __internal_linkage
! _cairo_font_glyph_bbox (cairo_font_t            *font,
! 			cairo_surface_t         *surface,
! 			cairo_glyph_t           *glyphs,
! 			int                     num_glyphs,
! 			cairo_box_t		*bbox);
  
  extern cairo_status_t __internal_linkage
! _cairo_font_show_text (cairo_font_t             *font,
!                        cairo_operator_t         operator,
!                        cairo_surface_t          *source,
!                        cairo_surface_t          *surface,
! 		       int                      source_x,
! 		       int                      source_y,
!                        double                   x,
!                        double                   y,
!                        const unsigned char      *utf8);
! 
  
  extern cairo_status_t __internal_linkage
! _cairo_font_show_glyphs (cairo_font_t           *font,
!                          cairo_operator_t       operator,
!                          cairo_surface_t        *source,
!                          cairo_surface_t        *surface,
! 			 int                    source_x,
! 			 int                    source_y,
!                          cairo_glyph_t          *glyphs,
!                          int                    num_glyphs);
! 
  
  extern cairo_status_t __internal_linkage
! _cairo_font_text_path (cairo_font_t             *font,
! 		       double			x,
! 		       double			y,
!                        const unsigned char      *utf8,
!                        cairo_path_t             *path);
  
  extern cairo_status_t __internal_linkage
! _cairo_font_glyph_path (cairo_font_t            *font,
!                         cairo_glyph_t           *glyphs, 
!                         int                     num_glyphs,
!                         cairo_path_t            *path);
! 
! extern cairo_surface_t *__internal_linkage
! _cairo_font_lookup_glyph (cairo_font_t          *font,
! 			  cairo_surface_t       *surface,
! 			  const cairo_glyph_t   *glyph,
! 			  cairo_glyph_size_t    *return_size);
  
  /* cairo_hull.c */
--- 1124,1190 ----
  /* cairo_font.c */
  
! extern cairo_unscaled_font_t * __internal_linkage
! _cairo_unscaled_font_create (const char           *family, 
! 			     cairo_font_slant_t   slant, 
! 			     cairo_font_weight_t  weight);
  
! extern void __internal_linkage
! _cairo_font_init (cairo_font_t 			*scaled, 
! 		  cairo_font_scale_t 		*scale,
! 		  cairo_unscaled_font_t 	*unscaled);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_init (cairo_unscaled_font_t		*font, 
! 			   const struct cairo_font_backend 	*backend);
  
! extern void __internal_linkage
! _cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
  
! extern void __internal_linkage
! _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_font_extents (cairo_unscaled_font_t 	*font, 
! 				   cairo_font_scale_t 		*scale,
! 				   cairo_font_extents_t		*extents);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t	*font,
! 				     cairo_font_scale_t 	*scale,
! 				     const unsigned char 	*utf8, 
! 				     cairo_glyph_t 		**glyphs, 
! 				     int 			*num_glyphs);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t	*font,
! 				    cairo_font_scale_t 		*scale,
! 				    cairo_glyph_t 		*glyphs,
! 				    int 			num_glyphs,
! 				    cairo_text_extents_t 	*extents);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t          *font,
! 				 cairo_font_scale_t 		*size,
! 				 cairo_glyph_t           	*glyphs,
! 				 int                     	num_glyphs,
! 				 cairo_box_t			*bbox);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t         *font,
! 				  cairo_font_scale_t		*size,
! 				  cairo_operator_t       	operator,
! 				  cairo_surface_t        	*source,
! 				  cairo_surface_t        	*surface,
! 				  int                    	source_x,
! 				  int                    	source_y,
! 				  cairo_glyph_t          	*glyphs,
! 				  int                    	num_glyphs);
  
  extern cairo_status_t __internal_linkage
! _cairo_unscaled_font_glyph_path (cairo_unscaled_font_t          	*font,
! 				 cairo_font_scale_t		*size,
! 				 cairo_glyph_t           	*glyphs, 
! 				 int                     	num_glyphs,
! 				 cairo_path_t            	*path);
  
  /* cairo_hull.c */




More information about the cairo-commit mailing list