Back to index

lightning-sunbird  0.9+nobinonly
nsBlockReflowState.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  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsBlockReflowContext.h"
00043 #include "nsBlockReflowState.h"
00044 #include "nsBlockFrame.h"
00045 #include "nsLineLayout.h"
00046 #include "nsPresContext.h"
00047 #include "nsLayoutAtoms.h"
00048 #include "nsIFrame.h"
00049 #include "nsFrameManager.h"
00050 
00051 #include "nsINameSpaceManager.h"
00052 #include "nsHTMLAtoms.h"
00053 
00054 
00055 #ifdef DEBUG
00056 #include "nsBlockDebugFlags.h"
00057 #endif
00058 
00059 nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
00060                                        nsPresContext* aPresContext,
00061                                        nsBlockFrame* aFrame,
00062                                        const nsHTMLReflowMetrics& aMetrics,
00063                                        PRBool aTopMarginRoot,
00064                                        PRBool aBottomMarginRoot)
00065   : mBlock(aFrame),
00066     mPresContext(aPresContext),
00067     mReflowState(aReflowState),
00068     mPrevBottomMargin(),
00069     mLineNumber(0),
00070     mFlags(0),
00071     mFloatBreakType(NS_STYLE_CLEAR_NONE)
00072 {
00073   SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nsnull);
00074 
00075   const nsMargin& borderPadding = BorderPadding();
00076 
00077   if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
00078     SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
00079   }
00080   if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
00081     SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
00082   }
00083   if (GetFlag(BRS_ISTOPMARGINROOT)) {
00084     SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
00085   }
00086   
00087   mSpaceManager = aReflowState.mSpaceManager;
00088 
00089   NS_ASSERTION(mSpaceManager,
00090                "SpaceManager should be set in nsBlockReflowState" );
00091   if (mSpaceManager) {
00092     // Translate into our content area and then save the 
00093     // coordinate system origin for later.
00094     mSpaceManager->Translate(borderPadding.left, borderPadding.top);
00095     mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY);
00096   }
00097 
00098   mReflowStatus = NS_FRAME_COMPLETE;
00099 
00100   mPresContext = aPresContext;
00101   mNextInFlow = NS_STATIC_CAST(nsBlockFrame*, mBlock->GetNextInFlow());
00102   mKidXMost = 0;
00103 
00104   // Compute content area width (the content area is inside the border
00105   // and padding)
00106   if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
00107     mContentArea.width = aReflowState.mComputedWidth;
00108   }
00109   else {
00110     if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
00111       mContentArea.width = NS_UNCONSTRAINEDSIZE;
00112       SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
00113     }
00114     else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
00115       // Choose a width based on the content (shrink wrap width) up
00116       // to the maximum width
00117       mContentArea.width = aReflowState.mComputedMaxWidth;
00118       SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
00119     }
00120     else {
00121       nscoord lr = borderPadding.left + borderPadding.right;
00122       mContentArea.width = PR_MAX(0, aReflowState.availableWidth - lr);
00123     }
00124   }
00125 
00126   // Compute content area height. Unlike the width, if we have a
00127   // specified style height we ignore it since extra content is
00128   // managed by the "overflow" property. When we don't have a
00129   // specified style height then we may end up limiting our height if
00130   // the availableHeight is constrained (this situation occurs when we
00131   // are paginated).
00132   if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
00133     // We are in a paginated situation. The bottom edge is just inside
00134     // the bottom border and padding. The content area height doesn't
00135     // include either border or padding edge.
00136     mBottomEdge = aReflowState.availableHeight - borderPadding.bottom;
00137     mContentArea.height = PR_MAX(0, mBottomEdge - borderPadding.top);
00138   }
00139   else {
00140     // When we are not in a paginated situation then we always use
00141     // an constrained height.
00142     SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
00143     mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
00144   }
00145 
00146   mY = borderPadding.top;
00147   mBand.Init(mSpaceManager, mContentArea);
00148 
00149   mPrevChild = nsnull;
00150   mCurrentLine = aFrame->end_lines();
00151 
00152   SetFlag(BRS_COMPUTEMAXELEMENTWIDTH, aMetrics.mComputeMEW);
00153 #ifdef DEBUG
00154   if (nsBlockFrame::gNoisyMaxElementWidth) {
00155     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
00156     printf("BRS: setting compute-MEW to %d\n", aMetrics.mComputeMEW);
00157   }
00158 #endif
00159   mMaxElementWidth = 0;
00160   SetFlag(BRS_COMPUTEMAXWIDTH, 
00161           (NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
00162   mMaximumWidth = 0;
00163 
00164   mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
00165                                                      aReflowState.rendContext,
00166                                                      aReflowState.frame);
00167 }
00168 
00169 void
00170 nsBlockReflowState::SetupOverflowPlaceholdersProperty()
00171 {
00172   if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE ||
00173       !mOverflowPlaceholders.IsEmpty()) {
00174     mBlock->SetProperty(nsLayoutAtoms::overflowPlaceholdersProperty,
00175                         &mOverflowPlaceholders, nsnull);
00176     mBlock->AddStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
00177   }
00178 }
00179  
00180 nsBlockReflowState::~nsBlockReflowState()
00181 {
00182   NS_ASSERTION(mOverflowPlaceholders.IsEmpty(),
00183                "Leaking overflow placeholder frames");
00184 
00185   // Restore the coordinate system, unless the space manager is null,
00186   // which means it was just destroyed.
00187   if (mSpaceManager) {
00188     const nsMargin& borderPadding = BorderPadding();
00189     mSpaceManager->Translate(-borderPadding.left, -borderPadding.top);
00190   }
00191 
00192   if (mBlock->GetStateBits() & NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS) {
00193     mBlock->UnsetProperty(nsLayoutAtoms::overflowPlaceholdersProperty);
00194     mBlock->RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_PLACEHOLDERS);
00195   }
00196 }
00197 
00198 nsLineBox*
00199 nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
00200                                PRInt32 aCount,
00201                                PRBool aIsBlock)
00202 {
00203   return NS_NewLineBox(mPresContext->PresShell(), aFrame, aCount, aIsBlock);
00204 }
00205 
00206 void
00207 nsBlockReflowState::FreeLineBox(nsLineBox* aLine)
00208 {
00209   if (aLine) {
00210     aLine->Destroy(mPresContext->PresShell());
00211   }
00212 }
00213 
00214 // Compute the amount of available space for reflowing a block frame
00215 // at the current Y coordinate. This method assumes that
00216 // GetAvailableSpace has already been called.
00217 void
00218 nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
00219                                            nsSplittableType aSplitType,
00220                                            const nsStyleDisplay* aDisplay,
00221                                            nsRect& aResult)
00222 {
00223 #ifdef REALLY_NOISY_REFLOW
00224   printf("CBAS frame=%p has float count %d\n", aFrame, mBand.GetFloatCount());
00225   mBand.List();
00226 #endif
00227   aResult.y = mY;
00228   aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
00229     ? NS_UNCONSTRAINEDSIZE
00230     : mBottomEdge - mY;
00231 
00232   const nsMargin& borderPadding = BorderPadding();
00233 
00234   /* bug 18445: treat elements mapped to display: block such as text controls
00235    * just like normal blocks   */
00236   // text controls are not splittable, so make a special case here
00237   // XXXldb Why not just set the frame state bit?
00238   PRBool treatAsNotSplittable =
00239     nsLayoutAtoms::textInputFrame == aFrame->GetType();
00240 
00241   if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType ||    // normal blocks 
00242       NS_FRAME_NOT_SPLITTABLE == aSplitType ||                // things like images mapped to display: block
00243       PR_TRUE == treatAsNotSplittable)                        // text input controls mapped to display: block (special case)
00244   {
00245     if (mBand.GetFloatCount()) {
00246       // Use the float-edge property to determine how the child block
00247       // will interact with the float.
00248       const nsStyleBorder* borderStyle = aFrame->GetStyleBorder();
00249       switch (borderStyle->mFloatEdge) {
00250         default:
00251         case NS_STYLE_FLOAT_EDGE_CONTENT:  // content and only content does runaround of floats
00252           // The child block will flow around the float. Therefore
00253           // give it all of the available space.
00254           aResult.x = borderPadding.left;
00255           aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
00256             ? NS_UNCONSTRAINEDSIZE
00257             : mContentArea.width;
00258            break;
00259         case NS_STYLE_FLOAT_EDGE_BORDER: 
00260         case NS_STYLE_FLOAT_EDGE_PADDING:
00261           {
00262             // The child block's border should be placed adjacent to,
00263             // but not overlap the float(s).
00264             nsMargin m(0, 0, 0, 0);
00265             const nsStyleMargin* styleMargin = aFrame->GetStyleMargin();
00266             styleMargin->GetMargin(m); // XXX percentage margins
00267             if (NS_STYLE_FLOAT_EDGE_PADDING == borderStyle->mFloatEdge) {
00268               // Add in border too
00269               m += borderStyle->GetBorder();
00270             }
00271 
00272             // determine left edge
00273             if (mBand.GetLeftFloatCount()) {
00274               aResult.x = mAvailSpaceRect.x + borderPadding.left - m.left;
00275             }
00276             else {
00277               aResult.x = borderPadding.left;
00278             }
00279 
00280             // determine width
00281             if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
00282               aResult.width = NS_UNCONSTRAINEDSIZE;
00283             }
00284             else {
00285               if (mBand.GetRightFloatCount()) {
00286                 if (mBand.GetLeftFloatCount()) {
00287                   aResult.width = mAvailSpaceRect.width + m.left + m.right;
00288                 }
00289                 else {
00290                   aResult.width = mAvailSpaceRect.width + m.right;
00291                 }
00292               }
00293               else {
00294                 aResult.width = mAvailSpaceRect.width + m.left;
00295               }
00296             }
00297           }
00298           break;
00299 
00300         case NS_STYLE_FLOAT_EDGE_MARGIN:
00301           {
00302             // The child block's margins should be placed adjacent to,
00303             // but not overlap the float.
00304             aResult.x = mAvailSpaceRect.x + borderPadding.left;
00305             aResult.width = mAvailSpaceRect.width;
00306           }
00307           break;
00308       }
00309     }
00310     else {
00311       // Since there are no floats present the float-edge property
00312       // doesn't matter therefore give the block element all of the
00313       // available space since it will flow around the float itself.
00314       aResult.x = borderPadding.left;
00315       aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
00316         ? NS_UNCONSTRAINEDSIZE
00317         : mContentArea.width;
00318     }
00319   }
00320   else {
00321     // The frame is clueless about the space manager and therefore we
00322     // only give it free space. An example is a table frame - the
00323     // tables do not flow around floats.
00324     aResult.x = mAvailSpaceRect.x + borderPadding.left;
00325     aResult.width = mAvailSpaceRect.width;
00326   }
00327 
00328 #ifdef REALLY_NOISY_REFLOW
00329   printf("  CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
00330 #endif
00331 }
00332 
00333 void
00334 nsBlockReflowState::GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint)
00335 {
00336 #ifdef DEBUG
00337   // Verify that the caller setup the coordinate system properly
00338   nscoord wx, wy;
00339   mSpaceManager->GetTranslation(wx, wy);
00340   NS_ASSERTION((wx == mSpaceManagerX) && (wy == mSpaceManagerY),
00341                "bad coord system");
00342 #endif
00343 
00344   mBand.GetAvailableSpace(aY - BorderPadding().top, aRelaxHeightConstraint,
00345                           mAvailSpaceRect);
00346 
00347 #ifdef DEBUG
00348   if (nsBlockFrame::gNoisyReflow) {
00349     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
00350     printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n",
00351            mAvailSpaceRect.x, mAvailSpaceRect.y,
00352            mAvailSpaceRect.width, mAvailSpaceRect.height,
00353            mBand.GetTrapezoidCount());
00354   }
00355 #endif
00356 }
00357 
00358 /*
00359  * Reconstruct the vertical margin before the line |aLine| in order to
00360  * do an incremental reflow that begins with |aLine| without reflowing
00361  * the line before it.  |aLine| may point to the fencepost at the end of
00362  * the line list, and it is used this way since we (for now, anyway)
00363  * always need to recover margins at the end of a block.
00364  *
00365  * The reconstruction involves walking backward through the line list to
00366  * find any collapsed margins preceding the line that would have been in
00367  * the reflow state's |mPrevBottomMargin| when we reflowed that line in
00368  * a full reflow (under the rule in CSS2 that all adjacent vertical
00369  * margins of blocks collapse).
00370  */
00371 void
00372 nsBlockReflowState::ReconstructMarginAbove(nsLineList::iterator aLine)
00373 {
00374   mPrevBottomMargin.Zero();
00375   nsBlockFrame *block = mBlock;
00376 
00377   nsLineList::iterator firstLine = block->begin_lines();
00378   for (;;) {
00379     --aLine;
00380     if (aLine->IsBlock()) {
00381       mPrevBottomMargin = aLine->GetCarriedOutBottomMargin();
00382       break;
00383     }
00384     if (!aLine->IsEmpty()) {
00385       break;
00386     }
00387     if (aLine == firstLine) {
00388       // If the top margin was carried out (and thus already applied),
00389       // set it to zero.  Either way, we're done.
00390       if ((0 == mReflowState.mComputedBorderPadding.top) &&
00391           !(block->mState & NS_BLOCK_MARGIN_ROOT)) {
00392         mPrevBottomMargin.Zero();
00393       }
00394       break;
00395     }
00396   }
00397 }
00398 
00407 void
00408 nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
00409                                   nscoord aDeltaY)
00410 {
00411   if (aLine->HasFloats()) {
00412     // Place the floats into the space-manager again. Also slide
00413     // them, just like the regular frames on the line.
00414     nsFloatCache* fc = aLine->GetFirstFloat();
00415     while (fc) {
00416       nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame();
00417       if (aDeltaY != 0) {
00418         fc->mRegion.y += aDeltaY;
00419         fc->mCombinedArea.y += aDeltaY;
00420         nsPoint p = floatFrame->GetPosition();
00421         floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY));
00422       }
00423 #ifdef DEBUG
00424       if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisySpaceManager) {
00425         nscoord tx, ty;
00426         mSpaceManager->GetTranslation(tx, ty);
00427         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
00428         printf("RecoverFloats: txy=%d,%d (%d,%d) ",
00429                tx, ty, mSpaceManagerX, mSpaceManagerY);
00430         nsFrame::ListTag(stdout, floatFrame);
00431         printf(" aDeltaY=%d region={%d,%d,%d,%d}\n",
00432                aDeltaY, fc->mRegion.x, fc->mRegion.y,
00433                fc->mRegion.width, fc->mRegion.height);
00434       }
00435 #endif
00436       mSpaceManager->AddRectRegion(floatFrame, fc->mRegion);
00437       fc = fc->Next();
00438     }
00439   } else if (aLine->IsBlock()) {
00440     nsBlockFrame *kid = nsnull;
00441     aLine->mFirstChild->QueryInterface(kBlockFrameCID, (void**)&kid);
00442     // don't recover any state inside a block that has its own space
00443     // manager (we don't currently have any blocks like this, though,
00444     // thanks to our use of extra frames for 'overflow')
00445     if (kid && !(kid->GetStateBits() & NS_BLOCK_SPACE_MGR)) {
00446       nscoord tx = kid->mRect.x, ty = kid->mRect.y;
00447 
00448       // If the element is relatively positioned, then adjust x and y
00449       // accordingly so that we consider relatively positioned frames
00450       // at their original position.
00451       if (NS_STYLE_POSITION_RELATIVE == kid->GetStyleDisplay()->mPosition) {
00452         nsPoint *offsets = NS_STATIC_CAST(nsPoint*,
00453           mPresContext->PropertyTable()->GetProperty(kid,
00454                                        nsLayoutAtoms::computedOffsetProperty));
00455 
00456         if (offsets) {
00457           tx -= offsets->x;
00458           ty -= offsets->y;
00459         }
00460       }
00461  
00462       mSpaceManager->Translate(tx, ty);
00463       for (nsBlockFrame::line_iterator line = kid->begin_lines(),
00464                                    line_end = kid->end_lines();
00465            line != line_end;
00466            ++line)
00467         // Pass 0, not the real DeltaY, since these floats aren't
00468         // moving relative to their parent block, only relative to
00469         // the space manager.
00470         RecoverFloats(line, 0);
00471       mSpaceManager->Translate(-tx, -ty);
00472     }
00473   }
00474 }
00475 
00488 void
00489 nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
00490                                      nscoord aDeltaY)
00491 {
00492   // Make the line being recovered the current line
00493   mCurrentLine = aLine;
00494 
00495   // Recover mKidXMost and mMaxElementWidth
00496   nscoord xmost = aLine->mBounds.XMost();
00497   // If we're shrink-wrapping, then include the right margin in the xmost
00498   // so that shrink-wrapping includes it.
00499   if (GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsBlock()) {
00500     nsHTMLReflowState blockHtmlRS(mPresContext, mReflowState, aLine->mFirstChild,
00501                                   nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
00502                                   mReflowState.reason, PR_TRUE);
00503     xmost += blockHtmlRS.mComputedMargin.right;
00504   }
00505   if (xmost > mKidXMost) {
00506 #ifdef DEBUG
00507     if (CRAZY_WIDTH(xmost)) {
00508       nsFrame::ListTag(stdout, mBlock);
00509       printf(": WARNING: xmost:%d\n", xmost);
00510     }
00511 #endif
00512 #ifdef NOISY_KIDXMOST
00513     printf("%p RecoverState block %p aState.mKidXMost=%d\n", this, mBlock, xmost); 
00514 #endif
00515     mKidXMost = xmost;
00516   }
00517   if (GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) {
00518 #ifdef DEBUG
00519     if (nsBlockFrame::gNoisyMaxElementWidth) {
00520       nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
00521       printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaxElementWidth);
00522     }
00523 #endif
00524     UpdateMaxElementWidth(aLine->mMaxElementWidth);
00525 
00526     // Recover the float MEWs for floats in this line (but not in
00527     // blocks within it, since their MEWs are already part of the block's
00528     // MEW).
00529     if (aLine->HasFloats()) {
00530       for (nsFloatCache* fc = aLine->GetFirstFloat(); fc; fc = fc->Next())
00531         UpdateMaxElementWidth(fc->mMaxElementWidth);
00532     }
00533   }
00534 
00535   // If computing the maximum width, then update mMaximumWidth
00536   if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
00537 #ifdef NOISY_MAXIMUM_WIDTH
00538     printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaximumWidth);
00539 #endif
00540     UpdateMaximumWidth(aLine->mMaximumWidth);
00541   }
00542 
00543   // Place floats for this line into the space manager
00544   if (aLine->HasFloats() || aLine->IsBlock()) {
00545     // Undo border/padding translation since the nsFloatCache's
00546     // coordinates are relative to the frame not relative to the
00547     // border/padding.
00548     const nsMargin& bp = BorderPadding();
00549     mSpaceManager->Translate(-bp.left, -bp.top);
00550 
00551     RecoverFloats(aLine, aDeltaY);
00552 
00553 #ifdef DEBUG
00554     if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisySpaceManager) {
00555       mSpaceManager->List(stdout);
00556     }
00557 #endif
00558     // And then put the translation back again
00559     mSpaceManager->Translate(bp.left, bp.top);
00560   }
00561 }
00562 
00563 PRBool
00564 nsBlockReflowState::IsImpactedByFloat() const
00565 {
00566 #ifdef REALLY_NOISY_REFLOW
00567   printf("nsBlockReflowState::IsImpactedByFloat %p returned %d\n", 
00568          this, mBand.GetFloatCount());
00569 #endif
00570   return mBand.GetFloatCount() > 0;
00571 }
00572 
00573 
00574 PRBool
00575 nsBlockReflowState::InitFloat(nsLineLayout&       aLineLayout,
00576                               nsPlaceholderFrame* aPlaceholder,
00577                               nsReflowStatus&     aReflowStatus)
00578 {
00579   // Set the geometric parent of the float
00580   nsIFrame* floatFrame = aPlaceholder->GetOutOfFlowFrame();
00581   floatFrame->SetParent(mBlock);
00582 
00583   // Then add the float to the current line and place it when
00584   // appropriate
00585   return AddFloat(aLineLayout, aPlaceholder, PR_TRUE, aReflowStatus);
00586 }
00587 
00588 // This is called by the line layout's AddFloat method when a
00589 // place-holder frame is reflowed in a line. If the float is a
00590 // left-most child (it's x coordinate is at the line's left margin)
00591 // then the float is place immediately, otherwise the float
00592 // placement is deferred until the line has been reflowed.
00593 
00594 // XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
00595 // technically we're supposed let the current line flow around the
00596 // float as well unless it won't fit next to what we already have.
00597 // But nobody else implements it that way...
00598 PRBool
00599 nsBlockReflowState::AddFloat(nsLineLayout&       aLineLayout,
00600                              nsPlaceholderFrame* aPlaceholder,
00601                              PRBool              aInitialReflow,
00602                              nsReflowStatus&     aReflowStatus)
00603 {
00604   NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
00605 
00606   aReflowStatus = NS_FRAME_COMPLETE;
00607   // Allocate a nsFloatCache for the float
00608   nsFloatCache* fc = mFloatCacheFreeList.Alloc();
00609   fc->mPlaceholder = aPlaceholder;
00610   fc->mIsCurrentLineFloat = aLineLayout.CanPlaceFloatNow();
00611   fc->mMaxElementWidth = 0;
00612 
00613   PRBool placed;
00614 
00615   // Now place the float immediately if possible. Otherwise stash it
00616   // away in mPendingFloats and place it later.
00617   if (fc->mIsCurrentLineFloat) {
00618     // Because we are in the middle of reflowing a placeholder frame
00619     // within a line (and possibly nested in an inline frame or two
00620     // that's a child of our block) we need to restore the space
00621     // manager's translation to the space that the block resides in
00622     // before placing the float.
00623     nscoord ox, oy;
00624     mSpaceManager->GetTranslation(ox, oy);
00625     nscoord dx = ox - mSpaceManagerX;
00626     nscoord dy = oy - mSpaceManagerY;
00627     mSpaceManager->Translate(-dx, -dy);
00628 
00629     // And then place it
00630     PRBool isLeftFloat;
00631     // force it to fit if we're at the top of the block and we can't
00632     // break before this
00633     PRBool forceFit = IsAdjacentWithTop() && !aLineLayout.LineIsBreakable();
00634     placed = FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus, forceFit);
00635     NS_ASSERTION(placed || !forceFit,
00636                  "If we asked for force-fit, it should have been placed");
00637     if (placed) {
00638       // Pass on updated available space to the current inline reflow engine
00639       GetAvailableSpace(mY, forceFit);
00640       aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
00641                              GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
00642                              mAvailSpaceRect.height,
00643                              isLeftFloat,
00644                              aPlaceholder->GetOutOfFlowFrame());
00645       
00646       // Record this float in the current-line list
00647       mCurrentLineFloats.Append(fc);
00648     }
00649 
00650     // Restore coordinate system
00651     mSpaceManager->Translate(dx, dy);
00652   }
00653   else {
00654     // This float will be placed after the line is done (it is a
00655     // below-current-line float).
00656     mBelowCurrentLineFloats.Append(fc);
00657     if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE ||
00658         aPlaceholder->GetNextInFlow()) {
00659       // If the float might not be complete, mark it incomplete now to
00660       // prevent the placeholders being torn down. We will destroy any
00661       // placeholders later if PlaceBelowCurrentLineFloats finds the
00662       // float is complete.
00663       // Note that we could have unconstrained height and yet have
00664       // a next-in-flow placeholder --- for example columns can switch
00665       // from constrained height to unconstrained height.
00666       aReflowStatus = NS_FRAME_NOT_COMPLETE;
00667     }
00668     placed = PR_TRUE;
00669   }
00670   return placed;
00671 }
00672 
00673 void
00674 nsBlockReflowState::UpdateMaxElementWidth(nscoord aMaxElementWidth)
00675 {
00676 #ifdef DEBUG
00677   nscoord oldWidth = mMaxElementWidth;
00678 #endif
00679   if (aMaxElementWidth > mMaxElementWidth) {
00680     mMaxElementWidth = aMaxElementWidth;
00681   }
00682 #ifdef DEBUG
00683   if (nsBlockFrame::gNoisyMaxElementWidth) {
00684     if (mMaxElementWidth != oldWidth) {
00685       nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
00686       if (NS_UNCONSTRAINEDSIZE == mReflowState.availableWidth) {
00687         printf("PASS1 ");
00688       }
00689       nsFrame::ListTag(stdout, mBlock);
00690       printf(": old max-element-width=%d new=%d\n",
00691              oldWidth, mMaxElementWidth);
00692     }
00693   }
00694 #endif
00695 }
00696 
00697 void
00698 nsBlockReflowState::UpdateMaximumWidth(nscoord aMaximumWidth)
00699 {
00700   if (aMaximumWidth > mMaximumWidth) {
00701 #ifdef NOISY_MAXIMUM_WIDTH
00702     printf("nsBlockReflowState::UpdateMaximumWidth block %p caching max width %d\n", mBlock, aMaximumWidth);
00703 #endif
00704     mMaximumWidth = aMaximumWidth;
00705   }
00706 }
00707 
00708 PRBool
00709 nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
00710                                   PRUint8 aFloats, PRBool aForceFit)
00711 {
00712   // If the current Y coordinate is not impacted by any floats
00713   // then by definition the float fits.
00714   PRBool result = PR_TRUE;
00715   if (0 != mBand.GetFloatCount()) {
00716     // XXX We should allow overflow by up to half a pixel here (bug 21193).
00717     if (mAvailSpaceRect.width < aFloatSize.width) {
00718       // The available width is too narrow (and its been impacted by a
00719       // prior float)
00720       result = PR_FALSE;
00721     }
00722     else {
00723       // At this point we know that there is enough horizontal space for
00724       // the float (somewhere). Lets see if there is enough vertical
00725       // space.
00726       if (mAvailSpaceRect.height < aFloatSize.height) {
00727         // The available height is too short. However, its possible that
00728         // there is enough open space below which is not impacted by a
00729         // float.
00730         //
00731         // Compute the X coordinate for the float based on its float
00732         // type, assuming its placed on the current line. This is
00733         // where the float will be placed horizontally if it can go
00734         // here.
00735         nscoord xa;
00736         if (NS_STYLE_FLOAT_LEFT == aFloats) {
00737           xa = mAvailSpaceRect.x;
00738         }
00739         else {
00740           xa = mAvailSpaceRect.XMost() - aFloatSize.width;
00741 
00742           // In case the float is too big, don't go past the left edge
00743           // XXXldb This seems wrong, but we might want to fix bug 6976
00744           // first.
00745           if (xa < mAvailSpaceRect.x) {
00746             xa = mAvailSpaceRect.x;
00747           }
00748         }
00749         nscoord xb = xa + aFloatSize.width;
00750 
00751         // Calculate the top and bottom y coordinates, again assuming
00752         // that the float is placed on the current line.
00753         const nsMargin& borderPadding = BorderPadding();
00754         nscoord ya = mY - borderPadding.top;
00755         if (ya < 0) {
00756           // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
00757           // be higher than the top of its containing block."  (Since the
00758           // containing block is the content edge of the block box, this
00759           // means the margin edge of the float can't be higher than the
00760           // content edge of the block that contains it.)
00761           ya = 0;
00762         }
00763         nscoord yb = ya + aFloatSize.height;
00764 
00765         nscoord saveY = mY;
00766         for (;;) {
00767           // Get the available space at the new Y coordinate
00768           if (mAvailSpaceRect.height <= 0) {
00769             // there is no more available space. We lose.
00770             result = PR_FALSE;
00771             break;
00772           }
00773 
00774           mY += mAvailSpaceRect.height;
00775           GetAvailableSpace(mY, aForceFit);
00776 
00777           if (0 == mBand.GetFloatCount()) {
00778             // Winner. This band has no floats on it, therefore
00779             // there can be no overlap.
00780             break;
00781           }
00782 
00783           // Check and make sure the float won't intersect any
00784           // floats on this band. The floats starting and ending
00785           // coordinates must be entirely in the available space.
00786           if ((xa < mAvailSpaceRect.x) || (xb > mAvailSpaceRect.XMost())) {
00787             // The float can't go here.
00788             result = PR_FALSE;
00789             break;
00790           }
00791 
00792           // See if there is now enough height for the float.
00793           if (yb < mY + mAvailSpaceRect.height) {
00794             // Winner. The bottom Y coordinate of the float is in
00795             // this band.
00796             break;
00797           }
00798         }
00799 
00800         // Restore Y coordinate and available space information
00801         // regardless of the outcome.
00802         mY = saveY;
00803         GetAvailableSpace(mY, aForceFit);
00804       }
00805     }
00806   }
00807   return result;
00808 }
00809 
00810 PRBool
00811 nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache*   aFloatCache,
00812                                       PRBool*         aIsLeftFloat,
00813                                       nsReflowStatus& aReflowStatus,
00814                                       PRBool          aForceFit)
00815 {
00816   aReflowStatus = NS_FRAME_COMPLETE;
00817   // Save away the Y coordinate before placing the float. We will
00818   // restore mY at the end after placing the float. This is
00819   // necessary because any adjustments to mY during the float
00820   // placement are for the float only, not for any non-floating
00821   // content.
00822   nscoord saveY = mY;
00823 
00824   nsPlaceholderFrame* placeholder = aFloatCache->mPlaceholder;
00825   nsIFrame*           floatFrame = placeholder->GetOutOfFlowFrame();
00826 
00827   // Grab the float's display information
00828   const nsStyleDisplay* floatDisplay = floatFrame->GetStyleDisplay();
00829 
00830   // The float's old region, so we can propagate damage.
00831   nsRect oldRegion = floatFrame->GetRect();
00832   oldRegion.Inflate(aFloatCache->mMargins);
00833 
00834   // Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
00835   // ``above'' another float that preceded it in the flow.
00836   mY = NS_MAX(mSpaceManager->GetLowestRegionTop() + BorderPadding().top, mY);
00837 
00838   // See if the float should clear any preceeding floats...
00839   if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
00840     // XXXldb Does this handle vertical margins correctly?
00841     mY = ClearFloats(mY, floatDisplay->mBreakType);
00842   }
00843     // Get the band of available space
00844   GetAvailableSpace(mY, aForceFit);
00845 
00846   NS_ASSERTION(floatFrame->GetParent() == mBlock,
00847                "Float frame has wrong parent");
00848 
00849   // Reflow the float
00850   mBlock->ReflowFloat(*this, placeholder, aFloatCache, aReflowStatus);
00851 
00852 #ifdef DEBUG
00853   if (nsBlockFrame::gNoisyReflow) {
00854     nsRect region = floatFrame->GetRect();
00855     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
00856     printf("flowed float: ");
00857     nsFrame::ListTag(stdout, floatFrame);
00858     printf(" (%d,%d,%d,%d)\n",
00859           region.x, region.y, region.width, region.height);
00860   }
00861 #endif
00862 
00863   nsSize floatSize = floatFrame->GetSize();
00864   // Adjust the float size by its margin. That's the area that will
00865   // impact the space manager.
00866   floatSize.width += aFloatCache->mMargins.left + aFloatCache->mMargins.right;
00867   floatSize.height += aFloatCache->mMargins.top + aFloatCache->mMargins.bottom;
00868 
00869   // Find a place to place the float. The CSS2 spec doesn't want
00870   // floats overlapping each other or sticking out of the containing
00871   // block if possible (CSS2 spec section 9.5.1, see the rule list).
00872   NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) ||
00873               (NS_STYLE_FLOAT_RIGHT == floatDisplay->mFloats),
00874               "invalid float type");
00875 
00876   // Can the float fit here?
00877   PRBool keepFloatOnSameLine = PR_FALSE;
00878 
00879   while (!CanPlaceFloat(floatSize, floatDisplay->mFloats, aForceFit)) {
00880     if (mAvailSpaceRect.height <= 0) {
00881       // No space, nowhere to put anything.
00882       mY = saveY;
00883       return PR_FALSE;
00884     }
00885 
00886     // Nope. try to advance to the next band.
00887     if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
00888           eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
00889 
00890       mY += mAvailSpaceRect.height;
00891       GetAvailableSpace(mY, aForceFit);
00892     } else {
00893       // This quirk matches the one in nsBlockFrame::ReflowFloat
00894       // IE handles float tables in a very special way
00895 
00896       // see if the previous float is also a table and has "align"
00897       nsFloatCache* fc = mCurrentLineFloats.Head();
00898       nsIFrame* prevFrame = nsnull;
00899       while (fc) {
00900         if (fc->mPlaceholder->GetOutOfFlowFrame() == floatFrame) {
00901           break;
00902         }
00903         prevFrame = fc->mPlaceholder->GetOutOfFlowFrame();
00904         fc = fc->Next();
00905       }
00906       
00907       if(prevFrame) {
00908         //get the frame type
00909         if (nsLayoutAtoms::tableOuterFrame == prevFrame->GetType()) {
00910           //see if it has "align="
00911           // IE makes a difference between align and he float property
00912           nsIContent* content = prevFrame->GetContent();
00913           if (content) {
00914             nsAutoString value;
00915             if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::align, value)) {
00916               // we're interested only if previous frame is align=left
00917               // IE messes things up when "right" (overlapping frames) 
00918               if (value.LowerCaseEqualsLiteral("left")) {
00919                 keepFloatOnSameLine = PR_TRUE;
00920                 // don't advance to next line (IE quirkie behaviour)
00921                 // it breaks rule CSS2/9.5.1/1, but what the hell
00922                 // since we cannot evangelize the world
00923                 break;
00924               }
00925             }
00926           }
00927         }
00928       }
00929 
00930       // the table does not fit anymore in this line so advance to next band 
00931       mY += mAvailSpaceRect.height;
00932       GetAvailableSpace(mY, aForceFit);
00933       // reflow the float again now since we have more space
00934       mBlock->ReflowFloat(*this, placeholder, aFloatCache, aReflowStatus);
00935       // Get the floats bounding box and margin information
00936       floatSize = floatFrame->GetSize();
00937       // Adjust the float size by its margin. That's the area that will
00938       // impact the space manager.
00939       floatSize.width += aFloatCache->mMargins.left + aFloatCache->mMargins.right;
00940       floatSize.height += aFloatCache->mMargins.top + aFloatCache->mMargins.bottom;
00941     }
00942   }
00943   // If the float is continued, it will get the same absolute x value as its prev-in-flow
00944   nsRect prevRect(0,0,0,0);
00945 
00946   // We don't worry about the geometry of the prev in flow, let the continuation
00947   // place and size itself as required.
00948 
00949   // Assign an x and y coordinate to the float. Note that the x,y
00950   // coordinates are computed <b>relative to the translation in the
00951   // spacemanager</b> which means that the impacted region will be
00952   // <b>inside</b> the border/padding area.
00953   PRBool isLeftFloat;
00954   nscoord floatX, floatY;
00955   if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
00956     isLeftFloat = PR_TRUE;
00957     floatX = mAvailSpaceRect.x;
00958   }
00959   else {
00960     isLeftFloat = PR_FALSE;
00961     if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.width) {
00962       if (!keepFloatOnSameLine) {
00963         floatX = mAvailSpaceRect.XMost() - floatSize.width;
00964       } 
00965       else {
00966         // this is the IE quirk (see few lines above)
00967         // the table is keept in the same line: don't let it overlap the previous float 
00968         floatX = mAvailSpaceRect.x;
00969       }
00970     }
00971     else {
00972       // For unconstrained reflows, pretend that a right float is
00973       // instead a left float.  This will make us end up with the
00974       // correct unconstrained width, and we'll place it later.
00975       floatX = mAvailSpaceRect.x;
00976     }
00977   }
00978   *aIsLeftFloat = isLeftFloat;
00979   const nsMargin& borderPadding = BorderPadding();
00980   floatY = mY - borderPadding.top;
00981   if (floatY < 0) {
00982     // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
00983     // be higher than the top of its containing block."  (Since the
00984     // containing block is the content edge of the block box, this
00985     // means the margin edge of the float can't be higher than the
00986     // content edge of the block that contains it.)
00987     floatY = 0;
00988   }
00989 
00990   // Place the float in the space manager
00991   // if the float split, then take up all of the vertical height 
00992   if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && 
00993       (NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
00994     floatSize.height = PR_MAX(floatSize.height, mContentArea.height - floatY);
00995   }
00996 
00997   nsRect region(floatX, floatY, floatSize.width, floatSize.height);
00998   
00999   // Don't send rectangles with negative margin-box width or height to
01000   // the space manager; it can't deal with them.
01001   if (region.width < 0) {
01002     // Preserve the right margin-edge for left floats and the left
01003     // margin-edge for right floats
01004     if (isLeftFloat) {
01005       region.x = region.XMost();
01006     }
01007     region.width = 0;
01008   }
01009   if (region.height < 0) {
01010     region.height = 0;
01011   }
01012 #ifdef DEBUG
01013   nsresult rv =
01014 #endif
01015   mSpaceManager->AddRectRegion(floatFrame, region);
01016   NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad float placement");
01017 
01018   // If the float's dimensions have changed, note the damage in the
01019   // space manager.
01020   if (region != oldRegion) {
01021     // XXXwaterson conservative: we could probably get away with noting
01022     // less damage; e.g., if only height has changed, then only note the
01023     // area into which the float has grown or from which the float has
01024     // shrunk.
01025     nscoord top = NS_MIN(region.y, oldRegion.y);
01026     nscoord bottom = NS_MAX(region.YMost(), oldRegion.YMost());
01027     mSpaceManager->IncludeInDamage(top, bottom);
01028   }
01029 
01030   // Save away the floats region in the spacemanager, after making
01031   // it relative to the containing block's frame instead of relative
01032   // to the spacemanager translation (which is inset by the
01033   // border+padding).
01034   aFloatCache->mRegion.x = region.x + borderPadding.left;
01035   aFloatCache->mRegion.y = region.y + borderPadding.top;
01036   aFloatCache->mRegion.width = region.width;
01037   aFloatCache->mRegion.height = region.height;
01038 #ifdef NOISY_SPACEMANAGER
01039   nscoord tx, ty;
01040   mSpaceManager->GetTranslation(tx, ty);
01041   nsFrame::ListTag(stdout, mBlock);
01042   printf(": FlowAndPlaceFloat: AddRectRegion: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
01043          tx, ty, mSpaceManagerX, mSpaceManagerY,
01044          aFloatCache->mRegion.x, aFloatCache->mRegion.y,
01045          aFloatCache->mRegion.width, aFloatCache->mRegion.height);
01046 #endif
01047 
01048   // Set the origin of the float frame, in frame coordinates. These
01049   // coordinates are <b>not</b> relative to the spacemanager
01050   // translation, therefore we have to factor in our border/padding.
01051   nscoord x = borderPadding.left + aFloatCache->mMargins.left + floatX;
01052   nscoord y = borderPadding.top + aFloatCache->mMargins.top + floatY;
01053 
01054   // If float is relatively positioned, factor that in as well
01055   // XXXldb Should this be done after handling the combined area
01056   // below?
01057   if (NS_STYLE_POSITION_RELATIVE == floatDisplay->mPosition) {
01058     x += aFloatCache->mOffsets.left;
01059     y += aFloatCache->mOffsets.top;
01060   }
01061 
01062   // Position the float and make sure and views are properly
01063   // positioned. We need to explicitly position its child views as
01064   // well, since we're moving the float after flowing it.
01065   floatFrame->SetPosition(nsPoint(x, y));
01066   nsContainerFrame::PositionFrameView(floatFrame);
01067   nsContainerFrame::PositionChildViews(floatFrame);
01068 
01069   // Update the float combined area state
01070   nsRect combinedArea = aFloatCache->mCombinedArea;
01071   combinedArea.x += x;
01072   combinedArea.y += y;
01073   // When we are placing a right float in an unconstrained situation or
01074   // when shrink wrapping, we don't apply it to the float combined area
01075   // immediately, since there's no need to since we're guaranteed another
01076   // reflow, and since there's no need to change the code that was
01077   // necessary back when the float was positioned relative to
01078   // NS_UNCONSTRAINEDSIZE.
01079   if (isLeftFloat ||
01080       !GetFlag(BRS_UNCONSTRAINEDWIDTH) ||
01081       !GetFlag(BRS_SHRINKWRAPWIDTH)) {
01082     mFloatCombinedArea.UnionRect(combinedArea, mFloatCombinedArea);
01083   } else if (GetFlag(BRS_SHRINKWRAPWIDTH)) {
01084     // Mark the line dirty so we come back and re-place the float once
01085     // the shrink wrap width is determined
01086     mCurrentLine->MarkDirty();
01087     SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
01088   }
01089 
01090   // Now restore mY
01091   mY = saveY;
01092 
01093 #ifdef DEBUG
01094   if (nsBlockFrame::gNoisyReflow) {
01095     nsRect r = floatFrame->GetRect();
01096     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
01097     printf("placed float: ");
01098     nsFrame::ListTag(stdout, floatFrame);
01099     printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
01100   }
01101 #endif
01102 
01103   return PR_TRUE;
01104 }
01105 
01109 PRBool
01110 nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheList& aList, PRBool aForceFit)
01111 {
01112   nsFloatCache* fc = aList.Head();
01113   while (fc) {
01114     NS_ASSERTION(!fc->mIsCurrentLineFloat,
01115                  "A cl float crept into the bcl float list.");
01116     if (!fc->mIsCurrentLineFloat) {
01117 #ifdef DEBUG
01118       if (nsBlockFrame::gNoisyReflow) {
01119         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
01120         printf("placing bcl float: ");
01121         nsFrame::ListTag(stdout, fc->mPlaceholder->GetOutOfFlowFrame());
01122         printf("\n");
01123       }
01124 #endif
01125       // Place the float
01126       PRBool isLeftFloat;
01127       nsReflowStatus reflowStatus;
01128       PRBool placed = FlowAndPlaceFloat(fc, &isLeftFloat, reflowStatus, aForceFit);
01129       NS_ASSERTION(placed || !aForceFit,
01130                    "If we're in force-fit mode, we should have placed the float");
01131 
01132       if (!placed || NS_FRAME_IS_TRUNCATED(reflowStatus)) {
01133         // return before processing all of the floats, since the line will be pushed.
01134         return PR_FALSE;
01135       }
01136       else if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus)) {
01137         // Create a continuation for the incomplete float and its placeholder.
01138         nsresult rv = mBlock->SplitPlaceholder(*this, fc->mPlaceholder);
01139         if (NS_FAILED(rv)) 
01140           return PR_FALSE;
01141       } else {
01142         // Float is complete. We need to delete any leftover placeholders now.
01143         nsIFrame* nextPlaceholder = fc->mPlaceholder->GetNextInFlow();
01144         if (nextPlaceholder) {
01145           nsHTMLContainerFrame* parent =
01146             NS_STATIC_CAST(nsHTMLContainerFrame*, nextPlaceholder->GetParent());
01147           parent->DeleteNextInFlowChild(mPresContext, nextPlaceholder);
01148         }
01149       }
01150     }
01151     fc = fc->Next();
01152   }
01153   return PR_TRUE;
01154 }
01155 
01156 nscoord
01157 nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType)
01158 {
01159 #ifdef DEBUG
01160   if (nsBlockFrame::gNoisyReflow) {
01161     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
01162     printf("clear floats: in: aY=%d(%d)\n",
01163            aY, aY - BorderPadding().top);
01164   }
01165 #endif
01166 
01167 #ifdef NOISY_FLOAT_CLEARING
01168   printf("nsBlockReflowState::ClearFloats: aY=%d breakType=%d\n",
01169          aY, aBreakType);
01170   mSpaceManager->List(stdout);
01171 #endif
01172   
01173   const nsMargin& bp = BorderPadding();
01174   nscoord newY = mSpaceManager->ClearFloats(aY - bp.top, aBreakType);
01175   newY += bp.top;
01176 
01177 #ifdef DEBUG
01178   if (nsBlockFrame::gNoisyReflow) {
01179     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
01180     printf("clear floats: out: y=%d(%d)\n", newY, newY - bp.top);
01181   }
01182 #endif
01183 
01184   return newY;
01185 }
01186