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