[pango] CoreText backend: implement font fallbacks



commit 37e74619215ede8a4fa7f5edabab14b517e673b2
Author: Kristian Rietveld <kris lanedo com>
Date:   Fri Oct 14 11:25:21 2011 +0200

    CoreText backend: implement font fallbacks
    
    We implement font fallbacks by making use of
    CTFontCopyDefaultCascadeList, a public, non-exposed, symbol in the
    CoreText library.  We might want to handle this differently.
    
    The code now also uses a PangoCoreTextFontsetKey and
    PangoCoreTextFontKey, similar to the font config backend. This has also
    helped to clean up the code in general.
    
    This patch contains two fixes by Michael Natterer:
     1. Fix a bug in pango_core_text_font_key_equal() where the return value
    of memcmp() was wrongly interpreted.
     2. Cache PangoCoverage in PangoCoreTextFont.

 pango/pangocairo-coretext.h        |    4 +-
 pango/pangocairo-coretextfont.c    |   50 +-
 pango/pangocairo-coretextfontmap.c |   72 ++-
 pango/pangocoretext-fontmap.c      | 1308 ++++++++++++++++++++++++++----------
 pango/pangocoretext-private.h      |   31 +-
 pango/pangocoretext.c              |   94 ++-
 6 files changed, 1131 insertions(+), 428 deletions(-)
---
diff --git a/pango/pangocairo-coretext.h b/pango/pangocairo-coretext.h
index 420e1c9..4310f45 100644
--- a/pango/pangocairo-coretext.h
+++ b/pango/pangocairo-coretext.h
@@ -46,9 +46,7 @@ GType pango_cairo_core_text_font_map_get_type (void) G_GNUC_CONST;
 
 PangoCoreTextFont *
 _pango_cairo_core_text_font_new (PangoCairoCoreTextFontMap  *cafontmap,
-                                 PangoContext               *context,
-                                 PangoCoreTextFace          *face,
-                                 const PangoFontDescription *desc);
+                                 PangoCoreTextFontKey       *key);
 
 G_END_DECLS
 
