4a48add
--- mozilla.back/gfx/src/gtk/nsFontMetricsPango.cpp.orig	2007-06-28 14:44:31.000000000 +0200
4a48add
+++ mozilla.back/gfx/src/gtk/nsFontMetricsPango.cpp	2007-06-28 15:48:04.000000000 +0200
4a48add
@@ -21,6 +21,8 @@
4a48add
  * are Copyright (C) 2004 the Initial Developer. All Rights Reserved.
4a48add
  *
4a48add
  * Contributor(s):
4a48add
+ *   Christopher Blizzard <blizzard@mozilla.org>
4a48add
+ *   Behdad Esfahbod <behdad@behdad.org>
4a48add
  *
4a48add
  * Alternatively, the contents of this file may be used under the terms of
4a48add
  * either the GNU General Public License Version 2 or later (the "GPL"), or
4a48add
@@ -36,6 +38,10 @@
4a48add
  *
4a48add
  * ***** END LICENSE BLOCK ***** */
4a48add
 
4a48add
+#define PANGO_ENABLE_BACKEND
4a48add
+
4a48add
+#include "nsFontMetricsPango.h"
4a48add
+
4a48add
 #include <strings.h>
4a48add
 #include "nsFont.h"
4a48add
 #include "nsIDeviceContext.h"
4a48add
@@ -43,27 +49,37 @@
4a48add
 #include "nsIPref.h"
4a48add
 #include "nsServiceManagerUtils.h"
4a48add
 
4a48add
-#define PANGO_ENABLE_BACKEND
4a48add
-#define PANGO_ENABLE_ENGINE
4a48add
-
4a48add
-#include "nsFontMetricsPango.h"
4a48add
-#include "nsRenderingContextGTK.h"
4a48add
-#include "nsDeviceContextGTK.h"
4a48add
 #include "nsFontConfigUtils.h"
4a48add
 
4a48add
 #include "nsUnicharUtils.h"
4a48add
 #include "nsQuickSort.h"
4a48add
 #include "nsFontConfigUtils.h"
4a48add
+#include "mozilla-decoder.h"
4a48add
+
4a48add
+#define FORCE_PR_LOG
4a48add
+#include "prlog.h"
4a48add
+
4a48add
 
4a48add
 #include <fontconfig/fontconfig.h>
4a48add
+#include <freetype/tttables.h>
4a48add
+
4a48add
+#include <pango/pango.h>
4a48add
+#include <pango/pangofc-font.h>
4a48add
+
4a48add
+#ifdef PSPANGO
4a48add
+#include <pango/pangoft2.h>
4a48add
+#include "nsRenderingContextPS.h"
4a48add
+#include "nsDeviceContextPS.h"
4a48add
+#include "nsType1.h"
4a48add
+#else
4a48add
 #include <gdk/gdk.h>
4a48add
 #include <gdk/gdkx.h>
4a48add
-#include <freetype/tttables.h>
4a48add
+#include "nsRenderingContextGTK.h"
4a48add
+#include "nsDeviceContextGTK.h"
4a48add
+#endif
4a48add
+
4a48add
 
4a48add
-#include "mozilla-decoder.h"
4a48add
 
4a48add
-#define FORCE_PR_LOG
4a48add
-#include "prlog.h"
4a48add
 
4a48add
 // Globals
4a48add
 
4a48add
@@ -108,6 +124,49 @@ static nsresult    EnumFontsPango   (nsI
4a48add
                                      PRUint32* aCount, PRUnichar*** aResult);
4a48add
 static int         CompareFontNames (const void* aArg1, const void* aArg2,
4a48add
                                      void* aClosure);
4a48add
+static void  utf16_to_utf8 (const PRUnichar* aString, PRUint32 aLength,
4a48add
+                            char *&text, gint &text_len);
4a48add
+
4a48add
+#ifdef PSPANGO
4a48add
+static void
4a48add
+default_substitute (FcPattern *pattern,
4a48add
+                    gpointer   data)
4a48add
+{
4a48add
+  FcPatternDel (pattern, FC_HINTING);
4a48add
+  FcPatternAddBool (pattern, FC_HINTING, 0);
4a48add
+}
4a48add
+#endif
4a48add
+
4a48add
+static PangoFontMap *
4a48add
+get_fontmap (void)
4a48add
+{
4a48add
+  static PangoFontMap               *fontmap = NULL;
4a48add
+
4a48add
+  if (!fontmap) {
4a48add
+#ifdef PSPANGO
4a48add
+    fontmap = pango_ft2_font_map_new ();
4a48add
+    pango_ft2_font_map_set_resolution ((PangoFT2FontMap *)fontmap, 72., 72.);
4a48add
+    pango_ft2_font_map_set_default_substitute ((PangoFT2FontMap *)fontmap, default_substitute, NULL, NULL);
4a48add
+#else
4a48add
+    PangoContext* context = gdk_pango_context_get ();
4a48add
+    fontmap = pango_context_get_font_map (context);
4a48add
+    g_object_unref (context);
4a48add
+#endif
4a48add
+  }
4a48add
+
4a48add
+  return fontmap;
4a48add
+}
4a48add
+
4a48add
+static PangoContext *
4a48add
+get_context (void)
4a48add
+{
4a48add
+#ifdef PSPANGO
4a48add
+  return pango_ft2_font_map_create_context ((PangoFT2FontMap *) get_fontmap ());
4a48add
+#else
4a48add
+  return gdk_pango_context_get();
4a48add
+#endif
4a48add
+}
4a48add
+
4a48add
 
4a48add
 nsFontMetricsPango::nsFontMetricsPango()
4a48add
 {
4a48add
@@ -169,14 +228,20 @@ nsFontMetricsPango::Init(const nsFont& a
4a48add
     mLangGroup = aLangGroup;
4a48add
 
4a48add
     // Hang on to the device context
4a48add
+#ifdef PSPANGO
4a48add
+    mDeviceContext = (nsDeviceContextPS *)aContext;
4a48add
+#else
4a48add
     mDeviceContext = aContext;
4a48add
+#endif
4a48add
     
4a48add
     mPointSize = NSTwipsToFloatPoints(mFont.size);
4a48add
 
4a48add
+#ifndef PSPANGO
4a48add
     // Make sure to clamp the pixel size to something reasonable so we
4a48add
     // don't make the X server blow up.
4a48add
     nscoord screenPixels = gdk_screen_height();
4a48add
     mPointSize = PR_MIN(screenPixels * FONT_MAX_FONT_SCALE, mPointSize);
4a48add
+#endif
4a48add
 
4a48add
     // enumerate over the font names passed in
4a48add
     mFont.EnumerateFamilies(nsFontMetricsPango::EnumFontCallback, this);
4a48add
@@ -329,7 +394,7 @@ nsFontMetricsPango::CacheFontMetrics(voi
4a48add
 
4a48add
     // mPangoSpaceWidth
4a48add
     PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
-    pango_layout_set_text(layout, " ", 1);
4a48add
+    pango_layout_set_text(layout, " ", -1);
4a48add
     int pswidth, psheight;
4a48add
     pango_layout_get_size(layout, &pswidth, &psheight);
4a48add
     mPangoSpaceWidth = pswidth;
4a48add
@@ -337,14 +402,14 @@ nsFontMetricsPango::CacheFontMetrics(voi
4a48add
 
4a48add
     // mSpaceWidth (width of a space)
4a48add
     nscoord tmpWidth;
4a48add
-    GetWidth(" ", 1, tmpWidth, NULL);
4a48add
+    GetWidth(" ", 1, tmpWidth CONTEXT_ARG_NULL);
4a48add
     mSpaceWidth = tmpWidth;
4a48add
 
4a48add
     // mAveCharWidth (width of an 'average' char)
4a48add
     //    XftTextExtents16(GDK_DISPLAY(), xftFont, &xUnichar, 1, &extents);
4a48add
     //rawWidth = extents.width;
4a48add
     //mAveCharWidth = NSToCoordRound(rawWidth * f);
4a48add
-    GetWidth("x", 1, tmpWidth, NULL);
4a48add
+    GetWidth("x", 1, tmpWidth CONTEXT_ARG_NULL);
4a48add
     mAveCharWidth = tmpWidth;
4a48add
 
4a48add
     // mXHeight (height of an 'x' character)
4a48add
@@ -460,130 +525,96 @@ nsFontMetricsPango::GetFontHandle(nsFont
4a48add
 
4a48add
 // nsIFontMetricsPango impl
4a48add
 
4a48add
-nsresult
4a48add
-nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
4a48add
-                             nscoord& aWidth,
4a48add
-                             nsRenderingContextGTK *aContext)
4a48add
+#ifdef PSPANGO
4a48add
+NS_IMETHODIMP
4a48add
+nsFontMetricsPSPango::GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength)
4a48add
 {
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
-
4a48add
-    pango_layout_set_text(layout, aString, aLength);
4a48add
+    return GetWidth (String, (PRUint32) aLength, aWidth CONTEXT_ARG_NULL);
4a48add
+}
4a48add
 
4a48add
-    if (mPangoSpaceWidth)
4a48add
-        FixupSpaceWidths(layout, aString);
4a48add
+NS_IMETHODIMP
4a48add
+nsFontMetricsPSPango::GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength)
4a48add
+{
4a48add
+    return GetWidth (aString, (PRUint32)aLength, aWidth, NULL CONTEXT_ARG_NULL);
4a48add
+}
4a48add
+#endif
4a48add
 
4a48add
+nsresult
4a48add
+nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
4a48add
+                             nscoord& aWidth
4a48add
+                             CONTEXT_ARG_DEF)
4a48add
+{
4a48add
     int width, height;
4a48add
-
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
     pango_layout_get_size(layout, &width, &height);
4a48add
-
4a48add
     g_object_unref(layout);
4a48add
 
4a48add
-    float f;
4a48add
-    f = mDeviceContext->DevUnitsToAppUnits();
4a48add
+    float f = mDeviceContext->DevUnitsToAppUnits();
4a48add
     aWidth = NSToCoordRound(width * f / PANGO_SCALE);
4a48add
 
4a48add
-    //    printf("GetWidth (char *) %d\n", aWidth);
4a48add
-
4a48add
     return NS_OK;
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
 nsFontMetricsPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
4a48add
-                             nscoord& aWidth, PRInt32 *aFontID,
4a48add
-                             nsRenderingContextGTK *aContext)
4a48add
+                             nscoord& aWidth, PRInt32 *aFontID
4a48add
+                             CONTEXT_ARG_DEF)
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
-
4a48add
-    gchar *text = g_utf16_to_utf8(aString, aLength,
4a48add
-                                  NULL, NULL, NULL);
4a48add
-
4a48add
-    if (!text) {
4a48add
-        aWidth = 0;
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aString, aLength)
4a48add
-#endif
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
-
4a48add
     gint width, height;
4a48add
-
4a48add
-    pango_layout_set_text(layout, text, strlen(text));
4a48add
-    FixupSpaceWidths(layout, text);
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
     pango_layout_get_size(layout, &width, &height);
4a48add
+    g_object_unref(layout);
4a48add
 
4a48add
-    float f;
4a48add
-    f = mDeviceContext->DevUnitsToAppUnits();
4a48add
+    float f = mDeviceContext->DevUnitsToAppUnits();
4a48add
     aWidth = NSToCoordRound(width * f / PANGO_SCALE);
