Bug 750066. r=roc a=lsblakk
authorMats Palmgren <matspal@gmail.com>
Thu, 10 May 2012 01:14:26 +0200
changeset 92185 0acdebce3898b88b762666fbdff006cabdb3ad9d
parent 92184 303d987789c5cd1b1a0504657b33b3aa3bc1ac01
child 92186 31261e28a23960ac28fef527273b21cb0920cef2
push idunknown
push userunknown
push dateunknown
reviewersroc, lsblakk
bugs750066
milestone13.0
Bug 750066. r=roc a=lsblakk
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -276,17 +276,16 @@ RecordReflowStatus(bool aChildIsBlock, n
 
 // Destructor function for the overflowLines frame property
 static void
 DestroyOverflowLines(void* aPropertyValue)
 {
   NS_ERROR("Overflow lines should never be destroyed by the FramePropertyTable");
 }
 
-NS_DECLARE_FRAME_PROPERTY(LineCursorProperty, nsnull)
 NS_DECLARE_FRAME_PROPERTY(OverflowLinesProperty, DestroyOverflowLines)
 NS_DECLARE_FRAME_PROPERTY(OverflowOutOfFlowsProperty,
                           nsContainerFrame::DestroyFrameList)
 NS_DECLARE_FRAME_PROPERTY(PushedFloatProperty,
                           nsContainerFrame::DestroyFrameList)
 NS_DECLARE_FRAME_PROPERTY(OutsideBulletProperty,
                           nsContainerFrame::DestroyFrameList)
 NS_DECLARE_FRAME_PROPERTY(InsideBulletProperty, nsnull)
@@ -307,23 +306,22 @@ NS_IMPL_FRAMEARENA_HELPERS(nsBlockFrame)
 
 nsBlockFrame::~nsBlockFrame()
 {
 }
 
 void
 nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
+  ClearLineCursor();
   DestroyAbsoluteFrames(aDestructRoot);
-
   mFloats.DestroyFramesFrom(aDestructRoot);
-
   nsPresContext* presContext = PresContext();
-
   nsLineBox::DeleteLineList(presContext, mLines, aDestructRoot);
+
   // Now clear mFrames, since we've destroyed all the frames in it.
   mFrames.Clear();
 
   nsFrameList* pushedFloats = RemovePushedFloats();
   if (pushedFloats) {
     pushedFloats->DestroyFrom(aDestructRoot);
   }
 
@@ -2264,20 +2262,23 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
         }
         isOverflowLine = true;
       }
 
       if (pulledFrames.IsEmpty()) {
         // The line is empty. Try the next one.
         NS_ASSERTION(pulledLine->GetChildCount() == 0 &&
                      !pulledLine->mFirstChild, "bad empty line");
-        FreeLineBox(pulledLine);
+        nextInFlow->FreeLineBox(pulledLine);
         continue;
       }
 
+      if (pulledLine == nextInFlow->GetLineCursor()) {
+        nextInFlow->ClearLineCursor();
+      }
       ReparentFrames(pulledFrames, nextInFlow, this);
 
       NS_ASSERTION(pulledFrames.LastChild() == pulledLine->LastChild(),
                    "Unexpected last frame");
       NS_ASSERTION(aState.mPrevChild || mLines.empty(), "should have a prevchild here");
       NS_ASSERTION(aState.mPrevChild == mFrames.LastChild(),
                    "Incorrect aState.mPrevChild before inserting line at end");
 
@@ -2382,16 +2383,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
 
   if (foundAnyClears) {
     AddStateBits(NS_BLOCK_HAS_CLEAR_CHILDREN);
   } else {
     RemoveStateBits(NS_BLOCK_HAS_CLEAR_CHILDREN);
   }
 
 #ifdef DEBUG
+  VerifyLines(true);
+  VerifyOverflowSituation();
   if (gNoisyReflow) {
     IndentBy(stdout, gNoiseIndent - 1);
     ListTag(stdout);
     printf(": done reflowing dirty lines (status=%x)\n",
            aState.mReflowStatus);
   }
 #endif
 
@@ -2457,17 +2460,17 @@ nsBlockFrame::DeleteLine(nsBlockReflowSt
                          nsLineList::iterator aLine,
                          nsLineList::iterator aLineEnd)
 {
   NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
   if (0 == aLine->GetChildCount()) {
     NS_ASSERTION(aState.mCurrentLine == aLine,
                  "using function more generally than designed, "
                  "but perhaps OK now");
-    nsLineBox *line = aLine;
+    nsLineBox* line = aLine;
     aLine = mLines.erase(aLine);
     FreeLineBox(line);
     // Mark the previous margin of the next line dirty since we need to
     // recompute its top position.
     if (aLine != aLineEnd)
       aLine->MarkPreviousMarginDirty();
   }
 }
