Backed out changeset 496886cb30a5 (bug 1867152) for bc failures on browser_user_input...
[gecko.git] / layout / generic / BlockReflowState.h
blobc352e0693047506f9d21aa78d3687ad640f84703
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/. */
7 /* state used in reflow of block frames */
9 #ifndef BlockReflowState_h
10 #define BlockReflowState_h
12 #include <tuple>
14 #include "mozilla/ReflowInput.h"
15 #include "nsFloatManager.h"
16 #include "nsLineBox.h"
18 class nsBlockFrame;
19 class nsFrameList;
20 class nsOverflowContinuationTracker;
22 namespace mozilla {
24 // BlockReflowState contains additional reflow input information that the
25 // block frame uses along with ReflowInput. Like ReflowInput, this
26 // is read-only data that is passed down from a parent frame to its children.
27 class BlockReflowState {
28 using BandInfoType = nsFloatManager::BandInfoType;
29 using ShapeType = nsFloatManager::ShapeType;
31 // Block reflow input flags.
32 struct Flags {
33 Flags()
34 : mIsBStartMarginRoot(false),
35 mIsBEndMarginRoot(false),
36 mShouldApplyBStartMargin(false),
37 mHasLineAdjacentToTop(false),
38 mBlockNeedsFloatManager(false),
39 mIsLineLayoutEmpty(false),
40 mIsFloatListInBlockPropertyTable(false),
41 mCanHaveOverflowMarkers(false) {}
43 // Set in the BlockReflowState constructor when reflowing a "block margin
44 // root" frame (i.e. a frame with the NS_BLOCK_MARGIN_ROOT flag set, for
45 // which margins apply by default).
47 // The flag is also set when reflowing a frame whose computed BStart border
48 // padding is non-zero.
49 bool mIsBStartMarginRoot : 1;
51 // Set in the BlockReflowState constructor when reflowing a "block margin
52 // root" frame (i.e. a frame with the NS_BLOCK_MARGIN_ROOT flag set, for
53 // which margins apply by default).
55 // The flag is also set when reflowing a frame whose computed BEnd border
56 // padding is non-zero.
57 bool mIsBEndMarginRoot : 1;
59 // Set if the BStart margin should be considered when placing a linebox that
60 // contains a block frame. It may be set as a side-effect of calling
61 // nsBlockFrame::ShouldApplyBStartMargin(); once set,
62 // ShouldApplyBStartMargin() uses it as a fast-path way to return whether
63 // the BStart margin should apply.
65 // If the flag hasn't been set in the block reflow state, then
66 // ShouldApplyBStartMargin() will crawl the line list to see if a block
67 // frame precedes the specified frame. If so, the BStart margin should be
68 // applied, and the flag is set to cache the result. (If not, the BStart
69 // margin will be applied as a result of the generational margin collapsing
70 // logic in nsBlockReflowContext::ComputeCollapsedBStartMargin(). In this
71 // case, the flag won't be set, so subsequent calls to
72 // ShouldApplyBStartMargin() will continue crawl the line list.)
74 // This flag is also set in the BlockReflowState constructor if
75 // mIsBStartMarginRoot is set; that is, the frame being reflowed is a margin
76 // root by default.
77 bool mShouldApplyBStartMargin : 1;
79 // Set when mLineAdjacentToTop is valid.
80 bool mHasLineAdjacentToTop : 1;
82 // Set when the block has the equivalent of NS_BLOCK_FLOAT_MGR.
83 bool mBlockNeedsFloatManager : 1;
85 // Set when nsLineLayout::LineIsEmpty was true at the end of reflowing
86 // the current line.
87 bool mIsLineLayoutEmpty : 1;
89 // Set when our mPushedFloats list is stored on the block's property table.
90 bool mIsFloatListInBlockPropertyTable : 1;
92 // Set when we need text-overflow or -webkit-line-clamp processing.
93 bool mCanHaveOverflowMarkers : 1;
96 public:
97 BlockReflowState(const ReflowInput& aReflowInput, nsPresContext* aPresContext,
98 nsBlockFrame* aFrame, bool aBStartMarginRoot,
99 bool aBEndMarginRoot, bool aBlockNeedsFloatManager,
100 const nscoord aConsumedBSize,
101 const nscoord aEffectiveContentBoxBSize,
102 const nscoord aInset = 0);
105 * Get the available reflow space (the area not occupied by floats)
106 * for the current y coordinate. The available space is relative to
107 * our coordinate system, which is the content box, with (0, 0) in the
108 * upper left.
110 * Returns whether there are floats present at the given block-direction
111 * coordinate and within the inline size of the content rect.
113 * Note: some codepaths clamp this structure's inline-size to be >=0 "for
114 * compatibility with nsSpaceManager". So if you encounter a nsFlowAreaRect
115 * which appears to have an ISize of 0, you can't necessarily assume that a
116 * 0-ISize float-avoiding block would actually fit; you need to check the
117 * InitialISizeIsNegative flag to see whether that 0 is actually a clamped
118 * negative value (in which case a 0-ISize float-avoiding block *should not*
119 * be considered as fitting, because it would intersect some float).
121 nsFlowAreaRect GetFloatAvailableSpace() const {
122 return GetFloatAvailableSpace(mBCoord);
124 nsFlowAreaRect GetFloatAvailableSpaceForPlacingFloat(nscoord aBCoord) const {
125 return GetFloatAvailableSpaceWithState(aBCoord, ShapeType::Margin, nullptr);
127 nsFlowAreaRect GetFloatAvailableSpace(nscoord aBCoord) const {
128 return GetFloatAvailableSpaceWithState(aBCoord, ShapeType::ShapeOutside,
129 nullptr);
131 nsFlowAreaRect GetFloatAvailableSpaceWithState(
132 nscoord aBCoord, ShapeType aShapeType,
133 nsFloatManager::SavedState* aState) const;
134 nsFlowAreaRect GetFloatAvailableSpaceForBSize(
135 nscoord aBCoord, nscoord aBSize,
136 nsFloatManager::SavedState* aState) const;
138 // @return true if AddFloat was able to place the float; false if the float
139 // did not fit in available space.
141 // Note: if it returns false, then the float's position and size should be
142 // considered stale/invalid (until the float is successfully placed).
143 bool AddFloat(nsLineLayout* aLineLayout, nsIFrame* aFloat,
144 nscoord aAvailableISize);
146 enum class PlaceFloatResult : uint8_t {
147 Placed,
148 ShouldPlaceBelowCurrentLine,
149 ShouldPlaceInNextContinuation,
151 // @param aAvailableISizeInCurrentLine the available inline-size of the
152 // current line if current line is not empty.
153 PlaceFloatResult FlowAndPlaceFloat(
154 nsIFrame* aFloat, mozilla::Maybe<nscoord> aAvailableISizeInCurrentLine =
155 mozilla::Nothing());
157 void PlaceBelowCurrentLineFloats(nsLineBox* aLine);
159 // Returns the first coordinate >= aBCoord that clears the
160 // floats indicated by aClearType and has enough inline size between floats
161 // (or no floats remaining) to accomodate aFloatAvoidingBlock.
162 enum class ClearFloatsResult : uint8_t {
163 BCoordNoChange,
164 BCoordAdvanced,
165 FloatsPushedOrSplit,
167 std::tuple<nscoord, ClearFloatsResult> ClearFloats(
168 nscoord aBCoord, StyleClear aClearType,
169 nsIFrame* aFloatAvoidingBlock = nullptr);
171 nsFloatManager* FloatManager() const {
172 MOZ_ASSERT(mReflowInput.mFloatManager,
173 "Float manager should be valid during the lifetime of "
174 "BlockReflowState!");
175 return mReflowInput.mFloatManager;
178 // Advances to the next band, i.e., the next horizontal stripe in
179 // which there is a different set of floats.
180 // Return false if it did not advance, which only happens for
181 // constrained heights (and means that we should get pushed to the
182 // next column/page).
183 bool AdvanceToNextBand(const LogicalRect& aFloatAvailableSpace,
184 nscoord* aBCoord) const {
185 WritingMode wm = mReflowInput.GetWritingMode();
186 if (aFloatAvailableSpace.BSize(wm) > 0) {
187 // See if there's room in the next band.
188 *aBCoord += aFloatAvailableSpace.BSize(wm);
189 } else {
190 if (mReflowInput.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
191 // Stop trying to clear here; we'll just get pushed to the
192 // next column or page and try again there.
193 return false;
195 MOZ_ASSERT_UNREACHABLE("avail space rect with zero height!");
196 *aBCoord += 1;
198 return true;
201 bool FloatAvoidingBlockFitsInAvailSpace(
202 nsIFrame* aFloatAvoidingBlock,
203 const nsFlowAreaRect& aFloatAvailableSpace) const;
205 // True if the current block-direction coordinate, for placing the children
206 // within the content area, is still adjacent with the block-start of the
207 // content area.
208 bool IsAdjacentWithBStart() const { return mBCoord == ContentBStart(); }
210 const LogicalMargin& BorderPadding() const { return mBorderPadding; }
212 // Reconstruct the previous block-end margin that goes before |aLine|.
213 void ReconstructMarginBefore(nsLineList::iterator aLine);
215 // Caller must have called GetFloatAvailableSpace for the correct position
216 // (which need not be the current mBCoord).
217 void ComputeFloatAvoidingOffsets(nsIFrame* aFloatAvoidingBlock,
218 const LogicalRect& aFloatAvailableSpace,
219 nscoord& aIStartResult,
220 nscoord& aIEndResult) const;
222 // Compute the amount of available space for reflowing a block frame at the
223 // current block-direction coordinate mBCoord. Caller must have called
224 // GetFloatAvailableSpace for the current mBCoord.
225 LogicalRect ComputeBlockAvailSpace(nsIFrame* aFrame,
226 const nsFlowAreaRect& aFloatAvailableSpace,
227 bool aBlockAvoidsFloats);
229 LogicalSize ComputeAvailableSizeForFloat() const;
231 void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaBCoord);
233 void AdvanceToNextLine() {
234 if (mFlags.mIsLineLayoutEmpty) {
235 mFlags.mIsLineLayoutEmpty = false;
236 } else {
237 mLineNumber++;
241 //----------------------------------------
243 // This state is the "global" state computed once for the reflow of
244 // the block.
246 // The block frame that is using this object
247 nsBlockFrame* const mBlock;
249 nsPresContext* const mPresContext;
251 const ReflowInput& mReflowInput;
253 // The coordinates within the float manager where the block is being
254 // placed <b>after</b> taking into account the blocks border and
255 // padding. This, therefore, represents the inner "content area" (in
256 // float manager coordinates) where child frames will be placed,
257 // including child blocks and floats.
258 nscoord mFloatManagerI, mFloatManagerB;
260 // XXX get rid of this
261 nsReflowStatus mReflowStatus;
263 // The float manager state as it was before the contents of this
264 // block. This is needed for positioning bullets, since we only want
265 // to move the bullet to flow around floats that were before this
266 // block, not floats inside of it.
267 nsFloatManager::SavedState mFloatManagerStateBefore;
269 // The content area to reflow child frames within. This is within
270 // this frame's coordinate system and writing mode, which means
271 // mContentArea.IStart == BorderPadding().IStart and
272 // mContentArea.BStart == BorderPadding().BStart.
273 // The block size may be NS_UNCONSTRAINEDSIZE, which indicates that there
274 // is no page/column boundary below (the common case).
275 // mContentArea.BEnd() should only be called after checking that
276 // mContentArea.BSize is not NS_UNCONSTRAINEDSIZE; otherwise
277 // coordinate overflow may occur.
278 LogicalRect mContentArea;
279 nscoord ContentIStart() const {
280 return mContentArea.IStart(mReflowInput.GetWritingMode());
282 nscoord ContentISize() const {
283 return mContentArea.ISize(mReflowInput.GetWritingMode());
285 nscoord ContentIEnd() const {
286 return mContentArea.IEnd(mReflowInput.GetWritingMode());
288 nscoord ContentBStart() const {
289 return mContentArea.BStart(mReflowInput.GetWritingMode());
291 nscoord ContentBSize() const {
292 return mContentArea.BSize(mReflowInput.GetWritingMode());
294 nscoord ContentBEnd() const {
295 NS_ASSERTION(
296 ContentBSize() != NS_UNCONSTRAINEDSIZE,
297 "ContentBSize() is unconstrained, so ContentBEnd() may overflow.");
298 return mContentArea.BEnd(mReflowInput.GetWritingMode());
300 LogicalSize ContentSize(WritingMode aWM) const {
301 WritingMode wm = mReflowInput.GetWritingMode();
302 return mContentArea.Size(wm).ConvertTo(aWM, wm);
305 // Amount of inset to apply during line-breaking, used by text-wrap:balance
306 // to adjust line-breaks for more consistent lengths throughout the block.
307 nscoord mInsetForBalance;
309 // Physical size. Use only for physical <-> logical coordinate conversion.
310 nsSize mContainerSize;
311 const nsSize& ContainerSize() const { return mContainerSize; }
313 // Continuation out-of-flow float frames that need to move to our
314 // next in flow are placed here during reflow. It's a pointer to
315 // a frame list stored in the block's property table.
316 nsFrameList* mPushedFloats;
317 // This method makes sure pushed floats are accessible to
318 // StealFrame. Call it before adding any frames to mPushedFloats.
319 void SetupPushedFloatList();
321 * Append aFloatCont and its next-in-flows within the same block to
322 * mPushedFloats. aFloatCont should not be on any child list when
323 * making this call. Its next-in-flows will be removed from
324 * mBlock using StealFrame() before being added to mPushedFloats.
325 * All appended frames will be marked NS_FRAME_IS_PUSHED_FLOAT.
327 void AppendPushedFloatChain(nsIFrame* aFloatCont);
329 // Track child overflow continuations.
330 nsOverflowContinuationTracker* mOverflowTracker;
332 //----------------------------------------
334 // This state is "running" state updated by the reflow of each line
335 // in the block. This same state is "recovered" when a line is not
336 // dirty and is passed over during incremental reflow.
338 // The current line being reflowed
339 // If it is mBlock->end_lines(), then it is invalid.
340 nsLineList::iterator mCurrentLine;
342 // When mHasLineAdjacentToTop is set, this refers to a line
343 // which we know is adjacent to the top of the block (in other words,
344 // all lines before it are empty and do not have clearance. This line is
345 // always before the current line.
346 nsLineList::iterator mLineAdjacentToTop;
348 // The current block-direction coordinate in the block
349 nscoord mBCoord;
351 // mBlock's computed logical border+padding with pre-reflow skip sides applied
352 // (See the constructor and nsIFrame::PreReflowBlockLevelLogicalSkipSides).
353 const LogicalMargin mBorderPadding;
355 // The overflow areas of all floats placed so far
356 OverflowAreas mFloatOverflowAreas;
358 // Previous child. This is used when pulling up a frame to update
359 // the sibling list.
360 nsIFrame* mPrevChild;
362 // The previous child frames collapsed bottom margin value.
363 nsCollapsingMargin mPrevBEndMargin;
365 // The current next-in-flow for the block. When lines are pulled
366 // from a next-in-flow, this is used to know which next-in-flow to
367 // pull from. When a next-in-flow is emptied of lines, we advance
368 // this to the next next-in-flow.
369 nsBlockFrame* mNextInFlow;
371 //----------------------------------------
373 // Temporary state, for line-reflow. This state is used during the reflow
374 // of a given line, but doesn't have meaning before or after.
376 // The list of floats that are "current-line" floats. These are
377 // added to the line after the line has been reflowed, to keep the
378 // list fiddling from being N^2.
379 nsTArray<nsIFrame*> mCurrentLineFloats;
381 // The list of floats which are "below current-line"
382 // floats. These are reflowed/placed after the line is reflowed
383 // and placed. Again, this is done to keep the list fiddling from
384 // being N^2.
385 nsTArray<nsIFrame*> mBelowCurrentLineFloats;
387 // The list of floats that are waiting on a break opportunity in order to be
388 // placed, since we're on a nowrap context.
389 nsTArray<nsIFrame*> mNoWrapFloats;
391 const nscoord mMinLineHeight;
393 int32_t mLineNumber;
395 Flags mFlags;
397 // Cache the result of nsBlockFrame::FindTrailingClear() from mBlock's
398 // prev-in-flows. See nsBlockFrame::ReflowPushedFloats().
399 StyleClear mTrailingClearFromPIF;
401 // The amount of computed content block-size "consumed" by our previous
402 // continuations.
403 const nscoord mConsumedBSize;
405 // Cache the current line's BSize if nsBlockFrame::PlaceLine() fails to
406 // place the line. When redoing the line, it will be used to query the
407 // accurate float available space in AddFloat() and
408 // nsBlockFrame::PlaceLine().
409 Maybe<nscoord> mLineBSize;
411 private:
412 bool CanPlaceFloat(nscoord aFloatISize,
413 const nsFlowAreaRect& aFloatAvailableSpace);
415 void PushFloatPastBreak(nsIFrame* aFloat);
417 void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaBCoord);
420 }; // namespace mozilla
422 #endif // BlockReflowState_h