Index: layout/generic/nsTextFrame.cpp
===================================================================
RCS file: /cvsroot/mozilla/layout/generic/nsTextFrame.cpp,v
retrieving revision 1.513
diff -u -r1.513 nsTextFrame.cpp
--- layout/generic/nsTextFrame.cpp	16 Jul 2005 19:58:26 -0000	1.513
+++ layout/generic/nsTextFrame.cpp	2 Aug 2005 00:51:29 -0000
@@ -2948,6 +2948,12 @@
   // context.
   nscolor textColor;
   aRenderingContext.GetColor(textColor);
+  
+  // EXPERIMENTAL: Fix Hebrew layout by "quizzing" platform font renderer
+  // more intelligently. -- Stephen Blackheath
+  PRUnichar* segmentStart = aBuffer;
+  nscoord segmentWidthSoFar = 0;
+
   for (; --aLength >= 0; aBuffer++) {
     nsIFontMetrics* nextFont;
     nscoord glyphWidth = 0;
@@ -2983,6 +2989,8 @@
       }
       aRenderingContext.SetFont(nextFont);
       lastFont = nextFont;
+      segmentStart = aBuffer;
+      segmentWidthSoFar = 0;
     }
     if (nextFont == aTextStyle.mSmallFont) {
       PRUnichar upper_ch;
@@ -3001,16 +3009,25 @@
         width += glyphWidth;
       }
       ch = upper_ch;
+      segmentStart = aBuffer+1;
+      segmentWidthSoFar = 0;
     }
     else if (ch == ' ') {
       glyphWidth += aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing + aTextStyle.mLetterSpacing;
+      segmentStart = aBuffer+1;
+      segmentWidthSoFar = 0;
     }
     else if (IS_HIGH_SURROGATE(ch) && aLength > 0 &&
            IS_LOW_SURROGATE(*(aBuffer+1))) {
-      
+
       // special handling for surrogate pair
-      aRenderingContext.GetWidth(aBuffer, 2, charWidth);
-      glyphWidth += charWidth + aTextStyle.mLetterSpacing;
+      nscoord newSegmentWidth;
+      aRenderingContext.GetWidth(segmentStart, (PRUint32)(aBuffer-segmentStart)+2, newSegmentWidth);
+      charWidth = newSegmentWidth - segmentWidthSoFar;
+      if (charWidth > 0)  {
+        segmentWidthSoFar = newSegmentWidth;
+        glyphWidth += charWidth + aTextStyle.mLetterSpacing;
+      }
       // copy the surrogate low
       *bp++ = ch;
       --aLength;
@@ -3025,8 +3042,13 @@
       glyphWidth = 0;
     }
     else {
-      aRenderingContext.GetWidth(ch, charWidth);
-      glyphWidth += charWidth + aTextStyle.mLetterSpacing;
+      nscoord newSegmentWidth;
+      aRenderingContext.GetWidth(segmentStart, (PRUint32)(aBuffer-segmentStart)+1, newSegmentWidth);
+      charWidth = newSegmentWidth - segmentWidthSoFar;
+      if (charWidth > 0) {
+        segmentWidthSoFar = newSegmentWidth;
+        glyphWidth += charWidth + aTextStyle.mLetterSpacing;
+      }
     }
     if (justifying && (!isEndOfLine || aLength > 0)
         && IsJustifiableCharacter(ch, isCJ)) {
Index: gfx/src/gtk/nsFontMetricsPango.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/gtk/nsFontMetricsPango.cpp,v
retrieving revision 1.16
diff -u -r1.16 nsFontMetricsPango.cpp
--- gfx/src/gtk/nsFontMetricsPango.cpp	26 Jul 2005 00:13:51 -0000	1.16
+++ gfx/src/gtk/nsFontMetricsPango.cpp	2 Aug 2005 00:51:32 -0000
@@ -733,7 +733,7 @@
     aContext->UpdateGC();
     GdkGC *gc = aContext->GetGC();
 
-    if (aSpacing && *aSpacing) {
+    if (aSpacing) {
         DrawStringSlowly(aString, NULL, aLength, aSurface->GetDrawable(),
                          gc, x, y, line, aSpacing);
     }
@@ -791,7 +791,7 @@
     }
     line = pango_layout_get_line(layout, 0);
 
-    if (aSpacing && *aSpacing) {
+    if (aSpacing) {
         DrawStringSlowly(text, aString, aLength, aSurface->GetDrawable(),
                          gc, x, y, line, aSpacing);
     }
@@ -1374,8 +1374,10 @@
              */
             gint thisOffset = (gint)(utf8spacing[layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset]
                                      * app2dev * PANGO_SCALE);
-            layoutRun->glyphs->glyphs[i].geometry.width = thisOffset;
-            tmpOffset += thisOffset;
+            if (layoutRun->glyphs->glyphs[i].geometry.width != 0) {
+                layoutRun->glyphs->glyphs[i].geometry.width = thisOffset;
+                tmpOffset += thisOffset;
+            }
         }
 
         /*        printf("    rendering at X coord %d\n", aX + offset); */
Index: gfx/src/windows/nsFontMetricsWin.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/windows/nsFontMetricsWin.cpp,v
retrieving revision 3.230
diff -u -r3.230 nsFontMetricsWin.cpp
--- gfx/src/windows/nsFontMetricsWin.cpp	23 Jun 2005 08:03:24 -0000	3.230
+++ gfx/src/windows/nsFontMetricsWin.cpp	2 Aug 2005 00:51:37 -0000
@@ -3854,11 +3854,11 @@
 }
 
 nsresult