4a48add
 
4a48add
-    //    printf("GetWidth %d\n", aWidth);
4a48add
-
4a48add
- loser:
4a48add
-    g_free(text);
4a48add
-    g_object_unref(layout);
4a48add
-
4a48add
-    return rv;
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 
4a48add
 nsresult
4a48add
-nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
4a48add
+nsFontMetricsPango::GetTextDimensions(const char* aString,
4a48add
                                       PRUint32 aLength,
4a48add
-                                      nsTextDimensions& aDimensions, 
4a48add
-                                      PRInt32* aFontID,
4a48add
-                                      nsRenderingContextGTK *aContext)
4a48add
+                                      nsTextDimensions& aDimensions
4a48add
+                                      CONTEXT_ARG_DEF)
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
-
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
4a48add
 
4a48add
-    gchar *text = g_utf16_to_utf8(aString, aLength,
4a48add
-                                  NULL, NULL, NULL);
4a48add
-
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetTextDimensions invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aString, aLength)
4a48add
-#endif
4a48add
-        aDimensions.width = 0;
4a48add
-        aDimensions.ascent = 0;
4a48add
-        aDimensions.descent = 0;
4a48add
-
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
-        
4a48add
+    PangoRectangle logical;
4a48add
+    pango_layout_line_get_extents(line, NULL, &logical);
4a48add
+    g_object_unref(layout);
4a48add
 
4a48add
-    pango_layout_set_text(layout, text, strlen(text));
4a48add
-    FixupSpaceWidths(layout, text);
4a48add
+    float P2T = mDeviceContext->DevUnitsToAppUnits();
4a48add
 
4a48add
-    // Get the logical extents
4a48add
-    PangoLayoutLine *line;
4a48add
-    if (pango_layout_get_line_count(layout) != 1) {
4a48add
-        printf("Warning: more than one line!\n");
4a48add
-    }
4a48add
-    line = pango_layout_get_line(layout, 0);
4a48add
+    aDimensions.ascent  = NSToCoordRound(PANGO_ASCENT(logical)  * P2T / PANGO_SCALE);
4a48add
+    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(logical) * P2T / PANGO_SCALE);
4a48add
+    aDimensions.width   = NSToCoordRound(logical.width          * P2T / PANGO_SCALE);
4a48add
 
4a48add
-    PangoRectangle rect;
4a48add
-    pango_layout_line_get_extents(line, NULL, &rect);
4a48add
+    return NS_OK;
4a48add
+}
4a48add
 
4a48add
-    float P2T;
4a48add
-    P2T = mDeviceContext->DevUnitsToAppUnits();
4a48add
+nsresult
4a48add
+nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
4a48add
+                                      PRUint32 aLength,
4a48add
+                                      nsTextDimensions& aDimensions, 
4a48add
+                                      PRInt32* aFontID
4a48add
+                                      CONTEXT_ARG_DEF)
4a48add
+{
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
4a48add
 
4a48add
-    aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
4a48add
-    aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
4a48add
-    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
4a48add
+    PangoRectangle logical;
4a48add
+    pango_layout_line_get_extents(line, NULL, &logical);
4a48add
+    g_object_unref(layout);
4a48add
 
4a48add
-    //    printf("GetTextDimensions %d %d %d\n", aDimensions.width,
4a48add
-    //aDimensions.ascent, aDimensions.descent);
4a48add
+    float P2T = mDeviceContext->DevUnitsToAppUnits();
4a48add
 
4a48add
- loser:
4a48add
-    g_free(text);
4a48add
-    g_object_unref(layout);
4a48add
+    aDimensions.ascent  = NSToCoordRound(PANGO_ASCENT(logical)  * P2T / PANGO_SCALE);
4a48add
+    aDimensions.descent = NSToCoordRound(PANGO_DESCENT(logical) * P2T / PANGO_SCALE);
4a48add
+    aDimensions.width   = NSToCoordRound(logical.width          * P2T / PANGO_SCALE);
4a48add
 
4a48add
-    return rv;
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
@@ -595,13 +626,13 @@ nsFontMetricsPango::GetTextDimensions(co
4a48add
                                       nsTextDimensions&   aDimensions,
4a48add
                                       PRInt32&            aNumCharsFit,
4a48add
                                       nsTextDimensions&   aLastWordDimensions,
4a48add
-                                      PRInt32*            aFontID,
4a48add
-                                      nsRenderingContextGTK *aContext)
4a48add
+                                      PRInt32*            aFontID
4a48add
+                                      CONTEXT_ARG_DEF)
4a48add
 {
4a48add
 
4a48add
     return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks,
4a48add
                                      aNumBreaks, aDimensions, aNumCharsFit,
4a48add
-                                     aLastWordDimensions, aContext);
4a48add
+                                     aLastWordDimensions CONTEXT_ARG_PASS);
4a48add
 
4a48add
 }
4a48add
 
4a48add
@@ -614,8 +645,8 @@ nsFontMetricsPango::GetTextDimensions(co
4a48add
                                       nsTextDimensions&   aDimensions,
4a48add
                                       PRInt32&            aNumCharsFit,
4a48add
                                       nsTextDimensions&   aLastWordDimensions,
4a48add
-                                      PRInt32*            aFontID,
4a48add
-                                      nsRenderingContextGTK *aContext)
4a48add
+                                      PRInt32*            aFontID
4a48add
+                                      CONTEXT_ARG_DEF)
4a48add
 {
4a48add
     nsresult rv = NS_OK;
4a48add
     PRInt32 curBreak = 0;
4a48add
@@ -623,23 +654,15 @@ nsFontMetricsPango::GetTextDimensions(co
4a48add
 
4a48add
     PRInt32 *utf8Breaks = new PRInt32[aNumBreaks];
4a48add
 
4a48add
-    gchar *text = g_utf16_to_utf8(aString, (PRInt32)aLength,
4a48add
-                                  NULL, NULL, NULL);
4a48add
+    gchar* text;
4a48add
+    gint text_len;
4a48add
+    utf16_to_utf8 (aString, aLength, text, text_len);
4a48add
 
4a48add
     curChar = text;
4a48add
 
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aString, (PRUint32)aLength)
4a48add
-#endif
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
-
4a48add
     // Covert the utf16 break offsets to utf8 break offsets
4a48add
     for (PRInt32 curOffset=0; curOffset < aLength;
4a48add
-         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
4a48add
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
4a48add
         if (aBreaks[curBreak] == curOffset) {
4a48add
             utf8Breaks[curBreak] = curChar - text;
4a48add
             curBreak++;
4a48add
@@ -653,10 +676,10 @@ nsFontMetricsPango::GetTextDimensions(co
4a48add
     utf8Breaks[curBreak] = curChar - text;
4a48add
 
4a48add
 #if 0
4a48add
-    if (strlen(text) != aLength) {
4a48add
-        printf("Different lengths for utf16 %d and utf8 %d\n", aLength, strlen(text));
4a48add
+    if (text_len != aLength) {
4a48add
+        printf("Different lengths for utf16 %d and utf8 %d\n", aLength, text_len);
4a48add
         DUMP_PRUNICHAR(aString, aLength)
4a48add
-        DUMP_PRUNICHAR(text, strlen(text))
4a48add
+        DUMP_PRUNICHAR(text, text_len)
4a48add
         for (PRInt32 i = 0; i < aNumBreaks; ++i) {
4a48add
             printf("  break %d utf16 %d utf8 %d\n", i, aBreaks[i], utf8Breaks[i]);
4a48add
         }
4a48add
@@ -666,9 +689,9 @@ nsFontMetricsPango::GetTextDimensions(co
4a48add
     // We'll use curBreak to indicate which of the breaks end up being
4a48add
     // used for the break point for this line.
4a48add
     curBreak = 0;
4a48add
-    rv = GetTextDimensionsInternal(text, strlen(text), aAvailWidth, utf8Breaks,
4a48add
+    rv = GetTextDimensionsInternal(text, text_len, aAvailWidth, utf8Breaks,
4a48add
                                    aNumBreaks, aDimensions, aNumCharsFit,
4a48add
-                                   aLastWordDimensions, aContext);
4a48add
+                                   aLastWordDimensions CONTEXT_ARG_PASS);
4a48add
 
4a48add
     // Figure out which of the breaks we ended up using to convert
4a48add
     // back to utf16 - start from the end.
4a48add
@@ -681,200 +704,365 @@ nsFontMetricsPango::GetTextDimensions(co
4a48add
         }
4a48add
     }
4a48add
 
4a48add
- loser:
4a48add
-    if (text)
4a48add
-        g_free(text);
4a48add
+    g_free(text);
4a48add
 
4a48add
     delete[] utf8Breaks;
4a48add
 
4a48add
     return rv;
4a48add
 }
4a48add
 
4a48add
-nsresult
4a48add
-nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
4a48add
-                               nscoord aX, nscoord aY,
4a48add
-                               const nscoord* aSpacing,
4a48add
-                               nsRenderingContextGTK *aContext,
4a48add
-                               nsDrawingSurfaceGTK *aSurface)
4a48add
+#ifdef PSPANGO
4a48add
+
4a48add
+typedef struct _nsPSPangoRenderer        nsPSPangoRenderer;
4a48add
+typedef struct _nsPSPangoRendererClass   nsPSPangoRendererClass;
4a48add
+
4a48add
+struct _nsPSPangoRenderer
4a48add
 {
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
+  PangoRenderer parent_instance;
4a48add
+  nsRenderingContextPS *psContext;
4a48add
+  nsFontMetricsPSPango *psPangoFontMetrics;
4a48add
+  float zoom;
4a48add
+};
4a48add
 
4a48add
-    pango_layout_set_text(layout, aString, aLength);
4a48add
-    FixupSpaceWidths(layout, aString);
4a48add
+struct _nsPSPangoRendererClass
4a48add
+{
4a48add
+  PangoRendererClass parent_class;
4a48add
+};
4a48add
 
4a48add
-    int x = aX;
4a48add
-    int y = aY;
4a48add
+#define _PS_TYPE_PANGO_RENDERER            (_ps_pango_renderer_get_type())
4a48add
+#define _PS_PANGO_RENDERER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRenderer))
4a48add
+#define _PS_IS_PANGO_RENDERER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), _PS_TYPE_PANGO_RENDERER))
4a48add
+#define _PS_PANGO_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
4a48add
+#define _PS_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), _PS_TYPE_PANGO_RENDERER))
4a48add
+#define _PS_PANGO_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), _PS_TYPE_PANGO_RENDERER, _nsPSPangoRendererClass))
4a48add
 
4a48add
-    aContext->GetTranMatrix()->TransformCoord(&x, &y);
4a48add
+G_DEFINE_TYPE (_nsPSPangoRenderer, _ps_pango_renderer, PANGO_TYPE_RENDERER)
4a48add
 
4a48add
-    PangoLayoutLine *line;
4a48add
-    if (pango_layout_get_line_count(layout) != 1) {
4a48add
-        printf("Warning: more than one line!\n");
4a48add
-    }
4a48add
-    line = pango_layout_get_line(layout, 0);
4a48add
+static PangoRenderer *
4a48add
+get_renderer (void)
4a48add
+{
4a48add
+  static PangoRenderer               *renderer = NULL;
4a48add
 
4a48add
-    aContext->UpdateGC();
4a48add
-    GdkGC *gc = aContext->GetGC();
4a48add
+  if (!renderer)
4a48add
+    renderer = (PangoRenderer *) g_object_new (_PS_TYPE_PANGO_RENDERER, NULL);
4a48add
 
4a48add
-    if (aSpacing && *aSpacing) {
4a48add
-        DrawStringSlowly(aString, NULL, aLength, aSurface->GetDrawable(),
4a48add
-                         gc, x, y, line, aSpacing);
4a48add
-    }
4a48add
-    else {
4a48add
-        gdk_draw_layout_line(aSurface->GetDrawable(), gc,
4a48add
-                             x, y,
4a48add
-                             line);
4a48add
-    }
4a48add
+  return renderer;
4a48add
+}
4a48add
 
4a48add
-    g_object_unref(gc);
4a48add
-    g_object_unref(layout);
4a48add
+static void
4a48add
+_ps_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
4a48add
+                              PangoFont        *font,
4a48add
+                              PangoGlyphString *glyphs,
4a48add
+                              int               x,
4a48add
+                              int               y);
4a48add
 
4a48add
-    //    printf("DrawString (char *)\n");
4a48add
+static void
4a48add
+_ps_pango_renderer_class_init (nsPSPangoRendererClass *klass)
4a48add
+{
4a48add
+  PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
4a48add
+  
4a48add
+  renderer_class->draw_glyphs = _ps_pango_renderer_draw_glyphs;
4a48add
+}
4a48add
 
4a48add
-    return NS_OK;
4a48add
+static void
4a48add
+_ps_pango_renderer_init (nsPSPangoRenderer *renderer)
4a48add
+{
4a48add
+}
4a48add
+
4a48add
+class nsPangoType1Generator : public nsPSFontGenerator {
4a48add
+public:
4a48add
+  nsPangoType1Generator();
4a48add
+  ~nsPangoType1Generator();
4a48add
+  nsresult Init(PangoFont *aFont);
4a48add
+  void  GeneratePSFont(FILE* aFile);
4a48add
+
4a48add
+protected:
4a48add
+  PangoFont *mFont;
4a48add
+};
4a48add
+
4a48add
+nsPangoType1Generator::nsPangoType1Generator()
4a48add
+{
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
-nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
4a48add
-                               nscoord aX, nscoord aY,
4a48add
-                               PRInt32 aFontID,
4a48add
-                               const nscoord* aSpacing,
4a48add
-                               nsRenderingContextGTK *aContext,
4a48add
-                               nsDrawingSurfaceGTK *aSurface)
4a48add
+nsPangoType1Generator::Init(PangoFont *aFont)
4a48add
+  {
4a48add
+  NS_ENSURE_TRUE(aFont, NS_ERROR_FAILURE);
4a48add
+  mFont = aFont;
4a48add
+  g_object_ref (mFont);
4a48add
+  return NS_OK;
4a48add
+}
4a48add
+
4a48add
+nsPangoType1Generator::~nsPangoType1Generator()
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
-    int x = aX;
4a48add
-    int y = aY;
4a48add
+  g_object_unref (mFont);
4a48add
+  mFont = nsnull;
4a48add
+}
4a48add
 
4a48add
-    aContext->UpdateGC();
4a48add
-    GdkGC *gc = aContext->GetGC();
4a48add
+void nsPangoType1Generator::GeneratePSFont(FILE* aFile)
4a48add
+{
4a48add
+  FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) mFont);
4a48add
 
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
+  if (face == nsnull)
4a48add
+    return;
4a48add
 
4a48add
-    gchar *text = g_utf16_to_utf8(aString, aLength,
4a48add
-                                  NULL, NULL, NULL);
4a48add
+  int wmode = 0;
4a48add
+  if (mGlyphSubset->Count())
4a48add
+    FT2SubsetToType1FontSet(face, mGlyphSubset, wmode, aFile);
4a48add
 
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::DrawString invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aString, aLength)
4a48add
-#endif
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
+ pango_fc_font_unlock_face ((PangoFcFont *) mFont);
4a48add
+}
4a48add
 
