Patch for Firefox 1.5/2.0 to add support for printing via Pango.
This also implements printing MathML via Pango, and prints bitmap
fonts too.  Improved handling of ligatures and NUL/invalid sequences
too.

Authors:
	Behdad Esfahbod
	Chris Blizzard
	Akira TAGOH

Index: gfx/src/gtk/mozilla-decoder.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/mozilla-decoder.cpp,v
retrieving revision 1.3
diff -u -p -d -r1.3 mozilla-decoder.cpp
--- gfx/src/gtk/mozilla-decoder.cpp	7 Nov 2004 23:59:23 -0000	1.3
+++ gfx/src/gtk/mozilla-decoder.cpp	22 Nov 2006 22:05:29 -0000
@@ -36,15 +36,11 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
-#define PANGO_ENABLE_BACKEND
-#define PANGO_ENABLE_ENGINE
-
-#include "mozilla-decoder.h"
-#include <pango/pangoxft.h>
+#include <pango/pangofc-decoder.h>
 #include <pango/pangofc-fontmap.h>
 #include <pango/pangofc-font.h>
-#include <gdk/gdkx.h>
 
+#include "mozilla-decoder.h"
 #include "nsString.h"
 #include "nsIPersistentProperties2.h"
 #include "nsNetUtil.h"
@@ -53,11 +49,39 @@
 #include "nsICharRepresentable.h"
 #include "nsCompressedCharMap.h"
 
+#ifdef PSPANGO
+#define MozillaDecoder MozillaDecoderPS
+#define MozillaDecoderClass MozillaDecoderPSClass
+#endif
+
+static GType           mozilla_decoder_get_type (void);
+
+#define MOZILLA_TYPE_DECODER (mozilla_decoder_get_type())
+#define MOZILLA_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaDecoder))
+#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER))
+
+typedef struct _MozillaDecoder      MozillaDecoder;
+typedef struct _MozillaDecoderClass MozillaDecoderClass;
+
+#define MOZILLA_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaDecoderClass))
+#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER))
+#define MOZILLA_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderClass))
+
+struct _MozillaDecoder
+{
+  PangoFcDecoder parent_instance;
+};
+
+struct _MozillaDecoderClass
+{
+  PangoFcDecoderClass parent_class;
+};
+
 #undef DEBUG_CUSTOM_ENCODER
 
 G_DEFINE_TYPE (MozillaDecoder, mozilla_decoder, PANGO_TYPE_FC_DECODER)
 
-MozillaDecoder *mozilla_decoder_new      (void);
+static MozillaDecoder *mozilla_decoder_new      (void);
 
 static FcCharSet  *mozilla_decoder_get_charset (PangoFcDecoder *decoder,
                                                 PangoFcFont    *fcfont);
@@ -92,12 +116,12 @@ GHashTable *encoder_hash = NULL;
 GHashTable *cmap_hash = NULL;
 GHashTable *wide_hash = NULL;
 
-void
+static void
 mozilla_decoder_init (MozillaDecoder *decoder)
 {
 }
 
-void
+static void
 mozilla_decoder_class_init (MozillaDecoderClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
@@ -111,14 +135,14 @@ mozilla_decoder_class_init (MozillaDecod
     g_type_class_add_private (object_class, sizeof (MozillaDecoderPrivate));
 }
 
-MozillaDecoder *
+static MozillaDecoder *
 mozilla_decoder_new(void)
 {
     return (MozillaDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
 }
 
 #ifdef DEBUG_CUSTOM_ENCODER
-void
+static void
 dump_hash(char *key, char *val, void *arg)
 {
     printf("%s -> %s\n", key, val);
@@ -137,13 +161,20 @@ dump_hash(char *key, char *val, void *ar
  * Return value: zero on success, not zero on failure.
  *
  **/
-
 int
-mozilla_decoders_init(void)
+mozilla_decoders_init(PangoFontMap *fontmap)
 {
-    static PRBool initialized = PR_FALSE;
-    if (initialized)
-        return 0;
+    static GQuark init_quark;
+
+    if (!PANGO_IS_FC_FONT_MAP (fontmap))
+        return -1;
+
+    if (G_UNLIKELY (!init_quark)) {
+      init_quark = g_quark_from_static_string ("mozilla-decoders-set");
+    }
+
+    if (G_LIKELY (g_object_get_qdata ((GObject *)fontmap, init_quark)))
+      return 0;
 
     encoder_hash = g_hash_table_new(g_str_hash, g_str_equal);
     cmap_hash = g_hash_table_new(g_str_hash, g_str_equal);
@@ -208,12 +239,12 @@ mozilla_decoders_init(void)
         }
     }
 
-    pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(pango_xft_get_font_map(GDK_DISPLAY(),gdk_x11_get_default_screen())),
+    pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(fontmap),
                                             mozilla_find_decoder,
                                             NULL,
                                             NULL);
 
-    initialized = PR_TRUE;
+    g_object_set_qdata ((GObject *)fontmap, init_quark, GINT_TO_POINTER (1));
 
 #ifdef DEBUG_CUSTOM_ENCODER
     printf("*** encoders\n");
@@ -229,7 +260,7 @@ mozilla_decoders_init(void)
     return -1;
 }
 
-FcCharSet *
+static FcCharSet *
 mozilla_decoder_get_charset (PangoFcDecoder *decoder,
                              PangoFcFont    *fcfont)
 {
@@ -277,7 +308,7 @@ mozilla_decoder_get_charset (PangoFcDeco
     return priv->charset;
 }
 
-PangoGlyph
+static PangoGlyph
 mozilla_decoder_get_glyph   (PangoFcDecoder *decoder,
                              PangoFcFont    *fcfont,
                              guint32         wc)
@@ -338,7 +369,7 @@ mozilla_decoder_get_glyph   (PangoFcDeco
     return retval;
 }
 
-PangoFcDecoder *
+static PangoFcDecoder *
 mozilla_find_decoder (FcPattern *pattern, gpointer user_data)
 {
     // Compare the family name of the font that's been opened to see
Index: gfx/src/gtk/mozilla-decoder.h
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/mozilla-decoder.h,v
retrieving revision 1.2
diff -u -p -d -r1.2 mozilla-decoder.h
--- gfx/src/gtk/mozilla-decoder.h	22 Sep 2004 19:53:45 -0000	1.2
+++ gfx/src/gtk/mozilla-decoder.h	22 Nov 2006 22:05:29 -0000
@@ -39,33 +39,15 @@
 #ifndef _MOZILLA_DECODER_H
 #define _MOZILLA_DECODER_H
 
-#include <pango/pangofc-decoder.h>
+#include <pango/pango-fontmap.h>
 
 G_BEGIN_DECLS
 
-#define MOZILLA_TYPE_DECODER (mozilla_decoder_get_type())
-#define MOZILLA_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaDecoder))
-#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER))
-
-typedef struct _MozillaDecoder      MozillaDecoder;
-typedef struct _MozillaDecoderClass MozillaDecoderClass;
-
-#define MOZILLA_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaDecoderClass))
-#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER))
-#define MOZILLA_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderClass))
-
-struct _MozillaDecoder
-{
-  PangoFcDecoder parent_instance;
-};
-
-struct _MozillaDecoderClass
-{
-  PangoFcDecoderClass parent_class;
-};
+#ifdef PSPANGO
+#define mozilla_decoders_init mozilla_decoders_init_ps
+#endif
 
-GType           mozilla_decoder_get_type (void);
-int             mozilla_decoders_init    (void);
+int             mozilla_decoders_init    (PangoFontMap *fontmap);
 
 G_END_DECLS
 
Index: gfx/src/gtk/nsDeviceContextGTK.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/nsDeviceContextGTK.cpp,v
retrieving revision 1.131
diff -u -p -d -r1.131 nsDeviceContextGTK.cpp
--- gfx/src/gtk/nsDeviceContextGTK.cpp	17 Dec 2004 20:36:28 -0000	1.131
+++ gfx/src/gtk/nsDeviceContextGTK.cpp	22 Nov 2006 22:05:29 -0000
@@ -576,8 +576,10 @@ NS_IMETHODIMP nsDeviceContextGTK::GetDev
     // Create a Postscript device context 
     nsCOMPtr<nsIDeviceContextPS> dcps(do_CreateInstance(kCDeviceContextPS, &rv));
     NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create PS Device context.");
-    if (NS_FAILED(rv)) 
+    if (NS_FAILED(rv)) { 
+      fprintf (stderr, "OK, failed here\n");
       return NS_ERROR_GFX_COULD_NOT_LOAD_PRINT_MODULE;
+    }
   
     rv = dcps->SetSpec(aDevice);
     if (NS_FAILED(rv)) 
Index: gfx/src/gtk/nsFontMetricsPango.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/nsFontMetricsPango.cpp,v
retrieving revision 1.16.2.2.2.2
diff -u -p -d -r1.16.2.2.2.2 nsFontMetricsPango.cpp
--- gfx/src/gtk/nsFontMetricsPango.cpp	23 Feb 2006 21:01:42 -0000	1.16.2.2.2.2
+++ gfx/src/gtk/nsFontMetricsPango.cpp	22 Nov 2006 22:05:29 -0000
@@ -21,6 +21,8 @@
  * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Christopher Blizzard <blizzard@mozilla.org>
+ *   Behdad Esfahbod <behdad@behdad.org>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -36,6 +38,10 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
+#define PANGO_ENABLE_BACKEND
+
+#include "nsFontMetricsPango.h"
+
 #include <strings.h>
 #include "nsFont.h"
 #include "nsIDeviceContext.h"
@@ -43,27 +49,37 @@
 #include "nsIPref.h"
 #include "nsServiceManagerUtils.h"
 
-#define PANGO_ENABLE_BACKEND
-#define PANGO_ENABLE_ENGINE
-
-#include "nsFontMetricsPango.h"
-#include "nsRenderingContextGTK.h"
-#include "nsDeviceContextGTK.h"
 #include "nsFontConfigUtils.h"
 
 #include "nsUnicharUtils.h"
 #include "nsQuickSort.h"
 #include "nsFontConfigUtils.h"
+#include "mozilla-decoder.h"
+
+#define FORCE_PR_LOG
+#include "prlog.h"
+
 
 #include <fontconfig/fontconfig.h>
+#include <freetype/tttables.h>
+
+#include <pango/pango.h>
+#include <pango/pangofc-font.h>
+
+#ifdef PSPANGO
+#include <pango/pangoft2.h>
+#include "nsRenderingContextPS.h"
+#include "nsDeviceContextPS.h"
+#include "nsType1.h"
+#else
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
-#include <freetype/tttables.h>
+#include "nsRenderingContextGTK.h"
+#include "nsDeviceContextGTK.h"
+#endif
+
 
-#include "mozilla-decoder.h"
 
-#define FORCE_PR_LOG
-#include "prlog.h"
 
 // Globals
 
@@ -108,6 +124,49 @@ static nsresult    EnumFontsPango   (nsI
                                      PRUint32* aCount, PRUnichar*** aResult);
 static int         CompareFontNames (const void* aArg1, const void* aArg2,
                                      void* aClosure);
+static void  utf16_to_utf8 (const PRUnichar* aString, PRUint32 aLength,
+                            char *&text, gint &text_len);
+
+#ifdef PSPANGO
+static void
+default_substitute (FcPattern *pattern,
+                    gpointer   data)
+{
+  FcPatternDel (pattern, FC_HINTING);
+  FcPatternAddBool (pattern, FC_HINTING, 0);
+}
+#endif
+
+static PangoFontMap *
+get_fontmap (void)
+{
+  static PangoFontMap               *fontmap = NULL;
+
+  if (!fontmap) {
+#ifdef PSPANGO
+    fontmap = pango_ft2_font_map_new ();
+    pango_ft2_font_map_set_resolution ((PangoFT2FontMap *)fontmap, 72., 72.);
+    pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, default_substitute, NULL, NULL);
+#else
+    PangoContext* context = gdk_pango_context_get ();
+    fontmap = pango_context_get_font_map (context);
+    g_object_unref (context);
+#endif
+  }
+
+  return fontmap;
+}
+
+static PangoContext *
+get_context (void)
+{
+#ifdef PSPANGO
+  return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ());
+#else
+  return gdk_pango_context_get();
+#endif
+}
+
 
 nsFontMetricsPango::nsFontMetricsPango()
 {
@@ -129,7 +188,7 @@ nsFontMetricsPango::nsFontMetricsPango()
         return;
 
     // Initialized the custom decoders
-    if (!mozilla_decoders_init())
+    if (!mozilla_decoders_init(get_fontmap ()))
         initialized = PR_TRUE;
 }
 
@@ -169,14 +228,20 @@ nsFontMetricsPango::Init(const nsFont& a
     mLangGroup = aLangGroup;
 
     // Hang on to the device context
+#ifdef PSPANGO
+    mDeviceContext = (nsDeviceContextPS *)aContext;
+#else
     mDeviceContext = aContext;
+#endif
     
     mPointSize = NSTwipsToFloatPoints(mFont.size);
 
+#ifndef PSPANGO
     // Make sure to clamp the pixel size to something reasonable so we
     // don't make the X server blow up.
     nscoord screenPixels = gdk_screen_height();
     mPointSize = PR_MIN(screenPixels * FONT_MAX_FONT_SCALE, mPointSize);
+#endif
 
     // enumerate over the font names passed in
     mFont.EnumerateFamilies(nsFontMetricsPango::EnumFontCallback, this);
@@ -325,7 +390,7 @@ nsFontMetricsPango::CacheFontMetrics(voi
 
     // mPangoSpaceWidth
     PangoLayout *layout = pango_layout_new(mPangoContext);
-    pango_layout_set_text(layout, " ", 1);
+    pango_layout_set_text(layout, " ", -1);
     int pswidth, psheight;
     pango_layout_get_size(layout, &pswidth, &psheight);
     mPangoSpaceWidth = pswidth;
@@ -333,14 +398,14 @@ nsFontMetricsPango::CacheFontMetrics(voi
 
     // mSpaceWidth (width of a space)
     nscoord tmpWidth;
-    GetWidth(" ", 1, tmpWidth, NULL);
+    GetWidth(" ", 1, tmpWidth CONTEXT_ARG_NULL);
     mSpaceWidth = tmpWidth;
 
     // mAveCharWidth (width of an 'average' char)
     //    XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
     //rawWidth = extents.width;
     //mAveCharWidth = NSToCoordRound(rawWidth * f);
-    GetWidth("x", 1, tmpWidth, NULL);
+    GetWidth("x", 1, tmpWidth CONTEXT_ARG_NULL);
     mAveCharWidth = tmpWidth;
 
     // mXHeight (height of an 'x' character)
@@ -456,130 +521,96 @@ nsFontMetricsPango::GetFontHandle(nsFont
 
 // nsIFontMetricsPango impl
 
-nsresult
-nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
-                             nscoord& aWidth,
-                             nsRenderingContextGTK *aContext)
+#ifdef PSPANGO
+NS_IMETHODIMP
+nsFontMetricsPSPango::GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength)
 {
-    PangoLayout *layout = pango_layout_new(mPangoContext);
-
-    pango_layout_set_text(layout, aString, aLength);
+    return GetWidth (String, (PRUint32) aLength, aWidth CONTEXT_ARG_NULL);
+}
 
-    if (mPangoSpaceWidth)
-        FixupSpaceWidths(layout, aString);
+NS_IMETHODIMP
+nsFontMetricsPSPango::GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength)
+{
+    return GetWidth (aString, (PRUint32)aLength, aWidth, NULL CONTEXT_ARG_NULL);
+}
+#endif
 
+nsresult
+nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
+                             nscoord& aWidth
+                             CONTEXT_ARG_DEF)
+{
     int width, height;
-
+    PangoLayout *layout = GetLayout(aString, aLength);
     pango_layout_get_size(layout, &width, &height);
-
     g_object_unref(layout);
 
-    float f;
-    f = mDeviceContext->DevUnitsToAppUnits();
+    float f = mDeviceContext->DevUnitsToAppUnits();
     aWidth = NSToCoordRound(width * f / PANGO_SCALE);
 
-    //    printf("GetWidth (char *) %d\n", aWidth);
-
     return NS_OK;
 }
 
 nsresult
 nsFontMetricsPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
-                             nscoord& aWidth, PRInt32 *aFontID,
-                             nsRenderingContextGTK *aContext)
+                             nscoord& aWidth, PRInt32 *aFontID
+                             CONTEXT_ARG_DEF)
 {
-    nsresult rv = NS_OK;
-    PangoLayout *layout = pango_layout_new(mPangoContext);
-
-    gchar *text = g_utf16_to_utf8(aString, aLength,
-                                  NULL, NULL, NULL);
-
-    if (!text) {
-        aWidth = 0;
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
-        DUMP_PRUNICHAR(aString, aLength)
-#endif
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
-
     gint width, height;
-
-    pango_layout_set_text(layout, text, strlen(text));
-    FixupSpaceWidths(layout, text);
+    PangoLayout *layout = GetLayout(aString, aLength);
     pango_layout_get_size(layout, &width, &height);
+    g_object_unref(layout);
 
-    float f;
-    f = mDeviceContext->DevUnitsToAppUnits();
+    float f = mDeviceContext->DevUnitsToAppUnits();
     aWidth = NSToCoordRound(width * f / PANGO_SCALE);
 
-    //    printf("GetWidth %d\n", aWidth);
-
- loser:
-    g_free(text);
-    g_object_unref(layout);
-
-    return rv;
+    return NS_OK;
 }
 
 
 nsresult
-nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
+nsFontMetricsPango::GetTextDimensions(const char* aString,
                                       PRUint32 aLength,
-                                      nsTextDimensions& aDimensions, 
-                                      PRInt32* aFontID,
-                                      nsRenderingContextGTK *aContext)
+                                      nsTextDimensions& aDimensions
+                                      CONTEXT_ARG_DEF)
 {
-    nsresult rv = NS_OK;
-
-    PangoLayout *layout = pango_layout_new(mPangoContext);
-
-    gchar *text = g_utf16_to_utf8(aString, aLength,
-                                  NULL, NULL, NULL);
-
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetTextDimensions invalid unicode to follow");
-        DUMP_PRUNICHAR(aString, aLength)
-#endif
-        aDimensions.width = 0;
-        aDimensions.ascent = 0;
-        aDimensions.descent = 0;
+    PangoLayout *layout = GetLayout(aString, aLength);
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
 
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
-        
+    PangoRectangle logical;
+    pango_layout_line_get_extents(line, NULL, &logical);
+    g_object_unref(layout);
 
-    pango_layout_set_text(layout, text, strlen(text));
-    FixupSpaceWidths(layout, text);
+    float P2T = mDeviceContext->DevUnitsToAppUnits();
 
-    // Get the logical extents
-    PangoLayoutLine *line;
-    if (pango_layout_get_line_count(layout) != 1) {
-        printf("Warning: more than one line!\n");
-    }
-    line = pango_layout_get_line(layout, 0);
+    aDimensions.ascent  = NSToCoordRound(PANGO_ASCENT(logical)  * P2T / PANGO_SCALE);
+    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(logical) * P2T / PANGO_SCALE);
+    aDimensions.width   = NSToCoordRound(logical.width          * P2T / PANGO_SCALE);
 