-nsFontMetricsWin::ResolveForwards(HDC                  aDC,
-                                  const PRUnichar*     aString,
-                                  PRUint32             aLength,
-                                  nsFontSwitchCallback aFunc, 
-                                  void*                aData)
+nsFontMetricsWin::Resolve(HDC                  aDC,
+                          const PRUnichar*     aString,
+                          PRUint32             aLength,
+                          nsFontSwitchCallback aFunc, 
+                          void*                aData)
 {
   NS_ASSERTION(aString || !aLength, "invalid call");
   const PRUnichar* firstChar = aString;
@@ -3941,107 +3941,6 @@
   return NS_OK;
 }
 
-nsresult
-nsFontMetricsWin::ResolveBackwards(HDC                  aDC,
-                                   const PRUnichar*     aString,
-                                   PRUint32             aLength,
-                                   nsFontSwitchCallback aFunc, 
-                                   void*                aData)
-{
-  NS_ASSERTION(aString || !aLength, "invalid call");
-  const PRUnichar* firstChar = aString + aLength - 1;
-  const PRUnichar* lastChar  = aString - 1;
-  const PRUnichar* currChar  = firstChar;
-  nsFontWin* currFont;
-  nsFontWin* nextFont;
-  PRInt32 count;
-  nsFontSwitch fontSwitch;
-
-  if (firstChar == lastChar)
-    return NS_OK;
-
-  count = mLoadedFonts.Count();
-
-  // see if one of our loaded fonts can represent the current character
-  if (IS_LOW_SURROGATE(*currChar) && (currChar-1) > lastChar && IS_HIGH_SURROGATE(*(currChar-1))) {
-    currFont = LocateFont(aDC, SURROGATE_TO_UCS4(*(currChar-1), *currChar), count);
-    currChar -= 2;
-  }
-  else {
-    currFont = LocateFont(aDC, *currChar, count);
-    --currChar;
-  }
-
-  //This if block is meant to speedup the process in normal situation, when
-  //most characters can be found in first font
-  NS_ASSERTION(count > 1, "only one font loaded");
-  // mLoadedFont[0] == font for invisible ignorable characters
-  PRUint32 firstFont = count > 1 ? 1 : 0; 
-  if (currFont == mLoadedFonts[firstFont]) {
-    while (currChar > lastChar && 
-           (currFont->HasGlyph(*currChar)) &&
-           !CCMAP_HAS_CHAR_EXT(gIgnorableCCMapExt, *currChar) &&
-           !IS_RTL_PRESENTATION_FORM(*currChar))
-      --currChar;
-    fontSwitch.mFontWin = currFont;
-    if (!(*aFunc)(&fontSwitch, currChar+1, firstChar - currChar, aData))
-      return NS_OK;
-    if (currChar == lastChar)
-      return NS_OK;
-    // continue with the next substring, re-using the available loaded fonts
-    firstChar = currChar;
-    if (IS_LOW_SURROGATE(*currChar) && (currChar-1) > lastChar && IS_HIGH_SURROGATE(*(currChar-1))) {
-      currFont = LocateFont(aDC, SURROGATE_TO_UCS4(*(currChar-1), *currChar), count);
-      currChar -= 2;
-    }
-    else {
-      currFont = LocateFont(aDC, *currChar, count);
-      --currChar;
-    }
-  }
-
-  // see if we can keep the same font for adjacent characters
-  PRInt32 lastCharLen;
-  PRUint32 codepoint;
-
-  while (currChar > lastChar) {
-    if (IS_LOW_SURROGATE(*currChar) && (currChar-1) > lastChar && IS_HIGH_SURROGATE(*(currChar-1))) {
-      codepoint =  SURROGATE_TO_UCS4(*(currChar-1), *currChar);
-      nextFont = LocateFont(aDC, codepoint, count);
-      lastCharLen = 2;
-    }
-    else {
-      codepoint = *currChar;
-      nextFont = LocateFont(aDC, codepoint, count);
-      lastCharLen = 1;
-    }
-    if (nextFont != currFont ||
-        /* render Hebrew and Arabic presentation forms and right-to-left
-           characters outside the BMP one by one, because Windows doesn't reorder
-           them. 
-       XXX If a future version of Uniscribe corrects this, we will need to make a
-           run-time check and set a rendering hint accordingly */
-        codepoint > 0xFFFF ||
-        IS_RTL_PRESENTATION_FORM(codepoint)) {
-      // We have a substring that can be represented with the same font, and
-      // we are about to switch fonts, it is time to notify our caller.
-      fontSwitch.mFontWin = currFont;
-      if (!(*aFunc)(&fontSwitch, currChar+1, firstChar - currChar, aData))
-        return NS_OK;
-      // continue with the next substring, re-using the available loaded fonts
-      firstChar = currChar;
-      currFont = nextFont; // use the font found earlier for the char
-    }
-    currChar -= lastCharLen;
-  }
-
-  //do it for last part of the string
-  fontSwitch.mFontWin = currFont;
-  (*aFunc)(&fontSwitch, currChar+1, firstChar - currChar, aData);
-
-  return NS_OK;
-}
-
 //
 
 nsFontWin::nsFontWin(LOGFONT* aLogFont, HFONT aFont, PRUint16* aCCMap)
