b=385263 a PangoFcFont using tree cairo r=roc
authorKarl Tomlinson <karlt+@karlt.net>
Sat, 27 Sep 2008 12:21:55 +1200
changeset 19807 25ca781361ed
parent 19806 03e2e5e8dad7
child 19808 406819ca370c
push id2456
push userktomlinson@mozilla.com
push date2008-09-27 00:22 +0000
treeherdermozilla-central@406819ca370c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs385263
milestone1.9.1b1pre
b=385263 a PangoFcFont using tree cairo r=roc
gfx/thebes/public/gfxPangoFonts.h
gfx/thebes/src/gfxBeOSPlatform.cpp
gfx/thebes/src/gfxPangoFonts.cpp
gfx/thebes/src/gfxPlatformGtk.cpp
--- a/gfx/thebes/public/gfxPangoFonts.h
+++ b/gfx/thebes/public/gfxPangoFonts.h
@@ -65,77 +65,38 @@ public:
     gfxPangoFontEntry(const nsAString& aName)
         : gfxFontEntry(aName)
     { }
 
     ~gfxPangoFontEntry() {}
         
 };
 
-class gfxPangoFont : public gfxFont {
-public:
-    gfxPangoFont (gfxPangoFontEntry *aFontEntry,
-                  const gfxFontStyle *aFontStyle);
-    virtual ~gfxPangoFont ();
-    static already_AddRefed<gfxPangoFont> GetOrMakeFont(PangoFont *aPangoFont);
-
-    static void Shutdown();
-
-    virtual const gfxFont::Metrics& GetMetrics();
-
-    PangoFont *GetPangoFont() { if (!mPangoFont) RealizePangoFont(); return mPangoFont; }
-
-    // Check GetStyle()->sizeAdjust != 0.0 before calling this 
-    gfxFloat GetAdjustedSize() { if (!mPangoFont) RealizePangoFont(); return mAdjustedSize; }
-
-    virtual nsString GetUniqueName();
-
-    // Get the glyphID of a space
-    virtual PRUint32 GetSpaceGlyph() {
-        NS_ASSERTION(GetStyle()->size != 0,
-                     "forgot to short-circuit a text run with zero-sized font?");
-        GetMetrics();
-        return mSpaceGlyph;
-    }
-
-protected:
-    PangoFont *mPangoFont;
-    cairo_scaled_font_t *mCairoFont;
-
-    PRBool   mHasMetrics;
-    PRUint32 mSpaceGlyph;
-    Metrics  mMetrics;
-    gfxFloat mAdjustedSize;
-
-    gfxPangoFont(PangoFont *aPangoFont, gfxPangoFontEntry *aFontEntry,
-                 const gfxFontStyle *aFontStyle);
-    void RealizePangoFont();
-    void GetCharSize(const char aChar, gfxSize& aInkSize, gfxSize& aLogSize,
-                     PRUint32 *aGlyphID = nsnull);
-
-    virtual PRBool SetupCairoFont(gfxContext *aContext);
-};
-
 class THEBES_API gfxPangoFontGroup : public gfxFontGroup {
 public:
     gfxPangoFontGroup (const nsAString& families,
                        const gfxFontStyle *aStyle);
     virtual ~gfxPangoFontGroup ();
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
     // Create and initialize a textrun using Pango
     virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
                                     const Parameters *aParams, PRUint32 aFlags);
     virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
                                     const Parameters *aParams, PRUint32 aFlags);
 
-    virtual gfxPangoFont *GetFontAt(PRInt32 i);
+    virtual gfxFont *GetFontAt(PRInt32 i);
+
+    static void Shutdown();
 
 protected:
+    PangoFont *mBasePangoFont;
+    gfxFloat mAdjustedSize;
+
     // ****** Textrun glyph conversion helpers ******
 
     /**
      * Fill in the glyph-runs for the textrun.
      * @param aTake8BitPath the text contains only characters below 0x100
      * (TEXT_IS_8BIT can return false when the characters are all below 0x100
      * but stored in UTF16 format)
      */
@@ -157,16 +118,25 @@ protected:
                                   PRUint32 aUTF8HeaderLength);
 #if defined(ENABLE_FAST_PATH_8BIT) || defined(ENABLE_FAST_PATH_ALWAYS)
     PRBool CanTakeFastPath(PRUint32 aFlags);
     nsresult CreateGlyphRunsFast(gfxTextRun *aTextRun,
                                  const gchar *aUTF8, PRUint32 aUTF8Length);
 #endif
 
     void GetFcFamilies(nsAString &aFcFamilies);
