Bug 571995. r=roc a=blocking2.0:final
authorMats Palmgren <matspal@gmail.com>
Fri, 15 Oct 2010 06:03:33 +0200
changeset 55835 9a1c991eddb067e2c6800ab16c622c2cbbd8d22c
parent 55834 9f342c85157a3e8235da059eb16cbfa6bf519317
child 55836 ad23e7efe0caec2232572c0d332dc70fe5767afc
push idunknown
push userunknown
push dateunknown
reviewersroc, blocking2
bugs571995
milestone2.0b8pre
Bug 571995. r=roc a=blocking2.0:final
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -24,17 +24,17 @@
  *   Roger B. Sidje <rbs@maths.uq.edu.au>
  *   Pierre Phaneuf <pp@ludusdesign.com>
  *   Prabhat Hegde <prabhat.hegde@sun.com>
  *   Tomi Leppikangas <tomi.leppikangas@oulu.fi>
  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
  *   Daniel Glazman <glazman@netscape.com>
  *   Neil Deakin <neil@mozdevgroup.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Uri Bernstein <uriber@gmail.com>
  *   Stephen Blackheath <entangled.mooched.stephen@blacksapphire.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
@@ -328,19 +328,16 @@ public:
   PRInt32 GetContentLengthHint() const { return mContentLengthHint; }
 
   // Compute the length of the content mapped by this frame
   // and all its in-flow siblings. Basically this means starting at mContentOffset
   // and going to the end of the text node or the next bidi continuation
   // boundary.
   PRInt32 GetInFlowContentLength();
 
-  // Clears out mTextRun from this frame and all other frames that hold a reference
-  // to it, then deletes the textrun.
-  void ClearTextRun();
   /**
    * Acquires the text run for this content, if necessary.
    * @param aRC the rendering context to use as a reference for creating
    * the textrun, if available (if not, we'll create one which will just be slower)
    * @param aBlock the block ancestor for this frame, or nsnull if unknown
    * @param aLine the line that this frame is on, if any, or nsnull if unknown
    * @param aFlowEndInTextRun if non-null, this returns the textrun offset of
    * end of the text associated with this frame and its in-flow siblings
@@ -350,16 +347,22 @@ public:
    */
   gfxSkipCharsIterator EnsureTextRun(gfxContext* aReferenceContext = nsnull,
                                      nsIFrame* aLineContainer = nsnull,
                                      const nsLineList::iterator* aLine = nsnull,
                                      PRUint32* aFlowEndInTextRun = nsnull);
 
   gfxTextRun* GetTextRun() { return mTextRun; }
   void SetTextRun(gfxTextRun* aTextRun) { mTextRun = aTextRun; }
