Blob Blame History Raw
--- mozilla/config/autoconf.mk.in.foo	2004-11-22 12:55:08.000000000 -0500
+++ mozilla/config/autoconf.mk.in	2004-11-22 12:56:21.000000000 -0500
@@ -394,6 +394,10 @@
 MOZ_XFT_LIBS		= @MOZ_XFT_LIBS@
 MOZ_ENABLE_COREXFONTS	= @MOZ_ENABLE_COREXFONTS@
 
+MOZ_ENABLE_PANGO        = @MOZ_ENABLE_PANGO@
+MOZ_PANGO_CFLAGS        = @MOZ_PANGO_CFLAGS@
+MOZ_PANGO_LIBS          = @MOZ_PANGO_LIBS@
+
 MOZ_EXTRA_X11CONVERTERS	= @MOZ_EXTRA_X11CONVERTERS@
 
 MOZ_ENABLE_XINERAMA	= @MOZ_ENABLE_XINERAMA@
--- mozilla/gfx/src/gtk/nsGfxFactoryGTK.cpp.foo	2003-09-07 18:20:38.000000000 -0400
+++ mozilla/gfx/src/gtk/nsGfxFactoryGTK.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -62,6 +62,9 @@
 #ifdef NATIVE_THEME_SUPPORT
 #include "nsNativeThemeGTK.h"
 #endif
+#ifdef MOZ_ENABLE_PANGO
+#include "nsFontMetricsPango.h"
+#endif
 #ifdef MOZ_ENABLE_XFT
 #include "nsFontMetricsXft.h"
 #endif
@@ -112,6 +115,13 @@
   if (aOuter)
     return NS_ERROR_NO_AGGREGATION;
 
+#ifdef MOZ_ENABLE_PANGO
+  if (NS_IsPangoEnabled()) {
+    result = new nsFontMetricsPango();
+    if (!result)
+      return NS_ERROR_OUT_OF_MEMORY;
+  } else {
+#endif
 #ifdef MOZ_ENABLE_XFT
   if (NS_IsXftEnabled()) {
     result = new nsFontMetricsXft();
@@ -127,6 +137,9 @@
 #ifdef MOZ_ENABLE_XFT
   }
 #endif
+#ifdef MOZ_ENABLE_PANGO
+  }
+#endif
 
   NS_ADDREF(result);
   nsresult rv = result->QueryInterface(aIID, aResult);
@@ -148,6 +161,13 @@
   if (aOuter)
     return NS_ERROR_NO_AGGREGATION;
 
+#ifdef MOZ_ENABLE_PANGO
+  if (NS_IsPangoEnabled()) {
+    result = new nsFontEnumeratorPango();
+    if (!result)
+      return NS_ERROR_OUT_OF_MEMORY;
+  } else {
+#endif
 #ifdef MOZ_ENABLE_XFT
   if (NS_IsXftEnabled()) {
     result = new nsFontEnumeratorXft();
@@ -163,6 +183,9 @@
 #ifdef MOZ_ENABLE_XFT
   }
 #endif
+#ifdef MOZ_ENABLE_PANGO
+  }
+#endif
 
   NS_ADDREF(result);
   nsresult rv = result->QueryInterface(aIID, aResult);
--- mozilla/gfx/src/gtk/mozilla-decoder.h.foo	2004-11-22 12:56:21.000000000 -0500
+++ mozilla/gfx/src/gtk/mozilla-decoder.h	2004-11-22 12:56:21.000000000 -0500
@@ -0,0 +1,72 @@
+/* -*- 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/pangofc-decoder.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;
+};
+
+GType           mozilla_decoder_get_type (void);
+int             mozilla_decoders_init    (void);
+
+G_END_DECLS
+
+#endif /*_MOZILLA_DECODER_H */
--- mozilla/gfx/src/gtk/mozilla-decoder.cpp.foo	2004-11-22 12:56:21.000000000 -0500
+++ mozilla/gfx/src/gtk/mozilla-decoder.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -0,0 +1,376 @@
+/* -*- 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 ***** */
+
+#define PANGO_ENABLE_BACKEND
+#define PANGO_ENABLE_ENGINE
+
+#include "mozilla-decoder.h"
+#include <pango/pangoxft.h>
+#include <pango/pangofc-fontmap.h>
+#include <pango/pangofc-font.h>
+#include <gdk/gdkx.h>
+
+#include "nsString.h"
+#include "nsIPersistentProperties2.h"
+#include "nsNetUtil.h"
+#include "nsReadableUtils.h"
+#include "nsICharsetConverterManager.h"
+#include "nsICharRepresentable.h"
+#include "nsCompressedCharMap.h"
+
+#undef DEBUG_CUSTOM_ENCODER
+
+G_DEFINE_TYPE (MozillaDecoder, mozilla_decoder, PANGO_TYPE_FC_DECODER)
+
+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;
+
+void
+mozilla_decoder_init (MozillaDecoder *decoder)
+{
+}
+
+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));
+}
+
+MozillaDecoder *
+mozilla_decoder_new(void)
+{
+    return (MozillaDecoder *)g_object_new(MOZILLA_TYPE_DECODER, NULL);
+}
+
+#ifdef DEBUG_CUSTOM_ENCODER
+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(void)
+{
+    static PRBool initialized = PR_FALSE;
+    if (initialized)
+        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(pango_xft_get_font_map(GDK_DISPLAY(),gdk_x11_get_default_screen())),
+                                            mozilla_find_decoder,
+                                            NULL,
+                                            NULL);
+
+    initialized = PR_TRUE;
+
+#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;
+}
+
+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) {
+        nsServiceManager::GetService(kCharsetConverterManagerCID,
+        NS_GET_IID(nsICharsetConverterManager), (nsISupports**)&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;
+}
+
+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;
+}
+
+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);
+}
--- mozilla/gfx/src/gtk/gfxgtk.pkg.foo	2004-01-06 20:21:35.000000000 -0500
+++ mozilla/gfx/src/gtk/gfxgtk.pkg	2004-11-22 12:56:21.000000000 -0500
@@ -7,3 +7,6 @@
 #if MOZ_ENABLE_XFT
 dist/bin/res/fonts/fontEncoding.properties
 #endif
+#if MOZ_ENABLE_PANGO
+dist/bin/res/fonts/pangoFontEncoding.properties
+#endif
--- mozilla/gfx/src/gtk/nsFontMetricsXft.cpp.foo	2004-10-14 16:36:14.000000000 -0400
+++ mozilla/gfx/src/gtk/nsFontMetricsXft.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -238,7 +238,7 @@
 
 static int      CalculateSlant   (PRUint8  aStyle);
 static int      CalculateWeight  (PRUint16 aWeight);
-static void     AddLangGroup     (FcPattern *aPattern, nsIAtom *aLangGroup);
+/* static */ void     AddLangGroup     (FcPattern *aPattern, nsIAtom *aLangGroup);
 static void     AddFFRE          (FcPattern *aPattern, nsCString *aFamily,
                                   PRBool aWeak);
 static void     FFREToFamily     (nsACString &aFFREName, nsACString &oFamily);
@@ -449,7 +449,7 @@
     // Make sure that the pixel size is at least greater than zero
     if (mPixelSize < 1) {
 #ifdef DEBUG
-        printf("*** Warning: nsFontMetricsXft was passed a pixel size of %d\n",
+        printf("*** Warning: nsFontMetricsXft was passed a pixel size of %f\n",
                mPixelSize);
 #endif
         mPixelSize = 1;
@@ -474,6 +474,26 @@
     if (NS_FAILED(RealizeFont()))
         return NS_ERROR_FAILURE;
 
+#ifdef DEBUG_foo
+    printf("%i\n", mXHeight);
+    printf("%i\n", mSuperscriptOffset);
+    printf("%i\n", mSubscriptOffset);
+    printf("%i\n", mStrikeoutOffset);
+    printf("%i\n", mStrikeoutSize);
+    printf("%i\n", mUnderlineOffset);
+    printf("%i\n", mUnderlineSize);
+    printf("%i\n", mMaxHeight);
+    printf("%i\n", mLeading);
+    printf("%i\n", mEmHeight);
+    printf("%i\n", mEmAscent);
+    printf("%i\n", mEmDescent);
+    printf("%i\n", mMaxAscent);
+    printf("%i\n", mMaxDescent);
+    printf("%i\n", mMaxAdvance);
+    printf("%i\n", mSpaceWidth);
+    printf("%i\n", mAveCharWidth);
+#endif /* DEBUG_foo */
+
     return NS_OK;
 }
 
@@ -530,6 +550,10 @@
     f = mDeviceContext->DevUnitsToAppUnits();
     aWidth = NSToCoordRound(glyphInfo.xOff * f);
 
+#ifdef DEBUG_foo
+    printf("GetWidth (char *) %d\n", aWidth);
+#endif
+
     return NS_OK;
 }
 
@@ -553,6 +577,10 @@
     if (aFontID)
         *aFontID = 0;
 
+#ifdef DEBUG_foo
+    printf("GetWidth %d\n", aWidth);
+#endif
+
     return NS_OK;
 }
 
@@ -586,6 +614,11 @@
     if (nsnull != aFontID)
         *aFontID = 0;
 
+#ifdef DEBUG_foo
+    printf("GetTextDimensions %d %d %d\n", aDimensions.width,
+           aDimensions.ascent, aDimensions.descent);
+#endif
+
     return NS_OK;
 }
 
@@ -645,6 +678,10 @@
     nsAutoDrawSpecBuffer drawBuffer(data.draw, &data.color);
     data.drawBuffer = &drawBuffer;
 
+#ifdef DEBUG_foo
+    printf("DrawString (char *)\n");
+#endif
+
     return EnumerateGlyphs(aString, aLength,
                            &nsFontMetricsXft::DrawStringCallback, &data);
 }