@@ -5252,11 +5151,11 @@
 }
 
 nsresult
-nsFontMetricsWinA::ResolveForwards(HDC                  aDC,
-                                   const PRUnichar*     aString,
-                                   PRUint32             aLength,
-                                   nsFontSwitchCallback aFunc, 
-                                   void*                aData)
+nsFontMetricsWinA::Resolve(HDC                  aDC,
+                           const PRUnichar*     aString,
+                           PRUint32             aLength,
+                           nsFontSwitchCallback aFunc, 
+                           void*                aData)
 {
   NS_ASSERTION(aString || !aLength, "invalid call");
   const PRUnichar* firstChar = aString;
@@ -5318,51 +5217,6 @@
   return NS_OK;
 }
 
-nsresult
-nsFontMetricsWinA::ResolveBackwards(HDC                  aDC,
-                                    const PRUnichar*     aString,
-                                    PRUint32             aLength,
-                                    nsFontSwitchCallback aFunc, 
-                                    void*                aData)
-{
-  NS_ASSERTION(aString || !aLength, "invalid call");
-  const PRUnichar* firstChar = aString + aLength - 1;
-  const PRUnichar* lastChar  = aString - 1;
-  const PRUnichar* currChar  = firstChar;
-  nsFontSubset* currSubset;
-  nsFontSubset* nextSubset;
-  nsFontWinA* currFont;
-  PRInt32 count;
-  nsFontSwitch fontSwitch;
-
-  if (firstChar == lastChar)
-    return NS_OK;
-
-  // see if one of our loaded fonts can represent the current character
-  count = mLoadedFonts.Count();
-  currSubset = LocateFontSubset(aDC, *currChar, count, currFont);
-
-  while (--currChar < lastChar) {
-    nextSubset = LocateFontSubset(aDC, *currChar, count, currFont);
-    if (nextSubset != currSubset) {
-      // We have a substring that can be represented with the same font, and
-      // we are about to switch fonts, it is time to notify our caller.
-      fontSwitch.mFontWin = currSubset;
-      if (!(*aFunc)(&fontSwitch, firstChar, firstChar - currChar, aData))
-        return NS_OK;
-      // continue with the next substring, re-using the available loaded fonts
-      firstChar = currChar;
-      currSubset = nextSubset; // use the font found earlier for the char
-    }
-  }
-
-  //do it for last part of the string
-  fontSwitch.mFontWin = currSubset;
-  (*aFunc)(&fontSwitch, firstChar, firstChar - currChar, aData);
-
-  return NS_OK;
-}
-
 // The Font Enumerator
 
 nsFontEnumeratorWin::nsFontEnumeratorWin()
