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 /* struct containing the input to nsIFrame::Reflow */
8
9 #ifndef mozilla_ReflowInput_h
10 #define mozilla_ReflowInput_h
11
12 #include "nsMargin.h"
13 #include "nsStyleConsts.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/EnumSet.h"
16 #include "mozilla/Maybe.h"
17 #include "mozilla/WritingModes.h"
18 #include "LayoutConstants.h"
19 #include "ReflowOutput.h"
20 #include <algorithm>
21
22 class gfxContext;
23 class nsFloatManager;
24 struct nsHypotheticalPosition;
25 class nsIPercentBSizeObserver;
26 class nsLineLayout;
27 class nsPlaceholderFrame;
28 class nsPresContext;
29 class nsReflowStatus;
30
31 namespace mozilla {
32 enum class LayoutFrameType : uint8_t;
33
34 /**
35 * A set of StyleSizes used as an input parameter to various functions that
36 * compute sizes like nsIFrame::ComputeSize(). If any of the member fields has a
37 * value, the function may use the value instead of retrieving it from the
38 * frame's style.
39 *
40 * The logical sizes are assumed to be in the associated frame's writing-mode.
41 */
42 struct StyleSizeOverrides {
43 Maybe<StyleSize> mStyleISize;
44 Maybe<StyleSize> mStyleBSize;
45 Maybe<AspectRatio> mAspectRatio;
46
HasAnyOverridesStyleSizeOverrides47 bool HasAnyOverrides() const { return mStyleISize || mStyleBSize; }
HasAnyLengthOverridesStyleSizeOverrides48 bool HasAnyLengthOverrides() const {
49 return (mStyleISize && mStyleISize->ConvertsToLength()) ||
50 (mStyleBSize && mStyleBSize->ConvertsToLength());
51 }
52
53 // By default, table wrapper frame considers the size overrides applied to
54 // itself, so it creates any length size overrides for inner table frame by
55 // subtracting the area occupied by the caption and border & padding according
56 // to box-sizing.
57 //
58 // When this flag is true, table wrapper frame is required to apply the size
59 // overrides to the inner table frame directly, without any modification,
60 // which is useful for flex container to override the inner table frame's
61 // preferred main size with 'flex-basis'.
62 //
63 // Note: if mStyleISize is a LengthPercentage, the inner table frame will
64 // comply with the inline-size override without enforcing its min-content
65 // inline-size in nsTableFrame::ComputeSize(). This is necessary so that small
66 // flex-basis values like 'flex-basis:1%' can be resolved correctly; the
67 // flexbox layout algorithm does still explicitly clamp to min-sizes *at a
68 // later step*, after the flex-basis has been resolved -- so this flag won't
69 // actually produce any user-visible tables whose final inline size is smaller
70 // than their min-content inline size.
71 bool mApplyOverridesVerbatim = false;
72 };
73 } // namespace mozilla
74
75 /**
76 * @return aValue clamped to [aMinValue, aMaxValue].
77 *
78 * @note This function needs to handle aMinValue > aMaxValue. In that case,
79 * aMinValue is returned.
80 * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
81 * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-heights
82 */
83 template <class NumericType>
NS_CSS_MINMAX(NumericType aValue,NumericType aMinValue,NumericType aMaxValue)84 NumericType NS_CSS_MINMAX(NumericType aValue, NumericType aMinValue,
85 NumericType aMaxValue) {
86 NumericType result = aValue;
87 if (aMaxValue < result) result = aMaxValue;
88 if (aMinValue > result) result = aMinValue;
89 return result;
90 }
91
92 namespace mozilla {
93
94 // A base class of ReflowInput that computes only the padding,
95 // border, and margin, since those values are needed more often.
96 struct SizeComputationInput {
97 public:
98 // The frame being reflowed.
99 nsIFrame* mFrame;
100
101 // Rendering context to use for measurement.
102 gfxContext* mRenderingContext;
103
ComputedPhysicalMarginSizeComputationInput104 nsMargin ComputedPhysicalMargin() const {
105 return mComputedMargin.GetPhysicalMargin(mWritingMode);
106 }
ComputedPhysicalBorderPaddingSizeComputationInput107 nsMargin ComputedPhysicalBorderPadding() const {
108 return mComputedBorderPadding.GetPhysicalMargin(mWritingMode);
109 }
ComputedPhysicalPaddingSizeComputationInput110 nsMargin ComputedPhysicalPadding() const {
111 return mComputedPadding.GetPhysicalMargin(mWritingMode);
112 }
113
ComputedLogicalMarginSizeComputationInput114 mozilla::LogicalMargin ComputedLogicalMargin(mozilla::WritingMode aWM) const {
115 return mComputedMargin.ConvertTo(aWM, mWritingMode);
116 }
ComputedLogicalBorderPaddingSizeComputationInput117 mozilla::LogicalMargin ComputedLogicalBorderPadding(
118 mozilla::WritingMode aWM) const {
119 return mComputedBorderPadding.ConvertTo(aWM, mWritingMode);
120 }
ComputedLogicalPaddingSizeComputationInput121 mozilla::LogicalMargin ComputedLogicalPadding(
122 mozilla::WritingMode aWM) const {
123 return mComputedPadding.ConvertTo(aWM, mWritingMode);
124 }
ComputedLogicalBorderSizeComputationInput125 mozilla::LogicalMargin ComputedLogicalBorder(mozilla::WritingMode aWM) const {
126 return (mComputedBorderPadding - mComputedPadding)
127 .ConvertTo(aWM, mWritingMode);
128 }
129
SetComputedLogicalMarginSizeComputationInput130 void SetComputedLogicalMargin(mozilla::WritingMode aWM,
131 const mozilla::LogicalMargin& aMargin) {
132 mComputedMargin = aMargin.ConvertTo(mWritingMode, aWM);
133 }
SetComputedLogicalBorderPaddingSizeComputationInput134 void SetComputedLogicalBorderPadding(
135 mozilla::WritingMode aWM, const mozilla::LogicalMargin& aBorderPadding) {
136 mComputedBorderPadding = aBorderPadding.ConvertTo(mWritingMode, aWM);
137 }
SetComputedLogicalPaddingSizeComputationInput138 void SetComputedLogicalPadding(mozilla::WritingMode aWM,
139 const mozilla::LogicalMargin& aPadding) {
140 mComputedPadding = aPadding.ConvertTo(mWritingMode, aWM);
141 }
142
GetWritingModeSizeComputationInput143 mozilla::WritingMode GetWritingMode() const { return mWritingMode; }
144
145 protected:
146 // cached copy of the frame's writing-mode, for logical coordinates
147 mozilla::WritingMode mWritingMode;
148
149 // Computed margin values
150 mozilla::LogicalMargin mComputedMargin;
151
152 // Cached copy of the border + padding values
153 mozilla::LogicalMargin mComputedBorderPadding;
154
155 // Computed padding values
156 mozilla::LogicalMargin mComputedPadding;
157
158 public:
159 // Callers using this constructor must call InitOffsets on their own.
160 SizeComputationInput(nsIFrame* aFrame, gfxContext* aRenderingContext);
161
162 SizeComputationInput(nsIFrame* aFrame, gfxContext* aRenderingContext,
163 mozilla::WritingMode aContainingBlockWritingMode,
164 nscoord aContainingBlockISize,
165 const mozilla::Maybe<mozilla::LogicalMargin>& aBorder =
166 mozilla::Nothing(),
167 const mozilla::Maybe<mozilla::LogicalMargin>& aPadding =
168 mozilla::Nothing());
169
170 #ifdef DEBUG
171 // Reflow trace methods. Defined in nsFrame.cpp so they have access
172 // to the display-reflow infrastructure.
173 static void* DisplayInitOffsetsEnter(nsIFrame* aFrame,
174 SizeComputationInput* aState,
175 nscoord aPercentBasis,
176 mozilla::WritingMode aCBWritingMode,
177 const nsMargin* aBorder,
178 const nsMargin* aPadding);
179 static void DisplayInitOffsetsExit(nsIFrame* aFrame,
180 SizeComputationInput* aState,
181 void* aValue);
182 #endif
183
184 private:
185 /**
186 * Computes margin values from the specified margin style information, and
187 * fills in the mComputedMargin member.
188 *
189 * @param aCBWM Writing mode of the containing block
190 * @param aPercentBasis
191 * Inline size of the containing block (in its own writing mode), to use
192 * for resolving percentage margin values in the inline and block axes.
193 * @return true if the margin is dependent on the containing block size.
194 */
195 bool ComputeMargin(mozilla::WritingMode aCBWM, nscoord aPercentBasis,
196 mozilla::LayoutFrameType aFrameType);
197
198 /**
199 * Computes padding values from the specified padding style information, and
200 * fills in the mComputedPadding member.
201 *
202 * @param aCBWM Writing mode of the containing block
203 * @param aPercentBasis
204 * Inline size of the containing block (in its own writing mode), to use
205 * for resolving percentage padding values in the inline and block axes.
206 * @return true if the padding is dependent on the containing block size.
207 */
208 bool ComputePadding(mozilla::WritingMode aCBWM, nscoord aPercentBasis,
209 mozilla::LayoutFrameType aFrameType);
210
211 protected:
212 void InitOffsets(mozilla::WritingMode aCBWM, nscoord aPercentBasis,
213 mozilla::LayoutFrameType aFrameType,
214 mozilla::ComputeSizeFlags aFlags = {},
215 const mozilla::Maybe<mozilla::LogicalMargin>& aBorder =
216 mozilla::Nothing(),
217 const mozilla::Maybe<mozilla::LogicalMargin>& aPadding =
218 mozilla::Nothing(),
219 const nsStyleDisplay* aDisplay = nullptr);
220
221 /*
222 * Convert StyleSize or StyleMaxSize to nscoord when percentages depend on the
223 * inline size of the containing block, and enumerated values are for inline
224 * size, min-inline-size, or max-inline-size. Does not handle auto inline
225 * sizes.
226 */
227 template <typename SizeOrMaxSize>
228 inline nscoord ComputeISizeValue(const WritingMode aWM,
229 const LogicalSize& aContainingBlockSize,
230 const LogicalSize& aContentEdgeToBoxSizing,
231 nscoord aBoxSizingToMarginEdge,
232 const SizeOrMaxSize&) const;
233 // same as previous, but using mComputedBorderPadding, mComputedPadding,
234 // and mComputedMargin
235 template <typename SizeOrMaxSize>
236 inline nscoord ComputeISizeValue(const LogicalSize& aContainingBlockSize,
237 mozilla::StyleBoxSizing aBoxSizing,
238 const SizeOrMaxSize&) const;
239
240 nscoord ComputeBSizeValue(nscoord aContainingBlockBSize,
241 mozilla::StyleBoxSizing aBoxSizing,
242 const mozilla::LengthPercentage& aCoord) const;
243 };
244
245 /**
246 * State passed to a frame during reflow or intrinsic size calculation.
247 *
248 * XXX Refactor so only a base class (nsSizingState?) is used for intrinsic
249 * size calculation.
250 *
251 * @see nsIFrame#Reflow()
252 */
253 struct ReflowInput : public SizeComputationInput {
254 // the reflow inputs are linked together. this is the pointer to the
255 // parent's reflow input
256 const ReflowInput* mParentReflowInput = nullptr;
257
258 // A non-owning pointer to the float manager associated with this area,
259 // which points to the object owned by nsAutoFloatManager::mNew.
260 nsFloatManager* mFloatManager = nullptr;
261
262 // LineLayout object (only for inline reflow; set to nullptr otherwise)
263 nsLineLayout* mLineLayout = nullptr;
264
265 // The appropriate reflow input for the containing block (for
266 // percentage widths, etc.) of this reflow input's frame. It will be setup
267 // properly in InitCBReflowInput().
268 const ReflowInput* mCBReflowInput = nullptr;
269
270 // The amount the in-flow position of the block is moving vertically relative
271 // to its previous in-flow position (i.e. the amount the line containing the
272 // block is moving).
273 // This should be zero for anything which is not a block outside, and it
274 // should be zero for anything which has a non-block parent.
275 // The intended use of this value is to allow the accurate determination
276 // of the potential impact of a float
277 // This takes on an arbitrary value the first time a block is reflowed
278 nscoord mBlockDelta = 0;
279
280 // If a ReflowInput finds itself initialized with an unconstrained
281 // inline-size, it will look up its parentReflowInput chain for a reflow input
282 // with an orthogonal writing mode and a non-NS_UNCONSTRAINEDSIZE value for
283 // orthogonal limit; when it finds such a reflow input, it will use its
284 // orthogonal-limit value to constrain inline-size.
285 // This is initialized to NS_UNCONSTRAINEDSIZE (so it will be ignored),
286 // but reset to a suitable value for the reflow root by PresShell.
287 nscoord mOrthogonalLimit = NS_UNCONSTRAINEDSIZE;
288
289 // Physical accessors for the private fields. They are needed for
290 // compatibility with not-yet-updated code. New code should use the accessors
291 // for logical coordinates, unless the code really works on physical
292 // coordinates.
AvailableWidthReflowInput293 nscoord AvailableWidth() const { return mAvailableSize.Width(mWritingMode); }
AvailableHeightReflowInput294 nscoord AvailableHeight() const {
295 return mAvailableSize.Height(mWritingMode);
296 }
ComputedWidthReflowInput297 nscoord ComputedWidth() const { return mComputedSize.Width(mWritingMode); }
ComputedHeightReflowInput298 nscoord ComputedHeight() const { return mComputedSize.Height(mWritingMode); }
ComputedMinWidthReflowInput299 nscoord ComputedMinWidth() const {
300 return mComputedMinSize.Width(mWritingMode);
301 }
ComputedMaxWidthReflowInput302 nscoord ComputedMaxWidth() const {
303 return mComputedMaxSize.Width(mWritingMode);
304 }
ComputedMinHeightReflowInput305 nscoord ComputedMinHeight() const {
306 return mComputedMinSize.Height(mWritingMode);
307 }
ComputedMaxHeightReflowInput308 nscoord ComputedMaxHeight() const {
309 return mComputedMaxSize.Height(mWritingMode);
310 }
311
312 // Logical accessors for private fields in mWritingMode.
AvailableISizeReflowInput313 nscoord AvailableISize() const { return mAvailableSize.ISize(mWritingMode); }
AvailableBSizeReflowInput314 nscoord AvailableBSize() const { return mAvailableSize.BSize(mWritingMode); }
ComputedISizeReflowInput315 nscoord ComputedISize() const { return mComputedSize.ISize(mWritingMode); }
ComputedBSizeReflowInput316 nscoord ComputedBSize() const { return mComputedSize.BSize(mWritingMode); }
ComputedMinISizeReflowInput317 nscoord ComputedMinISize() const {
318 return mComputedMinSize.ISize(mWritingMode);
319 }
ComputedMaxISizeReflowInput320 nscoord ComputedMaxISize() const {
321 return mComputedMaxSize.ISize(mWritingMode);
322 }
ComputedMinBSizeReflowInput323 nscoord ComputedMinBSize() const {
324 return mComputedMinSize.BSize(mWritingMode);
325 }
ComputedMaxBSizeReflowInput326 nscoord ComputedMaxBSize() const {
327 return mComputedMaxSize.BSize(mWritingMode);
328 }
329
AvailableISizeReflowInput330 nscoord& AvailableISize() { return mAvailableSize.ISize(mWritingMode); }
AvailableBSizeReflowInput331 nscoord& AvailableBSize() { return mAvailableSize.BSize(mWritingMode); }
ComputedISizeReflowInput332 nscoord& ComputedISize() { return mComputedSize.ISize(mWritingMode); }
ComputedBSizeReflowInput333 nscoord& ComputedBSize() { return mComputedSize.BSize(mWritingMode); }
ComputedMinISizeReflowInput334 nscoord& ComputedMinISize() { return mComputedMinSize.ISize(mWritingMode); }
ComputedMaxISizeReflowInput335 nscoord& ComputedMaxISize() { return mComputedMaxSize.ISize(mWritingMode); }
ComputedMinBSizeReflowInput336 nscoord& ComputedMinBSize() { return mComputedMinSize.BSize(mWritingMode); }
ComputedMaxBSizeReflowInput337 nscoord& ComputedMaxBSize() { return mComputedMaxSize.BSize(mWritingMode); }
338
AvailableSizeReflowInput339 mozilla::LogicalSize AvailableSize() const { return mAvailableSize; }
ComputedSizeReflowInput340 mozilla::LogicalSize ComputedSize() const { return mComputedSize; }
ComputedMinSizeReflowInput341 mozilla::LogicalSize ComputedMinSize() const { return mComputedMinSize; }
ComputedMaxSizeReflowInput342 mozilla::LogicalSize ComputedMaxSize() const { return mComputedMaxSize; }
343
AvailableSizeReflowInput344 mozilla::LogicalSize AvailableSize(mozilla::WritingMode aWM) const {
345 return AvailableSize().ConvertTo(aWM, mWritingMode);
346 }
ComputedSizeReflowInput347 mozilla::LogicalSize ComputedSize(mozilla::WritingMode aWM) const {
348 return ComputedSize().ConvertTo(aWM, mWritingMode);
349 }
ComputedMinSizeReflowInput350 mozilla::LogicalSize ComputedMinSize(mozilla::WritingMode aWM) const {
351 return ComputedMinSize().ConvertTo(aWM, mWritingMode);
352 }
ComputedMaxSizeReflowInput353 mozilla::LogicalSize ComputedMaxSize(mozilla::WritingMode aWM) const {
354 return ComputedMaxSize().ConvertTo(aWM, mWritingMode);
355 }
356
ComputedSizeWithPaddingReflowInput357 mozilla::LogicalSize ComputedSizeWithPadding(mozilla::WritingMode aWM) const {
358 return ComputedSize(aWM) + ComputedLogicalPadding(aWM).Size(aWM);
359 }
360
ComputedSizeWithBorderPaddingReflowInput361 mozilla::LogicalSize ComputedSizeWithBorderPadding(
362 mozilla::WritingMode aWM) const {
363 return ComputedSize(aWM) + ComputedLogicalBorderPadding(aWM).Size(aWM);
364 }
365
ComputedSizeWithMarginBorderPaddingReflowInput366 mozilla::LogicalSize ComputedSizeWithMarginBorderPadding(
367 mozilla::WritingMode aWM) const {
368 return ComputedSizeWithBorderPadding(aWM) +
369 ComputedLogicalMargin(aWM).Size(aWM);
370 }
371
ComputedPhysicalSizeReflowInput372 nsSize ComputedPhysicalSize() const {
373 return nsSize(ComputedWidth(), ComputedHeight());
374 }
375
ComputedPhysicalOffsetsReflowInput376 nsMargin ComputedPhysicalOffsets() const {
377 return mComputedOffsets.GetPhysicalMargin(mWritingMode);
378 }
379
ComputedLogicalOffsetsReflowInput380 LogicalMargin ComputedLogicalOffsets(mozilla::WritingMode aWM) const {
381 return mComputedOffsets.ConvertTo(aWM, mWritingMode);
382 }
383
SetComputedLogicalOffsetsReflowInput384 void SetComputedLogicalOffsets(mozilla::WritingMode aWM,
385 const LogicalMargin& aOffsets) {
386 mComputedOffsets = aOffsets.ConvertTo(mWritingMode, aWM);
387 }
388
389 // Return ReflowInput's computed size including border-padding, with
390 // unconstrained dimensions replaced by zero.
ComputedSizeAsContainerIfConstrainedReflowInput391 nsSize ComputedSizeAsContainerIfConstrained() const {
392 const nscoord wd = ComputedWidth();
393 const nscoord ht = ComputedHeight();
394 return nsSize(wd == NS_UNCONSTRAINEDSIZE
395 ? 0
396 : wd + ComputedPhysicalBorderPadding().LeftRight(),
397 ht == NS_UNCONSTRAINEDSIZE
398 ? 0
399 : ht + ComputedPhysicalBorderPadding().TopBottom());
400 }
401
402 // Our saved containing block dimensions.
403 LogicalSize mContainingBlockSize{mWritingMode};
404
405 // Cached pointers to the various style structs used during initialization.
406 const nsStyleDisplay* mStyleDisplay = nullptr;
407 const nsStyleVisibility* mStyleVisibility = nullptr;
408 const nsStylePosition* mStylePosition = nullptr;
409 const nsStyleBorder* mStyleBorder = nullptr;
410 const nsStyleMargin* mStyleMargin = nullptr;
411 const nsStylePadding* mStylePadding = nullptr;
412 const nsStyleText* mStyleText = nullptr;
413
414 enum class BreakType : uint8_t {
415 Auto,
416 Column,
417 Page,
418 };
419 BreakType mBreakType = BreakType::Auto;
420
421 // a frame (e.g. nsTableCellFrame) which may need to generate a special
422 // reflow for percent bsize calculations
423 nsIPercentBSizeObserver* mPercentBSizeObserver = nullptr;
424
425 // CSS margin collapsing sometimes requires us to reflow
426 // optimistically assuming that margins collapse to see if clearance
427 // is required. When we discover that clearance is required, we
428 // store the frame in which clearance was discovered to the location
429 // requested here.
430 nsIFrame** mDiscoveredClearance = nullptr;
431
432 struct Flags {
FlagsReflowInput::Flags433 Flags() { memset(this, 0, sizeof(*this)); }
434
435 // cached mFrame->IsFrameOfType(nsIFrame::eReplaced) ||
436 // mFrame->IsFrameOfType(nsIFrame::eReplacedContainsBlock)
437 bool mIsReplaced : 1;
438
439 // used by tables to communicate special reflow (in process) to handle
440 // percent bsize frames inside cells which may not have computed bsizes
441 bool mSpecialBSizeReflow : 1;
442
443 // nothing in the frame's next-in-flow (or its descendants) is changing
444 bool mNextInFlowUntouched : 1;
445
446 // Is the current context at the top of a page? When true, we force
447 // something that's too tall for a page/column to fit anyway to avoid
448 // infinite loops.
449 bool mIsTopOfPage : 1;
450
451 // parent frame is an nsIScrollableFrame and it is assuming a horizontal
452 // scrollbar
453 bool mAssumingHScrollbar : 1;
454
455 // parent frame is an nsIScrollableFrame and it is assuming a vertical
456 // scrollbar
457 bool mAssumingVScrollbar : 1;
458
459 // Is frame a different inline-size than before?
460 bool mIsIResize : 1;
461
462 // Is frame (potentially) a different block-size than before?
463 // This includes cases where the block-size is 'auto' and the
464 // contents or width have changed.
465 bool mIsBResize : 1;
466
467 // Has this frame changed block-size in a way that affects
468 // block-size percentages on frames for which it is the containing
469 // block? This includes a change between 'auto' and a length that
470 // doesn't actually change the frame's block-size. It does not
471 // include cases where the block-size is 'auto' and the frame's
472 // contents have changed.
473 //
474 // In the current code, this is only true when mIsBResize is also
475 // true, although it doesn't necessarily need to be that way (e.g.,
476 // in the case of a frame changing from 'auto' to a length that
477 // produces the same height).
478 bool mIsBResizeForPercentages : 1;
479
480 // tables are splittable, this should happen only inside a page and never
481 // insider a column frame
482 bool mTableIsSplittable : 1;
483
484 // Does frame height depend on an ancestor table-cell?
485 bool mHeightDependsOnAncestorCell : 1;
486
487 // nsColumnSetFrame is balancing columns
488 bool mIsColumnBalancing : 1;
489
490 // True if ColumnSetWrapperFrame has a constrained block-size, and is going
491 // to consume all of its block-size in this fragment. This bit is passed to
492 // nsColumnSetFrame to determine whether to give up balancing and create
493 // overflow columns.
494 bool mColumnSetWrapperHasNoBSizeLeft : 1;
495
496 // If this flag is set, the BSize of this frame should be considered
497 // indefinite for the purposes of percent resolution on child frames (we
498 // should behave as if ComputedBSize() were NS_UNCONSTRAINEDSIZE when doing
499 // percent resolution against this.ComputedBSize()). For example: flex
500 // items may have their ComputedBSize() resolved ahead-of-time by their
501 // flex container, and yet their BSize might have to be considered
502 // indefinite per https://drafts.csswg.org/css-flexbox/#definite-sizes
503 bool mTreatBSizeAsIndefinite : 1;
504
505 // a "fake" reflow input made in order to be the parent of a real one
506 bool mDummyParentReflowInput : 1;
507
508 // Should this frame reflow its place-holder children? If the available
509 // height of this frame didn't change, but its in a paginated environment
510 // (e.g. columns), it should always reflow its placeholder children.
511 bool mMustReflowPlaceholders : 1;
512
513 // the STATIC_POS_IS_CB_ORIGIN ctor flag
514 bool mStaticPosIsCBOrigin : 1;
515
516 // If set, the following two flags indicate that:
517 // (1) this frame is absolutely-positioned (or fixed-positioned).
518 // (2) this frame's static position depends on the CSS Box Alignment.
519 // (3) we do need to compute the static position, because the frame's
520 // {Inline and/or Block} offsets actually depend on it.
521 // When these bits are set, the offset values (IStart/IEnd, BStart/BEnd)
522 // represent the "start" edge of the frame's CSS Box Alignment container
523 // area, in that axis -- and these offsets need to be further-resolved
524 // (with CSS Box Alignment) after we know the OOF frame's size.
525 // NOTE: The "I" and "B" (for "Inline" and "Block") refer the axes of the
526 // *containing block's writing-mode*, NOT mFrame's own writing-mode. This
527 // is purely for convenience, since that's the writing-mode we're dealing
528 // with when we set & react to these bits.
529 bool mIOffsetsNeedCSSAlign : 1;
530 bool mBOffsetsNeedCSSAlign : 1;
531
532 // Are we somewhere inside an element with -webkit-line-clamp set?
533 // This flag is inherited into descendant ReflowInputs, but we don't bother
534 // resetting it to false when crossing over into a block descendant that
535 // -webkit-line-clamp skips over (such as a BFC).
536 bool mInsideLineClamp : 1;
537
538 // Is this a flex item, and should we add or remove a -webkit-line-clamp
539 // ellipsis on a descendant line? It's possible for this flag to be true
540 // when mInsideLineClamp is false if we previously had a numeric
541 // -webkit-line-clamp value, but now have 'none' and we need to find the
542 // line with the ellipsis flag and clear it.
543 // This flag is not inherited into descendant ReflowInputs.
544 bool mApplyLineClamp : 1;
545
546 // Is this frame or one of its ancestors being reflowed in a different
547 // continuation than the one in which it was previously reflowed? In
548 // other words, has it moved to a different column or page than it was in
549 // the previous reflow?
550 //
551 // FIXME: For now, we only ensure that this is set correctly for blocks.
552 // This is okay because the only thing that uses it only cares about
553 // whether there's been a fragment change within the same block formatting
554 // context.
555 bool mMovedBlockFragments : 1;
556
557 // Is the block-size computed by aspect-ratio and inline size (i.e. block
558 // axis is the ratio-dependent axis)? We set this flag so that we can check
559 // whether to apply automatic content-based minimum sizes once we know the
560 // children's block-size (after reflowing them).
561 // https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
562 bool mIsBSizeSetByAspectRatio : 1;
563 };
564 Flags mFlags;
565
566 mozilla::StyleSizeOverrides mStyleSizeOverrides;
567
568 mozilla::ComputeSizeFlags mComputeSizeFlags;
569
570 // This value keeps track of how deeply nested a given reflow input
571 // is from the top of the frame tree.
572 int16_t mReflowDepth = 0;
573
574 // Logical and physical accessors for the resize flags.
IsHResizeReflowInput575 bool IsHResize() const {
576 return mWritingMode.IsVertical() ? mFlags.mIsBResize : mFlags.mIsIResize;
577 }
IsVResizeReflowInput578 bool IsVResize() const {
579 return mWritingMode.IsVertical() ? mFlags.mIsIResize : mFlags.mIsBResize;
580 }
IsIResizeReflowInput581 bool IsIResize() const { return mFlags.mIsIResize; }
IsBResizeReflowInput582 bool IsBResize() const { return mFlags.mIsBResize; }
IsBResizeForWMReflowInput583 bool IsBResizeForWM(mozilla::WritingMode aWM) const {
584 return aWM.IsOrthogonalTo(mWritingMode) ? mFlags.mIsIResize
585 : mFlags.mIsBResize;
586 }
IsBResizeForPercentagesForWMReflowInput587 bool IsBResizeForPercentagesForWM(mozilla::WritingMode aWM) const {
588 // This uses the relatively-accurate mIsBResizeForPercentages flag
589 // when the writing modes are parallel, and is a bit more
590 // pessimistic when orthogonal.
591 return !aWM.IsOrthogonalTo(mWritingMode) ? mFlags.mIsBResizeForPercentages
592 : IsIResize();
593 }
SetHResizeReflowInput594 void SetHResize(bool aValue) {
595 if (mWritingMode.IsVertical()) {
596 mFlags.mIsBResize = aValue;
597 } else {
598 mFlags.mIsIResize = aValue;
599 }
600 }
SetVResizeReflowInput601 void SetVResize(bool aValue) {
602 if (mWritingMode.IsVertical()) {
603 mFlags.mIsIResize = aValue;
604 } else {
605 mFlags.mIsBResize = aValue;
606 }
607 }
SetIResizeReflowInput608 void SetIResize(bool aValue) { mFlags.mIsIResize = aValue; }
SetBResizeReflowInput609 void SetBResize(bool aValue) { mFlags.mIsBResize = aValue; }
610
611 // Values for |aFlags| passed to constructor
612 enum class InitFlag : uint8_t {
613 // Indicates that the parent of this reflow input is "fake" (see
614 // mDummyParentReflowInput in mFlags).
615 DummyParentReflowInput,
616
617 // Indicates that the calling function will initialize the reflow input, and
618 // that the constructor should not call Init().
619 CallerWillInit,
620
621 // The caller wants the abs.pos. static-position resolved at the origin of
622 // the containing block, i.e. at LogicalPoint(0, 0). (Note that this
623 // doesn't necessarily mean that (0, 0) is the *correct* static position
624 // for the frame in question.)
625 // @note In a Grid container's masonry axis we'll always use
626 // the placeholder's position in that axis regardless of this flag.
627 StaticPosIsCBOrigin,
628 };
629 using InitFlags = mozilla::EnumSet<InitFlag>;
630
631 // Note: The copy constructor is written by the compiler automatically. You
632 // can use that and then override specific values if you want, or you can
633 // call Init as desired...
634
635 /**
636 * Initialize a ROOT reflow input.
637 *
638 * @param aPresContext Must be equal to aFrame->PresContext().
639 * @param aFrame The frame for whose reflow input is being constructed.
640 * @param aRenderingContext The rendering context to be used for measurements.
641 * @param aAvailableSpace The available space to reflow aFrame (in aFrame's
642 * writing-mode). See comments for mAvailableSize for more information.
643 * @param aFlags A set of flags used for additional boolean parameters (see
644 * InitFlags above).
645 */
646 ReflowInput(nsPresContext* aPresContext, nsIFrame* aFrame,
647 gfxContext* aRenderingContext,
648 const mozilla::LogicalSize& aAvailableSpace,
649 InitFlags aFlags = {});
650
651 /**
652 * Initialize a reflow input for a child frame's reflow. Some parts of the
653 * state are copied from the parent's reflow input. The remainder is computed.
654 *
655 * @param aPresContext Must be equal to aFrame->PresContext().
656 * @param aParentReflowInput A reference to an ReflowInput object that
657 * is to be the parent of this object.
658 * @param aFrame The frame for whose reflow input is being constructed.
659 * @param aAvailableSpace The available space to reflow aFrame (in aFrame's
660 * writing-mode). See comments for mAvailableSize for more information.
661 * @param aContainingBlockSize An optional size (in aFrame's writing mode),
662 * specifying the containing block size to use instead of the default
663 * size computed by ComputeContainingBlockRectangle(). If
664 * InitFlag::CallerWillInit is used, this is ignored. Pass it via
665 * Init() instead.
666 * @param aFlags A set of flags used for additional boolean parameters (see
667 * InitFlags above).
668 * @param aStyleSizeOverrides The style data used to override mFrame's when we
669 * call nsIFrame::ComputeSize() internally.
670 * @param aComputeSizeFlags A set of flags used when we call
671 * nsIFrame::ComputeSize() internally.
672 */
673 ReflowInput(nsPresContext* aPresContext,
674 const ReflowInput& aParentReflowInput, nsIFrame* aFrame,
675 const mozilla::LogicalSize& aAvailableSpace,
676 const mozilla::Maybe<mozilla::LogicalSize>& aContainingBlockSize =
677 mozilla::Nothing(),
678 InitFlags aFlags = {},
679 const mozilla::StyleSizeOverrides& aSizeOverrides = {},
680 mozilla::ComputeSizeFlags aComputeSizeFlags = {});
681
682 /**
683 * This method initializes various data members. It is automatically called by
684 * the constructors if InitFlags::CallerWillInit is *not* used.
685 *
686 * @param aContainingBlockSize An optional size (in mFrame's writing mode),
687 * specifying the containing block size to use instead of the default
688 * size computed by ComputeContainingBlockRectangle().
689 * @param aBorder An optional border (in mFrame's writing mode). If given, use
690 * it instead of the border computed from mFrame's StyleBorder.
691 * @param aPadding An optional padding (in mFrame's writing mode). If given,
692 * use it instead of the padding computing from mFrame's StylePadding.
693 */
694 void Init(nsPresContext* aPresContext,
695 const mozilla::Maybe<mozilla::LogicalSize>& aContainingBlockSize =
696 mozilla::Nothing(),
697 const mozilla::Maybe<mozilla::LogicalMargin>& aBorder =
698 mozilla::Nothing(),
699 const mozilla::Maybe<mozilla::LogicalMargin>& aPadding =
700 mozilla::Nothing());
701
702 /**
703 * Get the used line-height property. The return value will be >= 0.
704 */
705 nscoord GetLineHeight() const;
706
707 /**
708 * Set the used line-height. aLineHeight must be >= 0.
709 */
710 void SetLineHeight(nscoord aLineHeight);
711
712 /**
713 * Calculate the used line-height property without a reflow input instance.
714 * The return value will be >= 0.
715 *
716 * @param aBlockBSize The computed block size of the content rect of the block
717 * that the line should fill. Only used with
718 * line-height:-moz-block-height. NS_UNCONSTRAINEDSIZE
719 * results in a normal line-height for
720 * line-height:-moz-block-height.
721 * @param aFontSizeInflation The result of the appropriate
722 * nsLayoutUtils::FontSizeInflationFor call,
723 * or 1.0 if during intrinsic size
724 * calculation.
725 */
726 static nscoord CalcLineHeight(nsIContent* aContent,
727 ComputedStyle* aComputedStyle,
728 nsPresContext* aPresContext,
729 nscoord aBlockBSize, float aFontSizeInflation);
730
731 mozilla::LogicalSize ComputeContainingBlockRectangle(
732 nsPresContext* aPresContext, const ReflowInput* aContainingBlockRI) const;
733
734 /**
735 * Apply the mComputed(Min/Max)Width constraints to the content
736 * size computed so far.
737 */
ApplyMinMaxWidthReflowInput738 nscoord ApplyMinMaxWidth(nscoord aWidth) const {
739 if (NS_UNCONSTRAINEDSIZE != ComputedMaxWidth()) {
740 aWidth = std::min(aWidth, ComputedMaxWidth());
741 }
742 return std::max(aWidth, ComputedMinWidth());
743 }
744
745 /**
746 * Apply the mComputed(Min/Max)ISize constraints to the content
747 * size computed so far.
748 */
ApplyMinMaxISizeReflowInput749 nscoord ApplyMinMaxISize(nscoord aISize) const {
750 if (NS_UNCONSTRAINEDSIZE != ComputedMaxISize()) {
751 aISize = std::min(aISize, ComputedMaxISize());
752 }
753 return std::max(aISize, ComputedMinISize());
754 }
755
756 /**
757 * Apply the mComputed(Min/Max)Height constraints to the content
758 * size computed so far.
759 *
760 * @param aHeight The height that we've computed an to which we want to apply
761 * min/max constraints.
762 * @param aConsumed The amount of the computed height that was consumed by
763 * our prev-in-flows.
764 */
765 nscoord ApplyMinMaxHeight(nscoord aHeight, nscoord aConsumed = 0) const {
766 aHeight += aConsumed;
767
768 if (NS_UNCONSTRAINEDSIZE != ComputedMaxHeight()) {
769 aHeight = std::min(aHeight, ComputedMaxHeight());
770 }
771
772 if (NS_UNCONSTRAINEDSIZE != ComputedMinHeight()) {
773 aHeight = std::max(aHeight, ComputedMinHeight());
774 }
775
776 return aHeight - aConsumed;
777 }
778
779 /**
780 * Apply the mComputed(Min/Max)BSize constraints to the content
781 * size computed so far.
782 *
783 * @param aBSize The block-size that we've computed an to which we want to
784 * apply min/max constraints.
785 * @param aConsumed The amount of the computed block-size that was consumed by
786 * our prev-in-flows.
787 */
788 nscoord ApplyMinMaxBSize(nscoord aBSize, nscoord aConsumed = 0) const {
789 aBSize += aConsumed;
790
791 if (NS_UNCONSTRAINEDSIZE != ComputedMaxBSize()) {
792 aBSize = std::min(aBSize, ComputedMaxBSize());
793 }
794
795 if (NS_UNCONSTRAINEDSIZE != ComputedMinBSize()) {
796 aBSize = std::max(aBSize, ComputedMinBSize());
797 }
798
799 return aBSize - aConsumed;
800 }
801
802 bool ShouldReflowAllKids() const;
803
804 // This method doesn't apply min/max computed widths to the value passed in.
SetComputedWidthReflowInput805 void SetComputedWidth(nscoord aComputedWidth) {
806 if (mWritingMode.IsVertical()) {
807 SetComputedBSize(aComputedWidth);
808 } else {
809 SetComputedISize(aComputedWidth);
810 }
811 }
812
813 // This method doesn't apply min/max computed heights to the value passed in.
SetComputedHeightReflowInput814 void SetComputedHeight(nscoord aComputedHeight) {
815 if (mWritingMode.IsVertical()) {
816 SetComputedISize(aComputedHeight);
817 } else {
818 SetComputedBSize(aComputedHeight);
819 }
820 }
821
822 // This method doesn't apply min/max computed inline-sizes to the value passed
823 // in.
824 void SetComputedISize(nscoord aComputedISize);
825
826 // These methods don't apply min/max computed block-sizes to the value passed
827 // in.
828 void SetComputedBSize(nscoord aComputedBSize);
SetComputedBSizeWithoutResettingResizeFlagsReflowInput829 void SetComputedBSizeWithoutResettingResizeFlags(nscoord aComputedBSize) {
830 // Viewport frames reset the computed block size on a copy of their reflow
831 // input when reflowing fixed-pos kids. In that case we actually don't
832 // want to mess with the resize flags, because comparing the frame's rect
833 // to the munged computed isize is pointless.
834 MOZ_ASSERT(aComputedBSize >= 0, "Invalid computed block-size!");
835 ComputedBSize() = aComputedBSize;
836 }
837
838 void SetTruncated(const ReflowOutput& aMetrics,
839 nsReflowStatus* aStatus) const;
840
WillReflowAgainForClearanceReflowInput841 bool WillReflowAgainForClearance() const {
842 return mDiscoveredClearance && *mDiscoveredClearance;
843 }
844
845 // Compute the offsets for a relative position element
846 //
847 // @param aWM the writing mode of aCBSize and the returned offsets.
848 static mozilla::LogicalMargin ComputeRelativeOffsets(
849 mozilla::WritingMode aWM, nsIFrame* aFrame,
850 const mozilla::LogicalSize& aCBSize);
851
852 // If a relatively positioned element, adjust the position appropriately.
853 static void ApplyRelativePositioning(nsIFrame* aFrame,
854 const nsMargin& aComputedOffsets,
855 nsPoint* aPosition);
856
ApplyRelativePositioningReflowInput857 void ApplyRelativePositioning(nsPoint* aPosition) const {
858 ApplyRelativePositioning(mFrame, ComputedPhysicalOffsets(), aPosition);
859 }
860
861 static void ApplyRelativePositioning(
862 nsIFrame* aFrame, mozilla::WritingMode aWritingMode,
863 const mozilla::LogicalMargin& aComputedOffsets,
864 mozilla::LogicalPoint* aPosition, const nsSize& aContainerSize);
865
ApplyRelativePositioningReflowInput866 void ApplyRelativePositioning(mozilla::LogicalPoint* aPosition,
867 const nsSize& aContainerSize) const {
868 ApplyRelativePositioning(mFrame, mWritingMode,
869 ComputedLogicalOffsets(mWritingMode), aPosition,
870 aContainerSize);
871 }
872
873 // Resolve any block-axis 'auto' margins (if any) for an absolutely positioned
874 // frame. aMargin and aOffsets are both outparams (though we only touch
875 // aOffsets if the position is overconstrained)
876 static void ComputeAbsPosBlockAutoMargin(nscoord aAvailMarginSpace,
877 WritingMode aContainingBlockWM,
878 bool aIsMarginBStartAuto,
879 bool aIsMarginBEndAuto,
880 LogicalMargin& aMargin,
881 LogicalMargin& aOffsets);
882
883 // Resolve any inline-axis 'auto' margins (if any) for an absolutely
884 // positioned frame. aMargin and aOffsets are both outparams (though we only
885 // touch aOffsets if the position is overconstrained)
886 static void ComputeAbsPosInlineAutoMargin(nscoord aAvailMarginSpace,
887 WritingMode aContainingBlockWM,
888 bool aIsMarginIStartAuto,
889 bool aIsMarginIEndAuto,
890 LogicalMargin& aMargin,
891 LogicalMargin& aOffsets);
892
893 #ifdef DEBUG
894 // Reflow trace methods. Defined in nsFrame.cpp so they have access
895 // to the display-reflow infrastructure.
896 static void* DisplayInitConstraintsEnter(nsIFrame* aFrame,
897 ReflowInput* aState,
898 nscoord aCBISize, nscoord aCBBSize,
899 const nsMargin* aBorder,
900 const nsMargin* aPadding);
901 static void DisplayInitConstraintsExit(nsIFrame* aFrame, ReflowInput* aState,
902 void* aValue);
903 static void* DisplayInitFrameTypeEnter(nsIFrame* aFrame, ReflowInput* aState);
904 static void DisplayInitFrameTypeExit(nsIFrame* aFrame, ReflowInput* aState,
905 void* aValue);
906 #endif
907
908 protected:
909 void InitCBReflowInput();
910 void InitResizeFlags(nsPresContext* aPresContext,
911 mozilla::LayoutFrameType aFrameType);
912 void InitDynamicReflowRoot();
913
914 void InitConstraints(
915 nsPresContext* aPresContext,
916 const mozilla::Maybe<mozilla::LogicalSize>& aContainingBlockSize,
917 const mozilla::Maybe<mozilla::LogicalMargin>& aBorder,
918 const mozilla::Maybe<mozilla::LogicalMargin>& aPadding,
919 mozilla::LayoutFrameType aFrameType);
920
921 // Returns the nearest containing block or block frame (whether or not
922 // it is a containing block) for the specified frame. Also returns
923 // the inline-start edge and logical size of the containing block's
924 // content area.
925 // These are returned in the coordinate space of the containing block.
926 nsIFrame* GetHypotheticalBoxContainer(nsIFrame* aFrame,
927 nscoord& aCBIStartEdge,
928 mozilla::LogicalSize& aCBSize) const;
929
930 // Calculate a "hypothetical box" position where the placeholder frame
931 // (for a position:fixed/absolute element) would have been placed if it were
932 // positioned statically. The hypothetical box position will have a writing
933 // mode with the same block direction as the absolute containing block
934 // (aCBReflowInput->frame), though it may differ in inline direction.
935 void CalculateHypotheticalPosition(nsPresContext* aPresContext,
936 nsPlaceholderFrame* aPlaceholderFrame,
937 const ReflowInput* aCBReflowInput,
938 nsHypotheticalPosition& aHypotheticalPos,
939 mozilla::LayoutFrameType aFrameType) const;
940
941 // Check if we can use the resolved auto block size (by insets) to compute
942 // the inline size through aspect-ratio on absolute-positioned elements.
943 // This is only needed for non-replaced elements.
944 // https://drafts.csswg.org/css-position/#abspos-auto-size
945 bool IsInlineSizeComputableByBlockSizeAndAspectRatio(
946 nscoord aBlockSize) const;
947
948 // This calculates the size by using the resolved auto block size (from
949 // non-auto block insets), according to the writing mode of current block.
950 LogicalSize CalculateAbsoluteSizeWithResolvedAutoBlockSize(
951 nscoord aAutoBSize, const LogicalSize& aTentativeComputedSize);
952
953 void InitAbsoluteConstraints(nsPresContext* aPresContext,
954 const ReflowInput* aCBReflowInput,
955 const mozilla::LogicalSize& aContainingBlockSize,
956 mozilla::LayoutFrameType aFrameType);
957
958 // Calculates the computed values for the 'min-inline-size',
959 // 'max-inline-size', 'min-block-size', and 'max-block-size' properties, and
960 // stores them in the assorted data members
961 void ComputeMinMaxValues(const mozilla::LogicalSize& aCBSize);
962
963 // aInsideBoxSizing returns the part of the padding, border, and margin
964 // in the aAxis dimension that goes inside the edge given by box-sizing;
965 // aOutsideBoxSizing returns the rest.
966 void CalculateBorderPaddingMargin(mozilla::LogicalAxis aAxis,
967 nscoord aContainingBlockSize,
968 nscoord* aInsideBoxSizing,
969 nscoord* aOutsideBoxSizing) const;
970
971 void CalculateBlockSideMargins();
972
973 /**
974 * @return true if mFrame is an internal table frame, i.e. an
975 * ns[RowGroup|ColGroup|Row|Cell]Frame. (We exclude nsTableColFrame
976 * here since we never setup a ReflowInput for those.)
977 */
978 bool IsInternalTableFrame() const;
979
980 private:
981 // The available size in which to reflow the frame. The space represents the
982 // amount of room for the frame's margin, border, padding, and content area.
983 //
984 // The available inline-size should be constrained. The frame's inline-size
985 // you choose should fit within it.
986
987 // In galley mode, the available block-size is always unconstrained, and only
988 // page mode or multi-column layout involves a constrained available
989 // block-size.
990 //
991 // An unconstrained available block-size means you can choose whatever size
992 // you want. If the value is constrained, the frame's block-start border,
993 // padding, and content, must fit. If a frame is fully-complete after reflow,
994 // then its block-end border, padding, and margin (and similar for its
995 // fully-complete ancestors) will need to fit within this available
996 // block-size. However, if a frame is monolithic, it may choose a block-size
997 // larger than the available block-size.
998 mozilla::LogicalSize mAvailableSize{mWritingMode};
999
1000 // The computed size specifies the frame's content area, and it does not apply
1001 // to inline non-replaced elements.
1002 //
1003 // For block-level frames, the computed inline-size is based on the
1004 // inline-size of the containing block, the margin/border/padding areas, and
1005 // the min/max inline-size.
1006 //
1007 // For non-replaced block-level frames in the flow and floated, if the
1008 // computed block-size is NS_UNCONSTRAINEDSIZE, you should choose a block-size
1009 // to shrink wrap around the normal flow child frames. The block-size must be
1010 // within the limit of the min/max block-size if there is such a limit.
1011 mozilla::LogicalSize mComputedSize{mWritingMode};
1012
1013 // Computed values for 'inset' properties. Only applies to 'positioned'
1014 // elements.
1015 mozilla::LogicalMargin mComputedOffsets{mWritingMode};
1016
1017 // Computed value for 'min-inline-size'/'min-block-size'.
1018 mozilla::LogicalSize mComputedMinSize{mWritingMode};
1019
1020 // Computed value for 'max-inline-size'/'max-block-size'.
1021 mozilla::LogicalSize mComputedMaxSize{mWritingMode, NS_UNCONSTRAINEDSIZE,
1022 NS_UNCONSTRAINEDSIZE};
1023
1024 // Cache the used line-height property.
1025 mutable nscoord mLineHeight = NS_UNCONSTRAINEDSIZE;
1026 };
1027
1028 } // namespace mozilla
1029
1030 #endif // mozilla_ReflowInput_h
1031