Bug 1708422: part 13) Factor code out to `mozInlineSpellChecker::SpellCheckerTimeSlic...
[gecko.git] / layout / generic / BlockReflowInput.h
blobb067370ab8a27aa58f374d11e147718969adc4e5
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 BlockReflowInput_h
10 #define BlockReflowInput_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 // BlockReflowInput 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 BlockReflowInput {
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 BlockReflowInput 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 BlockReflowInput 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 input, 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 BlockReflowInput 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 BlockReflowInput(const ReflowInput& aReflowInput, nsPresContext* aPresContext,
98 nsBlockFrame* aFrame, bool aBStartMarginRoot,
99 bool aBEndMarginRoot, bool aBlockNeedsFloatManager,
100 nscoord aConsumedBSize = NS_UNCONSTRAINEDSIZE);
103 * Get the available reflow space (the area not occupied by floats)
104 * for the current y coordinate. The available space is relative to
105 * our coordinate system, which is the content box, with (0, 0) in the
106 * upper left.
108 * Returns whether there are floats present at the given block-direction
109 * coordinate and within the inline size of the content rect.
111 nsFlowAreaRect GetFloatAvailableSpace() const {
112 return GetFloatAvailableSpace(mBCoord);
114 nsFlowAreaRect GetFloatAvailableSpaceForPlacingFloat(nscoord aBCoord) const {
115 return GetFloatAvailableSpaceWithState(aBCoord, ShapeType::Margin, nullptr);
117 nsFlowAreaRect GetFloatAvailableSpace(nscoord aBCoord) const {
118 return GetFloatAvailableSpaceWithState(aBCoord, ShapeType::ShapeOutside,
119 nullptr);
121 nsFlowAreaRect GetFloatAvailableSpaceWithState(
122 nscoord aBCoord, ShapeType aShapeType,
123 nsFloatManager::SavedState* aState) const;
124 nsFlowAreaRect GetFloatAvailableSpaceForBSize(
125 nscoord aBCoord, nscoord aBSize,
126 nsFloatManager::SavedState* aState) const;
129 * The following functions all return true if they were able to
130 * place the float, false if the float did not fit in available
131 * space.
132 * aLineLayout is null when we are reflowing pushed floats (because
133 * they are not associated with a line box).
135 bool AddFloat(nsLineLayout* aLineLayout, nsIFrame* aFloat,
136 nscoord aAvailableISize);
138 bool FlowAndPlaceFloat(nsIFrame* aFloat);
140 void PlaceBelowCurrentLineFloats(nsLineBox* aLine);
142 // Returns the first coordinate >= aBCoord that clears the
143 // floats indicated by aBreakType and has enough inline size between floats
144 // (or no floats remaining) to accomodate aReplacedBlock.
145 enum class ClearFloatsResult : uint8_t {
146 BCoordNoChange,
147 BCoordAdvanced,
148 FloatsPushedOrSplit,
150 std::tuple<nscoord, ClearFloatsResult> ClearFloats(
151 nscoord aBCoord, mozilla::StyleClear aBreakType,
152 nsIFrame* aReplacedBlock = nullptr);
154 nsFloatManager* FloatManager() const {
155 MOZ_ASSERT(mReflowInput.mFloatManager,
156 "Float manager should be valid during the lifetime of "
157 "BlockReflowInput!");
158 return mReflowInput.mFloatManager;
161 // Advances to the next band, i.e., the next horizontal stripe in
162 // which there is a different set of floats.
163 // Return false if it did not advance, which only happens for
164 // constrained heights (and means that we should get pushed to the
165 // next column/page).
166 bool AdvanceToNextBand(const mozilla::LogicalRect& aFloatAvailableSpace,
167 nscoord* aBCoord) const {
168 mozilla::WritingMode wm = mReflowInput.GetWritingMode();
169 if (aFloatAvailableSpace.BSize(wm) > 0) {
170 // See if there's room in the next band.
171 *aBCoord += aFloatAvailableSpace.BSize(wm);
172 } else {
173 if (mReflowInput.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
174 // Stop trying to clear here; we'll just get pushed to the
175 // next column or page and try again there.
176 return false;
178 MOZ_ASSERT_UNREACHABLE("avail space rect with zero height!");
179 *aBCoord += 1;
181 return true;
184 bool ReplacedBlockFitsInAvailSpace(
185 nsIFrame* aReplacedBlock,
186 const nsFlowAreaRect& aFloatAvailableSpace) const;
188 bool IsAdjacentWithTop() const {
189 return mBCoord == mBorderPadding.BStart(mReflowInput.GetWritingMode());
193 * Return mBlock's computed physical border+padding with GetSkipSides applied.
195 const mozilla::LogicalMargin& BorderPadding() const { return mBorderPadding; }
197 // Reconstruct the previous block-end margin that goes before |aLine|.
198 void ReconstructMarginBefore(nsLineList::iterator aLine);
200 // Caller must have called GetFloatAvailableSpace for the correct position
201 // (which need not be the current mBCoord).
202 void ComputeReplacedBlockOffsetsForFloats(
203 nsIFrame* aFrame, const mozilla::LogicalRect& aFloatAvailableSpace,
204 nscoord& aIStartResult, nscoord& aIEndResult) const;
206 // Caller must have called GetFloatAvailableSpace for the current mBCoord
207 void ComputeBlockAvailSpace(nsIFrame* aFrame,
208 const nsFlowAreaRect& aFloatAvailableSpace,
209 bool aBlockAvoidsFloats,
210 mozilla::LogicalRect& aResult);
212 void RecoverStateFrom(nsLineList::iterator aLine, nscoord aDeltaBCoord);
214 void AdvanceToNextLine() {
215 if (mFlags.mIsLineLayoutEmpty) {
216 mFlags.mIsLineLayoutEmpty = false;
217 } else {
218 mLineNumber++;
222 //----------------------------------------
224 // This state is the "global" state computed once for the reflow of
225 // the block.
227 // The block frame that is using this object
228 nsBlockFrame* mBlock;
230 nsPresContext* mPresContext;
232 const ReflowInput& mReflowInput;
234 // The coordinates within the float manager where the block is being
235 // placed <b>after</b> taking into account the blocks border and
236 // padding. This, therefore, represents the inner "content area" (in
237 // float manager coordinates) where child frames will be placed,
238 // including child blocks and floats.
239 nscoord mFloatManagerI, mFloatManagerB;
241 // XXX get rid of this
242 nsReflowStatus mReflowStatus;
244 // The float manager state as it was before the contents of this
245 // block. This is needed for positioning bullets, since we only want
246 // to move the bullet to flow around floats that were before this
247 // block, not floats inside of it.
248 nsFloatManager::SavedState mFloatManagerStateBefore;
250 // The content area to reflow child frames within. This is within
251 // this frame's coordinate system and writing mode, which means
252 // mContentArea.IStart == BorderPadding().IStart and
253 // mContentArea.BStart == BorderPadding().BStart.
254 // The block size may be NS_UNCONSTRAINEDSIZE, which indicates that there
255 // is no page/column boundary below (the common case).
256 // mContentArea.BEnd() should only be called after checking that
257 // mContentArea.BSize is not NS_UNCONSTRAINEDSIZE; otherwise
258 // coordinate overflow may occur.
259 mozilla::LogicalRect mContentArea;
260 nscoord ContentIStart() const {
261 return mContentArea.IStart(mReflowInput.GetWritingMode());
263 nscoord ContentISize() const {
264 return mContentArea.ISize(mReflowInput.GetWritingMode());
266 nscoord ContentIEnd() const {
267 return mContentArea.IEnd(mReflowInput.GetWritingMode());
269 nscoord ContentBStart() const {
270 return mContentArea.BStart(mReflowInput.GetWritingMode());
272 nscoord ContentBSize() const {
273 return mContentArea.BSize(mReflowInput.GetWritingMode());
275 nscoord ContentBEnd() const {
276 NS_ASSERTION(
277 ContentBSize() != NS_UNCONSTRAINEDSIZE,
278 "ContentBSize() is unconstrained, so ContentBEnd() may overflow.");
279 return mContentArea.BEnd(mReflowInput.GetWritingMode());
281 mozilla::LogicalSize ContentSize(mozilla::WritingMode aWM) const {
282 mozilla::WritingMode wm = mReflowInput.GetWritingMode();
283 return mContentArea.Size(wm).ConvertTo(aWM, wm);
286 // Physical size. Use only for physical <-> logical coordinate conversion.
287 nsSize mContainerSize;
288 const nsSize& ContainerSize() const { return mContainerSize; }
290 // Continuation out-of-flow float frames that need to move to our
291 // next in flow are placed here during reflow. It's a pointer to
292 // a frame list stored in the block's property table.
293 nsFrameList* mPushedFloats;
294 // This method makes sure pushed floats are accessible to
295 // StealFrame. Call it before adding any frames to mPushedFloats.
296 void SetupPushedFloatList();
298 * Append aFloatCont and its next-in-flows within the same block to
299 * mPushedFloats. aFloatCont should not be on any child list when
300 * making this call. Its next-in-flows will be removed from
301 * mBlock using StealFrame() before being added to mPushedFloats.
302 * All appended frames will be marked NS_FRAME_IS_PUSHED_FLOAT.
304 void AppendPushedFloatChain(nsIFrame* aFloatCont);
306 // Track child overflow continuations.
307 nsOverflowContinuationTracker* mOverflowTracker;
309 //----------------------------------------
311 // This state is "running" state updated by the reflow of each line
312 // in the block. This same state is "recovered" when a line is not
313 // dirty and is passed over during incremental reflow.
315 // The current line being reflowed
316 // If it is mBlock->end_lines(), then it is invalid.
317 nsLineList::iterator mCurrentLine;
319 // When mHasLineAdjacentToTop is set, this refers to a line
320 // which we know is adjacent to the top of the block (in other words,
321 // all lines before it are empty and do not have clearance. This line is
322 // always before the current line.
323 nsLineList::iterator mLineAdjacentToTop;
325 // The current block-direction coordinate in the block
326 nscoord mBCoord;
328 // mBlock's computed physical border+padding with GetSkipSides applied.
329 mozilla::LogicalMargin mBorderPadding;
331 // The overflow areas of all floats placed so far
332 mozilla::OverflowAreas mFloatOverflowAreas;
334 nsFloatCacheFreeList mFloatCacheFreeList;
336 // Previous child. This is used when pulling up a frame to update
337 // the sibling list.
338 nsIFrame* mPrevChild;
340 // The previous child frames collapsed bottom margin value.
341 nsCollapsingMargin mPrevBEndMargin;
343 // The current next-in-flow for the block. When lines are pulled
344 // from a next-in-flow, this is used to know which next-in-flow to
345 // pull from. When a next-in-flow is emptied of lines, we advance
346 // this to the next next-in-flow.
347 nsBlockFrame* mNextInFlow;
349 //----------------------------------------
351 // Temporary state, for line-reflow. This state is used during the reflow
352 // of a given line, but doesn't have meaning before or after.
354 // The list of floats that are "current-line" floats. These are
355 // added to the line after the line has been reflowed, to keep the
356 // list fiddling from being N^2.
357 nsFloatCacheFreeList mCurrentLineFloats;
359 // The list of floats which are "below current-line"
360 // floats. These are reflowed/placed after the line is reflowed
361 // and placed. Again, this is done to keep the list fiddling from
362 // being N^2.
363 nsFloatCacheFreeList mBelowCurrentLineFloats;
365 // The list of floats that are waiting on a break opportunity in order to be
366 // placed, since we're on a nowrap context.
367 nsTArray<nsIFrame*> mNoWrapFloats;
369 nscoord mMinLineHeight;
371 int32_t mLineNumber;
373 Flags mFlags;
375 StyleClear mFloatBreakType;
377 // The amount of computed content block-size "consumed" by our previous
378 // continuations.
379 const nscoord mConsumedBSize;
381 // Cache the current line's BSize if nsBlockFrame::PlaceLine() fails to
382 // place the line. When redoing the line, it will be used to query the
383 // accurate float available space in AddFloat() and
384 // nsBlockFrame::PlaceLine().
385 mozilla::Maybe<nscoord> mLineBSize;
387 private:
388 bool CanPlaceFloat(nscoord aFloatISize,
389 const nsFlowAreaRect& aFloatAvailableSpace);
391 void PushFloatPastBreak(nsIFrame* aFloat);
393 void RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaBCoord);
396 }; // namespace mozilla
398 #endif // BlockReflowInput_h