diff --git a/pango/pangocairo-coretextfont.c b/pango/pangocairo-coretextfont.c
index 7b58148..290a5cc 100644
--- a/pango/pangocairo-coretextfont.c
+++ b/pango/pangocairo-coretextfont.c
@@ -206,46 +206,24 @@ pango_cairo_core_text_font_init (PangoCairoCoreTextFont *cafont G_GNUC_UNUSED)
 
 PangoCoreTextFont *
 _pango_cairo_core_text_font_new (PangoCairoCoreTextFontMap  *cafontmap,
-                                 PangoContext               *context,
-                                 PangoCoreTextFace          *face,
-                                 const PangoFontDescription *desc)
+                                 PangoCoreTextFontKey       *key)
 {
-  const char *postscript_name;
   gboolean synthesize_italic = FALSE;
   PangoCairoCoreTextFont *cafont;
   PangoCoreTextFont *cfont;
-  CFStringRef cfstr;
   CTFontRef font_ref;
+  CTFontDescriptorRef ctdescriptor;
   CGFontRef font_id;
   double size, abs_size;
-  double dpi;
   cairo_matrix_t font_matrix;
 
-  postscript_name = _pango_core_text_face_get_postscript_name (face);
+  abs_size = pango_core_text_font_key_get_absolute_size (key);
+  size = pango_units_to_double (abs_size);
 
-  abs_size = size = pango_units_to_double (pango_font_description_get_size (desc));
+  ctdescriptor = pango_core_text_font_key_get_ctfontdescriptor (key);
+  font_ref = CTFontCreateWithFontDescriptor (ctdescriptor, size, NULL);
 
-  if (context)
-    {
-      dpi = pango_cairo_context_get_resolution (context);
-
-      if (dpi <= 0)
-	dpi = cafontmap->dpi;
-    }
-  else
-    dpi = cafontmap->dpi;
-
-  if (pango_font_description_get_size_is_absolute (desc))
-    size *= 72. / dpi;
-  else
-    abs_size *= dpi / 72.;
-
-  cfstr = CFStringCreateWithCString (NULL, postscript_name,
-                                     kCFStringEncodingUTF8);
-  font_ref = CTFontCreateWithName (cfstr, size, NULL);
-  CFRelease (cfstr);
-
-  if (_pango_core_text_face_get_synthetic_italic (face))
+  if (pango_core_text_font_key_get_synthetic_italic (key))
     synthesize_italic = TRUE;
 
   font_id = CTFontCopyGraphicsFont (font_ref, NULL);
@@ -255,10 +233,7 @@ _pango_cairo_core_text_font_new (PangoCairoCoreTextFontMap  *cafontmap,
   cafont = g_object_new (PANGO_TYPE_CAIRO_CORE_TEXT_FONT, NULL);
   cfont = PANGO_CORE_TEXT_FONT (cafont);
 
-  _pango_core_text_font_set_font_description (cfont, desc);
-  _pango_core_text_font_set_face (cfont, face);
-
-  cafont->abs_size = abs_size * PANGO_SCALE;
+  cafont->abs_size = abs_size;
 
   _pango_core_text_font_set_ctfont (cfont, font_ref);
 
@@ -270,14 +245,13 @@ _pango_cairo_core_text_font_new (PangoCairoCoreTextFontMap  *cafontmap,
   else
     cairo_matrix_init_identity (&font_matrix);
  
-  /* Scale using absolute size */
-  cairo_matrix_scale (&font_matrix, abs_size, abs_size);
+  cairo_matrix_scale (&font_matrix, size, size);
 
   _pango_cairo_font_private_initialize (&cafont->cf_priv,
 					(PangoCairoFont *) cafont,
-					pango_font_description_get_gravity (desc),
-					_pango_cairo_context_get_merged_font_options (context),
-					pango_context_get_matrix (context),
+                                        pango_core_text_font_key_get_gravity (key),
+                                        pango_core_text_font_key_get_context_key (key),
+                                        pango_core_text_font_key_get_matrix (key),
 					&font_matrix);
 
   return cfont;
diff --git a/pango/pangocairo-coretextfontmap.c b/pango/pangocairo-coretextfontmap.c
index e05a1d4..107c828 100644
--- a/pango/pangocairo-coretextfontmap.c
+++ b/pango/pangocairo-coretextfontmap.c
@@ -44,7 +44,7 @@ pango_cairo_core_text_font_map_set_resolution (PangoCairoFontMap *cfontmap,
 }
 
 static double
-pango_cairo_core_text_font_map_get_resolution (PangoCairoFontMap *cfontmap)
+pango_cairo_core_text_font_map_get_resolution_cairo (PangoCairoFontMap *cfontmap)
 {
   PangoCairoCoreTextFontMap *cafontmap = PANGO_CAIRO_CORE_TEXT_FONT_MAP (cfontmap);
 
@@ -64,7 +64,7 @@ static void
 cairo_font_map_iface_init (PangoCairoFontMapIface *iface)
 {
   iface->set_resolution = pango_cairo_core_text_font_map_set_resolution;
-  iface->get_resolution = pango_cairo_core_text_font_map_get_resolution;
+  iface->get_resolution = pango_cairo_core_text_font_map_get_resolution_cairo;
   iface->get_font_type  = pango_cairo_core_text_font_map_get_font_type;
 }
 
@@ -74,13 +74,11 @@ G_DEFINE_TYPE_WITH_CODE (PangoCairoCoreTextFontMap, pango_cairo_core_text_font_m
 
 static PangoCoreTextFont *
 pango_cairo_core_text_font_map_create_font (PangoCoreTextFontMap       *fontmap,
-                                            PangoContext               *context,
-                                            PangoCoreTextFace          *face,
-                                            const PangoFontDescription *desc)
+                                            PangoCoreTextFontKey       *key)
 
 {
   return _pango_cairo_core_text_font_new (PANGO_CAIRO_CORE_TEXT_FONT_MAP (fontmap),
-                                          context, face, desc);
+                                          key);
 }
 
 static void
@@ -89,6 +87,62 @@ pango_cairo_core_text_font_map_finalize (GObject *object)
   G_OBJECT_CLASS (pango_cairo_core_text_font_map_parent_class)->finalize (object);
 }
 
+static double
+pango_cairo_core_text_font_map_get_resolution_core_text (PangoCoreTextFontMap *ctfontmap,
+                                                         PangoContext         *context)
+{
+  PangoCairoCoreTextFontMap *cafontmap = PANGO_CAIRO_CORE_TEXT_FONT_MAP (ctfontmap);
+  double dpi;
+
+  if (context)
+    {
+      dpi = pango_cairo_context_get_resolution (context);
+
+      if (dpi <= 0)
+        dpi = cafontmap->dpi;
+    }
+  else
+    dpi = cafontmap->dpi;
+
+  return dpi;
+}
+
+static gconstpointer
+pango_cairo_core_text_font_map_context_key_get (PangoCoreTextFontMap *fontmap G_GNUC_UNUSED,
+                                                PangoContext         *context)
+{
+  return _pango_cairo_context_get_merged_font_options (context);
+}
+
+static gpointer
+pango_cairo_core_text_font_map_context_key_copy (PangoCoreTextFontMap *fontmap G_GNUC_UNUSED,
+                                                 gconstpointer         key)
+{
+  return cairo_font_options_copy (key);
+}
+
+static void
+pango_cairo_core_text_font_map_context_key_free (PangoCoreTextFontMap *fontmap G_GNUC_UNUSED,
+                                                 gpointer              key)
+{
+  cairo_font_options_destroy (key);
+}
+
+static guint32
+pango_cairo_core_text_font_map_context_key_hash (PangoCoreTextFontMap *fontmap G_GNUC_UNUSED,
+                                                 gconstpointer         key)
+{
+  return (guint32)cairo_font_options_hash (key);
+}
+
+static gboolean
+pango_cairo_core_text_font_map_context_key_equal (PangoCoreTextFontMap *fontmap G_GNUC_UNUSED,
+                                                  gconstpointer         key_a,
+                                                  gconstpointer         key_b)
+{
+  return cairo_font_options_equal (key_a, key_b);
+}
+
 static void
 pango_cairo_core_text_font_map_class_init (PangoCairoCoreTextFontMapClass *class)
 {
@@ -97,7 +151,13 @@ pango_cairo_core_text_font_map_class_init (PangoCairoCoreTextFontMapClass *class
 
   object_class->finalize = pango_cairo_core_text_font_map_finalize;
 
+  ctfontmapclass->get_resolution = pango_cairo_core_text_font_map_get_resolution_core_text;
   ctfontmapclass->create_font = pango_cairo_core_text_font_map_create_font;
+  ctfontmapclass->context_key_get = pango_cairo_core_text_font_map_context_key_get;
+  ctfontmapclass->context_key_copy = pango_cairo_core_text_font_map_context_key_copy;
+  ctfontmapclass->context_key_free = pango_cairo_core_text_font_map_context_key_free;
+  ctfontmapclass->context_key_hash = pango_cairo_core_text_font_map_context_key_hash;
+  ctfontmapclass->context_key_equal = pango_cairo_core_text_font_map_context_key_equal;
 }
 
 static void
diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c
index 9f67acb..511380d 100644
--- a/pango/pangocoretext-fontmap.c
+++ b/pango/pangocoretext-fontmap.c
@@ -32,6 +32,7 @@
 
 typedef struct _FontHashKey      FontHashKey;
 
+typedef struct _PangoCoreTextFontset PangoCoreTextFontset;
 
 #define PANGO_TYPE_CORE_TEXT_FAMILY              (pango_core_text_family_get_type ())
 #define PANGO_CORE_TEXT_FAMILY(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FAMILY, PangoCoreTextFamily))
@@ -40,6 +41,11 @@ typedef struct _FontHashKey      FontHashKey;
 #define PANGO_IS_CORE_TEXT_FAMILY_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_CORE_TEXT_FAMILY))
 #define PANGO_CORE_TEXT_FAMILY_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), PANGO_CORE_TEXT_FAMILY, PangoCoreTextFamilyClass))
 
+#define PANGO_TYPE_CORE_TEXT_FONTSET           (pango_core_text_fontset_get_type ())
+#define PANGO_CORE_TEXT_FONTSET(object)        (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FONTSET, PangoCoreTextFontset))
+#define PANGO_IS_CORE_TEXT_FONTSET(object)     (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CORE_TEXT_FONTSET))
+
+
 struct _PangoCoreTextFamily
 {
   PangoFontFamily parent_instance;
@@ -72,11 +78,9 @@ struct _PangoCoreTextFace
 
   PangoCoreTextFamily *family;
 
-  PangoCoverage *coverage;
+  CTFontDescriptorRef ctfontdescriptor;
 
-  char *postscript_name;
   char *style_name;
-
   PangoWeight weight;
   CTFontSymbolicTraits traits;
   guint synthetic_italic : 1;
@@ -91,6 +95,15 @@ typedef struct _PangoCoreTextFaceClass PangoCoreTextFaceClass;
 
 static GType pango_core_text_family_get_type (void);
 static GType pango_core_text_face_get_type (void);
+static GType pango_core_text_fontset_get_type (void);
+
+static PangoCoreTextFontset    *pango_core_text_fontset_new     (PangoCoreTextFontsetKey    *key,
+                                                                 const PangoFontDescription *description);
+static PangoCoreTextFontsetKey *pango_core_text_fontset_get_key (PangoCoreTextFontset       *fontset);
+
+/*
+ * Helper functions to translate CoreText data to Pango
+ */
 
 typedef struct
 {
@@ -153,88 +166,88 @@ gchar_from_cf_string (CFStringRef str)
   return buffer;
 }
 
-static PangoCoverage *
-pango_coverage_from_cf_charset (CFCharacterSetRef charset)
+static char *
+ct_font_descriptor_get_style_name (CTFontDescriptorRef desc)
 {
-  CFIndex i, length;
-  CFDataRef bitmap;
-  const UInt8 *ptr;
-  PangoCoverage *coverage;
-
-  coverage = pango_coverage_new ();
-
-  bitmap = CFCharacterSetCreateBitmapRepresentation (kCFAllocatorDefault,
-                                                     charset);
-
-  /* We only handle the BMP plane */
-  length = MIN (CFDataGetLength (bitmap), 8192);
-  ptr = CFDataGetBytePtr (bitmap);
-
-  /* FIXME: can and should this be done more efficiently? */
-  for (i = 0; i < length; i++)
-    {
-      int j;
-
-      for (j = 0; j < 8; j++)
-        pango_coverage_set (coverage, i * 8 + j,
-                            ((ptr[i] & (1 << j)) == (1 << j)) ?
-                            PANGO_COVERAGE_EXACT : PANGO_COVERAGE_NONE);
-    }
+  CFStringRef cf_str;
+  char *buffer;
 
-  CFRelease (bitmap);
+  cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontStyleNameAttribute);
+  buffer = gchar_from_cf_string (cf_str);
+  CFRelease (cf_str);
 
-  return coverage;
+  return buffer;
 }
 
-static inline gboolean
-pango_core_text_face_is_oblique (PangoCoreTextFace *face)
+static CTFontSymbolicTraits
+ct_font_descriptor_get_traits (CTFontDescriptorRef desc)
 {
-  return g_strrstr (face->style_name, "Oblique") != NULL;
+  CFDictionaryRef dict;
+  CFNumberRef cf_number;
+  SInt64 traits;
+
+  /* This is interesting, the value stored is a CTFontSymbolicTraits which
+   * is defined as uint32_t.  CFNumber does not have an obvious type which
+   * deals with unsigned values.  Upon inspection with CFNumberGetType,
+   * it turns out this value is stored as SInt64, so we use that to
+   * obtain the value from the CFNumber.
+   */
+  dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
+  cf_number = (CFNumberRef)CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
+  if (!CFNumberGetValue (cf_number, kCFNumberSInt64Type, &traits))
+    traits = 0;
+  CFRelease (dict);
+
+  return (CTFontSymbolicTraits)traits;
 }
 
-static inline PangoCoreTextFace *
-pango_core_text_face_from_ct_font_descriptor (CTFontDescriptorRef desc)
+static CTFontDescriptorRef
+cf_font_descriptor_copy_with_traits (CTFontDescriptorRef        desc,
+                                     const CTFontSymbolicTraits traits)
 {
-  SInt64 font_traits;
-  char *buffer;
-  CFStringRef str;
-  CFNumberRef number;
-  CGFloat value;
-  CFDictionaryRef dict;
-  CFCharacterSetRef charset;
-  PangoCoreTextFace *face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE,
-                                          NULL);
+  CFMutableDictionaryRef dict, traits_dict;
+  CFDictionaryRef tmp;
+  CTFontDescriptorRef new_desc;
+  SInt64 tmp_traits;
 
-  face->synthetic_italic = FALSE;
+  tmp = CTFontDescriptorCopyAttributes (desc);
+  dict = CFDictionaryCreateMutableCopy (kCFAllocatorDefault, 0, tmp);
+  CFRelease (tmp);
 
-  /* Get font name */
-  str = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
-  buffer = gchar_from_cf_string (str);
+  tmp = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
+  traits_dict = CFDictionaryCreateMutableCopy (kCFAllocatorDefault, 0, tmp);
+  CFRelease (tmp);
 
-  /* We strdup again to save space. */
-  face->postscript_name = g_strdup (buffer);
+  tmp_traits = traits;
+  CFDictionarySetValue (traits_dict, (CFTypeRef) kCTFontSymbolicTrait,
+                        CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &tmp_traits));
 
-  CFRelease (str);
-  g_free (buffer);
+  CFDictionarySetValue (dict, (CFTypeRef)kCTFontTraitsAttribute, traits_dict);
 
-  /* Get style name */
-  str = CTFontDescriptorCopyAttribute (desc, kCTFontStyleNameAttribute);
-  buffer = gchar_from_cf_string (str);
+  new_desc = CTFontDescriptorCreateCopyWithAttributes (desc, dict);
+  CFRelease (dict);
 
-  face->style_name = g_strdup (buffer);
+  return new_desc;
+}
 
-  CFRelease (str);
-  g_free (buffer);
+static PangoWeight
+ct_font_descriptor_get_weight (CTFontDescriptorRef desc)
+{
+  CFDictionaryRef dict;
+  CFNumberRef cf_number;
+  CGFloat value;
+  PangoWeight weight;
 
-  /* Get font traits, symbolic traits */
   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
-  number = (CFNumberRef)CFDictionaryGetValue (dict,
-                                              kCTFontWeightTrait);
-  if (CFNumberGetValue (number, kCFNumberCGFloatType, &value))
+  cf_number = (CFNumberRef)CFDictionaryGetValue (dict,
+                                                 kCTFontWeightTrait);
+
+  if (CFNumberGetValue (cf_number, kCFNumberCGFloatType, &value))
     {
       if (value < ct_weight_min || value > ct_weight_max)
 	{
-	  face->weight = PANGO_WEIGHT_NORMAL; /* This is really an error */
+          /* This is really an error */
+          weight = PANGO_WEIGHT_NORMAL;
 	}
       else
 	{
@@ -242,36 +255,207 @@ pango_core_text_face_from_ct_font_descriptor (CTFontDescriptorRef desc)
 	  for (i = 0; i < G_N_ELEMENTS(ct_weight_limits); i++)
 	    if (value < ct_weight_limits[i].bound)
 	      {
-		face->weight = ct_weight_limits[i].weight;
-		break;
+                weight = ct_weight_limits[i].weight;
+                break;
 	      }
 	}
     }
-  else
-    face->weight = PANGO_WEIGHT_NORMAL;
+ else
+   weight = PANGO_WEIGHT_NORMAL;
 
-  /* This is interesting, the value stored is a CTFontSymbolicTraits which
-   * is defined as uint32_t.  CFNumber does not have an obvious type which
-   * deals with unsigned values.  Upon inspection with CFNumberGetType,
-   * it turns out this value is stored as SInt64, so we use that to
-   * obtain the value from the CFNumber.
-   */
-  number = (CFNumberRef)CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
-  if (CFNumberGetValue (number, kCFNumberSInt64Type, &font_traits))
-    {
-      face->traits = font_traits;
-    }
   CFRelease (dict);
 
-  /* Get font coverage */
-  charset = CTFontDescriptorCopyAttribute (desc,
-                                           kCTFontCharacterSetAttribute);
-  face->coverage = pango_coverage_from_cf_charset (charset);
-  CFRelease (charset);
+  return weight;
+}
+
+static inline gboolean
+pango_core_text_style_name_is_oblique (const char *style_name)
+{
+  return g_strrstr (style_name, "Oblique") != NULL;
+}
+
+PangoFontDescription *
+_pango_core_text_font_description_from_ct_font_descriptor (CTFontDescriptorRef desc)
+{
+  SInt64 font_traits;
+  char *buffer;
+  char *style_name;
+  CFStringRef cf_str;
+  PangoFontDescription *font_desc;
+
+  font_desc = pango_font_description_new ();
+
+  /* Family name */
+
+  /* FIXME: Should we actually retrieve the family name from the list of families
+   * in a font map?
+   */
+  cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
+  buffer = gchar_from_cf_string (cf_str);
+
+  pango_font_description_set_family (font_desc, buffer);
+
+  g_free (buffer);
+  CFRelease (cf_str);
+
+  /* Weight */
+  pango_font_description_set_weight (font_desc,
+                                     ct_font_descriptor_get_weight (desc));
+
+  /* Font traits, style name; from this we deduce style and variant */
+  font_traits = ct_font_descriptor_get_traits (desc);
+  style_name = ct_font_descriptor_get_style_name (desc);
+
+  if ((font_traits & kCTFontItalicTrait) == kCTFontItalicTrait)
+    pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
+  else if (pango_core_text_style_name_is_oblique (style_name))
+    pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE);
+  else
+    pango_font_description_set_style (font_desc, PANGO_STYLE_NORMAL);
+
+  /* FIXME: How can this be figured using CoreText? */
+#if 0
+  if (font_traits & NSSmallCapsFontMask)
+    pango_font_description_set_variant (font_desc, PANGO_VARIANT_SMALL_CAPS);
+  else
+#endif
+    pango_font_description_set_variant (font_desc, PANGO_VARIANT_NORMAL);
+
+  g_free (style_name);
+
+  return font_desc;
+}
+
+/*
+ * PangoCoreTextFace
+ */
+
+static inline gboolean
+pango_core_text_face_is_oblique (PangoCoreTextFace *face)
+{
+  return pango_core_text_style_name_is_oblique (face->style_name);
+}
+
+static void
+pango_core_text_face_make_italic (PangoCoreTextFace *ctface,
+                                  gboolean           synthetic_italic)
+{
+  CTFontDescriptorRef new_desc;
+
+  ctface->traits |= kCTFontItalicTrait;
+  if (synthetic_italic)
+    ctface->synthetic_italic = TRUE;
+
+  /* Update the font descriptor */
+  new_desc = cf_font_descriptor_copy_with_traits (ctface->ctfontdescriptor,
+                                                  ctface->traits);
+  CFRelease (ctface->ctfontdescriptor);
+  ctface->ctfontdescriptor = new_desc;
+}
+
+static inline PangoCoreTextFace *
+pango_core_text_face_copy (const PangoCoreTextFace *old)
+{
+  PangoCoreTextFace *face;
+
+  face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE, NULL);
+  face->family = old->family;
+  face->ctfontdescriptor = CFRetain (old->ctfontdescriptor);
+  face->style_name = g_strdup (old->style_name);
+  face->weight = old->weight;
+  face->traits = old->traits;
+  face->synthetic_italic = old->synthetic_italic;
+
+  return face;
+}
+
+static inline PangoCoreTextFace *
+pango_core_text_face_from_ct_font_descriptor (CTFontDescriptorRef desc)
+{
+  PangoCoreTextFace *face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE,
+                                          NULL);
+
+  face->synthetic_italic = FALSE;
+
+  face->ctfontdescriptor = CFRetain (desc);
+
+  face->style_name = ct_font_descriptor_get_style_name (desc);
+  face->traits = ct_font_descriptor_get_traits (desc);
+  face->weight = ct_font_descriptor_get_weight (desc);
 
   return face;
 }
 