4a48add
-    pango_layout_set_text(layout, text, strlen(text));
4a48add
-    FixupSpaceWidths(layout, text);
4a48add
+typedef struct
4a48add
+{
4a48add
+  nsCString    *FontNameBase;
4a48add
+  nsCStringKey *key;
4a48add
+  int           font_size;
4a48add
+} PSPangoFontData;
4a48add
 
4a48add
-    aContext->GetTranMatrix()->TransformCoord(&x, &y);
4a48add
+static void
4a48add
+ps_pango_font_data_destroy (PSPangoFontData *data)
4a48add
+{
4a48add
+  delete data->key;
4a48add
+  delete data->FontNameBase;
4a48add
+  g_free (data);
4a48add
+}
4a48add
 
4a48add
-    PangoLayoutLine *line;
4a48add
-    if (pango_layout_get_line_count(layout) != 1) {
4a48add
-        printf("Warning: more than one line!\n");
4a48add
-    }
4a48add
-    line = pango_layout_get_line(layout, 0);
4a48add
+static void
4a48add
+_ps_pango_renderer_draw_glyphs (PangoRenderer    *renderer,
4a48add
+                              PangoFont        *font,
4a48add
+                              PangoGlyphString *glyphs,
4a48add
+                              int               x,
4a48add
+                              int               y)
4a48add
+{
4a48add
+  if (!glyphs->num_glyphs)
4a48add
+    return;
4a48add
 
4a48add
-    if (aSpacing && *aSpacing) {
4a48add
-        DrawStringSlowly(text, aString, aLength, aSurface->GetDrawable(),
4a48add
-                         gc, x, y, line, aSpacing);
4a48add
-    }
4a48add
-    else {
4a48add
-        gdk_draw_layout_line(aSurface->GetDrawable(), gc,
4a48add
-                             x, y,
4a48add
-                             line);
4a48add
-    }
4a48add
+  static GQuark data_quark = 0;
4a48add
+  if (!data_quark)
4a48add
+    data_quark = g_quark_from_static_string ("ps-pango-font-data");
4a48add
 
4a48add
- loser:
4a48add
+  PSPangoFontData *data;
4a48add
+  if (!(data = (PSPangoFontData *) g_object_get_qdata (G_OBJECT (font), data_quark)))
4a48add
+    {
4a48add
+      data = g_new (PSPangoFontData, 1);
4a48add
 
4a48add
-    g_free(text);
4a48add
-    g_object_unref(gc);
4a48add
-    g_object_unref(layout);
4a48add
+      FT_Face face = pango_fc_font_lock_face ((PangoFcFont *) font);
4a48add
+      if (face == nsnull)
4a48add
+        return;
4a48add
+      int wmode = 0;
4a48add
+      data->FontNameBase = new nsCString ();
4a48add
+      if (NS_FAILED(FT2ToType1FontName(face, wmode, *data->FontNameBase))) {
4a48add
+        g_free (data);
4a48add
+        pango_fc_font_unlock_face ((PangoFcFont *) font);
4a48add
+        return;
4a48add
+      }
4a48add
+      pango_fc_font_unlock_face ((PangoFcFont *) font);
4a48add
 
4a48add
-    //    printf("DrawString\n");
4a48add
+      PangoFontDescription *desc = pango_font_describe (font);
4a48add
+      data->font_size = pango_font_description_get_size (desc);
4a48add
+      pango_font_description_free (desc);
4a48add
+
4a48add
+      data->key = new nsCStringKey (*data->FontNameBase);
4a48add
+
4a48add
+      g_object_set_qdata_full (G_OBJECT (font), data_quark, data, (GDestroyNotify) ps_pango_font_data_destroy);
4a48add
+    }
4a48add
+
4a48add
+  nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
4a48add
+  nsRenderingContextPS *aContext = ps_renderer->psContext;
4a48add
+  nsFontMetricsPSPango *metrics = ps_renderer->psPangoFontMetrics;
4a48add
+  nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, metrics->GetDeviceContext());
4a48add
+  nsPostScriptObj* psObj = aContext->GetPostScriptObj();
4a48add
+  nsHashtable *psFGList = dc->GetPSFontGeneratorList();
4a48add
+  g_return_if_fail (psFGList);
4a48add
+  nsPSFontGenerator* psFontGen = (nsPSFontGenerator*) psFGList->Get(data->key);
4a48add
+  if (!psFontGen) {
4a48add
+    nsresult rv;
4a48add
+    psFontGen = new nsPangoType1Generator;
4a48add
+    g_return_if_fail (psFontGen);
4a48add
+    rv = ((nsPangoType1Generator*)psFontGen)->Init(font);
4a48add
+    if (NS_FAILED(rv)) {
4a48add
+      delete psFontGen;
4a48add
+      return;
4a48add
+    }
4a48add
+    psFGList->Put(data->key, (void *) psFontGen);
4a48add
+  }
4a48add
+  nscoord font_size = NSToCoordRound (ps_renderer->zoom * data->font_size / PANGO_SCALE);
4a48add
+
4a48add
+  g_return_if_fail (aContext);
4a48add
+  g_return_if_fail (psObj);
4a48add
+
4a48add
+  nscoord aX = NSToCoordRound(ps_renderer->zoom * x / PANGO_SCALE);
4a48add
+  nscoord aY = NSToCoordRound(ps_renderer->zoom * y / PANGO_SCALE);
4a48add
+  psObj->moveto(aX, aY);
4a48add
+
4a48add
+  PRInt32 currSubFont, prevSubFont = -1;
4a48add
+  PRUint32 i;
4a48add
+  PangoGlyphString gl;
4a48add
+
4a48add
+  gl.glyphs = glyphs->glyphs;
4a48add
+  gl.num_glyphs = 0;
4a48add
+  currSubFont = prevSubFont;
4a48add
+  for (i = 0; i < glyphs->num_glyphs; ++i) {
4a48add
+    PangoGlyph glyph = glyphs->glyphs[i].glyph;
4a48add
+
4a48add
+    if (glyph != PANGO_GLYPH_EMPTY)
4a48add
+      currSubFont = psFontGen->AddToGlyphSubset(glyph > 0x0fffffff ? 0 : glyph);
4a48add
+
4a48add
+    if (prevSubFont != currSubFont) {
4a48add
+      if (prevSubFont != -1)
4a48add
+        psObj->show(&gl, ps_renderer->zoom,  psFontGen, prevSubFont);
4a48add
+
4a48add
+      psObj->setfont(*data->FontNameBase, (PRUint32) font_size, currSubFont);
4a48add
+      prevSubFont = currSubFont;
4a48add
+      gl.glyphs = glyphs->glyphs + i;
4a48add
+      gl.num_glyphs = 0;
4a48add
+    }
4a48add
 
4a48add
-    return rv;
4a48add
+    gl.num_glyphs++;
4a48add
+  }
4a48add
+
4a48add
+  if (prevSubFont != -1)
4a48add
+    psObj->show(&gl, ps_renderer->zoom, psFontGen, prevSubFont);
4a48add
 }