@@ -2689,32 +2692,33 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo
     nsLineList* fromLineList =
       aFromOverflowLine ? &overflowLines->mLines : &aFromContainer->mLines;
     if (aFromLine.next() != fromLineList->end())
       aFromLine.next()->MarkPreviousMarginDirty();
 
     Invalidate(fromLine->GetVisualOverflowArea());
     fromLineList->erase(aFromLine);
     // aFromLine is now invalid
-    FreeLineBox(fromLine);
+    aFromContainer->FreeLineBox(fromLine);
 
     // Put any remaining overflow lines back.
     if (aFromOverflowLine) {
       if (!fromLineList->empty()) {
         aFromContainer->SetOverflowLines(overflowLines);
       } else {
         delete overflowLines;
         // Now any iterators into fromLineList are invalid (but
         // aFromLine already was invalidated above)
       }
     }
   }
 
 #ifdef DEBUG
   VerifyLines(true);
+  VerifyOverflowSituation();
 #endif
 
   return frame;
 }
 
 static void
 PlaceFrameView(nsIFrame* aFrame)
 {
@@ -4464,16 +4468,17 @@ nsBlockFrame::DrainOverflowLines()
   VerifyOverflowSituation();
 #endif
   FrameLines* overflowLines = nsnull;
   FrameLines* ourOverflowLines = nsnull;
 
   // First grab the prev-in-flows overflow lines
   nsBlockFrame* prevBlock = (nsBlockFrame*) GetPrevInFlow();
   if (prevBlock) {
+    prevBlock->ClearLineCursor();
     overflowLines = prevBlock->RemoveOverflowLines();
     if (overflowLines) {
       NS_ASSERTION(!overflowLines->mLines.empty(),
                    "overflow lines should never be set and empty");
       // Make all the frames on the overflow line list mine.
       ReparentFrames(overflowLines->mFrames, prevBlock, this);
 
       // Make the overflow out-of-flow frames mine too.
@@ -5223,18 +5228,17 @@ nsBlockInFlowLineIterator::nsBlockInFlow
 {
   *aFoundValidLine = false;
 
   nsIFrame* child = FindChildContaining(aFrame, aFindFrame);
   if (!child)
     return;
 
   // Try to use the cursor if it exists, otherwise fall back to the first line
-  nsLineBox* cursor = static_cast<nsLineBox*>
-    (aFrame->Properties().Get(LineCursorProperty()));
+  nsLineBox* cursor = aFrame->GetLineCursor();
   if (!cursor) {
     line_iterator iter = aFrame->begin_lines();
     if (iter != aFrame->end_lines()) {
       cursor = iter;
     }
   }
 
   if (cursor) {
@@ -5407,18 +5411,16 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
     }
     else {
       nsContainerFrame::DeleteNextInFlowChild(presContext, aDeletedFrame,
                                               (aFlags & FRAMES_ARE_EMPTY) != 0);
     }
     return NS_OK;
   }
 
-  nsIPresShell* presShell = presContext->PresShell();
-
   // Find the line that contains deletedFrame
   nsLineList::iterator line_start = mLines.begin(),
                        line_end = mLines.end();
   nsLineList::iterator line = line_start;
   FrameLines* overflowLines = nsnull;
   bool searchingOverflowList = false;
   // Make sure we look in the overflow lines even if the normal line
   // list is empty
@@ -5557,17 +5559,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
           // We just invalidated our iterators.  Since we were in
           // the overflow lines list, which is now empty, set them
           // so we're at the end of the regular line list.
           line_start = mLines.begin();
           line_end = mLines.end();
           line = line_end;
         }
       }
-      cur->Destroy(presShell);
+      FreeLineBox(cur);
 
       // If we're removing a line, ReflowDirtyLines isn't going to
       // know that it needs to slide lines unless something is marked
       // dirty.  So mark the previous margin of the next line dirty if
       // there is one.
       if (line != line_end) {
         line->MarkPreviousMarginDirty();
       }
@@ -5619,16 +5621,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
 
   if (!(aFlags & FRAMES_ARE_EMPTY) && line.next() != line_end) {
     line.next()->MarkDirty();
     line.next()->SetInvalidateTextRuns(true);
   }
 
 #ifdef DEBUG
   VerifyLines(true);
+  VerifyOverflowSituation();
 #endif
 
   // Advance to next flow block if the frame has more continuations
   return RemoveBlockChild(aDeletedFrame, !(aFlags & REMOVE_FIXED_CONTINUATIONS));
 }
 
 nsresult
 nsBlockFrame::StealFrame(nsPresContext* aPresContext,
@@ -5700,17 +5703,17 @@ nsBlockFrame::StealFrame(nsPresContext* 
               // so we're at the end of the regular line list.
               line_start = mLines.begin();
               line_end = mLines.end();
               line = line_end;
             }
           } else {
             line = mLines.erase(line);
           }
