Make all nsBidiPresUtils methods static. Bug 624798, r=roc
authorSimon Montagu <smontagu@smontagu.org>
Wed, 13 Apr 2011 12:23:49 +0300
changeset 73478 b529ffc1012b572199c8d53af5d874eb0b798df2
parent 73477 d6fa77966e7c1858547cf7e7cbfe8ef4411d9b7e
child 73479 51b49a7cf2e4fa78e6f4b2462046a3a7d8e51089
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs624798
milestone8.0a1
Make all nsBidiPresUtils methods static. Bug 624798, r=roc
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
layout/base/nsBidi.h
layout/base/nsBidiPresUtils.cpp
layout/base/nsBidiPresUtils.h
layout/base/nsLayoutUtils.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsFrameList.cpp
layout/generic/nsImageFrame.cpp
layout/generic/nsLineBox.cpp
layout/generic/nsTextFrameThebes.cpp
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/xul/base/src/nsTextBoxFrame.cpp
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -98,16 +98,17 @@
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxTextRunCache.h"
 #include "gfxBlur.h"
 #include "gfxUtils.h"
 
 #include "nsFrameManager.h"
 #include "nsFrameLoader.h"
+#include "nsBidi.h"
 #include "nsBidiPresUtils.h"
 #include "Layers.h"
 #include "CanvasUtils.h"
 #include "nsIMemoryReporter.h"
 #include "nsStyleUtil.h"
 #include "CanvasImageCache.h"
 
 #include <algorithm>
@@ -2733,20 +2734,16 @@ nsCanvasRenderingContext2D::DrawOrMeasur
     }
 
     nsIPresShell* presShell = GetPresShell();
     if (!presShell)
         return NS_ERROR_FAILURE;
 
     nsIDocument* document = presShell->GetDocument();
 
-    nsBidiPresUtils* bidiUtils = presShell->GetPresContext()->GetBidiUtils();
-    if (!bidiUtils)
-        return NS_ERROR_FAILURE;
-
     // replace all the whitespace characters with U+0020 SPACE
     nsAutoString textToDraw(aRawText);
     TextReplaceWhitespaceCharacters(textToDraw);
 
     // for now, default to ltr if not in doc
     PRBool isRTL = PR_FALSE;
 
     if (content && content->IsInDoc()) {
@@ -2782,25 +2779,27 @@ nsCanvasRenderingContext2D::DrawOrMeasur
 
     processor.mFontgrp = GetCurrentFontStyle();
     NS_ASSERTION(processor.mFontgrp, "font group is null");
 
     nscoord totalWidthCoord;
 
     // calls bidi algo twice since it needs the full text width and the
     // bounding boxes before rendering anything
-    rv = bidiUtils->ProcessText(textToDraw.get(),
-                                textToDraw.Length(),
-                                isRTL ? NSBIDI_RTL : NSBIDI_LTR,
-                                presShell->GetPresContext(),
-                                processor,
-                                nsBidiPresUtils::MODE_MEASURE,
-                                nsnull,
-                                0,
-                                &totalWidthCoord);
+    nsBidi bidiEngine;
+    rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
+                                      textToDraw.Length(),
+                                      isRTL ? NSBIDI_RTL : NSBIDI_LTR,
+                                      presShell->GetPresContext(),
+                                      processor,
+                                      nsBidiPresUtils::MODE_MEASURE,
+                                      nsnull,
+                                      0,
+                                      &totalWidthCoord,
+                                      &bidiEngine);
     if (NS_FAILED(rv))
         return rv;
 
     float totalWidth = float(totalWidthCoord) / processor.mAppUnitsPerDevPixel;
     if (aWidth)
         *aWidth = totalWidth;
 
     // if only measuring, don't need to do any more work
@@ -2889,25 +2888,26 @@ nsCanvasRenderingContext2D::DrawOrMeasur
 
         gfxContext* ctx = ShadowInitialize(drawExtents, blur);
 
         if (ctx) {
             CopyContext(ctx, mThebes);
             ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
             processor.mThebes = ctx;
 
-            rv = bidiUtils->ProcessText(textToDraw.get(),
-                                        textToDraw.Length(),
-                                        isRTL ? NSBIDI_RTL : NSBIDI_LTR,
-                                        presShell->GetPresContext(),
-                                        processor,
-                                        nsBidiPresUtils::MODE_DRAW,
-                                        nsnull,
-                                        0,
-                                        nsnull);
+            rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
+                                              textToDraw.Length(),
+                                              isRTL ? NSBIDI_RTL : NSBIDI_LTR,
+                                              presShell->GetPresContext(),
+                                              processor,
+                                              nsBidiPresUtils::MODE_DRAW,
+                                              nsnull,
+                                              0,
+                                              nsnull,
+                                              &bidiEngine);
             if (NS_FAILED(rv))
                 return rv;
 
             ShadowFinalize(blur);
         }
 
         processor.mThebes = mThebes;
     }
@@ -2926,25 +2926,26 @@ nsCanvasRenderingContext2D::DrawOrMeasur
 
             // don't want operators to be applied twice
             mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
         }
 
         ApplyStyle(STYLE_FILL);
     }
 
-    rv = bidiUtils->ProcessText(textToDraw.get(),
-                                textToDraw.Length(),
-                                isRTL ? NSBIDI_RTL : NSBIDI_LTR,
-                                presShell->GetPresContext(),
-                                processor,
-                                nsBidiPresUtils::MODE_DRAW,
-                                nsnull,
-                                0,
-                                nsnull);
+    rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
+                                      textToDraw.Length(),
+                                      isRTL ? NSBIDI_RTL : NSBIDI_LTR,
+                                      presShell->GetPresContext(),
+                                      processor,
+                                      nsBidiPresUtils::MODE_DRAW,
+                                      nsnull,
+                                      0,
+                                      nsnull,
+                                      &bidiEngine);
 
     // this needs to be restored before function can return
     if (doUseIntermediateSurface) {
         mThebes->PopGroupToSource();
         DirtyAllStyles();
     }
 
     if (NS_FAILED(rv))
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -95,16 +95,17 @@
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxTextRunCache.h"
 #include "gfxBlur.h"
 #include "gfxUtils.h"
 
 #include "nsFrameManager.h"
 #include "nsFrameLoader.h"
+#include "nsBidi.h"
 #include "nsBidiPresUtils.h"
 #include "Layers.h"
 #include "CanvasUtils.h"
 #include "nsIMemoryReporter.h"
 #include "nsStyleUtil.h"
 #include "CanvasImageCache.h"
 
 #include <algorithm>
@@ -3191,21 +3192,16 @@ nsCanvasRenderingContext2DAzure::DrawOrM
   }
 
   nsIPresShell* presShell = GetPresShell();
   if (!presShell)
       return NS_ERROR_FAILURE;
 
   nsIDocument* document = presShell->GetDocument();
 
-  nsBidiPresUtils* bidiUtils = presShell->GetPresContext()->GetBidiUtils();
-  if (!bidiUtils) {
-    return NS_ERROR_FAILURE;
-  }
-
   // replace all the whitespace characters with U+0020 SPACE
   nsAutoString textToDraw(aRawText);
   TextReplaceWhitespaceCharacters(textToDraw);
 
   // for now, default to ltr if not in doc
   PRBool isRTL = PR_FALSE;
 
   if (content && content->IsInDoc()) {
@@ -3246,25 +3242,27 @@ nsCanvasRenderingContext2DAzure::DrawOrM
 
   processor.mFontgrp = GetCurrentFontStyle();
   NS_ASSERTION(processor.mFontgrp, "font group is null");
 
   nscoord totalWidthCoord;
 
   // calls bidi algo twice since it needs the full text width and the
   // bounding boxes before rendering anything
-  rv = bidiUtils->ProcessText(textToDraw.get(),
-                              textToDraw.Length(),
-                              isRTL ? NSBIDI_RTL : NSBIDI_LTR,
-                              presShell->GetPresContext(),
-                              processor,
-                              nsBidiPresUtils::MODE_MEASURE,
-                              nsnull,
-                              0,
-                              &totalWidthCoord);
+  nsBidi bidiEngine;
+  rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
+                                textToDraw.Length(),
+                                isRTL ? NSBIDI_RTL : NSBIDI_LTR,
+                                presShell->GetPresContext(),
+                                processor,
+                                nsBidiPresUtils::MODE_MEASURE,
+                                nsnull,
+                                0,
+                                &totalWidthCoord,
+                                &bidiEngine);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   float totalWidth = float(totalWidthCoord) / processor.mAppUnitsPerDevPixel;
   if (aWidth) {
     *aWidth = totalWidth;
   }
@@ -3345,25 +3343,26 @@ nsCanvasRenderingContext2DAzure::DrawOrM
   }
 
   // save the previous bounding box
   gfxRect boundingBox = processor.mBoundingBox;
 
   // don't ever need to measure the bounding box twice
   processor.mDoMeasureBoundingBox = PR_FALSE;
 
-  rv = bidiUtils->ProcessText(textToDraw.get(),
-                              textToDraw.Length(),
-                              isRTL ? NSBIDI_RTL : NSBIDI_LTR,
-                              presShell->GetPresContext(),
-                              processor,
-                              nsBidiPresUtils::MODE_DRAW,
-                              nsnull,
-                              0,
-                              nsnull);
+  rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
+                                    textToDraw.Length(),
+                                    isRTL ? NSBIDI_RTL : NSBIDI_LTR,
+                                    presShell->GetPresContext(),
+                                    processor,
+                                    nsBidiPresUtils::MODE_DRAW,
+                                    nsnull,
+                                    0,
+                                    nsnull,
+                                    &bidiEngine);
 
 
   mTarget->SetTransform(oldTransform);
 
   if (aOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_FILL && !doDrawShadow)
     return RedrawUser(boundingBox);
 
   return Redraw();
--- a/layout/base/nsBidi.h
+++ b/layout/base/nsBidi.h
@@ -768,17 +768,17 @@ public:
    *      the number of objects to be reordered.
    *      It must be <code>aLength>0</code>.
    *
    * @param aIndexMap is a pointer to an array of <code>aLength</code>
    *      indexes which will reflect the reordering of the characters.
    *      The array does not need to be initialized.<p>
    *      The index map will result in <code>aIndexMap[aLogicalIndex]==aVisualIndex</code>.
    */
-  nsresult ReorderLogical(const nsBidiLevel *aLevels, PRInt32 aLength, PRInt32 *aIndexMap);
+  static nsresult ReorderLogical(const nsBidiLevel *aLevels, PRInt32 aLength, PRInt32 *aIndexMap);
 #endif // FULL_BIDI_ENGINE
   /**
    * This is a convenience function that does not use a nsBidi object.
    * It is intended to be used for when an application has determined the levels
    * of objects (character sequences) and just needs to have them reordered (L2).
    * This is equivalent to using <code>GetVisualMap</code> on a
    * <code>nsBidi</code> object.
    *
@@ -789,17 +789,17 @@ public:
    *      the number of objects to be reordered.
    *      It must be <code>aLength>0</code>.
    *
    * @param aIndexMap is a pointer to an array of <code>aLength</code>
    *      indexes which will reflect the reordering of the characters.
    *      The array does not need to be initialized.<p>
    *      The index map will result in <code>aIndexMap[aVisualIndex]==aLogicalIndex</code>.
    */
-  nsresult ReorderVisual(const nsBidiLevel *aLevels, PRInt32 aLength, PRInt32 *aIndexMap);
+  static nsresult ReorderVisual(const nsBidiLevel *aLevels, PRInt32 aLength, PRInt32 *aIndexMap);
 
 #ifdef FULL_BIDI_ENGINE
   /**
    * Invert an index map.
    * The one-to-one index mapping of the first map is inverted and written to
    * the second one.
    *
    * @param aSrcMap is an array with <code>aLength</code> indexes
@@ -912,16 +912,16 @@ private:
   void SetTrailingWSStart();
 
   PRBool GetRuns();
 
   void GetSingleRun(nsBidiLevel aLevel);
 
   void ReorderLine(nsBidiLevel aMinLevel, nsBidiLevel aMaxLevel);
 
-  PRBool PrepareReorder(const nsBidiLevel *aLevels, PRInt32 aLength, PRInt32 *aIndexMap, nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel);
+  static PRBool PrepareReorder(const nsBidiLevel *aLevels, PRInt32 aLength, PRInt32 *aIndexMap, nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel);
 
   PRInt32 doWriteReverse(const PRUnichar *src, PRInt32 srcLength,
                          PRUnichar *dest, PRUint16 options);
 
 };
 
 #endif // _nsBidi_h_
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -65,51 +65,281 @@ using namespace mozilla;
 static const PRUnichar kSpace            = 0x0020;
 static const PRUnichar kLineSeparator    = 0x2028;
 static const PRUnichar kObjectSubstitute = 0xFFFC;
 static const PRUnichar kLRE              = 0x202A;
 static const PRUnichar kRLE              = 0x202B;
 static const PRUnichar kLRO              = 0x202D;
 static const PRUnichar kRLO              = 0x202E;
 static const PRUnichar kPDF              = 0x202C;
-static const PRUnichar ALEF              = 0x05D0;
-
-#define CHAR_IS_HEBREW(c) ((0x0590 <= (c)) && ((c)<= 0x05FF))
-// Note: The above code are moved from gfx/src/windows/nsRenderingContextWin.cpp
 
 #define NS_BIDI_CONTROL_FRAME ((nsIFrame*)0xfffb1d1)
 
-nsBidiPresUtils::nsBidiPresUtils() : mArraySize(8),
-                                     mIndexMap(nsnull),
-                                     mLevels(nsnull),
-                                     mSuccess(NS_ERROR_FAILURE),
-                                     mBidiEngine(nsnull)
-{
-  mBidiEngine = new nsBidi();
-  if (mBidiEngine && mContentToFrameIndex.Init()) {
-    mSuccess = NS_OK;
+struct BidiParagraphData {
+  nsString            mBuffer;
+  nsAutoTArray<PRUnichar, 16> mEmbeddingStack;
+  nsTArray<nsIFrame*> mLogicalFrames;
+  nsTArray<nsLineBox*> mLinePerFrame;
+  nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;
+  PRPackedBool        mIsVisual;
+  nsBidiLevel         mParaLevel;
+  nsIContent*         mPrevContent;
+  nsAutoPtr<nsBidi>   mBidiEngine;
+  nsIFrame*           mPrevFrame;
+
+  void Init(nsBlockFrame *aBlockFrame)
+  {
+    mContentToFrameIndex.Init();
+    mBidiEngine = new nsBidi();
+    mPrevContent = nsnull;
+    mParaLevel =
+     (NS_STYLE_DIRECTION_RTL == aBlockFrame->GetStyleVisibility()->mDirection) ?
+        NSBIDI_RTL : NSBIDI_LTR;
+
+    mIsVisual = aBlockFrame->PresContext()->IsVisualMode();
+    if (mIsVisual) {
+      /**
+       * Drill up in content to detect whether this is an element that needs to
+       * be rendered with logical order even on visual pages.
+       *
+       * We always use logical order on form controls, firstly so that text
+       * entry will be in logical order, but also because visual pages were
+       * written with the assumption that even if the browser had no support
+       * for right-to-left text rendering, it would use native widgets with
+       * bidi support to display form controls.
+       *
+       * We also use logical order in XUL elements, since we expect that if a
+       * XUL element appears in a visual page, it will be generated by an XBL
+       * binding and contain localized text which will be in logical order.
+       */
+      for (nsIContent* content = aBlockFrame->GetContent() ; content; 
+           content = content->GetParent()) {
+        if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) ||
+            content->IsXUL()) {
+          mIsVisual = PR_FALSE;
+          break;
+        }
+      }
+    }
+  }
+
+  nsresult SetPara()
+  {
+    return mBidiEngine->SetPara(mBuffer.get(), BufferLength(),
+                                mParaLevel, nsnull);
   }
