/src/mozilla-central/layout/generic/BlockReflowInput.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
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 | | #ifndef BlockReflowInput_h |
10 | | #define BlockReflowInput_h |
11 | | |
12 | | #include "nsFloatManager.h" |
13 | | #include "nsLineBox.h" |
14 | | #include "mozilla/ReflowInput.h" |
15 | | |
16 | | class nsBlockFrame; |
17 | | class nsFrameList; |
18 | | class nsOverflowContinuationTracker; |
19 | | |
20 | | namespace mozilla { |
21 | | |
22 | | // BlockReflowInput contains additional reflow input information that the |
23 | | // block frame uses along with ReflowInput. Like ReflowInput, this |
24 | | // is read-only data that is passed down from a parent frame to its children. |
25 | | class BlockReflowInput { |
26 | | using BandInfoType = nsFloatManager::BandInfoType; |
27 | | using ShapeType = nsFloatManager::ShapeType; |
28 | | |
29 | | // Block reflow input flags. |
30 | | struct Flags { |
31 | | Flags() |
32 | | : mHasUnconstrainedBSize(false) |
33 | | , mIsBStartMarginRoot(false) |
34 | | , mIsBEndMarginRoot(false) |
35 | | , mShouldApplyBStartMargin(false) |
36 | | , mIsFirstInflow(false) |
37 | | , mHasLineAdjacentToTop(false) |
38 | | , mBlockNeedsFloatManager(false) |
39 | | , mIsLineLayoutEmpty(false) |
40 | | , mIsOverflowContainer(false) |
41 | | , mIsFloatListInBlockPropertyTable(false) |
42 | | , mFloatFragmentsInsideColumnEnabled(false) |
43 | | , mCanHaveTextOverflow(false) |
44 | 0 | {} |
45 | | |
46 | | // Set in the BlockReflowInput constructor when the frame being reflowed has |
47 | | // been given NS_UNCONSTRAINEDSIZE as its available BSize in the |
48 | | // ReflowInput. If set, NS_UNCONSTRAINEDSIZE is passed to nsLineLayout as |
49 | | // the available BSize. |
50 | | bool mHasUnconstrainedBSize : 1; |
51 | | |
52 | | // Set in the BlockReflowInput constructor when reflowing a "block margin |
53 | | // root" frame (i.e. a frame with the NS_BLOCK_MARGIN_ROOT flag set, for |
54 | | // which margins apply by default). |
55 | | // |
56 | | // The flag is also set when reflowing a frame whose computed BStart border |
57 | | // padding is non-zero. |
58 | | bool mIsBStartMarginRoot : 1; |
59 | | |
60 | | // Set in the BlockReflowInput constructor when reflowing a "block margin |
61 | | // root" frame (i.e. a frame with the NS_BLOCK_MARGIN_ROOT flag set, for |
62 | | // which margins apply by default). |
63 | | // |
64 | | // The flag is also set when reflowing a frame whose computed BEnd border |
65 | | // padding is non-zero. |
66 | | bool mIsBEndMarginRoot : 1; |
67 | | |
68 | | // Set if the BStart margin should be considered when placing a linebox that |
69 | | // contains a block frame. It may be set as a side-effect of calling |
70 | | // nsBlockFrame::ShouldApplyBStartMargin(); once set, |
71 | | // ShouldApplyBStartMargin() uses it as a fast-path way to return whether |
72 | | // the BStart margin should apply. |
73 | | // |
74 | | // If the flag hasn't been set in the block reflow input, then |
75 | | // ShouldApplyBStartMargin() will crawl the line list to see if a block frame |
76 | | // precedes the specified frame. If so, the BStart margin should be applied, and |
77 | | // the flag is set to cache the result. (If not, the BStart margin will be |
78 | | // applied as a result of the generational margin collapsing logic in |
79 | | // nsBlockReflowContext::ComputeCollapsedBStartMargin(). In this case, the flag |
80 | | // won't be set, so subsequent calls to ShouldApplyBStartMargin() will continue |
81 | | // crawl the line list.) |
82 | | // |
83 | | // This flag is also set in the BlockReflowInput constructor if |
84 | | // mIsBStartMarginRoot is set; that is, the frame being reflowed is a margin |
85 | | // root by default. |
86 | | bool mShouldApplyBStartMargin : 1; |
87 | | |
88 | | bool mIsFirstInflow : 1; |
89 | | |
90 | | // Set when mLineAdjacentToTop is valid. |
91 | | bool mHasLineAdjacentToTop : 1; |
92 | | |
93 | | // Set when the block has the equivalent of NS_BLOCK_FLOAT_MGR. |
94 | | bool mBlockNeedsFloatManager : 1; |
95 | | |
96 | | // Set when nsLineLayout::LineIsEmpty was true at the end of reflowing |
97 | | // the current line. |
98 | | bool mIsLineLayoutEmpty : 1; |
99 | | |
100 | | bool mIsOverflowContainer : 1; |
101 | | |
102 | | // Set when our mPushedFloats list is stored on the block's property table. |
103 | | bool mIsFloatListInBlockPropertyTable : 1; |
104 | | |
105 | | // Set when the pref layout.float-fragments-inside-column.enabled is true. |
106 | | bool mFloatFragmentsInsideColumnEnabled : 1; |
107 | | |
108 | | // Set when we need text-overflow processing. |
109 | | bool mCanHaveTextOverflow : 1; |
110 | | }; |
111 | | |
112 | | public: |
113 | | BlockReflowInput(const ReflowInput& aReflowInput, |
114 | | nsPresContext* aPresContext, |
115 | | nsBlockFrame* aFrame, |
116 | | bool aBStartMarginRoot, bool aBEndMarginRoot, |
117 | | bool aBlockNeedsFloatManager, |
118 | | nscoord aConsumedBSize = NS_INTRINSICSIZE); |
119 | | |
120 | | /** |
121 | | * Get the available reflow space (the area not occupied by floats) |
122 | | * for the current y coordinate. The available space is relative to |
123 | | * our coordinate system, which is the content box, with (0, 0) in the |
124 | | * upper left. |
125 | | * |
126 | | * Returns whether there are floats present at the given block-direction |
127 | | * coordinate and within the inline size of the content rect. |
128 | | */ |
129 | | nsFlowAreaRect GetFloatAvailableSpace() const |
130 | 0 | { return GetFloatAvailableSpace(mBCoord); } |
131 | | nsFlowAreaRect GetFloatAvailableSpaceForPlacingFloat(nscoord aBCoord) const |
132 | 0 | { return GetFloatAvailableSpaceWithState( |
133 | 0 | aBCoord, ShapeType::Margin, nullptr); } |
134 | | nsFlowAreaRect GetFloatAvailableSpace(nscoord aBCoord) const |
135 | 0 | { return GetFloatAvailableSpaceWithState( |
136 | 0 | aBCoord, ShapeType::ShapeOutside, nullptr); } |
137 | | nsFlowAreaRect |
138 | | GetFloatAvailableSpaceWithState(nscoord aBCoord, ShapeType aShapeType, |
139 | | nsFloatManager::SavedState *aState) const; |
140 | | nsFlowAreaRect |
141 | | GetFloatAvailableSpaceForBSize(nscoord aBCoord, nscoord aBSize, |
142 | | nsFloatManager::SavedState *aState) const; |
143 | | |
144 | | /* |
145 | | * The following functions all return true if they were able to |
146 | | * place the float, false if the float did not fit in available |
147 | | * space. |
148 | | * aLineLayout is null when we are reflowing pushed floats (because |
149 | | * they are not associated with a line box). |
150 | | */ |
151 | | bool AddFloat(nsLineLayout* aLineLayout, |
152 | | nsIFrame* aFloat, |
153 | | nscoord aAvailableISize); |
154 | | |
155 | | bool FlowAndPlaceFloat(nsIFrame* aFloat); |
156 | | |
157 | | void PlaceBelowCurrentLineFloats(nsLineBox* aLine); |
158 | | |
159 | | // Returns the first coordinate >= aBCoord that clears the |
160 | | // floats indicated by aBreakType and has enough inline size between floats |
161 | | // (or no floats remaining) to accomodate aReplacedBlock. |
162 | | nscoord ClearFloats(nscoord aBCoord, mozilla::StyleClear aBreakType, |
163 | | nsIFrame *aReplacedBlock = nullptr, |
164 | | uint32_t aFlags = 0); |
165 | | |
166 | 0 | nsFloatManager* FloatManager() const { |
167 | 0 | MOZ_ASSERT(mReflowInput.mFloatManager, |
168 | 0 | "Float manager should be valid during the lifetime of " |
169 | 0 | "BlockReflowInput!"); |
170 | 0 | return mReflowInput.mFloatManager; |
171 | 0 | } |
172 | | |
173 | | // Advances to the next band, i.e., the next horizontal stripe in |
174 | | // which there is a different set of floats. |
175 | | // Return false if it did not advance, which only happens for |
176 | | // constrained heights (and means that we should get pushed to the |
177 | | // next column/page). |
178 | | bool AdvanceToNextBand(const mozilla::LogicalRect& aFloatAvailableSpace, |
179 | 0 | nscoord *aBCoord) const { |
180 | 0 | mozilla::WritingMode wm = mReflowInput.GetWritingMode(); |
181 | 0 | if (aFloatAvailableSpace.BSize(wm) > 0) { |
182 | 0 | // See if there's room in the next band. |
183 | 0 | *aBCoord += aFloatAvailableSpace.BSize(wm); |
184 | 0 | } else { |
185 | 0 | if (mReflowInput.AvailableHeight() != NS_UNCONSTRAINEDSIZE) { |
186 | 0 | // Stop trying to clear here; we'll just get pushed to the |
187 | 0 | // next column or page and try again there. |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | MOZ_ASSERT_UNREACHABLE("avail space rect with zero height!"); |
191 | 0 | *aBCoord += 1; |
192 | 0 | } |
193 | 0 | return true; |
194 | 0 | } |
195 | | |
196 | | bool ReplacedBlockFitsInAvailSpace(nsIFrame* aReplacedBlock, |
197 | | const nsFlowAreaRect& aFloatAvailableSpace) const; |
198 | | |
199 | 0 | bool IsAdjacentWithTop() const { |
200 | 0 | return mBCoord == mBorderPadding.BStart(mReflowInput.GetWritingMode()); |
201 | 0 | } |
202 | | |
203 | | /** |
204 | | * Return mBlock's computed physical border+padding with GetSkipSides applied. |
205 | | */ |
206 | 0 | const mozilla::LogicalMargin& BorderPadding() const { |
207 | 0 | return mBorderPadding; |
208 | 0 | } |
209 | | |
210 | | /** |
211 | | * Retrieve the block-axis content size "consumed" by any prev-in-flows. |
212 | | * @note the value is cached so subsequent calls will return the same value |
213 | | */ |
214 | | nscoord ConsumedBSize(); |
215 | | |
216 | | // Reconstruct the previous block-end margin that goes before |aLine|. |
217 | | void ReconstructMarginBefore(nsLineList::iterator aLine); |
218 | | |
219 | | // Caller must have called GetAvailableSpace for the correct position |
220 | | // (which need not be the current mBCoord). |
221 | | void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame, |
222 | | const mozilla::LogicalRect& aFloatAvailableSpace, |
223 | | nscoord& aIStartResult, |
224 | | nscoord& aIEndResult) const; |
225 | | |
226 | | // Caller must have called GetAvailableSpace for the current mBCoord |
227 | | void ComputeBlockAvailSpace(nsIFrame* aFrame, |
228 | | const nsFlowAreaRect& aFloatAvailableSpace, |
229 | | bool aBlockAvoidsFloats, |
230 | | mozilla::LogicalRect& aResult); |
231 | | |
232 | | void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaBCoord); |
233 | | |
234 | 0 | void AdvanceToNextLine() { |
235 | 0 | if (mFlags.mIsLineLayoutEmpty) { |
236 | 0 | mFlags.mIsLineLayoutEmpty = false; |
237 | 0 | } else { |
238 | 0 | mLineNumber++; |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | | //---------------------------------------- |
243 | | |
244 | | // This state is the "global" state computed once for the reflow of |
245 | | // the block. |
246 | | |
247 | | // The block frame that is using this object |
248 | | nsBlockFrame* mBlock; |
249 | | |
250 | | nsPresContext* mPresContext; |
251 | | |
252 | | const ReflowInput& mReflowInput; |
253 | | |
254 | | // The coordinates within the float manager where the block is being |
255 | | // placed <b>after</b> taking into account the blocks border and |
256 | | // padding. This, therefore, represents the inner "content area" (in |
257 | | // float manager coordinates) where child frames will be placed, |
258 | | // including child blocks and floats. |
259 | | nscoord mFloatManagerI, mFloatManagerB; |
260 | | |
261 | | // XXX get rid of this |
262 | | nsReflowStatus mReflowStatus; |
263 | | |
264 | | // The float manager state as it was before the contents of this |
265 | | // block. This is needed for positioning bullets, since we only want |
266 | | // to move the bullet to flow around floats that were before this |
267 | | // block, not floats inside of it. |
268 | | nsFloatManager::SavedState mFloatManagerStateBefore; |
269 | | |
270 | | nscoord mBEndEdge; |
271 | | |
272 | | // The content area to reflow child frames within. This is within |
273 | | // this frame's coordinate system and writing mode, which means |
274 | | // mContentArea.IStart == BorderPadding().IStart and |
275 | | // mContentArea.BStart == BorderPadding().BStart. |
276 | | // The block size may be NS_UNCONSTRAINEDSIZE, which indicates that there |
277 | | // is no page/column boundary below (the common case). |
278 | | // mContentArea.BEnd() should only be called after checking that |
279 | | // mContentArea.BSize is not NS_UNCONSTRAINEDSIZE; otherwise |
280 | | // coordinate overflow may occur. |
281 | | mozilla::LogicalRect mContentArea; |
282 | 0 | nscoord ContentIStart() const { |
283 | 0 | return mContentArea.IStart(mReflowInput.GetWritingMode()); |
284 | 0 | } |
285 | 0 | nscoord ContentISize() const { |
286 | 0 | return mContentArea.ISize(mReflowInput.GetWritingMode()); |
287 | 0 | } |
288 | 0 | nscoord ContentIEnd() const { |
289 | 0 | return mContentArea.IEnd(mReflowInput.GetWritingMode()); |
290 | 0 | } |
291 | 0 | nscoord ContentBStart() const { |
292 | 0 | return mContentArea.BStart(mReflowInput.GetWritingMode()); |
293 | 0 | } |
294 | 0 | nscoord ContentBSize() const { |
295 | 0 | return mContentArea.BSize(mReflowInput.GetWritingMode()); |
296 | 0 | } |
297 | 0 | nscoord ContentBEnd() const { |
298 | 0 | return mContentArea.BEnd(mReflowInput.GetWritingMode()); |
299 | 0 | } |
300 | 0 | mozilla::LogicalSize ContentSize(mozilla::WritingMode aWM) const { |
301 | 0 | mozilla::WritingMode wm = mReflowInput.GetWritingMode(); |
302 | 0 | return mContentArea.Size(wm).ConvertTo(aWM, wm); |
303 | 0 | } |
304 | | |
305 | | // Physical size. Use only for physical <-> logical coordinate conversion. |
306 | | nsSize mContainerSize; |
307 | 0 | const nsSize& ContainerSize() const { return mContainerSize; } |
308 | | |
309 | | // Continuation out-of-flow float frames that need to move to our |
310 | | // next in flow are placed here during reflow. It's a pointer to |
311 | | // a frame list stored in the block's property table. |
312 | | nsFrameList *mPushedFloats; |
313 | | // This method makes sure pushed floats are accessible to |
314 | | // StealFrame. Call it before adding any frames to mPushedFloats. |
315 | | void SetupPushedFloatList(); |
316 | | /** |
317 | | * Append aFloatCont and its next-in-flows within the same block to |
318 | | * mPushedFloats. aFloatCont should not be on any child list when |
319 | | * making this call. Its next-in-flows will be removed from |
320 | | * mBlock using StealFrame() before being added to mPushedFloats. |
321 | | * All appended frames will be marked NS_FRAME_IS_PUSHED_FLOAT. |
322 | | */ |
323 | | void AppendPushedFloatChain(nsIFrame* aFloatCont); |
324 | | |
325 | | // Track child overflow continuations. |
326 | | nsOverflowContinuationTracker* mOverflowTracker; |
327 | | |
328 | | //---------------------------------------- |
329 | | |
330 | | // This state is "running" state updated by the reflow of each line |
331 | | // in the block. This same state is "recovered" when a line is not |
332 | | // dirty and is passed over during incremental reflow. |
333 | | |
334 | | // The current line being reflowed |
335 | | // If it is mBlock->end_lines(), then it is invalid. |
336 | | nsLineList::iterator mCurrentLine; |
337 | | |
338 | | // When mHasLineAdjacentToTop is set, this refers to a line |
339 | | // which we know is adjacent to the top of the block (in other words, |
340 | | // all lines before it are empty and do not have clearance. This line is |
341 | | // always before the current line. |
342 | | nsLineList::iterator mLineAdjacentToTop; |
343 | | |
344 | | // The current block-direction coordinate in the block |
345 | | nscoord mBCoord; |
346 | | |
347 | | // mBlock's computed physical border+padding with GetSkipSides applied. |
348 | | mozilla::LogicalMargin mBorderPadding; |
349 | | |
350 | | // The overflow areas of all floats placed so far |
351 | | nsOverflowAreas mFloatOverflowAreas; |
352 | | |
353 | | nsFloatCacheFreeList mFloatCacheFreeList; |
354 | | |
355 | | // Previous child. This is used when pulling up a frame to update |
356 | | // the sibling list. |
357 | | nsIFrame* mPrevChild; |
358 | | |
359 | | // The previous child frames collapsed bottom margin value. |
360 | | nsCollapsingMargin mPrevBEndMargin; |
361 | | |
362 | | // The current next-in-flow for the block. When lines are pulled |
363 | | // from a next-in-flow, this is used to know which next-in-flow to |
364 | | // pull from. When a next-in-flow is emptied of lines, we advance |
365 | | // this to the next next-in-flow. |
366 | | nsBlockFrame* mNextInFlow; |
367 | | |
368 | | //---------------------------------------- |
369 | | |
370 | | // Temporary line-reflow state. This state is used during the reflow |
371 | | // of a given line, but doesn't have meaning before or after. |
372 | | |
373 | | // The list of floats that are "current-line" floats. These are |
374 | | // added to the line after the line has been reflowed, to keep the |
375 | | // list fiddling from being N^2. |
376 | | nsFloatCacheFreeList mCurrentLineFloats; |
377 | | |
378 | | // The list of floats which are "below current-line" |
379 | | // floats. These are reflowed/placed after the line is reflowed |
380 | | // and placed. Again, this is done to keep the list fiddling from |
381 | | // being N^2. |
382 | | nsFloatCacheFreeList mBelowCurrentLineFloats; |
383 | | |
384 | | // The list of floats that are waiting on a break opportunity in order to be |
385 | | // placed, since we're on a nowrap context. |
386 | | nsTArray<nsIFrame*> mNoWrapFloats; |
387 | | |
388 | | nscoord mMinLineHeight; |
389 | | |
390 | | int32_t mLineNumber; |
391 | | |
392 | | Flags mFlags; |
393 | | |
394 | | StyleClear mFloatBreakType; |
395 | | |
396 | | // The amount of computed block-direction size "consumed" by previous-in-flows. |
397 | | nscoord mConsumedBSize; |
398 | | |
399 | | // Cache the current line's BSize if nsBlockFrame::PlaceLine() fails to |
400 | | // place the line. When redoing the line, it will be used to query the |
401 | | // accurate float available space in AddFloat() and |
402 | | // nsBlockFrame::PlaceLine(). |
403 | | mozilla::Maybe<nscoord> mLineBSize; |
404 | | |
405 | | private: |
406 | | bool CanPlaceFloat(nscoord aFloatISize, |
407 | | const nsFlowAreaRect& aFloatAvailableSpace); |
408 | | |
409 | | void PushFloatPastBreak(nsIFrame* aFloat); |
410 | | |
411 | | void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaBCoord); |
412 | | }; |
413 | | |
414 | | }; // namespace mozilla |
415 | | |
416 | | #endif // BlockReflowInput_h |