-          lineBox->Destroy(aPresContext->PresShell());
+          FreeLineBox(lineBox);
           if (line != line_end) {
             // Line disappeared, so tell next line it may have to change position
             line->MarkPreviousMarginDirty();
           }
         }
 
         // Ok, we're done
         return NS_OK;
@@ -7140,23 +7143,28 @@ nsBlockFrame::VerifyLines(bool aFinalChe
 {
   if (!gVerifyLines) {
     return;
   }
   if (mLines.empty()) {
     return;
   }
 
+  nsLineBox* cursor = GetLineCursor();
+
   // Add up the counts on each line. Also validate that IsFirstLine is
   // set properly.
   PRInt32 count = 0;
   line_iterator line, line_end;
   for (line = begin_lines(), line_end = end_lines();
        line != line_end;
        ++line) {
+    if (line == cursor) {
+      cursor = nsnull;
+    }
     if (aFinalCheckOK) {
       NS_ABORT_IF_FALSE(line->GetChildCount(), "empty line");
       if (line->IsBlock()) {
         NS_ASSERTION(1 == line->GetChildCount(), "bad first line");
       }
     }
     count += line->GetChildCount();
   }
@@ -7179,36 +7187,62 @@ nsBlockFrame::VerifyLines(bool aFinalChe
     while (--count >= 0) {
       frame = frame->GetNextSibling();
     }
     ++line;
     if ((line != line_end) && (0 != line->GetChildCount())) {
       NS_ASSERTION(frame == line->mFirstChild, "bad line list");
     }
   }
-}
-
-// Its possible that a frame can have some frames on an overflow
-// list. But its never possible for multiple frames to have overflow
-// lists. Check that this fact is actually true.
+
+  if (cursor) {
+    FrameLines* overflowLines = GetOverflowLines();
+    if (overflowLines) {
+      line_iterator line = overflowLines->mLines.begin();
+      line_iterator line_end = overflowLines->mLines.end();
+      for (; line != line_end; ++line) {
+        if (line == cursor) {
+          cursor = nsnull;
+          break;
+        }
+      }
+    }
+  }
+  NS_ASSERTION(!cursor, "stale LineCursorProperty");
+}
+
 void
 nsBlockFrame::VerifyOverflowSituation()
 {
   nsBlockFrame* flow = static_cast<nsBlockFrame*>(GetFirstInFlow());
   while (flow) {
-    FrameLines* overflowLines = GetOverflowLines();
+    FrameLines* overflowLines = flow->GetOverflowLines();
     if (overflowLines) {
       NS_ASSERTION(!overflowLines->mLines.empty(),
                    "should not be empty if present");
       NS_ASSERTION(overflowLines->mLines.front()->mFirstChild,
                    "bad overflow lines");
       NS_ASSERTION(overflowLines->mLines.front()->mFirstChild ==
                    overflowLines->mFrames.FirstChild(),
                    "bad overflow frames / lines");
     }
+    nsLineBox* cursor = flow->GetLineCursor();
+    if (cursor) {
+      line_iterator line = flow->begin_lines();
+      line_iterator line_end = flow->end_lines();
+      for (; line != line_end && line != cursor; ++line)
+        ;
+      if (line == line_end && overflowLines) {
+        line = overflowLines->mLines.begin();
+        line_end = overflowLines->mLines.end();
+        for (; line != line_end && line != cursor; ++line)
+          ;
+        }
+      MOZ_ASSERT(line != line_end, "stale LineCursorProperty");
+    }
     flow = static_cast<nsBlockFrame*>(flow->GetNextInFlow());
   }
 }
 
 PRInt32
 nsBlockFrame::GetDepth() const
 {
   PRInt32 depth = 0;
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -349,23 +349,32 @@ protected:
     return aPresContext->StyleSet()->
       ProbePseudoElementStyle(mContent->AsElement(),
                               nsCSSPseudoElements::ePseudo_firstLetter,
                               mStyleContext);
   }
 #endif
 #endif
 
+  NS_DECLARE_FRAME_PROPERTY(LineCursorProperty, nsnull)
+  nsLineBox* GetLineCursor() {
+    return (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR) ?
+      static_cast<nsLineBox*>(Properties().Get(LineCursorProperty())) : nsnull;
+  }
+
   nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
     return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock);
   }
   nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, PRInt32 aCount) {
     return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount);
   }
   void FreeLineBox(nsLineBox* aLine) {
+    if (aLine == GetLineCursor()) {
+      ClearLineCursor();
+    }
     aLine->Destroy(PresContext()->PresShell());
   }
 
   void TryAllLines(nsLineList::iterator* aIterator,
                    nsLineList::iterator* aStartIterator,
                    nsLineList::iterator* aEndIterator,
                    bool*        aInOverflowLines,
                    FrameLines** aOverflowLines);