+    PangoFont *GetBasePangoFont();
+
+    // Check GetStyle()->sizeAdjust != 0.0 before calling this 
+    gfxFloat GetAdjustedSize()
+    {
+        if (!mBasePangoFont)
+            GetBasePangoFont();
+        return mAdjustedSize;
+    }
 };
 
 class gfxPangoFontWrapper {
 public:
     gfxPangoFontWrapper(PangoFont *aFont) {
         mFont = aFont;
         g_object_ref(mFont);
     }
--- a/gfx/thebes/src/gfxBeOSPlatform.cpp
+++ b/gfx/thebes/src/gfxBeOSPlatform.cpp
@@ -50,17 +50,17 @@ gfxBeOSPlatform::gfxBeOSPlatform()
         sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
 }
 
 gfxBeOSPlatform::~gfxBeOSPlatform()
 {
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nsnull;
 
-    gfxPangoFont::Shutdown();
+    gfxPangoFontGroup::Shutdown();
 
 #if 0
     // It would be nice to do this (although it might need to be after
     // the cairo shutdown that happens in ~gfxPlatform).  It even looks
     // idempotent.  But it has fatal assertions that fire if stuff is
     // leaked, and we hit them.
     FcFini();
 #endif
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -55,21 +55,21 @@
 #include "gfxPangoFonts.h"
 #include "gfxFontconfigUtils.h"
 
 #include <freetype/tttables.h>
 
 #include <cairo.h>
 #include <cairo-ft.h>
 
+#include <fontconfig/fcfreetype.h>
 #include <pango/pango.h>
-#include <pango/pangocairo.h>
 #include <pango/pangofc-fontmap.h>
 
-#include <gdk/gdkpango.h>
+#include <gdk/gdkscreen.h>
 
 #include <math.h>
 
 #define FLOAT_PANGO_SCALE ((gfxFloat)PANGO_SCALE)
 
 #ifndef PANGO_VERSION_CHECK
 #define PANGO_VERSION_CHECK(x,y,z) 0
 #endif
@@ -78,20 +78,295 @@
 #endif
 #ifndef PANGO_GLYPH_EMPTY
 #define PANGO_GLYPH_EMPTY           ((PangoGlyph)0)
 #endif
 // For g a PangoGlyph,
 #define IS_MISSING_GLYPH(g) ((g) & PANGO_GLYPH_UNKNOWN_FLAG)
 #define IS_EMPTY_GLYPH(g) ((g) == PANGO_GLYPH_EMPTY)
 
+// Same as pango_units_from_double from Pango 1.16 (but not in older versions)
+int moz_pango_units_from_double(double d) {
+    return NS_lround(d * FLOAT_PANGO_SCALE);
+}
+
 static PangoLanguage *GetPangoLanguage(const nsACString& aLangGroup);
 
+static cairo_scaled_font_t *CreateScaledFont(FcPattern *aPattern);
+
 /* static */ gfxPangoFontCache* gfxPangoFontCache::sPangoFontCache = nsnull;
 
+static PangoFontMap *gPangoFontMap;
+
+/*
+ * gfxFcFont
+ *
+ * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
+ * cairo_scaled_font created from an FcPattern.
+ */
+
+class gfxFcFont : public gfxFont {
+public:
+    virtual ~gfxFcFont ();
+    static already_AddRefed<gfxFcFont> GetOrMakeFont(FcPattern *aPattern);
+
+    virtual const gfxFont::Metrics& GetMetrics();
+
+    virtual nsString GetUniqueName();
+
+    // Get the glyphID of a space
+    virtual PRUint32 GetSpaceGlyph() {
+        NS_ASSERTION(GetStyle()->size != 0,
+                     "forgot to short-circuit a text run with zero-sized font?");
+        GetMetrics();
+        return mSpaceGlyph;
+    }
+
+    cairo_scaled_font_t *CairoScaledFont() { return mCairoFont; }
+    void GetGlyphExtents(PRUint32 aGlyph, cairo_text_extents_t* aExtents);
+
+protected:
+    cairo_scaled_font_t *mCairoFont;
+
+    PRUint32 mSpaceGlyph;
+    Metrics mMetrics;
+    PRPackedBool mHasMetrics;
+
+    gfxFcFont(cairo_scaled_font_t *aCairoFont,
+              gfxPangoFontEntry *aFontEntry, const gfxFontStyle *aFontStyle);
+
+    virtual PRBool SetupCairoFont(gfxContext *aContext);
+
+    // key for locating a gfxFcFont corresponding to a cairo_scaled_font
+    static cairo_user_data_key_t sGfxFontKey;
+};
+
+class LockedFTFace {
+public:
+    LockedFTFace(gfxFcFont *aFont)
+        : mGfxFont(aFont),
+          mFace(cairo_ft_scaled_font_lock_face(aFont->CairoScaledFont()))
+    {
+    }
+
+    ~LockedFTFace()
+    {
+        if (mFace) {
+            cairo_ft_scaled_font_unlock_face(mGfxFont->CairoScaledFont());
+        }
+    }
+
+    /**
+     * Get extents for a simple character representable by a single glyph.
+     * The return value is the glyph id of that glyph or zero if no such glyph
+     * exists.  aExtents is only set when this returns a non-zero glyph id.
+     */
+    PRUint32 GetCharExtents(char aChar, cairo_text_extents_t* aExtents);
+
+    void GetMetrics(gfxFont::Metrics* aMetrics, PRUint32* aSpaceGlyph);
+
+private:
+    nsRefPtr<gfxFcFont> mGfxFont;
+    FT_Face mFace;
+};
+
+/**
+ * gfxPangoFcFont:
+ *
+ * An implementation of PangoFcFont that wraps a gfxFont so that it can be
+ * passed to PangoRenderFc shapers.
+ */
+
+#define GFX_TYPE_PANGO_FC_FONT              (gfx_pango_fc_font_get_type())
+#define GFX_PANGO_FC_FONT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFont))
+#define GFX_IS_PANGO_FC_FONT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FC_FONT))
+
+/* static */
+GType gfx_pango_fc_font_get_type (void);
+
+#define GFX_PANGO_FC_FONT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFontClass))
+#define GFX_IS_PANGO_FC_FONT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FC_FONT))
+#define GFX_PANGO_FC_FONT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFontClass))
+
+// This struct is POD so that it can be used as a GObject.
+struct gfxPangoFcFont {
+    PangoFcFont parent_instance;
+
+    gfxFcFont *mGfxFont;
+
+    static gfxFcFont *GfxFont(gfxPangoFcFont *self)
+    {
+        if (!self->mGfxFont) {
+            FcPattern *pattern = PANGO_FC_FONT(self)->font_pattern;
+            self->mGfxFont = gfxFcFont::GetOrMakeFont(pattern).get();
+        }
+        return self->mGfxFont;
+    }
+
+    static cairo_scaled_font_t *CairoFont(gfxPangoFcFont *self)
+    {
+        return gfxPangoFcFont::GfxFont(self)->CairoScaledFont();
+    }
+};
+
+struct gfxPangoFcFontClass {
+    PangoFcFontClass parent_class;
+};
+
+G_DEFINE_TYPE (gfxPangoFcFont, gfx_pango_fc_font, PANGO_TYPE_FC_FONT)
+
+static void
+gfx_pango_fc_font_init(gfxPangoFcFont *fontset)
+{
+}
+
+
+static void
+gfx_pango_fc_font_finalize(GObject *object)
+{
+    gfxPangoFcFont *self = GFX_PANGO_FC_FONT(object);
+
+    if (self->mGfxFont)
+        self->mGfxFont->Release();
+
+    G_OBJECT_CLASS(gfx_pango_fc_font_parent_class)->finalize(object);
+}
+
+static void
+gfx_pango_fc_font_get_glyph_extents(PangoFont *font, PangoGlyph glyph,
+                                    PangoRectangle *ink_rect,
+                                    PangoRectangle *logical_rect)
+{
+    gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
+    gfxFcFont *gfxFont = gfxPangoFcFont::GfxFont(self);
+
+    if (IS_MISSING_GLYPH(glyph)) {
+        const gfxFont::Metrics& metrics = gfxFont->GetMetrics();
+
+        PangoRectangle rect;
+        rect.x = 0;
+        rect.y = moz_pango_units_from_double(-metrics.maxAscent);
+        rect.width = moz_pango_units_from_double(metrics.aveCharWidth);
+        rect.height = moz_pango_units_from_double(metrics.maxHeight);
+        if (ink_rect) {
+            *ink_rect = rect;
+        }
+        if (logical_rect) {
+            *logical_rect = rect;
+        }
+        return;
+    }
+
+    if (logical_rect) {
+        // logical_rect.width is possibly used by pango_ot_buffer_output (used
+        // by many shapers) and used by fallback_engine_shape (possibly used
+        // by pango_shape and pango_itemize when no glyphs are found).  I
+        // doubt the other fields will be used but we won't have any way to
+        // detecting if they are so we'd better set them.
+        const gfxFont::Metrics& metrics = gfxFont->GetMetrics();
+        logical_rect->y = moz_pango_units_from_double(-metrics.maxAscent);
+        logical_rect->height = moz_pango_units_from_double(metrics.maxHeight);
+    }
+
+    cairo_text_extents_t extents;
+    if (IS_EMPTY_GLYPH(glyph)) {
+        new (&extents) cairo_text_extents_t(); // zero
+    } else {
+        gfxFont->GetGlyphExtents(glyph, &extents);
+    }
+
+    if (ink_rect) {
+        ink_rect->x = moz_pango_units_from_double(extents.x_bearing);
+        ink_rect->y = moz_pango_units_from_double(extents.y_bearing);
+        ink_rect->width = moz_pango_units_from_double(extents.width);
+        ink_rect->height = moz_pango_units_from_double(extents.height);
+    }
+    if (logical_rect) {
+        logical_rect->x = 0;
+        logical_rect->width = moz_pango_units_from_double(extents.x_advance);
+    }
+}
+
+#ifdef DEBUG
+static PangoFontMetrics *
+gfx_pango_fc_font_get_metrics(PangoFont *font, PangoLanguage *language)
+{
+    NS_WARNING("Using PangoFcFont::get_metrics");
+
+    return PANGO_FONT_CLASS(gfx_pango_fc_font_parent_class)->
+        get_metrics(font, language);
+}
+#endif
+
+static FT_Face
+gfx_pango_fc_font_lock_face(PangoFcFont *font)
+{
+    gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
+    return cairo_ft_scaled_font_lock_face(gfxPangoFcFont::CairoFont(self));
+}
+
+static void
+gfx_pango_fc_font_unlock_face(PangoFcFont *font)
+{
+    gfxPangoFcFont *self = GFX_PANGO_FC_FONT(font);
+    cairo_ft_scaled_font_unlock_face(gfxPangoFcFont::CairoFont(self));
+}
+
+static void
+gfx_pango_fc_font_class_init (gfxPangoFcFontClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    PangoFontClass *font_class = PANGO_FONT_CLASS (klass);
+    PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (klass);
+
+    object_class->finalize = gfx_pango_fc_font_finalize;
+
+#if 0
+    // This will need overriding for user fonts to defeat the PangoFcFontMap
+    // caching, unless each user font is guaranteed to have a unique filename.
+    font_class->get_coverage =
+#endif
+    font_class->get_glyph_extents = gfx_pango_fc_font_get_glyph_extents;
+#ifdef DEBUG
+    // non-DEBUG inherits from fc_font_class as this won't be used anyway.
+    font_class->get_metrics = gfx_pango_fc_font_get_metrics;
+#endif
+    // fc_font_class->has_char,get_glyph are inherited
+    fc_font_class->lock_face = gfx_pango_fc_font_lock_face;
+    fc_font_class->unlock_face = gfx_pango_fc_font_unlock_face;
+}
+
+/**
+ * Recording a base PangoFont on a PangoContext
+ */
+
+static GQuark GetBaseFontQuark()
+{
+    // Not using g_quark_from_static_string() because this module may be
+    // unloaded (which would leave a dangling pointer).  Using
+    // g_quark_from_string() instead, which creates a small shutdown leak.
+    static GQuark quark = g_quark_from_string("moz-base-font");
+    return quark;
+}
+
+static PangoFont *
+GetBaseFont(PangoContext *aContext)
+{
+    return static_cast<PangoFont*>
+        (g_object_get_qdata(G_OBJECT(aContext), GetBaseFontQuark()));
+}
+
+static void
+SetBaseFont(PangoContext *aContext, PangoFont *aBaseFont)
+{
+    g_object_ref(aBaseFont);
+    g_object_set_qdata_full(G_OBJECT(aContext), GetBaseFontQuark(),
+                            aBaseFont, g_object_unref);
+}
+
 /**
  * gfxPangoFontset: An implementation of a PangoFontset for gfxPangoFontMap
  */
 
 #define GFX_TYPE_PANGO_FONTSET              (gfx_pango_fontset_get_type())
 #define GFX_PANGO_FONTSET(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONTSET, gfxPangoFontset))
 #define GFX_IS_PANGO_FONTSET(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONTSET))
 
@@ -101,82 +376,76 @@ GType gfx_pango_fontset_get_type (void);
 #define GFX_PANGO_FONTSET_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONTSET, gfxPangoFontsetClass))
 #define GFX_IS_PANGO_FONTSET_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONTSET))
 #define GFX_PANGO_FONTSET_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONTSET, gfxPangoFontsetClass))
 
 // This struct is POD so that it can be used as a GObject.
 struct gfxPangoFontset {
     PangoFontset parent_instance;
 
+    PangoFontMap *mFontMap;
     PangoContext *mContext;
     PangoFontDescription *mFontDesc;
     PangoLanguage *mLanguage;
     PangoFont *mBaseFont;
-    PangoFontMap *mFontMap;
-    PangoFontset *mChildFontset;
+    PangoFontset *mFallbackFontset;
 
     static PangoFontset *
-    NewFontset(PangoContext *aContext,
+    NewFontset(PangoFontMap *aFontMap,
+               PangoContext *aContext,
                const PangoFontDescription *aFontDesc,
-               PangoLanguage *aLanguage,
-               PangoFont *aBaseFont, PangoFontMap *aFontMap)
+               PangoLanguage *aLanguage)
     {
         gfxPangoFontset *fontset = static_cast<gfxPangoFontset *>
             (g_object_new(GFX_TYPE_PANGO_FONTSET, NULL));
 
+        fontset->mFontMap = aFontMap;
+        g_object_ref(aFontMap);
+
         fontset->mContext = aContext;
         g_object_ref(aContext);
 
         fontset->mFontDesc = pango_font_description_copy(aFontDesc);
         fontset->mLanguage = aLanguage;
 
-        fontset->mBaseFont = aBaseFont;
-        if(aBaseFont)
-            g_object_ref(aBaseFont);
-
-        fontset->mFontMap = aFontMap;
-        g_object_ref(aFontMap);
+        fontset->mBaseFont = GetBaseFont(aContext);
+        if(fontset->mBaseFont)
+            g_object_ref(fontset->mBaseFont);
 
         return PANGO_FONTSET(fontset);
     }
 };
 
 struct gfxPangoFontsetClass {
     PangoFontsetClass parent_class;
 };
 
 G_DEFINE_TYPE (gfxPangoFontset, gfx_pango_fontset, PANGO_TYPE_FONTSET)
 
 static void
 gfx_pango_fontset_init(gfxPangoFontset *fontset)
 {
-    fontset->mContext = NULL;
-    fontset->mFontDesc = NULL;
-    fontset->mLanguage = NULL;
-    fontset->mBaseFont = NULL;
-    fontset->mFontMap = NULL;
-    fontset->mChildFontset = NULL;
 }
 
 
 static void
 gfx_pango_fontset_finalize(GObject *object)
 {
     gfxPangoFontset *self = GFX_PANGO_FONTSET(object);
 
     if (self->mContext)
         g_object_unref(self->mContext);
     if (self->mFontDesc)
         pango_font_description_free(self->mFontDesc);
     if (self->mBaseFont)
         g_object_unref(self->mBaseFont);
     if (self->mFontMap)
         g_object_unref(self->mFontMap);
-    if (self->mChildFontset)
-        g_object_unref(self->mChildFontset);
+    if (self->mFallbackFontset)
+        g_object_unref(self->mFallbackFontset);
 
     G_OBJECT_CLASS(gfx_pango_fontset_parent_class)->finalize(object);
 }
 
 static PangoLanguage *
 gfx_pango_fontset_get_language(PangoFontset *fontset)
 {
     gfxPangoFontset *self = GFX_PANGO_FONTSET(fontset);
@@ -197,49 +466,57 @@ foreach_except_base_cb(PangoFontset *fon
         static_cast<ForeachExceptBaseData *>(data);
     
     // returning false means continue with the other fonts in the set
     return font != baseData->mBaseFont &&
         (*baseData->mFunc)(baseData->mFontset, font, baseData->mData);
 }
 
 static PangoFontset *
-EnsureChildFontset(gfxPangoFontset *self)
+gfx_pango_font_map_load_fallback_fontset(PangoFontMap *fontmap,
+                                         PangoContext *context,
+                                         const PangoFontDescription *desc,
+                                         PangoLanguage *language);
+
+static PangoFontset *
+EnsureFallbackFontset(gfxPangoFontset *self)
 {
-    if (!self->mChildFontset) {
+    if (!self->mFallbackFontset) {
         // To consider:
         //
-        // * If this is happening often (e.g. Chinese/Japanese pagess where a
+        // * If this is happening often (e.g. Chinese/Japanese pages where a
         //   Latin font is specified first), and Pango's 64-entry pattern
         //   cache is not large enough, then a fontset cache here could be
         //   helpful.  Ideally we'd only cache the fonts that are actually
         //   accessed rather than all the fonts from the FcFontSort.
         //
         // * Mozilla's langGroup font prefs could be used to specify preferred
         //   fallback fonts for the script of the characters (as indicated by
         //   Pango in mLanguage), by doing the conversion from gfxFontGroup
         //   "families" to PangoFcFontMap "family" here.
-        self->mChildFontset =
-            pango_font_map_load_fontset(self->mFontMap, self->mContext,
-                                        self->mFontDesc, self->mLanguage);
+        self->mFallbackFontset =
+            gfx_pango_font_map_load_fallback_fontset(self->mFontMap,
+                                                     self->mContext,
+                                                     self->mFontDesc,
+                                                     self->mLanguage);
     }
-    return self->mChildFontset;
+    return self->mFallbackFontset;
 }
 
 static void
 gfx_pango_fontset_foreach(PangoFontset *fontset, PangoFontsetForeachFunc func,
                           gpointer data)
 {
     gfxPangoFontset *self = GFX_PANGO_FONTSET(fontset);
 
     if (self->mBaseFont && (*func)(fontset, self->mBaseFont, data))
         return;
 
     // Falling back to secondary fonts
-    PangoFontset *childFontset = EnsureChildFontset(self);
+    PangoFontset *childFontset = EnsureFallbackFontset(self);
     ForeachExceptBaseData baseData = { self->mBaseFont, fontset, func, data };
     pango_fontset_foreach(childFontset, foreach_except_base_cb, &baseData);
 }
 
 static PangoFont *
 gfx_pango_fontset_get_font(PangoFontset *fontset, guint wc)
 {
     gfxPangoFontset *self = GFX_PANGO_FONTSET(fontset);
@@ -251,17 +528,17 @@ gfx_pango_fontset_get_font(PangoFontset 
             pango_font_get_coverage(self->mBaseFont, self->mLanguage);
         if (coverage) {
             baseLevel = pango_coverage_get(coverage, wc);
             pango_coverage_unref(coverage);
         }
     }
 
     if (baseLevel != PANGO_COVERAGE_EXACT) {
-        PangoFontset *childFontset = EnsureChildFontset(self);
+        PangoFontset *childFontset = EnsureFallbackFontset(self);
         PangoFont *childFont = pango_fontset_get_font(childFontset, wc);
         if (!self->mBaseFont || childFont == self->mBaseFont)
             return childFont;
 
         if (childFont) {
             PangoCoverage *coverage =
                 pango_font_get_coverage(childFont, self->mLanguage);
             if (coverage) {
@@ -302,140 +579,180 @@ gfx_pango_fontset_class_init (gfxPangoFo
  *
  * 1. Always using the same base font irrespective of the language that Pango
  *    chooses for the script means that PANGO_SCRIPT_COMMON characters are
  *    consistently rendered with the same font.  (Bug 339513 and bug 416725)
  *
  * 2. We normally have the base font from the gfxFont cache so this saves a
  *    FcFontSort when the entry has expired from Pango's much smaller pattern
  *    cache.
- *
- * This object references a child font map rather than deriving so that
- * the cache of the child font map is shared.
  */
 
 #define GFX_TYPE_PANGO_FONT_MAP              (gfx_pango_font_map_get_type())
 #define GFX_PANGO_FONT_MAP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMap))
 #define GFX_IS_PANGO_FONT_MAP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONT_MAP))
 
 GType gfx_pango_font_map_get_type (void);
 
 #define GFX_PANGO_FONT_MAP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
 #define GFX_IS_PANGO_FONT_MAP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONT_MAP))
 #define GFX_PANGO_FONT_MAP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
 
 // Do not instantiate this class directly, but use NewFontMap.
 // This struct is POD so that it can be used as a GObject.
 struct gfxPangoFontMap {
-    PangoFontMap parent_instance;
-
-    PangoFontMap *mChildFontMap;
-    PangoFont *mBaseFont;
+    PangoFcFontMap parent_instance;
 
     static PangoFontMap *
-    NewFontMap(PangoFontMap *aChildFontMap, PangoFont *aBaseFont)
+    NewFontMap()
     {
-        NS_ASSERTION(strcmp(pango_font_map_get_shape_engine_type(aChildFontMap), 
-                            PANGO_RENDER_TYPE_FC) == 0,
-                     "Unexpected child PangoFontMap shape engine type");
-
         gfxPangoFontMap *fontmap = static_cast<gfxPangoFontMap *>
             (g_object_new(GFX_TYPE_PANGO_FONT_MAP, NULL));
 
-        fontmap->mChildFontMap = aChildFontMap;
-        g_object_ref(aChildFontMap);
-
-        fontmap->mBaseFont = aBaseFont;
-        if(aBaseFont)
-            g_object_ref(aBaseFont);
-
         return PANGO_FONT_MAP(fontmap);
     }
-
-    void
-    SetBaseFont(PangoFont *aBaseFont)
-    {
-        if (mBaseFont)
-            g_object_unref(mBaseFont);
-
-        mBaseFont = aBaseFont;
-
-        if (aBaseFont)
-            g_object_ref(aBaseFont);
-    }
 };
 
 struct gfxPangoFontMapClass {
-    PangoFontMapClass parent_class;
+    PangoFcFontMapClass parent_class;
 };
 
-G_DEFINE_TYPE (gfxPangoFontMap, gfx_pango_font_map, PANGO_TYPE_FONT_MAP)
+G_DEFINE_TYPE (gfxPangoFontMap, gfx_pango_font_map, PANGO_TYPE_FC_FONT_MAP)
 
 static void
 gfx_pango_font_map_init(gfxPangoFontMap *fontset)
 {
-    fontset->mChildFontMap = NULL;    
-    fontset->mBaseFont = NULL;
-}
-
-static void
-gfx_pango_font_map_finalize(GObject *object)
-{
-    gfxPangoFontMap *self = GFX_PANGO_FONT_MAP(object);
-
-    if (self->mChildFontMap)
-        g_object_unref(self->mChildFontMap);
-    if (self->mBaseFont)
-        g_object_unref(self->mBaseFont);
-
-    G_OBJECT_CLASS(gfx_pango_font_map_parent_class)->finalize(object);
 }
 
 static PangoFont *
 gfx_pango_font_map_load_font(PangoFontMap *fontmap, PangoContext *context,
                              const PangoFontDescription *description)
 {
-    gfxPangoFontMap *self = GFX_PANGO_FONT_MAP(fontmap);
-    if (self->mBaseFont) {
-        g_object_ref(self->mBaseFont);
-        return self->mBaseFont;
+    PangoFont *baseFont = GetBaseFont(context);
+    if (baseFont) {
+        g_object_ref(baseFont);
+        return baseFont;
     }
 
-    return pango_font_map_load_font(self->mChildFontMap, context, description);
+    return PANGO_FONT_MAP_CLASS(gfx_pango_font_map_parent_class)->
+        load_font(fontmap, context, description);
 }
 
 static PangoFontset *
 gfx_pango_font_map_load_fontset(PangoFontMap *fontmap, PangoContext *context,
                                const PangoFontDescription *desc,
                                PangoLanguage *language)
 {
-    gfxPangoFontMap *self = GFX_PANGO_FONT_MAP(fontmap);
-    return gfxPangoFontset::NewFontset(context, desc, language,
-                                       self->mBaseFont, self->mChildFontMap);
+    return gfxPangoFontset::NewFontset(fontmap, context, desc, language);
+}
+
+static PangoFontset *
+gfx_pango_font_map_load_fallback_fontset(PangoFontMap *fontmap,
+                                         PangoContext *context,
+                                         const PangoFontDescription *desc,
+                                         PangoLanguage *language)
+{
+    return PANGO_FONT_MAP_CLASS(gfx_pango_font_map_parent_class)->
+        load_fontset(fontmap, context, desc, language);
 }
 
 static void
 gfx_pango_font_map_list_families(PangoFontMap *fontmap,
                                  PangoFontFamily ***families, int *n_families)
 {
-    gfxPangoFontMap *self = GFX_PANGO_FONT_MAP(fontmap);
-    pango_font_map_list_families(self->mChildFontMap, families, n_families);
+    return PANGO_FONT_MAP_CLASS(gfx_pango_font_map_parent_class)->
+        list_families(fontmap, families, n_families);
+}
+
+static double
+gfx_pango_font_map_get_resolution(PangoFcFontMap *fcfontmap,
+                                  PangoContext *context)
+{
+    // This merely enables the FC_SIZE field of the pattern to be accurate.
+    // We use gfxPlatformGtk::DPI() much of the time...
+    return gfxPlatformGtk::DPI();
+}
+
+static void
+gfx_pango_font_map_context_substitute(PangoFcFontMap *fontmap,
+                                      PangoContext *context,
+                                      FcPattern *pattern)
+{
+    FcConfigSubstitute(NULL, pattern, FcMatchPattern);
+
+    // XXXkt This gets cairo_font_options_t for the Screen.  We should have
+    // different font options for printing (no hinting) but we are not told
+    // what we are measuring for.
+    const cairo_font_options_t *options =
+        gdk_screen_get_font_options(gdk_screen_get_default());
+
+    cairo_ft_font_options_substitute(options, pattern);
+
+    FcDefaultSubstitute(pattern);
+}
+
+static PangoFcFont *
+gfx_pango_font_map_create_font(PangoFcFontMap *fontmap,
+                               PangoContext *context,
+                               const PangoFontDescription *desc,
+                               FcPattern *pattern)
+{
+    // A pattern is needed for pango_fc_font_finalize.
+    //
+    // Adding a ref to one of fontconfig's patterns would use much less memory
+    // than using the fully resolved pattern here.  This could be done by
+    // setting the PangoFcFont field is_hinted directly.  (is_hinted is used
+    // by pango_fc_font_kern_glyphs, which is sometimes used by
+    // pango_ot_buffer_output.)  is_transformed is not used but maybe it
+    // should be set too.  describe_absolute would need to be overridden if
+    // required, and description would need to be set if describe is required
+    // but not overridden.
+    //
+    // An alternative memory-saving effort might remove elements from the
+    // resolved pattern that are unnecessary.
+
+    // Protect against any fontconfig settings that may have incorrectly
+    // modified the pixelsize.
+    PRBool newPattern = PR_FALSE;
+    double size;
+    if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch) {
+        size = pango_font_description_get_size(desc) / FLOAT_PANGO_SCALE;
+        pattern = FcPatternDuplicate(pattern);
+        newPattern = PR_TRUE;
+        FcPatternDel(pattern, FC_PIXEL_SIZE);
+        FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size);
+    }
+
+    PangoFcFont *font = PANGO_FC_FONT(g_object_new(GFX_TYPE_PANGO_FC_FONT,
+                                                   "pattern", pattern, NULL));
+
+    if (newPattern) {
+        FcPatternDestroy(pattern);
+    }
+    return font;
 }
 
 static void
 gfx_pango_font_map_class_init(gfxPangoFontMapClass *klass)
 {
-    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    // inherit GObjectClass::finalize from the parent as there is nothing to
+    // finalize in this object.
+
     PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (klass);
-
-    object_class->finalize = gfx_pango_font_map_finalize;
     fontmap_class->load_font = gfx_pango_font_map_load_font;
     fontmap_class->load_fontset = gfx_pango_font_map_load_fontset;
     fontmap_class->list_families = gfx_pango_font_map_list_families;
-    fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_FC;
+    // inherit fontmap_class->shape_engine_type from PangoFcFontMap
+
+    PangoFcFontMapClass *fcfontmap_class = PANGO_FC_FONT_MAP_CLASS (klass);
+    fcfontmap_class->get_resolution = gfx_pango_font_map_get_resolution;
+    // context_key_* virtual functions are only necessary if we want to
+    // dynamically respond to changes in the screen cairo_font_options_t.
+    fcfontmap_class->context_substitute = gfx_pango_font_map_context_substitute;
+    fcfontmap_class->create_font = gfx_pango_font_map_create_font;
 }
 
 /**
  ** gfxPangoFontGroup
  **/
 
 static int
 FFRECountHyphens (const nsAString &aFFREName)
@@ -461,46 +778,28 @@ FontCallback (const nsAString& fontName,
 
     if (sa->IndexOf(fontName) < 0) {
         sa->AppendString(fontName);
     }
 
     return PR_TRUE;
 }
 
-/**
- * Look up the font in the gfxFont cache. If we don't find it, create one.
- * In either case, add a ref, append it to the aFonts array, and return it ---
- * except for OOM in which case we do nothing and return null.
- */
-static already_AddRefed<gfxPangoFont>
-GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle)
-{
-    nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aName, aStyle);
-    if (!font) {
-        nsRefPtr<gfxPangoFontEntry> fe = new gfxPangoFontEntry(aName);
-        font = new gfxPangoFont(fe, aStyle);
-        if (!font)
-            return nsnull;
-        gfxFontCache::GetCache()->AddNew(font);
-    }
-    gfxFont *f = nsnull;
-    font.swap(f);
-    return static_cast<gfxPangoFont *>(f);
-}
-
 gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families,
                                       const gfxFontStyle *aStyle)
-    : gfxFontGroup(families, aStyle)
+    : gfxFontGroup(families, aStyle),
+      mBasePangoFont(nsnull), mAdjustedSize(0)
 {
     mFonts.AppendElements(1);
 }
 
 gfxPangoFontGroup::~gfxPangoFontGroup()
 {
+    if (mBasePangoFont)
+        g_object_unref(mBasePangoFont);
 }
 
 gfxFontGroup *
 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
 {
     return new gfxPangoFontGroup(mFamilies, aStyle);
 }
 
@@ -530,102 +829,78 @@ gfxPangoFontGroup::GetFcFamilies(nsAStri
         // Pango will resolve from this.
         // behdad: yep, looks good.
         // printf("%s(%s)\n", NS_ConvertUTF16toUTF8(families).get(),
         //                    aStyle->langGroup.get());
         aFcFamilies.Append(NS_LITERAL_STRING("sans-serif"));
     }
 }
 
-gfxPangoFont *
+gfxFont *
 gfxPangoFontGroup::GetFontAt(PRInt32 i) {
     NS_PRECONDITION(i == 0, "Only have one font");
 
     if (!mFonts[0]) {
-        nsAutoString fcFamilies;
-        GetFcFamilies(fcFamilies);
-        nsRefPtr<gfxPangoFont> font = GetOrMakeFont(fcFamilies, &mStyle);
-        mFonts[0] = font;
+        PangoFont *pangoFont = GetBasePangoFont();
+        mFonts[0] = gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(pangoFont));
     }
 
-    return static_cast<gfxPangoFont*>(mFonts[i].get());
+    return mFonts[0];
 }
 
 /**
- ** gfxPangoFont
+ ** gfxFcFont
  **/
 
-gfxPangoFont::gfxPangoFont(gfxPangoFontEntry *aFontEntry,
-                           const gfxFontStyle *aFontStyle)
-    : gfxFont(aFontEntry, aFontStyle),
-      mPangoFont(nsnull), mCairoFont(nsnull),
-      mHasMetrics(PR_FALSE), mAdjustedSize(0)
-{
-}
+cairo_user_data_key_t gfxFcFont::sGfxFontKey;
 
-// key for locating a gfxPangoFont corresponding to a PangoFont
-static GQuark GetFontQuark()
+gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont,
+                     gfxPangoFontEntry *aFontEntry,
+                     const gfxFontStyle *aFontStyle)
+    : gfxFont(aFontEntry, aFontStyle),
+      mCairoFont(aCairoFont),
+      mHasMetrics(PR_FALSE)
 {
-    // Not using g_quark_from_static_string() because this module may be
-    // unloaded (which would leave a dangling pointer).  Using
-    // g_quark_from_string() instead, which creates a small shutdown leak.
-    static GQuark quark = g_quark_from_string("moz-gfxFont");
-    return quark;
+    cairo_scaled_font_reference(mCairoFont);
+    cairo_scaled_font_set_user_data(mCairoFont, &sGfxFontKey, this, NULL);
 }
 
-gfxPangoFont::gfxPangoFont(PangoFont *aPangoFont, gfxPangoFontEntry *aFontEntry,
-                           const gfxFontStyle *aFontStyle)
-    : gfxFont(aFontEntry, aFontStyle),
-      mPangoFont(aPangoFont), mCairoFont(nsnull),
-      mHasMetrics(PR_FALSE), mAdjustedSize(aFontStyle->size)
+gfxFcFont::~gfxFcFont()
 {
-    g_object_ref(mPangoFont);
-    g_object_set_qdata(G_OBJECT(mPangoFont), GetFontQuark(), this);
-}
-
-gfxPangoFont::~gfxPangoFont()
-{
-    if (mPangoFont) {
-        if (g_object_get_qdata(G_OBJECT(mPangoFont), GetFontQuark()) == this)
-            g_object_set_qdata(G_OBJECT(mPangoFont), GetFontQuark(), NULL);
-        g_object_unref(mPangoFont);
-    }
-
-    if (mCairoFont)
-        cairo_scaled_font_destroy(mCairoFont);
+    cairo_scaled_font_set_user_data(mCairoFont, &sGfxFontKey, NULL, NULL);
+    cairo_scaled_font_destroy(mCairoFont);
 }
 
 /* static */ void
-gfxPangoFont::Shutdown()
+gfxPangoFontGroup::Shutdown()
 {
     gfxPangoFontCache::Shutdown();
+
+    if (gPangoFontMap) {
+        if (PANGO_IS_FC_FONT_MAP (gPangoFontMap)) {
+            // This clears circular references from the fontmap to itself
+            // through its fonts.
+            pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(gPangoFontMap));
+        }
+        g_object_unref(gPangoFontMap);
+        gPangoFontMap = NULL;
+    }
 }
 
 static PangoStyle
 ThebesStyleToPangoStyle (const gfxFontStyle *fs)
 {
     if (fs->style == FONT_STYLE_ITALIC)
         return PANGO_STYLE_ITALIC;
     if (fs->style == FONT_STYLE_OBLIQUE)
         return PANGO_STYLE_OBLIQUE;
 
     return PANGO_STYLE_NORMAL;
 }
 