Index: gfx/src/windows/nsFontMetricsWin.h
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/windows/nsFontMetricsWin.h,v
retrieving revision 3.58
diff -u -r3.58 nsFontMetricsWin.h
--- gfx/src/windows/nsFontMetricsWin.h	28 Jun 2005 17:20:35 -0000	3.58
+++ gfx/src/windows/nsFontMetricsWin.h	2 Aug 2005 00:51:37 -0000
@@ -185,12 +185,12 @@
 /**
  * nsFontSwitchCallback
  *
- * Font-switching callback function. Used by ResolveForwards() and
- * ResolveBackwards(). aFontSwitch points to a structure that gives
- * details about the current font needed to represent the current
- * substring. In particular, this struct contains a handler to the font
- * and some metrics of the font. These metrics may be different from
- * the metrics obtained via nsIFontMetrics.
+ * Font-switching callback function. Used by Resolve(). aFontSwitch
+ * points to a structure that gives details about the current font
+ * needed to represent the current substring. In particular, this
+ * struct contains a handler to the font and some metrics of the
+ * font. These metrics may be different from the metrics obtained
+ * via nsIFontMetrics.
  * Return PR_FALSE to stop the resolution of the remaining substrings.
  */
 
@@ -245,18 +245,11 @@
   NS_IMETHOD  GetSpaceWidth(nscoord &aSpaceWidth);
 
   virtual nsresult
-  ResolveForwards(HDC                  aDC,
-                  const PRUnichar*     aString,
-                  PRUint32             aLength,
-                  nsFontSwitchCallback aFunc, 
-                  void*                aData);
-
-  virtual nsresult
-  ResolveBackwards(HDC                  aDC,
-                   const PRUnichar*     aString,
-                   PRUint32             aLength,
-                   nsFontSwitchCallback aFunc, 
-                   void*                aData);
+  Resolve(HDC                  aDC,
+          const PRUnichar*     aString,
+          PRUint32             aLength,
+          nsFontSwitchCallback aFunc, 
+          void*                aData);
 
   nsFontWin*         FindFont(HDC aDC, PRUint32 aChar);
   virtual nsFontWin* FindUserDefinedFont(HDC aDC, PRUint32 aChar);
@@ -438,18 +431,11 @@
   virtual nsFontWin* GetFontFor(HFONT aHFONT);
 
   virtual nsresult
-  ResolveForwards(HDC                  aDC,
-                  const PRUnichar*     aString,
-                  PRUint32             aLength,
-                  nsFontSwitchCallback aFunc, 
-                  void*                aData);
-
-  virtual nsresult
-  ResolveBackwards(HDC                  aDC,
-                   const PRUnichar*     aString,
-                   PRUint32             aLength,
-                   nsFontSwitchCallback aFunc, 
-                   void*                aData);
+  Resolve(HDC                  aDC,
+          const PRUnichar*     aString,
+          PRUint32             aLength,
+          nsFontSwitchCallback aFunc, 
+          void*                aData);
 
 protected:
   nsFontSubset* LocateFontSubset(HDC aDC, PRUnichar aChar, PRInt32 & aCount, nsFontWinA*& aFont);