+static PangoFontDescription *
+pango_core_text_face_describe (PangoFontFace *face)
+{
+  PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
+
+  return _pango_core_text_font_description_from_ct_font_descriptor (ctface->ctfontdescriptor);
+}
+
+static const char *
+pango_core_text_face_get_face_name (PangoFontFace *face)
+{
+  PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
+
+  return ctface->style_name;
+}
+
+static void
+pango_core_text_face_list_sizes (PangoFontFace  *face,
+                                 int           **sizes,
+                                 int            *n_sizes)
+{
+  *n_sizes = 0;
+  *sizes = NULL;
+}
+
+G_DEFINE_TYPE (PangoCoreTextFace, pango_core_text_face, PANGO_TYPE_FONT_FACE);
+
+static void
+pango_core_text_face_init (PangoCoreTextFace *face)
+{
+  face->family = NULL;
+}
+
+static void
+pango_core_text_face_finalize (GObject *object)
+{
+  PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (object);
+
+  g_free (ctface->style_name);
+  CFRelease (ctface->ctfontdescriptor);
+
+  G_OBJECT_CLASS (pango_core_text_face_parent_class)->finalize (object);
+}
+
+static gboolean
+pango_core_text_face_is_synthesized (PangoFontFace *face)
+{
+  PangoCoreTextFace *cface = PANGO_CORE_TEXT_FACE (face);
+
+  return cface->synthetic_italic;
+}
+
+static void
+pango_core_text_face_class_init (PangoCoreTextFaceClass *klass)
+{
+  GObjectClass *object_class = (GObjectClass *)klass;
+  PangoFontFaceClass *pfclass = PANGO_FONT_FACE_CLASS(klass);
+
+  object_class->finalize = pango_core_text_face_finalize;
+
+  pfclass->describe = pango_core_text_face_describe;
+  pfclass->get_face_name = pango_core_text_face_get_face_name;
+  pfclass->list_sizes = pango_core_text_face_list_sizes;
+  pfclass->is_synthesized = pango_core_text_face_is_synthesized;
+}
+
+/*
+ * PangoCoreTextFamily
+ */
+
 static void
 pango_core_text_family_list_faces (PangoFontFamily  *family,
                                    PangoFontFace  ***faces,
@@ -356,16 +540,13 @@ pango_core_text_family_list_faces (PangoFontFamily  *family,
             {
               PangoCoreTextFace *italic_face;
 
-              italic_face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE, NULL);
+              italic_face = pango_core_text_face_copy (face);
 
               italic_face->family = ctfamily;
-              italic_face->postscript_name = g_strdup (face->postscript_name);
-              italic_face->weight = face->weight;
-              italic_face->traits = face->traits | kCTFontItalicTrait;
-              italic_face->synthetic_italic = TRUE;
-              italic_face->coverage = pango_coverage_ref (face->coverage);
+              pango_core_text_face_make_italic (italic_face, TRUE);
 
               /* Try to create a sensible face name. */
+              g_free (italic_face->style_name);
               if (strcasecmp (face->style_name, "regular") == 0)
                 italic_face->style_name = g_strdup ("Oblique");
               else
@@ -456,236 +637,279 @@ pango_core_text_family_init (PangoCoreTextFamily *family)
   family->n_faces = -1;
 }
 
-static PangoFontDescription *
-pango_core_text_face_describe (PangoFontFace *face)
-{
-  PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
-  PangoFontDescription *description;
-  PangoStyle pango_style;
-  PangoVariant pango_variant;
 
-  description = pango_font_description_new ();
 
-  pango_font_description_set_family (description, ctface->family->family_name);
+static void pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class);
+static void pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap);
 
 
-  if (ctface->traits & kCTFontItalicTrait)
-    pango_style = PANGO_STYLE_ITALIC;
-  else if (pango_core_text_face_is_oblique (ctface))
-    pango_style = PANGO_STYLE_OBLIQUE;
-  else
-    pango_style = PANGO_STYLE_NORMAL;
+G_DEFINE_TYPE (PangoCoreTextFontMap, pango_core_text_font_map, PANGO_TYPE_FONT_MAP);
 
