forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1037 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1037 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| // vim:cindent:ts=2:et:sw=2:
 | |
| /* ***** BEGIN LICENSE BLOCK *****
 | |
|  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 | |
|  *
 | |
|  * The contents of this file are subject to the Netscape Public License
 | |
|  * Version 1.1 (the "License"); you may not use this file except in
 | |
|  * compliance with the License. You may obtain a copy of the License at
 | |
|  * http://www.mozilla.org/NPL/
 | |
|  *
 | |
|  * Software distributed under the License is distributed on an "AS IS" basis,
 | |
|  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | |
|  * for the specific language governing rights and limitations under the
 | |
|  * License.
 | |
|  *
 | |
|  * The Original Code is Mozilla Communicator client code.
 | |
|  *
 | |
|  * The Initial Developer of the Original Code is 
 | |
|  * Netscape Communications Corporation.
 | |
|  * Portions created by the Initial Developer are Copyright (C) 1998
 | |
|  * the Initial Developer. All Rights Reserved.
 | |
|  *
 | |
|  * Contributor(s):
 | |
|  *   Steve Clark <buster@netscape.com>
 | |
|  *   Robert O'Callahan <roc+moz@cs.cmu.edu>
 | |
|  *   L. David Baron <dbaron@fas.harvard.edu>
 | |
|  *
 | |
|  * Alternatively, the contents of this file may be used under the terms of
 | |
|  * either the GNU General Public License Version 2 or later (the "GPL"), or 
 | |
|  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | |
|  * in which case the provisions of the GPL or the LGPL are applicable instead
 | |
|  * of those above. If you wish to allow use of your version of this file only
 | |
|  * under the terms of either the GPL or the LGPL, and not to allow others to
 | |
|  * use your version of this file under the terms of the NPL, indicate your
 | |
|  * decision by deleting the provisions above and replace them with the notice
 | |
|  * and other provisions required by the GPL or the LGPL. If you do not delete
 | |
|  * the provisions above, a recipient may use your version of this file under
 | |
|  * the terms of any one of the NPL, the GPL or the LGPL.
 | |
|  *
 | |
|  * ***** END LICENSE BLOCK ***** */
 | |
| 
 | |
| #include "nsBlockReflowContext.h"
 | |
| #include "nsBlockReflowState.h"
 | |
| #include "nsBlockFrame.h"
 | |
| #include "nsLineLayout.h"
 | |
| #include "nsIPresContext.h"
 | |
| #include "nsLayoutAtoms.h"
 | |
| #include "nsIFrame.h"
 | |
| 
 | |
| #ifdef DEBUG
 | |
| #include "nsBlockDebugFlags.h"
 | |
| #endif
 | |
| 
 | |
| nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
 | |
|                                        nsIPresContext* aPresContext,
 | |
|                                        nsBlockFrame* aFrame,
 | |
|                                        const nsHTMLReflowMetrics& aMetrics,
 | |
|                                        PRBool aBlockMarginRoot)
 | |
|   : mBlock(aFrame),
 | |
|     mPresContext(aPresContext),
 | |
|     mReflowState(aReflowState),
 | |
|     mLastFloaterY(0),
 | |
|     mNextRCFrame(nsnull),
 | |
|     mPrevBottomMargin(),
 | |
|     mLineNumber(0),
 | |
|     mFlags(0)
 | |
| {
 | |
|   const nsMargin& borderPadding = BorderPadding();
 | |
| 
 | |
|   if (aBlockMarginRoot) {
 | |
|     SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
 | |
|     SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
 | |
|   }
 | |
|   if (0 != aReflowState.mComputedBorderPadding.top) {
 | |
|     SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
 | |
|   }
 | |
|   if (0 != aReflowState.mComputedBorderPadding.bottom) {
 | |
|     SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
 | |
|   }
 | |
|   if (GetFlag(BRS_ISTOPMARGINROOT)) {
 | |
|     SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
 | |
|   }
 | |
|   
 | |
|   mSpaceManager = aReflowState.mSpaceManager;
 | |
| 
 | |
|   NS_ASSERTION(mSpaceManager,
 | |
|                "SpaceManager should be set in nsBlockReflowState" );
 | |
|   if (mSpaceManager) {
 | |
|     // Translate into our content area and then save the 
 | |
|     // coordinate system origin for later.
 | |
|     mSpaceManager->Translate(borderPadding.left, borderPadding.top);
 | |
|     mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY);
 | |
|   }
 | |
| 
 | |
|   mReflowStatus = NS_FRAME_COMPLETE;
 | |
| 
 | |
|   mPresContext = aPresContext;
 | |
|   mBlock->GetNextInFlow(NS_REINTERPRET_CAST(nsIFrame**, &mNextInFlow));
 | |
|   mKidXMost = 0;
 | |
| 
 | |
|   // Compute content area width (the content area is inside the border
 | |
|   // and padding)
 | |
|   if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
 | |
|     mContentArea.width = aReflowState.mComputedWidth;
 | |
|   }
 | |
|   else {
 | |
|     if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
 | |
|       mContentArea.width = NS_UNCONSTRAINEDSIZE;
 | |
|       SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
 | |
|     }
 | |
|     else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
 | |
|       // Choose a width based on the content (shrink wrap width) up
 | |
|       // to the maximum width
 | |
|       mContentArea.width = aReflowState.mComputedMaxWidth;
 | |
|       SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
 | |
|     }
 | |
|     else {
 | |
|       nscoord lr = borderPadding.left + borderPadding.right;
 | |
|       mContentArea.width = aReflowState.availableWidth - lr;
 | |
|     }
 | |
|   }
 | |
|   mHaveRightFloaters = PR_FALSE;
 | |
| 
 | |
|   // Compute content area height. Unlike the width, if we have a
 | |
|   // specified style height we ignore it since extra content is
 | |