Index: gfx/src/windows/nsRenderingContextWin.cpp
===================================================================
RCS file: /cvsroot/mozilla/gfx/src/windows/nsRenderingContextWin.cpp,v
retrieving revision 3.177
diff -u -r3.177 nsRenderingContextWin.cpp
--- gfx/src/windows/nsRenderingContextWin.cpp	8 Jun 2005 16:48:42 -0000	3.177
+++ gfx/src/windows/nsRenderingContextWin.cpp	2 Aug 2005 00:51:38 -0000
@@ -654,7 +654,7 @@
   }
 #ifndef WINCE
   if (GCP_REORDER == (gBidiInfo & GCP_REORDER) )
-    result |= NS_RENDERING_HINT_BIDI_REORDERING;
+    result |= NS_RENDERING_HINT_BIDI_REORDERING|NS_RENDERING_HINT_REORDER_SPACED_TEXT;
   if (GCP_GLYPHSHAPE == (gBidiInfo & GCP_GLYPHSHAPE) )
     result |= NS_RENDERING_HINT_ARABIC_SHAPING;
 #endif
@@ -1510,7 +1510,7 @@
   nsFontMetricsWin* metrics = (nsFontMetricsWin*)mFontMetrics;
   GetWidthData data = {mDC, mCurrFont, 0};
 
-  metrics->ResolveForwards(mDC, aString, aLength, do_GetWidth, &data);
+  metrics->Resolve(mDC, aString, aLength, do_GetWidth, &data);
   aWidth = NSToCoordRound(float(data.mWidth) * mP2T);
 
   if (mCurrFont != data.mFont) {
@@ -1964,7 +1964,7 @@
     0, 0, 0, -1, 0, &fonts, &offsets 
   };
 
-  metrics->ResolveForwards(mDC, aString, aLength, do_BreakGetTextDimensions, &data);
+  metrics->Resolve(mDC, aString, aLength, do_BreakGetTextDimensions, &data);
 
   if (mCurrFont != data.mFont) {
     // If the font was changed along the way, restore our font
@@ -2150,7 +2150,7 @@
   nsFontMetricsWin* metrics = (nsFontMetricsWin*)mFontMetrics;
   GetTextDimensionsData data = {mDC, mCurrFont, 0, 0, 0};
 
-  metrics->ResolveForwards(mDC, aString, aLength, do_GetTextDimensions, &data);
+  metrics->Resolve(mDC, aString, aLength, do_GetTextDimensions, &data);
   aDimensions.width = NSToCoordRound(float(data.mWidth) * mP2T);
   aDimensions.ascent = data.mAscent;
   aDimensions.descent = data.mDescent;
@@ -2206,6 +2206,7 @@
   const nscoord* mSpacing;    // IN
   nscoord        mMaxLength;  // IN (length of the full string)
   nscoord        mLength;     // IN/OUT (running, current length already rendered)
+  PRBool         mRightToLeftText;
 };
 
 static PRBool PR_CALLBACK
@@ -2218,6 +2219,7 @@
 
   PRInt32 x, y;
   DrawStringData* data = (DrawStringData*)aData;
