LCOV - code coverage report
Current view: top level - layout/generic - BlockReflowInput.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 93 457 20.4 %
Date: 2017-07-14 16:53:18 Functions: 7 20 35.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : // vim:cindent:ts=2:et:sw=2:
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* state used in reflow of block frames */
       8             : 
       9             : #include "BlockReflowInput.h"
      10             : 
      11             : #include <algorithm>
      12             : #include "LayoutLogging.h"
      13             : #include "nsBlockFrame.h"
      14             : #include "nsLineLayout.h"
      15             : #include "nsPresContext.h"
      16             : #include "nsIFrameInlines.h"
      17             : #include "mozilla/AutoRestore.h"
      18             : #include "mozilla/DebugOnly.h"
      19             : #include "mozilla/Preferences.h"
      20             : #include "TextOverflow.h"
      21             : 
      22             : #ifdef DEBUG
      23             : #include "nsBlockDebugFlags.h"
      24             : #endif
      25             : 
      26             : using namespace mozilla;
      27             : using namespace mozilla::layout;
      28             : 
      29             : static bool sFloatFragmentsInsideColumnEnabled;
      30             : static bool sFloatFragmentsInsideColumnPrefCached;
      31             : 
      32         162 : BlockReflowInput::BlockReflowInput(const ReflowInput& aReflowInput,
      33             :                                        nsPresContext* aPresContext,
      34             :                                        nsBlockFrame* aFrame,
      35             :                                        bool aBStartMarginRoot,
      36             :                                        bool aBEndMarginRoot,
      37             :                                        bool aBlockNeedsFloatManager,
      38         162 :                                        nscoord aConsumedBSize)
      39             :   : mBlock(aFrame),
      40             :     mPresContext(aPresContext),
      41             :     mReflowInput(aReflowInput),
      42             :     mContentArea(aReflowInput.GetWritingMode()),
      43             :     mPushedFloats(nullptr),
      44             :     mOverflowTracker(nullptr),
      45         162 :     mBorderPadding(mReflowInput.ComputedLogicalBorderPadding()),
      46             :     mPrevBEndMargin(),
      47             :     mLineNumber(0),
      48             :     mFloatBreakType(StyleClear::None),
      49         324 :     mConsumedBSize(aConsumedBSize)
      50             : {
      51         162 :   if (!sFloatFragmentsInsideColumnPrefCached) {
      52           2 :     sFloatFragmentsInsideColumnPrefCached = true;
      53             :     Preferences::AddBoolVarCache(&sFloatFragmentsInsideColumnEnabled,
      54           2 :                                  "layout.float-fragments-inside-column.enabled");
      55             :   }
      56         162 :   mFlags.mFloatFragmentsInsideColumnEnabled = sFloatFragmentsInsideColumnEnabled;
      57             : 
      58         162 :   WritingMode wm = aReflowInput.GetWritingMode();
      59         162 :   mFlags.mIsFirstInflow = !aFrame->GetPrevInFlow();
      60         162 :   mFlags.mIsOverflowContainer = IS_TRUE_OVERFLOW_CONTAINER(aFrame);
      61             : 
      62             :   nsIFrame::LogicalSides logicalSkipSides =
      63         162 :     aFrame->GetLogicalSkipSides(&aReflowInput);
      64         162 :   mBorderPadding.ApplySkipSides(logicalSkipSides);
      65             : 
      66             :   // Note that mContainerSize is the physical size, needed to
      67             :   // convert logical block-coordinates in vertical-rl writing mode
      68             :   // (measured from a RHS origin) to physical coordinates within the
      69             :   // containing block.
      70             :   // If aReflowInput doesn't have a constrained ComputedWidth(), we set
      71             :   // mContainerSize.width to zero, which means lines will be positioned
      72             :   // (physically) incorrectly; we will fix them up at the end of
      73             :   // nsBlockFrame::Reflow, after we know the total block-size of the
      74             :   // frame.
      75         162 :   mContainerSize.width = aReflowInput.ComputedWidth();
      76         162 :   if (mContainerSize.width == NS_UNCONSTRAINEDSIZE) {
      77           0 :     mContainerSize.width = 0;
      78             :   }
      79             : 
      80         162 :   mContainerSize.width += mBorderPadding.LeftRight(wm);
      81             : 
      82             :   // For now at least, we don't do that fix-up for mContainerHeight.
      83             :   // It's only used in nsBidiUtils::ReorderFrames for vertical rtl
      84             :   // writing modes, which aren't fully supported for the time being.
      85         324 :   mContainerSize.height = aReflowInput.ComputedHeight() +
      86         162 :                           mBorderPadding.TopBottom(wm);
      87             : 
      88         172 :   if ((aBStartMarginRoot && !logicalSkipSides.BStart()) ||
      89          10 :       0 != mBorderPadding.BStart(wm)) {
      90         152 :     mFlags.mIsBStartMarginRoot = true;
      91         152 :     mFlags.mShouldApplyBStartMargin = true;
      92             :   }
      93         172 :   if ((aBEndMarginRoot && !logicalSkipSides.BEnd()) ||
      94          10 :       0 != mBorderPadding.BEnd(wm)) {
      95         152 :     mFlags.mIsBEndMarginRoot = true;
      96             :   }
      97         162 :   if (aBlockNeedsFloatManager) {
      98         152 :     mFlags.mBlockNeedsFloatManager = true;
      99             :   }
     100         162 :   mFlags.mCanHaveTextOverflow = css::TextOverflow::CanHaveTextOverflow(mBlock);
     101             : 
     102         162 :   MOZ_ASSERT(FloatManager(),
     103             :              "Float manager should be valid when creating BlockReflowInput!");
     104             : 
     105             :   // Save the coordinate system origin for later.
     106         162 :   FloatManager()->GetTranslation(mFloatManagerI, mFloatManagerB);
     107         162 :   FloatManager()->PushState(&mFloatManagerStateBefore); // never popped
     108             : 
     109         162 :   mReflowStatus.Reset();
     110             : 
     111         162 :   mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow());
     112             : 
     113         162 :   LAYOUT_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedISize(),
     114             :                        "have unconstrained width; this should only result "
     115             :                        "from very large sizes, not attempts at intrinsic "
     116             :                        "width calculation");
     117         162 :   mContentArea.ISize(wm) = aReflowInput.ComputedISize();
     118             : 
     119             :   // Compute content area height. Unlike the width, if we have a
     120             :   // specified style height we ignore it since extra content is
     121             :   // managed by the "overflow" property. When we don't have a
     122             :   // specified style height then we may end up limiting our height if
     123             :   // the availableHeight is constrained (this situation occurs when we
     124             :   // are paginated).
     125         162 :   if (NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableBSize()) {
     126             :     // We are in a paginated situation. The bottom edge is just inside
     127             :     // the bottom border and padding. The content area height doesn't
     128             :     // include either border or padding edge.
     129           0 :     mBEndEdge = aReflowInput.AvailableBSize() - mBorderPadding.BEnd(wm);
     130           0 :     mContentArea.BSize(wm) = std::max(0, mBEndEdge - mBorderPadding.BStart(wm));
     131             :   }
     132             :   else {
     133             :     // When we are not in a paginated situation then we always use
     134             :     // a constrained height.
     135         162 :     mFlags.mHasUnconstrainedBSize = true;
     136         162 :     mContentArea.BSize(wm) = mBEndEdge = NS_UNCONSTRAINEDSIZE;
     137             :   }
     138         162 :   mContentArea.IStart(wm) = mBorderPadding.IStart(wm);
     139         162 :   mBCoord = mContentArea.BStart(wm) = mBorderPadding.BStart(wm);
     140             : 
     141         162 :   mPrevChild = nullptr;
     142         162 :   mCurrentLine = aFrame->LinesEnd();
     143             : 
     144         162 :   mMinLineHeight = aReflowInput.CalcLineHeight();
     145         162 : }
     146             : 
     147             : nscoord
     148           0 : BlockReflowInput::ConsumedBSize()
     149             : {
     150           0 :   if (mConsumedBSize == NS_INTRINSICSIZE) {
     151           0 :     mConsumedBSize = mBlock->ConsumedBSize(mReflowInput.GetWritingMode());
     152             :   }
     153             : 
     154           0 :   return mConsumedBSize;
     155             : }
     156             : 
     157             : void
     158           0 : BlockReflowInput::ComputeReplacedBlockOffsetsForFloats(
     159             :                       nsIFrame* aFrame,
     160             :                       const LogicalRect& aFloatAvailableSpace,
     161             :                       nscoord& aIStartResult,
     162             :                       nscoord& aIEndResult) const
     163             : {
     164           0 :   WritingMode wm = mReflowInput.GetWritingMode();
     165             :   // The frame is clueless about the float manager and therefore we
     166             :   // only give it free space. An example is a table frame - the
     167             :   // tables do not flow around floats.
     168             :   // However, we can let its margins intersect floats.
     169           0 :   NS_ASSERTION(aFloatAvailableSpace.IStart(wm) >= mContentArea.IStart(wm),
     170             :                "bad avail space rect inline-coord");
     171           0 :   NS_ASSERTION(aFloatAvailableSpace.ISize(wm) == 0 ||
     172             :                aFloatAvailableSpace.IEnd(wm) <= mContentArea.IEnd(wm),
     173             :                "bad avail space rect inline-size");
     174             : 
     175             :   nscoord iStartOffset, iEndOffset;
     176           0 :   if (aFloatAvailableSpace.ISize(wm) == mContentArea.ISize(wm)) {
     177             :     // We don't need to compute margins when there are no floats around.
     178           0 :     iStartOffset = 0;
     179           0 :     iEndOffset = 0;
     180             :   } else {
     181           0 :     LogicalMargin frameMargin(wm);
     182           0 :     SizeComputationInput os(aFrame, mReflowInput.mRenderingContext,
     183           0 :                         wm, mContentArea.ISize(wm));
     184           0 :     frameMargin =
     185           0 :       os.ComputedLogicalMargin().ConvertTo(wm, aFrame->GetWritingMode());
     186             : 
     187             :     nscoord iStartFloatIOffset =
     188           0 :       aFloatAvailableSpace.IStart(wm) - mContentArea.IStart(wm);
     189           0 :     iStartOffset = std::max(iStartFloatIOffset, frameMargin.IStart(wm)) -
     190           0 :                    frameMargin.IStart(wm);
     191           0 :     iStartOffset = std::max(iStartOffset, 0); // in case of negative margin
     192             :     nscoord iEndFloatIOffset =
     193           0 :       mContentArea.IEnd(wm) - aFloatAvailableSpace.IEnd(wm);
     194           0 :     iEndOffset = std::max(iEndFloatIOffset, frameMargin.IEnd(wm)) -
     195           0 :                  frameMargin.IEnd(wm);
     196           0 :     iEndOffset = std::max(iEndOffset, 0); // in case of negative margin
     197             :   }
     198           0 :   aIStartResult = iStartOffset;
     199           0 :   aIEndResult = iEndOffset;
     200           0 : }
     201             : 
     202             : static nscoord
     203           0 : GetBEndMarginClone(nsIFrame* aFrame,
     204             :                    gfxContext* aRenderingContext,
     205             :                    const LogicalRect& aContentArea,
     206             :                    WritingMode aWritingMode)
     207             : {
     208           0 :   if (aFrame->StyleBorder()->mBoxDecorationBreak ==
     209             :         StyleBoxDecorationBreak::Clone) {
     210             :     SizeComputationInput os(aFrame, aRenderingContext, aWritingMode,
     211           0 :                         aContentArea.ISize(aWritingMode));
     212           0 :     return os.ComputedLogicalMargin().
     213           0 :                 ConvertTo(aWritingMode,
     214           0 :                           aFrame->GetWritingMode()).BEnd(aWritingMode);
     215             :   }
     216           0 :   return 0;
     217             : }
     218             : 
     219             : // Compute the amount of available space for reflowing a block frame
     220             : // at the current Y coordinate. This method assumes that
     221             : // GetAvailableSpace has already been called.
     222             : void
     223          10 : BlockReflowInput::ComputeBlockAvailSpace(nsIFrame* aFrame,
     224             :                                          const nsFlowAreaRect& aFloatAvailableSpace,
     225             :                                          bool aBlockAvoidsFloats,
     226             :                                          LogicalRect& aResult)
     227             : {
     228             : #ifdef REALLY_NOISY_REFLOW
     229             :   printf("CBAS frame=%p has floats %d\n",
     230             :          aFrame, aFloatAvailableSpace.mHasFloats);
     231             : #endif
     232          10 :   WritingMode wm = mReflowInput.GetWritingMode();
     233          10 :   aResult.BStart(wm) = mBCoord;
     234          20 :   aResult.BSize(wm) = mFlags.mHasUnconstrainedBSize
     235          10 :     ? NS_UNCONSTRAINEDSIZE
     236           0 :     : mReflowInput.AvailableBSize() - mBCoord
     237           0 :       - GetBEndMarginClone(aFrame, mReflowInput.mRenderingContext, mContentArea, wm);
     238             :   // mBCoord might be greater than mBEndEdge if the block's top margin pushes
     239             :   // it off the page/column. Negative available height can confuse other code
     240             :   // and is nonsense in principle.
     241             : 
     242             :   // XXX Do we really want this condition to be this restrictive (i.e.,
     243             :   // more restrictive than it used to be)?  The |else| here is allowed
     244             :   // by the CSS spec, but only out of desperation given implementations,
     245             :   // and the behavior it leads to is quite undesirable (it can cause
     246             :   // things to become extremely narrow when they'd fit quite well a
     247             :   // little bit lower).  Should the else be a quirk or something that
     248             :   // applies to a specific set of frame classes and no new ones?
     249             :   // If we did that, then for those frames where the condition below is
     250             :   // true but nsBlockFrame::BlockCanIntersectFloats is false,
     251             :   // nsBlockFrame::ISizeToClearPastFloats would need to use the
     252             :   // shrink-wrap formula, max(MIN_ISIZE, min(avail width, PREF_ISIZE))
     253             :   // rather than just using MIN_ISIZE.
     254          10 :   NS_ASSERTION(nsBlockFrame::BlockCanIntersectFloats(aFrame) ==
     255             :                  !aBlockAvoidsFloats,
     256             :                "unexpected replaced width");
     257          10 :   if (!aBlockAvoidsFloats) {
     258          10 :     if (aFloatAvailableSpace.mHasFloats) {
     259             :       // Use the float-edge property to determine how the child block
     260             :       // will interact with the float.
     261           0 :       const nsStyleBorder* borderStyle = aFrame->StyleBorder();
     262           0 :       switch (borderStyle->mFloatEdge) {
     263             :         default:
     264             :         case StyleFloatEdge::ContentBox:  // content and only content does runaround of floats
     265             :           // The child block will flow around the float. Therefore
     266             :           // give it all of the available space.
     267           0 :           aResult.IStart(wm) = mContentArea.IStart(wm);
     268           0 :           aResult.ISize(wm) = mContentArea.ISize(wm);
     269           0 :           break;
     270             :         case StyleFloatEdge::MarginBox:
     271             :           {
     272             :             // The child block's margins should be placed adjacent to,
     273             :             // but not overlap the float.
     274           0 :             aResult.IStart(wm) = aFloatAvailableSpace.mRect.IStart(wm);
     275           0 :             aResult.ISize(wm) = aFloatAvailableSpace.mRect.ISize(wm);
     276             :           }
     277           0 :           break;
     278             :       }
     279             :     }
     280             :     else {
     281             :       // Since there are no floats present the float-edge property
     282             :       // doesn't matter therefore give the block element all of the
     283             :       // available space since it will flow around the float itself.
     284          10 :       aResult.IStart(wm) = mContentArea.IStart(wm);
     285          10 :       aResult.ISize(wm) = mContentArea.ISize(wm);
     286             :     }
     287             :   }
     288             :   else {
     289             :     nscoord iStartOffset, iEndOffset;
     290           0 :     ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace.mRect,
     291           0 :                                          iStartOffset, iEndOffset);
     292           0 :     aResult.IStart(wm) = mContentArea.IStart(wm) + iStartOffset;
     293           0 :     aResult.ISize(wm) = mContentArea.ISize(wm) - iStartOffset - iEndOffset;
     294             :   }
     295             : 
     296             : #ifdef REALLY_NOISY_REFLOW
     297             :   printf("  CBAS: result %d %d %d %d\n", aResult.IStart(wm), aResult.BStart(wm),
     298             :          aResult.ISize(wm), aResult.BSize(wm));
     299             : #endif
     300          10 : }
     301             : 
     302             : bool
     303           0 : BlockReflowInput::ReplacedBlockFitsInAvailSpace(nsIFrame* aReplacedBlock,
     304             :                             const nsFlowAreaRect& aFloatAvailableSpace) const
     305             : {
     306           0 :   if (!aFloatAvailableSpace.mHasFloats) {
     307             :     // If there aren't any floats here, then we always fit.
     308             :     // We check this before calling ISizeToClearPastFloats, which is
     309             :     // somewhat expensive.
     310           0 :     return true;
     311             :   }
     312           0 :   WritingMode wm = mReflowInput.GetWritingMode();
     313             :   nsBlockFrame::ReplacedElementISizeToClear replacedISize =
     314             :     nsBlockFrame::ISizeToClearPastFloats(*this, aFloatAvailableSpace.mRect,
     315           0 :                                          aReplacedBlock);
     316             :   // The inline-start side of the replaced element should be offset by
     317             :   // the larger of the float intrusion or the replaced element's own
     318             :   // start margin.  The inline-end side is similar, except for Web
     319             :   // compatibility we ignore the margin.
     320           0 :   return std::max(aFloatAvailableSpace.mRect.IStart(wm) -
     321           0 :                     mContentArea.IStart(wm),
     322           0 :                   replacedISize.marginIStart) +
     323           0 :            replacedISize.borderBoxISize +
     324           0 :            (mContentArea.IEnd(wm) -
     325           0 :             aFloatAvailableSpace.mRect.IEnd(wm)) <=
     326           0 :          mContentArea.ISize(wm);
     327             : }
     328             : 
     329             : nsFlowAreaRect
     330         160 : BlockReflowInput::GetFloatAvailableSpaceWithState(
     331             :                     nscoord aBCoord, ShapeType aShapeType,
     332             :                     nsFloatManager::SavedState* aState) const
     333             : {
     334         160 :   WritingMode wm = mReflowInput.GetWritingMode();
     335             : #ifdef DEBUG
     336             :   // Verify that the caller setup the coordinate system properly
     337             :   nscoord wI, wB;
     338         160 :   FloatManager()->GetTranslation(wI, wB);
     339             : 
     340         160 :   NS_ASSERTION((wI == mFloatManagerI) && (wB == mFloatManagerB),
     341             :                "bad coord system");
     342             : #endif
     343             : 
     344         160 :   nscoord blockSize = (mContentArea.BSize(wm) == nscoord_MAX)
     345         160 :     ? nscoord_MAX : std::max(mContentArea.BEnd(wm) - aBCoord, 0);
     346             :   nsFlowAreaRect result =
     347             :     FloatManager()->GetFlowArea(wm, aBCoord, blockSize,
     348             :                                 BandInfoType::BandFromPoint, aShapeType,
     349         160 :                                 mContentArea, aState, ContainerSize());
     350             :   // Keep the inline size >= 0 for compatibility with nsSpaceManager.
     351         160 :   if (result.mRect.ISize(wm) < 0) {
     352           0 :     result.mRect.ISize(wm) = 0;
     353             :   }
     354             : 
     355             : #ifdef DEBUG
     356         160 :   if (nsBlockFrame::gNoisyReflow) {
     357           0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     358           0 :     printf("%s: band=%d,%d,%d,%d hasfloats=%d\n", __func__,
     359           0 :            result.mRect.IStart(wm), result.mRect.BStart(wm),
     360           0 :            result.mRect.ISize(wm), result.mRect.BSize(wm), result.mHasFloats);
     361             :   }
     362             : #endif
     363         160 :   return result;
     364             : }
     365             : 
     366             : nsFlowAreaRect
     367          75 : BlockReflowInput::GetFloatAvailableSpaceForBSize(
     368             :                       nscoord aBCoord, nscoord aBSize,
     369             :                       nsFloatManager::SavedState *aState) const
     370             : {
     371          75 :   WritingMode wm = mReflowInput.GetWritingMode();
     372             : #ifdef DEBUG
     373             :   // Verify that the caller setup the coordinate system properly
     374             :   nscoord wI, wB;
     375          75 :   FloatManager()->GetTranslation(wI, wB);
     376             : 
     377          75 :   NS_ASSERTION((wI == mFloatManagerI) && (wB == mFloatManagerB),
     378             :                "bad coord system");
     379             : #endif
     380             :   nsFlowAreaRect result =
     381             :     FloatManager()->GetFlowArea(wm, aBCoord, aBSize,
     382             :                                 BandInfoType::WidthWithinHeight,
     383             :                                 ShapeType::ShapeOutside,
     384          75 :                                 mContentArea, aState, ContainerSize());
     385             :   // Keep the width >= 0 for compatibility with nsSpaceManager.
     386          75 :   if (result.mRect.ISize(wm) < 0) {
     387           0 :     result.mRect.ISize(wm) = 0;
     388             :   }
     389             : 
     390             : #ifdef DEBUG
     391          75 :   if (nsBlockFrame::gNoisyReflow) {
     392           0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     393           0 :     printf("%s: space=%d,%d,%d,%d hasfloats=%d\n", __func__,
     394           0 :            result.mRect.IStart(wm), result.mRect.BStart(wm),
     395           0 :            result.mRect.ISize(wm), result.mRect.BSize(wm), result.mHasFloats);
     396             :   }
     397             : #endif
     398          75 :   return result;
     399             : }
     400             : 
     401             : /*
     402             :  * Reconstruct the vertical margin before the line |aLine| in order to
     403             :  * do an incremental reflow that begins with |aLine| without reflowing
     404             :  * the line before it.  |aLine| may point to the fencepost at the end of
     405             :  * the line list, and it is used this way since we (for now, anyway)
     406             :  * always need to recover margins at the end of a block.
     407             :  *
     408             :  * The reconstruction involves walking backward through the line list to
     409             :  * find any collapsed margins preceding the line that would have been in
     410             :  * the reflow state's |mPrevBEndMargin| when we reflowed that line in
     411             :  * a full reflow (under the rule in CSS2 that all adjacent vertical
     412             :  * margins of blocks collapse).
     413             :  */
     414             : void
     415          66 : BlockReflowInput::ReconstructMarginBefore(nsLineList::iterator aLine)
     416             : {
     417          66 :   mPrevBEndMargin.Zero();
     418          66 :   nsBlockFrame *block = mBlock;
     419             : 
     420          66 :   nsLineList::iterator firstLine = block->LinesBegin();
     421             :   for (;;) {
     422          66 :     --aLine;
     423          66 :     if (aLine->IsBlock()) {
     424           0 :       mPrevBEndMargin = aLine->GetCarriedOutBEndMargin();
     425           0 :       break;
     426             :     }
     427          66 :     if (!aLine->IsEmpty()) {
     428          61 :       break;
     429             :     }
     430           5 :     if (aLine == firstLine) {
     431             :       // If the top margin was carried out (and thus already applied),
     432             :       // set it to zero.  Either way, we're done.
     433           5 :       if (!mFlags.mIsBStartMarginRoot) {
     434           0 :         mPrevBEndMargin.Zero();
     435             :       }
     436           5 :       break;
     437             :     }
     438             :   }
     439          66 : }
     440             : 
     441             : void
     442           0 : BlockReflowInput::SetupPushedFloatList()
     443             : {
     444           0 :   MOZ_ASSERT(!mFlags.mIsFloatListInBlockPropertyTable == !mPushedFloats,
     445             :              "flag mismatch");
     446           0 :   if (!mFlags.mIsFloatListInBlockPropertyTable) {
     447             :     // If we're being re-Reflow'd without our next-in-flow having been
     448             :     // reflowed, some pushed floats from our previous reflow might
     449             :     // still be on our pushed floats list.  However, that's
     450             :     // actually fine, since they'll all end up being stolen and
     451             :     // reordered into the correct order again.
     452             :     // (nsBlockFrame::ReflowDirtyLines ensures that any lines with
     453             :     // pushed floats are reflowed.)
     454           0 :     mPushedFloats = mBlock->EnsurePushedFloats();
     455           0 :     mFlags.mIsFloatListInBlockPropertyTable = true;
     456             :   }
     457           0 : }
     458             : 
     459             : void
     460           0 : BlockReflowInput::AppendPushedFloatChain(nsIFrame* aFloatCont)
     461             : {
     462           0 :   SetupPushedFloatList();
     463             :   while (true) {
     464           0 :     aFloatCont->AddStateBits(NS_FRAME_IS_PUSHED_FLOAT);
     465           0 :     mPushedFloats->AppendFrame(mBlock, aFloatCont);
     466           0 :     aFloatCont = aFloatCont->GetNextInFlow();
     467           0 :     if (!aFloatCont || aFloatCont->GetParent() != mBlock) {
     468           0 :       break;
     469             :     }
     470           0 :     DebugOnly<nsresult> rv = mBlock->StealFrame(aFloatCont);
     471           0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame should succeed");
     472           0 :   }
     473           0 : }
     474             : 
     475             : /**
     476             :  * Restore information about floats into the float manager for an
     477             :  * incremental reflow, and simultaneously push the floats by
     478             :  * |aDeltaBCoord|, which is the amount |aLine| was pushed relative to its
     479             :  * parent.  The recovery of state is one of the things that makes
     480             :  * incremental reflow O(N^2) and this state should really be kept
     481             :  * around, attached to the frame tree.
     482             :  */
     483             : void
     484           0 : BlockReflowInput::RecoverFloats(nsLineList::iterator aLine,
     485             :                                   nscoord aDeltaBCoord)
     486             : {
     487           0 :   WritingMode wm = mReflowInput.GetWritingMode();
     488           0 :   if (aLine->HasFloats()) {
     489             :     // Place the floats into the space-manager again. Also slide
     490             :     // them, just like the regular frames on the line.
     491           0 :     nsFloatCache* fc = aLine->GetFirstFloat();
     492           0 :     while (fc) {
     493           0 :       nsIFrame* floatFrame = fc->mFloat;
     494           0 :       if (aDeltaBCoord != 0) {
     495           0 :         floatFrame->MovePositionBy(nsPoint(0, aDeltaBCoord));
     496           0 :         nsContainerFrame::PositionFrameView(floatFrame);
     497           0 :         nsContainerFrame::PositionChildViews(floatFrame);
     498             :       }
     499             : #ifdef DEBUG
     500           0 :       if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
     501             :         nscoord tI, tB;
     502           0 :         FloatManager()->GetTranslation(tI, tB);
     503           0 :         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     504           0 :         printf("RecoverFloats: tIB=%d,%d (%d,%d) ",
     505           0 :                tI, tB, mFloatManagerI, mFloatManagerB);
     506           0 :         nsFrame::ListTag(stdout, floatFrame);
     507             :         LogicalRect region = nsFloatManager::GetRegionFor(wm, floatFrame,
     508           0 :                                                           ContainerSize());
     509           0 :         printf(" aDeltaBCoord=%d region={%d,%d,%d,%d}\n",
     510           0 :                aDeltaBCoord, region.IStart(wm), region.BStart(wm),
     511           0 :                region.ISize(wm), region.BSize(wm));
     512             :       }
     513             : #endif
     514           0 :       FloatManager()->AddFloat(floatFrame,
     515           0 :                                nsFloatManager::GetRegionFor(wm, floatFrame,
     516             :                                                             ContainerSize()),
     517           0 :                                wm, ContainerSize());
     518           0 :       fc = fc->Next();
     519             :     }
     520           0 :   } else if (aLine->IsBlock()) {
     521           0 :     nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *FloatManager(), wm,
     522           0 :                                    ContainerSize());
     523             :   }
     524           0 : }
     525             : 
     526             : /**
     527             :  * Everything done in this function is done O(N) times for each pass of
     528             :  * reflow so it is O(N*M) where M is the number of incremental reflow
     529             :  * passes.  That's bad.  Don't do stuff here.
     530             :  *
     531             :  * When this function is called, |aLine| has just been slid by |aDeltaBCoord|
     532             :  * and the purpose of RecoverStateFrom is to ensure that the
     533             :  * BlockReflowInput is in the same state that it would have been in
     534             :  * had the line just been reflowed.
     535             :  *
     536             :  * Most of the state recovery that we have to do involves floats.
     537             :  */
     538             : void
     539          66 : BlockReflowInput::RecoverStateFrom(nsLineList::iterator aLine,
     540             :                                      nscoord aDeltaBCoord)
     541             : {
     542             :   // Make the line being recovered the current line
     543          66 :   mCurrentLine = aLine;
     544             : 
     545             :   // Place floats for this line into the float manager
     546          66 :   if (aLine->HasFloats() || aLine->IsBlock()) {
     547           0 :     RecoverFloats(aLine, aDeltaBCoord);
     548             : 
     549             : #ifdef DEBUG
     550           0 :     if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
     551           0 :       FloatManager()->List(stdout);
     552             :     }
     553             : #endif
     554             :   }
     555          66 : }
     556             : 
     557             : // This is called by the line layout's AddFloat method when a
     558             : // place-holder frame is reflowed in a line. If the float is a
     559             : // left-most child (it's x coordinate is at the line's left margin)
     560             : // then the float is place immediately, otherwise the float
     561             : // placement is deferred until the line has been reflowed.
     562             : 
     563             : // XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
     564             : // technically we're supposed let the current line flow around the
     565             : // float as well unless it won't fit next to what we already have.
     566             : // But nobody else implements it that way...
     567             : bool
     568           0 : BlockReflowInput::AddFloat(nsLineLayout*       aLineLayout,
     569             :                              nsIFrame*           aFloat,
     570             :                              nscoord             aAvailableISize)
     571             : {
     572           0 :   NS_PRECONDITION(aLineLayout, "must have line layout");
     573           0 :   NS_PRECONDITION(mBlock->LinesEnd() != mCurrentLine, "null ptr");
     574           0 :   NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
     575             :                   "aFloat must be an out-of-flow frame");
     576             : 
     577           0 :   MOZ_ASSERT(aFloat->GetParent(), "float must have parent");
     578           0 :   MOZ_ASSERT(aFloat->GetParent()->IsFrameOfType(nsIFrame::eBlockFrame),
     579             :              "float's parent must be block");
     580           0 :   MOZ_ASSERT(aFloat->GetParent() == mBlock ||
     581             :              (aFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
     582             :              "float should be in this block unless it was marked as "
     583             :              "pushed float");
     584           0 :   if (aFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) {
     585             :     // If, in a previous reflow, the float was pushed entirely to
     586             :     // another column/page, we need to steal it back.  (We might just
     587             :     // push it again, though.)  Likewise, if that previous reflow
     588             :     // reflowed this block but not its next continuation, we might need
     589             :     // to steal it from our own float-continuations list.
     590             :     //
     591             :     // For more about pushed floats, see the comment above
     592             :     // nsBlockFrame::DrainPushedFloats.
     593             :     nsBlockFrame *floatParent =
     594           0 :       static_cast<nsBlockFrame*>(aFloat->GetParent());
     595           0 :     floatParent->StealFrame(aFloat);
     596             : 
     597           0 :     aFloat->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
     598             : 
     599             :     // Appending is fine, since if a float was pushed to the next
     600             :     // page/column, all later floats were also pushed.
     601           0 :     mBlock->mFloats.AppendFrame(mBlock, aFloat);
     602             :   }
     603             : 
     604             :   // Because we are in the middle of reflowing a placeholder frame
     605             :   // within a line (and possibly nested in an inline frame or two
     606             :   // that's a child of our block) we need to restore the space
     607             :   // manager's translation to the space that the block resides in
     608             :   // before placing the float.
     609             :   nscoord oI, oB;
     610           0 :   FloatManager()->GetTranslation(oI, oB);
     611           0 :   nscoord dI = oI - mFloatManagerI;
     612           0 :   nscoord dB = oB - mFloatManagerB;
     613           0 :   FloatManager()->Translate(-dI, -dB);
     614             : 
     615             :   bool placed;
     616             : 
     617             :   // Now place the float immediately if possible. Otherwise stash it
     618             :   // away in mBelowCurrentLineFloats and place it later.
     619             :   // If one or more floats has already been pushed to the next line,
     620             :   // don't let this one go on the current line, since that would violate
     621             :   // float ordering.
     622             :   LogicalRect floatAvailableSpace =
     623           0 :     GetFloatAvailableSpaceForPlacingFloat(mBCoord).mRect;
     624           0 :   if (mBelowCurrentLineFloats.IsEmpty() &&
     625           0 :       (aLineLayout->LineIsEmpty() ||
     626           0 :        mBlock->ComputeFloatISize(*this, floatAvailableSpace, aFloat)
     627             :        <= aAvailableISize)) {
     628             :     // And then place it
     629           0 :     placed = FlowAndPlaceFloat(aFloat);
     630           0 :     if (placed) {
     631             :       // Pass on updated available space to the current inline reflow engine
     632           0 :       WritingMode wm = mReflowInput.GetWritingMode();
     633             :       // If we have mLineBSize, we are reflowing the line again due to
     634             :       // LineReflowStatus::RedoMoreFloats. We should use mLineBSize to query the
     635             :       // correct available space.
     636             :       nsFlowAreaRect floatAvailSpace =
     637           0 :         mLineBSize.isNothing()
     638             :         ? GetFloatAvailableSpace(mBCoord)
     639           0 :         : GetFloatAvailableSpaceForBSize(mBCoord, mLineBSize.value(), nullptr);
     640           0 :       LogicalRect availSpace(wm, floatAvailSpace.mRect.IStart(wm), mBCoord,
     641           0 :                              floatAvailSpace.mRect.ISize(wm),
     642           0 :                              floatAvailSpace.mRect.BSize(wm));
     643           0 :       aLineLayout->UpdateBand(wm, availSpace, aFloat);
     644             :       // Record this float in the current-line list
     645           0 :       mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
     646             :     } else {
     647           0 :       (*aLineLayout->GetLine())->SetHadFloatPushed();
     648             :     }
     649             :   }
     650             :   else {
     651             :     // Always claim to be placed; we don't know whether we fit yet, so we
     652             :     // deal with this in PlaceBelowCurrentLineFloats
     653           0 :     placed = true;
     654             :     // This float will be placed after the line is done (it is a
     655             :     // below-current-line float).
     656           0 :     mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
     657             :   }
     658             : 
     659             :   // Restore coordinate system
     660           0 :   FloatManager()->Translate(dI, dB);
     661             : 
     662           0 :   return placed;
     663             : }
     664             : 
     665             : bool
     666           0 : BlockReflowInput::CanPlaceFloat(nscoord aFloatISize,
     667             :                                   const nsFlowAreaRect& aFloatAvailableSpace)
     668             : {
     669             :   // A float fits at a given block-dir position if there are no floats
     670             :   // at its inline-dir position (no matter what its inline size) or if
     671             :   // its inline size fits in the space remaining after prior floats have
     672             :   // been placed.
     673             :   // FIXME: We should allow overflow by up to half a pixel here (bug 21193).
     674           0 :   return !aFloatAvailableSpace.mHasFloats ||
     675           0 :     aFloatAvailableSpace.mRect.ISize(mReflowInput.GetWritingMode()) >=
     676           0 :       aFloatISize;
     677             : }
     678             : 
     679             : // Return the inline-size that the float (including margins) will take up
     680             : // in the writing mode of the containing block. If this returns
     681             : // NS_UNCONSTRAINEDSIZE, we're dealing with an orthogonal block that
     682             : // has block-size:auto, and we'll need to actually reflow it to find out
     683             : // how much inline-size it will occupy in the containing block's mode.
     684             : static nscoord
     685           0 : FloatMarginISize(const ReflowInput& aCBReflowInput,
     686             :                  nscoord aFloatAvailableISize,
     687             :                  nsIFrame *aFloat,
     688             :                  const SizeComputationInput& aFloatOffsetState)
     689             : {
     690           0 :   AutoMaybeDisableFontInflation an(aFloat);
     691           0 :   WritingMode wm = aFloatOffsetState.GetWritingMode();
     692             : 
     693             :   LogicalSize floatSize =
     694             :     aFloat->ComputeSize(
     695           0 :               aCBReflowInput.mRenderingContext,
     696             :               wm,
     697           0 :               aCBReflowInput.ComputedSize(wm),
     698             :               aFloatAvailableISize,
     699           0 :               aFloatOffsetState.ComputedLogicalMargin().Size(wm),
     700           0 :               aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm) -
     701           0 :                 aFloatOffsetState.ComputedLogicalPadding().Size(wm),
     702           0 :               aFloatOffsetState.ComputedLogicalPadding().Size(wm),
     703           0 :               nsIFrame::ComputeSizeFlags::eShrinkWrap);
     704             : 
     705           0 :   WritingMode cbwm = aCBReflowInput.GetWritingMode();
     706           0 :   nscoord floatISize = floatSize.ConvertTo(cbwm, wm).ISize(cbwm);
     707           0 :   if (floatISize == NS_UNCONSTRAINEDSIZE) {
     708           0 :     return NS_UNCONSTRAINEDSIZE; // reflow is needed to get the true size
     709             :   }
     710             : 
     711           0 :   return floatISize +
     712           0 :          aFloatOffsetState.ComputedLogicalMargin().Size(wm).
     713           0 :            ConvertTo(cbwm, wm).ISize(cbwm) +
     714           0 :          aFloatOffsetState.ComputedLogicalBorderPadding().Size(wm).
     715           0 :            ConvertTo(cbwm, wm).ISize(cbwm);
     716             : }
     717             : 
     718             : bool
     719           0 : BlockReflowInput::FlowAndPlaceFloat(nsIFrame* aFloat)
     720             : {
     721           0 :   WritingMode wm = mReflowInput.GetWritingMode();
     722             :   // Save away the Y coordinate before placing the float. We will
     723             :   // restore mBCoord at the end after placing the float. This is
     724             :   // necessary because any adjustments to mBCoord during the float
     725             :   // placement are for the float only, not for any non-floating
     726             :   // content.
     727           0 :   AutoRestore<nscoord> restoreBCoord(mBCoord);
     728             : 
     729             :   // Grab the float's display information
     730           0 :   const nsStyleDisplay* floatDisplay = aFloat->StyleDisplay();
     731             : 
     732             :   // The float's old region, so we can propagate damage.
     733             :   LogicalRect oldRegion = nsFloatManager::GetRegionFor(wm, aFloat,
     734           0 :                                                        ContainerSize());
     735             : 
     736             :   // Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
     737             :   // ``above'' another float that preceded it in the flow.
     738           0 :   mBCoord = std::max(FloatManager()->GetLowestFloatTop(), mBCoord);
     739             : 
     740             :   // See if the float should clear any preceding floats...
     741             :   // XXX We need to mark this float somehow so that it gets reflowed
     742             :   // when floats are inserted before it.
     743           0 :   if (StyleClear::None != floatDisplay->mBreakType) {
     744             :     // XXXldb Does this handle vertical margins correctly?
     745           0 :     mBCoord = ClearFloats(mBCoord, floatDisplay->PhysicalBreakType(wm));
     746             :   }
     747             :   // Get the band of available space with respect to margin box.
     748             :   nsFlowAreaRect floatAvailableSpace =
     749           0 :     GetFloatAvailableSpaceForPlacingFloat(mBCoord);
     750             :   LogicalRect adjustedAvailableSpace =
     751           0 :     mBlock->AdjustFloatAvailableSpace(*this, floatAvailableSpace.mRect, aFloat);
     752             : 
     753           0 :   NS_ASSERTION(aFloat->GetParent() == mBlock,
     754             :                "Float frame has wrong parent");
     755             : 
     756           0 :   SizeComputationInput offsets(aFloat, mReflowInput.mRenderingContext,
     757           0 :                            wm, mReflowInput.ComputedISize());
     758             : 
     759           0 :   nscoord floatMarginISize = FloatMarginISize(mReflowInput,
     760           0 :                                               adjustedAvailableSpace.ISize(wm),
     761           0 :                                               aFloat, offsets);
     762             : 
     763           0 :   LogicalMargin floatMargin(wm); // computed margin
     764           0 :   LogicalMargin floatOffsets(wm);
     765           0 :   nsReflowStatus reflowStatus;
     766             : 
     767             :   // If it's a floating first-letter, we need to reflow it before we
     768             :   // know how wide it is (since we don't compute which letters are part
     769             :   // of the first letter until reflow!).
     770             :   // We also need to do this early reflow if FloatMarginISize returned
     771             :   // an unconstrained inline-size, which can occur if the float had an
     772             :   // orthogonal writing mode and 'auto' block-size (in its mode).
     773             :   bool earlyFloatReflow =
     774           0 :     aFloat->IsLetterFrame() || floatMarginISize == NS_UNCONSTRAINEDSIZE;
     775           0 :   if (earlyFloatReflow) {
     776           0 :     mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin,
     777           0 :                         floatOffsets, false, reflowStatus);
     778           0 :     floatMarginISize = aFloat->ISize(wm) + floatMargin.IStartEnd(wm);
     779           0 :     NS_ASSERTION(reflowStatus.IsComplete(),
     780             :                  "letter frames and orthogonal floats with auto block-size "
     781             :                  "shouldn't break, and if they do now, then they're breaking "
     782             :                  "at the wrong point");
     783             :   }
     784             : 
     785             :   // Find a place to place the float. The CSS2 spec doesn't want
     786             :   // floats overlapping each other or sticking out of the containing
     787             :   // block if possible (CSS2 spec section 9.5.1, see the rule list).
     788           0 :   StyleFloat floatStyle = floatDisplay->PhysicalFloats(wm);
     789           0 :   MOZ_ASSERT(StyleFloat::Left == floatStyle || StyleFloat::Right == floatStyle,
     790             :              "Invalid float type!");
     791             : 
     792             :   // Can the float fit here?
     793           0 :   bool keepFloatOnSameLine = false;
     794             : 
     795             :   // Are we required to place at least part of the float because we're
     796             :   // at the top of the page (to avoid an infinite loop of pushing and
     797             :   // breaking).
     798             :   bool mustPlaceFloat =
     799           0 :     mReflowInput.mFlags.mIsTopOfPage && IsAdjacentWithTop();
     800             : 
     801             :   for (;;) {
     802           0 :     if (mReflowInput.AvailableHeight() != NS_UNCONSTRAINEDSIZE &&
     803           0 :         floatAvailableSpace.mRect.BSize(wm) <= 0 &&
     804           0 :         !mustPlaceFloat) {
     805             :       // No space, nowhere to put anything.
     806           0 :       PushFloatPastBreak(aFloat);
     807           0 :       return false;
     808             :     }
     809             : 
     810           0 :     if (CanPlaceFloat(floatMarginISize, floatAvailableSpace)) {
     811             :       // We found an appropriate place.
     812           0 :       break;
     813             :     }
     814             : 
     815             :     // Nope. try to advance to the next band.
     816           0 :     if (StyleDisplay::Table != floatDisplay->mDisplay ||
     817           0 :           eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
     818             : 
     819           0 :       mBCoord += floatAvailableSpace.mRect.BSize(wm);
     820           0 :       if (adjustedAvailableSpace.BSize(wm) != NS_UNCONSTRAINEDSIZE) {
     821           0 :         adjustedAvailableSpace.BSize(wm) -= floatAvailableSpace.mRect.BSize(wm);
     822             :       }
     823           0 :       floatAvailableSpace = GetFloatAvailableSpaceForPlacingFloat(mBCoord);
     824             :     } else {
     825             :       // This quirk matches the one in nsBlockFrame::AdjustFloatAvailableSpace
     826             :       // IE handles float tables in a very special way
     827             : 
     828             :       // see if the previous float is also a table and has "align"
     829           0 :       nsFloatCache* fc = mCurrentLineFloats.Head();
     830           0 :       nsIFrame* prevFrame = nullptr;
     831           0 :       while (fc) {
     832           0 :         if (fc->mFloat == aFloat) {
     833           0 :           break;
     834             :         }
     835           0 :         prevFrame = fc->mFloat;
     836           0 :         fc = fc->Next();
     837             :       }
     838             : 
     839           0 :       if(prevFrame) {
     840             :         //get the frame type
     841           0 :         if (prevFrame->IsTableWrapperFrame()) {
     842             :           //see if it has "align="
     843             :           // IE makes a difference between align and he float property
     844           0 :           nsIContent* content = prevFrame->GetContent();
     845           0 :           if (content) {
     846             :             // we're interested only if previous frame is align=left
     847             :             // IE messes things up when "right" (overlapping frames)
     848           0 :             if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::align,
     849           0 :                                      NS_LITERAL_STRING("left"), eIgnoreCase)) {
     850           0 :               keepFloatOnSameLine = true;
     851             :               // don't advance to next line (IE quirkie behaviour)
     852             :               // it breaks rule CSS2/9.5.1/1, but what the hell
     853             :               // since we cannot evangelize the world
     854           0 :               break;
     855             :             }
     856             :           }
     857             :         }
     858             :       }
     859             : 
     860             :       // the table does not fit anymore in this line so advance to next band
     861           0 :       mBCoord += floatAvailableSpace.mRect.BSize(wm);
     862             :       // To match nsBlockFrame::AdjustFloatAvailableSpace, we have to
     863             :       // get a new width for the new band.
     864           0 :       floatAvailableSpace = GetFloatAvailableSpaceForPlacingFloat(mBCoord);
     865           0 :       adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
     866             :                                  floatAvailableSpace.mRect, aFloat);
     867           0 :       floatMarginISize = FloatMarginISize(mReflowInput,
     868           0 :                                           adjustedAvailableSpace.ISize(wm),
     869           0 :                                           aFloat, offsets);
     870             :     }
     871             : 
     872           0 :     mustPlaceFloat = false;
     873           0 :   }
     874             : 
     875             :   // If the float is continued, it will get the same absolute x value as its prev-in-flow
     876             : 
     877             :   // We don't worry about the geometry of the prev in flow, let the continuation
     878             :   // place and size itself as required.
     879             : 
     880             :   // Assign inline and block dir coordinates to the float. We don't use
     881             :   // LineLeft() and LineRight() here, because we would only have to
     882             :   // convert the result back into this block's writing mode.
     883           0 :   LogicalPoint floatPos(wm);
     884           0 :   bool leftFloat = floatStyle == StyleFloat::Left;
     885             : 
     886           0 :   if (leftFloat == wm.IsBidiLTR()) {
     887           0 :     floatPos.I(wm) = floatAvailableSpace.mRect.IStart(wm);
     888             :   }
     889             :   else {
     890           0 :     if (!keepFloatOnSameLine) {
     891           0 :       floatPos.I(wm) = floatAvailableSpace.mRect.IEnd(wm) - floatMarginISize;
     892             :     }
     893             :     else {
     894             :       // this is the IE quirk (see few lines above)
     895             :       // the table is kept in the same line: don't let it overlap the
     896             :       // previous float
     897           0 :       floatPos.I(wm) = floatAvailableSpace.mRect.IStart(wm);
     898             :     }
     899             :   }
     900             :   // CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
     901             :   // be higher than the top of its containing block."  (Since the
     902             :   // containing block is the content edge of the block box, this
     903             :   // means the margin edge of the float can't be higher than the
     904             :   // content edge of the block that contains it.)
     905           0 :   floatPos.B(wm) = std::max(mBCoord, ContentBStart());
     906             : 
     907             :   // Reflow the float after computing its vertical position so it knows
     908             :   // where to break.
     909           0 :   if (!earlyFloatReflow) {
     910           0 :     bool pushedDown = mBCoord != restoreBCoord.SavedValue();
     911           0 :     mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat, floatMargin,
     912           0 :                         floatOffsets, pushedDown, reflowStatus);
     913             :   }
     914           0 :   if (aFloat->GetPrevInFlow())
     915           0 :     floatMargin.BStart(wm) = 0;
     916           0 :   if (reflowStatus.IsIncomplete())
     917           0 :     floatMargin.BEnd(wm) = 0;
     918             : 
     919             :   // In the case that we're in columns and not splitting floats, we need
     920             :   // to check here that the float's height fit, and if it didn't, bail.
     921             :   // (controlled by the pref "layout.float-fragments-inside-column.enabled")
     922             :   //
     923             :   // Likewise, if none of the float fit, and it needs to be pushed in
     924             :   // its entirety to the next page (IsTruncated() or IsInlineBreakBefore()),
     925             :   // we need to do the same.
     926           0 :   if ((ContentBSize() != NS_UNCONSTRAINEDSIZE &&
     927           0 :        !mFlags.mFloatFragmentsInsideColumnEnabled &&
     928           0 :        adjustedAvailableSpace.BSize(wm) == NS_UNCONSTRAINEDSIZE &&
     929           0 :        !mustPlaceFloat &&
     930           0 :        aFloat->BSize(wm) + floatMargin.BStartEnd(wm) >
     931           0 :        ContentBEnd() - floatPos.B(wm)) ||
     932           0 :       reflowStatus.IsTruncated() ||
     933           0 :       reflowStatus.IsInlineBreakBefore()) {
     934           0 :     PushFloatPastBreak(aFloat);
     935           0 :     return false;
     936             :   }
     937             : 
     938             :   // We can't use aFloat->ShouldAvoidBreakInside(mReflowInput) here since
     939             :   // its mIsTopOfPage may be true even though the float isn't at the
     940             :   // top when floatPos.B(wm) > 0.
     941           0 :   if (ContentBSize() != NS_UNCONSTRAINEDSIZE &&
     942           0 :       !mustPlaceFloat &&
     943           0 :       (!mReflowInput.mFlags.mIsTopOfPage || floatPos.B(wm) > 0) &&
     944           0 :       NS_STYLE_PAGE_BREAK_AVOID == aFloat->StyleDisplay()->mBreakInside &&
     945           0 :       (!reflowStatus.IsFullyComplete() ||
     946           0 :        aFloat->BSize(wm) + floatMargin.BStartEnd(wm) >
     947           0 :        ContentBEnd() - floatPos.B(wm)) &&
     948           0 :       !aFloat->GetPrevInFlow()) {
     949           0 :     PushFloatPastBreak(aFloat);
     950           0 :     return false;
     951             :   }
     952             : 
     953             :   // Calculate the actual origin of the float frame's border rect
     954             :   // relative to the parent block; the margin must be added in
     955             :   // to get the border rect
     956           0 :   LogicalPoint origin(wm, floatMargin.IStart(wm) + floatPos.I(wm),
     957           0 :                       floatMargin.BStart(wm) + floatPos.B(wm));
     958             : 
     959             :   // If float is relatively positioned, factor that in as well
     960           0 :   ReflowInput::ApplyRelativePositioning(aFloat, wm, floatOffsets,
     961           0 :                                               &origin, ContainerSize());
     962             : 
     963             :   // Position the float and make sure and views are properly
     964             :   // positioned. We need to explicitly position its child views as
     965             :   // well, since we're moving the float after flowing it.
     966           0 :   bool moved = aFloat->GetLogicalPosition(wm, ContainerSize()) != origin;
     967           0 :   if (moved) {
     968           0 :     aFloat->SetPosition(wm, origin, ContainerSize());
     969           0 :     nsContainerFrame::PositionFrameView(aFloat);
     970           0 :     nsContainerFrame::PositionChildViews(aFloat);
     971             :   }
     972             : 
     973             :   // Update the float combined area state
     974             :   // XXX Floats should really just get invalidated here if necessary
     975           0 :   mFloatOverflowAreas.UnionWith(aFloat->GetOverflowAreas() +
     976           0 :                                 aFloat->GetPosition());
     977             : 
     978             :   // Place the float in the float manager
     979             :   // calculate region
     980             :   LogicalRect region =
     981             :     nsFloatManager::CalculateRegionFor(wm, aFloat, floatMargin,
     982           0 :                                        ContainerSize());
     983             :   // if the float split, then take up all of the vertical height
     984           0 :   if (reflowStatus.IsIncomplete() &&
     985           0 :       (NS_UNCONSTRAINEDSIZE != ContentBSize())) {
     986           0 :     region.BSize(wm) = std::max(region.BSize(wm),
     987           0 :                                 ContentBSize() - floatPos.B(wm));
     988             :   }
     989           0 :   FloatManager()->AddFloat(aFloat, region, wm, ContainerSize());
     990             : 
     991             :   // store region
     992           0 :   nsFloatManager::StoreRegionFor(wm, aFloat, region, ContainerSize());
     993             : 
     994             :   // If the float's dimensions have changed, note the damage in the
     995             :   // float manager.
     996           0 :   if (!region.IsEqualEdges(oldRegion)) {
     997             :     // XXXwaterson conservative: we could probably get away with noting
     998             :     // less damage; e.g., if only height has changed, then only note the
     999             :     // area into which the float has grown or from which the float has
    1000             :     // shrunk.
    1001           0 :     nscoord blockStart = std::min(region.BStart(wm), oldRegion.BStart(wm));
    1002           0 :     nscoord blockEnd = std::max(region.BEnd(wm), oldRegion.BEnd(wm));
    1003           0 :     FloatManager()->IncludeInDamage(blockStart, blockEnd);
    1004             :   }
    1005             : 
    1006           0 :   if (!reflowStatus.IsFullyComplete()) {
    1007           0 :     mBlock->SplitFloat(*this, aFloat, reflowStatus);
    1008             :   } else {
    1009           0 :     MOZ_ASSERT(!aFloat->GetNextInFlow());
    1010             :   }
    1011             : 
    1012             : #ifdef DEBUG
    1013           0 :   if (nsBlockFrame::gNoisyFloatManager) {
    1014             :     nscoord tI, tB;
    1015           0 :     FloatManager()->GetTranslation(tI, tB);
    1016           0 :     nsIFrame::ListTag(stdout, mBlock);
    1017           0 :     printf(": FlowAndPlaceFloat: AddFloat: tIB=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
    1018             :            tI, tB, mFloatManagerI, mFloatManagerB,
    1019           0 :            region.IStart(wm), region.BStart(wm),
    1020           0 :            region.ISize(wm), region.BSize(wm));
    1021             :   }
    1022             : 
    1023           0 :   if (nsBlockFrame::gNoisyReflow) {
    1024           0 :     nsRect r = aFloat->GetRect();
    1025           0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
    1026           0 :     printf("placed float: ");
    1027           0 :     nsFrame::ListTag(stdout, aFloat);
    1028           0 :     printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
    1029             :   }
    1030             : #endif
    1031             : 
    1032           0 :   return true;
    1033             : }
    1034             : 
    1035             : void
    1036           0 : BlockReflowInput::PushFloatPastBreak(nsIFrame *aFloat)
    1037             : {
    1038             :   // This ensures that we:
    1039             :   //  * don't try to place later but smaller floats (which CSS says
    1040             :   //    must have their tops below the top of this float)
    1041             :   //  * don't waste much time trying to reflow this float again until
    1042             :   //    after the break
    1043             :   StyleFloat floatStyle =
    1044           0 :     aFloat->StyleDisplay()->PhysicalFloats(mReflowInput.GetWritingMode());
    1045           0 :   if (floatStyle == StyleFloat::Left) {
    1046           0 :     FloatManager()->SetPushedLeftFloatPastBreak();
    1047             :   } else {
    1048           0 :     MOZ_ASSERT(floatStyle == StyleFloat::Right, "Unexpected float value!");
    1049           0 :     FloatManager()->SetPushedRightFloatPastBreak();
    1050             :   }
    1051             : 
    1052             :   // Put the float on the pushed floats list, even though it
    1053             :   // isn't actually a continuation.
    1054           0 :   DebugOnly<nsresult> rv = mBlock->StealFrame(aFloat);
    1055           0 :   NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame should succeed");
    1056           0 :   AppendPushedFloatChain(aFloat);
    1057           0 :   mReflowStatus.SetOverflowIncomplete();
    1058           0 : }
    1059             : 
    1060             : /**
    1061             :  * Place below-current-line floats.
    1062             :  */
    1063             : void
    1064           0 : BlockReflowInput::PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aList,
    1065             :                                                 nsLineBox* aLine)
    1066             : {
    1067           0 :   nsFloatCache* fc = aList.Head();
    1068           0 :   while (fc) {
    1069             : #ifdef DEBUG
    1070           0 :     if (nsBlockFrame::gNoisyReflow) {
    1071           0 :       nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
    1072           0 :       printf("placing bcl float: ");
    1073           0 :       nsFrame::ListTag(stdout, fc->mFloat);
    1074           0 :       printf("\n");
    1075             :     }
    1076             : #endif
    1077             :     // Place the float
    1078           0 :     bool placed = FlowAndPlaceFloat(fc->mFloat);
    1079           0 :     nsFloatCache *next = fc->Next();
    1080           0 :     if (!placed) {
    1081           0 :       aList.Remove(fc);
    1082           0 :       delete fc;
    1083           0 :       aLine->SetHadFloatPushed();
    1084             :     }
    1085           0 :     fc = next;
    1086             :   }
    1087           0 : }
    1088             : 
    1089             : nscoord
    1090         314 : BlockReflowInput::ClearFloats(nscoord aBCoord, StyleClear aBreakType,
    1091             :                                 nsIFrame *aReplacedBlock,
    1092             :                                 uint32_t aFlags)
    1093             : {
    1094             : #ifdef DEBUG
    1095         314 :   if (nsBlockFrame::gNoisyReflow) {
    1096           0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
    1097           0 :     printf("clear floats: in: aBCoord=%d\n", aBCoord);
    1098             :   }
    1099             : #endif
    1100             : 
    1101             : #ifdef NOISY_FLOAT_CLEARING
    1102             :   printf("BlockReflowInput::ClearFloats: aBCoord=%d breakType=%s\n",
    1103             :          aBCoord, nsLineBox::BreakTypeToString(aBreakType));
    1104             :   FloatManager()->List(stdout);
    1105             : #endif
    1106             : 
    1107         314 :   if (!FloatManager()->HasAnyFloats()) {
    1108         314 :     return aBCoord;
    1109             :   }
    1110             : 
    1111           0 :   nscoord newBCoord = aBCoord;
    1112             : 
    1113           0 :   if (aBreakType != StyleClear::None) {
    1114           0 :     newBCoord = FloatManager()->ClearFloats(newBCoord, aBreakType, aFlags);
    1115             :   }
    1116             : 
    1117           0 :   if (aReplacedBlock) {
    1118             :     for (;;) {
    1119           0 :       nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newBCoord);
    1120           0 :       if (ReplacedBlockFitsInAvailSpace(aReplacedBlock, floatAvailableSpace)) {
    1121           0 :         break;
    1122             :       }
    1123             :       // See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
    1124           0 :       if (!AdvanceToNextBand(floatAvailableSpace.mRect, &newBCoord)) {
    1125             :         // Stop trying to clear here; we'll just get pushed to the
    1126             :         // next column or page and try again there.
    1127           0 :         break;
    1128             :       }
    1129           0 :     }
    1130             :   }
    1131             : 
    1132             : #ifdef DEBUG
    1133           0 :   if (nsBlockFrame::gNoisyReflow) {
    1134           0 :     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
    1135           0 :     printf("clear floats: out: y=%d\n", newBCoord);
    1136             :   }
    1137             : #endif
    1138             : 
    1139           0 :   return newBCoord;
    1140             : }
    1141             : 

Generated by: LCOV version 1.13