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