tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ReflowInput.h (41330B)


      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 <algorithm>
     13 
     14 #include "LayoutConstants.h"
     15 #include "ReflowOutput.h"
     16 #include "mozilla/EnumSet.h"
     17 #include "mozilla/LayoutStructs.h"
     18 #include "mozilla/Maybe.h"
     19 #include "mozilla/WritingModes.h"
     20 #include "nsMargin.h"
     21 #include "nsStyleConsts.h"
     22 
     23 class gfxContext;
     24 class nsFloatManager;
     25 struct nsHypotheticalPosition;
     26 class nsIPercentBSizeObserver;
     27 class nsLineLayout;
     28 class nsPlaceholderFrame;
     29 class nsPresContext;
     30 class nsReflowStatus;
     31 
     32 namespace mozilla {
     33 enum class LayoutFrameType : uint8_t;
     34 
     35 /**
     36 * @return aValue clamped to [aMinValue, aMaxValue].
     37 *
     38 * @note This function needs to handle aMinValue > aMaxValue. In that case,
     39 *       aMinValue is returned. That's why we cannot use std::clamp()
     40 *       since it asserts max >= min.
     41 * @note If aMinValue and aMaxValue are computed min block-size and max
     42 *       block-size, it is simpler to use ReflowInput::ApplyMinMaxBSize().
     43 *       Similarly, there is ReflowInput::ApplyMinMaxISize() for clamping an
     44 *       inline-size.
     45 * @see https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
     46 * @see https://www.w3.org/TR/CSS22/visudet.html#min-max-heights
     47 */
     48 template <class NumericType>
     49 NumericType CSSMinMax(NumericType aValue, NumericType aMinValue,
     50                      NumericType aMaxValue) {
     51  NumericType result = aValue;
     52  if (aMaxValue < result) {
     53    result = aMaxValue;
     54  }
     55  if (aMinValue > result) {
     56    result = aMinValue;
     57  }
     58  return result;
     59 }
     60 
     61 // A base class of ReflowInput that computes only the padding,
     62 // border, and margin, since those values are needed more often.
     63 struct SizeComputationInput {
     64 public:
     65  // The frame being reflowed.
     66  nsIFrame* const mFrame;
     67 
     68  // Rendering context to use for measurement.
     69  gfxContext* mRenderingContext;
     70 
     71  // Cache for anchor resolution in this computation.
     72  AnchorPosResolutionCache* mAnchorPosResolutionCache = nullptr;
     73 
     74  nsMargin ComputedPhysicalMargin() const {
     75    return mComputedMargin.GetPhysicalMargin(mWritingMode);
     76  }
     77  nsMargin ComputedPhysicalBorderPadding() const {
     78    return mComputedBorderPadding.GetPhysicalMargin(mWritingMode);
     79  }
     80  nsMargin ComputedPhysicalBorder() const {
     81    return ComputedLogicalBorder(mWritingMode).GetPhysicalMargin(mWritingMode);
     82  }
     83  nsMargin ComputedPhysicalPadding() const {
     84    return mComputedPadding.GetPhysicalMargin(mWritingMode);
     85  }
     86 
     87  LogicalMargin ComputedLogicalMargin(WritingMode aWM) const {
     88    return mComputedMargin.ConvertTo(aWM, mWritingMode);
     89  }
     90  LogicalMargin ComputedLogicalBorderPadding(WritingMode aWM) const {
     91    return mComputedBorderPadding.ConvertTo(aWM, mWritingMode);
     92  }
     93  LogicalMargin ComputedLogicalPadding(WritingMode aWM) const {
     94    return mComputedPadding.ConvertTo(aWM, mWritingMode);
     95  }
     96  LogicalMargin ComputedLogicalBorder(WritingMode aWM) const {
     97    return (mComputedBorderPadding - mComputedPadding)
     98        .ConvertTo(aWM, mWritingMode);
     99  }
    100 
    101  void SetComputedLogicalMargin(WritingMode aWM, const LogicalMargin& aMargin) {
    102    mComputedMargin = aMargin.ConvertTo(mWritingMode, aWM);
    103  }
    104  void SetComputedLogicalBorderPadding(WritingMode aWM,
    105                                       const LogicalMargin& aBorderPadding) {
    106    mComputedBorderPadding = aBorderPadding.ConvertTo(mWritingMode, aWM);
    107  }
    108  void SetComputedLogicalPadding(WritingMode aWM,
    109                                 const LogicalMargin& aPadding) {
    110    mComputedPadding = aPadding.ConvertTo(mWritingMode, aWM);
    111  }
    112 
    113  WritingMode GetWritingMode() const { return mWritingMode; }
    114 
    115 protected:
    116  // cached copy of the frame's writing-mode, for logical coordinates
    117  const WritingMode mWritingMode;
    118 
    119  // Cached mFrame->IsThemed().
    120  const bool mIsThemed = false;
    121 
    122  // Computed margin values
    123  LogicalMargin mComputedMargin;
    124 
    125  // Cached copy of the border + padding values
    126  LogicalMargin mComputedBorderPadding;
    127 
    128  // Computed padding values
    129  LogicalMargin mComputedPadding;
    130 
    131 public:
    132  // Callers using this constructor must call InitOffsets on their own.
    133  SizeComputationInput(
    134      nsIFrame* aFrame, gfxContext* aRenderingContext,
    135      AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr);
    136 
    137  SizeComputationInput(nsIFrame* aFrame, gfxContext* aRenderingContext,
    138                       WritingMode aContainingBlockWritingMode,
    139                       nscoord aContainingBlockISize,
    140                       const Maybe<LogicalMargin>& aBorder = Nothing(),
    141                       const Maybe<LogicalMargin>& aPadding = Nothing());
    142 
    143 private:
    144  /**
    145   * Computes margin values from the specified margin style information, and
    146   * fills in the mComputedMargin member.
    147   *
    148   * @param aCBWM Writing mode of the containing block
    149   * @param aPercentBasis
    150   *    Inline size of the containing block (in its own writing mode), to use
    151   *    for resolving percentage margin values in the inline and block axes.
    152   * @return true if the margin is dependent on the containing block size.
    153   */
    154  bool ComputeMargin(WritingMode aCBWM, nscoord aPercentBasis,
    155                     LayoutFrameType aFrameType);
    156 
    157  /**
    158   * Computes padding values from the specified padding style information, and
    159   * fills in the mComputedPadding member.
    160   *
    161   * @param aCBWM Writing mode of the containing block
    162   * @param aPercentBasis
    163   *    Inline size of the containing block (in its own writing mode), to use
    164   *    for resolving percentage padding values in the inline and block axes.
    165   * @return true if the padding is dependent on the containing block size.
    166   */
    167  bool ComputePadding(WritingMode aCBWM, nscoord aPercentBasis,
    168                      LayoutFrameType aFrameType);
    169 
    170 protected:
    171  void InitOffsets(WritingMode aCBWM, nscoord aPercentBasis,
    172                   LayoutFrameType aFrameType, ComputeSizeFlags aFlags,
    173                   const Maybe<LogicalMargin>& aBorder,
    174                   const Maybe<LogicalMargin>& aPadding,
    175                   const nsStyleDisplay* aDisplay = nullptr);
    176 
    177  /**
    178   * Convert StyleSize or StyleMaxSize to nscoord when percentages depend on the
    179   * inline size of the containing block, and enumerated values are for inline
    180   * size, min-inline-size, or max-inline-size.  Does not handle auto inline
    181   * sizes.
    182   */
    183  template <typename SizeOrMaxSize>
    184  inline nscoord ComputeISizeValue(const LogicalSize& aContainingBlockSize,
    185                                   StyleBoxSizing aBoxSizing,
    186                                   const SizeOrMaxSize&) const;
    187 
    188  /**
    189   * Wrapper for SizeComputationInput::ComputeBSizeValue (defined below, which
    190   * itself is a wrapper for nsLayoutUtils::ComputeBSizeValue). This one just
    191   * handles 'stretch' sizes first.
    192   */
    193  template <typename SizeOrMaxSize>
    194  inline nscoord ComputeBSizeValueHandlingStretch(
    195      nscoord aContainingBlockBSize, StyleBoxSizing aBoxSizing,
    196      const SizeOrMaxSize& aSize) const;
    197 
    198  /**
    199   * Wrapper for nsLayoutUtils::ComputeBSizeValue, which automatically figures
    200   * out the value to pass for its aContentEdgeToBoxSizingBoxEdge param.
    201   */
    202  nscoord ComputeBSizeValue(nscoord aContainingBlockBSize,
    203                            StyleBoxSizing aBoxSizing,
    204                            const LengthPercentage& aCoord) const;
    205 };
    206 
    207 /**
    208 * State passed to a frame during reflow.
    209 *
    210 * @see nsIFrame#Reflow()
    211 */
    212 struct ReflowInput : public SizeComputationInput {
    213  // the reflow inputs are linked together. this is the pointer to the
    214  // parent's reflow input
    215  const ReflowInput* mParentReflowInput = nullptr;
    216 
    217  // A non-owning pointer to the float manager associated with this area,
    218  // which points to the object owned by nsAutoFloatManager::mNew.
    219  nsFloatManager* mFloatManager = nullptr;
    220 
    221  // LineLayout object (only for inline reflow; set to nullptr otherwise)
    222  nsLineLayout* mLineLayout = nullptr;
    223 
    224  // The appropriate reflow input for the containing block (for
    225  // percentage widths, etc.) of this reflow input's frame. It will be setup
    226  // properly in InitCBReflowInput().
    227  const ReflowInput* mCBReflowInput = nullptr;
    228 
    229  // The amount the in-flow position of the block is moving vertically relative
    230  // to its previous in-flow position (i.e. the amount the line containing the
    231  // block is moving).
    232  // This should be zero for anything which is not a block outside, and it
    233  // should be zero for anything which has a non-block parent.
    234  // The intended use of this value is to allow the accurate determination
    235  // of the potential impact of a float
    236  // This takes on an arbitrary value the first time a block is reflowed
    237  nscoord mBlockDelta = 0;
    238 
    239  // Physical accessors for the private fields. They are needed for
    240  // compatibility with not-yet-updated code. New code should use the accessors
    241  // for logical coordinates, unless the code really works on physical
    242  // coordinates.
    243  nscoord AvailableWidth() const { return mAvailableSize.Width(mWritingMode); }
    244  nscoord AvailableHeight() const {
    245    return mAvailableSize.Height(mWritingMode);
    246  }
    247  nscoord ComputedWidth() const { return mComputedSize.Width(mWritingMode); }
    248  nscoord ComputedHeight() const { return mComputedSize.Height(mWritingMode); }
    249  nscoord ComputedMinWidth() const {
    250    return mComputedMinSize.Width(mWritingMode);
    251  }
    252  nscoord ComputedMaxWidth() const {
    253    return mComputedMaxSize.Width(mWritingMode);
    254  }
    255  nscoord ComputedMinHeight() const {
    256    return mComputedMinSize.Height(mWritingMode);
    257  }
    258  nscoord ComputedMaxHeight() const {
    259    return mComputedMaxSize.Height(mWritingMode);
    260  }
    261 
    262  // Logical accessors for private fields in mWritingMode.
    263  nscoord AvailableISize() const { return mAvailableSize.ISize(mWritingMode); }
    264  nscoord AvailableBSize() const { return mAvailableSize.BSize(mWritingMode); }
    265  nscoord ComputedISize() const { return mComputedSize.ISize(mWritingMode); }
    266  nscoord ComputedBSize() const { return mComputedSize.BSize(mWritingMode); }
    267  nscoord ComputedMinISize() const {
    268    return mComputedMinSize.ISize(mWritingMode);
    269  }
    270  nscoord ComputedMaxISize() const {
    271    return mComputedMaxSize.ISize(mWritingMode);
    272  }
    273  nscoord ComputedMinBSize() const {
    274    return mComputedMinSize.BSize(mWritingMode);
    275  }
    276  nscoord ComputedMaxBSize() const {
    277    return mComputedMaxSize.BSize(mWritingMode);
    278  }
    279 
    280  // WARNING: In general, adjusting available inline-size or block-size is not
    281  // safe because ReflowInput has members whose values depend on the available
    282  // size passing through the constructor. For example,
    283  // CalculateBlockSideMargins() is called during initialization, and uses
    284  // AvailableSize(). Make sure your use case doesn't lead to stale member
    285  // values in ReflowInput!
    286  void SetAvailableISize(nscoord aAvailableISize) {
    287    mAvailableSize.ISize(mWritingMode) = aAvailableISize;
    288  }
    289  void SetAvailableBSize(nscoord aAvailableBSize) {
    290    mAvailableSize.BSize(mWritingMode) = aAvailableBSize;
    291  }
    292 
    293  void SetComputedMinISize(nscoord aMinISize) {
    294    mComputedMinSize.ISize(mWritingMode) = aMinISize;
    295  }
    296  void SetComputedMaxISize(nscoord aMaxISize) {
    297    mComputedMaxSize.ISize(mWritingMode) = aMaxISize;
    298  }
    299  void SetComputedMinBSize(nscoord aMinBSize) {
    300    mComputedMinSize.BSize(mWritingMode) = aMinBSize;
    301  }
    302  void SetComputedMaxBSize(nscoord aMaxBSize) {
    303    mComputedMaxSize.BSize(mWritingMode) = aMaxBSize;
    304  }
    305  void SetPercentageBasisInBlockAxis(nscoord aBSize) {
    306    mPercentageBasisInBlockAxis = Some(aBSize);
    307  }
    308 
    309  LogicalSize AvailableSize() const { return mAvailableSize; }
    310  LogicalSize ComputedSize() const { return mComputedSize; }
    311 
    312  template <typename F>
    313  LogicalSize ComputedSizeWithBSizeFallback(F&& aFallback) const {
    314    auto size = mComputedSize;
    315    if (size.BSize(mWritingMode) == NS_UNCONSTRAINEDSIZE) {
    316      size.BSize(mWritingMode) = ApplyMinMaxBSize(aFallback());
    317    }
    318    return size;
    319  }
    320 
    321  LogicalSize ComputedMinSize() const { return mComputedMinSize; }
    322  LogicalSize ComputedMaxSize() const { return mComputedMaxSize; }
    323 
    324  LogicalSize AvailableSize(WritingMode aWM) const {
    325    return AvailableSize().ConvertTo(aWM, mWritingMode);
    326  }
    327  LogicalSize ComputedSize(WritingMode aWM) const {
    328    return ComputedSize().ConvertTo(aWM, mWritingMode);
    329  }
    330  LogicalSize ComputedMinSize(WritingMode aWM) const {
    331    return ComputedMinSize().ConvertTo(aWM, mWritingMode);
    332  }
    333  LogicalSize ComputedMaxSize(WritingMode aWM) const {
    334    return ComputedMaxSize().ConvertTo(aWM, mWritingMode);
    335  }
    336 
    337  LogicalSize ComputedSizeWithPadding(WritingMode aWM) const {
    338    return ComputedSize(aWM) + ComputedLogicalPadding(aWM).Size(aWM);
    339  }
    340 
    341  LogicalSize ComputedSizeWithBorderPadding(WritingMode aWM) const {
    342    return ComputedSize(aWM) + ComputedLogicalBorderPadding(aWM).Size(aWM);
    343  }
    344 
    345  LogicalSize ComputedSizeWithMarginBorderPadding(WritingMode aWM) const {
    346    return ComputedSizeWithBorderPadding(aWM) +
    347           ComputedLogicalMargin(aWM).Size(aWM);
    348  }
    349 
    350  nsSize ComputedPhysicalSize() const {
    351    return mComputedSize.GetPhysicalSize(mWritingMode);
    352  }
    353 
    354  nsMargin ComputedPhysicalOffsets() const {
    355    return mComputedOffsets.GetPhysicalMargin(mWritingMode);
    356  }
    357 
    358  LogicalMargin ComputedLogicalOffsets(WritingMode aWM) const {
    359    return mComputedOffsets.ConvertTo(aWM, mWritingMode);
    360  }
    361 
    362  void SetComputedLogicalOffsets(WritingMode aWM,
    363                                 const LogicalMargin& aOffsets) {
    364    mComputedOffsets = aOffsets.ConvertTo(mWritingMode, aWM);
    365  }
    366 
    367  // Return ReflowInput's computed size including border-padding, with
    368  // unconstrained dimensions replaced by zero.
    369  nsSize ComputedSizeAsContainerIfConstrained() const;
    370 
    371  // Return the physical content box relative to the frame itself.
    372  nsRect ComputedPhysicalContentBoxRelativeToSelf() const {
    373    auto bp = ComputedPhysicalBorderPadding();
    374    return nsRect(nsPoint(bp.left, bp.top), ComputedPhysicalSize());
    375  }
    376 
    377  // Get the writing mode of the containing block, to resolve float/clear
    378  // logical sides appropriately.
    379  WritingMode GetCBWritingMode() const;
    380 
    381  // Our saved containing block dimensions.
    382  LogicalSize mContainingBlockSize{mWritingMode};
    383 
    384  // Cached pointers to the various style structs used during initialization.
    385  const nsStyleDisplay* mStyleDisplay = nullptr;
    386  const nsStylePosition* mStylePosition = nullptr;
    387  const nsStyleBorder* mStyleBorder = nullptr;
    388  const nsStyleMargin* mStyleMargin = nullptr;
    389 
    390  enum class BreakType : uint8_t {
    391    Auto,
    392    Column,
    393    Page,
    394  };
    395  BreakType mBreakType = BreakType::Auto;
    396 
    397  // a frame (e.g. nsTableCellFrame) which may need to generate a special
    398  // reflow for percent bsize calculations
    399  nsIPercentBSizeObserver* mPercentBSizeObserver = nullptr;
    400 
    401  // CSS margin collapsing sometimes requires us to reflow
    402  // optimistically assuming that margins collapse to see if clearance
    403  // is required. When we discover that clearance is required, we
    404  // store the frame in which clearance was discovered to the location
    405  // requested here.
    406  nsIFrame** mDiscoveredClearance = nullptr;
    407 
    408  struct Flags {
    409    Flags() { memset(this, 0, sizeof(*this)); }
    410 
    411    // Cached mFrame->IsReplaced().
    412    bool mIsReplaced : 1;
    413 
    414    // used by tables to communicate special reflow (in process) to handle
    415    // percent bsize frames inside cells which may not have computed bsizes
    416    bool mSpecialBSizeReflow : 1;
    417 
    418    // nothing in the frame's next-in-flow (or its descendants) is changing
    419    bool mNextInFlowUntouched : 1;
    420 
    421    // Is the current context at the top of a page?  When true, we force
    422    // something that's too tall for a page/column to fit anyway to avoid
    423    // infinite loops.
    424    bool mIsTopOfPage : 1;
    425 
    426    // parent frame is an ScrollContainerFrame and it is assuming a horizontal
    427    // scrollbar
    428    bool mAssumingHScrollbar : 1;
    429 
    430    // parent frame is an ScrollContainerFrame and it is assuming a vertical
    431    // scrollbar
    432    bool mAssumingVScrollbar : 1;
    433 
    434    // Is frame a different inline-size than before?
    435    bool mIsIResize : 1;
    436 
    437    // Is frame (potentially) a different block-size than before?
    438    // This includes cases where the block-size is 'auto' and the
    439    // contents or width have changed.
    440    bool mIsBResize : 1;
    441 
    442    // Has this frame changed block-size in a way that affects
    443    // block-size percentages on frames for which it is the containing
    444    // block?  This includes a change between 'auto' and a length that
    445    // doesn't actually change the frame's block-size.  It does not
    446    // include cases where the block-size is 'auto' and the frame's
    447    // contents have changed.
    448    //
    449    // In the current code, this is only true when mIsBResize is also
    450    // true, although it doesn't necessarily need to be that way (e.g.,
    451    // in the case of a frame changing from 'auto' to a length that
    452    // produces the same height).
    453    bool mIsBResizeForPercentages : 1;
    454 
    455    // tables are splittable, this should happen only inside a page and never
    456    // insider a column frame
    457    bool mTableIsSplittable : 1;
    458 
    459    // Does frame height depend on an ancestor table-cell?
    460    bool mHeightDependsOnAncestorCell : 1;
    461 
    462    // Is this the final reflow of an orthogonal table-cell, after row sizing?
    463    bool mOrthogonalCellFinalReflow : 1;
    464 
    465    // nsColumnSetFrame is balancing columns
    466    bool mIsColumnBalancing : 1;
    467 
    468    // We have an ancestor nsColumnSetFrame performing the last column balancing
    469    // reflow. The available block-size of the last column might become
    470    // unconstrained.
    471    bool mIsInLastColumnBalancingReflow : 1;
    472 
    473    // True if ColumnSetWrapperFrame has a constrained block-size, and is going
    474    // to consume all of its block-size in this fragment. This bit is passed to
    475    // nsColumnSetFrame to determine whether to give up balancing and create
    476    // overflow columns.
    477    bool mColumnSetWrapperHasNoBSizeLeft : 1;
    478 
    479    // If this flag is set, the BSize of this frame should be considered
    480    // indefinite for the purposes of percent resolution on child frames (we
    481    // should behave as if ComputedBSize() were NS_UNCONSTRAINEDSIZE when doing
    482    // percent resolution against this.ComputedBSize()).  For example: flex
    483    // items may have their ComputedBSize() resolved ahead-of-time by their
    484    // flex container, and yet their BSize might have to be considered
    485    // indefinite per https://drafts.csswg.org/css-flexbox/#definite-sizes
    486    bool mTreatBSizeAsIndefinite : 1;
    487 
    488    // a "fake" reflow input made in order to be the parent of a real one
    489    bool mDummyParentReflowInput : 1;
    490 
    491    // Should this frame reflow its place-holder children? If the available
    492    // height of this frame didn't change, but its in a paginated environment
    493    // (e.g. columns), it should always reflow its placeholder children.
    494    bool mMustReflowPlaceholders : 1;
    495 
    496    // the STATIC_POS_IS_CB_ORIGIN ctor flag
    497    bool mStaticPosIsCBOrigin : 1;
    498 
    499    // If set, the following two flags indicate that:
    500    // (1) this frame is absolutely-positioned (or fixed-positioned).
    501    // (2) this frame's static position depends on the CSS Box Alignment.
    502    // (3) we do need to compute the static position, because the frame's
    503    //     {Inline and/or Block} offsets actually depend on it.
    504    // When these bits are set, the offset values (IStart/IEnd, BStart/BEnd)
    505    // represent the "start" edge of the frame's CSS Box Alignment container
    506    // area, in that axis -- and these offsets need to be further-resolved
    507    // (with CSS Box Alignment) after we know the OOF frame's size.
    508    // NOTE: The "I" and "B" (for "Inline" and "Block") refer the axes of the
    509    // *containing block's writing-mode*, NOT mFrame's own writing-mode. This
    510    // is purely for convenience, since that's the writing-mode we're dealing
    511    // with when we set & react to these bits.
    512    bool mIOffsetsNeedCSSAlign : 1;
    513    bool mBOffsetsNeedCSSAlign : 1;
    514 
    515    // Is this frame or one of its ancestors being reflowed in a different
    516    // continuation than the one in which it was previously reflowed?  In
    517    // other words, has it moved to a different column or page than it was in
    518    // the previous reflow?
    519    //
    520    // FIXME: For now, we only ensure that this is set correctly for blocks.
    521    // This is okay because the only thing that uses it only cares about
    522    // whether there's been a fragment change within the same block formatting
    523    // context.
    524    bool mMovedBlockFragments : 1;
    525 
    526    // Is the block-size computed by aspect-ratio and inline size (i.e. block
    527    // axis is the ratio-dependent axis)? We set this flag so that we can check
    528    // whether to apply automatic content-based minimum sizes once we know the
    529    // children's block-size (after reflowing them).
    530    // https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
    531    bool mIsBSizeSetByAspectRatio : 1;
    532 
    533    // If true, then children of this frame can generate class A breakpoints
    534    // for paginated reflow.
    535    bool mCanHaveClassABreakpoints : 1;
    536  };
    537  Flags mFlags;
    538 
    539  StyleSizeOverrides mStyleSizeOverrides;
    540 
    541  ComputeSizeFlags mComputeSizeFlags;
    542 
    543  // This value keeps track of how deeply nested a given reflow input
    544  // is from the top of the frame tree.
    545  int16_t mReflowDepth = 0;
    546 
    547  // Accessors for the resize flags.
    548  bool IsIResize() const { return mFlags.mIsIResize; }
    549  bool IsBResize() const { return mFlags.mIsBResize; }
    550  bool IsBResizeForWM(WritingMode aWM) const {
    551    return aWM.IsOrthogonalTo(mWritingMode) ? mFlags.mIsIResize
    552                                            : mFlags.mIsBResize;
    553  }
    554  bool IsBResizeForPercentagesForWM(WritingMode aWM) const {
    555    // This uses the relatively-accurate mIsBResizeForPercentages flag
    556    // when the writing modes are parallel, and is a bit more
    557    // pessimistic when orthogonal.
    558    return !aWM.IsOrthogonalTo(mWritingMode) ? mFlags.mIsBResizeForPercentages
    559                                             : IsIResize();
    560  }
    561  void SetIResize(bool aValue) { mFlags.mIsIResize = aValue; }
    562  void SetBResize(bool aValue) { mFlags.mIsBResize = aValue; }
    563  void SetBResizeForPercentages(bool aValue) {
    564    mFlags.mIsBResizeForPercentages = aValue;
    565  }
    566 
    567  // Values for |aFlags| passed to constructor
    568  enum class InitFlag : uint8_t {
    569    // Indicates that the parent of this reflow input is "fake" (see
    570    // mDummyParentReflowInput in mFlags).
    571    DummyParentReflowInput,
    572 
    573    // Indicates that the calling function will initialize the reflow input, and
    574    // that the constructor should not call Init().
    575    CallerWillInit,
    576 
    577    // The caller wants the abs.pos. static-position resolved at the origin of
    578    // the containing block, i.e. at LogicalPoint(0, 0). (Note that this
    579    // doesn't necessarily mean that (0, 0) is the *correct* static position
    580    // for the frame in question.)
    581    // @note In a Grid container's masonry axis we'll always use
    582    // the placeholder's position in that axis regardless of this flag.
    583    StaticPosIsCBOrigin,
    584  };
    585  using InitFlags = EnumSet<InitFlag>;
    586 
    587  // Note: The copy constructor is written by the compiler automatically. You
    588  // can use that and then override specific values if you want, or you can
    589  // call Init as desired...
    590 
    591  /**
    592   * Initialize a ROOT reflow input.
    593   *
    594   * @param aPresContext Must be equal to aFrame->PresContext().
    595   * @param aFrame The frame for whose reflow input is being constructed.
    596   * @param aRenderingContext The rendering context to be used for measurements.
    597   * @param aAvailableSpace The available space to reflow aFrame (in aFrame's
    598   *        writing-mode). See comments for mAvailableSize for more information.
    599   * @param aFlags A set of flags used for additional boolean parameters (see
    600   *        InitFlags above).
    601   */
    602  ReflowInput(nsPresContext* aPresContext, nsIFrame* aFrame,
    603              gfxContext* aRenderingContext, const LogicalSize& aAvailableSpace,
    604              InitFlags aFlags = {});
    605 
    606  /**
    607   * Initialize a reflow input for a child frame's reflow. Some parts of the
    608   * state are copied from the parent's reflow input. The remainder is computed.
    609   *
    610   * @param aPresContext Must be equal to aFrame->PresContext().
    611   * @param aParentReflowInput A reference to an ReflowInput object that
    612   *        is to be the parent of this object.
    613   * @param aFrame The frame for whose reflow input is being constructed.
    614   * @param aAvailableSpace The available space to reflow aFrame (in aFrame's
    615   *        writing-mode). See comments for mAvailableSize for more information.
    616   * @param aContainingBlockSize An optional size (in aFrame's writing mode),
    617   *        specifying the containing block size to use instead of the default
    618   *        size computed by ComputeContainingBlockRectangle(). If
    619   *        InitFlag::CallerWillInit is used, this is ignored. Pass it via
    620   *        Init() instead.
    621   * @param aFlags A set of flags used for additional boolean parameters (see
    622   *        InitFlags above).
    623   * @param aStyleSizeOverrides The style data used to override mFrame's when we
    624   *        call nsIFrame::ComputeSize() internally.
    625   * @param aComputeSizeFlags A set of flags used when we call
    626   *        nsIFrame::ComputeSize() internally.
    627   * @param aAnchorResolutionCache A cache of referenced anchors to be populated
    628   *        (If specified) for this reflowed frame. Should live for the lifetime
    629   *        of this ReflowInput.
    630   */
    631  ReflowInput(nsPresContext* aPresContext,
    632              const ReflowInput& aParentReflowInput, nsIFrame* aFrame,
    633              const LogicalSize& aAvailableSpace,
    634              const Maybe<LogicalSize>& aContainingBlockSize = Nothing(),
    635              InitFlags aFlags = {},
    636              const StyleSizeOverrides& aSizeOverrides = {},
    637              ComputeSizeFlags aComputeSizeFlags = {},
    638              AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr);
    639 
    640  /**
    641   * This method initializes various data members. It is automatically called by
    642   * the constructors if InitFlags::CallerWillInit is *not* used.
    643   *
    644   * @param aContainingBlockSize An optional size (in mFrame's writing mode),
    645   *        specifying the containing block size to use instead of the default
    646   *        size computed by ComputeContainingBlockRectangle().
    647   * @param aBorder An optional border (in mFrame's writing mode). If given, use
    648   *        it instead of the border computed from mFrame's StyleBorder.
    649   * @param aPadding An optional padding (in mFrame's writing mode). If given,
    650   *        use it instead of the padding computing from mFrame's StylePadding.
    651   */
    652  void Init(nsPresContext* aPresContext,
    653            const Maybe<LogicalSize>& aContainingBlockSize = Nothing(),
    654            const Maybe<LogicalMargin>& aBorder = Nothing(),
    655            const Maybe<LogicalMargin>& aPadding = Nothing());
    656 
    657  /**
    658   * Get the used line-height property. The return value will be >= 0.
    659   */
    660  nscoord GetLineHeight() const;
    661 
    662  /**
    663   * Set the used line-height. aLineHeight must be >= 0.
    664   */
    665  void SetLineHeight(nscoord aLineHeight);
    666 
    667  /**
    668   * Calculate the used line-height property without a reflow input instance.
    669   * The return value will be >= 0.
    670   *
    671   * @param aBlockBSize The computed block size of the content rect of the block
    672   *                    that the line should fill. Only used with
    673   *                    line-height:-moz-block-height. NS_UNCONSTRAINEDSIZE
    674   *                    results in a normal line-height for
    675   *                    line-height:-moz-block-height.
    676   * @param aFontSizeInflation The result of the appropriate
    677   *                           nsLayoutUtils::FontSizeInflationFor call,
    678   *                           or 1.0 if during intrinsic size
    679   *                           calculation.
    680   */
    681  static nscoord CalcLineHeight(const ComputedStyle&,
    682                                nsPresContext* aPresContext,
    683                                const nsIContent* aContent, nscoord aBlockBSize,
    684                                float aFontSizeInflation);
    685 
    686  static nscoord CalcLineHeight(const StyleLineHeight&,
    687                                const nsStyleFont& aRelativeToFont,
    688                                nsPresContext* aPresContext, bool aIsVertical,
    689                                const nsIContent* aContent, nscoord aBlockBSize,
    690                                float aFontSizeInflation);
    691 
    692  static nscoord CalcLineHeightForCanvas(const StyleLineHeight& aLh,
    693                                         const nsFont& aRelativeToFont,
    694                                         nsAtom* aLanguage,
    695                                         bool aExplicitLanguage,
    696                                         nsPresContext* aPresContext,
    697                                         WritingMode aWM);
    698 
    699  static constexpr float kNormalLineHeightFactor = 1.2f;
    700 
    701  /**
    702   * Apply the mComputed(Min/Max)ISize constraints to the content
    703   * size computed so far.
    704   */
    705  nscoord ApplyMinMaxISize(nscoord aISize) const {
    706    if (NS_UNCONSTRAINEDSIZE != ComputedMaxISize()) {
    707      aISize = std::min(aISize, ComputedMaxISize());
    708    }
    709    return std::max(aISize, ComputedMinISize());
    710  }
    711 
    712  /**
    713   * Apply the mComputed(Min/Max)BSize constraints to the content
    714   * size computed so far.
    715   *
    716   * @param aBSize The block-size that we've computed an to which we want to
    717   *        apply min/max constraints.
    718   * @param aConsumed The amount of the computed block-size that was consumed by
    719   *        our prev-in-flows.
    720   */
    721  nscoord ApplyMinMaxBSize(nscoord aBSize, nscoord aConsumed = 0) const {
    722    aBSize += aConsumed;
    723 
    724    if (NS_UNCONSTRAINEDSIZE != ComputedMaxBSize()) {
    725      aBSize = std::min(aBSize, ComputedMaxBSize());
    726    }
    727 
    728    if (NS_UNCONSTRAINEDSIZE != ComputedMinBSize()) {
    729      aBSize = std::max(aBSize, ComputedMinBSize());
    730    }
    731 
    732    return aBSize - aConsumed;
    733  }
    734 
    735  bool ShouldReflowAllKids() const;
    736 
    737  // This method doesn't apply min/max computed widths to the value passed in.
    738  void SetComputedWidth(nscoord aComputedWidth) {
    739    if (mWritingMode.IsVertical()) {
    740      SetComputedBSize(aComputedWidth);
    741    } else {
    742      SetComputedISize(aComputedWidth);
    743    }
    744  }
    745 
    746  // This method doesn't apply min/max computed heights to the value passed in.
    747  void SetComputedHeight(nscoord aComputedHeight) {
    748    if (mWritingMode.IsVertical()) {
    749      SetComputedISize(aComputedHeight);
    750    } else {
    751      SetComputedBSize(aComputedHeight);
    752    }
    753  }
    754 
    755  // Use "No" to request SetComputedISize/SetComputedBSize not to reset resize
    756  // flags.
    757  enum class ResetResizeFlags : bool { No, Yes };
    758 
    759  // This method doesn't apply min/max computed inline-sizes to the value passed
    760  // in.
    761  void SetComputedISize(nscoord aComputedISize,
    762                        ResetResizeFlags aFlags = ResetResizeFlags::Yes);
    763 
    764  // These methods don't apply min/max computed block-sizes to the value passed
    765  // in.
    766  void SetComputedBSize(nscoord aComputedBSize,
    767                        ResetResizeFlags aFlags = ResetResizeFlags::Yes);
    768 
    769  bool WillReflowAgainForClearance() const {
    770    return mDiscoveredClearance && *mDiscoveredClearance;
    771  }
    772 
    773  // Returns true if we should apply automatic minimum on the block axis.
    774  //
    775  // The automatic minimum size in the ratio-dependent axis of a box with a
    776  // preferred aspect ratio that is neither a replaced element nor a scroll
    777  // container is its min-content size clamped from above by its maximum size.
    778  //
    779  // https://drafts.csswg.org/css-sizing-4/#aspect-ratio-minimum
    780  bool ShouldApplyAutomaticMinimumOnBlockAxis() const;
    781 
    782  // Returns true if mFrame has a constrained available block-size, or if mFrame
    783  // is a continuation. When this method returns true, mFrame can be considered
    784  // to be in a "fragmented context."
    785  //
    786  // Note: this method usually returns true when mFrame is in a paged
    787  // environment (e.g. printing) or has a multi-column container ancestor.
    788  // However, this doesn't include several cases when we're intentionally
    789  // performing layout in a fragmentation-ignoring way, e.g. 1) mFrame is a flex
    790  // or grid item, and this ReflowInput is for a measuring reflow with an
    791  // unconstrained available block-size, or 2) mFrame is (or is inside of) an
    792  // element that forms an orthogonal writing-mode.
    793  bool IsInFragmentedContext() const;
    794 
    795  // Compute the offsets for a relative position element
    796  //
    797  // @param aWM the writing mode of aCBSize and the returned offsets.
    798  static LogicalMargin ComputeRelativeOffsets(WritingMode aWM, nsIFrame* aFrame,
    799                                              const LogicalSize& aCBSize);
    800 
    801  // If aFrame is a relatively or sticky positioned element, adjust aPosition
    802  // appropriately.
    803  //
    804  // @param aComputedOffsets aFrame's relative offset, either from the cached
    805  //        nsIFrame::ComputedOffsetProperty() or ComputedPhysicalOffsets().
    806  //        Note: This parameter is used only when aFrame is relatively
    807  //        positioned, not sticky positioned.
    808  // @param aPosition [in/out] Pass aFrame's normal position (pre-relative
    809  //        positioning), and this method will update it to indicate aFrame's
    810  //        actual position.
    811  static void ApplyRelativePositioning(nsIFrame* aFrame,
    812                                       const nsMargin& aComputedOffsets,
    813                                       nsPoint* aPosition);
    814 
    815  static void ApplyRelativePositioning(nsIFrame* aFrame,
    816                                       WritingMode aWritingMode,
    817                                       const LogicalMargin& aComputedOffsets,
    818                                       LogicalPoint* aPosition,
    819                                       const nsSize& aContainerSize);
    820 
    821  // Resolve any block-axis 'auto' margins (if any) for an absolutely positioned
    822  // frame. aMargin and aOffsets are both outparams (though we only touch
    823  // aOffsets if the position is overconstrained)
    824  static void ComputeAbsPosBlockAutoMargin(nscoord aAvailMarginSpace,
    825                                           WritingMode aContainingBlockWM,
    826                                           bool aIsMarginBStartAuto,
    827                                           bool aIsMarginBEndAuto,
    828                                           LogicalMargin& aMargin);
    829 
    830  // Resolve any inline-axis 'auto' margins (if any) for an absolutely
    831  // positioned frame. aMargin and aOffsets are both outparams (though we only
    832  // touch aOffsets if the position is overconstrained)
    833  static void ComputeAbsPosInlineAutoMargin(nscoord aAvailMarginSpace,
    834                                            WritingMode aContainingBlockWM,
    835                                            bool aIsMarginIStartAuto,
    836                                            bool aIsMarginIEndAuto,
    837                                            LogicalMargin& aMargin);
    838 
    839 protected:
    840  void InitCBReflowInput();
    841  void InitResizeFlags(nsPresContext* aPresContext, LayoutFrameType aFrameType);
    842  void InitDynamicReflowRoot();
    843 
    844  void InitConstraints(nsPresContext* aPresContext,
    845                       const Maybe<LogicalSize>& aContainingBlockSize,
    846                       const Maybe<LogicalMargin>& aBorder,
    847                       const Maybe<LogicalMargin>& aPadding,
    848                       LayoutFrameType aFrameType);
    849 
    850  // Compute the content-box size of the containing block frame in mFrame's
    851  // writing-mode (mWritingMode).
    852  //
    853  // Note: the block-size in the return value may be unconstrained.
    854  LogicalSize ComputeContainingBlockRectangle(
    855      nsPresContext* aPresContext, const ReflowInput* aContainingBlockRI) const;
    856 
    857  // mBorderPadding and mFrame are both in mBoxContainer's writing-mode.
    858  struct HypotheticalBoxContainerInfo {
    859    nsIFrame* mBoxContainer;
    860    LogicalMargin mBorderPadding;
    861    LogicalSize mContentBoxSize;
    862  };
    863 
    864  // Returns the nearest containing block for aFrame. Also returns its border &
    865  // padding and content-box size. These are returned in the coordinate space of
    866  // the containing block.
    867  HypotheticalBoxContainerInfo GetHypotheticalBoxContainer(
    868      const nsIFrame* aFrame) const;
    869 
    870  // Calculate the position of the hypothetical box that the placeholder frame
    871  // (for a position:fixed/absolute element) would have if it were in the flow
    872  // (i.e., positioned statically).
    873  //
    874  // The position of the hypothetical box is relative to the padding edge of the
    875  // absolute containing block (aCBReflowInput->mFrame). The writing mode of the
    876  // hypothetical box will have the same block direction as the absolute
    877  // containing block, but it may differ in the inline direction.
    878  //
    879  // @param aCBPaddingBoxSize the padding-box size of the absolute containing
    880  // block, in its own writing-mode.
    881  void CalculateHypotheticalPosition(
    882      nsPlaceholderFrame* aPlaceholderFrame, const ReflowInput* aCBReflowInput,
    883      const LogicalSize& aCBPaddingBoxSize,
    884      nsHypotheticalPosition& aHypotheticalPos) const;
    885 
    886  void InitAbsoluteConstraints(const ReflowInput* aCBReflowInput,
    887                               const LogicalSize& aCBSize);
    888 
    889  // Calculates the computed values for the 'min-inline-size',
    890  // 'max-inline-size', 'min-block-size', and 'max-block-size' properties, and
    891  // stores them in the assorted data members
    892  void ComputeMinMaxValues(const LogicalSize& aCBSize);
    893 
    894  // aInsideBoxSizing returns the part of the padding, border, and margin
    895  // in the aAxis dimension that goes inside the edge given by box-sizing;
    896  // aOutsideBoxSizing returns the rest.
    897  void CalculateBorderPaddingMargin(LogicalAxis aAxis,
    898                                    nscoord aContainingBlockSize,
    899                                    nscoord* aInsideBoxSizing,
    900                                    nscoord* aOutsideBoxSizing) const;
    901 
    902  void CalculateBlockSideMargins();
    903 
    904  /**
    905   * @return true if mFrame is an internal table frame, i.e. an
    906   * ns[RowGroup|ColGroup|Row|Cell]Frame.  (We exclude nsTableColFrame
    907   * here since we never setup a ReflowInput for those.)
    908   */
    909  bool IsInternalTableFrame() const;
    910 
    911 private:
    912  // The available size in which to reflow the frame. The space represents the
    913  // amount of room for the frame's margin, border, padding, and content area.
    914  //
    915  // The available inline-size should be constrained. The frame's inline-size
    916  // you choose should fit within it.
    917 
    918  // In galley mode, the available block-size is always unconstrained, and only
    919  // page mode or multi-column layout involves a constrained available
    920  // block-size.
    921  //
    922  // An unconstrained available block-size means you can choose whatever size
    923  // you want. If the value is constrained, the frame's block-start border,
    924  // padding, and content, must fit. If a frame is fully-complete after reflow,
    925  // then its block-end border, padding, and margin (and similar for its
    926  // fully-complete ancestors) will need to fit within this available
    927  // block-size. However, if a frame is monolithic, it may choose a block-size
    928  // larger than the available block-size.
    929  LogicalSize mAvailableSize{mWritingMode};
    930 
    931  // The computed size specifies the frame's content area, and it does not apply
    932  // to inline non-replaced elements.
    933  //
    934  // For block-level frames, the computed inline-size is based on the
    935  // inline-size of the containing block, the margin/border/padding areas, and
    936  // the min/max inline-size.
    937  //
    938  // For non-replaced block-level frames in the flow and floated, if the
    939  // computed block-size is NS_UNCONSTRAINEDSIZE, you should choose a block-size
    940  // to shrink wrap around the normal flow child frames. The block-size must be
    941  // within the limit of the min/max block-size if there is such a limit.
    942  LogicalSize mComputedSize{mWritingMode};
    943 
    944  // Computed values for 'inset' properties. Only applies to 'positioned'
    945  // elements.
    946  LogicalMargin mComputedOffsets{mWritingMode};
    947 
    948  // Computed value for 'min-inline-size'/'min-block-size'.
    949  LogicalSize mComputedMinSize{mWritingMode};
    950 
    951  // Computed value for 'max-inline-size'/'max-block-size'.
    952  LogicalSize mComputedMaxSize{mWritingMode, NS_UNCONSTRAINEDSIZE,
    953                               NS_UNCONSTRAINEDSIZE};
    954 
    955  // Percentage basis in the block axis for the purpose of percentage resolution
    956  // on children.
    957  //
    958  // This will be ignored when mTreatBSizeAsIndefinite flag is true, or when a
    959  // customized containing block size is provided via ReflowInput's constructor
    960  // or Init(). When this percentage basis exists, it will be used to replace
    961  // the containing block's ComputedBSize() in
    962  // ComputeContainingBlockRectangle().
    963  //
    964  // This is currently used in a special scenario where we treat certain
    965  // sized-to-content flex items as having an 'auto' block-size for their final
    966  // reflow to accomodate fragmentation-imposed block-size growth. This sort of
    967  // flex item does nonetheless have a known block-size (from the flex layout
    968  // algorithm) that it needs to use as a definite percentage-basis for its
    969  // children during its final reflow; and we represent that here.
    970  Maybe<nscoord> mPercentageBasisInBlockAxis;
    971 
    972  // Cache the used line-height property.
    973  mutable nscoord mLineHeight = NS_UNCONSTRAINEDSIZE;
    974 };
    975 
    976 }  // namespace mozilla
    977 
    978 #endif  // mozilla_ReflowInput_h