-    PangoRectangle rect;
-    pango_layout_line_get_extents(line, NULL, &rect);
+    return NS_OK;
+}
 
-    float P2T;
-    P2T = mDeviceContext->DevUnitsToAppUnits();
+nsresult
+nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
+                                      PRUint32 aLength,
+                                      nsTextDimensions& aDimensions, 
+                                      PRInt32* aFontID
+                                      CONTEXT_ARG_DEF)
+{
+    PangoLayout *layout = GetLayout(aString, aLength);
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
 
-    aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
-    aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
-    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
+    PangoRectangle logical;
+    pango_layout_line_get_extents(line, NULL, &logical);
+    g_object_unref(layout);
 
-    //    printf("GetTextDimensions %d %d %d\n", aDimensions.width,
-    //aDimensions.ascent, aDimensions.descent);
+    float P2T = mDeviceContext->DevUnitsToAppUnits();
 
- loser:
-    g_free(text);
-    g_object_unref(layout);
+    aDimensions.ascent  = NSToCoordRound(PANGO_ASCENT(logical)  * P2T / PANGO_SCALE);
+    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(logical) * P2T / PANGO_SCALE);
+    aDimensions.width   = NSToCoordRound(logical.width          * P2T / PANGO_SCALE);
 
-    return rv;
+    return NS_OK;
 }
 
 nsresult
@@ -591,13 +622,13 @@ nsFontMetricsPango::GetTextDimensions(co
                                       nsTextDimensions&   aDimensions,
                                       PRInt32&            aNumCharsFit,
                                       nsTextDimensions&   aLastWordDimensions,
-                                      PRInt32*            aFontID,
-                                      nsRenderingContextGTK *aContext)
+                                      PRInt32*            aFontID
+                                      CONTEXT_ARG_DEF)
 {
 
     return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks,
                                      aNumBreaks, aDimensions, aNumCharsFit,
-                                     aLastWordDimensions, aContext);
+                                     aLastWordDimensions CONTEXT_ARG_PASS);
 
 }
 
@@ -610,8 +641,8 @@ nsFontMetricsPango::GetTextDimensions(co
                                       nsTextDimensions&   aDimensions,
                                       PRInt32&            aNumCharsFit,
                                       nsTextDimensions&   aLastWordDimensions,
-                                      PRInt32*            aFontID,
-                                      nsRenderingContextGTK *aContext)
+                                      PRInt32*            aFontID
+                                      CONTEXT_ARG_DEF)
 {
     nsresult rv = NS_OK;
     PRInt32 curBreak = 0;
@@ -619,23 +650,15 @@ nsFontMetricsPango::GetTextDimensions(co
 
     PRInt32 *utf8Breaks = new PRInt32[aNumBreaks];
 
-    gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength,
-                                  NULL, NULL, NULL);
+    gchar* text;
+    gint text_len;
+    utf16_to_utf8 (aString, aLength, text, text_len);
 
     curChar = text;
 
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
-        DUMP_PRUNICHAR(aString, (PRUint32)aLength)
-#endif
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
-
     // Covert the utf16 break offsets to utf8 break offsets
     for (PRInt32 curOffset=0; curOffset < aLength;
-         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
         if (aBreaks[curBreak] == curOffset) {
             utf8Breaks[curBreak] = curChar - text;
             curBreak++;
@@ -649,10 +672,10 @@ nsFontMetricsPango::GetTextDimensions(co
     utf8Breaks[curBreak] = curChar - text;
 
 #if 0
-    if (strlen(text) != aLength) {
-        printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text));
+    if (text_len != aLength) {
+        printf("Different lengths for utf16 %d and utf8 %d\n", aLength, text_len);
         DUMP_PRUNICHAR(aString, aLength)
-        DUMP_PRUNICHAR(text, strlen(text))
+        DUMP_PRUNICHAR(text, text_len)
         for (PRInt32 i = 0; i < aNumBreaks; ++i) {
             printf("  break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]);
         }
@@ -662,9 +685,9 @@ nsFontMetricsPango::GetTextDimensions(co
     // We'll use curBreak to indicate which of the breaks end up being
     // used for the break point for this line.
     curBreak = 0;
-    rv = GetTextDimensionsInternal(text, strlen(text), aAvailWidth, utf8Breaks,
+    rv = GetTextDimensionsInternal(text, text_len, aAvailWidth, utf8Breaks,
                                    aNumBreaks, aDimensions, aNumCharsFit,
-                                   aLastWordDimensions, aContext);
+                                   aLastWordDimensions CONTEXT_ARG_PASS);
 
     // Figure out which of the breaks we ended up using to convert
     // back to utf16 - start from the end.
@@ -677,207 +700,366 @@ nsFontMetricsPango::GetTextDimensions(co
         }
     }
 
- loser:
-    if (text)
-        g_free(text);
+    g_free(text);
 
     delete[] utf8Breaks;
 
     return rv;
 }
 
-nsresult
-nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
-                               nscoord aX, nscoord aY,
-                               const nscoord* aSpacing,
-                               nsRenderingContextGTK *aContext,
-                               nsDrawingSurfaceGTK *aSurface)
+#ifdef PSPANGO
+
+typedef struct _nsPSPangoRenderer        nsPSPangoRenderer;
+typedef struct _nsPSPangoRendererClass   nsPSPangoRendererClass;
+
+struct _nsPSPangoRenderer
 {
-    PangoLayout *layout = pango_layout_new(mPangoContext);
+  PangoRenderer parent_instance;
+  nsRenderingContextPS *psContext;
+  nsFontMetricsPSPango *psPangoFontMetrics;
+  float zoom;
+};
 
-    pango_layout_set_text(layout, aString, aLength);
-    FixupSpaceWidths(layout, aString);
+struct _nsPSPangoRendererClass
+{
+  PangoRendererClass parent_class;
+};
 
-    int x = aX;
-    int y = aY;
+#define _PS_TYPE_PANGO_RENDERER            (_ps_pango_renderer_get_type())
+#define _PS_PANGO_RENDERER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRenderer))
+#define _PS_IS_PANGO_RENDERER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), _PS_TYPE_PANGO_RENDERER))
+#define _PS_PANGO_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
+#define _PS_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), _PS_TYPE_PANGO_RENDERER))
+#define _PS_PANGO_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
 
-    aContext->GetTranMatrix()->TransformCoord(&x, &y);
+G_DEFINE_TYPE (_nsPSPangoRenderer, _ps_pango_renderer, PANGO_TYPE_RENDERER)
 
-    PangoLayoutLine *line;
-    if (pango_layout_get_line_count(layout) != 1) {
-        printf("Warning: more than one line!\n");
-    }
-    line = pango_layout_get_line(layout, 0);
+static PangoRenderer *
+get_renderer (void)
+{
+  static PangoRenderer               *renderer = NULL;
 
-    aContext->UpdateGC();
-    GdkGC *gc = aContext->GetGC();
+  if (!renderer)
+    renderer = (PangoRenderer *) g_object_new (_PS_TYPE_PANGO_RENDERER, NULL);
 
-    if (aSpacing && *aSpacing) {
-        DrawStringSlowly(aString, NULL, aLength, aSurface->GetDrawable(),
-                         gc, x, y, line, aSpacing);
-    }
-    else {
-        gdk_draw_layout_line(aSurface->GetDrawable(), gc,
-                             x, y,
-                             line);
-    }
+  return renderer;
+}
 
-    g_object_unref(gc);
-    g_object_unref(layout);
+static void
+_ps_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
+				PangoFont        *font,
+				PangoGlyphString *glyphs,
+				int               x,
+				int               y);
 
-    //    printf("DrawString (char *)\n");
+static void
+_ps_pango_renderer_class_init (nsPSPangoRendererClass *klass)
+{
+  PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
+  
+  renderer_class->draw_glyphs = _ps_pango_renderer_draw_glyphs;
+}
 
-    return NS_OK;
+static void
+_ps_pango_renderer_init (nsPSPangoRenderer *renderer)
+{
+}
+
+class nsPangoType1Generator : public nsPSFontGenerator {
+public:
+  nsPangoType1Generator();
+  ~nsPangoType1Generator();
+  nsresult Init(PangoFont *aFont);
+  void  GeneratePSFont(FILE* aFile);
+
+protected:
+  PangoFont *mFont;
+};
+
+nsPangoType1Generator::nsPangoType1Generator()
+{
 }
 
 nsresult
-nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
-                               nscoord aX, nscoord aY,
-                               PRInt32 aFontID,
-                               const nscoord* aSpacing,
-                               nsRenderingContextGTK *aContext,
-                               nsDrawingSurfaceGTK *aSurface)
+nsPangoType1Generator::Init(PangoFont *aFont)
 {
-    nsresult rv = NS_OK;
-    int x = aX;
-    int y = aY;
+  NS_ENSURE_TRUE(aFont, NS_ERROR_FAILURE);
+  mFont = aFont;
+  g_object_ref (mFont);
+  return NS_OK;
+}
 
-    aContext->UpdateGC();
-    GdkGC *gc = aContext->GetGC();
+nsPangoType1Generator::~nsPangoType1Generator()
+{
+  g_object_unref (mFont);
+  mFont = nsnull;
+}
 
-    PangoLayout *layout = pango_layout_new(mPangoContext);
+void nsPangoType1Generator::GeneratePSFont(FILE* aFile)
+{
+  FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) mFont);
 
-    gchar *text = g_utf16_to_utf8(aString, aLength,
-                                  NULL, NULL, NULL);
+  if (face == nsnull)
+    return;
 
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::DrawString invalid unicode to follow");
-        DUMP_PRUNICHAR(aString, aLength)
-#endif
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
+  int wmode = 0;
+  if (mGlyphSubset->Count())
+    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
 
-    pango_layout_set_text(layout, text, strlen(text));
-    FixupSpaceWidths(layout, text);
+  pango_fc_font_unlock_face ((PangoFcFont *) mFont);
+}
 
-    aContext->GetTranMatrix()->TransformCoord(&x, &y);
+typedef struct
+{
+  nsCString    *FontNameBase;
+  nsCStringKey *key;
+  int           font_size;
+} PSPangoFontData;
 
-    PangoLayoutLine *line;
-    if (pango_layout_get_line_count(layout) != 1) {
-        printf("Warning: more than one line!\n");
+static void
+ps_pango_font_data_destroy (PSPangoFontData *data)
+{
+  delete data->key;
+  delete data->FontNameBase;
+  g_free (data);
+}
+
+static void
+_ps_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
+				PangoFont        *font,
+				PangoGlyphString *glyphs,
+				int               x,
+				int               y)
+{
+  if (!glyphs->num_glyphs)
+    return;
+
+  static GQuark data_quark = 0;
+  if (!data_quark)
+    data_quark = g_quark_from_static_string ("ps-pango-font-data");
+
+  PSPangoFontData *data;
+  if (!(data = (PSPangoFontData *) g_object_get_qdata (G_OBJECT (font), data_quark)))
+    {
+      data = g_new (PSPangoFontData, 1);
+
+      FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) font);
+      if (face == nsnull)
+        return;
+      int wmode = 0;
+      data->FontNameBase = new nsCString ();
+      if (NS_FAILED(FT2ToType1FontName(face, wmode, *data->FontNameBase))) {
+        g_free (data);
+        pango_fc_font_unlock_face ((PangoFcFont *) font);
+        return;
+      }
+      pango_fc_font_unlock_face ((PangoFcFont *) font);
+
+      PangoFontDescription *desc = pango_font_describe (font);
+      data->font_size = pango_font_description_get_size (desc);
+      pango_font_description_free (desc);
+
+      data->key = new nsCStringKey (*data->FontNameBase);
+
+      g_object_set_qdata_full (G_OBJECT (font), data_quark, data, (GDestroyNotify) ps_pango_font_data_destroy);
     }
-    line = pango_layout_get_line(layout, 0);
 
-    if (aSpacing && *aSpacing) {
-        DrawStringSlowly(text, aString, aLength, aSurface->GetDrawable(),
-                         gc, x, y, line, aSpacing);
+  nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
+  nsRenderingContextPS *aContext = ps_renderer->psContext;
+  nsFontMetricsPSPango *metrics = ps_renderer->psPangoFontMetrics;
+  nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, metrics->GetDeviceContext());
+  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
+  nsHashtable *psFGList = dc->GetPSFontGeneratorList();
+  g_return_if_fail (psFGList);
+  nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(data->key);
+  if (!psFontGen) {
+    nsresult rv;
+    psFontGen = new nsPangoType1Generator;
+    g_return_if_fail (psFontGen);
+    rv = ((nsPangoType1Generator*)psFontGen)->Init(font);
+    if (NS_FAILED(rv)) {
+      delete psFontGen;
+      return;
     }
-    else {
-        gdk_draw_layout_line(aSurface->GetDrawable(), gc,
-                             x, y,
-                             line);
+    psFGList->Put(data->key, (void *) psFontGen);
+  }
+  nscoord font_size = NSToCoordRound (ps_renderer->zoom * data->font_size / PANGO_SCALE);
+
+  g_return_if_fail (aContext);
+  g_return_if_fail (psObj);
+
+  nscoord aX = NSToCoordRound(ps_renderer->zoom * x / PANGO_SCALE);
+  nscoord aY = NSToCoordRound(ps_renderer->zoom * y / PANGO_SCALE);
+  psObj->moveto(aX, aY);
+
+  PRInt32 currSubFont, prevSubFont = -1;
+  PRUint32 i;
+  PangoGlyphString gl;
+
+  gl.glyphs = glyphs->glyphs;
+  gl.num_glyphs = 0;
+  currSubFont = prevSubFont;
+  for (i = 0; i < glyphs->num_glyphs; ++i) {
+    PangoGlyph glyph = glyphs->glyphs[i].glyph;
+
+    if (glyph != PANGO_GLYPH_EMPTY)
+      currSubFont = psFontGen->AddToGlyphSubset(glyph > 0x0fffffff ? 0 : glyph);
+
+    if (prevSubFont != currSubFont) {
+      if (prevSubFont != -1)
+        psObj->show(&gl, ps_renderer->zoom,  psFontGen, prevSubFont);
+
+      psObj->setfont(*data->FontNameBase, (PRUint32) font_size, currSubFont);
+      prevSubFont = currSubFont;
+      gl.glyphs = glyphs->glyphs + i;
+      gl.num_glyphs = 0;
     }
 
- loser:
+    gl.num_glyphs++;
+  }
 
-    g_free(text);
-    g_object_unref(gc);
-    g_object_unref(layout);
+  if (prevSubFont != -1)
+    psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont);
+}
 