-}
+
+  nsresult CountRuns(PRInt32 *runCount){ return mBidiEngine->CountRuns(runCount); }
+
+  nsresult GetLogicalRun(PRInt32 aLogicalStart, 
+                         PRInt32* aLogicalLimit,
+                         nsBidiLevel* aLevel)
+  {
+    nsresult rv = mBidiEngine->GetLogicalRun(aLogicalStart,
+                                             aLogicalLimit, aLevel);
+    if (mIsVisual || NS_FAILED(rv))
+      *aLevel = mParaLevel;
+    return rv;
+  }
+
+  void ResetData()
+  {
+    mLogicalFrames.Clear();
+    mLinePerFrame.Clear();
+    mContentToFrameIndex.Clear();
+    mBuffer.SetLength(0);
+    mPrevContent = nsnull;
+    for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
+      mBuffer.Append(mEmbeddingStack[i]);
+      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
+      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
+    }
+  }
+
+  void AppendFrame(nsIFrame* aFrame,
+                   nsBlockInFlowLineIterator* aLineIter,
+                   nsIContent* aContent = nsnull)
+  {
+    if (aContent) {
+      mContentToFrameIndex.Put(aContent, FrameCount());
+    }
+    mLogicalFrames.AppendElement(aFrame);
+
+    AdvanceLineIteratorToFrame(aFrame, aLineIter, mPrevFrame);
+    mLinePerFrame.AppendElement(aLineIter->GetLine().get());
+  }
+
+  void AdvanceAndAppendFrame(nsIFrame** aFrame,
+                             nsBlockInFlowLineIterator* aLineIter,
+                             nsIFrame** aNextSibling)
+  {
+    nsIFrame* frame = *aFrame;
+    nsIFrame* nextSibling = *aNextSibling;
+
+    frame = frame->GetNextContinuation();
+    if (frame) {
+      AppendFrame(frame, aLineIter, nsnull);
+
+      /*
+       * If we have already overshot the saved next-sibling while
+       * scanning the frame's continuations, advance it.
+       */
+      if (frame == nextSibling) {
+        nextSibling = frame->GetNextSibling();
+      }
+    }
+
+    *aFrame = frame;
+    *aNextSibling = nextSibling;
+  }
+
+  PRInt32 GetLastFrameForContent(nsIContent *aContent)
+  {
+    PRInt32 index = 0;
+    mContentToFrameIndex.Get(aContent, &index);
+    return index;
+  }
+
+  PRInt32 FrameCount(){ return mLogicalFrames.Length(); }
+
+  PRInt32 BufferLength(){ return mBuffer.Length(); }
+
+  nsIFrame* FrameAt(PRInt32 aIndex){ return mLogicalFrames[aIndex]; }
 
-nsBidiPresUtils::~nsBidiPresUtils()
-{
-  if (mLevels) {
-    delete[] mLevels;
+  nsLineBox* GetLineForFrameAt(PRInt32 aIndex){ return mLinePerFrame[aIndex]; }
+
+  void AppendUnichar(PRUnichar aCh){ mBuffer.Append(aCh); }
+
+  void AppendString(const nsDependentSubstring& aString){ mBuffer.Append(aString); }
+
+  void AppendUnicharFrame(nsIFrame* aFrame, PRUnichar aCh)
+  {
+    mLogicalFrames.AppendElement(aFrame);
+    mLinePerFrame.AppendElement((nsLineBox*)nsnull);
+    AppendUnichar(aCh);
+  }
+
+  void PushBidiControl(PRUnichar aCh)
+  {
+    AppendUnicharFrame(NS_BIDI_CONTROL_FRAME, aCh);
+    mEmbeddingStack.AppendElement(aCh);
   }
-  if (mIndexMap) {
-    delete[] mIndexMap;
+
+  void PopBidiControl()
+  {
+    AppendUnicharFrame(NS_BIDI_CONTROL_FRAME, kPDF);
+    NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
+    mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
+  }
+
+  void ClearBidiControls()
+  {
+    for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
+      AppendUnicharFrame(NS_BIDI_CONTROL_FRAME, kPDF);
+    }
+  }
+
+  static PRBool
+  IsFrameInCurrentLine(nsBlockInFlowLineIterator* aLineIter,
+                       nsIFrame* aPrevFrame, nsIFrame* aFrame)
+  {
+    nsIFrame* endFrame = aLineIter->IsLastLineInList() ? nsnull :
+      aLineIter->GetLine().next()->mFirstChild;
+    nsIFrame* startFrame = aPrevFrame ? aPrevFrame : aLineIter->GetLine()->mFirstChild;
+    for (nsIFrame* frame = startFrame; frame && frame != endFrame;
+         frame = frame->GetNextSibling()) {
+      if (frame == aFrame)
+        return PR_TRUE;
+    }
+    return PR_FALSE;
   }
-  delete mBidiEngine;
-}
+
+  static void
+  AdvanceLineIteratorToFrame(nsIFrame* aFrame,
+                             nsBlockInFlowLineIterator* aLineIter,
+                             nsIFrame*& aPrevFrame)
+  {
+    // Advance aLine to the line containing aFrame
+    nsIFrame* child = aFrame;
+    nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
+    nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, child);
+    while (parent && !nsLayoutUtils::GetAsBlock(parent)) {
+      child = parent;
+      parent = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, child);
+    }
+    NS_ASSERTION (parent, "aFrame is not a descendent of aBlockFrame");
+    while (!IsFrameInCurrentLine(aLineIter, aPrevFrame, child)) {
+#ifdef DEBUG
+      PRBool hasNext =
+#endif
+        aLineIter->Next();
+      NS_ASSERTION(hasNext, "Can't find frame in lines!");
+      aPrevFrame = nsnull;
+    }
+    aPrevFrame = child;
+  }
+
+};
+
+struct BidiLineData {
+  nsTArray<nsIFrame*> mLogicalFrames;
+  nsTArray<nsIFrame*> mVisualFrames;
+  nsTArray<PRInt32> mIndexMap;
+  nsAutoTArray<PRUint8, 18> mLevels;
+  PRBool mIsReordered;
 
-PRBool
-nsBidiPresUtils::IsSuccessful() const
-{ 
-  return NS_SUCCEEDED(mSuccess); 
-}
+  BidiLineData(nsIFrame* aFirstFrameOnLine, PRInt32   aNumFramesOnLine)
+  {
+    /**
+     * Initialize the logically-ordered array of frames using the top-level
+     * frames of a single line
+     */
+    mLogicalFrames.Clear();
+
+    PRBool isReordered = PR_FALSE;
+    PRBool hasRTLFrames = PR_FALSE;
+
+    for (nsIFrame* frame = aFirstFrameOnLine;
+         frame && aNumFramesOnLine--;
+         frame = frame->GetNextSibling()) {
+      AppendFrame(frame);
+      PRUint8 level = nsBidiPresUtils::GetFrameEmbeddingLevel(frame);
+      mLevels.AppendElement(level);
+      mIndexMap.AppendElement(0);
+      if (level & 1) {
+        hasRTLFrames = PR_TRUE;
+      }
+    }
+
+    // Reorder the line
+    nsBidi::ReorderVisual(mLevels.Elements(), FrameCount(),
+                          mIndexMap.Elements());
+
+    for (PRInt32 i = 0; i < FrameCount(); i++) {
+      mVisualFrames.AppendElement(LogicalFrameAt(mIndexMap[i]));
+      if (i != mIndexMap[i]) {
+        isReordered = PR_TRUE;
+      }
+    }
+
+    // If there's an RTL frame, assume the line is reordered
+    mIsReordered = isReordered || hasRTLFrames;
+  }
+
+  void AppendFrame(nsIFrame* aFrame)
+  {
+    mLogicalFrames.AppendElement(aFrame); 
+  }
+
+  PRInt32 FrameCount(){ return mLogicalFrames.Length(); }
+
+  nsIFrame* LogicalFrameAt(PRInt32 aIndex){ return mLogicalFrames[aIndex]; }
+
+  nsIFrame* VisualFrameAt(PRInt32 aIndex){ return mVisualFrames[aIndex]; }
+};
 
 /* Some helper methods for Resolve() */
 
 // Should this frame be split between text runs?
 PRBool
 IsBidiSplittable(nsIFrame* aFrame) {
   nsIAtom* frameType = aFrame->GetType();
   // Bidi inline containers should be split, unless they're line frames.
@@ -248,56 +478,16 @@ CreateContinuation(nsIFrame*  aFrame,
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   return NS_OK;
 }
 
-static PRBool
-IsFrameInCurrentLine(nsBlockInFlowLineIterator* aLineIter,
-                     nsIFrame* aPrevFrame, nsIFrame* aFrame)
-{
-  nsIFrame* endFrame = aLineIter->IsLastLineInList() ? nsnull :
-    aLineIter->GetLine().next()->mFirstChild;
-  nsIFrame* startFrame = aPrevFrame ? aPrevFrame : aLineIter->GetLine()->mFirstChild;
-  for (nsIFrame* frame = startFrame; frame && frame != endFrame;
-       frame = frame->GetNextSibling()) {
-    if (frame == aFrame)
-      return PR_TRUE;
-  }
-  return PR_FALSE;
-}
-
-static void
-AdvanceLineIteratorToFrame(nsIFrame* aFrame,
-                           nsBlockInFlowLineIterator* aLineIter,
-                           nsIFrame*& aPrevFrame)
-{
-  // Advance aLine to the line containing aFrame
-  nsIFrame* child = aFrame;
-  nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
-  nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, child);
-  while (parent && !nsLayoutUtils::GetAsBlock(parent)) {
-    child = parent;
-    parent = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, child);
-  }
-  NS_ASSERTION (parent, "aFrame is not a descendent of aBlockFrame");
-  while (!IsFrameInCurrentLine(aLineIter, aPrevFrame, child)) {
-#ifdef DEBUG
-    PRBool hasNext =
-#endif
-      aLineIter->Next();
-    NS_ASSERTION(hasNext, "Can't find frame in lines!");
-    aPrevFrame = nsnull;
-  }
-  aPrevFrame = child;
-}
-
 /*
  * Overview of the implementation of Resolve():
  *
  *  Walk through the descendants of aBlockFrame and build:
  *   * mLogicalFrames: an nsTArray of nsIFrame* pointers in logical order
  *   * mBuffer: an nsString containing a representation of
  *     the content of the frames.
  *     In the case of text frames, this is the actual text context of the
@@ -321,177 +511,129 @@ AdvanceLineIteratorToFrame(nsIFrame* aFr
  *  The rendering layer requires each text frame to contain text in only one
  *  direction, so we may need to call EnsureBidiContinuation() to split frames.
  *  We may also need to call RemoveBidiContinuation() to convert frames created
  *  by EnsureBidiContinuation() in previous reflows into fluid continuations.
  */
 nsresult
 nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
 {
-  mLogicalFrames.Clear();
-  mContentToFrameIndex.Clear();
-  mLinePerFrame.Clear();
-  mBuffer.SetLength(0);
-  mEmbeddingStack.Clear();
-  
-  nsPresContext *presContext = aBlockFrame->PresContext();
-
-  const nsStyleVisibility* vis = aBlockFrame->GetStyleVisibility();
-
-  mParaLevel = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
-                NSBIDI_RTL : NSBIDI_LTR;
-
-  mIsVisual = presContext->IsVisualMode();
-  if (mIsVisual) {
-    /**
-     * Drill up in content to detect whether this is an element that needs to be
-     * rendered with logical order even on visual pages.
-     *
-     * We always use logical order on form controls, firstly so that text entry
-     * will be in logical order, but also because visual pages were written with
-     * the assumption that even if the browser had no support for right-to-left
-     * text rendering, it would use native widgets with bidi support to display
-     * form controls.
-     *
-     * We also use logical order in XUL elements, since we expect that if a XUL
-     * element appears in a visual page, it will be generated by an XBL binding
-     * and contain localized text which will be in logical order.
-     */
-    for (nsIContent* content = aBlockFrame->GetContent() ; content; 
-         content = content->GetParent()) {
-      if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) ||
-          content->IsXUL()) {
-        mIsVisual = PR_FALSE;
-        break;
-      }
-    }
-  }
+  BidiParagraphData bpd;
+  bpd.Init(aBlockFrame);
 
   // handle bidi-override being set on the block itself before calling
   // TraverseFrames.
   const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
   PRUnichar ch = 0;
   if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
+    const nsStyleVisibility* vis = aBlockFrame->GetStyleVisibility();
     if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
       ch = kRLO;
     }
     else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
       ch = kLRO;
     }
     if (ch != 0) {
-      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
-      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
-      mBuffer.Append(ch);
-      mEmbeddingStack.AppendElement(ch);
+      bpd.PushBidiControl(ch);
     }
   }
-  mPrevContent = nsnull;
   for (nsBlockFrame* block = aBlockFrame; block;
        block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
     block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
     nsBlockInFlowLineIterator lineIter(block, block->begin_lines(), PR_FALSE);
-    mPrevFrame = nsnull;
-    TraverseFrames(aBlockFrame, &lineIter, block->GetFirstChild(nsnull));
+    bpd.mPrevFrame = nsnull;
+    TraverseFrames(aBlockFrame, &lineIter, block->GetFirstChild(nsnull), &bpd);
   }
 
   if (ch != 0) {
-    mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
-    mLinePerFrame.AppendElement((nsLineBox*)nsnull);
-    mBuffer.Append(kPDF);
-    NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
-    mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
+    bpd.PopBidiControl();
   }
 
-  ResolveParagraph(aBlockFrame);
-  return mSuccess;
+  return ResolveParagraph(aBlockFrame, &bpd);
 }
 