@@ -675,6 +712,10 @@
     nsAutoDrawSpecBuffer drawBuffer(data.draw, &data.color);
     data.drawBuffer = &drawBuffer;
 
+#ifdef DEBUG_foo
+    printf("DrawString\n");
+#endif
+
     return EnumerateGlyphs(aString, aLength,
                            &nsFontMetricsXft::DrawStringCallback, &data);
 }
@@ -714,6 +755,15 @@
     aBoundingMetrics.ascent = NSToCoordRound(aBoundingMetrics.ascent * P2T);
     aBoundingMetrics.descent = NSToCoordRound(aBoundingMetrics.descent * P2T);
 
+#ifdef DEBUG_foo
+    printf("GetBoundingMetrics (char *)%d %d %d %d %d\n",
+           aBoundingMetrics.leftBearing,
+           aBoundingMetrics.rightBearing,
+           aBoundingMetrics.width,
+           aBoundingMetrics.ascent,
+           aBoundingMetrics.descent);
+#endif
+
     return NS_OK;
 }
 
@@ -755,6 +805,15 @@
     if (nsnull != aFontID)
         *aFontID = 0;
 
+#ifdef DEBUG_foo
+    printf("GetBoundingMetrics %d %d %d %d %d\n",
+           aBoundingMetrics.leftBearing,
+           aBoundingMetrics.rightBearing,
+           aBoundingMetrics.width,
+           aBoundingMetrics.ascent,
+           aBoundingMetrics.descent);
+#endif
+
     return NS_OK;
 }
 
@@ -766,6 +825,12 @@
     return nsnull;
 }
 