-    //    printf("DrawString\n");
+#endif
 
-    return rv;
+static void
+draw_layout_line (int x, int y,
+                  PangoLayoutLine *line,
+                  nsFontMetricsPango *fm
+                  CONTEXT_AND_SURFACE_ARG_DEF)
+{
+#ifdef PSPANGO
+  PangoRenderer *renderer = get_renderer ();
+  nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
+  ps_renderer->psContext = aContext;
+  ps_renderer->psPangoFontMetrics = fm;
+  nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, fm->GetDeviceContext());
+  ps_renderer->zoom = dc->DevUnitsToAppUnits();
+
+  pango_renderer_draw_layout_line (renderer, line,
+                                   NSToCoordRound (x * PANGO_SCALE / ps_renderer->zoom),
+                                   NSToCoordRound (y * PANGO_SCALE / ps_renderer->zoom));
+#else
+    aContext->UpdateGC();
+    GdkGC *gc = aContext->GetGC();
+    gdk_draw_layout_line(aSurface->GetDrawable(), gc, x, y, line);
+    g_object_unref(gc);
+#endif
 }
 
-#ifdef MOZ_MATHML
+
 nsresult
-nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
-                                       nsBoundingMetrics &aBoundingMetrics,
-                                       nsRenderingContextGTK *aContext)
+nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
+                               nscoord aX, nscoord aY,
+                               const nscoord* aSpacing
+                               CONTEXT_AND_SURFACE_ARG_DEF)
 {
-    printf("GetBoundingMetrics (char *)\n");
-    return NS_ERROR_FAILURE;
+    int x = aX;
+    int y = aY;
+
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
+
+    PangoLayout *layout = GetLayout(aString, aLength);
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
+
+    ApplySpacing(aString, aLength, line, aSpacing);
+    draw_layout_line(x, y, line, this CONTEXT_AND_SURFACE_ARG_PASS);
+
+    g_object_unref(layout);
+
+    return NS_OK;
 }
 
 nsresult
-nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
-                                       PRUint32 aLength,
-                                       nsBoundingMetrics &aBoundingMetrics,
-                                       PRInt32 *aFontID,
-                                       nsRenderingContextGTK *aContext)
+nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
+                               nscoord aX, nscoord aY,
+                               PRInt32 aFontID,
+                               const nscoord* aSpacing
+                               CONTEXT_AND_SURFACE_ARG_DEF)
 {
-    nsresult rv = NS_OK;
-    PangoLayout *layout = pango_layout_new(mPangoContext);
+    int x = aX;
+    int y = aY;
 
-    gchar *text = g_utf16_to_utf8(aString, aLength,
-                                  NULL, NULL, NULL);
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
 
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetBoundingMetrics invalid unicode to follow");
-        DUMP_PRUNICHAR(aString, aLength)
-#endif
-        aBoundingMetrics.leftBearing = 0;
-        aBoundingMetrics.rightBearing = 0;
-        aBoundingMetrics.width = 0;
-        aBoundingMetrics.ascent = 0;
-        aBoundingMetrics.descent = 0;
+    PangoLayout *layout = GetLayout(aString, aLength);
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
 
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
+    ApplySpacing(aString, aLength, line, aSpacing);
+    draw_layout_line(x, y, line, this CONTEXT_AND_SURFACE_ARG_PASS);
 
-    pango_layout_set_text(layout, text, strlen(text));
-    FixupSpaceWidths(layout, text);
+    g_object_unref(layout);
 
-    // Get the logical extents
-    PangoLayoutLine *line;
-    if (pango_layout_get_line_count(layout) != 1) {
-        printf("Warning: more than one line!\n");
-    }
-    line = pango_layout_get_line(layout, 0);
+    return NS_OK;
+}
 
-    // Get the ink extents
-    PangoRectangle rect;
-    pango_layout_line_get_extents(line, NULL, &rect);
+#ifdef MOZ_MATHML
+void
+nsFontMetricsPango::GetBoundingMetricsInternal(PangoLayout *aLayout,
+                                               nsBoundingMetrics &aBoundingMetrics
+                                               CONTEXT_ARG_DEF)
+{
+    PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
 
-    float P2T;
-    P2T = mDeviceContext->DevUnitsToAppUnits();
+    // Get the ink and logical extents
+    PangoRectangle ink, logical;
+    pango_layout_line_get_extents(line, &ink, &logical);
 
-    aBoundingMetrics.leftBearing =
-        NSToCoordRound(rect.x * P2T / PANGO_SCALE);
-    aBoundingMetrics.rightBearing =
-        NSToCoordRound(rect.width * P2T / PANGO_SCALE);
-    aBoundingMetrics.width = NSToCoordRound((rect.x + rect.width) * P2T / PANGO_SCALE);
-    aBoundingMetrics.ascent = NSToCoordRound(rect.y * P2T / PANGO_SCALE);
-    aBoundingMetrics.descent = NSToCoordRound(rect.height * P2T / PANGO_SCALE);
+    float P2T = mDeviceContext->DevUnitsToAppUnits();
 
- loser:
-    g_free(text);
+    aBoundingMetrics.leftBearing  = NSToCoordRound(PANGO_LBEARING(ink) * P2T / PANGO_SCALE);
+    aBoundingMetrics.rightBearing = NSToCoordRound(PANGO_RBEARING(ink) * P2T / PANGO_SCALE);
+    aBoundingMetrics.ascent       = NSToCoordRound(PANGO_ASCENT(ink)   * P2T / PANGO_SCALE);
+    aBoundingMetrics.descent      = NSToCoordRound(PANGO_DESCENT(ink)  * P2T / PANGO_SCALE);
+    aBoundingMetrics.width        = NSToCoordRound(logical.width       * P2T / PANGO_SCALE);
+}
+
+
+nsresult
+nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
+                                       nsBoundingMetrics &aBoundingMetrics
+                                       CONTEXT_ARG_DEF)
+{
+    PangoLayout *layout = GetLayout(aString, aLength);
+    GetBoundingMetricsInternal (layout, aBoundingMetrics CONTEXT_ARG_PASS);
     g_object_unref(layout);
 
-    return rv;
+    return NS_OK;
+}
+
+nsresult
+nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
+                                       PRUint32 aLength,
+                                       nsBoundingMetrics &aBoundingMetrics,
+                                       PRInt32 *aFontID
+                                       CONTEXT_ARG_DEF)
+{
+    PangoLayout *layout = GetLayout(aString, aLength);
+    GetBoundingMetricsInternal (layout, aBoundingMetrics CONTEXT_ARG_PASS);
+    g_object_unref(layout);
+
+    return NS_OK;
 }
 
 #endif /* MOZ_MATHML */
 
+#ifndef PSPANGO
 GdkFont*
 nsFontMetricsPango::GetCurrentGDKFont(void)
 {
     return nsnull;
 }
+#endif
 
 nsresult
 nsFontMetricsPango::SetRightToLeftText(PRBool aIsRTL)
 {
     if (aIsRTL) {
         if (!mRTLPangoContext) {
-            mRTLPangoContext = gdk_pango_context_get();
+            mRTLPangoContext = get_context();
             pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL);
-
-            gdk_pango_context_set_colormap(mRTLPangoContext, gdk_rgb_get_cmap());
             pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup));
             pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc);
         }
@@ -896,34 +1078,18 @@ nsFontMetricsPango::GetClusterInfo(const
                                    PRUint32 aLength,
                                    PRUint8 *aClusterStarts)
 {
-    nsresult rv = NS_OK;
     PangoLogAttr *attrs = NULL;
     gint n_attrs = 0;
-    PangoLayout *layout = pango_layout_new(mPangoContext);
-    
-    // Convert the incoming UTF-16 to UTF-8
-    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
-
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
-        DUMP_PRUNICHAR(aText, aLength)
-#endif
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
 
-    // Set up the pango layout
-    pango_layout_set_text(layout, text, strlen(text));
-    FixupSpaceWidths(layout, text);
+    PangoLayout *layout = GetLayout(aText, aLength);
+    pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
+    g_object_unref(layout);
 
     // Convert back to UTF-16 while filling in the cluster info
     // structure.
-    pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
-
     for (PRUint32 pos = 0; pos < aLength; pos++) {
         if (IS_HIGH_SURROGATE(aText[pos])) {
-            aClusterStarts[pos] = 1;
+            aClusterStarts[pos] = 1;//FIXME: shouldn't this be zero?! --be
             pos++;
         }
         else {
@@ -931,67 +1097,34 @@ nsFontMetricsPango::GetClusterInfo(const
         }
     }
 
- loser:
-    if (attrs)
-        g_free(attrs);
-    if (text)
-        g_free(text);
-    if (layout)
-        g_object_unref(layout);
+    g_free(attrs);
 
-    return rv;
+    return NS_OK;
 }
 
 PRInt32
-nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength,
-                                nsPoint aPt)
+nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength, nsPoint aPt)
 {
     int trailing = 0;
     int inx = 0;
-    gboolean found = FALSE;
-    const gchar *curChar;
     PRInt32 retval = 0;
 
     float f = mDeviceContext->AppUnitsToDevUnits();
     
-    PangoLayout *layout = pango_layout_new(mPangoContext);
     PRUint32 localX = (PRUint32)(aPt.x * PANGO_SCALE * f);
     PRUint32 localY = (PRUint32)(aPt.y * PANGO_SCALE * f);
 
-    // Convert the incoming UTF-16 to UTF-8
-    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
-
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
-        DUMP_PRUNICHAR(aText, aLength)
-#endif
-        retval = -1;
-        goto loser;
-    }
-
-    // Set up the pango layout
-    pango_layout_set_text(layout, text, strlen(text));
-    FixupSpaceWidths(layout, text);
+    PangoLayout *layout = GetLayout(aText, aLength);
     
-    found = pango_layout_xy_to_index(layout, localX, localY,
-                                     &inx, &trailing);
+    pango_layout_xy_to_index(layout, localX, localY,
+                             &inx, &trailing);
 
     // Convert the index back to the utf-16 index