-void
-nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
+nsresult
+nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
+                                  BidiParagraphData* aBpd)
 {
   nsPresContext *presContext = aBlockFrame->PresContext();
-  PRInt32 bufferLength = mBuffer.Length();
 
-  if (bufferLength < 1) {
-    mSuccess = NS_OK;
-    return;
+  if (aBpd->BufferLength() < 1) {
+    return NS_OK;
   }
-  mBuffer.ReplaceChar("\t\r\n", kSpace);
+  aBpd->mBuffer.ReplaceChar("\t\r\n", kSpace);
 
   PRInt32 runCount;
-  PRUint8 embeddingLevel = mParaLevel;
+  PRUint8 embeddingLevel = aBpd->mParaLevel;
 
-  mSuccess = mBidiEngine->SetPara(mBuffer.get(), bufferLength, mParaLevel, nsnull);
-  if (NS_FAILED(mSuccess) ) {
-      return;
-  }
+  nsresult rv = aBpd->SetPara();
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  mSuccess = mBidiEngine->CountRuns(&runCount);
-  if (NS_FAILED(mSuccess) ) {
-    return;
-  }
+  rv = aBpd->CountRuns(&runCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   PRInt32     runLength      = 0;   // the length of the current run of text
   PRInt32     lineOffset     = 0;   // the start of the current run
   PRInt32     logicalLimit   = 0;   // the end of the current run + 1
   PRInt32     numRun         = -1;
   PRInt32     fragmentLength = 0;   // the length of the current text frame
   PRInt32     frameIndex     = -1;  // index to the frames in mLogicalFrames
-  PRInt32     frameCount     = mLogicalFrames.Length();
+  PRInt32     frameCount     = aBpd->FrameCount();
   PRInt32     contentOffset  = 0;   // offset of current frame in its content node
   PRBool      isTextFrame    = PR_FALSE;
   nsIFrame*   frame = nsnull;
   nsIContent* content = nsnull;
-  PRInt32     contentTextLength;
+  PRInt32     contentTextLength = 0;
 
   FramePropertyTable *propTable = presContext->PropertyTable();
   nsLineBox* currentLine = nsnull;
   
 #ifdef DEBUG
 #ifdef NOISY_BIDI
   printf("Before Resolve(), aBlockFrame=0x%p, mBuffer='%s', frameCount=%d\n",
-         (void*)aBlockFrame, NS_ConvertUTF16toUTF8(mBuffer).get(), frameCount);
+         (void*)aBlockFrame, NS_ConvertUTF16toUTF8(aBpd->mBuffer).get(), frameCount);
 #ifdef REALLY_NOISY_BIDI
   printf(" block frame tree=:\n");
   aBlockFrame->List(stdout, 0);
 #endif
 #endif
 #endif
 
   for (; ;) {
     if (fragmentLength <= 0) {
       // Get the next frame from mLogicalFrames
       if (++frameIndex >= frameCount) {
         break;
       }
-      frame = mLogicalFrames[frameIndex];
+      frame = aBpd->FrameAt(frameIndex);
       if (frame == NS_BIDI_CONTROL_FRAME ||
           nsGkAtoms::textFrame != frame->GetType()) {
         /*
          * Any non-text frame corresponds to a single character in the text buffer
          * (a bidi control character, LINE SEPARATOR, or OBJECT SUBSTITUTE)
          */
         isTextFrame = PR_FALSE;
         fragmentLength = 1;
       }
       else {
-        currentLine = mLinePerFrame[frameIndex];
+        currentLine = aBpd->GetLineForFrameAt(frameIndex);
         content = frame->GetContent();
         if (!content) {
-          mSuccess = NS_OK;
+          rv = NS_OK;
           break;
         }
         contentTextLength = content->TextLength();
         if (contentTextLength == 0) {
           frame->AdjustOffsetsForBidi(0, 0);
           // Set the base level and embedding level of the current run even
           // on an empty frame. Otherwise frame reordering will not be correct.
           propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
                          NS_INT32_TO_PTR(embeddingLevel));
           propTable->Set(frame, nsIFrame::BaseLevelProperty(),
-                         NS_INT32_TO_PTR(mParaLevel));
+                         NS_INT32_TO_PTR(aBpd->mParaLevel));
           continue;
         }
         PRInt32 start, end;
         frame->GetOffsets(start, end);
         NS_ASSERTION(!(contentTextLength < end - start),
                      "Frame offsets don't fit in content");
         fragmentLength = NS_MIN(contentTextLength, end - start);
         contentOffset = start;
@@ -500,81 +642,79 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
     } // if (fragmentLength <= 0)
 
     if (runLength <= 0) {
       // Get the next run of text from the Bidi engine
       if (++numRun >= runCount) {
         break;
       }
       lineOffset = logicalLimit;
-      if (NS_FAILED(mBidiEngine->GetLogicalRun(
+      if (NS_FAILED(aBpd->GetLogicalRun(
               lineOffset, &logicalLimit, &embeddingLevel) ) ) {
         break;
       }
       runLength = logicalLimit - lineOffset;
-      if (mIsVisual) {
-        embeddingLevel = mParaLevel;
-      }
     } // if (runLength <= 0)
 
     if (frame == NS_BIDI_CONTROL_FRAME) {
       frame = nsnull;
       ++lineOffset;
     }
     else {
       propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
                      NS_INT32_TO_PTR(embeddingLevel));
       propTable->Set(frame, nsIFrame::BaseLevelProperty(),
-                     NS_INT32_TO_PTR(mParaLevel));
+                     NS_INT32_TO_PTR(aBpd->mParaLevel));
       if (isTextFrame) {
         if ( (runLength > 0) && (runLength < fragmentLength) ) {
           /*
            * The text in this frame continues beyond the end of this directional run.
            * Create a non-fluid continuation frame for the next directional run.
            */
           currentLine->MarkDirty();
           nsIFrame* nextBidi;
           PRInt32 runEnd = contentOffset + runLength;
-          EnsureBidiContinuation(frame, &nextBidi, frameIndex,
-                                 contentOffset,
-                                 runEnd);
-          if (NS_FAILED(mSuccess)) {
+          rv = EnsureBidiContinuation(frame, &nextBidi, frameIndex,
+                                      contentOffset,
+                                      runEnd);
+          if (NS_FAILED(rv)) {
             break;
           }
           nextBidi->AdjustOffsetsForBidi(runEnd,
                                          contentOffset + fragmentLength);
           frame = nextBidi;
           contentOffset = runEnd;
         } // if (runLength < fragmentLength)
         else {
           if (contentOffset + fragmentLength == contentTextLength) {
             /* 
              * We have finished all the text in this content node. Convert any
              * further non-fluid continuations to fluid continuations and advance
              * frameIndex to the last frame in the content node
              */
-            PRInt32 newIndex = 0;
-            mContentToFrameIndex.Get(content, &newIndex);
+            PRInt32 newIndex = aBpd->GetLastFrameForContent(content);
             if (newIndex > frameIndex) {
-              RemoveBidiContinuation(frame, frameIndex, newIndex, lineOffset);
+              RemoveBidiContinuation(aBpd, frame,
+                                     frameIndex, newIndex, lineOffset);
               frameIndex = newIndex;
             }
           } else if (fragmentLength > 0 && runLength > fragmentLength) {
             /*
              * There is more text that belongs to this directional run in the next
              * text frame: make sure it is a fluid continuation of the current frame.
              * Do not advance frameIndex, because the next frame may contain
              * multi-directional text and need to be split
              */
             PRInt32 newIndex = frameIndex;
             do {
             } while (++newIndex < frameCount &&
-                     mLogicalFrames[newIndex] == NS_BIDI_CONTROL_FRAME);
+                     aBpd->FrameAt(newIndex) == NS_BIDI_CONTROL_FRAME);
             if (newIndex < frameCount) {
-              RemoveBidiContinuation(frame, frameIndex, newIndex, lineOffset);
+              RemoveBidiContinuation(aBpd, frame,
+                                     frameIndex, newIndex, lineOffset);
             }
           } else if (runLength == fragmentLength &&
                      numRun + 1 < runCount) {
             /*
              * If the directional run ends at the end of the frame, and this is
              * not the end of our paragraph, make sure that the next frame is a
              * non-fluid continuation
              */
@@ -639,56 +779,32 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
 
 #ifdef DEBUG
 #ifdef REALLY_NOISY_BIDI
   printf("---\nAfter Resolve(), frameTree =:\n");
   aBlockFrame->List(stdout, 0);
   printf("===\n");
 #endif
 #endif
+
+  return rv;
 }
 
 // Should this frame be treated as a leaf (e.g. when building mLogicalFrames)?
 PRBool IsBidiLeaf(nsIFrame* aFrame) {
   nsIFrame* kid = aFrame->GetFirstChild(nsnull);
   return !kid
     || !aFrame->IsFrameOfType(nsIFrame::eBidiInlineContainer);
 }
 
 void
-nsBidiPresUtils::AdvanceAndAppendFrame(nsIFrame** aFrame,
-                                       nsBlockInFlowLineIterator* aLineIter,
-                                       nsIFrame** aNextSibling)
-{
-  nsIFrame* frame = *aFrame;
-  nsIFrame* nextSibling = *aNextSibling;
-
-  frame = frame->GetNextContinuation();
-  if (frame) {
-    mLogicalFrames.AppendElement(frame);
-    AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
-    mLinePerFrame.AppendElement(aLineIter->GetLine().get());
-
-    /*
-     * If we have already overshot the saved next-sibling while
-     * scanning the frame's continuations, advance it.
-     */
-    if (frame == nextSibling) {
-      nextSibling = frame->GetNextSibling();
-    }
-  }
-
-  *aFrame = frame;
-  *aNextSibling = nextSibling;
-}
-
-void
 nsBidiPresUtils::TraverseFrames(nsBlockFrame*              aBlockFrame,
                                 nsBlockInFlowLineIterator* aLineIter,
-                                nsIFrame*                  aCurrentFrame)
+                                nsIFrame*                  aCurrentFrame,
+                                BidiParagraphData*         aBpd)
 {
   if (!aCurrentFrame)
     return;
 
   nsIFrame* childFrame = aCurrentFrame;
   do {
     /*
      * It's important to get the next sibling and next continuation *before*
@@ -736,45 +852,36 @@ nsBidiPresUtils::TraverseFrames(nsBlockF
             ch = kLRO;
           }
           break;
       }
 
       // Add a dummy frame pointer representing a bidi control code before the
       // first frame of an element specifying embedding or override
       if (ch != 0 && !frame->GetPrevContinuation()) {
-        mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
-        mLinePerFrame.AppendElement((nsLineBox*)nsnull);
-        mBuffer.Append(ch);
-        mEmbeddingStack.AppendElement(ch);
+        aBpd->PushBidiControl(ch);
       }
     }
 
     if (IsBidiLeaf(frame)) {
       /* Bidi leaf frame: add the frame to the mLogicalFrames array,
        * and add its index to the mContentToFrameIndex hashtable. This
        * will be used in RemoveBidiContinuation() to identify the last
        * frame in the array with a given content.
        */
       nsIContent* content = frame->GetContent();
-      if (content) {
-        mContentToFrameIndex.Put(content, mLogicalFrames.Length());
-      }
-      mLogicalFrames.AppendElement(frame);
-
-      AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
-      mLinePerFrame.AppendElement(aLineIter->GetLine().get());
+      aBpd->AppendFrame(frame, aLineIter, content);
 
       // Append the content of the frame to the paragraph buffer
       nsIAtom* frameType = frame->GetType();
       if (nsGkAtoms::textFrame == frameType) {
-        if (content != mPrevContent) {
-          mPrevContent = content;
+        if (content != aBpd->mPrevContent) {
+          aBpd->mPrevContent = content;
           if (!frame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
-            content->AppendTextTo(mBuffer);
+            content->AppendTextTo(aBpd->mBuffer);
           } else {
             /*
              * For preformatted text we have to do bidi resolution on each line
              * separately. 
              */
             nsAutoString text;
             content->AppendTextTo(text);
             nsIFrame* next;
@@ -785,45 +892,45 @@ nsBidiPresUtils::TraverseFrames(nsBlockF
               frame->GetOffsets(start, end);
               PRInt32 endLine = text.FindChar('\n', start);
               if (endLine == -1) {
                 /*
                  * If there is no newline in the text content, just save the
                  * text from this frame and its continuations, and do bidi
                  * resolution later
                  */
-                mBuffer.Append(Substring(text, start));
+                aBpd->AppendString(Substring(text, start));
                 while (frame && nextSibling) {
-                  AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling);
+                  aBpd->AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling);
                 }
                 break;
               }
 
               /*
                * If there is a newline in the frame, break the frame after the
                * newline, do bidi resolution and repeat until the last sibling
                */
               ++endLine;
 
               /*
                * If the frame ends before the new line, save the text and move
                * into the next continuation
                */
-              mBuffer.Append(Substring(text, start,
-                                       NS_MIN(end, endLine) - start));
+              aBpd->AppendString(Substring(text, start,
+                                           NS_MIN(end, endLine) - start));
               while (end < endLine && nextSibling) { 
-                AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling);
+                aBpd->AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling);
                 NS_ASSERTION(frame, "Premature end of continuation chain");
                 frame->GetOffsets(start, end);
-                mBuffer.Append(Substring(text, start,
-                                         NS_MIN(end, endLine) - start));
+                aBpd->AppendString(Substring(text, start,
+                                             NS_MIN(end, endLine) - start));
               }
 
               if (end < endLine) {
-                mPrevContent = nsnull;
+                aBpd->mPrevContent = nsnull;
                 break;
               }
 
               PRBool createdContinuation = PR_FALSE;
               if (PRUint32(endLine) < text.Length()) {
                 /*
                  * Timing is everything here: if the frame already has a bidi
                  * continuation, we need to make the continuation fluid *before*
@@ -850,194 +957,92 @@ nsBidiPresUtils::TraverseFrames(nsBlockF
                 textFrame->SetLength(endLine - start, nsnull);
 
                 if (!next) {
                   // If the frame has no next in flow, create one.
                   CreateContinuation(frame, &next, PR_TRUE);
                   createdContinuation = PR_TRUE;
                 }
               }
-              ResolveParagraphWithinBlock(aBlockFrame);
+              ResolveParagraphWithinBlock(aBlockFrame, aBpd);
 
               if (!nextSibling && !createdContinuation) {
                 break;
               } else if (next) {
                 frame = next;
-                mLogicalFrames.AppendElement(frame);
-                AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
-                mLinePerFrame.AppendElement(aLineIter->GetLine().get());
+                aBpd->AppendFrame(frame, aLineIter);
               }
 
               /*
                * If we have already overshot the saved next-sibling while
                * scanning the frame's continuations, advance it.
                */
               if (frame && frame == nextSibling) {
                 nextSibling = frame->GetNextSibling();
               }
 
             } while (next);
           }
         }
       } else if (nsGkAtoms::brFrame == frameType) {
         // break frame -- append line separator
-        mBuffer.Append(kLineSeparator);
-        ResolveParagraphWithinBlock(aBlockFrame);
+        aBpd->AppendUnichar(kLineSeparator);
+        ResolveParagraphWithinBlock(aBlockFrame, aBpd);
       } else { 
         // other frame type -- see the Unicode Bidi Algorithm:
         // "...inline objects (such as graphics) are treated as if they are ...
         // U+FFFC"
-        mBuffer.Append(kObjectSubstitute);
+        aBpd->AppendUnichar(kObjectSubstitute);
         if (!frame->GetStyleContext()->GetStyleDisplay()->IsInlineOutside()) {
           // if it is not inline, end the paragraph
-          ResolveParagraphWithinBlock(aBlockFrame);
+          ResolveParagraphWithinBlock(aBlockFrame, aBpd);
         }
       }
     }
     else {
       // For a non-leaf frame, recurse into TraverseFrames
       nsIFrame* kid = frame->GetFirstChild(nsnull);
-      TraverseFrames(aBlockFrame, aLineIter, kid);
+      TraverseFrames(aBlockFrame, aLineIter, kid, aBpd);
     }
 
     // If the element is attributed by dir, indicate direction pop (add PDF frame)
     if (ch != 0 && isLastFrame) {
       // Add a dummy frame pointer representing a bidi control code after the
       // last frame of an element specifying embedding or override
-      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
-      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
-      mBuffer.Append(kPDF);
-      NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
-      mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
+      aBpd->PopBidiControl();
     }
     childFrame = nextSibling;
   } while (childFrame);
 }
 
 void
-nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame)
+nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame,
+                                             BidiParagraphData* aBpd)
 {
-  nsIPresShell* shell;
-  nsStyleContext* styleContext;
-
-  if (mEmbeddingStack.Length() > 0) {
-    shell = aBlockFrame->PresContext()->PresShell();
-    styleContext = aBlockFrame->GetStyleContext();
-
-    // pop all embeddings and overrides
-    for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
-      mBuffer.Append(kPDF);
-      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
-      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
-    }
-  }
-
-  ResolveParagraph(aBlockFrame);
-
-  // Clear the frame array and paragraph buffer, and restore the stored 
-  // embeddings and overrides
-  mLogicalFrames.Clear();
-  mContentToFrameIndex.Clear();
-  mLinePerFrame.Clear();
-  mBuffer.SetLength(0);
-  mPrevContent = nsnull;
-  if (mEmbeddingStack.Length() > 0) {
-    for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
-      mBuffer.Append(mEmbeddingStack[i]);
-      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
-      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
-    }
-  } 
+  aBpd->ClearBidiControls();
+  ResolveParagraph(aBlockFrame, aBpd);
+  aBpd->ResetData();
 }
 
 void
 nsBidiPresUtils::ReorderFrames(nsIFrame*            aFirstFrameOnLine,
                                PRInt32              aNumFramesOnLine)
 {
   // If this line consists of a line frame, reorder the line frame's children.
   if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
     aFirstFrameOnLine = aFirstFrameOnLine->GetFirstChild(nsnull);
     if (!aFirstFrameOnLine)
       return;
     // All children of the line frame are on the first line. Setting aNumFramesOnLine
     // to -1 makes InitLogicalArrayFromLine look at all of them.
     aNumFramesOnLine = -1;
   }
 