+nsresult
+nsFontMetricsXft::SetRightToLeftText(PRBool aIsRTL)
+{
+    return NS_OK;
+}
+
 PRUint32
 nsFontMetricsXft::GetHints(void)
 {
--- mozilla/gfx/src/gtk/Makefile.in.foo	2003-11-10 07:24:51.000000000 -0500
+++ mozilla/gfx/src/gtk/Makefile.in	2004-11-22 12:56:21.000000000 -0500
@@ -102,6 +102,12 @@
 		nsFontMetricsXft.cpp
 endif
 
+ifdef MOZ_ENABLE_PANGO
+CPPSRCS		+= \
+		nsFontMetricsPango.cpp \
+		mozilla-decoder.cpp
+endif
+
 ifdef MOZ_ENABLE_GTK
 CPPSRCS 	+= \
 		nsRegionGTK.cpp \
@@ -155,10 +161,10 @@
 endif
 
 ifdef MOZ_ENABLE_XFT
-libs:: fontEncoding.properties
+libs:: fontEncoding.properties pangoFontEncoding.properties
 	$(INSTALL) $^ $(DIST)/bin/res/fonts
  
-install:: fontEncoding.properties
+install:: fontEncoding.properties pangoFontEncoding.properties
 	$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/res/fonts
 endif
 
--- mozilla/gfx/src/gtk/pangoFontEncoding.properties.foo	2004-11-22 12:56:21.000000000 -0500
+++ mozilla/gfx/src/gtk/pangoFontEncoding.properties	2004-11-22 12:56:21.000000000 -0500
@@ -0,0 +1,120 @@
+# ***** 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 MathML Project.
+#
+# The Initial Developer of the Original Code is
+# The University of Queensland.
+# Portions created by the Initial Developer are Copyright (C) 2001
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Roger B. Sidje <rbs@maths.uq.edu.au>
+#   Jungshik Shin <jshin@mailaps.org>
+#   Christopher Blizzard <blizzard@mozilla.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 *****
+
+#  LOCALIZATION NOTE: FILE
+#  Do not translate anything in this file
+
+# This file contains supported custom encodings for pango font
+# rendering.  For information about the specific encodings, look at
+# fontEncoding.properties.  It contains a lot more verbiage than you
+# will find here.  There are a lot of encodings supported in the old
+# encoding file that pango supports directly, so there should be
+# little reason to use those custom encodings.  The pango custom code
+# doesn't support .wide fonts, so consider yourself warned!
+#
+
+# To be honest, we basically support mathml and that's about it.
+
+encoding.cmr10.ttf  = x-ttf-cmr
+encoding.cmmi10.ttf = x-ttf-cmmi
+encoding.cmsy10.ttf = x-ttf-cmsy
+encoding.cmex10.ttf = x-ttf-cmex
+
+encoding.cmr10.ftcmap  = unicode
+encoding.cmmi10.ftcmap = unicode
+encoding.cmsy10.ftcmap = unicode
+encoding.cmex10.ftcmap = unicode
+
+encoding.math1.ttf          = x-mathematica1
+encoding.math1-bold.ttf     = x-mathematica1
+encoding.math1mono.ttf      = x-mathematica1
+encoding.math1mono-bold.ttf = x-mathematica1
+
+encoding.math2.ttf          = x-mathematica2
+encoding.math2-bold.ttf     = x-mathematica2
+encoding.math2mono.ttf      = x-mathematica2
+encoding.math2mono-bold.ttf = x-mathematica2
+
+encoding.math3.ttf          = x-mathematica3
+encoding.math3-bold.ttf     = x-mathematica3
+encoding.math3mono.ttf      = x-mathematica3
+encoding.math3mono-bold.ttf = x-mathematica3
+
+encoding.math4.ttf          = x-mathematica4
+encoding.math4-bold.ttf     = x-mathematica4
+encoding.math4mono.ttf      = x-mathematica4
+encoding.math4mono-bold.ttf = x-mathematica4
+
+encoding.math5.ttf          = x-mathematica5
+encoding.math5-bold.ttf     = x-mathematica5
+encoding.math5bold.ttf      = x-mathematica5
+encoding.math5mono.ttf      = x-mathematica5
+encoding.math5mono-bold.ttf = x-mathematica5
+encoding.math5monobold.ttf  = x-mathematica5
+
+encoding.math1.ftcmap          = mac_roman
+encoding.math1-bold.ftcmap     = mac_roman
+encoding.math1mono.ftcmap      = mac_roman
+encoding.math1mono-bold.ftcmap = mac_roman
+
+encoding.math2.ftcmap          = mac_roman
+encoding.math2-bold.ftcmap     = mac_roman
+encoding.math2mono.ftcmap      = mac_roman
+encoding.math2mono-bold.ftcmap = mac_roman
+
+encoding.math3.ftcmap          = mac_roman
+encoding.math3-bold.ftcmap     = mac_roman
+encoding.math3mono.ftcmap      = mac_roman
+encoding.math3mono-bold.ftcmap = mac_roman
+
+encoding.math4.ftcmap          = mac_roman
+encoding.math4-bold.ftcmap     = mac_roman
+encoding.math4mono.ftcmap      = mac_roman
+encoding.math4mono-bold.ftcmap = mac_roman
+
+encoding.math5.ftcmap          = mac_roman
+encoding.math5-bold.ftcmap     = mac_roman
+encoding.math5bold.ftcmap      = mac_roman
+encoding.math5mono.ftcmap      = mac_roman
+encoding.math5mono-bold.ftcmap = mac_roman
+encoding.math5monobold.ftcmap  = mac_roman
+
+encoding.mtextra.ttf = x-mtextra
+encoding.mtextra.ftcmap = mac_roman
+
--- mozilla/gfx/src/gtk/nsFontMetricsUtils.cpp.foo	2002-10-11 22:03:32.000000000 -0400
+++ mozilla/gfx/src/gtk/nsFontMetricsUtils.cpp	2004-11-22 12:57:33.000000000 -0500
@@ -50,11 +50,20 @@
 #include "nsFontMetricsGTK.h"
 #endif
 
+#ifdef MOZ_ENABLE_PANGO
+#include "nsFontMetricsPango.h"
+#endif
+
 #include "nsFontMetricsUtils.h"
 
 PRUint32
 NS_FontMetricsGetHints(void)
 {
+#ifdef MOZ_ENABLE_PANGO
+    if (NS_IsPangoEnabled()) {
+        return nsFontMetricsPango::GetHints();
+    }
+#endif
 #ifdef MOZ_ENABLE_XFT
     if (NS_IsXftEnabled()) {
         return nsFontMetricsXft::GetHints();
@@ -69,6 +78,11 @@
 nsresult
 NS_FontMetricsFamilyExists(nsIDeviceContext *aDevice, const nsString &aName)
 {
+#ifdef MOZ_ENABLE_PANGO
+    if (NS_IsPangoEnabled()) {
+        return nsFontMetricsPango::FamilyExists(aDevice, aName);
+    }
+#endif
 #ifdef MOZ_ENABLE_XFT
     // try to fall through to the core fonts if xft fails
     if (NS_IsXftEnabled()) {
@@ -121,3 +135,17 @@
 }
 
 #endif /* MOZ_ENABLE_XFT */
+
+#ifdef MOZ_ENABLE_PANGO
+
+PRBool
+NS_IsPangoEnabled(void)
+{
+    char *val = PR_GetEnv("MOZ_DISABLE_PANGO");
+    if (val)
+        return FALSE;
+
+    return TRUE;
+}
+
+#endif
--- mozilla/gfx/src/gtk/nsFontMetricsPango.cpp.foo	2004-11-22 12:56:21.000000000 -0500
+++ mozilla/gfx/src/gtk/nsFontMetricsPango.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -0,0 +1,1662 @@
+/* -*- 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 "nsFont.h"
+#include "nsIDeviceContext.h"
+#include "nsICharsetConverterManager.h"
+#include "nsIPref.h"
+#include "nsIServiceManagerUtils.h"
+
+#define PANGO_ENABLE_BACKEND
+#define PANGO_ENABLE_ENGINE
+
+#include "nsFontMetricsPango.h"
+#include "nsRenderingContextGTK.h"
+#include "nsDeviceContextGTK.h"
+
+#include "nsUnicharUtils.h"
+#include "nsQuickSort.h"
+
+#include <pango/pangoxft.h>
+#include <fontconfig/fontconfig.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <freetype/tttables.h>
+
+#include "mozilla-decoder.h"
+
+#define FORCE_PR_LOG
+#include "prlog.h"
+
+// 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);
+
+struct MozPangoLangGroup {
+    const char *mozLangGroup;
+    const char *PangoLang;
+};
+
+static const MozPangoLangGroup MozPangoLangGroups[] = {
+    { "x-western",      "en" },
+    { "x-central-euro", "pl" },
+    { "x-cyrillic",     "ru" },
+    { "x-baltic",       "lv" },
+    { "x-devanagari",   "hi" },
+    { "x-tamil",        "ta" },
+    { "x-unicode",      0    },
+    { "x-user-def",     0    },
+};
+
+#define NUM_PANGO_LANG_GROUPS (sizeof (MozPangoLangGroups) / \
+                               sizeof (MozPangoLangGroups[0]))
+
+#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 PRBool IsASCIIFontName  (const nsString& aName);
+static int    FFRECountHyphens (nsACString &aFFREName);
+
+static PangoLanguage *GetPangoLanguage(nsIAtom *aLangGroup);
+static const MozPangoLangGroup* FindPangoLangGroup (nsACString &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);
+
+extern void     AddLangGroup     (FcPattern *aPattern, nsIAtom *aLangGroup);
+
+nsFontMetricsPango::nsFontMetricsPango()
+{
+    if (!gPangoFontLog)
+        gPangoFontLog = PR_NewLogModule("PangoFont");
+
+    gNumInstances++;
+
+    mPangoFontDesc = nsnull;
+    mPangoContext = nsnull;
+    mLTRPangoContext = nsnull;
+    mRTLPangoContext = nsnull;
+    mPangoAttrList = nsnull;
+    mIsRTL = PR_FALSE;
+
+    static PRBool initialized = PR_FALSE;
+    if (initialized)
+        return;
+
+    // Initialized the custom decoders
+    if (!mozilla_decoders_init())
+        initialized = PR_TRUE;
+}
+
+nsFontMetricsPango::~nsFontMetricsPango()
+{
+    delete mFont;
+
+    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 = new nsFont(aFont);
+    mLangGroup = aLangGroup;
+
+    // Hang on to the device context
+    mDeviceContext = aContext;
+    
+    mPointSize = NSTwipsToFloatPoints(mFont->size);
+
+    // 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);
+
+    // 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;
+
+    // Set up the default font name if it's not set
+    if (!mGenericFont) {
+        prefService->CopyCharPref("font.default", 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('.'));
+
+        const char* langGroup;
+        mLangGroup->GetUTF8String(&langGroup);
+
+        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;
+    TT_OS2 *os2;
+    XftFont *xftFont = pango_xft_font_get_font(PANGO_FONT(fcfont));
+    if (!xftFont)
+        return NS_ERROR_NOT_AVAILABLE;
+
+    face = XftLockFace(xftFont);
+    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
+    mMaxAscent = nscoord(xftFont->ascent * f);
+
+    // mMaxDescent
+    mMaxDescent = nscoord(xftFont->descent * 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
+    mMaxAdvance = nscoord(xftFont->max_advance_width * f);
+
+    // mSpaceWidth (width of a space)
+    nscoord tmpWidth;
+    GetWidth(" ", 1, tmpWidth, 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);
+    mAveCharWidth = tmpWidth;
+
+    // mXHeight (height of an 'x' character)
+    PRUnichar xUnichar('x');
+    XGlyphInfo extents;
+    if (FcCharSetHasChar(xftFont->charset, xUnichar)) {
+        XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
+        mXHeight = extents.height;
+    }
+    else {
+        // 56% of ascent, best guess for non-true type or asian fonts
+        mXHeight = nscoord(((float)mMaxAscent) * 0.56);
+    }
+    mXHeight = nscoord(mXHeight * f);
+
+    // mUnderlineOffset (offset for underlines)
+    val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_position,
+                                         face->size->metrics.y_scale);
+    if (val) {
+        mUnderlineOffset = NSToIntRound(val * f);
+    }
+    else {
+        mUnderlineOffset =
+            -NSToIntRound(PR_MAX(1, floor(0.1 * xftFont->height + 0.5)) * f);
+    }
+
+    // mUnderlineSize (thickness of an underline)
+    val = CONVERT_DESIGN_UNITS_TO_PIXELS(face->underline_thickness,
+                                         face->size->metrics.y_scale);
+    if (val) {
+        mUnderlineSize = nscoord(PR_MAX(f, NSToIntRound(val * f)));
+    }
+    else {
+        mUnderlineSize =
+            NSToIntRound(PR_MAX(1, floor(0.05 * xftFont->height + 0.5)) * f);
+    }
+
+    // mSuperscriptOffset
+    if (os2 && os2->ySuperscriptYOffset) {
+        val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySuperscriptYOffset,
+                                             face->size->metrics.y_scale);
+        mSuperscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
+    }
+    else {
+        mSuperscriptOffset = mXHeight;
+    }
+
+    // mSubscriptOffset
+    if (os2 && os2->ySubscriptYOffset) {
+        val = CONVERT_DESIGN_UNITS_TO_PIXELS(os2->ySubscriptYOffset,
+                                             face->size->metrics.y_scale);
+        // some fonts have the incorrect sign. 
+        val = (val < 0) ? -val : val;
+        mSubscriptOffset = nscoord(PR_MAX(f, NSToIntRound(val * f)));
+    }
+    else {
+        mSubscriptOffset = mXHeight;
+    }
+
+    // mStrikeoutOffset
+    mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0);
+
+    // mStrikeoutSize
+    mStrikeoutSize = mUnderlineSize;
+
+    XftUnlockFace(xftFont);
+
+    /*
+    printf("%i\n", mXHeight);
+    printf("%i\n", mSuperscriptOffset);
+    printf("%i\n", mSubscriptOffset);
+    printf("%i\n", mStrikeoutOffset);
+    printf("%i\n", mStrikeoutSize);
+    printf("%i\n", mUnderlineOffset);
+    printf("%i\n", mUnderlineSize);
+    printf("%i\n", mMaxHeight);
+    printf("%i\n", mLeading);
+    printf("%i\n", mEmHeight);
+    printf("%i\n", mEmAscent);
+    printf("%i\n", mEmDescent);
+    printf("%i\n", mMaxAscent);
+    printf("%i\n", mMaxDescent);
+    printf("%i\n", mMaxAdvance);
+    printf("%i\n", mSpaceWidth);
+    printf("%i\n", mAveCharWidth);
+    */
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPango::Destroy()
+{
+    mDeviceContext = nsnull;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPango::GetFont(const nsFont *&aFont)
+{
+    aFont = mFont;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPango::GetLangGroup(nsIAtom** aLangGroup)
+{
+    *aLangGroup = mLangGroup;
+    NS_IF_ADDREF(*aLangGroup);
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontMetricsPango::GetFontHandle(nsFontHandle &aHandle)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// nsIFontMetricsPango impl
+
+nsresult
+nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
+                             nscoord& aWidth,
+                             nsRenderingContextGTK *aContext)
+{
+    PangoLayout *layout = pango_layout_new(mPangoContext);
+
+    pango_layout_set_text(layout, aString, aLength);
+
+    int width, height;
+
+    pango_layout_get_size(layout, &width, &height);
+
+    width /= PANGO_SCALE;
+
+    g_object_unref(layout);
+
+    float f;
+    f = mDeviceContext->DevUnitsToAppUnits();
+    aWidth = NSToCoordRound(width * f);
+
+    //    printf("GetWidth (char *) %d\n", aWidth);
+
+    return NS_OK;
+}
+
+nsresult
+nsFontMetricsPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
+                             nscoord& aWidth, PRInt32 *aFontID,
+                             nsRenderingContextGTK *aContext)
+{
+    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));
+    pango_layout_get_size(layout, &width, &height);
+
+    width /= PANGO_SCALE;
+
+    float f;
+    f = mDeviceContext->DevUnitsToAppUnits();
+    aWidth = NSToCoordRound(width * f);
+
+    //    printf("GetWidth %d\n", aWidth);
+
+ loser:
+    g_free(text);
+    g_object_unref(layout);
+
+    return rv;
+}
+
+
+nsresult
+nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
+                                      PRUint32 aLength,
+                                      nsTextDimensions& aDimensions, 
+                                      PRInt32* aFontID,
+                                      nsRenderingContextGTK *aContext)
+{
+    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;
+
+        rv = NS_ERROR_FAILURE;
+        goto loser;
+    }
+        
+
+    pango_layout_set_text(layout, text, strlen(text));
+
+    // 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);
+
+    PangoRectangle rect;
+    pango_layout_line_get_extents(line, NULL, &rect);
+
+    float P2T;
+    P2T = mDeviceContext->DevUnitsToAppUnits();
+
+    aDimensions.width = NSToCoordRound(rect.width / PANGO_SCALE * P2T);
+    aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) / PANGO_SCALE * P2T);
+    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) / PANGO_SCALE * P2T);
+
+    //    printf("GetTextDimensions %d %d %d\n", aDimensions.width,
+    //aDimensions.ascent, aDimensions.descent);
+
+ loser:
+    g_free(text);
+    g_object_unref(layout);
+
+    return rv;
+}
+
+nsresult
+nsFontMetricsPango::GetTextDimensions(const char*         aString,
+                                      PRInt32             aLength,
+                                      PRInt32             aAvailWidth,
+                                      PRInt32*            aBreaks,
+                                      PRInt32             aNumBreaks,
+                                      nsTextDimensions&   aDimensions,
+                                      PRInt32&            aNumCharsFit,
+                                      nsTextDimensions&   aLastWordDimensions,
+                                      PRInt32*            aFontID,
+                                      nsRenderingContextGTK *aContext)
+{
+
+    return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks,
+                                     aNumBreaks, aDimensions, aNumCharsFit,
+                                     aLastWordDimensions, aContext);
+
+}
+
+nsresult
+nsFontMetricsPango::GetTextDimensions(const PRUnichar*    aString,
+                                      PRInt32             aLength,
+                                      PRInt32             aAvailWidth,
+                                      PRInt32*            aBreaks,
+                                      PRInt32             aNumBreaks,
+                                      nsTextDimensions&   aDimensions,
+                                      PRInt32&            aNumCharsFit,
+                                      nsTextDimensions&   aLastWordDimensions,
+                                      PRInt32*            aFontID,
+                                      nsRenderingContextGTK *aContext)
+{
+    nsresult rv = NS_OK;
+    PRInt32 curBreak = 0;
+    gchar *curChar;
+
+    PRInt32 *utf8Breaks = new PRInt32[aNumBreaks];
+
+    gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength,
+                                  NULL, NULL, NULL);
+
+    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)) {
+        if (aBreaks[curBreak] == curOffset) {
+            utf8Breaks[curBreak] = curChar - text;
+            curBreak++;
+        }
+
+        if (IS_HIGH_SURROGATE(aString[curOffset]))
+            curOffset++;
+    }
+
+    // Always catch the last break
+    utf8Breaks[curBreak] = curChar - text;
+
+#if 0
+    if (strlen(text) != aLength) {
+        printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text));
+        DUMP_PRUNICHAR(aString, aLength)
+        DUMP_PRUNICHAR(text, strlen(text))
+        for (PRInt32 i = 0; i < aNumBreaks; ++i) {
+            printf("  break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]);
+        }
+    }
+#endif
+
+    // 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,
+                                   aNumBreaks, aDimensions, aNumCharsFit,
+                                   aLastWordDimensions, aContext);
+
+    // Figure out which of the breaks we ended up using to convert
+    // back to utf16 - start from the end.
+    for (PRInt32 i = aNumBreaks - 1; i >= 0; --i) {
+        if (utf8Breaks[i] == aNumCharsFit) {
+            //      if (aNumCharsFit != aBreaks[i])
+            //                printf("Fixing utf8 -> utf16 %d -> %d\n", aNumCharsFit, aBreaks[i]);
+            aNumCharsFit = aBreaks[i];
+            break;
+        }
+    }
+
+ loser:
+    if (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)
+{
+    PangoLayout *layout = pango_layout_new(mPangoContext);
+
+    pango_layout_set_text(layout, aString, aLength);
+
+    int x = aX;
+    int y = aY;
+
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
+
+    PangoLayoutLine *line;
+    if (pango_layout_get_line_count(layout) != 1) {
+        printf("Warning: more than one line!\n");
+    }
+    line = pango_layout_get_line(layout, 0);
+
+    aContext->UpdateGC();
+    GdkGC *gc = aContext->GetGC();
+
+    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);
+    }
+
+    g_object_unref(gc);
+    g_object_unref(layout);
+
+    //    printf("DrawString (char *)\n");
+
+    return NS_OK;
+}
+
+nsresult
+nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
+                               nscoord aX, nscoord aY,
+                               PRInt32 aFontID,
+                               const nscoord* aSpacing,
+                               nsRenderingContextGTK *aContext,
+                               nsDrawingSurfaceGTK *aSurface)
+{
+    nsresult rv = NS_OK;
+    int x = aX;
+    int y = aY;
+
+    aContext->UpdateGC();
+    GdkGC *gc = aContext->GetGC();
+
+    PangoLayout *layout = pango_layout_new(mPangoContext);
+
+    gchar *text = g_utf16_to_utf8(aString, aLength,
+                                  NULL, NULL, NULL);
+
+    if (!text) {
+#ifdef DEBUG
+        NS_WARNING("nsFontMetricsPango::DrawString invalid unicode to follow");
+        DUMP_PRUNICHAR(aString, aLength)
+#endif
+        rv = NS_ERROR_FAILURE;
+        goto loser;
+    }
+
+    pango_layout_set_text(layout, text, strlen(text));
+
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
+
+    PangoLayoutLine *line;
+    if (pango_layout_get_line_count(layout) != 1) {
+        printf("Warning: more than one line!\n");
+    }
+    line = pango_layout_get_line(layout, 0);
+
+    if (aSpacing && *aSpacing) {
+        DrawStringSlowly(text, aString, aLength, aSurface->GetDrawable(),
+                         gc, x, y, line, aSpacing);
+    }
+    else {
+        gdk_draw_layout_line(aSurface->GetDrawable(), gc,
+                             x, y,
+                             line);
+    }
+
+ loser:
+
+    g_free(text);
+    g_object_unref(gc);
+    g_object_unref(layout);
+
+    //    printf("DrawString\n");
+
+    return rv;
+}
+
+#ifdef MOZ_MATHML
+nsresult
+nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
+                                       nsBoundingMetrics &aBoundingMetrics,
+                                       nsRenderingContextGTK *aContext)
+{
+    printf("GetBoundingMetrics (char *)\n");
+    return NS_ERROR_FAILURE;
+}
+
+nsresult
+nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
+                                       PRUint32 aLength,
+                                       nsBoundingMetrics &aBoundingMetrics,
+                                       PRInt32 *aFontID,
+                                       nsRenderingContextGTK *aContext)
+{
+    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::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;
+
+        rv = NS_ERROR_FAILURE;
+        goto loser;
+    }
+
+    pango_layout_set_text(layout, text, strlen(text));
+
+    // 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);
+
+    // Get the ink extents
+    PangoRectangle rect;
+    pango_layout_line_get_extents(line, NULL, &rect);
+
+    float P2T;
+    P2T = mDeviceContext->DevUnitsToAppUnits();
+
+    aBoundingMetrics.leftBearing =
+        NSToCoordRound(rect.x / PANGO_SCALE * P2T);
+    aBoundingMetrics.rightBearing =
+        NSToCoordRound(rect.width / PANGO_SCALE * P2T);
+    aBoundingMetrics.width = NSToCoordRound((rect.x + rect.width) / PANGO_SCALE * P2T);
+    aBoundingMetrics.ascent = NSToCoordRound(rect.y / PANGO_SCALE * P2T);
+    aBoundingMetrics.descent = NSToCoordRound(rect.height / PANGO_SCALE * P2T);
+
+ loser:
+    g_free(text);
+    g_object_unref(layout);
+
+    return rv;
+}
+
+#endif /* MOZ_MATHML */
+
+GdkFont*
+nsFontMetricsPango::GetCurrentGDKFont(void)
+{
+    return nsnull;
+}
+
+nsresult
+nsFontMetricsPango::SetRightToLeftText(PRBool aIsRTL)
+{
+    if (aIsRTL) {
+        if (!mRTLPangoContext) {
+            mRTLPangoContext = pango_xft_get_context(GDK_DISPLAY(), 0);
+            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);
+        }
+        mPangoContext = mRTLPangoContext;
+    }
+    else {
+        mPangoContext = mLTRPangoContext;
+    }
+
+    mIsRTL = aIsRTL;
+    return NS_OK;
+}
+
+/* static */
+PRUint32
+nsFontMetricsPango::GetHints(void)
+{
+    return (NS_RENDERING_HINT_BIDI_REORDERING |
+            NS_RENDERING_HINT_ARABIC_SHAPING | 
+            NS_RENDERING_HINT_FAST_MEASURE);
+}
+
+/* static */
+nsresult
+nsFontMetricsPango::FamilyExists(nsIDeviceContext *aDevice,
+                                 const nsString &aName)
+{
+    if (!IsASCIIFontName(aName))
+        return NS_ERROR_FAILURE;
+
+    NS_ConvertUCS2toUTF8 name(aName);
+
+    nsresult rv = NS_ERROR_FAILURE;
+    PangoContext *context = pango_xft_get_context(GDK_DISPLAY(), 0);
+    PangoFontFamily **familyList;
+    int n;
+
+    pango_context_list_families(context, &familyList, &n);
+
+    for (int i=0; i < n; i++) {
+        const char *tmpname = pango_font_family_get_name(familyList[i]);
+        if (!Compare(nsDependentCString(tmpname), name,
+                     nsCaseInsensitiveCStringComparator())) {
+            rv = NS_OK;
+            break;
+        }
+    }
+
+    g_free(familyList);
+    g_object_unref(context);
+
+    return rv;
+}
+
+// Private Methods
+
+nsresult
+nsFontMetricsPango::RealizeFont(void)
+{
+    nsCString familyList;
+    // Create and fill out the font description.
+    mPangoFontDesc = pango_font_description_new();
+
+    // Add CSS names - walk the list of fonts, adding the generic as
+    // the last font
+    for (int i=0; i < mFontList.Count(); ++i) {
+        // if this was a generic name, break out of the loop since we
+        // don't want to add it to the pattern yet
+        if (mFontIsGeneric[i])
+            break;;
+
+        nsCString *familyName = mFontList.CStringAt(i);
+        familyList.Append(familyName->get());
+        familyList.Append(',');
+    }
+
+    // If there's a generic add a pref for the generic if there's one
+    // set.
+    if (mGenericFont && !mFont->systemFont) {
+        nsCString name;
+        name += "font.name.";
+        name += mGenericFont->get();
+        name += ".";
+
+        nsString langGroup;
+        mLangGroup->ToString(langGroup);
+
+        name.AppendWithConversion(langGroup);
+
+        nsCOMPtr<nsIPref> pref;
+        pref = do_GetService(NS_PREF_CONTRACTID);
+        if (pref) {
+            nsresult rv;
+            nsXPIDLCString value;
+            rv = pref->GetCharPref(name.get(), getter_Copies(value));
+
+            // we ignore prefs that have three hypens since they are X
+            // style prefs.
+            if (FFRECountHyphens(value) < 3) {
+                nsCString tmpstr;
+                tmpstr.Append(value);
+
+                familyList.Append(tmpstr);
+                familyList.Append(',');
+            }
+        }
+    }
+
+    // Add the generic if there is one.
+    if (mGenericFont && !mFont->systemFont) {
+        familyList.Append(mGenericFont->get());
+        familyList.Append(',');
+    }
+
+    // Set the family
+    pango_font_description_set_family(mPangoFontDesc,
+                                      familyList.get());
+
+    // Set the point size
+    pango_font_description_set_size(mPangoFontDesc,
+                                    (gint)(mPointSize * PANGO_SCALE));
+
+    // Set the style
+    pango_font_description_set_style(mPangoFontDesc,
+                                     CalculateStyle(mFont->style));
+
+    // Set the weight
+    pango_font_description_set_weight(mPangoFontDesc,
+                                      CalculateWeight(mFont->weight));
+
+    // Now that we have the font description set up, create the
+    // context.
+    mLTRPangoContext = pango_xft_get_context(GDK_DISPLAY(), 0);
+    mPangoContext = mLTRPangoContext;
+
+    // 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));
+
+    // And attach the font description to this context
+    pango_context_set_font_description(mPangoContext, mPangoFontDesc);
+
+    return NS_OK;
+}
+
+/* static */
+PRBool
+nsFontMetricsPango::EnumFontCallback(const nsString &aFamily,
+                                     PRBool aIsGeneric, void *aData)
+{
+    // make sure it's an ascii name, if not then return and continue
+    // enumerating
+    if (!IsASCIIFontName(aFamily))
+        return PR_TRUE;
+
+    nsCAutoString name;
+    name.AssignWithConversion(aFamily.get());
+    ToLowerCase(name);
+    nsFontMetricsPango *metrics = (nsFontMetricsPango *)aData;
+    metrics->mFontList.AppendCString(name);
+    metrics->mFontIsGeneric.AppendElement((void *)aIsGeneric);
+    if (aIsGeneric) {
+        metrics->mGenericFont = 
+            metrics->mFontList.CStringAt(metrics->mFontList.Count() - 1);
+        return PR_FALSE; // stop processing
+    }
+
+    return PR_TRUE; // keep processing
+}
+
+/*
+ * 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!
+ */
+
+void
+nsFontMetricsPango::DrawStringSlowly(const gchar *aText,
+                                     const PRUnichar *aOrigString,
+                                     PRUint32 aLength,
+                                     GdkDrawable *aDrawable,
+                                     GdkGC *aGC, gint aX, gint aY,
+                                     PangoLayoutLine *aLine,
+                                     const nscoord *aSpacing)
+{
+    float app2dev;
+    app2dev = mDeviceContext->AppUnitsToDevUnits();
+    gint offset = 0;
+
+    /*
+     * 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.
+     */
+    nscoord *utf8spacing = new nscoord[strlen(aText)];
+
+    if (aOrigString) {
+        const gchar *curChar = aText;
+        bzero(utf8spacing, sizeof(nscoord) * strlen(aText));
+
+        // 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];
+
+            if (IS_HIGH_SURROGATE(aOrigString[curOffset]))
+                curOffset++;
+        }
+    }
+    else {
+        memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength));
+    }
+
+    gint curRun = 0;
+
+    for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
+         tmpList = tmpList->next, curRun++) {
+        PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
+        gint tmpOffset = 0;
+
+        /*        printf("    Rendering run %d: \"%s\"\n", curRun,
+                  &aText[layoutRun->item->offset]); */
+
+        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;
+        }
+
+        /*        printf("    rendering at X coord %d\n", aX + offset); */
+
+        gdk_draw_glyphs(aDrawable, aGC, layoutRun->item->analysis.font,
+                        aX + (gint)(offset / PANGO_SCALE), aY, layoutRun->glyphs);
+
+        offset += tmpOffset;
+    }
+
+    delete[] utf8spacing;
+}
+
+nsresult
+nsFontMetricsPango::GetTextDimensionsInternal(const gchar*        aString,
+                                              PRInt32             aLength,
+                                              PRInt32             aAvailWidth,
+                                              PRInt32*            aBreaks,
+                                              PRInt32             aNumBreaks,
+                                              nsTextDimensions&   aDimensions,
+                                              PRInt32&            aNumCharsFit,
+                                              nsTextDimensions&   aLastWordDimensions,
+                                              nsRenderingContextGTK *aContext)
+{
+    NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
+
+    // If we need to back up this state represents the last place
+    // we could break. We can use this to avoid remeasuring text
+    PRInt32 prevBreakState_BreakIndex = -1; // not known
+                                            // (hasn't been computed)
+    nscoord prevBreakState_Width = 0; // accumulated width to this point
+
+    // Initialize OUT parameters
+    GetMaxAscent(aLastWordDimensions.ascent);
+    GetMaxDescent(aLastWordDimensions.descent);
+    aLastWordDimensions.width = -1;
+    aNumCharsFit = 0;
+
+    // Iterate each character in the string and determine which font to use
+    nscoord width = 0;
+    PRInt32 start = 0;
+    nscoord aveCharWidth;
+    GetAveCharWidth(aveCharWidth);
+
+    while (start < aLength) {
+        // Estimate how many characters will fit. Do that by
+        // diving the available space by the average character
+        // width. Make sure the estimated number of characters is
+        // at least 1
+        PRInt32 estimatedNumChars = 0;
+
+        if (aveCharWidth > 0)
+            estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
+
+        if (estimatedNumChars < 1)
+            estimatedNumChars = 1;
+
+        // Find the nearest break offset
+        PRInt32 estimatedBreakOffset = start + estimatedNumChars;
+        PRInt32 breakIndex;
+        nscoord numChars;
+
+        // Find the nearest place to break that is less than or equal to
+        // the estimated break offset
+        if (aLength <= estimatedBreakOffset) {
+            // All the characters should fit
+            numChars = aLength - start;
+            breakIndex = aNumBreaks - 1;
+        } 
+        else {
+            breakIndex = prevBreakState_BreakIndex;
+            while (((breakIndex + 1) < aNumBreaks) &&
+                   (aBreaks[breakIndex + 1] <= estimatedBreakOffset)) {
+                ++breakIndex;
+            }
+
+            if (breakIndex == prevBreakState_BreakIndex) {
+                ++breakIndex; // make sure we advanced past the
+                // previous break index
+            }
+
+            numChars = aBreaks[breakIndex] - start;
+        }
+
+        // Measure the text
+        nscoord twWidth = 0;
+        if ((1 == numChars) && (aString[start] == ' '))
+            GetSpaceWidth(twWidth);
+        else if (numChars > 0)
+            GetWidth(&aString[start], numChars, twWidth, aContext);
+
+        // See if the text fits
+        PRBool  textFits = (twWidth + width) <= aAvailWidth;
+
+        // If the text fits then update the width and the number of
+        // characters that fit
+        if (textFits) {
+            aNumCharsFit += numChars;
+            width += twWidth;
+            start += numChars;
+
+            // This is a good spot to back up to if we need to so remember
+            // this state
+            prevBreakState_BreakIndex = breakIndex;
+            prevBreakState_Width = width;
+        }
+        else {
+            // See if we can just back up to the previous saved
+            // state and not have to measure any text
+            if (prevBreakState_BreakIndex > 0) {
+                // If the previous break index is just before the
+                // current break index then we can use it
+                if (prevBreakState_BreakIndex == (breakIndex - 1)) {
+                    aNumCharsFit = aBreaks[prevBreakState_BreakIndex];
+                    width = prevBreakState_Width;
+                    break;
+                }
+            }
+
+            // We can't just revert to the previous break state
+            if (0 == breakIndex) {
+                // There's no place to back up to, so even though
+                // the text doesn't fit return it anyway
+                aNumCharsFit += numChars;
+                width += twWidth;
+                break;
+            }
+
+            // Repeatedly back up until we get to where the text
+            // fits or we're all the way back to the first word
+            width += twWidth;
+            while ((breakIndex >= 1) && (width > aAvailWidth)) {
+                twWidth = 0;
+                start = aBreaks[breakIndex - 1];
+                numChars = aBreaks[breakIndex] - start;
+
+                if ((1 == numChars) && (aString[start] == ' '))
+                    GetSpaceWidth(twWidth);
+                else if (numChars > 0)
+                    GetWidth(&aString[start], numChars, twWidth,
+                             aContext);
+                width -= twWidth;
+                aNumCharsFit = start;
+                breakIndex--;
+            }
+            break;
+        }
+    }
+
+    aDimensions.width = width;
+    GetMaxAscent(aDimensions.ascent);
+    GetMaxDescent(aDimensions.descent);
+
+    /*    printf("aDimensions %d %d %d aLastWordDimensions %d %d %d aNumCharsFit %d\n",
+           aDimensions.width, aDimensions.ascent, aDimensions.descent,
+           aLastWordDimensions.width, aLastWordDimensions.ascent, aLastWordDimensions.descent,
+           aNumCharsFit); */
+
+    return NS_OK;
+}
+
+/* static */
+PRBool
+IsASCIIFontName(const nsString& aName)
+{
+    PRUint32 len = aName.Length();
+    const PRUnichar* str = aName.get();
+    for (PRUint32 i = 0; i < len; i++) {
+        /*
+         * X font names are printable ASCII, ignore others (for now)
+         */
+        if ((str[i] < 0x20) || (str[i] > 0x7E)) {
+            return PR_FALSE;
+        }
+    }
+  
+    return PR_TRUE;
+}
+
+/* static */
+int
+FFRECountHyphens (nsACString &aFFREName)
+{
+    int h = 0;
+    PRInt32 hyphen = 0;
+    while ((hyphen = aFFREName.FindChar('-', hyphen)) >= 0) {
+        ++h;
+        ++hyphen;
+    }
+    return h;
+}
+
+/* static */
+PangoLanguage *
+GetPangoLanguage(nsIAtom *aLangGroup)
+{
+    // Find the FC lang group for this lang group
+    nsCAutoString cname;
+    aLangGroup->ToUTF8String(cname);
+
+    // see if the lang group needs to be translated from mozilla's
+    // internal mapping into fontconfig's
+    const struct MozPangoLangGroup *langGroup;
+    langGroup = FindPangoLangGroup(cname);
+
+    // if there's no lang group, just use the lang group as it was
+    // passed to us
+    //
+    // we're casting away the const here for the strings - should be
+    // safe.
+    if (!langGroup)
+        return pango_language_from_string(cname.get());
+    else if (langGroup->PangoLang) 
+        return pango_language_from_string(langGroup->PangoLang);
+
+    return pango_language_from_string("en");
+}
+
+/* static */
+const MozPangoLangGroup*
+FindPangoLangGroup (nsACString &aLangGroup)
+{
+    for (unsigned int i=0; i < NUM_PANGO_LANG_GROUPS; ++i) {
+        if (aLangGroup.Equals(MozPangoLangGroups[i].mozLangGroup,
+                              nsCaseInsensitiveCStringComparator())) {
+            return &MozPangoLangGroups[i];
+        }
+    }
+
+    return nsnull;
+}
+
+/* static */
+void
+FreeGlobals(void)
+{
+}
+
+/* static */
+PangoStyle
+CalculateStyle(PRUint8 aStyle)
+{
+    switch(aStyle) {
+    case NS_FONT_STYLE_ITALIC:
+        return PANGO_STYLE_OBLIQUE;
+        break;
+    case NS_FONT_STYLE_OBLIQUE:
+        return PANGO_STYLE_OBLIQUE;
+        break;
+    }
+
+    return PANGO_STYLE_NORMAL;
+}
+
+/* static */
+PangoWeight
+CalculateWeight (PRUint16 aWeight)
+{
+    /*
+     * weights come in two parts crammed into one
+     * integer -- the "base" weight is weight / 100,
+     * the rest of the value is the "offset" from that
+     * weight -- the number of steps to move to adjust
+     * the weight in the list of supported font weights,
+     * this value can be negative or positive.
+     */
+    PRInt32 baseWeight = (aWeight + 50) / 100;
+    PRInt32 offset = aWeight - baseWeight * 100;
+
+    /* clip weights to range 0 to 9 */
+    if (baseWeight < 0)
+        baseWeight = 0;
+    if (baseWeight > 9)
+        baseWeight = 9;
+
+    /* Map from weight value to fcWeights index */
+    static int fcWeightLookup[10] = {
+        0, 0, 0, 0, 1, 1, 2, 3, 3, 4,
+    };
+
+    PRInt32 fcWeight = fcWeightLookup[baseWeight];
+
+    /*
+     * adjust by the offset value, make sure we stay inside the 
+     * fcWeights table
+     */
+    fcWeight += offset;
+
+    if (fcWeight < 0)
+        fcWeight = 0;
+    if (fcWeight > 4)
+        fcWeight = 4;
+
+    /* Map to final PANGO_WEIGHT value */
+    static int fcWeights[5] = {
+        349,
+        499,
+        649,
+        749,
+        999
+    };
+
+    return (PangoWeight)fcWeights[fcWeight];
+}
+
+/* static */
+nsresult
+EnumFontsPango(nsIAtom* aLangGroup, const char* aGeneric,
+               PRUint32* aCount, PRUnichar*** aResult)
+{
+    FcPattern   *pat = NULL;
+    FcObjectSet *os  = NULL;
+    FcFontSet   *fs  = NULL;
+    nsresult     rv  = NS_ERROR_FAILURE;
+
+    PRUnichar **array = NULL;
+    PRUint32    narray = 0;
+    PRInt32     serif = 0, sansSerif = 0, monospace = 0, nGenerics;
+
+    *aCount = 0;
+    *aResult = nsnull;
+
+    pat = FcPatternCreate();
+    if (!pat)
+        goto end;
+
+    os = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, 0);
+    if (!os)
+        goto end;
+
+    // take the pattern and add the lang group to it
+    if (aLangGroup)
+        AddLangGroup(pat, aLangGroup);
+
+    // get the font list
+    fs = FcFontList(0, pat, os);
+
+    if (!fs)
+        goto end;
+
+    if (!fs->nfont) {
+        rv = NS_OK;
+        goto end;
+    }
+
+    // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and
+    // "monospace", slightly different from CSS's 5.
+    if (!aGeneric)
+        serif = sansSerif = monospace = 1;
+    else if (!strcmp(aGeneric, "serif"))
+        serif = 1;
+    else if (!strcmp(aGeneric, "sans-serif"))
+        sansSerif = 1;
+    else if (!strcmp(aGeneric, "monospace"))
+        monospace = 1;
+    else if (!strcmp(aGeneric, "cursive") || !strcmp(aGeneric, "fantasy"))
+        serif = sansSerif =  1;
+    else
+        NS_NOTREACHED("unexpected generic family");
+    nGenerics = serif + sansSerif + monospace;
+
+    array = NS_STATIC_CAST(PRUnichar **,
+               nsMemory::Alloc((fs->nfont + nGenerics) * sizeof(PRUnichar *)));
+    if (!array)
+        goto end;
+
+    if (serif) {
+        PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("serif"));
+        if (!name)
+            goto end;
+        array[narray++] = name;
+    }
+
+    if (sansSerif) {
+        PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("sans-serif"));
+        if (!name)
+            goto end;
+        array[narray++] = name;
+    }
+
+    if (monospace) {
+        PRUnichar *name = ToNewUnicode(NS_LITERAL_STRING("monospace"));
+        if (!name)
+            goto end;
+        array[narray++] = name;
+    }
+
+    for (int i=0; i < fs->nfont; ++i) {
+        char *family;
+        PRUnichar *name;
+
+        // if there's no family, just move to the next iteration
+        if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
+                                (FcChar8 **) &family) != FcResultMatch) {
+            continue;
+        }
+
+        name = NS_STATIC_CAST(PRUnichar *,
+                              nsMemory::Alloc ((strlen (family) + 1)
+                                               * sizeof (PRUnichar)));
+
+        if (!name)
+            goto end;
+
+        PRUnichar *r = name;
+        for (char *f = family; *f; ++f)
+            *r++ = *f;
+        *r = '\0';
+
+        array[narray++] = name;
+    }
+
+    NS_QuickSort(array + nGenerics, narray - nGenerics, sizeof (PRUnichar*),
+                 CompareFontNames, nsnull);
+
+    *aCount = narray;
+    if (narray)
+        *aResult = array;
+    else
+        nsMemory::Free(array);
+
+    rv = NS_OK;
+
+ end:
+    if (NS_FAILED(rv) && array) {
+        while (narray)
+            nsMemory::Free (array[--narray]);
+        nsMemory::Free (array);
+    }
+    if (pat)
+        FcPatternDestroy(pat);
+    if (os)
+        FcObjectSetDestroy(os);
+    if (fs)
+        FcFontSetDestroy(fs);
+
+    return rv;
+}
+
+/* static */
+int
+CompareFontNames (const void* aArg1, const void* aArg2, void* aClosure)
+{
+    const PRUnichar* str1 = *((const PRUnichar**) aArg1);
+    const PRUnichar* str2 = *((const PRUnichar**) aArg2);
+
+    return nsCRT::strcmp(str1, str2);
+}
+
+
+// nsFontEnumeratorPango class
+
+nsFontEnumeratorPango::nsFontEnumeratorPango()
+{
+}
+
+NS_IMPL_ISUPPORTS1(nsFontEnumeratorPango, nsIFontEnumerator)
+
+NS_IMETHODIMP
+nsFontEnumeratorPango::EnumerateAllFonts(PRUint32 *aCount,
+                                         PRUnichar ***aResult)
+{
+    NS_ENSURE_ARG_POINTER(aResult);
+    *aResult = nsnull;
+    NS_ENSURE_ARG_POINTER(aCount);
+    *aCount = 0;
+
+    return EnumFontsPango(nsnull, nsnull, aCount, aResult);
+}
+
+NS_IMETHODIMP
+nsFontEnumeratorPango::EnumerateFonts(const char *aLangGroup,
+                                      const char *aGeneric,
+                                      PRUint32 *aCount,
+                                      PRUnichar ***aResult)
+{
+    NS_ENSURE_ARG_POINTER(aResult);
+    *aResult = nsnull;
+    NS_ENSURE_ARG_POINTER(aCount);
+    *aCount = 0;
+
+    // aLangGroup=null or ""  means any (i.e., don't care)
+    // aGeneric=null or ""  means any (i.e, don't care)
+    nsCOMPtr<nsIAtom> langGroup;
+    if (aLangGroup && *aLangGroup)
+        langGroup = do_GetAtom(aLangGroup);
+    const char* generic = nsnull;
+    if (aGeneric && *aGeneric)
+        generic = aGeneric;
+
+    return EnumFontsPango(langGroup, generic, aCount, aResult);
+}
+
+NS_IMETHODIMP
+nsFontEnumeratorPango::HaveFontFor(const char *aLangGroup,
+                                   PRBool *aResult)
+{
+    NS_ENSURE_ARG_POINTER(aResult);
+    *aResult = PR_FALSE;
+    NS_ENSURE_ARG_POINTER(aLangGroup);
+
+    *aResult = PR_TRUE; // always return true for now.
+    // Finish me - ftang
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontEnumeratorPango::GetDefaultFont(const char *aLangGroup,
+                                      const char *aGeneric,
+                                      PRUnichar **aResult)
+{
+    NS_ENSURE_ARG_POINTER(aResult);
+    *aResult = nsnull;
+
+    // Have a look at nsFontEnumeratorXft::GetDefaultFont for some
+    // possible code for this function.
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFontEnumeratorPango::UpdateFontList(PRBool *_retval)
+{
+    *_retval = PR_FALSE; // always return false for now
+    return NS_OK;
+}
--- mozilla/gfx/src/gtk/nsRenderingContextGTK.h.foo	2003-02-24 21:38:34.000000000 -0500
+++ mozilla/gfx/src/gtk/nsRenderingContextGTK.h	2004-11-22 12:56:21.000000000 -0500
@@ -194,6 +194,8 @@
                                const nsRect &aDestBounds, PRUint32 aCopyFlags);
   NS_IMETHOD RetrieveCurrentNativeGraphicData(PRUint32 * ngd);
 
+  NS_IMETHOD SetRightToLeftText(PRBool aIsRTL);
+
   NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint);
   NS_IMETHOD DrawScaledImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsRect * aDestRect);
 