-static PRUint8
-PangoStyleToThebesStyle (PangoStyle aPangoStyle)
-{
-    if (aPangoStyle == PANGO_STYLE_ITALIC)
-        return FONT_STYLE_ITALIC;
-    if (aPangoStyle == FONT_STYLE_OBLIQUE)
-        return FONT_STYLE_OBLIQUE;
-
-    return FONT_STYLE_NORMAL;
-}
-
 static PangoWeight
 ThebesStyleToPangoWeight (const gfxFontStyle *fs)
 {
     PRInt32 w = fs->weight;
 
     /*
      * weights come in two parts crammed into one
      * integer -- the "base" weight is weight / 100,
@@ -676,18 +951,18 @@ ThebesStyleToPangoWeight (const gfxFontS
 /* Note this doesn't check sizeAdjust */
 static PangoFontDescription *
 NewPangoFontDescription(const nsAString &aName, const gfxFontStyle *aFontStyle)
 {
     PangoFontDescription *fontDesc = pango_font_description_new();
 
     pango_font_description_set_family(fontDesc,
                                       NS_ConvertUTF16toUTF8(aName).get());
-    pango_font_description_set_absolute_size(fontDesc,
-                                             aFontStyle->size * PANGO_SCALE);
+    pango_font_description_set_absolute_size
+        (fontDesc, moz_pango_units_from_double(aFontStyle->size));
     pango_font_description_set_style(fontDesc,
                                      ThebesStyleToPangoStyle(aFontStyle));
     pango_font_description_set_weight(fontDesc,
                                       ThebesStyleToPangoWeight(aFontStyle));
     return fontDesc;
 }
 
 /**
@@ -695,62 +970,103 @@ NewPangoFontDescription(const nsAString 
  * gfxFontCache hash table.  The gfxFontCache hash table is keyed by desired
  * family and style, whereas here we only know actual family and style.  There
  * may be more than one of these fonts with the same family and style, but
  * different PangoFont and actual font face.
  * 
  * The point of this is to record the exact font face for gfxTextRun glyph
  * indices.  The style of this font does not necessarily represent the exact
  * gfxFontStyle used to build the text run.  Notably, the language is not
- * recorded, but is used for GetMetrics().aveCharWidth.  However, the font
- * that should be used for aveCharWidth is gfxPangoFontGroup::GetFontAt(0),
- * which is not constructed here.
+ * recorded.
  */
 
 /* static */
-already_AddRefed<gfxPangoFont>
-gfxPangoFont::GetOrMakeFont(PangoFont *aPangoFont)
+already_AddRefed<gfxFcFont>
+gfxFcFont::GetOrMakeFont(FcPattern *aPattern)
 {
-    gfxPangoFont *font = static_cast<gfxPangoFont*>
-        (g_object_get_qdata(G_OBJECT(aPangoFont), GetFontQuark()));
+    cairo_scaled_font_t *cairoFont = CreateScaledFont(aPattern);
+
+    nsRefPtr<gfxFcFont> font = static_cast<gfxFcFont*>
+        (cairo_scaled_font_get_user_data(cairoFont, &sGfxFontKey));
 
     if (!font) {
-        // pango_font_describe_with_absolute_size requires Pango-1.14
-        PangoFontDescription *desc = pango_font_describe(aPangoFont);
-
-        PangoFcFont *fcfont = PANGO_FC_FONT(aPangoFont);
         double size;
-        if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size)
-            != FcResultMatch)
-            size = pango_font_description_get_size(desc) / FLOAT_PANGO_SCALE;
+        if (FcPatternGetDouble(aPattern,
+                               FC_PIXEL_SIZE, 0, &size) != FcResultMatch) {
+            NS_NOTREACHED("No size on pattern");
+            size = 0.0;
+        }
 
         // Shouldn't actually need to take too much care about the correct
-        // family or style, as size is the only thing expected to be
-        // important.
-        PRUint8 style =
-            PangoStyleToThebesStyle(pango_font_description_get_style(desc));
-        PRUint16 weight = pango_font_description_get_weight(desc);
+        // name or style, as size is the only thing expected to be important.
+        PRUint8 style = gfxFontconfigUtils::GetThebesStyle(aPattern);
+        PRUint16 weight = gfxFontconfigUtils::GetThebesWeight(aPattern);
+
+        // The LangSet in the FcPattern does not have an order so there is no
+        // one particular language to choose and converting the set to a
+        // string through FcNameUnparse() is more trouble than it's worth.
         NS_NAMED_LITERAL_CSTRING(langGroup, "x-unicode");
         gfxFontStyle fontStyle(style, weight, size, langGroup, 0.0,
                                PR_TRUE, PR_FALSE);
 
-        // (The PangoFontDescription owns the family string)
-        const char *family = pango_font_description_get_family(desc);
-        nsRefPtr<gfxPangoFontEntry> fe = new gfxPangoFontEntry(NS_ConvertUTF8toUTF16(family));
-        font = new gfxPangoFont(aPangoFont, fe, &fontStyle);
+        FcChar8 *fc_file; // unsigned char
+        const char *file; // signed for Mozilla string APIs
+        if (FcPatternGetString(aPattern,
+                               FC_FILE, 0, &fc_file) == FcResultMatch) {
+            file = reinterpret_cast<char*>(fc_file);
+        } else {
+            // cairo won't know which font to open without a file.
+            // (We don't create fonts from an FT_Face.)
+            NS_NOTREACHED("Fonts without a file are not supported");
+            static const char *noFile = "NO FILE";
+            file = noFile;
+        }
+        int index;
+        if (FcPatternGetInteger(aPattern, FC_INDEX, 0, &index)
+            != FcResultMatch) {
+            // cairo won't know what to do here either.
+            NS_NOTREACHED("No index in pattern");
+            index = 0;
+        }
+        // Get a unique face name from the file and id.
+        nsAutoString name;
+        AppendUTF8toUTF16(file, name);
+        if (index != 0) {
+            name.AppendLiteral("/");
+            name.AppendInt(index);
+        }
 
-        pango_font_description_free(desc);
-        if (!font)
-            return nsnull;
+        nsRefPtr<gfxPangoFontEntry> fe = new gfxPangoFontEntry(name);
+
+        // Note that the unique face in the name/fe and the gfxFontStyle are
+        // not necessarily enough to provide a key that will describe a unique
+        // font.  cairoFont contains information from aPattern, which is a
+        // fully resolved pattern from FcFontRenderPrepare.
+        // FcFontRenderPrepare takes the requested pattern and the face
+        // pattern as input and can modify elements of the resulting pattern
+        // that affect rendering but are not included in the gfxFontStyle.
+        font = new gfxFcFont(cairoFont, fe, &fontStyle);
+    }
 