|   // managed by the "overflow" property. When we don't have a
 | |
|   // specified style height then we may end up limiting our height if
 | |
|   // the availableHeight is constrained (this situation occurs when we
 | |
|   // are paginated).
 | |
|   if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
 | |
|     // We are in a paginated situation. The bottom edge is just inside
 | |
|     // the bottom border and padding. The content area height doesn't
 | |
|     // include either border or padding edge.
 | |
|     mBottomEdge = aReflowState.availableHeight - borderPadding.bottom;
 | |
|     mContentArea.height = mBottomEdge - borderPadding.top;
 | |
|   }
 | |
|   else {
 | |
|     // When we are not in a paginated situation then we always use
 | |
|     // an constrained height.
 | |
|     SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
 | |
|     mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
 | |
|   }
 | |
| 
 | |
|   mY = borderPadding.top;
 | |
|   mBand.Init(mSpaceManager, mContentArea);
 | |
| 
 | |
|   mPrevChild = nsnull;
 | |
|   mCurrentLine = aFrame->end_lines();
 | |
| 
 | |
|   const nsStyleText* styleText;
 | |
|   mBlock->GetStyleData(eStyleStruct_Text,
 | |
|                        (const nsStyleStruct*&) styleText);
 | |
|   switch (styleText->mWhiteSpace) {
 | |
|   case NS_STYLE_WHITESPACE_PRE:
 | |
|   case NS_STYLE_WHITESPACE_NOWRAP:
 | |
|     SetFlag(BRS_NOWRAP, PR_TRUE);
 | |
|     break;
 | |
|   default:
 | |
|     SetFlag(BRS_NOWRAP, PR_FALSE);
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
 | |
| #ifdef NOISY_MAX_ELEMENT_SIZE
 | |
|   printf("BRS: setting compute-MES to %d\n", (nsnull != aMetrics.maxElementSize));
 | |
| #endif
 | |
|   mMaxElementSize.SizeTo(0, 0);
 | |
|   SetFlag(BRS_COMPUTEMAXWIDTH, 
 | |
|           (NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
 | |
|   mMaximumWidth = 0;
 | |
| 
 | |
|   mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
 | |
|                                                      aReflowState.rendContext,
 | |
|                                                      aReflowState.frame);
 | |
| }
 | |
| 
 | |
| nsBlockReflowState::~nsBlockReflowState()
 | |
| {
 | |
|   // Restore the coordinate system
 | |
|   const nsMargin& borderPadding = BorderPadding();
 | |
|   mSpaceManager->Translate(-borderPadding.left, -borderPadding.top);
 | |
| }
 | |
| 
 | |
| nsLineBox*
 | |
| nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
 | |
|                                PRInt32 aCount,
 | |
|                                PRBool aIsBlock)
 | |