--- mozilla/gfx/src/gtk/nsFontMetricsPango.h.foo	2004-11-22 12:56:21.000000000 -0500
+++ mozilla/gfx/src/gtk/nsFontMetricsPango.h	2004-11-22 12:56:21.000000000 -0500
@@ -0,0 +1,278 @@
+/* -*- 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 Christopher Blizzard
+ * <blizzard@mozilla.org>.  Portions created by the Initial Developer
+ * are Copyright (C) 2002 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 "nsIFontMetrics.h"
+#include "nsIFontEnumerator.h"
+#include "nsCRT.h"
+#include "nsIAtom.h"
+#include "nsString.h"
+#include "nsVoidArray.h"
+#include "nsIFontMetricsGTK.h"
+
+#include <pango/pango.h>
+
+class nsFontMetricsPango : public nsIFontMetricsGTK
+{
+public:
+    nsFontMetricsPango();
+    virtual ~nsFontMetricsPango();
+
+    NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
+
+    // nsISupports
+    NS_DECL_ISUPPORTS
+
+    // nsIFontMetrics
+    NS_IMETHOD  Init                 (const nsFont& aFont, nsIAtom* aLangGroup,
+                                      nsIDeviceContext *aContext);
+    NS_IMETHOD  Destroy();
+    NS_IMETHOD  GetFont              (const nsFont *&aFont);
+    NS_IMETHOD  GetLangGroup         (nsIAtom** aLangGroup);
+    NS_IMETHOD  GetFontHandle        (nsFontHandle &aHandle);
+
+    NS_IMETHOD  GetXHeight           (nscoord& aResult)
+                                     { aResult = mXHeight; return NS_OK; };
+
+    NS_IMETHOD GetSuperscriptOffset  (nscoord& aResult)
+                                     { aResult = mSuperscriptOffset;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetSubscriptOffset    (nscoord& aResult)
+                                     { aResult = mSubscriptOffset;
+                                       return NS_OK; };
+                              
+    NS_IMETHOD GetStrikeout          (nscoord& aOffset, nscoord& aSize)
+                                     { aOffset = mStrikeoutOffset;
+                                       aSize = mStrikeoutSize; 
+                                       return NS_OK; };
+
+    NS_IMETHOD GetUnderline          (nscoord& aOffset, nscoord& aSize)
+                                     { aOffset = mUnderlineOffset;
+                                       aSize = mUnderlineSize; 
+                                       return NS_OK; };
+
+    NS_IMETHOD GetHeight             (nscoord &aHeight)
+                                     { aHeight = mMaxHeight; 
+                                       return NS_OK; };
+
+    NS_IMETHOD GetNormalLineHeight   (nscoord &aHeight)
+                                     { aHeight = mEmHeight + mLeading;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetLeading            (nscoord &aLeading)
+                                     { aLeading = mLeading; 
+                                       return NS_OK; };
+
+    NS_IMETHOD GetEmHeight           (nscoord &aHeight)
+                                     { aHeight = mEmHeight; 
+                                       return NS_OK; };
+
+    NS_IMETHOD GetEmAscent           (nscoord &aAscent)
+                                     { aAscent = mEmAscent;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetEmDescent          (nscoord &aDescent)
+                                     { aDescent = mEmDescent;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetMaxHeight          (nscoord &aHeight)
+                                     { aHeight = mMaxHeight;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetMaxAscent          (nscoord &aAscent)
+                                     { aAscent = mMaxAscent;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetMaxDescent         (nscoord &aDescent)
+                                     { aDescent = mMaxDescent;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetMaxAdvance         (nscoord &aAdvance)
+                                     { aAdvance = mMaxAdvance;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetSpaceWidth         (nscoord &aSpaceCharWidth)
+                                     { aSpaceCharWidth = mSpaceWidth;
+                                       return NS_OK; };
+
+    NS_IMETHOD GetAveCharWidth       (nscoord &aAveCharWidth)
+                                     { 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);
+
+    virtual nsresult GetTextDimensions(const PRUnichar* aString,
+                                       PRUint32 aLength,
+                                       nsTextDimensions& aDimensions, 
+                                       PRInt32* aFontID,
+                                       nsRenderingContextGTK *aContext);
+    virtual nsresult GetTextDimensions(const char*         aString,
+                                       PRInt32             aLength,
+                                       PRInt32             aAvailWidth,
+                                       PRInt32*            aBreaks,
+                                       PRInt32             aNumBreaks,
+                                       nsTextDimensions&   aDimensions,
+                                       PRInt32&            aNumCharsFit,
+                                       nsTextDimensions&   aLastWordDimensions,
+                                       PRInt32*            aFontID,
+                                       nsRenderingContextGTK *aContext);
+    virtual nsresult GetTextDimensions(const PRUnichar*    aString,
+                                       PRInt32             aLength,
+                                       PRInt32             aAvailWidth,
+                                       PRInt32*            aBreaks,
+                                       PRInt32             aNumBreaks,
+                                       nsTextDimensions&   aDimensions,
+                                       PRInt32&            aNumCharsFit,
+                                       nsTextDimensions&   aLastWordDimensions,
+                                       PRInt32*            aFontID,
+                                       nsRenderingContextGTK *aContext);
+
+    virtual nsresult 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,
+                                nscoord aX, nscoord aY,
+                                PRInt32 aFontID,
+                                const nscoord* aSpacing,
+                                nsRenderingContextGTK *aContext,
+                                nsDrawingSurfaceGTK *aSurface);
+
+#ifdef MOZ_MATHML
+    virtual nsresult GetBoundingMetrics(const char *aString, PRUint32 aLength,
+                                        nsBoundingMetrics &aBoundingMetrics,
+                                        nsRenderingContextGTK *aContext);
+    virtual nsresult GetBoundingMetrics(const PRUnichar *aString,
+                                        PRUint32 aLength,
+                                        nsBoundingMetrics &aBoundingMetrics,
+                                        PRInt32 *aFontID,
+                                        nsRenderingContextGTK *aContext);
+#endif /* MOZ_MATHML */
+
+    virtual GdkFont* GetCurrentGDKFont(void);
+
+    virtual nsresult SetRightToLeftText(PRBool aIsRTL);
+
+    // get hints for the font
+    static 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;
+    nsFont              *mFont;
+    float                mPointSize;
+
+    nsCAutoString        mDefaultFont;
+
+    // Pango-related items
+    PangoFontDescription *mPangoFontDesc;
+    PangoContext         *mPangoContext;
+    PangoContext         *mLTRPangoContext;
+    PangoContext         *mRTLPangoContext;
+    PangoAttrList        *mPangoAttrList;
+    PRBool                mIsRTL;
+
+    // Cached font metrics
+    nscoord                  mXHeight;
+    nscoord                  mSuperscriptOffset;
+    nscoord                  mSubscriptOffset;
+    nscoord                  mStrikeoutOffset;
+    nscoord                  mStrikeoutSize;
+    nscoord                  mUnderlineOffset;
+    nscoord                  mUnderlineSize;
+    nscoord                  mMaxHeight;
+    nscoord                  mLeading;
+    nscoord                  mEmHeight;
+    nscoord                  mEmAscent;
+    nscoord                  mEmDescent;
+    nscoord                  mMaxAscent;
+    nscoord                  mMaxDescent;
+    nscoord                  mMaxAdvance;
+    nscoord                  mSpaceWidth;
+    nscoord                  mAveCharWidth;
+
+    // Private methods
+    nsresult RealizeFont(void);
+    nsresult CacheFontMetrics(void);
+
+    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);
+
+    nsresult GetTextDimensionsInternal(const gchar*        aString,
+                                       PRInt32             aLength,
+                                       PRInt32             aAvailWidth,
+                                       PRInt32*            aBreaks,
+                                       PRInt32             aNumBreaks,
+                                       nsTextDimensions&   aDimensions,
+                                       PRInt32&            aNumCharsFit,
+                                       nsTextDimensions&   aLastWordDimensions,
+                                       nsRenderingContextGTK *aContext);
+};
+
+class nsFontEnumeratorPango : public nsIFontEnumerator
+{
+public:
+    nsFontEnumeratorPango();
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIFONTENUMERATOR
+};
--- mozilla/gfx/src/gtk/nsFontMetricsUtils.h.foo	2002-10-11 22:03:32.000000000 -0400
+++ mozilla/gfx/src/gtk/nsFontMetricsUtils.h	2004-11-22 12:56:21.000000000 -0500
@@ -42,9 +42,12 @@
 extern PRUint32 NS_FontMetricsGetHints    (void);
 extern nsresult NS_FontMetricsFamilyExists(nsIDeviceContext *aDevice,
                                            const nsString &aName);