-        // Do not add this font to the gfxFontCache hash table as this may not
-        // be the PangoFont that fontconfig chooses for this style.
+    cairo_scaled_font_destroy(cairoFont);
+    return font.forget();
+}
+
+static PangoContext *
+GetPangoContext()
+{
+    PangoContext *context = pango_context_new();
+
+    // Change the font map to recognize a base font on the context
+    if (!gPangoFontMap) {
+        gPangoFontMap = gfxPangoFontMap::NewFontMap();
     }
-    NS_ADDREF(font);
-    return font;
+    pango_context_set_font_map(context, gPangoFontMap);
+
+    return context;
 }
 
 static PangoFont*
 LoadPangoFont(PangoContext *aPangoCtx, const PangoFontDescription *aPangoFontDesc)
 {
     gfxPangoFontCache *cache = gfxPangoFontCache::GetPangoFontCache();
     if (!cache)
         return nsnull; // Error
@@ -759,315 +1075,411 @@ LoadPangoFont(PangoContext *aPangoCtx, c
         pangoFont = pango_context_load_font(aPangoCtx, aPangoFontDesc);
         if (pangoFont) {
             cache->Put(aPangoFontDesc, pangoFont);
         }
     }
     return pangoFont;
 }
 
-void
-gfxPangoFont::RealizePangoFont()
+// The font group holds the reference to the PangoFont
+PangoFont *
+gfxPangoFontGroup::GetBasePangoFont()
 {
-    // already realized?
-    if (mPangoFont)
-        return;
+    if (mBasePangoFont)
+        return mBasePangoFont;
 
-    PangoFontDescription *pangoFontDesc =
-        NewPangoFontDescription(GetName(), GetStyle());
+    nsAutoString fcFamilies;
+    GetFcFamilies(fcFamilies);
+    PangoFontDescription *pangoFontDesc = 
+        NewPangoFontDescription(fcFamilies, GetStyle());
 
-    PangoContext *pangoCtx = gdk_pango_context_get();
+    PangoContext *pangoCtx = GetPangoContext();
 
     if (!GetStyle()->langGroup.IsEmpty()) {
         PangoLanguage *lang = GetPangoLanguage(GetStyle()->langGroup);
         if (lang)
             pango_context_set_language(pangoCtx, lang);
     }
 
-    mPangoFont = LoadPangoFont(pangoCtx, pangoFontDesc);
+    PangoFont *pangoFont = LoadPangoFont(pangoCtx, pangoFontDesc);
 
     gfxFloat size = GetStyle()->size;
-    // Checking mPangoFont to avoid infinite recursion through GetCharSize
-    if (size != 0.0 && GetStyle()->sizeAdjust != 0.0 && mPangoFont) {
+    if (size != 0.0 && GetStyle()->sizeAdjust != 0.0) {
+        LockedFTFace
+            face(gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(pangoFont)));
         // Could try xHeight from TrueType/OpenType fonts.
-        gfxSize isz, lsz;
-        GetCharSize('x', isz, lsz);
-        if (isz.height != 0.0) {
-            gfxFloat aspect = isz.height / size;
+        cairo_text_extents_t extents;
+        if (face.GetCharExtents('x', &extents) &&
+            extents.y_bearing < 0.0) {
+            gfxFloat aspect = -extents.y_bearing / size;
             size = GetStyle()->GetAdjustedSize(aspect);
 
-            pango_font_description_set_absolute_size(pangoFontDesc,
-                                                     size * PANGO_SCALE);
-            g_object_unref(mPangoFont);
-            mPangoFont = LoadPangoFont(pangoCtx, pangoFontDesc);
+            pango_font_description_set_absolute_size
+                (pangoFontDesc, moz_pango_units_from_double(size));
+            g_object_unref(pangoFont);
+            pangoFont = LoadPangoFont(pangoCtx, pangoFontDesc);
         }
     }
 
-    NS_ASSERTION(mHasMetrics == PR_FALSE, "metrics will be invalid...");
-    mAdjustedSize = size;
-    if (!g_object_get_qdata(G_OBJECT(mPangoFont), GetFontQuark()))
-        g_object_set_qdata(G_OBJECT(mPangoFont), GetFontQuark(), this);
-
     if (pangoFontDesc)
         pango_font_description_free(pangoFontDesc);
     if (pangoCtx)
         g_object_unref(pangoCtx);
+
+    mBasePangoFont = pangoFont;
+    mAdjustedSize = size;
+
+    return pangoFont;
 }
 
 void
-gfxPangoFont::GetCharSize(char aChar, gfxSize& aInkSize, gfxSize& aLogSize,
-                          PRUint32 *aGlyphID)
+gfxFcFont::GetGlyphExtents(PRUint32 aGlyph, cairo_text_extents_t* aExtents)
 {
-    if (NS_UNLIKELY(GetStyle()->size == 0.0)) {
-        if (aGlyphID)
-            *aGlyphID = 0;
-        aInkSize.SizeTo(0.0, 0.0);
-        aLogSize.SizeTo(0.0, 0.0);
-        return;
+    NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
+
+    cairo_glyph_t glyphs[1];
+    glyphs[0].index = aGlyph;
+    glyphs[0].x = 0.0;
+    glyphs[0].y = 0.0;
+    // cairo does some caching for us here but perhaps a small gain could be
+    // made by caching more.  It is usually only the advance that is needed,
+    // so caching only the advance could allow many requests to be cached with
+    // little memory use.  Ideally this cache would be merged with
+    // gfxGlyphExtents.
+    cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs, 1, aExtents);
+}
+
+PRUint32
+LockedFTFace::GetCharExtents(char aChar,
+                             cairo_text_extents_t* aExtents)
+{
+    NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
+
+    if (!mFace)
+        return 0;
+
+    // pango_fc_font_real_get_glyph uses FcFreeTypeCharIndex which may change
+    // the charmap currently selected on the FT_Face, so, while
+    // pango_fc_font_real_get_glyph might be used, we should use the same
+    // function so as to search the charmaps.
+    //
+    // Unfortunately this considers the mac/roman cmap even when there is a
+    // unicode cmap, which will be bad for symbol fonts, so we should do this
+    // ourselves, perhaps with a lightweight cache like
+    // pango_fc_font_real_get_glyph uses.
+    FT_UInt gid = FcFreeTypeCharIndex(mFace, aChar); // glyph id
+    if (gid) {
+        mGfxFont->GetGlyphExtents(gid, aExtents);
     }
 
-    // XXXkt: Why not use pango_font_get_glyph_extents?  This function isn't
-    // currently being used for characters likely to involve glyph clusters.
-    // I don't think pango_shape will fallback to other fonts.
-    PangoAnalysis analysis;
-    // Initialize new fields, gravity and flags in pango 1.16
-    // (or padding in 1.14).
-    // Use memset instead of { 0 } aggregate initialization or placement new
-    // default initialization so that padding (which may have meaning in other
-    // versions) is initialized.
-    memset(&analysis, 0, sizeof(analysis));
-    analysis.font = GetPangoFont();
-    analysis.language = pango_language_from_string("en");
-    analysis.shape_engine = pango_font_find_shaper(analysis.font, analysis.language, aChar);
-
-    PangoGlyphString *glstr = pango_glyph_string_new();
-    pango_shape (&aChar, 1, &analysis, glstr);
-
-    if (aGlyphID) {
-        *aGlyphID = 0;
-        if (glstr->num_glyphs == 1) {
-            PangoGlyph glyph = glstr->glyphs[0].glyph;
-            if (!IS_MISSING_GLYPH(glyph) && !IS_EMPTY_GLYPH(glyph)) {
-                *aGlyphID = glyph;
-            }
-        }
-    }
-
-    PangoRectangle ink_rect, log_rect;
-    pango_glyph_string_extents(glstr, analysis.font, &ink_rect, &log_rect);
-
-    aInkSize.width = ink_rect.width / FLOAT_PANGO_SCALE;
-    aInkSize.height = ink_rect.height / FLOAT_PANGO_SCALE;
-
-    aLogSize.width = log_rect.width / FLOAT_PANGO_SCALE;
-    aLogSize.height = log_rect.height / FLOAT_PANGO_SCALE;
-
-    pango_glyph_string_free(glstr);
+    return gid;
 }
 
 // rounding and truncation functions for a Freetype fixed point number 
 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
 // part and low 6 bits for the fractional part. 
-#define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
-#define MOZ_FT_TRUNC(x) ((x) >> 6)
-#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
-        MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
+#define FLOAT_FROM_26_6(x) ((x) / 64.0)
+#define FLOAT_FROM_16_16(x) ((x) / 65536.0)
+#define ROUND_26_6_TO_INT(x) ((x) >= 0 ?  ((32 + (x)) >> 6) \
+                                       : -((32 - (x)) >> 6))
+// aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
+static inline FT_Long
+ScaleRoundDesignUnits(FT_Short aDesignMetric, FT_Fixed aScale)
+{
+    FT_Long fixed26dot6 = FT_MulFix(aDesignMetric, aScale);
+    return ROUND_26_6_TO_INT(fixed26dot6);
+}
+
+// Snap a line to pixels while keeping the center and size of the line as
+// close to the original position as possible.
+//
+// Pango does similar snapping for underline and strikethrough when fonts are
+// hinted, but nsCSSRendering::GetTextDecorationRectInternal always snaps the
+// top and size of lines.  Optimizing the distance between the line and
+// baseline is probably good for the gap between text and underline, but
+// optimizing the center of the line is better for positioning strikethough.
+static void
+SnapLineToPixels(gfxFloat& aOffset, gfxFloat& aSize)
+{
+    gfxFloat snappedSize = PR_MAX(NS_floor(aSize + 0.5), 1.0);
+    // Correct offset for change in size
+    gfxFloat offset = aOffset - 0.5 * (aSize - snappedSize);
+    // Snap offset
+    aOffset = NS_floor(offset + 0.5);
+    aSize = snappedSize;
+}
+
+void
+LockedFTFace::GetMetrics(gfxFont::Metrics* aMetrics, PRUint32* aSpaceGlyph)
+{
+    NS_PRECONDITION(aMetrics != NULL, "aMetrics must not be NULL");
+    NS_PRECONDITION(aSpaceGlyph != NULL, "aSpaceGlyph must not be NULL");
+
+    if (NS_UNLIKELY(!mFace)) {
+        // No face.  This unfortunate situation might happen if the font
+        // file is (re)moved at the wrong time.
+        aMetrics->emHeight = mGfxFont->GetStyle()->size;
+        aMetrics->emAscent = 0.8 * aMetrics->emHeight;
+        aMetrics->emDescent = 0.2 * aMetrics->emHeight;
+        aMetrics->maxAscent = aMetrics->emAscent;
+        aMetrics->maxDescent = aMetrics->maxDescent;
+        aMetrics->maxHeight = aMetrics->emHeight;
+        aMetrics->internalLeading = 0.0;
+        aMetrics->externalLeading = 0.2 * aMetrics->emHeight;
+        aSpaceGlyph = 0;
+        aMetrics->spaceWidth = 0.5 * aMetrics->emHeight;
+        aMetrics->maxAdvance = aMetrics->spaceWidth;
+        aMetrics->aveCharWidth = aMetrics->spaceWidth;
+        aMetrics->zeroOrAveCharWidth = aMetrics->spaceWidth;
+        aMetrics->xHeight = 0.5 * aMetrics->emHeight;
+        aMetrics->underlineSize = aMetrics->emHeight / 14.0;
+        aMetrics->underlineOffset = -aMetrics->underlineSize;
+        aMetrics->strikeoutOffset = 0.25 * aMetrics->emHeight;
+        aMetrics->strikeoutSize = aMetrics->underlineSize;
+        aMetrics->superscriptOffset = aMetrics->xHeight;
+        aMetrics->subscriptOffset = aMetrics->xHeight;
+
+        return;
+    }
+
+    const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
+
+    // Scale for vertical design metric conversion: pixels per design unit.
+    gfxFloat yScale;
+    if (FT_IS_SCALABLE(mFace)) {
+        // Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
+        // have subpixel accuracy.
+        //
+        // FT_Size_Metrics::y_scale is in 16.16 fixed point format.  Its
+        // (fractional) value is a factor that converts vertical metrics from
+        // design units to units of 1/64 pixels, so that the result may be
+        // interpreted as pixels in 26.6 fixed point format.
+        yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
+        aMetrics->emHeight = mFace->units_per_EM * yScale;
+    } else { // Not scalable.
+        // FT_Size_Metrics doc says x_scale is "only relevant for scalable
+        // font formats".
+        gfxFloat emUnit = mFace->units_per_EM;
+        aMetrics->emHeight = ftMetrics.y_ppem;
+        yScale = aMetrics->emHeight / emUnit;
+    }
+
+    TT_OS2 *os2 =
+        static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2));
+
+    aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
+    aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender);
+    aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
+
+    gfxFloat lineHeight;
+    if (os2 && os2->sTypoAscender) {
+        aMetrics->emAscent = os2->sTypoAscender * yScale;
+        aMetrics->emDescent = -os2->sTypoDescender * yScale;
+        FT_Short typoHeight =
+            os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
+        lineHeight = typoHeight * yScale;
+
+        // maxAscent/maxDescent get used for frame heights, and some fonts
+        // don't have the HHEA table ascent/descent set (bug 279032).
+        if (aMetrics->emAscent > aMetrics->maxAscent)
+            aMetrics->maxAscent = aMetrics->emAscent;
+        if (aMetrics->emDescent > aMetrics->maxDescent)
+            aMetrics->maxDescent = aMetrics->emDescent;
+    } else {
+        aMetrics->emAscent = aMetrics->maxAscent;
+        aMetrics->emDescent = aMetrics->maxDescent;
+        lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
+    }
+
+    cairo_text_extents_t extents;
+    *aSpaceGlyph = GetCharExtents(' ', &extents);
+    if (*aSpaceGlyph) {
+        aMetrics->spaceWidth = extents.x_advance;
+    } else {
+        aMetrics->spaceWidth = aMetrics->maxAdvance; // guess
+    }
+
+    aMetrics->zeroOrAveCharWidth = 0.0;
+    if (GetCharExtents('0', &extents)) {
+        aMetrics->zeroOrAveCharWidth = extents.x_advance;
+    }
+
+    // Prefering a measured x over sxHeight because sxHeight doesn't consider
+    // hinting, but maybe the x extents are not quite right in some fancy
+    // script fonts.  CSS 2.1 suggests possibly using the height of an "o",
+    // which would have a more consistent glyph across fonts.
+    if (GetCharExtents('x', &extents) && extents.y_bearing < 0.0) {
+        aMetrics->xHeight = -extents.y_bearing;
+        aMetrics->aveCharWidth = extents.x_advance;
+    } else {
+        if (os2 && os2->sxHeight) {
+            aMetrics->xHeight = os2->sxHeight * yScale;
+        } else {
+            // CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
+            // impossible or impractical to determine the x-height, a value of
+            // 0.5em should be used."
+            aMetrics->xHeight = 0.5 * aMetrics->emHeight;
+        }
+        aMetrics->aveCharWidth = 0.0; // updated below
+    }
+    // aveCharWidth is used for the width of text input elements so be
+    // liberal rather than conservative in the estimate.
+    if (os2 && os2->xAvgCharWidth) {
+        // Round to pixels as this is compared with maxAdvance to guess
+        // whether this is a fixed width font.
+        gfxFloat avgCharWidth =
+            ScaleRoundDesignUnits(os2->xAvgCharWidth, ftMetrics.x_scale);
+        aMetrics->aveCharWidth =
+            PR_MAX(aMetrics->aveCharWidth, avgCharWidth);
+    }
+    aMetrics->aveCharWidth =
+        PR_MAX(aMetrics->aveCharWidth, aMetrics->zeroOrAveCharWidth);
+    if (aMetrics->aveCharWidth == 0.0) {
+        aMetrics->aveCharWidth = aMetrics->spaceWidth;
+    }
+    if (aMetrics->zeroOrAveCharWidth == 0.0) {
+        aMetrics->zeroOrAveCharWidth = aMetrics->aveCharWidth;
+    }
+    // Apparently hinting can mean that max_advance is not always accurate.
+    aMetrics->maxAdvance =
+        PR_MAX(aMetrics->maxAdvance, aMetrics->aveCharWidth);
+
+    // gfxFont::Metrics::underlineOffset is the position of the top of the
+    // underline.
+    //
+    // FT_FaceRec documentation describes underline_position as "the
+    // center of the underlining stem".  This was the original definition
+    // of the PostScript metric, but in the PostScript table of OpenType
+    // fonts the metric is "the top of the underline"
+    // (http://www.microsoft.com/typography/otspec/post.htm), and FreeType
+    // (up to version 2.3.7) doesn't make any adjustment.
+    //
+    // Therefore get the underline position directly from the table
+    // ourselves when this table exists.  Use FreeType's metrics for
+    // other (including older PostScript) fonts.
+    if (mFace->underline_position && mFace->underline_thickness) {
+        aMetrics->underlineSize = mFace->underline_thickness * yScale;
+        TT_Postscript *post = static_cast<TT_Postscript*>
+            (FT_Get_Sfnt_Table(mFace, ft_sfnt_post));
+        if (post && post->underlinePosition) {
+            aMetrics->underlineOffset = post->underlinePosition * yScale;
+        } else {
+            aMetrics->underlineOffset = mFace->underline_position * yScale
+                + 0.5 * aMetrics->underlineSize;
+        }
+    } else { // No underline info.
+        // Imitate Pango.
+        aMetrics->underlineSize = aMetrics->emHeight / 14.0;
+        aMetrics->underlineOffset = -aMetrics->underlineSize;
+    }
+
+    if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
+        aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
+        aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
+    } else { // No strikeout info.
+        aMetrics->strikeoutSize = aMetrics->underlineSize;
+        // Use OpenType spec's suggested position for Roman font.
+        aMetrics->strikeoutOffset = aMetrics->emHeight * 409.0 / 2048.0
+            + 0.5 * aMetrics->strikeoutSize;
+    }
+    SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
+
+    if (os2 && os2->ySuperscriptYOffset) {
+        gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
+                                             ftMetrics.y_scale);
+        aMetrics->superscriptOffset = PR_MAX(1.0, val);
+    } else {
+        aMetrics->superscriptOffset = aMetrics->xHeight;
+    }
+    
+    if (os2 && os2->ySubscriptYOffset) {
+        gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset,
+                                             ftMetrics.y_scale);
+        // some fonts have the incorrect sign. 
+        val = fabs(val);
+        aMetrics->subscriptOffset = PR_MAX(1.0, val);
+    } else {
+        aMetrics->subscriptOffset = aMetrics->xHeight;
+    }
+
+    aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
+
+    // Ensure emAscent + emDescent == emHeight
+    gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent;
+    aMetrics->emAscent = sum > 0.0 ?
+        aMetrics->emAscent * aMetrics->emHeight / sum : 0.0;
+    aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent;
+
+    aMetrics->internalLeading = aMetrics->maxHeight - aMetrics->emHeight;
+    // Text input boxes currently don't work well with lineHeight < maxHeight
+    // (with Verdana, for example).
+    aMetrics->externalLeading = PR_MAX(lineHeight - aMetrics->maxHeight, 0);
+}
 
 const gfxFont::Metrics&