-  InitLogicalArrayFromLine(aFirstFrameOnLine, aNumFramesOnLine);
-
-  PRBool isReordered;
-  PRBool hasRTLFrames;
-  Reorder(isReordered, hasRTLFrames);
-  RepositionInlineFrames(aFirstFrameOnLine);
-}
-
-nsresult
-nsBidiPresUtils::Reorder(PRBool& aReordered, PRBool& aHasRTLFrames)
-{
-  aReordered = PR_FALSE;
-  aHasRTLFrames = PR_FALSE;
-  PRInt32 count = mLogicalFrames.Length();
-
-  if (mArraySize < count) {
-    mArraySize = count << 1;
-    if (mLevels) {
-      delete[] mLevels;
-      mLevels = nsnull;
-    }
-    if (mIndexMap) {
-      delete[] mIndexMap;
-      mIndexMap = nsnull;
-    }
-  }
-  if (!mLevels) {
-    mLevels = new PRUint8[mArraySize];
-    if (!mLevels) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-  }
-  memset(mLevels, 0, sizeof(PRUint8) * mArraySize);
-
-  nsIFrame* frame;
-  PRInt32   i;
-
-  for (i = 0; i < count; i++) {
-    frame = mLogicalFrames[i];
-    mLevels[i] = GetFrameEmbeddingLevel(frame);
-    if (mLevels[i] & 1) {
-      aHasRTLFrames = PR_TRUE;
-    }      
-  }
-  if (!mIndexMap) {
-    mIndexMap = new PRInt32[mArraySize];
-  }
-  if (!mIndexMap) {
-    mSuccess = NS_ERROR_OUT_OF_MEMORY;
-  }
-  else {
-    memset(mIndexMap, 0, sizeof(PRUint32) * mArraySize);
-
-    mSuccess = mBidiEngine->ReorderVisual(mLevels, count, mIndexMap);
-
-    if (NS_SUCCEEDED(mSuccess) ) {
-      mVisualFrames.Clear();
-
-      for (i = 0; i < count; i++) {
-        mVisualFrames.AppendElement(mLogicalFrames[mIndexMap[i]]);
-        if (i != mIndexMap[i]) {
-          aReordered = PR_TRUE;
-        }
-      }
-    } // NS_SUCCEEDED(mSuccess)
-  } // indexMap
-
-  if (NS_FAILED(mSuccess) ) {
-    aReordered = PR_FALSE;
-  }
-  return mSuccess;
+  BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
+  RepositionInlineFrames(&bld, aFirstFrameOnLine);
 }
 
 nsBidiLevel
 nsBidiPresUtils::GetFrameEmbeddingLevel(nsIFrame* aFrame)
 {
   nsIFrame* firstLeaf = aFrame;
   while (!IsBidiLeaf(firstLeaf)) {
     nsIFrame* firstChild = firstLeaf->GetFirstChild(nsnull);
@@ -1057,17 +1062,17 @@ nsBidiPresUtils::GetFrameBaseLevel(nsIFr
   }
   return NS_GET_BASE_LEVEL(firstLeaf);
 }
 
 void
 nsBidiPresUtils::IsLeftOrRightMost(nsIFrame*              aFrame,
                                    nsContinuationStates*  aContinuationStates,
                                    PRBool&                aIsLeftMost /* out */,
-                                   PRBool&                aIsRightMost /* out */) const
+                                   PRBool&                aIsRightMost /* out */)
 {
   const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
   PRBool isLTR = (NS_STYLE_DIRECTION_LTR == vis->mDirection);
 
   /*
    * Since we lay out frames from left to right (in both LTR and RTL), visiting a
    * frame with 'mFirstVisualFrame == nsnull', means it's the first appearance of
    * one of its continuation chain frames on the line.
@@ -1151,17 +1156,17 @@ nsBidiPresUtils::IsLeftOrRightMost(nsIFr
   // Reduce number of remaining frames of the continuation chain on the line.
   firstFrameState->mFrameCount--;
 }
 
 void
 nsBidiPresUtils::RepositionFrame(nsIFrame*              aFrame,
                                  PRBool                 aIsOddLevel,
                                  nscoord&               aLeft,
-                                 nsContinuationStates*  aContinuationStates) const
+                                 nsContinuationStates*  aContinuationStates)
 {
   if (!aFrame)
     return;
 
   PRBool isLeftMost, isRightMost;
   IsLeftOrRightMost(aFrame,
                     aContinuationStates,
                     isLeftMost /* out */,
@@ -1236,17 +1241,17 @@ nsBidiPresUtils::RepositionFrame(nsIFram
   aFrame->SetRect(nsRect(start, rect.y, aLeft - start, rect.height));
 
   if (isRightMost)
     aLeft += margin.right;
 }
 
 void
 nsBidiPresUtils::InitContinuationStates(nsIFrame*              aFrame,
-                                        nsContinuationStates*  aContinuationStates) const
+                                        nsContinuationStates*  aContinuationStates)
 {
   nsFrameContinuationState* state = aContinuationStates->PutEntry(aFrame);
   state->mFirstVisualFrame = nsnull;
   state->mFrameCount = 0;
 
   if (!IsBidiLeaf(aFrame)) {
     // Continue for child frames
     nsIFrame* frame;
@@ -1255,165 +1260,145 @@ nsBidiPresUtils::InitContinuationStates(
          frame = frame->GetNextSibling()) {
       InitContinuationStates(frame,
                              aContinuationStates);
     }
   }
 }
 
 void
-nsBidiPresUtils::RepositionInlineFrames(nsIFrame* aFirstChild) const
+nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
+                                        nsIFrame* aFirstChild)
 {
   const nsStyleVisibility* vis = aFirstChild->GetStyleVisibility();
   PRBool isLTR = (NS_STYLE_DIRECTION_LTR == vis->mDirection);
   nscoord leftSpace = 0;
 
   // This method is called from nsBlockFrame::PlaceLine via the call to
   // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
   // have been reflowed, which is required for GetUsedMargin/Border/Padding
   nsMargin margin = aFirstChild->GetUsedMargin();
   if (!aFirstChild->GetPrevContinuation() &&
       !nsLayoutUtils::FrameIsNonFirstInIBSplit(aFirstChild))
     leftSpace = isLTR ? margin.left : margin.right;
 
   nscoord left = aFirstChild->GetPosition().x - leftSpace;
   nsIFrame* frame;
-  PRInt32 count = mVisualFrames.Length();
+  PRInt32 count = aBld->mVisualFrames.Length();
   PRInt32 index;
   nsContinuationStates continuationStates;
 
   continuationStates.Init();
 
   // Initialize continuation states to (nsnull, 0) for
   // each frame on the line.
   for (index = 0; index < count; index++) {
-    InitContinuationStates(mVisualFrames[index], &continuationStates);
+    InitContinuationStates(aBld->VisualFrameAt(index), &continuationStates);
   }
 
   // Reposition frames in visual order
   for (index = 0; index < count; index++) {
-    frame = mVisualFrames[index];
+    frame = aBld->VisualFrameAt(index);
     RepositionFrame(frame,
-                    (mLevels[mIndexMap[index]] & 1),
+                    (aBld->mLevels[aBld->mIndexMap[index]] & 1),
                     left,
                     &continuationStates);
   } // for
 }
 
