1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Steve Clark <buster@netscape.com>
24 : * Robert O'Callahan <roc+moz@cs.cmu.edu>
25 : * L. David Baron <dbaron@dbaron.org>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /* state used in reflow of block frames */
42 :
43 : #ifndef nsBlockReflowState_h__
44 : #define nsBlockReflowState_h__
45 :
46 : #include "nsFloatManager.h"
47 : #include "nsLineBox.h"
48 : #include "nsFrameList.h"
49 : #include "nsBlockFrame.h"
50 :
51 : // block reflow state flags
52 : #define BRS_UNCONSTRAINEDHEIGHT 0x00000001
53 : #define BRS_ISTOPMARGINROOT 0x00000002 // Is this frame a root for top/bottom margin collapsing?
54 : #define BRS_ISBOTTOMMARGINROOT 0x00000004
55 : #define BRS_APPLYTOPMARGIN 0x00000008 // See ShouldApplyTopMargin
56 : #define BRS_ISFIRSTINFLOW 0x00000010
57 : // Set when mLineAdjacentToTop is valid
58 : #define BRS_HAVELINEADJACENTTOTOP 0x00000020
59 : // Set when the block has the equivalent of NS_BLOCK_FLOAT_MGR
60 : #define BRS_FLOAT_MGR 0x00000040
61 : // Set when nsLineLayout::LineIsEmpty was true at the end of reflowing
62 : // the current line
63 : #define BRS_LINE_LAYOUT_EMPTY 0x00000080
64 : #define BRS_ISOVERFLOWCONTAINER 0x00000100
65 : // Our mPushedFloats list is stored on the blocks' proptable
66 : #define BRS_PROPTABLE_FLOATCLIST 0x00000200
67 : #define BRS_LASTFLAG BRS_PROPTABLE_FLOATCLIST
68 :
69 0 : class nsBlockReflowState {
70 : public:
71 : nsBlockReflowState(const nsHTMLReflowState& aReflowState,
72 : nsPresContext* aPresContext,
73 : nsBlockFrame* aFrame,
74 : const nsHTMLReflowMetrics& aMetrics,
75 : bool aTopMarginRoot, bool aBottomMarginRoot,
76 : bool aBlockNeedsFloatManager);
77 :
78 : /**
79 : * Get the available reflow space (the area not occupied by floats)
80 : * for the current y coordinate. The available space is relative to
81 : * our coordinate system, which is the content box, with (0, 0) in the
82 : * upper left.
83 : *
84 : * Returns whether there are floats present at the given vertical
85 : * coordinate and within the width of the content rect.
86 : */
87 0 : nsFlowAreaRect GetFloatAvailableSpace() const
88 0 : { return GetFloatAvailableSpace(mY); }
89 0 : nsFlowAreaRect GetFloatAvailableSpace(nscoord aY) const
90 0 : { return GetFloatAvailableSpaceWithState(aY, nsnull); }
91 : nsFlowAreaRect
92 : GetFloatAvailableSpaceWithState(nscoord aY,
93 : nsFloatManager::SavedState *aState) const;
94 : nsFlowAreaRect
95 : GetFloatAvailableSpaceForHeight(nscoord aY, nscoord aHeight,
96 : nsFloatManager::SavedState *aState) const;
97 :
98 : /*
99 : * The following functions all return true if they were able to
100 : * place the float, false if the float did not fit in available
101 : * space.
102 : * aLineLayout is null when we are reflowing pushed floats (because
103 : * they are not associated with a line box).
104 : */
105 : bool AddFloat(nsLineLayout* aLineLayout,
106 : nsIFrame* aFloat,
107 : nscoord aAvailableWidth);
108 : private:
109 : bool CanPlaceFloat(nscoord aFloatWidth,
110 : const nsFlowAreaRect& aFloatAvailableSpace);
111 : public:
112 : bool FlowAndPlaceFloat(nsIFrame* aFloat);
113 : private:
114 : void PushFloatPastBreak(nsIFrame* aFloat);
115 : public:
116 : void PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aFloats,
117 : nsLineBox* aLine);
118 :
119 : // Returns the first coordinate >= aY that clears the
120 : // floats indicated by aBreakType and has enough width between floats
121 : // (or no floats remaining) to accomodate aReplacedBlock.
122 : nscoord ClearFloats(nscoord aY, PRUint8 aBreakType,
123 : nsIFrame *aReplacedBlock = nsnull,
124 : PRUint32 aFlags = 0);
125 :
126 0 : bool IsAdjacentWithTop() const {
127 : return mY ==
128 0 : ((mFlags & BRS_ISFIRSTINFLOW) ? mReflowState.mComputedBorderPadding.top : 0);
129 : }
130 :
131 : /**
132 : * Adjusts the border/padding to return 0 for the top if
133 : * we are not the first in flow.
134 : */
135 0 : nsMargin BorderPadding() const {
136 0 : nsMargin result = mReflowState.mComputedBorderPadding;
137 0 : if (!(mFlags & BRS_ISFIRSTINFLOW)) {
138 0 : result.top = 0;
139 0 : if (mFlags & BRS_ISOVERFLOWCONTAINER) {
140 0 : result.bottom = 0;
141 : }
142 : }
143 : return result;
144 : }
145 :
146 : // XXX maybe we should do the same adjustment for continuations here
147 : const nsMargin& Margin() const {
148 : return mReflowState.mComputedMargin;
149 : }
150 :
151 : // Reconstruct the previous bottom margin that goes above |aLine|.
152 : void ReconstructMarginAbove(nsLineList::iterator aLine);
153 :
154 : // Caller must have called GetAvailableSpace for the correct position
155 : // (which need not be the current mY).
156 : void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
157 : const nsRect& aFloatAvailableSpace,
158 : nscoord& aLeftResult,
159 : nscoord& aRightResult);
160 :
161 : // Caller must have called GetAvailableSpace for the current mY
162 : void ComputeBlockAvailSpace(nsIFrame* aFrame,
163 : const nsStyleDisplay* aDisplay,
164 : const nsFlowAreaRect& aFloatAvailableSpace,
165 : bool aBlockAvoidsFloats,
166 : nsRect& aResult);
167 :
168 : protected:
169 : void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaY);
170 :
171 : public:
172 : void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaY);
173 :
174 0 : void AdvanceToNextLine() {
175 0 : if (GetFlag(BRS_LINE_LAYOUT_EMPTY)) {
176 0 : SetFlag(BRS_LINE_LAYOUT_EMPTY, false);
177 : } else {
178 0 : mLineNumber++;
179 : }
180 0 : }
181 :
182 : //----------------------------------------
183 :
184 : // This state is the "global" state computed once for the reflow of
185 : // the block.
186 :
187 : // The block frame that is using this object
188 : nsBlockFrame* mBlock;
189 :
190 : nsPresContext* mPresContext;
191 :
192 : const nsHTMLReflowState& mReflowState;
193 :
194 : nsFloatManager* mFloatManager;
195 :
196 : // The coordinates within the float manager where the block is being
197 : // placed <b>after</b> taking into account the blocks border and
198 : // padding. This, therefore, represents the inner "content area" (in
199 : // spacemanager coordinates) where child frames will be placed,
200 : // including child blocks and floats.
201 : nscoord mFloatManagerX, mFloatManagerY;
202 :
203 : // XXX get rid of this
204 : nsReflowStatus mReflowStatus;
205 :
206 : // The float manager state as it was before the contents of this
207 : // block. This is needed for positioning bullets, since we only want
208 : // to move the bullet to flow around floats that were before this
209 : // block, not floats inside of it.
210 : nsFloatManager::SavedState mFloatManagerStateBefore;
211 :
212 : nscoord mBottomEdge;
213 :
214 : // The content area to reflow child frames within. This is within
215 : // this frame's coordinate system, which means mContentArea.x ==
216 : // BorderPadding().left and mContentArea.y == BorderPadding().top.
217 : // The height may be NS_UNCONSTRAINEDSIZE, which indicates that there
218 : // is no page/column boundary below (the common case).
219 : // mContentArea.YMost() should only be called after checking that
220 : // mContentArea.height is not NS_UNCONSTRAINEDSIZE; otherwise
221 : // coordinate overflow may occur.
222 : nsRect mContentArea;
223 :
224 : // Continuation out-of-flow float frames that need to move to our
225 : // next in flow are placed here during reflow. It's a pointer to
226 : // a frame list stored in the block's property table.
227 : nsFrameList *mPushedFloats;
228 : // This method makes sure pushed floats are accessible to
229 : // StealFrame. Call it before adding any frames to mPushedFloats.
230 : void SetupPushedFloatList();
231 : // Use this method to append to mPushedFloats.
232 0 : void AppendPushedFloat(nsIFrame* aFloatCont) {
233 0 : SetupPushedFloatList();
234 0 : aFloatCont->AddStateBits(NS_FRAME_IS_PUSHED_FLOAT);
235 0 : mPushedFloats->AppendFrame(mBlock, aFloatCont);
236 0 : }
237 :
238 : // Track child overflow continuations.
239 : nsOverflowContinuationTracker* mOverflowTracker;
240 :
241 : //----------------------------------------
242 :
243 : // This state is "running" state updated by the reflow of each line
244 : // in the block. This same state is "recovered" when a line is not
245 : // dirty and is passed over during incremental reflow.
246 :
247 : // The current line being reflowed
248 : // If it is mBlock->end_lines(), then it is invalid.
249 : nsLineList::iterator mCurrentLine;
250 :
251 : // When BRS_HAVELINEADJACENTTOTOP is set, this refers to a line
252 : // which we know is adjacent to the top of the block (in other words,
253 : // all lines before it are empty and do not have clearance. This line is
254 : // always before the current line.
255 : nsLineList::iterator mLineAdjacentToTop;
256 :
257 : // The current Y coordinate in the block
258 : nscoord mY;
259 :
260 : // The overflow areas of all floats placed so far
261 : nsOverflowAreas mFloatOverflowAreas;
262 :
263 : nsFloatCacheFreeList mFloatCacheFreeList;
264 :
265 : // Previous child. This is used when pulling up a frame to update
266 : // the sibling list.
267 : nsIFrame* mPrevChild;
268 :
269 : // The previous child frames collapsed bottom margin value.
270 : nsCollapsingMargin mPrevBottomMargin;
271 :
272 : // The current next-in-flow for the block. When lines are pulled
273 : // from a next-in-flow, this is used to know which next-in-flow to
274 : // pull from. When a next-in-flow is emptied of lines, we advance
275 : // this to the next next-in-flow.
276 : nsBlockFrame* mNextInFlow;
277 :
278 : //----------------------------------------
279 :
280 : // Temporary line-reflow state. This state is used during the reflow
281 : // of a given line, but doesn't have meaning before or after.
282 :
283 : // The list of floats that are "current-line" floats. These are
284 : // added to the line after the line has been reflowed, to keep the
285 : // list fiddling from being N^2.
286 : nsFloatCacheFreeList mCurrentLineFloats;
287 :
288 : // The list of floats which are "below current-line"
289 : // floats. These are reflowed/placed after the line is reflowed
290 : // and placed. Again, this is done to keep the list fiddling from
291 : // being N^2.
292 : nsFloatCacheFreeList mBelowCurrentLineFloats;
293 :
294 : nscoord mMinLineHeight;
295 :
296 : PRInt32 mLineNumber;
297 :
298 : PRInt16 mFlags;
299 :
300 : PRUint8 mFloatBreakType;
301 :
302 0 : void SetFlag(PRUint32 aFlag, bool aValue)
303 : {
304 0 : NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
305 : NS_ASSERTION(aValue==false || aValue==true, "bad value");
306 0 : if (aValue) { // set flag
307 0 : mFlags |= aFlag;
308 : }
309 : else { // unset flag
310 0 : mFlags &= ~aFlag;
311 : }
312 0 : }
313 :
314 0 : bool GetFlag(PRUint32 aFlag) const
315 : {
316 0 : NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
317 0 : return !!(mFlags & aFlag);
318 : }
319 : };
320 :
321 : #endif // nsBlockReflowState_h__
|