-
 #ifdef MOZ_ENABLE_XFT
 extern PRBool   NS_IsXftEnabled(void);
 #endif
 
+#ifdef MOZ_ENABLE_PANGO
+extern PRBool   NS_IsPangoEnabled(void);
+#endif
+
 #endif /* __nsFontMetricsUtils_h */
--- mozilla/gfx/src/gtk/nsIFontMetricsGTK.h.foo	2002-10-11 23:00:17.000000000 -0400
+++ mozilla/gfx/src/gtk/nsIFontMetricsGTK.h	2004-11-22 12:56:21.000000000 -0500
@@ -121,6 +121,9 @@
     // particular handle.
     virtual GdkFont* GetCurrentGDKFont(void) = 0;
 
+    // Set the direction of the text rendering
+    virtual nsresult SetRightToLeftText(PRBool aIsRTL) = 0;
+
 };
 
 #endif /* __nsIFontMetricsGTK_h */
--- mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp.foo	2004-02-12 11:52:22.000000000 -0500
+++ mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -524,6 +524,9 @@
 
   values.foreground.pixel =
     gdk_rgb_xpixel_from_rgb(NS_TO_GDK_RGB(mCurrentColor));
+  values.foreground.red = (NS_GET_R(mCurrentColor) << 8) | NS_GET_R(mCurrentColor);
+  values.foreground.green = (NS_GET_G(mCurrentColor) << 8) | NS_GET_G(mCurrentColor);
+  values.foreground.blue = (NS_GET_B(mCurrentColor) << 8) | NS_GET_B(mCurrentColor);
   valuesMask = GDK_GC_FOREGROUND;
 
 #ifdef MOZ_ENABLE_COREXFONTS