-gfxPangoFont::GetMetrics()
+gfxFcFont::GetMetrics()
 {
     if (mHasMetrics)
         return mMetrics;
 
-    /* pango_cairo case; try to get all the metrics from pango itself */
-    PangoFont *font;
-    PangoFontMetrics *pfm;
-    if (NS_LIKELY(GetStyle()->size > 0.0)) {
-        font = GetPangoFont(); // RealizePangoFont is called here.
-        PangoLanguage *lang = GetPangoLanguage(GetStyle()->langGroup);
-        // If lang is NULL, Pango will measure a string of many languages,
-        // which will require many FcFontSorts, but we don't want to go to
-        // that much trouble.
-        // pango_language_get_default() is available from Pango-1.16.
-        if (!lang)
-            lang = pango_language_from_string(setlocale(LC_CTYPE, NULL));
-
-        pfm = pango_font_get_metrics(font, lang);
-    } else {
-        // Don't ask pango when the font-size is zero since it causes
-        // some versions of libpango to crash (bug 404112).
-        font = NULL;
-        pfm = NULL;
-    }
-
-    if (NS_LIKELY(pfm)) {
-        mMetrics.maxAscent =
-            pango_font_metrics_get_ascent(pfm) / FLOAT_PANGO_SCALE;
-
-        mMetrics.maxDescent =
-            pango_font_metrics_get_descent(pfm) / FLOAT_PANGO_SCALE;
-
-        // This is used for the width of text input elements so be liberal
-        // rather than conservative in the estimate.
-        mMetrics.aveCharWidth =
-            PR_MAX(pango_font_metrics_get_approximate_char_width(pfm),
-                   pango_font_metrics_get_approximate_digit_width(pfm))
-            / FLOAT_PANGO_SCALE;
-
-        mMetrics.underlineOffset =
-            pango_font_metrics_get_underline_position(pfm) / FLOAT_PANGO_SCALE;
-
-        mMetrics.underlineSize =
-            pango_font_metrics_get_underline_thickness(pfm) / FLOAT_PANGO_SCALE;
-
-        mMetrics.strikeoutOffset =
-            pango_font_metrics_get_strikethrough_position(pfm) / FLOAT_PANGO_SCALE;
-
-        mMetrics.strikeoutSize =
-            pango_font_metrics_get_strikethrough_thickness(pfm) / FLOAT_PANGO_SCALE;
-
-        // We're going to overwrite this below if we have a FT_Face
-        // (which we normally should have...).
-        mMetrics.maxAdvance = mMetrics.aveCharWidth;
+    if (NS_UNLIKELY(GetStyle()->size <= 0.0)) {
+        new(&mMetrics) gfxFont::Metrics(); // zero initialize
+        mSpaceGlyph = 0;
     } else {
-        mMetrics.maxAscent = 0.0;
-        mMetrics.maxDescent = 0.0;
-        mMetrics.aveCharWidth = 0.0;
-        mMetrics.underlineOffset = -1.0;
-        mMetrics.underlineSize = 0.0;
-        mMetrics.strikeoutOffset = 0.0;
-        mMetrics.strikeoutSize = 0.0;
-        mMetrics.maxAdvance = 0.0;
-    }
-
-    // ??
-    mMetrics.emHeight = mAdjustedSize;
-
-    gfxFloat lineHeight = mMetrics.maxAscent + mMetrics.maxDescent;
-    if (lineHeight > mMetrics.emHeight)
-        mMetrics.externalLeading = lineHeight - mMetrics.emHeight;
-    else
-        mMetrics.externalLeading = 0;
-    mMetrics.internalLeading = 0;
-
-    mMetrics.maxHeight = lineHeight;
-
-    mMetrics.emAscent = lineHeight > 0.0 ?
-        mMetrics.maxAscent * mMetrics.emHeight / lineHeight : 0.0;
-    mMetrics.emDescent = mMetrics.emHeight - mMetrics.emAscent;
-
-    gfxSize isz, lsz;
-    PRUint32 zeroGlyph;
-    GetCharSize(' ', isz, lsz, &mSpaceGlyph);
-    mMetrics.spaceWidth = lsz.width;
-    GetCharSize('x', isz, lsz);
-    mMetrics.xHeight = isz.height;
-    GetCharSize('0', isz, lsz, &zeroGlyph);
-    if (zeroGlyph)
-        mMetrics.zeroOrAveCharWidth = lsz.width;
-    else
-        mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
-
-    FT_Face face = NULL;
-    if (pfm && PANGO_IS_FC_FONT(font))
-        face = pango_fc_font_lock_face(PANGO_FC_FONT(font));
-
-    if (face) {
-        mMetrics.maxAdvance = face->size->metrics.max_advance / 64.0; // 26.6
-
-        float val;
-
-        TT_OS2 *os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-    
-        if (os2 && os2->ySuperscriptYOffset) {
-            val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset,
-                                                 face->size->metrics.y_scale);
-            mMetrics.superscriptOffset = PR_MAX(1, val);
-        } else {
-            mMetrics.superscriptOffset = mMetrics.xHeight;
-        }
-    
-        if (os2 && os2->ySubscriptYOffset) {
-            val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset,
-                                                 face->size->metrics.y_scale);
-            // some fonts have the incorrect sign. 
-            val = (val < 0) ? -val : val;
-            mMetrics.subscriptOffset = PR_MAX(1, val);
-        } else {
-            mMetrics.subscriptOffset = mMetrics.xHeight;
-        }
-
-        pango_fc_font_unlock_face(PANGO_FC_FONT(font));
-    } else {
-        mMetrics.superscriptOffset = mMetrics.xHeight;
-        mMetrics.subscriptOffset = mMetrics.xHeight;
+        LockedFTFace(this).GetMetrics(&mMetrics, &mSpaceGlyph);
     }
 
     SanitizeMetrics(&mMetrics, PR_FALSE);
 
 #if 0
