Index: pango/pangocairo-fontmap.c
===================================================================
--- pango/pangocairo-fontmap.c	(revision 2325)
+++ pango/pangocairo-fontmap.c	(working copy)
@@ -181,19 +181,3 @@ pango_cairo_font_map_create_context (Pan
 
   return context;
 }
-
-/**
- * _pango_cairo_font_map_get_renderer:
- * @fontmap: a #PangoCairoFontmap
- *
- * Gets the singleton #PangoCairoRenderer for this fontmap.
- *
- * Return value: the singleton renderer
- **/
-PangoRenderer *
-_pango_cairo_font_map_get_renderer (PangoCairoFontMap *fontmap)
-{
-  g_return_val_if_fail (PANGO_IS_CAIRO_FONT_MAP (fontmap), NULL);
-
-  return (* PANGO_CAIRO_FONT_MAP_GET_IFACE (fontmap)->get_renderer) (fontmap);
-}
Index: pango/pangocairo-fcfont.c
===================================================================
--- pango/pangocairo-fcfont.c	(revision 2325)
+++ pango/pangocairo-fcfont.c	(working copy)
@@ -21,9 +21,6 @@
 
 #include <config.h>
 
-#include <math.h>
-#include <stdlib.h>
-
 #include <cairo-ft.h>
 
 #include "pango-fontmap.h"
@@ -41,36 +38,12 @@
 typedef struct _PangoCairoFcFont      PangoCairoFcFont;
 typedef struct _PangoCairoFcFontClass PangoCairoFcFontClass;
 
-typedef struct _GlyphExtentsCacheEntry    GlyphExtentsCacheEntry;
-
-#define GLYPH_CACHE_NUM_ENTRIES 256 /* should be power of two */
-#define GLYPH_CACHE_MASK (GLYPH_CACHE_NUM_ENTRIES - 1)
-
-/* An entry in the fixed-size cache for the glyph -> ink_rect mapping.
- * The cache is indexed by the lower N bits of the glyph (see
- * GLYPH_CACHE_NUM_ENTRIES).  For scripts with few glyphs,
- * this should provide pretty much instant lookups.
- */
-struct _GlyphExtentsCacheEntry
-{
-  PangoGlyph     glyph;
-  int            width;
-  PangoRectangle ink_rect;
-};
-
 struct _PangoCairoFcFont
 {
   PangoFcFont font;
+  PangoCairoFontPrivate cf_priv;
 
-  cairo_font_face_t *font_face;
-  cairo_scaled_font_t *scaled_font;
-  cairo_matrix_t font_matrix;
-  cairo_matrix_t ctm;
-  cairo_font_options_t *options;
   PangoGravity gravity;
-
-  PangoRectangle font_extents;
-  GlyphExtentsCacheEntry    *glyph_extents_cache;
 };
 
 struct _PangoCairoFcFontClass
@@ -80,86 +53,33 @@ struct _PangoCairoFcFontClass
 
 GType pango_cairo_fc_font_get_type (void);
 
-static cairo_font_face_t *pango_cairo_fc_font_get_font_face (PangoCairoFont *font);
-
-/*******************************
- *       Utility functions     *
- *******************************/
+/********************************
+ *    Method implementations    *
+ ********************************/
 
 static cairo_font_face_t *
-pango_cairo_fc_font_get_font_face (PangoCairoFont *font)
+pango_cairo_fc_font_create_font_face (PangoCairoFont *cfont)
 {
-  PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
-  PangoFcFont *fcfont = (PangoFcFont *) (cffont);
-
-  if (!cffont->font_face)
-    {
-      cffont->font_face = cairo_ft_font_face_create_for_pattern (fcfont->font_pattern);
-
-      /* Unable to create FT2 cairo scaled font.
-       * This means out of memory or a cairo/fontconfig/FreeType bug,
-       */
-      if (!cffont->font_face)
-	return NULL;
-    }
+  PangoFcFont *fcfont = (PangoFcFont *) (cfont);
 
-  return cffont->font_face;
+  return cairo_ft_font_face_create_for_pattern (fcfont->font_pattern);
 }
 