-    curChar = text;
-
-    // Jump to the end if it's not found.
-    if (!found) {
-        if (inx == 0)
-            retval = 0;
-        else if (trailing)
-            retval = aLength;
-
-        goto loser;
-    }
+    const gchar *text = pango_layout_get_text (layout);
+    const gchar *curChar = text;
 
     for (PRUint32 curOffset=0; curOffset < aLength;
-         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
 
         // Check for a match before checking for a surrogate pair
         if (curChar - text == inx) {
@@ -1014,13 +1147,9 @@ nsFontMetricsPango::GetPosition(const PR
         trailing--;
     }
 
- loser:
-    if (text)
-        g_free(text);
-    if (layout)
-        g_object_unref(layout);
+    g_object_unref(layout);
 
-    return retval;
+    return retval; 
 }
 
 nsresult
@@ -1030,28 +1159,21 @@ nsFontMetricsPango::GetRangeWidth(const 
                                   PRUint32 aEnd,
                                   PRUint32 &aWidth)
 {
-    nsresult rv = NS_OK;
     PRUint32 utf8Start = 0;
     PRUint32 utf8End = 0;
 
     aWidth = 0;
 
     // Convert the incoming UTF-16 to UTF-8
-    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
-    gchar *curChar = text;
 
-    if (!text) {
-#ifdef DEBUG
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
-        DUMP_PRUNICHAR(aText, aLength)
-#endif
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
+    gchar* text;
+    gint text_len;
+    utf16_to_utf8 (aText, aLength, text, text_len);
+    gchar *curChar = text;
 
     // Convert the utf16 offsets into utf8 offsets
     for (PRUint32 curOffset = 0; curOffset < aLength;
-         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
 
         if (curOffset == aStart)
             utf8Start = curChar - text;
@@ -1065,15 +1187,13 @@ nsFontMetricsPango::GetRangeWidth(const 
 
     // Special case where the end index is the same as the length
     if (aLength == aEnd)
-        utf8End = strlen(text);
+        utf8End = text_len;
 
-    rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth);
+    GetRangeWidth(text, text_len, utf8Start, utf8End, aWidth);
 
- loser:
-    if (text)
-        g_free(text);
+    g_free(text);
 
-    return rv;
+    return NS_OK;
 }
 
 nsresult
@@ -1083,43 +1203,26 @@ nsFontMetricsPango::GetRangeWidth(const 
                                   PRUint32 aEnd,
                                   PRUint32 &aWidth)
 {
-    nsresult rv = NS_OK;
     int *ranges = NULL;
     int n_ranges = 0;
     float f;
 
     aWidth = 0;
 
-    PangoLayout *layout = pango_layout_new(mPangoContext);
-
-    if (!aText) {
-        rv = NS_ERROR_FAILURE;
-        goto loser;
-    }
-
-    pango_layout_set_text(layout, aText, aLength);
-    FixupSpaceWidths(layout, aText);
-
-    PangoLayoutLine *line;
-    if (pango_layout_get_line_count(layout) != 1) {
-        printf("Warning: more than one line!\n");
-    }
-    line = pango_layout_get_line(layout, 0);
+    PangoLayout *layout = GetLayout(aText, aLength);
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
 
     pango_layout_line_get_x_ranges(line, aStart, aEnd, &ranges, &n_ranges);
 
     aWidth = (ranges[((n_ranges - 1) * 2) + 1] - ranges[0]);
 
     f = mDeviceContext-> DevUnitsToAppUnits();
-    aWidth = nscoord(aWidth * f / PANGO_SCALE);
+    aWidth = NSToCoordRound(aWidth * f / PANGO_SCALE);
 
- loser:
-    if (ranges)
-        g_free(ranges);
-    if (layout)
-        g_object_unref(layout);
+    g_free(ranges);
+    g_object_unref(layout);
 
-    return rv;
+    return NS_OK;
 }
 
 /* static */
@@ -1142,7 +1245,7 @@ nsFontMetricsPango::FamilyExists(nsIDevi
     NS_ConvertUTF16toUTF8 name(aName);
 
     nsresult rv = NS_ERROR_FAILURE;
-    PangoContext *context = gdk_pango_context_get();
+    PangoContext *context = get_context();
     PangoFontFamily **familyList;
     int n;
 
@@ -1241,16 +1344,13 @@ nsFontMetricsPango::RealizeFont(void)
 
     // Now that we have the font description set up, create the
     // context.
-    mLTRPangoContext = gdk_pango_context_get();
+    mLTRPangoContext = get_context();
     mPangoContext = mLTRPangoContext;
 
     // Make sure to set the base direction to LTR - if layout needs to
     // render RTL text it will use ::SetRightToLeftText()
     pango_context_set_base_dir(mPangoContext, PANGO_DIRECTION_LTR);
 
-    // Set the color map so we can draw later.
-    gdk_pango_context_set_colormap(mPangoContext, gdk_rgb_get_cmap());
-
     // Set the pango language now that we have a context
     pango_context_set_language(mPangoContext, GetPangoLanguage(mLangGroup));
 
@@ -1288,79 +1388,264 @@ nsFontMetricsPango::EnumFontCallback(con
  * This is only used when there's per-character spacing happening.
  * Well, really it can be either line or character spacing but it's
  * just turtles all the way down!
+ *
+ * To do it correctly (ligatures, etc) we need machinery that is private
+ * in Pango.  IMPORT IT:
  */
 
+#define _PangoGlyphItemIter _nsFontMetricsPangoGlyphItemIter
+#define PangoGlyphItemIter nsFontMetricsPangoGlyphItemIter
+
+#define LTR(glyph_item) (((glyph_item)->item->analysis.level % 2) == 0)
+
+/* Structure holding state when we're iterating over a GlyphItem.
+ * start_index/cluster_end (and range_start/range_end in
+ * apply_attrs()) are offsets into the text, so note the difference
+ * of glyph_item->item->offset between them and clusters in the
+ * log_clusters[] array.
+ */
+typedef struct _PangoGlyphItemIter PangoGlyphItemIter;
+
+struct _PangoGlyphItemIter
+{
+  PangoGlyphItem *glyph_item;
+  const gchar *text;
+  
+  int start_glyph;
+  int start_index;
+  int start_char;
+
+  int end_glyph;
+  int end_index;
+  int end_char;
+};
+
+/**
+ * _pango_glyph_item_iter_next_cluster:
+ * @iter: a #PangoGlyphItemIter
+ * 
+ * Advances the iterator to the next cluster in the glyph item.
+ * 
+ * Return value: %TRUE if the iterator was advanced, %FALSE if we were already on the
+ *  last cluster.
+ **/
+static gboolean
+_pango_glyph_item_iter_next_cluster (PangoGlyphItemIter *iter)
+{
+  int glyph_index = iter->end_glyph;
+  PangoGlyphString *glyphs = iter->glyph_item->glyphs;
+  PangoItem *item = iter->glyph_item->item;
+
+  if (LTR (iter->glyph_item))
+    {
+      if (glyph_index == glyphs->num_glyphs)
+	return FALSE;
+    }
+  else
+    {
+      if (glyph_index < 0)
+	return FALSE;
+    }
+      
+  iter->start_glyph = iter->end_glyph;
+  iter->start_index = iter->end_index;
+  iter->start_char = iter->end_char;
+  
+  if (LTR (iter->glyph_item))
+    {
+      while (TRUE)
+	{
+	  glyph_index++;
+	  
+	  if (glyph_index == glyphs->num_glyphs)
+	    {
+	      iter->end_index = item->offset + item->length;
+	      iter->end_char = item->num_chars;
+	      break;
+	    }
+	  
+	  if (item->offset + glyphs->log_clusters[glyph_index] != iter->start_index)
+	    {
+	      iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
+	      iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
+					       iter->end_index - iter->start_index);
+	      break; 
+	    }
+	}
+    }
+  else			/* RTL */
+    {
+      while (TRUE)
+	{
+	  glyph_index--;
+	  
+	  if (glyph_index < 0)
+	    {
+	      iter->end_index = item->offset + item->length;
+	      iter->end_char = item->num_chars;
+	      break;
+	    }
+	  
+	  if (item->offset + glyphs->log_clusters[glyph_index] != iter->start_index)
+	    {
+	      iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
+	      iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
+					       iter->end_index - iter->start_index);
+	      break; 
+	    }
+	}
+    }
+
+  iter->end_glyph = glyph_index;
+  return TRUE;
+}
+
+/**
+ * _pango_glyph_item_iter_init_start:
+ * @iter: pointer to a #PangoGlyphItemIter structure
+ * @glyph_item: the glyph item that the iter points into
+ * @text: text corresponding to the glyph item
+ * 
+ * Initializes a #PangoGlyphItemIter structure to point to the
+ * first cluster in a glyph item.
+ * 
+ * Return value: %FALSE if there are no clusters in the glyph item;
+ *  in this case, the state of the iter is undefined.
+ **/
+static gboolean
+_pango_glyph_item_iter_init_start (PangoGlyphItemIter  *iter,
+				   PangoGlyphItem      *glyph_item,
+				   const char          *text)
+{
+  iter->glyph_item = glyph_item;
+  iter->text = text;
+  
+  if (LTR (glyph_item))
+    iter->end_glyph = 0;
+  else
+    iter->end_glyph = glyph_item->glyphs->num_glyphs - 1;
+
+  iter->end_index = glyph_item->item->offset;
+  iter->end_char = 0;
+
+  /* Advance onto the first cluster of the glyph item */
+  return _pango_glyph_item_iter_next_cluster (iter);
+}
+
+
 void
-nsFontMetricsPango::DrawStringSlowly(const gchar *aText,
-                                     const PRUnichar *aOrigString,
-                                     PRUint32 aLength,
-                                     GdkDrawable *aDrawable,
-                                     GdkGC *aGC, gint aX, gint aY,
-                                     PangoLayoutLine *aLine,
-                                     const nscoord *aSpacing)
+nsFontMetricsPango::ApplySpacing(const gchar *aText,
+                                 PRUint32 aLength,
+                                 PangoLayoutLine *aLine,
+                                 const nscoord *aSpacing)
 {
-    float app2dev;
-    app2dev = mDeviceContext->AppUnitsToDevUnits();
-    gint offset = 0;
+    if (!(aSpacing && *aSpacing))
+      return;
+
+    float app2dev = mDeviceContext->AppUnitsToDevUnits();
 
     /*
      * We walk the list of glyphs returned in each layout run,
      * matching up the glyphs with the characters in the source text.
      * We use the aSpacing argument to figure out where to place those
-     * glyphs.  It's important to note that since the string we're
-     * working with is in UTF-8 while the spacing argument assumes
-     * that offset will be part of the UTF-16 string.  Logical
-     * attributes in pango are in byte offsets in the UTF-8 string, so
-     * we need to store the offsets based on the UTF-8 string.
+     * glyphs.
      */
-    nscoord *utf8spacing = new nscoord[strlen(aText)];
+    for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
+         tmpList = tmpList->next) {
+        PangoGlyphItem *glyph_item = (PangoGlyphItem *)tmpList->data;
+        PangoGlyphItemIter iter;
+        gboolean have_cluster;
+        PangoGlyphInfo *glyphs = glyph_item->glyphs->glyphs;
+        int residualWidth = 0;
 
-    if (aOrigString) {
-        const gchar *curChar = aText;
-        bzero(utf8spacing, sizeof(nscoord) * strlen(aText));
+        for (have_cluster = _pango_glyph_item_iter_init_start (&iter, glyph_item, aText);
+             have_cluster;
+             have_cluster = _pango_glyph_item_iter_next_cluster (&iter))
+        {
+          int clusterOldWidth = 0;
+          int clusterNewWidth = 0;
+          int dir = iter.start_glyph < iter.end_glyph ? +1 : -1;
 
-        // Covert the utf16 spacing offsets to utf8 spacing offsets
-        for (PRUint32 curOffset=0; curOffset < aLength;
-             curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
-            utf8spacing[curChar - aText] = aSpacing[curOffset];
+          for (const char *p = iter.text + iter.start_index;
+               p < iter.text + iter.end_index;
+               p = g_utf8_next_char (p))
+            clusterNewWidth += aSpacing[p - iter.text];
 
-            if (IS_HIGH_SURROGATE(aOrigString[curOffset]))
-                curOffset++;
+          clusterNewWidth = (gint)(clusterNewWidth * app2dev * PANGO_SCALE);
+
+          for (gint i = iter.start_glyph; i != iter.end_glyph; i += dir) {
+            /* if a zero-width glyph exists, don't touch the glyph widths.
+             * needed for combining marks.  ff thinks they have a width. */
+            if (!glyphs[i].geometry.width) {
+              clusterOldWidth = clusterNewWidth;
+              break;
+            }
+            clusterOldWidth += glyphs[i].geometry.width;
+          }
+            
+          if (clusterOldWidth == clusterNewWidth)
+            continue;
+
+#ifndef PSPANGO
+          /* do some hinting for display */
+
+          if (iter.end_index - iter.start_index == 1 &&
+              *(iter.text + iter.start_index) == ' ') {
+            clusterNewWidth += residualWidth;
+            residualWidth = 0;
+          }
+          
+          if (clusterOldWidth % PANGO_SCALE == 0 && clusterNewWidth % PANGO_SCALE != 0) {
+            int tmp = clusterNewWidth;
+            clusterNewWidth = PANGO_PIXELS (clusterNewWidth) * PANGO_SCALE;
+            residualWidth += tmp - clusterNewWidth;
+          }
+#endif
+
+          /* find the first non-zero-width glyph and adjust its width */
+          for (gint i = iter.start_glyph; i != iter.end_glyph; i += dir)
+            if (glyphs[i].geometry.width) {
+              glyphs[i].geometry.width += clusterNewWidth - clusterOldWidth;
+              break;
+            }
         }
     }
-    else {
-        memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength));
-    }
+}
 
-    gint curRun = 0;
+void
+nsFontMetricsPango::ApplySpacing(const PRUnichar *aText,
+                                 PRUint32 aLength,
+                                 PangoLayoutLine *aLine,
+                                 const nscoord *aSpacing)
+{
+    if (!(aSpacing && *aSpacing))
+      return;
 
-    for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
-         tmpList = tmpList->next, curRun++) {
-        PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
-        gint tmpOffset = 0;
+    const char *utf8Text = pango_layout_get_text (aLine->layout);
+    int utf8Text_len = aLine->start_index + aLine->length;
 
-        /*        printf("    Rendering run %d: \"%s\"\n", curRun,
-                  &aText[layoutRun->item->offset]); */
+    /* Since the string we're
+     * working with is in UTF-8 while the spacing argument assumes
+     * that offset will be part of the UTF-16 string.  Logical
+     * attributes in pango are in byte offsets in the UTF-8 string, so
+     * we need to store the offsets based on the UTF-8 string.
+     */
+    nscoord *utf8spacing = g_new0 (nscoord, utf8Text_len);
 
-        for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
-            /* printf("glyph %d offset %d orig width %d new width %d\n", i,
-             *        layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset,
-             *        layoutRun->glyphs->glyphs[i].geometry.width,
-             *       (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset] * app2dev * PANGO_SCALE));
-             */
-            gint thisOffset = (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset]
-                                     * app2dev * PANGO_SCALE);
-            layoutRun->glyphs->glyphs[i].geometry.width = thisOffset;
-            tmpOffset += thisOffset;
-        }
+    const gchar *curChar = utf8Text + aLine->start_index;
 
-        /*        printf("    rendering at X coord %d\n", aX + offset); */
-        offset += tmpOffset;
+    // Covert the utf16 spacing offsets to utf8 spacing offsets
+    for (PRUint32 curOffset=0; curOffset < aLength;
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
+        utf8spacing[curChar - utf8Text] = aSpacing[curOffset];
+
+        if (IS_HIGH_SURROGATE(aText[curOffset]))
+            curOffset++;
     }
 
-    gdk_draw_layout_line(aDrawable, aGC, aX, aY, aLine);
+    ApplySpacing (utf8Text, utf8Text_len, aLine, utf8spacing);
 
-    delete[] utf8spacing;
+    g_free (utf8spacing);
 }
 
 nsresult
@@ -1371,8 +1656,8 @@ nsFontMetricsPango::GetTextDimensionsInt
                                               PRInt32             aNumBreaks,
                                               nsTextDimensions&   aDimensions,
                                               PRInt32&            aNumCharsFit,
-                                              nsTextDimensions&   aLastWordDimensions,
-                                              nsRenderingContextGTK *aContext)
+                                              nsTextDimensions&   aLastWordDimensions
+                                              CONTEXT_ARG_DEF)
 {
     NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
 
@@ -1418,7 +1703,7 @@ nsFontMetricsPango::GetTextDimensionsInt
             // All the characters should fit
             numChars = aLength - start;
             breakIndex = aNumBreaks - 1;
-        } 
+        }
         else {
             breakIndex = prevBreakState_BreakIndex;
             while (((breakIndex + 1) < aNumBreaks) &&
@@ -1439,7 +1724,7 @@ nsFontMetricsPango::GetTextDimensionsInt
         if ((1 == numChars) && (aString[start] == ' '))
             GetSpaceWidth(twWidth);
         else if (numChars > 0)
-            GetWidth(&aString[start], numChars, twWidth, aContext);
+            GetWidth(&aString[start], numChars, twWidth CONTEXT_ARG_PASS);
 
         // See if the text fits
         PRBool  textFits = (twWidth + width) <= aAvailWidth;
@@ -1489,8 +1774,7 @@ nsFontMetricsPango::GetTextDimensionsInt
                 if ((1 == numChars) && (aString[start] == ' '))
                     GetSpaceWidth(twWidth);
                 else if (numChars > 0)
-                    GetWidth(&aString[start], numChars, twWidth,
-                             aContext);
+                    GetWidth(&aString[start], numChars, twWidth CONTEXT_ARG_PASS);
                 width -= twWidth;
                 aNumCharsFit = start;
                 breakIndex--;
@@ -1512,9 +1796,16 @@ nsFontMetricsPango::GetTextDimensionsInt
 }
 
 void
-nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout,
-                                      const char *aString)
+nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout)
 {
+    if (!mPangoSpaceWidth)
+      return;
+
+    const char *aString = pango_layout_get_text (aLayout);
+
+    if (pango_layout_get_line_count(aLayout) != 1) {
+        printf("Warning: more than one line!\n");
+    }
     PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
 
     gint curRun = 0;
@@ -1531,6 +1822,107 @@ nsFontMetricsPango::FixupSpaceWidths (Pa
     }
 }
 
+PangoLayout*
+nsFontMetricsPango::GetLayout (const PRUnichar* aText,
+                               PRUint32         aLength)
+{
+  gchar* text;
+  gint length;
+  utf16_to_utf8 (aText, aLength, text, length);
+
+  PangoLayout *layout = pango_layout_new(mPangoContext);
+  pango_layout_set_text (layout, text, length);
+  FixupSpaceWidths (layout);
+
+  g_free ((gpointer) text);
+
+  return layout;
+}
+
+PangoLayout*
+nsFontMetricsPango::GetLayout (const gchar*     aText,
+                               PRInt32          aLength)
+{
+  gboolean has_nul = FALSE;
+  int i;
+
+  for (i = 0; i < aLength; i++)
+    if (!aText[i]) {
+      has_nul = TRUE;
+      break;
+    }
+
+  if (has_nul) {
+    /* Pango doesn't correctly handle nuls.  We convert them to 0xff. */
+
+    char *p = (char *) g_memdup (aText, aLength);
+
+    /* don't need to reset i */
+    for (; i < aLength; i++)
+      if (!p[i])
+        p[i] = (char) 0xff;
+
+    aText = p;
+  }
+
+  PangoLayout *layout = pango_layout_new(mPangoContext);
+  pango_layout_set_text (layout, aText, aLength);
+  FixupSpaceWidths (layout);
+
+  if (has_nul)
+    g_free ((gpointer) aText);
+
+  return layout;
+}
+
+static void
+utf16_to_utf8 (const PRUnichar* aText, PRUint32 aLength, char *&text, gint &length)
+{
+  gboolean need_copy = FALSE;
+  int i;
+
+  for (i = 0; i < aLength; i++) {
+    if (!aText[i] || IS_LOW_SURROGATE (aText[i]))
+      need_copy = TRUE;
+    else if (IS_HIGH_SURROGATE (aText[i])) {
+      if (i < aLength - 1 && IS_LOW_SURROGATE (aText[i+1]))
+        i++;
+      else
+        need_copy = TRUE;
+    }
+  }
+
+  if (need_copy) {
+
+    /* Pango doesn't correctly handle nuls.  We convert them to 0xff. */
+    /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
+
+    PRUnichar *p = (PRUnichar *) g_memdup (aText, aLength * sizeof (aText[0]));
+
+    /* don't need to reset i */
+    for (i = 0; i < aLength; i++) {
+      if (!p[i] || IS_LOW_SURROGATE (p[i]))
+        p[i] = 0xFFFD;
+      else if (IS_HIGH_SURROGATE (p[i])) {
+        if (i < aLength - 1 && IS_LOW_SURROGATE (aText[i+1]))
+          i++;
+        else
+          p[i] = 0xFFFD;
+      }
+    }
+
+    aText = p;
+  }
+
+  glong items_written;
+  text = g_utf16_to_utf8 (aText, aLength, NULL, &items_written, NULL);
+  length = items_written;
+
+  if (need_copy)
+    g_free ((gpointer) aText);
+
+}
+
 /* static */
 PangoLanguage *
 GetPangoLanguage(nsIAtom *aLangGroup)
Index: gfx/src/gtk/nsFontMetricsPango.h
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/nsFontMetricsPango.h,v
retrieving revision 1.7
diff -u -p -d -r1.7 nsFontMetricsPango.h
--- gfx/src/gtk/nsFontMetricsPango.h	2 May 2005 20:48:30 -0000	1.7
+++ gfx/src/gtk/nsFontMetricsPango.h	22 Nov 2006 22:05:29 -0000
@@ -37,17 +37,53 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
+
 #include "nsIFontMetrics.h"
 #include "nsIFontEnumerator.h"
 #include "nsCRT.h"
 #include "nsIAtom.h"
 #include "nsString.h"
 #include "nsVoidArray.h"