-void 
-nsBidiPresUtils::InitLogicalArrayFromLine(nsIFrame* aFirstFrameOnLine,
-                                          PRInt32   aNumFramesOnLine) {
-  mLogicalFrames.Clear();
-  for (nsIFrame* frame = aFirstFrameOnLine;
-       frame && aNumFramesOnLine--;
-       frame = frame->GetNextSibling()) {
-    mLogicalFrames.AppendElement(frame);
-  }
-}
-
 PRBool
 nsBidiPresUtils::CheckLineOrder(nsIFrame*  aFirstFrameOnLine,
                                 PRInt32    aNumFramesOnLine,
                                 nsIFrame** aFirstVisual,
                                 nsIFrame** aLastVisual)
 {
-  InitLogicalArrayFromLine(aFirstFrameOnLine, aNumFramesOnLine);
-  
-  PRBool isReordered;
-  PRBool hasRTLFrames;
-  Reorder(isReordered, hasRTLFrames);
-  PRInt32 count = mLogicalFrames.Length();
+  BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
+  PRInt32 count = bld.FrameCount();
   
   if (aFirstVisual) {
-    *aFirstVisual = mVisualFrames[0];
+    *aFirstVisual = bld.VisualFrameAt(0);
   }
   if (aLastVisual) {
-    *aLastVisual = mVisualFrames[count-1];
+    *aLastVisual = bld.VisualFrameAt(count-1);
   }
   
-  // If there's an RTL frame, assume the line is reordered
-  return isReordered || hasRTLFrames;
+  return bld.mIsReordered;
 }
 
 nsIFrame*
 nsBidiPresUtils::GetFrameToRightOf(const nsIFrame*  aFrame,
                                    nsIFrame*        aFirstFrameOnLine,
                                    PRInt32          aNumFramesOnLine)
 {
-  InitLogicalArrayFromLine(aFirstFrameOnLine, aNumFramesOnLine);
-  
-  PRBool isReordered;
-  PRBool hasRTLFrames;
-  Reorder(isReordered, hasRTLFrames);
-  PRInt32 count = mVisualFrames.Length();
+  BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
+
+  PRInt32 count = bld.mVisualFrames.Length();
 
   if (aFrame == nsnull)
-    return mVisualFrames[0];
+    return bld.VisualFrameAt(0);
   
   for (PRInt32 i = 0; i < count - 1; i++) {
-    if (mVisualFrames[i] == aFrame) {
-      return mVisualFrames[i+1];
+    if (bld.VisualFrameAt(i) == aFrame) {
+      return bld.VisualFrameAt(i+1);
     }
   }
   
   return nsnull;
 }
 
 nsIFrame*
 nsBidiPresUtils::GetFrameToLeftOf(const nsIFrame*  aFrame,
                                   nsIFrame*        aFirstFrameOnLine,
                                   PRInt32          aNumFramesOnLine)
 {
-  InitLogicalArrayFromLine(aFirstFrameOnLine, aNumFramesOnLine);
-  
-  PRBool isReordered;
-  PRBool hasRTLFrames;
-  Reorder(isReordered, hasRTLFrames);
-  PRInt32 count = mVisualFrames.Length();
+  BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
+
+  PRInt32 count = bld.mVisualFrames.Length();
   
   if (aFrame == nsnull)
-    return mVisualFrames[count-1];
+    return bld.VisualFrameAt(count-1);
   
   for (PRInt32 i = 1; i < count; i++) {
-    if (mVisualFrames[i] == aFrame) {
-      return mVisualFrames[i-1];
+    if (bld.VisualFrameAt(i) == aFrame) {
+      return bld.VisualFrameAt(i-1);
     }
   }
   
   return nsnull;
 }
 
-inline void
+inline nsresult
 nsBidiPresUtils::EnsureBidiContinuation(nsIFrame*       aFrame,
                                         nsIFrame**      aNewFrame,
                                         PRInt32&        aFrameIndex,
                                         PRInt32         aStart,
                                         PRInt32         aEnd)
 {
   NS_PRECONDITION(aNewFrame, "null OUT ptr");
   NS_PRECONDITION(aFrame, "aFrame is null");
 
   aFrame->AdjustOffsetsForBidi(aStart, aEnd);
-  mSuccess = CreateContinuation(aFrame, aNewFrame, PR_FALSE);
+  return CreateContinuation(aFrame, aNewFrame, PR_FALSE);
 }
 
 void
-nsBidiPresUtils::RemoveBidiContinuation(nsIFrame*       aFrame,
+nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd,
+                                        nsIFrame*       aFrame,
                                         PRInt32         aFirstIndex,
                                         PRInt32         aLastIndex,
-                                        PRInt32&        aOffset) const
+                                        PRInt32&        aOffset)
 {
   FrameProperties props = aFrame->Properties();
   nsBidiLevel embeddingLevel =
     (nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::EmbeddingLevelProperty()));
   nsBidiLevel baseLevel =
     (nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::BaseLevelProperty()));
 
   for (PRInt32 index = aFirstIndex + 1; index <= aLastIndex; index++) {
-    nsIFrame* frame = mLogicalFrames[index];
+    nsIFrame* frame = aBpd->FrameAt(index);
     if (frame == NS_BIDI_CONTROL_FRAME) {
       ++aOffset;
     }
     else {
       // Make the frame and its continuation ancestors fluid,
       // so they can be reused or deleted by normal reflow code
       FrameProperties frameProps = frame->Properties();
       frameProps.Set(nsIFrame::EmbeddingLevelProperty(),
@@ -1497,17 +1482,17 @@ nsBidiPresUtils::FormatUnicodeText(nsPre
   }
 
   StripBidiControlCharacters(aText, aTextLength);
   return rv;
 }
 
 void
 nsBidiPresUtils::StripBidiControlCharacters(PRUnichar* aText,
-                                            PRInt32&   aTextLength) const
+                                            PRInt32&   aTextLength)
 {
   if ( (nsnull == aText) || (aTextLength < 1) ) {
     return;
   }
 
   PRInt32 stripLen = 0;
 
   for (PRInt32 i = 0; i < aTextLength; i++) {
@@ -1540,43 +1525,45 @@ RemoveDiacritics(PRUnichar* aText,
     }
     aTextLength = i - offset;
     aText[aTextLength] = 0;
   }
 }
 #endif
 
 void
-nsBidiPresUtils::CalculateCharType(PRInt32& aOffset,
+nsBidiPresUtils::CalculateCharType(nsBidi* aBidiEngine,
+                                   const PRUnichar* aText,
+                                   PRInt32& aOffset,
                                    PRInt32  aCharTypeLimit,
                                    PRInt32& aRunLimit,
                                    PRInt32& aRunLength,
                                    PRInt32& aRunCount,
                                    PRUint8& aCharType,
-                                   PRUint8& aPrevCharType) const
+                                   PRUint8& aPrevCharType)
 
 {
   PRBool     strongTypeFound = PR_FALSE;
   PRInt32    offset;
   nsCharType charType;
 
   aCharType = eCharType_OtherNeutral;
 
   for (offset = aOffset; offset < aCharTypeLimit; offset++) {
     // Make sure we give RTL chartype to all characters that would be classified
     // as Right-To-Left by a bidi platform.
     // (May differ from the UnicodeData, eg we set RTL chartype to some NSMs.)
-    if (IS_HEBREW_CHAR(mBuffer[offset]) ) {
+    if (IS_HEBREW_CHAR(aText[offset]) ) {
       charType = eCharType_RightToLeft;
     }
-    else if (IS_ARABIC_ALPHABETIC(mBuffer[offset]) ) {
+    else if (IS_ARABIC_ALPHABETIC(aText[offset]) ) {
       charType = eCharType_RightToLeftArabic;
     }
     else {
-      mBidiEngine->GetCharTypeAt(offset, &charType);
+      aBidiEngine->GetCharTypeAt(offset, &charType);
     }
 
     if (!CHARTYPE_IS_WEAK(charType) ) {
 
       if (strongTypeFound
           && (charType != aPrevCharType)
           && (CHARTYPE_IS_RTL(charType) || CHARTYPE_IS_RTL(aPrevCharType) ) ) {
         // Stop at this point to ensure uni-directionality of the text
@@ -1609,54 +1596,55 @@ nsBidiPresUtils::CalculateCharType(PRInt
 nsresult nsBidiPresUtils::ProcessText(const PRUnichar*       aText,
                                       PRInt32                aLength,
                                       nsBidiDirection        aBaseDirection,
                                       nsPresContext*         aPresContext,
                                       BidiProcessor&         aprocessor,
                                       Mode                   aMode,
                                       nsBidiPositionResolve* aPosResolve,
                                       PRInt32                aPosResolveCount,
-                                      nscoord*               aWidth)
+                                      nscoord*               aWidth,
+                                      nsBidi*                aBidiEngine)
 {
   NS_ASSERTION((aPosResolve == nsnull) != (aPosResolveCount > 0), "Incorrect aPosResolve / aPosResolveCount arguments");
 
   PRInt32 runCount;
 
-  mBuffer.Assign(aText, aLength);
+  nsAutoString textBuffer(aText, aLength);
 
-  nsresult rv = mBidiEngine->SetPara(mBuffer.get(), aLength, aBaseDirection, nsnull);
+  nsresult rv = aBidiEngine->SetPara(aText, aLength, aBaseDirection, nsnull);
   if (NS_FAILED(rv))
     return rv;
 
-  rv = mBidiEngine->CountRuns(&runCount);
+  rv = aBidiEngine->CountRuns(&runCount);
   if (NS_FAILED(rv))
     return rv;
 
   nscoord xOffset = 0;
-  nscoord width, xEndRun;
+  nscoord width, xEndRun = 0;
   nscoord totalWidth = 0;
   PRInt32 i, start, limit, length;
   PRUint32 visualStart = 0;
   PRUint8 charType;
   PRUint8 prevType = eCharType_LeftToRight;
   nsBidiLevel level;
       
   for(int nPosResolve=0; nPosResolve < aPosResolveCount; ++nPosResolve)
   {
     aPosResolve[nPosResolve].visualIndex = kNotFound;
     aPosResolve[nPosResolve].visualLeftTwips = kNotFound;
     aPosResolve[nPosResolve].visualWidth = kNotFound;
   }
 
   for (i = 0; i < runCount; i++) {
-    rv = mBidiEngine->GetVisualRun(i, &start, &length, &aBaseDirection);
+    rv = aBidiEngine->GetVisualRun(i, &start, &length, &aBaseDirection);
     if (NS_FAILED(rv))
       return rv;
 
-    rv = mBidiEngine->GetLogicalRun(start, &limit, &level);
+    rv = aBidiEngine->GetLogicalRun(start, &limit, &level);
     if (NS_FAILED(rv))
       return rv;
 
     PRInt32 subRunLength = limit - start;
     PRInt32 lineOffset = start;
     PRInt32 typeLimit = NS_MIN(limit, aLength);
     PRInt32 subRunCount = 1;
     PRInt32 subRunLimit = typeLimit;
@@ -1678,17 +1666,17 @@ nsresult nsBidiPresUtils::ProcessText(co
       width = aprocessor.GetWidth();
       xOffset += width;
       xEndRun = xOffset;
     }
 
     while (subRunCount > 0) {
       // CalculateCharType can increment subRunCount if the run
       // contains mixed character types
-      CalculateCharType(lineOffset, typeLimit, subRunLimit, subRunLength, subRunCount, charType, prevType);
+      CalculateCharType(aBidiEngine, aText, lineOffset, typeLimit, subRunLimit, subRunLength, subRunCount, charType, prevType);
       
       nsAutoString runVisualText;
       runVisualText.Assign(aText + start, subRunLength);
       if (PRInt32(runVisualText.Length()) < subRunLength)
         return NS_ERROR_OUT_OF_MEMORY;
       FormatUnicodeText(aPresContext, runVisualText.BeginWriting(), subRunLength,
                         (nsCharType)charType, level & 1);
 
@@ -1864,19 +1852,19 @@ nsresult nsBidiPresUtils::ProcessTextFor
                                                          Mode                   aMode,
                                                          nscoord                aX,
                                                          nscoord                aY,
                                                          nsBidiPositionResolve* aPosResolve,
                                                          PRInt32                aPosResolveCount,
                                                          nscoord*               aWidth)
 {
   nsIRenderingContextBidiProcessor processor(&aRenderingContext, &aTextRunConstructionContext, nsPoint(aX, aY));
-
+  nsBidi bidiEngine;
   return ProcessText(aText, aLength, aBaseDirection, aPresContext, processor,
-                     aMode, aPosResolve, aPosResolveCount, aWidth);
+                     aMode, aPosResolve, aPosResolveCount, aWidth, &bidiEngine);
 }
 
 /* static */
 void nsBidiPresUtils::WriteReverse(const PRUnichar* aSrc,
                                    PRUint32 aSrcLength,
                                    PRUnichar* aDest)
 {
   const PRUnichar* src = aSrc + aSrcLength;
@@ -1988,55 +1976,23 @@ void nsBidiPresUtils::CopyLogicalToVisua
       // no need to use the converter -- just copy the string in reverse order
       WriteReverse(fromBegin.get(), srcLength, toBegin.get());
     } else {
       // if aOverride && aBaseDirection == NSBIDI_LTR, fall through to the
       // simple copy
       aDest.SetLength(0);
     }
   } else {
+    nsBidi bidiEngine;
     if (!WriteLogicalToVisual(fromBegin.get(), srcLength, toBegin.get(),
-                             aBaseDirection, mBidiEngine)) {
+                             aBaseDirection, &bidiEngine)) {
       aDest.SetLength(0);
     }
   }
 
   if (aDest.IsEmpty()) {
     // Either there was an error or the source is unidirectional
     //  left-to-right. In either case, just copy source to dest.
     CopyUnicodeTo(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
                   aDest);
   }
 }
-
-PRUint32 nsBidiPresUtils::EstimateMemoryUsed()
-{
-  PRUint32 size = 0;
-
-  size += sizeof(nsBidiPresUtils);
-  size += mBuffer.Length() * sizeof(PRUnichar);
-  size += moz_malloc_usable_size(mBidiEngine->mDirPropsMemory);
-  size += moz_malloc_usable_size(mBidiEngine->mLevelsMemory);
-  size += moz_malloc_usable_size(mBidiEngine->mRunsMemory);
-
-  return size;
-}
-
-static PLDHashOperator
-TraverseKey(nsISupports *aKey, PRInt32 aData, void *aUserArg)
-{
-  nsCycleCollectionTraversalCallback *cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mContentToFrameIndex key");
-  cb->NoteXPCOMChild(aKey);
-  return PL_DHASH_NEXT;
-}
-
-void nsBidiPresUtils::Traverse(nsCycleCollectionTraversalCallback &cb) const
-{
-  mContentToFrameIndex.EnumerateRead(TraverseKey, &cb);
-}
-
-void nsBidiPresUtils::Unlink()
-{
-  mContentToFrameIndex.Clear();
-}
 #endif // IBMBIDI
--- a/layout/base/nsBidiPresUtils.h
+++ b/layout/base/nsBidiPresUtils.h
@@ -50,16 +50,19 @@
 #include "nsDataHashtable.h"
 #include "nsBlockFrame.h"
 #include "nsTHashtable.h"
 
 #ifdef DrawText
 #undef DrawText
 #endif
 
+struct BidiParagraphData;
+struct BidiLineData;
+
 /**
  * A structure representing some continuation state for each frame on the line,
  * used to determine the first and the last continuation frame for each
  * continuation chain on the line.
  */
 struct nsFrameContinuationState : public nsVoidPtrHashKey
 {
   nsFrameContinuationState(const void *aFrame) : nsVoidPtrHashKey(aFrame) {}
@@ -113,17 +116,16 @@ struct nsBidiPositionResolve
   // If the logical position was not found, set to kNotFound.
   PRInt32 visualWidth;
 };
 
 class nsBidiPresUtils {
 public:
   nsBidiPresUtils();
   ~nsBidiPresUtils();
-  PRBool IsSuccessful(void) const;
   
   /**
    * Interface for the processor used by ProcessText. Used by process text to
    * collect information about the width of subruns and to notify where each
    * subrun should be rendered.
    */
   class BidiProcessor {
   public:
@@ -169,41 +171,43 @@ public:
   /**
    * Make Bidi engine calculate the embedding levels of the frames that are
    * descendants of a given block frame.
    *
    * @param aBlockFrame          The block frame
    *
    *  @lina 06/18/2000
    */
-  nsresult Resolve(nsBlockFrame* aBlockFrame);
-  void ResolveParagraph(nsBlockFrame* aBlockFrame);
-  void ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame);
+  static nsresult Resolve(nsBlockFrame* aBlockFrame);
+  static nsresult ResolveParagraph(nsBlockFrame* aBlockFrame,
+                                   BidiParagraphData* aBpd);
+  static void ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame,
+                                          BidiParagraphData* aBpd);
 
   /**
    * Reorder this line using Bidi engine.
    * Update frame array, following the new visual sequence.
    * 
    * @lina 05/02/2000
    */
-  void ReorderFrames(nsIFrame*            aFirstFrameOnLine,
-                     PRInt32              aNumFramesOnLine);
+  static void ReorderFrames(nsIFrame*            aFirstFrameOnLine,
+                            PRInt32              aNumFramesOnLine);
 
   /**
    * Format Unicode text, taking into account bidi capabilities
    * of the platform. The formatting includes: reordering, Arabic shaping,
    * symmetric and numeric swapping, removing control characters.
    *
    * @lina 06/18/2000 
    */
-  nsresult FormatUnicodeText(nsPresContext* aPresContext,
-                             PRUnichar*      aText,
-                             PRInt32&        aTextLength,
-                             nsCharType      aCharType,
-                             PRBool          aIsOddLevel);
+  static nsresult FormatUnicodeText(nsPresContext* aPresContext,
+                                    PRUnichar*      aText,
+                                    PRInt32&        aTextLength,
+                                    nsCharType      aCharType,
+                                    PRBool          aIsOddLevel);
 
   /**
    * Reorder plain text using the Unicode Bidi algorithm and send it to
    * a rendering context for rendering.
    *
    * @param[in] aText  the string to be rendered (in logical order)
    * @param aLength the number of characters in the string
    * @param aBaseDirection the base direction of the string
@@ -212,78 +216,78 @@ public:
    * @param aPresContext the presentation context
    * @param aRenderingContext the rendering context to render to
    * @param aTextRunConstructionContext the rendering context to be used to construct the textrun (affects font hinting)
    * @param aX the x-coordinate to render the string
    * @param aY the y-coordinate to render the string
    * @param[in,out] aPosResolve array of logical positions to resolve into visual positions; can be nsnull if this functionality is not required
    * @param aPosResolveCount number of items in the aPosResolve array
    */
-  nsresult RenderText(const PRUnichar*       aText,
-                      PRInt32                aLength,
-                      nsBidiDirection        aBaseDirection,
-                      nsPresContext*         aPresContext,
-                      nsRenderingContext&    aRenderingContext,
-                      nsRenderingContext&    aTextRunConstructionContext,
-                      nscoord                aX,
-                      nscoord                aY,
-                      nsBidiPositionResolve* aPosResolve = nsnull,
-                      PRInt32                aPosResolveCount = 0)
+  static nsresult RenderText(const PRUnichar*       aText,
+                             PRInt32                aLength,
+                             nsBidiDirection        aBaseDirection,
+                             nsPresContext*         aPresContext,
+                             nsRenderingContext&    aRenderingContext,
+                             nsRenderingContext&    aTextRunConstructionContext,
+                             nscoord                aX,
+                             nscoord                aY,
+                             nsBidiPositionResolve* aPosResolve = nsnull,
+                             PRInt32                aPosResolveCount = 0)
   {
     return ProcessTextForRenderingContext(aText, aLength, aBaseDirection, aPresContext, aRenderingContext,
                                           aTextRunConstructionContext, MODE_DRAW, aX, aY, aPosResolve, aPosResolveCount, nsnull);
   }
   
-  nscoord MeasureTextWidth(const PRUnichar*     aText,
-                           PRInt32              aLength,
-                           nsBidiDirection      aBaseDirection,
-                           nsPresContext*       aPresContext,
-                           nsRenderingContext&  aRenderingContext)
+  static nscoord MeasureTextWidth(const PRUnichar*     aText,
+                                  PRInt32              aLength,
+                                  nsBidiDirection      aBaseDirection,
+                                  nsPresContext*       aPresContext,
+                                  nsRenderingContext&  aRenderingContext)
   {
     nscoord length;
     nsresult rv = ProcessTextForRenderingContext(aText, aLength, aBaseDirection, aPresContext,
                                                  aRenderingContext, aRenderingContext,
                                                  MODE_MEASURE, 0, 0, nsnull, 0, &length);
     return NS_SUCCEEDED(rv) ? length : 0;
   }
 
   /**
    * Check if a line is reordered, i.e., if the child frames are not
    * all laid out left-to-right.
    * @param aFirstFrameOnLine : first frame of the line to be tested
    * @param aNumFramesOnLine : number of frames on this line
    * @param[out] aLeftMost : leftmost frame on this line
    * @param[out] aRightMost : rightmost frame on this line
    */
-  PRBool CheckLineOrder(nsIFrame*  aFirstFrameOnLine,
-                        PRInt32    aNumFramesOnLine,
-                        nsIFrame** aLeftmost,
-                        nsIFrame** aRightmost);
+  static PRBool CheckLineOrder(nsIFrame*  aFirstFrameOnLine,
+                               PRInt32    aNumFramesOnLine,
+                               nsIFrame** aLeftmost,
+                               nsIFrame** aRightmost);
 
   /**
    * Get the frame to the right of the given frame, on the same line.
    * @param aFrame : We're looking for the frame to the right of this frame.
    *                 If null, return the leftmost frame on the line.
    * @param aFirstFrameOnLine : first frame of the line to be tested
    * @param aNumFramesOnLine : number of frames on this line
    */
-  nsIFrame* GetFrameToRightOf(const nsIFrame*  aFrame,
-                              nsIFrame*        aFirstFrameOnLine,
-                              PRInt32          aNumFramesOnLine);
+  static nsIFrame* GetFrameToRightOf(const nsIFrame*  aFrame,
+                                     nsIFrame*        aFirstFrameOnLine,
+                                     PRInt32          aNumFramesOnLine);
     
   /**
    * Get the frame to the left of the given frame, on the same line.
    * @param aFrame : We're looking for the frame to the left of this frame.
    *                 If null, return the rightmost frame on the line.
    * @param aFirstFrameOnLine : first frame of the line to be tested
    * @param aNumFramesOnLine : number of frames on this line
    */
-  nsIFrame* GetFrameToLeftOf(const nsIFrame*  aFrame,
-                             nsIFrame*        aFirstFrameOnLine,
-                             PRInt32          aNumFramesOnLine);
+  static nsIFrame* GetFrameToLeftOf(const nsIFrame*  aFrame,
+                                    nsIFrame*        aFirstFrameOnLine,
+                                    PRInt32          aNumFramesOnLine);
     
   /**
    * Get the bidi embedding level of the given (inline) frame.
    */
   static nsBidiLevel GetFrameEmbeddingLevel(nsIFrame* aFrame);
 
   /**
    * Get the bidi base level of the given (inline) frame.
@@ -307,178 +311,153 @@ public:
    *  MODE_DRAW - invokes DrawText on the processor for each substring
    *  MODE_MEASURE - does not invoke DrawText on the processor
    *  Note that the string is always measured, regardless of mode
    * @param[in,out] aPosResolve array of logical positions to resolve into
    *  visual positions; can be nsnull if this functionality is not required
    * @param aPosResolveCount number of items in the aPosResolve array
    * @param[out] aWidth Pointer to where the width will be stored (may be null)
    */
-  nsresult ProcessText(const PRUnichar*       aText,
-                       PRInt32                aLength,
-                       nsBidiDirection        aBaseDirection,
-                       nsPresContext*         aPresContext,
-                       BidiProcessor&         aprocessor,
-                       Mode                   aMode,
-                       nsBidiPositionResolve* aPosResolve,
-                       PRInt32                aPosResolveCount,
-                       nscoord*               aWidth);
+  static nsresult ProcessText(const PRUnichar*       aText,
+                              PRInt32                aLength,
+                              nsBidiDirection        aBaseDirection,
+                              nsPresContext*         aPresContext,
+                              BidiProcessor&         aprocessor,
+                              Mode                   aMode,
+                              nsBidiPositionResolve* aPosResolve,
+                              PRInt32                aPosResolveCount,
+                              nscoord*               aWidth,
+                              nsBidi*                aBidiEngine);
 
   /**
    * Make a copy of a string, converting from logical to visual order
    *
    * @param aSource the source string
    * @param aDest the destination string
    * @param aBaseDirection the base direction of the string
    *       (NSBIDI_LTR or NSBIDI_RTL to force the base direction;
    *        NSBIDI_DEFAULT_LTR or NSBIDI_DEFAULT_RTL to let the bidi engine
    *        determine the direction from rules P2 and P3 of the bidi algorithm.
    *  @see nsBidi::GetPara
    * @param aOverride if TRUE, the text has a bidi override, according to
    *                    the direction in aDir
    */
-  void CopyLogicalToVisual(const nsAString& aSource,
-                           nsAString& aDest,
-                           nsBidiLevel aBaseDirection,
-                           PRBool aOverride);
-
-  /**
-   * Guess at how much memory is being used by this nsBidiPresUtils instance,
-   * including memory used by nsBidi.
-   */
-  PRUint32 EstimateMemoryUsed();
-
-  void Traverse(nsCycleCollectionTraversalCallback &cb) const;
-  void Unlink();
+  static void CopyLogicalToVisual(const nsAString& aSource,
+                                  nsAString& aDest,
+                                  nsBidiLevel aBaseDirection,
+                                  PRBool aOverride);
 
 private:
-  nsresult ProcessTextForRenderingContext(const PRUnichar*       aText,
-                                          PRInt32                aLength,
-                                          nsBidiDirection        aBaseDirection,
-                                          nsPresContext*         aPresContext,
-                                          nsRenderingContext&    aRenderingContext,
-                                          nsRenderingContext&    aTextRunConstructionContext,
-                                          Mode                   aMode,
-                                          nscoord                aX, // DRAW only
-                                          nscoord                aY, // DRAW only
-                                          nsBidiPositionResolve* aPosResolve,  /* may be null */
-                                          PRInt32                aPosResolveCount,
-                                          nscoord*               aWidth /* may be null */);
-  void AdvanceAndAppendFrame(nsIFrame**                 aFrame,
-                             nsBlockInFlowLineIterator* aLineIter,
-                             nsIFrame**                 aNextSibling);
+  static nsresult
+  ProcessTextForRenderingContext(const PRUnichar*       aText,
+                                 PRInt32                aLength,
+                                 nsBidiDirection        aBaseDirection,
+                                 nsPresContext*         aPresContext,
+                                 nsRenderingContext&    aRenderingContext,
+                                 nsRenderingContext&    aTextRunConstructionContext,
+                                 Mode                   aMode,
+                                 nscoord                aX, // DRAW only
+                                 nscoord                aY, // DRAW only
+                                 nsBidiPositionResolve* aPosResolve,  /* may be null */
+                                 PRInt32                aPosResolveCount,
+                                 nscoord*               aWidth /* may be null */);
 
   /**
    * Traverse the child frames of the block element and:
    *  Set up an array of the frames in logical order
    *  Create a string containing the text content of all the frames
    *  If we encounter content that requires us to split the element into more
    *  than one paragraph for bidi resolution, resolve the paragraph up to that
    *  point.
    */
-  void TraverseFrames(nsBlockFrame*              aBlockFrame,
-                      nsBlockInFlowLineIterator* aLineIter,
-                      nsIFrame*                  aCurrentFrame);
-
-  /**
-   * Initialize the logically-ordered array of frames
-   * using the top-level frames of a single line
-   */
-  void InitLogicalArrayFromLine(nsIFrame* aFirstFrameOnLine,
-                                PRInt32   aNumFramesOnLine);
-
-  /**
-   * Reorder the frame array from logical to visual order
-   * 
-   * @param aReordered TRUE on return if the visual order is different from
-   *                   the logical order
-   * @param aHasRTLFrames TRUE on return if at least one of the frames is RTL
-   *                      (and therefore might have reordered descendents)
-   */
-  nsresult Reorder(PRBool& aReordered, PRBool& aHasRTLFrames);
+  static void TraverseFrames(nsBlockFrame*              aBlockFrame,
+                             nsBlockInFlowLineIterator* aLineIter,
+                             nsIFrame*                  aCurrentFrame,
+                             BidiParagraphData*         aBpd);
   
   /*
    * Position aFrame and it's descendants to their visual places. Also if aFrame
    * is not leaf, resize it to embrace it's children.
    *
    * @param aFrame               The frame which itself and its children are going
    *                             to be repositioned
    * @param aIsOddLevel          TRUE means the embedding level of this frame is odd
    * @param[in,out] aLeft        IN value is the starting position of aFrame(without
    *                             considering its left margin)
    *                             OUT value will be the ending position of aFrame(after
    *                             adding its right margin)
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
    */
-  void RepositionFrame(nsIFrame*              aFrame,
-                       PRBool                 aIsOddLevel,
-                       nscoord&               aLeft,
-                       nsContinuationStates*  aContinuationStates) const;
+  static void RepositionFrame(nsIFrame*              aFrame,
+                              PRBool                 aIsOddLevel,
+                              nscoord&               aLeft,
+                              nsContinuationStates*  aContinuationStates);
 
   /*
    * Initialize the continuation state(nsFrameContinuationState) to
    * (nsnull, 0) for aFrame and its descendants.
    *
    * @param aFrame               The frame which itself and its descendants will
    *                             be initialized
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
    */
-  void InitContinuationStates(nsIFrame*              aFrame,
-                              nsContinuationStates*  aContinuationStates) const;
+  static void InitContinuationStates(nsIFrame*              aFrame,
+                                     nsContinuationStates*  aContinuationStates);
 
   /*
    * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
    * aIsRightMost values. Also set continuation states of aContinuationStates.
    *
    * A frame is leftmost if it's the first appearance of its continuation chain
    * on the line and the chain is on its first line if it's LTR or the chain is
    * on its last line if it's RTL.
    * A frame is rightmost if it's the last appearance of its continuation chain
    * on the line and the chain is on its first line if it's RTL or the chain is
    * on its last line if it's LTR.
    *
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
    * @param[out] aIsLeftMost     TRUE means aFrame is leftmost frame or continuation
    * @param[out] aIsRightMost    TRUE means aFrame is rightmost frame or continuation
    */
-   void IsLeftOrRightMost(nsIFrame*              aFrame,
-                          nsContinuationStates*  aContinuationStates,
-                          PRBool&                aIsLeftMost /* out */,
-                          PRBool&                aIsRightMost /* out */) const;
+   static void IsLeftOrRightMost(nsIFrame*              aFrame,
+                                 nsContinuationStates*  aContinuationStates,
+                                 PRBool&                aIsLeftMost /* out */,
+                                 PRBool&                aIsRightMost /* out */);
 
   /**
    *  Adjust frame positions following their visual order
    *
    *  @param aFirstChild the first kid
    *
    *  @lina 04/11/2000
    */
-  void RepositionInlineFrames(nsIFrame* aFirstChild) const;
+  static void RepositionInlineFrames(BidiLineData* aBld,
+                                     nsIFrame* aFirstChild);
   
   /**
    * Helper method for Resolve()
    * Truncate a text frame to the end of a single-directional run and possibly
    * create a continuation frame for the remainder of its content.
    *
    * @param aFrame       the original frame
    * @param aNewFrame    [OUT] the new frame that was created
    * @param aFrameIndex  [IN/OUT] index of aFrame in mLogicalFrames
    * @param aStart       [IN] the start of the content mapped by aFrame (and 
    *                          any fluid continuations)
    * @param aEnd         [IN] the offset of the end of the single-directional
    *                          text run.
    * @see Resolve()
    * @see RemoveBidiContinuation()
    */
-  inline
-  void EnsureBidiContinuation(nsIFrame*       aFrame,
-                              nsIFrame**      aNewFrame,
-                              PRInt32&        aFrameIndex,
-                              PRInt32         aStart,
-                              PRInt32         aEnd);
+  static inline
+  nsresult EnsureBidiContinuation(nsIFrame*       aFrame,
+                                  nsIFrame**      aNewFrame,
+                                  PRInt32&        aFrameIndex,
+                                  PRInt32         aStart,
+                                  PRInt32         aEnd);
 
   /**
    * Helper method for Resolve()
    * Convert one or more bidi continuation frames created in a previous reflow by
    * EnsureBidiContinuation() into fluid continuations.
    * @param aFrame       the frame whose continuations are to be removed
    * @param aFirstIndex  index of aFrame in mLogicalFrames
    * @param aLastIndex   index of the last frame to be removed
@@ -486,54 +465,40 @@ private:
    *                     directional frames have control characters
    *                     corresponding to them in mBuffer, the pointers to
    *                     mBuffer in Resolve() will need to be updated after
    *                     deleting the frames.
    *
    * @see Resolve()
    * @see EnsureBidiContinuation()
    */
-  void RemoveBidiContinuation(nsIFrame*       aFrame,
-                              PRInt32         aFirstIndex,
-                              PRInt32         aLastIndex,
-                              PRInt32&        aOffset) const;
-  void CalculateCharType(PRInt32& aOffset,
-                         PRInt32  aCharTypeLimit,
-                         PRInt32& aRunLimit,
-                         PRInt32& aRunLength,
-                         PRInt32& aRunCount,
-                         PRUint8& aCharType,
-                         PRUint8& aPrevCharType) const;
+  static void RemoveBidiContinuation(BidiParagraphData* aBpd,
+                                     nsIFrame*          aFrame,
+                                     PRInt32            aFirstIndex,
+                                     PRInt32            aLastIndex,
+                                     PRInt32&           aOffset);
+  static void CalculateCharType(nsBidi*          aBidiEngine,
+                                const PRUnichar* aText,
+                                PRInt32&         aOffset,
+                                PRInt32          aCharTypeLimit,
+                                PRInt32&         aRunLimit,
+                                PRInt32&         aRunLength,
+                                PRInt32&         aRunCount,
+                                PRUint8&         aCharType,
+                                PRUint8&         aPrevCharType);
   
-  void StripBidiControlCharacters(PRUnichar* aText,
-                                  PRInt32&   aTextLength) const;
+  static void StripBidiControlCharacters(PRUnichar* aText,
+                                         PRInt32&   aTextLength);
 
   static PRBool WriteLogicalToVisual(const PRUnichar* aSrc,
                                      PRUint32 aSrcLength,
                                      PRUnichar* aDest,
                                      nsBidiLevel aBaseDirection,
                                      nsBidi* aBidiEngine);
 
- static void WriteReverse(const PRUnichar* aSrc,
-                          PRUint32 aSrcLength,
-                          PRUnichar* aDest);
-
-  nsString        mBuffer;
-  nsTArray<PRUnichar> mEmbeddingStack;
-  nsTArray<nsIFrame*> mLogicalFrames;
-  nsTArray<nsLineBox*> mLinePerFrame;
-  nsTArray<nsIFrame*> mVisualFrames;
-  nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;
-  PRInt32         mArraySize;
-  PRInt32*        mIndexMap;
-  PRUint8*        mLevels;
-  nsresult        mSuccess;
-  PRPackedBool    mIsVisual;
-  nsBidiLevel     mParaLevel;
-  nsIFrame*       mPrevFrame;
-  nsIContent*     mPrevContent;
-
-  nsBidi*         mBidiEngine;
+  static void WriteReverse(const PRUnichar* aSrc,
+                           PRUint32 aSrcLength,
+                           PRUnichar* aDest);
 };
 
 #endif /* nsBidiPresUtils_h___ */
 
 #endif // IBMBIDI
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2849,29 +2849,25 @@ nsLayoutUtils::DrawString(const nsIFrame
                           PRInt32              aLength,
                           nsPoint              aPoint,
                           PRUint8              aDirection)
 {
 #ifdef IBMBIDI
   nsresult rv = NS_ERROR_FAILURE;
   nsPresContext* presContext = aFrame->PresContext();
   if (presContext->BidiEnabled()) {
-    nsBidiPresUtils* bidiUtils = presContext->GetBidiUtils();
-
-    if (bidiUtils) {
-      if (aDirection == NS_STYLE_DIRECTION_INHERIT) {
-        aDirection = aFrame->GetStyleVisibility()->mDirection;
-      }
-      nsBidiDirection direction =
-        (NS_STYLE_DIRECTION_RTL == aDirection) ?
-        NSBIDI_RTL : NSBIDI_LTR;
-      rv = bidiUtils->RenderText(aString, aLength, direction,
-                                 presContext, *aContext, *aContext,
-                                 aPoint.x, aPoint.y);
+    if (aDirection == NS_STYLE_DIRECTION_INHERIT) {
+      aDirection = aFrame->GetStyleVisibility()->mDirection;
     }
+    nsBidiDirection direction =
+      (NS_STYLE_DIRECTION_RTL == aDirection) ?
+      NSBIDI_RTL : NSBIDI_LTR;
+    rv = nsBidiPresUtils::RenderText(aString, aLength, direction,
+                                     presContext, *aContext, *aContext,
+                                     aPoint.x, aPoint.y);
   }
   if (NS_FAILED(rv))
 #endif // IBMBIDI
   {
     aContext->SetTextRunRTL(PR_FALSE);
     aContext->DrawString(aString, aLength, aPoint.x, aPoint.y);
   }
 }
@@ -2880,26 +2876,22 @@ nscoord
 nsLayoutUtils::GetStringWidth(const nsIFrame*      aFrame,
                               nsRenderingContext* aContext,
                               const PRUnichar*     aString,
                               PRInt32              aLength)
 {
 #ifdef IBMBIDI
   nsPresContext* presContext = aFrame->PresContext();
   if (presContext->BidiEnabled()) {
-    nsBidiPresUtils* bidiUtils = presContext->GetBidiUtils();
-
-    if (bidiUtils) {
-      const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
-      nsBidiDirection direction =
-        (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
-        NSBIDI_RTL : NSBIDI_LTR;
-      return bidiUtils->MeasureTextWidth(aString, aLength,
-                                         direction, presContext, *aContext);
-    }
+    const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
+    nsBidiDirection direction =
+      (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
+      NSBIDI_RTL : NSBIDI_LTR;
+    return nsBidiPresUtils::MeasureTextWidth(aString, aLength,
+                                             direction, presContext, *aContext);
   }
 #endif // IBMBIDI
   aContext->SetTextRunRTL(PR_FALSE);
   return aContext->GetWidth(aString, aLength);
 }
 
 /* static */ void
 nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -364,18 +364,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
 
   for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
     tmp->mImageLoaders[i].Enumerate(TraverseImageLoader, &cb);
 
   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTheme); // a service
   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLangService); // a service
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrintSettings);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrefChangedTimer);
-  if (tmp->mBidiUtils)
-    tmp->mBidiUtils->Traverse(cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPresContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument);
   NS_RELEASE(tmp->mDeviceContext); // worth bothering?
   if (tmp->mEventManager) {
     // unclear if these are needed, but can't hurt
     tmp->mEventManager->NotifyDestroyPresContext(tmp);
@@ -390,18 +388,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTheme); // a service
   // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLangService); // a service
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPrintSettings);
   if (tmp->mPrefChangedTimer)
   {
     tmp->mPrefChangedTimer->Cancel();
     tmp->mPrefChangedTimer = nsnull;
   }
-  if (tmp->mBidiUtils)
-    tmp->mBidiUtils->Unlink();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 #define MAKE_FONT_PREF_KEY(_pref, _s0, _s1) \
  _pref.Assign(_s0); \
  _pref.Append(_s1);
 
 static const char* const kGenericFont[] = {
@@ -1456,25 +1452,16 @@ nsPresContext::SetBidiEnabled() const
   if (mShell) {
     nsIDocument *doc = mShell->GetDocument();
     if (doc) {
       doc->SetBidiEnabled();
     }
   }
 }
 
-nsBidiPresUtils*
-nsPresContext::GetBidiUtils()
-{
-  if (!mBidiUtils)
-    mBidiUtils = new nsBidiPresUtils;
-
-  return mBidiUtils;
-}
-
 void
 nsPresContext::SetBidi(PRUint32 aSource, PRBool aForceRestyle)
 {
   // Don't do all this stuff unless the options have changed.
   if (aSource == GetBidi()) {
     return;
   }
 
@@ -1507,25 +1494,16 @@ nsPresContext::SetBidi(PRUint32 aSource,
 }
 
 PRUint32
 nsPresContext::GetBidi() const
 {
   return Document()->GetBidiOptions();
 }
 
-PRUint32
-nsPresContext::GetBidiMemoryUsed()
-{
-  if (!mBidiUtils)
-    return 0;
-
-  return mBidiUtils->EstimateMemoryUsed();
-}
-
 #endif //IBMBIDI
 
 PRBool
 nsPresContext::IsTopLevelWindowInactive()
 {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryReferent(mContainer));
   if (!treeItem)
     return PR_FALSE;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -753,36 +753,27 @@ public:
    *
    *  @lina 05/02/2000
    */
   PRBool IsVisualMode() const { return mIsVisual; }
 
 //Mohamed
 
   /**
-   * Get a Bidi presentation utilities object
-   */
-  NS_HIDDEN_(nsBidiPresUtils*) GetBidiUtils();
-
-  /**
    * Set the Bidi options for the presentation context
    */  
   NS_HIDDEN_(void) SetBidi(PRUint32 aBidiOptions,
                            PRBool aForceRestyle = PR_FALSE);
 
   /**
    * Get the Bidi options for the presentation context
    * Not inline so consumers of nsPresContext are not forced to
    * include nsIDocument.
    */  
   NS_HIDDEN_(PRUint32) GetBidi() const;
-
-  PRUint32 GetBidiMemoryUsed();
-#else
-  PRUint32 GetBidiMemoryUsed() { return 0; }
 #endif // IBMBIDI
 
   /**
    * Render only Selection
    */
   void SetIsRenderingOnlySelection(PRBool aResult)
   {
     NS_ASSERTION(!(aResult & ~1), "Value must be true or false");
@@ -1005,17 +996,16 @@ public:
 
   PRBool MayHaveFixedBackgroundFrames() { return mMayHaveFixedBackgroundFrames; }
   void SetHasFixedBackgroundFrame() { mMayHaveFixedBackgroundFrames = PR_TRUE; }
 
   PRUint32 EstimateMemoryUsed() {
     PRUint32 result = 0;
 
     result += sizeof(nsPresContext);
-    result += GetBidiMemoryUsed();
 
     return result;
   }
 
   PRBool IsRootContentDocument();
 
 protected:
   friend class nsRunnableMethod<nsPresContext>;
@@ -1095,20 +1085,16 @@ protected:
 
   PRInt32               mMinFontSize;   // Min font size, defaults to 0
   float                 mTextZoom;      // Text zoom, defaults to 1.0
   float                 mFullZoom;      // Page zoom, defaults to 1.0
 
   PRInt32               mCurAppUnitsPerDevPixel;
   PRInt32               mAutoQualityMinFontSizePixelsPref;
 
-#ifdef IBMBIDI
-  nsAutoPtr<nsBidiPresUtils> mBidiUtils;
-#endif
-
   nsCOMPtr<nsITheme> mTheme;
   nsCOMPtr<nsILanguageAtomService> mLangService;
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   nsCOMPtr<nsITimer>    mPrefChangedTimer;
 
   FramePropertyTable    mPropertyTable;
 
   nsInvalidateRequestList mInvalidateRequests;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1429,42 +1429,29 @@ public:
   {
     PresShell *aShell = static_cast<PresShell*>(aEntry->GetKey());
     PRUint32 *val = (PRUint32*)userArg;
     *val += aShell->EstimateMemoryUsed();
     *val += aShell->mPresContext->EstimateMemoryUsed();
     return PL_DHASH_NEXT;
   }
 
-  static PLDHashOperator LiveShellBidiSizeEnumerator(PresShellPtrKey *aEntry,
-                                                     void *userArg)
-  {
-    PresShell *aShell = static_cast<PresShell*>(aEntry->GetKey());
-    PRUint32 *val = (PRUint32*)userArg;
-    *val += aShell->mPresContext->GetBidiMemoryUsed();
-    return PL_DHASH_NEXT;
-  }
-
   static PRUint32
   EstimateShellsMemory(nsTHashtable<PresShellPtrKey>::Enumerator aEnumerator)
   {
     PRUint32 result = 0;
     sLiveShells->EnumerateEntries(aEnumerator, &result);
     return result;
   }
                   
                                   
   static PRInt64 SizeOfLayoutMemoryReporter() {
     return EstimateShellsMemory(LiveShellSizeEnumerator);
   }
 
-  static PRInt64 SizeOfBidiMemoryReporter() {
-    return EstimateShellsMemory(LiveShellBidiSizeEnumerator);
-  }
-
 protected:
   void QueryIsActive();
   nsresult UpdateImageLockingState();
 };
 
 class nsAutoCauseReflowNotifier
 {
 public:
@@ -1670,23 +1657,16 @@ static PRBool sSynthMouseMove = PR_TRUE;
 
 NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell,
     "explicit/layout/all",
     KIND_HEAP,
     UNITS_BYTES,
     PresShell::SizeOfLayoutMemoryReporter,
     "Memory used by layout PresShell, PresContext, and other related areas.")
 
-NS_MEMORY_REPORTER_IMPLEMENT(LayoutBidi,
-    "explicit/layout/bidi",
-    KIND_HEAP,
-    UNITS_BYTES,
-    PresShell::SizeOfBidiMemoryReporter,
-    "Memory used by layout Bidi processor.")
-
 PresShell::PresShell()
   : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
 {
   mSelection = nsnull;
 #ifdef MOZ_REFLOW_PERF
   mReflowCountMgr = new ReflowCountMgr();
   mReflowCountMgr->SetPresContext(mPresContext);
   mReflowCountMgr->SetPresShell(this);
@@ -1705,17 +1685,16 @@ PresShell::PresShell()
   mRenderFlags = 0;
   mXResolution = 1.0;
   mYResolution = 1.0;
   mViewportOverridden = PR_FALSE;
 
   static bool registeredReporter = false;
   if (!registeredReporter) {
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutPresShell));
-    NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutBidi));
     Preferences::AddBoolVarCache(&sSynthMouseMove,
                                  "layout.reflow.synthMouseMove", PR_TRUE);
     registeredReporter = true;
   }
 
   new (this) nsFrameManager();
 
   sLiveShells->PutEntry(this);
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -4252,21 +4252,17 @@ nsBlockFrame::PlaceLine(nsBlockReflowSta
   // RelativePositionFrames!!!
   // XXXldb Is something here considering relatively positioned frames at
   // other than their original positions?
 #ifdef IBMBIDI
   // XXXldb Why don't we do this earlier?
   if (aState.mPresContext->BidiEnabled()) {
     if (!aState.mPresContext->IsVisualMode() ||
         GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
-      nsBidiPresUtils* bidiUtils = aState.mPresContext->GetBidiUtils();
-
-      if (bidiUtils && bidiUtils->IsSuccessful() ) {
-        bidiUtils->ReorderFrames(aLine->mFirstChild, aLine->GetChildCount());
-      } // bidiUtils
+      nsBidiPresUtils::ReorderFrames(aLine->mFirstChild, aLine->GetChildCount());
     } // not visual mode
   } // bidi enabled
 #endif // IBMBIDI
 
   // From here on, pfd->mBounds rectangles are incorrect because bidi
   // might have moved frames around!
   nsOverflowAreas overflowAreas;
   aLineLayout.RelativePositionFrames(overflowAreas);
@@ -7215,21 +7211,17 @@ nsBlockFrame::ResolveBidi()
   NS_ASSERTION(!GetPrevInFlow(),
                "ResolveBidi called on non-first continuation");
 
   nsPresContext* presContext = PresContext();
   if (!presContext->BidiEnabled()) {
     return NS_OK;
   }
 
-  nsBidiPresUtils* bidiUtils = presContext->GetBidiUtils();
-  if (!bidiUtils)
-    return NS_ERROR_NULL_POINTER;
-
-  return bidiUtils->Resolve(this);
+  return nsBidiPresUtils::Resolve(this);
 }
 #endif
 
 #ifdef DEBUG
 void
 nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
 {
   if (!gVerifyLines) {
--- a/layout/generic/nsFrameList.cpp
+++ b/layout/generic/nsFrameList.cpp
@@ -443,27 +443,26 @@ nsFrameList::GetPrevVisualFor(nsIFrame* 
   if (!mFirstChild)
     return nsnull;
   
   nsIFrame* parent = mFirstChild->GetParent();
   if (!parent)
     return aFrame ? aFrame->GetPrevSibling() : LastChild();
 
   nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild);  
-  nsBidiPresUtils* bidiUtils = mFirstChild->PresContext()->GetBidiUtils();
 
   nsAutoLineIterator iter = parent->GetLineIterator();
   if (!iter) { 
     // Parent is not a block Frame
     if (parent->GetType() == nsGkAtoms::lineFrame) {
       // Line frames are not bidi-splittable, so need to consider bidi reordering
       if (baseLevel == NSBIDI_LTR) {
-        return bidiUtils->GetFrameToLeftOf(aFrame, mFirstChild, -1);
+        return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1);
       } else { // RTL
-        return bidiUtils->GetFrameToRightOf(aFrame, mFirstChild, -1);
+        return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1);
       }
     } else {
       // Just get the next or prev sibling, depending on block and frame direction.
       nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild);
       if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) {
         return aFrame ? aFrame->GetPrevSibling() : LastChild();
       } else {
         return aFrame ? aFrame->GetNextSibling() : mFirstChild;
@@ -488,57 +487,56 @@ nsFrameList::GetPrevVisualFor(nsIFrame* 
   PRInt32 numFramesOnLine;
   nsRect lineBounds;
   PRUint32 lineFlags;
 
   if (aFrame) {
     iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
 
     if (baseLevel == NSBIDI_LTR) {
-      frame = bidiUtils->GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine);
     } else { // RTL
-      frame = bidiUtils->GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine);
     }
   }
 
   if (!frame && thisLine > 0) {
     // Get the last frame of the previous line
     iter->GetLine(thisLine - 1, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
 
     if (baseLevel == NSBIDI_LTR) {
-      frame = bidiUtils->GetFrameToLeftOf(nsnull, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToLeftOf(nsnull, firstFrameOnLine, numFramesOnLine);
     } else { // RTL
-      frame = bidiUtils->GetFrameToRightOf(nsnull, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToRightOf(nsnull, firstFrameOnLine, numFramesOnLine);
     }
   }
   return frame;
 }
 
 nsIFrame*
 nsFrameList::GetNextVisualFor(nsIFrame* aFrame) const
 {
   if (!mFirstChild)
     return nsnull;
   
   nsIFrame* parent = mFirstChild->GetParent();
   if (!parent)
     return aFrame ? aFrame->GetPrevSibling() : mFirstChild;
 
   nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild);
-  nsBidiPresUtils* bidiUtils = mFirstChild->PresContext()->GetBidiUtils();
   
   nsAutoLineIterator iter = parent->GetLineIterator();
   if (!iter) { 
     // Parent is not a block Frame
     if (parent->GetType() == nsGkAtoms::lineFrame) {
       // Line frames are not bidi-splittable, so need to consider bidi reordering
       if (baseLevel == NSBIDI_LTR) {
-        return bidiUtils->GetFrameToRightOf(aFrame, mFirstChild, -1);
+        return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1);
       } else { // RTL
-        return bidiUtils->GetFrameToLeftOf(aFrame, mFirstChild, -1);
+        return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1);
       }
     } else {
       // Just get the next or prev sibling, depending on block and frame direction.
       nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild);
       if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) {
         return aFrame ? aFrame->GetNextSibling() : mFirstChild;
       } else {
         return aFrame ? aFrame->GetPrevSibling() : LastChild();
@@ -563,31 +561,31 @@ nsFrameList::GetNextVisualFor(nsIFrame* 
   PRInt32 numFramesOnLine;
   nsRect lineBounds;
   PRUint32 lineFlags;
 
   if (aFrame) {
     iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
     
     if (baseLevel == NSBIDI_LTR) {
-      frame = bidiUtils->GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine);
     } else { // RTL
-      frame = bidiUtils->GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine);
     }
   }
   
   PRInt32 numLines = iter->GetNumLines();
   if (!frame && thisLine < numLines - 1) {
     // Get the first frame of the next line
     iter->GetLine(thisLine + 1, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags);
     
     if (baseLevel == NSBIDI_LTR) {
-      frame = bidiUtils->GetFrameToRightOf(nsnull, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToRightOf(nsnull, firstFrameOnLine, numFramesOnLine);
     } else { // RTL
-      frame = bidiUtils->GetFrameToLeftOf(nsnull, firstFrameOnLine, numFramesOnLine);
+      frame = nsBidiPresUtils::GetFrameToLeftOf(nsnull, firstFrameOnLine, numFramesOnLine);
     }
   }
   return frame;
 }
 #endif
 
 #ifdef DEBUG_FRAME_LIST
 void
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -998,31 +998,27 @@ nsImageFrame::DisplayAltText(nsPresConte
     PRUint32  maxFit;  // number of characters that fit
     nscoord strWidth = MeasureString(str, strLen, aRect.width, maxFit,
                                      aRenderingContext);
     
     // Display the text
     nsresult rv = NS_ERROR_FAILURE;
 
     if (aPresContext->BidiEnabled()) {
-      nsBidiPresUtils* bidiUtils =  aPresContext->GetBidiUtils();
-      
-      if (bidiUtils) {
-        const nsStyleVisibility* vis = GetStyleVisibility();
-        if (vis->mDirection == NS_STYLE_DIRECTION_RTL)
-          rv = bidiUtils->RenderText(str, maxFit, NSBIDI_RTL,
-                                     aPresContext, aRenderingContext,
-                                     aRenderingContext,
-                                     aRect.XMost() - strWidth, y + maxAscent);
-        else
-          rv = bidiUtils->RenderText(str, maxFit, NSBIDI_LTR,
-                                     aPresContext, aRenderingContext,
-                                     aRenderingContext,
-                                     aRect.x, y + maxAscent);
-      }
+      const nsStyleVisibility* vis = GetStyleVisibility();
+      if (vis->mDirection == NS_STYLE_DIRECTION_RTL)
+        rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_RTL,
+                                         aPresContext, aRenderingContext,
+                                         aRenderingContext,
+                                         aRect.XMost() - strWidth, y + maxAscent);
+      else
+        rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_LTR,
+                                         aPresContext, aRenderingContext,
+                                         aRenderingContext,
+                                         aRect.x, y + maxAscent);
     }
     if (NS_FAILED(rv))
       aRenderingContext.DrawString(str, maxFit, aRect.x, y + maxAscent);
 
     // Move to the next line
     str += maxFit;
     strLen -= maxFit;
     y += height;
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -651,21 +651,19 @@ nsLineIterator::CheckLineOrder(PRInt32  
 
   if (!line->mFirstChild) { // empty line
     *aIsReordered = PR_FALSE;
     *aFirstVisual = nsnull;
     *aLastVisual = nsnull;
     return NS_OK;
   }
 
-  nsBidiPresUtils* bidiUtils = line->mFirstChild->PresContext()->GetBidiUtils();
-
   nsIFrame* leftmostFrame;
   nsIFrame* rightmostFrame;
-  *aIsReordered = bidiUtils->CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame);
+  *aIsReordered = nsBidiPresUtils::CheckLineOrder(line->mFirstChild, line->GetChildCount(), &leftmostFrame, &rightmostFrame);
 
   // map leftmost/rightmost to first/last according to paragraph direction
   *aFirstVisual = mRightToLeft ? rightmostFrame : leftmostFrame;
   *aLastVisual = mRightToLeft ? leftmostFrame : rightmostFrame;
 
   return NS_OK;
 }
 #endif // IBMBIDI
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -101,17 +101,16 @@
 #include "nsILineIterator.h"
 
 #include "nsIServiceManager.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 #include "nsAutoPtr.h"
 