-    //    printf("font name: %s %f %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size, mAdjustedSize);
+    //    printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
     //    printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
 
     fprintf (stderr, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
     fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
     fprintf (stderr, "    maxAscent: %f maxDescent: %f\n", mMetrics.maxAscent, mMetrics.maxDescent);
     fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.externalLeading, mMetrics.internalLeading);
     fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight);
     fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset);
 #endif
 
-    if (pfm)
-        pango_font_metrics_unref(pfm);
-
     mHasMetrics = PR_TRUE;
     return mMetrics;
 }
 
 nsString
-gfxPangoFont::GetUniqueName()
+gfxFcFont::GetUniqueName()
 {
-    PangoFont *font = GetPangoFont();
-    PangoFontDescription *desc = pango_font_describe(font);
-    pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE);
-    char *str = pango_font_description_to_string(desc);
-    pango_font_description_free (desc);
-
-    nsString result;
-    CopyUTF8toUTF16(str, result);
-    g_free(str);
-    return result;
+    return GetName();
 }
 
 /**
  ** gfxTextRun
  * 
- * Some serious problems:
+ * A serious problem:
  *
  * -- We draw with a font that's hinted for the CTM, but we measure with a font
  * hinted to the identity matrix, so our "bounding metrics" may not be accurate.
  * 
- * -- CreateScaledFont doesn't necessarily give us the font that the Pango
- * metrics assume.
- * 
  **/
 
 /**
  * We use this to append an LTR or RTL Override character to the start of the
  * string. This forces Pango to honour our direction even if there are neutral characters
  * in the string.
  */
 static PRInt32 AppendDirectionalIndicatorUTF8(PRBool aIsRTL, nsACString& aString)
 {
     static const PRUnichar overrides[2][2] =
       { { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO
     AppendUTF16toUTF8(overrides[aIsRTL], aString);
     return 3; // both overrides map to 3 bytes in UTF8
 }
-	
+
 gfxTextRun *
 gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
                                const Parameters *aParams, PRUint32 aFlags)
 {
     NS_ASSERTION(aFlags & TEXT_IS_8BIT, "8bit should have been set");
     gfxTextRun *run = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
     if (!run)
         return nsnull;
@@ -1094,17 +1506,17 @@ gfxPangoFontGroup::MakeTextRun(const PRU
 PRBool
 gfxPangoFontGroup::CanTakeFastPath(PRUint32 aFlags)
 {
     // Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't.
     // We need to always use Pango for RTL text, in case glyph mirroring is
     // required.
     PRBool speed = aFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
     PRBool isRTL = aFlags & gfxTextRunFactory::TEXT_IS_RTL;
-    return speed && !isRTL && PANGO_IS_FC_FONT(GetFontAt(0)->GetPangoFont());
+    return speed && !isRTL && PANGO_IS_FC_FONT(GetBasePangoFont());
 }
 #endif
 
 gfxTextRun *
 gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
                                const Parameters *aParams, PRUint32 aFlags)
 {
     gfxTextRun *run = gfxTextRun::Create(aParams, aString, aLength, this, aFlags);
@@ -1148,82 +1560,233 @@ gfxPangoFontGroup::InitTextRun(gfxTextRu
             return;
     }
 #endif
 
     CreateGlyphRunsItemizing(aTextRun, aUTF8Text, aUTF8Length, aUTF8HeaderLength);
 #endif
 }
 
-static cairo_scaled_font_t*
-CreateScaledFont(cairo_t *aCR, cairo_matrix_t *aCTM, PangoFont *aPangoFont)
+// This will fetch an existing scaled_font if one exists.
+static cairo_scaled_font_t *
+CreateScaledFont(FcPattern *aPattern)
 {
-// XXX this needs to also check that we're using system cairo
-// otherwise this causes bad problems.
-#if 0
-//#if PANGO_VERSION_CHECK(1,17,5)
-    // Lets just use pango_cairo_font_get_scaled_font() for now.  it's only
-    // available in pango 1.17.x though :(
-    return cairo_scaled_font_reference (pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (aPangoFont)));
-#else
-    // XXX is this safe really? We should probably check the font type or something.
-    // XXX does this really create the same font that Pango used for measurement?
-    // We probably need to work harder here. We should pay particular attention
-    // to the font options.
-    PangoFcFont *fcfont = PANGO_FC_FONT(aPangoFont);
-    cairo_font_face_t *face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern);
+    cairo_font_face_t *face = cairo_ft_font_face_create_for_pattern(aPattern);
     double size;
-    if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
-        size = 12.0;
+    if (FcPatternGetDouble(aPattern,
+                           FC_PIXEL_SIZE, 0, &size) != FcResultMatch) {
+        NS_NOTREACHED("No size on pattern");
+        size = 0.0;
+    }
+        
     cairo_matrix_t fontMatrix;
     FcMatrix *fcMatrix;
-    if (FcPatternGetMatrix(fcfont->font_pattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch)
+    if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch)
         cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0);
     else
         cairo_matrix_init_identity(&fontMatrix);
     cairo_matrix_scale(&fontMatrix, size, size);