+  /**
+   * Clears out |mTextRun| from all frames that hold a reference to it,
+   * starting at |aStartContinuation|, or if it's nsnull, starting at |this|.
+   * Deletes |mTextRun| if all references were cleared and it's not cached.
+   */
+  void ClearTextRun(nsTextFrame* aStartContinuation);
 
   // Get the DOM content range mapped by this frame after excluding
   // whitespace subject to start-of-line and end-of-line trimming.
   // The textrun must have been created before calling this.
   struct TrimmedOffsets {
     PRInt32 mStart;
     PRInt32 mLength;
     PRInt32 GetEnd() { return mStart + mLength; }
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -24,17 +24,17 @@
  *   Roger B. Sidje <rbs@maths.uq.edu.au>
  *   Pierre Phaneuf <pp@ludusdesign.com>
  *   Prabhat Hegde <prabhat.hegde@sun.com>
  *   Tomi Leppikangas <tomi.leppikangas@oulu.fi>
  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
  *   Daniel Glazman <glazman@netscape.com>
  *   Neil Deakin <neil@mozdevgroup.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Uri Bernstein <uriber@gmail.com>
  *   Stephen Blackheath <entangled.mooched.stephen@blacksapphire.com>
  *   Michael Ventnor <m.ventnor@gmail.com>
  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -357,54 +357,108 @@ static void
 DestroyUserData(void* aUserData)
 {
   TextRunUserData* userData = static_cast<TextRunUserData*>(aUserData);
   if (userData) {
     nsMemory::Free(userData);
   }
 }
 
-// Remove the textrun from the frame continuation chain starting at aFrame,
-// which should be marked as a textrun owner.
-static void
-ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun)
-{
-  aFrame->RemoveStateBits(TEXT_IN_TEXTRUN_USER_DATA);
+/**
+ * Remove |aTextRun| from the frame continuation chain starting at
+ * |aStartContinuation| if non-null, otherwise starting at |aFrame|.
+ * Unmark |aFrame| as a text run owner if it's the frame we start at.
+ * Return PR_TRUE if |aStartContinuation| is non-null and was found
+ * in the next-continuation chain of |aFrame|.
+ */
+static PRBool
+ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun,
+                          nsTextFrame* aStartContinuation)
+{
+  NS_PRECONDITION(aFrame, "");
+  NS_PRECONDITION(!aStartContinuation ||
+                  !aStartContinuation->GetTextRun() ||
+                  aStartContinuation->GetTextRun() == aTextRun,
+                  "wrong aStartContinuation for this text run");
+
+  if (!aStartContinuation || aStartContinuation == aFrame) {
+    aFrame->RemoveStateBits(TEXT_IN_TEXTRUN_USER_DATA);
+  } else {
+    do {
+      NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame, "Bad frame");
+      aFrame = static_cast<nsTextFrame*>(aFrame->GetNextContinuation());
+    } while (aFrame && aFrame != aStartContinuation);
+  }
+  PRBool found = aStartContinuation == aFrame;
   while (aFrame) {
-    NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame,
-                 "Bad frame");
+    NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame, "Bad frame");
     if (aFrame->GetTextRun() != aTextRun)
       break;
     aFrame->SetTextRun(nsnull);
     aFrame = static_cast<nsTextFrame*>(aFrame->GetNextContinuation());
   }
-}
-
-// Figure out which frames 
+  NS_POSTCONDITION(!found || aStartContinuation, "how did we find null?");
+  return found;
+}
+
+/**
+ * Kill all references to |aTextRun| starting at |aStartContinuation|.
+ * It could be referenced by any of its owners, and all their in-flows.
+ * If |aStartContinuation| is null then process all userdata frames
+ * and their continuations.
+ * @note the caller is expected to take care of possibly destroying the
+ * text run if all userdata frames were reset (userdata is deallocated
+ * by this function though). The caller can detect this has occured by
+ * checking |aTextRun->GetUserData() == nsnull|.
+ */
 static void