-  /* FIXME: How can this be figured using CoreText? */
-#if 0
-  if (ctface->traits & NSSmallCapsFontMask)
-    pango_variant = PANGO_VARIANT_SMALL_CAPS;
-  else
-#endif
-    pango_variant = PANGO_VARIANT_NORMAL;
+static void
+pango_core_text_font_map_finalize (GObject *object)
+{
+  PangoCoreTextFontMap *fontmap = PANGO_CORE_TEXT_FONT_MAP (object);
 
-  pango_font_description_set_weight (description, ctface->weight);
-  pango_font_description_set_style (description, pango_style);
-  pango_font_description_set_variant (description, pango_variant);
+  g_hash_table_destroy (fontmap->fontset_hash);
+  g_hash_table_destroy (fontmap->font_hash);
+  g_hash_table_destroy (fontmap->families);
 
-  return description;
+  G_OBJECT_CLASS (pango_core_text_font_map_parent_class)->finalize (object);
 }
 
-static const char *
-pango_core_text_face_get_face_name (PangoFontFace *face)
+/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
+ *
+ * Not necessarily better than a lot of other hashes, but should be OK, and
+ * well tested with binary data.
+ */
+
+#define FNV_32_PRIME ((guint32)0x01000193)
+#define FNV1_32_INIT ((guint32)0x811c9dc5)
+
+static guint32
+hash_bytes_fnv (unsigned char *buffer,
+		int            len,
+		guint32        hval)
 {
-  PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
+  while (len--)
+    {
+      hval *= FNV_32_PRIME;
+      hval ^= *buffer++;
+    }
 
-  return ctface->style_name;
+  return hval;
 }
 
 static void
-pango_core_text_face_list_sizes (PangoFontFace  *face,
-                                 int           **sizes,
-                                 int            *n_sizes)
+get_context_matrix (PangoContext *context,
+		    PangoMatrix *matrix)
 {
-  *n_sizes = 0;
-  *sizes = NULL;
-}
+  const PangoMatrix *set_matrix;
+  static const PangoMatrix identity = PANGO_MATRIX_INIT;
 
-G_DEFINE_TYPE (PangoCoreTextFace, pango_core_text_face, PANGO_TYPE_FONT_FACE);
+  if (context)
+    set_matrix = pango_context_get_matrix (context);
+  else
+    set_matrix = NULL;
 
-static void
-pango_core_text_face_init (PangoCoreTextFace *face)
-{
-  face->family = NULL;
-  face->coverage = NULL;
+  if (set_matrix)
+    *matrix = *set_matrix;
+  else
+    *matrix = identity;
 }
 
+/*
+ * Helper functions for PangoCoreTextFontsetKey
+ */
 
-
-static void
-pango_core_text_face_finalize (GObject *object)
+static double
+pango_core_text_font_map_get_resolution (PangoCoreTextFontMap *fontmap,
+                                         PangoContext         *context)
 {
-  PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (object);
-
-  if (ctface->coverage)
-    pango_coverage_unref (ctface->coverage);
+  if (PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->get_resolution)
+    return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->get_resolution (fontmap, context);
 
-  g_free (ctface->postscript_name);
-  g_free (ctface->style_name);
+  /* FIXME: acquire DPI from CoreText using some deafault font */
+  g_warning ("FIXME: returning default DPI");
 
-  G_OBJECT_CLASS (pango_core_text_face_parent_class)->finalize (object);
+  return 72.0;
 }
 
-static gboolean
-pango_core_text_face_is_synthesized (PangoFontFace *face)
-{
-  PangoCoreTextFace *cface = PANGO_CORE_TEXT_FACE (face);
-
-  return cface->synthetic_italic;
-}
-
-static void
-pango_core_text_face_class_init (PangoCoreTextFaceClass *klass)
+static int
+get_scaled_size (PangoCoreTextFontMap       *fontmap,
+                 PangoContext               *context,
+                 const PangoFontDescription *desc)
 {
-  GObjectClass *object_class = (GObjectClass *)klass;
-  PangoFontFaceClass *pfclass = PANGO_FONT_FACE_CLASS(klass);
+  double size = pango_font_description_get_size (desc);
 
-  object_class->finalize = pango_core_text_face_finalize;
+  if (!pango_font_description_get_size_is_absolute (desc))
+    {
+      double dpi = pango_core_text_font_map_get_resolution (fontmap, context);
+      size = size * dpi / 72.;
+    }
 
-  pfclass->describe = pango_core_text_face_describe;
-  pfclass->get_face_name = pango_core_text_face_get_face_name;
-  pfclass->list_sizes = pango_core_text_face_list_sizes;
-  pfclass->is_synthesized = pango_core_text_face_is_synthesized;
+  return .5 + pango_matrix_get_font_scale_factor (pango_context_get_matrix (context)) * size;
 }
 
-const char *
-_pango_core_text_face_get_postscript_name (PangoCoreTextFace *face)
-{
-  return face->postscript_name;
-}
 
-gboolean
-_pango_core_text_face_get_synthetic_italic (PangoCoreTextFace *face)
+/*
+ * PangoCoreTextFontsetKey
+ */
+struct _PangoCoreTextFontsetKey
 {
-  return face->synthetic_italic;
-}
+  PangoCoreTextFontMap *fontmap;
+  PangoLanguage *language;
+  PangoFontDescription *desc;
+  PangoMatrix matrix;
+  int pixelsize;
+  double resolution;
+  PangoGravity gravity;
+  gpointer context_key;
+};
 
-PangoCoverage *
-_pango_core_text_face_get_coverage (PangoCoreTextFace *face,
-                                    PangoLanguage     *language)
+static void
+pango_core_text_fontset_key_init (PangoCoreTextFontsetKey    *key,
+                                  PangoCoreTextFontMap       *fontmap,
+                                  PangoContext               *context,
+                                  const PangoFontDescription *desc,
+                                  PangoLanguage              *language)
 {
-  return face->coverage;
+  if (!language && context)
+    language = pango_context_get_language (context);
+
+  key->fontmap = fontmap;
+  get_context_matrix (context, &key->matrix);
+  key->language = language;
+  key->pixelsize = get_scaled_size (fontmap, context, desc);
+  key->resolution = pango_core_text_font_map_get_resolution (fontmap, context);
+  key->gravity = pango_context_get_gravity (context);
+  key->desc = pango_font_description_copy_static (desc);
+  pango_font_description_unset_fields (key->desc, PANGO_FONT_MASK_SIZE);
+
+  if (context && PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->context_key_get)
+    key->context_key = (gpointer)PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->context_key_get (fontmap, context);
+  else
+    key->context_key = NULL;
 }
 
-static void pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class);
-static void pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap);
+static PangoCoreTextFontsetKey *
+pango_core_text_fontset_key_copy (const PangoCoreTextFontsetKey *old)
+{
+  PangoCoreTextFontsetKey *key = g_slice_new (PangoCoreTextFontsetKey);
 
-static guint    font_hash_key_hash  (const FontHashKey *key);
-static gboolean font_hash_key_equal (const FontHashKey *key_a,
-				     const FontHashKey *key_b);
-static void     font_hash_key_free  (FontHashKey       *key);
+  key->fontmap = old->fontmap;
+  key->matrix = old->matrix;
+  key->language = old->language;
+  key->pixelsize = old->pixelsize;
+  key->resolution = old->resolution;
+  key->gravity = old->gravity;
+  key->desc = pango_font_description_copy (old->desc);
+  if (old->context_key)
+    key->context_key = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap, old->context_key);
+  else
+    key->context_key = NULL;
 
-G_DEFINE_TYPE (PangoCoreTextFontMap, pango_core_text_font_map, PANGO_TYPE_FONT_MAP);
+  return key;
+}
 
 static void
-pango_core_text_font_map_finalize (GObject *object)
+pango_core_text_fontset_key_free (PangoCoreTextFontsetKey *key)
 {
-  PangoCoreTextFontMap *fontmap = PANGO_CORE_TEXT_FONT_MAP (object);
+  pango_font_description_free (key->desc);
 
-  g_hash_table_destroy (fontmap->font_hash);
-  g_hash_table_destroy (fontmap->families);
+  if (key->context_key)
+    PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap, key->context_key);
 
-  G_OBJECT_CLASS (pango_core_text_font_map_parent_class)->finalize (object);
+  g_slice_free (PangoCoreTextFontsetKey, key);
 }
 
-struct _FontHashKey {
-  PangoCoreTextFontMap *fontmap;
-  PangoMatrix matrix;
-  PangoFontDescription *desc;
-  char *postscript_name;
-  gpointer context_key;
-};
-
-/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
- *
- * Not necessarily better than a lot of other hashes, but should be OK, and
- * well tested with binary data.
- */
+static guint
+pango_core_text_fontset_key_hash (const PangoCoreTextFontsetKey *key)
+{
+  guint32 hash = FNV1_32_INIT;
 
-#define FNV_32_PRIME ((guint32)0x01000193)
-#define FNV1_32_INIT ((guint32)0x811c9dc5)
+  hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
+  hash ^= hash_bytes_fnv ((unsigned char *)(&key->resolution), sizeof (double), hash);
 
-static guint32
-hash_bytes_fnv (unsigned char *buffer,
-		int            len,
-		guint32        hval)
-{
-  while (len--)
-    {
-      hval *= FNV_32_PRIME;
-      hval ^= *buffer++;
-    }
+  if (key->context_key)
+    hash ^= PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap, key->context_key);
 
-  return hval;
+  return (hash ^
+          GPOINTER_TO_UINT (key->language) ^
+          pango_font_description_hash (key->desc));
 }
 
 static gboolean