+
+#ifdef PSPANGO
+#include "nsFontMetricsPS.h"
+#else
 #include "nsIFontMetricsGTK.h"
+#endif
 
 #include <pango/pango.h>
 
-class nsFontMetricsPango : public nsIFontMetricsGTK
+#ifdef PSPANGO
+
+#define CONTEXT_ARG_DEF
+#define CONTEXT_ARG_PASS
+#define CONTEXT_ARG_NULL
+#define CONTEXT_AND_SURFACE_ARG_DEF  , nsRenderingContextPS *aContext
+#define CONTEXT_AND_SURFACE_ARG_PASS , aContext
+
+#else
+
+#define CONTEXT_ARG_DEF              , nsRenderingContextGTK *aContext
+#define CONTEXT_ARG_PASS             , aContext
+#define CONTEXT_ARG_NULL             , NULL
+#define CONTEXT_AND_SURFACE_ARG_DEF  , nsRenderingContextGTK *aContext, nsDrawingSurfaceGTK *aSurface
+#define CONTEXT_AND_SURFACE_ARG_PASS , aContext, aSurface
+
+#endif
+
+
+#ifdef PSPANGO
+
+#define nsFontMetricsPango   nsFontMetricsPSPango
+#define PSPANGO_PARENT_CLASS nsFontMetricsPS
+
+#else
+
+#define PSPANGO_PARENT_CLASS nsIFontMetricsGTK
+
+#endif
+
+class nsFontMetricsPango : public PSPANGO_PARENT_CLASS
 {
 public:
     nsFontMetricsPango();
@@ -134,20 +170,30 @@ public:
                                      { aAveCharWidth = mAveCharWidth;
                                        return NS_OK; };
 
-    // nsIFontMetricsGTK (calls from the font rendering layer)
-    virtual nsresult GetWidth(const char* aString, PRUint32 aLength,
-                              nscoord& aWidth,
-                              nsRenderingContextGTK *aContext);
-    virtual nsresult GetWidth(const PRUnichar* aString, PRUint32 aLength,
-                              nscoord& aWidth, PRInt32 *aFontID,
-                              nsRenderingContextGTK *aContext);
+    // nsIFontMetrics (calls from the font rendering layer)
 
-    virtual nsresult GetTextDimensions(const PRUnichar* aString,
+#ifdef PSPANGO
+    NS_IMETHOD  GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
+    NS_IMETHOD  GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
+#endif
+
+    NS_METHOD        GetWidth(const char* aString, PRUint32 aLength,
+                              nscoord& aWidth
+                              CONTEXT_ARG_DEF);
+    NS_METHOD        GetWidth(const PRUnichar* aString, PRUint32 aLength,
+                              nscoord& aWidth, PRInt32 *aFontID
+                              CONTEXT_ARG_DEF);
+
+    NS_METHOD        GetTextDimensions(const char* aString,
+                                       PRUint32 aLength,
+                                       nsTextDimensions& aDimensions
+                                       CONTEXT_ARG_DEF);
+    NS_METHOD        GetTextDimensions(const PRUnichar* aString,
                                        PRUint32 aLength,
                                        nsTextDimensions& aDimensions, 
-                                       PRInt32* aFontID,
-                                       nsRenderingContextGTK *aContext);
-    virtual nsresult GetTextDimensions(const char*         aString,
+                                       PRInt32* aFontID
+                                       CONTEXT_ARG_DEF);
+    NS_METHOD        GetTextDimensions(const char*         aString,
                                        PRInt32             aLength,
                                        PRInt32             aAvailWidth,
                                        PRInt32*            aBreaks,
@@ -155,9 +201,9 @@ public:
                                        nsTextDimensions&   aDimensions,
                                        PRInt32&            aNumCharsFit,
                                        nsTextDimensions&   aLastWordDimensions,
-                                       PRInt32*            aFontID,
-                                       nsRenderingContextGTK *aContext);
-    virtual nsresult GetTextDimensions(const PRUnichar*    aString,
+                                       PRInt32*            aFontID
+                                       CONTEXT_ARG_DEF);
+    NS_METHOD        GetTextDimensions(const PRUnichar*    aString,
                                        PRInt32             aLength,
                                        PRInt32             aAvailWidth,
                                        PRInt32*            aBreaks,
@@ -165,37 +211,37 @@ public:
                                        nsTextDimensions&   aDimensions,
                                        PRInt32&            aNumCharsFit,
                                        nsTextDimensions&   aLastWordDimensions,
-                                       PRInt32*            aFontID,
-                                       nsRenderingContextGTK *aContext);
+                                       PRInt32*            aFontID
+                                       CONTEXT_ARG_DEF);
 
-    virtual nsresult DrawString(const char *aString, PRUint32 aLength,
+    NS_METHOD        DrawString(const char *aString, PRUint32 aLength,
                                 nscoord aX, nscoord aY,
-                                const nscoord* aSpacing,
-                                nsRenderingContextGTK *aContext,
-                                nsDrawingSurfaceGTK *aSurface);
-    virtual nsresult DrawString(const PRUnichar* aString, PRUint32 aLength,
+                                const nscoord* aSpacing
+                                CONTEXT_AND_SURFACE_ARG_DEF);
+    NS_METHOD        DrawString(const PRUnichar* aString, PRUint32 aLength,
                                 nscoord aX, nscoord aY,
                                 PRInt32 aFontID,
-                                const nscoord* aSpacing,
-                                nsRenderingContextGTK *aContext,
-                                nsDrawingSurfaceGTK *aSurface);
+                                const nscoord* aSpacing
+                                CONTEXT_AND_SURFACE_ARG_DEF);
 
 #ifdef MOZ_MATHML
-    virtual nsresult GetBoundingMetrics(const char *aString, PRUint32 aLength,
-                                        nsBoundingMetrics &aBoundingMetrics,
-                                        nsRenderingContextGTK *aContext);
-    virtual nsresult GetBoundingMetrics(const PRUnichar *aString,
+    NS_METHOD        GetBoundingMetrics(const char *aString, PRUint32 aLength,
+                                        nsBoundingMetrics &aBoundingMetrics
+                                        CONTEXT_ARG_DEF);
+    NS_METHOD        GetBoundingMetrics(const PRUnichar *aString,
                                         PRUint32 aLength,
                                         nsBoundingMetrics &aBoundingMetrics,
-                                        PRInt32 *aFontID,
-                                        nsRenderingContextGTK *aContext);
+                                        PRInt32 *aFontID
+                                        CONTEXT_ARG_DEF);
 #endif /* MOZ_MATHML */
 
+#ifndef PSPANGO
     virtual GdkFont* GetCurrentGDKFont(void);
+#endif
 
-    virtual nsresult SetRightToLeftText(PRBool aIsRTL);
+    NS_METHOD        SetRightToLeftText(PRBool aIsRTL);
 
-    virtual nsresult GetClusterInfo(const PRUnichar *aText,
+    NS_METHOD        GetClusterInfo(const PRUnichar *aText,
                                     PRUint32 aLength,
                                     PRUint8 *aClusterStarts);
 
@@ -203,32 +249,35 @@ public:
                                 PRUint32 aLength,
                                 nsPoint aPt);
 
-    virtual nsresult GetRangeWidth(const PRUnichar *aText,
+    NS_METHOD        GetRangeWidth(const PRUnichar *aText,
                                    PRUint32 aLength,
                                    PRUint32 aStart,
                                    PRUint32 aEnd,
                                    PRUint32 &aWidth);
 
-    virtual nsresult GetRangeWidth(const char *aText,
+    NS_METHOD        GetRangeWidth(const char *aText,
                                    PRUint32 aLength,
                                    PRUint32 aStart,
                                    PRUint32 aEnd,
                                    PRUint32 &aWidth);
 
     // get hints for the font
-    static PRUint32    GetHints     (void);
+#ifndef PSPANGO
+    static
+#endif
+    PRUint32    GetHints     (void);
 
     // drawing surface methods
     static nsresult FamilyExists    (nsIDeviceContext *aDevice,
                                      const nsString &aName);
 
+
 private:
 
     // generic font metrics class bits
     nsCStringArray       mFontList;
     nsAutoVoidArray      mFontIsGeneric;
 
-    nsIDeviceContext    *mDeviceContext;
     nsCOMPtr<nsIAtom>    mLangGroup;
     nsCString           *mGenericFont;
     float                mPointSize;
@@ -243,6 +292,9 @@ private:
     PangoAttrList        *mPangoAttrList;
     PRBool                mIsRTL;
 
+#ifndef PSPANGO
+    nsIDeviceContext    *mDeviceContext; 
+
     // Cached font metrics
     nscoord                  mXHeight;
     nscoord                  mSuperscriptOffset;
@@ -260,8 +312,9 @@ private:
     nscoord                  mMaxDescent;
     nscoord                  mMaxAdvance;
     nscoord                  mSpaceWidth;
-    nscoord                  mPangoSpaceWidth;
     nscoord                  mAveCharWidth;
+#endif
+    nscoord                  mPangoSpaceWidth;
 
     // Private methods
     nsresult RealizeFont(void);
@@ -270,13 +323,14 @@ private:
     static PRBool EnumFontCallback(const nsString &aFamily,
                                    PRBool aIsGeneric, void *aData);
 
-    void     DrawStringSlowly(const gchar *aText,
-                              const PRUnichar *aOrigString,
-                              PRUint32 aLength,
-                              GdkDrawable *aDrawable,
-                              GdkGC *aGC, gint aX, gint aY,
-                              PangoLayoutLine *aLine,
-                              const nscoord *aSpacing);
+    void ApplySpacing(const gchar *aText,
+                      PRUint32 aLength,
+                      PangoLayoutLine *aLine,
+                      const nscoord *aSpacing);
+    void ApplySpacing(const PRUnichar *aText,
+                      PRUint32 aLength,
+                      PangoLayoutLine *aLine,
+                      const nscoord *aSpacing);
 
     nsresult GetTextDimensionsInternal(const gchar*        aString,
                                        PRInt32             aLength,
@@ -285,10 +339,20 @@ private:
                                        PRInt32             aNumBreaks,
                                        nsTextDimensions&   aDimensions,
                                        PRInt32&            aNumCharsFit,
-                                       nsTextDimensions&   aLastWordDimensions,
-                                       nsRenderingContextGTK *aContext);
+                                       nsTextDimensions&   aLastWordDimensions
+                                       CONTEXT_ARG_DEF);
+#ifdef MOZ_MATHML
+    void GetBoundingMetricsInternal(PangoLayout *aLayout,
+                                    nsBoundingMetrics &aBoundingMetrics
+                                    CONTEXT_ARG_DEF);
+#endif /* MOZ_MATHML */
 
-    void FixupSpaceWidths (PangoLayout *aLayout, const char *aString);
+    void FixupSpaceWidths (PangoLayout *aLayout);
+
+    PangoLayout* GetLayout (const PRUnichar* aText,
+                            PRUint32         aLength);
+    PangoLayout* GetLayout (const gchar*     aText,
+                            PRInt32          aLength);
 };
 
 class nsFontEnumeratorPango : public nsIFontEnumerator
Index: gfx/src/gtk/nsFontMetricsUtils.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/nsFontMetricsUtils.cpp,v
retrieving revision 1.6
diff -u -p -d -r1.6 nsFontMetricsUtils.cpp
--- gfx/src/gtk/nsFontMetricsUtils.cpp	28 Mar 2005 02:14:17 -0000	1.6
+++ gfx/src/gtk/nsFontMetricsUtils.cpp	22 Nov 2006 22:05:29 -0000
@@ -143,11 +143,24 @@ NS_IsXftEnabled(void)
 PRBool
 NS_IsPangoEnabled(void)
 {
-    char *val = PR_GetEnv("MOZ_DISABLE_PANGO");
-    if (val)
-        return FALSE;
+    static PRBool beenHere;
+    static PRBool pangoEnabled;
 
-    return TRUE;
+    if (!beenHere) {
+        beenHere = PR_TRUE;
+
+        char *val = PR_GetEnv("MOZ_DISABLE_PANGO");
+        pangoEnabled = !(val);
+
+        if (pangoEnabled) {
+            nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
+            if (prefService)
+                prefService->SetDefaultCharPref("general.useragent.extra.pango",
+                                                "pango-text");
+        }
+    }
+
+    return pangoEnabled;
 }
 
 #endif
Index: gfx/src/freetype/nsFreeType.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.cpp,v
retrieving revision 1.28
diff -u -p -d -r1.28 nsFreeType.cpp
--- gfx/src/freetype/nsFreeType.cpp	13 Jul 2005 18:21:10 -0000	1.28
+++ gfx/src/freetype/nsFreeType.cpp	22 Nov 2006 22:05:29 -0000
@@ -123,6 +123,8 @@ FtFuncList nsFreeType2::FtFuncs [] = {
 // #endif
   {"FT_Get_First_Char",       NS_FT2_OFFSET(nsFT_Get_First_Char),       PR_FALSE},
   {"FT_Get_Next_Char",        NS_FT2_OFFSET(nsFT_Get_Next_Char),        PR_FALSE},
+  {"FT_Has_PS_Glyph_Names",   NS_FT2_OFFSET(nsFT_Has_PS_Glyph_Names),   PR_FALSE},
+  {"FT_Get_Glyph_Name",       NS_FT2_OFFSET(nsFT_Get_Glyph_Name),       PR_TRUE},
   {nsnull,                    0, 0}
 };
 
@@ -388,6 +390,22 @@ nsFreeType2::GetNextChar(FT_Face face, F
 } 
 
 NS_IMETHODIMP
+nsFreeType2::HasPSGlyphNames(FT_Face face, FT_Int *result)
+{
+  // call the FreeType2 function via the function pointer
+  *result = nsFT_Has_PS_Glyph_Names(face);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFreeType2::GetGlyphName(FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max)
+{
+  // call the FreeType2 function via the function pointer
+  FT_Error error = nsFT_Get_Glyph_Name(face, glyph_index, buffer, buffer_max);
+  return error ? NS_ERROR_FAILURE : NS_OK;
+}
+
+NS_IMETHODIMP
 nsFreeType2::SupportsExtFunc(PRBool *res)
 { 
   *res = gHasExtFunc;
Index: gfx/src/freetype/nsFreeType.h
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/freetype/nsFreeType.h,v
retrieving revision 1.18
diff -u -p -d -r1.18 nsFreeType.h
--- gfx/src/freetype/nsFreeType.h	1 May 2005 17:36:19 -0000	1.18
+++ gfx/src/freetype/nsFreeType.h	22 Nov 2006 22:05:29 -0000
@@ -52,6 +52,7 @@
 #include FT_CACHE_H
 #include FT_CACHE_IMAGE_H
 #include FT_TRUETYPE_TABLES_H
+#include FT_TYPE1_TABLES_H
 #include "nsIFreeType2.h"
 
 typedef struct FT_FaceRec_*  FT_Face;
@@ -138,6 +139,8 @@ typedef FT_Error (*FT_Glyph_To_Bitmap_t)
 
 typedef FT_ULong (*FT_Get_First_Char_t)(FT_Face, FT_UInt*);
 typedef FT_ULong (*FT_Get_Next_Char_t)(FT_Face, FT_ULong, FT_UInt*);
+typedef FT_Int   (*FT_Has_PS_Glyph_Names_t)(FT_Face);
+typedef FT_Error (*FT_Get_Glyph_Name_t)(FT_Face, FT_UInt, FT_Pointer, FT_UInt);
 
 class nsFreeTypeFace;
 
@@ -193,11 +196,13 @@ protected:
 // #endif
   FT_Get_First_Char_t       nsFT_Get_First_Char;
   FT_Get_Next_Char_t        nsFT_Get_Next_Char;
+  FT_Has_PS_Glyph_Names_t   nsFT_Has_PS_Glyph_Names;
+  FT_Get_Glyph_Name_t       nsFT_Get_Glyph_Name;
 
   // this array needs to be big enough to hold all the function pointers
   // plus one extra for the null at the end
 // #ifdef MOZ_SVG
-  static FtFuncList FtFuncs[24];
+  static FtFuncList FtFuncs[28];
 // #else
 //  static FtFuncList FtFuncs[20];
 // #endif
Index: gfx/src/ps/Makefile.in
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/ps/Makefile.in,v
retrieving revision 1.57
diff -u -p -d -r1.57 Makefile.in
--- gfx/src/ps/Makefile.in	4 Mar 2005 07:39:27 -0000	1.57
+++ gfx/src/ps/Makefile.in	22 Nov 2006 22:05:29 -0000
@@ -98,13 +98,23 @@ EXTRA_DSO_LDOPTS = \
 		$(MOZ_UNICHARUTIL_LIBS) \
 		$(NULL)
 
+ifdef MOZ_ENABLE_PANGO
+CPPSRCS		+= \
+		nsFontMetricsPango.cpp \
+		mozilla-decoder.cpp
+EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS)
+CXXFLAGS	+= $(MOZ_PANGO_CFLAGS)
+CFLAGS		+= $(MOZ_PANGO_CFLAGS)
+DEFINES		+= -DPSPANGO
+endif
+
 ifdef MOZ_ENABLE_XFT
 EXTRA_DSO_LDOPTS += \
 		$(MOZ_XFT_LIBS) \
 		$(NULL)
 endif
 
-ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT))
+ifneq (,$(MOZ_ENABLE_FREETYPE2)$(MOZ_ENABLE_XFT)$(MOZ_ENABLE_PANGO))
 CPPSRCS		+= \
 		nsType1.cpp \
 		$(NULL)