-UnhookTextRunFromFrames(gfxTextRun* aTextRun)
+UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation)
 {
   if (!aTextRun->GetUserData())
     return;
 
-  // Kill all references to the textrun. It could be referenced by any of its
-  // owners, and all their in-flows.
   if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
-    nsIFrame* firstInFlow = static_cast<nsIFrame*>(aTextRun->GetUserData());
-    ClearAllTextRunReferences(static_cast<nsTextFrame*>(firstInFlow), aTextRun);
+    nsIFrame* userDataFrame = static_cast<nsIFrame*>(aTextRun->GetUserData());
+    PRBool found =
+      ClearAllTextRunReferences(static_cast<nsTextFrame*>(userDataFrame),
+                                aTextRun, aStartContinuation);
+    NS_ASSERTION(!aStartContinuation || found,
+                 "aStartContinuation wasn't found in simple flow text run");
+    if (!(userDataFrame->GetStateBits() & TEXT_IN_TEXTRUN_USER_DATA)) {
+      aTextRun->SetUserData(nsnull);
+    }
   } else {
     TextRunUserData* userData =
       static_cast<TextRunUserData*>(aTextRun->GetUserData());
-    PRInt32 i;
-    for (i = 0; i < userData->mMappedFlowCount; ++i) {
-      ClearAllTextRunReferences(userData->mMappedFlows[i].mStartFrame, aTextRun);
-    }
-    DestroyUserData(userData);
-  }
-  aTextRun->SetUserData(nsnull);  
+    PRInt32 destroyFromIndex = aStartContinuation ? -1 : 0;
+    for (PRInt32 i = 0; i < userData->mMappedFlowCount; ++i) {
+      nsTextFrame* userDataFrame = userData->mMappedFlows[i].mStartFrame;
+      PRBool found =
+        ClearAllTextRunReferences(userDataFrame, aTextRun,
+                                  aStartContinuation);
+      if (found) {
+        if (userDataFrame->GetStateBits() & TEXT_IN_TEXTRUN_USER_DATA) {
+          destroyFromIndex = i + 1;
+        }
+        else {
+          destroyFromIndex = i;
+        }
+        aStartContinuation = nsnull;
+      }
+    }
+    NS_ASSERTION(destroyFromIndex >= 0,
+                 "aStartContinuation wasn't found in multi flow text run");
+    if (destroyFromIndex == 0) {
+      DestroyUserData(userData);
+      aTextRun->SetUserData(nsnull);
+    }
+    else {
+      userData->mMappedFlowCount = destroyFromIndex;
+    }
+  }
 }
 
 class FrameTextRunCache;
 
 static FrameTextRunCache *gTextRuns = nsnull;
 
 /*
  * Cache textruns and expire them after 3*10 seconds of no use.
@@ -424,17 +478,17 @@ public:
     }
     if (aTextRun->GetFlags() & gfxTextRunWordCache::TEXT_IN_CACHE) {
       gfxTextRunWordCache::RemoveTextRun(aTextRun);
     }
   }
 
   // This gets called when the timeout has expired on a gfxTextRun
   virtual void NotifyExpired(gfxTextRun* aTextRun) {
-    UnhookTextRunFromFrames(aTextRun);
+    UnhookTextRunFromFrames(aTextRun, nsnull);
     RemoveFromCache(aTextRun);
     delete aTextRun;
   }
 };
 
 static gfxTextRun *
 MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
             gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams,
@@ -1967,17 +2021,40 @@ BuildTextRunsScanner::AssignTextRun(gfxT
           if (PRUint32(userData->mMappedFlowCount) >= mMappedFlows.Length() ||
               userData->mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame !=
               mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame) {
             NS_WARNING("REASSIGNING MULTIFLOW TEXT RUN (not append)!");
           }
         }
       }
 #endif
-      f->ClearTextRun();
+#ifdef DEBUG
+      gfxTextRun* oldTextRun = f->GetTextRun();
+      nsTextFrame* firstFrame = nsnull;
+      if (oldTextRun) {
+        if (oldTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
+          firstFrame = static_cast<nsTextFrame*>(oldTextRun->GetUserData());
+        }
+        else {
+          TextRunUserData* userData =
+            static_cast<TextRunUserData*>(oldTextRun->GetUserData());
+          firstFrame = userData->mMappedFlows[0].mStartFrame;
+        }
+      }
+#endif
+      f->ClearTextRun(f);
+#ifdef DEBUG
+      if (firstFrame && !firstFrame->GetTextRun()) {
+        // oldTextRun was destroyed - assert that we don't reference it.
+        for (PRUint32 i = 0; i < mBreakSinks.Length(); ++i) {
+          NS_ASSERTION(oldTextRun != mBreakSinks[i]->mTextRun,
+                       "destroyed text run is still in use");
+        }
+      }
+#endif
       f->SetTextRun(aTextRun);
     }
     // Set this bit now; we can't set it any earlier because
     // f->ClearTextRun() might clear it out.
     startFrame->AddStateBits(TEXT_IN_TEXTRUN_USER_DATA);
   }
 }
 
@@ -3488,17 +3565,17 @@ nsTextFrame::ClearFrameOffsetCache()
 void
 nsTextFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   ClearFrameOffsetCache();
 
   // We might want to clear NS_CREATE_FRAME_IF_NON_WHITESPACE or
   // NS_REFRAME_IF_WHITESPACE on mContent here, since our parent frame
   // type might be changing.  Not clear whether it's worth it.
-  ClearTextRun();
+  ClearTextRun(nsnull);
   if (mNextContinuation) {
     mNextContinuation->SetPrevInFlow(nsnull);
   }
   // Let the base class destroy the frame
   nsFrame::DestroyFrom(aDestructRoot);
 }
 
 class nsContinuingTextFrame : public nsTextFrame {
@@ -3576,17 +3653,17 @@ nsContinuingTextFrame::Init(nsIContent* 
   aPrevInFlow->SetNextInFlow(this);
   nsTextFrame* prev = static_cast<nsTextFrame*>(aPrevInFlow);
   mContentOffset = prev->GetContentOffset() + prev->GetContentLengthHint();
   NS_ASSERTION(mContentOffset < PRInt32(aContent->GetText()->GetLength()),
                "Creating ContinuingTextFrame, but there is no more content");
   if (prev->GetStyleContext() != GetStyleContext()) {
     // We're taking part of prev's text, and its style may be different
     // so clear its textrun which may no longer be valid (and don't set ours)
-    prev->ClearTextRun();
+    prev->ClearTextRun(nsnull);
   } else {
     mTextRun = prev->GetTextRun();
   }
 #ifdef IBMBIDI
   if (aPrevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) {
     FramePropertyTable *propTable = PresContext()->PropertyTable();
     // Get all the properties from the prev-in-flow first to take
     // advantage of the propTable's cache and simplify the assertion below
@@ -3628,21 +3705,21 @@ nsContinuingTextFrame::DestroyFrom(nsIFr
   // frame chain from the start to the end.
   // If this frame is mentioned in the userData for a textrun (say
   // because there's a direction change at the start of this frame), then
   // we have to clear the textrun because we're going away and the
   // textrun had better not keep a dangling reference to us.
   if ((GetStateBits() & TEXT_IN_TEXTRUN_USER_DATA) ||
       !mPrevContinuation ||
       mPrevContinuation->GetStyleContext() != GetStyleContext()) {
-    ClearTextRun();
+    ClearTextRun(nsnull);
     // Clear the previous continuation's text run also, so that it can rebuild
     // the text run to include our text.
     if (mPrevContinuation) {
-      (static_cast<nsTextFrame*>(mPrevContinuation))->ClearTextRun();
+      (static_cast<nsTextFrame*>(mPrevContinuation))->ClearTextRun(nsnull);
     }
   }
   nsSplittableFrame::RemoveFromFlow(this);
   // Let the base class destroy the frame
   nsFrame::DestroyFrom(aDestructRoot);
 }
 
 nsIFrame*
@@ -3813,38 +3890,39 @@ nsTextFrame::GetLastContinuation() const
   while (lastInFlow->mNextContinuation)  {
     lastInFlow = static_cast<nsTextFrame*>(lastInFlow->mNextContinuation);
   }
   NS_POSTCONDITION(lastInFlow, "illegal state in continuation chain.");
   return lastInFlow;
 }
 
 void
-nsTextFrame::ClearTextRun()
-{
-  // save textrun because ClearAllTextRunReferences will clear ours
+nsTextFrame::ClearTextRun(nsTextFrame* aStartContinuation)
+{
+  // save textrun because ClearAllTextRunReferences may clear ours
   gfxTextRun* textRun = mTextRun;
   
   if (!textRun)
     return;
 
-  UnhookTextRunFromFrames(textRun);
+  UnhookTextRunFromFrames(textRun, aStartContinuation);
   // see comments in BuildTextRunForFrames...
 //  if (textRun->GetFlags() & gfxFontGroup::TEXT_IS_PERSISTENT) {
 //    NS_ERROR("Shouldn't reach here for now...");
 //    // the textrun's text may be referencing a DOM node that has changed,
 //    // so we'd better kill this textrun now.
 //    if (textRun->GetExpirationState()->IsTracked()) {
 //      gTextRuns->RemoveFromCache(textRun);
 //    }
 //    delete textRun;
 //    return;
 //  }
 
-  if (!(textRun->GetFlags() & gfxTextRunWordCache::TEXT_IN_CACHE)) {
+  if (!(textRun->GetFlags() & gfxTextRunWordCache::TEXT_IN_CACHE) &&
+      !textRun->GetUserData()) {
     // Remove it now because it's not doing anything useful
     gTextRuns->RemoveFromCache(textRun);
     delete textRun;
   }
 }
 
 NS_IMETHODIMP
 nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
@@ -3865,17 +3943,17 @@ nsTextFrame::CharacterDataChanged(Charac
   PRInt32 endOfChangedText = aInfo->mChangeStart + aInfo->mReplaceLength;
   nsTextFrame* lastDirtiedFrame = nsnull;
 
   nsIPresShell* shell = PresContext()->GetPresShell();
   do {
     // textFrame contained deleted text (or the insertion point,
     // if this was a pure insertion).
     textFrame->mState &= ~TEXT_WHITESPACE_FLAGS;
-    textFrame->ClearTextRun();
+    textFrame->ClearTextRun(nsnull);
     if (!lastDirtiedFrame ||
         lastDirtiedFrame->GetParent() != textFrame->GetParent()) {
       // Ask the parent frame to reflow me.
       shell->FrameNeedsReflow(textFrame, nsIPresShell::eStyleChange,
                               NS_FRAME_IS_DIRTY);
       lastDirtiedFrame = textFrame;
     } else {
       // if the parent is a block, we're cheating here because we should
@@ -3905,29 +3983,29 @@ nsTextFrame::CharacterDataChanged(Charac
 
   if (sizeChange) {
     // Fix the offsets of the text frames that start in the trailing
     // unchanged text.
     while (textFrame) {
       textFrame->mContentOffset += sizeChange;
       // XXX we could rescue some text runs by adjusting their user data
       // to reflect the change in DOM offsets
-      textFrame->ClearTextRun();
+      textFrame->ClearTextRun(nsnull);
       textFrame = static_cast<nsTextFrame*>(textFrame->GetNextContinuation());
     }
   }
 
   return NS_OK;
 }
 
 /* virtual */ void
 nsTextFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   nsFrame::DidSetStyleContext(aOldStyleContext);