+
+    // The cairo_scaled_font is created with a unit ctm so that metrics and
+    // positions are in user space, but this means that hinting effects will
+    // not be estimated accurately for non-unit transformations.
+    cairo_matrix_t identityMatrix;
+    cairo_matrix_init_identity(&identityMatrix);
+
+    // Font options are set explicitly here to improve cairo's caching
+    // behavior and to record the relevant parts of the pattern for
+    // SetupCairoFont (so that the pattern can be released).
+    //
+    // Most font_options have already been set as defaults on the FcPattern
+    // with cairo_ft_font_options_substitute(), then user and system
+    // fontconfig configurations were applied.  The resulting font_options
+    // have been recorded on the face during
+    // cairo_ft_font_face_create_for_pattern().
+    //
+    // None of the settings here cause this scaled_font to behave any
+    // differently from how it would behave if it were created from the same
+    // face with default font_options.
+    //
+    // We set options explicitly so that the same scaled_font will be found in
+    // the cairo_scaled_font_map when cairo loads glyphs from a context with
+    // the same font_face, font_matrix, ctm, and surface font_options.
+    //
+    // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
+    // font_options on the cairo_ft_font_face, and doesn't consider default
+    // option values to not match any explicit values.
+    //
+    // Even after cairo_set_scaled_font is used to set font_options for the
+    // cairo context, when cairo looks for a scaled_font for the context, it
+    // will look for a font with some option values from the target surface if
+    // any values are left default on the context font_options.  If this
+    // scaled_font is created with default font_options, cairo will not find
+    // it.
     cairo_font_options_t *fontOptions = cairo_font_options_create();
-    cairo_get_font_options(aCR, fontOptions);
+
+    // The one option not recorded in the pattern is hint_metrics, which will
+    // affect glyph metrics.  The default behaves as CAIRO_HINT_METRICS_ON.
+    // We should be considering the font_options of the surface on which this
+    // font will be used, but currently we don't have different gfxFonts for
+    // different surface font_options, so we'll create a font suitable for the
+    // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
+    cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON);
+
+    // The remaining options have been recorded on the pattern and the face.
+    // _cairo_ft_options_merge has some logic to decide which options from the
+    // scaled_font or from the cairo_ft_font_face take priority in the way the
+    // font behaves.
+    //
+    // In the majority of cases, _cairo_ft_options_merge uses the options from
+    // the cairo_ft_font_face, so sometimes it is not so important which
+    // values are set here so long as they are not defaults, but we'll set
+    // them to the exact values that we expect from the font, to be consistent
+    // and to protect against changes in cairo.
+    //
+    // In some cases, _cairo_ft_options_merge uses some options from the
+    // scaled_font's font_options rather than options on the
+    // cairo_ft_font_face (from fontconfig).
+    // https://bugs.freedesktop.org/show_bug.cgi?id=11838
+    //
+    // Surface font options were set on the pattern in
+    // cairo_ft_font_options_substitute.  If fontconfig has changed the
+    // hint_style then that is what the user (or distribution) wants, so we
+    // use the setting from the FcPattern.
+    //
+    // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
+    FcBool hinting;
+    if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) {
+        hinting = FcTrue;
+    }
+    cairo_hint_style_t hint_style;
+    if (!hinting) {
+        hint_style = CAIRO_HINT_STYLE_NONE;
+    } else {
+#ifdef FC_HINT_STYLE  // FC_HINT_STYLE is available from fontconfig 2.2.91.
+        int fc_hintstyle;
+        if (FcPatternGetInteger(aPattern, FC_HINT_STYLE,
+                                0, &fc_hintstyle        ) != FcResultMatch) {
+            fc_hintstyle = FC_HINT_FULL;
+        }
+        switch (fc_hintstyle) {
+            case FC_HINT_NONE:
+                hint_style = CAIRO_HINT_STYLE_NONE;
+                break;
+            case FC_HINT_SLIGHT:
+                hint_style = CAIRO_HINT_STYLE_SLIGHT;
+                break;
+            case FC_HINT_MEDIUM:
+            default: // This fallback mirrors _get_pattern_ft_options in cairo.
+                hint_style = CAIRO_HINT_STYLE_MEDIUM;
+                break;
+            case FC_HINT_FULL:
+                hint_style = CAIRO_HINT_STYLE_FULL;
+                break;
+        }
+#else // no FC_HINT_STYLE
+        hint_style = CAIRO_HINT_STYLE_FULL;
+#endif
+    }
+    cairo_font_options_set_hint_style(fontOptions, hint_style);
+
+    int rgba;
+    if (FcPatternGetInteger(aPattern,
+                            FC_RGBA, 0, &rgba) != FcResultMatch) {
+        rgba = FC_RGBA_UNKNOWN;
+    }
+    cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+    switch (rgba) {
+        case FC_RGBA_UNKNOWN:
+        case FC_RGBA_NONE:
+        default:
+            // There is no CAIRO_SUBPIXEL_ORDER_NONE.  Subpixel antialiasing
+            // is disabled through cairo_antialias_t.
+            rgba = FC_RGBA_NONE;
+            // subpixel_order won't be used by the font as we won't use
+            // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
+            // caching reasons described above.  Fall through:
+        case FC_RGBA_RGB:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
+            break;
+        case FC_RGBA_BGR:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
+            break;
+        case FC_RGBA_VRGB:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
+            break;
+        case FC_RGBA_VBGR:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
+            break;
+    }
+    cairo_font_options_set_subpixel_order(fontOptions, subpixel_order);
+
+    FcBool fc_antialias;
+    if (FcPatternGetBool(aPattern,
+                         FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) {
+        fc_antialias = FcTrue;
+    }
+    cairo_antialias_t antialias;
+    if (!fc_antialias) {
+        antialias = CAIRO_ANTIALIAS_NONE;
+    } else if (rgba == FC_RGBA_NONE) {
+        antialias = CAIRO_ANTIALIAS_GRAY;
+    } else {
+        antialias = CAIRO_ANTIALIAS_SUBPIXEL;
+    }
+    cairo_font_options_set_antialias(fontOptions, antialias);
+
     cairo_scaled_font_t *scaledFont =
-        cairo_scaled_font_create(face, &fontMatrix, aCTM, fontOptions);
+        cairo_scaled_font_create(face, &fontMatrix, &identityMatrix,
+                                 fontOptions);
+
     cairo_font_options_destroy(fontOptions);
     cairo_font_face_destroy(face);
+
     NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
                  "Failed to create scaled font");
     return scaledFont;