Index: gfx/src/ps/mozilla-decoder.cpp
===================================================================
RCS file: gfx/src/ps/mozilla-decoder.cpp
diff -N gfx/src/ps/mozilla-decoder.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gfx/src/ps/mozilla-decoder.cpp	22 Nov 2006 22:05:29 -0000
@@ -0,0 +1,406 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Christopher Blizzard
+ * <blizzard@mozilla.org>.  Portions created by the Initial Developer
+ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <pango/pangofc-decoder.h>
+#include <pango/pangofc-fontmap.h>
+#include <pango/pangofc-font.h>
+
+#include "mozilla-decoder.h"
+#include "nsString.h"
+#include "nsIPersistentProperties2.h"
+#include "nsNetUtil.h"
+#include "nsReadableUtils.h"
+#include "nsICharsetConverterManager.h"
+#include "nsICharRepresentable.h"
+#include "nsCompressedCharMap.h"
+
+#ifdef PSPANGO
+#define MozillaDecoder MozillaDecoderPS
+#define MozillaDecoderClass MozillaDecoderPSClass
+#endif
+
+static GType           mozilla_decoder_get_type (void);
+
+#define MOZILLA_TYPE_DECODER (mozilla_decoder_get_type())
+#define MOZILLA_DECODER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOZILLA_TYPE_DECODER, MozillaDecoder))
+#define MOZILLA_IS_DECODER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOZILLA_TYPE_DECODER))
+
+typedef struct _MozillaDecoder      MozillaDecoder;
+typedef struct _MozillaDecoderClass MozillaDecoderClass;
+
+#define MOZILLA_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOZILLA_TYPE_DECODER, MozillaDecoderClass))
+#define MOZILLA_IS_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOZILLA_TYPE_DECODER))
+#define MOZILLA_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderClass))
+
+struct _MozillaDecoder
+{
+  PangoFcDecoder parent_instance;
+};
+
+struct _MozillaDecoderClass
+{
+  PangoFcDecoderClass parent_class;
+};
+
+#undef DEBUG_CUSTOM_ENCODER
+
+G_DEFINE_TYPE (MozillaDecoder, mozilla_decoder, PANGO_TYPE_FC_DECODER)
+
+static MozillaDecoder *mozilla_decoder_new      (void);
+
+static FcCharSet  *mozilla_decoder_get_charset (PangoFcDecoder *decoder,
+                                                PangoFcFont    *fcfont);
+static PangoGlyph  mozilla_decoder_get_glyph   (PangoFcDecoder *decoder,
+                                                PangoFcFont    *fcfont,
+                                                guint32         wc);
+
+static PangoFcDecoder *mozilla_find_decoder    (FcPattern *pattern,
+                                                gpointer   user_data);
+
+typedef struct _MozillaDecoderPrivate MozillaDecoderPrivate;
+
+#define MOZILLA_DECODER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOZILLA_TYPE_DECODER, MozillaDecoderPrivate))
+
+struct _MozillaDecoderPrivate {
+    char *family;
+    char *encoder;
+    char *cmap;
+    gboolean is_wide;
+    FcCharSet *charset;
+    nsCOMPtr<nsIUnicodeEncoder> uEncoder;
+};
+
+static nsICharsetConverterManager *gCharsetManager = NULL;
+
+static NS_DEFINE_CID(kCharsetConverterManagerCID,
+                     NS_ICHARSETCONVERTERMANAGER_CID);
+
+// Hash tables that hold the custom encodings and custom cmaps used in
+// various fonts.
+GHashTable *encoder_hash = NULL;
+GHashTable *cmap_hash = NULL;
+GHashTable *wide_hash = NULL;
+
+static void
+mozilla_decoder_init (MozillaDecoder *decoder)
+{
+}
+
+static void
+mozilla_decoder_class_init (MozillaDecoderClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+    PangoFcDecoderClass *parent_class = PANGO_FC_DECODER_CLASS (klass);
+
+    /*   object_class->finalize = test_finalize; */
+
+    parent_class->get_charset = mozilla_decoder_get_charset;
+    parent_class->get_glyph = mozilla_decoder_get_glyph;
+
+    g_type_class_add_private (object_class, sizeof (MozillaDecoderPrivate));
+}
+
+static MozillaDecoder *
+mozilla_decoder_new(void)
+{
+    return (MozillaDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
+}
+
+#ifdef DEBUG_CUSTOM_ENCODER
+static void
+dump_hash(char *key, char *val, void *arg)
+{
+    printf("%s -> %s\n", key, val);
+}
+#endif
+
+/**
+ * mozilla_decoders_init:
+ *
+ * #mozilla_decoders_init:
+ *
+ * This initializes all of the application-specific custom decoders
+ * that Mozilla uses.  This should only be called once during the
+ * lifetime of the application.
+ *
+ * Return value: zero on success, not zero on failure.
+ *
+ **/
+int
+mozilla_decoders_init(PangoFontMap *fontmap)
+{
+    static GQuark init_quark;
+
+    if (!PANGO_IS_FC_FONT_MAP (fontmap))
+        return -1;
+
+    if (G_UNLIKELY (!init_quark)) {
+      init_quark = g_quark_from_static_string ("mozilla-decoders-set");
+    }
+
+    if (G_LIKELY (g_object_get_qdata ((GObject *)fontmap, init_quark)))
+      return 0;
+
+    encoder_hash = g_hash_table_new(g_str_hash, g_str_equal);
+    cmap_hash = g_hash_table_new(g_str_hash, g_str_equal);
+    wide_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+    PRBool dumb = PR_FALSE;
+    nsCOMPtr<nsIPersistentProperties> props;
+    nsCOMPtr<nsISimpleEnumerator> encodeEnum;
+
+    NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(props),
+        NS_LITERAL_CSTRING("resource://gre/res/fonts/pangoFontEncoding.properties"));
+
+    if (!props)
+        goto loser;
+
+    // Enumerate the properties in this file and figure out all of the
+    // fonts for which we have custom encodings.
+    props->Enumerate(getter_AddRefs(encodeEnum));
+    if (!encodeEnum)
+        goto loser;
+
+    while (encodeEnum->HasMoreElements(&dumb), dumb) {
+        nsCOMPtr<nsIPropertyElement> prop;
+        encodeEnum->GetNext(getter_AddRefs(prop));
+        if (!prop)
+            goto loser;
+
+        nsCAutoString name;
+        prop->GetKey(name);
+        nsAutoString value;
+        prop->GetValue(value);
+
+        if (!StringBeginsWith(name, NS_LITERAL_CSTRING("encoding."))) {
+            printf("string doesn't begin with encoding?\n");
+            continue;
+        }
+
+        name = Substring(name, 9);
+
+        if (StringEndsWith(name, NS_LITERAL_CSTRING(".ttf"))) {
+            name = Substring(name, 0, name.Length() - 4);
+
+            // Strip off a .wide if it's there.
+            if (StringEndsWith(value, NS_LITERAL_STRING(".wide"))) {
+                g_hash_table_insert(wide_hash, g_strdup(name.get()),
+                                    g_strdup("wide"));
+                value = Substring(value, 0, name.Length() - 5);
+            }
+
+            g_hash_table_insert(encoder_hash,
+                                g_strdup(name.get()),
+                                g_strdup(NS_ConvertUTF16toUTF8(value).get()));
+        }
+        else if (StringEndsWith(name, NS_LITERAL_CSTRING(".ftcmap"))) {
+            name = Substring(name, 0, name.Length() - 7);
+            g_hash_table_insert(cmap_hash,
+                                g_strdup(name.get()),
+                                g_strdup(NS_ConvertUTF16toUTF8(value).get()));
+        }
+        else {
+            printf("unknown suffix used for mapping\n");
+        }
+    }
+
+    pango_fc_font_map_add_decoder_find_func(PANGO_FC_FONT_MAP(fontmap),
+                                            mozilla_find_decoder,
+                                            NULL,
+                                            NULL);
+
+    g_object_set_qdata ((GObject *)fontmap, init_quark, GINT_TO_POINTER (1));
+
+#ifdef DEBUG_CUSTOM_ENCODER
+    printf("*** encoders\n");
+    g_hash_table_foreach(encoder_hash, (GHFunc)dump_hash, NULL);
+
+    printf("*** cmaps\n");
+    g_hash_table_foreach(cmap_hash, (GHFunc)dump_hash, NULL);
+#endif
+
+    return 0;
+
+ loser:
+    return -1;
+}
+
+static FcCharSet *
+mozilla_decoder_get_charset (PangoFcDecoder *decoder,
+                             PangoFcFont    *fcfont)
+{
+    MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
+
+    if (priv->charset)
+        return priv->charset;
+
+    // First time this has been accessed.  Populate the charset.
+    priv->charset = FcCharSetCreate();
+
+    if (!gCharsetManager) {
+        CallGetService(kCharsetConverterManagerCID, &gCharsetManager);
+    }
+
+    nsCOMPtr<nsIUnicodeEncoder> encoder;
+    nsCOMPtr<nsICharRepresentable> represent;
+
+    if (!gCharsetManager)
+        goto end;
+
+    gCharsetManager->GetUnicodeEncoderRaw(priv->encoder, getter_AddRefs(encoder));
+    if (!encoder)
+        goto end;
+    
+    encoder->SetOutputErrorBehavior(encoder->kOnError_Replace, nsnull, '?');
+
+    priv->uEncoder = encoder;
+
+    represent = do_QueryInterface(encoder);
+    if (!represent)
+        goto end;
+
+    PRUint32 map[UCS2_MAP_LEN];
+    memset(map, 0, sizeof(map));
+
+    represent->FillInfo(map);
+
+    for (int i = 0; i < NUM_UNICODE_CHARS; i++) {
+        if (IS_REPRESENTABLE(map, i))
+            FcCharSetAddChar(priv->charset, i);
+    }
+
+ end:
+    return priv->charset;
+}
+
+static PangoGlyph
+mozilla_decoder_get_glyph   (PangoFcDecoder *decoder,
+                             PangoFcFont    *fcfont,
+                             guint32         wc)
+{
+    MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
+
+    PangoGlyph retval = 0;
+    PRUnichar inchar = wc;
+    PRInt32 inlen = 1;
+    char outchar[2] = {0,0};
+    PRInt32 outlen = 2;
+
+    priv->uEncoder->Convert(&inchar, &inlen, outchar, &outlen);
+    if (outlen != 1) {
+        printf("Warning: mozilla_decoder_get_glyph doesn't support more than one character conversions.\n");
+        return 0;
+    }
+
+    FT_Face face = pango_fc_font_lock_face(fcfont);
+
+#ifdef DEBUG_CUSTOM_ENCODER
+    char *filename;
+    FcPatternGetString(fcfont->font_pattern, FC_FILE, 0, (FcChar8 **)&filename);
+    printf("filename is %s\n", filename);
+#endif
+
+    // Make sure to set the right charmap before trying to get the
+    // glyph
+    if (priv->cmap) {
+        if (!strcmp(priv->cmap, "mac_roman")) {
+            FT_Select_Charmap(face, ft_encoding_apple_roman);
+        }
+        else if (!strcmp(priv->cmap, "unicode")) {
+            FT_Select_Charmap(face, ft_encoding_unicode);
+        }
+        else {
+            printf("Warning: Invalid charmap entry for family %s\n",
+                   priv->family);
+        }
+    }
+
+    // Standard 8 bit to glyph translation
+    if (!priv->is_wide) {
+        FcChar32 blah = PRUint8(outchar[0]);
+        retval = FT_Get_Char_Index(face, blah);
+#ifdef DEBUG_CUSTOM_ENCODER
+        printf("wc 0x%x outchar[0] 0x%x index 0x%x retval 0x%x face %p\n",
+               wc, outchar[0], blah, retval, (void *)face);
+#endif
+    }
+    else {
+        printf("Warning: We don't support .wide fonts!\n");
+        retval = 0;
+    }
+
+    pango_fc_font_unlock_face(fcfont);
+
+    return retval;
+}
+
+static PangoFcDecoder *
+mozilla_find_decoder (FcPattern *pattern, gpointer user_data)
+{
+    // Compare the family name of the font that's been opened to see
+    // if we have a custom decoder.
+    const char *orig = NULL;
+    FcPatternGetString(pattern, FC_FAMILY, 0, (FcChar8 **)&orig);
+
+    nsCAutoString family;
+    family.Assign(orig);
+
+    family.StripWhitespace();
+    ToLowerCase(family);
+
+    char *encoder = (char *)g_hash_table_lookup(encoder_hash, family.get());
+    if (!encoder)
+        return NULL;
+
+    MozillaDecoder *decoder = mozilla_decoder_new();
+
+    MozillaDecoderPrivate *priv = MOZILLA_DECODER_GET_PRIVATE(decoder);
+
+    priv->family = g_strdup(family.get());
+    priv->encoder = g_strdup(encoder);
+
+    char *cmap = (char *)g_hash_table_lookup(cmap_hash, family.get());
+    if (cmap)
+        priv->cmap = g_strdup(cmap);
+
+    char *wide = (char *)g_hash_table_lookup(wide_hash, family.get());
+    if (wide)
+        priv->is_wide = TRUE;
+
+    return PANGO_FC_DECODER(decoder);
+}
Index: gfx/src/ps/mozilla-decoder.h
===================================================================
RCS file: gfx/src/ps/mozilla-decoder.h
diff -N gfx/src/ps/mozilla-decoder.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gfx/src/ps/mozilla-decoder.h	22 Nov 2006 22:05:29 -0000
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Christopher Blizzard
+ * <blizzard@mozilla.org>.  Portions created by the Initial Developer
+ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _MOZILLA_DECODER_H
+#define _MOZILLA_DECODER_H
+
+#include <pango/pango-fontmap.h>
+
+G_BEGIN_DECLS
+
+#ifdef PSPANGO
+#define mozilla_decoders_init mozilla_decoders_init_ps
+#endif
+
+int             mozilla_decoders_init    (PangoFontMap *fontmap);
+
+G_END_DECLS
+
+#endif /*_MOZILLA_DECODER_H */
Index: gfx/src/ps/nsDeviceContextPS.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/ps/nsDeviceContextPS.cpp,v
retrieving revision 1.73
diff -u -p -d -r1.73 nsDeviceContextPS.cpp
--- gfx/src/ps/nsDeviceContextPS.cpp	21 May 2005 15:33:08 -0000	1.73
+++ gfx/src/ps/nsDeviceContextPS.cpp	22 Nov 2006 22:05:29 -0000
@@ -58,12 +58,15 @@
 #include "nsIPref.h"
 #include "nsString.h"
 #include "nsFontMetricsPS.h"
+#ifdef MOZ_ENABLE_PANGO
+#include "nsFontMetricsPango.h"
+#endif
 #include "nsPostScriptObj.h"
 #include "nspr.h"
 #include "nsILanguageAtomService.h"
 #include "nsPrintJobPS.h"
 #include "nsPrintJobFactoryPS.h"
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
 #include "nsType1.h"
 #endif
 