-font_hash_key_equal (const FontHashKey *key_a,
-		     const FontHashKey *key_b)
+pango_core_text_fontset_key_equal (const PangoCoreTextFontsetKey *key_a,
+                                   const PangoCoreTextFontsetKey *key_b)
 {
-  if (key_a->matrix.xx == key_b->matrix.xx &&
-      key_a->matrix.xy == key_b->matrix.xy &&
-      key_a->matrix.yx == key_b->matrix.yx &&
-      key_a->matrix.yy == key_b->matrix.yy &&
+  if (key_a->language == key_b->language &&
+      key_a->pixelsize == key_b->pixelsize &&
+      key_a->resolution == key_b->resolution &&
+      key_a->gravity == key_b->gravity &&
       pango_font_description_equal (key_a->desc, key_b->desc) &&
-      strcmp (key_a->postscript_name, key_b->postscript_name) == 0)
+      memcmp ((void *)&key_a->matrix, (void *)&key_b->matrix, 4 * sizeof (double)) == 0)
     {
       if (key_a->context_key)
         return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
                                                                                        key_a->context_key,
                                                                                        key_b->context_key);
       else
-	return TRUE;
+        return key_a->context_key == key_b->context_key;
     }
-  else
-    return FALSE;
+  /* else */
+  return FALSE;
 }
 
-static guint
-font_hash_key_hash (const FontHashKey *key)
+static PangoLanguage *
+pango_core_text_fontset_key_get_language (const PangoCoreTextFontsetKey *key)
 {
-  guint32 hash = FNV1_32_INIT;
-
-  /* We do a bytewise hash on the context matrix */
-  hash = hash_bytes_fnv ((unsigned char *)(&key->matrix),
-                         sizeof(double) * 4,
-                         hash);
+  return key->language;
+}
 
-  if (key->context_key)
-    hash ^= PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
-                                                                                 key->context_key);
+static const PangoMatrix *
+pango_core_text_fontset_key_get_matrix (const PangoCoreTextFontsetKey *key)
+{
+  return &key->matrix;
+}
 
-  hash ^= g_str_hash (key->postscript_name);
+static PangoGravity
+pango_core_text_fontset_key_get_gravity (const PangoCoreTextFontsetKey *key)
+{
+  return key->gravity;
+}
 
-  return (hash ^ pango_font_description_hash (key->desc));
+static gpointer
+pango_core_text_fontset_key_get_context_key (const PangoCoreTextFontsetKey *key)
+{
+  return key->context_key;
 }
 
-static void
-font_hash_key_free (FontHashKey *key)
+/*
+ * PangoCoreTextFontKey
+ */
+struct _PangoCoreTextFontKey
 {
-  if (key->context_key)
-    PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
-                                                                         key->context_key);
+  PangoCoreTextFontMap *fontmap;
+  CTFontDescriptorRef ctfontdescriptor;
+  PangoMatrix matrix;
+  PangoGravity gravity;
+  int pixelsize;
+  double resolution;
+  gboolean synthetic_italic;
+  gpointer context_key;
+};
 
-  g_slice_free (FontHashKey, key);
+static void
+pango_core_text_font_key_init (PangoCoreTextFontKey    *key,
+                               PangoCoreTextFontMap    *ctfontmap,
+                               PangoCoreTextFontsetKey *fontset_key,
+                               CTFontDescriptorRef      ctdescriptor,
+                               gboolean                 synthetic_italic)
+{
+  key->fontmap = ctfontmap;
+  key->ctfontdescriptor = ctdescriptor;
+  key->matrix = *pango_core_text_fontset_key_get_matrix (fontset_key);
+  key->pixelsize = fontset_key->pixelsize;
+  key->resolution = fontset_key->resolution;
+  key->synthetic_italic = synthetic_italic;
+  key->gravity = pango_core_text_fontset_key_get_gravity (fontset_key);
+  key->context_key = pango_core_text_fontset_key_get_context_key (fontset_key);
 }
 
-static FontHashKey *
-font_hash_key_copy (FontHashKey *old)
+static PangoCoreTextFontKey *
+pango_core_text_font_key_copy (const PangoCoreTextFontKey *old)
 {
-  FontHashKey *key = g_slice_new (FontHashKey);
+  PangoCoreTextFontKey *key = g_slice_new (PangoCoreTextFontKey);
 
   key->fontmap = old->fontmap;
+  key->ctfontdescriptor = old->ctfontdescriptor;
+  CFRetain (key->ctfontdescriptor);
   key->matrix = old->matrix;
-  key->desc = pango_font_description_copy (old->desc);
-  key->postscript_name = g_strdup (old->postscript_name);
+  key->pixelsize = old->pixelsize;
+  key->resolution = old->resolution;
+  key->synthetic_italic = old->synthetic_italic;
+  key->gravity = old->gravity;
   if (old->context_key)
     key->context_key = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap, old->context_key);
   else
@@ -694,73 +918,140 @@ font_hash_key_copy (FontHashKey *old)
   return key;
 }
 
-
 static void
-get_context_matrix (PangoContext *context,
-		    PangoMatrix *matrix)
+pango_core_text_font_key_free (PangoCoreTextFontKey *key)
 {
-  const PangoMatrix *set_matrix;
-  static const PangoMatrix identity = PANGO_MATRIX_INIT;
+  if (key->ctfontdescriptor)
+    CFRelease (key->ctfontdescriptor);
 
-  if (context)
-    set_matrix = pango_context_get_matrix (context);
-  else
-    set_matrix = NULL;
+  if (key->context_key)
+    PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap, key->context_key);
 
-  if (set_matrix)
-    *matrix = *set_matrix;
-  else
-    *matrix = identity;
+  g_slice_free (PangoCoreTextFontKey, key);
 }
 
-static void
-font_hash_key_for_context (PangoCoreTextFontMap *fcfontmap,
-                           PangoContext         *context,
-                           FontHashKey          *key)
+static guint
+pango_core_text_font_key_hash (const PangoCoreTextFontKey *key)
 {
-  key->fontmap = fcfontmap;
-  get_context_matrix (context, &key->matrix);
+  guint32 hash = FNV1_32_INIT;
+
+  /* Not everything is included here, probably good enough for a hash */
+
+  hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
+
+  if (key->context_key)
+    hash ^= PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap, key->context_key);
 
-  if (PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get)
-    key->context_key = (gpointer)PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get (fcfontmap, context);
+  return (hash ^ CFHash (key->ctfontdescriptor));
+}
+
+static gboolean
+pango_core_text_font_key_equal (const PangoCoreTextFontKey *key_a,
+                                const PangoCoreTextFontKey *key_b)
+{
+  if (CFEqual (key_a->ctfontdescriptor, key_b->ctfontdescriptor) &&
+      memcmp (&key_a->matrix, &key_b->matrix, 4 * sizeof (double)) == 0 &&
+      key_a->gravity == key_b->gravity &&
+      key_a->pixelsize == key_b->pixelsize &&
+      key_a->resolution == key_b->resolution &&
+      key_a->synthetic_italic == key_b->synthetic_italic)
+    {
+      if (key_a->context_key && key_b->context_key)
+        return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
+                                                                                       key_a->context_key,
+                                                                                       key_b->context_key);
+      else
+        return key_a->context_key == key_b->context_key;
+    }
   else
-    key->context_key = NULL;
+    return FALSE;
+}
+
+int
+pango_core_text_font_key_get_absolute_size (const PangoCoreTextFontKey *key)
+{
+  return key->pixelsize;
+}
+
+double
+pango_core_text_font_key_get_resolution (const PangoCoreTextFontKey *key)
+{
+  return key->resolution;
+}
+
+gboolean
+pango_core_text_font_key_get_synthetic_italic (const PangoCoreTextFontKey *key)
+{
+  return key->synthetic_italic;
+}
+
+gpointer
+pango_core_text_font_key_get_context_key (const PangoCoreTextFontKey *key)
+{
+  return key->context_key;
+}
+
+const PangoMatrix *
+pango_core_text_font_key_get_matrix (const PangoCoreTextFontKey *key)
+{
+  return &key->matrix;
+}
+
+PangoGravity
+pango_core_text_font_key_get_gravity (const PangoCoreTextFontKey *key)
+{
+  return key->gravity;
+}
+
+CTFontDescriptorRef
+pango_core_text_font_key_get_ctfontdescriptor (const PangoCoreTextFontKey *key)
+{
+  return key->ctfontdescriptor;
 }
 