-#endif
 }
 
 PRBool
-gfxPangoFont::SetupCairoFont(gfxContext *aContext)
+gfxFcFont::SetupCairoFont(gfxContext *aContext)
 {
     cairo_t *cr = aContext->GetCairo();
-    cairo_matrix_t currentCTM;
-    cairo_get_matrix(cr, &currentCTM);
 
-    if (mCairoFont) {
-        // Need to validate that its CTM is OK
-        cairo_matrix_t fontCTM;
-        cairo_scaled_font_get_ctm(mCairoFont, &fontCTM);
-        if (fontCTM.xx != currentCTM.xx || fontCTM.yy != currentCTM.yy ||
-            fontCTM.xy != currentCTM.xy || fontCTM.yx != currentCTM.yx) {
-            // Just recreate it from scratch, simplest way
-            cairo_scaled_font_destroy(mCairoFont);
-            mCairoFont = nsnull;
-        }
-    }
-    if (!mCairoFont) {
-        mCairoFont = CreateScaledFont(cr, &currentCTM, GetPangoFont());
-    }
-    if (cairo_scaled_font_status(mCairoFont) != CAIRO_STATUS_SUCCESS) {
+    // The scaled font ctm is not relevant right here because
+    // cairo_set_scaled_font does not record the scaled font itself, but
+    // merely the font_face, font_matrix, font_options.  The scaled_font used
+    // for the target can be different from the scaled_font passed to
+    // cairo_set_scaled_font.  (Unfortunately we have measured only for an
+    // identity ctm.)
+    cairo_scaled_font_t *cairoFont = CairoScaledFont();
+
+    if (cairo_scaled_font_status(cairoFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
         return PR_FALSE;
     }
-    cairo_set_scaled_font(cr, mCairoFont);
+    // Thoughts on which font_options to set on the context:
+    //
+    // cairoFont has been created for screen rendering.
+    //
+    // When the context is being used for screen rendering, we should set
+    // font_options such that the same scaled_font gets used (when the ctm is
+    // the same).  The use of explicit font_options recorded in
+    // CreateScaledFont ensures that this will happen.
+    //
+    // XXXkt: For pdf and ps surfaces, I don't know whether it's better to
+    // remove surface-specific options, or try to draw with the same
+    // scaled_font that was used to measure.  As the same font_face is being
+    // used, its font_options will often override some values anyway (unless
+    // perhaps we remove those from the FcPattern at face creation).
+    //
+    // I can't see any significant difference in printing, irrespective of
+    // what is set here.  It's too late to change things here as measuring has
+    // already taken place.  We should really be measuring with a different
+    // font for pdf and ps surfaces (bug 403513).
+    cairo_set_scaled_font(cr, cairoFont);
     return PR_TRUE;
 }
 
 static void
 SetupClusterBoundaries(gfxTextRun* aTextRun, const gchar *aUTF8, PRUint32 aUTF8Length,
                        PRUint32 aUTF16Offset, PangoAnalysis *aAnalysis)
 {
     if (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) {
@@ -1507,24 +2070,24 @@ gfxPangoFontGroup::SetMissingGlyphs(gfxT
 }
 
 #if defined(ENABLE_FAST_PATH_8BIT) || defined(ENABLE_FAST_PATH_ALWAYS)
 nsresult
 gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun *aTextRun,
                                        const gchar *aUTF8, PRUint32 aUTF8Length)
 {
     const gchar *p = aUTF8;
-    gfxPangoFont *font = GetFontAt(0);
-    PangoFont *pangofont = font->GetPangoFont();
+    PangoFont *pangofont = GetBasePangoFont();
     PangoFcFont *fcfont = PANGO_FC_FONT (pangofont);
+    gfxFcFont *gfxFont = gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(pangofont));
     PRUint32 utf16Offset = 0;
     gfxTextRun::CompressedGlyph g;
     const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
 
-    aTextRun->AddGlyphRun(font, 0);
+    aTextRun->AddGlyphRun(gfxFont, 0);
 
     while (p < aUTF8 + aUTF8Length) {
         // glib-2.12.9: "If p does not point to a valid UTF-8 encoded
         // character, results are undefined." so it is not easy to assert that
         // aUTF8 in fact points to UTF8 data but asserting
         // g_unichar_validate(ch) may be mildly useful.
         gunichar ch = g_utf8_get_char(p);
         p = g_utf8_next_char(p);
@@ -1534,20 +2097,20 @@ gfxPangoFontGroup::CreateGlyphRunsFast(g
             // doesn't create glyphs for these, not even missing-glyphs.
             aTextRun->SetMissingGlyph(utf16Offset, 0);
         } else {
             NS_ASSERTION(!IsInvalidChar(ch), "Invalid char detected");
             FT_UInt glyph = pango_fc_font_get_glyph (fcfont, ch);
             if (!glyph)                  // character not in font,
                 return NS_ERROR_FAILURE; // fallback to CreateGlyphRunsItemizing
 
-            PangoRectangle rect;
-            pango_font_get_glyph_extents (pangofont, glyph, NULL, &rect);
+            cairo_text_extents_t extents;
+            gfxFont->GetGlyphExtents(glyph, &extents);
 
-            PRInt32 advance = PANGO_PIXELS (rect.width * appUnitsPerDevUnit);
+            PRInt32 advance = NS_lround(extents.x_advance * appUnitsPerDevUnit);
             if (advance >= 0 &&
                 gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
                 gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph)) {
                 aTextRun->SetSimpleGlyph(utf16Offset,
                                          g.SetSimpleGlyph(advance, glyph));
             } else {
                 gfxTextRun::DetailedGlyph details;
                 details.mGlyphID = glyph;
@@ -1568,46 +2131,33 @@ gfxPangoFontGroup::CreateGlyphRunsFast(g
         }
 
         ++utf16Offset;
     }
     return NS_OK;
 }
 #endif
 
-static void
-SetBaseFont(PangoContext *aContext, PangoFont *aBaseFont)
-{
-    PangoFontMap *fontmap = pango_context_get_font_map(aContext);
-    if (GFX_IS_PANGO_FONT_MAP(fontmap)) {
-        // Update the base font in the gfxPangoFontMap
-        GFX_PANGO_FONT_MAP(fontmap)->SetBaseFont(aBaseFont);
-    }
-    else if (aBaseFont) {
-        // Change the font map to record and activate the base font
-        fontmap = gfxPangoFontMap::NewFontMap(fontmap, aBaseFont);
-        pango_context_set_font_map(aContext, fontmap);
-        g_object_unref(fontmap);
-    }
-}
-
 void 
 gfxPangoFontGroup::CreateGlyphRunsItemizing(gfxTextRun *aTextRun,
                                             const gchar *aUTF8, PRUint32 aUTF8Length,
                                             PRUint32 aUTF8HeaderLen)
 {
 
-    PangoContext *context = gdk_pango_context_get();
+    PangoContext *context = GetPangoContext();
 
+    // The font description could be cached on the gfxPangoFontGroup...
+    nsAutoString fcFamilies;
+    GetFcFamilies(fcFamilies);
     PangoFontDescription *fontDesc =
-        NewPangoFontDescription(GetFontAt(0)->GetName(), GetStyle());
+        NewPangoFontDescription(fcFamilies, GetStyle());
     if (GetStyle()->sizeAdjust != 0.0) {
-        gfxFloat size = 
-            static_cast<gfxPangoFont*>(GetFontAt(0))->GetAdjustedSize();
-        pango_font_description_set_absolute_size(fontDesc, size * PANGO_SCALE);
+        gfxFloat size = GetAdjustedSize();
+        pango_font_description_set_absolute_size
+            (fontDesc, moz_pango_units_from_double(size));
     }
 
     pango_context_set_font_description(context, fontDesc);
     pango_font_description_free(fontDesc);
 
     PangoLanguage *lang = GetPangoLanguage(GetStyle()->langGroup);
 
     // we should set this to null if we don't have a text language from the page...
@@ -1618,17 +2168,17 @@ gfxPangoFontGroup::CreateGlyphRunsItemiz
     // characters, but use the default Pango behavior
     // (selecting generic fonts from the script of the characters)
     // in two situations:
     //   1. When we don't have a language to make a good choice for the
     //      primary font.
     //   2. For system fonts, use the default Pango behavior
     //      to give consistency with other apps.
     if (lang && !GetStyle()->systemFont) {
-        SetBaseFont(context, GetFontAt(0)->GetPangoFont());
+        SetBaseFont(context, GetBasePangoFont());
     }
 
     PangoDirection dir = aTextRun->IsRightToLeft() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
     GList *items = pango_itemize_with_base_dir(context, dir, aUTF8, 0, aUTF8Length, nsnull, nsnull);
 
     PRUint32 utf16Offset = 0;
 #ifdef DEBUG
     PRBool isRTL = aTextRun->IsRightToLeft();
@@ -1647,27 +2197,27 @@ gfxPangoFontGroup::CreateGlyphRunsItemiz
         if (offset < aUTF8HeaderLen) {
             if (offset + length <= aUTF8HeaderLen)
                 continue;
 
             length -= aUTF8HeaderLen - offset;
             offset = aUTF8HeaderLen;
         }
 
-        /* look up the gfxPangoFont from the PangoFont */
-        nsRefPtr<gfxPangoFont> font =
-            gfxPangoFont::GetOrMakeFont(item->analysis.font);
+        gfxFcFont *font =
+            gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(item->analysis.font));
 
         nsresult rv = aTextRun->AddGlyphRun(font, utf16Offset, PR_TRUE);
         if (NS_FAILED(rv)) {
             NS_ERROR("AddGlyphRun Failed");
             goto out;
         }
 
-        PRUint32 spaceWidth = NS_lround(font->GetMetrics().spaceWidth * FLOAT_PANGO_SCALE);
+        PRUint32 spaceWidth =
+            moz_pango_units_from_double(font->GetMetrics().spaceWidth);
 
         const gchar *p = aUTF8 + offset;
         const gchar *end = p + length;
         while (p < end) {
             if (*p == 0) {
                 aTextRun->SetMissingGlyph(utf16Offset, 0);
                 ++p;
                 ++utf16Offset;
--- a/gfx/thebes/src/gfxPlatformGtk.cpp
+++ b/gfx/thebes/src/gfxPlatformGtk.cpp
@@ -128,17 +128,17 @@ gfxPlatformGtk::gfxPlatformGtk()
 }
 
 gfxPlatformGtk::~gfxPlatformGtk()
 {
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nsnull;
 
 #ifdef MOZ_PANGO
-    gfxPangoFont::Shutdown();
+    gfxPangoFontGroup::Shutdown();
 #else
     delete gPlatformFonts;
     gPlatformFonts = NULL;
     delete gPlatformFontAliases;
     gPlatformFontAliases = NULL;
 
     FT_Done_FreeType(gPlatformFTLibrary);
     gPlatformFTLibrary = NULL;