michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* state used in reflow of block frames */ michael@0: michael@0: #ifndef nsBlockReflowState_h__ michael@0: #define nsBlockReflowState_h__ michael@0: michael@0: #include "nsFloatManager.h" michael@0: #include "nsLineBox.h" michael@0: #include "nsHTMLReflowState.h" michael@0: michael@0: class nsBlockFrame; michael@0: class nsFrameList; michael@0: class nsOverflowContinuationTracker; michael@0: michael@0: // block reflow state flags michael@0: #define BRS_UNCONSTRAINEDHEIGHT 0x00000001 michael@0: #define BRS_ISTOPMARGINROOT 0x00000002 // Is this frame a root for top/bottom margin collapsing? michael@0: #define BRS_ISBOTTOMMARGINROOT 0x00000004 michael@0: #define BRS_APPLYTOPMARGIN 0x00000008 // See ShouldApplyTopMargin michael@0: #define BRS_ISFIRSTINFLOW 0x00000010 michael@0: // Set when mLineAdjacentToTop is valid michael@0: #define BRS_HAVELINEADJACENTTOTOP 0x00000020 michael@0: // Set when the block has the equivalent of NS_BLOCK_FLOAT_MGR michael@0: #define BRS_FLOAT_MGR 0x00000040 michael@0: // Set when nsLineLayout::LineIsEmpty was true at the end of reflowing michael@0: // the current line michael@0: #define BRS_LINE_LAYOUT_EMPTY 0x00000080 michael@0: #define BRS_ISOVERFLOWCONTAINER 0x00000100 michael@0: // Our mPushedFloats list is stored on the blocks' proptable michael@0: #define BRS_PROPTABLE_FLOATCLIST 0x00000200 michael@0: #define BRS_LASTFLAG BRS_PROPTABLE_FLOATCLIST michael@0: michael@0: class nsBlockReflowState { michael@0: public: michael@0: nsBlockReflowState(const nsHTMLReflowState& aReflowState, michael@0: nsPresContext* aPresContext, michael@0: nsBlockFrame* aFrame, michael@0: bool aTopMarginRoot, bool aBottomMarginRoot, michael@0: bool aBlockNeedsFloatManager, michael@0: nscoord aConsumedHeight = NS_INTRINSICSIZE); michael@0: michael@0: /** michael@0: * Get the available reflow space (the area not occupied by floats) michael@0: * for the current y coordinate. The available space is relative to michael@0: * our coordinate system, which is the content box, with (0, 0) in the michael@0: * upper left. michael@0: * michael@0: * Returns whether there are floats present at the given vertical michael@0: * coordinate and within the width of the content rect. michael@0: */ michael@0: nsFlowAreaRect GetFloatAvailableSpace() const michael@0: { return GetFloatAvailableSpace(mY); } michael@0: nsFlowAreaRect GetFloatAvailableSpace(nscoord aY) const michael@0: { return GetFloatAvailableSpaceWithState(aY, nullptr); } michael@0: nsFlowAreaRect michael@0: GetFloatAvailableSpaceWithState(nscoord aY, michael@0: nsFloatManager::SavedState *aState) const; michael@0: nsFlowAreaRect michael@0: GetFloatAvailableSpaceForHeight(nscoord aY, nscoord aHeight, michael@0: nsFloatManager::SavedState *aState) const; michael@0: michael@0: /* michael@0: * The following functions all return true if they were able to michael@0: * place the float, false if the float did not fit in available michael@0: * space. michael@0: * aLineLayout is null when we are reflowing pushed floats (because michael@0: * they are not associated with a line box). michael@0: */ michael@0: bool AddFloat(nsLineLayout* aLineLayout, michael@0: nsIFrame* aFloat, michael@0: nscoord aAvailableWidth); michael@0: private: michael@0: bool CanPlaceFloat(nscoord aFloatWidth, michael@0: const nsFlowAreaRect& aFloatAvailableSpace); michael@0: public: michael@0: bool FlowAndPlaceFloat(nsIFrame* aFloat); michael@0: private: michael@0: void PushFloatPastBreak(nsIFrame* aFloat); michael@0: public: michael@0: void PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aFloats, michael@0: nsLineBox* aLine); michael@0: michael@0: // Returns the first coordinate >= aY that clears the michael@0: // floats indicated by aBreakType and has enough width between floats michael@0: // (or no floats remaining) to accomodate aReplacedBlock. michael@0: nscoord ClearFloats(nscoord aY, uint8_t aBreakType, michael@0: nsIFrame *aReplacedBlock = nullptr, michael@0: uint32_t aFlags = 0); michael@0: michael@0: bool IsAdjacentWithTop() const { michael@0: return mY == michael@0: ((mFlags & BRS_ISFIRSTINFLOW) ? mReflowState.ComputedPhysicalBorderPadding().top : 0); michael@0: } michael@0: michael@0: /** michael@0: * Adjusts the border/padding to return 0 for the top if michael@0: * we are not the first in flow. michael@0: */ michael@0: nsMargin BorderPadding() const { michael@0: nsMargin result = mReflowState.ComputedPhysicalBorderPadding(); michael@0: if (!(mFlags & BRS_ISFIRSTINFLOW)) { michael@0: result.top = 0; michael@0: if (mFlags & BRS_ISOVERFLOWCONTAINER) { michael@0: result.bottom = 0; michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Retrieve the height "consumed" by any previous-in-flows. michael@0: */ michael@0: nscoord GetConsumedHeight(); michael@0: michael@0: // Reconstruct the previous bottom margin that goes above |aLine|. michael@0: void ReconstructMarginAbove(nsLineList::iterator aLine); michael@0: michael@0: // Caller must have called GetAvailableSpace for the correct position michael@0: // (which need not be the current mY). michael@0: void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame, michael@0: const nsRect& aFloatAvailableSpace, michael@0: nscoord& aLeftResult, michael@0: nscoord& aRightResult); michael@0: michael@0: // Caller must have called GetAvailableSpace for the current mY michael@0: void ComputeBlockAvailSpace(nsIFrame* aFrame, michael@0: const nsStyleDisplay* aDisplay, michael@0: const nsFlowAreaRect& aFloatAvailableSpace, michael@0: bool aBlockAvoidsFloats, michael@0: nsRect& aResult); michael@0: michael@0: protected: michael@0: void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaY); michael@0: michael@0: public: michael@0: void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY); michael@0: michael@0: void AdvanceToNextLine() { michael@0: if (GetFlag(BRS_LINE_LAYOUT_EMPTY)) { michael@0: SetFlag(BRS_LINE_LAYOUT_EMPTY, false); michael@0: } else { michael@0: mLineNumber++; michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------- michael@0: michael@0: // This state is the "global" state computed once for the reflow of michael@0: // the block. michael@0: michael@0: // The block frame that is using this object michael@0: nsBlockFrame* mBlock; michael@0: michael@0: nsPresContext* mPresContext; michael@0: michael@0: const nsHTMLReflowState& mReflowState; michael@0: michael@0: nsFloatManager* mFloatManager; michael@0: michael@0: // The coordinates within the float manager where the block is being michael@0: // placed after taking into account the blocks border and michael@0: // padding. This, therefore, represents the inner "content area" (in michael@0: // spacemanager coordinates) where child frames will be placed, michael@0: // including child blocks and floats. michael@0: nscoord mFloatManagerX, mFloatManagerY; michael@0: michael@0: // XXX get rid of this michael@0: nsReflowStatus mReflowStatus; michael@0: michael@0: // The float manager state as it was before the contents of this michael@0: // block. This is needed for positioning bullets, since we only want michael@0: // to move the bullet to flow around floats that were before this michael@0: // block, not floats inside of it. michael@0: nsFloatManager::SavedState mFloatManagerStateBefore; michael@0: michael@0: nscoord mBottomEdge; michael@0: michael@0: // The content area to reflow child frames within. This is within michael@0: // this frame's coordinate system, which means mContentArea.x == michael@0: // BorderPadding().left and mContentArea.y == BorderPadding().top. michael@0: // The height may be NS_UNCONSTRAINEDSIZE, which indicates that there michael@0: // is no page/column boundary below (the common case). michael@0: // mContentArea.YMost() should only be called after checking that michael@0: // mContentArea.height is not NS_UNCONSTRAINEDSIZE; otherwise michael@0: // coordinate overflow may occur. michael@0: nsRect mContentArea; michael@0: nscoord mContainerWidth; michael@0: michael@0: // Continuation out-of-flow float frames that need to move to our michael@0: // next in flow are placed here during reflow. It's a pointer to michael@0: // a frame list stored in the block's property table. michael@0: nsFrameList *mPushedFloats; michael@0: // This method makes sure pushed floats are accessible to michael@0: // StealFrame. Call it before adding any frames to mPushedFloats. michael@0: void SetupPushedFloatList(); michael@0: // Use this method to append to mPushedFloats. michael@0: void AppendPushedFloat(nsIFrame* aFloatCont); michael@0: michael@0: // Track child overflow continuations. michael@0: nsOverflowContinuationTracker* mOverflowTracker; michael@0: michael@0: //---------------------------------------- michael@0: michael@0: // This state is "running" state updated by the reflow of each line michael@0: // in the block. This same state is "recovered" when a line is not michael@0: // dirty and is passed over during incremental reflow. michael@0: michael@0: // The current line being reflowed michael@0: // If it is mBlock->end_lines(), then it is invalid. michael@0: nsLineList::iterator mCurrentLine; michael@0: michael@0: // When BRS_HAVELINEADJACENTTOTOP is set, this refers to a line michael@0: // which we know is adjacent to the top of the block (in other words, michael@0: // all lines before it are empty and do not have clearance. This line is michael@0: // always before the current line. michael@0: nsLineList::iterator mLineAdjacentToTop; michael@0: michael@0: // The current Y coordinate in the block michael@0: nscoord mY; michael@0: michael@0: // The overflow areas of all floats placed so far michael@0: nsOverflowAreas mFloatOverflowAreas; michael@0: michael@0: nsFloatCacheFreeList mFloatCacheFreeList; michael@0: michael@0: // Previous child. This is used when pulling up a frame to update michael@0: // the sibling list. michael@0: nsIFrame* mPrevChild; michael@0: michael@0: // The previous child frames collapsed bottom margin value. michael@0: nsCollapsingMargin mPrevBottomMargin; michael@0: michael@0: // The current next-in-flow for the block. When lines are pulled michael@0: // from a next-in-flow, this is used to know which next-in-flow to michael@0: // pull from. When a next-in-flow is emptied of lines, we advance michael@0: // this to the next next-in-flow. michael@0: nsBlockFrame* mNextInFlow; michael@0: michael@0: //---------------------------------------- michael@0: michael@0: // Temporary line-reflow state. This state is used during the reflow michael@0: // of a given line, but doesn't have meaning before or after. michael@0: michael@0: // The list of floats that are "current-line" floats. These are michael@0: // added to the line after the line has been reflowed, to keep the michael@0: // list fiddling from being N^2. michael@0: nsFloatCacheFreeList mCurrentLineFloats; michael@0: michael@0: // The list of floats which are "below current-line" michael@0: // floats. These are reflowed/placed after the line is reflowed michael@0: // and placed. Again, this is done to keep the list fiddling from michael@0: // being N^2. michael@0: nsFloatCacheFreeList mBelowCurrentLineFloats; michael@0: michael@0: nscoord mMinLineHeight; michael@0: michael@0: int32_t mLineNumber; michael@0: michael@0: int16_t mFlags; michael@0: michael@0: uint8_t mFloatBreakType; michael@0: michael@0: // The amount of computed height "consumed" by previous-in-flows. michael@0: nscoord mConsumedHeight; michael@0: michael@0: void SetFlag(uint32_t aFlag, bool aValue) michael@0: { michael@0: NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag"); michael@0: if (aValue) { // set flag michael@0: mFlags |= aFlag; michael@0: } michael@0: else { // unset flag michael@0: mFlags &= ~aFlag; michael@0: } michael@0: } michael@0: michael@0: bool GetFlag(uint32_t aFlag) const michael@0: { michael@0: NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag"); michael@0: return !!(mFlags & aFlag); michael@0: } michael@0: }; michael@0: michael@0: #endif // nsBlockReflowState_h__