+
+
 static void
 pango_core_text_font_map_add (PangoCoreTextFontMap *ctfontmap,
-                              PangoContext         *context,
+                              PangoCoreTextFontKey *key,
                               PangoCoreTextFont    *ctfont)
 {
-  FontHashKey key;
-  FontHashKey *key_copy;
-  PangoCoreTextFace *face;
+  PangoCoreTextFontKey *key_copy;
 
   _pango_core_text_font_set_font_map (ctfont, ctfontmap);
 
-  font_hash_key_for_context (ctfontmap, context, &key);
-  face = _pango_core_text_font_get_face (ctfont);
-  key.postscript_name = (char *)_pango_core_text_face_get_postscript_name (face);
-  key.desc = _pango_core_text_font_get_font_description (ctfont);
-
-  key_copy = font_hash_key_copy (&key);
-  _pango_core_text_font_set_context_key (ctfont, key_copy->context_key);
-  g_hash_table_insert (ctfontmap->font_hash, key_copy, g_object_ref (ctfont));
+  key_copy = pango_core_text_font_key_copy (key);
+  _pango_core_text_font_set_font_key (ctfont, key_copy);
+  g_hash_table_insert (ctfontmap->font_hash, key_copy, ctfont);
 }
 
 static PangoCoreTextFont *
-pango_core_text_font_map_lookup (PangoCoreTextFontMap *ctfontmap,
-                                 PangoContext         *context,
-                                 PangoFontDescription *desc,
-                                 PangoCoreTextFace    *face)
+pango_core_text_font_map_new_font (PangoCoreTextFontMap    *fontmap,
+                                   PangoCoreTextFontsetKey *fontset_key,
+                                   CTFontDescriptorRef      ctfontdescriptor,
+                                   gboolean                 synthetic_italic)
 {
-  FontHashKey key;
+  PangoCoreTextFontMapClass *klass;
+  PangoCoreTextFont *font;
+  PangoCoreTextFontKey key;
+
+  pango_core_text_font_key_init (&key, fontmap, fontset_key, ctfontdescriptor,
+                                 synthetic_italic);
+
+  font = g_hash_table_lookup (fontmap->font_hash, &key);
+  if (font)
+    return g_object_ref (font);
 
-  font_hash_key_for_context (ctfontmap, context, &key);
-  key.postscript_name = (char *)_pango_core_text_face_get_postscript_name (face);
-  key.desc = desc;
+  /* Call create_font */
+  klass = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap);
+  font = klass->create_font (fontmap, &key);
 
-  return g_hash_table_lookup (ctfontmap->font_hash, &key);
+  if (!font)
+    return NULL;
+
+  pango_core_text_font_map_add (fontmap, &key, font);
+
+  return font;
 }
 
 static gboolean
@@ -795,73 +1086,44 @@ find_best_match (PangoCoreTextFamily         *font_family,
   return FALSE;
 }
 
+static gboolean
+get_first_font (PangoFontset *fontset G_GNUC_UNUSED,
+                PangoFont    *font,
+                gpointer      data)
+{
+  *(PangoFont **)data = font;
+
+  return TRUE;
+}
+
 static PangoFont *
 pango_core_text_font_map_load_font (PangoFontMap               *fontmap,
                                     PangoContext               *context,
                                     const PangoFontDescription *description)
 {
-  PangoCoreTextFontMap *ctfontmap = (PangoCoreTextFontMap *)fontmap;
-  PangoCoreTextFamily *font_family;
-  const gchar *family;
-  gchar *name;
-  gint size;
-  gboolean is_absolute;
+  PangoLanguage *language;
+  PangoFontset *fontset;
+  PangoFont *font = NULL;
 
-  size = pango_font_description_get_size (description);
-  if (size < 0)
-    return NULL;
+  if (context)
+    language = pango_context_get_language (context);
+  else
+    language = NULL;
 
-  is_absolute = pango_font_description_get_size_is_absolute (description);
+  fontset = pango_font_map_load_fontset (fontmap, context,
+                                         description, language);
 
-  family = pango_font_description_get_family (description);
-  family = family ? family : "";
-  name = g_utf8_casefold (family, -1);
-  font_family = g_hash_table_lookup (ctfontmap->families, name);
-  g_free (name);
-
-  if (font_family)
+  if (fontset)
     {
-      PangoFontDescription *best_description;
-      PangoCoreTextFace *best_face;
-      PangoCoreTextFont *best_font;
-
-      /* Force a listing of the available faces */
-      pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
-
-      if (!find_best_match (font_family, description, &best_description, &best_face))
-	return NULL;
-      
-      if (is_absolute)
-        pango_font_description_set_absolute_size (best_description, size);
-      else
-        pango_font_description_set_size (best_description, size);
-
-      best_font = pango_core_text_font_map_lookup (ctfontmap,
-                                                   context,
-                                                   best_description,
-                                                   best_face);
-
-      if (best_font)
-        g_object_ref (best_font);
-      else
-        {
-          PangoCoreTextFontMapClass *klass;
-
-          klass = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (ctfontmap);
-          best_font = klass->create_font (ctfontmap, context,
-                                          best_face, best_description);
-
-          if (best_font)
-            pango_core_text_font_map_add (ctfontmap, context, best_font);
-          /* FIXME: Handle the else case here. */
-        }
+      pango_fontset_foreach (fontset, get_first_font, &font);
 
-      pango_font_description_free (best_description);
+      if (font)
+        g_object_ref (font);
 
-      return (PangoFont *)best_font;
+      g_object_unref (fontset);
     }
 
-  return NULL;
+  return font;
 }
 
 static void
@@ -909,6 +1171,63 @@ pango_core_text_font_map_list_families (PangoFontMap      *fontmap,
   g_slist_free (family_list);
 }
 
+static PangoFontset *
+pango_core_text_font_map_load_fontset (PangoFontMap               *fontmap,
+                                       PangoContext               *context,
+                                       const PangoFontDescription *desc,
+                                       PangoLanguage              *language)
+{
+  PangoCoreTextFontset *fontset;
+  PangoCoreTextFontsetKey key;
+  PangoCoreTextFontMap *ctfontmap = PANGO_CORE_TEXT_FONT_MAP (fontmap);
+
+  pango_core_text_fontset_key_init (&key, ctfontmap,
+                                    context, desc, language);
+
+  fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
+
+  if (G_UNLIKELY (!fontset))
+    {
+      fontset = pango_core_text_fontset_new (&key, desc);
+
+      if (G_LIKELY (fontset))
+        g_hash_table_insert (ctfontmap->fontset_hash,
+                             pango_core_text_fontset_get_key (fontset),
+                             fontset);
+      else
+        {
+          /* If no font(set) could be loaded, we fallback to "Sans",
+           * which should always work on Mac.
+           */
+          PangoFontDescription *tmp_desc;
+
+          /* Cannot use pango_core_text_fontset_key_free() here */
+          pango_font_description_free (key.desc);
+
+          tmp_desc = pango_font_description_copy_static (desc);
+          pango_font_description_set_family_static (tmp_desc, "Sans");
+
+          pango_core_text_fontset_key_init (&key, ctfontmap, context, tmp_desc,
+                                            language);
+
+          fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
+          if (G_UNLIKELY (!fontset))
+            {
+              fontset = pango_core_text_fontset_new (&key, tmp_desc);
+              g_hash_table_insert (ctfontmap->fontset_hash,
+                                   pango_core_text_fontset_get_key (fontset),
+                                   fontset);
+
+            }
+        }
+    }
+
+  /* Cannot use pango_core_text_fontset_key_free() here */
+  pango_font_description_free (key.desc);
+
+  return g_object_ref (fontset);
+}
+
 static void
 pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
 {
@@ -921,18 +1240,23 @@ pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
                                                g_free, g_object_unref);
 
 