-static cairo_scaled_font_t *
-pango_cairo_fc_font_get_scaled_font (PangoCairoFont *font)
+static PangoFontMetrics *
+pango_cairo_fc_font_create_metrics_for_context (PangoCairoFont *cfont,
+					        PangoContext   *context)
 {
-  PangoCairoFcFont *cffont = (PangoCairoFcFont *)font;
-
-  if (!cffont->scaled_font)
-    {
-      cairo_font_face_t *font_face;
-
-      font_face = pango_cairo_fc_font_get_font_face (font);
+  PangoFcFont *fcfont = (PangoFcFont *) (cfont);
 
-      if (!font_face)
-	return NULL;
-
-      cffont->scaled_font = cairo_scaled_font_create (font_face,
-						      &cffont->font_matrix,
-						      &cffont->ctm,
-						      cffont->options);
-
-      /* Unable to create FT2 cairo scaled font.
-       * This means out of memory or a cairo/fontconfig/FreeType bug,
-       * or a missing font...
-       */
-      if (!cffont->scaled_font)
-	return NULL;
-    }
-
-  return cffont->scaled_font;
-}
-
-/********************************
- *    Method implementations    *
- ********************************/
-
-static gboolean
-pango_cairo_fc_font_install (PangoCairoFont *font,
-			     cairo_t        *cr)
-{
-  PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
-
-  cairo_set_font_face (cr,
-		       pango_cairo_fc_font_get_font_face (font));
-  cairo_set_font_matrix (cr, &cffont->font_matrix);
-  cairo_set_font_options (cr, cffont->options);
-
-  return TRUE;
+  return pango_fc_font_create_metrics_for_context (fcfont, context);
 }
 
 static void
 cairo_font_iface_init (PangoCairoFontIface *iface)
 {
-  iface->install = pango_cairo_fc_font_install;
-  iface->get_font_face = pango_cairo_fc_font_get_font_face;
-  iface->get_scaled_font = pango_cairo_fc_font_get_scaled_font;
+  iface->create_font_face = pango_cairo_fc_font_create_font_face;
+  iface->create_metrics_for_context = pango_cairo_fc_font_create_metrics_for_context;
+  iface->cf_priv_offset = G_STRUCT_OFFSET (PangoCairoFcFont, cf_priv);
 }
 
 G_DEFINE_TYPE_WITH_CODE (PangoCairoFcFont, pango_cairo_fc_font, PANGO_TYPE_FC_FONT,
@@ -170,105 +90,34 @@ pango_cairo_fc_font_finalize (GObject *o
 {
   PangoCairoFcFont *cffont = (PangoCairoFcFont *) (object);
 
-  if (cffont->font_face)
-    cairo_font_face_destroy (cffont->font_face);
-  if (cffont->scaled_font)
-    cairo_scaled_font_destroy (cffont->scaled_font);
-  if (cffont->options)
-    cairo_font_options_destroy (cffont->options);
-
-
-  if (cffont->glyph_extents_cache)
-    {
-      g_free (cffont->glyph_extents_cache);
-    }
+  _pango_cairo_font_private_finalize (&cffont->cf_priv);
 
   G_OBJECT_CLASS (pango_cairo_fc_font_parent_class)->finalize (object);
 }
 
-/* This function is cut-and-pasted from pangocairo-fcfont.c - it might be
- * better to add a virtual fcfont->create_context (font).
- */
-static PangoFontMetrics *
-pango_cairo_fc_font_get_metrics (PangoFont     *font,
-				 PangoLanguage *language)
+/* we want get_glyph_extents extremely fast, so we use a small wrapper here
+ * to avoid having to lookup the interface data like we do for get_metrics
+ * in _pango_cairo_font_get_metrics(). */
+static void
+pango_cairo_fc_font_get_glyph_extents (PangoFont      *font,
+				       PangoGlyph      glyph,
+				       PangoRectangle *ink_rect,
+				       PangoRectangle *logical_rect)
 {
-  PangoFcFont *fcfont = (PangoFcFont *) (font);
   PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
-  PangoFcMetricsInfo *info = NULL; /* Quiet gcc */
-  GSList *tmp_list;
-
-  const char *sample_str = pango_language_get_sample_string (language);
-
-  tmp_list = fcfont->metrics_by_lang;
-  while (tmp_list)
-    {
-      info = tmp_list->data;
 
-      if (info->sample_str == sample_str)    /* We _don't_ need strcmp */
-	break;
-
-      tmp_list = tmp_list->next;
-    }
-
-  if (!tmp_list)
-    {
-      PangoContext *context;
-      int height, shift;
-
-      if (!fcfont->fontmap)
-	return pango_font_metrics_new ();
-
-      info = g_slice_new0 (PangoFcMetricsInfo);
-
-      fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang, info);
-
-      info->sample_str = sample_str;
-
-      context = pango_fc_font_map_create_context (PANGO_FC_FONT_MAP (fcfont->fontmap));
-      pango_context_set_language (context, language);
-      pango_cairo_context_set_font_options (context, cffont->options);
-
-      info->metrics = pango_fc_font_create_metrics_for_context (fcfont, context);
-      /* We may actually reuse ascent/descent we got from cairo here.  that's
-       * in cffont->font_extents.
-       */
-      height = info->metrics->ascent + info->metrics->descent;
-      switch (cffont->gravity)
-	{
-	  default:
-	  case PANGO_GRAVITY_AUTO:
-	  case PANGO_GRAVITY_SOUTH:
-	    break;
-	  case PANGO_GRAVITY_NORTH:
-	    info->metrics->ascent = info->metrics->descent;
-	    break;
-	  case PANGO_GRAVITY_EAST:
-	  case PANGO_GRAVITY_WEST:
-	    {
-	      int ascent = height / 2;
-	      if (fcfont->is_hinted)
-	        ascent = PANGO_UNITS_ROUND (ascent);
-	      info->metrics->ascent = ascent;
-	    }
-	}
-      shift = (height - info->metrics->ascent) - info->metrics->descent;
-      info->metrics->descent += shift;
-      info->metrics->underline_position -= shift;
-      info->metrics->strikethrough_position -= shift;
-      info->metrics->ascent = height - info->metrics->descent;
-
-      g_object_unref (context);
-    }
-
-  return pango_font_metrics_ref (info->metrics);
+  _pango_cairo_font_private_get_glyph_extents (&cffont->cf_priv,
+					       glyph,
+					       ink_rect,
+					       logical_rect);
 }
 
 static FT_Face
 pango_cairo_fc_font_lock_face (PangoFcFont *font)
 {
-  PangoCairoFont *cfont = (PangoCairoFont *)font;
-  cairo_scaled_font_t *scaled_font = pango_cairo_fc_font_get_scaled_font (cfont);
+  PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
+  cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (&cffont->cf_priv);
+
   if (G_UNLIKELY (!scaled_font))
     return NULL;
 
@@ -278,8 +127,9 @@ pango_cairo_fc_font_lock_face (PangoFcFo
 static void
 pango_cairo_fc_font_unlock_face (PangoFcFont *font)
 {
-  PangoCairoFont *cfont = (PangoCairoFont *)font;
-  cairo_scaled_font_t *scaled_font = pango_cairo_fc_font_get_scaled_font (cfont);
+  PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
+  cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (&cffont->cf_priv);
+
   if (G_UNLIKELY (!scaled_font))
     return;
 
@@ -287,146 +137,11 @@ pango_cairo_fc_font_unlock_face (PangoFc
 }
 
 static void
-pango_cairo_fc_font_glyph_extents_cache_init (PangoCairoFcFont *cffont)
-{
-  PangoCairoFont *cfont = (PangoCairoFont *)cffont;
-  cairo_scaled_font_t *scaled_font = pango_cairo_fc_font_get_scaled_font (cfont);
-  cairo_font_extents_t font_extents;
-
-  cairo_scaled_font_extents (scaled_font, &font_extents);
-
-  cffont->font_extents.x = 0;
-  cffont->font_extents.width = 0;
-  cffont->font_extents.height = pango_units_from_double (font_extents.ascent + font_extents.descent);
-  switch (cffont->gravity)
-    {
-      default:
-      case PANGO_GRAVITY_AUTO:
-      case PANGO_GRAVITY_SOUTH:
-	cffont->font_extents.y = - pango_units_from_double (font_extents.ascent);
-	break;
-      case PANGO_GRAVITY_NORTH:
-	cffont->font_extents.y = - pango_units_from_double (font_extents.descent);
-	break;
-      case PANGO_GRAVITY_EAST:
-      case PANGO_GRAVITY_WEST:
-	{
-	  PangoFcFont *fcfont = (PangoFcFont *) (cffont);
-	  int ascent = pango_units_from_double (font_extents.ascent + font_extents.descent) / 2;
-	  if (fcfont->is_hinted)
-	    ascent = PANGO_UNITS_ROUND (ascent);
-	  cffont->font_extents.y = - ascent;
-	}
-    }
-
-  cffont->glyph_extents_cache = g_new0 (GlyphExtentsCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
-  /* Make sure all cache entries are invalid initially */
-  cffont->glyph_extents_cache[0].glyph = 1; /* glyph 1 cannot happen in bucket 0 */
-}
-
-/* Fills in the glyph extents cache entry
- */
-static void
-compute_glyph_extents (PangoCairoFcFont       *cffont,
-		       PangoGlyph              glyph,
-		       GlyphExtentsCacheEntry *entry)
-{
-  cairo_text_extents_t extents;
-  cairo_glyph_t cairo_glyph;
-
-  cairo_glyph.index = glyph;
-  cairo_glyph.x = 0;
-  cairo_glyph.y = 0;
-
-  cairo_scaled_font_glyph_extents (cffont->scaled_font,
-				   &cairo_glyph, 1, &extents);
-
-  entry->glyph = glyph;
-  entry->width = pango_units_from_double (extents.x_advance);
-  entry->ink_rect.x = pango_units_from_double (extents.x_bearing);
-  entry->ink_rect.y = pango_units_from_double (extents.y_bearing);
-  entry->ink_rect.width = pango_units_from_double (extents.width);
-  entry->ink_rect.height = pango_units_from_double (extents.height);
-}
-
-static GlyphExtentsCacheEntry *
-pango_cairo_fc_font_get_glyph_extents_cache_entry (PangoCairoFcFont       *cffont,
-						   PangoGlyph              glyph)
-{
-  GlyphExtentsCacheEntry *entry;
-  guint idx;
-
-  idx = glyph & GLYPH_CACHE_MASK;
-  entry = cffont->glyph_extents_cache + idx;
-
-  if (entry->glyph != glyph)
-    {
-      compute_glyph_extents (cffont, glyph, entry);
-    }
-
-  return entry;
-}
-
-static void
-pango_cairo_fc_font_get_glyph_extents (PangoFont      *font,
-				       PangoGlyph      glyph,
-				       PangoRectangle *ink_rect,
-				       PangoRectangle *logical_rect)
-{
-  PangoCairoFcFont *cffont = (PangoCairoFcFont *)font;
-  GlyphExtentsCacheEntry *entry;
-
-  if (!pango_cairo_fc_font_get_scaled_font ((PangoCairoFont *)cffont))
-    {
-      /* Get generic unknown-glyph extents. */
-      pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
-      return;
-    }
-
-  /* We need to initialize the cache here, since we use cffont->font_extents
-   */
-  if (cffont->glyph_extents_cache == NULL)
-    pango_cairo_fc_font_glyph_extents_cache_init (cffont);
-
-  if (glyph == PANGO_GLYPH_EMPTY)
-    {
-      if (ink_rect)
-	ink_rect->x = ink_rect->y = ink_rect->width = ink_rect->height = 0;
-      if (logical_rect)
-	*logical_rect = cffont->font_extents;
-      return;
-    }
-  else if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
-    {
-      _pango_cairo_get_glyph_extents_missing((PangoCairoFont *)font, glyph, ink_rect, logical_rect);
-      return;
-    }
-
-  entry = pango_cairo_fc_font_get_glyph_extents_cache_entry (cffont, glyph);
-
-  if (ink_rect)
-    *ink_rect = entry->ink_rect;
-  if (logical_rect)
-    {
-      *logical_rect = cffont->font_extents;
-      logical_rect->width = entry->width;
-    }
-}
-
-static void
 pango_cairo_fc_font_shutdown (PangoFcFont *fcfont)
 {
   PangoCairoFcFont *cffont = (PangoCairoFcFont *) (fcfont);
-  if (cffont->scaled_font)
-    {
-      cairo_scaled_font_destroy (cffont->scaled_font);
-      cffont->scaled_font = NULL;
-    }
-  if (cffont->font_face)
-    {
-      cairo_font_face_destroy (cffont->font_face);
-      cffont->font_face = NULL;
-    }
+
+  _pango_cairo_font_private_finalize (&cffont->cf_priv);
 }
 
 static void
@@ -439,7 +154,7 @@ pango_cairo_fc_font_class_init (PangoCai
   object_class->finalize = pango_cairo_fc_font_finalize;
 
   font_class->get_glyph_extents = pango_cairo_fc_font_get_glyph_extents;
-  font_class->get_metrics = pango_cairo_fc_font_get_metrics;
+  font_class->get_metrics = _pango_cairo_font_get_metrics;
 
   fc_font_class->lock_face = pango_cairo_fc_font_lock_face;
   fc_font_class->unlock_face = pango_cairo_fc_font_unlock_face;
@@ -459,8 +174,7 @@ static double
 get_font_size (PangoCairoFcFontMap        *cffontmap,
 	       PangoContext               *context,
 	       const PangoFontDescription *desc,
-	       FcPattern                  *pattern,
-	       const PangoMatrix          *matrix)
+	       FcPattern                  *pattern)
 {
   double size;
 
@@ -478,7 +192,7 @@ get_font_size (PangoCairoFcFontMap      
   */
 
   if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
-    return size * PANGO_SCALE / pango_matrix_get_font_scale_factor (matrix);
+    return size * PANGO_SCALE / pango_matrix_get_font_scale_factor (pango_context_get_matrix (context));
 
   /* Just in case FC_PIXEL_SIZE got unset between pango_fc_make_pattern()
    * and here.
@@ -503,7 +217,7 @@ _pango_cairo_fc_font_new (PangoCairoFcFo
 			  FcPattern	             *pattern)
 {
   PangoCairoFcFont *cffont;
-  const PangoMatrix *pango_ctm;
+  cairo_matrix_t font_matrix;
   FcMatrix *fc_matrix;
   double size;
 
@@ -514,56 +228,29 @@ _pango_cairo_fc_font_new (PangoCairoFcFo
 			 "pattern", pattern,
 			 NULL);
 
-  cffont->gravity = pango_font_description_get_gravity (desc);
-
-  /* first apply gravity rotation, then pattern matrix, such that
-   * vertical italic text comes out "correct".  we don't do anything
-   * like baseline adjustment etc though.  should be specially
-   * handled when we support italic correction. */
-  cairo_matrix_init_rotate(&cffont->font_matrix,
-			  pango_gravity_to_rotation (cffont->gravity));
+  size = get_font_size (cffontmap, context, desc, pattern);
 
   if  (FcPatternGetMatrix (pattern,
 			   FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
-    {
-      cairo_matrix_t matrix;
-
-      cairo_matrix_init (&matrix,
-			 fc_matrix->xx,
-			 - fc_matrix->yx,
-			 - fc_matrix->xy,
-			 fc_matrix->yy,
-			 0., 0.);
-
-      cairo_matrix_multiply (&cffont->font_matrix,
-			     &matrix,
-			     &cffont->font_matrix);
-    }
-
-  pango_ctm = pango_context_get_matrix (context);
-
-  size = get_font_size (cffontmap, context, desc, pattern, pango_ctm);
-
-  cairo_matrix_scale (&cffont->font_matrix,
-		      size / PANGO_SCALE, size / PANGO_SCALE);
-
-  if (pango_ctm)
-    cairo_matrix_init (&cffont->ctm,
-		       pango_ctm->xx,
-		       pango_ctm->yx,
-		       pango_ctm->xy,
-		       pango_ctm->yy,
+    cairo_matrix_init (&font_matrix,
+		       fc_matrix->xx,
+		       - fc_matrix->yx,
+		       - fc_matrix->xy,
+		       fc_matrix->yy,
 		       0., 0.);
   else
-    cairo_matrix_init_identity (&cffont->ctm);
+    cairo_matrix_init_identity (&font_matrix);
 
+  cairo_matrix_scale (&font_matrix,
+		      size / PANGO_SCALE, size / PANGO_SCALE);
 
-  cffont->options = cairo_font_options_copy (_pango_cairo_context_get_merged_font_options (context));
+  _pango_cairo_font_private_initialize (&cffont->cf_priv,
+					(PangoCairoFont *) cffont,
+					context,
+					desc,
+					&font_matrix);
 
-  /* fcfont's is_hinted controls metric hinting
-   */
-  ((PangoFcFont *)(cffont))->is_hinted =
-    (cairo_font_options_get_hint_metrics(cffont->options) != CAIRO_HINT_METRICS_OFF);
+  ((PangoFcFont *)(cffont))->is_hinted = _pango_cairo_font_private_is_metrics_hinted (&cffont->cf_priv);
 
-  return (PangoFcFont *) (cffont);
+  return (PangoFcFont *) cffont;
 }
Index: pango/pangocairo-private.h
===================================================================
--- pango/pangocairo-private.h	(revision 2325)
+++ pango/pangocairo-private.h	(working copy)
@@ -27,6 +27,7 @@
 
 G_BEGIN_DECLS
 
+
 #define PANGO_CAIRO_FONT_MAP_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PANGO_TYPE_CAIRO_FONT_MAP, PangoCairoFontMapIface))
 
 typedef struct _PangoCairoFontMapIface PangoCairoFontMapIface;
@@ -38,10 +39,8 @@ struct _PangoCairoFontMapIface
   void           (*set_resolution) (PangoCairoFontMap *fontmap,
 				    double             dpi);
   double         (*get_resolution) (PangoCairoFontMap *fontmap);
-  PangoRenderer *(*get_renderer)   (PangoCairoFontMap *fontmap);
 };
 
-PangoRenderer *_pango_cairo_font_map_get_renderer (PangoCairoFontMap *cfontmap);
 
 #define PANGO_CAIRO_FONT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PANGO_TYPE_CAIRO_FONT, PangoCairoFontIface))
 
@@ -49,27 +48,82 @@ PangoRenderer *_pango_cairo_font_map_get
 #define PANGO_CAIRO_FONT(object)    (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CAIRO_FONT, PangoCairoFont))
 #define PANGO_IS_CAIRO_FONT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CAIRO_FONT))
 
-typedef struct _PangoCairoFont      PangoCairoFont;
-typedef struct _PangoCairoFontIface PangoCairoFontIface;
+typedef struct _PangoCairoFont                       PangoCairoFont;
+typedef struct _PangoCairoFontIface                  PangoCairoFontIface;
+typedef struct _PangoCairoFontPrivate                PangoCairoFontPrivate;
+typedef struct _PangoCairoFontHexBoxInfo             PangoCairoFontHexBoxInfo;
+typedef struct _PangoCairoFontPrivateScaledFontData  PangoCairoFontPrivateScaledFontData;
+typedef struct _PangoCairoFontGlyphExtentsCacheEntry PangoCairoFontGlyphExtentsCacheEntry;
+
+struct _PangoCairoFontHexBoxInfo
+{
+  PangoCairoFont *font;
+  int rows;
+  double digit_width;
+  double digit_height;
+  double pad_x;
+  double pad_y;
+  double line_width;
+  double box_descent;
+  double box_height;
+};
+
+struct _PangoCairoFontPrivateScaledFontData
+{
+  cairo_matrix_t font_matrix;
+  cairo_matrix_t ctm;
+  cairo_font_options_t *options;
+};
+
+struct _PangoCairoFontPrivate
+{
+  PangoCairoFont *cfont;
+   
+  PangoCairoFontPrivateScaledFontData *data;
+
+  cairo_scaled_font_t *scaled_font;
+  PangoCairoFontHexBoxInfo *hbi;
+
+  gboolean is_hinted;
+  PangoGravity gravity;
+
+  PangoRectangle font_extents;
+  PangoCairoFontGlyphExtentsCacheEntry *glyph_extents_cache;
+
+  GSList *metrics_by_lang;
+};
 
 struct _PangoCairoFontIface
 {
   GTypeInterface g_iface;
 
-  gboolean (*install) (PangoCairoFont *font,
-		       cairo_t        *cr);
-
-  cairo_font_face_t *(*get_font_face) (PangoCairoFont *font);
+  cairo_font_face_t *(*create_font_face) (PangoCairoFont *cfont);
+  PangoFontMetrics *(*create_metrics_for_context) (PangoCairoFont *cfont,
+						   PangoContext   *context);
 
-  cairo_scaled_font_t *(*get_scaled_font) (PangoCairoFont *font);
+  gssize cf_priv_offset;
 };
 
 GType pango_cairo_font_get_type (void);
 
-gboolean _pango_cairo_font_install (PangoCairoFont *font,
-				    cairo_t        *cr);
-cairo_font_face_t *_pango_cairo_font_get_font_face (PangoCairoFont *font);
-cairo_scaled_font_t *_pango_cairo_font_get_scaled_font (PangoCairoFont *font);
+gboolean _pango_cairo_font_install (PangoFont *font,
+				    cairo_t   *cr);
+PangoFontMetrics * _pango_cairo_font_get_metrics (PangoFont     *font,
+						  PangoLanguage *language);
+PangoCairoFontHexBoxInfo *_pango_cairo_font_get_hex_box_info (PangoCairoFont *cfont);
+
+void _pango_cairo_font_private_initialize (PangoCairoFontPrivate      *cf_priv,
+					   PangoCairoFont             *font,
+					   PangoContext               *context,
+					   const PangoFontDescription *desc,
+					   const cairo_matrix_t       *font_matrix);
+void _pango_cairo_font_private_finalize (PangoCairoFontPrivate *cf_priv);
+cairo_scaled_font_t *_pango_cairo_font_private_get_scaled_font (PangoCairoFontPrivate *cf_priv);
+gboolean _pango_cairo_font_private_is_metrics_hinted (PangoCairoFontPrivate *cf_priv);
+void _pango_cairo_font_private_get_glyph_extents (PangoCairoFontPrivate *cf_priv,
+						  PangoGlyph             glyph,
+						  PangoRectangle        *ink_rect,
+						  PangoRectangle        *logical_rect);
 
 #define PANGO_TYPE_CAIRO_RENDERER            (pango_cairo_renderer_get_type())
 #define PANGO_CAIRO_RENDERER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CAIRO_RENDERER, PangoCairoRenderer))
@@ -79,35 +133,13 @@ typedef struct _PangoCairoRenderer Pango
 
 GType pango_cairo_renderer_get_type    (void);
 
-const cairo_font_options_t *_pango_cairo_context_get_merged_font_options (PangoContext *context);
-
 
-typedef struct _PangoCairoHexBoxInfo PangoCairoHexBoxInfo;
+const cairo_font_options_t *_pango_cairo_context_get_merged_font_options (PangoContext *context);
 
-struct _PangoCairoHexBoxInfo
-{
-	PangoFont *font;
-	int rows;
-	double digit_width;
-	double digit_height;
-	double pad_x;
-	double pad_y;
-	double line_width;
-	double box_descent;
-	double box_height;
-};
-
-PangoCairoHexBoxInfo *_pango_cairo_font_get_hex_box_info (PangoCairoFont *font);
-
-void _pango_cairo_get_glyph_extents_missing (PangoCairoFont *cfont,
-					     PangoGlyph      glyph,
-					     PangoRectangle *ink_rect,
-					     PangoRectangle *logical_rect);
 
 typedef struct _PangoCairoWarningHistory PangoCairoWarningHistory;
 
 struct _PangoCairoWarningHistory {
-  guint font_install		: 1;
   guint font_get_scaled_font	: 1;
 };
 
Index: pango/pangocairo-fcfontmap.c
===================================================================
--- pango/pangocairo-fcfontmap.c	(revision 2325)
+++ pango/pangocairo-fcfontmap.c	(working copy)
@@ -52,23 +52,11 @@ pango_cairo_fc_font_map_get_resolution_c
   return cffontmap->dpi;
 }
 
-static PangoRenderer *
-pango_cairo_fc_font_map_get_renderer (PangoCairoFontMap *cfontmap)
-{
-  PangoCairoFcFontMap *cffontmap = (PangoCairoFcFontMap *) (cfontmap);
-
-  if (!cffontmap->renderer)
-    cffontmap->renderer = g_object_new (PANGO_TYPE_CAIRO_RENDERER, NULL);
-
-  return cffontmap->renderer;
-}
-
 static void
 cairo_font_map_iface_init (PangoCairoFontMapIface *iface)
 {
   iface->set_resolution = pango_cairo_fc_font_map_set_resolution;
   iface->get_resolution = pango_cairo_fc_font_map_get_resolution_cairo;
-  iface->get_renderer = pango_cairo_fc_font_map_get_renderer;
 }
 
 G_DEFINE_TYPE_WITH_CODE (PangoCairoFcFontMap, pango_cairo_fc_font_map, PANGO_TYPE_FC_FONT_MAP,
Index: pango/pangocairo-render.c
===================================================================
--- pango/pangocairo-render.c	(revision 2325)
+++ pango/pangocairo-render.c	(working copy)
@@ -128,7 +128,7 @@ _pango_cairo_renderer_draw_unknown_glyph
   int rows, cols;
   char hexbox_string[2] = {0, 0};
   double temp_x, temp_y;
-  PangoCairoHexBoxInfo *hbi;
+  PangoCairoFontHexBoxInfo *hbi;
   gunichar ch;
 
   cairo_save (crenderer->cr);
@@ -136,7 +136,7 @@ _pango_cairo_renderer_draw_unknown_glyph
 
   hbi = _pango_cairo_font_get_hex_box_info ((PangoCairoFont *)font);
 
-  if (!hbi || !_pango_cairo_font_install ((PangoCairoFont *) (hbi->font), crenderer->cr))
+  if (!hbi || !_pango_cairo_font_install ((PangoFont *)(hbi->font), crenderer->cr))
     {
       _pango_cairo_renderer_draw_box_glyph (crenderer, gi, cx, cy);
       goto done;
@@ -204,7 +204,7 @@ pango_cairo_renderer_draw_glyphs (PangoR
   if (!crenderer->do_path)
     set_color (crenderer, PANGO_RENDER_PART_FOREGROUND);
 
-  if (!_pango_cairo_font_install ((PangoCairoFont *) (font), crenderer->cr))
+  if (!_pango_cairo_font_install (font, crenderer->cr))
     {
       for (i = 0; i < glyphs->num_glyphs; i++)
 	{
@@ -455,8 +455,6 @@ acquire_renderer (gboolean *free_rendere
 {
   PangoCairoRenderer *renderer;
 
-  /* renderer = _pango_cairo_font_map_get_renderer (PANGO_CAIRO_FONT_MAP (fontmap)); */
-
   if (G_LIKELY (G_TRYLOCK (cached_renderer)))
     {
       if (G_UNLIKELY (!cached_renderer))
Index: pango/pangocairo-font.c
===================================================================
--- pango/pangocairo-font.c	(revision 2332)
+++ pango/pangocairo-font.c	(working copy)
@@ -29,6 +29,12 @@
 
 PangoCairoWarningHistory _pango_cairo_warning_history = { FALSE };
 
+#define PANGO_CAIRO_FONT_PRIVATE(font)		\
+  ((PangoCairoFontPrivate *)			\
+   (font == NULL ? NULL :			\
+    G_STRUCT_MEMBER_P (font,			\
+    PANGO_CAIRO_FONT_GET_IFACE(PANGO_CAIRO_FONT(font))->cf_priv_offset)))
+
 GType
 pango_cairo_font_get_type (void)
 {
@@ -60,45 +66,86 @@ pango_cairo_font_get_type (void)
   return cairo_font_type;
 }
 
-/**
- * _pango_cairo_font_install:
- * @font: a #PangoCairoFont
- * @cr: a #cairo_t
- *
- * Makes @font the current font for rendering in the specified
- * Cairo context.
- **/
-gboolean
-_pango_cairo_font_install (PangoCairoFont *font,
-			   cairo_t        *cr)
+static PangoCairoFontPrivateScaledFontData *
+_pango_cairo_font_private_scaled_font_data_create (void)
+{
+  return g_slice_new (PangoCairoFontPrivateScaledFontData);
+}
+
+static void
+_pango_cairo_font_private_scaled_font_data_destroy (PangoCairoFontPrivateScaledFontData *data)
 {
-  if (G_UNLIKELY (!PANGO_IS_CAIRO_FONT (font)))
+  cairo_font_options_destroy (data->options);
+  g_slice_free (PangoCairoFontPrivateScaledFontData, data);
+}
+
+cairo_scaled_font_t *
+_pango_cairo_font_private_get_scaled_font (PangoCairoFontPrivate *cf_priv)
+{
+  cairo_font_face_t *font_face;
+
+  if (G_LIKELY (cf_priv->scaled_font))
+    return cf_priv->scaled_font;
+
+  /* need to create it */
+
+  if (G_UNLIKELY (cf_priv->data == NULL))
     {
-      if (!_pango_cairo_warning_history.font_install)
+      /* we have tried to create and failed before */
+      return NULL;
+    }
+
+  font_face = (* PANGO_CAIRO_FONT_GET_IFACE (cf_priv->cfont)->create_font_face) (cf_priv->cfont);
+  if (G_UNLIKELY (font_face == NULL))
+    goto done;
+
+  cf_priv->scaled_font = cairo_scaled_font_create (font_face,
+						   &cf_priv->data->font_matrix,
+						   &cf_priv->data->ctm,
+						   cf_priv->data->options);
+
+  cairo_font_face_destroy (font_face);
+
+done:
+  _pango_cairo_font_private_scaled_font_data_destroy (cf_priv->data);
+  cf_priv->data = NULL;
+
+  if (G_UNLIKELY (cf_priv->scaled_font == NULL || cairo_scaled_font_status (cf_priv->scaled_font) != CAIRO_STATUS_SUCCESS))
+    {
+      PangoFont *font = PANGO_FONT (cf_priv->cfont);
+      static GQuark warned_quark = 0;
+      if (!warned_quark)
+	warned_quark = g_quark_from_static_string ("pangocairo-scaledfont-warned");
+
+      if (!g_object_get_qdata (G_OBJECT (font), warned_quark))
 	{
-	  _pango_cairo_warning_history.font_install = TRUE;
-	  g_warning ("_pango_cairo_font_install called with bad font, expect ugly output");
-	  cairo_set_font_face (cr, NULL);
+	  PangoFontDescription *desc;
+	  char *s;
+
+	  desc = pango_font_describe (font);
+	  s = pango_font_description_to_string (desc);
+	  pango_font_description_free (desc);
+
+	  g_warning ("failed to create cairo %s, expect ugly output. the offending font is '%s'",
+		     font_face ? "scaled font" : "font face",
+		     s);
+
+	  g_free (s);
+
+	  g_object_set_qdata_full (G_OBJECT (font), warned_quark,
+				   GINT_TO_POINTER (1), NULL);
 	}
-      return FALSE;
     }
 
-  return (* PANGO_CAIRO_FONT_GET_IFACE (font)->install) (font, cr);
+  return cf_priv->scaled_font;
 }
 
-cairo_font_face_t *
-_pango_cairo_font_get_font_face (PangoCairoFont *font)
+static cairo_scaled_font_t *
+_pango_cairo_font_get_scaled_font (PangoFont *cfont)
 {
-  g_return_val_if_fail (PANGO_IS_CAIRO_FONT (font), NULL);
-  /* this function will be removed.  don't bother with warning history here */
-
-  return (* PANGO_CAIRO_FONT_GET_IFACE (font)->get_font_face) (font);
-}
+  PangoCairoFontPrivate *cf_priv;
 
-cairo_scaled_font_t *
-_pango_cairo_font_get_scaled_font (PangoCairoFont *font)
-{
-  if (G_UNLIKELY (!PANGO_IS_CAIRO_FONT (font)))
+  if (G_UNLIKELY (!PANGO_IS_CAIRO_FONT (cfont)))
     {
       if (!_pango_cairo_warning_history.font_get_scaled_font)
 	{
@@ -108,27 +155,126 @@ _pango_cairo_font_get_scaled_font (Pango
       return NULL;
     }
 
-  return (* PANGO_CAIRO_FONT_GET_IFACE (font)->get_scaled_font) (font);
+  cf_priv = PANGO_CAIRO_FONT_PRIVATE (cfont);
+
+  return _pango_cairo_font_private_get_scaled_font (cf_priv);
 }
 
-static void
-_pango_cairo_hex_box_info_destroy (PangoCairoHexBoxInfo *hbi)
+/**
+ * _pango_cairo_font_install:
+ * @font: a #PangoCairoFont
+ * @cr: a #cairo_t
+ *
+ * Makes @font the current font for rendering in the specified
+ * Cairo context.
+ *
+ * Return value: %TRUE if font was installed successfully, %FALSE otherwise.
+ **/
+gboolean
+_pango_cairo_font_install (PangoFont *font,
+			   cairo_t   *cr)
 {
-  if (hbi)
+  cairo_scaled_font_t *scaled_font = _pango_cairo_font_get_scaled_font (font);
+
+  if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
+    return FALSE;
+
+  cairo_set_scaled_font (cr, scaled_font);
+
+  return TRUE;
+}
+
+
+typedef struct _PangoCairoFontMetricsInfo
+{
+  const char       *sample_str;
+  PangoFontMetrics *metrics;
+} PangoCairoFontMetricsInfo;
+
+PangoFontMetrics *
+_pango_cairo_font_get_metrics (PangoFont     *font,
+			       PangoLanguage *language)
+{
+  PangoCairoFont *cfont = (PangoCairoFont *) font;
+  PangoCairoFontPrivate *cf_priv = PANGO_CAIRO_FONT_PRIVATE (font);
+  PangoCairoFontMetricsInfo *info = NULL; /* Quiet gcc */
+  GSList *tmp_list;
+
+  const char *sample_str = pango_language_get_sample_string (language);
+
+  tmp_list = cf_priv->metrics_by_lang;
+  while (tmp_list)
     {
-      g_object_unref (hbi->font);
-      g_slice_free (PangoCairoHexBoxInfo, hbi);
+      info = tmp_list->data;
+
+      if (info->sample_str == sample_str)    /* We _don't_ need strcmp */
+	break;
+
+      tmp_list = tmp_list->next;
     }
+
+  if (!tmp_list)
+    {
+      PangoContext *context;
+      cairo_font_options_t *font_options;
+      int height, shift;
+
+      info = g_slice_new0 (PangoCairoFontMetricsInfo);
+
+      cf_priv->metrics_by_lang = g_slist_prepend (cf_priv->metrics_by_lang, info);
+
+      info->sample_str = sample_str;
+
+      context = pango_cairo_font_map_create_context ((PangoCairoFontMap *) pango_font_get_font_map (font));
+      pango_context_set_language (context, language);
+      font_options = cairo_font_options_create ();
+      cairo_scaled_font_get_font_options (_pango_cairo_font_private_get_scaled_font (cf_priv), font_options);
+      pango_cairo_context_set_font_options (context, font_options);
+      cairo_font_options_destroy (font_options);
+
+      info->metrics = (* PANGO_CAIRO_FONT_GET_IFACE (font)->create_metrics_for_context) (cfont, context);
+
+      /* We may actually reuse ascent/descent we got from cairo here.  that's
+       * in cf_priv->font_extents.
+       */
+      height = info->metrics->ascent + info->metrics->descent;
+      switch (cf_priv->gravity)
+	{
+	  default:
+	  case PANGO_GRAVITY_AUTO:
+	  case PANGO_GRAVITY_SOUTH:
+	    break;
+	  case PANGO_GRAVITY_NORTH:
+	    info->metrics->ascent = info->metrics->descent;
+	    break;
+	  case PANGO_GRAVITY_EAST:
+	  case PANGO_GRAVITY_WEST:
+	    {
+	      int ascent = height / 2;
+	      if (cf_priv->is_hinted)
+	        ascent = PANGO_UNITS_ROUND (ascent);
+	      info->metrics->ascent = ascent;
+	    }
+	}
+      shift = (height - info->metrics->ascent) - info->metrics->descent;
+      info->metrics->descent += shift;
+      info->metrics->underline_position -= shift;
+      info->metrics->strikethrough_position -= shift;
+      info->metrics->ascent = height - info->metrics->descent;
+
+      g_object_unref (context);
+    }
+
+  return pango_font_metrics_ref (info->metrics);
 }
 
-PangoCairoHexBoxInfo *
-_pango_cairo_font_get_hex_box_info (PangoCairoFont *cfont)
+static PangoCairoFontHexBoxInfo *
+_pango_cairo_font_private_get_hex_box_info (PangoCairoFontPrivate *cf_priv)
 {
   static const char hexdigits[] = "0123456789ABCDEF";
   char c[2] = {0, 0};
   PangoFont *mini_font;
-  PangoCairoFont *mini_cfont;
-  PangoCairoHexBoxInfo *hbi;
+  PangoCairoFontHexBoxInfo *hbi;
 
   /* for metrics hinting */
   double scale_x = 1., scale_x_inv = 1., scale_y = 1., scale_y_inv = 1.;
@@ -148,24 +294,20 @@ _pango_cairo_font_get_hex_box_info (Pang
   cairo_matrix_t cairo_ctm;
   PangoGravity gravity;
 
-  if (!cfont)
+  if (!cf_priv)
     return NULL;
 
-  hbi = (PangoCairoHexBoxInfo *) g_object_get_data (G_OBJECT (cfont), "hex_box_info");
-  if (hbi)
-    return hbi;
+  if (cf_priv->hbi)
+    return cf_priv->hbi;
 
-  scaled_font = _pango_cairo_font_get_scaled_font (cfont);
-  if (!scaled_font)
-    {
-      g_object_set_data_full (G_OBJECT (cfont), "hex_box_info", NULL, NULL);
-      return NULL;
-    }
+  scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv);
+  if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
+    return NULL;
+
+  is_hinted = cf_priv->is_hinted;
 
   font_options = cairo_font_options_create ();
-  cairo_scaled_font_get_font_options (scaled_font, font_options);
-  is_hinted = (cairo_font_options_get_hint_metrics(font_options) != CAIRO_HINT_METRICS_OFF);
-  desc = pango_font_describe_with_absolute_size ((PangoFont *)cfont);
+  desc = pango_font_describe_with_absolute_size ((PangoFont *)cf_priv->cfont);
   size = pango_font_description_get_size (desc) / (1.*PANGO_SCALE);
   gravity = pango_font_description_get_gravity (desc);
 
@@ -208,7 +350,7 @@ _pango_cairo_font_get_hex_box_info (Pang
     PangoContext *context;
     PangoFontMap *fontmap;
 
-    fontmap = pango_font_get_font_map ((PangoFont *)cfont);
+    fontmap = pango_font_get_font_map ((PangoFont *)cf_priv->cfont);
 
     /* we inherit most font properties for the mini font.  just
      * change family and size.  means, you get bold hex digits
@@ -233,8 +375,7 @@ _pango_cairo_font_get_hex_box_info (Pang
 	  }
       }
 
-    pango_font_description_set_absolute_size (desc, mini_size * PANGO_SCALE);
-
+    pango_font_description_set_absolute_size (desc, pango_units_from_double (mini_size));
 
     /* load mini_font */
 
@@ -251,8 +392,7 @@ _pango_cairo_font_get_hex_box_info (Pang
   cairo_font_options_destroy (font_options);
 
 
-  mini_cfont = (PangoCairoFont *) mini_font;
-  scaled_mini_font = _pango_cairo_font_get_scaled_font (mini_cfont);
+  scaled_mini_font = _pango_cairo_font_get_scaled_font (mini_font);
 
   for (i = 0 ; i < 16 ; i++)
     {
@@ -274,8 +414,8 @@ _pango_cairo_font_get_hex_box_info (Pang
   pad = (font_extents.ascent + font_extents.descent) / 43;
   pad = MIN (pad, mini_size);
 
-  hbi = g_slice_new (PangoCairoHexBoxInfo);
-  hbi->font = mini_font;
+  hbi = g_slice_new (PangoCairoFontHexBoxInfo);
+  hbi->font = (PangoCairoFont *) mini_font;
   hbi->rows = rows;
 
   hbi->digit_width  = width;
@@ -314,21 +454,114 @@ _pango_cairo_font_get_hex_box_info (Pang
        hbi->box_descent = HINT_Y (hbi->box_descent);
     }
 
-  g_object_set_data_full (G_OBJECT (cfont), "hex_box_info", hbi, (GDestroyNotify)_pango_cairo_hex_box_info_destroy);
-
   return hbi;
 }
 
+static void
+_pango_cairo_font_hex_box_info_destroy (PangoCairoFontHexBoxInfo *hbi)
+{
+  if (hbi)
+    {
+      g_object_unref (hbi->font);
+      g_slice_free (PangoCairoFontHexBoxInfo, hbi);
+    }
+}
+
+PangoCairoFontHexBoxInfo *
+_pango_cairo_font_get_hex_box_info (PangoCairoFont *cfont)
+{
+  PangoCairoFontPrivate *cf_priv = PANGO_CAIRO_FONT_PRIVATE (cfont);
+
+  return _pango_cairo_font_private_get_hex_box_info (cf_priv);
+}
+
 void
-_pango_cairo_get_glyph_extents_missing (PangoCairoFont *cfont,
-					PangoGlyph      glyph,
-					PangoRectangle *ink_rect,
-					PangoRectangle *logical_rect)
+_pango_cairo_font_private_initialize (PangoCairoFontPrivate      *cf_priv,
+				      PangoCairoFont             *cfont,
+				      PangoContext               *context,
+				      const PangoFontDescription *desc,
+				      const cairo_matrix_t       *font_matrix)
 {
-  PangoCairoHexBoxInfo *hbi;
+  const cairo_font_options_t *font_options;
+  cairo_matrix_t gravity_matrix;
+  const PangoMatrix *pango_ctm;
+
+  cf_priv->cfont = cfont;
+  cf_priv->gravity = pango_font_description_get_gravity (desc);
+
+  cf_priv->data = _pango_cairo_font_private_scaled_font_data_create (); 
+
+  /* first apply gravity rotation, then font_matrix, such that
+   * vertical italic text comes out "correct".  we don't do anything
+   * like baseline adjustment etc though.  should be specially
+   * handled when we support italic correction. */
+  cairo_matrix_init_rotate(&gravity_matrix,
+			   pango_gravity_to_rotation (cf_priv->gravity));
+  cairo_matrix_multiply (&cf_priv->data->font_matrix,
+			 font_matrix,
+			 &gravity_matrix);
+
+  pango_ctm = pango_context_get_matrix (context);
+  if (pango_ctm)
+    cairo_matrix_init (&cf_priv->data->ctm,
+		       pango_ctm->xx,
+		       pango_ctm->yx,
+		       pango_ctm->xy,
+		       pango_ctm->yy,
+		       0., 0.);
+  else
+    cairo_matrix_init_identity (&cf_priv->data->ctm);
+
+  font_options = _pango_cairo_context_get_merged_font_options (context);
+  cf_priv->data->options = cairo_font_options_copy (font_options);
+  cf_priv->is_hinted = cairo_font_options_get_hint_metrics (font_options) != CAIRO_HINT_METRICS_OFF;
+
+  cf_priv->scaled_font = NULL;
+  cf_priv->hbi = NULL;
+  cf_priv->glyph_extents_cache = NULL;
+  cf_priv->metrics_by_lang = NULL;
+}
+
+static void
+free_metrics_info (PangoCairoFontMetricsInfo *info)
+{
+  pango_font_metrics_unref (info->metrics);
+  g_slice_free (PangoCairoFontMetricsInfo, info);
+}
+
+void
+_pango_cairo_font_private_finalize (PangoCairoFontPrivate *cf_priv)
+{
+  _pango_cairo_font_private_scaled_font_data_destroy (cf_priv->data);
+
+  if (cf_priv->scaled_font)
+    cairo_scaled_font_destroy (cf_priv->scaled_font);
+
+  _pango_cairo_font_hex_box_info_destroy (cf_priv->hbi);
+
+  if (cf_priv->glyph_extents_cache)
+    g_free (cf_priv->glyph_extents_cache);
+
+  g_slist_foreach (cf_priv->metrics_by_lang, (GFunc)free_metrics_info, NULL);
+  g_slist_free (cf_priv->metrics_by_lang);
+}
+
+gboolean
+_pango_cairo_font_private_is_metrics_hinted (PangoCairoFontPrivate *cf_priv)
+{
+  return cf_priv->is_hinted;
+}
+
+static void
+_pango_cairo_font_private_get_glyph_extents_missing (PangoCairoFontPrivate *cf_priv,
+						     PangoGlyph             glyph,
+						     PangoRectangle        *ink_rect,
+						     PangoRectangle        *logical_rect)
+{
+  PangoCairoFontHexBoxInfo *hbi;
   gint rows, cols;
 
-  hbi = _pango_cairo_font_get_hex_box_info (cfont);
+  hbi = _pango_cairo_font_private_get_hex_box_info (cf_priv);
   if (!hbi)
     {
       pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
@@ -355,3 +588,142 @@ _pango_cairo_get_glyph_extents_missing (
     }
 }
 
+#define GLYPH_CACHE_NUM_ENTRIES 256 /* should be power of two */
+#define GLYPH_CACHE_MASK (GLYPH_CACHE_NUM_ENTRIES - 1)
+/* An entry in the fixed-size cache for the glyph->extents mapping.
+ * The cache is indexed by the lower N bits of the glyph (see
+ * GLYPH_CACHE_NUM_ENTRIES).  For scripts with few glyphs,
+ * this should provide pretty much instant lookups.
+ */
+struct _PangoCairoFontGlyphExtentsCacheEntry
+{
+  PangoGlyph     glyph;
+  int            width;
+  PangoRectangle ink_rect;
+};
+
+static gboolean
+_pango_cairo_font_private_glyph_extents_cache_init (PangoCairoFontPrivate *cf_priv)
+{
+  cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv);
+  cairo_font_extents_t font_extents;
+
+  if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
+    return FALSE;
+
+  cairo_scaled_font_extents (scaled_font, &font_extents);
+
+  cf_priv->font_extents.x = 0;
+  cf_priv->font_extents.width = 0;
+  cf_priv->font_extents.height = pango_units_from_double (font_extents.ascent + font_extents.descent);
+  switch (cf_priv->gravity)
+    {
+      default:
+      case PANGO_GRAVITY_AUTO:
+      case PANGO_GRAVITY_SOUTH:
+	cf_priv->font_extents.y = - pango_units_from_double (font_extents.ascent);
+	break;
+      case PANGO_GRAVITY_NORTH:
+	cf_priv->font_extents.y = - pango_units_from_double (font_extents.descent);
+	break;
+      case PANGO_GRAVITY_EAST:
+      case PANGO_GRAVITY_WEST:
+	{
+	  int ascent = pango_units_from_double (font_extents.ascent + font_extents.descent) / 2;
+	  if (cf_priv->is_hinted)
+	    ascent = PANGO_UNITS_ROUND (ascent);
+	  cf_priv->font_extents.y = - ascent;
+	}
+    }
+
+  cf_priv->glyph_extents_cache = g_new0 (PangoCairoFontGlyphExtentsCacheEntry, GLYPH_CACHE_NUM_ENTRIES);
+  /* Make sure all cache entries are invalid initially */
+  cf_priv->glyph_extents_cache[0].glyph = 1; /* glyph 1 cannot happen in bucket 0 */
+
+  return TRUE;
+}
+
+/* Fills in the glyph extents cache entry
+ */
+static void
+compute_glyph_extents (PangoCairoFontPrivate  *cf_priv,
+		       PangoGlyph              glyph,
+		       PangoCairoFontGlyphExtentsCacheEntry *entry)
+{
+  cairo_text_extents_t extents;
+  cairo_glyph_t cairo_glyph;
+
+  cairo_glyph.index = glyph;
+  cairo_glyph.x = 0;
+  cairo_glyph.y = 0;
+
+  cairo_scaled_font_glyph_extents (_pango_cairo_font_private_get_scaled_font (cf_priv),
+				   &cairo_glyph, 1, &extents);
+
+  entry->glyph = glyph;
+  entry->width = pango_units_from_double (extents.x_advance);
+  entry->ink_rect.x = pango_units_from_double (extents.x_bearing);
+  entry->ink_rect.y = pango_units_from_double (extents.y_bearing);
+  entry->ink_rect.width = pango_units_from_double (extents.width);
+  entry->ink_rect.height = pango_units_from_double (extents.height);
+}
+
+static PangoCairoFontGlyphExtentsCacheEntry *
+_pango_cairo_font_private_get_glyph_extents_cache_entry (PangoCairoFontPrivate  *cf_priv,
+							 PangoGlyph              glyph)
+{
+  PangoCairoFontGlyphExtentsCacheEntry *entry;
+  guint idx;
+
+  idx = glyph & GLYPH_CACHE_MASK;
+  entry = cf_priv->glyph_extents_cache + idx;
+
+  if (entry->glyph != glyph)
+    {
+      compute_glyph_extents (cf_priv, glyph, entry);
+    }
+
+  return entry;
+}
+
+void
+_pango_cairo_font_private_get_glyph_extents (PangoCairoFontPrivate *cf_priv,
+					     PangoGlyph             glyph,
+					     PangoRectangle        *ink_rect,
+					     PangoRectangle        *logical_rect)
+{
+  PangoCairoFontGlyphExtentsCacheEntry *entry;
+
+  if (!cf_priv ||
+      (cf_priv->glyph_extents_cache == NULL &&
+       !_pango_cairo_font_private_glyph_extents_cache_init (cf_priv)))
+    {
+      /* Get generic unknown-glyph extents. */
+      pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
+      return;
+    }
+
+  if (glyph == PANGO_GLYPH_EMPTY)
+    {
+      if (ink_rect)
+	ink_rect->x = ink_rect->y = ink_rect->width = ink_rect->height = 0;
+      if (logical_rect)
+	*logical_rect = cf_priv->font_extents;
+      return;
+    }
+  else if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+    {
+      _pango_cairo_font_private_get_glyph_extents_missing(cf_priv, glyph, ink_rect, logical_rect);
+      return;
+    }
+
+  entry = _pango_cairo_font_private_get_glyph_extents_cache_entry (cf_priv, glyph);
+
+  if (ink_rect)
+    *ink_rect = entry->ink_rect;
+  if (logical_rect)
+    {
+      *logical_rect = cf_priv->font_extents;
+      logical_rect->width = entry->width;
+    }
+}
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2333)
+++ ChangeLog	(working copy)
@@ -1,3 +1,23 @@
+2007-06-09  Behdad Esfahbod  <behdad@gnome.org>
+
+	Bug 337593 – move glyph extents code (and cache) from
+	pangocairo-*font.c into pangocairo-font.c
+
+	* pango/pangocairo-fontmap.c:
+	* pango/pangocairo-fcfontmap.c:
+	Remove per-fontmap renderer.  We've not been using it for a while
+	and there is no reason to use it.
+
+	* pango/pangocairo-font.c
+	* pango/pangocairo-fcfont.c:
+	Most most code (including glyph extents caching) from fcfont.c to
+	font.c.  Simplifies individual backends a lot. ATSUI and Win32
+	cairo backends should adapt.
+
+	* pango/pangocairo-render.c
+	* pango/pangocairo-private.h:
+	Update to reflect above changes.
+
 2007-06-05  Behdad Esfahbod  <behdad@gnome.org>
 
 	* pango/fonts.c (pango_font_description_merge),
