Back to index

lightning-sunbird  0.9+nobinonly
nsBlockFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 // vim:cindent:ts=2:et:sw=2:
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Steve Clark <buster@netscape.com>
00025  *   Robert O'Callahan <roc+moz@cs.cmu.edu>
00026  *   L. David Baron <dbaron@dbaron.org>
00027  *   IBM Corporation
00028  *   Mats Palmgren <mats.palmgren@bredband.net>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either of the GNU General Public License Version 2 or later (the "GPL"),
00032  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 #include "nsCOMPtr.h"
00044 #include "nsBlockFrame.h"
00045 #include "nsBlockReflowContext.h"
00046 #include "nsBlockReflowState.h"
00047 #include "nsBlockBandData.h"
00048 #include "nsBulletFrame.h"
00049 #include "nsLineBox.h"
00050 #include "nsInlineFrame.h"
00051 #include "nsLineLayout.h"
00052 #include "nsPlaceholderFrame.h"
00053 #include "nsStyleConsts.h"
00054 #include "nsFrameManager.h"
00055 #include "nsPresContext.h"
00056 #include "nsIPresShell.h"
00057 #include "nsReflowPath.h"
00058 #include "nsStyleContext.h"
00059 #include "nsIView.h"
00060 #include "nsIFontMetrics.h"
00061 #include "nsHTMLParts.h"
00062 #include "nsHTMLAtoms.h"
00063 #include "nsIDOMEvent.h"
00064 #include "nsGenericHTMLElement.h"
00065 #include "prprf.h"
00066 #include "nsLayoutAtoms.h"
00067 #include "nsITextContent.h"
00068 #include "nsStyleChangeList.h"
00069 #include "nsIFrameSelection.h"
00070 #include "nsSpaceManager.h"
00071 #include "nsIntervalSet.h"
00072 #include "prenv.h"
00073 #include "plstr.h"
00074 #include "nsGUIEvent.h"
00075 #include "nsLayoutErrors.h"
00076 #include "nsAutoPtr.h"
00077 #include "nsIServiceManager.h"
00078 #include "nsIScrollableFrame.h"
00079 #ifdef ACCESSIBILITY
00080 #include "nsIAccessibilityService.h"
00081 #endif
00082 #include "nsLayoutUtils.h"
00083 #include "nsBoxLayoutState.h"
00084 #include "nsCSSAnonBoxes.h"
00085 
00086 #ifdef IBMBIDI
00087 #include "nsBidiPresUtils.h"
00088 #endif // IBMBIDI
00089 
00090 #include "nsIDOMHTMLBodyElement.h"
00091 #include "nsIDOMHTMLHtmlElement.h"
00092 
00093 static const int MIN_LINES_NEEDING_CURSOR = 20;
00094 
00095 #ifdef DEBUG
00096 #include "nsPrintfCString.h"
00097 #include "nsBlockDebugFlags.h"
00098 
00099 PRBool nsBlockFrame::gLamePaintMetrics;
00100 PRBool nsBlockFrame::gLameReflowMetrics;
00101 PRBool nsBlockFrame::gNoisy;
00102 PRBool nsBlockFrame::gNoisyDamageRepair;
00103 PRBool nsBlockFrame::gNoisyMaxElementWidth;
00104 PRBool nsBlockFrame::gNoisyReflow;
00105 PRBool nsBlockFrame::gReallyNoisyReflow;
00106 PRBool nsBlockFrame::gNoisySpaceManager;
00107 PRBool nsBlockFrame::gVerifyLines;
00108 PRBool nsBlockFrame::gDisableResizeOpt;
00109 
00110 PRInt32 nsBlockFrame::gNoiseIndent;
00111 
00112 struct BlockDebugFlags {
00113   const char* name;
00114   PRBool* on;
00115 };
00116 
00117 static const BlockDebugFlags gFlags[] = {
00118   { "reflow", &nsBlockFrame::gNoisyReflow },
00119   { "really-noisy-reflow", &nsBlockFrame::gReallyNoisyReflow },
00120   { "max-element-width", &nsBlockFrame::gNoisyMaxElementWidth },
00121   { "space-manager", &nsBlockFrame::gNoisySpaceManager },
00122   { "verify-lines", &nsBlockFrame::gVerifyLines },
00123   { "damage-repair", &nsBlockFrame::gNoisyDamageRepair },
00124   { "lame-paint-metrics", &nsBlockFrame::gLamePaintMetrics },
00125   { "lame-reflow-metrics", &nsBlockFrame::gLameReflowMetrics },
00126   { "disable-resize-opt", &nsBlockFrame::gDisableResizeOpt },
00127 };
00128 #define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
00129 
00130 static void
00131 ShowDebugFlags()
00132 {
00133   printf("Here are the available GECKO_BLOCK_DEBUG_FLAGS:\n");
00134   const BlockDebugFlags* bdf = gFlags;
00135   const BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
00136   for (; bdf < end; bdf++) {
00137     printf("  %s\n", bdf->name);
00138   }
00139   printf("Note: GECKO_BLOCK_DEBUG_FLAGS is a comma separated list of flag\n");
00140   printf("names (no whitespace)\n");
00141 }
00142 
00143 void
00144 nsBlockFrame::InitDebugFlags()
00145 {
00146   static PRBool firstTime = PR_TRUE;
00147   if (firstTime) {
00148     firstTime = PR_FALSE;
00149     char* flags = PR_GetEnv("GECKO_BLOCK_DEBUG_FLAGS");
00150     if (flags) {
00151       PRBool error = PR_FALSE;
00152       for (;;) {
00153         char* cm = PL_strchr(flags, ',');
00154         if (cm) *cm = '\0';
00155 
00156         PRBool found = PR_FALSE;
00157         const BlockDebugFlags* bdf = gFlags;
00158         const BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
00159         for (; bdf < end; bdf++) {
00160           if (PL_strcasecmp(bdf->name, flags) == 0) {
00161             *(bdf->on) = PR_TRUE;
00162             printf("nsBlockFrame: setting %s debug flag on\n", bdf->name);
00163             gNoisy = PR_TRUE;
00164             found = PR_TRUE;
00165             break;
00166           }
00167         }
00168         if (!found) {
00169           error = PR_TRUE;
00170         }
00171 
00172         if (!cm) break;
00173         *cm = ',';
00174         flags = cm + 1;
00175       }
00176       if (error) {
00177         ShowDebugFlags();
00178       }
00179     }
00180   }
00181 }
00182 
00183 #endif
00184 
00185 // add in a sanity check for absurdly deep frame trees.  See bug 42138
00186 // can't just use IsFrameTreeTooDeep() because that method has side effects we don't want
00187 #define MAX_DEPTH_FOR_LIST_RENUMBERING 200  // 200 open displayable tags is pretty unrealistic
00188 
00189 //----------------------------------------------------------------------
00190 
00191 // Debugging support code
00192 
00193 #ifdef DEBUG
00194 const char* nsBlockFrame::kReflowCommandType[] = {
00195   "ContentChanged",
00196   "StyleChanged",
00197   "ReflowDirty",
00198   "Timeout",
00199   "UserDefined",
00200 };
00201 #endif
00202 
00203 #ifdef REALLY_NOISY_FIRST_LINE
00204 static void
00205 DumpStyleGeneaology(nsIFrame* aFrame, const char* gap)
00206 {
00207   fputs(gap, stdout);
00208   nsFrame::ListTag(stdout, aFrame);
00209   printf(": ");
00210   nsStyleContext* sc = aFrame->GetStyleContext();
00211   while (nsnull != sc) {
00212     nsStyleContext* psc;
00213     printf("%p ", sc);
00214     psc = sc->GetParent();
00215     sc = psc;
00216   }
00217   printf("\n");
00218 }
00219 #endif
00220 
00221 #ifdef REFLOW_STATUS_COVERAGE
00222 static void
00223 RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus)
00224 {
00225   static PRUint32 record[2];
00226 
00227   // 0: child-is-block
00228   // 1: child-is-inline
00229   PRIntn index = 0;
00230   if (!aChildIsBlock) index |= 1;
00231 
00232   // Compute new status
00233   PRUint32 newS = record[index];
00234   if (NS_INLINE_IS_BREAK(aFrameReflowStatus)) {
00235     if (NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
00236       newS |= 1;
00237     }
00238     else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) {
00239       newS |= 2;
00240     }
00241     else {
00242       newS |= 4;
00243     }
00244   }
00245   else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) {
00246     newS |= 8;
00247   }
00248   else {
00249     newS |= 16;
00250   }
00251 
00252   // Log updates to the status that yield different values
00253   if (record[index] != newS) {
00254     record[index] = newS;
00255     printf("record(%d): %02x %02x\n", index, record[0], record[1]);
00256   }
00257 }
00258 #endif
00259 
00260 //----------------------------------------------------------------------
00261 
00262 const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
00263 
00264 nsresult
00265 NS_NewBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aFlags)
00266 {
00267   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00268   if (nsnull == aNewFrame) {
00269     return NS_ERROR_NULL_POINTER;
00270   }
00271   nsBlockFrame* it = new (aPresShell) nsBlockFrame;
00272   if (nsnull == it) {
00273     return NS_ERROR_OUT_OF_MEMORY;
00274   }
00275   it->SetFlags(aFlags);
00276   *aNewFrame = it;
00277   return NS_OK;
00278 }
00279 
00280 nsBlockFrame::nsBlockFrame() 
00281 {
00282 #ifdef DEBUG
00283   InitDebugFlags();
00284 #endif
00285 }
00286 
00287 nsBlockFrame::~nsBlockFrame()
00288 {
00289 }
00290 
00291 NS_IMETHODIMP
00292 nsBlockFrame::Destroy(nsPresContext* aPresContext)
00293 {
00294   mAbsoluteContainer.DestroyFrames(this, aPresContext);
00295   // Outside bullets are not in our child-list so check for them here
00296   // and delete them when present.
00297   if (mBullet && HaveOutsideBullet()) {
00298     mBullet->Destroy(aPresContext);
00299     mBullet = nsnull;
00300   }
00301 
00302   mFloats.DestroyFrames(aPresContext);
00303 
00304   nsLineBox::DeleteLineList(aPresContext, mLines);
00305 
00306   // destroy overflow lines now
00307   nsLineList* overflowLines = RemoveOverflowLines();
00308   if (overflowLines) {
00309     nsLineBox::DeleteLineList(aPresContext, *overflowLines);
00310   }
00311 
00312   {
00313     nsAutoOOFFrameList oofs(this);
00314     oofs.mList.DestroyFrames(aPresContext);
00315     // oofs is now empty and will remove the frame list property
00316   }
00317 
00318   return nsBlockFrameSuper::Destroy(aPresContext);
00319 }
00320 
00321 NS_IMETHODIMP
00322 nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00323 {
00324   NS_PRECONDITION(aInstancePtr, "null out param");
00325   if (aIID.Equals(kBlockFrameCID)) {
00326     *aInstancePtr = NS_STATIC_CAST(void*, NS_STATIC_CAST(nsBlockFrame*, this));
00327     return NS_OK;
00328   }
00329   if (aIID.Equals(NS_GET_IID(nsILineIterator)) ||
00330       aIID.Equals(NS_GET_IID(nsILineIteratorNavigator)))
00331   {
00332     nsLineIterator* it = new nsLineIterator;
00333     if (!it) {
00334       *aInstancePtr = nsnull;
00335       return NS_ERROR_OUT_OF_MEMORY;
00336     }
00337     NS_ADDREF(it); // reference passed to caller
00338     const nsStyleVisibility* visibility = GetStyleVisibility();
00339     nsresult rv = it->Init(mLines,
00340                            visibility->mDirection == NS_STYLE_DIRECTION_RTL);
00341     if (NS_FAILED(rv)) {
00342       NS_RELEASE(it);
00343       return rv;
00344     }
00345     *aInstancePtr = NS_STATIC_CAST(void*,
00346             NS_STATIC_CAST(nsILineIteratorNavigator*, it));
00347     return NS_OK;
00348   }
00349   return nsBlockFrameSuper::QueryInterface(aIID, aInstancePtr);
00350 }
00351 
00352 NS_IMETHODIMP
00353 nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const
00354 {
00355   aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR;
00356   return NS_OK;
00357 }
00358 
00359 #ifdef DEBUG
00360 NS_METHOD
00361 nsBlockFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
00362 {
00363   IndentBy(out, aIndent);
00364   ListTag(out);
00365 #ifdef DEBUG_waterson
00366   fprintf(out, " [parent=%p]", mParent);
00367 #endif
00368   if (HasView()) {
00369     fprintf(out, " [view=%p]", NS_STATIC_CAST(void*, GetView()));
00370   }
00371   if (nsnull != mNextSibling) {
00372     fprintf(out, " next=%p", NS_STATIC_CAST(void*, mNextSibling));
00373   }
00374 
00375   // Output the flow linkage
00376   if (nsnull != mPrevInFlow) {
00377     fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, mPrevInFlow));
00378   }
00379   if (nsnull != mNextInFlow) {
00380     fprintf(out, " next-in-flow=%p", NS_STATIC_CAST(void*, mNextInFlow));
00381   }
00382 
00383   // Output the rect and state
00384   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
00385   if (0 != mState) {
00386     fprintf(out, " [state=%08x]", mState);
00387   }
00388   nsBlockFrame* f = NS_CONST_CAST(nsBlockFrame*, this);
00389   nsRect* overflowArea = f->GetOverflowAreaProperty(PR_FALSE);
00390   if (overflowArea) {
00391     fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea->x, overflowArea->y,
00392             overflowArea->width, overflowArea->height);
00393   }
00394   PRInt32 numInlineLines = 0;
00395   PRInt32 numBlockLines = 0;
00396   if (! mLines.empty()) {
00397     for (const_line_iterator line = begin_lines(), line_end = end_lines();
00398          line != line_end;
00399          ++line)
00400     {
00401       if (line->IsBlock())
00402         numBlockLines++;
00403       else
00404         numInlineLines++;
00405     }
00406   }
00407   fprintf(out, " sc=%p(i=%d,b=%d)",
00408           NS_STATIC_CAST(void*, mStyleContext), numInlineLines, numBlockLines);
00409   nsIAtom* pseudoTag = mStyleContext->GetPseudoType();
00410   if (pseudoTag) {
00411     nsAutoString atomString;
00412     pseudoTag->ToString(atomString);
00413     fprintf(out, " pst=%s",
00414             NS_LossyConvertUCS2toASCII(atomString).get());
00415   }
00416   fputs("<\n", out);
00417 
00418   aIndent++;
00419 
00420   // Output the lines
00421   if (! mLines.empty()) {
00422     for (const_line_iterator line = begin_lines(), line_end = end_lines();
00423          line != line_end;
00424          ++line)
00425     {
00426       line->List(aPresContext, out, aIndent);
00427     }
00428   }
00429 
00430   nsIAtom* listName = nsnull;
00431   PRInt32 listIndex = 0;
00432   for (;;) {
00433     listName = GetAdditionalChildListName(listIndex++);
00434     if (nsnull == listName) {
00435       break;
00436     }
00437     nsIFrame* kid = GetFirstChild(listName);
00438     if (kid) {
00439       IndentBy(out, aIndent);
00440       nsAutoString tmp;
00441       if (nsnull != listName) {
00442         listName->ToString(tmp);
00443         fputs(NS_LossyConvertUCS2toASCII(tmp).get(), out);
00444       }
00445       fputs("<\n", out);
00446       while (kid) {
00447         nsIFrameDebug*  frameDebug;
00448 
00449         if (NS_SUCCEEDED(CallQueryInterface(kid, &frameDebug))) {
00450           frameDebug->List(aPresContext, out, aIndent + 1);
00451         }
00452         kid = kid->GetNextSibling();
00453       }
00454       IndentBy(out, aIndent);
00455       fputs(">\n", out);
00456     }
00457   }
00458 
00459   aIndent--;
00460   IndentBy(out, aIndent);
00461   fputs(">\n", out);
00462 
00463   return NS_OK;
00464 }
00465 
00466 NS_IMETHODIMP_(nsFrameState)
00467 nsBlockFrame::GetDebugStateBits() const
00468 {
00469   // We don't want to include our cursor flag in the bits the
00470   // regression tester looks at
00471   return nsBlockFrameSuper::GetDebugStateBits() & ~NS_BLOCK_HAS_LINE_CURSOR;
00472 }
00473 
00474 NS_IMETHODIMP
00475 nsBlockFrame::GetFrameName(nsAString& aResult) const
00476 {
00477   return MakeFrameName(NS_LITERAL_STRING("Block"), aResult);
00478 }
00479 #endif
00480 
00481 nsIAtom*
00482 nsBlockFrame::GetType() const
00483 {
00484   return nsLayoutAtoms::blockFrame;
00485 }
00486 
00488 // Child frame enumeration
00489 
00490 nsIFrame*
00491 nsBlockFrame::GetFirstChild(nsIAtom* aListName) const
00492 {
00493   if (mAbsoluteContainer.GetChildListName() == aListName) {
00494     nsIFrame* result = nsnull;
00495     mAbsoluteContainer.FirstChild(this, aListName, &result);
00496     return result;
00497   }
00498   else if (nsnull == aListName) {
00499     return (mLines.empty()) ? nsnull : mLines.front()->mFirstChild;
00500   }
00501   else if (aListName == nsLayoutAtoms::overflowList) {
00502     nsLineList* overflowLines = GetOverflowLines();
00503     return overflowLines ? overflowLines->front()->mFirstChild : nsnull;
00504   }
00505   else if (aListName == nsLayoutAtoms::overflowOutOfFlowList) {
00506     return GetOverflowOutOfFlows().FirstChild();
00507   }
00508   else if (aListName == nsLayoutAtoms::floatList) {
00509     return mFloats.FirstChild();
00510   }
00511   else if (aListName == nsLayoutAtoms::bulletList) {
00512     if (HaveOutsideBullet()) {
00513       return mBullet;
00514     }
00515   }
00516   return nsnull;
00517 }
00518 
00519 nsIAtom*
00520 nsBlockFrame::GetAdditionalChildListName(PRInt32 aIndex) const
00521 {
00522   switch (aIndex) {
00523   case NS_BLOCK_FRAME_FLOAT_LIST_INDEX:
00524     return nsLayoutAtoms::floatList;
00525   case NS_BLOCK_FRAME_BULLET_LIST_INDEX:
00526     return nsLayoutAtoms::bulletList;
00527   case NS_BLOCK_FRAME_OVERFLOW_LIST_INDEX:
00528     return nsLayoutAtoms::overflowList;
00529   case NS_BLOCK_FRAME_OVERFLOW_OOF_LIST_INDEX:
00530     return nsLayoutAtoms::overflowOutOfFlowList;
00531   case NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX:
00532     return mAbsoluteContainer.GetChildListName();
00533   default:
00534     return nsnull;
00535   }
00536 }
00537 
00538 /* virtual */ PRBool
00539 nsBlockFrame::IsContainingBlock() const
00540 {
00541   return PR_TRUE;
00542 }
00543 
00544 /* virtual */ PRBool
00545 nsBlockFrame::IsFloatContainingBlock() const
00546 {
00547   return PR_TRUE;
00548 }
00549 
00550 static PRBool IsContinuationPlaceholder(nsIFrame* aFrame)
00551 {
00552   return aFrame->GetPrevInFlow() &&
00553     nsLayoutAtoms::placeholderFrame == aFrame->GetType();
00554 }
00555 
00556 static void ReparentFrame(nsIFrame* aFrame, nsIFrame* aOldParent,
00557                           nsIFrame* aNewParent) {
00558   NS_ASSERTION(aOldParent == aFrame->GetParent(),
00559                "Parent not consistent with exepectations");
00560 
00561   aFrame->SetParent(aNewParent);
00562 
00563   // When pushing and pulling frames we need to check for whether any
00564   // views need to be reparented
00565   nsHTMLContainerFrame::ReparentFrameView(aFrame->GetPresContext(), aFrame,
00566                                           aOldParent, aNewParent);
00567 }
00568  
00570 // Frame structure methods
00571 
00573 // Reflow methods
00574 
00575 static nsSize
00576 CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
00577                                          nsSize aFrameSize)
00578 {
00579   // The issue here is that for a 'height' of 'auto' the reflow state
00580   // code won't know how to calculate the containing block height
00581   // because it's calculated bottom up. So we use our own computed
00582   // size as the dimensions. We don't really want to do this for the
00583   // initial containing block
00584   nsIFrame* frame = aReflowState.frame;
00585   if (nsLayoutUtils::IsInitialContainingBlock(frame)) {
00586     return nsSize(-1, -1);
00587   }
00588 
00589   nsSize cbSize(aFrameSize);
00590     // Containing block is relative to the padding edge
00591   const nsMargin& border = aReflowState.mStyleBorder->GetBorder();
00592   cbSize.width -= border.left + border.right;
00593   cbSize.height -= border.top + border.bottom;
00594 
00595   if (frame->GetParent()->GetContent() == frame->GetContent()) {
00596     // We are a wrapped frame for the content. Use the container's
00597     // dimensions, if they have been precomputed.
00598     // XXX This is a hack! We really should be waiting until the outermost
00599     // frame is fully reflowed and using the resulting dimensions, even
00600     // if they're intrinsic.
00601     // In fact we should be attaching absolute children to the outermost
00602     // frame and not always sticking them in block frames.
00603 
00604     // First, find the reflow state for the outermost frame for this
00605     // content.
00606     const nsHTMLReflowState* aLastRS = &aReflowState;
00607     const nsHTMLReflowState* lastButOneRS = &aReflowState;
00608     while (aLastRS->parentReflowState &&
00609            aLastRS->parentReflowState->frame->GetContent() == frame->GetContent()) {
00610       lastButOneRS = aLastRS;
00611       aLastRS = aLastRS->parentReflowState;
00612     }
00613     if (aLastRS != &aReflowState) {
00614       // The wrapper frame should be block-level. If it isn't, how the
00615       // heck did it end up wrapping this block frame?
00616       NS_ASSERTION(aLastRS->frame->GetStyleDisplay()->IsBlockLevel(),
00617                    "Wrapping frame should be block-level");
00618       // Scrollbars need to be specifically excluded, if present, because they are outside the
00619       // padding-edge. We need better APIs for getting the various boxes from a frame.
00620       nsIScrollableFrame* scrollFrame;
00621       CallQueryInterface(aLastRS->frame, &scrollFrame);
00622       nsMargin scrollbars(0,0,0,0);
00623       if (scrollFrame) {
00624         nsBoxLayoutState dummyState(aLastRS->frame->GetPresContext());
00625         scrollbars = scrollFrame->GetDesiredScrollbarSizes(&dummyState);
00626         // XXX We should account for the horizontal scrollbar too --- but currently
00627         // nsGfxScrollFrame assumes nothing depends on the presence (or absence) of
00628         // a horizontal scrollbar, so accounting for it would create incremental
00629         // reflow bugs.
00630         //if (!lastButOneRS->mFlags.mAssumingHScrollbar) {
00631           scrollbars.top = scrollbars.bottom = 0;
00632         //}
00633         if (!lastButOneRS->mFlags.mAssumingVScrollbar) {
00634           scrollbars.left = scrollbars.right = 0;
00635         }
00636       }
00637       // We found a reflow state for the outermost wrapping frame, so use
00638       // its computed metrics if available
00639       if (aLastRS->mComputedWidth != NS_UNCONSTRAINEDSIZE) {
00640         cbSize.width = PR_MAX(0,
00641           aLastRS->mComputedWidth + aLastRS->mComputedPadding.LeftRight() - scrollbars.LeftRight());
00642       }
00643       if (aLastRS->mComputedHeight != NS_UNCONSTRAINEDSIZE) {
00644         cbSize.height = PR_MAX(0,
00645           aLastRS->mComputedHeight + aLastRS->mComputedPadding.TopBottom() - scrollbars.TopBottom());
00646       }
00647     }
00648   }
00649 
00650   return cbSize;
00651 }
00652 
00653 NS_IMETHODIMP
00654 nsBlockFrame::Reflow(nsPresContext*          aPresContext,
00655                      nsHTMLReflowMetrics&     aMetrics,
00656                      const nsHTMLReflowState& aReflowState,
00657                      nsReflowStatus&          aStatus)
00658 {
00659   DO_GLOBAL_REFLOW_COUNT("nsBlockFrame", aReflowState.reason);
00660   DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
00661 #ifdef DEBUG
00662   if (gNoisyReflow) {
00663     nsCAutoString reflow;
00664     reflow.Append(nsHTMLReflowState::ReasonToString(aReflowState.reason));
00665 
00666     if (aReflowState.reason == eReflowReason_Incremental) {
00667       nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand;
00668 
00669       if (command) {
00670         // We're the target.
00671         reflow += " (";
00672 
00673         reflow += kReflowCommandType[command->Type()];
00674 
00675         reflow += ")";
00676       }
00677     }
00678 
00679     IndentBy(stdout, gNoiseIndent);
00680     ListTag(stdout);
00681     printf(": begin %s reflow availSize=%d,%d computedSize=%d,%d\n",
00682            reflow.get(),
00683            aReflowState.availableWidth, aReflowState.availableHeight,
00684            aReflowState.mComputedWidth, aReflowState.mComputedHeight);
00685   }
00686   AutoNoisyIndenter indent(gNoisy);
00687   PRTime start = LL_ZERO; // Initialize these variablies to silence the compiler.
00688   PRInt32 ctc = 0;        // We only use these if they are set (gLameReflowMetrics).
00689   if (gLameReflowMetrics) {
00690     start = PR_Now();
00691     ctc = nsLineBox::GetCtorCount();
00692   }
00693 #endif
00694 
00695   nsSize oldSize = GetSize();
00696 
00697   // Should we create a space manager?
00698   nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState));
00699 
00700   // XXXldb If we start storing the space manager in the frame rather
00701   // than keeping it around only during reflow then we should create it
00702   // only when there are actually floats to manage.  Otherwise things
00703   // like tables will gain significant bloat.
00704   if (NS_BLOCK_SPACE_MGR & mState)
00705     autoSpaceManager.CreateSpaceManagerFor(aPresContext, this);
00706 
00707   // See if it's an incremental reflow command targeted only at
00708   // absolute frames and we can skip ReflowDirtyLines().
00709   PRBool needToReflowLines = aMetrics.mComputeMEW ||
00710     // If we have lines with clearance, and the space manager already has
00711     // floats, we need to check the positions of our lines with clearance
00712     ((GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN) &&
00713      aReflowState.mSpaceManager->HasAnyFloats()) ||
00714     // The areas of any floats in this block or in blocks under us
00715     // need to be put into the space manager --- unless we are our own
00716     // space manager, in which case it doesn't matter.
00717     !(GetStateBits() & NS_BLOCK_SPACE_MGR);
00718 
00719   if (mAbsoluteContainer.HasAbsoluteFrames() &&
00720       eReflowReason_Incremental == aReflowState.reason &&
00721       !needToReflowLines &&
00722       mAbsoluteContainer.ReflowingAbsolutesOnly(this, aReflowState)) {
00723     nsSize containingBlockSize
00724       = CalculateContainingBlockSizeForAbsolutes(aReflowState, GetSize());
00725     
00726     mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState,
00727                                          containingBlockSize.width,
00728                                          containingBlockSize.height);
00729 
00730     // Just return our current size as our desired size.
00731     aMetrics.width = mRect.width;
00732     aMetrics.height = mRect.height;
00733     aMetrics.ascent = mAscent;
00734     aMetrics.descent = aMetrics.height - aMetrics.ascent;
00735     
00736     // Whether or not we're complete hasn't changed
00737     aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE;
00738     
00739     // Factor the absolutely positioned child bounds into the overflow area
00740     ComputeCombinedArea(aReflowState, aMetrics);
00741     nsRect childBounds;
00742     mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
00743     aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds);
00744     
00745     FinishAndStoreOverflow(&aMetrics);
00746 
00747     return NS_OK;
00748   }
00749 
00750   // OK, some lines may be reflowed. Blow away any saved line cursor because
00751   // we may invalidate the nondecreasing combinedArea.y/yMost invariant,
00752   // and we may even delete the line with the line cursor.
00753   ClearLineCursor();
00754 
00755   if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
00756 #ifdef DEBUG_kipp
00757     {
00758       extern char* nsPresShell_ReflowStackPointerTop;
00759       char marker;
00760       char* newsp = (char*) &marker;
00761       printf("XXX: frame tree is too deep; approx stack size = %d\n",
00762              nsPresShell_ReflowStackPointerTop - newsp);
00763     }
00764 #endif
00765     aStatus = NS_FRAME_COMPLETE;
00766     return NS_OK;
00767   }
00768 
00769   nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
00770                            (NS_BLOCK_MARGIN_ROOT & mState),
00771                            (NS_BLOCK_MARGIN_ROOT & mState));
00772 
00773   // The condition for doing Bidi resolutions includes a test for the
00774   // dirtiness flags, because blocks sometimes send a resize reflow
00775   // even though they have dirty children, An example where this can
00776   // occur is when adding lines to a text control (bugs 95228 and 95400
00777   // were caused by not doing Bidi resolution in these cases)
00778   if (eReflowReason_Resize != aReflowState.reason ||
00779       mState & NS_FRAME_IS_DIRTY || mState & NS_FRAME_HAS_DIRTY_CHILDREN) {
00780 #ifdef IBMBIDI
00781     if (! mLines.empty()) {
00782       if (aPresContext->BidiEnabled()) {
00783         nsBidiPresUtils* bidiUtils = aPresContext->GetBidiUtils();
00784         if (bidiUtils) {
00785           PRBool forceReflow;
00786           nsresult rc = bidiUtils->Resolve(aPresContext, this,
00787                                            mLines.front()->mFirstChild,
00788                                            forceReflow,
00789                                            aReflowState.mFlags.mVisualBidiFormControl);
00790           if (NS_SUCCEEDED(rc) && forceReflow) {
00791             // Mark everything dirty
00792             // XXXldb This should be done right.
00793             for (line_iterator line = begin_lines(), line_end = end_lines();
00794                  line != line_end;
00795                  ++line)
00796             {
00797               line->MarkDirty();
00798             }
00799           }
00800         }
00801       }
00802     }
00803 #endif // IBMBIDI
00804     RenumberLists(aPresContext);
00805   }
00806 
00807   nsresult rv = NS_OK;
00808 
00809   // ALWAYS drain overflow. We never want to leave the previnflow's
00810   // overflow lines hanging around; block reflow depends on the
00811   // overflow line lists being cleared out between reflow passes.
00812   DrainOverflowLines(state);
00813   state.SetupOverflowPlaceholdersProperty();
00814 
00815   switch (aReflowState.reason) {
00816   case eReflowReason_Initial:
00817 #ifdef NOISY_REFLOW_REASON
00818     ListTag(stdout);
00819     printf(": reflow=initial\n");
00820 #endif
00821     rv = PrepareInitialReflow(state);
00822     mState &= ~NS_FRAME_FIRST_REFLOW;
00823     break;  
00824 
00825   case eReflowReason_Dirty:
00826     // Do nothing; the dirty lines will already have been marked.
00827     break;
00828 
00829   case eReflowReason_Incremental: {
00830 #ifdef NOISY_REFLOW_REASON
00831     ListTag(stdout);
00832     printf(": reflow=incremental ");
00833 #endif
00834     nsReflowPath *path = aReflowState.path;
00835     nsHTMLReflowCommand *command = path->mReflowCommand;
00836     if (command) {
00837 #ifdef NOISY_REFLOW_REASON
00838       printf("type=%s ", kReflowCommandType[command->Type()]);
00839 #endif
00840       switch (command->Type()) {
00841       case eReflowType_StyleChanged:
00842         rv = PrepareStyleChangedReflow(state);
00843         break;
00844       case eReflowType_ReflowDirty:
00845         // Do nothing; the dirty lines will already have been marked.
00846         break;
00847       case eReflowType_ContentChanged:
00848         // Perform a full reflow.
00849         rv = PrepareResizeReflow(state);
00850         break;
00851       default:
00852         // We shouldn't get here. But, if we do, perform a full reflow.
00853         NS_ERROR("unexpected reflow type");
00854         rv = PrepareResizeReflow(state);
00855         break;
00856       }
00857     }
00858 
00859     if (path->FirstChild() != path->EndChildren()) {
00860       // We're along the reflow path, but not necessarily the target
00861       // of the reflow.
00862 #ifdef NOISY_REFLOW_REASON
00863       ListTag(stdout);
00864       printf(" next={ ");
00865 
00866       for (nsReflowPath::iterator iter = path->FirstChild();
00867            iter != path->EndChildren();
00868            ++iter) {
00869         nsFrame::ListTag(stdout, *iter);
00870         printf(" ");
00871       }
00872 
00873       printf("}");
00874 #endif
00875 
00876       rv = PrepareChildIncrementalReflow(state);
00877     }
00878 
00879 #ifdef NOISY_REFLOW_REASON
00880     printf("\n");
00881 #endif
00882 
00883     break;
00884   }
00885 
00886   case eReflowReason_StyleChange:
00887     rv = PrepareStyleChangedReflow(state);
00888     break;
00889 
00890   case eReflowReason_Resize:
00891   default:
00892 #ifdef NOISY_REFLOW_REASON
00893     ListTag(stdout);
00894     printf(": reflow=resize (%d)\n", aReflowState.reason);
00895 #endif
00896     rv = PrepareResizeReflow(state);
00897     break;
00898   }
00899 
00900   NS_ASSERTION(NS_SUCCEEDED(rv), "setting up reflow failed");
00901   if (NS_FAILED(rv)) return rv;
00902 
00903   // Now reflow...
00904   rv = ReflowDirtyLines(state, PR_TRUE);
00905   NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
00906   if (NS_FAILED(rv)) return rv;
00907 
00908   // If the block is complete, put continuted floats in the closest ancestor 
00909   // block that uses the same space manager and leave the block complete; this 
00910   // allows subsequent lines on the page to be impacted by floats. If the 
00911   // block is incomplete or there is no ancestor using the same space manager, 
00912   // put continued floats at the beginning of the first overflow line.
00913   if (state.mOverflowPlaceholders.NotEmpty()) {
00914     NS_ASSERTION(aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE,
00915                  "Somehow we failed to fit all content, even though we have unlimited space!");
00916     if (NS_FRAME_IS_COMPLETE(state.mReflowStatus)) {
00917       // find the nearest block ancestor that uses the same space manager
00918       for (const nsHTMLReflowState* ancestorRS = aReflowState.parentReflowState; 
00919            ancestorRS; 
00920            ancestorRS = ancestorRS->parentReflowState) {
00921         nsIFrame* ancestor = ancestorRS->frame;
00922         nsIAtom* fType = ancestor->GetType();
00923         if ((nsLayoutAtoms::blockFrame == fType || nsLayoutAtoms::areaFrame == fType) &&
00924             aReflowState.mSpaceManager == ancestorRS->mSpaceManager) {
00925           // Put the continued floats in ancestor since it uses the same space manager
00926           nsFrameList* ancestorPlace =
00927             ((nsBlockFrame*)ancestor)->GetOverflowPlaceholders();
00928           // The ancestor should have this list, since it's being reflowed. But maybe
00929           // it isn't because of reflow roots or something.
00930           if (ancestorPlace) {
00931             for (nsIFrame* f = state.mOverflowPlaceholders.FirstChild();
00932                  f; f = f->GetNextSibling()) {
00933               NS_ASSERTION(IsContinuationPlaceholder(f),
00934                            "Overflow placeholders must be continuation placeholders");
00935               ReparentFrame(f, this, ancestorRS->frame);
00936               nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
00937               mFloats.RemoveFrame(oof);
00938               ReparentFrame(oof, this, ancestorRS->frame);
00939               // Clear the next-sibling in case the frame wasn't in mFloats
00940               oof->SetNextSibling(nsnull);
00941               // Do not put the float into any child frame list, because
00942               // placeholders in the overflow-placeholder block-state list
00943               // don't keep their out of flows in a child frame list.
00944             }
00945             ancestorPlace->AppendFrames(nsnull, state.mOverflowPlaceholders.FirstChild());
00946             state.mOverflowPlaceholders.SetFrames(nsnull);
00947             break;
00948           }
00949         }
00950       }
00951     }
00952     if (!state.mOverflowPlaceholders.IsEmpty()) {
00953       state.mOverflowPlaceholders.SortByContentOrder();
00954       PRInt32 numOverflowPlace = state.mOverflowPlaceholders.GetLength();
00955       nsLineBox* newLine =
00956         state.NewLineBox(state.mOverflowPlaceholders.FirstChild(),
00957                          numOverflowPlace, PR_FALSE);
00958       if (newLine) {
00959         nsLineList* overflowLines = GetOverflowLines();
00960         if (overflowLines) {
00961           // Need to put the overflow placeholders' floats into our
00962           // overflow-out-of-flows list, since the overflow placeholders are
00963           // going onto our overflow line list. Put them last, because that's
00964           // where the placeholders are going.
00965           nsFrameList floats;
00966           nsIFrame* lastFloat = nsnull;
00967           for (nsIFrame* f = state.mOverflowPlaceholders.FirstChild();
00968                f; f = f->GetNextSibling()) {
00969             NS_ASSERTION(IsContinuationPlaceholder(f),
00970                          "Overflow placeholders must be continuation placeholders");
00971             nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
00972             // oof is not currently in any child list
00973             floats.InsertFrames(nsnull, lastFloat, oof);
00974             lastFloat = oof;
00975           }
00976 
00977           // Put the new placeholders *last* in the overflow lines
00978           // because they might have previnflows in the overflow lines.
00979           nsIFrame* lastChild = overflowLines->back()->LastChild();
00980           lastChild->SetNextSibling(state.mOverflowPlaceholders.FirstChild());
00981           // Create a new line as the last line and put the
00982           // placeholders there
00983           overflowLines->push_back(newLine);
00984 
00985           nsAutoOOFFrameList oofs(this);
00986           oofs.mList.AppendFrames(nsnull, floats.FirstChild());
00987         }
00988         else {
00989           mLines.push_back(newLine);
00990           nsLineList::iterator nextToLastLine = ----end_lines();
00991           PushLines(state, nextToLastLine);
00992         }
00993         state.mOverflowPlaceholders.SetFrames(nsnull);
00994       }
00995       state.mReflowStatus |= NS_FRAME_NOT_COMPLETE | NS_FRAME_REFLOW_NEXTINFLOW;
00996     }
00997   }
00998 
00999   if (NS_FRAME_IS_NOT_COMPLETE(state.mReflowStatus)) {
01000     if (GetOverflowLines()) {
01001       state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
01002     }
01003 
01004     if (NS_STYLE_OVERFLOW_CLIP == aReflowState.mStyleDisplay->mOverflowX) {
01005       state.mReflowStatus = NS_FRAME_COMPLETE;
01006     }
01007     else {
01008 #ifdef DEBUG_kipp
01009       ListTag(stdout); printf(": block is not complete\n");
01010 #endif
01011     }
01012   }
01013 
01014   CheckFloats(state);
01015 
01016   // Compute our final size
01017   ComputeFinalSize(aReflowState, state, aMetrics);
01018   nsRect currentOverflow = aMetrics.mOverflowArea;
01019   FinishAndStoreOverflow(&aMetrics);
01020 
01021   // see if verifyReflow is enabled, and if so store off the space manager pointer
01022 #ifdef DEBUG
01023   PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags();
01024   if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags)
01025   {
01026     // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal
01027     nsIPresShell *shell = aPresContext->GetPresShell();
01028     if (shell) {
01029       nsHTMLReflowState&  reflowState = (nsHTMLReflowState&)aReflowState;
01030       rv = SetProperty(nsLayoutAtoms::spaceManagerProperty,
01031                        reflowState.mSpaceManager,
01032                        nsnull /* should be nsSpaceManagerDestroyer*/);
01033 
01034       autoSpaceManager.DebugOrphanSpaceManager();
01035     }
01036   }
01037 #endif
01038 
01039   // Let the absolutely positioned container reflow any absolutely positioned
01040   // child frames that need to be reflowed, e.g., elements with a percentage
01041   // based width/height
01042   // We want to do this under either of two conditions:
01043   //  1. If we didn't do the incremental reflow above.
01044   //  2. If our size changed.
01045   // Even though it's the padding edge that's the containing block, we
01046   // can use our rect (the border edge) since if the border style
01047   // changed, the reflow would have been targeted at us so we'd satisfy
01048   // condition 1.
01049   if (mAbsoluteContainer.HasAbsoluteFrames()) {
01050     nsRect childBounds;
01051     nsSize containingBlockSize
01052       = CalculateContainingBlockSizeForAbsolutes(aReflowState,
01053                                                  nsSize(aMetrics.width, aMetrics.height));
01054 
01055     PRBool forceAbsoluteReflow = PR_TRUE;
01056     PRBool cbWidthChanged = PR_TRUE;
01057     PRBool cbHeightChanged = PR_TRUE;
01058     if (eReflowReason_Incremental == aReflowState.reason) {
01059       // Do the incremental reflows ... would be nice to merge with
01060       // the reflows below but that would be more work, and more risky
01061       mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState,
01062                                            containingBlockSize.width,
01063                                            containingBlockSize.height);
01064       
01065       // If a reflow was targeted at this block then we'd better
01066       // reflow the absolutes. For example the borders and padding
01067       // might have changed in a way that leaves the frame size the
01068       // same but the padding edge has moved.
01069       if (!aReflowState.path->mReflowCommand) {
01070         // We don't have to force reflow of all the absolutes.
01071         forceAbsoluteReflow = PR_FALSE;
01072         
01073         // We need to reflow those absolutes that depend on their
01074         // placeholder position, or the containing block size in a
01075         // direction in which the containing block size might have
01076         // changed.  So figure out whether our size changed.
01077         cbWidthChanged = aMetrics.width != oldSize.width;
01078         PRBool isRoot = !GetContent()->GetParent();
01079         // If isRoot and we have auto height, then we are the initial
01080         // containing block and the containing block height is the
01081         // viewport height, which can't change during incremental
01082         // reflow.
01083         cbHeightChanged = isRoot && NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight
01084           ? PR_FALSE : aMetrics.height != oldSize.height;
01085       }
01086     }
01087 
01088     rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
01089                                    containingBlockSize.width,
01090                                    containingBlockSize.height,
01091                                    &childBounds,
01092                                    forceAbsoluteReflow,
01093                                    cbWidthChanged,
01094                                    cbHeightChanged);
01095 
01096     // Factor the absolutely positioned child bounds into the overflow area
01097     aMetrics.mOverflowArea.UnionRect(currentOverflow, childBounds);
01098     FinishAndStoreOverflow(&aMetrics);
01099   }
01100 
01101   // Determine if we need to repaint our border, background or outline
01102   CheckInvalidateSizeChange(aPresContext, aMetrics, aReflowState);
01103 
01104   // Clear the space manager pointer in the block reflow state so we
01105   // don't waste time translating the coordinate system back on a dead
01106   // space manager.
01107   if (NS_BLOCK_SPACE_MGR & mState)
01108     state.mSpaceManager = nsnull;
01109 
01110   aStatus = state.mReflowStatus;
01111 
01112 #ifdef DEBUG
01113   if (gNoisyReflow) {
01114     IndentBy(stdout, gNoiseIndent);
01115     ListTag(stdout);
01116     printf(": status=%x (%scomplete) metrics=%d,%d carriedMargin=%d",
01117            aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ",
01118            aMetrics.width, aMetrics.height,
01119            aMetrics.mCarriedOutBottomMargin.get());
01120     if (mState & NS_FRAME_OUTSIDE_CHILDREN) {
01121       printf(" combinedArea={%d,%d,%d,%d}",
01122              aMetrics.mOverflowArea.x,
01123              aMetrics.mOverflowArea.y,
01124              aMetrics.mOverflowArea.width,
01125              aMetrics.mOverflowArea.height);
01126     }
01127     if (aMetrics.mComputeMEW) {
01128       printf(" maxElementWidth=%d", aMetrics.mMaxElementWidth);
01129     }
01130     printf("\n");
01131   }
01132 
01133   if (gLameReflowMetrics) {
01134     PRTime end = PR_Now();
01135 
01136     PRInt32 ectc = nsLineBox::GetCtorCount();
01137     PRInt32 numLines = mLines.size();
01138     if (!numLines) numLines = 1;
01139     PRTime delta, perLineDelta, lines;
01140     LL_I2L(lines, numLines);
01141     LL_SUB(delta, end, start);
01142     LL_DIV(perLineDelta, delta, lines);
01143 
01144     ListTag(stdout);
01145     char buf[400];
01146     PR_snprintf(buf, sizeof(buf),
01147                 ": %lld elapsed (%lld per line) (%d lines; %d new lines)",
01148                 delta, perLineDelta, numLines, ectc - ctc);
01149     printf("%s\n", buf);
01150   }
01151   if (gNoisyMaxElementWidth) {
01152     if (aMetrics.mComputeMEW) {
01153       IndentBy(stdout, gNoiseIndent);
01154       printf("block %p returning with maxElementWidth=%d\n",
01155              NS_STATIC_CAST(void*, this),
01156              aMetrics.mMaxElementWidth);
01157     }
01158   }
01159 #endif
01160 
01161   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
01162   return rv;
01163 }
01164 
01165 static PRBool
01166 HaveAutoWidth(const nsHTMLReflowState& aReflowState)
01167 {
01168   return NS_UNCONSTRAINEDSIZE == aReflowState.mComputedWidth ||
01169          eStyleUnit_Auto == aReflowState.mStylePosition->mWidth.GetUnit();
01170 }
01171 
01172 
01173 // XXXldb why do we check vertical and horizontal at the same time?  Don't
01174 // we usually care about one or the other?
01175 static PRBool
01176 IsPercentageAwareChild(const nsIFrame* aFrame)
01177 {
01178   NS_ASSERTION(aFrame, "null frame is not allowed");
01179 
01180   const nsStyleMargin* margin = aFrame->GetStyleMargin();
01181   if (nsLineLayout::IsPercentageUnitSides(&margin->mMargin)) {
01182     return PR_TRUE;
01183   }
01184 
01185   const nsStylePadding* padding = aFrame->GetStylePadding();
01186   if (nsLineLayout::IsPercentageUnitSides(&padding->mPadding)) {
01187     return PR_TRUE;
01188   }
01189 
01190   // Note that borders can't be aware of percentages
01191 
01192   const nsStylePosition* pos = aFrame->GetStylePosition();
01193 
01194   if (eStyleUnit_Percent == pos->mWidth.GetUnit()
01195     || eStyleUnit_Percent == pos->mMaxWidth.GetUnit()
01196     || eStyleUnit_Percent == pos->mMinWidth.GetUnit()
01197     || eStyleUnit_Percent == pos->mHeight.GetUnit()
01198     || eStyleUnit_Percent == pos->mMinHeight.GetUnit()
01199     || eStyleUnit_Percent == pos->mMaxHeight.GetUnit()
01200     || nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!!
01201     return PR_TRUE;
01202   }
01203 
01204   return PR_FALSE;
01205 }
01206 
01207 PRBool
01208 nsBlockFrame::CheckForCollapsedBottomMarginFromClearanceLine()
01209 {
01210   line_iterator begin = begin_lines();
01211   line_iterator line = end_lines();
01212 
01213   while (PR_TRUE) {
01214     if (begin == line) {
01215       return PR_FALSE;
01216     }
01217     --line;
01218     if (line->mBounds.height != 0 || !line->CachedIsEmpty()) {
01219       return PR_FALSE;
01220     }
01221     if (line->HasClearance()) {
01222       return PR_TRUE;
01223     }
01224   }
01225   // not reached
01226 }
01227 
01228 void
01229 nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
01230                                nsBlockReflowState&      aState,
01231                                nsHTMLReflowMetrics&     aMetrics)
01232 {
01233   const nsMargin& borderPadding = aState.BorderPadding();
01234 #ifdef NOISY_FINAL_SIZE
01235   ListTag(stdout);
01236   printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
01237          aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
01238          aState.mPrevBottomMargin,
01239          borderPadding.top, borderPadding.bottom);
01240 #endif
01241 
01242   // XXXldb Handling min-width/max-width stuff after reflowing children
01243   // seems wrong.  But IIRC this function only does more than a little
01244   // bit in rare cases (or something like that, I'm not really sure).
01245   // What are those cases, and do we get the wrong behavior?
01246 
01247   // Compute final width
01248   nscoord maxElementWidth = 0;
01249 #ifdef NOISY_KIDXMOST
01250   printf("%p aState.mKidXMost=%d\n", this, aState.mKidXMost); 
01251 #endif
01252   if (!HaveAutoWidth(aReflowState)) {
01253     // Use style defined width
01254     aMetrics.width = borderPadding.left + aReflowState.mComputedWidth +
01255       borderPadding.right;
01256 
01257     if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
01258       if (GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Percent) {
01259         // for percentage widths, |HaveAutoWidth| is sometimes true and
01260         // sometimes false (XXXldb check that this is really true), and
01261         // we want the max-element-width to be the same either way
01262         // (i.e., whether it's an uncontsrained reflow or a fixed-width
01263         // reflow).  Thus, do the same thing we do below.
01264         maxElementWidth = aState.mMaxElementWidth +
01265           borderPadding.left + borderPadding.right;
01266       } else {
01267         // When style defines the width use it for the max-element-width
01268         // because we can't shrink any smaller.
01269         maxElementWidth = aMetrics.width;
01270       }
01271     }
01272   }
01273   else {
01274     nscoord computedWidth;
01275 
01276     // XXX Misleading comment:
01277     // There are two options here. We either shrink wrap around our
01278     // contents or we fluff out to the maximum block width. Note:
01279     // We always shrink wrap when given an unconstrained width.
01280     if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
01281         !aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) &&
01282         !aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
01283       // XXX Misleading comment:
01284       // Set our width to the max width if we aren't already that
01285       // wide. Note that the max-width has nothing to do with our
01286       // contents (CSS2 section XXX)
01287       // XXXldb In what cases do we reach this code?
01288       computedWidth = borderPadding.left + aState.mContentArea.width +
01289         borderPadding.right;
01290     } else {
01291       computedWidth = aState.mKidXMost;
01292       if (NS_BLOCK_SPACE_MGR & mState) {
01293         // Include the space manager's state to properly account for the
01294         // extent of floated elements.
01295         nscoord xmost;
01296         if (aReflowState.mSpaceManager->XMost(xmost) &&
01297             computedWidth < xmost)
01298           computedWidth = xmost;
01299       }
01300       computedWidth += borderPadding.right;
01301     }
01302 
01303     if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
01304       // Add in border and padding dimensions to already computed
01305       // max-element-width values.
01306       maxElementWidth = aState.mMaxElementWidth +
01307         borderPadding.left + borderPadding.right;
01308     }
01309 
01310     // Apply min/max values
01311     computedWidth -= borderPadding.left + borderPadding.right;
01312     aReflowState.ApplyMinMaxConstraints(&computedWidth, nsnull);
01313     computedWidth += borderPadding.left + borderPadding.right;
01314     if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
01315       nscoord computedMinWidth = aReflowState.mComputedMinWidth +
01316         borderPadding.left + borderPadding.right;
01317       if (maxElementWidth < computedMinWidth &&
01318           GetStylePosition()->mMinWidth.GetUnit() != eStyleUnit_Percent) {
01319         maxElementWidth = computedMinWidth;
01320       }
01321     }
01322     aMetrics.width = computedWidth;
01323 
01324     // If we're shrink wrapping, then now that we know our final width we
01325     // need to do horizontal alignment of the inline lines and make sure
01326     // blocks are correctly sized and positioned. Any lines that need
01327     // final adjustment will have been marked as dirty
01328     if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
01329       // If the closest block ancestor (and anything in between) is also
01330       // shrink wrap width, then we don't need to do this, because it
01331       // will reflow us after it calculates the final width
01332       PRBool rewrap = PR_TRUE;
01333       for (const nsHTMLReflowState *prs = aReflowState.parentReflowState;
01334            prs && prs->mComputedWidth == NS_SHRINKWRAPWIDTH;
01335            prs = prs->parentReflowState) {
01336         if (prs->frame->GetType() == nsLayoutAtoms::blockFrame ||
01337             prs->frame->GetType() == nsLayoutAtoms::areaFrame) {
01338           rewrap = PR_FALSE;
01339           break;
01340         }
01341       }
01342       if (rewrap) {
01343         // XXX Is this only used on things that are already NS_BLOCK_SPACE_MGR
01344         // and NS_BLOCK_MARGIN_ROOT?
01345         nsHTMLReflowState reflowState(aReflowState);
01346 
01347         reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
01348                                      borderPadding.right;
01349         reflowState.reason = eReflowReason_Resize;
01350         reflowState.mSpaceManager->ClearRegions();
01351 
01352 #ifdef DEBUG
01353         nscoord oldDesiredWidth = aMetrics.width;
01354 #endif
01355         nsBlockReflowState state(reflowState, aState.mPresContext, this,
01356                                  aMetrics,
01357                                  aReflowState.mFlags.mHasClearance || (NS_BLOCK_MARGIN_ROOT & mState),
01358                                  (NS_BLOCK_MARGIN_ROOT & mState));
01359         // Don't try to pull up any new content from our next in flow. Shrinkwrapping
01360         // shouldn't make us shorter anyway.
01361         ReflowDirtyLines(state, PR_FALSE);
01362         aState.mY = state.mY;
01363         NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
01364       }
01365     }
01366   }
01367 
01368   // Return bottom margin information
01369   // rbs says he hit this assertion occasionally (see bug 86947), so
01370   // just set the margin to zero and we'll figure out why later
01371   //NS_ASSERTION(aMetrics.mCarriedOutBottomMargin.IsZero(),
01372   //             "someone else set the margin");
01373   nscoord nonCarriedOutVerticalMargin = 0;
01374   if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
01375     // Apply rule from CSS 2.1 section 8.3.1. If we have some empty
01376     // line with clearance and a non-zero top margin and all
01377     // subsequent lines are empty, then we do not allow our childrens'
01378     // carried out bottom margin to be carried out of us and collapse
01379     // with our own bottom margin.
01380     if (CheckForCollapsedBottomMarginFromClearanceLine()) {
01381       // Convert the children's carried out margin to something that
01382       // we will include in our height
01383       nonCarriedOutVerticalMargin = aState.mPrevBottomMargin.get();
01384       aState.mPrevBottomMargin.Zero();
01385     }
01386     aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
01387   } else {
01388     aMetrics.mCarriedOutBottomMargin.Zero();
01389   }
01390 
01391   // Compute final height
01392   if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
01393     if (NS_FRAME_IS_COMPLETE(aState.mReflowStatus)) {
01394       // Figure out how much of the computed height should be
01395       // applied to this frame.
01396       nscoord computedHeightLeftOver = aReflowState.mComputedHeight;
01397       if (mPrevInFlow) {
01398         // Reduce the height by the computed height of prev-in-flows.
01399         for (nsIFrame* prev = mPrevInFlow; prev; prev = prev->GetPrevInFlow()) {
01400           nscoord contentHeight = prev->GetRect().height;
01401           if (prev == mPrevInFlow) {
01402             // subtract off the style top borderpadding to get the
01403             // content height
01404             contentHeight -= aReflowState.mComputedBorderPadding.top;
01405           }
01406           computedHeightLeftOver -= contentHeight;
01407         }
01408         // We may have stretched the frame beyond its computed height. Oh well.
01409         computedHeightLeftOver = PR_MAX(0, computedHeightLeftOver);
01410       }
01411 
01412       aMetrics.height = borderPadding.top + computedHeightLeftOver + borderPadding.bottom;
01413       if (computedHeightLeftOver > 0 &&
01414           aMetrics.height > aReflowState.availableHeight) {
01415         // We don't fit and we consumed some of the computed height,
01416         // so we should consume all the available height and then
01417         // break.  If our bottom border/padding straddles the break
01418         // point, then this will increase our height and push the
01419         // border/padding to the next page/column.
01420         aMetrics.height = aReflowState.availableHeight;
01421         aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE;
01422       }
01423     }
01424     else {
01425       // Use the current height; continuations will take up the rest.
01426       // Do extend the height to at least consume the available
01427       // height, otherwise our left/right borders (for example) won't
01428       // extend all the way to the break.
01429       aMetrics.height = PR_MAX(aReflowState.availableHeight,
01430                                aState.mY + nonCarriedOutVerticalMargin);
01431     }
01432 
01433     // Don't carry out a bottom margin when our height is fixed.
01434     aMetrics.mCarriedOutBottomMargin.Zero();
01435   }
01436   else {
01437     nscoord autoHeight = aState.mY + nonCarriedOutVerticalMargin;
01438 
01439     // Shrink wrap our height around our contents.
01440     if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
01441       // When we are a bottom-margin root make sure that our last
01442       // childs bottom margin is fully applied.
01443       // Apply the margin only if there's space for it.
01444       if (autoHeight < aState.mReflowState.availableHeight)
01445       {
01446         // Truncate bottom margin if it doesn't fit to our available height.
01447         autoHeight = PR_MIN(autoHeight + aState.mPrevBottomMargin.get(), aState.mReflowState.availableHeight);
01448       }
01449     }
01450 
01451     if (NS_BLOCK_SPACE_MGR & mState) {
01452       // Include the space manager's state to properly account for the
01453       // bottom margin of any floated elements; e.g., inside a table cell.
01454       nscoord ymost;
01455       if (aReflowState.mSpaceManager->YMost(ymost) &&
01456           autoHeight < ymost)
01457         autoHeight = ymost;
01458     }
01459 
01460     // Apply min/max values
01461     autoHeight -= borderPadding.top;
01462     nscoord oldAutoHeight = autoHeight;
01463     aReflowState.ApplyMinMaxConstraints(nsnull, &autoHeight);
01464     if (autoHeight != oldAutoHeight) {
01465       // Our min-height or max-height made our height change.  Don't carry out
01466       // our kids' bottom margins.
01467       aMetrics.mCarriedOutBottomMargin.Zero();
01468     }
01469     autoHeight += borderPadding.top + borderPadding.bottom;
01470     aMetrics.height = autoHeight;
01471   }
01472 
01473   aMetrics.ascent = mAscent;
01474   aMetrics.descent = aMetrics.height - aMetrics.ascent;
01475 
01476   if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
01477     // Store away the final value
01478     aMetrics.mMaxElementWidth = maxElementWidth;
01479 #ifdef DEBUG
01480     if (gNoisyMaxElementWidth) {
01481       IndentBy(stdout, gNoiseIndent);
01482       printf ("nsBlockFrame::CFS: %p returning MEW %d\n", 
01483               NS_STATIC_CAST(void*, this), aMetrics.mMaxElementWidth);
01484     }
01485 #endif
01486   }
01487 
01488 #ifdef DEBUG_blocks
01489   if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
01490     ListTag(stdout);
01491     printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
01492   }
01493   if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH) &&
01494       (maxElementWidth > aMetrics.width))) {
01495     ListTag(stdout);
01496     printf(": WARNING: max-element-width:%d desired:%d,%d maxSize:%d,%d\n",
01497            maxElementWidth, aMetrics.width, aMetrics.height,
01498            aState.mReflowState.availableWidth,
01499            aState.mReflowState.availableHeight);
01500   }
01501 #endif
01502 #ifdef DEBUG
01503   if (gNoisyMaxElementWidth) {
01504     if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
01505       IndentBy(stdout, gNoiseIndent);
01506       if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
01507         printf("PASS1 ");
01508       }
01509       ListTag(stdout);
01510       printf(": max-element-width:%d desired:%d,%d maxSize:%d,%d\n",
01511              maxElementWidth, aMetrics.width, aMetrics.height,
01512              aState.mReflowState.availableWidth,
01513              aState.mReflowState.availableHeight);
01514     }
01515   }
01516 #endif
01517 
01518   // If we're requested to update our maximum width, then compute it
01519   if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
01520     if (!HaveAutoWidth(aReflowState) &&
01521         aReflowState.mStylePosition->mWidth.GetUnit() != eStyleUnit_Percent) {
01522       aMetrics.mMaximumWidth = aMetrics.width;
01523     } else {
01524       // We need to add in for the right border/padding
01525       // The maximum width in the reflow state includes the left
01526       // border/padding but not the right.
01527       aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
01528     }
01529 #ifdef NOISY_MAXIMUM_WIDTH
01530     printf("nsBlockFrame::ComputeFinalSize block %p setting aMetrics.mMaximumWidth to %d\n", this, aMetrics.mMaximumWidth);
01531 #endif
01532   }
01533 
01534   ComputeCombinedArea(aReflowState, aMetrics);
01535 }
01536 
01537 void
01538 nsBlockFrame::ComputeCombinedArea(const nsHTMLReflowState& aReflowState,
01539                                   nsHTMLReflowMetrics& aMetrics)
01540 {
01541   // Compute the combined area of our children
01542   // XXX_perf: This can be done incrementally.  It is currently one of
01543   // the things that makes incremental reflow O(N^2).
01544   nsRect area(0, 0, aMetrics.width, aMetrics.height);
01545   if (NS_STYLE_OVERFLOW_CLIP != aReflowState.mStyleDisplay->mOverflowX) {
01546     for (line_iterator line = begin_lines(), line_end = end_lines();
01547          line != line_end;
01548          ++line) {
01549       area.UnionRect(area, line->GetCombinedArea());
01550     }
01551 
01552     // Factor the bullet in; normally the bullet will be factored into
01553     // the line-box's combined area. However, if the line is a block
01554     // line then it won't; if there are no lines, it won't. So just
01555     // factor it in anyway (it can't hurt if it was already done).
01556     // XXXldb Can we just fix GetCombinedArea instead?
01557     if (mBullet) {
01558       area.UnionRect(area, mBullet->GetRect());
01559     }
01560   }
01561 #ifdef NOISY_COMBINED_AREA
01562   ListTag(stdout);
01563   printf(": ca=%d,%d,%d,%d\n", area.x, area.y, area.width, area.height);
01564 #endif
01565 
01566   aMetrics.mOverflowArea = area;
01567 }
01568 
01569 nsresult
01570 nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState)
01571 {
01572   PrepareResizeReflow(aState);
01573   return NS_OK;
01574 }
01575 
01576 nsresult
01577 nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
01578 {
01579   // XXXwaterson this is non-optimal. We'd rather do this in
01580   // ReflowDirtyLines; however, I'm not quite ready to figure out how
01581   // to deal with reflow path retargeting yet.
01582   nsReflowPath *path = aState.mReflowState.path;
01583 
01584   nsReflowPath::iterator iter = path->FirstChild();
01585   nsReflowPath::iterator end = path->EndChildren();
01586 
01587   for ( ; iter != end; ++iter) {
01588     // Determine the line being impacted
01589     line_iterator line = FindLineFor(*iter);
01590     if (line == end_lines()) {
01591       // This assertion actually fires on lots of pages
01592       // (e.g., bugzilla, bugzilla query page), so limit it
01593       // to a few people until we fix the problem causing it.
01594       //
01595       // I think waterson explained once why it was happening -- I think
01596       // it has something to do with the interaction of the unconstrained
01597       // reflow in multi-pass reflow with the reflow command's chain, but
01598       // I don't remember the details.
01599 #if defined(DEBUG_dbaron) || defined(DEBUG_waterson)
01600       NS_NOTREACHED("We don't have a line for the target of the reflow.  "
01601                     "Being inefficient");
01602 #endif
01603       // This can't happen, but just in case it does...
01604       PrepareResizeReflow(aState);
01605       continue;
01606     }
01607 
01608     if (line->IsInline()) {
01609       if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
01610         // We've been asked to compute the maximum width of the block
01611         // frame, which ReflowLine() will handle by performing an
01612         // unconstrained reflow on the line. If this incremental
01613         // reflow is targeted at a continuing frame, we may have to
01614         // retarget it, as the unconstrained reflow can destroy some
01615         // of the continuations. This will allow the incremental
01616         // reflow to arrive at the target frame during the first-pass
01617         // unconstrained reflow.
01618         nsIFrame *prevInFlow = (*iter)->GetPrevInFlow();
01619         if (prevInFlow)
01620           RetargetInlineIncrementalReflow(iter, line, prevInFlow);
01621       }
01622     }
01623 
01624     // Mark this line dirty.  We need to mark the previous line dirty
01625     // if it is an inline line so that it can maybe pull up something
01626     // from the just affected line.
01627     MarkLineDirty(line);
01628   }
01629   return NS_OK;
01630 }
01631 
01632 void
01633 nsBlockFrame::RetargetInlineIncrementalReflow(nsReflowPath::iterator &aTarget,
01634                                               line_iterator &aLine,
01635                                               nsIFrame *aPrevInFlow)
01636 {
01637   // To retarget the reflow, we'll walk back through the continuations
01638   // until we reach the primary frame, or we reach a continuation that
01639   // is preceded by a ``hard'' line break.
01640   NS_ASSERTION(aLine->Contains(*aTarget),
01641                "line doesn't contain the target of the incremental reflow");
01642 
01643   // Now fix the iterator, keeping track of how many lines we walk
01644   // back through.
01645   PRInt32 lineCount = 0;
01646   const line_iterator begin = begin_lines();
01647   do {
01648     // XXX this might happen if the block is split; e.g.,
01649     // printing or print preview.
01650     if (aLine == begin) {
01651 #ifdef NS_DEBUG
01652       if (GetParent() == aPrevInFlow->GetParent()) {
01653         NS_ERROR("ran out of lines before we ran out of prev-in-flows");
01654       }
01655       else {
01656         NS_ERROR("not yet implemented: retarget incremental reflow to"
01657                  " prev-in-flow with different parent");
01658       }
01659 #endif
01660       break;
01661     }
01662     // Is the previous line a ``hard'' break? If so, stop: these
01663     // continuations will be preserved during an unconstrained reflow.
01664     // XXXwaterson should this be `!= NS_STYLE_CLEAR_NONE'?
01665     --aLine;
01666     if (aLine->GetBreakTypeAfter() == NS_STYLE_CLEAR_LINE)
01667       break;
01668 
01669     *aTarget = aPrevInFlow;
01670     aPrevInFlow = aPrevInFlow->GetPrevInFlow();
01671 
01672 #ifdef DEBUG
01673     // Paranoia. Ensure that the prev-in-flow is really in the
01674     // previous line.
01675     line_iterator check = FindLineFor(*aTarget);
01676     NS_ASSERTION(check == aLine, "prev-in-flow not in previous linebox");
01677 #endif
01678 
01679     ++lineCount;
01680   } while (aPrevInFlow);
01681 
01682   if (lineCount > 0) {
01683     // Fix any frames deeper in the reflow path.
01684 #if 0
01685     // XXXwaterson fix me! we've got to recurse through the iterator's
01686     // kids.  This really shouldn't matter unless we want to implement
01687     // `display: inline-block' or do XBL form controls. Why, you ask?
01688     // Because what will happen is that inline frames will get flowed
01689     // with a resize reflow, which will be sufficient to mask any
01690     // glitches that would otherwise occur. However, as soon as boxes
01691     // or blocks end up in the flow here (and aren't explicit reflow
01692     // roots), they may optimize away the resize reflow.
01693 
01694     // Get the reflow path, which is stored as a stack (i.e., the next
01695     // frame in the reflow is at the _end_ of the array).
01696     nsVoidArray *path = aState.mReflowState.reflowCommand->GetPath();
01697 
01698     for (PRInt32 i = path->Count() - 1; i >= 0; --i) {
01699       nsIFrame *frame = NS_STATIC_CAST(nsIFrame *, path->ElementAt(i));
01700 
01701       // Stop if we encounter a non-inline frame in the reflow path.
01702       const nsStyleDisplay* display = frame->GetStyleDisplay();
01703 
01704       if (NS_STYLE_DISPLAY_INLINE != display->mDisplay)
01705         break;
01706 
01707       // Walk back to the primary frame.
01708       PRInt32 count = lineCount;
01709       nsIFrame *prevInFlow;
01710       do {
01711         prevInFlow = frame->GetPrevInFlow();
01712       } while (--count >= 0 && prevInFlow && (frame = prevInFlow));
01713 
01714       path->ReplaceElementAt(frame, i);
01715     }
01716 #else
01717     NS_WARNING("blowing an incremental reflow targeted at a nested inline");
01718 #endif
01719   }
01720 }
01721 
01722 nsresult
01723 nsBlockFrame::MarkLineDirty(line_iterator aLine)
01724 {
01725   // Mark aLine dirty
01726   aLine->MarkDirty();
01727 #ifdef DEBUG
01728   if (gNoisyReflow) {
01729     IndentBy(stdout, gNoiseIndent);
01730     ListTag(stdout);
01731     printf(": mark line %p dirty\n", NS_STATIC_CAST(void*, aLine.get()));
01732   }
01733 #endif
01734 
01735   // Mark previous line dirty if its an inline line so that it can
01736   // maybe pullup something from the line just affected.
01737   // XXX We don't need to do this if aPrevLine ends in a break-after...
01738   if (aLine != mLines.front() &&
01739       aLine->IsInline() &&
01740       aLine.prev()->IsInline()) {
01741     aLine.prev()->MarkDirty();
01742 #ifdef DEBUG
01743     if (gNoisyReflow) {
01744       IndentBy(stdout, gNoiseIndent);
01745       ListTag(stdout);
01746       printf(": mark prev-line %p dirty\n",
01747              NS_STATIC_CAST(void*, aLine.prev().get()));
01748     }
01749 #endif
01750   }
01751 
01752   return NS_OK;
01753 }
01754 
01755 nsresult
01756 nsBlockFrame::UpdateBulletPosition(nsBlockReflowState& aState)
01757 {
01758   if (nsnull == mBullet) {
01759     // Don't bother if there is no bullet
01760     return NS_OK;
01761   }
01762   const nsStyleList* styleList = GetStyleList();
01763   if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
01764     if (mBullet && HaveOutsideBullet()) {
01765       // We now have an inside bullet, but used to have an outside
01766       // bullet.  Adjust the frame line list
01767       if (! mLines.empty()) {
01768         // if we have a line already, then move the bullet to the front of the
01769         // first line
01770         nsIFrame* child = nsnull;
01771         nsLineBox* firstLine = mLines.front();
01772         
01773         // bullet should not have any siblings if it was an outside bullet
01774         NS_ASSERTION(!mBullet->GetNextSibling(), "outside bullet should not have siblings");
01775 
01776         // move bullet to front and chain the previous frames, and update the line count
01777         child = firstLine->mFirstChild;
01778         firstLine->mFirstChild = mBullet;
01779         mBullet->SetNextSibling(child);
01780         PRInt32 count = firstLine->GetChildCount();
01781         firstLine->SetChildCount(count+1);
01782         // dirty it here in case the caller does not
01783         firstLine->MarkDirty();
01784       } else {
01785         // no prior lines, just create a new line for the bullet
01786         nsLineBox* line = aState.NewLineBox(mBullet, 1, PR_FALSE);
01787         if (!line) {
01788           return NS_ERROR_OUT_OF_MEMORY;
01789         }
01790         mLines.push_back(line);
01791       }
01792     }
01793     mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
01794   }
01795   else {
01796     if (!HaveOutsideBullet()) {
01797       // We now have an outside bullet, but used to have an inside
01798       // bullet. Take the bullet frame out of the first lines frame
01799       // list.
01800       if ((! mLines.empty()) && (mBullet == mLines.front()->mFirstChild)) {
01801         nsIFrame* next = mBullet->GetNextSibling();
01802         mBullet->SetNextSibling(nsnull);
01803         PRInt32 count = mLines.front()->GetChildCount() - 1;
01804         NS_ASSERTION(count >= 0, "empty line w/o bullet");
01805         mLines.front()->SetChildCount(count);
01806         if (0 == count) {
01807           nsLineBox* oldFront = mLines.front();
01808           mLines.pop_front();
01809           aState.FreeLineBox(oldFront);
01810           if (! mLines.empty()) {
01811             mLines.front()->MarkDirty();
01812           }
01813         }
01814         else {
01815           mLines.front()->mFirstChild = next;
01816           mLines.front()->MarkDirty();
01817         }
01818       }
01819     }
01820     mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
01821   }
01822 #ifdef DEBUG
01823   VerifyLines(PR_TRUE);
01824 #endif
01825   return NS_OK;
01826 }
01827 
01828 nsresult
01829 nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState)
01830 {
01831   nsresult rv = UpdateBulletPosition(aState);
01832 
01833   // Mark everything dirty
01834   for (line_iterator line = begin_lines(), line_end = end_lines();
01835        line != line_end;
01836        ++line)
01837   {
01838     line->MarkDirty();
01839   }
01840   return rv;
01841 }
01842 
01843 nsresult
01844 nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
01845 {
01846   // See if we can try and avoid marking all the lines as dirty
01847   PRBool  tryAndSkipLines = PR_FALSE;
01848 
01849   // we need to calculate if any part of then block itself 
01850   // is impacted by a float (bug 19579)
01851   aState.GetAvailableSpace();
01852 
01853   // See if this is a constrained resize reflow that is not impacted by floats
01854   if ((! aState.IsImpactedByFloat()) &&
01855       (aState.mReflowState.reason == eReflowReason_Resize) &&
01856       (NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
01857 
01858     // If the text is left-aligned, then we try and avoid reflowing the lines
01859     const nsStyleText* styleText = GetStyleText();
01860 
01861     if ((NS_STYLE_TEXT_ALIGN_LEFT == styleText->mTextAlign) ||
01862         ((NS_STYLE_TEXT_ALIGN_DEFAULT == styleText->mTextAlign) &&
01863          (NS_STYLE_DIRECTION_LTR == aState.mReflowState.mStyleVisibility->mDirection))) {
01864       tryAndSkipLines = PR_TRUE;
01865     }
01866   }
01867 
01868 #ifdef DEBUG
01869   if (gDisableResizeOpt) {
01870     tryAndSkipLines = PR_FALSE;
01871   }
01872   if (gNoisyReflow) {
01873     if (!tryAndSkipLines) {
01874       const nsStyleText* styleText = GetStyleText();
01875       IndentBy(stdout, gNoiseIndent);
01876       ListTag(stdout);
01877       printf(": marking all lines dirty: reason=%d availWidth=%d textAlign=%d\n",
01878              aState.mReflowState.reason,
01879              aState.mReflowState.availableWidth,
01880              styleText->mTextAlign);
01881     }
01882   }
01883 #endif
01884 
01885   if (tryAndSkipLines) {
01886     nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
01887      
01888     if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
01889       if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedMaxWidth) {
01890         newAvailWidth += aState.mReflowState.mComputedMaxWidth;
01891       }
01892       else {
01893         newAvailWidth += aState.mReflowState.availableWidth;
01894       }
01895     } else {
01896       if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedWidth) {
01897         newAvailWidth += aState.mReflowState.mComputedWidth;
01898       }
01899       else {
01900         newAvailWidth += aState.mReflowState.availableWidth;
01901       }
01902     }
01903     NS_ASSERTION(NS_UNCONSTRAINEDSIZE != newAvailWidth, "bad math, newAvailWidth is infinite");
01904 
01905 #ifdef DEBUG
01906     if (gNoisyReflow) {
01907       IndentBy(stdout, gNoiseIndent);
01908       ListTag(stdout);
01909       printf(": trying to avoid marking all lines dirty\n");
01910     }
01911 #endif
01912 
01913     for (line_iterator line = begin_lines(), line_end = end_lines();
01914          line != line_end;
01915          ++line)
01916     {
01917       // We let child blocks make their own decisions the same
01918       // way we are here.
01919       if (line->IsBlock() ||
01920           // XXXldb We need HasPercentageDescendant, not HasPercentageChild!!!
01921           line->HasPercentageChild() || 
01922           line->HasFloats() ||
01923           (line != mLines.back() && !line->HasBreakAfter()) ||
01924           line->ResizeReflowOptimizationDisabled() ||
01925           line->IsImpactedByFloat() ||
01926           (line->mBounds.XMost() > newAvailWidth)) {
01927         line->MarkDirty();
01928       }
01929 
01930 #ifdef REALLY_NOISY_REFLOW
01931       if (!line->IsBlock()) {
01932         printf("PrepareResizeReflow thinks line %p is %simpacted by floats\n", 
01933                line.get(), line->IsImpactedByFloat() ? "" : "not ");
01934       }
01935 #endif
01936 #ifdef DEBUG
01937       if (gNoisyReflow && !line->IsDirty()) {
01938         IndentBy(stdout, gNoiseIndent + 1);
01939         printf("skipped: line=%p next=%p %s %s%s%s breakTypeBefore/After=%d/%d xmost=%d\n",
01940            NS_STATIC_CAST(void*, line.get()),
01941            NS_STATIC_CAST(void*, (line.next() != end_lines() ? line.next().get() : nsnull)),
01942            line->IsBlock() ? "block" : "inline",
01943            line->HasBreakAfter() ? "has-break-after " : "",
01944            line->HasFloats() ? "has-floats " : "",
01945            line->IsImpactedByFloat() ? "impacted " : "",
01946            line->GetBreakTypeBefore(), line->GetBreakTypeAfter(),
01947            line->mBounds.XMost());
01948       }
01949 #endif
01950     }
01951   }
01952   else {
01953     // Mark everything dirty
01954     for (line_iterator line = begin_lines(), line_end = end_lines();
01955          line != line_end;
01956          ++line)
01957     {
01958       line->MarkDirty();
01959     }
01960   }
01961   return NS_OK;
01962 }
01963 
01964 //----------------------------------------
01965 
01966 nsBlockFrame::line_iterator
01967 nsBlockFrame::FindLineFor(nsIFrame* aFrame)
01968 {
01969   // This assertion actually fires on lots of pages (e.g., bugzilla,
01970   // bugzilla query page), so limit it to a few people until we fix the
01971   // problem causing it.  It's related to the similarly |#ifdef|ed
01972   // assertion in |PrepareChildIncrementalReflow|.
01973 #if defined(DEBUG_dbaron) || defined(DEBUG_waterson)
01974   NS_PRECONDITION(aFrame, "why pass a null frame?");
01975 #endif
01976 
01977   line_iterator line = begin_lines(),
01978                 line_end = end_lines();
01979   for ( ; line != line_end; ++line) {
01980     // If the target frame is in-flow, and this line contains the it,
01981     // then we've found our line.
01982     if (line->Contains(aFrame))
01983       return line;
01984 
01985     // If the target frame is floated, and this line contains the
01986     // float's placeholder, then we've found our line.
01987     if (line->HasFloats()) {
01988       for (nsFloatCache *fc = line->GetFirstFloat();
01989            fc != nsnull;
01990            fc = fc->Next()) {
01991         if (aFrame == fc->mPlaceholder->GetOutOfFlowFrame())
01992           return line;
01993       }
01994     }
01995   }
01996 
01997   return line_end;
01998 }
01999 
02011 void
02012 nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
02013                                    nsLineBox* aLine,
02014                                    nscoord aDeltaY)
02015 {
02016   NS_PRECONDITION(!aLine->IsDirty(), "should never be called on dirty lines");
02017 
02018   // Check the damage region recorded in the float damage.
02019   nsSpaceManager *spaceManager = aState.mReflowState.mSpaceManager;
02020   if (spaceManager->HasFloatDamage()) {
02021     nscoord lineYA = aLine->mBounds.y + aDeltaY;
02022     nscoord lineYB = lineYA + aLine->mBounds.height;
02023     if (spaceManager->IntersectsDamage(lineYA, lineYB)) {
02024       aLine->MarkDirty();
02025       return;
02026     }
02027   }
02028 
02029   if (aDeltaY) {
02030     // Cases we need to find:
02031     //
02032     // 1. the line was impacted by a float and now isn't
02033     // 2. the line wasn't impacted by a float and now is
02034     // 3. the line is impacted by a float both before and after and 
02035     //    the float has changed position relative to the line (or it's
02036     //    a different float).  (XXXPerf we don't currently
02037     //    check whether the float changed size.  We currently just
02038     //    mark blocks dirty and ignore any possibility of damage to
02039     //    inlines by it being a different float with a different
02040     //    size.)
02041     //
02042     //    XXXPerf: An optimization: if the line was and is completely
02043     //    impacted by a float and the float hasn't changed size,
02044     //    then we don't need to mark the line dirty.
02045     aState.GetAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE);
02046     PRBool wasImpactedByFloat = aLine->IsImpactedByFloat();
02047     PRBool isImpactedByFloat = aState.IsImpactedByFloat();
02048 #ifdef REALLY_NOISY_REFLOW
02049     printf("nsBlockFrame::PropagateFloatDamage %p was = %d, is=%d\n", 
02050        this, wasImpactedByFloat, isImpactedByFloat);
02051 #endif
02052     // Mark the line dirty if:
02053     //  1. It used to be impacted by a float and now isn't, or vice
02054     //     versa.
02055     //  2. It is impacted by a float and it is a block, which means
02056     //     that more or less of the line could be impacted than was in
02057     //     the past.  (XXXPerf This could be optimized further, since
02058     //     we're marking the whole line dirty.)
02059     if ((wasImpactedByFloat != isImpactedByFloat) ||
02060         (isImpactedByFloat && aLine->IsBlock())) {
02061       aLine->MarkDirty();
02062     }
02063   }
02064 }
02065 
02066 static void
02067 DirtyLinesWithDirtyContinuations(const nsLineList::iterator& aLineStart,
02068                                  const nsLineList::iterator& aLineEnd)
02069 {
02070   // The line we're looking at right now
02071   nsLineList::iterator line(aLineEnd);
02072 
02073   // Whether the line following the current one is dirty
02074   PRBool nextLineDirty = PR_FALSE;
02075   
02076   while (line != aLineStart) {
02077     --line;
02078 
02079     if (nextLineDirty && line->IsInline() && line->IsLineWrapped()) {
02080       line->MarkDirty();
02081       // Note that nextLineDirty is already true and |line| will be the "next
02082       // line" next time through this loop, and we just marked it dirty, so
02083       // just leave nextLineDirty as true.
02084     } else {
02085       nextLineDirty = line->IsDirty();
02086     }
02087   }
02088 }
02089 
02090 static void PlaceFrameView(nsIFrame* aFrame);
02091 
02092 static PRBool LineHasClear(nsLineBox* aLine) {
02093   return aLine->GetBreakTypeBefore() || aLine->HasFloatBreakAfter()
02094     || (aLine->IsBlock() && (aLine->mFirstChild->GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN));
02095 }
02096 
02097 
02103 void
02104 nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame,
02105                              nsBlockFrame* aOldParent, PRBool aFromOverflow,
02106                              PRBool aReparentSiblings) {
02107   nsFrameList list;
02108   nsIFrame* tail = nsnull;
02109   aOldParent->CollectFloats(aFirstFrame, list, &tail, aFromOverflow, aReparentSiblings);
02110   if (list.NotEmpty()) {
02111     for (nsIFrame* f = list.FirstChild(); f; f = f->GetNextSibling()) {
02112       ReparentFrame(f, aOldParent, this);
02113     }
02114     mFloats.AppendFrames(nsnull, list.FirstChild());
02115   }
02116 }
02117 
02118 static void DumpLine(const nsBlockReflowState& aState, nsLineBox* aLine,
02119                      nscoord aDeltaY, PRInt32 aDeltaIndent) {
02120 #ifdef DEBUG
02121   if (nsBlockFrame::gNoisyReflow) {
02122     nsRect lca(aLine->GetCombinedArea());
02123     nsBlockFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent + aDeltaIndent);
02124     printf("line=%p mY=%d dirty=%s oldBounds={%d,%d,%d,%d} oldCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d childCount=%d\n",
02125            NS_STATIC_CAST(void*, aLine), aState.mY,
02126            aLine->IsDirty() ? "yes" : "no",
02127            aLine->mBounds.x, aLine->mBounds.y,
02128            aLine->mBounds.width, aLine->mBounds.height,
02129            lca.x, lca.y, lca.width, lca.height,
02130            aDeltaY, aState.mPrevBottomMargin.get(), aLine->GetChildCount());
02131   }
02132 #endif
02133 }
02134 
02138 nsresult
02139 nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull)
02140 {
02141   nsresult rv = NS_OK;
02142   PRBool keepGoing = PR_TRUE;
02143   PRBool repositionViews = PR_FALSE; // should we really need this?
02144   PRBool foundAnyClears = PR_FALSE;
02145 
02146 #ifdef DEBUG
02147   if (gNoisyReflow) {
02148     if (aState.mReflowState.reason == eReflowReason_Incremental) {
02149       IndentBy(stdout, gNoiseIndent);
02150       ListTag(stdout);
02151       printf(": incrementally reflowing dirty lines");
02152 
02153       nsHTMLReflowCommand *command = aState.mReflowState.path->mReflowCommand;
02154       if (command) {
02155         printf(": type=%s(%d)", kReflowCommandType[command->Type()],
02156                command->Type());
02157       }
02158     }
02159     else {
02160       IndentBy(stdout, gNoiseIndent);
02161       ListTag(stdout);
02162       printf(": reflowing dirty lines");
02163     }
02164     printf(" computedWidth=%d\n", aState.mReflowState.mComputedWidth);
02165   }
02166   AutoNoisyIndenter indent(gNoisyReflow);
02167 #endif
02168 
02169   // Check whether we need to do invalidation for the child block
02170   PRBool doInvalidate =
02171     aState.mReflowState.reason == eReflowReason_Incremental ||
02172     aState.mReflowState.reason == eReflowReason_Dirty ||
02173     aState.mReflowState.reason == eReflowReason_Resize;
02174   
02175     // the amount by which we will slide the current line if it is not
02176     // dirty
02177   nscoord deltaY = 0;
02178 
02179     // whether we did NOT reflow the previous line and thus we need to
02180     // recompute the carried out margin before the line if we want to
02181     // reflow it or if its previous margin is dirty
02182   PRBool needToRecoverState = PR_FALSE;
02183   PRBool reflowedFloat = PR_FALSE;
02184   PRBool lastLineMovedUp = PR_FALSE;
02185   // We save up information about BR-clearance here
02186   PRUint8 inlineFloatBreakType = NS_STYLE_CLEAR_NONE;
02187 
02188   line_iterator line = begin_lines(), line_end = end_lines();
02189 
02190   // If we're supposed to update our maximum width, then we'll also need to
02191   // reflow any line if it's line wrapped and has a dirty continuing line.
02192   if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
02193     ::DirtyLinesWithDirtyContinuations(line, line_end);
02194   }
02195 
02196   // Reflow the lines that are already ours
02197   for ( ; line != line_end; ++line, aState.AdvanceToNextLine()) {
02198     DumpLine(aState, line, deltaY, 0);
02199 #ifdef DEBUG
02200     AutoNoisyIndenter indent2(gNoisyReflow);
02201 #endif
02202 
02203     // This really sucks, but we have to look inside any blocks that have clear
02204     // elements inside them.
02205     // XXX what can we do smarter here?
02206     if (line->IsBlock() &&
02207         (line->mFirstChild->GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN)) {
02208       line->MarkDirty();
02209     }
02210 
02211     // We have to reflow the line if it's a block whose clearance
02212     // might have changed, so detect that.
02213     if (!line->IsDirty() && line->GetBreakTypeBefore() != NS_STYLE_CLEAR_NONE) {
02214       nscoord curY = aState.mY;
02215       // See where we would be after applying any clearance due to
02216       // BRs.
02217       if (inlineFloatBreakType != NS_STYLE_CLEAR_NONE) {
02218         curY = aState.ClearFloats(curY, inlineFloatBreakType);
02219       }
02220 
02221       nscoord newY = aState.ClearFloats(curY, line->GetBreakTypeBefore());
02222       
02223       if (line->HasClearance()) {
02224         // Reflow the line if it might not have clearance anymore.
02225         if (newY == curY
02226             // aState.mY is the clearance point which should be the
02227             // top border-edge of the block frame. If sliding the
02228             // block by deltaY isn't going to put it in the predicted
02229             // position, then we'd better reflow the line.
02230             || newY != line->mBounds.y + deltaY) {
02231           line->MarkDirty();
02232         }
02233       } else {
02234         // Reflow the line if the line might have clearance now.
02235         if (curY != newY) {
02236           line->MarkDirty();
02237         }
02238       }
02239     }
02240 
02241     // We might have to reflow a line that is after a clearing BR.
02242     if (inlineFloatBreakType != NS_STYLE_CLEAR_NONE) {
02243       aState.mY = aState.ClearFloats(aState.mY, inlineFloatBreakType);
02244       if (aState.mY != line->mBounds.y + deltaY) {
02245         // SlideLine is not going to put the line where the clearance
02246         // put it. Reflow the line to be sure.
02247         line->MarkDirty();
02248       }
02249       inlineFloatBreakType = NS_STYLE_CLEAR_NONE;
02250     }
02251 
02252     PRBool previousMarginWasDirty = line->IsPreviousMarginDirty();
02253     if (previousMarginWasDirty) {
02254       // If the previous margin is dirty, reflow the current line
02255       line->MarkDirty();
02256       line->ClearPreviousMarginDirty();
02257     } else if (line->mBounds.YMost() + deltaY > aState.mBottomEdge) {
02258       // Lines that aren't dirty but get slid past our height constraint must
02259       // be reflowed.
02260       line->MarkDirty();
02261     }
02262 
02263     if (!line->IsDirty()) {
02264       // See if there's any reflow damage that requires that we mark the
02265       // line dirty.
02266       PropagateFloatDamage(aState, line, deltaY);
02267     }
02268 
02269     if (needToRecoverState && line->IsDirty()) {
02270       // We need to reconstruct the bottom margin only if we didn't
02271       // reflow the previous line and we do need to reflow (or repair
02272       // the top position of) the next line.
02273       aState.ReconstructMarginAbove(line);
02274     }
02275 
02276     if (needToRecoverState) {
02277       needToRecoverState = PR_FALSE;
02278 
02279       // Update aState.mPrevChild as if we had reflowed all of the frames in
02280       // this line.  This is expensive in some cases, since it requires
02281       // walking |GetNextSibling|.
02282       if (line->IsDirty())
02283         aState.mPrevChild = line.prev()->LastChild();
02284     }
02285 
02286     // Now repair the line and update |aState.mY| by calling
02287     // |ReflowLine| or |SlideLine|.
02288     if (line->IsDirty()) {
02289       lastLineMovedUp = PR_TRUE;
02290 
02291       PRBool maybeReflowingForFirstTime =
02292         line->mBounds.x == 0 && line->mBounds.y == 0 &&
02293         line->mBounds.width == 0 && line->mBounds.height == 0;
02294 
02295       // Compute the dirty lines "before" YMost, after factoring in
02296       // the running deltaY value - the running value is implicit in
02297       // aState.mY.
02298       nscoord oldY = line->mBounds.y;
02299       nscoord oldYMost = line->mBounds.YMost();
02300 
02301       // Reflow the dirty line. If it's an incremental reflow, then force
02302       // it to invalidate the dirty area if necessary
02303       rv = ReflowLine(aState, line, aTryPull, &keepGoing, doInvalidate);
02304       if (NS_FAILED(rv)) {
02305         return rv;
02306       }
02307       
02308       if (line->HasFloats()) {
02309         reflowedFloat = PR_TRUE;
02310       }
02311 
02312       if (!keepGoing) {
02313         DumpLine(aState, line, deltaY, -1);
02314         if (0 == line->GetChildCount()) {
02315           DeleteLine(aState, line, line_end);
02316         }
02317         break;
02318       }
02319 
02320       // Test to see whether the margin that should be carried out
02321       // to the next line (NL) might have changed. In ReflowBlockFrame
02322       // we call nextLine->MarkPreviousMarginDirty if the block's
02323       // actual carried-out bottom margin changed. So here we only
02324       // need to worry about the following effects:
02325       // 1) the line was just created, and it might now be blocking
02326       // a carried-out bottom margin from previous lines that
02327       // used to reach NL from reaching NL
02328       // 2) the line used to be empty, and is now not empty,
02329       // thus blocking a carried-out bottom margin from previous lines
02330       // that used to reach NL from reaching NL
02331       // 3) the line wasn't empty, but now is, so a carried-out
02332       // bottom margin from previous lines that didn't used to reach NL
02333       // now does
02334       // 4) the line might have changed in a way that affects NL's
02335       // ShouldApplyTopMargin decision. The three things that matter
02336       // are the line's emptiness, its adjacency to the top of the block,
02337       // and whether it has clearance (the latter only matters if the block
02338       // was and is adjacent to the top and empty).
02339       //
02340       // If the line is empty now, we can't reliably tell if the line was empty
02341       // before, so we just assume it was and do nextLine->MarkPreviousMarginDirty.
02342       // This means the checks in 4) are redundant; if the line is empty now
02343       // we don't need to check 4), but if the line is not empty now and we're sure
02344       // it wasn't empty before, any adjacency and clearance changes are irrelevant
02345       // to the result of nextLine->ShouldApplyTopMargin.
02346       if (line.next() != end_lines()) {
02347         PRBool maybeWasEmpty = oldY == oldYMost;
02348         PRBool isEmpty = line->mBounds.height == 0 && line->CachedIsEmpty();
02349         if (maybeReflowingForFirstTime /*1*/ ||
02350             (isEmpty || maybeWasEmpty) /*2/3/4*/) {
02351           line.next()->MarkPreviousMarginDirty();
02352           // since it's marked dirty, nobody will care about |deltaY|
02353         }
02354       }
02355 
02356       // If the line was just reflowed for the first time, then its
02357       // old mBounds cannot be trusted so this deltaY computation is
02358       // bogus. But that's OK because we just did
02359       // MarkPreviousMarginDirty on the next line which will force it
02360       // to be reflowed, so this computation of deltaY will not be
02361       // used.
02362       deltaY = line->mBounds.YMost() - oldYMost;
02363     } else {
02364       lastLineMovedUp = deltaY < 0;
02365 
02366       if (deltaY != 0)
02367         SlideLine(aState, line, deltaY);
02368       else
02369         repositionViews = PR_TRUE;
02370 
02371       // XXX EVIL O(N^2) EVIL
02372       aState.RecoverStateFrom(line, deltaY);
02373 
02374       // Keep mY up to date in case we're propagating reflow damage
02375       // and also because our final height may depend on it. If the
02376       // line is inlines, then only update mY if the line is not
02377       // empty, because that's what PlaceLine does. (Empty blocks may
02378       // want to update mY, e.g. if they have clearance.)
02379       if (line->IsBlock() || !line->CachedIsEmpty()) {
02380         aState.mY = line->mBounds.YMost();
02381 
02382         if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
02383           // Mark the line as dirty so once we known the final shrink
02384           // wrap width we can reflow the line to the correct size.
02385           // It's OK to skip doing this for empty lines of inlines.
02386           // XXX We don't always need to do this...
02387           // XXX For inlines, we could record in the line box
02388           // that HorzontalAlignFrames does not depend on the line width,
02389           // and thus we don't have to mark it dirty here
02390           line->MarkDirty();
02391           aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
02392         }
02393       }
02394 
02395       needToRecoverState = PR_TRUE;
02396     }
02397 
02398     // Record if we need to clear floats before reflowing the next
02399     // line. Note that inlineFloatBreakType will be handled and
02400     // cleared before the next line is processed, so there is no
02401     // need to combine break types here.
02402     if (line->HasFloatBreakAfter()) {
02403       inlineFloatBreakType = line->GetBreakTypeAfter();
02404     }
02405 
02406     if (LineHasClear(line.get())) {
02407       foundAnyClears = PR_TRUE;
02408     }
02409 
02410     DumpLine(aState, line, deltaY, -1);
02411   }
02412 
02413   if (needToRecoverState) {
02414     // Is this expensive?
02415     aState.ReconstructMarginAbove(line);
02416 
02417     // Update aState.mPrevChild as if we had reflowed all of the frames in
02418     // the last line.  This is expensive in some cases, since it requires
02419     // walking |GetNextSibling|.
02420     aState.mPrevChild = line.prev()->LastChild();
02421   }
02422 
02423   // Should we really have to do this?
02424   if (repositionViews)
02425     ::PlaceFrameView(this);
02426 
02427   // We can skip trying to pull up the next line if there is no next
02428   // in flow or we were told not to or we know it will be futile, i.e.,
02429   // -- the next in flow is not changing
02430   // -- and we cannot have added more space for its first line to be
02431   // pulled up into,
02432   // -- and it's a not a resize reflow (so our width didn't change),
02433   // -- and we didn't reflow any floats (so the available space
02434   // didn't change)
02435   if (!aState.mNextInFlow || !aTryPull ||
02436       (aState.mReflowState.mFlags.mNextInFlowUntouched &&
02437        !lastLineMovedUp && 
02438        (aState.mReflowState.reason == eReflowReason_Incremental ||
02439         aState.mReflowState.reason == eReflowReason_Dirty) &&
02440        !reflowedFloat)) {
02441     if (aState.mNextInFlow) {
02442       aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE;
02443     }
02444   } else {
02445     // Pull data from a next-in-flow if there's still room for more
02446     // content here.
02447     while (keepGoing && (nsnull != aState.mNextInFlow)) {
02448       // Grab first line from our next-in-flow
02449       nsBlockFrame* nextInFlow = aState.mNextInFlow;
02450       line_iterator nifLine = nextInFlow->begin_lines();
02451       nsLineBox *toMove;
02452       PRBool collectOverflowFloats;
02453       if (nifLine != nextInFlow->end_lines()) {
02454         if (HandleOverflowPlaceholdersOnPulledLine(aState, nifLine)) {
02455           // go around again in case the line was deleted
02456           continue;
02457         }
02458         toMove = nifLine;
02459         nextInFlow->mLines.erase(nifLine);
02460         collectOverflowFloats = PR_FALSE;
02461       } else {
02462         // Grab an overflow line if there are any
02463         nsLineList* overflowLines = nextInFlow->GetOverflowLines();
02464         if (overflowLines &&
02465             HandleOverflowPlaceholdersOnPulledLine(aState, overflowLines->front())) {
02466           // go around again in case the line was deleted
02467           continue;
02468         }
02469         if (!overflowLines) {
02470           aState.mNextInFlow =
02471             NS_STATIC_CAST(nsBlockFrame*, nextInFlow->mNextInFlow);
02472           continue;
02473         }
02474         nifLine = overflowLines->begin();
02475         NS_ASSERTION(nifLine != overflowLines->end(),
02476                      "Stored overflow line list should not be empty");
02477         toMove = nifLine;
02478         nextInFlow->RemoveOverflowLines();
02479         nifLine = overflowLines->erase(nifLine);
02480         if (nifLine != overflowLines->end()) {
02481           // We need to this remove-and-put-back dance because we want
02482           // to avoid making the overflow line list empty while it's
02483           // stored in the property (because the property has the
02484           // invariant that the list is never empty).
02485           nextInFlow->SetOverflowLines(overflowLines);
02486         }
02487         collectOverflowFloats = PR_TRUE;
02488       }
02489 
02490       if (0 == toMove->GetChildCount()) {
02491         // The line is empty. Try the next one.
02492         NS_ASSERTION(nsnull == toMove->mFirstChild, "bad empty line");
02493         aState.FreeLineBox(toMove);
02494         continue;
02495       }
02496 
02497       // XXX move to a subroutine: run-in, overflow, pullframe and this do this
02498       // Make the children in the line ours.
02499       nsIFrame* frame = toMove->mFirstChild;
02500       nsIFrame* lastFrame = nsnull;
02501       PRInt32 n = toMove->GetChildCount();
02502       while (--n >= 0) {
02503         ReparentFrame(frame, nextInFlow, this);
02504         lastFrame = frame;
02505         frame = frame->GetNextSibling();
02506       }
02507       lastFrame->SetNextSibling(nsnull);
02508 
02509       // Reparent floats whose placeholders are in the line.
02510       ReparentFloats(toMove->mFirstChild, nextInFlow, collectOverflowFloats, PR_TRUE);
02511 
02512       // Add line to our line list
02513       if (aState.mPrevChild) {
02514         aState.mPrevChild->SetNextSibling(toMove->mFirstChild);
02515       }
02516 
02517       line = mLines.before_insert(end_lines(), toMove);
02518 
02519       DumpLine(aState, toMove, deltaY, 0);
02520 #ifdef DEBUG
02521       AutoNoisyIndenter indent2(gNoisyReflow);
02522 #endif
02523 
02524       // Now reflow it and any lines that it makes during it's reflow
02525       // (we have to loop here because reflowing the line may case a new
02526       // line to be created; see SplitLine's callers for examples of
02527       // when this happens).
02528       while (line != end_lines()) {
02529         NS_ASSERTION(aTryPull, "We shouldn't be in here if we can't pull!");
02530         rv = ReflowLine(aState, line, PR_TRUE, &keepGoing, doInvalidate);
02531         if (NS_FAILED(rv)) {
02532           NS_WARNING("Line reflow failed");
02533           return rv;
02534         }
02535         DumpLine(aState, line, deltaY, -1);
02536         if (!keepGoing) {
02537           if (0 == line->GetChildCount()) {
02538             DeleteLine(aState, line, line_end);
02539           }
02540           break;
02541         }
02542 
02543         if (LineHasClear(line.get())) {
02544           foundAnyClears = PR_TRUE;
02545         }
02546 
02547         // If this is an inline frame then its time to stop
02548         ++line;
02549         aState.AdvanceToNextLine();
02550       }
02551     }
02552 
02553     if (NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)) {
02554       aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
02555     }
02556   }
02557 
02558   // Handle an odd-ball case: a list-item with no lines
02559   if (mBullet && HaveOutsideBullet() && mLines.empty()) {
02560     nsHTMLReflowMetrics metrics(nsnull);
02561     ReflowBullet(aState, metrics);
02562 
02563     // There are no lines so we have to fake up some y motion so that
02564     // we end up with *some* height.
02565     aState.mY += metrics.height;
02566   }
02567 
02568   if (foundAnyClears) {
02569     AddStateBits(NS_BLOCK_HAS_CLEAR_CHILDREN);
02570   } else {
02571     RemoveStateBits(NS_BLOCK_HAS_CLEAR_CHILDREN);
02572   }
02573 
02574 #ifdef DEBUG
02575   if (gNoisyReflow) {
02576     IndentBy(stdout, gNoiseIndent - 1);
02577     ListTag(stdout);
02578     printf(": done reflowing dirty lines (status=%x)\n",
02579            aState.mReflowStatus);
02580   }
02581 #endif
02582 
02583   return rv;
02584 }
02585 
02586 void
02587 nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
02588                          nsLineList::iterator aLine,
02589                          nsLineList::iterator aLineEnd)
02590 {
02591   NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
02592   if (0 == aLine->GetChildCount()) {
02593     NS_ASSERTION(aState.mCurrentLine == aLine,
02594                  "using function more generally than designed, "
02595                  "but perhaps OK now");
02596     nsLineBox *line = aLine;
02597     aLine = mLines.erase(aLine);
02598     aState.FreeLineBox(line);
02599     // Mark the previous margin of the next line dirty since we need to
02600     // recompute its top position.
02601     if (aLine != aLineEnd)
02602       aLine->MarkPreviousMarginDirty();
02603   }
02604 }
02605 
02612 static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
02613                                     nsRect* aHStrip, nsRect* aVStrip) {
02614   NS_ASSERTION(aR1.TopLeft() == aR2.TopLeft(),
02615                "expected rects at the same position");
02616   nsRect unionRect(aR1.x, aR1.y, PR_MAX(aR1.width, aR2.width),
02617                    PR_MAX(aR1.height, aR2.height));
02618   nscoord VStripStart = PR_MIN(aR1.width, aR2.width);
02619   nscoord HStripStart = PR_MIN(aR1.height, aR2.height);
02620   *aVStrip = unionRect;
02621   aVStrip->x += VStripStart;
02622   aVStrip->width -= VStripStart;
02623   *aHStrip = unionRect;
02624   aHStrip->y += HStripStart;
02625   aHStrip->height -= HStripStart;
02626 }
02627 
02633 nsresult
02634 nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
02635                          line_iterator aLine,
02636                          PRBool aTryPull,
02637                          PRBool* aKeepReflowGoing,
02638                          PRBool aDamageDirtyArea)
02639 {
02640   nsresult rv = NS_OK;
02641 
02642   NS_ABORT_IF_FALSE(aLine->GetChildCount(), "reflowing empty line");
02643 
02644   // Setup the line-layout for the new line
02645   aState.mCurrentLine = aLine;
02646   aLine->ClearDirty();
02647   aLine->InvalidateCachedIsEmpty();
02648   
02649   // Now that we know what kind of line we have, reflow it
02650   if (aLine->IsBlock()) {
02651     nsRect oldBounds = aLine->mFirstChild->GetRect();
02652     nsRect oldCombinedArea(aLine->GetCombinedArea());
02653     rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
02654     nsRect newBounds = aLine->mFirstChild->GetRect();
02655 
02656     // We expect blocks to damage any area inside their bounds that is
02657     // dirty; however, if the frame changes size or position then we
02658     // need to do some repainting.
02659     // XXX roc --- the above statement is ambiguous about whether 'bounds'
02660     // means the frame's bounds or overflowArea, and in fact this is a source
02661     // of much confusion and bugs. Thus the following hack considers *both*
02662     // overflowArea and bounds. This should be considered a temporary hack
02663     // until we decide how it's really supposed to work.
02664     if (aDamageDirtyArea) {
02665       nsRect lineCombinedArea(aLine->GetCombinedArea());
02666       if (oldCombinedArea.TopLeft() != lineCombinedArea.TopLeft() ||
02667           oldBounds.TopLeft() != newBounds.TopLeft()) {
02668         // The block has moved, and so to be safe we need to repaint
02669         // XXX We need to improve on this...
02670         nsRect  dirtyRect;
02671         dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
02672 #ifdef NOISY_BLOCK_INVALIDATE
02673         printf("%p invalidate 6 (%d, %d, %d, %d)\n",
02674                this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
02675 #endif
02676         Invalidate(dirtyRect);
02677       } else {
02678         nsRect combinedAreaHStrip, combinedAreaVStrip;
02679         nsRect boundsHStrip, boundsVStrip;
02680         GetRectDifferenceStrips(oldBounds, newBounds,
02681                                 &boundsHStrip, &boundsVStrip);
02682         GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea,
02683                                 &combinedAreaHStrip, &combinedAreaVStrip);
02684 
02685 #ifdef NOISY_BLOCK_INVALIDATE
02686         printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n",
02687                this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height);
02688         printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n",
02689                this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height);
02690         printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n",
02691                this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height);
02692         printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n",
02693                this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height);
02694 #endif
02695         // The first thing Invalidate does is check if the rect is empty, so
02696         // don't bother doing that here.
02697         Invalidate(boundsVStrip);
02698         Invalidate(boundsHStrip);
02699         Invalidate(combinedAreaVStrip);
02700         Invalidate(combinedAreaHStrip);
02701       }
02702     }
02703   }
02704   else {
02705     nsRect oldCombinedArea(aLine->GetCombinedArea());
02706     aLine->SetLineWrapped(PR_FALSE);
02707 
02708     // If we're supposed to update the maximum width, then we'll need to reflow
02709     // the line with an unconstrained width (which will give us the new maximum
02710     // width), then we'll reflow it again with the constrained width.
02711     // We only do this if this is a beginning line, i.e., don't do this for
02712     // lines associated with content that line wrapped (see ReflowDirtyLines()
02713     // for details).
02714     // XXX This approach doesn't work when floats are involved in which case
02715     // we'll either need to recover the float state that applies to the
02716     // unconstrained reflow or keep it around in a separate space manager...
02717     PRBool isBeginningLine = aState.mCurrentLine == begin_lines() ||
02718                              !aState.mCurrentLine.prev()->IsLineWrapped();
02719     // XXXldb Add &&!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)
02720     // If we're not allowed to pull frames from our next-in-flow (e.g., during
02721     // shrinkwrap) then we shouldn't be doing this.
02722     if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine && aTryPull) {
02723       // First reflow the line with an unconstrained width. 
02724       nscoord oldY = aState.mY;
02725       nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin);
02726       PRBool  oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
02727 
02728 #if defined(DEBUG_waterson) || defined(DEBUG_dbaron)
02729       // XXXwaterson if oldUnconstrainedWidth was set, why do we need
02730       // to do the second reflow, below?
02731 
02732       if (oldUnconstrainedWidth)
02733         printf("*** oldUnconstrainedWidth was already set.\n"
02734                "*** This code (%s:%d) could be optimized a lot!\n"
02735                "+++ possibly doing an unnecessary second-pass unconstrained "
02736                "reflow\n",
02737                __FILE__, __LINE__);
02738 #endif
02739 
02740       // When doing this we need to set the block reflow state's
02741       // "mUnconstrainedWidth" variable to PR_TRUE so if we encounter
02742       // a placeholder and then reflow its associated float we don't
02743       // end up resetting the line's right edge and have it think the
02744       // width is unconstrained...
02745       aState.mSpaceManager->PushState();
02746       aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
02747       ReflowInlineFrames(aState, aLine, PR_TRUE, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
02748       aState.mY = oldY;
02749       aState.mPrevBottomMargin = oldPrevBottomMargin;
02750       aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
02751       aState.mSpaceManager->PopState();
02752 
02753       // Update the line's maximum width
02754       aLine->mMaximumWidth = aLine->mBounds.XMost();
02755 #ifdef NOISY_MAXIMUM_WIDTH
02756       printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n", 
02757              this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaximumWidth);
02758 #endif
02759       aState.UpdateMaximumWidth(aLine->mMaximumWidth);
02760 
02761       // Now reflow the line again this time without having it compute
02762       // the maximum width.
02763       // We leave whether to compute max-element-width as-is, because
02764       // making this call throws out the previous max-element-width
02765       // information stored in the float cache.
02766       nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
02767 
02768       aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
02769       rv = ReflowInlineFrames(aState, aLine, PR_TRUE, aKeepReflowGoing, aDamageDirtyArea);
02770       aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
02771 
02772     } else {
02773       rv = ReflowInlineFrames(aState, aLine, aTryPull, aKeepReflowGoing, aDamageDirtyArea);
02774       if (NS_SUCCEEDED(rv))
02775       {
02776         if (aState.GetFlag(BRS_COMPUTEMAXWIDTH))
02777         {
02778 #ifdef NOISY_MAXIMUM_WIDTH
02779           printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n", 
02780                  this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaximumWidth);
02781 #endif
02782           aState.UpdateMaximumWidth(aLine->mMaximumWidth);
02783         }
02784         if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH))
02785         {
02786 #ifdef DEBUG
02787           if (gNoisyMaxElementWidth) {
02788             IndentBy(stdout, gNoiseIndent);
02789             printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaxElementWidth to %d\n", 
02790                    NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine.get()),
02791                    aLine->mMaxElementWidth);
02792           }
02793 #endif
02794           aState.UpdateMaxElementWidth(aLine->mMaxElementWidth);
02795         }
02796       }
02797     }
02798 
02799     // We don't really know what changed in the line, so use the union
02800     // of the old and new combined areas
02801     if (aDamageDirtyArea) {
02802       nsRect dirtyRect;
02803       dirtyRect.UnionRect(oldCombinedArea, aLine->GetCombinedArea());
02804 #ifdef NOISY_BLOCK_INVALIDATE
02805       printf("%p invalidate because %s is true (%d, %d, %d, %d)\n",
02806              this, aDamageDirtyArea ? "aDamageDirtyArea" : "aLine->IsForceInvalidate",
02807              dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
02808       if (aLine->IsForceInvalidate())
02809         printf("  dirty line is %p\n", NS_STATIC_CAST(void*, aLine.get());
02810 #endif
02811       Invalidate(dirtyRect);
02812     }
02813   }
02814 
02815   return rv;
02816 }
02817 
02822 nsresult
02823 nsBlockFrame::PullFrame(nsBlockReflowState& aState,
02824                         line_iterator aLine,
02825                         PRBool aDamageDeletedLines,
02826                         nsIFrame*& aFrameResult)
02827 {
02828   aFrameResult = nsnull;
02829 
02830   // First check our remaining lines
02831   if (end_lines() != aLine.next()) {
02832 #ifdef DEBUG
02833     PRBool retry =
02834 #endif
02835       PullFrameFrom(aState, aLine, this, PR_FALSE, aLine.next(),
02836                     aDamageDeletedLines, aFrameResult);
02837     NS_ASSERTION(!retry, "Shouldn't have to retry in the current block");
02838     return NS_OK;
02839   }
02840 
02841   NS_ASSERTION(!GetOverflowLines(),
02842     "Our overflow lines should have been removed at the start of reflow");
02843 
02844   // Try each next in flows
02845   nsBlockFrame* nextInFlow = aState.mNextInFlow;
02846   while (nextInFlow) {
02847     // first normal lines, then overflow lines
02848     if (!nextInFlow->mLines.empty()) {
02849       if (PullFrameFrom(aState, aLine, nextInFlow, PR_FALSE,
02850                         nextInFlow->mLines.begin(),
02851                         aDamageDeletedLines, aFrameResult)) {
02852         // try again with the same value of nextInFlow
02853         continue;
02854       }
02855       break;
02856     }
02857 
02858     nsLineList* overflowLines = nextInFlow->GetOverflowLines();
02859     if (overflowLines) {
02860       if (PullFrameFrom(aState, aLine, nextInFlow, PR_TRUE,
02861                         overflowLines->begin(),
02862                         aDamageDeletedLines, aFrameResult)) {
02863         // try again with the same value of nextInFlow
02864         continue;
02865       }
02866       break;
02867     }
02868 
02869     nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
02870     aState.mNextInFlow = nextInFlow;
02871   }
02872 
02873   return NS_OK;
02874 }
02875 
02890 PRBool
02891 nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
02892                             nsLineBox* aLine,
02893                             nsBlockFrame* aFromContainer,
02894                             PRBool aFromOverflowLine,
02895                             nsLineList::iterator aFromLine,
02896                             PRBool aDamageDeletedLines,
02897                             nsIFrame*& aFrameResult)
02898 {
02899   nsLineBox* fromLine = aFromLine;
02900   NS_ABORT_IF_FALSE(fromLine, "bad line to pull from");
02901   NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line");
02902   NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line");
02903 
02904   NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->GetStyleDisplay()->IsBlockLevel(),
02905                "Disagreement about whether it's a block or not");
02906 
02907   if (fromLine->IsBlock()) {
02908     // If our line is not empty and the child in aFromLine is a block
02909     // then we cannot pull up the frame into this line. In this case
02910     // we stop pulling.
02911     aFrameResult = nsnull;
02912   }
02913   else {
02914     // Take frame from fromLine
02915     nsIFrame* frame = fromLine->mFirstChild;
02916 
02917     if (aFromContainer != this) {
02918       if (HandleOverflowPlaceholdersForPulledFrame(aState, frame)) {
02919         // we lost this one, retry
02920         return PR_TRUE;
02921       }
02922 
02923       aLine->LastChild()->SetNextSibling(frame);
02924     }
02925     // when aFromContainer is 'this', then aLine->LastChild()'s next sibling
02926     // is already set correctly.
02927     aLine->SetChildCount(aLine->GetChildCount() + 1);
02928       
02929     PRInt32 fromLineChildCount = fromLine->GetChildCount();
02930     if (0 != --fromLineChildCount) {
02931       // Mark line dirty now that we pulled a child
02932       fromLine->SetChildCount(fromLineChildCount);
02933       fromLine->MarkDirty();
02934       fromLine->mFirstChild = frame->GetNextSibling();
02935     }
02936     else {
02937       // Free up the fromLine now that it's empty
02938       // Its bounds might need to be redrawn, though.
02939       // XXX WHY do we invalidate the bounds AND the combined area? doesn't
02940       // the combined area always enclose the bounds?
02941       if (aDamageDeletedLines) {
02942         Invalidate(fromLine->mBounds);
02943       }
02944       nsLineList* fromLineList = aFromOverflowLine
02945         ? aFromContainer->RemoveOverflowLines()
02946         : &aFromContainer->mLines;
02947       if (aFromLine.next() != fromLineList->end())
02948         aFromLine.next()->MarkPreviousMarginDirty();
02949 
02950       Invalidate(fromLine->GetCombinedArea());
02951       fromLineList->erase(aFromLine);
02952       // Note that aFromLine just got incremented, so don't use it again here!
02953       aState.FreeLineBox(fromLine);
02954 
02955       // Put any remaining overflow lines back.
02956       if (aFromOverflowLine && !fromLineList->empty()) {
02957         aFromContainer->SetOverflowLines(fromLineList);
02958       }
02959     }
02960 
02961     // Change geometric parents
02962     if (aFromContainer != this) {
02963       // When pushing and pulling frames we need to check for whether any
02964       // views need to be reparented
02965       NS_ASSERTION(frame->GetParent() == aFromContainer, "unexpected parent frame");
02966 
02967       ReparentFrame(frame, aFromContainer, this);
02968 
02969       // The frame is being pulled from a next-in-flow; therefore we
02970       // need to add it to our sibling list.
02971       frame->SetNextSibling(nsnull);
02972       if (nsnull != aState.mPrevChild) {
02973         aState.mPrevChild->SetNextSibling(frame);
02974       }
02975 
02976       // The frame might have (or contain) floats that need to be
02977       // brought over too.
02978       ReparentFloats(frame, aFromContainer, aFromOverflowLine, PR_TRUE);
02979     }
02980 
02981     // Stop pulling because we found a frame to pull
02982     aFrameResult = frame;
02983 #ifdef DEBUG
02984     VerifyLines(PR_TRUE);
02985 #endif
02986   }
02987   return PR_FALSE;
02988 }
02989 
02990 static void
02991 PlaceFrameView(nsIFrame* aFrame)
02992 {
02993   if (aFrame->HasView())
02994     nsContainerFrame::PositionFrameView(aFrame);
02995   else
02996     nsContainerFrame::PositionChildViews(aFrame);
02997 }
02998 
02999 void
03000 nsBlockFrame::SlideLine(nsBlockReflowState& aState,
03001                         nsLineBox* aLine, nscoord aDY)
03002 {
03003   NS_PRECONDITION(aDY != 0, "why slide a line nowhere?");
03004 
03005   Invalidate(aLine->GetCombinedArea());
03006   // Adjust line state
03007   aLine->SlideBy(aDY);
03008   Invalidate(aLine->GetCombinedArea());
03009 
03010   // Adjust the frames in the line
03011   nsIFrame* kid = aLine->mFirstChild;
03012   if (!kid) {
03013     return;
03014   }
03015 
03016   if (aLine->IsBlock()) {
03017     if (aDY) {
03018       nsPoint p = kid->GetPosition();
03019       p.y += aDY;
03020       kid->SetPosition(p);
03021     }
03022 
03023     // Make sure the frame's view and any child views are updated
03024     ::PlaceFrameView(kid);
03025   }
03026   else {
03027     // Adjust the Y coordinate of the frames in the line.
03028     // Note: we need to re-position views even if aDY is 0, because
03029     // one of our parent frames may have moved and so the view's position
03030     // relative to its parent may have changed
03031     PRInt32 n = aLine->GetChildCount();
03032     while (--n >= 0) {
03033       if (aDY) {
03034         nsPoint p = kid->GetPosition();
03035         p.y += aDY;
03036         kid->SetPosition(p);
03037       }
03038       // Make sure the frame's view and any child views are updated
03039       ::PlaceFrameView(kid);
03040       kid = kid->GetNextSibling();
03041     }
03042   }
03043 }
03044 
03045 NS_IMETHODIMP 
03046 nsBlockFrame::AttributeChanged(nsIContent*     aChild,
03047                                PRInt32         aNameSpaceID,
03048                                nsIAtom*        aAttribute,
03049                                PRInt32         aModType)
03050 {
03051   nsresult rv = nsBlockFrameSuper::AttributeChanged(aChild, aNameSpaceID,
03052                                                     aAttribute, aModType);
03053 
03054   if (NS_FAILED(rv)) {
03055     return rv;
03056   }
03057   if (nsHTMLAtoms::start == aAttribute) {
03058     nsPresContext* presContext = GetPresContext();
03059 
03060     // XXX Not sure if this is necessary anymore
03061     RenumberLists(presContext);
03062 
03063     rv = presContext->PresShell()->
03064       AppendReflowCommand(this, eReflowType_ContentChanged, nsnull);
03065   }
03066   else if (nsHTMLAtoms::value == aAttribute) {
03067     const nsStyleDisplay* styleDisplay = GetStyleDisplay();
03068     if (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) {
03069       nsIFrame* nextAncestor = mParent;
03070       nsBlockFrame* blockParent = nsnull;
03071       
03072       // Search for the closest ancestor that's a block frame. We
03073       // make the assumption that all related list items share a
03074       // common block parent.
03075       // XXXldb I think that's a bad assumption.
03076       while (nextAncestor) {
03077         if (NS_OK == nextAncestor->QueryInterface(kBlockFrameCID, 
03078                                                   (void**)&blockParent)) {
03079           break;
03080         }
03081         nextAncestor = nextAncestor->GetParent();
03082       }
03083 
03084       // Tell the enclosing block frame to renumber list items within
03085       // itself
03086       if (nsnull != blockParent) {
03087         nsPresContext* presContext = GetPresContext();
03088         // XXX Not sure if this is necessary anymore
03089         blockParent->RenumberLists(presContext);
03090 
03091         rv = presContext->PresShell()->
03092           AppendReflowCommand(blockParent, eReflowType_ContentChanged, nsnull);
03093       }
03094     }
03095   }
03096 
03097   return rv;
03098 }
03099 
03100 inline PRBool
03101 IsPaddingZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
03102 {
03103     return (aUnit == eStyleUnit_Null ||
03104             (aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
03105             (aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
03106 }
03107 
03108 inline PRBool
03109 IsMarginZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
03110 {
03111     return (aUnit == eStyleUnit_Null ||
03112             aUnit == eStyleUnit_Auto ||
03113             (aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
03114             (aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
03115 }
03116 
03117 /* virtual */ PRBool
03118 nsBlockFrame::IsSelfEmpty()
03119 {
03120   const nsStylePosition* position = GetStylePosition();
03121 
03122   switch (position->mMinHeight.GetUnit()) {
03123     case eStyleUnit_Coord:
03124       if (position->mMinHeight.GetCoordValue() != 0)
03125         return PR_FALSE;
03126       break;
03127     case eStyleUnit_Percent:
03128       if (position->mMinHeight.GetPercentValue() != 0.0f)
03129         return PR_FALSE;
03130       break;
03131     default:
03132       return PR_FALSE;
03133   }
03134 
03135   switch (position->mHeight.GetUnit()) {
03136     case eStyleUnit_Auto:
03137       break;
03138     case eStyleUnit_Coord:
03139       if (position->mHeight.GetCoordValue() != 0)
03140         return PR_FALSE;
03141       break;
03142     case eStyleUnit_Percent:
03143       if (position->mHeight.GetPercentValue() != 0.0f)
03144         return PR_FALSE;
03145       break;
03146     default:
03147       return PR_FALSE;
03148   }
03149 
03150   const nsStyleBorder* border = GetStyleBorder();
03151   const nsStylePadding* padding = GetStylePadding();
03152   nsStyleCoord coord;
03153   if (border->GetBorderWidth(NS_SIDE_TOP) != 0 ||
03154       border->GetBorderWidth(NS_SIDE_BOTTOM) != 0 ||
03155       !IsPaddingZero(padding->mPadding.GetTopUnit(),
03156                     padding->mPadding.GetTop(coord)) ||
03157       !IsPaddingZero(padding->mPadding.GetBottomUnit(),
03158                     padding->mPadding.GetBottom(coord))) {
03159     return PR_FALSE;
03160   }
03161 
03162   return PR_TRUE;
03163 }
03164 
03165 PRBool
03166 nsBlockFrame::IsEmpty()
03167 {
03168   if (!IsSelfEmpty()) {
03169     return PR_FALSE;
03170   }
03171 
03172   for (line_iterator line = begin_lines(), line_end = end_lines();
03173        line != line_end;
03174        ++line)
03175   {
03176     if (!line->IsEmpty())
03177       return PR_FALSE;
03178   }
03179 
03180   return PR_TRUE;
03181 }
03182 
03183 PRBool
03184 nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
03185                                    nsLineBox* aLine)
03186 {
03187   if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
03188     // Apply short-circuit check to avoid searching the line list
03189     return PR_TRUE;
03190   }
03191 
03192   if (!aState.IsAdjacentWithTop()) {
03193     // If we aren't at the top Y coordinate then something of non-zero
03194     // height must have been placed. Therefore the childs top-margin
03195     // applies.
03196     aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
03197     return PR_TRUE;
03198   }
03199 
03200   // Determine if this line is "essentially" the first line
03201   for (line_iterator line = begin_lines(); line != aLine; ++line) {
03202     if (!line->CachedIsEmpty() || line->HasClearance()) {
03203       // A line which preceeds aLine is non-empty, or has clearance,
03204       // so therefore the top margin applies.
03205       aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
03206       return PR_TRUE;
03207     }
03208     // No need to apply the top margin if the line has floats.  We
03209     // should collapse anyway (bug 44419)
03210   }
03211 
03212   // The line being reflowed is "essentially" the first line in the
03213   // block. Therefore its top-margin will be collapsed by the
03214   // generational collapsing logic with its parent (us).
03215   return PR_FALSE;
03216 }
03217 
03218 nsIFrame*
03219 nsBlockFrame::GetTopBlockChild(nsPresContext* aPresContext)
03220 {
03221   if (mLines.empty())
03222     return nsnull;
03223 
03224   nsLineBox *firstLine = mLines.front();
03225   if (firstLine->IsBlock())
03226     return firstLine->mFirstChild;
03227 
03228   if (!firstLine->CachedIsEmpty())
03229     return nsnull;
03230 
03231   line_iterator secondLine = begin_lines();
03232   ++secondLine;
03233   if (secondLine == end_lines() || !secondLine->IsBlock())
03234     return nsnull;
03235 
03236   return secondLine->mFirstChild;
03237 }
03238 
03239 // If placeholders/floats split during reflowing a line, but that line will 
03240 // be put on the next page, then put the placeholders/floats back the way
03241 // they were before the line was reflowed. 
03242 void
03243 nsBlockFrame::UndoSplitPlaceholders(nsBlockReflowState& aState,
03244                                     nsIFrame*           aLastPlaceholder)
03245 {
03246   nsIFrame* undoPlaceholder;
03247   if (aLastPlaceholder) {
03248     undoPlaceholder = aLastPlaceholder->GetNextSibling();
03249     aLastPlaceholder->SetNextSibling(nsnull);
03250   }
03251   else {
03252     undoPlaceholder = aState.mOverflowPlaceholders.FirstChild();
03253     aState.mOverflowPlaceholders.SetFrames(nsnull);
03254   }
03255   // remove the next in flows of the placeholders that need to be removed
03256   for (nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, undoPlaceholder);
03257        placeholder; ) {
03258     NS_ASSERTION(!placeholder->GetNextInFlow(), "Must be the last placeholder");
03259 
03260     nsFrameManager* fm = aState.mPresContext->GetPresShell()->FrameManager();
03261     fm->UnregisterPlaceholderFrame(placeholder);
03262     placeholder->SetOutOfFlowFrame(nsnull);
03263 
03264     // XXX we probably should be doing something with oof here. But what?
03265 
03266     nsSplittableFrame::RemoveFromFlow(placeholder);
03267     nsIFrame* savePlaceholder = placeholder; 
03268     placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, placeholder->GetNextSibling());
03269     savePlaceholder->Destroy(aState.mPresContext);
03270   }
03271 }
03272 
03273 nsresult
03274 nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
03275                                line_iterator aLine,
03276                                PRBool* aKeepReflowGoing)
03277 {
03278   NS_PRECONDITION(*aKeepReflowGoing, "bad caller");
03279 
03280   nsresult rv = NS_OK;
03281 
03282   nsIFrame* frame = aLine->mFirstChild;
03283   if (!frame) {
03284     NS_ASSERTION(PR_FALSE, "program error - unexpected empty line"); 
03285     return NS_ERROR_NULL_POINTER; 
03286   }
03287 
03288   // Prepare the block reflow engine
03289   const nsStyleDisplay* display = frame->GetStyleDisplay();
03290   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
03291                            aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH),
03292                            aState.GetFlag(BRS_COMPUTEMAXWIDTH));
03293 
03294   PRUint8 breakType = display->mBreakType;
03295   // If a float split and its prev-in-flow was followed by a <BR>, then combine 
03296   // the <BR>'s break type with the block's break type (the block will be the very 
03297   // next frame after the split float).
03298   if (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType) {
03299     breakType = nsLayoutUtils::CombineBreakType(breakType,
03300                                                 aState.mFloatBreakType);
03301     aState.mFloatBreakType = NS_STYLE_CLEAR_NONE;
03302   }
03303 
03304   // Clear past floats before the block if the clear style is not none
03305   aLine->SetBreakTypeBefore(breakType);
03306 
03307   // See if we should apply the top margin. If the block frame being
03308   // reflowed is a continuation (non-null prev-in-flow) then we don't
03309   // apply its top margin because its not significant. Otherwise, dig
03310   // deeper.
03311   PRBool applyTopMargin =
03312     !frame->GetPrevInFlow() && ShouldApplyTopMargin(aState, aLine);
03313 
03314   if (applyTopMargin) {
03315     // The HasClearance setting is only valid if ShouldApplyTopMargin
03316     // returned PR_FALSE (in which case the top-margin-root set our
03317     // clearance flag). Otherwise clear it now. We'll set it later on
03318     // ourselves if necessary.
03319     aLine->ClearHasClearance();
03320   }
03321   PRBool treatWithClearance = aLine->HasClearance();
03322   // If our top margin was counted as part of some parents top-margin
03323   // collapse and we are being speculatively reflowed assuming this
03324   // frame DID NOT need clearance, then we need to check that
03325   // assumption.
03326   if (!treatWithClearance && !applyTopMargin && breakType != NS_STYLE_CLEAR_NONE &&
03327       aState.mReflowState.mDiscoveredClearance) {
03328     nscoord curY = aState.mY + aState.mPrevBottomMargin.get();
03329     nscoord clearY = aState.ClearFloats(curY, breakType);
03330     if (clearY != curY) {
03331       // Looks like that assumption was invalid, we do need
03332       // clearance. Tell our ancestor so it can reflow again. It is
03333       // responsible for actually setting our clearance flag before
03334       // the next reflow.
03335       treatWithClearance = PR_TRUE;
03336       // Only record the first frame that requires clearance
03337       if (!*aState.mReflowState.mDiscoveredClearance) {
03338         *aState.mReflowState.mDiscoveredClearance = frame;
03339       }
03340       // Exactly what we do now is flexible since we'll definitely be
03341       // reflowed.
03342     }
03343   }
03344   if (treatWithClearance) {
03345     applyTopMargin = PR_TRUE;
03346   }
03347 
03348   nsIFrame* clearanceFrame = nsnull;
03349   nscoord startingY = aState.mY;
03350   nsCollapsingMargin incomingMargin = aState.mPrevBottomMargin;
03351   nscoord clearance;
03352   while (PR_TRUE) {
03353     clearance = 0;
03354     nscoord topMargin = 0;
03355     PRBool mayNeedRetry = PR_FALSE;
03356     if (applyTopMargin) {
03357       // Precompute the blocks top margin value so that we can get the
03358       // correct available space (there might be a float that's
03359       // already been placed below the aState.mPrevBottomMargin
03360 
03361       // Setup a reflowState to get the style computed margin-top
03362       // value. We'll use a reason of `resize' so that we don't fudge
03363       // any incremental reflow state.
03364       
03365       // The availSpace here is irrelevant to our needs - all we want
03366       // out if this setup is the margin-top value which doesn't depend
03367       // on the childs available space.
03368       // XXX building a complete nsHTMLReflowState just to get the margin-top
03369       // seems like a waste. And we do this for almost every block!
03370       nsSize availSpace(aState.mContentArea.width, NS_UNCONSTRAINEDSIZE);
03371       nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
03372                                     frame, availSpace, eReflowReason_Resize);
03373       
03374       if (treatWithClearance) {
03375         aState.mY += aState.mPrevBottomMargin.get();
03376         aState.mPrevBottomMargin.Zero();
03377       }
03378       
03379       // Now compute the collapsed margin-top value into aState.mPrevBottomMargin, assuming
03380       // that all child margins collapse down to clearanceFrame.
03381       nsBlockReflowContext::ComputeCollapsedTopMargin(reflowState,
03382                                                       &aState.mPrevBottomMargin, clearanceFrame, &mayNeedRetry);
03383       
03384       // XXX optimization; we could check the collapsing children to see if they are sure
03385       // to require clearance, and so avoid retrying them
03386       
03387       if (clearanceFrame) {
03388         // Don't allow retries on the second pass. The clearance decisions for the
03389         // blocks whose top-margins collapse with ours are now fixed.
03390         mayNeedRetry = PR_FALSE;
03391       }
03392       
03393       if (!treatWithClearance && !clearanceFrame && breakType != NS_STYLE_CLEAR_NONE) {
03394         // We don't know if we need clearance and this is the first,
03395         // optimistic pass.  So determine whether *this block* needs
03396         // clearance. Note that we do not allow the decision for whether
03397         // this block has clearance to change on the second pass; that
03398         // decision is only allowed to be made under the optimistic
03399         // first pass.
03400         nscoord curY = aState.mY + aState.mPrevBottomMargin.get();
03401         nscoord clearY = aState.ClearFloats(curY, breakType);
03402         if (clearY != curY) {
03403           // Looks like we need clearance and we didn't know about it already. So
03404           // recompute collapsed margin
03405           treatWithClearance = PR_TRUE;
03406           // Remember this decision, needed for incremental reflow
03407           aLine->SetHasClearance();
03408           
03409           // Apply incoming margins
03410           aState.mY += aState.mPrevBottomMargin.get();
03411           aState.mPrevBottomMargin.Zero();
03412           
03413           // Compute the collapsed margin again, ignoring the incoming margin this time
03414           mayNeedRetry = PR_FALSE;
03415           nsBlockReflowContext::ComputeCollapsedTopMargin(reflowState,
03416                                                           &aState.mPrevBottomMargin, clearanceFrame, &mayNeedRetry);
03417         }
03418       }
03419       
03420       // Temporarily advance the running Y value so that the
03421       // GetAvailableSpace method will return the right available
03422       // space. This undone as soon as the horizontal margins are
03423       // computed.
03424       topMargin = aState.mPrevBottomMargin.get();
03425       
03426       if (treatWithClearance) {
03427         nscoord currentY = aState.mY;
03428         // advance mY to the clear position.
03429         aState.mY = aState.ClearFloats(aState.mY, breakType);
03430         
03431         // Compute clearance. It's the amount we need to add to the top
03432         // border-edge of the frame, after applying collapsed margins
03433         // from the frame and its children, to get it to line up with
03434         // the bottom of the floats. The former is currentY + topMargin,
03435         // the latter is the current aState.mY.
03436         // Note that negative clearance is possible
03437         clearance = aState.mY - (currentY + topMargin);
03438         
03439         // Add clearance to our top margin while we compute available
03440         // space for the frame
03441         topMargin += clearance;
03442         
03443         // Note that aState.mY should stay where it is: at the top
03444         // border-edge of the frame
03445       } else {
03446         // Advance aState.mY to the top border-edge of the frame.
03447         aState.mY += topMargin;
03448       }
03449     }
03450     
03451     // Here aState.mY is the top border-edge of the block.
03452     // Compute the available space for the block
03453     aState.GetAvailableSpace();
03454 #ifdef REALLY_NOISY_REFLOW
03455     printf("setting line %p isImpacted to %s\n", aLine.get(), aState.IsImpactedByFloat()?"true":"false");
03456 #endif
03457     PRBool isImpacted = aState.IsImpactedByFloat() ? PR_TRUE : PR_FALSE;
03458     aLine->SetLineIsImpactedByFloat(isImpacted);
03459     nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
03460     frame->IsSplittable(splitType);
03461     nsRect availSpace;
03462     aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
03463     
03464     // Now put the Y coordinate back to the top of the top-margin +
03465     // clearance, and flow the block.
03466     aState.mY -= topMargin;
03467     availSpace.y -= topMargin;
03468     if (NS_UNCONSTRAINEDSIZE != availSpace.height) {
03469       availSpace.height += topMargin;
03470     }
03471     
03472     // keep track of the last overflow float in case we need to undo any new additions
03473     nsIFrame* lastPlaceholder = aState.mOverflowPlaceholders.LastChild();
03474     
03475     // Reflow the block into the available space
03476     nsMargin computedOffsets;
03477     // construct the html reflow state for the block. ReflowBlock 
03478     // will initialize it
03479     nsHTMLReflowState blockHtmlRS(aState.mPresContext, aState.mReflowState, frame, 
03480                                   nsSize(availSpace.width, availSpace.height), 
03481                                   aState.mReflowState.reason, PR_TRUE);
03482     blockHtmlRS.mFlags.mHasClearance = aLine->HasClearance();
03483     
03484     if (mayNeedRetry) {
03485       blockHtmlRS.mDiscoveredClearance = &clearanceFrame;
03486       aState.mSpaceManager->PushState();
03487     } else if (!applyTopMargin) {
03488       blockHtmlRS.mDiscoveredClearance = aState.mReflowState.mDiscoveredClearance;
03489     }
03490     
03491     nsReflowStatus frameReflowStatus = NS_FRAME_COMPLETE;
03492     rv = brc.ReflowBlock(availSpace, applyTopMargin, aState.mPrevBottomMargin,
03493                          clearance, aState.IsAdjacentWithTop(), computedOffsets,
03494                          blockHtmlRS, frameReflowStatus);
03495     
03496   // Remove the frame from the reflow tree.
03497     if (aState.mReflowState.path)
03498       aState.mReflowState.path->RemoveChild(frame);
03499     if (NS_FAILED(rv)) {
03500       return rv;
03501     }
03502     
03503     if (mayNeedRetry) {
03504       if (clearanceFrame) {
03505         UndoSplitPlaceholders(aState, lastPlaceholder);
03506         aState.mSpaceManager->PopState();
03507         aState.mY = startingY;
03508         aState.mPrevBottomMargin = incomingMargin;
03509         continue;
03510       } else {
03511         // pop the saved state off the stack and discard it, because we
03512         // want to keep the current state, since our speculation
03513         // succeeded
03514         aState.mSpaceManager->DiscardState();
03515       }
03516     }
03517     
03518     aState.mPrevChild = frame;
03519     
03520 #if defined(REFLOW_STATUS_COVERAGE)
03521     RecordReflowStatus(PR_TRUE, frameReflowStatus);
03522 #endif
03523     
03524     if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
03525       // None of the child block fits.
03526       UndoSplitPlaceholders(aState, lastPlaceholder);
03527       PushLines(aState, aLine.prev());
03528       *aKeepReflowGoing = PR_FALSE;
03529       aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
03530     }
03531     else {
03532       // Note: line-break-after a block is a nop
03533       
03534       // Try to place the child block.
03535       // Don't force the block to fit if we have positive clearance, because
03536       // pushing it to the next page would give it more room.
03537       // Don't force the block to fit if it's impacted by a float. If it is,
03538       // then pushing it to the next page would give it more room. Note that
03539       // isImpacted doesn't include impact from the block's own floats.
03540       PRBool forceFit = aState.IsAdjacentWithTop() && clearance <= 0 &&
03541         !isImpacted;
03542       nsCollapsingMargin collapsedBottomMargin;
03543       nsRect combinedArea(0,0,0,0);
03544       *aKeepReflowGoing = brc.PlaceBlock(blockHtmlRS, forceFit, aLine.get(),
03545                                          computedOffsets, collapsedBottomMargin,
03546                                          aLine->mBounds, combinedArea, frameReflowStatus);
03547       if (aLine->SetCarriedOutBottomMargin(collapsedBottomMargin)) {
03548         line_iterator nextLine = aLine;
03549         ++nextLine;
03550         if (nextLine != end_lines()) {
03551           nextLine->MarkPreviousMarginDirty();
03552         }
03553       }
03554       
03555       if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
03556         // Mark the line as dirty so once we known the final shrink wrap width
03557         // we can reflow the block to the correct size
03558         // XXX We don't always need to do this...
03559         aLine->MarkDirty();
03560         aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
03561       }
03562       if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
03563         // Add the right margin to the line's bounds.  That way it will be
03564         // taken into account when we compute our shrink wrap size.
03565         nscoord marginRight = brc.GetMargin().right;
03566         if (marginRight != NS_UNCONSTRAINEDSIZE) {
03567           aLine->mBounds.width += marginRight;
03568         }
03569       }
03570       aLine->SetCombinedArea(combinedArea);
03571       if (*aKeepReflowGoing) {
03572         // Some of the child block fit
03573         
03574         // Advance to new Y position
03575         nscoord newY = aLine->mBounds.YMost();
03576         aState.mY = newY;
03577         
03578         // Continue the block frame now if it didn't completely fit in
03579         // the available space.
03580         if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
03581           PRBool madeContinuation;
03582           rv = CreateContinuationFor(aState, nsnull, frame, madeContinuation);
03583           if (NS_FAILED(rv)) 
03584             return rv;
03585           
03586           nsIFrame* nextFrame = frame->GetNextInFlow();
03587           
03588           // Push continuation to a new line, but only if we actually made one.
03589           if (madeContinuation) {
03590             nsLineBox* line = aState.NewLineBox(nextFrame, 1, PR_TRUE);
03591             if (nsnull == line) {
03592               return NS_ERROR_OUT_OF_MEMORY;
03593             }
03594             mLines.after_insert(aLine, line);
03595           }
03596           
03597           // Advance to next line since some of the block fit. That way
03598           // only the following lines will be pushed.
03599           PushLines(aState, aLine);
03600           aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
03601           // If we need to reflow the continuation of the block child,
03602           // then we'd better reflow our continuation
03603           if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
03604             aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
03605             // We also need to make that continuation's line dirty so
03606             // it gets reflowed when we reflow our next in flow. The
03607             // nif's line must always be either a line of the nif's
03608             // parent block (only if we didn't make a continuation) or
03609             // else one of our own overflow lines. In the latter case
03610             // the line is already marked dirty, so just handle the
03611             // first case.
03612             if (!madeContinuation) {
03613               nsBlockFrame* nifBlock = NS_STATIC_CAST(nsBlockFrame*, nextFrame->GetParent());
03614               NS_ASSERTION(nifBlock->GetType() == nsLayoutAtoms::blockFrame
03615                            || nifBlock->GetType() == nsLayoutAtoms::areaFrame,
03616                            "A block's child's next in flow's parent must be a block!");
03617               for (line_iterator line = nifBlock->begin_lines(),
03618                      line_end = nifBlock->end_lines(); line != line_end; ++line) {
03619                 if (line->Contains(nextFrame)) {
03620                   line->MarkDirty();
03621                   break;
03622                 }
03623               }
03624             }
03625           }
03626           *aKeepReflowGoing = PR_FALSE;
03627           
03628           // The bottom margin for a block is only applied on the last
03629           // flow block. Since we just continued the child block frame,
03630           // we know that line->mFirstChild is not the last flow block
03631           // therefore zero out the running margin value.
03632 #ifdef NOISY_VERTICAL_MARGINS
03633           ListTag(stdout);
03634           printf(": reflow incomplete, frame=");
03635           nsFrame::ListTag(stdout, frame);
03636           printf(" prevBottomMargin=%d, setting to zero\n",
03637                  aState.mPrevBottomMargin);
03638 #endif
03639           aState.mPrevBottomMargin.Zero();
03640         }
03641         else {
03642 #ifdef NOISY_VERTICAL_MARGINS
03643           ListTag(stdout);
03644           printf(": reflow complete for ");
03645           nsFrame::ListTag(stdout, frame);
03646           printf(" prevBottomMargin=%d collapsedBottomMargin=%d\n",
03647                  aState.mPrevBottomMargin, collapsedBottomMargin.get());
03648 #endif
03649           aState.mPrevBottomMargin = collapsedBottomMargin;
03650         }
03651 #ifdef NOISY_VERTICAL_MARGINS
03652         ListTag(stdout);
03653         printf(": frame=");
03654         nsFrame::ListTag(stdout, frame);
03655         printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
03656                brc.GetCarriedOutBottomMargin(), collapsedBottomMargin.get(),
03657                aState.mPrevBottomMargin);
03658 #endif
03659         
03660         // Post-process the "line"
03661         nscoord maxElementWidth = 0;
03662         if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
03663           maxElementWidth = brc.GetMaxElementWidth();
03664         }
03665         // If we asked the block to update its maximum width, then record the
03666         // updated value in the line, and update the current maximum width
03667         if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
03668           // The maximum width in the line box includes the left
03669           // border/padding of this block, but not the right.
03670           aLine->mMaximumWidth = brc.GetMaximumWidth() + availSpace.x;
03671           aState.UpdateMaximumWidth(aLine->mMaximumWidth);
03672         }
03673         PostPlaceLine(aState, aLine, maxElementWidth);
03674         
03675         // If the block frame that we just reflowed happens to be our
03676         // first block, then its computed ascent is ours
03677         if (frame == GetTopBlockChild(aState.mPresContext)) {
03678           const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
03679           mAscent = metrics.ascent;
03680         }
03681         
03682         // Place the "marker" (bullet) frame.
03683         //
03684         // According to the CSS2 spec, section 12.6.1, the "marker" box
03685         // participates in the height calculation of the list-item box's
03686         // first line box.
03687         //
03688         // There are exactly two places a bullet can be placed: near the
03689         // first or second line. Its only placed on the second line in a
03690         // rare case: an empty first line followed by a second line that
03691         // contains a block (example: <LI>\n<P>... ). This is where
03692         // the second case can happen.
03693         if (mBullet && HaveOutsideBullet() &&
03694             ((aLine == mLines.front()) ||
03695              ((0 == mLines.front()->mBounds.height) &&
03696               (aLine == begin_lines().next())))) {
03697           // Reflow the bullet
03698           nsHTMLReflowMetrics metrics(nsnull);
03699           ReflowBullet(aState, metrics);
03700           
03701           // Doing the alignment using |mAscent| will also cater for bullets
03702           // that are placed next to a child block (bug 92896)
03703           // (Note that mAscent should be set by now, otherwise why would
03704           // we be placing the bullet yet?)
03705           
03706           // Tall bullets won't look particularly nice here...
03707           nsRect bbox = mBullet->GetRect();
03708           nscoord bulletTopMargin = applyTopMargin
03709             ? collapsedBottomMargin.get()
03710             : 0;
03711           bbox.y = aState.BorderPadding().top + mAscent -
03712             metrics.ascent + bulletTopMargin;
03713           mBullet->SetRect(bbox);
03714         }
03715       }
03716       else {
03717         // None of the block fits. Determine the correct reflow status.
03718         if (aLine == mLines.front()) {
03719           // If it's our very first line then we need to be pushed to
03720           // our parents next-in-flow. Therefore, return break-before
03721           // status for our reflow status.
03722           aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
03723         }
03724         else {
03725           // Push the line that didn't fit and any lines that follow it
03726           // to our next-in-flow.
03727           UndoSplitPlaceholders(aState, lastPlaceholder);
03728           PushLines(aState, aLine.prev());
03729           aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
03730         }
03731       }
03732     }
03733     break; // out of the reflow retry loop
03734   }
03735   
03736 #ifdef DEBUG
03737   VerifyLines(PR_TRUE);
03738 #endif
03739   return rv;
03740 }
03741 
03742 #define LINE_REFLOW_OK        0
03743 #define LINE_REFLOW_STOP      1
03744 #define LINE_REFLOW_REDO      2
03745 // a frame was complete, but truncated and not at the top of a page
03746 #define LINE_REFLOW_TRUNCATED 3
03747 
03748 nsresult
03749 nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
03750                                  line_iterator aLine,
03751                                  PRBool aTryPull,
03752                                  PRBool* aKeepReflowGoing,
03753                                  PRBool aDamageDirtyArea,
03754                                  PRBool aUpdateMaximumWidth)
03755 {
03756   nsresult rv = NS_OK;
03757   *aKeepReflowGoing = PR_TRUE;
03758 
03759 #ifdef DEBUG
03760   PRInt32 spins = 0;
03761 #endif
03762   PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
03763   PRBool didRedo = PR_FALSE;
03764   do {
03765     // Once upon a time we allocated the first 30 nsLineLayout objects
03766     // on the stack, and then we switched to the heap.  At that time
03767     // these objects were large (1100 bytes on a 32 bit system).
03768     // Then the nsLineLayout object was shrunk to 156 bytes by
03769     // removing some internal buffers.  Given that it is so much
03770     // smaller, the complexity of 2 different ways of allocating
03771     // no longer makes sense.  Now we always allocate on the stack
03772 
03773     nsLineLayout lineLayout(aState.mPresContext,
03774                             aState.mReflowState.mSpaceManager,
03775                             &aState.mReflowState,
03776                             aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH));
03777     lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
03778     rv = DoReflowInlineFrames(aState, lineLayout, aLine,
03779                               aKeepReflowGoing, &lineReflowStatus,
03780                               aUpdateMaximumWidth, aDamageDirtyArea, aTryPull);
03781     lineLayout.EndLineReflow();
03782     
03783     if (LINE_REFLOW_REDO == lineReflowStatus) {
03784       didRedo = PR_TRUE;
03785     }
03786 
03787 #ifdef DEBUG
03788     spins++;
03789     if (1000 == spins) {
03790       ListTag(stdout);
03791       printf(": yikes! spinning on a line over 1000 times!\n");
03792       NS_ABORT();
03793     }
03794 #endif
03795 
03796   } while (NS_SUCCEEDED(rv) && LINE_REFLOW_REDO == lineReflowStatus);
03797 
03798   // If we did at least one REDO, then the line did not fit next to some float.
03799   // Mark it as impacted by a float, even if it no longer is next to a float.
03800   if (didRedo) {
03801     aLine->SetLineIsImpactedByFloat(PR_TRUE);
03802   }
03803 
03804   return rv;
03805 }
03806 
03807 // If at least one float on the line was complete, not at the top of
03808 // page, but was truncated, then restore the overflow floats to what
03809 // they were before and push the line.  The floats that will be removed
03810 // from the list aren't yet known by the block's next in flow.  
03811 void
03812 nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
03813                                            line_iterator       aLine,
03814                                            nsIFrame*           aLastPlaceholder,
03815                                            PRBool&             aKeepReflowGoing)
03816 {
03817   UndoSplitPlaceholders(aState, aLastPlaceholder);
03818 
03819   line_iterator prevLine = aLine;
03820   --prevLine;
03821   PushLines(aState, prevLine);
03822   aKeepReflowGoing = PR_FALSE;
03823   aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
03824 }
03825 
03826 nsresult
03827 nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
03828                                    nsLineLayout& aLineLayout,
03829                                    line_iterator aLine,
03830                                    PRBool* aKeepReflowGoing,
03831                                    PRUint8* aLineReflowStatus,
03832                                    PRBool aUpdateMaximumWidth,
03833                                    PRBool aDamageDirtyArea,
03834                                    PRBool aAllowPullUp)
03835 {
03836   // Forget all of the floats on the line
03837   aLine->FreeFloats(aState.mFloatCacheFreeList);
03838   aState.mFloatCombinedArea.SetRect(0, 0, 0, 0);
03839 
03840   // Setup initial coordinate system for reflowing the inline frames
03841   // into. Apply a previous block frame's bottom margin first.
03842   if (ShouldApplyTopMargin(aState, aLine)) {
03843     aState.mY += aState.mPrevBottomMargin.get();
03844   }
03845   aState.GetAvailableSpace();
03846   PRBool impactedByFloats = aState.IsImpactedByFloat() ? PR_TRUE : PR_FALSE;
03847   aLine->SetLineIsImpactedByFloat(impactedByFloats);
03848 #ifdef REALLY_NOISY_REFLOW
03849   printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
03850          this, impactedByFloats);
03851 #endif
03852 
03853   const nsMargin& borderPadding = aState.BorderPadding();
03854   nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
03855   nscoord availWidth = aState.mAvailSpaceRect.width;
03856   nscoord availHeight;
03857   if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
03858     availHeight = NS_UNCONSTRAINEDSIZE;
03859   }
03860   else {
03861     /* XXX get the height right! */
03862     availHeight = aState.mAvailSpaceRect.height;
03863   }
03864   if (aUpdateMaximumWidth) {
03865     availWidth = NS_UNCONSTRAINEDSIZE;
03866   }
03867   aLineLayout.BeginLineReflow(x, aState.mY,
03868                               availWidth, availHeight,
03869                               impactedByFloats,
03870                               PR_FALSE /*XXX isTopOfPage*/);
03871 
03872   // XXX Unfortunately we need to know this before reflowing the first
03873   // inline frame in the line. FIX ME.
03874   if ((0 == aLineLayout.GetLineNumber()) &&
03875       (NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
03876     aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
03877   }
03878 
03879   // keep track of the last overflow float in case we need to undo any new additions
03880   nsIFrame* lastPlaceholder = aState.mOverflowPlaceholders.LastChild();
03881 
03882   // Reflow the frames that are already on the line first
03883   nsresult rv = NS_OK;
03884   PRUint8 lineReflowStatus = LINE_REFLOW_OK;
03885   PRInt32 i;
03886   nsIFrame* frame = aLine->mFirstChild;
03887   aLine->SetHasPercentageChild(PR_FALSE); // To be set by ReflowInlineFrame below
03888   // Determine whether this is a line of placeholders for out-of-flow
03889   // continuations
03890   PRBool isContinuingPlaceholders = PR_FALSE;
03891 
03892   // need to repeatedly call GetChildCount here, because the child
03893   // count can change during the loop!
03894   for (i = 0; i < aLine->GetChildCount(); i++) {
03895     if (IsContinuationPlaceholder(frame)) {
03896       isContinuingPlaceholders = PR_TRUE;
03897     }
03898     rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
03899                            &lineReflowStatus);
03900     if (NS_FAILED(rv)) {
03901       return rv;
03902     }
03903     if (LINE_REFLOW_OK != lineReflowStatus) {
03904       // It is possible that one or more of next lines are empty
03905       // (because of DeleteNextInFlowChild). If so, delete them now
03906       // in case we are finished.
03907       ++aLine;
03908       while ((aLine != end_lines()) && (0 == aLine->GetChildCount())) {
03909         // XXX Is this still necessary now that DeleteNextInFlowChild
03910         // uses DoRemoveFrame?
03911         nsLineBox *toremove = aLine;
03912         aLine = mLines.erase(aLine);
03913         NS_ASSERTION(nsnull == toremove->mFirstChild, "bad empty line");
03914         aState.FreeLineBox(toremove);
03915       }
03916       --aLine;
03917 
03918       if (LINE_REFLOW_TRUNCATED == lineReflowStatus) {
03919         // Don't push any lines if we just want to calculate the maximum width
03920         if (!aUpdateMaximumWidth) {
03921           // Push the line with the truncated float 
03922           PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing);
03923         }
03924       }
03925       break;
03926     }
03927     frame = frame->GetNextSibling();
03928   }
03929 
03930   // Don't pull up new frames into lines with continuation placeholders
03931   if (!isContinuingPlaceholders && aAllowPullUp) {
03932     // Pull frames and reflow them until we can't
03933     while (LINE_REFLOW_OK == lineReflowStatus) {
03934       rv = PullFrame(aState, aLine, aDamageDirtyArea, frame);
03935       if (NS_FAILED(rv)) {
03936         return rv;
03937       }
03938       if (nsnull == frame) {
03939         break;
03940       }
03941 
03942       while (LINE_REFLOW_OK == lineReflowStatus) {
03943         PRInt32 oldCount = aLine->GetChildCount();
03944         rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
03945                                &lineReflowStatus);
03946         if (NS_FAILED(rv)) {
03947           return rv;
03948         }
03949         if (aLine->GetChildCount() != oldCount) {
03950           // We just created a continuation for aFrame AND its going
03951           // to end up on this line (e.g. :first-letter
03952           // situation). Therefore we have to loop here before trying
03953           // to pull another frame.
03954           frame = frame->GetNextSibling();
03955         }
03956         else {
03957           break;
03958         }
03959       }
03960     }
03961   } 
03962 
03963   if (LINE_REFLOW_REDO == lineReflowStatus) {
03964     // This happens only when we have a line that is impacted by
03965     // floats and the first element in the line doesn't fit with
03966     // the floats.
03967     //
03968     // What we do is to advance past the first float we find and
03969     // then reflow the line all over again.
03970     NS_ASSERTION(aState.IsImpactedByFloat(),
03971                  "redo line on totally empty line");
03972     NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
03973                  "unconstrained height on totally empty line");
03974 
03975 
03976     if (aState.mAvailSpaceRect.height > 0) {
03977       aState.mY += aState.mAvailSpaceRect.height;
03978     } else {
03979       NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight,
03980                    "We shouldn't be running out of height here");
03981       if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableHeight) {
03982         // just move it down a bit to try to get out of this mess
03983         aState.mY += 1;
03984       } else {
03985         // There's nowhere to retry placing the line. Just treat it as if
03986         // we placed the float but it was truncated so we need this line
03987         // to go to the next page/column.
03988         lineReflowStatus = LINE_REFLOW_TRUNCATED;
03989         // Don't push any lines if we just want to calculate the maximum width
03990         if (!aUpdateMaximumWidth) {
03991           // Push the line that didn't fit
03992           PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing);
03993         }
03994       }
03995     }
03996       
03997     // We don't want to advance by the bottom margin anymore (we did it
03998     // once at the beginning of this function, which will just be called
03999     // again), and we certainly don't want to go back if it's negative
04000     // (infinite loop, bug 153429).
04001     aState.mPrevBottomMargin.Zero();
04002 
04003     // XXX: a small optimization can be done here when paginating:
04004     // if the new Y coordinate is past the end of the block then
04005     // push the line and return now instead of later on after we are
04006     // past the float.
04007   }
04008   else if (LINE_REFLOW_TRUNCATED != lineReflowStatus) {
04009     // If we are propagating out a break-before status then there is
04010     // no point in placing the line.
04011     if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
04012       if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) {
04013         UndoSplitPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line
04014       }
04015     }
04016   }
04017   *aLineReflowStatus = lineReflowStatus;
04018 
04019   return rv;
04020 }
04021 
04030 nsresult
04031 nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
04032                                 nsLineLayout& aLineLayout,
04033                                 line_iterator aLine,
04034                                 nsIFrame* aFrame,
04035                                 PRUint8* aLineReflowStatus)
04036 {
04037  NS_ENSURE_ARG_POINTER(aFrame);
04038   
04039   *aLineReflowStatus = LINE_REFLOW_OK;
04040 
04041   // If it's currently ok to be reflowing in first-letter style then
04042   // we must be about to reflow a frame that has first-letter style.
04043   PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
04044 #ifdef NOISY_FIRST_LETTER
04045   ListTag(stdout);
04046   printf(": reflowing ");
04047   nsFrame::ListTag(stdout, aFrame);
04048   printf(" reflowingFirstLetter=%s\n", reflowingFirstLetter ? "on" : "off");
04049 #endif
04050 
04051   // Remember if we have a percentage aware child on this line
04052   if (IsPercentageAwareChild(aFrame)) {
04053     aLine->SetHasPercentageChild(PR_TRUE);
04054   }
04055 
04056   // Reflow the inline frame
04057   nsReflowStatus frameReflowStatus;
04058   PRBool         pushedFrame;
04059   nsresult rv = aLineLayout.ReflowFrame(aFrame, frameReflowStatus,
04060                                         nsnull, pushedFrame);
04061 
04062   if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
04063     // we need to ensure that the frame's nextinflow gets reflowed.
04064     aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
04065     nsBlockFrame* ourNext = NS_STATIC_CAST(nsBlockFrame*, GetNextInFlow());
04066     if (ourNext && aFrame->GetNextInFlow()) {
04067       line_iterator f = ourNext->FindLineFor(aFrame->GetNextInFlow());
04068       if (f != ourNext->end_lines()) {
04069         f->MarkDirty();
04070       }
04071     }
04072   }
04073 
04074   // If this is an incremental reflow, prune the child from the path
04075   // so we don't incrementally reflow it again.
04076   // XXX note that we don't currently have any incremental reflows
04077   // that trace a path through an inline frame (thanks to reflow roots
04078   // dealing with text inputs), but we may need to deal with this
04079   // again, someday.
04080   if (aState.mReflowState.path)
04081     aState.mReflowState.path->RemoveChild(aFrame);
04082 
04083   if (NS_FAILED(rv)) {
04084     return rv;
04085   }
04086 #ifdef REALLY_NOISY_REFLOW_CHILD
04087   nsFrame::ListTag(stdout, aFrame);
04088   printf(": status=%x\n", frameReflowStatus);
04089 #endif
04090 
04091 #if defined(REFLOW_STATUS_COVERAGE)
04092   RecordReflowStatus(PR_FALSE, frameReflowStatus);
04093 #endif
04094 
04095   // Send post-reflow notification
04096   aState.mPrevChild = aFrame;
04097 
04098    /* XXX
04099       This is where we need to add logic to handle some odd behavior.
04100       For one thing, we should usually place at least one thing next
04101       to a left float, even when that float takes up all the width on a line.
04102       see bug 22496
04103    */
04104 
04105   // Process the child frames reflow status. There are 5 cases:
04106   // complete, not-complete, break-before, break-after-complete,
04107   // break-after-not-complete. There are two situations: we are a
04108   // block or we are an inline. This makes a total of 10 cases
04109   // (fortunately, there is some overlap).
04110   aLine->SetBreakTypeAfter(NS_STYLE_CLEAR_NONE);
04111   if (NS_INLINE_IS_BREAK(frameReflowStatus) || 
04112       (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType)) {
04113     // Always abort the line reflow (because a line break is the
04114     // minimal amount of break we do).
04115     *aLineReflowStatus = LINE_REFLOW_STOP;
04116 
04117     // XXX what should aLine's break-type be set to in all these cases?
04118     PRUint8 breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
04119     NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) || 
04120                  (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType), "bad break type");
04121     NS_ASSERTION(NS_STYLE_CLEAR_PAGE != breakType, "no page breaks yet");
04122 
04123     if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
04124       // Break-before cases.
04125       if (aFrame == aLine->mFirstChild) {
04126         // If we break before the first frame on the line then we must
04127         // be trying to place content where theres no room (e.g. on a
04128         // line with wide floats). Inform the caller to reflow the
04129         // line after skipping past a float.
04130         *aLineReflowStatus = LINE_REFLOW_REDO;
04131       }
04132       else {
04133         // It's not the first child on this line so go ahead and split
04134         // the line. We will see the frame again on the next-line.
04135         rv = SplitLine(aState, aLineLayout, aLine, aFrame);
04136         if (NS_FAILED(rv)) {
04137           return rv;
04138         }
04139 
04140         // If we're splitting the line because the frame didn't fit and it
04141         // was pushed, then mark the line as having word wrapped. We need to
04142         // know that if we're shrink wrapping our width
04143         if (pushedFrame) {
04144           aLine->SetLineWrapped(PR_TRUE);
04145         }
04146       }
04147     }
04148     else {
04149       // If a float split and its prev-in-flow was followed by a <BR>, then combine 
04150       // the <BR>'s break type with the inline's break type (the inline will be the very 
04151       // next frame after the split float).
04152       if (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType) {
04153         breakType = nsLayoutUtils::CombineBreakType(breakType,
04154                                                     aState.mFloatBreakType);
04155         aState.mFloatBreakType = NS_STYLE_CLEAR_NONE;
04156       }
04157       // Break-after cases
04158       if (breakType == NS_STYLE_CLEAR_LINE) {
04159         if (!aLineLayout.GetLineEndsInBR()) {
04160           breakType = NS_STYLE_CLEAR_NONE;
04161         }
04162       }
04163       aLine->SetBreakTypeAfter(breakType);
04164       if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
04165         // Create a continuation for the incomplete frame. Note that the
04166         // frame may already have a continuation.
04167         PRBool madeContinuation;
04168         rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
04169         if (NS_FAILED(rv)) 
04170           return rv;
04171         if (!aLineLayout.GetLineEndsInBR()) {
04172           // Remember that the line has wrapped
04173           aLine->SetLineWrapped(PR_TRUE);
04174         }
04175       }
04176 
04177       // Split line, but after the frame just reflowed
04178       rv = SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling());
04179       if (NS_FAILED(rv)) {
04180         return rv;
04181       }
04182 
04183       if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
04184         // Mark next line dirty in case SplitLine didn't end up
04185         // pushing any frames.
04186         nsLineList_iterator next = aLine.next();
04187         if (next != end_lines() && !next->IsBlock()) {
04188           next->MarkDirty();
04189         }
04190       }
04191     }
04192   }
04193   else if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
04194     // Frame is not-complete, no special breaking status
04195 
04196     nsIAtom* frameType = aFrame->GetType();
04197 
04198     // Create a continuation for the incomplete frame. Note that the
04199     // frame may already have a continuation.
04200     PRBool madeContinuation;
04201     rv = (nsLayoutAtoms::placeholderFrame == frameType)
04202          ? SplitPlaceholder(aState, aFrame)
04203          : CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
04204     if (NS_FAILED(rv)) 
04205       return rv;
04206 
04207     // Remember that the line has wrapped
04208     if (!aLineLayout.GetLineEndsInBR()) {
04209       aLine->SetLineWrapped(PR_TRUE);
04210     }
04211     
04212     // If we are reflowing the first letter frame or a placeholder then 
04213     // don't split the line and don't stop the line reflow...
04214     PRBool splitLine = !reflowingFirstLetter && 
04215       nsLayoutAtoms::placeholderFrame != frameType;
04216     if (reflowingFirstLetter) {
04217       if ((nsLayoutAtoms::inlineFrame == frameType) ||
04218           (nsLayoutAtoms::lineFrame == frameType)) {
04219         splitLine = PR_TRUE;
04220       }
04221     }
04222 
04223     if (splitLine) {
04224       // Split line after the current frame
04225       *aLineReflowStatus = LINE_REFLOW_STOP;
04226       rv = SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling());
04227       if (NS_FAILED(rv)) {
04228         return rv;
04229       }
04230 
04231       // Mark next line dirty in case SplitLine didn't end up
04232       // pushing any frames.
04233       nsLineList_iterator next = aLine.next();
04234       if (next != end_lines() && !next->IsBlock()) {
04235         next->MarkDirty();
04236       }
04237     }
04238   }
04239   else if (NS_FRAME_IS_TRUNCATED(frameReflowStatus)) {
04240     // if the frame is a placeholder and was complete but truncated (and not at the top
04241     // of page), the entire line will be pushed to give it another chance to not truncate.
04242     if (nsLayoutAtoms::placeholderFrame == aFrame->GetType()) {
04243       *aLineReflowStatus = LINE_REFLOW_TRUNCATED;
04244     }
04245   }  
04246 
04247   return NS_OK;
04248 }
04249 
04254 nsresult
04255 nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
04256                                     nsLineBox*          aLine,
04257                                     nsIFrame*           aFrame,
04258                                     PRBool&             aMadeNewFrame)
04259 {
04260   aMadeNewFrame = PR_FALSE;
04261   nsresult rv;
04262   nsIFrame* nextInFlow;
04263   rv = CreateNextInFlow(aState.mPresContext, this, aFrame, nextInFlow);
04264   if (NS_FAILED(rv)) {
04265     return rv;
04266   }
04267   if (nsnull != nextInFlow) {
04268     aMadeNewFrame = PR_TRUE;
04269     if (aLine) { 
04270       aLine->SetChildCount(aLine->GetChildCount() + 1);
04271     }
04272   }
04273 #ifdef DEBUG
04274   VerifyLines(PR_FALSE);
04275 #endif
04276   return rv;
04277 }
04278 
04279 nsresult
04280 nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
04281                                nsIFrame*           aPlaceholder)
04282 {
04283   nsIFrame* nextInFlow;
04284   nsresult rv = CreateNextInFlow(aState.mPresContext, this, aPlaceholder, nextInFlow);
04285   if (NS_FAILED(rv))
04286     return rv;
04287 
04288   if (!nextInFlow) {
04289     // Next in flow was not created because it already exists.
04290     return NS_OK;
04291   }
04292 
04293   // put the sibling list back to what it was before the continuation was created
04294   nsIFrame *contFrame = aPlaceholder->GetNextSibling();
04295   nsIFrame *next = contFrame->GetNextSibling();
04296   aPlaceholder->SetNextSibling(next);
04297   contFrame->SetNextSibling(nsnull);
04298 
04299   NS_ASSERTION(IsContinuationPlaceholder(contFrame),
04300                "Didn't create the right kind of frame");
04301 
04302   // The new out of flow frame does not get put anywhere; the out-of-flows
04303   // for placeholders in mOverflowPlaceholders are not kept in any child list
04304   aState.mOverflowPlaceholders.AppendFrame(this, contFrame);
04305   return NS_OK;
04306 }
04307 
04308 nsresult
04309 nsBlockFrame::SplitLine(nsBlockReflowState& aState,
04310                         nsLineLayout& aLineLayout,
04311                         line_iterator aLine,
04312                         nsIFrame* aFrame)
04313 {
04314   NS_ABORT_IF_FALSE(aLine->IsInline(), "illegal SplitLine on block line");
04315 
04316   PRInt32 pushCount = aLine->GetChildCount() - aLineLayout.GetCurrentSpanCount();
04317   NS_ABORT_IF_FALSE(pushCount >= 0, "bad push count"); 
04318 
04319 #ifdef DEBUG
04320   if (gNoisyReflow) {
04321     nsFrame::IndentBy(stdout, gNoiseIndent);
04322     printf("split line: from line=%p pushCount=%d aFrame=",
04323            NS_STATIC_CAST(void*, aLine.get()), pushCount);
04324     if (aFrame) {
04325       nsFrame::ListTag(stdout, aFrame);
04326     }
04327     else {
04328       printf("(null)");
04329     }
04330     printf("\n");
04331     if (gReallyNoisyReflow) {
04332       aLine->List(aState.mPresContext, stdout, gNoiseIndent+1);
04333     }
04334   }
04335 #endif
04336 
04337   if (0 != pushCount) {
04338     NS_ABORT_IF_FALSE(aLine->GetChildCount() > pushCount, "bad push");
04339     NS_ABORT_IF_FALSE(nsnull != aFrame, "whoops");
04340     NS_ASSERTION(nsFrameList(aFrame).GetLength() >= pushCount,
04341                  "Not enough frames to push");
04342 
04343     // Put frames being split out into their own line
04344     nsLineBox* newLine = aState.NewLineBox(aFrame, pushCount, PR_FALSE);
04345     if (!newLine) {
04346       return NS_ERROR_OUT_OF_MEMORY;
04347     }
04348     mLines.after_insert(aLine, newLine);
04349     aLine->SetChildCount(aLine->GetChildCount() - pushCount);
04350 #ifdef DEBUG
04351     if (gReallyNoisyReflow) {
04352       newLine->List(aState.mPresContext, stdout, gNoiseIndent+1);
04353     }
04354 #endif
04355 
04356     // Let line layout know that some frames are no longer part of its
04357     // state.
04358     aLineLayout.SplitLineTo(aLine->GetChildCount());
04359 #ifdef DEBUG
04360     VerifyLines(PR_TRUE);
04361 #endif
04362   }
04363   return NS_OK;
04364 }
04365 
04366 PRBool
04367 nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState,
04368                                 line_iterator aLine)
04369 {
04370   while (++aLine != end_lines()) {
04371     // There is another line
04372     if (0 != aLine->GetChildCount()) {
04373       // If the next line is a block line then we must not justify
04374       // this line because it means that this line is the last in a
04375       // group of inline lines.
04376       return !aLine->IsBlock();
04377     }
04378     // The next line is empty, try the next one
04379   }
04380 
04381   // XXX Not sure about this part
04382   // Try our next-in-flows lines to answer the question
04383   nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow;
04384   while (nsnull != nextInFlow) {
04385     for (line_iterator line = nextInFlow->begin_lines(),
04386                    line_end = nextInFlow->end_lines();
04387          line != line_end;
04388          ++line)
04389     {
04390       if (0 != line->GetChildCount())
04391         return !line->IsBlock();
04392     }
04393     nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
04394   }
04395 
04396   // This is the last line - so don't allow justification
04397   return PR_FALSE;
04398 }
04399 
04400 PRBool
04401 nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
04402                         nsLineLayout&       aLineLayout,
04403                         line_iterator       aLine,
04404                         PRBool*             aKeepReflowGoing,
04405                         PRBool              aUpdateMaximumWidth)
04406 {
04407   // Trim extra white-space from the line before placing the frames
04408   aLineLayout.TrimTrailingWhiteSpace();
04409 
04410   // Vertically align the frames on this line.
04411   //
04412   // According to the CSS2 spec, section 12.6.1, the "marker" box
04413   // participates in the height calculation of the list-item box's
04414   // first line box.
04415   //
04416   // There are exactly two places a bullet can be placed: near the
04417   // first or second line. Its only placed on the second line in a
04418   // rare case: an empty first line followed by a second line that
04419   // contains a block (example: <LI>\n<P>... ).
04420   //
04421   // For this code, only the first case is possible because this
04422   // method is used for placing a line of inline frames. If the rare
04423   // case is happening then the worst that will happen is that the
04424   // bullet frame will be reflowed twice.
04425   PRBool addedBullet = PR_FALSE;
04426   if (mBullet && HaveOutsideBullet() && (aLine == mLines.front()) &&
04427       (!aLineLayout.IsZeroHeight() || (aLine == mLines.back()))) {
04428     nsHTMLReflowMetrics metrics(nsnull);
04429     ReflowBullet(aState, metrics);
04430     aLineLayout.AddBulletFrame(mBullet, metrics);
04431     addedBullet = PR_TRUE;
04432   }
04433   nscoord maxElementWidth;
04434   aLineLayout.VerticalAlignLine(aLine, &maxElementWidth);
04435   // Our ascent is the ascent of our first line (but if this line is all
04436   // whitespace we'll correct things in |ReflowBlockFrame|).
04437   if (aLine == mLines.front()) {
04438     mAscent = aLine->mBounds.y + aLine->GetAscent();
04439   }
04440 
04441   // See if we're shrink wrapping the width
04442   if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
04443     // XXXldb Do we really still want to do this?
04444     // When determining the line's width we also need to include any
04445     // right floats that impact us. This represents the shrink wrap
04446     // width of the line
04447     if (aState.IsImpactedByFloat() && !aLine->IsLineWrapped()) {
04448       NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
04449       aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
04450     }
04451   }
04452 #ifdef DEBUG
04453   {
04454     static nscoord lastHeight = 0;
04455     if (CRAZY_HEIGHT(aLine->mBounds.y)) {
04456       lastHeight = aLine->mBounds.y;
04457       if (abs(aLine->mBounds.y - lastHeight) > CRAZY_H/10) {
04458         nsFrame::ListTag(stdout);
04459         printf(": line=%p y=%d line.bounds.height=%d\n",
04460                NS_STATIC_CAST(void*, aLine.get()),
04461                aLine->mBounds.y, aLine->mBounds.height);
04462       }
04463     }
04464     else {
04465       lastHeight = 0;
04466     }
04467   }
04468 #endif
04469 
04470   // Only block frames horizontally align their children because
04471   // inline frames "shrink-wrap" around their children (therefore
04472   // there is no extra horizontal space).
04473   const nsStyleText* styleText = GetStyleText();
04474   PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign &&
04475                         !aLineLayout.GetLineEndsInBR() &&
04476                         ShouldJustifyLine(aState, aLine);
04477   PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds,
04478                             allowJustify, aState.GetFlag(BRS_SHRINKWRAPWIDTH));
04479   // XXX: not only bidi: right alignment can be broken after
04480   // RelativePositionFrames!!!
04481   // XXXldb Is something here considering relatively positioned frames at
04482   // other than their original positions?
04483   if (!successful) {
04484     // Mark the line dirty and then later once we've determined the width
04485     // we can do the horizontal alignment
04486     aLine->MarkDirty();
04487     aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
04488   }
04489 #ifdef IBMBIDI
04490   // XXXldb Why don't we do this earlier?
04491   else {
04492     if (aState.mPresContext->BidiEnabled()) {
04493       if (!aState.mPresContext->IsVisualMode()) {
04494         nsBidiPresUtils* bidiUtils = aState.mPresContext->GetBidiUtils();
04495 
04496         if (bidiUtils && bidiUtils->IsSuccessful() ) {
04497           nsIFrame* nextInFlow = (aLine.next() != end_lines())
04498                                  ? aLine.next()->mFirstChild : nsnull;
04499 
04500           bidiUtils->ReorderFrames(aState.mPresContext,
04501                                    aState.mReflowState.rendContext,
04502                                    aLine->mFirstChild, nextInFlow,
04503                                    aLine->GetChildCount() );
04504         } // bidiUtils
04505       } // not visual mode
04506     } // bidi enabled
04507   } // successful
04508 #endif // IBMBIDI
04509 
04510   nsRect combinedArea;
04511   aLineLayout.RelativePositionFrames(combinedArea);  // XXXldb This returned width as -15, 2001-06-12, Bugzilla
04512   aLine->SetCombinedArea(combinedArea);
04513   if (addedBullet) {
04514     aLineLayout.RemoveBulletFrame(mBullet);
04515   }
04516 
04517   // Inline lines do not have margins themselves; however they are
04518   // impacted by prior block margins. If this line ends up having some
04519   // height then we zero out the previous bottom margin value that was
04520   // already applied to the line's starting Y coordinate. Otherwise we
04521   // leave it be so that the previous blocks bottom margin can be
04522   // collapsed with a block that follows.
04523   nscoord newY;
04524 
04525   if (!aLine->CachedIsEmpty()) {
04526     // This line has some height. Therefore the application of the
04527     // previous-bottom-margin should stick.
04528     aState.mPrevBottomMargin.Zero();
04529     newY = aLine->mBounds.YMost();
04530   }
04531   else {
04532     // Don't let the previous-bottom-margin value affect the newY
04533     // coordinate (it was applied in ReflowInlineFrames speculatively)
04534     // since the line is empty.
04535     // We already called |ShouldApplyTopMargin|, and if we applied it
04536     // then BRS_APPLYTOPMARGIN is set.
04537     nscoord dy = aState.GetFlag(BRS_APPLYTOPMARGIN)
04538                    ? -aState.mPrevBottomMargin.get() : 0;
04539     newY = aState.mY + dy;
04540     aLine->SlideBy(dy); // XXXldb Do we really want to do this?
04541     // keep our ascent in sync
04542     // XXXldb If it's empty, shouldn't the next line control the ascent?
04543     if (mLines.front() == aLine) {
04544       mAscent += dy;
04545     }
04546   }
04547 
04548   // See if the line fit. If it doesn't we need to push it. Our first
04549   // line will always fit.
04550 
04551   // If we're just updating the maximum width then we don't care if it
04552   // fits; we'll assume it does, so that the maximum width will get
04553   // updated below. The line will be reflowed again and pushed then
04554   // if necessary.
04555   if (mLines.front() != aLine &&
04556       newY > aState.mBottomEdge &&
04557       aState.mBottomEdge != NS_UNCONSTRAINEDSIZE &&
04558       !aUpdateMaximumWidth) {
04559     // Push this line and all of it's children and anything else that
04560     // follows to our next-in-flow
04561     NS_ASSERTION((aState.mCurrentLine == aLine), "oops");
04562     PushLines(aState, aLine.prev());
04563 
04564     // Stop reflow and whack the reflow status if reflow hasn't
04565     // already been stopped.
04566     if (*aKeepReflowGoing) {
04567       aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE;
04568       *aKeepReflowGoing = PR_FALSE;
04569     }
04570     return PR_TRUE;
04571   }
04572 
04573   // May be needed below
04574   PRBool wasAdjacentWIthTop = aState.IsAdjacentWithTop();
04575 
04576   aState.mY = newY;
04577   
04578   // If we're reflowing the line just to incrementally update the
04579   // maximum width, then don't post-place the line. It's doing work we
04580   // don't need, and it will update things like aState.mKidXMost that
04581   // we don't want updated...
04582   if (aUpdateMaximumWidth) {
04583     // However, we do need to update the max-element-width if requested
04584     if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
04585       aState.UpdateMaxElementWidth(maxElementWidth);
04586       // We also cache the max element width in the line. This is needed for
04587       // incremental reflow
04588       aLine->mMaxElementWidth = maxElementWidth;
04589 #ifdef DEBUG
04590       if (gNoisyMaxElementWidth) {
04591         IndentBy(stdout, gNoiseIndent);
04592         printf ("nsBlockFrame::PlaceLine: %p setting MEW for line %p to %d\n", 
04593                 NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine.get()),
04594                 maxElementWidth);
04595       }
04596 #endif
04597     }
04598 
04599   } else {
04600     PostPlaceLine(aState, aLine, maxElementWidth);
04601   }
04602 
04603   // Add the already placed current-line floats to the line
04604   aLine->AppendFloats(aState.mCurrentLineFloats);
04605 
04606   // Any below current line floats to place?
04607   if (aState.mBelowCurrentLineFloats.NotEmpty()) {
04608     // Reflow the below-current-line floats, then add them to the
04609     // lines float list if there aren't any truncated floats.
04610     if (aState.PlaceBelowCurrentLineFloats(aState.mBelowCurrentLineFloats,
04611                                            wasAdjacentWIthTop)) {
04612       aLine->AppendFloats(aState.mBelowCurrentLineFloats);
04613     }
04614     else { 
04615       // At least one float is truncated, so fix up any placeholders that got split and 
04616       // push the line. XXX It may be better to put the float on the next line, but this 
04617       // is not common enough to justify the complexity. Or maybe it is now...
04618 
04619       // If we just want to calculate the maximum width, then don't push the line.
04620       // We'll reflow it again and then it will get pushed if necessary.
04621       if (!aUpdateMaximumWidth) {
04622         nsIFrame* lastPlaceholder = aState.mOverflowPlaceholders.LastChild();
04623         PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing);
04624       }
04625     }
04626   }
04627 
04628   // When a line has floats, factor them into the combined-area
04629   // computations.
04630   if (aLine->HasFloats()) {
04631     // Combine the float combined area (stored in aState) and the
04632     // value computed by the line layout code.
04633     nsRect lineCombinedArea(aLine->GetCombinedArea());
04634 #ifdef NOISY_COMBINED_AREA
04635     ListTag(stdout);
04636     printf(": lineCA=%d,%d,%d,%d floatCA=%d,%d,%d,%d\n",
04637            lineCombinedArea.x, lineCombinedArea.y,
04638            lineCombinedArea.width, lineCombinedArea.height,
04639            aState.mFloatCombinedArea.x, aState.mFloatCombinedArea.y,
04640            aState.mFloatCombinedArea.width,
04641            aState.mFloatCombinedArea.height);
04642 #endif
04643     lineCombinedArea.UnionRect(aState.mFloatCombinedArea, lineCombinedArea);
04644 
04645     aLine->SetCombinedArea(lineCombinedArea);
04646 #ifdef NOISY_COMBINED_AREA
04647     printf("  ==> final lineCA=%d,%d,%d,%d\n",
04648            lineCombinedArea.x, lineCombinedArea.y,
04649            lineCombinedArea.width, lineCombinedArea.height);
04650 #endif
04651   }
04652 
04653   // Apply break-after clearing if necessary
04654   // This must stay in sync with |ReflowDirtyLines|.
04655   if (aLine->HasFloatBreakAfter()) {
04656     aState.mY = aState.ClearFloats(aState.mY, aLine->GetBreakTypeAfter());
04657   }
04658 
04659   return PR_FALSE;
04660 }
04661 
04662 void
04663 nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
04664                             nsLineBox* aLine,
04665                             nscoord aMaxElementWidth)
04666 {
04667   // Update max-element-width
04668   if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
04669     aState.UpdateMaxElementWidth(aMaxElementWidth);
04670     // We also cache the max element width in the line. This is needed for
04671     // incremental reflow
04672     aLine->mMaxElementWidth = aMaxElementWidth;
04673 #ifdef DEBUG
04674     if (gNoisyMaxElementWidth) {
04675       IndentBy(stdout, gNoiseIndent);
04676       printf ("nsBlockFrame::PostPlaceLine: %p setting line %p MEW %d\n", 
04677               NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine),
04678               aMaxElementWidth);
04679     }
04680 #endif
04681   }
04682 
04683   // If this is an unconstrained reflow, then cache the line width in the
04684   // line. We'll need this during incremental reflow if we're asked to
04685   // calculate the maximum width
04686   if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
04687 #ifdef NOISY_MAXIMUM_WIDTH
04688     printf("nsBlockFrame::PostPlaceLine during UC Reflow of block %p line %p caching max width %d\n", 
04689            NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine),
04690            aLine->mBounds.XMost());
04691 #endif
04692     aLine->mMaximumWidth = aLine->mBounds.XMost();
04693   }
04694 
04695   // Update xmost
04696   nscoord xmost = aLine->mBounds.XMost();
04697 
04698 #ifdef DEBUG
04699   if (CRAZY_WIDTH(xmost)) {
04700     ListTag(stdout);
04701     printf(": line=%p xmost=%d\n", NS_STATIC_CAST(void*, aLine), xmost);
04702   }
04703 #endif
04704   if (xmost > aState.mKidXMost) {
04705     aState.mKidXMost = xmost;
04706 #ifdef NOISY_KIDXMOST
04707     printf("%p PostPlaceLine aState.mKidXMost=%d\n", this, aState.mKidXMost); 
04708 #endif
04709   }
04710 }
04711 
04712 void
04713 nsBlockFrame::PushLines(nsBlockReflowState&  aState,
04714                         nsLineList::iterator aLineBefore)
04715 {
04716   nsLineList::iterator overBegin(aLineBefore.next());
04717 
04718   // PushTruncatedPlaceholderLine sometimes pushes the first line.  Ugh.
04719   PRBool firstLine = overBegin == begin_lines();
04720 
04721   if (overBegin != end_lines()) {
04722     // Remove floats in the lines from mFloats
04723     nsFrameList floats;
04724     nsIFrame* tail = nsnull;
04725     CollectFloats(overBegin->mFirstChild, floats, &tail, PR_FALSE, PR_TRUE);
04726 
04727     if (floats.NotEmpty()) {
04728       // Push the floats onto the front of the overflow out-of-flows list
04729       nsFrameList oofs = GetOverflowOutOfFlows();
04730       if (oofs.NotEmpty()) {
04731         floats.InsertFrames(nsnull, tail, oofs.FirstChild());
04732       }
04733       SetOverflowOutOfFlows(floats);
04734     }
04735 
04736     // overflow lines can already exist in some cases, in particular,
04737     // when shrinkwrapping and we discover that the shrinkwap causes
04738     // the height of some child block to grow which creates additional
04739     // overflowing content. In such cases we must prepend the new
04740     // overflow to the existing overflow.
04741     nsLineList* overflowLines = RemoveOverflowLines();
04742     if (!overflowLines) {
04743       // XXXldb use presshell arena!
04744       overflowLines = new nsLineList();
04745     }
04746     if (overflowLines) {
04747       if (!overflowLines->empty()) {
04748         mLines.back()->LastChild()->SetNextSibling(overflowLines->front()->mFirstChild);
04749       }
04750       overflowLines->splice(overflowLines->begin(), mLines, overBegin,
04751                             end_lines());
04752       NS_ASSERTION(!overflowLines->empty(), "should not be empty");
04753       // this takes ownership but it won't delete it immediately so we
04754       // can keep using it.
04755       SetOverflowLines(overflowLines);
04756   
04757       // Mark all the overflow lines dirty so that they get reflowed when
04758       // they are pulled up by our next-in-flow.
04759 
04760       // XXXldb Can this get called O(N) times making the whole thing O(N^2)?
04761       for (line_iterator line = overflowLines->begin(),
04762              line_end = overflowLines->end();
04763            line != line_end;
04764            ++line)
04765         {
04766           line->MarkDirty();
04767           line->MarkPreviousMarginDirty();
04768           line->mBounds.SetRect(0, 0, 0, 0);
04769           if (line->HasFloats()) {
04770             line->FreeFloats(aState.mFloatCacheFreeList);
04771           }
04772         }
04773     }
04774   }
04775 
04776   // Break frame sibling list
04777   if (!firstLine)
04778     aLineBefore->LastChild()->SetNextSibling(nsnull);
04779 
04780 #ifdef DEBUG
04781   VerifyOverflowSituation();
04782 #endif
04783 }
04784 
04800 PRBool
04801 nsBlockFrame::HandleOverflowPlaceholdersForPulledFrame(
04802   nsBlockReflowState& aState, nsIFrame* aFrame)
04803 {
04804   if (nsLayoutAtoms::placeholderFrame != aFrame->GetType()) {
04805     // Descend into children that are not float containing blocks.
04806     // We should encounter only first-in-flow placeholders, so the
04807     // frame subtree rooted at aFrame should not change.
04808     if (!aFrame->IsFloatContainingBlock()) {
04809       for (nsIFrame* f = aFrame->GetFirstChild(nsnull); f; f = f->GetNextSibling()) {
04810 #ifdef DEBUG
04811         PRBool changed =
04812 #endif
04813           HandleOverflowPlaceholdersForPulledFrame(aState, f);
04814         NS_ASSERTION(!changed, "Shouldn't find any continuation placeholders inside inlines");
04815       }
04816     }
04817     return PR_FALSE;
04818   }
04819 
04820   PRBool taken = PR_TRUE;
04821   nsIFrame* frame = aFrame;
04822   if (!aFrame->GetPrevInFlow()) {
04823     // First in flow frame. We only want to deal with its
04824     // next in flows, if there are any.
04825     taken = PR_FALSE;
04826     frame = frame->GetNextInFlow();
04827     if (!frame)
04828       return PR_FALSE;
04829   }
04830 
04831   nsBlockFrame* parent = NS_STATIC_CAST(nsBlockFrame*, frame->GetParent());
04832   // Remove aFrame and all its next in flows from their parents, but
04833   // don't destroy the frames.
04834 #ifdef DEBUG
04835   nsresult rv =
04836 #endif
04837     parent->DoRemoveFrame(frame, PR_FALSE);
04838   NS_ASSERTION(NS_SUCCEEDED(rv), "frame should be in parent's lists");
04839   
04840   nsIFrame* lastOverflowPlace = aState.mOverflowPlaceholders.LastChild();
04841   while (frame) {
04842     NS_ASSERTION(IsContinuationPlaceholder(frame),
04843                  "Should only be dealing with continuation placeholders here");
04844 
04845     parent = NS_STATIC_CAST(nsBlockFrame*, frame->GetParent());
04846     ReparentFrame(frame, parent, this);
04847 
04848     // continuation placeholders are always direct children of a block
04849     nsIFrame* outOfFlow = nsPlaceholderFrame::GetRealFrameForPlaceholder(frame);
04850 
04851     if (!parent->mFloats.RemoveFrame(outOfFlow)) {
04852       nsAutoOOFFrameList oofs(parent);
04853 #ifdef DEBUG
04854       PRBool found =
04855 #endif
04856         oofs.mList.RemoveFrame(outOfFlow);
04857       NS_ASSERTION(found, "Must have the out of flow in some child list");
04858     }
04859     ReparentFrame(outOfFlow, parent, this);
04860 
04861     aState.mOverflowPlaceholders.InsertFrames(nsnull, lastOverflowPlace, frame);
04862     // outOfFlow isn't inserted anywhere yet. Eventually the overflow
04863     // placeholders get put into the overflow lines, and at the same time we
04864     // insert the placeholders' out of flows into the overflow out-of-flows
04865     // list.
04866     lastOverflowPlace = frame;
04867 
04868     frame = frame->GetNextInFlow();
04869   }
04870 
04871   return taken;
04872 }
04873 
04880 PRBool
04881 nsBlockFrame::HandleOverflowPlaceholdersOnPulledLine(
04882   nsBlockReflowState& aState, nsLineBox* aLine)
04883 {
04884   // First, see if it's a line of continuation placeholders. If it
04885   // is, remove one and retry.
04886   if (aLine->mFirstChild && IsContinuationPlaceholder(aLine->mFirstChild)) {
04887     PRBool taken =
04888       HandleOverflowPlaceholdersForPulledFrame(aState, aLine->mFirstChild);
04889     NS_ASSERTION(taken, "We must have removed that frame");
04890     return PR_TRUE;
04891   }
04892  
04893   // OK, it's a normal line. Scan it for floats with continuations that
04894   // need to be taken care of. We won't need to change the line.
04895   PRInt32 n = aLine->GetChildCount();
04896   for (nsIFrame* f = aLine->mFirstChild; n > 0; f = f->GetNextSibling(), --n) {
04897 #ifdef DEBUG
04898     PRBool taken =
04899 #endif
04900       HandleOverflowPlaceholdersForPulledFrame(aState, f);
04901     NS_ASSERTION(!taken, "Shouldn't be any continuation placeholders on this line");
04902   }
04903 
04904   return PR_FALSE;
04905 }
04906 
04907 // The overflowLines property is stored as a pointer to a line list,
04908 // which must be deleted.  However, the following functions all maintain
04909 // the invariant that the property is never set if the list is empty.
04910 
04911 PRBool
04912 nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
04913 {
04914 #ifdef DEBUG
04915   VerifyOverflowSituation();
04916 #endif
04917   nsLineList* overflowLines = nsnull;
04918   nsLineList* ourOverflowLines = nsnull;
04919 
04920   // First grab the prev-in-flows overflow lines
04921   nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow;
04922   if (prevBlock) {
04923     overflowLines = prevBlock->RemoveOverflowLines();
04924     if (overflowLines) {
04925       NS_ASSERTION(! overflowLines->empty(),
04926                    "overflow lines should never be set and empty");
04927       // Make all the frames on the overflow line list mine
04928       nsIFrame* frame = overflowLines->front()->mFirstChild;
04929       while (nsnull != frame) {
04930         ReparentFrame(frame, prevBlock, this);
04931 
04932         // Get the next frame
04933         frame = frame->GetNextSibling();
04934       }
04935 
04936       // make the overflow out-of-flow frames mine too
04937       nsAutoOOFFrameList oofs(prevBlock);
04938       if (oofs.mList.NotEmpty()) {
04939         for (nsIFrame* f = oofs.mList.FirstChild(); f; f = f->GetNextSibling()) {
04940           ReparentFrame(f, prevBlock, this);
04941         }
04942         mFloats.InsertFrames(nsnull, nsnull, oofs.mList.FirstChild());
04943         oofs.mList.SetFrames(nsnull);
04944       }
04945     }
04946     
04947     // The lines on the overflow list have already been marked dirty and their
04948     // previous margins marked dirty also.
04949   }
04950 
04951   // Don't need to reparent frames in our own overflow lines/oofs, because they're
04952   // already ours. But we should put overflow floats back in mFloats.
04953   ourOverflowLines = RemoveOverflowLines();
04954   if (ourOverflowLines) {
04955     nsAutoOOFFrameList oofs(this);
04956     if (oofs.mList.NotEmpty()) {
04957       // The overflow floats go after our regular floats
04958       mFloats.AppendFrames(nsnull, oofs.mList.FirstChild());
04959       oofs.mList.SetFrames(nsnull);
04960     }
04961   }
04962 
04963   if (!overflowLines && !ourOverflowLines) {
04964     // nothing to do; always the case for non-constrained-height reflows
04965     return PR_FALSE;
04966   }
04967 
04968   NS_ASSERTION(aState.mOverflowPlaceholders.IsEmpty(),
04969                "Should have no overflow placeholders yet");
04970 
04971   // HANDLING CONTINUATION PLACEHOLDERS (floats only at the moment, because
04972   // abs-pos frames don't have continuations)
04973   //
04974   // All continuation placeholders need to be moved to the front of
04975   // our line list. We also need to maintain the invariant that at
04976   // most one frame for a given piece of content is in our normal
04977   // child list, by pushing all but the first placeholder to our
04978   // overflow placeholders list.
04979   // 
04980   // One problem we have to deal with is that some of these
04981   // continuation placeholders may have been donated to us by a
04982   // descendant block that was complete. We need to push them down to
04983   // a lower block if possible.
04984   //
04985   // We keep the lists ordered so that prev in flows come before their
04986   // next in flows. We do not worry about properly ordering the
04987   // placeholders for different content relative to each other until
04988   // the end. Then we sort them.
04989   //
04990   // When we're shuffling placeholders we also need to shuffle their out of
04991   // flows to match. As we put placeholders into keepPlaceholders, we unhook
04992   // their floats from mFloats. Later we put the floats back based on the
04993   // order of the placeholders.
04994   nsIFrame* lastOP = nsnull;
04995   nsFrameList keepPlaceholders;
04996   nsFrameList keepOutOfFlows;
04997   nsIFrame* lastKP = nsnull;
04998   nsIFrame* lastKOOF = nsnull;
04999   nsLineList* lineLists[3] = { overflowLines, &mLines, ourOverflowLines };
05000   static const PRPackedBool searchFirstLinesOnly[3] = { PR_FALSE, PR_TRUE, PR_FALSE };
05001   for (PRInt32 i = 0; i < 3; ++i) {
05002     nsLineList* ll = lineLists[i];
05003     if (ll && !ll->empty()) {
05004       line_iterator iter = ll->begin();
05005       line_iterator iter_end = ll->end();
05006       nsIFrame* lastFrame = nsnull;
05007       while (iter != iter_end) {
05008         PRUint32 n = iter->GetChildCount();
05009         if (n == 0 || !IsContinuationPlaceholder(iter->mFirstChild)) {
05010           if (lastFrame) {
05011             lastFrame->SetNextSibling(iter->mFirstChild);
05012           }
05013           if (searchFirstLinesOnly[i]) {
05014             break;
05015           }
05016           lastFrame = iter->LastChild();
05017           ++iter;
05018         } else {
05019           nsLineBox* line = iter;
05020           iter = ll->erase(iter);
05021           nsIFrame* next;
05022           for (nsPlaceholderFrame* f = NS_STATIC_CAST(nsPlaceholderFrame*, line->mFirstChild);
05023                n > 0; --n, f = NS_STATIC_CAST(nsPlaceholderFrame*, next)) {
05024             NS_ASSERTION(IsContinuationPlaceholder(f),
05025                          "Line frames should all be continuation placeholders");
05026             next = f->GetNextSibling();
05027             nsIFrame* fpif = f->GetPrevInFlow();
05028             nsIFrame* oof = f->GetOutOfFlowFrame();
05029             
05030             // Take this out of mFloats for now. We may put it back later in
05031             // this function
05032 #ifdef DEBUG
05033             PRBool found =
05034 #endif
05035               mFloats.RemoveFrame(oof);
05036             NS_ASSERTION(found, "Float should have been put in our mFloats list");
05037 
05038             PRBool isAncestor = nsLayoutUtils::IsProperAncestorFrame(this, fpif);
05039             if (isAncestor) {
05040               // oops. we already have a prev-in-flow for this
05041               // placeholder. We have to move this frame out of here. We
05042               // can put it in our overflow placeholders.
05043               aState.mOverflowPlaceholders.InsertFrame(nsnull, lastOP, f);
05044               // Let oof dangle for now, because placeholders in
05045               // mOverflowPlaceholders do not keep their floats in any child list
05046               lastOP = f;
05047             } else {
05048               if (fpif->GetParent() == prevBlock) {
05049                 keepPlaceholders.InsertFrame(nsnull, lastKP, f);
05050                 keepOutOfFlows.InsertFrame(nsnull, lastKOOF, oof);
05051                 lastKP = f;
05052                 lastKOOF = oof;
05053               } else {
05054                 // Ok, now we're in the tough situation where some child
05055                 // of prevBlock was complete and pushed its overflow
05056                 // placeholders up to prevBlock's overflow. We might be
05057                 // able to find a more appropriate parent for f somewhere
05058                 // down in our descendants.
05059                 NS_ASSERTION(nsLayoutUtils::IsProperAncestorFrame(prevBlock, fpif),
05060                              "bad prev-in-flow ancestor chain");
05061                 // Find the first ancestor of f's prev-in-flow that has a next in flow
05062                 // that can contain the float.
05063                 // That next in flow should become f's parent.
05064                 nsIFrame* fpAncestor;
05065                 for (fpAncestor = fpif->GetParent();
05066                      !fpAncestor->GetNextInFlow() || !fpAncestor->IsFloatContainingBlock();
05067                      fpAncestor = fpAncestor->GetParent())
05068                   ;
05069                 if (fpAncestor == prevBlock) {
05070                   // We're still the best parent.
05071                   keepPlaceholders.InsertFrame(nsnull, lastKP, f);
05072                   keepOutOfFlows.InsertFrame(nsnull, lastKOOF, oof);
05073                   lastKP = f;
05074                   lastKOOF = oof;
05075                 } else {
05076                   // Just put it at the front of
05077                   // fpAncestor->GetNextInFlow()'s lines.
05078                   nsLineBox* newLine = aState.NewLineBox(f, 1, PR_FALSE);
05079                   if (newLine) {
05080                     nsBlockFrame* target =
05081                       NS_STATIC_CAST(nsBlockFrame*, fpAncestor->GetNextInFlow());
05082                     if (!target->mLines.empty()) {
05083                       f->SetNextSibling(target->mLines.front()->mFirstChild);
05084                     } else {
05085                       f->SetNextSibling(nsnull);
05086                     }
05087                     target->mLines.push_front(newLine);
05088                     ReparentFrame(f, this, target);
05089 
05090                     target->mFloats.InsertFrame(nsnull, nsnull, oof);
05091                     ReparentFrame(oof, this, target);
05092                   }
05093                 }
05094               }
05095             }
05096           }
05097           aState.FreeLineBox(line);
05098         }
05099       }
05100       if (lastFrame) {
05101         lastFrame->SetNextSibling(nsnull);
05102       }
05103     }
05104   }
05105 
05106   // Now join the line lists into mLines
05107   if (overflowLines) {
05108     if (!overflowLines->empty()) {
05109       // Join the line lists
05110       if (! mLines.empty()) 
05111         {
05112           // Remember to recompute the margins on the first line. This will
05113           // also recompute the correct deltaY if necessary.
05114           mLines.front()->MarkPreviousMarginDirty();
05115           // Join the sibling lists together
05116           nsIFrame* lastFrame = overflowLines->back()->LastChild();
05117           lastFrame->SetNextSibling(mLines.front()->mFirstChild);
05118         }
05119       // Place overflow lines at the front of our line list
05120       mLines.splice(mLines.begin(), *overflowLines);
05121       NS_ASSERTION(overflowLines->empty(), "splice should empty list");
05122     }
05123     delete overflowLines;
05124   }
05125   if (ourOverflowLines) {
05126     if (!ourOverflowLines->empty()) {
05127       if (!mLines.empty()) {
05128         mLines.back()->LastChild()->
05129           SetNextSibling(ourOverflowLines->front()->mFirstChild);
05130       }
05131       // append the overflow to mLines
05132       mLines.splice(mLines.end(), *ourOverflowLines);
05133     }
05134     delete ourOverflowLines;
05135   }
05136 
05137   // store the placeholders that we're keeping in our frame list
05138   if (keepPlaceholders.NotEmpty()) {
05139     keepPlaceholders.SortByContentOrder();
05140     nsLineBox* newLine = aState.NewLineBox(keepPlaceholders.FirstChild(),
05141                                            keepPlaceholders.GetLength(), PR_FALSE);
05142     if (newLine) {
05143       if (!mLines.empty()) {
05144         keepPlaceholders.LastChild()->SetNextSibling(mLines.front()->mFirstChild);
05145       }
05146       mLines.push_front(newLine);
05147     }
05148 
05149     // Put the placeholders' out of flows into the float list
05150     keepOutOfFlows.SortByContentOrder();
05151     mFloats.InsertFrames(nsnull, nsnull, keepOutOfFlows.FirstChild());
05152   }
05153 
05154   return PR_TRUE;
05155 }
05156 
05157 nsLineList*
05158 nsBlockFrame::GetOverflowLines() const
05159 {
05160   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES)) {
05161     return nsnull;
05162   }
05163   nsLineList* lines = NS_STATIC_CAST(nsLineList*,
05164     GetProperty(nsLayoutAtoms::overflowLinesProperty));
05165   NS_ASSERTION(lines && !lines->empty(),
05166                "value should always be stored and non-empty when state set");
05167   return lines;
05168 }
05169 
05170 nsLineList*
05171 nsBlockFrame::RemoveOverflowLines()
05172 {
05173   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES)) {
05174     return nsnull;
05175   }
05176   nsLineList* lines = NS_STATIC_CAST(nsLineList*,
05177     UnsetProperty(nsLayoutAtoms::overflowLinesProperty));
05178   NS_ASSERTION(lines && !lines->empty(),
05179                "value should always be stored and non-empty when state set");
05180   RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
05181   return lines;
05182 }
05183 
05184 // Destructor function for the overflowLines frame property
05185 static void
05186 DestroyOverflowLines(void*           aFrame,
05187                      nsIAtom*        aPropertyName,
05188                      void*           aPropertyValue,
05189                      void*           aDtorData)
05190 {
05191   if (aPropertyValue) {
05192     nsLineList* lines = NS_STATIC_CAST(nsLineList*, aPropertyValue);
05193     nsPresContext *context = NS_STATIC_CAST(nsPresContext*, aDtorData);
05194     nsLineBox::DeleteLineList(context, *lines);
05195     delete lines;
05196   }
05197 }
05198 
05199 // This takes ownership of aOverflowLines.
05200 // XXX We should allocate overflowLines from presShell arena!
05201 nsresult
05202 nsBlockFrame::SetOverflowLines(nsLineList* aOverflowLines)
05203 {
05204   NS_ASSERTION(aOverflowLines, "null lines");
05205   NS_ASSERTION(!aOverflowLines->empty(), "empty lines");
05206   NS_ASSERTION(!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES),
05207                "Overwriting existing overflow lines");
05208 
05209   nsPresContext *presContext = GetPresContext();
05210   nsresult rv = presContext->PropertyTable()->
05211     SetProperty(this, nsLayoutAtoms::overflowLinesProperty, aOverflowLines,
05212                 DestroyOverflowLines, presContext);
05213   // Verify that we didn't overwrite an existing overflow list
05214   NS_ASSERTION(rv != NS_PROPTABLE_PROP_OVERWRITTEN, "existing overflow list");
05215   AddStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
05216   return rv;
05217 }
05218 
05219 nsFrameList
05220 nsBlockFrame::GetOverflowOutOfFlows() const
05221 {
05222   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)) {
05223     return nsFrameList();
05224   }
05225   nsIFrame* result = NS_STATIC_CAST(nsIFrame*,
05226     GetProperty(nsLayoutAtoms::overflowOutOfFlowsProperty));
05227   NS_ASSERTION(result, "value should always be non-empty when state set");
05228   return nsFrameList(result);
05229 }
05230 
05231 // This takes ownership of the frames
05232 void
05233 nsBlockFrame::SetOverflowOutOfFlows(const nsFrameList& aList)
05234 {
05235   if (aList.IsEmpty()) {
05236     if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)) {
05237       return;
05238     }
05239     nsIFrame* result = NS_STATIC_CAST(nsIFrame*,
05240                                       UnsetProperty(nsLayoutAtoms::overflowOutOfFlowsProperty));
05241     NS_ASSERTION(result, "value should always be non-empty when state set");
05242     RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
05243   } else {
05244     SetProperty(nsLayoutAtoms::overflowOutOfFlowsProperty,
05245                 aList.FirstChild(), nsnull);
05246     AddStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
05247   }
05248 }
05249 
05250 nsFrameList*
05251 nsBlockFrame::GetOverflowPlaceholders() const
05252 {
05253   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS)) {
05254     return nsnull;
05255   }
05256   nsFrameList* result = NS_STATIC_CAST(nsFrameList*,
05257     GetProperty(nsLayoutAtoms::overflowPlaceholdersProperty));
05258   NS_ASSERTION(result, "value should always be non-empty when state set");
05259   return result;
05260 }
05261 
05263 // Frame list manipulation routines
05264 
05265 nsIFrame*
05266 nsBlockFrame::LastChild()
05267 {
05268   if (! mLines.empty()) {
05269     return mLines.back()->LastChild();
05270   }
05271   return nsnull;
05272 }
05273 
05274 NS_IMETHODIMP
05275 nsBlockFrame::AppendFrames(nsIAtom*  aListName,
05276                            nsIFrame* aFrameList)
05277 {
05278   if (nsnull == aFrameList) {
05279     return NS_OK;
05280   }
05281   if (mAbsoluteContainer.GetChildListName() == aListName) {
05282     return mAbsoluteContainer.AppendFrames(this, aListName, aFrameList);
05283   }
05284   else if (nsLayoutAtoms::floatList == aListName) {
05285     mFloats.AppendFrames(nsnull, aFrameList);
05286     return NS_OK;
05287   }
05288   else if (nsnull != aListName) {
05289     return NS_ERROR_INVALID_ARG;
05290   }
05291 
05292   // Find the proper last-child for where the append should go
05293   nsIFrame* lastKid = nsnull;
05294   nsLineBox* lastLine = mLines.empty() ? nsnull : mLines.back();
05295   if (lastLine) {
05296     lastKid = lastLine->LastChild();
05297   }
05298 
05299   // Add frames after the last child
05300 #ifdef NOISY_REFLOW_REASON
05301   ListTag(stdout);
05302   printf(": append ");
05303   nsFrame::ListTag(stdout, aFrameList);
05304   if (lastKid) {
05305     printf(" after ");
05306     nsFrame::ListTag(stdout, lastKid);
05307   }
05308   printf("\n");
05309 #endif
05310   nsresult rv = AddFrames(aFrameList, lastKid);
05311   if (NS_SUCCEEDED(rv)) {
05312     // Ask the parent frame to reflow me.
05313     ReflowDirtyChild(GetPresContext()->PresShell(), nsnull);
05314   }
05315   return rv;
05316 }
05317 
05318 NS_IMETHODIMP
05319 nsBlockFrame::InsertFrames(nsIAtom*  aListName,
05320                            nsIFrame* aPrevFrame,
05321                            nsIFrame* aFrameList)
05322 {
05323   if (mAbsoluteContainer.GetChildListName() == aListName) {
05324     return mAbsoluteContainer.InsertFrames(this, aListName, aPrevFrame,
05325                                            aFrameList);
05326   }
05327   else if (nsLayoutAtoms::floatList == aListName) {
05328     mFloats.InsertFrames(this, aPrevFrame, aFrameList);
05329     return NS_OK;
05330   }
05331 #ifdef IBMBIDI
05332   else if (nsLayoutAtoms::nextBidi == aListName) {}
05333 #endif // IBMBIDI
05334   else if (nsnull != aListName) {
05335     return NS_ERROR_INVALID_ARG;
05336   }
05337 
05338 #ifdef NOISY_REFLOW_REASON
05339   ListTag(stdout);
05340   printf(": insert ");
05341   nsFrame::ListTag(stdout, aFrameList);
05342   if (aPrevFrame) {
05343     printf(" after ");
05344     nsFrame::ListTag(stdout, aPrevFrame);
05345   }
05346   printf("\n");
05347 #endif
05348   nsresult rv = AddFrames(aFrameList, aPrevFrame);
05349 #ifdef IBMBIDI
05350   if (aListName != nsLayoutAtoms::nextBidi)
05351 #endif // IBMBIDI
05352   if (NS_SUCCEEDED(rv)) {
05353     // Ask the parent frame to reflow me.
05354     ReflowDirtyChild(GetPresContext()->PresShell(), nsnull);
05355   }
05356   return rv;
05357 }
05358 
05359 static PRBool
05360 ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
05361 {
05362   nsIAtom* type = aLastFrame->GetType();
05363   if (type == nsLayoutAtoms::brFrame)
05364     return PR_TRUE;
05365   if (type == nsLayoutAtoms::placeholderFrame)
05366     return IsContinuationPlaceholder(aLastFrame);
05367   return PR_FALSE;
05368 }
05369 
05370 nsresult
05371 nsBlockFrame::AddFrames(nsIFrame* aFrameList,
05372                         nsIFrame* aPrevSibling)
05373 {
05374   // Clear our line cursor, since our lines may change.
05375   ClearLineCursor();
05376 
05377   if (nsnull == aFrameList) {
05378     return NS_OK;
05379   }
05380 
05381   // If we're inserting at the beginning of our list and we have an
05382   // inside bullet, insert after that bullet.
05383   if (!aPrevSibling && mBullet && !HaveOutsideBullet()) {
05384     NS_ASSERTION(!nsFrameList(aFrameList).ContainsFrame(mBullet),
05385                  "Trying to make mBullet prev sibling to itself");
05386     aPrevSibling = mBullet;
05387   }
05388   
05389   nsIPresShell *presShell = GetPresContext()->PresShell();
05390 
05391   // Attempt to find the line that contains the previous sibling
05392   nsLineList::iterator prevSibLine = end_lines();
05393   PRInt32 prevSiblingIndex = -1;
05394   if (aPrevSibling) {
05395     // XXX_perf This is technically O(N^2) in some cases, but by using
05396     // RFind instead of Find, we make it O(N) in the most common case,
05397     // which is appending cotent.
05398 
05399     // Find the line that contains the previous sibling
05400     if (! nsLineBox::RFindLineContaining(aPrevSibling,
05401                                          begin_lines(), prevSibLine,
05402                                          &prevSiblingIndex)) {
05403       // Note: defensive code! RFindLineContaining must not return
05404       // false in this case, so if it does...
05405       NS_NOTREACHED("prev sibling not in line list");
05406       aPrevSibling = nsnull;
05407       prevSibLine = end_lines();
05408     }
05409   }
05410 
05411   // Find the frame following aPrevSibling so that we can join up the
05412   // two lists of frames.
05413   nsIFrame* prevSiblingNextFrame = nsnull;
05414   if (aPrevSibling) {
05415     prevSiblingNextFrame = aPrevSibling->GetNextSibling();
05416 
05417     // Split line containing aPrevSibling in two if the insertion
05418     // point is somewhere in the middle of the line.
05419     PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
05420     if (rem) {
05421       // Split the line in two where the frame(s) are being inserted.
05422       nsLineBox* line = NS_NewLineBox(presShell, prevSiblingNextFrame, rem, PR_FALSE);
05423       if (!line) {
05424         return NS_ERROR_OUT_OF_MEMORY;
05425       }
05426       mLines.after_insert(prevSibLine, line);
05427       prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem);
05428       prevSibLine->MarkDirty();
05429     }
05430 
05431     // Now (partially) join the sibling lists together
05432     aPrevSibling->SetNextSibling(aFrameList);
05433   }
05434   else if (! mLines.empty()) {
05435     prevSiblingNextFrame = mLines.front()->mFirstChild;
05436   }
05437 
05438   // Walk through the new frames being added and update the line data
05439   // structures to fit.
05440   nsIFrame* newFrame = aFrameList;
05441   while (newFrame) {
05442     PRBool isBlock = nsLineLayout::TreatFrameAsBlock(newFrame);
05443 
05444     // If the frame is a block frame, or if there is no previous line or if the
05445     // previous line is a block line or ended with a <br> then make a new line.
05446     if (isBlock || prevSibLine == end_lines() || prevSibLine->IsBlock() ||
05447         (aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) {
05448       // Create a new line for the frame and add its line to the line
05449       // list.
05450       nsLineBox* line = NS_NewLineBox(presShell, newFrame, 1, isBlock);
05451       if (!line) {
05452         return NS_ERROR_OUT_OF_MEMORY;
05453       }
05454       if (prevSibLine != end_lines()) {
05455         // Append new line after prevSibLine
05456         mLines.after_insert(prevSibLine, line);
05457         ++prevSibLine;
05458       }
05459       else {
05460         // New line is going before the other lines
05461         mLines.push_front(line);
05462         prevSibLine = begin_lines();
05463       }
05464     }
05465     else {
05466       prevSibLine->SetChildCount(prevSibLine->GetChildCount() + 1);
05467       prevSibLine->MarkDirty();
05468     }
05469 
05470     aPrevSibling = newFrame;
05471     newFrame = newFrame->GetNextSibling();
05472   }
05473   if (prevSiblingNextFrame) {
05474     // Connect the last new frame to the remainder of the sibling list
05475     aPrevSibling->SetNextSibling(prevSiblingNextFrame);
05476   }
05477 
05478 #ifdef DEBUG
05479   VerifyLines(PR_TRUE);
05480 #endif
05481   return NS_OK;
05482 }
05483 
05484 nsBlockFrame::line_iterator
05485 nsBlockFrame::RemoveFloat(nsIFrame* aFloat) {
05486   // Find which line contains the float, so we can update
05487   // the float cache.
05488   line_iterator line = begin_lines(), line_end = end_lines();
05489   for ( ; line != line_end; ++line) {
05490     if (line->IsInline() && line->RemoveFloat(aFloat)) {
05491       break;
05492     }
05493   }
05494 
05495   // Unlink the placeholder *after* we searched the lines, because
05496   // the line search uses the placeholder relationship.
05497   nsFrameManager* fm = GetPresContext()->GetPresShell()->FrameManager();
05498   nsPlaceholderFrame* placeholder = fm->GetPlaceholderFrameFor(aFloat);
05499   if (placeholder) {
05500     fm->UnregisterPlaceholderFrame(placeholder);
05501     placeholder->SetOutOfFlowFrame(nsnull);
05502   }
05503 
05504   // Try to destroy if it's in mFloats.
05505   if (mFloats.DestroyFrame(GetPresContext(), aFloat)) {
05506     return line;
05507   }
05508 
05509   // Try our overflow list
05510   {
05511     nsAutoOOFFrameList oofs(this);
05512     if (oofs.mList.DestroyFrame(GetPresContext(), aFloat)) {
05513       return line_end;
05514     }
05515   }
05516 
05517   // If this is during reflow, it could be the out-of-flow frame for a
05518   // placeholder in our block reflow state's mOverflowPlaceholders. But that's
05519   // OK; it's not part of any child list, so we can just go ahead and delete it.
05520   aFloat->Destroy(GetPresContext());
05521   return line_end;
05522 }
05523 
05524 static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock)
05525 {
05526   nsLineList::iterator line = aBlock->begin_lines();
05527   nsLineList::iterator endLine = aBlock->end_lines();
05528   while (line != endLine) {
05529     if (line->IsBlock()) {
05530       nsIFrame* f = line->mFirstChild;
05531       void* bf;
05532       if (NS_SUCCEEDED(f->QueryInterface(kBlockFrameCID, &bf))) {
05533         MarkAllDescendantLinesDirty(NS_STATIC_CAST(nsBlockFrame*, f));
05534       }
05535     }
05536     line->MarkDirty();
05537     ++line;
05538   }
05539 }
05540 
05541 static void MarkSameSpaceManagerLinesDirty(nsBlockFrame* aBlock)
05542 {
05543   nsBlockFrame* blockWithSpaceMgr = aBlock;
05544   while (!(blockWithSpaceMgr->GetStateBits() & NS_BLOCK_SPACE_MGR)) {
05545     void* bf;
05546     if (NS_FAILED(blockWithSpaceMgr->GetParent()->
05547                   QueryInterface(kBlockFrameCID, &bf))) {
05548       break;
05549     }
05550     blockWithSpaceMgr = NS_STATIC_CAST(nsBlockFrame*, blockWithSpaceMgr->GetParent());
05551   }
05552     
05553   // Mark every line at and below the line where the float was
05554   // dirty, and mark their lines dirty too. We could probably do
05555   // something more efficient --- e.g., just dirty the lines that intersect
05556   // the float vertically.
05557   MarkAllDescendantLinesDirty(blockWithSpaceMgr);
05558 }
05559 
05563 static PRBool BlockHasAnyFloats(nsIFrame* aFrame)
05564 {
05565   void* bf;
05566   if (NS_FAILED(aFrame->QueryInterface(kBlockFrameCID, &bf)))
05567     return PR_FALSE;
05568   nsBlockFrame* block = NS_STATIC_CAST(nsBlockFrame*, aFrame);
05569   if (block->GetFirstChild(nsLayoutAtoms::floatList))
05570     return PR_TRUE;
05571     
05572   nsLineList::iterator line = block->begin_lines();
05573   nsLineList::iterator endLine = block->end_lines();
05574   while (line != endLine) {
05575     if (line->IsBlock() && BlockHasAnyFloats(line->mFirstChild))
05576       return PR_TRUE;
05577     ++line;
05578   }
05579   return PR_FALSE;
05580 }
05581 
05582 NS_IMETHODIMP
05583 nsBlockFrame::RemoveFrame(nsIAtom*  aListName,
05584                           nsIFrame* aOldFrame)
05585 {
05586   nsresult rv = NS_OK;
05587 
05588 #ifdef NOISY_REFLOW_REASON
05589   ListTag(stdout);
05590   printf(": remove ");
05591   nsFrame::ListTag(stdout, aOldFrame);
05592   printf("\n");
05593 #endif
05594 
05595   if (nsnull == aListName) {
05596     PRBool hasFloats = BlockHasAnyFloats(aOldFrame);
05597     rv = DoRemoveFrame(aOldFrame);
05598     if (hasFloats) {
05599       MarkSameSpaceManagerLinesDirty(this);
05600     }
05601   }
05602   else if (mAbsoluteContainer.GetChildListName() == aListName) {
05603     return mAbsoluteContainer.RemoveFrame(this, aListName, aOldFrame);
05604   }
05605   else if (nsLayoutAtoms::floatList == aListName) {
05606     RemoveFloat(aOldFrame);
05607     MarkSameSpaceManagerLinesDirty(this);
05608   }
05609 #ifdef IBMBIDI
05610   else if (nsLayoutAtoms::nextBidi == aListName) {
05611     // Skip the call to |ReflowDirtyChild| below by returning now.
05612     return DoRemoveFrame(aOldFrame);
05613   }
05614 #endif // IBMBIDI
05615   else {
05616     rv = NS_ERROR_INVALID_ARG;
05617   }
05618 
05619   if (NS_SUCCEEDED(rv)) {
05620     // Ask the parent frame to reflow me.
05621     ReflowDirtyChild(GetPresContext()->PresShell(), nsnull);
05622   }
05623   return rv;
05624 }
05625 
05626 void
05627 nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
05628 {
05629   // First remove aFrame's next in flow
05630   nsIFrame* nextInFlow = aFrame->GetNextInFlow();
05631   if (nextInFlow) {
05632     nsBlockFrame::DoRemoveOutOfFlowFrame(nextInFlow);
05633   }
05634   // Now remove aFrame
05635   const nsStyleDisplay* display = aFrame->GetStyleDisplay();
05636 
05637   // The containing block is always the parent of aFrame.
05638   nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent();
05639   // Remove aFrame from the appropriate list. 
05640   if (display->IsAbsolutelyPositioned()) {
05641     block->mAbsoluteContainer.RemoveFrame(block,
05642                                           block->mAbsoluteContainer.GetChildListName(),
05643                                           aFrame);
05644     aFrame->Destroy(aFrame->GetPresContext());
05645   }
05646   else {
05647     // This also destroys the frame.
05648     block->RemoveFloat(aFrame);
05649   }
05650 }
05651 
05655 void
05656 nsBlockFrame::TryAllLines(nsLineList::iterator* aIterator,
05657                           nsLineList::iterator* aEndIterator,
05658                           PRBool* aInOverflowLines) {
05659   if (*aIterator == *aEndIterator) {
05660     if (!*aInOverflowLines) {
05661       *aInOverflowLines = PR_TRUE;
05662       // Try the overflow lines
05663       nsLineList* overflowLines = GetOverflowLines();
05664       if (overflowLines) {
05665         *aIterator = overflowLines->begin();
05666         *aEndIterator = overflowLines->end();
05667       }
05668     }
05669   }
05670 }
05671 
05672 static nsresult RemoveBlockChild(nsIFrame* aFrame, PRBool aDestroyFrames)
05673 {
05674   if (!aFrame)
05675     return NS_OK;
05676 
05677   nsBlockFrame* nextBlock = NS_STATIC_CAST(nsBlockFrame*, aFrame->GetParent());
05678   NS_ASSERTION(nextBlock->GetType() == nsLayoutAtoms::blockFrame ||
05679                nextBlock->GetType() == nsLayoutAtoms::areaFrame,
05680                "Our child's continuation's parent is not a block?");
05681   return nextBlock->DoRemoveFrame(aFrame, aDestroyFrames);
05682 }
05683 
05684 // This function removes aDeletedFrame and all its continuations.  It
05685 // is optimized for deleting a whole series of frames. The easy
05686 // implementation would invoke itself recursively on
05687 // aDeletedFrame->GetNextInFlow, then locate the line containing
05688 // aDeletedFrame and remove aDeletedFrame from that line. But here we
05689 // start by locating aDeletedFrame and then scanning from that point
05690 // on looking for continuations.
05691 nsresult
05692 nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRBool aDestroyFrames)
05693 {
05694   // Clear our line cursor, since our lines may change.
05695   ClearLineCursor();
05696         
05697   if (aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
05698     NS_ASSERTION(aDestroyFrames, "We can't not destroy out of flows");
05699     DoRemoveOutOfFlowFrame(aDeletedFrame);
05700     return NS_OK;
05701   }
05702   
05703   nsPresContext* presContext = GetPresContext();
05704   nsIPresShell* presShell = presContext->PresShell();
05705 
05706   PRBool isPlaceholder = nsLayoutAtoms::placeholderFrame == aDeletedFrame->GetType();
05707   if (isPlaceholder) {
05708     nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
05709     if (overflowPlaceholders && overflowPlaceholders->RemoveFrame(aDeletedFrame)) {
05710       nsIFrame* nif = aDeletedFrame->GetNextInFlow();
05711       if (aDestroyFrames) {
05712         aDeletedFrame->Destroy(presContext);
05713       } else {
05714         aDeletedFrame->SetNextSibling(nsnull);
05715       }
05716       return RemoveBlockChild(nif, aDestroyFrames);
05717     }
05718   }
05719   
05720   // Find the line and the previous sibling that contains
05721   // deletedFrame; we also find the pointer to the line.
05722   nsLineList::iterator line = mLines.begin(),
05723                        line_end = mLines.end();
05724   PRBool searchingOverflowList = PR_FALSE;
05725   nsIFrame* prevSibling = nsnull;
05726   // Make sure we look in the overflow lines even if the normal line
05727   // list is empty
05728   TryAllLines(&line, &line_end, &searchingOverflowList);
05729   while (line != line_end) {
05730     nsIFrame* frame = line->mFirstChild;
05731     PRInt32 n = line->GetChildCount();
05732     while (--n >= 0) {
05733       if (frame == aDeletedFrame) {
05734         goto found_frame;
05735       }
05736       prevSibling = frame;
05737       frame = frame->GetNextSibling();
05738     }
05739     ++line;
05740     TryAllLines(&line, &line_end, &searchingOverflowList);
05741   }
05742 found_frame:;
05743   if (line == line_end) {
05744     NS_ERROR("can't find deleted frame in lines");
05745     return NS_ERROR_FAILURE;
05746   }
05747 
05748   if (prevSibling && !prevSibling->GetNextSibling()) {
05749     // We must have found the first frame in the overflow line list. So
05750     // there is no prevSibling
05751     prevSibling = nsnull;
05752   }
05753   NS_ASSERTION(!prevSibling || prevSibling->GetNextSibling() == aDeletedFrame, "bad prevSibling");
05754 
05755   while ((line != line_end) && (nsnull != aDeletedFrame)) {
05756     NS_ASSERTION(this == aDeletedFrame->GetParent(), "messed up delete code");
05757     NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line");
05758 
05759     // If the frame being deleted is the last one on the line then
05760     // optimize away the line->Contains(next-in-flow) call below.
05761     PRBool isLastFrameOnLine = (1 == line->GetChildCount() ||
05762                                 line->LastChild() == aDeletedFrame);
05763 
05764     // Remove aDeletedFrame from the line
05765     nsIFrame* nextFrame = aDeletedFrame->GetNextSibling();
05766     if (line->mFirstChild == aDeletedFrame) {
05767       // We should be setting this to null if aDeletedFrame
05768       // is the only frame on the line. HOWEVER in that case
05769       // we will be removing the line anyway, see below.
05770       line->mFirstChild = nextFrame;
05771     }
05772 
05773     // Hmm, this won't do anything if we're removing a frame in the first
05774     // overflow line... Hopefully doesn't matter
05775     --line;
05776     if (line != line_end && !line->IsBlock()) {
05777       // Since we just removed a frame that follows some inline
05778       // frames, we need to reflow the previous line.
05779       line->MarkDirty();
05780     }
05781     ++line;
05782 
05783     // Take aDeletedFrame out of the sibling list. Note that
05784     // prevSibling will only be nsnull when we are deleting the very
05785     // first frame in the main or overflow list.
05786     if (prevSibling) {
05787       prevSibling->SetNextSibling(nextFrame);
05788     }
05789 
05790     // Update the child count of the line to be accurate
05791     PRInt32 lineChildCount = line->GetChildCount();
05792     lineChildCount--;
05793     line->SetChildCount(lineChildCount);
05794 
05795     // Destroy frame; capture its next-in-flow first in case we need
05796     // to destroy that too.
05797     nsIFrame* deletedNextInFlow = aDeletedFrame->GetNextInFlow();
05798 #ifdef NOISY_REMOVE_FRAME
05799     printf("DoRemoveFrame: %s line=%p frame=",
05800            searchingOverflowList?"overflow":"normal", line.get());
05801     nsFrame::ListTag(stdout, aDeletedFrame);
05802     printf(" prevSibling=%p deletedNextInFlow=%p\n", prevSibling, deletedNextInFlow);
05803 #endif
05804 
05805     if (aDestroyFrames) {
05806       aDeletedFrame->Destroy(presContext);
05807     } else {
05808       aDeletedFrame->SetNextSibling(nsnull);
05809     }
05810     aDeletedFrame = deletedNextInFlow;
05811 
05812     PRBool haveAdvancedToNextLine = PR_FALSE;
05813     // If line is empty, remove it now.
05814     if (0 == lineChildCount) {
05815 #ifdef NOISY_REMOVE_FRAME
05816         printf("DoRemoveFrame: %s line=%p became empty so it will be removed\n",
05817                searchingOverflowList?"overflow":"normal", line.get());
05818 #endif
05819       nsLineBox *cur = line;
05820       if (!searchingOverflowList) {
05821         line = mLines.erase(line);
05822         // Invalidate the space taken up by the line.
05823         // XXX We need to do this if we're removing a frame as a result of
05824         // a call to RemoveFrame(), but we may not need to do this in all
05825         // cases...
05826         nsRect lineCombinedArea(cur->GetCombinedArea());
05827 #ifdef NOISY_BLOCK_INVALIDATE
05828         printf("%p invalidate 10 (%d, %d, %d, %d)\n",
05829                this, lineCombinedArea.x, lineCombinedArea.y,
05830                lineCombinedArea.width, lineCombinedArea.height);
05831 #endif
05832         Invalidate(lineCombinedArea);
05833       } else {
05834         nsLineList* lineList = RemoveOverflowLines();
05835         line = lineList->erase(line);
05836         if (!lineList->empty()) {
05837           SetOverflowLines(lineList);
05838         }
05839       }
05840       cur->Destroy(presShell);
05841 
05842       // If we're removing a line, ReflowDirtyLines isn't going to
05843       // know that it needs to slide lines unless something is marked
05844       // dirty.  So mark the previous margin of the next line dirty if
05845       // there is one.
05846       if (line != line_end) {
05847         line->MarkPreviousMarginDirty();
05848       }
05849       haveAdvancedToNextLine = PR_TRUE;
05850     } else {
05851       // Make the line that just lost a frame dirty, and advance to
05852       // the next line.
05853       if (!deletedNextInFlow || isLastFrameOnLine ||
05854           !line->Contains(deletedNextInFlow)) {
05855         line->MarkDirty();
05856         ++line;
05857         haveAdvancedToNextLine = PR_TRUE;
05858       }
05859     }
05860 
05861     if (deletedNextInFlow) {
05862       // Continuations for placeholder frames don't always appear in
05863       // consecutive lines. So for placeholders, just continue the slow easy way.
05864       if (isPlaceholder) {
05865         return RemoveBlockChild(deletedNextInFlow, aDestroyFrames);
05866       }
05867 
05868       // See if we should keep looking in the current flow's line list.
05869       if (deletedNextInFlow->GetParent() != this) {
05870         // The deceased frames continuation is not a child of the
05871         // current block. So break out of the loop so that we advance
05872         // to the next parent.
05873         break;
05874       }
05875 
05876       // If we advanced to the next line then check if we should switch to the
05877       // overflow line list.
05878       if (haveAdvancedToNextLine) {
05879         if (line != line_end && !searchingOverflowList &&
05880             !line->Contains(deletedNextInFlow)) {
05881           // We have advanced to the next *normal* line but the next-in-flow
05882           // is not there - force a switch to the overflow line list.
05883           line = line_end;
05884         }
05885 
05886         PRBool wasSearchingOverflowList = searchingOverflowList;
05887         TryAllLines(&line, &line_end, &searchingOverflowList);
05888         if (NS_UNLIKELY(searchingOverflowList && !wasSearchingOverflowList &&
05889                         prevSibling)) {
05890           // We switched to the overflow line list and we have a prev sibling
05891           // (in the main list), in this case we don't want to pick up any
05892           // sibling list from the deceased frames (bug 344557).
05893           prevSibling->SetNextSibling(nsnull);
05894           prevSibling = nsnull;
05895         }
05896 #ifdef NOISY_REMOVE_FRAME
05897         printf("DoRemoveFrame: now on %s line=%p prevSibling=%p\n",
05898                searchingOverflowList?"overflow":"normal", line.get(),
05899                prevSibling);
05900 #endif
05901       }
05902     }
05903   }
05904 
05905 #ifdef DEBUG
05906   VerifyLines(PR_TRUE);
05907 #endif
05908 
05909   // Advance to next flow block if the frame has more continuations
05910   return RemoveBlockChild(aDeletedFrame, aDestroyFrames);
05911 }
05912 
05913 void
05914 nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
05915                                     nsIFrame*       aNextInFlow)
05916 {
05917   nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
05918   NS_PRECONDITION(prevInFlow, "bad next-in-flow");
05919   NS_PRECONDITION(IsChild(aNextInFlow), "bad geometric parent");
05920 
05921 #ifdef IBMBIDI
05922   if (!(prevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) ||
05923       (NS_STATIC_CAST(nsIFrame*,
05924                       aPresContext->PropertyTable()->GetProperty(prevInFlow, nsLayoutAtoms::nextBidi)) !=
05925        aNextInFlow))
05926 #endif // IBMBIDI
05927     DoRemoveFrame(aNextInFlow);
05928 }
05929 
05931 // Float support
05932 nsresult
05933 nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
05934                           nsPlaceholderFrame* aPlaceholder,
05935                           nsFloatCache*       aFloatCache,
05936                           nsReflowStatus&     aReflowStatus)
05937 {
05938   // Reflow the float.
05939   nsIFrame* floatFrame = aPlaceholder->GetOutOfFlowFrame();
05940   aReflowStatus = NS_FRAME_COMPLETE;
05941 
05942 #ifdef NOISY_FLOAT
05943   printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n",
05944           aPlaceholder->GetOutOfFlowFrame(), this, 
05945           aState.mAvailSpaceRect.x, aState.mAvailSpaceRect.y, 
05946           aState.mAvailSpaceRect.width, aState.mAvailSpaceRect.height
05947   );
05948 #endif
05949 
05950   // Compute the available width. By default, assume the width of the
05951   // containing block.
05952   nscoord availWidth;
05953   if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
05954     availWidth = NS_UNCONSTRAINEDSIZE;
05955   }
05956   else {
05957     const nsStyleDisplay* floatDisplay = floatFrame->GetStyleDisplay();
05958 
05959     if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
05960         eCompatibility_NavQuirks != aState.mPresContext->CompatibilityMode() ) {
05961       availWidth = aState.mContentArea.width;
05962     }
05963     else {
05964       // This quirk matches the one in nsBlockReflowState::FlowAndPlaceFloat
05965       // give tables only the available space
05966       // if they can shrink we may not be constrained to place
05967       // them in the next line
05968       availWidth = aState.mAvailSpaceRect.width;
05969       // round down to twips per pixel so that we fit
05970       // needed when prev. float has procentage width
05971       // (maybe is a table flaw that makes table chose to round up
05972       // but i don't want to change that, too risky)
05973       nscoord twp = aState.mPresContext->IntScaledPixelsToTwips(1);
05974       availWidth -=  availWidth % twp;
05975     }
05976   }
05977   nscoord availHeight = NS_UNCONSTRAINEDSIZE == aState.mContentArea.height
05978                         ? NS_UNCONSTRAINEDSIZE 
05979                         : PR_MAX(0, aState.mContentArea.height - aState.mY);
05980 
05981   // If the float's width is automatic, we can't let the float's
05982   // width shrink below its maxElementWidth.
05983   const nsStylePosition* position = floatFrame->GetStylePosition();
05984   PRBool isAutoWidth = (eStyleUnit_Auto == position->mWidth.GetUnit());
05985 
05986   // We'll need to compute the max element size if either 1) we're
05987   // auto-width or 2) the state wanted us to compute it anyway.
05988   PRBool computeMaxElementWidth =
05989     isAutoWidth || aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH);
05990 
05991   nsRect availSpace(aState.BorderPadding().left,
05992                     aState.BorderPadding().top,
05993                     availWidth, availHeight);
05994 
05995   // construct the html reflow state for the float. ReflowBlock will 
05996   // initialize it.
05997   nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState,
05998                             floatFrame, 
05999                             nsSize(availSpace.width, availSpace.height), 
06000                             aState.mReflowState.reason);
06001 
06002   // Setup a block reflow state to reflow the float.
06003   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
06004                            computeMaxElementWidth,
06005                            aState.GetFlag(BRS_COMPUTEMAXWIDTH));
06006 
06007   // Reflow the float
06008   PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
06009 
06010   nsIFrame* clearanceFrame = nsnull;
06011   nsresult rv;
06012   do {
06013     nsCollapsingMargin margin;
06014     PRBool mayNeedRetry = PR_FALSE;
06015     floatRS.mDiscoveredClearance = nsnull;
06016     // Only first in flow gets a top margin.
06017     if (!floatFrame->GetPrevInFlow()) {
06018       nsBlockReflowContext::ComputeCollapsedTopMargin(floatRS, &margin,
06019                                                       clearanceFrame, &mayNeedRetry);
06020 
06021       if (mayNeedRetry && !clearanceFrame) {
06022         floatRS.mDiscoveredClearance = &clearanceFrame;
06023         // We don't need to push the space manager state because the the block has its own
06024         // space manager that will be destroyed and recreated
06025       }
06026     }
06027 
06028     rv = brc.ReflowBlock(availSpace, PR_TRUE, margin,
06029                          0, isAdjacentWithTop,
06030                          aFloatCache->mOffsets, floatRS,
06031                          aReflowStatus);
06032   } while (NS_SUCCEEDED(rv) && clearanceFrame);
06033 
06034   // An incomplete reflow status means we should split the float 
06035   // if the height is constrained (bug 145305). 
06036   if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight))
06037     aReflowStatus = NS_FRAME_COMPLETE;
06038   
06039   if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
06040     // Float is now complete, so delete the placeholder's next in
06041     // flows, if any; their floats (which are this float's continuations)
06042     // have already been deleted.
06043     // XXX won't this be done later in nsLineLayout::ReflowFrame anyway??
06044     nsIFrame* nextInFlow = aPlaceholder->GetNextInFlow();
06045     if (nextInFlow) {
06046       NS_STATIC_CAST(nsHTMLContainerFrame*, nextInFlow->GetParent())
06047         ->DeleteNextInFlowChild(aState.mPresContext, nextInFlow);
06048       // that takes care of all subsequent nextinflows too
06049     }
06050   }
06051   if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
06052     aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
06053   }
06054 
06055   if (NS_SUCCEEDED(rv) && isAutoWidth) {
06056     nscoord maxElementWidth = brc.GetMaxElementWidth();
06057     if (maxElementWidth > availSpace.width) {
06058       // The float's maxElementWidth is larger than the available
06059       // width. Reflow it again, this time pinning the width to the
06060       // maxElementWidth.
06061       availSpace.width = maxElementWidth;
06062       // construct the html reflow state for the float. 
06063       // ReflowBlock will initialize it.
06064       nsHTMLReflowState redoFloatRS(aState.mPresContext, aState.mReflowState,
06065                                     floatFrame, 
06066                                     nsSize(availSpace.width, availSpace.height), 
06067                                     aState.mReflowState.reason);
06068 
06069       clearanceFrame = nsnull;
06070       do {
06071         nsCollapsingMargin marginMEW;
06072         PRBool mayNeedRetry = PR_FALSE;
06073         nsBlockReflowContext::ComputeCollapsedTopMargin(redoFloatRS, &marginMEW, clearanceFrame, &mayNeedRetry);
06074 
06075         if (mayNeedRetry && !clearanceFrame) {
06076           redoFloatRS.mDiscoveredClearance = &clearanceFrame;
06077           // We don't need to push the space manager state because the
06078           // the block has its own space manager that will be
06079           // destroyed and recreated
06080         } else {
06081           redoFloatRS.mDiscoveredClearance = nsnull;
06082         }
06083 
06084         rv = brc.ReflowBlock(availSpace, PR_TRUE, marginMEW,
06085                              0, isAdjacentWithTop,
06086                              aFloatCache->mOffsets, redoFloatRS,
06087                              aReflowStatus);
06088       } while (NS_SUCCEEDED(rv) && clearanceFrame);
06089     }
06090   }
06091 
06092   if (floatFrame->GetType() == nsLayoutAtoms::letterFrame) {
06093     // We never split floating first letters; an incomplete state for
06094     // such frames simply means that there is more content to be
06095     // reflowed on the line.
06096     if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus)) 
06097       aReflowStatus = NS_FRAME_COMPLETE;
06098   }
06099 
06100   // Remove the float from the reflow tree.
06101   if (aState.mReflowState.path)
06102     aState.mReflowState.path->RemoveChild(floatFrame);
06103 
06104   if (NS_FAILED(rv)) {
06105     return rv;
06106   }
06107 
06108   // Capture the margin information for the caller
06109   const nsMargin& m = brc.GetMargin();
06110   aFloatCache->mMargins.top = brc.GetTopMargin();
06111   aFloatCache->mMargins.right = m.right;
06112   // Only last in flows get a bottom margin
06113   if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
06114     brc.GetCarriedOutBottomMargin().Include(m.bottom);
06115   }
06116   aFloatCache->mMargins.bottom = brc.GetCarriedOutBottomMargin().get();
06117   aFloatCache->mMargins.left = m.left;
06118 
06119   const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
06120   aFloatCache->mCombinedArea = metrics.mOverflowArea;
06121 
06122   // Set the rect, make sure the view is properly sized and positioned,
06123   // and tell the frame we're done reflowing it
06124   // XXXldb This seems like the wrong place to be doing this -- shouldn't
06125   // we be doing this in nsBlockReflowState::FlowAndPlaceFloat after
06126   // we've positioned the float, and shouldn't we be doing the equivalent
06127   // of |::PlaceFrameView| here?
06128   floatFrame->SetSize(nsSize(metrics.width, metrics.height));
06129   if (floatFrame->HasView()) {
06130     nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, floatFrame,
06131                                                floatFrame->GetView(),
06132                                                &metrics.mOverflowArea,
06133                                                NS_FRAME_NO_MOVE_VIEW);
06134   }
06135   // Pass floatRS so the frame hierarchy can be used (redoFloatRS has the same hierarchy)  
06136   floatFrame->DidReflow(aState.mPresContext, &floatRS,
06137                         NS_FRAME_REFLOW_FINISHED);
06138 
06139   // If we computed it, then stash away the max-element-width for later
06140   if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
06141     nscoord mew = brc.GetMaxElementWidth() +
06142                   aFloatCache->mMargins.left + aFloatCache->mMargins.right;
06143 
06144     // This is all we need to do to include the float
06145     // max-element-width since we don't require that we end up with
06146     // content next to floats.
06147     aState.UpdateMaxElementWidth(mew); // fix for bug 13553
06148 
06149     // Allow the float width to be restored in state recovery.
06150     aFloatCache->mMaxElementWidth = mew;
06151   }
06152 #ifdef NOISY_FLOAT
06153   printf("end ReflowFloat %p, sized to %d,%d\n",
06154          floatFrame, metrics.width, metrics.height);
06155 #endif
06156 
06157   // If the placeholder was continued and its first-in-flow was followed by a 
06158   // <BR>, then cache the <BR>'s break type in aState.mFloatBreakType so that
06159   // the next frame after the placeholder can combine that break type with its own
06160   nsIFrame* prevPlaceholder = aPlaceholder->GetPrevInFlow();
06161   if (prevPlaceholder) {
06162     // the break occurs only after the last continued placeholder
06163     PRBool lastPlaceholder = PR_TRUE;
06164     nsIFrame* next = aPlaceholder->GetNextSibling();
06165     if (next) {
06166       if (nsLayoutAtoms::placeholderFrame == next->GetType()) {
06167         lastPlaceholder = PR_FALSE;
06168       }
06169     }
06170     if (lastPlaceholder) {
06171       // get the containing block of prevPlaceholder which is our prev-in-flow
06172       if (mPrevInFlow) {
06173         // get the break type of the last line in mPrevInFlow
06174         line_iterator endLine = --((nsBlockFrame*)mPrevInFlow)->end_lines();
06175         if (endLine->HasFloatBreakAfter()) {
06176           aState.mFloatBreakType = endLine->GetBreakTypeAfter();
06177         }
06178       }
06179       else NS_ASSERTION(PR_FALSE, "no prev in flow");
06180     }
06181   }
06182   return NS_OK;
06183 }
06184 
06186 // Painting, event handling
06187 
06188 PRIntn
06189 nsBlockFrame::GetSkipSides() const
06190 {
06191   PRIntn skip = 0;
06192   if (nsnull != mPrevInFlow) {
06193     skip |= 1 << NS_SIDE_TOP;
06194   }
06195   if (nsnull != mNextInFlow) {
06196     skip |= 1 << NS_SIDE_BOTTOM;
06197   }
06198   return skip;
06199 }
06200 
06201 #ifdef DEBUG
06202 static void ComputeCombinedArea(nsLineList& aLines,
06203                                 nscoord aWidth, nscoord aHeight,
06204                                 nsRect& aResult)
06205 {
06206   nscoord xa = 0, ya = 0, xb = aWidth, yb = aHeight;
06207   for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end();
06208        line != line_end;
06209        ++line) {
06210     // Compute min and max x/y values for the reflowed frame's
06211     // combined areas
06212     nsRect lineCombinedArea(line->GetCombinedArea());
06213     nscoord x = lineCombinedArea.x;
06214     nscoord y = lineCombinedArea.y;
06215     nscoord xmost = x + lineCombinedArea.width;
06216     nscoord ymost = y + lineCombinedArea.height;
06217     if (x < xa) {
06218       xa = x;
06219     }
06220     if (xmost > xb) {
06221       xb = xmost;
06222     }
06223     if (y < ya) {
06224       ya = y;
06225     }
06226     if (ymost > yb) {
06227       yb = ymost;
06228     }
06229   }
06230 
06231   aResult.x = xa;
06232   aResult.y = ya;
06233   aResult.width = xb - xa;
06234   aResult.height = yb - ya;
06235 }
06236 #endif
06237 
06238 NS_IMETHODIMP
06239 nsBlockFrame::IsVisibleForPainting(nsPresContext *     aPresContext, 
06240                                    nsIRenderingContext& aRenderingContext,
06241                                    PRBool               aCheckVis,
06242                                    PRBool*              aIsVisible)
06243 {
06244   // first check to see if we are visible
06245   if (aCheckVis) {
06246     if (!GetStyleVisibility()->IsVisible()) {
06247       *aIsVisible = PR_FALSE;
06248       return NS_OK;
06249     }
06250   }
06251 
06252   // Start by assuming we are visible and need to be painted
06253   *aIsVisible = PR_TRUE;
06254 
06255   // NOTE: GetSelectionforVisCheck checks the pagination to make sure we are printing
06256   // In otherwords, the selection will ALWAYS be null if we are not printing, meaning
06257   // the visibility will be TRUE in that case
06258   nsCOMPtr<nsISelection> selection;
06259   nsresult rv = GetSelectionForVisCheck(aPresContext, getter_AddRefs(selection));
06260   if (NS_SUCCEEDED(rv) && selection) {
06261     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
06262 
06263     nsCOMPtr<nsIDOMHTMLHtmlElement> html(do_QueryInterface(mContent));
06264     nsCOMPtr<nsIDOMHTMLBodyElement> body(do_QueryInterface(mContent));
06265 
06266     if (!html && !body) {
06267       rv = selection->ContainsNode(node, PR_TRUE, aIsVisible);
06268     }
06269   }
06270 
06271   return rv;
06272 }
06273 
06274 /* virtual */ void
06275 nsBlockFrame::PaintTextDecorationLines(nsIRenderingContext& aRenderingContext, 
06276                                        nscolor aColor, 
06277                                        nscoord aOffset, 
06278                                        nscoord aAscent, 
06279                                        nscoord aSize) 
06280 {
06281   aRenderingContext.SetColor(aColor);
06282   for (nsLineList::iterator line = begin_lines(), line_start = line,
06283          line_end = end_lines(); 
06284        line != line_end; ++line) {
06285     if (!line->IsBlock()) {
06286       nscoord start = line->mBounds.x;
06287       nscoord width = line->mBounds.width;
06288 
06289       if (line == line_start) {
06290         // Adjust for the text-indent.  See similar code in
06291         // nsLineLayout::BeginLineReflow.
06292         nscoord indent = 0;
06293         const nsStyleText* styleText = GetStyleText();
06294         nsStyleUnit unit = styleText->mTextIndent.GetUnit();
06295         if (eStyleUnit_Coord == unit) {
06296           indent = styleText->mTextIndent.GetCoordValue();
06297         } else if (eStyleUnit_Percent == unit) {
06298           // It's a percentage of the containing block width.
06299           nsIFrame* containingBlock =
06300             nsHTMLReflowState::GetContainingBlockFor(this);
06301           NS_ASSERTION(containingBlock, "Must have containing block!");
06302           indent = nscoord(styleText->mTextIndent.GetPercentValue() *
06303                            containingBlock->GetRect().width);
06304         }
06305 
06306         // Adjust the start position and the width of the decoration by the
06307         // value of the indent.  Note that indent can be negative; that's OK.
06308         // It'll just increase the width (which can also happen to be
06309         // negative!).
06310         start += indent;
06311         width -= indent;
06312       }
06313       
06314       // Only paint if we have a positive width
06315       if (width > 0) {
06316         aRenderingContext.FillRect(start,
06317                                    line->mBounds.y + line->GetAscent() - aOffset, 
06318                                    width, aSize);
06319       }
06320     }
06321   }
06322 }
06323 
06324 NS_IMETHODIMP
06325 nsBlockFrame::Paint(nsPresContext*      aPresContext,
06326                     nsIRenderingContext& aRenderingContext,
06327                     const nsRect&        aDirtyRect,
06328                     nsFramePaintLayer    aWhichLayer,
06329                     PRUint32             aFlags)
06330 {
06331   if (NS_FRAME_IS_UNFLOWABLE & mState) {
06332     return NS_OK;
06333   }
06334 
06335 #ifdef DEBUG
06336   if (gNoisyDamageRepair) {
06337     if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
06338       PRInt32 depth = GetDepth();
06339       nsRect ca;
06340       ::ComputeCombinedArea(mLines, mRect.width, mRect.height, ca);
06341       nsFrame::IndentBy(stdout, depth);
06342       ListTag(stdout);
06343       printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
06344              mRect.x, mRect.y, mRect.width, mRect.height,
06345              aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height,
06346              ca.x, ca.y, ca.width, ca.height);
06347     }
06348   }
06349 #endif  
06350 
06351   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
06352     PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
06353   }
06354 
06355   PRBool paintingSuppressed = PR_FALSE;  
06356   aPresContext->PresShell()->IsPaintingSuppressed(&paintingSuppressed);
06357   if (paintingSuppressed)
06358     return NS_OK;
06359 
06360   const nsStyleDisplay* disp = GetStyleDisplay();
06361 
06362   // If overflow is hidden then set the clip rect so that children don't
06363   // leak out of us. Note that because overflow'-clip' only applies to
06364   // the content area we do this after painting the border and background
06365   if (NS_STYLE_OVERFLOW_CLIP == disp->mOverflowX) {
06366     aRenderingContext.PushState();
06367     SetOverflowClipRect(aRenderingContext);
06368   }
06369 
06370   // Child elements have the opportunity to override the visibility
06371   // property and display even if the parent is hidden
06372   if (NS_FRAME_PAINT_LAYER_FLOATS == aWhichLayer) {
06373     PaintFloats(aPresContext, aRenderingContext, aDirtyRect);
06374   }
06375 
06376   PaintDecorationsAndChildren(aPresContext, aRenderingContext,
06377                               aDirtyRect, aWhichLayer, PR_TRUE);
06378 
06379   if (NS_STYLE_OVERFLOW_CLIP == disp->mOverflowX)
06380     aRenderingContext.PopState();
06381 
06382 #if 0
06383   if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
06384     // Render the bands in the spacemanager
06385     nsSpaceManager* sm = mSpaceManager;
06386 
06387     if (nsnull != sm) {
06388       nsBlockBandData band;
06389       band.Init(sm, nsSize(mRect.width, mRect.height));
06390       nscoord y = 0;
06391       while (y < mRect.height) {
06392         nsRect availArea;
06393         band.GetAvailableSpace(y, PR_FALSE, availArea);
06394   
06395         // Render a box and a diagonal line through the band
06396         aRenderingContext.SetColor(NS_RGB(0,255,0));
06397         aRenderingContext.DrawRect(0, availArea.y,
06398                                    mRect.width, availArea.height);
06399         aRenderingContext.DrawLine(0, availArea.y,
06400                                    mRect.width, availArea.YMost());
06401   
06402         // Render boxes and opposite diagonal lines around the
06403         // unavailable parts of the band.
06404         PRInt32 i;
06405         for (i = 0; i < band.GetTrapezoidCount(); i++) {
06406           const nsBandTrapezoid* trapezoid = band.GetTrapezoid(i);
06407           if (nsBandTrapezoid::Available != trapezoid->mState) {
06408             nsRect r = trapezoid->GetRect();
06409             if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
06410               aRenderingContext.SetColor(NS_RGB(0,255,128));
06411             }
06412             else {
06413               aRenderingContext.SetColor(NS_RGB(128,255,0));
06414             }
06415             aRenderingContext.DrawRect(r);
06416             aRenderingContext.DrawLine(r.x, r.YMost(), r.XMost(), r.y);
06417           }
06418         }
06419         y = availArea.YMost();
06420       }
06421     }
06422   }
06423 #endif
06424 
06425   return NS_OK;
06426 }
06427 
06428 void
06429 nsBlockFrame::PaintFloats(nsPresContext* aPresContext,
06430                           nsIRenderingContext& aRenderingContext,
06431                           const nsRect& aDirtyRect)
06432 {
06433   for (nsIFrame* floatFrame = mFloats.FirstChild();
06434        floatFrame;
06435        floatFrame = floatFrame->GetNextSibling()) {
06436     PaintChild(aPresContext, aRenderingContext, aDirtyRect,
06437                floatFrame, NS_FRAME_PAINT_LAYER_BACKGROUND);
06438     PaintChild(aPresContext, aRenderingContext, aDirtyRect,
06439                floatFrame, NS_FRAME_PAINT_LAYER_FLOATS);
06440     PaintChild(aPresContext, aRenderingContext, aDirtyRect,
06441                floatFrame, NS_FRAME_PAINT_LAYER_FOREGROUND);
06442   }
06443 }
06444 
06445 #ifdef DEBUG
06446 static void DebugOutputDrawLine(nsFramePaintLayer aWhichLayer, PRInt32 aDepth,
06447                                 nsLineBox* aLine, PRBool aDrawn) {
06448   if (nsBlockFrame::gNoisyDamageRepair &&
06449       (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) {
06450     nsFrame::IndentBy(stdout, aDepth+1);
06451     nsRect lineArea = aLine->GetCombinedArea();
06452     printf("%s line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
06453            aDrawn ? "draw" : "skip",
06454            NS_STATIC_CAST(void*, aLine),
06455            aLine->mBounds.x, aLine->mBounds.y,
06456            aLine->mBounds.width, aLine->mBounds.height,
06457            lineArea.x, lineArea.y,
06458            lineArea.width, lineArea.height);
06459   }
06460 }
06461 #endif
06462 
06463 static inline void
06464 PaintLine(const nsRect& aLineArea, const nsRect& aDirtyRect,
06465           nsBlockFrame::line_iterator& aLine, PRInt32 aDepth,
06466           PRInt32& aDrawnLines, nsPresContext* aPresContext, 
06467           nsIRenderingContext& aRenderingContext,
06468           nsFramePaintLayer aWhichLayer, nsBlockFrame* aFrame) {
06469   // If the line's combined area (which includes child frames that
06470   // stick outside of the line's bounding box or our bounding box)
06471   // intersects the dirty rect then paint the line.
06472   if (aLineArea.Intersects(aDirtyRect)) {
06473 #ifdef DEBUG
06474     DebugOutputDrawLine(aWhichLayer, aDepth, aLine.get(), PR_TRUE);
06475     if (nsBlockFrame::gLamePaintMetrics) {
06476       aDrawnLines++;
06477     }
06478 #endif
06479     nsIFrame* kid = aLine->mFirstChild;
06480     PRInt32 n = aLine->GetChildCount();
06481     while (--n >= 0) {
06482       aFrame->PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid,
06483                          aWhichLayer);
06484       kid = kid->GetNextSibling();
06485     }
06486   }
06487 #ifdef DEBUG
06488   else {
06489     DebugOutputDrawLine(aWhichLayer, aDepth, aLine.get(), PR_FALSE);
06490   }
06491 #endif  
06492 }
06493 
06494 void
06495 nsBlockFrame::PaintChildren(nsPresContext*      aPresContext,
06496                             nsIRenderingContext& aRenderingContext,
06497                             const nsRect&        aDirtyRect,
06498                             nsFramePaintLayer    aWhichLayer,
06499                             PRUint32             aFlags)
06500 {
06501   PRInt32 drawnLines; // Will only be used if set (gLamePaintMetrics).
06502   PRInt32 depth = 0;
06503 #ifdef DEBUG
06504   if (gNoisyDamageRepair) {
06505     if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
06506       depth = GetDepth();
06507     }
06508   }
06509   PRTime start = LL_ZERO; // Initialize these variables to silence the compiler.
06510   if (gLamePaintMetrics) {
06511     start = PR_Now();
06512     drawnLines = 0;
06513   }
06514 #endif
06515 
06516   nsLineBox* cursor = GetFirstLineContaining(aDirtyRect.y);
06517   line_iterator line_end = end_lines();
06518 
06519   if (cursor) {
06520     for (line_iterator line = mLines.begin(cursor);
06521          line != line_end;
06522          ++line) {
06523       nsRect lineArea = line->GetCombinedArea();
06524       if (!lineArea.IsEmpty()) {
06525         // Because we have a cursor, the combinedArea.ys are non-decreasing.
06526         // Once we've passed aDirtyRect.YMost(), we can never see it again.
06527         if (lineArea.y >= aDirtyRect.YMost()) {
06528           break;
06529         }
06530         PaintLine(lineArea, aDirtyRect, line, depth, drawnLines, aPresContext,
06531                   aRenderingContext, aWhichLayer, this);
06532       }
06533     }
06534   } else {
06535     PRBool nonDecreasingYs = PR_TRUE;
06536     PRInt32 lineCount = 0;
06537     nscoord lastY = PR_INT32_MIN;
06538     nscoord lastYMost = PR_INT32_MIN;
06539     for (line_iterator line = begin_lines();
06540          line != line_end;
06541          ++line) {
06542       nsRect lineArea = line->GetCombinedArea();
06543       if (!lineArea.IsEmpty()) {
06544         if (lineArea.y < lastY
06545             || lineArea.YMost() < lastYMost) {
06546           nonDecreasingYs = PR_FALSE;
06547         }
06548         lastY = lineArea.y;
06549         lastYMost = lineArea.YMost();
06550 
06551         PaintLine(lineArea, aDirtyRect, line, depth, drawnLines, aPresContext,
06552                   aRenderingContext, aWhichLayer, this);
06553       }
06554       lineCount++;
06555     }
06556 
06557     if (nonDecreasingYs && lineCount >= MIN_LINES_NEEDING_CURSOR) {
06558       SetupLineCursor();
06559     }
06560   }
06561 
06562   if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
06563     if ((nsnull != mBullet) && HaveOutsideBullet()) {
06564       // Paint outside bullets manually
06565       PaintChild(aPresContext, aRenderingContext, aDirtyRect, mBullet,
06566                  aWhichLayer);
06567     }
06568   }
06569 
06570 #ifdef DEBUG
06571   if (gLamePaintMetrics) {
06572     PRTime end = PR_Now();
06573 
06574     PRInt32 numLines = mLines.size();
06575     if (!numLines) numLines = 1;
06576     PRTime lines, deltaPerLine, delta;
06577     LL_I2L(lines, numLines);
06578     LL_SUB(delta, end, start);
06579     LL_DIV(deltaPerLine, delta, lines);
06580 
06581     ListTag(stdout);
06582     char buf[400];
06583     PR_snprintf(buf, sizeof(buf),
06584                 ": %lld elapsed (%lld per line) lines=%d drawn=%d skip=%d",
06585                 delta, deltaPerLine,
06586                 numLines, drawnLines, numLines - drawnLines);
06587     printf("%s\n", buf);
06588   }
06589 #endif
06590 }
06591 
06592 // XXXldb Does this handle all overlap cases correctly?  (How?)
06593 nsresult
06594 nsBlockFrame::GetClosestLine(nsILineIterator *aLI,
06595                              const nsPoint &aPoint,
06596                              PRInt32 &aClosestLine)
06597 {
06598   if (!aLI)
06599     return NS_ERROR_NULL_POINTER;
06600 
06601   nsRect rect;
06602   PRInt32 numLines;
06603   PRInt32 lineFrameCount;
06604   nsIFrame *firstFrame;
06605   PRUint32 flags;
06606 
06607   nsresult result = aLI->GetNumLines(&numLines);
06608 
06609   if (NS_FAILED(result) || numLines < 0)
06610     return NS_OK;//do not handle
06611 
06612   PRInt32 shifted = numLines;
06613   PRInt32 start = 0, midpoint = 0;
06614   PRInt32 y = 0;
06615 
06616   while(shifted > 0)
06617   {
06618     // Cut the number of lines to look at in half and
06619     // calculate the midpoint of the region we are looking at.
06620 
06621     shifted >>= 1; //divide by 2
06622     midpoint  = start + shifted;
06623 
06624     // Get the dimensions of the line that is at the half
06625     // point of the region we are looking at.
06626 
06627     result = aLI->GetLine(midpoint, &firstFrame, &lineFrameCount,rect,&flags);
06628     if (NS_FAILED(result))
06629       break;//do not handle
06630 
06631     // Check to see if our point lies with the line's Y bounds.
06632 
06633     y = aPoint.y - rect.y;
06634     if (y >=0 && (aPoint.y < (rect.y+rect.height)))
06635     {
06636       aClosestLine = midpoint; //spot on!
06637       return NS_OK;
06638     }
06639 
06640     if (y > 0)
06641     {
06642       // If we get here, no match was found above, so aPoint.y must
06643       // be greater than the Y bounds of the current line rect. Move
06644       // our starting point just beyond the midpoint of the current region.
06645 
06646       start = midpoint;
06647 
06648       if (numLines > 1 && start < (numLines - 1))
06649         ++start;
06650       else
06651         shifted = 0;
06652     }
06653   }
06654 
06655   // Make sure we don't go off the edge in either direction!
06656 
06657   NS_ASSERTION(start >=0 && start <= numLines, "Invalid start calculated.");
06658 
06659   if (start < 0)
06660     start = 0;
06661   else if (start >= numLines)
06662     start = numLines - 1; 
06663 
06664   aClosestLine = start; //close as we could come
06665 
06666   return NS_OK;
06667 }
06668 
06669 NS_IMETHODIMP
06670 nsBlockFrame::HandleEvent(nsPresContext* aPresContext, 
06671                           nsGUIEvent*     aEvent,
06672                           nsEventStatus*  aEventStatus)
06673 {
06674 
06675   nsresult result;
06676   nsIPresShell *shell = nsnull;
06677   if (aEvent->message == NS_MOUSE_MOVE) {
06678     shell = aPresContext->GetPresShell();
06679     if (!shell)
06680       return NS_OK;
06681     nsCOMPtr<nsIFrameSelection> frameSelection;
06682     PRBool mouseDown = PR_FALSE;
06683 //check to see if we need to ask the selection controller..
06684     if (mState & NS_FRAME_INDEPENDENT_SELECTION)
06685     {
06686       nsCOMPtr<nsISelectionController> selCon;
06687       result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
06688       if (NS_FAILED(result) || !selCon)
06689         return result?result:NS_ERROR_FAILURE;
06690       frameSelection = do_QueryInterface(selCon);
06691     }
06692     else
06693       frameSelection = shell->FrameSelection();
06694     if (!frameSelection || NS_FAILED(frameSelection->GetMouseDownState(&mouseDown)) || !mouseDown) 
06695       return NS_OK;//do not handle
06696   }
06697 
06698   if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN || aEvent->message == NS_MOUSE_MOVE ||
06699     aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK ) {
06700 
06701     nsMouseEvent *me = (nsMouseEvent *)aEvent;
06702 
06703     nsIFrame *resultFrame = nsnull;//this will be passed the handle event when we 
06704                                    //can tell who to pass it to
06705     nsIFrame *mainframe = this;
06706     shell = aPresContext->GetPresShell();
06707     if (!shell)
06708       return NS_OK;
06709     nsCOMPtr<nsILineIterator> it( do_QueryInterface(mainframe, &result) );
06710     nsPeekOffsetStruct pos;
06711     nsPoint viewOffset;
06712     nsIView* parentWithView;
06713     GetOffsetFromView(viewOffset, &parentWithView);
06714     // The offset returned by GetOffsetFromView is not trustworthy.
06715     // It's just the sum of frame positions and is not the true
06716     // geometric offset. So recalculate the true geometric offset.
06717     NS_ASSERTION(nsLayoutUtils::GetFrameFor(parentWithView),
06718                  "GetOffsetFromView shouldn't be returning a frameless view");
06719     viewOffset = GetOffsetTo(nsLayoutUtils::GetFrameFor(parentWithView));
06720 
06721     while(NS_OK == result)
06722     { //we are starting aloop to allow us to "drill down to the one we want"
06723       PRInt32 closestLine;
06724 
06725       // aEvent->point is relative to our view. We need to make it relative to
06726       // mainframe, via this frame.
06727       if (NS_FAILED(result = GetClosestLine(it,
06728           aEvent->point - viewOffset - mainframe->GetOffsetTo(this), closestLine)))
06729         return result;
06730       
06731       //we will now ask where to go. if we cant find what we want"aka another block frame" 
06732       //we drill down again
06733       pos.mShell = shell;
06734       pos.mDirection = eDirNext;
06735       pos.mDesiredX = aEvent->point.x;
06736       pos.mScrollViewStop = PR_FALSE;
06737       pos.mIsKeyboardSelect = PR_FALSE;
06738       result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext,
06739                                           &pos,
06740                                           mainframe, 
06741                                           closestLine-1, 
06742                                           0
06743                                           );
06744       
06745       if (NS_SUCCEEDED(result) && pos.mResultFrame){
06746         if (result == NS_OK)
06747           it = do_QueryInterface(pos.mResultFrame, &result);//if this fails thats ok
06748         resultFrame = pos.mResultFrame;
06749         mainframe = resultFrame;
06750       }
06751       else
06752         break;//time to go nothing was found
06753     }
06754     //end while loop. if nssucceeded resutl then keep going that means
06755     //we have successfully hit another block frame and we should keep going.
06756 
06757 
06758     if (resultFrame)
06759     {
06760       // Translate aEvent->point to resultFrame's closest view (bug 180015).
06761       nsPoint tmp;
06762       nsIView* resultFrameParentView;
06763       resultFrame->GetOffsetFromView(tmp, &resultFrameParentView);
06764       if (parentWithView != resultFrameParentView && resultFrameParentView) {
06765         aEvent->point -= resultFrameParentView->GetOffsetTo(parentWithView);
06766       }
06767 
06768       if (NS_POSITION_BEFORE_TABLE == result)
06769       {
06770         nsCOMPtr<nsISelectionController> selCon;
06771         result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
06772         //get the selection controller
06773         if (NS_SUCCEEDED(result) && selCon) 
06774         {
06775           PRInt16 displayresult;
06776           selCon->GetDisplaySelection(&displayresult);
06777           if (displayresult == nsISelectionController::SELECTION_OFF)
06778             return NS_OK;//nothing to do we cannot affect selection from here
06779         }
06780         PRBool mouseDown = aEvent->message == NS_MOUSE_MOVE;
06781         result = shell->FrameSelection()->HandleClick(pos.mResultContent,
06782                                                       pos.mContentOffset, 
06783                                                       pos.mContentOffsetEnd,
06784                                                       mouseDown || me->isShift,
06785                                                       PR_FALSE,
06786                                                       pos.mPreferLeft);
06787       }
06788       else
06789         result = resultFrame->HandleEvent(aPresContext, aEvent, aEventStatus);//else let the frame/container do what it needs
06790       /* Note that the above call to HandleEvent may capture the
06791          mouse. If so, don't try to capture again. */
06792       if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext))
06793           CaptureMouse(aPresContext, PR_TRUE);
06794       return result;
06795     }
06796     else
06797     {
06798       return NS_OK; //just stop it
06799     }
06800   }
06801   return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
06802 }
06803 
06804 #ifdef ACCESSIBILITY
06805 NS_IMETHODIMP nsBlockFrame::GetAccessible(nsIAccessible** aAccessible)
06806 {
06807   *aAccessible = nsnull;
06808   nsCOMPtr<nsIAccessibilityService> accService = 
06809     do_GetService("@mozilla.org/accessibilityService;1");
06810   NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
06811 
06812   // treat <hr> as block element instead of inline.
06813   if (mContent->Tag() == nsHTMLAtoms::hr) {
06814     return accService->CreateHTMLHRAccessible(NS_STATIC_CAST(nsIFrame*, this), aAccessible);
06815   }
06816 
06817   nsPresContext *aPresContext = GetPresContext();
06818   if (!mBullet || !aPresContext) {
06819     return NS_ERROR_FAILURE;
06820   }
06821 
06822   const nsStyleList* myList = GetStyleList();
06823   nsAutoString bulletText;
06824   if (myList->mListStyleImage || myList->mListStyleType == NS_STYLE_LIST_STYLE_DISC ||
06825       myList->mListStyleType == NS_STYLE_LIST_STYLE_CIRCLE ||
06826       myList->mListStyleType == NS_STYLE_LIST_STYLE_SQUARE) {
06827     bulletText.Assign(PRUnichar(0x2022));; // Unicode bullet character
06828   }
06829   else if (myList->mListStyleType != NS_STYLE_LIST_STYLE_NONE) {
06830     mBullet->GetListItemText(*myList, bulletText);
06831   }
06832 
06833   return accService->CreateHTMLLIAccessible(NS_STATIC_CAST(nsIFrame*, this), 
06834                                             NS_STATIC_CAST(nsIFrame*, mBullet), 
06835                                             bulletText,
06836                                             aAccessible);
06837 }
06838 #endif
06839 
06840 void nsBlockFrame::ClearLineCursor() {
06841   if (!(GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR)) {
06842     return;
06843   }
06844 
06845   UnsetProperty(nsLayoutAtoms::lineCursorProperty);
06846   RemoveStateBits(NS_BLOCK_HAS_LINE_CURSOR);
06847 }
06848 
06849 void nsBlockFrame::SetupLineCursor() {
06850   if (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR
06851       || mLines.empty()) {
06852     return;
06853   }
06854    
06855   SetProperty(nsLayoutAtoms::lineCursorProperty,
06856               mLines.front(), nsnull);
06857   AddStateBits(NS_BLOCK_HAS_LINE_CURSOR);
06858 }
06859 
06860 nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y) {
06861   if (!(GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR)) {
06862     return nsnull;
06863   }
06864 
06865   nsLineBox* property = NS_STATIC_CAST(nsLineBox*,
06866     GetProperty(nsLayoutAtoms::lineCursorProperty));
06867   line_iterator cursor = mLines.begin(property);
06868   nsRect cursorArea = cursor->GetCombinedArea();
06869 
06870   while ((cursorArea.IsEmpty() || cursorArea.YMost() > y)
06871          && cursor != mLines.front()) {
06872     cursor = cursor.prev();
06873     cursorArea = cursor->GetCombinedArea();
06874   }
06875   while ((cursorArea.IsEmpty() || cursorArea.YMost() <= y)
06876          && cursor != mLines.back()) {
06877     cursor = cursor.next();
06878     cursorArea = cursor->GetCombinedArea();
06879   }
06880 
06881   if (cursor.get() != property) {
06882     SetProperty(nsLayoutAtoms::lineCursorProperty,
06883                 cursor.get(), nsnull);
06884   }
06885 
06886   return cursor.get();
06887 }
06888 
06889 static inline void
06890 GetFrameFromLine(const nsRect& aLineArea, const nsPoint& aTmp,
06891                  nsBlockFrame::line_iterator& aLine,
06892                  nsFramePaintLayer aWhichLayer, nsIFrame** aFrame) {
06893   if (aLineArea.Contains(aTmp)) {
06894     nsIFrame* kid = aLine->mFirstChild;
06895     PRInt32 n = aLine->GetChildCount();
06896     while (--n >= 0) {
06897       nsIFrame *hit;
06898       nsresult rv = kid->GetFrameForPoint(aTmp, aWhichLayer, &hit);
06899       
06900       if (NS_SUCCEEDED(rv) && hit) {
06901         *aFrame = hit;
06902       }
06903       kid = kid->GetNextSibling();
06904     }
06905   }
06906 }
06907 
06908 // Optimized function that uses line combined areas to skip lines
06909 // we know can't contain the point
06910 nsresult
06911 nsBlockFrame::GetFrameForPointUsing(const nsPoint& aPoint,
06912                                     nsIAtom*       aList,
06913                                     nsFramePaintLayer aWhichLayer,
06914                                     PRBool         aConsiderSelf,
06915                                     nsIFrame**     aFrame)
06916 {
06917   if (aList) {
06918     return nsContainerFrame::GetFrameForPointUsing(aPoint,
06919       aList, aWhichLayer, aConsiderSelf, aFrame);
06920   }
06921 
06922   PRBool inThisFrame = mRect.Contains(aPoint);
06923 
06924   if (! ((mState & NS_FRAME_OUTSIDE_CHILDREN) || inThisFrame ) ) {
06925     return NS_ERROR_FAILURE;
06926   }
06927 
06928   *aFrame = nsnull;
06929   nsPoint tmp(aPoint.x - mRect.x, aPoint.y - mRect.y);
06930 
06931   nsPoint originOffset;
06932   nsIView *view = nsnull;
06933   nsresult rv = GetOriginToViewOffset(originOffset, &view);
06934 
06935   if (NS_SUCCEEDED(rv) && view)
06936     tmp += originOffset;
06937 
06938   nsLineBox* cursor = GetFirstLineContaining(tmp.y);
06939   line_iterator line_end = end_lines();
06940 
06941   if (cursor) {
06942     // This is the fast path for large blocks
06943     for (line_iterator line = mLines.begin(cursor);
06944          line != line_end;
06945          ++line) {
06946       nsRect lineArea = line->GetCombinedArea();
06947       // Because we have a cursor, the combinedArea.ys are non-decreasing.
06948       // Once we've passed tmp.y, we can never see it again.
06949       if (!lineArea.IsEmpty()) {
06950         if (lineArea.y > tmp.y) {
06951           break;
06952         }
06953         GetFrameFromLine(lineArea, tmp, line, aWhichLayer, aFrame);
06954       }
06955     }
06956   } else {
06957     PRBool nonDecreasingYs = PR_TRUE;
06958     PRInt32 lineCount = 0;
06959     nscoord lastY = PR_INT32_MIN;
06960     nscoord lastYMost = PR_INT32_MIN;
06961     for (line_iterator line = mLines.begin();
06962          line != line_end;
06963          ++line) {
06964       nsRect lineArea = line->GetCombinedArea();
06965       if (!lineArea.IsEmpty()) {
06966         if (lineArea.y < lastY
06967             || lineArea.YMost() < lastYMost) {
06968           nonDecreasingYs = PR_FALSE;
06969         }
06970         lastY = lineArea.y;
06971         lastYMost = lineArea.YMost();
06972 
06973         GetFrameFromLine(lineArea, tmp, line, aWhichLayer, aFrame);
06974       }
06975       lineCount++;
06976     }
06977 
06978     if (nonDecreasingYs && lineCount >= MIN_LINES_NEEDING_CURSOR) {
06979       SetupLineCursor();
06980     }
06981   }
06982   
06983   if (*aFrame) {
06984     return NS_OK;
06985   }
06986 
06987   if ( inThisFrame && aConsiderSelf ) {
06988     if (GetStyleVisibility()->IsVisible()) {
06989       *aFrame = this;
06990       return NS_OK;
06991     }
06992   }
06993 
06994   return NS_ERROR_FAILURE;
06995 }
06996 
06997 NS_IMETHODIMP
06998 nsBlockFrame::GetFrameForPoint(const nsPoint& aPoint,
06999                                nsFramePaintLayer aWhichLayer,
07000                                nsIFrame** aFrame)
07001 {
07002   nsresult rv;
07003 
07004   switch (aWhichLayer) {
07005     case NS_FRAME_PAINT_LAYER_FOREGROUND:
07006       rv = GetFrameForPointUsing(aPoint, nsnull,
07007                                  NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE,
07008                                  aFrame);
07009       if (NS_OK == rv) {
07010         return NS_OK;
07011       }
07012       if (nsnull != mBullet) {
07013         rv = GetFrameForPointUsing(aPoint, nsLayoutAtoms::bulletList,
07014                                    NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE,
07015                                    aFrame);
07016       }
07017       return rv;
07018       break;
07019 
07020     case NS_FRAME_PAINT_LAYER_FLOATS:
07021       // we painted our floats before our children, and thus
07022       // we should check floats within children first
07023       rv = GetFrameForPointUsing(aPoint, nsnull,
07024                                  NS_FRAME_PAINT_LAYER_FLOATS, PR_FALSE,
07025                                  aFrame);
07026       if (NS_OK == rv) {
07027         return NS_OK;
07028       }
07029       if (mFloats.NotEmpty()) {
07030         return GetFrameForPointUsing(aPoint, nsLayoutAtoms::floatList,
07031                                      NS_FRAME_PAINT_LAYER_ALL, PR_FALSE,
07032                                      aFrame);
07033       } else {
07034         return NS_ERROR_FAILURE;
07035       }
07036       break;
07037 
07038     case NS_FRAME_PAINT_LAYER_BACKGROUND:
07039       // we're a block, so PR_TRUE for consider self
07040       return GetFrameForPointUsing(aPoint, nsnull,
07041                                    NS_FRAME_PAINT_LAYER_BACKGROUND, PR_TRUE,
07042                                    aFrame);
07043       break;
07044   }
07045   // we shouldn't get here
07046   NS_ASSERTION(PR_FALSE, "aWhichLayer was not understood");
07047   return NS_ERROR_FAILURE;
07048 }
07049 
07050 NS_IMETHODIMP
07051 nsBlockFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
07052 {
07053 #ifdef DEBUG
07054   if (gNoisyReflow) {
07055     IndentBy(stdout, gNoiseIndent);
07056     ListTag(stdout);
07057     printf(": ReflowDirtyChild (");
07058     if (aChild)
07059       nsFrame::ListTag(stdout, aChild);
07060     else
07061       printf("null");
07062     printf(")\n");
07063   }
07064   AutoNoisyIndenter indent(gNoisyReflow);
07065 #endif
07066 
07067   if (aChild) {
07068     // See if the child is absolutely positioned
07069     if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
07070       const nsStyleDisplay* disp = aChild->GetStyleDisplay();
07071 
07072       if (disp->IsAbsolutelyPositioned()) {
07073         // Generate a reflow command to reflow our dirty absolutely
07074         // positioned child frames.
07075         // XXX Note that we don't currently try and coalesce the reflow commands,
07076         // although we should. We can't use the NS_FRAME_HAS_DIRTY_CHILDREN
07077         // flag, because that's used to indicate whether in-flow children are
07078         // dirty...
07079         nsresult rv = aPresShell->
07080           AppendReflowCommand(this, eReflowType_ReflowDirty,
07081                               mAbsoluteContainer.GetChildListName());
07082 
07083 #ifdef DEBUG
07084         if (gNoisyReflow) {
07085           IndentBy(stdout, gNoiseIndent);
07086           printf("scheduled reflow command for absolutely positioned frame\n");
07087         }
07088 #endif
07089 
07090         return rv;
07091       }
07092     }
07093 
07094     if (aChild == mBullet && HaveOutsideBullet()) {
07095       // The bullet lives in the first line, unless the first line has
07096       // height 0 and there is a second line, in which case it lives
07097       // in the second line.
07098       line_iterator bulletLine = begin_lines();
07099       if (bulletLine != end_lines() && bulletLine->mBounds.height == 0 &&
07100           bulletLine != mLines.back()) {
07101         bulletLine = bulletLine.next();
07102       }
07103       
07104       if (bulletLine != end_lines()) {
07105         MarkLineDirty(bulletLine);
07106       }
07107       // otherwise we have an empty line list, and ReflowDirtyLines
07108       // will handle reflowing the bullet.
07109     } else {
07110       // Mark the line containing the child frame dirty.
07111       line_iterator fline = FindLineFor(aChild);
07112       if (fline != end_lines())
07113         MarkLineDirty(fline);
07114     }
07115   }
07116 
07117   // Either generate a reflow command to reflow the dirty child or 
07118   // coalesce this reflow request with an existing reflow command    
07119   if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
07120     // If this is the first dirty child, 
07121     // post a dirty children reflow command targeted at yourself
07122     mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
07123 
07124     aPresShell->AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull);
07125 
07126 #ifdef DEBUG
07127     if (gNoisyReflow) {
07128       IndentBy(stdout, gNoiseIndent);
07129       printf("scheduled reflow command targeted at self\n");
07130     }
07131 #endif
07132   }
07133   
07134   return NS_OK;
07135 }
07136 
07138 // Start Debugging
07139 
07140 #ifdef NS_DEBUG
07141 static PRBool
07142 InLineList(nsLineList& aLines, nsIFrame* aFrame)
07143 {
07144   for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end();
07145        line != line_end;
07146        ++line) {
07147     nsIFrame* frame = line->mFirstChild;
07148     PRInt32 n = line->GetChildCount();
07149     while (--n >= 0) {
07150       if (frame == aFrame) {
07151         return PR_TRUE;
07152       }
07153       frame = frame->GetNextSibling();
07154     }
07155   }
07156   return PR_FALSE;
07157 }
07158 
07159 static PRBool
07160 InSiblingList(nsLineList& aLines, nsIFrame* aFrame)
07161 {
07162   if (! aLines.empty()) {
07163     nsIFrame* frame = aLines.front()->mFirstChild;
07164     while (frame) {
07165       if (frame == aFrame) {
07166         return PR_TRUE;
07167       }
07168       frame = frame->GetNextSibling();
07169     }
07170   }
07171   return PR_FALSE;
07172 }
07173 
07174 PRBool
07175 nsBlockFrame::IsChild(nsIFrame* aFrame)
07176 {
07177   // Continued out-of-flows don't satisfy InLineList(), continued out-of-flows
07178   // and placeholders don't satisfy InSiblingList().
07179   PRBool skipLineList    = PR_FALSE;
07180   PRBool skipSiblingList = PR_FALSE;
07181   nsIFrame* prevInFlow = aFrame->GetPrevInFlow();
07182   PRBool isPlaceholder = nsLayoutAtoms::placeholderFrame == aFrame->GetType();
07183   if (prevInFlow) {
07184     nsFrameState state = aFrame->GetStateBits();
07185     skipLineList    = (state & NS_FRAME_OUT_OF_FLOW); 
07186     skipSiblingList = isPlaceholder || (state & NS_FRAME_OUT_OF_FLOW);
07187   }
07188 
07189   if (isPlaceholder) {
07190     nsFrameList* overflowPlaceholders = GetOverflowPlaceholders();
07191     if (overflowPlaceholders && overflowPlaceholders->ContainsFrame(aFrame)) {
07192       return PR_TRUE;
07193     }
07194   }
07195 
07196   if (aFrame->GetParent() != (nsIFrame*)this) {
07197     return PR_FALSE;
07198   }
07199   if ((skipLineList || InLineList(mLines, aFrame)) && 
07200       (skipSiblingList || InSiblingList(mLines, aFrame))) {
07201     return PR_TRUE;
07202   }
07203   nsLineList* overflowLines = GetOverflowLines();
07204   if (overflowLines && (skipLineList || InLineList(*overflowLines, aFrame)) && 
07205       (skipSiblingList || InSiblingList(*overflowLines, aFrame))) {
07206     return PR_TRUE;
07207   }
07208   return PR_FALSE;
07209 }
07210 
07211 NS_IMETHODIMP
07212 nsBlockFrame::VerifyTree() const
07213 {
07214   // XXX rewrite this
07215   return NS_OK;
07216 }
07217 #endif
07218 
07219 // End Debugging
07221 
07222 NS_IMETHODIMP
07223 nsBlockFrame::Init(nsPresContext*  aPresContext,
07224                    nsIContent*      aContent,
07225                    nsIFrame*        aParent,
07226                    nsStyleContext*  aContext,
07227                    nsIFrame*        aPrevInFlow)
07228 {
07229   if (aPrevInFlow) {
07230     // Copy over the block/area frame type flags
07231     nsBlockFrame*  blockFrame = (nsBlockFrame*)aPrevInFlow;
07232 
07233     SetFlags(blockFrame->mState & NS_BLOCK_FLAGS_MASK);
07234   }
07235 
07236   nsresult rv = nsBlockFrameSuper::Init(aPresContext, aContent, aParent,
07237                                         aContext, aPrevInFlow);
07238 
07239   if (IsBoxWrapped())
07240     mState |= NS_BLOCK_SPACE_MGR;
07241 
07242   return rv;
07243 }
07244 
07245 NS_IMETHODIMP
07246 nsBlockFrame::SetInitialChildList(nsPresContext* aPresContext,
07247                                   nsIAtom*        aListName,
07248                                   nsIFrame*       aChildList)
07249 {
07250   nsresult rv = NS_OK;
07251 
07252   if (mAbsoluteContainer.GetChildListName() == aListName) {
07253     mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList);
07254   }
07255   else if (nsLayoutAtoms::floatList == aListName) {
07256     mFloats.SetFrames(aChildList);
07257   }
07258   else {
07259 
07260 #ifdef DEBUG
07261     // The only times a block that is an anonymous box is allowed to have a
07262     // first-letter frame are when it's the block inside a non-anonymous cell,
07263     // the block inside a fieldset, a scrolled content block, or a column
07264     // content block.  Also, a block that has a previous continuation can't
07265     // have a first letter frame.
07266     nsIAtom *pseudo = GetStyleContext()->GetPseudoType();
07267     PRBool haveFirstLetterStyle =
07268       !mPrevInFlow &&
07269       (!pseudo ||
07270        (pseudo == nsCSSAnonBoxes::cellContent &&
07271         mParent->GetStyleContext()->GetPseudoType() == nsnull) ||
07272        pseudo == nsCSSAnonBoxes::fieldsetContent ||
07273        pseudo == nsCSSAnonBoxes::scrolledContent ||
07274        pseudo == nsCSSAnonBoxes::columnContent) &&
07275       nsRefPtr<nsStyleContext>(GetFirstLetterStyle(aPresContext)) != nsnull;
07276     NS_ASSERTION(haveFirstLetterStyle ==
07277                  ((mState & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0),
07278                  "NS_BLOCK_HAS_FIRST_LETTER_STYLE state out of sync");
07279 #endif
07280     
07281     rv = AddFrames(aChildList, nsnull);
07282     if (NS_FAILED(rv)) {
07283       return rv;
07284     }
07285 
07286     // Create list bullet if this is a list-item. Note that this is done
07287     // here so that RenumberLists will work (it needs the bullets to
07288     // store the bullet numbers).
07289     const nsStyleDisplay* styleDisplay = GetStyleDisplay();
07290     if ((nsnull == mPrevInFlow) &&
07291         (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
07292         (nsnull == mBullet)) {
07293       // Resolve style for the bullet frame
07294       const nsStyleList* styleList = GetStyleList();
07295       nsIAtom *pseudoElement;
07296       switch (styleList->mListStyleType) {
07297         case NS_STYLE_LIST_STYLE_DISC:
07298         case NS_STYLE_LIST_STYLE_CIRCLE:
07299         case NS_STYLE_LIST_STYLE_SQUARE:
07300           pseudoElement = nsCSSPseudoElements::mozListBullet;
07301           break;
07302         default:
07303           pseudoElement = nsCSSPseudoElements::mozListNumber;
07304           break;
07305       }
07306 
07307       nsIPresShell *shell = aPresContext->PresShell();
07308 
07309       nsRefPtr<nsStyleContext> kidSC = shell->StyleSet()->
07310         ResolvePseudoStyleFor(mContent, pseudoElement, mStyleContext);
07311 
07312       // Create bullet frame
07313       nsBulletFrame* bullet = new (shell) nsBulletFrame;
07314 
07315       if (nsnull == bullet) {
07316         return NS_ERROR_OUT_OF_MEMORY;
07317       }
07318       bullet->Init(aPresContext, mContent, this, kidSC, nsnull);
07319 
07320       // If the list bullet frame should be positioned inside then add
07321       // it to the flow now.
07322       if (NS_STYLE_LIST_STYLE_POSITION_INSIDE ==
07323           styleList->mListStylePosition) {
07324         AddFrames(bullet, nsnull);
07325         mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
07326       }
07327       else {
07328         mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
07329       }
07330 
07331       mBullet = bullet;
07332     }
07333   }
07334 
07335   return NS_OK;
07336 }
07337 
07338 // static
07339 PRBool
07340 nsBlockFrame::FrameStartsCounterScope(nsIFrame* aFrame)
07341 {
07342   nsIContent* content = aFrame->GetContent();
07343   if (!content || !content->IsContentOfType(nsIContent::eHTML))
07344     return PR_FALSE;
07345   nsINodeInfo *ni = content->GetNodeInfo();
07346   return ni->Equals(nsHTMLAtoms::ol) ||
07347          ni->Equals(nsHTMLAtoms::ul) ||
07348          ni->Equals(nsHTMLAtoms::dir) ||
07349          ni->Equals(nsHTMLAtoms::menu);
07350 }
07351 
07352 void
07353 nsBlockFrame::RenumberLists(nsPresContext* aPresContext)
07354 {
07355   if (!FrameStartsCounterScope(this)) {
07356     // If this frame doesn't start a counter scope then we don't need
07357     // to renumber child list items.
07358     return;
07359   }
07360 
07361   // Setup initial list ordinal value
07362   // XXX Map html's start property to counter-reset style
07363   PRInt32 ordinal = 1;
07364 
07365   nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
07366 
07367   if (hc) {
07368     const nsAttrValue* attr = hc->GetParsedAttr(nsHTMLAtoms::start);
07369     if (attr && attr->Type() == nsAttrValue::eInteger) {
07370       ordinal = attr->GetIntegerValue();
07371     }
07372   }
07373 
07374   // Get to first-in-flow
07375   nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow();
07376   RenumberListsInBlock(aPresContext, block, &ordinal, 0);
07377 }
07378 
07379 PRBool
07380 nsBlockFrame::RenumberListsInBlock(nsPresContext* aPresContext,
07381                                    nsBlockFrame* aBlockFrame,
07382                                    PRInt32* aOrdinal,
07383                                    PRInt32 aDepth)
07384 {
07385   PRBool renumberedABullet = PR_FALSE;
07386 
07387   while (nsnull != aBlockFrame) {
07388     // Examine each line in the block
07389     for (line_iterator line = aBlockFrame->begin_lines(),
07390                        line_end = aBlockFrame->end_lines();
07391          line != line_end;
07392          ++line) {
07393       nsIFrame* kid = line->mFirstChild;
07394       PRInt32 n = line->GetChildCount();
07395       while (--n >= 0) {
07396         PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth);
07397         if (kidRenumberedABullet) {
07398           line->MarkDirty();
07399           renumberedABullet = PR_TRUE;
07400         }
07401         kid = kid->GetNextSibling();
07402       }
07403     }
07404 
07405     // Advance to the next continuation
07406     aBlockFrame = NS_STATIC_CAST(nsBlockFrame*, aBlockFrame->GetNextInFlow());
07407   }
07408 
07409   return renumberedABullet;
07410 }
07411 
07412 PRBool
07413 nsBlockFrame::RenumberListsFor(nsPresContext* aPresContext,
07414                                nsIFrame* aKid,
07415                                PRInt32* aOrdinal,
07416                                PRInt32 aDepth)
07417 {
07418   NS_PRECONDITION(aPresContext && aKid && aOrdinal, "null params are immoral!");
07419 
07420   // add in a sanity check for absurdly deep frame trees.  See bug 42138
07421   if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth)
07422     return PR_FALSE;