+  PRBool aRightToLeftText = data->mRightToLeftText;
   if (data->mFont != fontWin->mFont) {
     data->mFont = fontWin->mFont;
     ::SelectObject(data->mDC, data->mFont);
@@ -2233,31 +2235,55 @@
     const PRUnichar* str = aSubstring;
     const PRUnichar* end = aSubstring + aSubstringLength;
     while (str < end) {
+      nscoord spacing = 0;
+      int chars = 0;
+      // Collect a group together of one character followed a sequence
+      // of any length of characters with a spacing of zero (in most
+      // cases we will handle a single character only).  Thus for
+      // certain languages we pass a character together with its
+      // diacritical marks and let the operating system lay them out
+      // correctly.
+      while (str+chars < end) {
+	if (IS_HIGH_SURROGATE(str[chars]) && 
+	    ((str+chars+1)<end) && 
+	    IS_LOW_SURROGATE(str[chars+1])) 
+	{
+          if (chars != 0 && (data->mSpacing[0] != 0 || data->mSpacing[1] != 0))
+            break;
+	  spacing += *data->mSpacing++;
+	  spacing += *data->mSpacing++;
+          chars += 2;
+	}
+        else {
+          if (chars != 0 && data->mSpacing[0] != 0)
+            break;
+          spacing += *data->mSpacing++;
+          chars++;
+        }
+      }
+      // For right-to-left languages, we subtract the width of the character
+      // BEFORE rendering.
+      if (aRightToLeftText)
+        data->mX -= spacing;
       // XXX can shave some cycles by inlining a version of transform
       // coord where y is constant and transformed once
       x = data->mX;
       y = data->mY;
       data->mTranMatrix->TransformCoord(&x, &y);
-      if (IS_HIGH_SURROGATE(*str) && 
-          ((str+1)<end) && 
-          IS_LOW_SURROGATE(*(str+1))) 
-      {
-        // special case for surrogate pair
-        fontWin->DrawString(data->mDC, x, y, str, 2);
-        // we need to advance data->mX and str twice
-        data->mX += *data->mSpacing++;
-        ++str;
-      } else {
-        fontWin->DrawString(data->mDC, x, y, str, 1);
-      }
-      data->mX += *data->mSpacing++;
-      ++str;
+      fontWin->DrawString(data->mDC, x, y, str, chars);
+      if (!aRightToLeftText)
+        data->mX += spacing;
+      str += chars;
     }
   }
   else {
+    // For right-to-left languages, we subtract the width of the character
+    // BEFORE rendering.
+    if (aRightToLeftText)
+      data->mX -= fontWin->GetWidth(data->mDC, aSubstring, aSubstringLength);
     fontWin->DrawString(data->mDC, data->mX, data->mY, aSubstring, aSubstringLength);
     // be ready if there is more to come
-    if (data->mLength < data->mMaxLength) {
+    if (!aRightToLeftText && data->mLength < data->mMaxLength) {
       data->mX += fontWin->GetWidth(data->mDC, aSubstring, aSubstringLength);
     }
   }
@@ -2272,23 +2298,30 @@
   if (!mFontMetrics) return NS_ERROR_FAILURE;
 
   CheckLength(&aLength);
-  SetupFontAndColor();
 
   nsFontMetricsWin* metrics = (nsFontMetricsWin*)mFontMetrics;
   DrawStringData data = {mDC, mCurrFont, mTranMatrix, 
-    aX, aY, aSpacing, aLength, 0
+    aX, aY, aSpacing, aLength, 0, mRightToLeftText
   };
+  
+  if (mRightToLeftText) {
+    // For RTL languages, we start at the right and work leftwards.
+    if (aSpacing) {
+      for (int i = 0; i < (int)aLength; i++)
+        data.mX += aSpacing[i];
+    }
+    else {
+      nscoord aWidth;
+      GetWidth(aString, aLength, aWidth, NULL);
+      data.mX += aWidth;  // Add width to start at right-most co-ordinate.
+    }
+  }
   if (!aSpacing) { // @see do_DrawString for the spacing case
     mTranMatrix->TransformCoord(&data.mX, &data.mY);
   }
 
-  if (mRightToLeftText) {
-    metrics->ResolveBackwards(mDC, aString, aLength, do_DrawString, &data);
-  }
-  else
-  {
-    metrics->ResolveForwards(mDC, aString, aLength, do_DrawString, &data);
-  }
+  SetupFontAndColor();
+  metrics->Resolve(mDC, aString, aLength, do_DrawString, &data);
 
   if (mCurrFont != data.mFont) {
     // If the font was changed along the way, restore our font
@@ -2385,7 +2418,7 @@
   nsFontMetricsWin* metrics = (nsFontMetricsWin*)mFontMetrics;
   GetBoundingMetricsData data = {mDC, mCurrFont, &aBoundingMetrics, PR_TRUE, NS_OK};
 
-  nsresult rv = metrics->ResolveForwards(mDC, aString, aLength, do_GetBoundingMetrics, &data);
+  nsresult rv = metrics->Resolve(mDC, aString, aLength, do_GetBoundingMetrics, &data);
   if (NS_SUCCEEDED(rv)) {
     rv = data.mStatus;
   }