@@ -1438,6 +1441,11 @@
 
 #endif /* MOZ_MATHML */
 
+NS_IMETHODIMP nsRenderingContextGTK::SetRightToLeftText(PRBool aIsRTL)
+{
+  return mFontMetrics->SetRightToLeftText(aIsRTL);
+}
+
 NS_IMETHODIMP nsRenderingContextGTK::DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint)
 {
   UpdateGC();
--- mozilla/gfx/src/gtk/nsGCCache.cpp.foo	2002-02-02 22:47:15.000000000 -0500
+++ mozilla/gfx/src/gtk/nsGCCache.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -232,98 +232,42 @@
   // We have old GC, reuse it and check what
   // we have to change
 
-  XGCValues xvalues;
-  unsigned long xvalues_mask=0;
+  GdkGCValues xvalues;
+  int xvalues_mask = 0;
 
   if (entry->clipRegion) {
     // set it to none here and then set the clip region with
     // gdk_gc_set_clip_region in GetGC()
     xvalues.clip_mask = None;
-    xvalues_mask |= GCClipMask;
+    xvalues_mask |= GDK_GC_CLIP_MASK;
     gdk_region_destroy(entry->clipRegion);
     entry->clipRegion = NULL;
   }
 
   if (entry->gcv.foreground.pixel != gcv->foreground.pixel) {
-    xvalues.foreground = gcv->foreground.pixel;
-    xvalues_mask |= GCForeground;
+    xvalues.foreground.pixel = gcv->foreground.pixel;
+    xvalues_mask |= GDK_GC_FOREGROUND;
   }
 
   if (entry->gcv.function != gcv->function) {
-    switch (gcv->function) {
-    case GDK_COPY:
-      xvalues.function = GXcopy;
-      break;
-    case GDK_INVERT:
-      xvalues.function = GXinvert;
-      break;
-    case GDK_XOR:
-      xvalues.function = GXxor;
-      break;
-    case GDK_CLEAR:
-      xvalues.function = GXclear;
-      break;
-    case GDK_AND:
-      xvalues.function = GXand;
-      break;
-    case GDK_AND_REVERSE:
-      xvalues.function = GXandReverse;
-      break;
-    case GDK_AND_INVERT:
-      xvalues.function = GXandInverted;
-      break;
-    case GDK_NOOP:
-      xvalues.function = GXnoop;
-      break;
-    case GDK_OR:
-      xvalues.function = GXor;
-      break;
-    case GDK_EQUIV:
-      xvalues.function = GXequiv;
-      break;
-    case GDK_OR_REVERSE:
-      xvalues.function = GXorReverse;
-      break;
-    case GDK_COPY_INVERT:
-      xvalues.function = GXcopyInverted;
-      break;
-    case GDK_OR_INVERT:
-      xvalues.function = GXorInverted;
-      break;
-    case GDK_NAND:
-      xvalues.function = GXnand;
-      break;
-    case GDK_SET:
-      xvalues.function = GXset;
-      break;
-    }
-    xvalues_mask |= GCFunction;
+    xvalues.function = gcv->function;
+    xvalues_mask |= GDK_GC_FUNCTION;
   }
 
   if(entry->gcv.font != gcv->font && flags & GDK_GC_FONT) {
-    xvalues.font =  ((XFontStruct *)GDK_FONT_XFONT(gcv->font))->fid;
-    xvalues_mask |= GCFont;
+    xvalues.font = gcv->font;
+    xvalues_mask |= GDK_GC_FONT;
   }
 
   if (entry->gcv.line_style != gcv->line_style) {
-    switch (gcv->line_style) {
-    case GDK_LINE_SOLID:
-      xvalues.line_style = LineSolid;
-      break;
-    case GDK_LINE_ON_OFF_DASH:
-      xvalues.line_style = LineOnOffDash;
-      break;
-    case GDK_LINE_DOUBLE_DASH:
-      xvalues.line_style = LineDoubleDash;
-      break;
-    }
-    xvalues_mask |= GCLineStyle;
+    xvalues.line_style = gcv->line_style;
+    xvalues_mask |= GDK_GC_LINE_STYLE;
   }
 
   if (xvalues_mask != 0) {
-    XChangeGC(GDK_GC_XDISPLAY(entry->gc), GDK_GC_XGC(entry->gc),
-              xvalues_mask, &xvalues);
+    gdk_gc_set_values(entry->gc, &xvalues, (GdkGCValuesMask)xvalues_mask);
   }
+
   entry->flags = flags;
   entry->gcv = *gcv;
 }