| {
 | |
|   nsCOMPtr<nsIPresShell> shell;
 | |
|   mPresContext->GetShell(getter_AddRefs(shell));
 | |
| 
 | |
|   return NS_NewLineBox(shell, aFrame, aCount, aIsBlock);
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::FreeLineBox(nsLineBox* aLine)
 | |
| {
 | |
|   if (aLine) {
 | |
|     nsCOMPtr<nsIPresShell> presShell;
 | |
|     mPresContext->GetShell(getter_AddRefs(presShell));
 | |
|     
 | |
|     aLine->Destroy(presShell);
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Compute the amount of available space for reflowing a block frame
 | |
| // at the current Y coordinate. This method assumes that
 | |
| // GetAvailableSpace has already been called.
 | |
| void
 | |
| nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
 | |
|                                            nsSplittableType aSplitType,
 | |
|                                            const nsStyleDisplay* aDisplay,
 | |
|                                            nsRect& aResult)
 | |
| {
 | |
| #ifdef REALLY_NOISY_REFLOW
 | |
|   printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
 | |
|   mBand.List();
 | |
| #endif
 | |
|   aResult.y = mY;
 | |
|   aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
 | |
|     ? NS_UNCONSTRAINEDSIZE
 | |
|     : mBottomEdge - mY;
 | |
| 
 | |
|   const nsMargin& borderPadding = BorderPadding();
 | |
| 
 | |
|   /* bug 18445: treat elements mapped to display: block such as text controls
 | |
|    * just like normal blocks   */
 | |
|   PRBool treatAsNotSplittable=PR_FALSE;
 | |
|   nsCOMPtr<nsIAtom>frameType;
 | |
|   aFrame->GetFrameType(getter_AddRefs(frameType));
 | |
|   if (frameType) {
 | |
|     // text controls are not splittable, so make a special case here
 | |
|     // XXXldb Why not just set the frame state bit?
 | |
|     if (nsLayoutAtoms::textInputFrame == frameType.get())
 | |
|       treatAsNotSplittable = PR_TRUE;
 | |
|   }
 | |
| 
 | |
|   if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType ||    // normal blocks 
 | |
|       NS_FRAME_NOT_SPLITTABLE == aSplitType ||                // things like images mapped to display: block
 | |
|       PR_TRUE == treatAsNotSplittable)                        // text input controls mapped to display: block (special case)
 | |
|   {
 | |
|     if (mBand.GetFloaterCount()) {
 | |
|       // Use the float-edge property to determine how the child block
 | |
|       // will interact with the floater.
 | |
|       const nsStyleBorder* borderStyle;
 | |
|       aFrame->GetStyleData(eStyleStruct_Border,
 | |
|                            (const nsStyleStruct*&) borderStyle);
 | |
|       switch (borderStyle->mFloatEdge) {
 | |
|         default:
 | |
|         case NS_STYLE_FLOAT_EDGE_CONTENT:  // content and only content does runaround of floaters
 | |
|           // The child block will flow around the floater. Therefore
 | |
|           // give it all of the available space.
 | |
|           aResult.x = borderPadding.left;
 | |
|           aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
 | |
|             ? NS_UNCONSTRAINEDSIZE
 | |
|             : mContentArea.width;
 | |
|            break;
 | |
|         case NS_STYLE_FLOAT_EDGE_BORDER: 
 | |
|         case NS_STYLE_FLOAT_EDGE_PADDING:
 | |
|           {
 | |
|             // The child block's border should be placed adjacent to,
 | |
|             // but not overlap the floater(s).
 | |
|             nsMargin m(0, 0, 0, 0);
 | |
|             const nsStyleMargin* styleMargin;
 | |
|             aFrame->GetStyleData(eStyleStruct_Margin,
 | |
|                                  (const nsStyleStruct*&) styleMargin);
 | |
|             styleMargin->GetMargin(m); // XXX percentage margins
 | |
|             if (NS_STYLE_FLOAT_EDGE_PADDING == borderStyle->mFloatEdge) {
 | |
|               // Add in border too
 | |
|               nsMargin b;
 | |
|               borderStyle->GetBorder(b);
 | |
|               m += b;
 | |
|             }
 | |
| 
 | |
|             // determine left edge
 | |
|             if (mBand.GetLeftFloaterCount()) {
 | |
|               aResult.x = mAvailSpaceRect.x + borderPadding.left - m.left;
 | |
|             }
 | |
|             else {
 | |
|               aResult.x = borderPadding.left;
 | |
|             }
 | |
| 
 | |
|             // determine width
 | |
|             if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
 | |
|               aResult.width = NS_UNCONSTRAINEDSIZE;
 | |
|             }
 | |
|             else {
 | |
|               if (mBand.GetRightFloaterCount()) {
 | |
|                 if (mBand.GetLeftFloaterCount()) {
 | |
|                   aResult.width = mAvailSpaceRect.width + m.left + m.right;
 | |
|                 }
 | |
|                 else {
 | |
|                   aResult.width = mAvailSpaceRect.width + m.right;
 | |
|                 }
 | |
|               }
 | |
|               else {
 | |
|                 aResult.width = mAvailSpaceRect.width + m.left;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
| 
 | |
|         case NS_STYLE_FLOAT_EDGE_MARGIN:
 | |
|           {
 | |
|             // The child block's margins should be placed adjacent to,
 | |
|             // but not overlap the floater.
 | |
|             aResult.x = mAvailSpaceRect.x + borderPadding.left;
 | |
|             aResult.width = mAvailSpaceRect.width;
 | |
|           }
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       // Since there are no floaters present the float-edge property
 | |
|       // doesn't matter therefore give the block element all of the
 | |
|       // available space since it will flow around the floater itself.
 | |
|       aResult.x = borderPadding.left;
 | |
|       aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
 | |
|         ? NS_UNCONSTRAINEDSIZE
 | |
|         : mContentArea.width;
 | |
|     }
 | |
|   }
 | |
|   else {
 | |
|     // The frame is clueless about the space manager and therefore we
 | |
|     // only give it free space. An example is a table frame - the
 | |
|     // tables do not flow around floaters.
 | |
|     aResult.x = mAvailSpaceRect.x + borderPadding.left;
 | |
|     aResult.width = mAvailSpaceRect.width;
 | |
|   }
 | |
| #ifdef REALLY_NOISY_REFLOW
 | |
|   printf("  CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::GetAvailableSpace(nscoord aY)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|   // Verify that the caller setup the coordinate system properly
 | |
|   nscoord wx, wy;
 | |
|   mSpaceManager->GetTranslation(wx, wy);
 | |
|   NS_ASSERTION((wx == mSpaceManagerX) && (wy == mSpaceManagerY),
 | |
|                "bad coord system");
 | |
| #endif
 | |
| 
 | |
|   mBand.GetAvailableSpace(aY - BorderPadding().top, mAvailSpaceRect);
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   if (nsBlockFrame::gNoisyReflow) {
 | |
|     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|     printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n",
 | |
|            mAvailSpaceRect.x, mAvailSpaceRect.y,
 | |
|            mAvailSpaceRect.width, mAvailSpaceRect.height,
 | |
|            mBand.GetTrapezoidCount());
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| PRBool
 | |
| nsBlockReflowState::ClearPastFloaters(PRUint8 aBreakType)
 | |
| {
 | |
|   nscoord saveY, deltaY;
 | |
| 
 | |
|   PRBool applyTopMargin = PR_FALSE;
 | |
|   switch (aBreakType) {
 | |
|   case NS_STYLE_CLEAR_LEFT:
 | |
|   case NS_STYLE_CLEAR_RIGHT:
 | |
|   case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
 | |
|     // Apply the previous margin before clearing
 | |
|     saveY = mY + mPrevBottomMargin.get();
 | |
|     ClearFloaters(saveY, aBreakType);
 | |
| #ifdef NOISY_FLOATER_CLEARING
 | |
|     nsFrame::ListTag(stdout, mBlock);
 | |
|     printf(": ClearPastFloaters: mPrevBottomMargin=%d saveY=%d oldY=%d newY=%d deltaY=%d\n",
 | |
|            mPrevBottomMargin, saveY, saveY - mPrevBottomMargin, mY,
 | |
|            mY - saveY);
 | |
| #endif
 | |
| 
 | |
|     // Determine how far we just moved. If we didn't move then there
 | |
|     // was nothing to clear to don't mess with the normal margin
 | |
|     // collapsing behavior. In either case we need to restore the Y
 | |
|     // coordinate to what it was before the clear.
 | |
|     deltaY = mY - saveY;
 | |
|     if (0 != deltaY) {
 | |
|       // Pretend that the distance we just moved is a previous
 | |
|       // blocks bottom margin. Note that GetAvailableSpace has been
 | |
|       // done so that the available space calculations will be done
 | |
|       // after clearing the appropriate floaters.
 | |
|       //
 | |
|       // What we are doing here is applying CSS2 section 9.5.2's
 | |
|       // rules for clearing - "The top margin of the generated box
 | |
|       // is increased enough that the top border edge is below the
 | |
|       // bottom outer edge of the floating boxes..."
 | |
|       //
 | |
|       // What this will do is cause the top-margin of the block
 | |
|       // frame we are about to reflow to be collapsed with that
 | |
|       // distance.
 | |
|       
 | |
|       // XXXldb This doesn't handle collapsing with negative margins
 | |
|       // correctly, although it's arguable what "correct" is.
 | |
| 
 | |
|       // XXX Are all the other margins included by this point?
 | |
|       mPrevBottomMargin.Zero();
 | |
|       mPrevBottomMargin.Include(deltaY);
 | |
|       mY = saveY;
 | |
| 
 | |
|       // Force margin to be applied in this circumstance
 | |
|       applyTopMargin = PR_TRUE;
 | |
|     }
 | |
|     else {
 | |
|       // Put mY back to its original value since no clearing
 | |
|       // happened. That way the previous blocks bottom margin will
 | |
|       // be applied properly.
 | |
|       mY = saveY - mPrevBottomMargin.get();
 | |
|     }
 | |
|     break;
 | |
|   }
 | |
|   return applyTopMargin;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Reconstruct the vertical margin before the line |aLine| in order to
 | |
|  * do an incremental reflow that begins with |aLine| without reflowing
 | |
|  * the line before it.  |aLine| may point to the fencepost at the end of
 | |
|  * the line list, and it is used this way since we (for now, anyway)
 | |
|  * always need to recover margins at the end of a block.
 | |
|  *
 | |
|  * The reconstruction involves walking backward through the line list to
 | |
|  * find any collapsed margins preceding the line that would have been in
 | |
|  * the reflow state's |mPrevBottomMargin| when we reflowed that line in
 | |
|  * a full reflow (under the rule in CSS2 that all adjacent vertical
 | |
|  * margins of blocks collapse).
 | |
|  */
 | |
| void
 | |
| nsBlockReflowState::ReconstructMarginAbove(nsLineList::iterator aLine)
 | |
| {
 | |
|   mPrevBottomMargin.Zero();
 | |
|   nsBlockFrame *block = mBlock;
 | |
| 
 | |
|   const nsStyleText* styleText = NS_STATIC_CAST(const nsStyleText*,
 | |
|       block->mStyleContext->GetStyleData(eStyleStruct_Text));
 | |
|   PRBool isPre =
 | |
|       ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
 | |
|        (NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace));
 | |
| 
 | |
|   nsCompatibility mode;
 | |
|   mPresContext->GetCompatibilityMode(&mode);
 | |
|   PRBool isQuirkMode = mode == eCompatibility_NavQuirks;
 | |
| 
 | |
|   nsLineList::iterator firstLine = block->begin_lines();
 | |
|   for (;;) {
 | |
|     --aLine;
 | |
|     if (aLine->IsBlock()) {
 | |
|       mPrevBottomMargin = aLine->GetCarriedOutBottomMargin();
 | |
|       break;
 | |
|     }
 | |
|     PRBool isEmpty;
 | |
|     aLine->IsEmpty(isQuirkMode, isPre, &isEmpty);
 | |
|     if (! isEmpty) {
 | |
|       break;
 | |
|     }
 | |
|     if (aLine == firstLine) {
 | |
|       // If the top margin was carried out (and thus already applied),
 | |
|       // set it to zero.  Either way, we're done.
 | |
|       if ((0 == mReflowState.mComputedBorderPadding.top) &&
 | |
|           !(block->mState & NS_BLOCK_MARGIN_ROOT)) {
 | |
|         mPrevBottomMargin.Zero();
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
 | |
|                                      nscoord aDeltaY)
 | |
| {
 | |
|   // Make the line being recovered the current line
 | |
|   mCurrentLine = aLine;
 | |
| 
 | |
|   // Update aState.mPrevChild as if we had reflowed all of the frames
 | |
|   // in this line.
 | |
|   // XXXldb This is expensive in some cases, since it requires walking
 | |
|   // |GetNextSibling|.
 | |
|   mPrevChild = aLine->LastChild();
 | |
| 
 | |
|   // Recover mKidXMost and mMaxElementSize
 | |
|   nscoord xmost = aLine->mBounds.XMost();
 | |
|   if (xmost > mKidXMost) {
 | |
| #ifdef DEBUG
 | |
|     if (CRAZY_WIDTH(xmost)) {
 | |
|       nsFrame::ListTag(stdout, mBlock);
 | |
|       printf(": WARNING: xmost:%d\n", xmost);
 | |
|     }
 | |
| #endif
 | |
| #ifdef NOISY_KIDXMOST
 | |
|     printf("%p RecoverState block %p aState.mKidXMost=%d\n", this, mBlock, xmost); 
 | |
| #endif
 | |
|     mKidXMost = xmost;
 | |
|   }
 | |
|   if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
 | |
| #ifdef NOISY_MAX_ELEMENT_SIZE
 | |
|     printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaxElementWidth);
 | |
| #endif
 | |
|     UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
 | |
|   }
 | |
| 
 | |
|   // If computing the maximum width, then update mMaximumWidth
 | |
|   if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
 | |
| #ifdef NOISY_MAXIMUM_WIDTH
 | |
|     printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaximumWidth);
 | |
| #endif
 | |
|     UpdateMaximumWidth(aLine->mMaximumWidth);
 | |
|   }
 | |
| 
 | |
|   // Place floaters for this line into the space manager
 | |
|   if (aLine->HasFloaters()) {
 | |
|     // Undo border/padding translation since the nsFloaterCache's
 | |
|     // coordinates are relative to the frame not relative to the
 | |
|     // border/padding.
 | |
|     const nsMargin& bp = BorderPadding();
 | |
|     mSpaceManager->Translate(-bp.left, -bp.top);
 | |
| 
 | |
|     // Place the floaters into the space-manager again. Also slide
 | |
|     // them, just like the regular frames on the line.
 | |
|     nsRect r;
 | |
|     nsFloaterCache* fc = aLine->GetFirstFloater();
 | |
|     while (fc) {
 | |
|       fc->mRegion.y += aDeltaY;
 | |
|       fc->mCombinedArea.y += aDeltaY;
 | |
|       nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
 | |
|       floater->GetRect(r);
 | |
|       floater->MoveTo(mPresContext, r.x, r.y + aDeltaY);
 | |
| #ifdef DEBUG
 | |
|       if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisySpaceManager) {
 | |
|         nscoord tx, ty;
 | |
|         mSpaceManager->GetTranslation(tx, ty);
 | |
|         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|         printf("RecoverState: txy=%d,%d (%d,%d) ",
 | |
|                tx, ty, mSpaceManagerX, mSpaceManagerY);
 | |
|         nsFrame::ListTag(stdout, floater);
 | |
|         printf(" r.y=%d aDeltaY=%d (sum=%d) region={%d,%d,%d,%d}\n",
 | |
|                r.y, aDeltaY, r.y + aDeltaY,
 | |
|                fc->mRegion.x, fc->mRegion.y,
 | |
|                fc->mRegion.width, fc->mRegion.height);
 | |
|       }
 | |
| #endif
 | |
|       mSpaceManager->AddRectRegion(floater, fc->mRegion);
 | |
|       mLastFloaterY = fc->mRegion.y;
 | |
|       fc = fc->Next();
 | |
|     }
 | |
| #ifdef DEBUG
 | |
|     if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisySpaceManager) {
 | |
|       mSpaceManager->List(stdout);
 | |
|     }
 | |
| #endif
 | |
|     // And then put the translation back again
 | |
|     mSpaceManager->Translate(bp.left, bp.top);
 | |
|   }
 | |
| }
 | |
| 
 | |
| PRBool
 | |
| nsBlockReflowState::IsImpactedByFloater() const
 | |
| {
 | |
| #ifdef REALLY_NOISY_REFLOW
 | |
|   printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", 
 | |
|          this, mBand.GetFloaterCount());
 | |
| #endif
 | |
|   return mBand.GetFloaterCount() > 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
 | |
|                                 nsPlaceholderFrame* aPlaceholder)
 | |
| {
 | |
|   // Set the geometric parent of the floater
 | |
|   nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
 | |
|   floater->SetParent(mBlock);
 | |
| 
 | |
|   // Then add the floater to the current line and place it when
 | |
|   // appropriate
 | |
|   AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
 | |
| }
 | |
| 
 | |
| // This is called by the line layout's AddFloater method when a
 | |
| // place-holder frame is reflowed in a line. If the floater is a
 | |
| // left-most child (it's x coordinate is at the line's left margin)
 | |
| // then the floater is place immediately, otherwise the floater
 | |
| // placement is deferred until the line has been reflowed.
 | |
| 
 | |
| // XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
 | |
| // technically we're supposed let the current line flow around the
 | |
| // float as well unless it won't fit next to what we already have.
 | |
| // But nobody else implements it that way...
 | |
| void
 | |
| nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
 | |
|                                nsPlaceholderFrame* aPlaceholder,
 | |
|                                PRBool aInitialReflow)
 | |
| {
 | |
|   NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
 | |
| 
 | |
|   // Allocate a nsFloaterCache for the floater
 | |
|   nsFloaterCache* fc = mFloaterCacheFreeList.Alloc();
 | |
|   fc->mPlaceholder = aPlaceholder;
 | |
|   fc->mIsCurrentLineFloater = aLineLayout.CanPlaceFloaterNow();
 | |
| 
 | |
|   // Now place the floater immediately if possible. Otherwise stash it
 | |
|   // away in mPendingFloaters and place it later.
 | |
|   if (fc->mIsCurrentLineFloater) {
 | |
|     // Record this floater in the current-line list
 | |
|     mCurrentLineFloaters.Append(fc);
 | |
| 
 | |
|     // Because we are in the middle of reflowing a placeholder frame
 | |
|     // within a line (and possibly nested in an inline frame or two
 | |
|     // that's a child of our block) we need to restore the space
 | |
|     // manager's translation to the space that the block resides in
 | |
|     // before placing the floater.
 | |
|     nscoord ox, oy;
 | |
|     mSpaceManager->GetTranslation(ox, oy);
 | |
|     nscoord dx = ox - mSpaceManagerX;
 | |
|     nscoord dy = oy - mSpaceManagerY;
 | |
|     mSpaceManager->Translate(-dx, -dy);
 | |
| 
 | |
|     // And then place it
 | |
|     PRBool isLeftFloater;
 | |
|     FlowAndPlaceFloater(fc, &isLeftFloater);    
 | |
| 
 | |
|     // Pass on updated available space to the current inline reflow engine
 | |
|     GetAvailableSpace();
 | |
|     aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
 | |
|                            GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
 | |
|                            mAvailSpaceRect.height,
 | |
|                            isLeftFloater,
 | |
|                            aPlaceholder->GetOutOfFlowFrame());
 | |
| 
 | |
|     // Restore coordinate system
 | |
|     mSpaceManager->Translate(dx, dy);
 | |
|   }
 | |
|   else {
 | |
|     // This floater will be placed after the line is done (it is a
 | |
|     // below-current-line floater).
 | |
|     mBelowCurrentLineFloaters.Append(fc);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::UpdateMaxElementSize(const nsSize& aMaxElementSize)
 | |
| {
 | |
| #ifdef NOISY_MAX_ELEMENT_SIZE
 | |
|   nsSize oldSize = mMaxElementSize;
 | |
| #endif
 | |
|   if (aMaxElementSize.width > mMaxElementSize.width) {
 | |
|     mMaxElementSize.width = aMaxElementSize.width;
 | |
|   }
 | |
|   if (aMaxElementSize.height > mMaxElementSize.height) {
 | |
|     mMaxElementSize.height = aMaxElementSize.height;
 | |
|   }
 | |
| #ifdef NOISY_MAX_ELEMENT_SIZE
 | |
|   if ((mMaxElementSize.width != oldSize.width) ||
 | |
|       (mMaxElementSize.height != oldSize.height)) {
 | |
|     nsFrame::IndentBy(stdout, mBlock->GetDepth());
 | |
|     if (NS_UNCONSTRAINEDSIZE == mReflowState.availableWidth) {
 | |
|       printf("PASS1 ");
 | |
|     }
 | |
|     nsFrame::ListTag(stdout, mBlock);
 | |
|     printf(": old max-element-size=%d,%d new=%d,%d\n",
 | |
|            oldSize.width, oldSize.height,
 | |
|            mMaxElementSize.width, mMaxElementSize.height);
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::UpdateMaximumWidth(nscoord aMaximumWidth)
 | |
| {
 | |
|   if (aMaximumWidth > mMaximumWidth) {
 | |
| #ifdef NOISY_MAXIMUM_WIDTH
 | |
|     printf("nsBlockReflowState::UpdateMaximumWidth block %p caching max width %d\n", mBlock, aMaximumWidth);
 | |
| #endif
 | |
|     mMaximumWidth = aMaximumWidth;
 | |
|   }
 | |
| }
 | |
| 
 | |
| PRBool
 | |
| nsBlockReflowState::CanPlaceFloater(const nsRect& aFloaterRect,
 | |
|                                     PRUint8 aFloats)
 | |
| {
 | |
|   // If the current Y coordinate is not impacted by any floaters
 | |
|   // then by definition the floater fits.
 | |
|   PRBool result = PR_TRUE;
 | |
|   if (0 != mBand.GetFloaterCount()) {
 | |
|     // XXX We should allow overflow by up to half a pixel here (bug 21193).
 | |
|     if (mAvailSpaceRect.width < aFloaterRect.width) {
 | |
|       // The available width is too narrow (and its been impacted by a
 | |
|       // prior floater)
 | |
|       result = PR_FALSE;
 | |
|     }
 | |
|     else {
 | |
|       // At this point we know that there is enough horizontal space for
 | |
|       // the floater (somewhere). Lets see if there is enough vertical
 | |
|       // space.
 | |
|       if (mAvailSpaceRect.height < aFloaterRect.height) {
 | |
|         // The available height is too short. However, its possible that
 | |
|         // there is enough open space below which is not impacted by a
 | |
|         // floater.
 | |
|         //
 | |
|         // Compute the X coordinate for the floater based on its float
 | |
|         // type, assuming its placed on the current line. This is
 | |
|         // where the floater will be placed horizontally if it can go
 | |
|         // here.
 | |
|         nscoord xa;
 | |
|         if (NS_STYLE_FLOAT_LEFT == aFloats) {
 | |
|           xa = mAvailSpaceRect.x;
 | |
|         }
 | |
|         else {
 | |
|           xa = mAvailSpaceRect.XMost() - aFloaterRect.width;
 | |
| 
 | |
|           // In case the floater is too big, don't go past the left edge
 | |
|           if (xa < mAvailSpaceRect.x) {
 | |
|             xa = mAvailSpaceRect.x;
 | |
|           }
 | |
|         }
 | |
|         nscoord xb = xa + aFloaterRect.width;
 | |
| 
 | |
|         // Calculate the top and bottom y coordinates, again assuming
 | |
|         // that the floater is placed on the current line.
 | |
|         const nsMargin& borderPadding = BorderPadding();
 | |
|         nscoord ya = mY - borderPadding.top;
 | |
|         if (ya < 0) {
 | |
|           // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
 | |
|           // be higher than the top of its containing block."  (Since the
 | |
|           // containing block is the content edge of the block box, this
 | |
|           // means the margin edge of the floater can't be higher than the
 | |
|           // content edge of the block that contains it.)
 | |
|           ya = 0;
 | |
|         }
 | |
|         nscoord yb = ya + aFloaterRect.height;
 | |
| 
 | |
|         nscoord saveY = mY;
 | |
|         for (;;) {
 | |
|           // Get the available space at the new Y coordinate
 | |
|           mY += mAvailSpaceRect.height;
 | |
|           GetAvailableSpace();
 | |
| 
 | |
|           if (0 == mBand.GetFloaterCount()) {
 | |
|             // Winner. This band has no floaters on it, therefore
 | |
|             // there can be no overlap.
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           // Check and make sure the floater won't intersect any
 | |
|           // floaters on this band. The floaters starting and ending
 | |
|           // coordinates must be entirely in the available space.
 | |
|           if ((xa < mAvailSpaceRect.x) || (xb > mAvailSpaceRect.XMost())) {
 | |
|             // The floater can't go here.
 | |
|             result = PR_FALSE;
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           // See if there is now enough height for the floater.
 | |
|           if (yb < mY + mAvailSpaceRect.height) {
 | |
|             // Winner. The bottom Y coordinate of the floater is in
 | |
|             // this band.
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         // Restore Y coordinate and available space information
 | |
|         // regardless of the outcome.
 | |
|         mY = saveY;
 | |
|         GetAvailableSpace();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::FlowAndPlaceFloater(nsFloaterCache* aFloaterCache,
 | |
|                                         PRBool* aIsLeftFloater)
 | |
| {
 | |
|   // Save away the Y coordinate before placing the floater. We will
 | |
|   // restore mY at the end after placing the floater. This is
 | |
|   // necessary because any adjustments to mY during the floater
 | |
|   // placement are for the floater only, not for any non-floating
 | |
|   // content.
 | |
|   nscoord saveY = mY;
 | |
| 
 | |
|   // Grab the compatibility mode
 | |
|   nsCompatibility mode;
 | |
|   mPresContext->GetCompatibilityMode(&mode);
 | |
| 
 | |
|   nsIFrame* floater = aFloaterCache->mPlaceholder->GetOutOfFlowFrame();
 | |
| 
 | |
|   // Grab the floater's display information
 | |
|   const nsStyleDisplay* floaterDisplay;
 | |
|   floater->GetStyleData(eStyleStruct_Display,
 | |
|                         (const nsStyleStruct*&)floaterDisplay);
 | |
| 
 | |
|   // This will hold the floater's geometry when we've found a place
 | |
|   // for it to live.
 | |
|   nsRect region;
 | |
| 
 | |
|   // Advance mY to mLastFloaterY (if it's not past it already) to
 | |
|   // enforce 9.5.1 rule [2]; i.e., make sure that a float isn't
 | |
|   // ``above'' another float that preceded it in the flow.
 | |
|   mY = NS_MAX(mLastFloaterY, mY);
 | |
| 
 | |
|   // See if the floater should clear any preceeding floaters...
 | |
|   if (NS_STYLE_CLEAR_NONE != floaterDisplay->mBreakType) {
 | |
|     // XXXldb Does this handle vertical margins correctly?
 | |
|     ClearFloaters(mY, floaterDisplay->mBreakType);
 | |
|   }
 | |
|   else {
 | |
|     // Get the band of available space
 | |
|     GetAvailableSpace();
 | |
|   }
 | |
| 
 | |
|   // Reflow the floater
 | |
|   mBlock->ReflowFloater(*this, aFloaterCache->mPlaceholder, aFloaterCache->mCombinedArea,
 | |
| 			aFloaterCache->mMargins, aFloaterCache->mOffsets);
 | |
| 
 | |
|   // Get the floaters bounding box and margin information
 | |
|   floater->GetRect(region);
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   if (nsBlockFrame::gNoisyReflow) {
 | |
|     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|     printf("flowed floater: ");
 | |
|     nsFrame::ListTag(stdout, floater);
 | |
|     printf(" (%d,%d,%d,%d)\n",
 | |
| 	   region.x, region.y, region.width, region.height);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   // Adjust the floater size by its margin. That's the area that will
 | |
|   // impact the space manager.
 | |
|   region.width += aFloaterCache->mMargins.left + aFloaterCache->mMargins.right;
 | |
|   region.height += aFloaterCache->mMargins.top + aFloaterCache->mMargins.bottom;
 | |
| 
 | |
|   // Find a place to place the floater. The CSS2 spec doesn't want
 | |
|   // floaters overlapping each other or sticking out of the containing
 | |
|   // block if possible (CSS2 spec section 9.5.1, see the rule list).
 | |
|   NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) ||
 | |
| 	       (NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats),
 | |
| 	       "invalid float type");
 | |
| 
 | |
|   // In backwards compatibility mode, we don't bother to see if a
 | |
|   // floated table can ``really'' fit: in old browsers, floating
 | |
|   // tables are horizontally stacked regardless of available space.
 | |
|   // (See bug 43086 about tables vs. non-tables.)
 | |
|   if ((eCompatibility_NavQuirks != mode) ||
 | |
|       (NS_STYLE_DISPLAY_TABLE != floaterDisplay->mDisplay)) {
 | |
|     // Can the floater fit here?
 | |
|     while (! CanPlaceFloater(region, floaterDisplay->mFloats)) {
 | |
|       // Nope. Advance to the next band.
 | |
|       mY += mAvailSpaceRect.height;
 | |
|       GetAvailableSpace();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Assign an x and y coordinate to the floater. Note that the x,y
 | |
|   // coordinates are computed <b>relative to the translation in the
 | |
|   // spacemanager</b> which means that the impacted region will be
 | |
|   // <b>inside</b> the border/padding area.
 | |
|   PRBool okToAddRectRegion = PR_TRUE;
 | |
|   PRBool isLeftFloater;
 | |
|   if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) {
 | |
|     isLeftFloater = PR_TRUE;
 | |
|     region.x = mAvailSpaceRect.x;
 | |
|   }
 | |
|   else {
 | |
|     isLeftFloater = PR_FALSE;
 | |
|     if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
 | |
|       region.x = mAvailSpaceRect.XMost() - region.width;
 | |
|     else {
 | |
|       okToAddRectRegion = PR_FALSE;
 | |
|       region.x = mAvailSpaceRect.x;
 | |
|     }
 | |
|   }
 | |
|   *aIsLeftFloater = isLeftFloater;
 | |
|   const nsMargin& borderPadding = BorderPadding();
 | |
|   region.y = mY - borderPadding.top;
 | |
|   if (region.y < 0) {
 | |
|     // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
 | |
|     // be higher than the top of its containing block."  (Since the
 | |
|     // containing block is the content edge of the block box, this
 | |
|     // means the margin edge of the floater can't be higher than the
 | |
|     // content edge of the block that contains it.)
 | |
|     region.y = 0;
 | |
|   }
 | |
| 
 | |
|   // Place the floater in the space manager
 | |
|   if (okToAddRectRegion) {
 | |
| #ifdef DEBUG
 | |
|     nsresult rv =
 | |
| #endif
 | |
|     mSpaceManager->AddRectRegion(floater, region);
 | |
|     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
 | |
|   }
 | |
| 
 | |
|   // Save away the floaters region in the spacemanager, after making
 | |
|   // it relative to the containing block's frame instead of relative
 | |
|   // to the spacemanager translation (which is inset by the
 | |
|   // border+padding).
 | |
|   aFloaterCache->mRegion.x = region.x + borderPadding.left;
 | |
|   aFloaterCache->mRegion.y = region.y + borderPadding.top;
 | |
|   aFloaterCache->mRegion.width = region.width;
 | |
|   aFloaterCache->mRegion.height = region.height;
 | |
| #ifdef NOISY_SPACEMANAGER
 | |
|   nscoord tx, ty;
 | |
|   mSpaceManager->GetTranslation(tx, ty);
 | |
|   nsFrame::ListTag(stdout, mBlock);
 | |
|   printf(": PlaceFloater: AddRectRegion: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
 | |
|          tx, ty, mSpaceManagerX, mSpaceManagerY,
 | |
|          aFloaterCache->mRegion.x, aFloaterCache->mRegion.y,
 | |
|          aFloaterCache->mRegion.width, aFloaterCache->mRegion.height);
 | |
| #endif
 | |
| 
 | |
|   // Set the origin of the floater frame, in frame coordinates. These
 | |
|   // coordinates are <b>not</b> relative to the spacemanager
 | |
|   // translation, therefore we have to factor in our border/padding.
 | |
|   nscoord x = borderPadding.left + aFloaterCache->mMargins.left + region.x;
 | |
|   nscoord y = borderPadding.top + aFloaterCache->mMargins.top + region.y;
 | |
| 
 | |
|   // If floater is relatively positioned, factor that in as well
 | |
|   // XXXldb Should this be done after handling the combined area
 | |
|   // below?
 | |
|   if (NS_STYLE_POSITION_RELATIVE == floaterDisplay->mPosition) {
 | |
|     x += aFloaterCache->mOffsets.left;
 | |
|     y += aFloaterCache->mOffsets.top;
 | |
|   }
 | |
| 
 | |
|   // Position the floater and make sure and views are properly
 | |
|   // positioned. We need to explicitly position its child views as
 | |
|   // well, since we're moving the floater after flowing it.
 | |
|   floater->MoveTo(mPresContext, x, y);
 | |
|   nsContainerFrame::PositionFrameView(mPresContext, floater);
 | |
|   nsContainerFrame::PositionChildViews(mPresContext, floater);
 | |
| 
 | |
|   // Update the floater combined area state
 | |
|   nsRect combinedArea = aFloaterCache->mCombinedArea;
 | |
|   combinedArea.x += x;
 | |
|   combinedArea.y += y;
 | |
|   if (!isLeftFloater && 
 | |
|       (GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
 | |
|     // When we are placing a right floater in an unconstrained situation or
 | |
|     // when shrink wrapping, we don't apply it to the floater combined area
 | |
|     // immediately. Otherwise we end up with an infinitely wide combined
 | |
|     // area. Instead, we save it away in mRightFloaterCombinedArea so that
 | |
|     // later on when we know the width of a line we can compute a better value.
 | |
|     if (!mHaveRightFloaters) {
 | |
|       mRightFloaterCombinedArea = combinedArea;
 | |
|       mHaveRightFloaters = PR_TRUE;
 | |
|     }
 | |
|     else {
 | |
|       nsBlockFrame::CombineRects(combinedArea, mRightFloaterCombinedArea);
 | |
|     }
 | |
|   }
 | |
|   else {
 | |
|     nsBlockFrame::CombineRects(combinedArea, mFloaterCombinedArea);
 | |
|   }
 | |
| 
 | |
|   // Remember the y-coordinate of the floater we've just placed
 | |
|   mLastFloaterY = mY;
 | |
| 
 | |
|   // Now restore mY
 | |
|   mY = saveY;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   if (nsBlockFrame::gNoisyReflow) {
 | |
|     nsRect r;
 | |
|     floater->GetRect(r);
 | |
|     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|     printf("placed floater: ");
 | |
|     nsFrame::ListTag(stdout, floater);
 | |
|     printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Place below-current-line floaters.
 | |
|  */
 | |
| void
 | |
| nsBlockReflowState::PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aList)
 | |
| {
 | |
|   nsFloaterCache* fc = aList.Head();
 | |
|   while (fc) {
 | |
|     if (!fc->mIsCurrentLineFloater) {
 | |
| #ifdef DEBUG
 | |
|       if (nsBlockFrame::gNoisyReflow) {
 | |
|         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|         printf("placing bcl floater: ");
 | |
|         nsFrame::ListTag(stdout, fc->mPlaceholder->GetOutOfFlowFrame());
 | |
|         printf("\n");
 | |
|       }
 | |
| #endif
 | |
| 
 | |
|       // Place the floater
 | |
|       PRBool isLeftFloater;
 | |
|       FlowAndPlaceFloater(fc, &isLeftFloater);
 | |
|     }
 | |
|     fc = fc->Next();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType)
 | |
| {
 | |
| #ifdef DEBUG
 | |
|   if (nsBlockFrame::gNoisyReflow) {
 | |
|     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|     printf("clear floaters: in: mY=%d aY=%d(%d)\n",
 | |
|            mY, aY, aY - BorderPadding().top);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef NOISY_FLOATER_CLEARING
 | |
|   printf("nsBlockReflowState::ClearFloaters: aY=%d breakType=%d\n",
 | |
|          aY, aBreakType);
 | |
|   mSpaceManager->List(stdout);
 | |
| #endif
 | |
|   const nsMargin& bp = BorderPadding();
 | |
|   nscoord newY = mBand.ClearFloaters(aY - bp.top, aBreakType);
 | |
|   mY = newY + bp.top;
 | |
|   GetAvailableSpace();
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   if (nsBlockFrame::gNoisyReflow) {
 | |
|     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
 | |
|     printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top);
 | |
|   }
 | |
| #endif
 | |
| }
 | |
| 
 | 