-#include "nsBidiPresUtils.h"
 #include "nsBidiUtils.h"
 
 #include "gfxFont.h"
 #include "gfxContext.h"
 #include "gfxTextRunWordCache.h"
 #include "gfxImageSurface.h"
 
 #include "mozilla/dom/Element.h"
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -1516,58 +1516,55 @@ nsSVGGlyphFrame::EnsureTextRun(float *aD
   double textRunSize;
   if (mTextRun) {
     textRunSize = mTextRun->GetFontGroup()->GetStyle()->size;
   } else {
     nsAutoString text;
     if (!GetCharacterData(text))
       return PR_FALSE;
 
-    nsBidiPresUtils* bidiUtils = presContext->GetBidiUtils();
-    if (bidiUtils) {
-      nsAutoString visualText;
-
-      /*
-       * XXXsmontagu: The SVG spec says:
-       *
-       * http://www.w3.org/TR/SVG11/text.html#DirectionProperty
-       *  "For the 'direction' property to have any effect, the 'unicode-bidi'
-       *   property's value must be embed or bidi-override."
-       *
-       * The SVGTiny spec, on the other hand, says 
-       *
-       * http://www.w3.org/TR/SVGTiny12/text.html#DirectionProperty
-       *  "For the 'direction' property to have any effect on an element that 
-       *   does not by itself establish a new text chunk (such as the 'tspan'
-       *   element in SVG 1.2 Tiny), the 'unicode-bidi' property's value must
-       *   be embed or bidi-override."
-       *
-       * Note that this is different from HTML/CSS, where setting the 'dir'
-       *  attribute on an inline element automatically sets unicode-bidi: embed
-       *
-       * Our current implementation of bidi in SVG does not distinguish between
-       * different text elements, but treats every text container frame as a
-       * new text chunk, so we always set the base direction according to the
-       * direction property
-       *
-       * See also XXXsmontagu comments in nsSVGTextFrame::UpdateGlyphPositioning
-       */
-        
-      // Get the unicodeBidi property from the parent, because it doesn't
-      // inherit
-      PRBool bidiOverride = (mParent->GetStyleTextReset()->mUnicodeBidi ==
-                             NS_STYLE_UNICODE_BIDI_OVERRIDE);
-      nsBidiLevel baseDirection =
-        GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL ?
-          NSBIDI_RTL : NSBIDI_LTR;
-      bidiUtils->CopyLogicalToVisual(text, visualText,
-                                     baseDirection, bidiOverride);
-      if (!visualText.IsEmpty()) {
-        text = visualText;
-      }
+    nsAutoString visualText;
+      
+    /*
+     * XXXsmontagu: The SVG spec says:
+     *
+     * http://www.w3.org/TR/SVG11/text.html#DirectionProperty
+     *  "For the 'direction' property to have any effect, the 'unicode-bidi'
+     *   property's value must be embed or bidi-override."
+     *
+     * The SVGTiny spec, on the other hand, says 
+     *
+     * http://www.w3.org/TR/SVGTiny12/text.html#DirectionProperty
+     *  "For the 'direction' property to have any effect on an element that 
+     *   does not by itself establish a new text chunk (such as the 'tspan'
+     *   element in SVG 1.2 Tiny), the 'unicode-bidi' property's value must
+     *   be embed or bidi-override."
+     *
+     * Note that this is different from HTML/CSS, where setting the 'dir'
+     *  attribute on an inline element automatically sets unicode-bidi: embed
+     *
+     * Our current implementation of bidi in SVG does not distinguish between
+     * different text elements, but treats every text container frame as a
+     * new text chunk, so we always set the base direction according to the
+     * direction property
+     *
+     * See also XXXsmontagu comments in nsSVGTextFrame::UpdateGlyphPositioning
+     */
+    
+    // Get the unicodeBidi property from the parent, because it doesn't
+    // inherit
+    PRBool bidiOverride = (mParent->GetStyleTextReset()->mUnicodeBidi ==
+                           NS_STYLE_UNICODE_BIDI_OVERRIDE);
+    nsBidiLevel baseDirection =
+      GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL ?
+        NSBIDI_RTL : NSBIDI_LTR;
+    nsBidiPresUtils::CopyLogicalToVisual(text, visualText,
+                                         baseDirection, bidiOverride);
+    if (!visualText.IsEmpty()) {
+      text = visualText;
     }
 
     gfxMatrix m;
     if (aForceGlobalTransform ||
         !(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
       if (!GetGlobalTransform(&m))
         return PR_FALSE;
     }
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -550,42 +550,38 @@ nsTextBoxFrame::DrawText(nsRenderingCont
 
     aRenderingContext.SetColor(aOverrideColor ? *aOverrideColor : GetStyleColor()->mColor);
 
 #ifdef IBMBIDI
     nsresult rv = NS_ERROR_FAILURE;
 
     if (mState & NS_FRAME_IS_BIDI) {
       presContext->SetBidiEnabled();
-      nsBidiPresUtils* bidiUtils = presContext->GetBidiUtils();
-
-      if (bidiUtils) {
-        const nsStyleVisibility* vis = GetStyleVisibility();
-        nsBidiDirection direction = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ? NSBIDI_RTL : NSBIDI_LTR;
-        if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
-           // We let the RenderText function calculate the mnemonic's
-           // underline position for us.
-           nsBidiPositionResolve posResolve;
-           posResolve.logicalIndex = mAccessKeyInfo->mAccesskeyIndex;
-           rv = bidiUtils->RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), direction,
-                                      presContext, aRenderingContext,
-                                      *refContext,
-                                      aTextRect.x, baseline,
-                                      &posResolve,
-                                      1);
-           mAccessKeyInfo->mBeforeWidth = posResolve.visualLeftTwips;
-           mAccessKeyInfo->mAccessWidth = posResolve.visualWidth;
-        }
-        else
-        {
-           rv = bidiUtils->RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), direction,
-                                      presContext, aRenderingContext,
-                                      *refContext,
-                                      aTextRect.x, baseline);
-        }
+      const nsStyleVisibility* vis = GetStyleVisibility();
+      nsBidiDirection direction = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ? NSBIDI_RTL : NSBIDI_LTR;
+      if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
+          // We let the RenderText function calculate the mnemonic's
+          // underline position for us.
+          nsBidiPositionResolve posResolve;
+          posResolve.logicalIndex = mAccessKeyInfo->mAccesskeyIndex;
+          rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), direction,
+                                           presContext, aRenderingContext,
+                                           *refContext,
+                                           aTextRect.x, baseline,
+                                           &posResolve,
+                                           1);
+          mAccessKeyInfo->mBeforeWidth = posResolve.visualLeftTwips;
+          mAccessKeyInfo->mAccessWidth = posResolve.visualWidth;
+      }
+      else
+      {
+          rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), direction,
+                                           presContext, aRenderingContext,
+                                           *refContext,
+                                           aTextRect.x, baseline);
       }
     }
     if (NS_FAILED(rv) )
 #endif // IBMBIDI
     {
        aRenderingContext.SetTextRunRTL(PR_FALSE);
 
        if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -100,17 +100,17 @@
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsEventDispatcher.h"
 #include "nsDisplayList.h"
 #include "nsTreeBoxObject.h"
 #include "nsRenderingContext.h"
 
 #ifdef IBMBIDI
-#include "nsBidiPresUtils.h"
+#include "nsBidiUtils.h"
 #endif
 
 // Enumeration function that cancels all the image requests in our cache
 static PLDHashOperator
 CancelImageRequest(const nsAString& aKey,
                    nsTreeImageCacheEntry aEntry, void* aData)
 {
   aEntry.request->CancelAndForgetObserver(NS_BINDING_ABORTED);