--- mozilla/gfx/src/gtk/nsFontMetricsGTK.cpp.foo	2004-03-09 09:14:54.000000000 -0500
+++ mozilla/gfx/src/gtk/nsFontMetricsGTK.cpp	2004-11-22 12:56:21.000000000 -0500
@@ -4600,6 +4600,12 @@
   return mCurrentFont->GetGDKFont();
 }
 
+nsresult
+nsFontMetricsGTK::SetRightToLeftText(PRBool aIsRTL)
+{
+    return NS_OK;
+}
+
 PR_BEGIN_EXTERN_C
 static int
 CompareSizes(const void* aArg1, const void* aArg2, void *data)
--- mozilla/gfx/src/gtk/nsFontMetricsXft.h.foo	2004-02-23 16:38:52.000000000 -0500
+++ mozilla/gfx/src/gtk/nsFontMetricsXft.h	2004-11-22 12:56:21.000000000 -0500
@@ -202,6 +202,8 @@
 
     virtual GdkFont* GetCurrentGDKFont(void);
 
+    virtual nsresult SetRightToLeftText(PRBool aIsRTL);
+
     // get hints for the font
     static PRUint32    GetHints  (void);
 
--- mozilla/gfx/src/gtk/nsFontMetricsGTK.h.foo	2004-02-04 20:57:03.000000000 -0500
+++ mozilla/gfx/src/gtk/nsFontMetricsGTK.h	2004-11-22 12:56:21.000000000 -0500
@@ -344,6 +344,8 @@
 
   virtual GdkFont* GetCurrentGDKFont(void);
 