4a48add
+#endif
4a48add
+
4a48add
+static void
4a48add
+draw_layout_line (int x, int y,
4a48add
+                  PangoLayoutLine *line,
4a48add
+                  nsFontMetricsPango *fm
4a48add
+                  CONTEXT_AND_SURFACE_ARG_DEF)
4a48add
+{
4a48add
+#ifdef PSPANGO
4a48add
+  PangoRenderer *renderer = get_renderer ();
4a48add
+  nsPSPangoRenderer *ps_renderer = (nsPSPangoRenderer *)renderer;
4a48add
+  ps_renderer->psContext = aContext;
4a48add
+  ps_renderer->psPangoFontMetrics = fm;
4a48add
+  nsDeviceContextPS* dc = NS_REINTERPRET_CAST (nsDeviceContextPS*, fm->GetDeviceContext());
4a48add
+  ps_renderer->zoom = dc->DevUnitsToAppUnits();
4a48add
+
4a48add
+  pango_renderer_draw_layout_line (renderer, line,
4a48add
+                                   NSToCoordRound (x * PANGO_SCALE / ps_renderer->zoom),
4a48add
+                                   NSToCoordRound (y * PANGO_SCALE / ps_renderer->zoom));
4a48add
+#else
4a48add
+    aContext->UpdateGC();
4a48add
+    GdkGC *gc = aContext->GetGC();
4a48add
+    gdk_draw_layout_line(aSurface->GetDrawable(), gc, x, y, line);
4a48add
+    g_object_unref(gc);
4a48add
+#endif
4a48add
+}
4a48add
+
4a48add
 
4a48add
-#ifdef MOZ_MATHML
4a48add
 nsresult
4a48add
-nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
4a48add
-                                       nsBoundingMetrics &aBoundingMetrics,
4a48add
-                                       nsRenderingContextGTK *aContext)
4a48add
+nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
4a48add
+                               nscoord aX, nscoord aY,
4a48add
+                               const nscoord* aSpacing
4a48add
+                               CONTEXT_AND_SURFACE_ARG_DEF)
4a48add
 {
4a48add
-    printf("GetBoundingMetrics (char *)\n");
4a48add
-    return NS_ERROR_FAILURE;
4a48add
+    int x = aX;
4a48add
+    int y = aY;
4a48add
+
4a48add
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
4a48add
+
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
4a48add
+
4a48add
+    ApplySpacing(aString, aLength, line, aSpacing);
4a48add
+    draw_layout_line(x, y, line, this CONTEXT_AND_SURFACE_ARG_PASS);
4a48add
+
4a48add
+    g_object_unref(layout);
4a48add
+
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
-nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
4a48add
-                                       PRUint32 aLength,
4a48add
-                                       nsBoundingMetrics &aBoundingMetrics,
4a48add
-                                       PRInt32 *aFontID,
4a48add
-                                       nsRenderingContextGTK *aContext)
4a48add
+nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
4a48add
+                               nscoord aX, nscoord aY,
4a48add
+                               PRInt32 aFontID,
4a48add
+                               const nscoord* aSpacing
4a48add
+                               CONTEXT_AND_SURFACE_ARG_DEF)
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
+    int x = aX;
4a48add
+    int y = aY;
4a48add
 
4a48add
-    gchar *text = g_utf16_to_utf8(aString, aLength,
4a48add
-                                  NULL, NULL, NULL);
4a48add
+    aContext->GetTranMatrix()->TransformCoord(&x, &y);
4a48add
 
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetBoundingMetrics invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aString, aLength)
4a48add
-#endif
4a48add
-        aBoundingMetrics.Clear();
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
4a48add
 
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
+    ApplySpacing(aString, aLength, line, aSpacing);
4a48add
+    draw_layout_line(x, y, line, this CONTEXT_AND_SURFACE_ARG_PASS);
4a48add
 
4a48add
-    pango_layout_set_text(layout, text, -1);
4a48add
-    FixupSpaceWidths(layout, text);
4a48add
+    g_object_unref(layout);
4a48add
+
4a48add
+    return NS_OK;
4a48add
+}
4a48add
 
4a48add
-    PangoLayoutLine *line;
4a48add
-    if (pango_layout_get_line_count(layout) != 1) {
4a48add
-        printf("Warning: more than one line!\n");
4a48add
-    }
4a48add
-    line = pango_layout_get_line(layout, 0);
4a48add
+
4a48add
+#ifdef MOZ_MATHML
4a48add
+void
4a48add
+nsFontMetricsPango::GetBoundingMetricsInternal(PangoLayout *aLayout,
4a48add
+                                               nsBoundingMetrics &aBoundingMetrics
4a48add
+                                               CONTEXT_ARG_DEF)
4a48add
+{
4a48add
+    PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
4a48add
 
4a48add
     // Get the ink and logical extents
4a48add
     PangoRectangle ink, logical;
4a48add
     pango_layout_line_get_extents(line, &ink, &logical);
4a48add
 
4a48add
-    float P2T;
4a48add
-    P2T = mDeviceContext->DevUnitsToAppUnits();
4a48add
+    float P2T = mDeviceContext->DevUnitsToAppUnits();
4a48add
 
4a48add
     aBoundingMetrics.leftBearing  = NSToCoordRound(PANGO_LBEARING(ink) * P2T / PANGO_SCALE);
4a48add
     aBoundingMetrics.rightBearing = NSToCoordRound(PANGO_RBEARING(ink) * P2T / PANGO_SCALE);
4a48add
     aBoundingMetrics.ascent       = NSToCoordRound(PANGO_ASCENT(ink)   * P2T / PANGO_SCALE);
4a48add
     aBoundingMetrics.descent      = NSToCoordRound(PANGO_DESCENT(ink)  * P2T / PANGO_SCALE);
4a48add
     aBoundingMetrics.width        = NSToCoordRound(logical.width       * P2T / PANGO_SCALE);
4a48add
+}
4a48add
 
4a48add
- loser:
4a48add
-    g_free(text);
4a48add
+nsresult
4a48add
+nsFontMetricsPango::GetBoundingMetrics(const char *aString, PRUint32 aLength,
4a48add
+                                       nsBoundingMetrics &aBoundingMetrics
4a48add
+                                       CONTEXT_ARG_DEF)
4a48add
+{
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
+    GetBoundingMetricsInternal (layout, aBoundingMetrics CONTEXT_ARG_PASS);
4a48add
     g_object_unref(layout);
4a48add
 
4a48add
-    return rv;
4a48add
+   return NS_OK;
4a48add
+}
4a48add
+
4a48add
+nsresult
4a48add
+nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
4a48add
+                                       PRUint32 aLength,
4a48add
+                                       nsBoundingMetrics &aBoundingMetrics,
4a48add
+                                       PRInt32 *aFontID
4a48add
+                                       CONTEXT_ARG_DEF)
4a48add
+{
4a48add
+    PangoLayout *layout = GetLayout(aString, aLength);
4a48add
+    GetBoundingMetricsInternal (layout, aBoundingMetrics CONTEXT_ARG_PASS);
4a48add
+    g_object_unref(layout);
4a48add
+
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 #endif /* MOZ_MATHML */
4a48add
 
4a48add
+#ifndef PSPANGO
4a48add
 GdkFont*
4a48add
 nsFontMetricsPango::GetCurrentGDKFont(void)
4a48add
 {
4a48add
     return nsnull;
4a48add
 }
4a48add
+#endif
4a48add
 
4a48add
 nsresult
4a48add
 nsFontMetricsPango::SetRightToLeftText(PRBool aIsRTL)
4a48add
 {
4a48add
     if (aIsRTL) {
4a48add
         if (!mRTLPangoContext) {
4a48add
-            mRTLPangoContext = gdk_pango_context_get();
4a48add
+            mRTLPangoContext = get_context();
4a48add
             pango_context_set_base_dir(mRTLPangoContext, PANGO_DIRECTION_RTL);
4a48add
-
4a48add
-            gdk_pango_context_set_colormap(mRTLPangoContext, gdk_rgb_get_cmap());
4a48add
             pango_context_set_language(mRTLPangoContext, GetPangoLanguage(mLangGroup));
4a48add
             pango_context_set_font_description(mRTLPangoContext, mPangoFontDesc);
4a48add
         }
4a48add
@@ -899,34 +1087,18 @@ nsFontMetricsPango::GetClusterInfo(const
4a48add
                                    PRUint32 aLength,
4a48add
                                    PRUint8 *aClusterStarts)
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
     PangoLogAttr *attrs = NULL;
4a48add
     gint n_attrs = 0;
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
-    
4a48add
-    // Convert the incoming UTF-16 to UTF-8
4a48add
-    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
4a48add
 
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aText, aLength)
4a48add
-#endif
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
-
4a48add
-    // Set up the pango layout
4a48add
-    pango_layout_set_text(layout, text, strlen(text));
4a48add
-    FixupSpaceWidths(layout, text);
4a48add
+    PangoLayout *layout = GetLayout(aText, aLength);
4a48add
+    pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
4a48add
+    g_object_unref(layout);
4a48add
 
4a48add
     // Convert back to UTF-16 while filling in the cluster info
4a48add
     // structure.
4a48add
-    pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
4a48add
-
4a48add
     for (PRUint32 pos = 0; pos < aLength; pos++) {
4a48add
         if (IS_HIGH_SURROGATE(aText[pos])) {
4a48add
-            aClusterStarts[pos] = 1;
4a48add
+            aClusterStarts[pos] = 1;//FIXME: shouldn't this be zero?! --be
4a48add
             pos++;
4a48add
         }
4a48add
         else {
4a48add
@@ -934,56 +1106,34 @@ nsFontMetricsPango::GetClusterInfo(const
4a48add
         }
4a48add
     }
4a48add
 
4a48add
- loser:
4a48add
-    if (attrs)
4a48add
-        g_free(attrs);
4a48add
-    if (text)
4a48add
-        g_free(text);
4a48add
-    if (layout)
4a48add
-        g_object_unref(layout);
4a48add
+    g_free(attrs);
4a48add
 
4a48add
-    return rv;
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 PRInt32
4a48add
-nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength,
4a48add
-                                nsPoint aPt)
4a48add
+nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength, nsPoint aPt)
4a48add
 {
4a48add
     int trailing = 0;
4a48add
     int inx = 0;
4a48add
-    const gchar *curChar;
4a48add
     PRInt32 retval = 0;
4a48add
 
4a48add
     float f = mDeviceContext->AppUnitsToDevUnits();
4a48add
     
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
     PRUint32 localX = (PRUint32)(aPt.x * PANGO_SCALE * f);
4a48add
     PRUint32 localY = (PRUint32)(aPt.y * PANGO_SCALE * f);
4a48add
 
4a48add
-    // Convert the incoming UTF-16 to UTF-8
4a48add
-    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
4a48add
-
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aText, aLength)
4a48add
-#endif
4a48add
-        retval = -1;
4a48add
-        goto loser;
4a48add
-    }
4a48add
-
4a48add
-    // Set up the pango layout
4a48add
-    pango_layout_set_text(layout, text, strlen(text));
4a48add
-    FixupSpaceWidths(layout, text);
4a48add
+    PangoLayout *layout = GetLayout(aText, aLength);
4a48add
     
4a48add
     pango_layout_xy_to_index(layout, localX, localY,
4a48add
                              &inx, &trailing);
4a48add
 