-  ctfontmap->font_hash = g_hash_table_new_full ((GHashFunc)font_hash_key_hash,
-                                                (GEqualFunc)font_hash_key_equal,
-                                                (GDestroyNotify)font_hash_key_free,
+  ctfontmap->font_hash = g_hash_table_new_full ((GHashFunc)pango_core_text_font_key_hash,
+                                                (GEqualFunc)pango_core_text_font_key_equal,
+                                                (GDestroyNotify)pango_core_text_font_key_free,
                                                 NULL);
 
+  ctfontmap->fontset_hash = g_hash_table_new_full ((GHashFunc)pango_core_text_fontset_key_hash,
+                                                   (GEqualFunc)pango_core_text_fontset_key_equal,
+                                                   NULL,
+                                                   (GDestroyNotify)g_object_unref);
+
   collection = CTFontCollectionCreateFromAvailableFonts (0);
   ctfaces = CTFontCollectionCreateMatchingFontDescriptors (collection);
   count = CFArrayGetCount (ctfaces);
 
   for (i = 0; i < count; i++)
     {
-      int font_traits;
+      SInt64 font_traits;
       char *buffer;
       char *family_name;
       CFStringRef str;
@@ -965,9 +1289,9 @@ pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
       number = (CFNumberRef)CFDictionaryGetValue (dict,
                                                   kCTFontSymbolicTrait);
 
-      if (CFNumberGetValue (number, kCFNumberIntType, &font_traits))
+      if (CFNumberGetValue (number, kCFNumberSInt64Type, &font_traits))
         {
-          if (font_traits & kCTFontMonoSpaceTrait)
+          if ((font_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait)
             family->is_monospace = TRUE;
         }
 
@@ -1002,5 +1326,295 @@ pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class)
 
   fontmap_class->load_font = pango_core_text_font_map_load_font;
   fontmap_class->list_families = pango_core_text_font_map_list_families;
+  fontmap_class->load_fontset = pango_core_text_font_map_load_fontset;
   fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_CORE_TEXT;
 }
+
+/*
+ * PangoCoreTextFontSet
+ */
+
+static void              pango_core_text_fontset_finalize     (GObject                   *object);
+static void              pango_core_text_fontset_init         (PangoCoreTextFontset      *fontset);
+static PangoLanguage *   pango_core_text_fontset_get_language (PangoFontset              *fontset);
+static  PangoFont *      pango_core_text_fontset_get_font     (PangoFontset              *fontset,
+                                                               guint                      wc);
+static void              pango_core_text_fontset_foreach      (PangoFontset              *fontset,
+                                                               PangoFontsetForeachFunc    func,
+                                                               gpointer                   data);
+
+struct _PangoCoreTextFontset
+{
+  PangoFontset parent_instance;
+
+  const gchar *orig_family;
+  PangoFontDescription *orig_description;
+
+  PangoCoreTextFontsetKey *key;
+  CFArrayRef cascade_list;
+
+  GPtrArray *fonts;
+  GPtrArray *coverages;
+};
+
+typedef PangoFontsetClass PangoCoreTextFontsetClass;
+
+static PangoFontsetClass *core_text_fontset_parent_class;
+
+
+/* This symbol does exist in the CoreText library shipped with Snow
+ * Leopard and Lion, however, it is not found in the public header files.
+ */
+CFArrayRef CTFontCopyDefaultCascadeList (CTFontRef font_ref);
+
+static PangoCoreTextFontset *
+pango_core_text_fontset_new (PangoCoreTextFontsetKey    *key,
+                             const PangoFontDescription *description)
+{
+  PangoCoreTextFamily *font_family;
+  PangoCoreTextFontset *fontset;
+  PangoCoreTextFont *best_font = NULL;
+  const gchar *family;
+  gchar *name;
+
+  family = pango_font_description_get_family (description);
+  family = family ? family : "";
+  name = g_utf8_casefold (family, -1);
+  font_family = g_hash_table_lookup (key->fontmap->families, name);
+  g_free (name);
+
+  if (font_family)
+    {
+      PangoFontDescription *best_description;
+      PangoCoreTextFace *best_face;
+      gint size;
+      gboolean is_absolute;
+
+      /* Force a listing of the available faces */
+      pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
+
+      if (!find_best_match (font_family, description, &best_description, &best_face))
+	return NULL;
+
+      size = pango_font_description_get_size (description);
+      if (size < 0)
+        return NULL;
+
+      is_absolute = pango_font_description_get_size_is_absolute (description);
+      if (is_absolute)
+        pango_font_description_set_absolute_size (best_description, size);
+      else
+        pango_font_description_set_size (best_description, size);
+
+      best_font = pango_core_text_font_map_new_font (key->fontmap,
+                                                     key,
+                                                     best_face->ctfontdescriptor,
+                                                     best_face->synthetic_italic);
+
+      pango_font_description_free (best_description);
+    }
+  else
+    return NULL;
+
+  if (!best_font)
+    return NULL;
+
+  /* Create a font set with best font */
+  fontset = g_object_new (PANGO_TYPE_CORE_TEXT_FONTSET, NULL);
+  fontset->key = pango_core_text_fontset_key_copy (key);
+  fontset->orig_description = pango_font_description_copy (description);
+
+  fontset->fonts = g_ptr_array_new ();
+  g_ptr_array_add (fontset->fonts, best_font);
+  fontset->coverages = g_ptr_array_new ();
+
+  /* Add the cascade list for this language */
+  fontset->cascade_list = CTFontCopyDefaultCascadeList (pango_core_text_font_get_ctfont (best_font));
+
+  /* length of cascade list + 1 for the "real" font at the front */
+  g_ptr_array_set_size (fontset->fonts, CFArrayGetCount (fontset->cascade_list) + 1);
+  g_ptr_array_set_size (fontset->coverages, CFArrayGetCount (fontset->cascade_list) + 1);
+
+  return fontset;
+}
+
+static PangoFont *
+pango_core_text_fontset_load_font (PangoCoreTextFontset *ctfontset,
+                                   CTFontDescriptorRef   ctdescriptor)
+{
+  PangoCoreTextFontsetKey *key;
+  PangoCoreTextFont *font;
+
+  key = pango_core_text_fontset_get_key (ctfontset);
+
+  /* For now, we will default the fallbacks to not have synthetic italic,
+   * in the future this may be improved.
+   */
+  font = pango_core_text_font_map_new_font (ctfontset->key->fontmap,
+                                            ctfontset->key,
+                                            ctdescriptor,
+                                            FALSE);
+
+  return PANGO_FONT (font);
+}
+
+static PangoFont *
+pango_core_text_fontset_get_font_at (PangoCoreTextFontset *ctfontset,
+                                     unsigned int          i)
+{
+  /* The first font is loaded as soon as the fontset is created */
+  if (i == 0)
+    return g_ptr_array_index (ctfontset->fonts, i);
+
+  if (i >= ctfontset->fonts->len)
+    return NULL;
+
+  if (g_ptr_array_index (ctfontset->fonts, i) == NULL)
+    {
+      CTFontDescriptorRef ctdescriptor = CFArrayGetValueAtIndex (ctfontset->cascade_list, i - 1);
+      PangoFont *font = pango_core_text_fontset_load_font (ctfontset, ctdescriptor);
+      g_ptr_array_index (ctfontset->fonts, i) = font;
+      g_ptr_array_index (ctfontset->coverages, i) = NULL;
+    }
+
+  return g_ptr_array_index (ctfontset->fonts, i);
+}
+
+static void
+pango_core_text_fontset_class_init (PangoCoreTextFontsetClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  PangoFontsetClass *fontset_class = PANGO_FONTSET_CLASS (klass);
+
+  core_text_fontset_parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = pango_core_text_fontset_finalize;
+
+  fontset_class->get_font = pango_core_text_fontset_get_font;
+  fontset_class->get_language = pango_core_text_fontset_get_language;
+  fontset_class->foreach = pango_core_text_fontset_foreach;
+}
+
+static void
+pango_core_text_fontset_init (PangoCoreTextFontset *ctfontset)
+{
+  ctfontset->key = NULL;
+  ctfontset->cascade_list = NULL;
+  ctfontset->fonts = g_ptr_array_new ();
+  ctfontset->coverages = g_ptr_array_new ();
+}
+
+static void
+pango_core_text_fontset_finalize (GObject *object)
+{
+  PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (object);
+  unsigned int i;
+
+  for (i = 0; i < ctfontset->fonts->len; i++)
+    {
+      PangoFont *font = g_ptr_array_index (ctfontset->fonts, i);
+      if (font)
+        g_object_unref (font);
+    }
+  g_ptr_array_free (ctfontset->fonts, TRUE);
+
+  for (i = 0; i < ctfontset->coverages->len; i++)
+    {
+      PangoCoverage *coverage = g_ptr_array_index (ctfontset->coverages, i);
+      if (coverage)
+        pango_coverage_unref (coverage);
+    }
+  g_ptr_array_free (ctfontset->coverages, TRUE);
+
+  CFRelease (ctfontset->cascade_list);
+
+  pango_font_description_free (ctfontset->orig_description);
+
+  if (ctfontset->key)
+    pango_core_text_fontset_key_free (ctfontset->key);
+
+  G_OBJECT_CLASS (core_text_fontset_parent_class)->finalize (object);
+}
+
+static PangoCoreTextFontsetKey *
+pango_core_text_fontset_get_key (PangoCoreTextFontset *fontset)
+{
+  return fontset->key;
+}
+
+static PangoLanguage *
+pango_core_text_fontset_get_language (PangoFontset *fontset)
+{
+  PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (fontset);
+
+  return pango_core_text_fontset_key_get_language (pango_core_text_fontset_get_key (ctfontset));
+}
+
+static PangoFont *
+pango_core_text_fontset_get_font (PangoFontset *fontset,
+                                  guint         wc)
+{
+  PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (fontset);
+  PangoCoverageLevel best_level = PANGO_COVERAGE_NONE;
+  PangoCoverageLevel level;
+  PangoFont *font;
+  PangoCoverage *coverage;
+  int result = -1;
+  unsigned int i;
+
+  for (i = 0; i < ctfontset->fonts->len; i++)
+    {
+      PangoFont *font = pango_core_text_fontset_get_font_at (ctfontset, i);
+      if (!font)
+        continue;
+
+      coverage = g_ptr_array_index (ctfontset->coverages, i);
+
+      if (coverage == NULL)
+        {
+          font = g_ptr_array_index (ctfontset->fonts, i);
+
+          coverage = pango_font_get_coverage (font, ctfontset->key->language);
+          g_ptr_array_index (ctfontset->coverages, i) = coverage;
+        }
+
+      level = pango_coverage_get (coverage, wc);
+
+      if (result == -1 || level > best_level)
+        {
+          result = i;
+          best_level = level;
+          if (level == PANGO_COVERAGE_EXACT)
+            break;
+        }
+    }
+
+  if (G_UNLIKELY (result == -1))
+    return NULL;
+
+  font = g_ptr_array_index (ctfontset->fonts, result);
+  return g_object_ref (font);
+}
+
+static void
+pango_core_text_fontset_foreach (PangoFontset *fontset,
+                                 PangoFontsetForeachFunc func,
+                                 gpointer data)
+{
+  PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (fontset);
+  unsigned int i;
+
+  for (i = 0; i < ctfontset->fonts->len; i++)
+    {
+      PangoFont *font = pango_core_text_fontset_get_font_at (ctfontset, i);
+      if (!font)
+        continue;
+
+      if ((* func) (fontset, font, data))
+        return;
+    }
+}
+
+G_DEFINE_TYPE (PangoCoreTextFontset,
+               pango_core_text_fontset,
+               PANGO_TYPE_FONTSET);
diff --git a/pango/pangocoretext-private.h b/pango/pangocoretext-private.h
index 4ed0e8e..3e0dafd 100644
--- a/pango/pangocoretext-private.h
+++ b/pango/pangocoretext-private.h
@@ -44,10 +44,14 @@ typedef struct _PangoCoreTextFace         PangoCoreTextFace;
 typedef struct _PangoCoreTextFontMap      PangoCoreTextFontMap;
 typedef struct _PangoCoreTextFontMapClass PangoCoreTextFontMapClass;
 
+typedef struct _PangoCoreTextFontsetKey   PangoCoreTextFontsetKey;
+typedef struct _PangoCoreTextFontKey      PangoCoreTextFontKey;
+
 struct _PangoCoreTextFontMap
 {
   PangoFontMap parent_instance;
 
+  GHashTable *fontset_hash;
   GHashTable *font_hash;
 
   GHashTable *families;
@@ -70,22 +74,15 @@ struct _PangoCoreTextFontMapClass
                                       gconstpointer           key_b);
 
   PangoCoreTextFont * (* create_font)   (PangoCoreTextFontMap       *fontmap,
-                                         PangoContext               *context,
-                                         PangoCoreTextFace          *face,
-                                         const PangoFontDescription *desc);
+                                         PangoCoreTextFontKey       *key);
+
+  double              (* get_resolution) (PangoCoreTextFontMap      *fontmap,
+                                          PangoContext              *context);
 };
 
 
 GType                 pango_core_text_font_map_get_type          (void) G_GNUC_CONST;
 