@@ -223,7 +226,7 @@ nsDeviceContextPS::InitDeviceContextPS(n
  
   nsresult rv;
   nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
-#ifdef MOZ_ENABLE_XFT
+#if defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
   if (NS_SUCCEEDED(rv)) {
       rv = pref->GetBoolPref("font.FreeType2.printing", &mFTPEnable);
       if (NS_FAILED(rv))
@@ -469,7 +472,7 @@ NS_IMETHODIMP nsDeviceContextPS::EndDocu
       NS_ASSERTION(submitFP, "No print job submission handle");
 
       // Start writing the print job to the job handler
-#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT) || defined(MOZ_ENABLE_PANGO)
       mPSObj->write_prolog(submitFP, mFTPEnable);
 #else 
       mPSObj->write_prolog(submitFP);
@@ -550,15 +553,52 @@ public:
   virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** aResult);
 };
 
+#if defined(MOZ_ENABLE_PANGO)
+PRBool
+NS_IsPangoEnabled(void)
+{
+    static PRBool beenHere;
+    static PRBool pangoEnabled;
+
+    if (!beenHere) {
+        beenHere = PR_TRUE;
+
+        char *val = PR_GetEnv("MOZ_DISABLE_PANGO");
+        pangoEnabled = !(val);
+
+        if (pangoEnabled) {
+            nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
+            if (prefService)
+                prefService->SetDefaultCharPref("general.useragent.extra.pango",
+                                                "pango-text");
+        }
+    }
+
+    return pangoEnabled;
+}
+#endif
 
 nsresult nsFontCachePS::CreateFontMetricsInstance(nsIFontMetrics** aResult)
 {
   NS_PRECONDITION(aResult, "null out param");
-  nsIFontMetrics *fm = new nsFontMetricsPS();
-  if (!fm)
-    return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(fm);
-  *aResult = fm;
+#ifdef MOZ_ENABLE_PANGO
+  if (NS_IsPangoEnabled())
+  {
+    nsIFontMetrics *fm = new nsFontMetricsPSPango();
+    if (!fm)
+      return NS_ERROR_OUT_OF_MEMORY;
+    NS_ADDREF(fm);
+    *aResult = fm;
+  }
+  else
+#endif
+  {
+    nsIFontMetrics *fm = new nsFontMetricsPS();
+    if (!fm)
+      return NS_ERROR_OUT_OF_MEMORY;
+    NS_ADDREF(fm);
+    *aResult = fm;
+  }
   return NS_OK;
 }
 
Index: gfx/src/ps/nsFontMetricsPS.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.cpp,v
retrieving revision 1.57.16.2
diff -u -p -d -r1.57.16.2 nsFontMetricsPS.cpp
--- gfx/src/ps/nsFontMetricsPS.cpp	7 May 2006 02:01:25 -0000	1.57.16.2
+++ gfx/src/ps/nsFontMetricsPS.cpp	22 Nov 2006 22:05:29 -0000
@@ -461,6 +461,239 @@ nsFontMetricsPS :: GetStringWidth(const 
   return NS_OK;
 }
 
+nsresult
+nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength,
+                               nscoord aX, nscoord aY,
+                               const nscoord* aSpacing,
+                               nsRenderingContextPS *aContext)
+{
+  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
+  // When FT2 printing is enabled, we don't need to set langgroup
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
+  if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) {
+#endif
+    nsCOMPtr<nsIAtom> langGroup;
+    GetLangGroup(getter_AddRefs(langGroup));
+    psObj->setlanggroup(langGroup);
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
+  }
+#endif
+
+  if (aLength == 0)
+    return NS_OK;
+  nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this);
+  NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
+  fontPS->SetupFont(aContext);
+
+  PRUint32 i, start = 0;
+  for (i=0; i<aLength; i++) {
+    nsFontPS* fontThisChar;
+    fontThisChar = nsFontPS::FindFont(aString[i], Font(), this);
+    NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
+    if (fontThisChar != fontPS) {
+      // draw text up to this point
+      aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
+                       aSpacing?aSpacing+start:nsnull, aContext);
+      start = i;
+
+      // setup for following text
+      fontPS = fontThisChar;
+      fontPS->SetupFont(aContext);
+    }
+  }
+
+  // draw the last part
+  if (aLength-start)
+    DrawString(aString+start, aLength-start, aX, aY, fontPS, 
+               aSpacing?aSpacing+start:nsnull, aContext);
+
+  return NS_OK;
+}
+
+nsresult
+nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength,
+                               nscoord aX, nscoord aY,
+                               PRInt32 aFontID,
+                               const nscoord* aSpacing,
+                               nsRenderingContextPS *aContext)
+{
+  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
+  // When FT2 printing is enabled, we don't need to set langgroup
+  if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, GetDeviceContext())->mFTPEnable) {
+#endif
+    nsCOMPtr<nsIAtom> langGroup = nsnull;
+    GetLangGroup(getter_AddRefs(langGroup));
+    psObj->setlanggroup(langGroup);
+#if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
+  }
+#endif
+
+  /* build up conversion table */
+  psObj->preshow(aString, aLength);
+
+  if (aLength == 0)
+    return NS_OK;
+  nsFontPS* fontPS = nsFontPS::FindFont(aString[0], Font(), this);
+  NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
+  fontPS->SetupFont(aContext);
+
+  PRUint32 i, start = 0;
+  for (i=0; i<aLength; i++) {
+    nsFontPS* fontThisChar;
+    fontThisChar = nsFontPS::FindFont(aString[i], Font(), this);
+    NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
+    if (fontThisChar != fontPS) {
+      // draw text up to this point
+      aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
+                       aSpacing?aSpacing+start:nsnull, aContext);
+      start = i;
+
+      // setup for following text
+      fontPS = fontThisChar;
+      fontPS->SetupFont(aContext);
+    }
+  }
+
+  // draw the last part
+  if (aLength-start)
+    DrawString(aString+start, aLength-start, aX, aY, fontPS, 
+               aSpacing?aSpacing+start:nsnull, aContext);
+
+  return NS_OK;
+}
+
+PRInt32
+nsFontMetricsPS::DrawString(const char *aString, PRUint32 aLength,
+                        nscoord aX, nscoord aY, nsFontPS* aFontPS,
+                        const nscoord* aSpacing,
+			nsRenderingContextPS *aContext)
+{
+  nscoord width = 0;
+  PRInt32 x = aX;
+  PRInt32 y = aY;
+
+  PRInt32 dxMem[500];
+  PRInt32* dx0 = 0;
+  if (aSpacing) {
+    dx0 = dxMem;
+    if (aLength > 500) {
+      dx0 = new PRInt32[aLength];
+      NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY);
+    }
+    aContext->GetTranMatrix()->ScaleXCoords(aSpacing, aLength, dx0);
+  }
+
+  aContext->GetTranMatrix()->TransformCoord(&x, &y);
+  width = aFontPS->DrawString(aContext, x, y, aString, aLength);
+
+  if ((aSpacing) && (dx0 != dxMem)) {
+    delete [] dx0;
+  }
+
+  return width;
+}
+
+
+PRInt32
+nsFontMetricsPS::DrawString(const PRUnichar* aString, PRUint32 aLength,
+                                 nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
+                                 const nscoord* aSpacing,
+				 nsRenderingContextPS *aContext)
+{
+  nscoord width = 0;
+  PRInt32 x = aX;
+  PRInt32 y = aY;
+
+  if (aSpacing) {
+    // Slow, but accurate rendering
+    const PRUnichar* end = aString + aLength;
+    while (aString < end){
+      x = aX;
+      y = aY;
+      aContext->GetTranMatrix()->TransformCoord(&x, &y);
+      aFontPS->DrawString(aContext, x, y, aString, 1);
+      aX += *aSpacing++;
+      aString++;
+    }
+    width = aX;
+  } else {
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
+    width = aFontPS->DrawString(aContext, x, y, aString, aLength);
+  }
+
+  return width;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPS::GetTextDimensions(const char*       aString,
+                                        PRInt32           aLength,
+                                        PRInt32           aAvailWidth,
+                                        PRInt32*          aBreaks,
+                                        PRInt32           aNumBreaks,
+                                        nsTextDimensions& aDimensions,
+                                        PRInt32&          aNumCharsFit,
+                                        nsTextDimensions& aLastWordDimensions,
+                                        PRInt32*          aFontID)
+{
+  NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPS::GetTextDimensions(const PRUnichar*  aString,
+                                        PRInt32           aLength,
+                                        PRInt32           aAvailWidth,
+                                        PRInt32*          aBreaks,
+                                        PRInt32           aNumBreaks,
+                                        nsTextDimensions& aDimensions,
+                                        PRInt32&          aNumCharsFit,
+                                        nsTextDimensions& aLastWordDimensions,
+                                        PRInt32*          aFontID)
+{
+  NS_NOTYETIMPLEMENTED("nsFontMetricsPS::GetTextDimensions");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
+                                          nsTextDimensions& aDimensions)
+{
+  GetStringWidth(aString, aDimensions.width, aLength);
+  GetMaxAscent(aDimensions.ascent);
+  GetMaxDescent(aDimensions.descent);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
+                                          nsTextDimensions& aDimensions, PRInt32* aFontID)
+{
+  GetStringWidth(aString, aDimensions.width, aLength);
+  //XXX temporary - bug 96609
+  GetMaxAscent(aDimensions.ascent);
+  GetMaxDescent(aDimensions.descent);
+  return NS_OK;
+}
+
+nsresult
+nsFontMetricsPS::GetBoundingMetrics(const char*        aString,
+                                     PRUint32           aLength,
+                                     nsBoundingMetrics& aBoundingMetrics)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsFontMetricsPS::GetBoundingMetrics(const PRUnichar*   aString,
+                                     PRUint32           aLength,
+                                     nsBoundingMetrics &aBoundingMetrics,
+                                     PRInt32 *aFontID)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+
 nsFontPS*
 nsFontPS::FindFont(char aChar, const nsFont& aFont, 
                    nsFontMetricsPS* aFontMetrics)
@@ -993,7 +1226,7 @@ nsFontPSXft::FindFont(PRUnichar aChar, c
 
         fontps *fps = new fontps;
         fps->entry = xftEntry;
-        fps->charset = fc_charset;
+        fps->charset = FcCharSetCopy (fc_charset);
         fps->fontps = nsnull;
         fpi.fontps->AppendElement(fps);
     }
@@ -1128,23 +1361,38 @@ nsFontPSXft::DrawString(nsRenderingConte
   PRUint32 start = 0;
   PRUint32 i;
 
+  FT_Face face = getFTFace();
+  if (!face) {
+    NS_WARNING("Failed to get FT Face in nsFontPSXft::DrawString\n");
+    return 0;
+  }
+
+  nsValueArray glyphs(PR_UINT16_MAX);
+
   // XXX : ignore surrogate pairs for now
-  nsString *subSet = mPSFontGenerator->GetSubset();
   for (i = 0; i < aLength; ++i) {
-    currSubFont = mPSFontGenerator->AddToSubset(aString[i]);
+    PRUint32 glyph = FT_Get_Char_Index(face, aString[i]);
+    currSubFont = mPSFontGenerator->AddToGlyphSubset(glyph);
+
+    // Check if we need to render the current string
     if (prevSubFont != currSubFont) {
-      if (prevSubFont != -1)
-        psObj->show(&aString[start], i - start, *subSet, prevSubFont);
+      if (prevSubFont != -1) {
+        psObj->show(&glyphs, mPSFontGenerator, prevSubFont);
+      }
       NS_ASSERTION(!mFontNameBase.IsEmpty(),
                   "font base name shouldn't be empty");
       psObj->setfont(mFontNameBase, mHeight, currSubFont);
       prevSubFont = currSubFont;
       start = i;
+      glyphs.Clear();
     }
+
+    glyphs.AppendValue(glyph);
   }
 
-  if (prevSubFont != -1)
-    psObj->show(&aString[start], i - start, *subSet, prevSubFont); 
+  if (prevSubFont != -1) {
+    psObj->show(&glyphs, mPSFontGenerator, prevSubFont);
+  }
   
   return GetWidth(aString, aLength);
 }
@@ -2278,10 +2526,13 @@ nsFontPSFreeType::GetBoundingMetrics(con
 // Implementation of nsPSFontGenerator
 nsPSFontGenerator::nsPSFontGenerator()
 {
+  mGlyphSubset = new nsValueArray(PR_UINT16_MAX, 40);
 }
 
 nsPSFontGenerator::~nsPSFontGenerator()
 {
+  if (mGlyphSubset)
+    delete mGlyphSubset;
 }
 
 void nsPSFontGenerator::GeneratePSFont(FILE* aFile)
@@ -2289,24 +2540,29 @@ void nsPSFontGenerator::GeneratePSFont(F
   NS_ERROR("should never call nsPSFontGenerator::GeneratePSFont");
 }
 
-// Add a Unicode character to mSubset which will be divided into 
-// multiple chunks (subfonts) of 255 (kSubFontSize) characters each. 
-// Each chunk will be converted to a Type 1 font. Return the index of 
-// a subfont (chunk) this character belongs to.
+// Add a glyph offset to mSubset which will be divided into multiple
+// chunks (subfonts) of 255 (kSubFontSize) glyphs each.  Each chunk
+// will then be converted into a Type 1 font.  Return the index of a
+// subfont (chunk) this glyph belongs to.
 PRInt32
-nsPSFontGenerator::AddToSubset(PRUnichar aChar)
+nsPSFontGenerator::AddToGlyphSubset(PRUint32 aGlyph)
 {
-  PRInt32 index = mSubset.FindChar(aChar);
-  if (index == kNotFound) {
-    mSubset.Append(aChar);
-    index = mSubset.Length() - 1;
+  nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph);
+  if (index == NSVALUEARRAY_INVALID) {
+    mGlyphSubset->AppendValue(aGlyph);
+    index = mGlyphSubset->Count() - 1;
   }
+
   return index / kSubFontSize;
 }
 
-nsString *nsPSFontGenerator::GetSubset()
+PRInt32
+nsPSFontGenerator::InSubsetIndexOf(PRUint32 aGlyph)
 {
-  return &mSubset;
+  nsValueArrayIndex index = mGlyphSubset->IndexOf(aGlyph);
+  if (index == NSVALUEARRAY_INVALID)
+    return 0;
+  return (index % kSubFontSize) + 1;
 }
 
 #ifdef MOZ_ENABLE_XFT
@@ -2332,8 +2588,8 @@ nsXftType1Generator::Init(nsXftEntry* aE
 
 nsXftType1Generator::~nsXftType1Generator()
 {
-  if (mEntry->mFace) 
-    FT_Done_Face(mEntry->mFace);
+ if (mEntry->mFace) 
+   FT_Done_Face(mEntry->mFace);
 
   if (FT_Done_FreeType(mFreeTypeLibrary))
     return;
@@ -2353,8 +2609,8 @@ void nsXftType1Generator::GeneratePSFont
   }
 
   int wmode = 0;
-  if (!mSubset.IsEmpty())
-    FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
+  if (mGlyphSubset->Count())
+    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
 }
 
 #else
@@ -2402,8 +2658,8 @@ void nsFT2Type1Generator::GeneratePSFont
     return;
  
   int wmode = 0;
-  if (!mSubset.IsEmpty())
-    FT2SubsetToType1FontSet(face, mSubset, wmode, aFile);
+  if (mGlyphSubset->Count())
+    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
 }
 
 #endif //MOZ_ENABLE_FREETYPE2
Index: gfx/src/ps/nsFontMetricsPS.h
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/ps/nsFontMetricsPS.h,v
retrieving revision 1.31
diff -u -p -d -r1.31 nsFontMetricsPS.h
--- gfx/src/ps/nsFontMetricsPS.h	28 Jun 2005 18:29:10 -0000	1.31
+++ gfx/src/ps/nsFontMetricsPS.h	22 Nov 2006 22:05:29 -0000
@@ -66,6 +66,7 @@
 #endif
 #include "nsVoidArray.h"
 #include "nsHashtable.h"
+#include "nsValueArray.h"
 
 class nsPSFontGenerator;
 class nsDeviceContextPS;
@@ -108,6 +109,65 @@ public:
   NS_IMETHOD  GetFontHandle(nsFontHandle &aHandle);
   NS_IMETHOD  GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
   NS_IMETHOD  GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
+
+    NS_IMETHOD       GetTextDimensions(const char* aString,
+                                       PRUint32 aLength,
+                                       nsTextDimensions& aDimensions);
+    NS_IMETHOD       GetTextDimensions(const PRUnichar* aString,
+                                       PRUint32 aLength,
+                                       nsTextDimensions& aDimensions, 
+                                       PRInt32* aFontID);
+    NS_IMETHOD       GetTextDimensions(const char*         aString,
+                                       PRInt32             aLength,
+                                       PRInt32             aAvailWidth,
+                                       PRInt32*            aBreaks,
+                                       PRInt32             aNumBreaks,
+                                       nsTextDimensions&   aDimensions,
+                                       PRInt32&            aNumCharsFit,
+                                       nsTextDimensions&   aLastWordDimensions,
+                                       PRInt32*            aFontID);
+    NS_IMETHOD       GetTextDimensions(const PRUnichar*    aString,
+                                       PRInt32             aLength,
+                                       PRInt32             aAvailWidth,
+                                       PRInt32*            aBreaks,
+                                       PRInt32             aNumBreaks,
+                                       nsTextDimensions&   aDimensions,
+                                       PRInt32&            aNumCharsFit,
+                                       nsTextDimensions&   aLastWordDimensions,
+                                       PRInt32*            aFontID);
+#ifdef MOZ_MATHML
+    NS_IMETHOD       GetBoundingMetrics(const char *aString, PRUint32 aLength,
+                                        nsBoundingMetrics &aBoundingMetrics);
+    NS_IMETHOD       GetBoundingMetrics(const PRUnichar *aString,
+                                        PRUint32 aLength,
+                                        nsBoundingMetrics &aBoundingMetrics,
+                                        PRInt32 *aFontID);
+#endif /* MOZ_MATHML */
+
+  NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
+                        nscoord aX, nscoord aY,
+                        const nscoord* aSpacing,
+			nsRenderingContextPS *aContext);
+  NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength,
+                        nscoord aX, nscoord aY,
+                        PRInt32 aFontID,
+                        const nscoord* aSpacing,
+			nsRenderingContextPS *aContext);
+
+protected:
+  PRInt32 DrawString(const char *aString, PRUint32 aLength,
+                        nscoord aX, nscoord aY, nsFontPS* aFontPS,
+                        const nscoord* aSpacing,
+			nsRenderingContextPS *aContext);
+  PRInt32 DrawString(const PRUnichar *aString, PRUint32 aLength,
+                        nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
+                        const nscoord* aSpacing,
+			nsRenderingContextPS *aContext);
+
+public:
+
+  virtual PRUint32    GetHints     (void) { return 0; }
+
   
   inline void SetXHeight(nscoord aXHeight) { mXHeight = aXHeight; };
   inline void SetSuperscriptOffset(nscoord aSuperscriptOffset) { mSuperscriptOffset = aSuperscriptOffset; };