-  ClearTextRun();
+  ClearTextRun(nsnull);
 } 
 
 class nsDisplayText : public nsDisplayItem {
 public:
   nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame) :
     nsDisplayItem(aBuilder, aFrame) {
     MOZ_COUNT_CTOR(nsDisplayText);
   }
@@ -5789,17 +5867,17 @@ FindStartAfterSkippingWhitespace(Propert
     }
   }
   return aIterator->GetSkippedOffset();
 }
 
 /* virtual */ 
 void nsTextFrame::MarkIntrinsicWidthsDirty()
 {
-  ClearTextRun();
+  ClearTextRun(nsnull);
   nsFrame::MarkIntrinsicWidthsDirty();
 }
 
 // XXX this doesn't handle characters shaped by line endings. We need to
 // temporarily override the "current line ending" settings.
 void
 nsTextFrame::AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext,
                                       nsIFrame::InlineMinWidthData *aData)
@@ -6135,31 +6213,31 @@ nsTextFrame::SetLength(PRInt32 aLength, 
       (end != f->mContentOffset || (f->GetStateBits() & NS_FRAME_IS_DIRTY))) {
     aLineLayout->SetDirtyNextLine();
   }
 
   if (end < f->mContentOffset) {
     // Our frame is shrinking. Give the text to our next in flow.
     f->mContentOffset = end;
     if (f->GetTextRun() != mTextRun) {
-      ClearTextRun();
-      f->ClearTextRun();
+      ClearTextRun(nsnull);
+      f->ClearTextRun(nsnull);
     }
     return;
   }
   // Our frame is growing. Take text from our in-flow(s).
   // We can take text from frames in lines beyond just the next line.
   // We don't dirty those lines. That's OK, because when we reflow
   // our empty next-in-flow, it will take text from its next-in-flow and
   // dirty that line.
   while (f && f->mContentOffset < end) {
     f->mContentOffset = end;
     if (f->GetTextRun() != mTextRun) {
-      ClearTextRun();
-      f->ClearTextRun();
+      ClearTextRun(nsnull);
+      f->ClearTextRun(nsnull);
     }
     f = static_cast<nsTextFrame*>(f->GetNextInFlow());
   }
 
 #ifdef DEBUG
   f = this;
   PRInt32 iterations = 0;
   while (f && iterations < 10) {
@@ -6326,17 +6404,17 @@ nsTextFrame::ReflowText(nsLineLayout& aL
   // the gfxTextRun based on our layout.
   if (aLineLayout.GetInFirstLetter() || aLineLayout.GetInFirstLine()) {
     SetLength(maxContentLength, &aLineLayout);
 
     if (aLineLayout.GetInFirstLetter()) {
       // floating first-letter boundaries are significant in textrun
       // construction, so clear the textrun out every time we hit a first-letter
       // and have changed our length (which controls the first-letter boundary)
-      ClearTextRun();
+      ClearTextRun(nsnull);
       // Find the length of the first-letter. We need a textrun for this.
       gfxSkipCharsIterator iter =
         EnsureTextRun(ctx, lineContainer, aLineLayout.GetLine(), &flowEndInTextRun);
 
       if (mTextRun) {
         PRInt32 firstLetterLength = length;
         if (aLineLayout.GetFirstLetterStyleOK()) {
           completedFirstLetter =
@@ -6364,30 +6442,30 @@ nsTextFrame::ReflowText(nsLineLayout& aL
         if (length) {
           AddStateBits(TEXT_FIRST_LETTER);
         }
         // Change this frame's length to the first-letter length right now
         // so that when we rebuild the textrun it will be built with the
         // right first-letter boundary
         SetLength(offset + length - GetContentOffset(), &aLineLayout);
         // Ensure that the textrun will be rebuilt
-        ClearTextRun();
+        ClearTextRun(nsnull);
       }
     } 
   }
 
   gfxSkipCharsIterator iter =
     EnsureTextRun(ctx, lineContainer, aLineLayout.GetLine(), &flowEndInTextRun);
 
   if (mTextRun && iter.GetOriginalEnd() < offset + length) {
     // The textrun does not map enough text for this frame. This can happen
     // when the textrun was ended in the middle of a text node because a
     // preformatted newline was encountered, and prev-in-flow frames have
     // consumed all the text of the textrun. We need a new textrun.
-    ClearTextRun();
+    ClearTextRun(nsnull);
     iter = EnsureTextRun(ctx, lineContainer,
                          aLineLayout.GetLine(), &flowEndInTextRun);
   }
 
   if (!mTextRun) {
     ClearMetrics(aMetrics);
     aStatus = NS_FRAME_COMPLETE;
     return;
@@ -7106,26 +7184,26 @@ nsTextFrame::AdjustOffsetsForBidi(PRInt3
 {
   AddStateBits(NS_FRAME_IS_BIDI);
 
   /*
    * After Bidi resolution we may need to reassign text runs.
    * This is called during bidi resolution from the block container, so we
    * shouldn't be holding a local reference to a textrun anywhere.
    */
-  ClearTextRun();
+  ClearTextRun(nsnull);
 
   nsTextFrame* prev = static_cast<nsTextFrame*>(GetPrevContinuation());
   if (prev) {
     // the bidi resolver can be very evil when columns/pages are involved. Don't
     // let it violate our invariants.
     PRInt32 prevOffset = prev->GetContentOffset();
     aStart = NS_MAX(aStart, prevOffset);
     aEnd = NS_MAX(aEnd, prevOffset);
-    prev->ClearTextRun();
+    prev->ClearTextRun(nsnull);
   }
 
   mContentOffset = aStart;
   SetLength(aEnd - aStart, nsnull);
 }
 
 /**
  * @return PR_TRUE if this text frame ends with a newline character.  It should return