+  virtual nsresult SetRightToLeftText(PRBool aIsRTL);
+
   static nsresult FamilyExists(nsIDeviceContext *aDevice, const nsString& aName);
   static PRUint32 GetHints(void);
 
--- mozilla/configure.in.foo	2004-11-22 12:55:08.000000000 -0500
+++ mozilla/configure.in	2004-11-22 12:56:21.000000000 -0500
@@ -3476,6 +3476,34 @@
 AC_SUBST(MOZ_XFT_LIBS)
 
 dnl ========================================================
+dnl = pango font rendering
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(pango,
+[  --enable-pango          Enable Pango font rendering support],
+    MOZ_ENABLE_PANGO=1,
+    MOZ_ENABLE_PANGO=)
+
+if test "$MOZ_ENABLE_PANGO"
+then
+    AC_DEFINE(MOZ_ENABLE_PANGO)
+    PKG_CHECK_MODULES(MOZ_PANGO, pango >= 1.5.0)
+
+    dnl Make sure that the pango version is _actually_ new enough
+    _SAVE_CFLAGS=$CFLAGS
+    _SAVE_LDFLAGS=$LDFLAGS
+    CFLAGS="$MOZ_PANGO_CFLAGS $CFLAGS"
+    LDFLAGS="$MOZ_PANGO_LIBS $LDFLAGS"
+    AC_CHECK_LIB(pangoft2-1.0, pango_fc_font_map_add_decoder_find_func,,
+                 AC_MSG_ERROR([Your Pango is too old. Sorry.]))
+    CFLAGS=$_SAVE_CFLAGS
+    LDFLAGS=$_SAVE_LDFLAGS
+
+    AC_SUBST(MOZ_ENABLE_PANGO)
+    AC_SUBST(MOZ_PANGO_CFLAGS)
+    AC_SUBST(MOZ_PANGO_LIBS)
+fi
+
+dnl ========================================================
 dnl = disabling x11 core support, enabled by default
 dnl ========================================================
 MOZ_ENABLE_COREXFONTS=${MOZ_ENABLE_COREXFONTS-1}