Coverage Report

Created: 2018-09-25 14:53

/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