4a48add
     // Convert the index back to the utf-16 index
4a48add
-    curChar = text;
4a48add
+    const gchar *text = pango_layout_get_text (layout);
4a48add
+    const gchar *curChar = text;
4a48add
 
4a48add
     for (PRUint32 curOffset=0; curOffset < aLength;
4a48add
-         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
4a48add
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
4a48add
 
4a48add
         // Check for a match before checking for a surrogate pair
4a48add
         if (curChar - text == inx) {
4a48add
@@ -1006,13 +1156,9 @@ nsFontMetricsPango::GetPosition(const PR
4a48add
         trailing--;
4a48add
     }
4a48add
 
4a48add
- loser:
4a48add
-    if (text)
4a48add
-        g_free(text);
4a48add
-    if (layout)
4a48add
-        g_object_unref(layout);
4a48add
+    g_object_unref(layout);
4a48add
 
4a48add
-    return retval;
4a48add
+    return retval; 
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
@@ -1022,28 +1168,21 @@ nsFontMetricsPango::GetRangeWidth(const 
4a48add
                                   PRUint32 aEnd,
4a48add
                                   PRUint32 &aWidth)
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
     PRUint32 utf8Start = 0;
4a48add
     PRUint32 utf8End = 0;
4a48add
 
4a48add
     aWidth = 0;
4a48add
 
4a48add
     // Convert the incoming UTF-16 to UTF-8
4a48add
-    gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
4a48add
-    gchar *curChar = text;
4a48add
 
4a48add
-    if (!text) {
4a48add
-#ifdef DEBUG
4a48add
-        NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
4a48add
-        DUMP_PRUNICHAR(aText, aLength)
4a48add
-#endif
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
+    gchar* text;
4a48add
+    gint text_len;
4a48add
+    utf16_to_utf8 (aText, aLength, text, text_len);
4a48add
+    gchar *curChar = text;
4a48add
 
4a48add
     // Convert the utf16 offsets into utf8 offsets
4a48add
     for (PRUint32 curOffset = 0; curOffset < aLength;
4a48add
-         curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
4a48add
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
4a48add
 
4a48add
         if (curOffset == aStart)
4a48add
             utf8Start = curChar - text;
4a48add
@@ -1057,15 +1196,13 @@ nsFontMetricsPango::GetRangeWidth(const 
4a48add
 
4a48add
     // Special case where the end index is the same as the length
4a48add
     if (aLength == aEnd)
4a48add
-        utf8End = strlen(text);
4a48add
+        utf8End = text_len;
4a48add
 
4a48add
-    rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth);
4a48add
+    GetRangeWidth(text, text_len, utf8Start, utf8End, aWidth);
4a48add
 
4a48add
- loser:
4a48add
-    if (text)
4a48add
-        g_free(text);
4a48add
+    g_free(text);
4a48add
 
4a48add
-    return rv;
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
@@ -1075,43 +1212,26 @@ nsFontMetricsPango::GetRangeWidth(const 
4a48add
                                   PRUint32 aEnd,
4a48add
                                   PRUint32 &aWidth)
4a48add
 {
4a48add
-    nsresult rv = NS_OK;
4a48add
     int *ranges = NULL;
4a48add
     int n_ranges = 0;
4a48add
     float f;
4a48add
 
4a48add
     aWidth = 0;
4a48add
 
4a48add
-    PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
-
4a48add
-    if (!aText) {
4a48add
-        rv = NS_ERROR_FAILURE;
4a48add
-        goto loser;
4a48add
-    }
4a48add
-
4a48add
-    pango_layout_set_text(layout, aText, aLength);
4a48add
-    FixupSpaceWidths(layout, aText);
4a48add
-
4a48add
-    PangoLayoutLine *line;
4a48add
-    if (pango_layout_get_line_count(layout) != 1) {
4a48add
-        printf("Warning: more than one line!\n");
4a48add
-    }
4a48add
-    line = pango_layout_get_line(layout, 0);
4a48add
+    PangoLayout *layout = GetLayout(aText, aLength);
4a48add
+    PangoLayoutLine *line = pango_layout_get_line(layout, 0);
4a48add
 
4a48add
     pango_layout_line_get_x_ranges(line, aStart, aEnd, &ranges, &n_ranges);
4a48add
 
4a48add
     aWidth = (ranges[((n_ranges - 1) * 2) + 1] - ranges[0]);
4a48add
 
4a48add
     f = mDeviceContext-> DevUnitsToAppUnits();
4a48add
-    aWidth = nscoord(aWidth * f / PANGO_SCALE);
4a48add
+    aWidth = NSToCoordRound(aWidth * f / PANGO_SCALE);
4a48add
 
4a48add
- loser:
4a48add
-    if (ranges)
4a48add
-        g_free(ranges);
4a48add
-    if (layout)
4a48add
-        g_object_unref(layout);
4a48add
+    g_free(ranges);
4a48add
+    g_object_unref(layout);
4a48add
 
4a48add
-    return rv;
4a48add
+    return NS_OK;
4a48add
 }
4a48add
 
4a48add
 /* static */
4a48add
@@ -1134,7 +1254,7 @@ nsFontMetricsPango::FamilyExists(nsIDevi
4a48add
     NS_ConvertUTF16toUTF8 name(aName);
4a48add
 
4a48add
     nsresult rv = NS_ERROR_FAILURE;
4a48add
-    PangoContext *context = gdk_pango_context_get();
4a48add
+    PangoContext *context = get_context();
4a48add
     PangoFontFamily **familyList;
4a48add
     int n;
4a48add
 
4a48add
@@ -1233,16 +1353,13 @@ nsFontMetricsPango::RealizeFont(void)
4a48add
 
4a48add
     // Now that we have the font description set up, create the
4a48add
     // context.
4a48add
-    mLTRPangoContext = gdk_pango_context_get();
4a48add
+    mLTRPangoContext = get_context();
4a48add
     mPangoContext = mLTRPangoContext;
4a48add
 
4a48add
     // Make sure to set the base direction to LTR - if layout needs to
4a48add
     // render RTL text it will use ::SetRightToLeftText()
4a48add
     pango_context_set_base_dir(mPangoContext, PANGO_DIRECTION_LTR);
4a48add
 
4a48add
-    // Set the color map so we can draw later.
4a48add
-    gdk_pango_context_set_colormap(mPangoContext, gdk_rgb_get_cmap());
4a48add
-
4a48add
     // Set the pango language now that we have a context
4a48add
     pango_context_set_language(mPangoContext, GetPangoLanguage(mLangGroup));
4a48add
 
4a48add
@@ -1280,79 +1397,268 @@ nsFontMetricsPango::EnumFontCallback(con
4a48add
  * This is only used when there's per-character spacing happening.
4a48add
  * Well, really it can be either line or character spacing but it's
4a48add
  * just turtles all the way down!
4a48add
+ *
4a48add
+ * To do it correctly (ligatures, etc) we need machinery that is private
4a48add
+ * in Pango.  IMPORT IT:
4a48add
+ */
4a48add
+
4a48add
+#define _PangoGlyphItemIter _nsFontMetricsPangoGlyphItemIter
4a48add
+#define PangoGlyphItemIter nsFontMetricsPangoGlyphItemIter
4a48add
+
4a48add
+#define LTR(glyph_item) (((glyph_item)->item->analysis.level % 2) == 0)
4a48add
+
4a48add
+/* Structure holding state when we're iterating over a GlyphItem.
4a48add
+ * start_index/cluster_end (and range_start/range_end in
4a48add
+ * apply_attrs()) are offsets into the text, so note the difference
4a48add
+ * of glyph_item->item->offset between them and clusters in the
4a48add
+ * log_clusters[] array.
4a48add
  */
4a48add
+typedef struct _PangoGlyphItemIter PangoGlyphItemIter;
4a48add
+
4a48add
+struct _PangoGlyphItemIter
4a48add
+{
4a48add
+  PangoGlyphItem *glyph_item;
4a48add
+  const gchar *text;
4a48add
+  
4a48add
+  int start_glyph;
4a48add
+  int start_index;
4a48add
+  int start_char;
4a48add
+
4a48add
+  int end_glyph;
4a48add
+  int end_index;
4a48add
+  int end_char;
4a48add
+};
4a48add
+
4a48add
+/**
4a48add
+ * _pango_glyph_item_iter_next_cluster:
4a48add
+ * @iter: a #PangoGlyphItemIter
4a48add
+ * 
4a48add
+ * Advances the iterator to the next cluster in the glyph item.
4a48add
+ * 
4a48add
+ * Return value: %TRUE if the iterator was advanced, %FALSE if we were already on the
4a48add
+ *  last cluster.
4a48add
+ **/
4a48add
+static gboolean
4a48add
+_pango_glyph_item_iter_next_cluster (PangoGlyphItemIter *iter)
4a48add
+{
4a48add
+  int glyph_index = iter->end_glyph;
4a48add
+  PangoGlyphString *glyphs = iter->glyph_item->glyphs;
4a48add
+  PangoItem *item = iter->glyph_item->item;
4a48add
+
4a48add
+  if (LTR (iter->glyph_item))
4a48add
+    {
4a48add
+      if (glyph_index == glyphs->num_glyphs)
4a48add
+	return FALSE;
4a48add
+    }
4a48add
+  else
4a48add
+    {
4a48add
+      if (glyph_index < 0)
4a48add
+	return FALSE;
4a48add
+    }
4a48add
+      
4a48add
+  iter->start_glyph = iter->end_glyph;
4a48add
+  iter->start_index = iter->end_index;
4a48add
+  iter->start_char = iter->end_char;
4a48add
+  
4a48add
+  if (LTR (iter->glyph_item))
4a48add
+    {
4a48add
+      while (TRUE)
4a48add
+	{
4a48add
+	  glyph_index++;
4a48add
+	  
4a48add
+	  if (glyph_index == glyphs->num_glyphs)
4a48add
+	    {
4a48add
+	      iter->end_index = item->offset + item->length;
4a48add
+	      iter->end_char = item->num_chars;
4a48add
+	      break;
4a48add
+	    }
4a48add
+	  
4a48add
+	  if (item->offset + glyphs->log_clusters[glyph_index] != iter->start_index)
4a48add
+	    {
4a48add
+	      iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
4a48add
+	      iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
4a48add
+					       iter->end_index - iter->start_index);
4a48add
+	      break; 
4a48add
+	    }
4a48add
+	}
4a48add
+    }
4a48add
+  else			/* RTL */
4a48add
+    {
4a48add
+      while (TRUE)
4a48add
+	{
4a48add
+	  glyph_index--;
4a48add
+	  
4a48add
+	  if (glyph_index < 0)
4a48add
+	    {
4a48add
+	      iter->end_index = item->offset + item->length;
4a48add
+	      iter->end_char = item->num_chars;
4a48add
+	      break;
4a48add
+	    }
4a48add
+	  
4a48add
+	  if (item->offset + glyphs->log_clusters[glyph_index] != iter->start_index)
4a48add
+	    {
4a48add
+	      iter->end_index = item->offset + glyphs->log_clusters[glyph_index];
4a48add
+	      iter->end_char += g_utf8_strlen (iter->text + iter->start_index,
4a48add
+					       iter->end_index - iter->start_index);
4a48add
+	      break; 
4a48add
+	    }
4a48add
+	}
4a48add
+    }
4a48add
+
4a48add
+  iter->end_glyph = glyph_index;
4a48add
+  return TRUE;
4a48add
+}
4a48add
+
4a48add
+/**
4a48add
+ * _pango_glyph_item_iter_init_start:
4a48add
+ * @iter: pointer to a #PangoGlyphItemIter structure
4a48add
+ * @glyph_item: the glyph item that the iter points into
4a48add
+ * @text: text corresponding to the glyph item
4a48add
+ * 
4a48add
+ * Initializes a #PangoGlyphItemIter structure to point to the
4a48add
+ * first cluster in a glyph item.
4a48add
+ * 
4a48add
+ * Return value: %FALSE if there are no clusters in the glyph item;
4a48add
+ *  in this case, the state of the iter is undefined.
4a48add
+ **/
4a48add
+static gboolean
4a48add
+_pango_glyph_item_iter_init_start (PangoGlyphItemIter  *iter,
4a48add
+				   PangoGlyphItem      *glyph_item,
4a48add
+				   const char          *text)
4a48add
+{
4a48add
+  iter->glyph_item = glyph_item;
4a48add
+  iter->text = text;
4a48add
+  
4a48add
+  if (LTR (glyph_item))
4a48add
+    iter->end_glyph = 0;
4a48add
+  else
4a48add
+    iter->end_glyph = glyph_item->glyphs->num_glyphs - 1;
4a48add
+
4a48add
+  iter->end_index = glyph_item->item->offset;
4a48add
+  iter->end_char = 0;
4a48add
+
4a48add
+  /* Advance onto the first cluster of the glyph item */
4a48add
+  return _pango_glyph_item_iter_next_cluster (iter);
4a48add
+}
4a48add
+
4a48add
 
4a48add
 void
4a48add
-nsFontMetricsPango::DrawStringSlowly(const gchar *aText,
4a48add
-                                     const PRUnichar *aOrigString,
4a48add
-                                     PRUint32 aLength,
4a48add
-                                     GdkDrawable *aDrawable,
4a48add
-                                     GdkGC *aGC, gint aX, gint aY,
4a48add
-                                     PangoLayoutLine *aLine,
4a48add
-                                     const nscoord *aSpacing)
4a48add
-{
4a48add
-    float app2dev;
4a48add
-    app2dev = mDeviceContext->AppUnitsToDevUnits();
4a48add
-    gint offset = 0;
4a48add
+nsFontMetricsPango::ApplySpacing(const gchar *aText,
4a48add
+                                 PRUint32 aLength,
4a48add
+                                 PangoLayoutLine *aLine,
4a48add
+                                 const nscoord *aSpacing)
4a48add
+{
4a48add
+    if (!(aSpacing && *aSpacing))
4a48add
+      return;
4a48add
+
4a48add
+    float app2dev = mDeviceContext->AppUnitsToDevUnits();
4a48add
 
4a48add
     /*
4a48add
      * We walk the list of glyphs returned in each layout run,
4a48add
      * matching up the glyphs with the characters in the source text.
4a48add
      * We use the aSpacing argument to figure out where to place those
4a48add
-     * glyphs.  It's important to note that since the string we're
4a48add
-     * working with is in UTF-8 while the spacing argument assumes
4a48add
-     * that offset will be part of the UTF-16 string.  Logical
4a48add
-     * attributes in pango are in byte offsets in the UTF-8 string, so
4a48add
-     * we need to store the offsets based on the UTF-8 string.
4a48add
+     * glyphs.
4a48add
      */
4a48add
-    nscoord *utf8spacing = new nscoord[strlen(aText)];
4a48add
+    for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
4a48add
+         tmpList = tmpList->next) {
4a48add
+        PangoGlyphItem *glyph_item = (PangoGlyphItem *)tmpList->data;
4a48add
+        PangoGlyphItemIter iter;
4a48add
+        gboolean have_cluster;
4a48add
+        PangoGlyphInfo *glyphs = glyph_item->glyphs->glyphs;
4a48add
+        int residualWidth = 0;
4a48add
+
4a48add
+        for (have_cluster = _pango_glyph_item_iter_init_start (&iter, glyph_item, aText);
4a48add
+             have_cluster;
4a48add
+             have_cluster = _pango_glyph_item_iter_next_cluster (&iter))
4a48add
+        {
4a48add
+          int clusterOldWidth = 0;
4a48add
+          int clusterNewWidth = 0;
4a48add
+          int dir = iter.start_glyph < iter.end_glyph ? +1 : -1;
4a48add
+          gboolean has_zero_width = FALSE;
4a48add
+
4a48add
+          for (const char *p = iter.text + iter.start_index;
4a48add
+               p < iter.text + iter.end_index;
4a48add
+               p = g_utf8_next_char (p))
4a48add
+            clusterNewWidth += aSpacing[p - iter.text];
4a48add
+
4a48add
+          clusterNewWidth = (gint)(clusterNewWidth * app2dev * PANGO_SCALE);
4a48add
+
4a48add
+          for (gint i = iter.start_glyph; i != iter.end_glyph; i += dir) {
4a48add
+            if (!glyphs[i].geometry.width)
4a48add
+              has_zero_width = TRUE;
4a48add
+            clusterOldWidth += glyphs[i].geometry.width;
4a48add
+          }
4a48add
+            
4a48add
+          /* if a zero-width glyph exists, don't touch the glyph widths.
4a48add
+           * required for combining marks.  ff thinks they have a width.
4a48add
+           * instead, we charge the difference to the next space glyph. */
4a48add
+          if (has_zero_width) {
4a48add
+            residualWidth += clusterNewWidth - clusterOldWidth;
4a48add
+            continue;
4a48add
+          }
4a48add
 
4a48add
-    if (aOrigString) {
4a48add
-        const gchar *curChar = aText;
4a48add
-        bzero(utf8spacing, sizeof(nscoord) * strlen(aText));
4a48add
-
4a48add
-        // Covert the utf16 spacing offsets to utf8 spacing offsets
4a48add
-        for (PRUint32 curOffset=0; curOffset < aLength;
4a48add
-             curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
4a48add
-            utf8spacing[curChar - aText] = aSpacing[curOffset];
4a48add
+          /* If a space glyph is found, charge it whatever residual we
4a48add
+           * have accumulated so far. */
4a48add
+          if (iter.end_index - iter.start_index == 1 &&
4a48add
+              *(iter.text + iter.start_index) == ' ') {
4a48add
+            clusterNewWidth += residualWidth;
4a48add
+            residualWidth = 0;
4a48add
+          }
4a48add
+          
4a48add
+#ifndef PSPANGO
4a48add
+          /* do some hinting for display */
4a48add
+
4a48add
+          if (clusterOldWidth % PANGO_SCALE == 0 && clusterNewWidth % PANGO_SCALE != 0) {
4a48add
+            int tmp = clusterNewWidth;
4a48add
+            clusterNewWidth = PANGO_PIXELS (clusterNewWidth) * PANGO_SCALE;
4a48add
+            residualWidth += tmp - clusterNewWidth;
4a48add
+          }
4a48add
+#endif
4a48add
 
4a48add
-            if (IS_HIGH_SURROGATE(aOrigString[curOffset]))
4a48add
-                curOffset++;
4a48add
+          /* find the first non-zero-width glyph and adjust its width */
4a48add
+          for (gint i = iter.start_glyph; i != iter.end_glyph; i += dir)
4a48add
+            if (glyphs[i].geometry.width) {
4a48add
+              glyphs[i].geometry.width += clusterNewWidth - clusterOldWidth;
4a48add
+              break;
4a48add
+            }
4a48add
         }
4a48add
     }
4a48add
-    else {
4a48add
-        memcpy(utf8spacing, aSpacing, (sizeof(nscoord *) * aLength));
4a48add
-    }
4a48add
+}
4a48add
 
4a48add
-    gint curRun = 0;
4a48add
+void
4a48add
+nsFontMetricsPango::ApplySpacing(const PRUnichar *aText,
4a48add
+                                 PRUint32 aLength,
4a48add
+                                 PangoLayoutLine *aLine,
4a48add
+                                 const nscoord *aSpacing)
4a48add
+{
4a48add
+    if (!(aSpacing && *aSpacing))
4a48add
+      return;
4a48add
 
4a48add
-    for (GSList *tmpList = aLine->runs; tmpList && tmpList->data;
4a48add
-         tmpList = tmpList->next, curRun++) {
4a48add
-        PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
4a48add
-        gint tmpOffset = 0;
4a48add
+    const char *utf8Text = pango_layout_get_text (aLine->layout);
4a48add
+    int utf8Text_len = aLine->start_index + aLine->length;
4a48add
 
4a48add
-        /*        printf("    Rendering run %d: \"%s\"\n", curRun,
4a48add
-                  &aText[layoutRun->item->offset]); */
4a48add
+    /* Since the string we're
4a48add
+     * working with is in UTF-8 while the spacing argument assumes
4a48add
+     * that offset will be part of the UTF-16 string.  Logical
4a48add
+     * attributes in pango are in byte offsets in the UTF-8 string, so
4a48add
+     * we need to store the offsets based on the UTF-8 string.
4a48add
+     */
4a48add
+    nscoord *utf8spacing = g_new0 (nscoord, utf8Text_len);
4a48add
 
4a48add
-        for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
4a48add
-            /* printf("glyph %d offset %d orig width %d new width %d\n", i,
4a48add
-             *        layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset,
4a48add
-             *        layoutRun->glyphs->glyphs[i].geometry.width,
4a48add
-             *       (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset] * app2dev * PANGO_SCALE));
4a48add
-             */
4a48add
-            gint thisOffset = (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset]
4a48add
-                                     * app2dev * PANGO_SCALE);
4a48add
-            layoutRun->glyphs->glyphs[i].geometry.width = thisOffset;
4a48add
-            tmpOffset += thisOffset;
4a48add
-        }
4a48add
+    const gchar *curChar = utf8Text + aLine->start_index;
4a48add
 
4a48add
-        /*        printf("    rendering at X coord %d\n", aX + offset); */
4a48add
-        offset += tmpOffset;
4a48add
+    // Covert the utf16 spacing offsets to utf8 spacing offsets
4a48add
+    for (PRUint32 curOffset=0; curOffset < aLength;
4a48add
+         curOffset++, curChar = g_utf8_next_char(curChar)) {
4a48add
+        utf8spacing[curChar - utf8Text] = aSpacing[curOffset];
4a48add
+
4a48add
+        if (IS_HIGH_SURROGATE(aText[curOffset]))
4a48add
+            curOffset++;
4a48add
     }
4a48add
 
4a48add
-    gdk_draw_layout_line(aDrawable, aGC, aX, aY, aLine);
4a48add
+    ApplySpacing (utf8Text, utf8Text_len, aLine, utf8spacing);
4a48add
 
4a48add
-    delete[] utf8spacing;
4a48add
+    g_free (utf8spacing);
4a48add
 }
4a48add
 
4a48add
 nsresult
4a48add
@@ -1363,8 +1669,8 @@ nsFontMetricsPango::GetTextDimensionsInt
4a48add
                                               PRInt32             aNumBreaks,
4a48add
                                               nsTextDimensions&   aDimensions,
4a48add
                                               PRInt32&            aNumCharsFit,
4a48add
-                                              nsTextDimensions&   aLastWordDimensions,
4a48add
-                                              nsRenderingContextGTK *aContext)
4a48add
+                                              nsTextDimensions&   aLastWordDimensions
4a48add
+                                              CONTEXT_ARG_DEF)
4a48add
 {
4a48add
     NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
4a48add
 
4a48add
@@ -1410,7 +1716,7 @@ nsFontMetricsPango::GetTextDimensionsInt
4a48add
             // All the characters should fit
4a48add
             numChars = aLength - start;
4a48add
             breakIndex = aNumBreaks - 1;
4a48add
-        } 
4a48add
+        }
4a48add
         else {
4a48add
             breakIndex = prevBreakState_BreakIndex;
4a48add
             while (((breakIndex + 1) < aNumBreaks) &&
4a48add
@@ -1431,7 +1737,7 @@ nsFontMetricsPango::GetTextDimensionsInt
4a48add
         if ((1 == numChars) && (aString[start] == ' '))
4a48add
             GetSpaceWidth(twWidth);
4a48add
         else if (numChars > 0)
4a48add
-            GetWidth(&aString[start], numChars, twWidth, aContext);
4a48add
+            GetWidth(&aString[start], numChars, twWidth CONTEXT_ARG_PASS);
4a48add
 
4a48add
         // See if the text fits
4a48add
         PRBool  textFits = (twWidth + width) <= aAvailWidth;
4a48add
@@ -1481,8 +1787,7 @@ nsFontMetricsPango::GetTextDimensionsInt
4a48add
                 if ((1 == numChars) && (aString[start] == ' '))
4a48add
                     GetSpaceWidth(twWidth);
4a48add
                 else if (numChars > 0)
4a48add
-                    GetWidth(&aString[start], numChars, twWidth,
4a48add
-                             aContext);
4a48add
+                    GetWidth(&aString[start], numChars, twWidth CONTEXT_ARG_PASS);
4a48add
                 width -= twWidth;
4a48add
                 aNumCharsFit = start;
4a48add
                 breakIndex--;
4a48add
@@ -1504,9 +1809,16 @@ nsFontMetricsPango::GetTextDimensionsInt
4a48add
 }
4a48add
 
4a48add
 void
4a48add
-nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout,
4a48add
-                                      const char *aString)
4a48add
+nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout)
4a48add
 {
4a48add
+    if (!mPangoSpaceWidth)
4a48add
+      return;
4a48add
+
4a48add
+    const char *aString = pango_layout_get_text (aLayout);
4a48add
+
4a48add
+    if (pango_layout_get_line_count(aLayout) != 1) {
4a48add
+        printf("Warning: more than one line!\n");
4a48add
+    }
4a48add
     PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
4a48add
 
4a48add
     gint curRun = 0;
4a48add
@@ -1523,6 +1835,107 @@ nsFontMetricsPango::FixupSpaceWidths (Pa
4a48add
     }
4a48add
 }
4a48add
 
4a48add
+PangoLayout*
4a48add
+nsFontMetricsPango::GetLayout (const PRUnichar* aText,
4a48add
+                               PRUint32         aLength)
4a48add
+{
4a48add
+  gchar* text;
4a48add
+  gint length;
4a48add
+  utf16_to_utf8 (aText, aLength, text, length);
4a48add
+
4a48add
+  PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
+  pango_layout_set_text (layout, text, length);
4a48add
+  FixupSpaceWidths (layout);
4a48add
+
4a48add
+  g_free ((gpointer) text);
4a48add
+
4a48add
+  return layout;
4a48add
+}
4a48add
+
4a48add
+PangoLayout*
4a48add
+nsFontMetricsPango::GetLayout (const gchar*     aText,
4a48add
+                               PRInt32          aLength)
4a48add
+{
4a48add
+  gboolean has_nul = FALSE;
4a48add
+  int i;
4a48add
+
4a48add
+  for (i = 0; i < aLength; i++)
4a48add
+    if (!aText[i]) {
4a48add
+      has_nul = TRUE;
4a48add
+      break;
4a48add
+    }
4a48add
+
4a48add
+  if (has_nul) {
4a48add
+    /* Pango doesn't correctly handle nuls.  We convert them to 0xff. */
4a48add
+
4a48add
+    char *p = (char *) g_memdup (aText, aLength);
4a48add
+
4a48add
+    /* don't need to reset i */
4a48add
+    for (; i < aLength; i++)
4a48add
+      if (!p[i])
4a48add
+        p[i] = (char) 0xff;
4a48add
+
4a48add
+    aText = p;
4a48add
+  }
4a48add
+
4a48add
+  PangoLayout *layout = pango_layout_new(mPangoContext);
4a48add
+  pango_layout_set_text (layout, aText, aLength);
4a48add
+  FixupSpaceWidths (layout);
4a48add
+
4a48add
+  if (has_nul)
4a48add
+    g_free ((gpointer) aText);
4a48add
+
4a48add
+  return layout;
4a48add
+}
4a48add
+
4a48add
+static void
4a48add
+utf16_to_utf8 (const PRUnichar* aText, PRUint32 aLength, char *&text, gint &length)
4a48add
+{
4a48add
+  gboolean need_copy = FALSE;
4a48add
+  int i;
4a48add
+
4a48add
+  for (i = 0; i < aLength; i++) {
4a48add
+    if (!aText[i] || IS_LOW_SURROGATE (aText[i]))
4a48add
+      need_copy = TRUE;
4a48add
+    else if (IS_HIGH_SURROGATE (aText[i])) {
4a48add
+      if (i < aLength - 1 && IS_LOW_SURROGATE (aText[i+1]))
4a48add
+        i++;
4a48add
+      else
4a48add
+        need_copy = TRUE;
4a48add
+    }
4a48add
+  }
4a48add
+
4a48add
+  if (need_copy) {
4a48add
+
4a48add
+    /* Pango doesn't correctly handle nuls.  We convert them to 0xff. */
4a48add
+    /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
4a48add
+
4a48add
+    PRUnichar *p = (PRUnichar *) g_memdup (aText, aLength * sizeof (aText[0]));
4a48add
+
4a48add
+    /* don't need to reset i */
4a48add
+    for (i = 0; i < aLength; i++) {
4a48add
+      if (!p[i] || IS_LOW_SURROGATE (p[i]))
4a48add
+        p[i] = 0xFFFD;
4a48add
+      else if (IS_HIGH_SURROGATE (p[i])) {
4a48add
+        if (i < aLength - 1 && IS_LOW_SURROGATE (aText[i+1]))
4a48add
+          i++;
4a48add
+        else
4a48add
+          p[i] = 0xFFFD;
4a48add
+      }
4a48add
+    }
4a48add
+
4a48add
+    aText = p;
4a48add
+  }
4a48add
+
4a48add
+  glong items_written;
4a48add
+  text = g_utf16_to_utf8 (aText, aLength, NULL, &items_written, NULL);
4a48add
+  length = items_written;
4a48add
+
4a48add
+  if (need_copy)
4a48add
+    g_free ((gpointer) aText);
4a48add
+
4a48add
+}
4a48add
+
4a48add
 /* static */
4a48add
 PangoLanguage *
4a48add
 GetPangoLanguage(nsIAtom *aLangGroup)
4a48add
--- mozilla.back/gfx/src/gtk/nsFontMetricsPango.h.orig	2006-06-30 01:18:34.000000000 +0200
4a48add
+++ mozilla.back/gfx/src/gtk/nsFontMetricsPango.h	2007-06-28 15:16:39.000000000 +0200
4a48add
@@ -37,17 +37,53 @@
4a48add
  *
4a48add
  * ***** END LICENSE BLOCK ***** */
4a48add
 
4a48add
+
4a48add
 #include "nsIFontMetrics.h"
4a48add
 #include "nsIFontEnumerator.h"
4a48add
 #include "nsCRT.h"
4a48add
 #include "nsIAtom.h"
4a48add
 #include "nsString.h"
4a48add
 #include "nsVoidArray.h"
4a48add
+
4a48add
+#ifdef PSPANGO
4a48add
+#include "nsFontMetricsPS.h"
4a48add
+#else
4a48add
 #include "nsIFontMetricsGTK.h"
4a48add
+#endif
4a48add
 
4a48add
 #include <pango/pango.h>
4a48add
 
4a48add
-class nsFontMetricsPango : public nsIFontMetricsGTK
4a48add
+#ifdef PSPANGO
4a48add
+
4a48add
+#define CONTEXT_ARG_DEF
4a48add
+#define CONTEXT_ARG_PASS
4a48add
+#define CONTEXT_ARG_NULL
4a48add
+#define CONTEXT_AND_SURFACE_ARG_DEF  , nsRenderingContextPS *aContext
4a48add
+#define CONTEXT_AND_SURFACE_ARG_PASS , aContext
4a48add
+
4a48add
+#else
4a48add
+
4a48add
+#define CONTEXT_ARG_DEF              , nsRenderingContextGTK *aContext
4a48add
+#define CONTEXT_ARG_PASS             , aContext
4a48add
+#define CONTEXT_ARG_NULL             , NULL
4a48add
+#define CONTEXT_AND_SURFACE_ARG_DEF  , nsRenderingContextGTK *aContext, nsDrawingSurfaceGTK *aSurface
4a48add
+#define CONTEXT_AND_SURFACE_ARG_PASS , aContext, aSurface
4a48add
+
4a48add
+#endif
4a48add
+
4a48add
+
4a48add
+#ifdef PSPANGO
4a48add
+
4a48add
+#define nsFontMetricsPango   nsFontMetricsPSPango
4a48add
+#define PSPANGO_PARENT_CLASS nsFontMetricsPS
4a48add
+
4a48add
+#else
4a48add
+
4a48add
+#define PSPANGO_PARENT_CLASS nsIFontMetricsGTK
4a48add
+
4a48add
+#endif
4a48add
+
4a48add
+class nsFontMetricsPango : public PSPANGO_PARENT_CLASS
4a48add
 {
4a48add
 public:
4a48add
     nsFontMetricsPango();
4a48add
@@ -136,20 +172,30 @@ public:
4a48add
 
4a48add
     PRInt32 GetMaxStringLength() { return mMaxStringLength; }
4a48add
 
4a48add
-    // nsIFontMetricsGTK (calls from the font rendering layer)
4a48add
-    virtual nsresult GetWidth(const char* aString, PRUint32 aLength,
4a48add
-                              nscoord& aWidth,
4a48add
-                              nsRenderingContextGTK *aContext);
4a48add
-    virtual nsresult GetWidth(const PRUnichar* aString, PRUint32 aLength,
4a48add
-                              nscoord& aWidth, PRInt32 *aFontID,
4a48add
-                              nsRenderingContextGTK *aContext);
4a48add
+    // nsIFontMetrics (calls from the font rendering layer)
4a48add
 
4a48add
-    virtual nsresult GetTextDimensions(const PRUnichar* aString,
4a48add
+#ifdef PSPANGO
4a48add
+    NS_IMETHOD  GetStringWidth(const char *String,nscoord &aWidth,nscoord aLength);
4a48add
+    NS_IMETHOD  GetStringWidth(const PRUnichar *aString,nscoord &aWidth,nscoord aLength);
4a48add
+#endif
4a48add
+
4a48add
+    NS_METHOD        GetWidth(const char* aString, PRUint32 aLength,
4a48add
+                              nscoord& aWidth
4a48add
+                              CONTEXT_ARG_DEF);
4a48add
+    NS_METHOD        GetWidth(const PRUnichar* aString, PRUint32 aLength,
4a48add
+                              nscoord& aWidth, PRInt32 *aFontID
4a48add
+                              CONTEXT_ARG_DEF);
4a48add
+
4a48add
+    NS_METHOD        GetTextDimensions(const char* aString,
4a48add
+                                       PRUint32 aLength,
4a48add
+                                       nsTextDimensions& aDimensions
4a48add
+                                       CONTEXT_ARG_DEF);
4a48add
+    NS_METHOD        GetTextDimensions(const PRUnichar* aString,
4a48add
                                        PRUint32 aLength,
4a48add
                                        nsTextDimensions& aDimensions, 
4a48add
-                                       PRInt32* aFontID,
4a48add
-                                       nsRenderingContextGTK *aContext);
4a48add
-    virtual nsresult GetTextDimensions(const char*         aString,
4a48add
+                                       PRInt32* aFontID
4a48add
+                                       CONTEXT_ARG_DEF);
4a48add
+    NS_METHOD        GetTextDimensions(const char*         aString,
4a48add
                                        PRInt32             aLength,
4a48add
                                        PRInt32             aAvailWidth,
4a48add
                                        PRInt32*            aBreaks,
4a48add
@@ -157,9 +203,9 @@ public:
4a48add
                                        nsTextDimensions&   aDimensions,
4a48add
                                        PRInt32&            aNumCharsFit,
4a48add
                                        nsTextDimensions&   aLastWordDimensions,
4a48add
-                                       PRInt32*            aFontID,
4a48add
-                                       nsRenderingContextGTK *aContext);
4a48add
-    virtual nsresult GetTextDimensions(const PRUnichar*    aString,
4a48add
+                                       PRInt32*            aFontID
4a48add
+                                       CONTEXT_ARG_DEF);
4a48add
+    NS_METHOD        GetTextDimensions(const PRUnichar*    aString,
4a48add
                                        PRInt32             aLength,
4a48add
                                        PRInt32             aAvailWidth,
4a48add
                                        PRInt32*            aBreaks,
4a48add
@@ -167,38 +213,37 @@ public:
4a48add
                                        nsTextDimensions&   aDimensions,
4a48add
                                        PRInt32&            aNumCharsFit,
4a48add
                                        nsTextDimensions&   aLastWordDimensions,
4a48add
-                                       PRInt32*            aFontID,
4a48add
-                                       nsRenderingContextGTK *aContext);
4a48add
+                                       PRInt32*            aFontID
4a48add
+                                       CONTEXT_ARG_DEF);
4a48add
 
4a48add
-    virtual nsresult DrawString(const char *aString, PRUint32 aLength,
4a48add
+    NS_METHOD        DrawString(const char *aString, PRUint32 aLength,
4a48add
                                 nscoord aX, nscoord aY,
4a48add
-                                const nscoord* aSpacing,
4a48add
-                                nsRenderingContextGTK *aContext,
4a48add
-                                nsDrawingSurfaceGTK *aSurface);
4a48add
-    virtual nsresult DrawString(const PRUnichar* aString, PRUint32 aLength,
4a48add
+                                const nscoord* aSpacing  
4a48add
+                                CONTEXT_AND_SURFACE_ARG_DEF);
4a48add
+
4a48add
+    NS_METHOD        DrawString(const PRUnichar* aString, PRUint32 aLength,
4a48add
                                 nscoord aX, nscoord aY,
4a48add
                                 PRInt32 aFontID,
4a48add
-                                const nscoord* aSpacing,
4a48add
-                                nsRenderingContextGTK *aContext,
4a48add
-                                nsDrawingSurfaceGTK *aSurface);
4a48add
+                                const nscoord* aSpacing  
4a48add
+                                CONTEXT_AND_SURFACE_ARG_DEF);
4a48add
 
4a48add
 #ifdef MOZ_MATHML
4a48add
-    virtual nsresult GetBoundingMetrics(const char *aString, PRUint32 aLength,
4a48add
-                                        nsBoundingMetrics &aBoundingMetrics,
4a48add
-                                        nsRenderingContextGTK *aContext);
4a48add
-    virtual nsresult GetBoundingMetrics(const PRUnichar *aString,
4a48add
+    NS_METHOD        GetBoundingMetrics(const char *aString, PRUint32 aLength,
4a48add
+                                        nsBoundingMetrics &aBoundingMetrics
4a48add
+                                        CONTEXT_ARG_DEF);
4a48add
+    NS_METHOD        GetBoundingMetrics(const PRUnichar *aString,
4a48add
                                         PRUint32 aLength,
4a48add
                                         nsBoundingMetrics &aBoundingMetrics,
4a48add
-                                        PRInt32 *aFontID,
4a48add
-                                        nsRenderingContextGTK *aContext);
4a48add
+                                        PRInt32 *aFontID
4a48add
+                                        CONTEXT_ARG_DEF);
4a48add
 #endif /* MOZ_MATHML */
4a48add
-
4a48add
+#ifndef PSPANGO
4a48add
     virtual GdkFont* GetCurrentGDKFont(void);
4a48add
-
4a48add
-    virtual nsresult SetRightToLeftText(PRBool aIsRTL);
4a48add
+#endif
4a48add
     virtual PRBool GetRightToLeftText();
4a48add
-
4a48add
-    virtual nsresult GetClusterInfo(const PRUnichar *aText,
4a48add
+    NS_METHOD        SetRightToLeftText(PRBool aIsRTL);
4a48add
+    
4a48add
+    NS_METHOD        GetClusterInfo(const PRUnichar *aText,
4a48add
                                     PRUint32 aLength,
4a48add
                                     PRUint8 *aClusterStarts);
4a48add
 
4a48add
@@ -206,32 +251,35 @@ public:
4a48add
                                 PRUint32 aLength,
4a48add
                                 nsPoint aPt);
4a48add
 
4a48add
-    virtual nsresult GetRangeWidth(const PRUnichar *aText,
4a48add
+    NS_METHOD        GetRangeWidth(const PRUnichar *aText,
4a48add
                                    PRUint32 aLength,
4a48add
                                    PRUint32 aStart,
4a48add
                                    PRUint32 aEnd,
4a48add
                                    PRUint32 &aWidth);
4a48add
 
4a48add
-    virtual nsresult GetRangeWidth(const char *aText,
4a48add
+    NS_METHOD        GetRangeWidth(const char *aText,
4a48add
                                    PRUint32 aLength,
4a48add
                                    PRUint32 aStart,
4a48add
                                    PRUint32 aEnd,
4a48add
                                    PRUint32 &aWidth);
4a48add
 
4a48add
     // get hints for the font
4a48add
-    static PRUint32    GetHints     (void);
4a48add
+#ifndef PSPANGO
4a48add
+    static
4a48add
+#endif
4a48add
+    PRUint32    GetHints     (void);
4a48add
 
4a48add
     // drawing surface methods
4a48add
     static nsresult FamilyExists    (nsIDeviceContext *aDevice,
4a48add
                                      const nsString &aName);
4a48add
 
4a48add
+
4a48add
 private:
4a48add
 
4a48add
     // generic font metrics class bits
4a48add
     nsCStringArray       mFontList;
4a48add
     nsAutoVoidArray      mFontIsGeneric;
4a48add
 
4a48add
-    nsIDeviceContext    *mDeviceContext;
4a48add
     nsCOMPtr<nsIAtom>    mLangGroup;
4a48add
     nsCString           *mGenericFont;
4a48add
     float                mPointSize;
4a48add
@@ -246,6 +294,9 @@ private:
4a48add
     PangoAttrList        *mPangoAttrList;
4a48add
     PRBool                mIsRTL;
4a48add
 
4a48add
+#ifndef PSPANGO
4a48add
+    nsIDeviceContext    *mDeviceContext; 
4a48add
+
4a48add
     // Cached font metrics
4a48add
     nscoord                  mXHeight;
4a48add
     nscoord                  mSuperscriptOffset;
4a48add
@@ -263,6 +314,7 @@ private:
4a48add
     nscoord                  mMaxDescent;
4a48add
     nscoord                  mMaxAdvance;
4a48add
     nscoord                  mSpaceWidth;
4a48add
+#endif
4a48add
     nscoord                  mPangoSpaceWidth;
4a48add
     nscoord                  mAveCharWidth;
4a48add
     PRInt32                  mMaxStringLength;
4a48add
@@ -274,13 +326,14 @@ private:
4a48add
     static PRBool EnumFontCallback(const nsString &aFamily,
4a48add
                                    PRBool aIsGeneric, void *aData);
4a48add
 
4a48add
-    void     DrawStringSlowly(const gchar *aText,
4a48add
-                              const PRUnichar *aOrigString,
4a48add
-                              PRUint32 aLength,
4a48add
-                              GdkDrawable *aDrawable,
4a48add
-                              GdkGC *aGC, gint aX, gint aY,
4a48add
-                              PangoLayoutLine *aLine,
4a48add
-                              const nscoord *aSpacing);
4a48add
+    void ApplySpacing(const gchar *aText,
4a48add
+                      PRUint32 aLength,
4a48add
+                      PangoLayoutLine *aLine,
4a48add
+                      const nscoord *aSpacing);
4a48add
+    void ApplySpacing(const PRUnichar *aText,
4a48add
+                      PRUint32 aLength,
4a48add
+                      PangoLayoutLine *aLine,
4a48add
+                      const nscoord *aSpacing);
4a48add
 
4a48add
     nsresult GetTextDimensionsInternal(const gchar*        aString,
4a48add
                                        PRInt32             aLength,
4a48add
@@ -289,10 +342,20 @@ private:
4a48add
                                        PRInt32             aNumBreaks,
4a48add
                                        nsTextDimensions&   aDimensions,
4a48add
                                        PRInt32&            aNumCharsFit,
4a48add
-                                       nsTextDimensions&   aLastWordDimensions,
4a48add
-                                       nsRenderingContextGTK *aContext);
4a48add
+                                       nsTextDimensions&   aLastWordDimensions
4a48add
+                                       CONTEXT_ARG_DEF);
4a48add
+#ifdef MOZ_MATHML
4a48add
+    void GetBoundingMetricsInternal(PangoLayout *aLayout,
4a48add
+                                    nsBoundingMetrics &aBoundingMetrics
4a48add
+                                    CONTEXT_ARG_DEF);
4a48add
+#endif /* MOZ_MATHML */
4a48add
+
4a48add
+    void FixupSpaceWidths (PangoLayout *aLayout);
4a48add
 
4a48add
-    void FixupSpaceWidths (PangoLayout *aLayout, const char *aString);
4a48add
+    PangoLayout* GetLayout (const PRUnichar* aText,
4a48add
+                            PRUint32         aLength);
4a48add
+    PangoLayout* GetLayout (const gchar*     aText,
4a48add
+                            PRInt32          aLength);
4a48add
 };
4a48add
 
4a48add
 class nsFontEnumeratorPango : public nsIFontEnumerator