-const char *          _pango_core_text_face_get_postscript_name  (PangoCoreTextFace    *face);
-gboolean              _pango_core_text_face_get_synthetic_italic (PangoCoreTextFace    *face);
-PangoCoverage *       _pango_core_text_face_get_coverage         (PangoCoreTextFace    *face,
-                                                                  PangoLanguage     *language);
-
-void                  _pango_core_text_font_set_font_description (PangoCoreTextFont    *afont,
-                                                                  const PangoFontDescription *desc);
-PangoFontDescription *_pango_core_text_font_get_font_description (PangoCoreTextFont    *afont);
 void                  _pango_core_text_font_set_font_map         (PangoCoreTextFont    *afont,
                                                                   PangoCoreTextFontMap *fontmap);
 void                  _pango_core_text_font_set_face             (PangoCoreTextFont    *afont, 
@@ -94,9 +91,21 @@ PangoCoreTextFace *   _pango_core_text_font_get_face             (PangoCoreTextF
 gpointer              _pango_core_text_font_get_context_key      (PangoCoreTextFont    *afont);
 void                  _pango_core_text_font_set_context_key      (PangoCoreTextFont    *afont,
                                                                   gpointer           context_key);
+void                  _pango_core_text_font_set_font_key         (PangoCoreTextFont    *font,
+                                                                  PangoCoreTextFontKey *key);
 void                  _pango_core_text_font_set_ctfont           (PangoCoreTextFont    *font,
                                                                   CTFontRef         font_ref);
 
+PangoFontDescription *_pango_core_text_font_description_from_ct_font_descriptor (CTFontDescriptorRef desc);
+
+int                   pango_core_text_font_key_get_absolute_size    (const PangoCoreTextFontKey *key);
+double                pango_core_text_font_key_get_resolution       (const PangoCoreTextFontKey *key);
+gboolean              pango_core_text_font_key_get_synthetic_italic (const PangoCoreTextFontKey *key);
+gpointer              pango_core_text_font_key_get_context_key      (const PangoCoreTextFontKey *key);
+const PangoMatrix    *pango_core_text_font_key_get_matrix           (const PangoCoreTextFontKey *key);
+PangoGravity          pango_core_text_font_key_get_gravity          (const PangoCoreTextFontKey *key);
+CTFontDescriptorRef   pango_core_text_font_key_get_ctfontdescriptor (const PangoCoreTextFontKey *key);
+
 G_END_DECLS
 
 #endif /* __PANGOCORETEXT_PRIVATE_H__ */
diff --git a/pango/pangocoretext.c b/pango/pangocoretext.c
index 36e5a37..5023e93 100644
--- a/pango/pangocoretext.c
+++ b/pango/pangocoretext.c
@@ -30,10 +30,12 @@ G_DEFINE_TYPE (PangoCoreTextFont, pango_core_text_font, PANGO_TYPE_FONT);
 struct _PangoCoreTextFontPrivate
 {
   PangoCoreTextFace *face;
-  PangoFontDescription *desc;
   gpointer context_key;
 
   CTFontRef font_ref;
+  PangoCoreTextFontKey *key;
+
+  PangoCoverage *coverage;
 
   PangoFontMap *fontmap;
 };
@@ -44,12 +46,13 @@ pango_core_text_font_finalize (GObject *object)
   PangoCoreTextFont *ctfont = (PangoCoreTextFont *)object;
   PangoCoreTextFontPrivate *priv = ctfont->priv;
 
-  pango_font_description_free (priv->desc);
-
   g_assert (priv->fontmap != NULL);
   g_object_remove_weak_pointer (G_OBJECT (priv->fontmap), (gpointer *) (gpointer) &priv->fontmap);
   priv->fontmap = NULL;
 
+  if (priv->coverage)
+    pango_coverage_unref (priv->coverage);
+
   G_OBJECT_CLASS (pango_core_text_font_parent_class)->finalize (object);
 }
 
@@ -58,8 +61,47 @@ pango_core_text_font_describe (PangoFont *font)
 {
   PangoCoreTextFont *ctfont = (PangoCoreTextFont *)font;
   PangoCoreTextFontPrivate *priv = ctfont->priv;
+  CTFontDescriptorRef ctfontdesc;
+
+  ctfontdesc = pango_core_text_font_key_get_ctfontdescriptor (priv->key);
+
+  return _pango_core_text_font_description_from_ct_font_descriptor (ctfontdesc);
+}
+
+static PangoCoverage *
+ct_font_descriptor_get_coverage (CTFontDescriptorRef desc)
+{
+  CFCharacterSetRef charset;
+  CFIndex i, length;
+  CFDataRef bitmap;
+  const UInt8 *ptr;
+  PangoCoverage *coverage;
 
-  return pango_font_description_copy (priv->desc);
+  coverage = pango_coverage_new ();
+
+  charset = CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
+  bitmap = CFCharacterSetCreateBitmapRepresentation (kCFAllocatorDefault,
+                                                     charset);
+
+  /* We only handle the BMP plane */
+  length = MIN (CFDataGetLength (bitmap), 8192);
+  ptr = CFDataGetBytePtr (bitmap);
+
+  /* FIXME: can and should this be done more efficiently? */
+  for (i = 0; i < length; i++)
+    {
+      int j;
+
+      for (j = 0; j < 8; j++)
+        pango_coverage_set (coverage, i * 8 + j,
+                            ((ptr[i] & (1 << j)) == (1 << j)) ?
+                            PANGO_COVERAGE_EXACT : PANGO_COVERAGE_NONE);
+    }
+
+  CFRelease (bitmap);
+  CFRelease (charset);
+
+  return coverage;
 }
 
 static PangoCoverage *
@@ -69,8 +111,16 @@ pango_core_text_font_get_coverage (PangoFont     *font,
   PangoCoreTextFont *ctfont = (PangoCoreTextFont *)font;
   PangoCoreTextFontPrivate *priv = ctfont->priv;
 
-  return pango_coverage_ref (_pango_core_text_face_get_coverage (priv->face,
-                                                                 language));
+  if (!priv->coverage)
+    {
+      CTFontDescriptorRef ctfontdesc;
+
+      ctfontdesc = pango_core_text_font_key_get_ctfontdescriptor (priv->key);
+
+      priv->coverage = ct_font_descriptor_get_coverage (ctfontdesc);
+    }
+
+  return pango_coverage_ref (priv->coverage);
 }
 
 static PangoEngineShape *
@@ -115,23 +165,6 @@ pango_core_text_font_class_init (PangoCoreTextFontClass *class)
 }
 
 void
-_pango_core_text_font_set_font_description (PangoCoreTextFont          *font,
-                                            const PangoFontDescription *desc)
-{
-  PangoCoreTextFontPrivate *priv = font->priv;
-
-  priv->desc = pango_font_description_copy (desc);
-}
-
-PangoFontDescription *
-_pango_core_text_font_get_font_description (PangoCoreTextFont *font)
-{
-  PangoCoreTextFontPrivate *priv = font->priv;
-
-  return priv->desc;
-}
-
-void
 _pango_core_text_font_set_font_map (PangoCoreTextFont    *font,
                                     PangoCoreTextFontMap *fontmap)
 {
@@ -177,6 +210,21 @@ _pango_core_text_font_set_context_key (PangoCoreTextFont *font,
 }
 
 void
+_pango_core_text_font_set_font_key (PangoCoreTextFont    *font,
+                                    PangoCoreTextFontKey *key)
+{
+  PangoCoreTextFontPrivate *priv = font->priv;
+
+  priv->key = key;
+
+  if (priv->coverage)
+    {
+      pango_coverage_unref (priv->coverage);
+      priv->coverage = NULL;
+    }
+}
+
+void
 _pango_core_text_font_set_ctfont (PangoCoreTextFont *font,
                                   CTFontRef          font_ref)
 {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]