LCOV - code coverage report
Current view: directory - layout/generic - nsBlockReflowState.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 340 0 0.0 %
Date: 2012-06-02 Functions: 16 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim:cindent:ts=2:et:sw=2:
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Steve Clark <buster@netscape.com>
      25                 :  *   Robert O'Callahan <roc+moz@cs.cmu.edu>
      26                 :  *   L. David Baron <dbaron@dbaron.org>
      27                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : /* state used in reflow of block frames */
      44                 : 
      45                 : #include "nsBlockReflowContext.h"
      46                 : #include "nsBlockReflowState.h"
      47                 : #include "nsBlockFrame.h"
      48                 : #include "nsLineLayout.h"
      49                 : #include "nsPresContext.h"
      50                 : #include "nsGkAtoms.h"
      51                 : #include "nsIFrame.h"
      52                 : #include "nsFrameManager.h"
      53                 : #include "mozilla/AutoRestore.h"
      54                 : #include "FrameLayerBuilder.h"
      55                 : 
      56                 : #include "nsINameSpaceManager.h"
      57                 : 
      58                 : #include "mozilla/Util.h" // for DebugOnly
      59                 : 
      60                 : #ifdef DEBUG
      61                 : #include "nsBlockDebugFlags.h"
      62                 : #endif
      63                 : 
      64                 : using namespace mozilla;
      65                 : using namespace mozilla::layout;
      66                 : 
      67               0 : nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
      68                 :                                        nsPresContext* aPresContext,
      69                 :                                        nsBlockFrame* aFrame,
      70                 :                                        const nsHTMLReflowMetrics& aMetrics,
      71                 :                                        bool aTopMarginRoot,
      72                 :                                        bool aBottomMarginRoot,
      73                 :                                        bool aBlockNeedsFloatManager)
      74                 :   : mBlock(aFrame),
      75                 :     mPresContext(aPresContext),
      76                 :     mReflowState(aReflowState),
      77                 :     mPushedFloats(nsnull),
      78                 :     mOverflowTracker(nsnull),
      79                 :     mPrevBottomMargin(),
      80                 :     mLineNumber(0),
      81                 :     mFlags(0),
      82               0 :     mFloatBreakType(NS_STYLE_CLEAR_NONE)
      83                 : {
      84               0 :   SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nsnull);
      85                 :   SetFlag(BRS_ISOVERFLOWCONTAINER,
      86               0 :           IS_TRUE_OVERFLOW_CONTAINER(aFrame));
      87                 : 
      88               0 :   const nsMargin& borderPadding = BorderPadding();
      89                 : 
      90               0 :   if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
      91               0 :     SetFlag(BRS_ISTOPMARGINROOT, true);
      92                 :   }
      93               0 :   if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
      94               0 :     SetFlag(BRS_ISBOTTOMMARGINROOT, true);
      95                 :   }
      96               0 :   if (GetFlag(BRS_ISTOPMARGINROOT)) {
      97               0 :     SetFlag(BRS_APPLYTOPMARGIN, true);
      98                 :   }
      99               0 :   if (aBlockNeedsFloatManager) {
     100               0 :     SetFlag(BRS_FLOAT_MGR, true);
     101                 :   }
     102                 :   
     103               0 :   mFloatManager = aReflowState.mFloatManager;
     104                 : 
     105               0 :   NS_ASSERTION(mFloatManager,
     106                 :                "FloatManager should be set in nsBlockReflowState" );
     107               0 :   if (mFloatManager) {
     108                 :     // Save the coordinate system origin for later.
     109               0 :     mFloatManager->GetTranslation(mFloatManagerX, mFloatManagerY);
     110               0 :     mFloatManager->PushState(&mFloatManagerStateBefore); // never popped
     111                 :   }
     112                 : 
     113               0 :   mReflowStatus = NS_FRAME_COMPLETE;
     114                 : 
     115               0 :   mPresContext = aPresContext;
     116               0 :   mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow());
     117                 : 
     118               0 :   NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.ComputedWidth(),
     119                 :                    "have unconstrained width; this should only result from "
     120                 :                    "very large sizes, not attempts at intrinsic width "
     121                 :                    "calculation");
     122               0 :   mContentArea.width = aReflowState.ComputedWidth();
     123                 : 
     124                 :   // Compute content area height. Unlike the width, if we have a
     125                 :   // specified style height we ignore it since extra content is
     126                 :   // managed by the "overflow" property. When we don't have a
     127                 :   // specified style height then we may end up limiting our height if
     128                 :   // the availableHeight is constrained (this situation occurs when we
     129                 :   // are paginated).
     130               0 :   if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
     131                 :     // We are in a paginated situation. The bottom edge is just inside
     132                 :     // the bottom border and padding. The content area height doesn't
     133                 :     // include either border or padding edge.
     134               0 :     mBottomEdge = aReflowState.availableHeight - borderPadding.bottom;
     135               0 :     mContentArea.height = NS_MAX(0, mBottomEdge - borderPadding.top);
     136                 :   }
     137                 :   else {
     138                 :     // When we are not in a paginated situation then we always use
     139                 :     // an constrained height.
     140               0 :     SetFlag(BRS_UNCONSTRAINEDHEIGHT, true);
     141               0 :     mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
     142                 :   }
     143               0 :   mContentArea.x = borderPadding.left;
     144               0 :   mY = mContentArea.y = borderPadding.top;
     145                 : 
     146               0 :   mPrevChild = nsnull;
     147               0 :   mCurrentLine = aFrame->end_lines();
     148                 : 
     149               0 :   mMinLineHeight = aReflowState.CalcLineHeight();
     150               0 : }
     151                 : 
     152                 : void
     153               0 : nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
     154                 :                                                          const nsRect& aFloatAvailableSpace,
     155                 :                                                          nscoord& aLeftResult,
     156                 :                                                          nscoord& aRightResult)
     157                 : {
     158                 :   // The frame is clueless about the float manager and therefore we
     159                 :   // only give it free space. An example is a table frame - the
     160                 :   // tables do not flow around floats.
     161                 :   // However, we can let its margins intersect floats.
     162               0 :   NS_ASSERTION(aFloatAvailableSpace.x >= mContentArea.x, "bad avail space rect x");
     163               0 :   NS_ASSERTION(aFloatAvailableSpace.width == 0 ||
     164                 :                aFloatAvailableSpace.XMost() <= mContentArea.XMost(),
     165                 :                "bad avail space rect width");
     166                 : 
     167                 :   nscoord leftOffset, rightOffset;
     168               0 :   if (aFloatAvailableSpace.width == mContentArea.width) {
     169                 :     // We don't need to compute margins when there are no floats around.
     170               0 :     leftOffset = 0;
     171               0 :     rightOffset = 0;
     172                 :   } else {
     173               0 :     nsMargin frameMargin;
     174               0 :     nsCSSOffsetState os(aFrame, mReflowState.rendContext, mContentArea.width);
     175               0 :     frameMargin = os.mComputedMargin;
     176                 : 
     177               0 :     nscoord leftFloatXOffset = aFloatAvailableSpace.x - mContentArea.x;
     178               0 :     leftOffset = NS_MAX(leftFloatXOffset, frameMargin.left) -
     179               0 :                  frameMargin.left;
     180               0 :     leftOffset = NS_MAX(leftOffset, 0); // in case of negative margin
     181                 :     nscoord rightFloatXOffset =
     182               0 :       mContentArea.XMost() - aFloatAvailableSpace.XMost();
     183               0 :     rightOffset = NS_MAX(rightFloatXOffset, frameMargin.right) -
     184               0 :                   frameMargin.right;
     185               0 :     rightOffset = NS_MAX(rightOffset, 0); // in case of negative margin
     186                 :   }
     187               0 :   aLeftResult = leftOffset;
     188               0 :   aRightResult = rightOffset;
     189               0 : }
     190                 : 
     191                 : // Compute the amount of available space for reflowing a block frame
     192                 : // at the current Y coordinate. This method assumes that
     193                 : // GetAvailableSpace has already been called.
     194                 : void
     195               0 : nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
     196                 :                                            const nsStyleDisplay* aDisplay,
     197                 :                                            const nsFlowAreaRect& aFloatAvailableSpace,
     198                 :                                            bool aBlockAvoidsFloats,
     199                 :                                            nsRect& aResult)
     200                 : {
     201                 : #ifdef REALLY_NOISY_REFLOW
     202                 :   printf("CBAS frame=%p has floats %d\n",
     203                 :          aFrame, aFloatAvailableSpace.mHasFloats);
     204                 : #endif
     205               0 :   aResult.y = mY;
     206               0 :   aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
     207                 :     ? NS_UNCONSTRAINEDSIZE
     208               0 :     : mReflowState.availableHeight - mY;
     209                 :   // mY might be greater than mBottomEdge if the block's top margin pushes
     210                 :   // it off the page/column. Negative available height can confuse other code
     211                 :   // and is nonsense in principle.
     212                 : 
     213                 :   // XXX Do we really want this condition to be this restrictive (i.e.,
     214                 :   // more restrictive than it used to be)?  The |else| here is allowed
     215                 :   // by the CSS spec, but only out of desperation given implementations,
     216                 :   // and the behavior it leads to is quite undesirable (it can cause
     217                 :   // things to become extremely narrow when they'd fit quite well a
     218                 :   // little bit lower).  Should the else be a quirk or something that
     219                 :   // applies to a specific set of frame classes and no new ones?
     220                 :   // If we did that, then for those frames where the condition below is
     221                 :   // true but nsBlockFrame::BlockCanIntersectFloats is false,
     222                 :   // nsBlockFrame::WidthToClearPastFloats would need to use the
     223                 :   // shrink-wrap formula, max(MIN_WIDTH, min(avail width, PREF_WIDTH))
     224                 :   // rather than just using MIN_WIDTH.
     225               0 :   NS_ASSERTION(nsBlockFrame::BlockCanIntersectFloats(aFrame) == 
     226                 :                  !aBlockAvoidsFloats,
     227                 :                "unexpected replaced width");
     228               0 :   if (!aBlockAvoidsFloats) {
     229               0 :     if (aFloatAvailableSpace.mHasFloats) {
     230                 :       // Use the float-edge property to determine how the child block
     231                 :       // will interact with the float.
     232               0 :       const nsStyleBorder* borderStyle = aFrame->GetStyleBorder();
     233               0 :       switch (borderStyle->mFloatEdge) {
     234                 :         default:
     235                 :         case NS_STYLE_FLOAT_EDGE_CONTENT:  // content and only content does runaround of floats
     236                 :           // The child block will flow around the float. Therefore
     237                 :           // give it all of the available space.
     238               0 :           aResult.x = mContentArea.x;
     239               0 :           aResult.width = mContentArea.width;
     240               0 :           break;
     241                 :         case NS_STYLE_FLOAT_EDGE_MARGIN:
     242                 :           {
     243                 :             // The child block's margins should be placed adjacent to,
     244                 :             // but not overlap the float.
     245               0 :             aResult.x = aFloatAvailableSpace.mRect.x;
     246               0 :             aResult.width = aFloatAvailableSpace.mRect.width;
     247                 :           }
     248               0 :           break;
     249                 :       }
     250                 :     }
     251                 :     else {
     252                 :       // Since there are no floats present the float-edge property
     253                 :       // doesn't matter therefore give the block element all of the
     254                 :       // available space since it will flow around the float itself.
     255               0 :       aResult.x = mContentArea.x;
     256               0 :       aResult.width = mContentArea.width;
     257                 :     }
     258                 :   }
     259                 :   else {
     260                 :     nscoord leftOffset, rightOffset;
     261                 :     ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace.mRect,
     262               0 :                                          leftOffset, rightOffset);
     263               0 :     aResult.x = mContentArea.x + leftOffset;
     264               0 :     aResult.width = mContentArea.width - leftOffset - rightOffset;
     265                 :   }
     266                 : 
     267                 : #ifdef REALLY_NOISY_REFLOW
     268                 :   printf("  CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
     269                 : #endif
     270               0 : }
     271                 : 
     272                 : nsFlowAreaRect
     273               0 : nsBlockReflowState::GetFloatAvailableSpaceWithState(
     274                 :                       nscoord aY,
     275                 :                       nsFloatManager::SavedState *aState) const
     276                 : {
     277                 : #ifdef DEBUG
     278                 :   // Verify that the caller setup the coordinate system properly
     279                 :   nscoord wx, wy;
     280               0 :   mFloatManager->GetTranslation(wx, wy);
     281               0 :   NS_ASSERTION((wx == mFloatManagerX) && (wy == mFloatManagerY),
     282                 :                "bad coord system");
     283                 : #endif
     284                 : 
     285                 :   nscoord height = (mContentArea.height == nscoord_MAX)
     286               0 :                      ? nscoord_MAX : NS_MAX(mContentArea.YMost() - aY, 0);
     287                 :   nsFlowAreaRect result =
     288                 :     mFloatManager->GetFlowArea(aY, nsFloatManager::BAND_FROM_POINT,
     289               0 :                                height, mContentArea, aState);
     290                 :   // Keep the width >= 0 for compatibility with nsSpaceManager.
     291               0 :   if (result.mRect.width < 0)
     292               0 :     result.mRect.width = 0;
     293                 : 
     294                 : #ifdef DEBUG
     295               0 :   if (nsBlockFrame::gNoisyReflow) {
     296               0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     297                 :     printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
     298                 :            result.mRect.x, result.mRect.y, result.mRect.width,
     299               0 :            result.mRect.height, result.mHasFloats);
     300                 :   }
     301                 : #endif
     302                 :   return result;
     303                 : }
     304                 : 
     305                 : nsFlowAreaRect
     306               0 : nsBlockReflowState::GetFloatAvailableSpaceForHeight(
     307                 :                       nscoord aY, nscoord aHeight,
     308                 :                       nsFloatManager::SavedState *aState) const
     309                 : {
     310                 : #ifdef DEBUG
     311                 :   // Verify that the caller setup the coordinate system properly
     312                 :   nscoord wx, wy;
     313               0 :   mFloatManager->GetTranslation(wx, wy);
     314               0 :   NS_ASSERTION((wx == mFloatManagerX) && (wy == mFloatManagerY),
     315                 :                "bad coord system");
     316                 : #endif
     317                 : 
     318                 :   nsFlowAreaRect result =
     319                 :     mFloatManager->GetFlowArea(aY, nsFloatManager::WIDTH_WITHIN_HEIGHT,
     320               0 :                                aHeight, mContentArea, aState);
     321                 :   // Keep the width >= 0 for compatibility with nsSpaceManager.
     322               0 :   if (result.mRect.width < 0)
     323               0 :     result.mRect.width = 0;
     324                 : 
     325                 : #ifdef DEBUG
     326               0 :   if (nsBlockFrame::gNoisyReflow) {
     327               0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     328                 :     printf("GetAvailableSpaceForHeight: space=%d,%d,%d,%d hasfloats=%d\n",
     329                 :            result.mRect.x, result.mRect.y, result.mRect.width,
     330               0 :            result.mRect.height, result.mHasFloats);
     331                 :   }
     332                 : #endif
     333                 :   return result;
     334                 : }
     335                 : 
     336                 : /*
     337                 :  * Reconstruct the vertical margin before the line |aLine| in order to
     338                 :  * do an incremental reflow that begins with |aLine| without reflowing
     339                 :  * the line before it.  |aLine| may point to the fencepost at the end of
     340                 :  * the line list, and it is used this way since we (for now, anyway)
     341                 :  * always need to recover margins at the end of a block.
     342                 :  *
     343                 :  * The reconstruction involves walking backward through the line list to
     344                 :  * find any collapsed margins preceding the line that would have been in
     345                 :  * the reflow state's |mPrevBottomMargin| when we reflowed that line in
     346                 :  * a full reflow (under the rule in CSS2 that all adjacent vertical
     347                 :  * margins of blocks collapse).
     348                 :  */
     349                 : void
     350               0 : nsBlockReflowState::ReconstructMarginAbove(nsLineList::iterator aLine)
     351                 : {
     352               0 :   mPrevBottomMargin.Zero();
     353               0 :   nsBlockFrame *block = mBlock;
     354                 : 
     355               0 :   nsLineList::iterator firstLine = block->begin_lines();
     356               0 :   for (;;) {
     357               0 :     --aLine;
     358               0 :     if (aLine->IsBlock()) {
     359               0 :       mPrevBottomMargin = aLine->GetCarriedOutBottomMargin();
     360               0 :       break;
     361                 :     }
     362               0 :     if (!aLine->IsEmpty()) {
     363               0 :       break;
     364                 :     }
     365               0 :     if (aLine == firstLine) {
     366                 :       // If the top margin was carried out (and thus already applied),
     367                 :       // set it to zero.  Either way, we're done.
     368               0 :       if (!GetFlag(BRS_ISTOPMARGINROOT)) {
     369               0 :         mPrevBottomMargin.Zero();
     370                 :       }
     371               0 :       break;
     372                 :     }
     373                 :   }
     374               0 : }
     375                 : 
     376                 : void
     377               0 : nsBlockReflowState::SetupPushedFloatList()
     378                 : {
     379               0 :   NS_ABORT_IF_FALSE(!GetFlag(BRS_PROPTABLE_FLOATCLIST) == !mPushedFloats,
     380                 :                     "flag mismatch");
     381               0 :   if (!GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
     382                 :     // If we're being re-Reflow'd without our next-in-flow having been
     383                 :     // reflowed, some pushed floats from our previous reflow might
     384                 :     // still be on our pushed floats list.  However, that's
     385                 :     // actually fine, since they'll all end up being stolen and
     386                 :     // reordered into the correct order again.
     387                 :     // (nsBlockFrame::ReflowDirtyLines ensures that any lines with
     388                 :     // pushed floats are reflowed.)
     389               0 :     mPushedFloats = mBlock->EnsurePushedFloats();
     390               0 :     SetFlag(BRS_PROPTABLE_FLOATCLIST, true);
     391                 :   }
     392               0 : }
     393                 : 
     394                 : /**
     395                 :  * Restore information about floats into the float manager for an
     396                 :  * incremental reflow, and simultaneously push the floats by
     397                 :  * |aDeltaY|, which is the amount |aLine| was pushed relative to its
     398                 :  * parent.  The recovery of state is one of the things that makes
     399                 :  * incremental reflow O(N^2) and this state should really be kept
     400                 :  * around, attached to the frame tree.
     401                 :  */
     402                 : void
     403               0 : nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
     404                 :                                   nscoord aDeltaY)
     405                 : {
     406               0 :   if (aLine->HasFloats()) {
     407                 :     // Place the floats into the space-manager again. Also slide
     408                 :     // them, just like the regular frames on the line.
     409               0 :     nsFloatCache* fc = aLine->GetFirstFloat();
     410               0 :     while (fc) {
     411               0 :       nsIFrame* floatFrame = fc->mFloat;
     412               0 :       if (aDeltaY != 0) {
     413               0 :         nsPoint p = floatFrame->GetPosition();
     414               0 :         floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY));
     415               0 :         nsContainerFrame::PositionFrameView(floatFrame);
     416               0 :         nsContainerFrame::PositionChildViews(floatFrame);
     417                 :       }
     418                 : #ifdef DEBUG
     419               0 :       if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
     420                 :         nscoord tx, ty;
     421               0 :         mFloatManager->GetTranslation(tx, ty);
     422               0 :         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     423                 :         printf("RecoverFloats: txy=%d,%d (%d,%d) ",
     424               0 :                tx, ty, mFloatManagerX, mFloatManagerY);
     425               0 :         nsFrame::ListTag(stdout, floatFrame);
     426               0 :         nsRect region = nsFloatManager::GetRegionFor(floatFrame);
     427                 :         printf(" aDeltaY=%d region={%d,%d,%d,%d}\n",
     428               0 :                aDeltaY, region.x, region.y, region.width, region.height);
     429                 :       }
     430                 : #endif
     431                 :       mFloatManager->AddFloat(floatFrame,
     432               0 :                               nsFloatManager::GetRegionFor(floatFrame));
     433               0 :       fc = fc->Next();
     434                 :     }
     435               0 :   } else if (aLine->IsBlock()) {
     436               0 :     nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager);
     437                 :   }
     438               0 : }
     439                 : 
     440                 : /**
     441                 :  * Everything done in this function is done O(N) times for each pass of
     442                 :  * reflow so it is O(N*M) where M is the number of incremental reflow
     443                 :  * passes.  That's bad.  Don't do stuff here.
     444                 :  *
     445                 :  * When this function is called, |aLine| has just been slid by |aDeltaY|
     446                 :  * and the purpose of RecoverStateFrom is to ensure that the
     447                 :  * nsBlockReflowState is in the same state that it would have been in
     448                 :  * had the line just been reflowed.
     449                 :  *
     450                 :  * Most of the state recovery that we have to do involves floats.
     451                 :  */
     452                 : void
     453               0 : nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
     454                 :                                      nscoord aDeltaY)
     455                 : {
     456                 :   // Make the line being recovered the current line
     457               0 :   mCurrentLine = aLine;
     458                 : 
     459                 :   // Place floats for this line into the float manager
     460               0 :   if (aLine->HasFloats() || aLine->IsBlock()) {
     461               0 :     RecoverFloats(aLine, aDeltaY);
     462                 : 
     463                 : #ifdef DEBUG
     464               0 :     if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
     465               0 :       mFloatManager->List(stdout);
     466                 :     }
     467                 : #endif
     468                 :   }
     469               0 : }
     470                 : 
     471                 : // This is called by the line layout's AddFloat method when a
     472                 : // place-holder frame is reflowed in a line. If the float is a
     473                 : // left-most child (it's x coordinate is at the line's left margin)
     474                 : // then the float is place immediately, otherwise the float
     475                 : // placement is deferred until the line has been reflowed.
     476                 : 
     477                 : // XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
     478                 : // technically we're supposed let the current line flow around the
     479                 : // float as well unless it won't fit next to what we already have.
     480                 : // But nobody else implements it that way...
     481                 : bool
     482               0 : nsBlockReflowState::AddFloat(nsLineLayout*       aLineLayout,
     483                 :                              nsIFrame*           aFloat,
     484                 :                              nscoord             aAvailableWidth)
     485                 : {
     486               0 :   NS_PRECONDITION(aLineLayout, "must have line layout");
     487               0 :   NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
     488               0 :   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
     489                 :                   "aFloat must be an out-of-flow frame");
     490                 : 
     491               0 :   NS_ABORT_IF_FALSE(aFloat->GetParent(), "float must have parent");
     492               0 :   NS_ABORT_IF_FALSE(aFloat->GetParent()->IsFrameOfType(nsIFrame::eBlockFrame),
     493                 :                     "float's parent must be block");
     494               0 :   NS_ABORT_IF_FALSE(aFloat->GetParent() == mBlock ||
     495                 :                     (aFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
     496                 :                     "float should be in this block unless it was marked as "
     497                 :                     "pushed float");
     498               0 :   if (aFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) {
     499                 :     // If, in a previous reflow, the float was pushed entirely to
     500                 :     // another column/page, we need to steal it back.  (We might just
     501                 :     // push it again, though.)  Likewise, if that previous reflow
     502                 :     // reflowed this block but not its next continuation, we might need
     503                 :     // to steal it from our own float-continuations list.
     504                 :     nsBlockFrame *floatParent =
     505               0 :       static_cast<nsBlockFrame*>(aFloat->GetParent());
     506               0 :     floatParent->StealFrame(mPresContext, aFloat);
     507                 : 
     508               0 :     aFloat->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
     509                 : 
     510                 :     // Appending is fine, since if a float was pushed to the next
     511                 :     // page/column, all later floats were also pushed.
     512               0 :     mBlock->mFloats.AppendFrame(mBlock, aFloat);
     513                 :   }
     514                 : 
     515                 :   // Because we are in the middle of reflowing a placeholder frame
     516                 :   // within a line (and possibly nested in an inline frame or two
     517                 :   // that's a child of our block) we need to restore the space
     518                 :   // manager's translation to the space that the block resides in
     519                 :   // before placing the float.
     520                 :   nscoord ox, oy;
     521               0 :   mFloatManager->GetTranslation(ox, oy);
     522               0 :   nscoord dx = ox - mFloatManagerX;
     523               0 :   nscoord dy = oy - mFloatManagerY;
     524               0 :   mFloatManager->Translate(-dx, -dy);
     525                 : 
     526                 :   bool placed;
     527                 : 
     528                 :   // Now place the float immediately if possible. Otherwise stash it
     529                 :   // away in mPendingFloats and place it later.
     530                 :   // If one or more floats has already been pushed to the next line,
     531                 :   // don't let this one go on the current line, since that would violate
     532                 :   // float ordering.
     533               0 :   nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
     534               0 :   if (mBelowCurrentLineFloats.IsEmpty() &&
     535               0 :       (aLineLayout->LineIsEmpty() ||
     536               0 :        mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat)
     537                 :        <= aAvailableWidth)) {
     538                 :     // And then place it
     539               0 :     placed = FlowAndPlaceFloat(aFloat);
     540               0 :     if (placed) {
     541                 :       // Pass on updated available space to the current inline reflow engine
     542               0 :       nsFlowAreaRect floatAvailSpace = GetFloatAvailableSpace(mY);
     543                 :       nsRect availSpace(nsPoint(floatAvailSpace.mRect.x, mY),
     544               0 :                         floatAvailSpace.mRect.Size());
     545               0 :       aLineLayout->UpdateBand(availSpace, aFloat);
     546                 :       // Record this float in the current-line list
     547               0 :       mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
     548                 :     } else {
     549               0 :       (*aLineLayout->GetLine())->SetHadFloatPushed();
     550                 :     }
     551                 :   }
     552                 :   else {
     553                 :     // Always claim to be placed; we don't know whether we fit yet, so we
     554                 :     // deal with this in PlaceBelowCurrentLineFloats
     555               0 :     placed = true;
     556                 :     // This float will be placed after the line is done (it is a
     557                 :     // below-current-line float).
     558               0 :     mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
     559                 :   }
     560                 : 
     561                 :   // Restore coordinate system
     562               0 :   mFloatManager->Translate(dx, dy);
     563                 : 
     564               0 :   return placed;
     565                 : }
     566                 : 
     567                 : bool
     568               0 : nsBlockReflowState::CanPlaceFloat(nscoord aFloatWidth,
     569                 :                                   const nsFlowAreaRect& aFloatAvailableSpace)
     570                 : {
     571                 :   // A float fits at a given vertical position if there are no floats at
     572                 :   // its horizontal position (no matter what its width) or if its width
     573                 :   // fits in the space remaining after prior floats have been placed.
     574                 :   // FIXME: We should allow overflow by up to half a pixel here (bug 21193).
     575               0 :   return !aFloatAvailableSpace.mHasFloats ||
     576               0 :          aFloatAvailableSpace.mRect.width >= aFloatWidth;
     577                 : }
     578                 : 
     579                 : static nscoord
     580               0 : FloatMarginWidth(const nsHTMLReflowState& aCBReflowState,
     581                 :                  nscoord aFloatAvailableWidth,
     582                 :                  nsIFrame *aFloat,
     583                 :                  const nsCSSOffsetState& aFloatOffsetState)
     584                 : {
     585               0 :   AutoMaybeNullInflationContainer an(aFloat);
     586                 :   return aFloat->ComputeSize(
     587                 :     aCBReflowState.rendContext,
     588                 :     nsSize(aCBReflowState.ComputedWidth(),
     589                 :            aCBReflowState.ComputedHeight()),
     590                 :     aFloatAvailableWidth,
     591                 :     nsSize(aFloatOffsetState.mComputedMargin.LeftRight(),
     592                 :            aFloatOffsetState.mComputedMargin.TopBottom()),
     593               0 :     nsSize(aFloatOffsetState.mComputedBorderPadding.LeftRight() -
     594               0 :              aFloatOffsetState.mComputedPadding.LeftRight(),
     595               0 :            aFloatOffsetState.mComputedBorderPadding.TopBottom() -
     596               0 :              aFloatOffsetState.mComputedPadding.TopBottom()),
     597                 :     nsSize(aFloatOffsetState.mComputedPadding.LeftRight(),
     598                 :            aFloatOffsetState.mComputedPadding.TopBottom()),
     599               0 :     true).width +
     600               0 :   aFloatOffsetState.mComputedMargin.LeftRight() +
     601               0 :   aFloatOffsetState.mComputedBorderPadding.LeftRight();
     602                 : }
     603                 : 
     604                 : bool
     605               0 : nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
     606                 : {
     607                 :   // Save away the Y coordinate before placing the float. We will
     608                 :   // restore mY at the end after placing the float. This is
     609                 :   // necessary because any adjustments to mY during the float
     610                 :   // placement are for the float only, not for any non-floating
     611                 :   // content.
     612               0 :   AutoRestore<nscoord> restoreY(mY);
     613                 :   // FIXME: Should give AutoRestore a getter for the value to avoid this.
     614               0 :   const nscoord saveY = mY;
     615                 : 
     616                 :   // Grab the float's display information
     617               0 :   const nsStyleDisplay* floatDisplay = aFloat->GetStyleDisplay();
     618                 : 
     619                 :   // The float's old region, so we can propagate damage.
     620               0 :   nsRect oldRegion = nsFloatManager::GetRegionFor(aFloat);
     621                 : 
     622                 :   // Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
     623                 :   // ``above'' another float that preceded it in the flow.
     624               0 :   mY = NS_MAX(mFloatManager->GetLowestFloatTop(), mY);
     625                 : 
     626                 :   // See if the float should clear any preceding floats...
     627                 :   // XXX We need to mark this float somehow so that it gets reflowed
     628                 :   // when floats are inserted before it.
     629               0 :   if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
     630                 :     // XXXldb Does this handle vertical margins correctly?
     631               0 :     mY = ClearFloats(mY, floatDisplay->mBreakType);
     632                 :   }
     633                 :     // Get the band of available space
     634               0 :   nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY);
     635                 :   nsRect adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
     636               0 :                                     floatAvailableSpace.mRect, aFloat);
     637                 : 
     638               0 :   NS_ASSERTION(aFloat->GetParent() == mBlock,
     639                 :                "Float frame has wrong parent");
     640                 : 
     641                 :   nsCSSOffsetState offsets(aFloat, mReflowState.rendContext,
     642               0 :                            mReflowState.ComputedWidth());
     643                 : 
     644                 :   nscoord floatMarginWidth = FloatMarginWidth(mReflowState,
     645                 :                                               adjustedAvailableSpace.width,
     646               0 :                                               aFloat, offsets);
     647                 : 
     648               0 :   nsMargin floatMargin; // computed margin
     649                 :   nsReflowStatus reflowStatus;
     650                 : 
     651                 :   // If it's a floating first-letter, we need to reflow it before we
     652                 :   // know how wide it is (since we don't compute which letters are part
     653                 :   // of the first letter until reflow!).
     654               0 :   bool isLetter = aFloat->GetType() == nsGkAtoms::letterFrame;
     655               0 :   if (isLetter) {
     656                 :     mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat,
     657               0 :                         floatMargin, false, reflowStatus);
     658               0 :     floatMarginWidth = aFloat->GetSize().width + floatMargin.LeftRight();
     659               0 :     NS_ASSERTION(NS_FRAME_IS_COMPLETE(reflowStatus),
     660                 :                  "letter frames shouldn't break, and if they do now, "
     661                 :                  "then they're breaking at the wrong point");
     662                 :   }
     663                 : 
     664                 :   // Find a place to place the float. The CSS2 spec doesn't want
     665                 :   // floats overlapping each other or sticking out of the containing
     666                 :   // block if possible (CSS2 spec section 9.5.1, see the rule list).
     667               0 :   NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) ||
     668                 :                (NS_STYLE_FLOAT_RIGHT == floatDisplay->mFloats),
     669                 :                "invalid float type");
     670                 : 
     671                 :   // Can the float fit here?
     672               0 :   bool keepFloatOnSameLine = false;
     673                 : 
     674                 :   // Are we required to place at least part of the float because we're
     675                 :   // at the top of the page (to avoid an infinite loop of pushing and
     676                 :   // breaking).
     677                 :   bool mustPlaceFloat =
     678               0 :     mReflowState.mFlags.mIsTopOfPage && IsAdjacentWithTop();
     679                 : 
     680               0 :   for (;;) {
     681               0 :     if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE &&
     682                 :         floatAvailableSpace.mRect.height <= 0 &&
     683               0 :         !mustPlaceFloat) {
     684                 :       // No space, nowhere to put anything.
     685               0 :       PushFloatPastBreak(aFloat);
     686               0 :       return false;
     687                 :     }
     688                 : 
     689               0 :     if (CanPlaceFloat(floatMarginWidth, floatAvailableSpace)) {
     690                 :       // We found an appropriate place.
     691               0 :       break;
     692                 :     }
     693                 : 
     694                 :     // Nope. try to advance to the next band.
     695               0 :     if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
     696               0 :           eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
     697                 : 
     698               0 :       mY += floatAvailableSpace.mRect.height;
     699               0 :       if (adjustedAvailableSpace.height != NS_UNCONSTRAINEDSIZE) {
     700               0 :         adjustedAvailableSpace.height -= floatAvailableSpace.mRect.height;
     701                 :       }
     702               0 :       floatAvailableSpace = GetFloatAvailableSpace(mY);
     703                 :     } else {
     704                 :       // This quirk matches the one in nsBlockFrame::AdjustFloatAvailableSpace
     705                 :       // IE handles float tables in a very special way
     706                 : 
     707                 :       // see if the previous float is also a table and has "align"
     708               0 :       nsFloatCache* fc = mCurrentLineFloats.Head();
     709               0 :       nsIFrame* prevFrame = nsnull;
     710               0 :       while (fc) {
     711               0 :         if (fc->mFloat == aFloat) {
     712               0 :           break;
     713                 :         }
     714               0 :         prevFrame = fc->mFloat;
     715               0 :         fc = fc->Next();
     716                 :       }
     717                 :       
     718               0 :       if(prevFrame) {
     719                 :         //get the frame type
     720               0 :         if (nsGkAtoms::tableOuterFrame == prevFrame->GetType()) {
     721                 :           //see if it has "align="
     722                 :           // IE makes a difference between align and he float property
     723               0 :           nsIContent* content = prevFrame->GetContent();
     724               0 :           if (content) {
     725                 :             // we're interested only if previous frame is align=left
     726                 :             // IE messes things up when "right" (overlapping frames) 
     727               0 :             if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::align,
     728               0 :                                      NS_LITERAL_STRING("left"), eIgnoreCase)) {
     729               0 :               keepFloatOnSameLine = true;
     730                 :               // don't advance to next line (IE quirkie behaviour)
     731                 :               // it breaks rule CSS2/9.5.1/1, but what the hell
     732                 :               // since we cannot evangelize the world
     733               0 :               break;
     734                 :             }
     735                 :           }
     736                 :         }
     737                 :       }
     738                 : 
     739                 :       // the table does not fit anymore in this line so advance to next band 
     740               0 :       mY += floatAvailableSpace.mRect.height;
     741                 :       // To match nsBlockFrame::AdjustFloatAvailableSpace, we have to
     742                 :       // get a new width for the new band.
     743               0 :       floatAvailableSpace = GetFloatAvailableSpace(mY);
     744                 :       adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
     745               0 :                                  floatAvailableSpace.mRect, aFloat);
     746                 :       floatMarginWidth = FloatMarginWidth(mReflowState,
     747                 :                                           adjustedAvailableSpace.width,
     748               0 :                                           aFloat, offsets);
     749                 :     }
     750                 : 
     751               0 :     mustPlaceFloat = false;
     752                 :   }
     753                 : 
     754                 :   // If the float is continued, it will get the same absolute x value as its prev-in-flow
     755                 : 
     756                 :   // We don't worry about the geometry of the prev in flow, let the continuation
     757                 :   // place and size itself as required.
     758                 : 
     759                 :   // Assign an x and y coordinate to the float.
     760                 :   nscoord floatX, floatY;
     761               0 :   if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
     762               0 :     floatX = floatAvailableSpace.mRect.x;
     763                 :   }
     764                 :   else {
     765               0 :     if (!keepFloatOnSameLine) {
     766               0 :       floatX = floatAvailableSpace.mRect.XMost() - floatMarginWidth;
     767                 :     } 
     768                 :     else {
     769                 :       // this is the IE quirk (see few lines above)
     770                 :       // the table is kept in the same line: don't let it overlap the
     771                 :       // previous float 
     772               0 :       floatX = floatAvailableSpace.mRect.x;
     773                 :     }
     774                 :   }
     775                 :   // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
     776                 :   // be higher than the top of its containing block."  (Since the
     777                 :   // containing block is the content edge of the block box, this
     778                 :   // means the margin edge of the float can't be higher than the
     779                 :   // content edge of the block that contains it.)
     780               0 :   floatY = NS_MAX(mY, mContentArea.y);
     781                 : 
     782                 :   // Reflow the float after computing its vertical position so it knows
     783                 :   // where to break.
     784               0 :   if (!isLetter) {
     785               0 :     bool pushedDown = mY != saveY;
     786                 :     mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat,
     787               0 :                         floatMargin, pushedDown, reflowStatus);
     788                 :   }
     789               0 :   if (aFloat->GetPrevInFlow())
     790               0 :     floatMargin.top = 0;
     791               0 :   if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus))
     792               0 :     floatMargin.bottom = 0;
     793                 : 
     794                 :   // In the case that we're in columns and not splitting floats, we need
     795                 :   // to check here that the float's height fit, and if it didn't, bail.
     796                 :   // (This code is only for DISABLE_FLOAT_BREAKING_IN_COLUMNS .)
     797                 :   //
     798                 :   // Likewise, if none of the float fit, and it needs to be pushed in
     799                 :   // its entirety to the next page (NS_FRAME_IS_TRUNCATED), we need to
     800                 :   // do the same.
     801               0 :   if ((mContentArea.height != NS_UNCONSTRAINEDSIZE &&
     802                 :        adjustedAvailableSpace.height == NS_UNCONSTRAINEDSIZE &&
     803               0 :        !mustPlaceFloat &&
     804               0 :        aFloat->GetSize().height + floatMargin.TopBottom() >
     805               0 :          mContentArea.YMost() - floatY) ||
     806                 :       NS_FRAME_IS_TRUNCATED(reflowStatus)) {
     807                 : 
     808               0 :     PushFloatPastBreak(aFloat);
     809               0 :     return false;
     810                 :   }
     811                 : 
     812                 :   // Calculate the actual origin of the float frame's border rect
     813                 :   // relative to the parent block; the margin must be added in
     814                 :   // to get the border rect
     815                 :   nsPoint origin(floatMargin.left + floatX,
     816               0 :                  floatMargin.top + floatY);
     817                 : 
     818                 :   // If float is relatively positioned, factor that in as well
     819               0 :   origin += aFloat->GetRelativeOffset(floatDisplay);
     820                 : 
     821                 :   // Position the float and make sure and views are properly
     822                 :   // positioned. We need to explicitly position its child views as
     823                 :   // well, since we're moving the float after flowing it.
     824               0 :   bool moved = aFloat->GetPosition() != origin;
     825               0 :   if (moved) {
     826               0 :     aFloat->SetPosition(origin);
     827               0 :     nsContainerFrame::PositionFrameView(aFloat);
     828               0 :     nsContainerFrame::PositionChildViews(aFloat);
     829               0 :     FrameLayerBuilder::InvalidateThebesLayersInSubtree(aFloat);
     830                 :   }
     831                 : 
     832                 :   // Update the float combined area state
     833                 :   // XXX Floats should really just get invalidated here if necessary
     834               0 :   mFloatOverflowAreas.UnionWith(aFloat->GetOverflowAreas() + origin);
     835                 : 
     836                 :   // Place the float in the float manager
     837                 :   // calculate region
     838               0 :   nsRect region = nsFloatManager::CalculateRegionFor(aFloat, floatMargin);
     839                 :   // if the float split, then take up all of the vertical height
     840               0 :   if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
     841                 :       (NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
     842               0 :     region.height = NS_MAX(region.height, mContentArea.height - floatY);
     843                 :   }
     844                 :   nsresult rv =
     845               0 :   mFloatManager->AddFloat(aFloat, region);
     846               0 :   NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad float placement");
     847                 :   // store region
     848               0 :   nsFloatManager::StoreRegionFor(aFloat, region);
     849                 : 
     850                 :   // If the float's dimensions have changed, note the damage in the
     851                 :   // float manager.
     852               0 :   if (!region.IsEqualEdges(oldRegion)) {
     853                 :     // XXXwaterson conservative: we could probably get away with noting
     854                 :     // less damage; e.g., if only height has changed, then only note the
     855                 :     // area into which the float has grown or from which the float has
     856                 :     // shrunk.
     857               0 :     nscoord top = NS_MIN(region.y, oldRegion.y);
     858               0 :     nscoord bottom = NS_MAX(region.YMost(), oldRegion.YMost());
     859               0 :     mFloatManager->IncludeInDamage(top, bottom);
     860                 :   }
     861                 : 
     862               0 :   if (!NS_FRAME_IS_FULLY_COMPLETE(reflowStatus)) {
     863               0 :     mBlock->SplitFloat(*this, aFloat, reflowStatus);
     864                 :   }
     865                 : 
     866                 : #ifdef NOISY_FLOATMANAGER
     867                 :   nscoord tx, ty;
     868                 :   mFloatManager->GetTranslation(tx, ty);
     869                 :   nsFrame::ListTag(stdout, mBlock);
     870                 :   printf(": FlowAndPlaceFloat: AddFloat: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
     871                 :          tx, ty, mFloatManagerX, mFloatManagerY,
     872                 :          region.x, region.y, region.width, region.height);
     873                 : #endif
     874                 : 
     875                 : #ifdef DEBUG
     876               0 :   if (nsBlockFrame::gNoisyReflow) {
     877               0 :     nsRect r = aFloat->GetRect();
     878               0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     879               0 :     printf("placed float: ");
     880               0 :     nsFrame::ListTag(stdout, aFloat);
     881               0 :     printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
     882                 :   }
     883                 : #endif
     884                 : 
     885               0 :   return true;
     886                 : }
     887                 : 
     888                 : void
     889               0 : nsBlockReflowState::PushFloatPastBreak(nsIFrame *aFloat)
     890                 : {
     891                 :   // This ensures that we:
     892                 :   //  * don't try to place later but smaller floats (which CSS says
     893                 :   //    must have their tops below the top of this float)
     894                 :   //  * don't waste much time trying to reflow this float again until
     895                 :   //    after the break
     896               0 :   if (aFloat->GetStyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) {
     897               0 :     mFloatManager->SetPushedLeftFloatPastBreak();
     898                 :   } else {
     899               0 :     NS_ABORT_IF_FALSE(aFloat->GetStyleDisplay()->mFloats ==
     900                 :                         NS_STYLE_FLOAT_RIGHT,
     901                 :                       "unexpected float value");
     902               0 :     mFloatManager->SetPushedRightFloatPastBreak();
     903                 :   }
     904                 : 
     905                 :   // Put the float on the pushed floats list, even though it
     906                 :   // isn't actually a continuation.
     907               0 :   DebugOnly<nsresult> rv = mBlock->StealFrame(mPresContext, aFloat);
     908               0 :   NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame should succeed");
     909               0 :   AppendPushedFloat(aFloat);
     910                 : 
     911               0 :   NS_FRAME_SET_OVERFLOW_INCOMPLETE(mReflowStatus);
     912               0 : }
     913                 : 
     914                 : /**
     915                 :  * Place below-current-line floats.
     916                 :  */
     917                 : void
     918               0 : nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aList,
     919                 :                                                 nsLineBox* aLine)
     920                 : {
     921               0 :   nsFloatCache* fc = aList.Head();
     922               0 :   while (fc) {
     923                 : #ifdef DEBUG
     924               0 :     if (nsBlockFrame::gNoisyReflow) {
     925               0 :       nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     926               0 :       printf("placing bcl float: ");
     927               0 :       nsFrame::ListTag(stdout, fc->mFloat);
     928               0 :       printf("\n");
     929                 :     }
     930                 : #endif
     931                 :     // Place the float
     932               0 :     bool placed = FlowAndPlaceFloat(fc->mFloat);
     933               0 :     nsFloatCache *next = fc->Next();
     934               0 :     if (!placed) {
     935               0 :       aList.Remove(fc);
     936               0 :       delete fc;
     937               0 :       aLine->SetHadFloatPushed();
     938                 :     }
     939               0 :     fc = next;
     940                 :   }
     941               0 : }
     942                 : 
     943                 : nscoord
     944               0 : nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType,
     945                 :                                 nsIFrame *aReplacedBlock,
     946                 :                                 PRUint32 aFlags)
     947                 : {
     948                 : #ifdef DEBUG
     949               0 :   if (nsBlockFrame::gNoisyReflow) {
     950               0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     951               0 :     printf("clear floats: in: aY=%d\n", aY);
     952                 :   }
     953                 : #endif
     954                 : 
     955                 : #ifdef NOISY_FLOAT_CLEARING
     956                 :   printf("nsBlockReflowState::ClearFloats: aY=%d breakType=%d\n",
     957                 :          aY, aBreakType);
     958                 :   mFloatManager->List(stdout);
     959                 : #endif
     960                 :   
     961               0 :   nscoord newY = aY;
     962                 : 
     963               0 :   if (aBreakType != NS_STYLE_CLEAR_NONE) {
     964               0 :     newY = mFloatManager->ClearFloats(newY, aBreakType, aFlags);
     965                 :   }
     966                 : 
     967               0 :   if (aReplacedBlock) {
     968               0 :     for (;;) {
     969               0 :       nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newY);
     970                 :       nsBlockFrame::ReplacedElementWidthToClear replacedWidth =
     971                 :         nsBlockFrame::WidthToClearPastFloats(*this, floatAvailableSpace.mRect,
     972               0 :                                              aReplacedBlock);
     973               0 :       if (!floatAvailableSpace.mHasFloats ||
     974                 :           NS_MAX(floatAvailableSpace.mRect.x - mContentArea.x,
     975               0 :                  replacedWidth.marginLeft) +
     976                 :             replacedWidth.borderBoxWidth +
     977               0 :             NS_MAX(mContentArea.XMost() - floatAvailableSpace.mRect.XMost(),
     978               0 :                    replacedWidth.marginRight) <=
     979                 :           mContentArea.width) {
     980                 :         break;
     981                 :       }
     982                 :       // See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
     983               0 :       if (floatAvailableSpace.mRect.height > 0) {
     984                 :         // See if there's room in the next band.
     985               0 :         newY += floatAvailableSpace.mRect.height;
     986                 :       } else {
     987               0 :         if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
     988                 :           // Stop trying to clear here; we'll just get pushed to the
     989                 :           // next column or page and try again there.
     990                 :           break;
     991                 :         }
     992               0 :         NS_NOTREACHED("avail space rect with zero height!");
     993               0 :         newY += 1;
     994                 :       }
     995                 :     }
     996                 :   }
     997                 : 
     998                 : #ifdef DEBUG
     999               0 :   if (nsBlockFrame::gNoisyReflow) {
    1000               0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
    1001               0 :     printf("clear floats: out: y=%d\n", newY);
    1002                 :   }
    1003                 : #endif
    1004                 : 
    1005               0 :   return newY;
    1006                 : }
    1007                 : 

Generated by: LCOV version 1.7