@@ -455,16 +515,14 @@ public:
   nsPSFontGenerator();
   virtual ~nsPSFontGenerator();
   virtual void  GeneratePSFont(FILE* aFile);
-  PRInt32  AddToSubset(PRUnichar aChar);
-  nsString *GetSubset();
+  PRInt32  AddToGlyphSubset(PRUint32 aGlyph);
+  PRInt32  InSubsetIndexOf(PRUint32 aGlyph);
 
   // 256 (PS type 1 encoding vector size) - 1 (1 is for mandatory /.notdef)
   const static PRUint16 kSubFontSize; 
 
 protected:
-  // XXX To support non-BMP characters, we may have to use 
-  // nsValueArray with PRUint32
-  nsString mSubset;
+  nsValueArray *mGlyphSubset;
 };
 
 
Index: gfx/src/ps/nsFontMetricsPango.cpp
===================================================================
RCS file: gfx/src/ps/nsFontMetricsPango.cpp
diff -N gfx/src/ps/nsFontMetricsPango.cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gfx/src/ps/nsFontMetricsPango.cpp	22 Nov 2006 22:05:29 -0000
@@ -0,0 +1,2238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Christopher Blizzard
+ * <blizzard@mozilla.org>.  Portions created by the Initial Developer
+ * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Christopher Blizzard <blizzard@mozilla.org>
+ *   Behdad Esfahbod <behdad@behdad.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#define PANGO_ENABLE_BACKEND
+
+#include "nsFontMetricsPango.h"
+
+#include <strings.h>
+#include "nsFont.h"
+#include "nsIDeviceContext.h"
+#include "nsICharsetConverterManager.h"
+#include "nsIPref.h"
+#include "nsServiceManagerUtils.h"
+
+#include "nsFontConfigUtils.h"
+
+#include "nsUnicharUtils.h"
+#include "nsQuickSort.h"
+#include "nsFontConfigUtils.h"
+#include "mozilla-decoder.h"
+
+#define FORCE_PR_LOG
+#include "prlog.h"
+
+
+#include <fontconfig/fontconfig.h>
+#include <freetype/tttables.h>
+
+#include <pango/pango.h>
+#include <pango/pangofc-font.h>
+
+#ifdef PSPANGO
+#include <pango/pangoft2.h>
+#include "nsRenderingContextPS.h"
+#include "nsDeviceContextPS.h"
+#include "nsType1.h"
+#else
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include "nsRenderingContextGTK.h"
+#include "nsDeviceContextGTK.h"
+#endif
+
+
+
+
+// Globals
+
+static PRLogModuleInfo            *gPangoFontLog;
+static int                         gNumInstances;
+
+// Defines
+
+// This is the scaling factor that we keep fonts limited to against
+// the display size.  If a pixel size is requested that is more than
+// this factor larger than the height of the display, it's clamped to
+// that value instead of the requested size.
+#define FONT_MAX_FONT_SCALE 2
+
+static NS_DEFINE_CID(kCharsetConverterManagerCID,
+                     NS_ICHARSETCONVERTERMANAGER_CID);
+
+#ifdef DEBUG
+#define DUMP_PRUNICHAR(ustr, ulen) for (PRUint32 llen=0;llen<ulen;llen++) \
+                                      printf("0x%x ", ustr[llen]); \
+                                   printf("\n");
+#endif
+
+// rounding and truncation functions for a Freetype floating 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))))
+
+// Static function decls
+
+static PangoLanguage *GetPangoLanguage(nsIAtom *aLangGroup);
+
+static void   FreeGlobals    (void);
+
+static PangoStyle  CalculateStyle  (PRUint8 aStyle);
+static PangoWeight CalculateWeight (PRUint16 aWeight);
+
+static nsresult    EnumFontsPango   (nsIAtom* aLangGroup, const char* aGeneric,
+                                     PRUint32* aCount, PRUnichar*** aResult);
+static int         CompareFontNames (const void* aArg1, const void* aArg2,
+                                     void* aClosure);
+static void  utf16_to_utf8 (const PRUnichar* aString, PRUint32 aLength,
+                            char *&text, gint &text_len);
+
+#ifdef PSPANGO
+static void
+default_substitute (FcPattern *pattern,
+                    gpointer   data)
+{
+  FcPatternDel (pattern, FC_HINTING);
+  FcPatternAddBool (pattern, FC_HINTING, 0);
+}
+#endif
+
+static PangoFontMap *
+get_fontmap (void)
+{
+  static PangoFontMap               *fontmap = NULL;
+
+  if (!fontmap) {
+#ifdef PSPANGO
+    fontmap = pango_ft2_font_map_new ();
+    pango_ft2_font_map_set_resolution ((PangoFT2FontMap *)fontmap, 72., 72.);
+    pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, default_substitute, NULL, NULL);
+#else
+    PangoContext* context = gdk_pango_context_get ();
+    fontmap = pango_context_get_font_map (context);
+    g_object_unref (context);
+#endif
+  }
+
+  return fontmap;
+}
+
+static PangoContext *
+get_context (void)
+{
+#ifdef PSPANGO
+  return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ());
+#else
+  return gdk_pango_context_get();
+#endif
+}
+
+
+nsFontMetricsPango::nsFontMetricsPango()
+{
+    if (!gPangoFontLog)
+        gPangoFontLog = PR_NewLogModule("PangoFont");
+
+    gNumInstances++;
+
+    mPangoFontDesc = nsnull;
+    mPangoContext = nsnull;
+    mLTRPangoContext = nsnull;
+    mRTLPangoContext = nsnull;
+    mPangoAttrList = nsnull;
+    mIsRTL = PR_FALSE;
+    mPangoSpaceWidth = 0;
+
+    static PRBool initialized = PR_FALSE;
+    if (initialized)
+        return;
+
+    // Initialized the custom decoders
+    if (!mozilla_decoders_init(get_fontmap ()))
+        initialized = PR_TRUE;
+}
+
+nsFontMetricsPango::~nsFontMetricsPango()
+{
+    if (mDeviceContext)
+        mDeviceContext->FontMetricsDeleted(this);
+
+    if (mPangoFontDesc)
+        pango_font_description_free(mPangoFontDesc);
+
+    if (mLTRPangoContext)
+        g_object_unref(mLTRPangoContext);
+
+    if (mRTLPangoContext)
+        g_object_unref(mRTLPangoContext);
+
+    if (mPangoAttrList)
+        pango_attr_list_unref(mPangoAttrList);
+
+    // XXX clean up all the pango objects
+
+    if (--gNumInstances == 0)
+        FreeGlobals();
+}
+
+
+NS_IMPL_ISUPPORTS1(nsFontMetricsPango, nsIFontMetrics)
+
+// nsIFontMetrics impl
+
+NS_IMETHODIMP
+nsFontMetricsPango::Init(const nsFont& aFont, nsIAtom* aLangGroup,
+                         nsIDeviceContext *aContext)
+{
+    mFont = aFont;
+    mLangGroup = aLangGroup;
+
+    // Hang on to the device context
+#ifdef PSPANGO
+    mDeviceContext = (nsDeviceContextPS *)aContext;
+#else
+    mDeviceContext = aContext;
+#endif
+    
+    mPointSize = NSTwipsToFloatPoints(mFont.size);
+
+#ifndef PSPANGO
+    // Make sure to clamp the pixel size to something reasonable so we
+    // don't make the X server blow up.
+    nscoord screenPixels = gdk_screen_height();
+    mPointSize = PR_MIN(screenPixels * FONT_MAX_FONT_SCALE, mPointSize);
+#endif
+
+    // enumerate over the font names passed in
+    mFont.EnumerateFamilies(nsFontMetricsPango::EnumFontCallback, this);
+
+    nsCOMPtr<nsIPref> prefService;
+    prefService = do_GetService(NS_PREF_CONTRACTID);
+    if (!prefService)
+        return NS_ERROR_FAILURE;
+        
+    nsXPIDLCString value;
+    const char* langGroup;
+    mLangGroup->GetUTF8String(&langGroup);
+
+    // Set up the default font name if it's not set
+    if (!mGenericFont) {
+        nsCAutoString name("font.default.");
+        name.Append(langGroup);
+        prefService->CopyCharPref(name.get(), getter_Copies(value));
+
+        if (value.get())
+            mDefaultFont = value.get();
+        else
+            mDefaultFont = "serif";
+        
+        mGenericFont = &mDefaultFont;
+    }
+
+    // set up the minimum sizes for fonts
+    if (mLangGroup) {
+        nsCAutoString name("font.min-size.");
+
+        if (mGenericFont->Equals("monospace"))
+            name.Append("fixed");
+        else
+            name.Append("variable");
+
+        name.Append(char('.'));
+        name.Append(langGroup);
+
+        PRInt32 minimumInt = 0;
+        float minimum;
+        nsresult res;
+        res = prefService->GetIntPref(name.get(), &minimumInt);
+        if (NS_FAILED(res))
+            prefService->GetDefaultIntPref(name.get(), &minimumInt);
+
+        if (minimumInt < 0)
+            minimumInt = 0;
+
+        minimum = minimumInt;
+
+        // The minimum size is specified in pixels, not in points.
+        // Convert the size from pixels to points.
+        minimum = NSTwipsToFloatPoints(NSFloatPixelsToTwips(minimum, mDeviceContext->DevUnitsToAppUnits()));
+        if (mPointSize < minimum)
+            mPointSize = minimum;
+    }
+
+    // Make sure that the pixel size is at least greater than zero
+    if (mPointSize < 1) {
+#ifdef DEBUG
+        printf("*** Warning: nsFontMetricsPango created with point size %f\n",
+               mPointSize);
+#endif
+        mPointSize = 1;
+    }
+
+    nsresult rv = RealizeFont();
+    if (NS_FAILED(rv))
+        return rv;
+
+    // Cache font metrics for the 'x' character
+    return CacheFontMetrics();
+}
+
+nsresult
+nsFontMetricsPango::CacheFontMetrics(void)
+{
+    // Get our scale factor
+    float f;
+    float val;
+    f = mDeviceContext->DevUnitsToAppUnits();
+
+    mPangoAttrList = pango_attr_list_new();
+
+    GList *items = pango_itemize(mPangoContext,
+                                 "a", 0, 1, mPangoAttrList, NULL);
+
+    if (!items)
+        return NS_ERROR_FAILURE;
+
+    guint nitems = g_list_length(items);
+    if (nitems != 1)
+        return NS_ERROR_FAILURE;
+
+    PangoItem *item = (PangoItem *)items->data;
+    PangoFcFont  *fcfont = PANGO_FC_FONT(item->analysis.font);
+    if (!fcfont)
+        return NS_ERROR_FAILURE;
+
+    // Get our font face
+    FT_Face face;
+    face = pango_fc_font_lock_face(fcfont);
+    if (!face)
+    	return NS_ERROR_NOT_AVAILABLE;
+    	
+    TT_OS2 *os2;
+    os2 = (TT_OS2 *) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+
+    // mEmHeight (size in pixels of EM height)
+    int size;
+    if (FcPatternGetInteger(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) !=
+        FcResultMatch) {
+        size = 12;
+    }
+    mEmHeight = PR_MAX(1, nscoord(size * f));
+
+    // mMaxAscent
+    val = MOZ_FT_TRUNC(face->size->metrics.ascender);
+    mMaxAscent = NSToIntRound(val * f);
+
+    // mMaxDescent
+    val = -MOZ_FT_TRUNC(face->size->metrics.descender);
+    mMaxDescent = NSToIntRound(val * f);
+
+    nscoord lineHeight = mMaxAscent + mMaxDescent;
+
+    // mLeading (needs ascent and descent and EM height) 
+    if (lineHeight > mEmHeight)
+        mLeading = lineHeight - mEmHeight;
+    else
+        mLeading = 0;
+
+    // mMaxHeight (needs ascent and descent)
+    mMaxHeight = lineHeight;
+
+    // mEmAscent (needs maxascent, EM height, ascent and descent)
+    mEmAscent = nscoord(mMaxAscent * mEmHeight / lineHeight);
+
+    // mEmDescent (needs EM height and EM ascent
+    mEmDescent = mEmHeight - mEmAscent;
+
+    // mMaxAdvance
+    val = MOZ_FT_TRUNC(face->size->metrics.max_advance);
+    mMaxAdvance = NSToIntRound(val * f);
+
+    // mPangoSpaceWidth
+    PangoLayout *layout = pango_layout_new(mPangoContext);
+    pango_layout_set_text(layout, " ", -1);
+    int pswidth, psheight;
+    pango_layout_get_size(layout, &pswidth, &psheight);
+    mPangoSpaceWidth = pswidth;
+    g_object_unref(layout);
+
+    // mSpaceWidth (width of a space)
+    nscoord tmpWidth;
+    GetWidth(" ", 1, tmpWidth CONTEXT_ARG_NULL);
+    mSpaceWidth = tmpWidth;
+
+    // mAveCharWidth (width of an 'average' char)
+    //    XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
+    //rawWidth = extents.width;
+    //mAveCharWidth = NSToCoordRound(rawWidth * f);
+    GetWidth("x", 1, tmpWidth CONTEXT_ARG_NULL);
+    mAveCharWidth = tmpWidth;
+
+    // mXHeight (height of an 'x' character)
+    if (pango_fc_font_has_char(fcfont, 'x')) {
+        PangoRectangle rect;
+        PangoGlyph glyph = pango_fc_font_get_glyph (fcfont, 'x');
+        pango_font_get_glyph_extents (PANGO_FONT (fcfont), glyph, &rect, NULL);
+        mXHeight = NSToIntRound(rect.height * f / PANGO_SCALE);
+    }
+    else {
+        // 56% of ascent, best guess for non-true type or asian fonts
+        mXHeight = nscoord(((float)mMaxAscent) * 0.56 * f);
+    }
+
+    // mUnderlineOffset (offset for underlines)
+    val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position,
+                                         face->size->metrics.y_scale);
+    if (val) {
+        mUnderlineOffset = NSToIn