LCOV - code coverage report
Current view: top level - layout/generic - nsFlexContainerFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1565 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 172 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=2 et sw=2 tw=80: */
       3             : 
       4             : /* This Source Code is subject to the terms of the Mozilla Public License
       5             :  * version 2.0 (the "License"). You can obtain a copy of the License at
       6             :  * http://mozilla.org/MPL/2.0/. */
       7             : 
       8             : /* rendering object for CSS "display: flex" */
       9             : 
      10             : #include "nsFlexContainerFrame.h"
      11             : #include "nsContentUtils.h"
      12             : #include "nsCSSAnonBoxes.h"
      13             : #include "nsDisplayList.h"
      14             : #include "nsIFrameInlines.h"
      15             : #include "nsLayoutUtils.h"
      16             : #include "nsPlaceholderFrame.h"
      17             : #include "nsPresContext.h"
      18             : #include "nsStyleContext.h"
      19             : #include "mozilla/CSSOrderAwareFrameIterator.h"
      20             : #include "mozilla/Logging.h"
      21             : #include <algorithm>
      22             : #include "gfxContext.h"
      23             : #include "mozilla/LinkedList.h"
      24             : #include "mozilla/FloatingPoint.h"
      25             : #include "mozilla/UniquePtr.h"
      26             : #include "WritingModes.h"
      27             : 
      28             : using namespace mozilla;
      29             : using namespace mozilla::layout;
      30             : 
      31             : // Convenience typedefs for helper classes that we forward-declare in .h file
      32             : // (so that nsFlexContainerFrame methods can use them as parameters):
      33             : typedef nsFlexContainerFrame::FlexItem FlexItem;
      34             : typedef nsFlexContainerFrame::FlexLine FlexLine;
      35             : typedef nsFlexContainerFrame::FlexboxAxisTracker FlexboxAxisTracker;
      36             : typedef nsFlexContainerFrame::StrutInfo StrutInfo;
      37             : typedef nsFlexContainerFrame::CachedMeasuringReflowResult
      38             :           CachedMeasuringReflowResult;
      39             : 
      40             : static mozilla::LazyLogModule gFlexContainerLog("nsFlexContainerFrame");
      41             : 
      42             : // XXXdholbert Some of this helper-stuff should be separated out into a general
      43             : // "main/cross-axis utils" header, shared by grid & flexbox?
      44             : // (Particularly when grid gets support for align-*/justify-* properties.)
      45             : 
      46             : // Helper enums
      47             : // ============
      48             : 
      49             : // Represents a physical orientation for an axis.
      50             : // The directional suffix indicates the direction in which the axis *grows*.
      51             : // So e.g. eAxis_LR means a horizontal left-to-right axis, whereas eAxis_BT
      52             : // means a vertical bottom-to-top axis.
      53             : // NOTE: The order here is important -- these values are used as indices into
      54             : // the static array 'kAxisOrientationToSidesMap', defined below.
      55             : enum AxisOrientationType {
      56             :   eAxis_LR,
      57             :   eAxis_RL,
      58             :   eAxis_TB,
      59             :   eAxis_BT,
      60             :   eNumAxisOrientationTypes // For sizing arrays that use these values as indices
      61             : };
      62             : 
      63             : // Represents one or the other extreme of an axis (e.g. for the main axis, the
      64             : // main-start vs. main-end edge.
      65             : // NOTE: The order here is important -- these values are used as indices into
      66             : // the sub-arrays in 'kAxisOrientationToSidesMap', defined below.
      67             : enum AxisEdgeType {
      68             :   eAxisEdge_Start,
      69             :   eAxisEdge_End,
      70             :   eNumAxisEdges // For sizing arrays that use these values as indices
      71             : };
      72             : 
      73             : // This array maps each axis orientation to a pair of corresponding
      74             : // [start, end] physical mozilla::Side values.
      75             : static const mozilla::Side
      76             : kAxisOrientationToSidesMap[eNumAxisOrientationTypes][eNumAxisEdges] = {
      77             :   { eSideLeft,   eSideRight  },  // eAxis_LR
      78             :   { eSideRight,  eSideLeft   },  // eAxis_RL
      79             :   { eSideTop,    eSideBottom },  // eAxis_TB
      80             :   { eSideBottom, eSideTop }      // eAxis_BT
      81             : };
      82             : 
      83             : // Helper structs / classes / methods
      84             : // ==================================
      85             : // Returns true iff the given nsStyleDisplay has display:-webkit-{inline-}-box.
      86             : static inline bool
      87           0 : IsDisplayValueLegacyBox(const nsStyleDisplay* aStyleDisp)
      88             : {
      89           0 :   return aStyleDisp->mDisplay == mozilla::StyleDisplay::WebkitBox ||
      90           0 :     aStyleDisp->mDisplay == mozilla::StyleDisplay::WebkitInlineBox;
      91             : }
      92             : 
      93             : // Returns true if aFlexContainer is the frame for an element with
      94             : // "display:-webkit-box" or "display:-webkit-inline-box". aFlexContainer is
      95             : // expected to be an instance of nsFlexContainerFrame (enforced with an assert);
      96             : // otherwise, this function's state-bit-check here is bogus.
      97             : static bool
      98           0 : IsLegacyBox(const nsIFrame* aFlexContainer)
      99             : {
     100           0 :   MOZ_ASSERT(aFlexContainer->IsFlexContainerFrame(),
     101             :              "only flex containers may be passed to this function");
     102           0 :   return aFlexContainer->HasAnyStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX);
     103             : }
     104             : 
     105             : // Returns the OrderingProperty enum that we should pass to
     106             : // CSSOrderAwareFrameIterator (depending on whether it's a legacy box).
     107             : static CSSOrderAwareFrameIterator::OrderingProperty
     108           0 : OrderingPropertyForIter(const nsFlexContainerFrame* aFlexContainer)
     109             : {
     110           0 :   return IsLegacyBox(aFlexContainer)
     111           0 :     ? CSSOrderAwareFrameIterator::OrderingProperty::eUseBoxOrdinalGroup
     112           0 :     : CSSOrderAwareFrameIterator::OrderingProperty::eUseOrder;
     113             : }
     114             : 
     115             : // Returns the "align-items" value that's equivalent to the legacy "box-align"
     116             : // value in the given style struct.
     117             : static uint8_t
     118           0 : ConvertLegacyStyleToAlignItems(const nsStyleXUL* aStyleXUL)
     119             : {
     120             :   // -[moz|webkit]-box-align corresponds to modern "align-items"
     121           0 :   switch (aStyleXUL->mBoxAlign) {
     122             :     case StyleBoxAlign::Stretch:
     123           0 :       return NS_STYLE_ALIGN_STRETCH;
     124             :     case StyleBoxAlign::Start:
     125           0 :       return NS_STYLE_ALIGN_FLEX_START;
     126             :     case StyleBoxAlign::Center:
     127           0 :       return NS_STYLE_ALIGN_CENTER;
     128             :     case StyleBoxAlign::Baseline:
     129           0 :       return NS_STYLE_ALIGN_BASELINE;
     130             :     case StyleBoxAlign::End:
     131           0 :       return NS_STYLE_ALIGN_FLEX_END;
     132             :   }
     133             : 
     134           0 :   MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxAlign enum value");
     135             :   // Fall back to default value of "align-items" property:
     136             :   return NS_STYLE_ALIGN_STRETCH;
     137             : }
     138             : 
     139             : // Returns the "justify-content" value that's equivalent to the legacy
     140             : // "box-pack" value in the given style struct.
     141             : static uint8_t
     142           0 : ConvertLegacyStyleToJustifyContent(const nsStyleXUL* aStyleXUL)
     143             : {
     144             :   // -[moz|webkit]-box-pack corresponds to modern "justify-content"
     145           0 :   switch (aStyleXUL->mBoxPack) {
     146             :     case StyleBoxPack::Start:
     147           0 :       return NS_STYLE_ALIGN_FLEX_START;
     148             :     case StyleBoxPack::Center:
     149           0 :       return NS_STYLE_ALIGN_CENTER;
     150             :     case StyleBoxPack::End:
     151           0 :       return NS_STYLE_ALIGN_FLEX_END;
     152             :     case StyleBoxPack::Justify:
     153           0 :       return NS_STYLE_ALIGN_SPACE_BETWEEN;
     154             :   }
     155             : 
     156           0 :   MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxPack enum value");
     157             :   // Fall back to default value of "justify-content" property:
     158             :   return NS_STYLE_ALIGN_FLEX_START;
     159             : }
     160             : 
     161             : // Indicates whether advancing along the given axis is equivalent to
     162             : // increasing our X or Y position (as opposed to decreasing it).
     163             : static inline bool
     164           0 : AxisGrowsInPositiveDirection(AxisOrientationType aAxis)
     165             : {
     166           0 :   return eAxis_LR == aAxis || eAxis_TB == aAxis;
     167             : }
     168             : 
     169             : // Given an AxisOrientationType, returns the "reverse" AxisOrientationType
     170             : // (in the same dimension, but the opposite direction)
     171             : static inline AxisOrientationType
     172           0 : GetReverseAxis(AxisOrientationType aAxis)
     173             : {
     174             :   AxisOrientationType reversedAxis;
     175             : 
     176           0 :   if (aAxis % 2 == 0) {
     177             :     // even enum value. Add 1 to reverse.
     178           0 :     reversedAxis = AxisOrientationType(aAxis + 1);
     179             :   } else {
     180             :     // odd enum value. Subtract 1 to reverse.
     181           0 :     reversedAxis = AxisOrientationType(aAxis - 1);
     182             :   }
     183             : 
     184             :   // Check that we're still in the enum's valid range
     185           0 :   MOZ_ASSERT(reversedAxis >= eAxis_LR &&
     186             :              reversedAxis <= eAxis_BT);
     187             : 
     188           0 :   return reversedAxis;
     189             : }
     190             : 
     191             : /**
     192             :  * Converts a "flex-relative" coordinate in a single axis (a main- or cross-axis
     193             :  * coordinate) into a coordinate in the corresponding physical (x or y) axis. If
     194             :  * the flex-relative axis in question already maps *directly* to a physical
     195             :  * axis (i.e. if it's LTR or TTB), then the physical coordinate has the same
     196             :  * numeric value as the provided flex-relative coordinate. Otherwise, we have to
     197             :  * subtract the flex-relative coordinate from the flex container's size in that
     198             :  * axis, to flip the polarity. (So e.g. a main-axis position of 2px in a RTL
     199             :  * 20px-wide container would correspond to a physical coordinate (x-value) of
     200             :  * 18px.)
     201             :  */
     202             : static nscoord
     203           0 : PhysicalCoordFromFlexRelativeCoord(nscoord aFlexRelativeCoord,
     204             :                                    nscoord aContainerSize,
     205             :                                    AxisOrientationType aAxis) {
     206           0 :   if (AxisGrowsInPositiveDirection(aAxis)) {
     207           0 :     return aFlexRelativeCoord;
     208             :   }
     209           0 :   return aContainerSize - aFlexRelativeCoord;
     210             : }
     211             : 
     212             : // Helper-macro to let us pick one of two expressions to evaluate
     213             : // (a width expression vs. a height expression), to get a main-axis or
     214             : // cross-axis component.
     215             : // For code that has e.g. a nsSize object, FlexboxAxisTracker::GetMainComponent
     216             : // and GetCrossComponent are cleaner; but in cases where we simply have
     217             : // two separate expressions for width and height (which may be expensive to
     218             : // evaluate), these macros will ensure that only the expression for the correct
     219             : // axis gets evaluated.
     220             : #define GET_MAIN_COMPONENT(axisTracker_, width_, height_)  \
     221             :   (axisTracker_).IsMainAxisHorizontal() ? (width_) : (height_)
     222             : 
     223             : #define GET_CROSS_COMPONENT(axisTracker_, width_, height_)  \
     224             :   (axisTracker_).IsCrossAxisHorizontal() ? (width_) : (height_)
     225             : 
     226             : // Logical versions of helper-macros above:
     227             : #define GET_MAIN_COMPONENT_LOGICAL(axisTracker_, wm_, isize_, bsize_)  \
     228             :   wm_.IsOrthogonalTo(axisTracker_.GetWritingMode()) != \
     229             :     (axisTracker_).IsRowOriented() ? (isize_) : (bsize_)
     230             : 
     231             : #define GET_CROSS_COMPONENT_LOGICAL(axisTracker_, wm_, isize_, bsize_)  \
     232             :   wm_.IsOrthogonalTo(axisTracker_.GetWritingMode()) != \
     233             :     (axisTracker_).IsRowOriented() ? (bsize_) : (isize_)
     234             : 
     235             : // Flags to customize behavior of the FlexboxAxisTracker constructor:
     236             : enum AxisTrackerFlags {
     237             :   eNoFlags = 0x0,
     238             : 
     239             :   // Normally, FlexboxAxisTracker may attempt to reverse axes & iteration order
     240             :   // to avoid bottom-to-top child ordering, for saner pagination. This flag
     241             :   // suppresses that behavior (so that we allow bottom-to-top child ordering).
     242             :   // (This may be helpful e.g. when we're only dealing with a single child.)
     243             :   eAllowBottomToTopChildOrdering = 0x1
     244             : };
     245           0 : MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AxisTrackerFlags)
     246             : 
     247             : // Encapsulates our flex container's main & cross axes.
     248             : class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker {
     249             : public:
     250             :   FlexboxAxisTracker(const nsFlexContainerFrame* aFlexContainer,
     251             :                      const WritingMode& aWM,
     252             :                      AxisTrackerFlags aFlags = eNoFlags);
     253             : 
     254             :   // Accessors:
     255             :   // XXXdholbert [BEGIN DEPRECATED]
     256           0 :   AxisOrientationType GetMainAxis() const  { return mMainAxis;  }
     257           0 :   AxisOrientationType GetCrossAxis() const { return mCrossAxis; }
     258             : 
     259           0 :   bool IsMainAxisHorizontal() const {
     260             :     // If we're row-oriented, and our writing mode is NOT vertical,
     261             :     // or we're column-oriented and our writing mode IS vertical,
     262             :     // then our main axis is horizontal. This handles all cases:
     263           0 :     return mIsRowOriented != mWM.IsVertical();
     264             :   }
     265           0 :   bool IsCrossAxisHorizontal() const {
     266           0 :     return !IsMainAxisHorizontal();
     267             :   }
     268             :   // XXXdholbert [END DEPRECATED]
     269             : 
     270             :   // Returns the flex container's writing mode.
     271           0 :   WritingMode GetWritingMode() const { return mWM; }
     272             : 
     273             :   // Returns true if our main axis is in the reverse direction of our
     274             :   // writing mode's corresponding axis. (From 'flex-direction: *-reverse')
     275           0 :   bool IsMainAxisReversed() const {
     276           0 :     return mIsMainAxisReversed;
     277             :   }
     278             :   // Returns true if our cross axis is in the reverse direction of our
     279             :   // writing mode's corresponding axis. (From 'flex-wrap: *-reverse')
     280           0 :   bool IsCrossAxisReversed() const {
     281           0 :     return mIsCrossAxisReversed;
     282             :   }
     283             : 
     284           0 :   bool IsRowOriented() const { return mIsRowOriented; }
     285           0 :   bool IsColumnOriented() const { return !mIsRowOriented; }
     286             : 
     287             :   nscoord GetMainComponent(const nsSize& aSize) const {
     288             :     return GET_MAIN_COMPONENT(*this, aSize.width, aSize.height);
     289             :   }
     290           0 :   int32_t GetMainComponent(const LayoutDeviceIntSize& aIntSize) const {
     291           0 :     return GET_MAIN_COMPONENT(*this, aIntSize.width, aIntSize.height);
     292             :   }
     293             : 
     294           0 :   nscoord GetCrossComponent(const nsSize& aSize) const {
     295           0 :     return GET_CROSS_COMPONENT(*this, aSize.width, aSize.height);
     296             :   }
     297           0 :   int32_t GetCrossComponent(const LayoutDeviceIntSize& aIntSize) const {
     298           0 :     return GET_CROSS_COMPONENT(*this, aIntSize.width, aIntSize.height);
     299             :   }
     300             : 
     301           0 :   nscoord GetMarginSizeInMainAxis(const nsMargin& aMargin) const {
     302           0 :     return IsMainAxisHorizontal() ?
     303           0 :       aMargin.LeftRight() :
     304           0 :       aMargin.TopBottom();
     305             :   }
     306           0 :   nscoord GetMarginSizeInCrossAxis(const nsMargin& aMargin) const {
     307           0 :     return IsCrossAxisHorizontal() ?
     308           0 :       aMargin.LeftRight() :
     309           0 :       aMargin.TopBottom();
     310             :   }
     311             : 
     312             :   // Returns aFrame's computed value for 'height' or 'width' -- whichever is in
     313             :   // the cross-axis. (NOTE: This is cross-axis-specific for now. If we need a
     314             :   // main-axis version as well, we could generalize or clone this function.)
     315           0 :   const nsStyleCoord& ComputedCrossSize(const nsIFrame* aFrame) const {
     316           0 :     const nsStylePosition* stylePos = aFrame->StylePosition();
     317             : 
     318           0 :     return IsCrossAxisHorizontal() ?
     319             :       stylePos->mWidth :
     320           0 :       stylePos->mHeight;
     321             :   }
     322             : 
     323             :   /**
     324             :    * Converts a "flex-relative" point (a main-axis & cross-axis coordinate)
     325             :    * into a LogicalPoint, using the flex container's writing mode.
     326             :    *
     327             :    *  @arg aMainCoord  The main-axis coordinate -- i.e an offset from the
     328             :    *                   main-start edge of the flex container's content box.
     329             :    *  @arg aCrossCoord The cross-axis coordinate -- i.e an offset from the
     330             :    *                   cross-start edge of the flex container's content box.
     331             :    *  @arg aContainerMainSize  The main size of flex container's content box.
     332             :    *  @arg aContainerCrossSize The cross size of flex container's content box.
     333             :    *  @return A LogicalPoint, with the flex container's writing mode, that
     334             :    *          represents the same position. The logical coordinates are
     335             :    *          relative to the flex container's content box.
     336             :    */
     337             :   LogicalPoint
     338           0 :   LogicalPointFromFlexRelativePoint(nscoord aMainCoord,
     339             :                                     nscoord aCrossCoord,
     340             :                                     nscoord aContainerMainSize,
     341             :                                     nscoord aContainerCrossSize) const {
     342           0 :     nscoord logicalCoordInMainAxis = mIsMainAxisReversed ?
     343           0 :       aContainerMainSize - aMainCoord : aMainCoord;
     344           0 :     nscoord logicalCoordInCrossAxis = mIsCrossAxisReversed ?
     345           0 :       aContainerCrossSize - aCrossCoord : aCrossCoord;
     346             : 
     347           0 :     return mIsRowOriented ?
     348             :       LogicalPoint(mWM, logicalCoordInMainAxis, logicalCoordInCrossAxis) :
     349           0 :       LogicalPoint(mWM, logicalCoordInCrossAxis, logicalCoordInMainAxis);
     350             :   }
     351             : 
     352             :   /**
     353             :    * Converts a "flex-relative" size (a main-axis & cross-axis size)
     354             :    * into a LogicalSize, using the flex container's writing mode.
     355             :    *
     356             :    *  @arg aMainSize  The main-axis size.
     357             :    *  @arg aCrossSize The cross-axis size.
     358             :    *  @return A LogicalSize, with the flex container's writing mode, that
     359             :    *          represents the same size.
     360             :    */
     361           0 :   LogicalSize LogicalSizeFromFlexRelativeSizes(nscoord aMainSize,
     362             :                                                nscoord aCrossSize) const {
     363           0 :     return mIsRowOriented ?
     364             :       LogicalSize(mWM, aMainSize, aCrossSize) :
     365           0 :       LogicalSize(mWM, aCrossSize, aMainSize);
     366             :   }
     367             : 
     368             :   // Are my axes reversed with respect to what the author asked for?
     369             :   // (We may reverse the axes in the FlexboxAxisTracker constructor and set
     370             :   // this flag, to avoid reflowing our children in bottom-to-top order.)
     371           0 :   bool AreAxesInternallyReversed() const
     372             :   {
     373           0 :     return mAreAxesInternallyReversed;
     374             :   }
     375             : 
     376             : private:
     377             :   // Delete copy-constructor & reassignment operator, to prevent accidental
     378             :   // (unnecessary) copying.
     379             :   FlexboxAxisTracker(const FlexboxAxisTracker&) = delete;
     380             :   FlexboxAxisTracker& operator=(const FlexboxAxisTracker&) = delete;
     381             : 
     382             :   // Helpers for constructor which determine the orientation of our axes, based
     383             :   // on legacy box properties (-webkit-box-orient, -webkit-box-direction) or
     384             :   // modern flexbox properties (flex-direction, flex-wrap) depending on whether
     385             :   // the flex container is a "legacy box" (as determined by IsLegacyBox).
     386             :   void InitAxesFromLegacyProps(const nsFlexContainerFrame* aFlexContainer);
     387             :   void InitAxesFromModernProps(const nsFlexContainerFrame* aFlexContainer);
     388             : 
     389             :   // XXXdholbert [BEGIN DEPRECATED]
     390             :   AxisOrientationType mMainAxis;
     391             :   AxisOrientationType mCrossAxis;
     392             :   // XXXdholbert [END DEPRECATED]
     393             : 
     394             :   const WritingMode mWM; // The flex container's writing mode.
     395             : 
     396             :   bool mIsRowOriented; // Is our main axis the inline axis?
     397             :                        // (Are we 'flex-direction:row[-reverse]'?)
     398             : 
     399             :   bool mIsMainAxisReversed; // Is our main axis in the opposite direction
     400             :                             // as mWM's corresponding axis? (e.g. RTL vs LTR)
     401             :   bool mIsCrossAxisReversed; // Is our cross axis in the opposite direction
     402             :                              // as mWM's corresponding axis? (e.g. BTT vs TTB)
     403             : 
     404             :   // Implementation detail -- this indicates whether we've decided to
     405             :   // transparently reverse our axes & our child ordering, to avoid having
     406             :   // frames flow from bottom to top in either axis (& to make pagination saner).
     407             :   bool mAreAxesInternallyReversed;
     408             : };
     409             : 
     410             : /**
     411             :  * Represents a flex item.
     412             :  * Includes the various pieces of input that the Flexbox Layout Algorithm uses
     413             :  * to resolve a flexible width.
     414             :  */
     415           0 : class nsFlexContainerFrame::FlexItem : public LinkedListElement<FlexItem>
     416             : {
     417             : public:
     418             :   // Normal constructor:
     419             :   FlexItem(ReflowInput& aFlexItemReflowInput,
     420             :            float aFlexGrow, float aFlexShrink, nscoord aMainBaseSize,
     421             :            nscoord aMainMinSize, nscoord aMainMaxSize,
     422             :            nscoord aTentativeCrossSize,
     423             :            nscoord aCrossMinSize, nscoord aCrossMaxSize,
     424             :            const FlexboxAxisTracker& aAxisTracker);
     425             : 
     426             :   // Simplified constructor, to be used only for generating "struts":
     427             :   // (NOTE: This "strut" constructor uses the *container's* writing mode, which
     428             :   // we'll use on this FlexItem instead of the child frame's real writing mode.
     429             :   // This is fine - it doesn't matter what writing mode we use for a
     430             :   // strut, since it won't render any content and we already know its size.)
     431             :   FlexItem(nsIFrame* aChildFrame, nscoord aCrossSize, WritingMode aContainerWM);
     432             : 
     433             :   // Accessors
     434           0 :   nsIFrame* Frame() const          { return mFrame; }
     435           0 :   nscoord GetFlexBaseSize() const  { return mFlexBaseSize; }
     436             : 
     437           0 :   nscoord GetMainMinSize() const   {
     438           0 :     MOZ_ASSERT(!mNeedsMinSizeAutoResolution,
     439             :                "Someone's using an unresolved 'auto' main min-size");
     440           0 :     return mMainMinSize;
     441             :   }
     442           0 :   nscoord GetMainMaxSize() const   { return mMainMaxSize; }
     443             : 
     444             :   // Note: These return the main-axis position and size of our *content box*.
     445           0 :   nscoord GetMainSize() const      { return mMainSize; }
     446           0 :   nscoord GetMainPosition() const  { return mMainPosn; }
     447             : 
     448             :   nscoord GetCrossMinSize() const  { return mCrossMinSize; }
     449             :   nscoord GetCrossMaxSize() const  { return mCrossMaxSize; }
     450             : 
     451             :   // Note: These return the cross-axis position and size of our *content box*.
     452           0 :   nscoord GetCrossSize() const     { return mCrossSize;  }
     453           0 :   nscoord GetCrossPosition() const { return mCrossPosn; }
     454             : 
     455           0 :   nscoord ResolvedAscent(bool aUseFirstBaseline) const {
     456           0 :     if (mAscent == ReflowOutput::ASK_FOR_BASELINE) {
     457             :       // XXXdholbert We should probably be using the *container's* writing-mode
     458             :       // here, instead of the item's -- though it doesn't much matter right
     459             :       // now, because all of the baseline-handling code here essentially
     460             :       // assumes that the container & items have the same writing-mode. This
     461             :       // will matter more (& can be expanded/tested) once we officially support
     462             :       // logical directions & vertical writing-modes in flexbox, in bug 1079155
     463             :       // or a dependency.
     464             :       // Use GetFirstLineBaseline() or GetLastLineBaseline() as appropriate,
     465             :       // or just GetLogicalBaseline() if that fails.
     466           0 :       bool found = aUseFirstBaseline ?
     467           0 :         nsLayoutUtils::GetFirstLineBaseline(mWM, mFrame, &mAscent) :
     468           0 :         nsLayoutUtils::GetLastLineBaseline(mWM, mFrame, &mAscent);
     469             : 
     470           0 :       if (!found) {
     471           0 :         mAscent = mFrame->SynthesizeBaselineBOffsetFromBorderBox(mWM,
     472             :                             BaselineSharingGroup::eFirst);
     473             :       }
     474             :     }
     475           0 :     return mAscent;
     476             :   }
     477             : 
     478             :   // Convenience methods to compute the main & cross size of our *margin-box*.
     479             :   // The caller is responsible for telling us the right axis, so that we can
     480             :   // pull out the appropriate components of our margin/border/padding structs.
     481           0 :   nscoord GetOuterMainSize(AxisOrientationType aMainAxis) const
     482             :   {
     483           0 :     return mMainSize + GetMarginBorderPaddingSizeInAxis(aMainAxis);
     484             :   }
     485             : 
     486           0 :   nscoord GetOuterCrossSize(AxisOrientationType aCrossAxis) const
     487             :   {
     488           0 :     return mCrossSize + GetMarginBorderPaddingSizeInAxis(aCrossAxis);
     489             :   }
     490             : 
     491             :   // Returns the distance between this FlexItem's baseline and the cross-start
     492             :   // edge of its margin-box. Used in baseline alignment.
     493             :   // (This function needs to be told which edge we're measuring the baseline
     494             :   // from, so that it can look up the appropriate components from mMargin.)
     495             :   nscoord GetBaselineOffsetFromOuterCrossEdge(
     496             :     AxisEdgeType aEdge,
     497             :     const FlexboxAxisTracker& aAxisTracker,
     498             :     bool aUseFirstLineBaseline) const;
     499             : 
     500           0 :   float GetShareOfWeightSoFar() const { return mShareOfWeightSoFar; }
     501             : 
     502           0 :   bool IsFrozen() const            { return mIsFrozen; }
     503             : 
     504           0 :   bool HadMinViolation() const     { return mHadMinViolation; }
     505           0 :   bool HadMaxViolation() const     { return mHadMaxViolation; }
     506             : 
     507             :   // Indicates whether this item received a preliminary "measuring" reflow
     508             :   // before its actual reflow.
     509           0 :   bool HadMeasuringReflow() const  { return mHadMeasuringReflow; }
     510             : 
     511             :   // Indicates whether this item's cross-size has been stretched (from having
     512             :   // "align-self: stretch" with an auto cross-size and no auto margins in the
     513             :   // cross axis).
     514           0 :   bool IsStretched() const         { return mIsStretched; }
     515             : 
     516             :   // Indicates whether we need to resolve an 'auto' value for the main-axis
     517             :   // min-[width|height] property.
     518           0 :   bool NeedsMinSizeAutoResolution() const
     519           0 :     { return mNeedsMinSizeAutoResolution; }
     520             : 
     521             :   // Indicates whether this item is a "strut" left behind by an element with
     522             :   // visibility:collapse.
     523             :   bool IsStrut() const             { return mIsStrut; }
     524             : 
     525           0 :   WritingMode GetWritingMode() const { return mWM; }
     526           0 :   uint8_t GetAlignSelf() const     { return mAlignSelf; }
     527             : 
     528             :   // Returns the flex factor (flex-grow or flex-shrink), depending on
     529             :   // 'aIsUsingFlexGrow'.
     530             :   //
     531             :   // Asserts fatally if called on a frozen item (since frozen items are not
     532             :   // flexible).
     533           0 :   float GetFlexFactor(bool aIsUsingFlexGrow)
     534             :   {
     535           0 :     MOZ_ASSERT(!IsFrozen(), "shouldn't need flex factor after item is frozen");
     536             : 
     537           0 :     return aIsUsingFlexGrow ? mFlexGrow : mFlexShrink;
     538             :   }
     539             : 
     540             :   // Returns the weight that we should use in the "resolving flexible lengths"
     541             :   // algorithm.  If we're using the flex grow factor, we just return that;
     542             :   // otherwise, we return the "scaled flex shrink factor" (scaled by our flex
     543             :   // base size, so that when both large and small items are shrinking, the large
     544             :   // items shrink more).
     545             :   //
     546             :   // I'm calling this a "weight" instead of a "[scaled] flex-[grow|shrink]
     547             :   // factor", to more clearly distinguish it from the actual flex-grow &
     548             :   // flex-shrink factors.
     549             :   //
     550             :   // Asserts fatally if called on a frozen item (since frozen items are not
     551             :   // flexible).
     552           0 :   float GetWeight(bool aIsUsingFlexGrow)
     553             :   {
     554           0 :     MOZ_ASSERT(!IsFrozen(), "shouldn't need weight after item is frozen");
     555             : 
     556           0 :     if (aIsUsingFlexGrow) {
     557           0 :       return mFlexGrow;
     558             :     }
     559             : 
     560             :     // We're using flex-shrink --> return mFlexShrink * mFlexBaseSize
     561           0 :     if (mFlexBaseSize == 0) {
     562             :       // Special-case for mFlexBaseSize == 0 -- we have no room to shrink, so
     563             :       // regardless of mFlexShrink, we should just return 0.
     564             :       // (This is really a special-case for when mFlexShrink is infinity, to
     565             :       // avoid performing mFlexShrink * mFlexBaseSize = inf * 0 = undefined.)
     566           0 :       return 0.0f;
     567             :     }
     568           0 :     return mFlexShrink * mFlexBaseSize;
     569             :   }
     570             : 
     571           0 :   const nsSize& IntrinsicRatio() const { return mIntrinsicRatio; }
     572           0 :   bool HasIntrinsicRatio() const { return mIntrinsicRatio != nsSize(); }
     573             : 
     574             :   // Getters for margin:
     575             :   // ===================
     576           0 :   const nsMargin& GetMargin() const { return mMargin; }
     577             : 
     578             :   // Returns the margin component for a given mozilla::Side
     579           0 :   nscoord GetMarginComponentForSide(mozilla::Side aSide) const
     580           0 :   { return mMargin.Side(aSide); }
     581             : 
     582             :   // Returns the total space occupied by this item's margins in the given axis
     583           0 :   nscoord GetMarginSizeInAxis(AxisOrientationType aAxis) const
     584             :   {
     585           0 :     mozilla::Side startSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_Start];
     586           0 :     mozilla::Side endSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_End];
     587           0 :     return GetMarginComponentForSide(startSide) +
     588           0 :       GetMarginComponentForSide(endSide);
     589             :   }
     590             : 
     591             :   // Getters for border/padding
     592             :   // ==========================
     593           0 :   const nsMargin& GetBorderPadding() const { return mBorderPadding; }
     594             : 
     595             :   // Returns the border+padding component for a given mozilla::Side
     596           0 :   nscoord GetBorderPaddingComponentForSide(mozilla::Side aSide) const
     597           0 :   { return mBorderPadding.Side(aSide); }
     598             : 
     599             :   // Returns the total space occupied by this item's borders and padding in
     600             :   // the given axis
     601           0 :   nscoord GetBorderPaddingSizeInAxis(AxisOrientationType aAxis) const
     602             :   {
     603           0 :     mozilla::Side startSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_Start];
     604           0 :     mozilla::Side endSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_End];
     605           0 :     return GetBorderPaddingComponentForSide(startSide) +
     606           0 :       GetBorderPaddingComponentForSide(endSide);
     607             :   }
     608             : 
     609             :   // Getter for combined margin/border/padding
     610             :   // =========================================
     611             :   // Returns the total space occupied by this item's margins, borders and
     612             :   // padding in the given axis
     613           0 :   nscoord GetMarginBorderPaddingSizeInAxis(AxisOrientationType aAxis) const
     614             :   {
     615           0 :     return GetMarginSizeInAxis(aAxis) + GetBorderPaddingSizeInAxis(aAxis);
     616             :   }
     617             : 
     618             :   // Setters
     619             :   // =======
     620             :   // Helper to set the resolved value of min-[width|height]:auto for the main
     621             :   // axis. (Should only be used if NeedsMinSizeAutoResolution() returns true.)
     622           0 :   void UpdateMainMinSize(nscoord aNewMinSize)
     623             :   {
     624           0 :     NS_ASSERTION(aNewMinSize >= 0,
     625             :                  "How did we end up with a negative min-size?");
     626           0 :     MOZ_ASSERT(mMainMaxSize >= aNewMinSize,
     627             :                "Should only use this function for resolving min-size:auto, "
     628             :                "and main max-size should be an upper-bound for resolved val");
     629           0 :     MOZ_ASSERT(mNeedsMinSizeAutoResolution &&
     630             :                (mMainMinSize == 0 || mFrame->IsThemed(mFrame->StyleDisplay())),
     631             :                "Should only use this function for resolving min-size:auto, "
     632             :                "so we shouldn't already have a nonzero min-size established "
     633             :                "(unless it's a themed-widget-imposed minimum size)");
     634             : 
     635           0 :     if (aNewMinSize > mMainMinSize) {
     636           0 :       mMainMinSize = aNewMinSize;
     637             :       // Also clamp main-size to be >= new min-size:
     638           0 :       mMainSize = std::max(mMainSize, aNewMinSize);
     639             :     }
     640           0 :     mNeedsMinSizeAutoResolution = false;
     641           0 :   }
     642             : 
     643             :   // This sets our flex base size, and then sets our main size to the
     644             :   // resulting "hypothetical main size" (the base size clamped to our
     645             :   // main-axis [min,max] sizing constraints).
     646           0 :   void SetFlexBaseSizeAndMainSize(nscoord aNewFlexBaseSize)
     647             :   {
     648           0 :     MOZ_ASSERT(!mIsFrozen || mFlexBaseSize == NS_INTRINSICSIZE,
     649             :                "flex base size shouldn't change after we're frozen "
     650             :                "(unless we're just resolving an intrinsic size)");
     651           0 :     mFlexBaseSize = aNewFlexBaseSize;
     652             : 
     653             :     // Before we've resolved flexible lengths, we keep mMainSize set to
     654             :     // the 'hypothetical main size', which is the flex base size, clamped
     655             :     // to the [min,max] range:
     656           0 :     mMainSize = NS_CSS_MINMAX(mFlexBaseSize, mMainMinSize, mMainMaxSize);
     657           0 :   }
     658             : 
     659             :   // Setters used while we're resolving flexible lengths
     660             :   // ---------------------------------------------------
     661             : 
     662             :   // Sets the main-size of our flex item's content-box.
     663           0 :   void SetMainSize(nscoord aNewMainSize)
     664             :   {
     665           0 :     MOZ_ASSERT(!mIsFrozen, "main size shouldn't change after we're frozen");
     666           0 :     mMainSize = aNewMainSize;
     667           0 :   }
     668             : 
     669           0 :   void SetShareOfWeightSoFar(float aNewShare)
     670             :   {
     671           0 :     MOZ_ASSERT(!mIsFrozen || aNewShare == 0.0f,
     672             :                "shouldn't be giving this item any share of the weight "
     673             :                "after it's frozen");
     674           0 :     mShareOfWeightSoFar = aNewShare;
     675           0 :   }
     676             : 
     677           0 :   void Freeze() { mIsFrozen = true; }
     678             : 
     679           0 :   void SetHadMinViolation()
     680             :   {
     681           0 :     MOZ_ASSERT(!mIsFrozen,
     682             :                "shouldn't be changing main size & having violations "
     683             :                "after we're frozen");
     684           0 :     mHadMinViolation = true;
     685           0 :   }
     686           0 :   void SetHadMaxViolation()
     687             :   {
     688           0 :     MOZ_ASSERT(!mIsFrozen,
     689             :                "shouldn't be changing main size & having violations "
     690             :                "after we're frozen");
     691           0 :     mHadMaxViolation = true;
     692           0 :   }
     693           0 :   void ClearViolationFlags()
     694           0 :   { mHadMinViolation = mHadMaxViolation = false; }
     695             : 
     696             :   // Setters for values that are determined after we've resolved our main size
     697             :   // -------------------------------------------------------------------------
     698             : 
     699             :   // Sets the main-axis position of our flex item's content-box.
     700             :   // (This is the distance between the main-start edge of the flex container
     701             :   // and the main-start edge of the flex item's content-box.)
     702           0 :   void SetMainPosition(nscoord aPosn) {
     703           0 :     MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
     704           0 :     mMainPosn  = aPosn;
     705           0 :   }
     706             : 
     707             :   // Sets the cross-size of our flex item's content-box.
     708           0 :   void SetCrossSize(nscoord aCrossSize) {
     709           0 :     MOZ_ASSERT(!mIsStretched,
     710             :                "Cross size shouldn't be modified after it's been stretched");
     711           0 :     mCrossSize = aCrossSize;
     712           0 :   }
     713             : 
     714             :   // Sets the cross-axis position of our flex item's content-box.
     715             :   // (This is the distance between the cross-start edge of the flex container
     716             :   // and the cross-start edge of the flex item.)
     717           0 :   void SetCrossPosition(nscoord aPosn) {
     718           0 :     MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
     719           0 :     mCrossPosn = aPosn;
     720           0 :   }
     721             : 
     722             :   // After a FlexItem has had a reflow, this method can be used to cache its
     723             :   // (possibly-unresolved) ascent, in case it's needed later for
     724             :   // baseline-alignment or to establish the container's baseline.
     725             :   // (NOTE: This can be marked 'const' even though it's modifying mAscent,
     726             :   // because mAscent is mutable. It's nice for this to be 'const', because it
     727             :   // means our final reflow can iterate over const FlexItem pointers, and we
     728             :   // can be sure it's not modifying those FlexItems, except via this method.)
     729           0 :   void SetAscent(nscoord aAscent) const {
     730           0 :     mAscent = aAscent; // NOTE: this may be ASK_FOR_BASELINE
     731           0 :   }
     732             : 
     733           0 :   void SetHadMeasuringReflow() {
     734           0 :     mHadMeasuringReflow = true;
     735           0 :   }
     736             : 
     737             :   void SetIsStretched() {
     738             :     MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
     739             :     mIsStretched = true;
     740             :   }
     741             : 
     742             :   // Setter for margin components (for resolving "auto" margins)
     743           0 :   void SetMarginComponentForSide(mozilla::Side aSide, nscoord aLength)
     744             :   {
     745           0 :     MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
     746           0 :     mMargin.Side(aSide) = aLength;
     747           0 :   }
     748             : 
     749             :   void ResolveStretchedCrossSize(nscoord aLineCrossSize,
     750             :                                  const FlexboxAxisTracker& aAxisTracker);
     751             : 
     752             :   uint32_t GetNumAutoMarginsInAxis(AxisOrientationType aAxis) const;
     753             : 
     754             :   // Once the main size has been resolved, should we bother doing layout to
     755             :   // establish the cross size?
     756             :   bool CanMainSizeInfluenceCrossSize(const FlexboxAxisTracker& aAxisTracker) const;
     757             : 
     758             : protected:
     759             :   // Helper called by the constructor, to set mNeedsMinSizeAutoResolution:
     760             :   void CheckForMinSizeAuto(const ReflowInput& aFlexItemReflowInput,
     761             :                            const FlexboxAxisTracker& aAxisTracker);
     762             : 
     763             :   // Our frame:
     764             :   nsIFrame* const mFrame;
     765             : 
     766             :   // Values that we already know in constructor: (and are hence mostly 'const')
     767             :   const float mFlexGrow;
     768             :   const float mFlexShrink;
     769             : 
     770             :   const nsSize mIntrinsicRatio;
     771             : 
     772             :   const nsMargin mBorderPadding;
     773             :   nsMargin mMargin; // non-const because we need to resolve auto margins
     774             : 
     775             :   // These are non-const so that we can lazily update them with the item's
     776             :   // intrinsic size (obtained via a "measuring" reflow), when necessary.
     777             :   // (e.g. for "flex-basis:auto;height:auto" & "min-height:auto")
     778             :   nscoord mFlexBaseSize;
     779             :   nscoord mMainMinSize;
     780             :   nscoord mMainMaxSize;
     781             : 
     782             :   const nscoord mCrossMinSize;
     783             :   const nscoord mCrossMaxSize;
     784             : 
     785             :   // Values that we compute after constructor:
     786             :   nscoord mMainSize;
     787             :   nscoord mMainPosn;
     788             :   nscoord mCrossSize;
     789             :   nscoord mCrossPosn;
     790             :   mutable nscoord mAscent; // Mutable b/c it's set & resolved lazily, sometimes
     791             :                            // via const pointer. See comment above SetAscent().
     792             : 
     793             :   // Temporary state, while we're resolving flexible widths (for our main size)
     794             :   // XXXdholbert To save space, we could use a union to make these variables
     795             :   // overlay the same memory as some other member vars that aren't touched
     796             :   // until after main-size has been resolved. In particular, these could share
     797             :   // memory with mMainPosn through mAscent, and mIsStretched.
     798             :   float mShareOfWeightSoFar;
     799             :   bool mIsFrozen;
     800             :   bool mHadMinViolation;
     801             :   bool mHadMaxViolation;
     802             : 
     803             :   // Misc:
     804             :   bool mHadMeasuringReflow; // Did this item get a preliminary reflow,
     805             :                             // to measure its desired height?
     806             :   bool mIsStretched; // See IsStretched() documentation
     807             :   bool mIsStrut;     // Is this item a "strut" left behind by an element
     808             :                      // with visibility:collapse?
     809             : 
     810             :   // Does this item need to resolve a min-[width|height]:auto (in main-axis).
     811             :   bool mNeedsMinSizeAutoResolution;
     812             : 
     813             :   const WritingMode mWM; // The flex item's writing mode.
     814             :   uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
     815             :                       // swapped out for parent"s "align-items" value,
     816             :                       // in our constructor).
     817             : };
     818             : 
     819             : /**
     820             :  * Represents a single flex line in a flex container.
     821             :  * Manages a linked list of the FlexItems that are in the line.
     822             :  */
     823           0 : class nsFlexContainerFrame::FlexLine : public LinkedListElement<FlexLine>
     824             : {
     825             : public:
     826           0 :   FlexLine()
     827           0 :   : mNumItems(0),
     828             :     mNumFrozenItems(0),
     829             :     mTotalInnerHypotheticalMainSize(0),
     830             :     mTotalOuterHypotheticalMainSize(0),
     831             :     mLineCrossSize(0),
     832             :     mFirstBaselineOffset(nscoord_MIN),
     833           0 :     mLastBaselineOffset(nscoord_MIN)
     834           0 :   {}
     835             : 
     836             :   // Returns the sum of our FlexItems' outer hypothetical main sizes.
     837             :   // ("outer" = margin-box, and "hypothetical" = before flexing)
     838           0 :   nscoord GetTotalOuterHypotheticalMainSize() const {
     839           0 :     return mTotalOuterHypotheticalMainSize;
     840             :   }
     841             : 
     842             :   // Accessors for our FlexItems & information about them:
     843           0 :   FlexItem* GetFirstItem()
     844             :   {
     845           0 :     MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
     846             :                "mNumItems bookkeeping is off");
     847           0 :     return mItems.getFirst();
     848             :   }
     849             : 
     850           0 :   const FlexItem* GetFirstItem() const
     851             :   {
     852           0 :     MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
     853             :                "mNumItems bookkeeping is off");
     854           0 :     return mItems.getFirst();
     855             :   }
     856             : 
     857           0 :   FlexItem* GetLastItem()
     858             :   {
     859           0 :     MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
     860             :                "mNumItems bookkeeping is off");
     861           0 :     return mItems.getLast();
     862             :   }
     863             : 
     864             :   const FlexItem* GetLastItem() const
     865             :   {
     866             :     MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
     867             :                "mNumItems bookkeeping is off");
     868             :     return mItems.getLast();
     869             :   }
     870             : 
     871           0 :   bool IsEmpty() const
     872             :   {
     873           0 :     MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
     874             :                "mNumItems bookkeeping is off");
     875           0 :     return mItems.isEmpty();
     876             :   }
     877             : 
     878           0 :   uint32_t NumItems() const
     879             :   {
     880           0 :     MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
     881             :                "mNumItems bookkeeping is off");
     882           0 :     return mNumItems;
     883             :   }
     884             : 
     885             :   // Adds the given FlexItem to our list of items (at the front or back
     886             :   // depending on aShouldInsertAtFront), and adds its hypothetical
     887             :   // outer & inner main sizes to our totals. Use this method instead of
     888             :   // directly modifying the item list, so that our bookkeeping remains correct.
     889           0 :   void AddItem(FlexItem* aItem,
     890             :                bool aShouldInsertAtFront,
     891             :                nscoord aItemInnerHypotheticalMainSize,
     892             :                nscoord aItemOuterHypotheticalMainSize)
     893             :   {
     894           0 :     if (aShouldInsertAtFront) {
     895           0 :       mItems.insertFront(aItem);
     896             :     } else {
     897           0 :       mItems.insertBack(aItem);
     898             :     }
     899             : 
     900             :     // Update our various bookkeeping member-vars:
     901           0 :     mNumItems++;
     902           0 :     if (aItem->IsFrozen()) {
     903           0 :       mNumFrozenItems++;
     904             :     }
     905           0 :     mTotalInnerHypotheticalMainSize += aItemInnerHypotheticalMainSize;
     906           0 :     mTotalOuterHypotheticalMainSize += aItemOuterHypotheticalMainSize;
     907           0 :   }
     908             : 
     909             :   // Computes the cross-size and baseline position of this FlexLine, based on
     910             :   // its FlexItems.
     911             :   void ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker);
     912             : 
     913             :   // Returns the cross-size of this line.
     914           0 :   nscoord GetLineCrossSize() const { return mLineCrossSize; }
     915             : 
     916             :   // Setter for line cross-size -- needed for cases where the flex container
     917             :   // imposes a cross-size on the line. (e.g. for single-line flexbox, or for
     918             :   // multi-line flexbox with 'align-content: stretch')
     919           0 :   void SetLineCrossSize(nscoord aLineCrossSize) {
     920           0 :     mLineCrossSize = aLineCrossSize;
     921           0 :   }
     922             : 
     923             :   /**
     924             :    * Returns the offset within this line where any baseline-aligned FlexItems
     925             :    * should place their baseline. Usually, this represents a distance from the
     926             :    * line's cross-start edge, but if we're internally reversing the axes (see
     927             :    * AreAxesInternallyReversed()), this instead represents the distance from
     928             :    * its cross-end edge.
     929             :    *
     930             :    * If there are no baseline-aligned FlexItems, returns nscoord_MIN.
     931             :    */
     932           0 :   nscoord GetFirstBaselineOffset() const {
     933           0 :     return mFirstBaselineOffset;
     934             :   }
     935             : 
     936             :   /**
     937             :    * Returns the offset within this line where any last baseline-aligned
     938             :    * FlexItems should place their baseline. Opposite the case of the first
     939             :    * baseline offset, this represents a distance from the line's cross-end
     940             :    * edge (since last baseline-aligned items are flush to the cross-end edge).
     941             :    * If we're internally reversing the axes, this instead represents the
     942             :    * distance from the line's cross-start edge.
     943             :    *
     944             :    * If there are no last baseline-aligned FlexItems, returns nscoord_MIN.
     945             :    */
     946           0 :   nscoord GetLastBaselineOffset() const {
     947           0 :     return mLastBaselineOffset;
     948             :   }
     949             : 
     950             :   // Runs the "Resolving Flexible Lengths" algorithm from section 9.7 of the
     951             :   // CSS flexbox spec to distribute aFlexContainerMainSize among our flex items.
     952             :   void ResolveFlexibleLengths(nscoord aFlexContainerMainSize);
     953             : 
     954             :   void PositionItemsInMainAxis(uint8_t aJustifyContent,
     955             :                                nscoord aContentBoxMainSize,
     956             :                                const FlexboxAxisTracker& aAxisTracker);
     957             : 
     958             :   void PositionItemsInCrossAxis(nscoord aLineStartPosition,
     959             :                                 const FlexboxAxisTracker& aAxisTracker);
     960             : 
     961             :   friend class AutoFlexLineListClearer; // (needs access to mItems)
     962             : 
     963             : private:
     964             :   // Helpers for ResolveFlexibleLengths():
     965             :   void FreezeItemsEarly(bool aIsUsingFlexGrow);
     966             : 
     967             :   void FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
     968             :                                        bool aIsFinalIteration);
     969             : 
     970             :   LinkedList<FlexItem> mItems; // Linked list of this line's flex items.
     971             : 
     972             :   uint32_t mNumItems; // Number of FlexItems in this line (in |mItems|).
     973             :                       // (Shouldn't change after GenerateFlexLines finishes
     974             :                       // with this line -- at least, not until we add support
     975             :                       // for splitting lines across continuations. Then we can
     976             :                       // update this count carefully.)
     977             : 
     978             :   // Number of *frozen* FlexItems in this line, based on FlexItem::IsFrozen().
     979             :   // Mostly used for optimization purposes, e.g. to bail out early from loops
     980             :   // when we can tell they have nothing left to do.
     981             :   uint32_t mNumFrozenItems;
     982             : 
     983             :   nscoord mTotalInnerHypotheticalMainSize;
     984             :   nscoord mTotalOuterHypotheticalMainSize;
     985             :   nscoord mLineCrossSize;
     986             :   nscoord mFirstBaselineOffset;
     987             :   nscoord mLastBaselineOffset;
     988             : };
     989             : 
     990             : // Information about a strut left behind by a FlexItem that's been collapsed
     991             : // using "visibility:collapse".
     992             : struct nsFlexContainerFrame::StrutInfo {
     993           0 :   StrutInfo(uint32_t aItemIdx, nscoord aStrutCrossSize)
     994           0 :     : mItemIdx(aItemIdx),
     995           0 :       mStrutCrossSize(aStrutCrossSize)
     996             :   {
     997           0 :   }
     998             : 
     999             :   uint32_t mItemIdx;      // Index in the child list.
    1000             :   nscoord mStrutCrossSize; // The cross-size of this strut.
    1001             : };
    1002             : 
    1003             : static void
    1004           0 : BuildStrutInfoFromCollapsedItems(const FlexLine* aFirstLine,
    1005             :                                  nsTArray<StrutInfo>& aStruts)
    1006             : {
    1007           0 :   MOZ_ASSERT(aFirstLine, "null first line pointer");
    1008           0 :   MOZ_ASSERT(aStruts.IsEmpty(),
    1009             :              "We should only build up StrutInfo once per reflow, so "
    1010             :              "aStruts should be empty when this is called");
    1011             : 
    1012           0 :   uint32_t itemIdxInContainer = 0;
    1013           0 :   for (const FlexLine* line = aFirstLine; line; line = line->getNext()) {
    1014           0 :     for (const FlexItem* item = line->GetFirstItem(); item;
    1015           0 :          item = item->getNext()) {
    1016           0 :       if (NS_STYLE_VISIBILITY_COLLAPSE ==
    1017           0 :           item->Frame()->StyleVisibility()->mVisible) {
    1018             :         // Note the cross size of the line as the item's strut size.
    1019           0 :         aStruts.AppendElement(StrutInfo(itemIdxInContainer,
    1020           0 :                                         line->GetLineCrossSize()));
    1021             :       }
    1022           0 :       itemIdxInContainer++;
    1023             :     }
    1024             :   }
    1025           0 : }
    1026             : 
    1027             : uint8_t
    1028           0 : SimplifyAlignOrJustifyContentForOneItem(uint16_t aAlignmentVal,
    1029             :                                         bool aIsAlign)
    1030             : {
    1031             :   // Mask away any explicit fallback, to get the main (non-fallback) part of
    1032             :   // the specified value:
    1033           0 :   uint16_t specified = aAlignmentVal & NS_STYLE_ALIGN_ALL_BITS;
    1034             : 
    1035             :   // XXX strip off <overflow-position> bits until we implement it (bug 1311892)
    1036           0 :   specified &= ~NS_STYLE_ALIGN_FLAG_BITS;
    1037             : 
    1038             :   // FIRST: handle a special-case for "justify-content:stretch" (or equivalent),
    1039             :   // which requires that we ignore any author-provided explicit fallback value.
    1040           0 :   if (specified == NS_STYLE_ALIGN_NORMAL) {
    1041             :     // In a flex container, *-content: "'normal' behaves as 'stretch'".
    1042             :     // Do that conversion early, so it benefits from our 'stretch' special-case.
    1043             :     // https://drafts.csswg.org/css-align-3/#distribution-flex
    1044           0 :     specified = NS_STYLE_ALIGN_STRETCH;
    1045             :   }
    1046           0 :   if (!aIsAlign && specified == NS_STYLE_ALIGN_STRETCH) {
    1047             :     // In a flex container, in "justify-content Axis: [...] 'stretch' behaves
    1048             :     // as 'flex-start' (ignoring the specified fallback alignment, if any)."
    1049             :     // https://drafts.csswg.org/css-align-3/#distribution-flex
    1050             :     // So, we just directly return 'flex-start', & ignore explicit fallback..
    1051           0 :     return NS_STYLE_ALIGN_FLEX_START;
    1052             :   }
    1053             : 
    1054             :   // Now check for an explicit fallback value (and if it's present, use it).
    1055           0 :   uint16_t explicitFallback = aAlignmentVal >> NS_STYLE_ALIGN_ALL_SHIFT;
    1056           0 :   if (explicitFallback) {
    1057             :     // XXX strip off <overflow-position> bits until we implement it
    1058             :     // (bug 1311892)
    1059           0 :     explicitFallback &= ~NS_STYLE_ALIGN_FLAG_BITS;
    1060           0 :     return explicitFallback;
    1061             :   }
    1062             : 
    1063             :   // There's no explicit fallback. Use the implied fallback values for
    1064             :   // space-{between,around,evenly} (since those values only make sense with
    1065             :   // multiple alignment subjects), and otherwise just use the specified value:
    1066           0 :   switch (specified) {
    1067             :     case NS_STYLE_ALIGN_SPACE_BETWEEN:
    1068           0 :       return NS_STYLE_ALIGN_START;
    1069             :     case NS_STYLE_ALIGN_SPACE_AROUND:
    1070             :     case NS_STYLE_ALIGN_SPACE_EVENLY:
    1071           0 :       return NS_STYLE_ALIGN_CENTER;
    1072             :     default:
    1073           0 :       return specified;
    1074             :   }
    1075             : }
    1076             : 
    1077             : uint16_t
    1078           0 : nsFlexContainerFrame::CSSAlignmentForAbsPosChild(
    1079             :   const ReflowInput& aChildRI,
    1080             :   LogicalAxis aLogicalAxis) const
    1081             : {
    1082           0 :   WritingMode wm = GetWritingMode();
    1083             :   const FlexboxAxisTracker
    1084           0 :     axisTracker(this, wm, AxisTrackerFlags::eAllowBottomToTopChildOrdering);
    1085             : 
    1086             :   // If we're row-oriented and the caller is asking about our inline axis (or
    1087             :   // alternately, if we're column-oriented and the caller is asking about our
    1088             :   // block axis), then the caller is really asking about our *main* axis.
    1089             :   // Otherwise, the caller is asking about our cross axis.
    1090           0 :   const bool isMainAxis = (axisTracker.IsRowOriented() ==
    1091           0 :                            (aLogicalAxis == eLogicalAxisInline));
    1092           0 :   const nsStylePosition* containerStylePos = StylePosition();
    1093           0 :   const bool isAxisReversed = isMainAxis ? axisTracker.IsMainAxisReversed()
    1094           0 :                                          : axisTracker.IsCrossAxisReversed();
    1095             : 
    1096             :   uint8_t alignment;
    1097           0 :   if (isMainAxis) {
    1098           0 :     alignment = SimplifyAlignOrJustifyContentForOneItem(
    1099           0 :                   containerStylePos->mJustifyContent,
    1100           0 :                   /*aIsAlign = */false);
    1101             :   } else {
    1102           0 :     const uint8_t alignContent = SimplifyAlignOrJustifyContentForOneItem(
    1103           0 :                                    containerStylePos->mAlignContent,
    1104           0 :                                    /*aIsAlign = */true);
    1105           0 :     if (NS_STYLE_FLEX_WRAP_NOWRAP != containerStylePos->mFlexWrap &&
    1106             :         alignContent != NS_STYLE_ALIGN_STRETCH) {
    1107             :       // Multi-line, align-content isn't stretch --> align-content determines
    1108             :       // this child's alignment in the cross axis.
    1109           0 :       alignment = alignContent;
    1110             :     } else {
    1111             :       // Single-line, or multi-line but the (one) line stretches to fill
    1112             :       // container. Respect align-self.
    1113           0 :       alignment = aChildRI.mStylePosition->UsedAlignSelf(StyleContext());
    1114             :       // XXX strip off <overflow-position> bits until we implement it
    1115             :       // (bug 1311892)
    1116           0 :       alignment &= ~NS_STYLE_ALIGN_FLAG_BITS;
    1117             : 
    1118           0 :       if (alignment == NS_STYLE_ALIGN_NORMAL) {
    1119             :         // "the 'normal' keyword behaves as 'start' on replaced
    1120             :         // absolutely-positioned boxes, and behaves as 'stretch' on all other
    1121             :         // absolutely-positioned boxes."
    1122             :         // https://drafts.csswg.org/css-align/#align-abspos
    1123           0 :         alignment = aChildRI.mFrame->IsFrameOfType(nsIFrame::eReplaced) ?
    1124           0 :           NS_STYLE_ALIGN_START : NS_STYLE_ALIGN_STRETCH;
    1125             :       }
    1126             :     }
    1127             :   }
    1128             : 
    1129             :   // Resolve flex-start, flex-end, auto, left, right, baseline, last baseline;
    1130           0 :   if (alignment == NS_STYLE_ALIGN_FLEX_START) {
    1131           0 :     alignment = isAxisReversed ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
    1132           0 :   } else if (alignment == NS_STYLE_ALIGN_FLEX_END) {
    1133           0 :     alignment = isAxisReversed ? NS_STYLE_ALIGN_START : NS_STYLE_ALIGN_END;
    1134           0 :   } else if (alignment == NS_STYLE_ALIGN_LEFT ||
    1135             :              alignment == NS_STYLE_ALIGN_RIGHT) {
    1136           0 :     if (aLogicalAxis == eLogicalAxisInline) {
    1137           0 :       const bool isLeft = (alignment == NS_STYLE_ALIGN_LEFT);
    1138           0 :       alignment = (isLeft == wm.IsBidiLTR()) ? NS_STYLE_ALIGN_START
    1139           0 :                                              : NS_STYLE_ALIGN_END;
    1140             :     } else {
    1141           0 :       alignment = NS_STYLE_ALIGN_START;
    1142           0 :     }
    1143           0 :   } else if (alignment == NS_STYLE_ALIGN_BASELINE) {
    1144           0 :     alignment = NS_STYLE_ALIGN_START;
    1145           0 :   } else if (alignment == NS_STYLE_ALIGN_LAST_BASELINE) {
    1146           0 :     alignment = NS_STYLE_ALIGN_END;
    1147             :   }
    1148             : 
    1149           0 :   return alignment;
    1150             : }
    1151             : 
    1152             : bool
    1153           0 : nsFlexContainerFrame::IsHorizontal()
    1154             : {
    1155           0 :   const FlexboxAxisTracker axisTracker(this, GetWritingMode());
    1156           0 :   return axisTracker.IsMainAxisHorizontal();
    1157             : }
    1158             : 
    1159             : UniquePtr<FlexItem>
    1160           0 : nsFlexContainerFrame::GenerateFlexItemForChild(
    1161             :   nsPresContext* aPresContext,
    1162             :   nsIFrame*      aChildFrame,
    1163             :   const ReflowInput& aParentReflowInput,
    1164             :   const FlexboxAxisTracker& aAxisTracker)
    1165             : {
    1166             :   // Create temporary reflow state just for sizing -- to get hypothetical
    1167             :   // main-size and the computed values of min / max main-size property.
    1168             :   // (This reflow state will _not_ be used for reflow.)
    1169             :   ReflowInput
    1170             :     childRI(aPresContext, aParentReflowInput, aChildFrame,
    1171           0 :             aParentReflowInput.ComputedSize(aChildFrame->GetWritingMode()));
    1172             : 
    1173             :   // FLEX GROW & SHRINK WEIGHTS
    1174             :   // --------------------------
    1175             :   float flexGrow, flexShrink;
    1176           0 :   if (IsLegacyBox(this)) {
    1177           0 :     flexGrow = flexShrink = aChildFrame->StyleXUL()->mBoxFlex;
    1178             :   } else {
    1179           0 :     const nsStylePosition* stylePos = aChildFrame->StylePosition();
    1180           0 :     flexGrow   = stylePos->mFlexGrow;
    1181           0 :     flexShrink = stylePos->mFlexShrink;
    1182             :   }
    1183             : 
    1184           0 :   WritingMode childWM = childRI.GetWritingMode();
    1185             : 
    1186             :   // MAIN SIZES (flex base size, min/max size)
    1187             :   // -----------------------------------------
    1188           0 :   nscoord flexBaseSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
    1189             :                                                     childRI.ComputedISize(),
    1190             :                                                     childRI.ComputedBSize());
    1191           0 :   nscoord mainMinSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
    1192             :                                                    childRI.ComputedMinISize(),
    1193             :                                                    childRI.ComputedMinBSize());
    1194           0 :   nscoord mainMaxSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
    1195             :                                                    childRI.ComputedMaxISize(),
    1196             :                                                    childRI.ComputedMaxBSize());
    1197             :   // This is enforced by the ReflowInput where these values come from:
    1198           0 :   MOZ_ASSERT(mainMinSize <= mainMaxSize, "min size is larger than max size");
    1199             : 
    1200             :   // CROSS SIZES (tentative cross size, min/max cross size)
    1201             :   // ------------------------------------------------------
    1202             :   // Grab the cross size from the reflow state. This might be the right value,
    1203             :   // or we might resolve it to something else in SizeItemInCrossAxis(); hence,
    1204             :   // it's tentative. See comment under "Cross Size Determination" for more.
    1205             :   nscoord tentativeCrossSize =
    1206           0 :     GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, childWM,
    1207             :                                 childRI.ComputedISize(),
    1208             :                                 childRI.ComputedBSize());
    1209             :   nscoord crossMinSize =
    1210           0 :     GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, childWM,
    1211             :                                 childRI.ComputedMinISize(),
    1212             :                                 childRI.ComputedMinBSize());
    1213             :   nscoord crossMaxSize =
    1214           0 :     GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, childWM,
    1215             :                                 childRI.ComputedMaxISize(),
    1216             :                                 childRI.ComputedMaxBSize());
    1217             : 
    1218             :   // SPECIAL-CASE FOR WIDGET-IMPOSED SIZES
    1219             :   // Check if we're a themed widget, in which case we might have a minimum
    1220             :   // main & cross size imposed by our widget (which we can't go below), or
    1221             :   // (more severe) our widget might have only a single valid size.
    1222           0 :   bool isFixedSizeWidget = false;
    1223           0 :   const nsStyleDisplay* disp = aChildFrame->StyleDisplay();
    1224           0 :   if (aChildFrame->IsThemed(disp)) {
    1225           0 :     LayoutDeviceIntSize widgetMinSize;
    1226           0 :     bool canOverride = true;
    1227           0 :     aPresContext->GetTheme()->
    1228           0 :       GetMinimumWidgetSize(aPresContext, aChildFrame,
    1229           0 :                            disp->mAppearance,
    1230           0 :                            &widgetMinSize, &canOverride);
    1231             : 
    1232             :     nscoord widgetMainMinSize =
    1233           0 :       aPresContext->DevPixelsToAppUnits(
    1234           0 :         aAxisTracker.GetMainComponent(widgetMinSize));
    1235             :     nscoord widgetCrossMinSize =
    1236           0 :       aPresContext->DevPixelsToAppUnits(
    1237           0 :         aAxisTracker.GetCrossComponent(widgetMinSize));
    1238             : 
    1239             :     // GMWS() returns border-box. We need content-box, so subtract
    1240             :     // borderPadding (but don't let that push our min sizes below 0).
    1241           0 :     nsMargin& bp = childRI.ComputedPhysicalBorderPadding();
    1242           0 :     widgetMainMinSize = std::max(widgetMainMinSize -
    1243           0 :                                  aAxisTracker.GetMarginSizeInMainAxis(bp), 0);
    1244           0 :     widgetCrossMinSize = std::max(widgetCrossMinSize -
    1245           0 :                                   aAxisTracker.GetMarginSizeInCrossAxis(bp), 0);
    1246             : 
    1247           0 :     if (!canOverride) {
    1248             :       // Fixed-size widget: freeze our main-size at the widget's mandated size.
    1249             :       // (Set min and max main-sizes to that size, too, to keep us from
    1250             :       // clamping to any other size later on.)
    1251           0 :       flexBaseSize = mainMinSize = mainMaxSize = widgetMainMinSize;
    1252           0 :       tentativeCrossSize = crossMinSize = crossMaxSize = widgetCrossMinSize;
    1253           0 :       isFixedSizeWidget = true;
    1254             :     } else {
    1255             :       // Variable-size widget: ensure our min/max sizes are at least as large
    1256             :       // as the widget's mandated minimum size, so we don't flex below that.
    1257           0 :       mainMinSize = std::max(mainMinSize, widgetMainMinSize);
    1258           0 :       mainMaxSize = std::max(mainMaxSize, widgetMainMinSize);
    1259             : 
    1260           0 :       if (tentativeCrossSize != NS_INTRINSICSIZE) {
    1261           0 :         tentativeCrossSize = std::max(tentativeCrossSize, widgetCrossMinSize);
    1262             :       }
    1263           0 :       crossMinSize = std::max(crossMinSize, widgetCrossMinSize);
    1264           0 :       crossMaxSize = std::max(crossMaxSize, widgetCrossMinSize);
    1265             :     }
    1266             :   }
    1267             : 
    1268             :   // Construct the flex item!
    1269             :   auto item = MakeUnique<FlexItem>(childRI,
    1270             :                                    flexGrow, flexShrink, flexBaseSize,
    1271             :                                    mainMinSize, mainMaxSize,
    1272             :                                    tentativeCrossSize,
    1273             :                                    crossMinSize, crossMaxSize,
    1274           0 :                                    aAxisTracker);
    1275             : 
    1276             :   // If we're inflexible, we can just freeze to our hypothetical main-size
    1277             :   // up-front. Similarly, if we're a fixed-size widget, we only have one
    1278             :   // valid size, so we freeze to keep ourselves from flexing.
    1279           0 :   if (isFixedSizeWidget || (flexGrow == 0.0f && flexShrink == 0.0f)) {
    1280           0 :     item->Freeze();
    1281             :   }
    1282             : 
    1283             :   // Resolve "flex-basis:auto" and/or "min-[width|height]:auto" (which might
    1284             :   // require us to reflow the item to measure content height)
    1285           0 :   ResolveAutoFlexBasisAndMinSize(aPresContext, *item,
    1286           0 :                                  childRI, aAxisTracker);
    1287           0 :   return item;
    1288             : }
    1289             : 
    1290             : // Static helper-functions for ResolveAutoFlexBasisAndMinSize():
    1291             : // -------------------------------------------------------------
    1292             : // Indicates whether the cross-size property is set to something definite.
    1293             : // The logic here should be similar to the logic for isAutoWidth/isAutoHeight
    1294             : // in nsFrame::ComputeSizeWithIntrinsicDimensions().
    1295             : static bool
    1296           0 : IsCrossSizeDefinite(const ReflowInput& aItemReflowInput,
    1297             :                     const FlexboxAxisTracker& aAxisTracker)
    1298             : {
    1299           0 :   const nsStylePosition* pos = aItemReflowInput.mStylePosition;
    1300           0 :   if (aAxisTracker.IsCrossAxisHorizontal()) {
    1301           0 :     return pos->mWidth.GetUnit() != eStyleUnit_Auto;
    1302             :   }
    1303             :   // else, vertical. (We need to use IsAutoHeight() to catch e.g. %-height
    1304             :   // applied to indefinite-height containing block, which counts as auto.)
    1305           0 :   nscoord cbHeight = aItemReflowInput.mCBReflowInput->ComputedHeight();
    1306           0 :   return !nsLayoutUtils::IsAutoHeight(pos->mHeight, cbHeight);
    1307             : }
    1308             : 
    1309             : // If aFlexItem has a definite cross size, this function returns it, for usage
    1310             : // (in combination with an intrinsic ratio) for resolving the item's main size
    1311             : // or main min-size.
    1312             : //
    1313             : // The parameter "aMinSizeFallback" indicates whether we should fall back to
    1314             : // returning the cross min-size, when the cross size is indefinite. (This param
    1315             : // should be set IFF the caller intends to resolve the main min-size.) If this
    1316             : // param is true, then this function is guaranteed to return a definite value
    1317             : // (i.e. not NS_AUTOHEIGHT, excluding cases where huge sizes are involved).
    1318             : //
    1319             : // XXXdholbert the min-size behavior here is based on my understanding in
    1320             : //   http://lists.w3.org/Archives/Public/www-style/2014Jul/0053.html
    1321             : // If my understanding there ends up being wrong, we'll need to update this.
    1322             : static nscoord
    1323           0 : CrossSizeToUseWithRatio(const FlexItem& aFlexItem,
    1324             :                         const ReflowInput& aItemReflowInput,
    1325             :                         bool aMinSizeFallback,
    1326             :                         const FlexboxAxisTracker& aAxisTracker)
    1327             : {
    1328           0 :   if (aFlexItem.IsStretched()) {
    1329             :     // Definite cross-size, imposed via 'align-self:stretch' & flex container.
    1330           0 :     return aFlexItem.GetCrossSize();
    1331             :   }
    1332             : 
    1333           0 :   if (IsCrossSizeDefinite(aItemReflowInput, aAxisTracker)) {
    1334             :     // Definite cross size.
    1335           0 :     return GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aFlexItem.GetWritingMode(),
    1336             :                                        aItemReflowInput.ComputedISize(),
    1337             :                                        aItemReflowInput.ComputedBSize());
    1338             :   }
    1339             : 
    1340           0 :   if (aMinSizeFallback) {
    1341             :     // Indefinite cross-size, and we're resolving main min-size, so we'll fall
    1342             :     // back to ussing the cross min-size (which should be definite).
    1343           0 :     return GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aFlexItem.GetWritingMode(),
    1344             :                                        aItemReflowInput.ComputedMinISize(),
    1345             :                                        aItemReflowInput.ComputedMinBSize());
    1346             :   }
    1347             : 
    1348             :   // Indefinite cross-size.
    1349           0 :   return NS_AUTOHEIGHT;
    1350             : }
    1351             : 
    1352             : // Convenience function; returns a main-size, given a cross-size and an
    1353             : // intrinsic ratio. The intrinsic ratio must not have 0 in its cross-axis
    1354             : // component (or else we'll divide by 0).
    1355             : static nscoord
    1356           0 : MainSizeFromAspectRatio(nscoord aCrossSize,
    1357             :                         const nsSize& aIntrinsicRatio,
    1358             :                         const FlexboxAxisTracker& aAxisTracker)
    1359             : {
    1360           0 :   MOZ_ASSERT(aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0,
    1361             :              "Invalid ratio; will divide by 0! Caller should've checked...");
    1362             : 
    1363           0 :   if (aAxisTracker.IsCrossAxisHorizontal()) {
    1364             :     // cross axis horiz --> aCrossSize is a width. Converting to height.
    1365           0 :     return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.height, aIntrinsicRatio.width);
    1366             :   }
    1367             :   // cross axis vert --> aCrossSize is a height. Converting to width.
    1368           0 :   return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.width, aIntrinsicRatio.height);
    1369             : }
    1370             : 
    1371             : // Partially resolves "min-[width|height]:auto" and returns the resulting value.
    1372             : // By "partially", I mean we don't consider the min-content size (but we do
    1373             : // consider flex-basis, main max-size, and the intrinsic aspect ratio).
    1374             : // The caller is responsible for computing & considering the min-content size
    1375             : // in combination with the partially-resolved value that this function returns.
    1376             : //
    1377             : // Spec reference: http://dev.w3.org/csswg/css-flexbox/#min-size-auto
    1378             : static nscoord
    1379           0 : PartiallyResolveAutoMinSize(const FlexItem& aFlexItem,
    1380             :                             const ReflowInput& aItemReflowInput,
    1381             :                             const FlexboxAxisTracker& aAxisTracker)
    1382             : {
    1383           0 :   MOZ_ASSERT(aFlexItem.NeedsMinSizeAutoResolution(),
    1384             :              "only call for FlexItems that need min-size auto resolution");
    1385             : 
    1386           0 :   nscoord minMainSize = nscoord_MAX; // Intentionally huge; we'll shrink it
    1387             :                                      // from here, w/ std::min().
    1388             : 
    1389             :   // We need the smallest of:
    1390             :   // * the used flex-basis, if the computed flex-basis was 'auto':
    1391             :   // XXXdholbert ('auto' might be renamed to 'main-size'; see bug 1032922)
    1392           0 :   if (eStyleUnit_Auto ==
    1393           0 :       aItemReflowInput.mStylePosition->mFlexBasis.GetUnit() &&
    1394           0 :       aFlexItem.GetFlexBaseSize() != NS_AUTOHEIGHT) {
    1395             :     // NOTE: We skip this if the flex base size depends on content & isn't yet
    1396             :     // resolved. This is OK, because the caller is responsible for computing
    1397             :     // the min-content height and min()'ing it with the value we return, which
    1398             :     // is equivalent to what would happen if we min()'d that at this point.
    1399           0 :     minMainSize = std::min(minMainSize, aFlexItem.GetFlexBaseSize());
    1400             :   }
    1401             : 
    1402             :   // * the computed max-width (max-height), if that value is definite:
    1403             :   nscoord maxSize =
    1404           0 :     GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, aFlexItem.GetWritingMode(),
    1405             :                                aItemReflowInput.ComputedMaxISize(),
    1406             :                                aItemReflowInput.ComputedMaxBSize());
    1407           0 :   if (maxSize != NS_UNCONSTRAINEDSIZE) {
    1408           0 :     minMainSize = std::min(minMainSize, maxSize);
    1409             :   }
    1410             : 
    1411             :   // * if the item has no intrinsic aspect ratio, its min-content size:
    1412             :   //  --- SKIPPING THIS IN THIS FUNCTION --- caller's responsibility.
    1413             : 
    1414             :   // * if the item has an intrinsic aspect ratio, the width (height) calculated
    1415             :   //   from the aspect ratio and any definite size constraints in the opposite
    1416             :   //   dimension.
    1417           0 :   if (aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) != 0) {
    1418             :     // We have a usable aspect ratio. (not going to divide by 0)
    1419           0 :     const bool useMinSizeIfCrossSizeIsIndefinite = true;
    1420             :     nscoord crossSizeToUseWithRatio =
    1421             :       CrossSizeToUseWithRatio(aFlexItem, aItemReflowInput,
    1422             :                               useMinSizeIfCrossSizeIsIndefinite,
    1423           0 :                               aAxisTracker);
    1424             :     nscoord minMainSizeFromRatio =
    1425           0 :       MainSizeFromAspectRatio(crossSizeToUseWithRatio,
    1426           0 :                               aFlexItem.IntrinsicRatio(), aAxisTracker);
    1427           0 :     minMainSize = std::min(minMainSize, minMainSizeFromRatio);
    1428             :   }
    1429             : 
    1430           0 :   return minMainSize;
    1431             : }
    1432             : 
    1433             : // Resolves flex-basis:auto, using the given intrinsic ratio and the flex
    1434             : // item's cross size.  On success, updates the flex item with its resolved
    1435             : // flex-basis and returns true. On failure (e.g. if the ratio is invalid or
    1436             : // the cross-size is indefinite), returns false.
    1437             : static bool
    1438           0 : ResolveAutoFlexBasisFromRatio(FlexItem& aFlexItem,
    1439             :                               const ReflowInput& aItemReflowInput,
    1440             :                               const FlexboxAxisTracker& aAxisTracker)
    1441             : {
    1442           0 :   MOZ_ASSERT(NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize(),
    1443             :              "Should only be called to resolve an 'auto' flex-basis");
    1444             :   // If the flex item has ...
    1445             :   //  - an intrinsic aspect ratio,
    1446             :   //  - a [used] flex-basis of 'main-size' [auto?] [We have this, if we're here.]
    1447             :   //  - a definite cross size
    1448             :   // then the flex base size is calculated from its inner cross size and the
    1449             :   // flex item’s intrinsic aspect ratio.
    1450           0 :   if (aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) != 0) {
    1451             :     // We have a usable aspect ratio. (not going to divide by 0)
    1452           0 :     const bool useMinSizeIfCrossSizeIsIndefinite = false;
    1453             :     nscoord crossSizeToUseWithRatio =
    1454             :       CrossSizeToUseWithRatio(aFlexItem, aItemReflowInput,
    1455             :                               useMinSizeIfCrossSizeIsIndefinite,
    1456           0 :                               aAxisTracker);
    1457           0 :     if (crossSizeToUseWithRatio != NS_AUTOHEIGHT) {
    1458             :       // We have a definite cross-size
    1459             :       nscoord mainSizeFromRatio =
    1460           0 :         MainSizeFromAspectRatio(crossSizeToUseWithRatio,
    1461           0 :                                 aFlexItem.IntrinsicRatio(), aAxisTracker);
    1462           0 :       aFlexItem.SetFlexBaseSizeAndMainSize(mainSizeFromRatio);
    1463           0 :       return true;
    1464             :     }
    1465             :   }
    1466           0 :   return false;
    1467             : }
    1468             : 
    1469             : // Note: If & when we handle "min-height: min-content" for flex items,
    1470             : // we may want to resolve that in this function, too.
    1471             : void
    1472           0 : nsFlexContainerFrame::
    1473             :   ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
    1474             :                                  FlexItem& aFlexItem,
    1475             :                                  const ReflowInput& aItemReflowInput,
    1476             :                                  const FlexboxAxisTracker& aAxisTracker)
    1477             : {
    1478             :   // (Note: We should never have a used flex-basis of "auto" if our main axis
    1479             :   // is horizontal; width values should always be resolvable without reflow.)
    1480           0 :   const bool isMainSizeAuto = (!aAxisTracker.IsMainAxisHorizontal() &&
    1481           0 :                                NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
    1482             : 
    1483           0 :   const bool isMainMinSizeAuto = aFlexItem.NeedsMinSizeAutoResolution();
    1484             : 
    1485           0 :   if (!isMainSizeAuto && !isMainMinSizeAuto) {
    1486             :     // Nothing to do; this function is only needed for flex items
    1487             :     // with a used flex-basis of "auto" or a min-main-size of "auto".
    1488           0 :     return;
    1489             :   }
    1490             : 
    1491             :   // We may be about to do computations based on our item's cross-size
    1492             :   // (e.g. using it as a contstraint when measuring our content in the
    1493             :   // main axis, or using it with the intrinsic ratio to obtain a main size).
    1494             :   // BEFORE WE DO THAT, we need let the item "pre-stretch" its cross size (if
    1495             :   // it's got 'align-self:stretch'), for a certain case where the spec says
    1496             :   // the stretched cross size is considered "definite". That case is if we
    1497             :   // have a single-line (nowrap) flex container which itself has a definite
    1498             :   // cross-size.  Otherwise, we'll wait to do stretching, since (in other
    1499             :   // cases) we don't know how much the item should stretch yet.
    1500           0 :   const ReflowInput* flexContainerRI = aItemReflowInput.mParentReflowInput;
    1501           0 :   MOZ_ASSERT(flexContainerRI,
    1502             :              "flex item's reflow state should have ptr to container's state");
    1503           0 :   if (NS_STYLE_FLEX_WRAP_NOWRAP == flexContainerRI->mStylePosition->mFlexWrap) {
    1504             :     // XXXdholbert Maybe this should share logic with ComputeCrossSize()...
    1505             :     // Alternately, maybe tentative container cross size should be passed down.
    1506             :     nscoord containerCrossSize =
    1507           0 :       GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aAxisTracker.GetWritingMode(),
    1508             :                                   flexContainerRI->ComputedISize(),
    1509             :                                   flexContainerRI->ComputedBSize());
    1510             :     // Is container's cross size "definite"?
    1511             :     // (Container's cross size is definite if cross-axis is horizontal, or if
    1512             :     // cross-axis is vertical and the cross-size is not NS_AUTOHEIGHT.)
    1513           0 :     if (aAxisTracker.IsCrossAxisHorizontal() ||
    1514             :         containerCrossSize != NS_AUTOHEIGHT) {
    1515           0 :       aFlexItem.ResolveStretchedCrossSize(containerCrossSize, aAxisTracker);
    1516             :     }
    1517             :   }
    1518             : 
    1519             :   nscoord resolvedMinSize; // (only set/used if isMainMinSizeAuto==true)
    1520           0 :   bool minSizeNeedsToMeasureContent = false; // assume the best
    1521           0 :   if (isMainMinSizeAuto) {
    1522             :     // Resolve the min-size, except for considering the min-content size.
    1523             :     // (We'll consider that later, if we need to.)
    1524           0 :     resolvedMinSize = PartiallyResolveAutoMinSize(aFlexItem, aItemReflowInput,
    1525             :                                                   aAxisTracker);
    1526           0 :     if (resolvedMinSize > 0 &&
    1527           0 :         aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) == 0) {
    1528             :       // We don't have a usable aspect ratio, so we need to consider our
    1529             :       // min-content size as another candidate min-size, which we'll have to
    1530             :       // min() with the current resolvedMinSize.
    1531             :       // (If resolvedMinSize were already at 0, we could skip this measurement
    1532             :       // because it can't go any lower. But it's not 0, so we need it.)
    1533           0 :       minSizeNeedsToMeasureContent = true;
    1534             :     }
    1535             :   }
    1536             : 
    1537           0 :   bool flexBasisNeedsToMeasureContent = false; // assume the best
    1538           0 :   if (isMainSizeAuto) {
    1539           0 :     if (!ResolveAutoFlexBasisFromRatio(aFlexItem, aItemReflowInput,
    1540             :                                        aAxisTracker)) {
    1541           0 :       flexBasisNeedsToMeasureContent = true;
    1542             :     }
    1543             :   }
    1544             : 
    1545             :   // Measure content, if needed (w/ intrinsic-width method or a reflow)
    1546           0 :   if (minSizeNeedsToMeasureContent || flexBasisNeedsToMeasureContent) {
    1547           0 :     if (aAxisTracker.IsMainAxisHorizontal()) {
    1548           0 :       if (minSizeNeedsToMeasureContent) {
    1549             :         nscoord frameMinISize =
    1550           0 :           aFlexItem.Frame()->GetMinISize(aItemReflowInput.mRenderingContext);
    1551           0 :         resolvedMinSize = std::min(resolvedMinSize, frameMinISize);
    1552             :       }
    1553           0 :       NS_ASSERTION(!flexBasisNeedsToMeasureContent,
    1554             :                    "flex-basis:auto should have been resolved in the "
    1555             :                    "reflow state, for horizontal flexbox. It shouldn't need "
    1556             :                    "special handling here");
    1557             :     } else {
    1558             :       // If this item is flexible (vertically), or if we're measuring the
    1559             :       // 'auto' min-height and our main-size is something else, then we assume
    1560             :       // that the computed-height we're reflowing with now could be different
    1561             :       // from the one we'll use for this flex item's "actual" reflow later on.
    1562             :       // In that case, we need to be sure the flex item treats this as a
    1563             :       // vertical resize, even though none of its ancestors are necessarily
    1564             :       // being vertically resized.
    1565             :       // (Note: We don't have to do this for width, because InitResizeFlags
    1566             :       // will always turn on mHResize on when it sees that the computed width
    1567             :       // is different from current width, and that's all we need.)
    1568             :       bool forceVerticalResizeForMeasuringReflow =
    1569           0 :         !aFlexItem.IsFrozen() ||         // Is the item flexible?
    1570           0 :         !flexBasisNeedsToMeasureContent; // Are we *only* measuring it for
    1571             :                                          // 'min-height:auto'?
    1572             : 
    1573             :       nscoord contentHeight =
    1574           0 :         MeasureFlexItemContentHeight(aPresContext, aFlexItem,
    1575             :                                      forceVerticalResizeForMeasuringReflow,
    1576           0 :                                      *flexContainerRI);
    1577           0 :       if (minSizeNeedsToMeasureContent) {
    1578           0 :         resolvedMinSize = std::min(resolvedMinSize, contentHeight);
    1579             :       }
    1580           0 :       if (flexBasisNeedsToMeasureContent) {
    1581           0 :         aFlexItem.SetFlexBaseSizeAndMainSize(contentHeight);
    1582             :       }
    1583             :     }
    1584             :   }
    1585             : 
    1586           0 :   if (isMainMinSizeAuto) {
    1587           0 :     aFlexItem.UpdateMainMinSize(resolvedMinSize);
    1588             :   }
    1589             : }
    1590             : 
    1591             : /**
    1592             :  * A cached result for a measuring reflow.
    1593             :  *
    1594             :  * Right now we only need to cache the available size and the computed height
    1595             :  * for checking that the reflow input is valid, and the height and the ascent
    1596             :  * to be used. This can be extended later if needed.
    1597             :  *
    1598             :  * The assumption here is that a given flex item measurement won't change until
    1599             :  * either the available size or computed height changes, or the flex container
    1600             :  * intrinsic size is marked as dirty (due to a style or DOM change).
    1601             :  *
    1602             :  * In particular the computed height may change between measuring reflows due to
    1603             :  * how the mIsFlexContainerMeasuringReflow flag affects size computation (see
    1604             :  * bug 1336708).
    1605             :  *
    1606             :  * Caching it prevents us from doing exponential reflows in cases of deeply
    1607             :  * nested flex and scroll frames.
    1608             :  *
    1609             :  * We store them in the frame property table for simplicity.
    1610             :  */
    1611             : class nsFlexContainerFrame::CachedMeasuringReflowResult
    1612             : {
    1613             :   // Members that are part of the cache key:
    1614             :   const LogicalSize mAvailableSize;
    1615             :   const nscoord mComputedHeight;
    1616             : 
    1617             :   // Members that are part of the cache value:
    1618             :   const nscoord mHeight;
    1619             :   const nscoord mAscent;
    1620             : 
    1621             : public:
    1622           0 :   CachedMeasuringReflowResult(const ReflowInput& aReflowInput,
    1623             :                               const ReflowOutput& aDesiredSize)
    1624           0 :     : mAvailableSize(aReflowInput.AvailableSize())
    1625           0 :     , mComputedHeight(aReflowInput.ComputedHeight())
    1626           0 :     , mHeight(aDesiredSize.Height())
    1627           0 :     , mAscent(aDesiredSize.BlockStartAscent())
    1628           0 :   {}
    1629             : 
    1630           0 :   bool IsValidFor(const ReflowInput& aReflowInput) const {
    1631           0 :     return mAvailableSize == aReflowInput.AvailableSize() &&
    1632           0 :       mComputedHeight == aReflowInput.ComputedHeight();
    1633             :   }
    1634             : 
    1635           0 :   nscoord Height() const { return mHeight; }
    1636             : 
    1637           0 :   nscoord Ascent() const { return mAscent; }
    1638             : };
    1639             : 
    1640           0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedFlexMeasuringReflow,
    1641             :                                     CachedMeasuringReflowResult);
    1642             : 
    1643             : const CachedMeasuringReflowResult&
    1644           0 : nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem(
    1645             :   FlexItem& aItem,
    1646             :   nsPresContext* aPresContext,
    1647             :   ReflowInput& aChildReflowInput)
    1648             : {
    1649           0 :   if (const auto* cachedResult =
    1650           0 :         aItem.Frame()->GetProperty(CachedFlexMeasuringReflow())) {
    1651           0 :     if (cachedResult->IsValidFor(aChildReflowInput)) {
    1652           0 :       return *cachedResult;
    1653             :     }
    1654             :   }
    1655             : 
    1656           0 :   ReflowOutput childDesiredSize(aChildReflowInput);
    1657           0 :   nsReflowStatus childReflowStatus;
    1658             : 
    1659           0 :   const uint32_t flags = NS_FRAME_NO_MOVE_FRAME;
    1660           0 :   ReflowChild(aItem.Frame(), aPresContext,
    1661             :               childDesiredSize, aChildReflowInput,
    1662           0 :               0, 0, flags, childReflowStatus);
    1663           0 :   aItem.SetHadMeasuringReflow();
    1664             : 
    1665             :   // XXXdholbert Once we do pagination / splitting, we'll need to actually
    1666             :   // handle incomplete childReflowStatuses. But for now, we give our kids
    1667             :   // unconstrained available height, which means they should always complete.
    1668           0 :   MOZ_ASSERT(childReflowStatus.IsComplete(),
    1669             :              "We gave flex item unconstrained available height, so it "
    1670             :              "should be complete");
    1671             : 
    1672             :   // Tell the child we're done with its initial reflow.
    1673             :   // (Necessary for e.g. GetBaseline() to work below w/out asserting)
    1674           0 :   FinishReflowChild(aItem.Frame(), aPresContext,
    1675           0 :                     childDesiredSize, &aChildReflowInput, 0, 0, flags);
    1676             : 
    1677             :   auto result =
    1678           0 :     new CachedMeasuringReflowResult(aChildReflowInput, childDesiredSize);
    1679             : 
    1680           0 :   aItem.Frame()->SetProperty(CachedFlexMeasuringReflow(), result);
    1681           0 :   return *result;
    1682             : }
    1683             : 
    1684             : /* virtual */ void
    1685           0 : nsFlexContainerFrame::MarkIntrinsicISizesDirty()
    1686             : {
    1687           0 :   for (nsIFrame* childFrame : mFrames) {
    1688           0 :     childFrame->DeleteProperty(CachedFlexMeasuringReflow());
    1689             :   }
    1690           0 :   nsContainerFrame::MarkIntrinsicISizesDirty();
    1691           0 : }
    1692             : 
    1693             : nscoord
    1694           0 : nsFlexContainerFrame::
    1695             :   MeasureFlexItemContentHeight(nsPresContext* aPresContext,
    1696             :                                FlexItem& aFlexItem,
    1697             :                                bool aForceVerticalResizeForMeasuringReflow,
    1698             :                                const ReflowInput& aParentReflowInput)
    1699             : {
    1700             :   // Set up a reflow state for measuring the flex item's auto-height:
    1701           0 :   WritingMode wm = aFlexItem.Frame()->GetWritingMode();
    1702           0 :   LogicalSize availSize = aParentReflowInput.ComputedSize(wm);
    1703           0 :   availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    1704             :   ReflowInput
    1705             :     childRIForMeasuringHeight(aPresContext, aParentReflowInput,
    1706             :                               aFlexItem.Frame(), availSize,
    1707           0 :                               nullptr, ReflowInput::CALLER_WILL_INIT);
    1708           0 :   childRIForMeasuringHeight.mFlags.mIsFlexContainerMeasuringHeight = true;
    1709           0 :   childRIForMeasuringHeight.Init(aPresContext);
    1710             : 
    1711           0 :   if (aFlexItem.IsStretched()) {
    1712           0 :     childRIForMeasuringHeight.SetComputedWidth(aFlexItem.GetCrossSize());
    1713           0 :     childRIForMeasuringHeight.SetHResize(true);
    1714             :   }
    1715             : 
    1716           0 :   if (aForceVerticalResizeForMeasuringReflow) {
    1717           0 :     childRIForMeasuringHeight.SetVResize(true);
    1718             :   }
    1719             : 
    1720             :   const CachedMeasuringReflowResult& reflowResult =
    1721             :     MeasureAscentAndHeightForFlexItem(aFlexItem, aPresContext,
    1722           0 :                                       childRIForMeasuringHeight);
    1723             : 
    1724           0 :   aFlexItem.SetAscent(reflowResult.Ascent());
    1725             : 
    1726             :   // Subtract border/padding in vertical axis, to get _just_
    1727             :   // the effective computed value of the "height" property.
    1728           0 :   nscoord childDesiredHeight = reflowResult.Height() -
    1729           0 :     childRIForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom();
    1730             : 
    1731           0 :   return std::max(0, childDesiredHeight);
    1732             : }
    1733             : 
    1734           0 : FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput,
    1735             :                    float aFlexGrow, float aFlexShrink, nscoord aFlexBaseSize,
    1736             :                    nscoord aMainMinSize,  nscoord aMainMaxSize,
    1737             :                    nscoord aTentativeCrossSize,
    1738             :                    nscoord aCrossMinSize, nscoord aCrossMaxSize,
    1739           0 :                    const FlexboxAxisTracker& aAxisTracker)
    1740           0 :   : mFrame(aFlexItemReflowInput.mFrame),
    1741             :     mFlexGrow(aFlexGrow),
    1742             :     mFlexShrink(aFlexShrink),
    1743           0 :     mIntrinsicRatio(mFrame->GetIntrinsicRatio()),
    1744           0 :     mBorderPadding(aFlexItemReflowInput.ComputedPhysicalBorderPadding()),
    1745           0 :     mMargin(aFlexItemReflowInput.ComputedPhysicalMargin()),
    1746             :     mMainMinSize(aMainMinSize),
    1747             :     mMainMaxSize(aMainMaxSize),
    1748             :     mCrossMinSize(aCrossMinSize),
    1749             :     mCrossMaxSize(aCrossMaxSize),
    1750             :     mMainPosn(0),
    1751             :     mCrossSize(aTentativeCrossSize),
    1752             :     mCrossPosn(0),
    1753             :     mAscent(0),
    1754             :     mShareOfWeightSoFar(0.0f),
    1755             :     mIsFrozen(false),
    1756             :     mHadMinViolation(false),
    1757             :     mHadMaxViolation(false),
    1758             :     mHadMeasuringReflow(false),
    1759             :     mIsStretched(false),
    1760             :     mIsStrut(false),
    1761             :     // mNeedsMinSizeAutoResolution is initialized in CheckForMinSizeAuto()
    1762           0 :     mWM(aFlexItemReflowInput.GetWritingMode())
    1763             :     // mAlignSelf, see below
    1764             : {
    1765           0 :   MOZ_ASSERT(mFrame, "expecting a non-null child frame");
    1766           0 :   MOZ_ASSERT(!mFrame->IsPlaceholderFrame(),
    1767             :              "placeholder frames should not be treated as flex items");
    1768           0 :   MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
    1769             :              "out-of-flow frames should not be treated as flex items");
    1770             : 
    1771           0 :   const ReflowInput* containerRS = aFlexItemReflowInput.mParentReflowInput;
    1772           0 :   if (IsLegacyBox(containerRS->mFrame)) {
    1773             :     // For -webkit-box/-webkit-inline-box, we need to:
    1774             :     // (1) Use "-webkit-box-align" instead of "align-items" to determine the
    1775             :     //     container's cross-axis alignment behavior.
    1776             :     // (2) Suppress the ability for flex items to override that with their own
    1777             :     //     cross-axis alignment. (The legacy box model doesn't support this.)
    1778             :     // So, each FlexItem simply copies the container's converted "align-items"
    1779             :     // value and disregards their own "align-self" property.
    1780           0 :     const nsStyleXUL* containerStyleXUL = containerRS->mFrame->StyleXUL();
    1781           0 :     mAlignSelf = ConvertLegacyStyleToAlignItems(containerStyleXUL);
    1782             :   } else {
    1783           0 :     mAlignSelf = aFlexItemReflowInput.mStylePosition->UsedAlignSelf(
    1784           0 :                    containerRS->mFrame->StyleContext());
    1785           0 :     if (MOZ_LIKELY(mAlignSelf == NS_STYLE_ALIGN_NORMAL)) {
    1786           0 :       mAlignSelf = NS_STYLE_ALIGN_STRETCH;
    1787             :     }
    1788             : 
    1789             :     // XXX strip off the <overflow-position> bit until we implement that
    1790           0 :     mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS;
    1791             :   }
    1792             : 
    1793           0 :   SetFlexBaseSizeAndMainSize(aFlexBaseSize);
    1794           0 :   CheckForMinSizeAuto(aFlexItemReflowInput, aAxisTracker);
    1795             : 
    1796             :   // Assert that any "auto" margin components are set to 0.
    1797             :   // (We'll resolve them later; until then, we want to treat them as 0-sized.)
    1798             : #ifdef DEBUG
    1799             :   {
    1800             :     const nsStyleSides& styleMargin =
    1801           0 :       aFlexItemReflowInput.mStyleMargin->mMargin;
    1802           0 :     NS_FOR_CSS_SIDES(side) {
    1803           0 :       if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
    1804           0 :         MOZ_ASSERT(GetMarginComponentForSide(side) == 0,
    1805             :                    "Someone else tried to resolve our auto margin");
    1806             :       }
    1807             :     }
    1808             :   }
    1809             : #endif // DEBUG
    1810             : 
    1811             :   // Map align-self 'baseline' value to 'start' when baseline alignment
    1812             :   // is not possible because the FlexItem's writing mode is orthogonal to
    1813             :   // the main axis of the container. If that's the case, we just directly
    1814             :   // convert our align-self value here, so that we don't have to handle this
    1815             :   // with special cases elsewhere.
    1816             :   // We are treating this case as one where it is appropriate to use the
    1817             :   // fallback values defined at https://www.w3.org/TR/css-align-3/#baseline
    1818           0 :   if (aAxisTracker.IsRowOriented() ==
    1819           0 :       aAxisTracker.GetWritingMode().IsOrthogonalTo(mWM)) {
    1820           0 :     if (mAlignSelf == NS_STYLE_ALIGN_BASELINE) {
    1821           0 :       mAlignSelf = NS_STYLE_ALIGN_FLEX_START;
    1822           0 :     } else if (mAlignSelf == NS_STYLE_ALIGN_LAST_BASELINE) {
    1823           0 :       mAlignSelf = NS_STYLE_ALIGN_FLEX_END;
    1824             :     }
    1825             :   }
    1826           0 : }
    1827             : 
    1828             : // Simplified constructor for creating a special "strut" FlexItem, for a child
    1829             : // with visibility:collapse. The strut has 0 main-size, and it only exists to
    1830             : // impose a minimum cross size on whichever FlexLine it ends up in.
    1831           0 : FlexItem::FlexItem(nsIFrame* aChildFrame, nscoord aCrossSize,
    1832           0 :                    WritingMode aContainerWM)
    1833             :   : mFrame(aChildFrame),
    1834             :     mFlexGrow(0.0f),
    1835             :     mFlexShrink(0.0f),
    1836             :     mIntrinsicRatio(),
    1837             :     // mBorderPadding uses default constructor,
    1838             :     // mMargin uses default constructor,
    1839             :     mFlexBaseSize(0),
    1840             :     mMainMinSize(0),
    1841             :     mMainMaxSize(0),
    1842             :     mCrossMinSize(0),
    1843             :     mCrossMaxSize(0),
    1844             :     mMainSize(0),
    1845             :     mMainPosn(0),
    1846             :     mCrossSize(aCrossSize),
    1847             :     mCrossPosn(0),
    1848             :     mAscent(0),
    1849             :     mShareOfWeightSoFar(0.0f),
    1850             :     mIsFrozen(true),
    1851             :     mHadMinViolation(false),
    1852             :     mHadMaxViolation(false),
    1853             :     mHadMeasuringReflow(false),
    1854             :     mIsStretched(false),
    1855             :     mIsStrut(true), // (this is the constructor for making struts, after all)
    1856             :     mNeedsMinSizeAutoResolution(false),
    1857             :     mWM(aContainerWM),
    1858           0 :     mAlignSelf(NS_STYLE_ALIGN_FLEX_START)
    1859             : {
    1860           0 :   MOZ_ASSERT(mFrame, "expecting a non-null child frame");
    1861           0 :   MOZ_ASSERT(NS_STYLE_VISIBILITY_COLLAPSE ==
    1862             :              mFrame->StyleVisibility()->mVisible,
    1863             :              "Should only make struts for children with 'visibility:collapse'");
    1864           0 :   MOZ_ASSERT(!mFrame->IsPlaceholderFrame(),
    1865             :              "placeholder frames should not be treated as flex items");
    1866           0 :   MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
    1867             :              "out-of-flow frames should not be treated as flex items");
    1868           0 : }
    1869             : 
    1870             : void
    1871           0 : FlexItem::CheckForMinSizeAuto(const ReflowInput& aFlexItemReflowInput,
    1872             :                               const FlexboxAxisTracker& aAxisTracker)
    1873             : {
    1874           0 :   const nsStylePosition* pos = aFlexItemReflowInput.mStylePosition;
    1875           0 :   const nsStyleDisplay* disp = aFlexItemReflowInput.mStyleDisplay;
    1876             : 
    1877             :   // We'll need special behavior for "min-[width|height]:auto" (whichever is in
    1878             :   // the main axis) iff:
    1879             :   // (a) its computed value is "auto"
    1880             :   // (b) the "overflow" sub-property in the same axis (the main axis) has a
    1881             :   //     computed value of "visible"
    1882           0 :   const nsStyleCoord& minSize = GET_MAIN_COMPONENT(aAxisTracker,
    1883             :                                                    pos->mMinWidth,
    1884             :                                                    pos->mMinHeight);
    1885             : 
    1886           0 :   const uint8_t overflowVal = GET_MAIN_COMPONENT(aAxisTracker,
    1887             :                                                  disp->mOverflowX,
    1888             :                                                  disp->mOverflowY);
    1889             : 
    1890           0 :   mNeedsMinSizeAutoResolution = (minSize.GetUnit() == eStyleUnit_Auto &&
    1891             :                                  overflowVal == NS_STYLE_OVERFLOW_VISIBLE);
    1892           0 : }
    1893             : 
    1894             : nscoord
    1895           0 : FlexItem::GetBaselineOffsetFromOuterCrossEdge(
    1896             :   AxisEdgeType aEdge,
    1897             :   const FlexboxAxisTracker& aAxisTracker,
    1898             :   bool aUseFirstLineBaseline) const
    1899             : {
    1900             :   // NOTE: Currently, 'mAscent' (taken from reflow) is an inherently vertical
    1901             :   // measurement -- it's the distance from the border-top edge of this FlexItem
    1902             :   // to its baseline. So, we can really only do baseline alignment when the
    1903             :   // cross axis is vertical. (The FlexItem constructor enforces this when
    1904             :   // resolving the item's "mAlignSelf" value).
    1905           0 :   MOZ_ASSERT(!aAxisTracker.IsCrossAxisHorizontal(),
    1906             :              "Only expecting to be doing baseline computations when the "
    1907             :              "cross axis is vertical");
    1908             : 
    1909           0 :   AxisOrientationType crossAxis = aAxisTracker.GetCrossAxis();
    1910           0 :   mozilla::Side sideToMeasureFrom = kAxisOrientationToSidesMap[crossAxis][aEdge];
    1911             : 
    1912           0 :   nscoord marginTopToBaseline = ResolvedAscent(aUseFirstLineBaseline) +
    1913           0 :                                 mMargin.top;
    1914             : 
    1915           0 :   if (sideToMeasureFrom == eSideTop) {
    1916             :     // Measuring from top (normal case): the distance from the margin-box top
    1917             :     // edge to the baseline is just ascent + margin-top.
    1918           0 :     return marginTopToBaseline;
    1919             :   }
    1920             : 
    1921           0 :   MOZ_ASSERT(sideToMeasureFrom == eSideBottom,
    1922             :              "We already checked that we're dealing with a vertical axis, and "
    1923             :              "we're not using the top side, so that only leaves the bottom...");
    1924             : 
    1925             :   // Measuring from bottom: The distance from the margin-box bottom edge to the
    1926             :   // baseline is just the margin-box cross size (i.e. outer cross size), minus
    1927             :   // the already-computed distance from margin-top to baseline.
    1928           0 :   return GetOuterCrossSize(crossAxis) - marginTopToBaseline;
    1929             : }
    1930             : 
    1931             : uint32_t
    1932           0 : FlexItem::GetNumAutoMarginsInAxis(AxisOrientationType aAxis) const
    1933             : {
    1934           0 :   uint32_t numAutoMargins = 0;
    1935           0 :   const nsStyleSides& styleMargin = mFrame->StyleMargin()->mMargin;
    1936           0 :   for (uint32_t i = 0; i < eNumAxisEdges; i++) {
    1937           0 :     mozilla::Side side = kAxisOrientationToSidesMap[aAxis][i];
    1938           0 :     if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
    1939           0 :       numAutoMargins++;
    1940             :     }
    1941             :   }
    1942             : 
    1943             :   // Mostly for clarity:
    1944           0 :   MOZ_ASSERT(numAutoMargins <= 2,
    1945             :              "We're just looking at one item along one dimension, so we "
    1946             :              "should only have examined 2 margins");
    1947             : 
    1948           0 :   return numAutoMargins;
    1949             : }
    1950             : 
    1951             : bool
    1952           0 : FlexItem::CanMainSizeInfluenceCrossSize(
    1953             :   const FlexboxAxisTracker& aAxisTracker) const
    1954             : {
    1955           0 :   if (mIsStretched) {
    1956             :     // We've already had our cross-size stretched for "align-self:stretch").
    1957             :     // The container is imposing its cross size on us.
    1958           0 :     return false;
    1959             :   }
    1960             : 
    1961           0 :   if (mIsStrut) {
    1962             :     // Struts (for visibility:collapse items) have a predetermined size;
    1963             :     // no need to measure anything.
    1964           0 :     return false;
    1965             :   }
    1966             : 
    1967           0 :   if (HasIntrinsicRatio()) {
    1968             :     // For flex items that have an intrinsic ratio (and maintain it, i.e. are
    1969             :     // not stretched, which we already checked above): changes to main-size
    1970             :     // *do* influence the cross size.
    1971           0 :     return true;
    1972             :   }
    1973             : 
    1974           0 :   if (aAxisTracker.IsCrossAxisHorizontal()) {
    1975             :     // If the cross axis is horizontal, then changes to the item's main size
    1976             :     // (height) can't influence its cross size (width), if the item is a block
    1977             :     // with a horizontal writing-mode.
    1978             :     // XXXdholbert This doesn't account for vertical writing-modes, items with
    1979             :     // aspect ratios, items that are multicol elements, & items that are
    1980             :     // multi-line vertical flex containers. In all of those cases, a change to
    1981             :     // the height could influence the width.
    1982           0 :     return false;
    1983             :   }
    1984             : 
    1985             :   // Default assumption, if we haven't proven otherwise: the resolved main size
    1986             :   // *can* change the cross size.
    1987           0 :   return true;
    1988             : }
    1989             : 
    1990             : // Keeps track of our position along a particular axis (where a '0' position
    1991             : // corresponds to the 'start' edge of that axis).
    1992             : // This class shouldn't be instantiated directly -- rather, it should only be
    1993             : // instantiated via its subclasses defined below.
    1994             : class MOZ_STACK_CLASS PositionTracker {
    1995             : public:
    1996             :   // Accessor for the current value of the position that we're tracking.
    1997           0 :   inline nscoord GetPosition() const { return mPosition; }
    1998           0 :   inline AxisOrientationType GetAxis() const { return mAxis; }
    1999             : 
    2000             :   // Advances our position across the start edge of the given margin, in the
    2001             :   // axis we're tracking.
    2002           0 :   void EnterMargin(const nsMargin& aMargin)
    2003             :   {
    2004           0 :     mozilla::Side side = kAxisOrientationToSidesMap[mAxis][eAxisEdge_Start];
    2005           0 :     mPosition += aMargin.Side(side);
    2006           0 :   }
    2007             : 
    2008             :   // Advances our position across the end edge of the given margin, in the axis
    2009             :   // we're tracking.
    2010           0 :   void ExitMargin(const nsMargin& aMargin)
    2011             :   {
    2012           0 :     mozilla::Side side = kAxisOrientationToSidesMap[mAxis][eAxisEdge_End];
    2013           0 :     mPosition += aMargin.Side(side);
    2014           0 :   }
    2015             : 
    2016             :   // Advances our current position from the start side of a child frame's
    2017             :   // border-box to the frame's upper or left edge (depending on our axis).
    2018             :   // (Note that this is a no-op if our axis grows in the same direction as
    2019             :   // the corresponding logical axis.)
    2020           0 :   void EnterChildFrame(nscoord aChildFrameSize)
    2021             :   {
    2022           0 :     if (mIsAxisReversed) {
    2023           0 :       mPosition += aChildFrameSize;
    2024             :     }
    2025           0 :   }
    2026             : 
    2027             :   // Advances our current position from a frame's upper or left border-box edge
    2028             :   // (whichever is in the axis we're tracking) to the 'end' side of the frame
    2029             :   // in the axis that we're tracking. (Note that this is a no-op if our axis
    2030             :   // is reversed with respect to the corresponding logical axis.)
    2031           0 :   void ExitChildFrame(nscoord aChildFrameSize)
    2032             :   {
    2033           0 :     if (!mIsAxisReversed) {
    2034           0 :       mPosition += aChildFrameSize;
    2035             :     }
    2036           0 :   }
    2037             : 
    2038             : protected:
    2039             :   // Protected constructor, to be sure we're only instantiated via a subclass.
    2040           0 :   PositionTracker(AxisOrientationType aAxis, bool aIsAxisReversed)
    2041           0 :     : mPosition(0),
    2042             :       mAxis(aAxis),
    2043           0 :       mIsAxisReversed(aIsAxisReversed)
    2044           0 :   {}
    2045             : 
    2046             :   // Delete copy-constructor & reassignment operator, to prevent accidental
    2047             :   // (unnecessary) copying.
    2048             :   PositionTracker(const PositionTracker&) = delete;
    2049             :   PositionTracker& operator=(const PositionTracker&) = delete;
    2050             : 
    2051             :   // Member data:
    2052             :   nscoord mPosition;               // The position we're tracking
    2053             :   // XXXdholbert [BEGIN DEPRECATED]
    2054             :   const AxisOrientationType mAxis; // The axis along which we're moving.
    2055             :   // XXXdholbert [END DEPRECATED]
    2056             :   const bool mIsAxisReversed; // Is the axis along which we're moving reversed
    2057             :                               // (e.g. LTR vs RTL) with respect to the
    2058             :                               // corresponding axis on the flex container's WM?
    2059             : };
    2060             : 
    2061             : // Tracks our position in the main axis, when we're laying out flex items.
    2062             : // The "0" position represents the main-start edge of the flex container's
    2063             : // content-box.
    2064             : class MOZ_STACK_CLASS MainAxisPositionTracker : public PositionTracker {
    2065             : public:
    2066             :   MainAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker,
    2067             :                           const FlexLine* aLine,
    2068             :                           uint8_t aJustifyContent,
    2069             :                           nscoord aContentBoxMainSize);
    2070             : 
    2071           0 :   ~MainAxisPositionTracker() {
    2072           0 :     MOZ_ASSERT(mNumPackingSpacesRemaining == 0,
    2073             :                "miscounted the number of packing spaces");
    2074           0 :     MOZ_ASSERT(mNumAutoMarginsInMainAxis == 0,
    2075             :                "miscounted the number of auto margins");
    2076           0 :   }
    2077             : 
    2078             :   // Advances past the packing space (if any) between two flex items
    2079             :   void TraversePackingSpace();
    2080             : 
    2081             :   // If aItem has any 'auto' margins in the main axis, this method updates the
    2082             :   // corresponding values in its margin.
    2083             :   void ResolveAutoMarginsInMainAxis(FlexItem& aItem);
    2084             : 
    2085             : private:
    2086             :   nscoord  mPackingSpaceRemaining;
    2087             :   uint32_t mNumAutoMarginsInMainAxis;
    2088             :   uint32_t mNumPackingSpacesRemaining;
    2089             :   // XXX this should be uint16_t when we add explicit fallback handling
    2090             :   uint8_t  mJustifyContent;
    2091             : };
    2092             : 
    2093             : // Utility class for managing our position along the cross axis along
    2094             : // the whole flex container (at a higher level than a single line).
    2095             : // The "0" position represents the cross-start edge of the flex container's
    2096             : // content-box.
    2097             : class MOZ_STACK_CLASS CrossAxisPositionTracker : public PositionTracker {
    2098             : public:
    2099             :   CrossAxisPositionTracker(FlexLine* aFirstLine,
    2100             :                            const ReflowInput& aReflowInput,
    2101             :                            nscoord aContentBoxCrossSize,
    2102             :                            bool aIsCrossSizeDefinite,
    2103             :                            const FlexboxAxisTracker& aAxisTracker);
    2104             : 
    2105             :   // Advances past the packing space (if any) between two flex lines
    2106             :   void TraversePackingSpace();
    2107             : 
    2108             :   // Advances past the given FlexLine
    2109           0 :   void TraverseLine(FlexLine& aLine) { mPosition += aLine.GetLineCrossSize(); }
    2110             : 
    2111             : private:
    2112             :   // Redeclare the frame-related methods from PositionTracker as private with
    2113             :   // = delete, to be sure (at compile time) that no client code can invoke
    2114             :   // them. (Unlike the other PositionTracker derived classes, this class here
    2115             :   // deals with FlexLines, not with individual FlexItems or frames.)
    2116             :   void EnterMargin(const nsMargin& aMargin) = delete;
    2117             :   void ExitMargin(const nsMargin& aMargin) = delete;
    2118             :   void EnterChildFrame(nscoord aChildFrameSize) = delete;
    2119             :   void ExitChildFrame(nscoord aChildFrameSize) = delete;
    2120             : 
    2121             :   nscoord  mPackingSpaceRemaining;
    2122             :   uint32_t mNumPackingSpacesRemaining;
    2123             :   // XXX this should be uint16_t when we add explicit fallback handling
    2124             :   uint8_t  mAlignContent;
    2125             : };
    2126             : 
    2127             : // Utility class for managing our position along the cross axis, *within* a
    2128             : // single flex line.
    2129             : class MOZ_STACK_CLASS SingleLineCrossAxisPositionTracker : public PositionTracker {
    2130             : public:
    2131             :   explicit SingleLineCrossAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker);
    2132             : 
    2133             :   void ResolveAutoMarginsInCrossAxis(const FlexLine& aLine,
    2134             :                                      FlexItem& aItem);
    2135             : 
    2136             :   void EnterAlignPackingSpace(const FlexLine& aLine,
    2137             :                               const FlexItem& aItem,
    2138             :                               const FlexboxAxisTracker& aAxisTracker);
    2139             : 
    2140             :   // Resets our position to the cross-start edge of this line.
    2141           0 :   inline void ResetPosition() { mPosition = 0; }
    2142             : };
    2143             : 
    2144             : //----------------------------------------------------------------------
    2145             : 
    2146             : // Frame class boilerplate
    2147             : // =======================
    2148             : 
    2149           0 : NS_QUERYFRAME_HEAD(nsFlexContainerFrame)
    2150           0 :   NS_QUERYFRAME_ENTRY(nsFlexContainerFrame)
    2151           0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    2152             : 
    2153           0 : NS_IMPL_FRAMEARENA_HELPERS(nsFlexContainerFrame)
    2154             : 
    2155             : nsContainerFrame*
    2156           0 : NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
    2157             :                          nsStyleContext* aContext)
    2158             : {
    2159           0 :   return new (aPresShell) nsFlexContainerFrame(aContext);
    2160             : }
    2161             : 
    2162             : //----------------------------------------------------------------------
    2163             : 
    2164             : // nsFlexContainerFrame Method Implementations
    2165             : // ===========================================
    2166             : 
    2167             : /* virtual */
    2168           0 : nsFlexContainerFrame::~nsFlexContainerFrame()
    2169             : {
    2170           0 : }
    2171             : 
    2172             : /* virtual */
    2173             : void
    2174           0 : nsFlexContainerFrame::Init(nsIContent*       aContent,
    2175             :                            nsContainerFrame* aParent,
    2176             :                            nsIFrame*         aPrevInFlow)
    2177             : {
    2178           0 :   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    2179             : 
    2180           0 :   const nsStyleDisplay* styleDisp = StyleContext()->StyleDisplay();
    2181             : 
    2182             :   // Figure out if we should set a frame state bit to indicate that this frame
    2183             :   // represents a legacy -webkit-{inline-}box container.
    2184             :   // First, the trivial case: just check "display" directly.
    2185           0 :   bool isLegacyBox = IsDisplayValueLegacyBox(styleDisp);
    2186             : 
    2187             :   // If this frame is for a scrollable element, then it will actually have
    2188             :   // "display:block", and its *parent frame* will have the real
    2189             :   // flex-flavored display value. So in that case, check the parent frame to
    2190             :   // find out if we're legacy.
    2191           0 :   if (!isLegacyBox && styleDisp->mDisplay == mozilla::StyleDisplay::Block) {
    2192           0 :     nsStyleContext* parentStyleContext = GetParent()->StyleContext();
    2193           0 :     NS_ASSERTION(parentStyleContext &&
    2194             :                  (mStyleContext->GetPseudo() == nsCSSAnonBoxes::buttonContent ||
    2195             :                   mStyleContext->GetPseudo() == nsCSSAnonBoxes::scrolledContent),
    2196             :                  "The only way a nsFlexContainerFrame can have 'display:block' "
    2197             :                  "should be if it's the inner part of a scrollable or button "
    2198             :                  "element");
    2199           0 :     isLegacyBox = IsDisplayValueLegacyBox(parentStyleContext->StyleDisplay());
    2200             :   }
    2201             : 
    2202           0 :   if (isLegacyBox) {
    2203           0 :     AddStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX);
    2204             :   }
    2205           0 : }
    2206             : 
    2207             : #ifdef DEBUG_FRAME_DUMP
    2208             : nsresult
    2209           0 : nsFlexContainerFrame::GetFrameName(nsAString& aResult) const
    2210             : {
    2211           0 :   return MakeFrameName(NS_LITERAL_STRING("FlexContainer"), aResult);
    2212             : }
    2213             : #endif
    2214             : 
    2215             : nscoord
    2216           0 : nsFlexContainerFrame::GetLogicalBaseline(mozilla::WritingMode aWM) const
    2217             : {
    2218           0 :   NS_ASSERTION(mBaselineFromLastReflow != NS_INTRINSIC_WIDTH_UNKNOWN,
    2219             :                "baseline has not been set");
    2220             : 
    2221           0 :   if (HasAnyStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE)) {
    2222             :     // Return a baseline synthesized from our margin-box.
    2223           0 :     return nsContainerFrame::GetLogicalBaseline(aWM);
    2224             :   }
    2225           0 :   return mBaselineFromLastReflow;
    2226             : }
    2227             : 
    2228             : // Helper for BuildDisplayList, to implement this special-case for flex items
    2229             : // from the spec:
    2230             : //    Flex items paint exactly the same as block-level elements in the
    2231             : //    normal flow, except that 'z-index' values other than 'auto' create
    2232             : //    a stacking context even if 'position' is 'static'.
    2233             : // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#painting
    2234             : uint32_t
    2235           0 : GetDisplayFlagsForFlexItem(nsIFrame* aFrame)
    2236             : {
    2237           0 :   MOZ_ASSERT(aFrame->IsFlexItem(), "Should only be called on flex items");
    2238             : 
    2239           0 :   const nsStylePosition* pos = aFrame->StylePosition();
    2240           0 :   if (pos->mZIndex.GetUnit() == eStyleUnit_Integer) {
    2241           0 :     return nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT;
    2242             :   }
    2243           0 :   return nsIFrame::DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT;
    2244             : }
    2245             : 
    2246             : void
    2247           0 : nsFlexContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    2248             :                                        const nsRect&           aDirtyRect,
    2249             :                                        const nsDisplayListSet& aLists)
    2250             : {
    2251           0 :   DisplayBorderBackgroundOutline(aBuilder, aLists);
    2252             : 
    2253             :   // Our children are all block-level, so their borders/backgrounds all go on
    2254             :   // the BlockBorderBackgrounds list.
    2255           0 :   nsDisplayListSet childLists(aLists, aLists.BlockBorderBackgrounds());
    2256             : 
    2257             :   typedef CSSOrderAwareFrameIterator::OrderState OrderState;
    2258             :   OrderState orderState =
    2259           0 :     HasAnyStateBits(NS_STATE_FLEX_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
    2260           0 :     ? OrderState::eKnownOrdered
    2261           0 :     : OrderState::eKnownUnordered;
    2262             : 
    2263             :   CSSOrderAwareFrameIterator iter(this, kPrincipalList,
    2264             :                                   CSSOrderAwareFrameIterator::eIncludeAll,
    2265             :                                   orderState,
    2266           0 :                                   OrderingPropertyForIter(this));
    2267           0 :   for (; !iter.AtEnd(); iter.Next()) {
    2268           0 :     nsIFrame* childFrame = *iter;
    2269           0 :     BuildDisplayListForChild(aBuilder, childFrame, aDirtyRect, childLists,
    2270           0 :                              GetDisplayFlagsForFlexItem(childFrame));
    2271             :   }
    2272           0 : }
    2273             : 
    2274             : void
    2275           0 : FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow)
    2276             : {
    2277             :   // After we've established the type of flexing we're doing (growing vs.
    2278             :   // shrinking), and before we try to flex any items, we freeze items that
    2279             :   // obviously *can't* flex.
    2280             :   //
    2281             :   // Quoting the spec:
    2282             :   //  # Freeze, setting its target main size to its hypothetical main size...
    2283             :   //  #  - any item that has a flex factor of zero
    2284             :   //  #  - if using the flex grow factor: any item that has a flex base size
    2285             :   //  #    greater than its hypothetical main size
    2286             :   //  #  - if using the flex shrink factor: any item that has a flex base size
    2287             :   //  #    smaller than its hypothetical main size
    2288             :   //  http://dev.w3.org/csswg/css-flexbox/#resolve-flexible-lengths-flex-factors
    2289             :   //
    2290             :   // (NOTE: At this point, item->GetMainSize() *is* the item's hypothetical
    2291             :   // main size, since SetFlexBaseSizeAndMainSize() sets it up that way, and the
    2292             :   // item hasn't had a chance to flex away from that yet.)
    2293             : 
    2294             :   // Since this loop only operates on unfrozen flex items, we can break as
    2295             :   // soon as we have seen all of them.
    2296           0 :   uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
    2297           0 :   for (FlexItem* item = mItems.getFirst();
    2298           0 :        numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
    2299           0 :     MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
    2300             : 
    2301           0 :     if (!item->IsFrozen()) {
    2302           0 :       numUnfrozenItemsToBeSeen--;
    2303           0 :       bool shouldFreeze = (0.0f == item->GetFlexFactor(aIsUsingFlexGrow));
    2304           0 :       if (!shouldFreeze) {
    2305           0 :         if (aIsUsingFlexGrow) {
    2306           0 :           if (item->GetFlexBaseSize() > item->GetMainSize()) {
    2307           0 :             shouldFreeze = true;
    2308             :           }
    2309             :         } else { // using flex-shrink
    2310           0 :           if (item->GetFlexBaseSize() < item->GetMainSize()) {
    2311           0 :             shouldFreeze = true;
    2312             :           }
    2313             :         }
    2314             :       }
    2315           0 :       if (shouldFreeze) {
    2316             :         // Freeze item! (at its hypothetical main size)
    2317           0 :         item->Freeze();
    2318           0 :         mNumFrozenItems++;
    2319             :       }
    2320             :     }
    2321             :   }
    2322           0 : }
    2323             : 
    2324             : // Based on the sign of aTotalViolation, this function freezes a subset of our
    2325             : // flexible sizes, and restores the remaining ones to their initial pref sizes.
    2326             : void
    2327           0 : FlexLine::FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
    2328             :                                           bool aIsFinalIteration)
    2329             : {
    2330             :   enum FreezeType {
    2331             :     eFreezeEverything,
    2332             :     eFreezeMinViolations,
    2333             :     eFreezeMaxViolations
    2334             :   };
    2335             : 
    2336             :   FreezeType freezeType;
    2337           0 :   if (aTotalViolation == 0) {
    2338           0 :     freezeType = eFreezeEverything;
    2339           0 :   } else if (aTotalViolation > 0) {
    2340           0 :     freezeType = eFreezeMinViolations;
    2341             :   } else { // aTotalViolation < 0
    2342           0 :     freezeType = eFreezeMaxViolations;
    2343             :   }
    2344             : 
    2345             :   // Since this loop only operates on unfrozen flex items, we can break as
    2346             :   // soon as we have seen all of them.
    2347           0 :   uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
    2348           0 :   for (FlexItem* item = mItems.getFirst();
    2349           0 :        numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
    2350           0 :     MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
    2351           0 :     if (!item->IsFrozen()) {
    2352           0 :       numUnfrozenItemsToBeSeen--;
    2353             : 
    2354           0 :       MOZ_ASSERT(!item->HadMinViolation() || !item->HadMaxViolation(),
    2355             :                  "Can have either min or max violation, but not both");
    2356             : 
    2357           0 :       if (eFreezeEverything == freezeType ||
    2358           0 :           (eFreezeMinViolations == freezeType && item->HadMinViolation()) ||
    2359           0 :           (eFreezeMaxViolations == freezeType && item->HadMaxViolation())) {
    2360             : 
    2361           0 :         MOZ_ASSERT(item->GetMainSize() >= item->GetMainMinSize(),
    2362             :                    "Freezing item at a size below its minimum");
    2363           0 :         MOZ_ASSERT(item->GetMainSize() <= item->GetMainMaxSize(),
    2364             :                    "Freezing item at a size above its maximum");
    2365             : 
    2366           0 :         item->Freeze();
    2367           0 :         mNumFrozenItems++;
    2368           0 :       } else if (MOZ_UNLIKELY(aIsFinalIteration)) {
    2369             :         // XXXdholbert If & when bug 765861 is fixed, we should upgrade this
    2370             :         // assertion to be fatal except in documents with enormous lengths.
    2371           0 :         NS_ERROR("Final iteration still has unfrozen items, this shouldn't"
    2372             :                  " happen unless there was nscoord under/overflow.");
    2373           0 :         item->Freeze();
    2374           0 :         mNumFrozenItems++;
    2375             :       } // else, we'll reset this item's main size to its flex base size on the
    2376             :         // next iteration of this algorithm.
    2377             : 
    2378             :       // Clear this item's violation(s), now that we've dealt with them
    2379           0 :       item->ClearViolationFlags();
    2380             :     }
    2381             :   }
    2382           0 : }
    2383             : 
    2384             : void
    2385           0 : FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize)
    2386             : {
    2387           0 :   MOZ_LOG(gFlexContainerLog, LogLevel::Debug, ("ResolveFlexibleLengths\n"));
    2388             : 
    2389             :   // Determine whether we're going to be growing or shrinking items.
    2390             :   const bool isUsingFlexGrow =
    2391           0 :     (mTotalOuterHypotheticalMainSize < aFlexContainerMainSize);
    2392             : 
    2393             :   // Do an "early freeze" for flex items that obviously can't flex in the
    2394             :   // direction we've chosen:
    2395           0 :   FreezeItemsEarly(isUsingFlexGrow);
    2396             : 
    2397           0 :   if (mNumFrozenItems == mNumItems) {
    2398             :     // All our items are frozen, so we have no flexible lengths to resolve.
    2399           0 :     return;
    2400             :   }
    2401           0 :   MOZ_ASSERT(!IsEmpty(), "empty lines should take the early-return above");
    2402             : 
    2403             :   // Subtract space occupied by our items' margins/borders/padding, so we can
    2404             :   // just be dealing with the space available for our flex items' content
    2405             :   // boxes.
    2406             :   nscoord spaceReservedForMarginBorderPadding =
    2407           0 :     mTotalOuterHypotheticalMainSize - mTotalInnerHypotheticalMainSize;
    2408             : 
    2409             :   nscoord spaceAvailableForFlexItemsContentBoxes =
    2410           0 :     aFlexContainerMainSize - spaceReservedForMarginBorderPadding;
    2411             : 
    2412             :   nscoord origAvailableFreeSpace;
    2413           0 :   bool isOrigAvailFreeSpaceInitialized = false;
    2414             : 
    2415             :   // NOTE: I claim that this chunk of the algorithm (the looping part) needs to
    2416             :   // run the loop at MOST mNumItems times.  This claim should hold up
    2417             :   // because we'll freeze at least one item on each loop iteration, and once
    2418             :   // we've run out of items to freeze, there's nothing left to do.  However,
    2419             :   // in most cases, we'll break out of this loop long before we hit that many
    2420             :   // iterations.
    2421           0 :   for (uint32_t iterationCounter = 0;
    2422           0 :        iterationCounter < mNumItems; iterationCounter++) {
    2423             :     // Set every not-yet-frozen item's used main size to its
    2424             :     // flex base size, and subtract all the used main sizes from our
    2425             :     // total amount of space to determine the 'available free space'
    2426             :     // (positive or negative) to be distributed among our flexible items.
    2427           0 :     nscoord availableFreeSpace = spaceAvailableForFlexItemsContentBoxes;
    2428           0 :     for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
    2429           0 :       if (!item->IsFrozen()) {
    2430           0 :         item->SetMainSize(item->GetFlexBaseSize());
    2431             :       }
    2432           0 :       availableFreeSpace -= item->GetMainSize();
    2433             :     }
    2434             : 
    2435           0 :     MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
    2436             :            (" available free space = %d\n", availableFreeSpace));
    2437             : 
    2438             : 
    2439             :     // The sign of our free space should agree with the type of flexing
    2440             :     // (grow/shrink) that we're doing (except if we've had integer overflow;
    2441             :     // then, all bets are off). Any disagreement should've made us use the
    2442             :     // other type of flexing, or should've been resolved in FreezeItemsEarly.
    2443             :     // XXXdholbert If & when bug 765861 is fixed, we should upgrade this
    2444             :     // assertion to be fatal except in documents with enormous lengths.
    2445           0 :     NS_ASSERTION((isUsingFlexGrow && availableFreeSpace >= 0) ||
    2446             :                  (!isUsingFlexGrow && availableFreeSpace <= 0),
    2447             :                  "availableFreeSpace's sign should match isUsingFlexGrow");
    2448             : 
    2449             :     // If we have any free space available, give each flexible item a portion
    2450             :     // of availableFreeSpace.
    2451           0 :     if (availableFreeSpace != 0) {
    2452             :       // The first time we do this, we initialize origAvailableFreeSpace.
    2453           0 :       if (!isOrigAvailFreeSpaceInitialized) {
    2454           0 :         origAvailableFreeSpace = availableFreeSpace;
    2455           0 :         isOrigAvailFreeSpaceInitialized = true;
    2456             :       }
    2457             : 
    2458             :       // STRATEGY: On each item, we compute & store its "share" of the total
    2459             :       // weight that we've seen so far:
    2460             :       //   curWeight / weightSum
    2461             :       //
    2462             :       // Then, when we go to actually distribute the space (in the next loop),
    2463             :       // we can simply walk backwards through the elements and give each item
    2464             :       // its "share" multiplied by the remaining available space.
    2465             :       //
    2466             :       // SPECIAL CASE: If the sum of the weights is larger than the
    2467             :       // maximum representable float (overflowing to infinity), then we can't
    2468             :       // sensibly divide out proportional shares anymore. In that case, we
    2469             :       // simply treat the flex item(s) with the largest weights as if
    2470             :       // their weights were infinite (dwarfing all the others), and we
    2471             :       // distribute all of the available space among them.
    2472           0 :       float weightSum = 0.0f;
    2473           0 :       float flexFactorSum = 0.0f;
    2474           0 :       float largestWeight = 0.0f;
    2475           0 :       uint32_t numItemsWithLargestWeight = 0;
    2476             : 
    2477             :       // Since this loop only operates on unfrozen flex items, we can break as
    2478             :       // soon as we have seen all of them.
    2479           0 :       uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
    2480           0 :       for (FlexItem* item = mItems.getFirst();
    2481           0 :            numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
    2482           0 :         MOZ_ASSERT(item,
    2483             :                    "numUnfrozenItemsToBeSeen says items remain to be seen");
    2484           0 :         if (!item->IsFrozen()) {
    2485           0 :           numUnfrozenItemsToBeSeen--;
    2486             : 
    2487           0 :           float curWeight = item->GetWeight(isUsingFlexGrow);
    2488           0 :           float curFlexFactor = item->GetFlexFactor(isUsingFlexGrow);
    2489           0 :           MOZ_ASSERT(curWeight >= 0.0f, "weights are non-negative");
    2490           0 :           MOZ_ASSERT(curFlexFactor >= 0.0f, "flex factors are non-negative");
    2491             : 
    2492           0 :           weightSum += curWeight;
    2493           0 :           flexFactorSum += curFlexFactor;
    2494             : 
    2495           0 :           if (IsFinite(weightSum)) {
    2496           0 :             if (curWeight == 0.0f) {
    2497           0 :               item->SetShareOfWeightSoFar(0.0f);
    2498             :             } else {
    2499           0 :               item->SetShareOfWeightSoFar(curWeight / weightSum);
    2500             :             }
    2501             :           } // else, the sum of weights overflows to infinity, in which
    2502             :             // case we don't bother with "SetShareOfWeightSoFar" since
    2503             :             // we know we won't use it. (instead, we'll just give every
    2504             :             // item with the largest weight an equal share of space.)
    2505             : 
    2506             :           // Update our largest-weight tracking vars
    2507           0 :           if (curWeight > largestWeight) {
    2508           0 :             largestWeight = curWeight;
    2509           0 :             numItemsWithLargestWeight = 1;
    2510           0 :           } else if (curWeight == largestWeight) {
    2511           0 :             numItemsWithLargestWeight++;
    2512             :           }
    2513             :         }
    2514             :       }
    2515             : 
    2516           0 :       if (weightSum != 0.0f) {
    2517           0 :         MOZ_ASSERT(flexFactorSum != 0.0f,
    2518             :                    "flex factor sum can't be 0, if a weighted sum "
    2519             :                    "of its components (weightSum) is nonzero");
    2520           0 :         if (flexFactorSum < 1.0f) {
    2521             :           // Our unfrozen flex items don't want all of the original free space!
    2522             :           // (Their flex factors add up to something less than 1.)
    2523             :           // Hence, make sure we don't distribute any more than the portion of
    2524             :           // our original free space that these items actually want.
    2525             :           nscoord totalDesiredPortionOfOrigFreeSpace =
    2526           0 :             NSToCoordRound(origAvailableFreeSpace * flexFactorSum);
    2527             : 
    2528             :           // Clamp availableFreeSpace to be no larger than that ^^.
    2529             :           // (using min or max, depending on sign).
    2530             :           // This should not change the sign of availableFreeSpace (except
    2531             :           // possibly by setting it to 0), as enforced by this assertion:
    2532           0 :           MOZ_ASSERT(totalDesiredPortionOfOrigFreeSpace == 0 ||
    2533             :                      ((totalDesiredPortionOfOrigFreeSpace > 0) ==
    2534             :                       (availableFreeSpace > 0)),
    2535             :                      "When we reduce available free space for flex factors < 1,"
    2536             :                      "we shouldn't change the sign of the free space...");
    2537             : 
    2538           0 :           if (availableFreeSpace > 0) {
    2539           0 :             availableFreeSpace = std::min(availableFreeSpace,
    2540           0 :                                           totalDesiredPortionOfOrigFreeSpace);
    2541             :           } else {
    2542           0 :             availableFreeSpace = std::max(availableFreeSpace,
    2543           0 :                                           totalDesiredPortionOfOrigFreeSpace);
    2544             :           }
    2545             :         }
    2546             : 
    2547           0 :         MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
    2548             :                (" Distributing available space:"));
    2549             :         // Since this loop only operates on unfrozen flex items, we can break as
    2550             :         // soon as we have seen all of them.
    2551           0 :         numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
    2552             : 
    2553             :         // NOTE: It's important that we traverse our items in *reverse* order
    2554             :         // here, for correct width distribution according to the items'
    2555             :         // "ShareOfWeightSoFar" progressively-calculated values.
    2556           0 :         for (FlexItem* item = mItems.getLast();
    2557           0 :              numUnfrozenItemsToBeSeen > 0; item = item->getPrevious()) {
    2558           0 :           MOZ_ASSERT(item,
    2559             :                      "numUnfrozenItemsToBeSeen says items remain to be seen");
    2560           0 :           if (!item->IsFrozen()) {
    2561           0 :             numUnfrozenItemsToBeSeen--;
    2562             : 
    2563             :             // To avoid rounding issues, we compute the change in size for this
    2564             :             // item, and then subtract it from the remaining available space.
    2565           0 :             nscoord sizeDelta = 0;
    2566           0 :             if (IsFinite(weightSum)) {
    2567             :               float myShareOfRemainingSpace =
    2568           0 :                 item->GetShareOfWeightSoFar();
    2569             : 
    2570           0 :               MOZ_ASSERT(myShareOfRemainingSpace >= 0.0f &&
    2571             :                          myShareOfRemainingSpace <= 1.0f,
    2572             :                          "my share should be nonnegative fractional amount");
    2573             : 
    2574           0 :               if (myShareOfRemainingSpace == 1.0f) {
    2575             :                 // (We special-case 1.0f to avoid float error from converting
    2576             :                 // availableFreeSpace from integer*1.0f --> float --> integer)
    2577           0 :                 sizeDelta = availableFreeSpace;
    2578           0 :               } else if (myShareOfRemainingSpace > 0.0f) {
    2579           0 :                 sizeDelta = NSToCoordRound(availableFreeSpace *
    2580           0 :                                            myShareOfRemainingSpace);
    2581             :               }
    2582           0 :             } else if (item->GetWeight(isUsingFlexGrow) == largestWeight) {
    2583             :               // Total flexibility is infinite, so we're just distributing
    2584             :               // the available space equally among the items that are tied for
    2585             :               // having the largest weight (and this is one of those items).
    2586             :               sizeDelta =
    2587           0 :                 NSToCoordRound(availableFreeSpace /
    2588           0 :                                float(numItemsWithLargestWeight));
    2589           0 :               numItemsWithLargestWeight--;
    2590             :             }
    2591             : 
    2592           0 :             availableFreeSpace -= sizeDelta;
    2593             : 
    2594           0 :             item->SetMainSize(item->GetMainSize() + sizeDelta);
    2595           0 :             MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
    2596             :                    ("  child %p receives %d, for a total of %d\n",
    2597             :                     item, sizeDelta, item->GetMainSize()));
    2598             :           }
    2599             :         }
    2600             :       }
    2601             :     }
    2602             : 
    2603             :     // Fix min/max violations:
    2604           0 :     nscoord totalViolation = 0; // keeps track of adjustments for min/max
    2605           0 :     MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
    2606             :            (" Checking for violations:"));
    2607             : 
    2608             :     // Since this loop only operates on unfrozen flex items, we can break as
    2609             :     // soon as we have seen all of them.
    2610           0 :     uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
    2611           0 :     for (FlexItem* item = mItems.getFirst();
    2612           0 :          numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
    2613           0 :       MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
    2614           0 :       if (!item->IsFrozen()) {
    2615           0 :         numUnfrozenItemsToBeSeen--;
    2616             : 
    2617           0 :         if (item->GetMainSize() < item->GetMainMinSize()) {
    2618             :           // min violation
    2619           0 :           totalViolation += item->GetMainMinSize() - item->GetMainSize();
    2620           0 :           item->SetMainSize(item->GetMainMinSize());
    2621           0 :           item->SetHadMinViolation();
    2622           0 :         } else if (item->GetMainSize() > item->GetMainMaxSize()) {
    2623             :           // max violation
    2624           0 :           totalViolation += item->GetMainMaxSize() - item->GetMainSize();
    2625           0 :           item->SetMainSize(item->GetMainMaxSize());
    2626           0 :           item->SetHadMaxViolation();
    2627             :         }
    2628             :       }
    2629             :     }
    2630             : 
    2631           0 :     FreezeOrRestoreEachFlexibleSize(totalViolation,
    2632           0 :                                     iterationCounter + 1 == mNumItems);
    2633             : 
    2634           0 :     MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
    2635             :            (" Total violation: %d\n", totalViolation));
    2636             : 
    2637           0 :     if (mNumFrozenItems == mNumItems) {
    2638           0 :       break;
    2639             :     }
    2640             : 
    2641           0 :     MOZ_ASSERT(totalViolation != 0,
    2642             :                "Zero violation should've made us freeze all items & break");
    2643             :   }
    2644             : 
    2645             : #ifdef DEBUG
    2646             :   // Post-condition: all items should've been frozen.
    2647             :   // Make sure the counts match:
    2648           0 :   MOZ_ASSERT(mNumFrozenItems == mNumItems, "All items should be frozen");
    2649             : 
    2650             :   // For good measure, check each item directly, in case our counts are busted:
    2651           0 :   for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
    2652           0 :     MOZ_ASSERT(item->IsFrozen(), "All items should be frozen");
    2653             :   }
    2654             : #endif // DEBUG
    2655             : }
    2656             : 
    2657           0 : MainAxisPositionTracker::
    2658             :   MainAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker,
    2659             :                           const FlexLine* aLine,
    2660             :                           uint8_t aJustifyContent,
    2661           0 :                           nscoord aContentBoxMainSize)
    2662             :   : PositionTracker(aAxisTracker.GetMainAxis(),
    2663           0 :                     aAxisTracker.IsMainAxisReversed()),
    2664             :     mPackingSpaceRemaining(aContentBoxMainSize), // we chip away at this below
    2665             :     mNumAutoMarginsInMainAxis(0),
    2666             :     mNumPackingSpacesRemaining(0),
    2667           0 :     mJustifyContent(aJustifyContent)
    2668             : {
    2669             :   // 'normal' behaves as 'stretch', and 'stretch' behaves as 'flex-start',
    2670             :   // in the main axis
    2671             :   // https://drafts.csswg.org/css-align-3/#propdef-justify-content
    2672           0 :   if (mJustifyContent == NS_STYLE_JUSTIFY_NORMAL ||
    2673           0 :       mJustifyContent == NS_STYLE_JUSTIFY_STRETCH) {
    2674           0 :     mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
    2675             :   }
    2676             : 
    2677             :   // XXX strip off the <overflow-position> bit until we implement that
    2678           0 :   mJustifyContent &= ~NS_STYLE_JUSTIFY_FLAG_BITS;
    2679             : 
    2680             :   // mPackingSpaceRemaining is initialized to the container's main size.  Now
    2681             :   // we'll subtract out the main sizes of our flex items, so that it ends up
    2682             :   // with the *actual* amount of packing space.
    2683           0 :   for (const FlexItem* item = aLine->GetFirstItem(); item;
    2684           0 :        item = item->getNext()) {
    2685           0 :     mPackingSpaceRemaining -= item->GetOuterMainSize(mAxis);
    2686           0 :     mNumAutoMarginsInMainAxis += item->GetNumAutoMarginsInAxis(mAxis);
    2687             :   }
    2688             : 
    2689           0 :   if (mPackingSpaceRemaining <= 0) {
    2690             :     // No available packing space to use for resolving auto margins.
    2691           0 :     mNumAutoMarginsInMainAxis = 0;
    2692             :   }
    2693             : 
    2694             :   // If packing space is negative, 'space-between' falls back to 'flex-start',
    2695             :   // and 'space-around' & 'space-evenly' fall back to 'center'. In those cases,
    2696             :   // it's simplest to just pretend we have a different 'justify-content' value
    2697             :   // and share code.
    2698           0 :   if (mPackingSpaceRemaining < 0) {
    2699           0 :     if (mJustifyContent == NS_STYLE_JUSTIFY_SPACE_BETWEEN) {
    2700           0 :       mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
    2701           0 :     } else if (mJustifyContent == NS_STYLE_JUSTIFY_SPACE_AROUND ||
    2702           0 :                mJustifyContent == NS_STYLE_JUSTIFY_SPACE_EVENLY) {
    2703           0 :       mJustifyContent = NS_STYLE_JUSTIFY_CENTER;
    2704             :     }
    2705             :   }
    2706             : 
    2707             :   // Map 'left'/'right' to 'start'/'end'
    2708           0 :   if (mJustifyContent == NS_STYLE_JUSTIFY_LEFT ||
    2709           0 :       mJustifyContent == NS_STYLE_JUSTIFY_RIGHT) {
    2710           0 :     if (aAxisTracker.IsColumnOriented()) {
    2711             :       // Container's alignment axis is not parallel to the inline axis,
    2712             :       // so we map both 'left' and 'right' to 'start'.
    2713           0 :       mJustifyContent = NS_STYLE_JUSTIFY_START;
    2714             :     } else {
    2715             :       // Row-oriented, so we map 'left' and 'right' to 'start' or 'end',
    2716             :       // depending on left-to-right writing mode.
    2717           0 :       const bool isLTR = aAxisTracker.GetWritingMode().IsBidiLTR();
    2718           0 :       const bool isJustifyLeft = (mJustifyContent == NS_STYLE_JUSTIFY_LEFT);
    2719           0 :       mJustifyContent = (isJustifyLeft == isLTR) ? NS_STYLE_JUSTIFY_START
    2720           0 :                                                  : NS_STYLE_JUSTIFY_END;
    2721             :     }
    2722             :   }
    2723             : 
    2724             :   // Map 'start'/'end' to 'flex-start'/'flex-end'.
    2725           0 :   if (mJustifyContent == NS_STYLE_JUSTIFY_START) {
    2726           0 :     mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
    2727           0 :   } else if (mJustifyContent == NS_STYLE_JUSTIFY_END) {
    2728           0 :     mJustifyContent = NS_STYLE_JUSTIFY_FLEX_END;
    2729             :   }
    2730             : 
    2731             :   // If our main axis is (internally) reversed, swap the justify-content
    2732             :   // "flex-start" and "flex-end" behaviors:
    2733           0 :   if (aAxisTracker.AreAxesInternallyReversed()) {
    2734           0 :     if (mJustifyContent == NS_STYLE_JUSTIFY_FLEX_START) {
    2735           0 :       mJustifyContent = NS_STYLE_JUSTIFY_FLEX_END;
    2736           0 :     } else if (mJustifyContent == NS_STYLE_JUSTIFY_FLEX_END) {
    2737           0 :       mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
    2738             :     }
    2739             :   }
    2740             : 
    2741             :   // Figure out how much space we'll set aside for auto margins or
    2742             :   // packing spaces, and advance past any leading packing-space.
    2743           0 :   if (mNumAutoMarginsInMainAxis == 0 &&
    2744           0 :       mPackingSpaceRemaining != 0 &&
    2745           0 :       !aLine->IsEmpty()) {
    2746           0 :     switch (mJustifyContent) {
    2747             :       case NS_STYLE_JUSTIFY_BASELINE:
    2748             :       case NS_STYLE_JUSTIFY_LAST_BASELINE:
    2749           0 :         NS_WARNING("NYI: justify-content:left/right/baseline/last baseline");
    2750             :         MOZ_FALLTHROUGH;
    2751             :       case NS_STYLE_JUSTIFY_FLEX_START:
    2752             :         // All packing space should go at the end --> nothing to do here.
    2753           0 :         break;
    2754             :       case NS_STYLE_JUSTIFY_FLEX_END:
    2755             :         // All packing space goes at the beginning
    2756           0 :         mPosition += mPackingSpaceRemaining;
    2757           0 :         break;
    2758             :       case NS_STYLE_JUSTIFY_CENTER:
    2759             :         // Half the packing space goes at the beginning
    2760           0 :         mPosition += mPackingSpaceRemaining / 2;
    2761           0 :         break;
    2762             :       case NS_STYLE_JUSTIFY_SPACE_BETWEEN:
    2763             :       case NS_STYLE_JUSTIFY_SPACE_AROUND:
    2764             :       case NS_STYLE_JUSTIFY_SPACE_EVENLY:
    2765           0 :         nsFlexContainerFrame::CalculatePackingSpace(aLine->NumItems(),
    2766           0 :                                                     mJustifyContent,
    2767             :                                                     &mPosition,
    2768             :                                                     &mNumPackingSpacesRemaining,
    2769           0 :                                                     &mPackingSpaceRemaining);
    2770           0 :         break;
    2771             :       default:
    2772           0 :         MOZ_ASSERT_UNREACHABLE("Unexpected justify-content value");
    2773             :     }
    2774             :   }
    2775             : 
    2776           0 :   MOZ_ASSERT(mNumPackingSpacesRemaining == 0 ||
    2777             :              mNumAutoMarginsInMainAxis == 0,
    2778             :              "extra space should either go to packing space or to "
    2779             :              "auto margins, but not to both");
    2780           0 : }
    2781             : 
    2782             : void
    2783           0 : MainAxisPositionTracker::ResolveAutoMarginsInMainAxis(FlexItem& aItem)
    2784             : {
    2785           0 :   if (mNumAutoMarginsInMainAxis) {
    2786           0 :     const nsStyleSides& styleMargin = aItem.Frame()->StyleMargin()->mMargin;
    2787           0 :     for (uint32_t i = 0; i < eNumAxisEdges; i++) {
    2788           0 :       mozilla::Side side = kAxisOrientationToSidesMap[mAxis][i];
    2789           0 :       if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
    2790             :         // NOTE: This integer math will skew the distribution of remainder
    2791             :         // app-units towards the end, which is fine.
    2792             :         nscoord curAutoMarginSize =
    2793           0 :           mPackingSpaceRemaining / mNumAutoMarginsInMainAxis;
    2794             : 
    2795           0 :         MOZ_ASSERT(aItem.GetMarginComponentForSide(side) == 0,
    2796             :                    "Expecting auto margins to have value '0' before we "
    2797             :                    "resolve them");
    2798           0 :         aItem.SetMarginComponentForSide(side, curAutoMarginSize);
    2799             : 
    2800           0 :         mNumAutoMarginsInMainAxis--;
    2801           0 :         mPackingSpaceRemaining -= curAutoMarginSize;
    2802             :       }
    2803             :     }
    2804             :   }
    2805           0 : }
    2806             : 
    2807             : void
    2808           0 : MainAxisPositionTracker::TraversePackingSpace()
    2809             : {
    2810           0 :   if (mNumPackingSpacesRemaining) {
    2811           0 :     MOZ_ASSERT(mJustifyContent == NS_STYLE_JUSTIFY_SPACE_BETWEEN ||
    2812             :                mJustifyContent == NS_STYLE_JUSTIFY_SPACE_AROUND ||
    2813             :                mJustifyContent == NS_STYLE_JUSTIFY_SPACE_EVENLY,
    2814             :                "mNumPackingSpacesRemaining only applies for "
    2815             :                "space-between/space-around/space-evenly");
    2816             : 
    2817           0 :     MOZ_ASSERT(mPackingSpaceRemaining >= 0,
    2818             :                "ran out of packing space earlier than we expected");
    2819             : 
    2820             :     // NOTE: This integer math will skew the distribution of remainder
    2821             :     // app-units towards the end, which is fine.
    2822             :     nscoord curPackingSpace =
    2823           0 :       mPackingSpaceRemaining / mNumPackingSpacesRemaining;
    2824             : 
    2825           0 :     mPosition += curPackingSpace;
    2826           0 :     mNumPackingSpacesRemaining--;
    2827           0 :     mPackingSpaceRemaining -= curPackingSpace;
    2828             :   }
    2829           0 : }
    2830             : 
    2831           0 : CrossAxisPositionTracker::
    2832             :   CrossAxisPositionTracker(FlexLine* aFirstLine,
    2833             :                            const ReflowInput& aReflowInput,
    2834             :                            nscoord aContentBoxCrossSize,
    2835             :                            bool aIsCrossSizeDefinite,
    2836           0 :                            const FlexboxAxisTracker& aAxisTracker)
    2837             :   : PositionTracker(aAxisTracker.GetCrossAxis(),
    2838           0 :                     aAxisTracker.IsCrossAxisReversed()),
    2839             :     mPackingSpaceRemaining(0),
    2840             :     mNumPackingSpacesRemaining(0),
    2841           0 :     mAlignContent(aReflowInput.mStylePosition->mAlignContent)
    2842             : {
    2843           0 :   MOZ_ASSERT(aFirstLine, "null first line pointer");
    2844             : 
    2845             :   // 'normal' behaves as 'stretch'
    2846           0 :   if (mAlignContent == NS_STYLE_ALIGN_NORMAL) {
    2847           0 :     mAlignContent = NS_STYLE_ALIGN_STRETCH;
    2848             :   }
    2849             : 
    2850             :   // XXX strip of the <overflow-position> bit until we implement that
    2851           0 :   mAlignContent &= ~NS_STYLE_ALIGN_FLAG_BITS;
    2852             : 
    2853             :   const bool isSingleLine =
    2854           0 :     NS_STYLE_FLEX_WRAP_NOWRAP == aReflowInput.mStylePosition->mFlexWrap;
    2855           0 :   if (isSingleLine) {
    2856           0 :     MOZ_ASSERT(!aFirstLine->getNext(),
    2857             :                "If we're styled as single-line, we should only have 1 line");
    2858             :     // "If the flex container is single-line and has a definite cross size, the
    2859             :     // cross size of the flex line is the flex container's inner cross size."
    2860             :     //
    2861             :     // SOURCE: https://drafts.csswg.org/css-flexbox/#algo-cross-line
    2862             :     // NOTE: This means (by definition) that there's no packing space, which
    2863             :     // means we don't need to be concerned with "align-conent" at all and we
    2864             :     // can return early. This is handy, because this is the usual case (for
    2865             :     // single-line flexbox).
    2866           0 :     if (aIsCrossSizeDefinite) {
    2867           0 :       aFirstLine->SetLineCrossSize(aContentBoxCrossSize);
    2868           0 :       return;
    2869             :     }
    2870             : 
    2871             :     // "If the flex container is single-line, then clamp the line's
    2872             :     // cross-size to be within the container's computed min and max cross-size
    2873             :     // properties."
    2874           0 :     aFirstLine->SetLineCrossSize(NS_CSS_MINMAX(aFirstLine->GetLineCrossSize(),
    2875             :                                                aReflowInput.ComputedMinBSize(),
    2876           0 :                                                aReflowInput.ComputedMaxBSize()));
    2877             :   }
    2878             : 
    2879             :   // NOTE: The rest of this function should essentially match
    2880             :   // MainAxisPositionTracker's constructor, though with FlexLines instead of
    2881             :   // FlexItems, and with the additional value "stretch" (and of course with
    2882             :   // cross sizes instead of main sizes.)
    2883             : 
    2884             :   // Figure out how much packing space we have (container's cross size minus
    2885             :   // all the lines' cross sizes).  Also, share this loop to count how many
    2886             :   // lines we have. (We need that count in some cases below.)
    2887           0 :   mPackingSpaceRemaining = aContentBoxCrossSize;
    2888           0 :   uint32_t numLines = 0;
    2889           0 :   for (FlexLine* line = aFirstLine; line; line = line->getNext()) {
    2890           0 :     mPackingSpaceRemaining -= line->GetLineCrossSize();
    2891           0 :     numLines++;
    2892             :   }
    2893             : 
    2894             :   // If packing space is negative, 'space-between' and 'stretch' behave like
    2895             :   // 'flex-start', and 'space-around' and 'space-evenly' behave like 'center'.
    2896             :   // In those cases, it's simplest to just pretend we have a different
    2897             :   // 'align-content' value and share code.
    2898           0 :   if (mPackingSpaceRemaining < 0) {
    2899           0 :     if (mAlignContent == NS_STYLE_ALIGN_SPACE_BETWEEN ||
    2900           0 :         mAlignContent == NS_STYLE_ALIGN_STRETCH) {
    2901           0 :       mAlignContent = NS_STYLE_ALIGN_FLEX_START;
    2902           0 :     } else if (mAlignContent == NS_STYLE_ALIGN_SPACE_AROUND ||
    2903           0 :                mAlignContent == NS_STYLE_ALIGN_SPACE_EVENLY) {
    2904           0 :       mAlignContent = NS_STYLE_ALIGN_CENTER;
    2905             :     }
    2906             :   }
    2907             : 
    2908             :   // Map 'left'/'right' to 'start'/'end'
    2909           0 :   if (mAlignContent == NS_STYLE_ALIGN_LEFT ||
    2910           0 :       mAlignContent == NS_STYLE_ALIGN_RIGHT) {
    2911           0 :     if (aAxisTracker.IsRowOriented()) {
    2912             :       // Container's alignment axis is not parallel to the inline axis,
    2913             :       // so we map both 'left' and 'right' to 'start'.
    2914           0 :       mAlignContent = NS_STYLE_ALIGN_START;
    2915             :     } else {
    2916             :       // Column-oriented, so we map 'left' and 'right' to 'start' or 'end',
    2917             :       // depending on left-to-right writing mode.
    2918           0 :       const bool isLTR = aAxisTracker.GetWritingMode().IsBidiLTR();
    2919           0 :       const bool isAlignLeft = (mAlignContent == NS_STYLE_ALIGN_LEFT);
    2920           0 :       mAlignContent = (isAlignLeft == isLTR) ? NS_STYLE_ALIGN_START
    2921           0 :                                              : NS_STYLE_ALIGN_END;
    2922             :     }
    2923             :   }
    2924             : 
    2925             :   // Map 'start'/'end' to 'flex-start'/'flex-end'.
    2926           0 :   if (mAlignContent == NS_STYLE_ALIGN_START) {
    2927           0 :     mAlignContent = NS_STYLE_ALIGN_FLEX_START;
    2928           0 :   } else if (mAlignContent == NS_STYLE_ALIGN_END) {
    2929           0 :     mAlignContent = NS_STYLE_ALIGN_FLEX_END;
    2930             :   }
    2931             : 
    2932             :   // If our cross axis is (internally) reversed, swap the align-content
    2933             :   // "flex-start" and "flex-end" behaviors:
    2934           0 :   if (aAxisTracker.AreAxesInternallyReversed()) {
    2935           0 :     if (mAlignContent == NS_STYLE_ALIGN_FLEX_START) {
    2936           0 :       mAlignContent = NS_STYLE_ALIGN_FLEX_END;
    2937           0 :     } else if (mAlignContent == NS_STYLE_ALIGN_FLEX_END) {
    2938           0 :       mAlignContent = NS_STYLE_ALIGN_FLEX_START;
    2939             :     }
    2940             :   }
    2941             : 
    2942             :   // Figure out how much space we'll set aside for packing spaces, and advance
    2943             :   // past any leading packing-space.
    2944           0 :   if (mPackingSpaceRemaining != 0) {
    2945           0 :     switch (mAlignContent) {
    2946             :       case NS_STYLE_ALIGN_SELF_START:
    2947             :       case NS_STYLE_ALIGN_SELF_END:
    2948             :       case NS_STYLE_ALIGN_BASELINE:
    2949             :       case NS_STYLE_ALIGN_LAST_BASELINE:
    2950           0 :         NS_WARNING("NYI: align-items/align-self:left/right/self-start/self-end/baseline/last baseline");
    2951             :         MOZ_FALLTHROUGH;
    2952             :       case NS_STYLE_ALIGN_FLEX_START:
    2953             :         // All packing space should go at the end --> nothing to do here.
    2954           0 :         break;
    2955             :       case NS_STYLE_ALIGN_FLEX_END:
    2956             :         // All packing space goes at the beginning
    2957           0 :         mPosition += mPackingSpaceRemaining;
    2958           0 :         break;
    2959             :       case NS_STYLE_ALIGN_CENTER:
    2960             :         // Half the packing space goes at the beginning
    2961           0 :         mPosition += mPackingSpaceRemaining / 2;
    2962           0 :         break;
    2963             :       case NS_STYLE_ALIGN_SPACE_BETWEEN:
    2964             :       case NS_STYLE_ALIGN_SPACE_AROUND:
    2965             :       case NS_STYLE_ALIGN_SPACE_EVENLY:
    2966           0 :         nsFlexContainerFrame::CalculatePackingSpace(numLines,
    2967           0 :                                                     mAlignContent,
    2968             :                                                     &mPosition,
    2969             :                                                     &mNumPackingSpacesRemaining,
    2970           0 :                                                     &mPackingSpaceRemaining);
    2971           0 :         break;
    2972             :       case NS_STYLE_ALIGN_STRETCH: {
    2973             :         // Split space equally between the lines:
    2974           0 :         MOZ_ASSERT(mPackingSpaceRemaining > 0,
    2975             :                    "negative packing space should make us use 'flex-start' "
    2976             :                    "instead of 'stretch' (and we shouldn't bother with this "
    2977             :                    "code if we have 0 packing space)");
    2978             : 
    2979           0 :         uint32_t numLinesLeft = numLines;
    2980           0 :         for (FlexLine* line = aFirstLine; line; line = line->getNext()) {
    2981             :           // Our share is the amount of space remaining, divided by the number
    2982             :           // of lines remainig.
    2983           0 :           MOZ_ASSERT(numLinesLeft > 0, "miscalculated num lines");
    2984           0 :           nscoord shareOfExtraSpace = mPackingSpaceRemaining / numLinesLeft;
    2985           0 :           nscoord newSize = line->GetLineCrossSize() + shareOfExtraSpace;
    2986           0 :           line->SetLineCrossSize(newSize);
    2987             : 
    2988           0 :           mPackingSpaceRemaining -= shareOfExtraSpace;
    2989           0 :           numLinesLeft--;
    2990             :         }
    2991           0 :         MOZ_ASSERT(numLinesLeft == 0, "miscalculated num lines");
    2992           0 :         break;
    2993             :       }
    2994             :       default:
    2995           0 :         MOZ_ASSERT_UNREACHABLE("Unexpected align-content value");
    2996             :     }
    2997             :   }
    2998             : }
    2999             : 
    3000             : void
    3001           0 : CrossAxisPositionTracker::TraversePackingSpace()
    3002             : {
    3003           0 :   if (mNumPackingSpacesRemaining) {
    3004           0 :     MOZ_ASSERT(mAlignContent == NS_STYLE_ALIGN_SPACE_BETWEEN ||
    3005             :                mAlignContent == NS_STYLE_ALIGN_SPACE_AROUND ||
    3006             :                mAlignContent == NS_STYLE_ALIGN_SPACE_EVENLY,
    3007             :                "mNumPackingSpacesRemaining only applies for "
    3008             :                "space-between/space-around/space-evenly");
    3009             : 
    3010           0 :     MOZ_ASSERT(mPackingSpaceRemaining >= 0,
    3011             :                "ran out of packing space earlier than we expected");
    3012             : 
    3013             :     // NOTE: This integer math will skew the distribution of remainder
    3014             :     // app-units towards the end, which is fine.
    3015             :     nscoord curPackingSpace =
    3016           0 :       mPackingSpaceRemaining / mNumPackingSpacesRemaining;
    3017             : 
    3018           0 :     mPosition += curPackingSpace;
    3019           0 :     mNumPackingSpacesRemaining--;
    3020           0 :     mPackingSpaceRemaining -= curPackingSpace;
    3021             :   }
    3022           0 : }
    3023             : 
    3024           0 : SingleLineCrossAxisPositionTracker::
    3025           0 :   SingleLineCrossAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker)
    3026             :   : PositionTracker(aAxisTracker.GetCrossAxis(),
    3027           0 :                     aAxisTracker.IsCrossAxisReversed())
    3028             : {
    3029           0 : }
    3030             : 
    3031             : void
    3032           0 : FlexLine::ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker)
    3033             : {
    3034           0 :   nscoord crossStartToFurthestFirstBaseline = nscoord_MIN;
    3035           0 :   nscoord crossEndToFurthestFirstBaseline = nscoord_MIN;
    3036           0 :   nscoord crossStartToFurthestLastBaseline = nscoord_MIN;
    3037           0 :   nscoord crossEndToFurthestLastBaseline = nscoord_MIN;
    3038           0 :   nscoord largestOuterCrossSize = 0;
    3039           0 :   for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
    3040             :     nscoord curOuterCrossSize =
    3041           0 :       item->GetOuterCrossSize(aAxisTracker.GetCrossAxis());
    3042             : 
    3043           0 :     if ((item->GetAlignSelf() == NS_STYLE_ALIGN_BASELINE ||
    3044           0 :         item->GetAlignSelf() == NS_STYLE_ALIGN_LAST_BASELINE) &&
    3045           0 :         item->GetNumAutoMarginsInAxis(aAxisTracker.GetCrossAxis()) == 0) {
    3046           0 :       const bool useFirst = (item->GetAlignSelf() == NS_STYLE_ALIGN_BASELINE);
    3047             :       // FIXME: Once we support "writing-mode", we'll have to do baseline
    3048             :       // alignment in vertical flex containers here (w/ horizontal cross-axes).
    3049             : 
    3050             :       // Find distance from our item's cross-start and cross-end margin-box
    3051             :       // edges to its baseline.
    3052             :       //
    3053             :       // Here's a diagram of a flex-item that we might be doing this on.
    3054             :       // "mmm" is the margin-box, "bbb" is the border-box. The bottom of
    3055             :       // the text "BASE" is the baseline.
    3056             :       //
    3057             :       // ---(cross-start)---
    3058             :       //                ___              ___            ___
    3059             :       //   mmmmmmmmmmmm  |                |margin-start  |
    3060             :       //   m          m  |               _|_   ___       |
    3061             :       //   m bbbbbbbb m  |curOuterCrossSize     |        |crossStartToBaseline
    3062             :       //   m b      b m  |                      |ascent  |
    3063             :       //   m b BASE b m  |                     _|_      _|_
    3064             :       //   m b      b m  |                               |
    3065             :       //   m bbbbbbbb m  |                               |crossEndToBaseline
    3066             :       //   m          m  |                               |
    3067             :       //   mmmmmmmmmmmm _|_                             _|_
    3068             :       //
    3069             :       // ---(cross-end)---
    3070             :       //
    3071             :       // We already have the curOuterCrossSize, margin-start, and the ascent.
    3072             :       // * We can get crossStartToBaseline by adding margin-start + ascent.
    3073             :       // * If we subtract that from the curOuterCrossSize, we get
    3074             :       //   crossEndToBaseline.
    3075             : 
    3076             :       nscoord crossStartToBaseline =
    3077           0 :         item->GetBaselineOffsetFromOuterCrossEdge(eAxisEdge_Start,
    3078             :                                                   aAxisTracker,
    3079           0 :                                                   useFirst);
    3080           0 :       nscoord crossEndToBaseline = curOuterCrossSize - crossStartToBaseline;
    3081             : 
    3082             :       // Now, update our "largest" values for these (across all the flex items
    3083             :       // in this flex line), so we can use them in computing the line's cross
    3084             :       // size below:
    3085           0 :       if (useFirst) {
    3086           0 :         crossStartToFurthestFirstBaseline =
    3087           0 :           std::max(crossStartToFurthestFirstBaseline, crossStartToBaseline);
    3088           0 :         crossEndToFurthestFirstBaseline =
    3089           0 :           std::max(crossEndToFurthestFirstBaseline, crossEndToBaseline);
    3090             :       } else {
    3091           0 :         crossStartToFurthestLastBaseline =
    3092           0 :           std::max(crossStartToFurthestLastBaseline, crossStartToBaseline);
    3093           0 :         crossEndToFurthestLastBaseline =
    3094           0 :           std::max(crossEndToFurthestLastBaseline, crossEndToBaseline);
    3095             :       }
    3096             :     } else {
    3097           0 :       largestOuterCrossSize = std::max(largestOuterCrossSize, curOuterCrossSize);
    3098             :     }
    3099             :   }
    3100             : 
    3101             :   // The line's baseline offset is the distance from the line's edge (start or
    3102             :   // end, depending on whether we've flipped the axes) to the furthest
    3103             :   // item-baseline. The item(s) with that baseline will be exactly aligned with
    3104             :   // the line's edge.
    3105           0 :   mFirstBaselineOffset = aAxisTracker.AreAxesInternallyReversed() ?
    3106             :     crossEndToFurthestFirstBaseline : crossStartToFurthestFirstBaseline;
    3107             : 
    3108           0 :   mLastBaselineOffset = aAxisTracker.AreAxesInternallyReversed() ?
    3109             :     crossStartToFurthestLastBaseline : crossEndToFurthestLastBaseline;
    3110             : 
    3111             :   // The line's cross-size is the larger of:
    3112             :   //  (a) [largest cross-start-to-baseline + largest baseline-to-cross-end] of
    3113             :   //      all baseline-aligned items with no cross-axis auto margins...
    3114             :   // and
    3115             :   //  (b) [largest cross-start-to-baseline + largest baseline-to-cross-end] of
    3116             :   //      all last baseline-aligned items with no cross-axis auto margins...
    3117             :   // and
    3118             :   //  (c) largest cross-size of all other children.
    3119           0 :   mLineCrossSize = std::max(
    3120           0 :     std::max(crossStartToFurthestFirstBaseline + crossEndToFurthestFirstBaseline,
    3121           0 :              crossStartToFurthestLastBaseline + crossEndToFurthestLastBaseline),
    3122           0 :     largestOuterCrossSize);
    3123           0 : }
    3124             : 
    3125             : void
    3126           0 : FlexItem::ResolveStretchedCrossSize(nscoord aLineCrossSize,
    3127             :                                     const FlexboxAxisTracker& aAxisTracker)
    3128             : {
    3129           0 :   AxisOrientationType crossAxis = aAxisTracker.GetCrossAxis();
    3130             :   // We stretch IFF we are align-self:stretch, have no auto margins in
    3131             :   // cross axis, and have cross-axis size property == "auto". If any of those
    3132             :   // conditions don't hold up, we won't stretch.
    3133           0 :   if (mAlignSelf != NS_STYLE_ALIGN_STRETCH ||
    3134           0 :       GetNumAutoMarginsInAxis(crossAxis) != 0 ||
    3135           0 :       eStyleUnit_Auto != aAxisTracker.ComputedCrossSize(mFrame).GetUnit()) {
    3136           0 :     return;
    3137             :   }
    3138             : 
    3139             :   // If we've already been stretched, we can bail out early, too.
    3140             :   // No need to redo the calculation.
    3141           0 :   if (mIsStretched) {
    3142           0 :     return;
    3143             :   }
    3144             : 
    3145             :   // Reserve space for margins & border & padding, and then use whatever
    3146             :   // remains as our item's cross-size (clamped to its min/max range).
    3147             :   nscoord stretchedSize = aLineCrossSize -
    3148           0 :     GetMarginBorderPaddingSizeInAxis(crossAxis);
    3149             : 
    3150           0 :   stretchedSize = NS_CSS_MINMAX(stretchedSize, mCrossMinSize, mCrossMaxSize);
    3151             : 
    3152             :   // Update the cross-size & make a note that it's stretched, so we know to
    3153             :   // override the reflow state's computed cross-size in our final reflow.
    3154           0 :   SetCrossSize(stretchedSize);
    3155           0 :   mIsStretched = true;
    3156             : }
    3157             : 
    3158             : void
    3159           0 : SingleLineCrossAxisPositionTracker::
    3160             :   ResolveAutoMarginsInCrossAxis(const FlexLine& aLine,
    3161             :                                 FlexItem& aItem)
    3162             : {
    3163             :   // Subtract the space that our item is already occupying, to see how much
    3164             :   // space (if any) is available for its auto margins.
    3165           0 :   nscoord spaceForAutoMargins = aLine.GetLineCrossSize() -
    3166           0 :     aItem.GetOuterCrossSize(mAxis);
    3167             : 
    3168           0 :   if (spaceForAutoMargins <= 0) {
    3169           0 :     return; // No available space  --> nothing to do
    3170             :   }
    3171             : 
    3172           0 :   uint32_t numAutoMargins = aItem.GetNumAutoMarginsInAxis(mAxis);
    3173           0 :   if (numAutoMargins == 0) {
    3174           0 :     return; // No auto margins --> nothing to do.
    3175             :   }
    3176             : 
    3177             :   // OK, we have at least one auto margin and we have some available space.
    3178             :   // Give each auto margin a share of the space.
    3179           0 :   const nsStyleSides& styleMargin = aItem.Frame()->StyleMargin()->mMargin;
    3180           0 :   for (uint32_t i = 0; i < eNumAxisEdges; i++) {
    3181           0 :     mozilla::Side side = kAxisOrientationToSidesMap[mAxis][i];
    3182           0 :     if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
    3183           0 :       MOZ_ASSERT(aItem.GetMarginComponentForSide(side) == 0,
    3184             :                  "Expecting auto margins to have value '0' before we "
    3185             :                  "update them");
    3186             : 
    3187             :       // NOTE: integer divison is fine here; numAutoMargins is either 1 or 2.
    3188             :       // If it's 2 & spaceForAutoMargins is odd, 1st margin gets smaller half.
    3189           0 :       nscoord curAutoMarginSize = spaceForAutoMargins / numAutoMargins;
    3190           0 :       aItem.SetMarginComponentForSide(side, curAutoMarginSize);
    3191           0 :       numAutoMargins--;
    3192           0 :       spaceForAutoMargins -= curAutoMarginSize;
    3193             :     }
    3194             :   }
    3195             : }
    3196             : 
    3197             : void
    3198           0 : SingleLineCrossAxisPositionTracker::
    3199             :   EnterAlignPackingSpace(const FlexLine& aLine,
    3200             :                          const FlexItem& aItem,
    3201             :                          const FlexboxAxisTracker& aAxisTracker)
    3202             : {
    3203             :   // We don't do align-self alignment on items that have auto margins
    3204             :   // in the cross axis.
    3205           0 :   if (aItem.GetNumAutoMarginsInAxis(mAxis)) {
    3206           0 :     return;
    3207             :   }
    3208             : 
    3209           0 :   uint8_t alignSelf = aItem.GetAlignSelf();
    3210             :   // NOTE: 'stretch' behaves like 'flex-start' once we've stretched any
    3211             :   // auto-sized items (which we've already done).
    3212           0 :   if (alignSelf == NS_STYLE_ALIGN_STRETCH) {
    3213           0 :     alignSelf = NS_STYLE_ALIGN_FLEX_START;
    3214             :   }
    3215             : 
    3216             :   // Map 'left'/'right' to 'start'/'end'
    3217           0 :   if (alignSelf == NS_STYLE_ALIGN_LEFT || alignSelf == NS_STYLE_ALIGN_RIGHT) {
    3218           0 :     if (aAxisTracker.IsRowOriented()) {
    3219             :       // Container's alignment axis is not parallel to the inline axis,
    3220             :       // so we map both 'left' and 'right' to 'start'.
    3221           0 :       alignSelf = NS_STYLE_ALIGN_START;
    3222             :     } else {
    3223             :       // Column-oriented, so we map 'left' and 'right' to 'start' or 'end',
    3224             :       // depending on left-to-right writing mode.
    3225           0 :       const bool isLTR = aAxisTracker.GetWritingMode().IsBidiLTR();
    3226           0 :       const bool isAlignLeft = (alignSelf == NS_STYLE_ALIGN_LEFT);
    3227           0 :       alignSelf = (isAlignLeft == isLTR) ? NS_STYLE_ALIGN_START
    3228           0 :                                          : NS_STYLE_ALIGN_END;
    3229             :     }
    3230             :   }
    3231             : 
    3232             :   // Map 'start'/'end' to 'flex-start'/'flex-end'.
    3233           0 :   if (alignSelf == NS_STYLE_ALIGN_START) {
    3234           0 :     alignSelf = NS_STYLE_ALIGN_FLEX_START;
    3235           0 :   } else if (alignSelf == NS_STYLE_ALIGN_END) {
    3236           0 :     alignSelf = NS_STYLE_ALIGN_FLEX_END;
    3237             :   }
    3238             : 
    3239             :   // If our cross axis is (internally) reversed, swap the align-self
    3240             :   // "flex-start" and "flex-end" behaviors:
    3241           0 :   if (aAxisTracker.AreAxesInternallyReversed()) {
    3242           0 :     if (alignSelf == NS_STYLE_ALIGN_FLEX_START) {
    3243           0 :       alignSelf = NS_STYLE_ALIGN_FLEX_END;
    3244           0 :     } else if (alignSelf == NS_STYLE_ALIGN_FLEX_END) {
    3245           0 :       alignSelf = NS_STYLE_ALIGN_FLEX_START;
    3246             :     }
    3247             :   }
    3248             : 
    3249           0 :   switch (alignSelf) {
    3250             :     case NS_STYLE_ALIGN_SELF_START:
    3251             :     case NS_STYLE_ALIGN_SELF_END:
    3252           0 :       NS_WARNING("NYI: align-items/align-self:left/right/self-start/self-end");
    3253             :       MOZ_FALLTHROUGH;
    3254             :     case NS_STYLE_ALIGN_FLEX_START:
    3255             :       // No space to skip over -- we're done.
    3256           0 :       break;
    3257             :     case NS_STYLE_ALIGN_FLEX_END:
    3258           0 :       mPosition += aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis);
    3259           0 :       break;
    3260             :     case NS_STYLE_ALIGN_CENTER:
    3261             :       // Note: If cross-size is odd, the "after" space will get the extra unit.
    3262           0 :       mPosition +=
    3263           0 :         (aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis)) / 2;
    3264           0 :       break;
    3265             :     case NS_STYLE_ALIGN_BASELINE:
    3266             :     case NS_STYLE_ALIGN_LAST_BASELINE: {
    3267           0 :       const bool useFirst = (alignSelf == NS_STYLE_ALIGN_BASELINE);
    3268             : 
    3269             :       // Normally, baseline-aligned items are collectively aligned with the
    3270             :       // line's cross-start edge; however, if our cross axis is (internally)
    3271             :       // reversed, we instead align them with the cross-end edge.
    3272             :       // A similar logic holds for last baseline-aligned items, but in reverse.
    3273             :       AxisEdgeType baselineAlignEdge =
    3274           0 :         aAxisTracker.AreAxesInternallyReversed() == useFirst ?
    3275           0 :         eAxisEdge_End : eAxisEdge_Start;
    3276             : 
    3277             :       nscoord itemBaselineOffset =
    3278           0 :         aItem.GetBaselineOffsetFromOuterCrossEdge(baselineAlignEdge,
    3279             :                                                   aAxisTracker,
    3280           0 :                                                   useFirst);
    3281             : 
    3282           0 :       nscoord lineBaselineOffset = useFirst ? aLine.GetFirstBaselineOffset()
    3283           0 :                                             : aLine.GetLastBaselineOffset();
    3284             : 
    3285           0 :       NS_ASSERTION(lineBaselineOffset >= itemBaselineOffset,
    3286             :                    "failed at finding largest baseline offset");
    3287             : 
    3288             :       // How much do we need to adjust our position (from the line edge),
    3289             :       // to get the item's baseline to hit the line's baseline offset:
    3290           0 :       nscoord baselineDiff = lineBaselineOffset - itemBaselineOffset;
    3291             : 
    3292           0 :       if (aAxisTracker.AreAxesInternallyReversed() == useFirst) {
    3293             :         // Advance to align item w/ line's flex-end edge (as in FLEX_END case):
    3294           0 :         mPosition += aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis);
    3295             :         // ...and step *back* by the baseline adjustment:
    3296           0 :         mPosition -= baselineDiff;
    3297             :       } else {
    3298             :         // mPosition is already at line's flex-start edge.
    3299             :         // From there, we step *forward* by the baseline adjustment:
    3300           0 :         mPosition += baselineDiff;
    3301             :       }
    3302           0 :       break;
    3303             :     }
    3304             :     default:
    3305           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected align-self value");
    3306             :       break;
    3307             :   }
    3308             : }
    3309             : 
    3310             : // Utility function to convert an InlineDir to an AxisOrientationType
    3311             : static inline AxisOrientationType
    3312           0 : InlineDirToAxisOrientation(WritingMode::InlineDir aInlineDir)
    3313             : {
    3314           0 :   switch (aInlineDir) {
    3315             :     case WritingMode::eInlineLTR:
    3316           0 :       return eAxis_LR;
    3317             :     case WritingMode::eInlineRTL:
    3318           0 :       return eAxis_RL;
    3319             :     case WritingMode::eInlineTTB:
    3320           0 :       return eAxis_TB;
    3321             :     case WritingMode::eInlineBTT:
    3322           0 :       return eAxis_BT;
    3323             :   }
    3324             : 
    3325           0 :   MOZ_ASSERT_UNREACHABLE("Unhandled InlineDir");
    3326             :   return eAxis_LR; // in case of unforseen error, assume English LTR text flow.
    3327             : }
    3328             : 
    3329             : // Utility function to convert a BlockDir to an AxisOrientationType
    3330             : static inline AxisOrientationType
    3331           0 : BlockDirToAxisOrientation(WritingMode::BlockDir aBlockDir)
    3332             : {
    3333           0 :   switch (aBlockDir) {
    3334             :     case WritingMode::eBlockLR:
    3335           0 :       return eAxis_LR;
    3336             :     case WritingMode::eBlockRL:
    3337           0 :       return eAxis_RL;
    3338             :     case WritingMode::eBlockTB:
    3339           0 :       return eAxis_TB;
    3340             :     // NOTE: WritingMode::eBlockBT (bottom-to-top) does not exist.
    3341             :   }
    3342             : 
    3343           0 :   MOZ_ASSERT_UNREACHABLE("Unhandled BlockDir");
    3344             :   return eAxis_TB; // in case of unforseen error, assume English TTB block-flow
    3345             : }
    3346             : 
    3347           0 : FlexboxAxisTracker::FlexboxAxisTracker(
    3348             :   const nsFlexContainerFrame* aFlexContainer,
    3349             :   const WritingMode& aWM,
    3350           0 :   AxisTrackerFlags aFlags)
    3351             :   : mWM(aWM),
    3352           0 :     mAreAxesInternallyReversed(false)
    3353             : {
    3354           0 :   if (IsLegacyBox(aFlexContainer)) {
    3355           0 :     InitAxesFromLegacyProps(aFlexContainer);
    3356             :   } else {
    3357           0 :     InitAxesFromModernProps(aFlexContainer);
    3358             :   }
    3359             : 
    3360             :   // Master switch to enable/disable bug 983427's code for reversing our axes
    3361             :   // and reversing some logic, to avoid reflowing children in bottom-to-top
    3362             :   // order. (This switch can be removed eventually, but for now, it allows
    3363             :   // this special-case code path to be compared against the normal code path.)
    3364             :   static bool sPreventBottomToTopChildOrdering = true;
    3365             : 
    3366             :   // Note: if the eAllowBottomToTopChildOrdering flag is set, that overrides
    3367             :   // the static boolean and makes us skip this special case.
    3368           0 :   if (!(aFlags & AxisTrackerFlags::eAllowBottomToTopChildOrdering) &&
    3369             :       sPreventBottomToTopChildOrdering) {
    3370             :     // If either axis is bottom-to-top, we flip both axes (and set a flag
    3371             :     // so that we can flip some logic to make the reversal transparent).
    3372           0 :     if (eAxis_BT == mMainAxis || eAxis_BT == mCrossAxis) {
    3373           0 :       mMainAxis = GetReverseAxis(mMainAxis);
    3374           0 :       mCrossAxis = GetReverseAxis(mCrossAxis);
    3375           0 :       mAreAxesInternallyReversed = true;
    3376           0 :       mIsMainAxisReversed = !mIsMainAxisReversed;
    3377           0 :       mIsCrossAxisReversed = !mIsCrossAxisReversed;
    3378             :     }
    3379             :   }
    3380           0 : }
    3381             : 
    3382             : void
    3383           0 : FlexboxAxisTracker::InitAxesFromLegacyProps(
    3384             :   const nsFlexContainerFrame* aFlexContainer)
    3385             : {
    3386           0 :   const nsStyleXUL* styleXUL = aFlexContainer->StyleXUL();
    3387             : 
    3388           0 :   const bool boxOrientIsVertical = (styleXUL->mBoxOrient ==
    3389           0 :                                     StyleBoxOrient::Vertical);
    3390           0 :   const bool wmIsVertical = mWM.IsVertical();
    3391             : 
    3392             :   // If box-orient agrees with our writing-mode, then we're "row-oriented"
    3393             :   // (i.e. the flexbox main axis is the same as our writing mode's inline
    3394             :   // direction).  Otherwise, we're column-oriented (i.e. the flexbox's main
    3395             :   // axis is perpendicular to the writing-mode's inline direction).
    3396           0 :   mIsRowOriented = (boxOrientIsVertical == wmIsVertical);
    3397             : 
    3398             :   // XXXdholbert BEGIN CODE TO SET DEPRECATED MEMBER-VARS
    3399           0 :   if (boxOrientIsVertical) {
    3400           0 :     mMainAxis = eAxis_TB;
    3401           0 :     mCrossAxis = eAxis_LR;
    3402             :   } else {
    3403           0 :     mMainAxis = eAxis_LR;
    3404           0 :     mCrossAxis = eAxis_TB;
    3405             :   }
    3406             :   // "direction: rtl" reverses the writing-mode's inline axis.
    3407             :   // So, we need to reverse the corresponding flex axis to match.
    3408             :   // (Note this we don't toggle "mIsMainAxisReversed" for this condition,
    3409             :   // because the main axis will still match mWM's inline direction.)
    3410           0 :   if (!mWM.IsBidiLTR()) {
    3411           0 :     AxisOrientationType& axisToFlip = mIsRowOriented ? mMainAxis : mCrossAxis;
    3412           0 :     axisToFlip = GetReverseAxis(axisToFlip);
    3413             :   }
    3414             :   // XXXdholbert END CODE TO SET DEPRECATED MEMBER-VARS
    3415             : 
    3416             :   // Legacy flexbox can use "-webkit-box-direction: reverse" to reverse the
    3417             :   // main axis (so it runs in the reverse direction of the inline axis):
    3418           0 :   if (styleXUL->mBoxDirection == StyleBoxDirection::Reverse) {
    3419           0 :     mMainAxis = GetReverseAxis(mMainAxis);
    3420           0 :     mIsMainAxisReversed = true;
    3421             :   } else {
    3422           0 :     mIsMainAxisReversed = false;
    3423             :   }
    3424             : 
    3425             :   // Legacy flexbox does not support reversing the cross axis -- it has no
    3426             :   // equivalent of modern flexbox's "flex-wrap: wrap-reverse".
    3427           0 :   mIsCrossAxisReversed = false;
    3428           0 : }
    3429             : 
    3430             : void
    3431           0 : FlexboxAxisTracker::InitAxesFromModernProps(
    3432             :   const nsFlexContainerFrame* aFlexContainer)
    3433             : {
    3434           0 :   const nsStylePosition* stylePos = aFlexContainer->StylePosition();
    3435           0 :   uint32_t flexDirection = stylePos->mFlexDirection;
    3436             : 
    3437             :   // Inline dimension ("start-to-end"):
    3438             :   // (NOTE: I'm intentionally not calling these "inlineAxis"/"blockAxis", since
    3439             :   // those terms have explicit definition in the writing-modes spec, which are
    3440             :   // the opposite of how I'd be using them here.)
    3441             :   AxisOrientationType inlineDimension =
    3442           0 :     InlineDirToAxisOrientation(mWM.GetInlineDir());
    3443             :   AxisOrientationType blockDimension =
    3444           0 :     BlockDirToAxisOrientation(mWM.GetBlockDir());
    3445             : 
    3446             :   // Determine main axis:
    3447           0 :   switch (flexDirection) {
    3448             :     case NS_STYLE_FLEX_DIRECTION_ROW:
    3449           0 :       mMainAxis = inlineDimension;
    3450           0 :       mIsRowOriented = true;
    3451           0 :       mIsMainAxisReversed = false;
    3452           0 :       break;
    3453             :     case NS_STYLE_FLEX_DIRECTION_ROW_REVERSE:
    3454           0 :       mMainAxis = GetReverseAxis(inlineDimension);
    3455           0 :       mIsRowOriented = true;
    3456           0 :       mIsMainAxisReversed = true;
    3457           0 :       break;
    3458             :     case NS_STYLE_FLEX_DIRECTION_COLUMN:
    3459           0 :       mMainAxis = blockDimension;
    3460           0 :       mIsRowOriented = false;
    3461           0 :       mIsMainAxisReversed = false;
    3462           0 :       break;
    3463             :     case NS_STYLE_FLEX_DIRECTION_COLUMN_REVERSE:
    3464           0 :       mMainAxis = GetReverseAxis(blockDimension);
    3465           0 :       mIsRowOriented = false;
    3466           0 :       mIsMainAxisReversed = true;
    3467           0 :       break;
    3468             :     default:
    3469           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected flex-direction value");
    3470             :   }
    3471             : 
    3472             :   // Determine cross axis:
    3473             :   // (This is set up so that a bogus |flexDirection| value will
    3474             :   // give us blockDimension.
    3475           0 :   if (flexDirection == NS_STYLE_FLEX_DIRECTION_COLUMN ||
    3476             :       flexDirection == NS_STYLE_FLEX_DIRECTION_COLUMN_REVERSE) {
    3477           0 :     mCrossAxis = inlineDimension;
    3478             :   } else {
    3479           0 :     mCrossAxis = blockDimension;
    3480             :   }
    3481             : 
    3482             :   // "flex-wrap: wrap-reverse" reverses our cross axis.
    3483           0 :   if (stylePos->mFlexWrap == NS_STYLE_FLEX_WRAP_WRAP_REVERSE) {
    3484           0 :     mCrossAxis = GetReverseAxis(mCrossAxis);
    3485           0 :     mIsCrossAxisReversed = true;
    3486             :   } else {
    3487           0 :     mIsCrossAxisReversed = false;
    3488             :   }
    3489           0 : }
    3490             : 
    3491             : // Allocates a new FlexLine, adds it to the given LinkedList (at the front or
    3492             : // back depending on aShouldInsertAtFront), and returns a pointer to it.
    3493             : static FlexLine*
    3494           0 : AddNewFlexLineToList(LinkedList<FlexLine>& aLines,
    3495             :                      bool aShouldInsertAtFront)
    3496             : {
    3497           0 :   FlexLine* newLine = new FlexLine();
    3498           0 :   if (aShouldInsertAtFront) {
    3499           0 :     aLines.insertFront(newLine);
    3500             :   } else {
    3501           0 :     aLines.insertBack(newLine);
    3502             :   }
    3503           0 :   return newLine;
    3504             : }
    3505             : 
    3506             : void
    3507           0 : nsFlexContainerFrame::GenerateFlexLines(
    3508             :   nsPresContext* aPresContext,
    3509             :   const ReflowInput& aReflowInput,
    3510             :   nscoord aContentBoxMainSize,
    3511             :   nscoord aAvailableBSizeForContent,
    3512             :   const nsTArray<StrutInfo>& aStruts,
    3513             :   const FlexboxAxisTracker& aAxisTracker,
    3514             :   nsTArray<nsIFrame*>& aPlaceholders, /* out */
    3515             :   LinkedList<FlexLine>& aLines /* out */)
    3516             : {
    3517           0 :   MOZ_ASSERT(aLines.isEmpty(), "Expecting outparam to start out empty");
    3518             : 
    3519             :   const bool isSingleLine =
    3520           0 :     NS_STYLE_FLEX_WRAP_NOWRAP == aReflowInput.mStylePosition->mFlexWrap;
    3521             : 
    3522             :   // If we're transparently reversing axes, then we'll need to link up our
    3523             :   // FlexItems and FlexLines in the reverse order, so that the rest of flex
    3524             :   // layout (with flipped axes) will still produce the correct result.
    3525             :   // Here, we declare a convenience bool that we'll pass when adding a new
    3526             :   // FlexLine or FlexItem, to make us insert it at the beginning of its list
    3527             :   // (so the list ends up reversed).
    3528           0 :   const bool shouldInsertAtFront = aAxisTracker.AreAxesInternallyReversed();
    3529             : 
    3530             :   // We have at least one FlexLine. Even an empty flex container has a single
    3531             :   // (empty) flex line.
    3532           0 :   FlexLine* curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
    3533             : 
    3534             :   nscoord wrapThreshold;
    3535           0 :   if (isSingleLine) {
    3536             :     // Not wrapping. Set threshold to sentinel value that tells us not to wrap.
    3537           0 :     wrapThreshold = NS_UNCONSTRAINEDSIZE;
    3538             :   } else {
    3539             :     // Wrapping! Set wrap threshold to flex container's content-box main-size.
    3540           0 :     wrapThreshold = aContentBoxMainSize;
    3541             : 
    3542             :     // If the flex container doesn't have a definite content-box main-size
    3543             :     // (e.g. if main axis is vertical & 'height' is 'auto'), make sure we at
    3544             :     // least wrap when we hit its max main-size.
    3545           0 :     if (wrapThreshold == NS_UNCONSTRAINEDSIZE) {
    3546             :       const nscoord flexContainerMaxMainSize =
    3547           0 :         GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, aAxisTracker.GetWritingMode(),
    3548             :                                    aReflowInput.ComputedMaxISize(),
    3549             :                                    aReflowInput.ComputedMaxBSize());
    3550             : 
    3551           0 :       wrapThreshold = flexContainerMaxMainSize;
    3552             :     }
    3553             : 
    3554             :     // Also: if we're column-oriented and paginating in the block dimension,
    3555             :     // we may need to wrap to a new flex line sooner (before we grow past the
    3556             :     // available BSize, potentially running off the end of the page).
    3557           0 :     if (aAxisTracker.IsColumnOriented() &&
    3558           0 :         aAvailableBSizeForContent != NS_UNCONSTRAINEDSIZE) {
    3559           0 :       wrapThreshold = std::min(wrapThreshold, aAvailableBSizeForContent);
    3560             :     }
    3561             :   }
    3562             : 
    3563             :   // Tracks the index of the next strut, in aStruts (and when this hits
    3564             :   // aStruts.Length(), that means there are no more struts):
    3565           0 :   uint32_t nextStrutIdx = 0;
    3566             : 
    3567             :   // Overall index of the current flex item in the flex container. (This gets
    3568             :   // checked against entries in aStruts.)
    3569           0 :   uint32_t itemIdxInContainer = 0;
    3570             : 
    3571             :   CSSOrderAwareFrameIterator iter(this, kPrincipalList,
    3572             :                                   CSSOrderAwareFrameIterator::eIncludeAll,
    3573             :                                   CSSOrderAwareFrameIterator::eUnknownOrder,
    3574           0 :                                   OrderingPropertyForIter(this));
    3575             : 
    3576           0 :   if (iter.ItemsAreAlreadyInOrder()) {
    3577           0 :     AddStateBits(NS_STATE_FLEX_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
    3578             :   } else {
    3579           0 :     RemoveStateBits(NS_STATE_FLEX_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
    3580             :   }
    3581             : 
    3582           0 :   for (; !iter.AtEnd(); iter.Next()) {
    3583           0 :     nsIFrame* childFrame = *iter;
    3584             :     // Don't create flex items / lines for placeholder frames:
    3585           0 :     if (childFrame->IsPlaceholderFrame()) {
    3586           0 :       aPlaceholders.AppendElement(childFrame);
    3587           0 :       continue;
    3588             :     }
    3589             : 
    3590             :     // Honor "page-break-before", if we're multi-line and this line isn't empty:
    3591           0 :     if (!isSingleLine && !curLine->IsEmpty() &&
    3592           0 :         childFrame->StyleDisplay()->mBreakBefore) {
    3593           0 :       curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
    3594             :     }
    3595             : 
    3596           0 :     UniquePtr<FlexItem> item;
    3597           0 :     if (nextStrutIdx < aStruts.Length() &&
    3598           0 :         aStruts[nextStrutIdx].mItemIdx == itemIdxInContainer) {
    3599             : 
    3600             :       // Use the simplified "strut" FlexItem constructor:
    3601           0 :       item = MakeUnique<FlexItem>(childFrame, aStruts[nextStrutIdx].mStrutCrossSize,
    3602           0 :                                   aReflowInput.GetWritingMode());
    3603           0 :       nextStrutIdx++;
    3604             :     } else {
    3605           0 :       item = GenerateFlexItemForChild(aPresContext, childFrame,
    3606           0 :                                       aReflowInput, aAxisTracker);
    3607             :     }
    3608             : 
    3609           0 :     nscoord itemInnerHypotheticalMainSize = item->GetMainSize();
    3610             :     nscoord itemOuterHypotheticalMainSize =
    3611           0 :       item->GetOuterMainSize(aAxisTracker.GetMainAxis());
    3612             : 
    3613             :     // Check if we need to wrap |item| to a new line
    3614             :     // (i.e. check if its outer hypothetical main size pushes our line over
    3615             :     // the threshold)
    3616           0 :     if (wrapThreshold != NS_UNCONSTRAINEDSIZE &&
    3617           0 :         !curLine->IsEmpty() && // No need to wrap at start of a line.
    3618           0 :         wrapThreshold < (curLine->GetTotalOuterHypotheticalMainSize() +
    3619             :                          itemOuterHypotheticalMainSize)) {
    3620           0 :       curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
    3621             :     }
    3622             : 
    3623             :     // Add item to current flex line (and update the line's bookkeeping about
    3624             :     // how large its items collectively are).
    3625           0 :     curLine->AddItem(item.release(), shouldInsertAtFront,
    3626             :                      itemInnerHypotheticalMainSize,
    3627           0 :                      itemOuterHypotheticalMainSize);
    3628             : 
    3629             :     // Honor "page-break-after", if we're multi-line and have more children:
    3630           0 :     if (!isSingleLine && childFrame->GetNextSibling() &&
    3631           0 :         childFrame->StyleDisplay()->mBreakAfter) {
    3632           0 :       curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
    3633             :     }
    3634           0 :     itemIdxInContainer++;
    3635             :   }
    3636           0 : }
    3637             : 
    3638             : // Retrieves the content-box main-size of our flex container from the
    3639             : // reflow state (specifically, the main-size of *this continuation* of the
    3640             : // flex container).
    3641             : nscoord
    3642           0 : nsFlexContainerFrame::GetMainSizeFromReflowInput(
    3643             :   const ReflowInput& aReflowInput,
    3644             :   const FlexboxAxisTracker& aAxisTracker)
    3645             : {
    3646           0 :   if (aAxisTracker.IsRowOriented()) {
    3647             :     // Row-oriented --> our main axis is the inline axis, so our main size
    3648             :     // is our inline size (which should already be resolved).
    3649           0 :     NS_WARNING_ASSERTION(
    3650             :       aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE,
    3651             :       "Unconstrained inline size; this should only result from huge sizes "
    3652             :       "(not intrinsic sizing w/ orthogonal flows)");
    3653           0 :     return aReflowInput.ComputedISize();
    3654             :   }
    3655             : 
    3656             :   // Note: This may be unconstrained, if our block size is "auto":
    3657           0 :   return GetEffectiveComputedBSize(aReflowInput);
    3658             : }
    3659             : 
    3660             : // Returns the largest outer hypothetical main-size of any line in |aLines|.
    3661             : // (i.e. the hypothetical main-size of the largest line)
    3662             : static nscoord
    3663           0 : GetLargestLineMainSize(const FlexLine* aFirstLine)
    3664             : {
    3665           0 :   nscoord largestLineOuterSize = 0;
    3666           0 :   for (const FlexLine* line = aFirstLine; line; line = line->getNext()) {
    3667           0 :     largestLineOuterSize = std::max(largestLineOuterSize,
    3668           0 :                                     line->GetTotalOuterHypotheticalMainSize());
    3669             :   }
    3670           0 :   return largestLineOuterSize;
    3671             : }
    3672             : 
    3673             : /* Resolves the content-box main-size of a flex container frame,
    3674             :  * primarily based on:
    3675             :  * - the "tentative" main size, taken from the reflow state ("tentative"
    3676             :  *    because it may be unconstrained or may run off the page).
    3677             :  * - the available BSize (needed if the main axis is the block axis).
    3678             :  * - the sizes of our lines of flex items.
    3679             :  *
    3680             :  * Guaranteed to return a definite length, i.e. not NS_UNCONSTRAINEDSIZE,
    3681             :  * aside from cases with huge lengths which happen to compute to that value.
    3682             :  *
    3683             :  * (Note: This function should be structurally similar to 'ComputeCrossSize()',
    3684             :  * except that here, the caller has already grabbed the tentative size from the
    3685             :  * reflow state.)
    3686             :  */
    3687             : static nscoord
    3688           0 : ResolveFlexContainerMainSize(const ReflowInput& aReflowInput,
    3689             :                              const FlexboxAxisTracker& aAxisTracker,
    3690             :                              nscoord aTentativeMainSize,
    3691             :                              nscoord aAvailableBSizeForContent,
    3692             :                              const FlexLine* aFirstLine,
    3693             :                              nsReflowStatus& aStatus)
    3694             : {
    3695           0 :   MOZ_ASSERT(aFirstLine, "null first line pointer");
    3696             : 
    3697           0 :   if (aAxisTracker.IsRowOriented()) {
    3698             :     // Row-oriented --> our main axis is the inline axis, so our main size
    3699             :     // is our inline size (which should already be resolved).
    3700           0 :     return aTentativeMainSize;
    3701             :   }
    3702             : 
    3703           0 :   if (aTentativeMainSize != NS_INTRINSICSIZE) {
    3704             :     // Column-oriented case, with fixed BSize:
    3705           0 :     if (aAvailableBSizeForContent == NS_UNCONSTRAINEDSIZE ||
    3706           0 :         aTentativeMainSize < aAvailableBSizeForContent) {
    3707             :       // Not in a fragmenting context, OR no need to fragment because we have
    3708             :       // more available BSize than we need. Either way, we don't need to clamp.
    3709             :       // (Note that the reflow state has already done the appropriate
    3710             :       // min/max-BSize clamping.)
    3711           0 :       return aTentativeMainSize;
    3712             :     }
    3713             : 
    3714             :     // Fragmenting *and* our fixed BSize is larger than available BSize:
    3715             :     // Mark incomplete so we get a next-in-flow, and take up all of the
    3716             :     // available BSize (or the amount of BSize required by our children, if
    3717             :     // that's larger; but of course not more than our own computed BSize).
    3718             :     // XXXdholbert For now, we don't support pushing children to our next
    3719             :     // continuation or splitting children, so "amount of BSize required by
    3720             :     // our children" is just the main-size (BSize) of our longest flex line.
    3721           0 :     aStatus.SetIncomplete();
    3722           0 :     nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
    3723             : 
    3724           0 :     if (largestLineOuterSize <= aAvailableBSizeForContent) {
    3725           0 :       return aAvailableBSizeForContent;
    3726             :     }
    3727           0 :     return std::min(aTentativeMainSize, largestLineOuterSize);
    3728             :   }
    3729             : 
    3730             :   // Column-oriented case, with auto BSize:
    3731             :   // Resolve auto BSize to the largest FlexLine length, clamped to our
    3732             :   // computed min/max main-size properties.
    3733             :   // XXXdholbert Handle constrained-aAvailableBSizeForContent case here.
    3734           0 :   nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
    3735           0 :   return NS_CSS_MINMAX(largestLineOuterSize,
    3736             :                        aReflowInput.ComputedMinBSize(),
    3737           0 :                        aReflowInput.ComputedMaxBSize());
    3738             : }
    3739             : 
    3740             : nscoord
    3741           0 : nsFlexContainerFrame::ComputeCrossSize(const ReflowInput& aReflowInput,
    3742             :                                        const FlexboxAxisTracker& aAxisTracker,
    3743             :                                        nscoord aSumLineCrossSizes,
    3744             :                                        nscoord aAvailableBSizeForContent,
    3745             :                                        bool* aIsDefinite,
    3746             :                                        nsReflowStatus& aStatus)
    3747             : {
    3748           0 :   MOZ_ASSERT(aIsDefinite, "outparam pointer must be non-null");
    3749             : 
    3750           0 :   if (aAxisTracker.IsColumnOriented()) {
    3751             :     // Column-oriented --> our cross axis is the inline axis, so our cross size
    3752             :     // is our inline size (which should already be resolved).
    3753           0 :     NS_WARNING_ASSERTION(
    3754             :       aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE,
    3755             :       "Unconstrained inline size; this should only result from huge sizes "
    3756             :       "(not intrinsic sizing w/ orthogonal flows)");
    3757           0 :     *aIsDefinite = true;
    3758           0 :     return aReflowInput.ComputedISize();
    3759             :   }
    3760             : 
    3761           0 :   nscoord effectiveComputedBSize = GetEffectiveComputedBSize(aReflowInput);
    3762           0 :   if (effectiveComputedBSize != NS_INTRINSICSIZE) {
    3763             :     // Row-oriented case (cross axis is block-axis), with fixed BSize:
    3764           0 :     *aIsDefinite = true;
    3765           0 :     if (aAvailableBSizeForContent == NS_UNCONSTRAINEDSIZE ||
    3766           0 :         effectiveComputedBSize < aAvailableBSizeForContent) {
    3767             :       // Not in a fragmenting context, OR no need to fragment because we have
    3768             :       // more available BSize than we need. Either way, just use our fixed
    3769             :       // BSize.  (Note that the reflow state has already done the appropriate
    3770             :       // min/max-BSize clamping.)
    3771           0 :       return effectiveComputedBSize;
    3772             :     }
    3773             : 
    3774             :     // Fragmenting *and* our fixed BSize is too tall for available BSize:
    3775             :     // Mark incomplete so we get a next-in-flow, and take up all of the
    3776             :     // available BSize (or the amount of BSize required by our children, if
    3777             :     // that's larger; but of course not more than our own computed BSize).
    3778             :     // XXXdholbert For now, we don't support pushing children to our next
    3779             :     // continuation or splitting children, so "amount of BSize required by
    3780             :     // our children" is just the sum of our FlexLines' BSizes (cross sizes).
    3781           0 :     aStatus.SetIncomplete();
    3782           0 :     if (aSumLineCrossSizes <= aAvailableBSizeForContent) {
    3783           0 :       return aAvailableBSizeForContent;
    3784             :     }
    3785           0 :     return std::min(effectiveComputedBSize, aSumLineCrossSizes);
    3786             :   }
    3787             : 
    3788             :   // Row-oriented case (cross axis is block axis), with auto BSize:
    3789             :   // Shrink-wrap our line(s), subject to our min-size / max-size
    3790             :   // constraints in that (block) axis.
    3791             :   // XXXdholbert Handle constrained-aAvailableBSizeForContent case here.
    3792           0 :   *aIsDefinite = false;
    3793           0 :   return NS_CSS_MINMAX(aSumLineCrossSizes,
    3794             :                        aReflowInput.ComputedMinBSize(),
    3795           0 :                        aReflowInput.ComputedMaxBSize());
    3796             : }
    3797             : 
    3798             : void
    3799           0 : FlexLine::PositionItemsInMainAxis(uint8_t aJustifyContent,
    3800             :                                   nscoord aContentBoxMainSize,
    3801             :                                   const FlexboxAxisTracker& aAxisTracker)
    3802             : {
    3803             :   MainAxisPositionTracker mainAxisPosnTracker(aAxisTracker, this,
    3804             :                                               aJustifyContent,
    3805           0 :                                               aContentBoxMainSize);
    3806           0 :   for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
    3807             :     nscoord itemMainBorderBoxSize =
    3808           0 :       item->GetMainSize() +
    3809           0 :       item->GetBorderPaddingSizeInAxis(mainAxisPosnTracker.GetAxis());
    3810             : 
    3811             :     // Resolve any main-axis 'auto' margins on aChild to an actual value.
    3812           0 :     mainAxisPosnTracker.ResolveAutoMarginsInMainAxis(*item);
    3813             : 
    3814             :     // Advance our position tracker to child's upper-left content-box corner,
    3815             :     // and use that as its position in the main axis.
    3816           0 :     mainAxisPosnTracker.EnterMargin(item->GetMargin());
    3817           0 :     mainAxisPosnTracker.EnterChildFrame(itemMainBorderBoxSize);
    3818             : 
    3819           0 :     item->SetMainPosition(mainAxisPosnTracker.GetPosition());
    3820             : 
    3821           0 :     mainAxisPosnTracker.ExitChildFrame(itemMainBorderBoxSize);
    3822           0 :     mainAxisPosnTracker.ExitMargin(item->GetMargin());
    3823           0 :     mainAxisPosnTracker.TraversePackingSpace();
    3824             :   }
    3825           0 : }
    3826             : 
    3827             : /**
    3828             :  * Given the flex container's "flex-relative ascent" (i.e. distance from the
    3829             :  * flex container's content-box cross-start edge to its baseline), returns
    3830             :  * its actual physical ascent value (the distance from the *border-box* top
    3831             :  * edge to its baseline).
    3832             :  */
    3833             : static nscoord
    3834           0 : ComputePhysicalAscentFromFlexRelativeAscent(
    3835             :   nscoord aFlexRelativeAscent,
    3836             :   nscoord aContentBoxCrossSize,
    3837             :   const ReflowInput& aReflowInput,
    3838             :   const FlexboxAxisTracker& aAxisTracker)
    3839             : {
    3840           0 :   return aReflowInput.ComputedPhysicalBorderPadding().top +
    3841           0 :     PhysicalCoordFromFlexRelativeCoord(aFlexRelativeAscent,
    3842             :                                        aContentBoxCrossSize,
    3843           0 :                                        aAxisTracker.GetCrossAxis());
    3844             : }
    3845             : 
    3846             : void
    3847           0 : nsFlexContainerFrame::SizeItemInCrossAxis(
    3848             :   nsPresContext* aPresContext,
    3849             :   const FlexboxAxisTracker& aAxisTracker,
    3850             :   ReflowInput& aChildReflowInput,
    3851             :   FlexItem& aItem)
    3852             : {
    3853           0 :   if (aAxisTracker.IsCrossAxisHorizontal()) {
    3854           0 :     MOZ_ASSERT(aItem.HasIntrinsicRatio(),
    3855             :                "For now, caller's CanMainSizeInfluenceCrossSize check should "
    3856             :                "only allow us to get here for items with intrinsic ratio");
    3857             :     // XXXdholbert When we finish support for vertical writing-modes,
    3858             :     // (in bug 1079155 or a dependency), we'll relax the horizontal check in
    3859             :     // CanMainSizeInfluenceCrossSize, and this function will need to be able
    3860             :     // to measure the baseline & width (given our resolved height)
    3861             :     // of vertical-writing-mode flex items here.
    3862             :     // For now, we only expect to get here for items with an intrinsic aspect
    3863             :     // ratio; and for those items, we can just read the size off of the reflow
    3864             :     // state, without performing reflow.
    3865           0 :     aItem.SetCrossSize(aChildReflowInput.ComputedWidth());
    3866           0 :     return;
    3867             :   }
    3868             : 
    3869           0 :   MOZ_ASSERT(!aItem.HadMeasuringReflow(),
    3870             :              "We shouldn't need more than one measuring reflow");
    3871             : 
    3872           0 :   if (aItem.GetAlignSelf() == NS_STYLE_ALIGN_STRETCH) {
    3873             :     // This item's got "align-self: stretch", so we probably imposed a
    3874             :     // stretched computed height on it during its previous reflow. We're
    3875             :     // not imposing that height for *this* measuring reflow, so we need to
    3876             :     // tell it to treat this reflow as a vertical resize (regardless of
    3877             :     // whether any of its ancestors are being resized).
    3878           0 :     aChildReflowInput.SetVResize(true);
    3879             :   }
    3880             : 
    3881             :   // Potentially reflow the item, and get the sizing info.
    3882             :   const CachedMeasuringReflowResult& reflowResult =
    3883           0 :     MeasureAscentAndHeightForFlexItem(aItem, aPresContext, aChildReflowInput);
    3884             : 
    3885             :   // Save the sizing info that we learned from this reflow
    3886             :   // -----------------------------------------------------
    3887             : 
    3888             :   // Tentatively store the child's desired content-box cross-size.
    3889             :   // Note that childDesiredSize is the border-box size, so we have to
    3890             :   // subtract border & padding to get the content-box size.
    3891             :   // (Note that at this point in the code, we know our cross axis is vertical,
    3892             :   // so we don't bother with making aAxisTracker pick the cross-axis component
    3893             :   // for us.)
    3894           0 :   nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom();
    3895           0 :   if (reflowResult.Height() < crossAxisBorderPadding) {
    3896             :     // Child's requested size isn't large enough for its border/padding!
    3897             :     // This is OK for the trivial nsFrame::Reflow() impl, but other frame
    3898             :     // classes should know better. So, if we get here, the child had better be
    3899             :     // an instance of nsFrame (i.e. it should return null from GetType()).
    3900             :     // XXXdholbert Once we've fixed bug 765861, we should upgrade this to an
    3901             :     // assertion that trivially passes if bug 765861's flag has been flipped.
    3902           0 :     NS_WARNING_ASSERTION(
    3903             :       aItem.Frame()->Type() == LayoutFrameType::None,
    3904             :       "Child should at least request space for border/padding");
    3905           0 :     aItem.SetCrossSize(0);
    3906             :   } else {
    3907             :     // (normal case)
    3908           0 :     aItem.SetCrossSize(reflowResult.Height() - crossAxisBorderPadding);
    3909             :   }
    3910             : 
    3911           0 :   aItem.SetAscent(reflowResult.Ascent());
    3912             : }
    3913             : 
    3914             : void
    3915           0 : FlexLine::PositionItemsInCrossAxis(nscoord aLineStartPosition,
    3916             :                                    const FlexboxAxisTracker& aAxisTracker)
    3917             : {
    3918           0 :   SingleLineCrossAxisPositionTracker lineCrossAxisPosnTracker(aAxisTracker);
    3919             : 
    3920           0 :   for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
    3921             :     // First, stretch the item's cross size (if appropriate), and resolve any
    3922             :     // auto margins in this axis.
    3923           0 :     item->ResolveStretchedCrossSize(mLineCrossSize, aAxisTracker);
    3924           0 :     lineCrossAxisPosnTracker.ResolveAutoMarginsInCrossAxis(*this, *item);
    3925             : 
    3926             :     // Compute the cross-axis position of this item
    3927             :     nscoord itemCrossBorderBoxSize =
    3928           0 :       item->GetCrossSize() +
    3929           0 :       item->GetBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
    3930           0 :     lineCrossAxisPosnTracker.EnterAlignPackingSpace(*this, *item, aAxisTracker);
    3931           0 :     lineCrossAxisPosnTracker.EnterMargin(item->GetMargin());
    3932           0 :     lineCrossAxisPosnTracker.EnterChildFrame(itemCrossBorderBoxSize);
    3933             : 
    3934           0 :     item->SetCrossPosition(aLineStartPosition +
    3935           0 :                            lineCrossAxisPosnTracker.GetPosition());
    3936             : 
    3937             :     // Back out to cross-axis edge of the line.
    3938           0 :     lineCrossAxisPosnTracker.ResetPosition();
    3939             :   }
    3940           0 : }
    3941             : 
    3942             : void
    3943           0 : nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
    3944             :                              ReflowOutput& aDesiredSize,
    3945             :                              const ReflowInput& aReflowInput,
    3946             :                              nsReflowStatus& aStatus)
    3947             : {
    3948           0 :   MarkInReflow();
    3949           0 :   DO_GLOBAL_REFLOW_COUNT("nsFlexContainerFrame");
    3950           0 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
    3951           0 :   MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
    3952             :          ("Reflow() for nsFlexContainerFrame %p\n", this));
    3953             : 
    3954           0 :   if (IsFrameTreeTooDeep(aReflowInput, aDesiredSize, aStatus)) {
    3955           0 :     return;
    3956             :   }
    3957             : 
    3958             :   // We (and our children) can only depend on our ancestor's bsize if we have
    3959             :   // a percent-bsize, or if we're positioned and we have "block-start" and "block-end"
    3960             :   // set and have block-size:auto.  (There are actually other cases, too -- e.g. if
    3961             :   // our parent is itself a block-dir flex container and we're flexible -- but
    3962             :   // we'll let our ancestors handle those sorts of cases.)
    3963           0 :   WritingMode wm = aReflowInput.GetWritingMode();
    3964           0 :   const nsStylePosition* stylePos = StylePosition();
    3965           0 :   const nsStyleCoord& bsize = stylePos->BSize(wm);
    3966           0 :   if (bsize.HasPercent() ||
    3967           0 :       (StyleDisplay()->IsAbsolutelyPositionedStyle() &&
    3968           0 :        eStyleUnit_Auto == bsize.GetUnit() &&
    3969           0 :        eStyleUnit_Auto != stylePos->mOffset.GetBStartUnit(wm) &&
    3970           0 :        eStyleUnit_Auto != stylePos->mOffset.GetBEndUnit(wm))) {
    3971           0 :     AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
    3972             :   }
    3973             : 
    3974           0 :   RenumberList();
    3975             : 
    3976           0 :   const FlexboxAxisTracker axisTracker(this, aReflowInput.GetWritingMode());
    3977             : 
    3978             :   // If we're being fragmented into a constrained BSize, then subtract off
    3979             :   // borderpadding BStart from that constrained BSize, to get the available
    3980             :   // BSize for our content box. (No need to subtract the borderpadding BStart
    3981             :   // if we're already skipping it via GetLogicalSkipSides, though.)
    3982           0 :   nscoord availableBSizeForContent = aReflowInput.AvailableBSize();
    3983           0 :   if (availableBSizeForContent != NS_UNCONSTRAINEDSIZE &&
    3984           0 :       !(GetLogicalSkipSides(&aReflowInput).BStart())) {
    3985           0 :     availableBSizeForContent -=
    3986           0 :       aReflowInput.ComputedLogicalBorderPadding().BStart(wm);
    3987             :     // (Don't let that push availableBSizeForContent below zero, though):
    3988           0 :     availableBSizeForContent = std::max(availableBSizeForContent, 0);
    3989             :   }
    3990             : 
    3991             :   nscoord contentBoxMainSize = GetMainSizeFromReflowInput(aReflowInput,
    3992           0 :                                                           axisTracker);
    3993             : 
    3994           0 :   AutoTArray<StrutInfo, 1> struts;
    3995             :   DoFlexLayout(aPresContext, aDesiredSize, aReflowInput, aStatus,
    3996             :                contentBoxMainSize, availableBSizeForContent,
    3997           0 :                struts, axisTracker);
    3998             : 
    3999           0 :   if (!struts.IsEmpty()) {
    4000             :     // We're restarting flex layout, with new knowledge of collapsed items.
    4001             :     DoFlexLayout(aPresContext, aDesiredSize, aReflowInput, aStatus,
    4002             :                  contentBoxMainSize, availableBSizeForContent,
    4003           0 :                  struts, axisTracker);
    4004             :   }
    4005             : }
    4006             : 
    4007             : // RAII class to clean up a list of FlexLines.
    4008             : // Specifically, this removes each line from the list, deletes all the
    4009             : // FlexItems in its list, and deletes the FlexLine.
    4010             : class MOZ_RAII AutoFlexLineListClearer
    4011             : {
    4012             : public:
    4013           0 :   explicit AutoFlexLineListClearer(LinkedList<FlexLine>& aLines
    4014             :                                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    4015           0 :   : mLines(aLines)
    4016             :   {
    4017           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    4018           0 :   }
    4019             : 
    4020           0 :   ~AutoFlexLineListClearer()
    4021           0 :   {
    4022           0 :     while (FlexLine* line = mLines.popFirst()) {
    4023           0 :       while (FlexItem* item = line->mItems.popFirst()) {
    4024           0 :         delete item;
    4025           0 :       }
    4026           0 :       delete line;
    4027           0 :     }
    4028           0 :   }
    4029             : 
    4030             : private:
    4031             :   LinkedList<FlexLine>& mLines;
    4032             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    4033             : };
    4034             : 
    4035             : // Class to let us temporarily provide an override value for the the main-size
    4036             : // CSS property ('width' or 'height') on a flex item, for use in
    4037             : // nsFrame::ComputeSizeWithIntrinsicDimensions.
    4038             : // (We could use this overridden size more broadly, too, but it's probably
    4039             : // better to avoid property-table accesses.  So, where possible, we communicate
    4040             : // the resolved main-size to the child via modifying its reflow state directly,
    4041             : // instead of using this class.)
    4042             : class MOZ_RAII AutoFlexItemMainSizeOverride final
    4043             : {
    4044             : public:
    4045           0 :   explicit AutoFlexItemMainSizeOverride(FlexItem& aItem
    4046             :                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    4047           0 :     : mItemFrame(aItem.Frame())
    4048             :   {
    4049           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    4050             : 
    4051           0 :     MOZ_ASSERT(!mItemFrame->HasProperty(nsIFrame::FlexItemMainSizeOverride()),
    4052             :                "FlexItemMainSizeOverride prop shouldn't be set already; "
    4053             :                "it should only be set temporarily (& not recursively)");
    4054           0 :     NS_ASSERTION(aItem.HasIntrinsicRatio(),
    4055             :                  "This should only be needed for items with an aspect ratio");
    4056             : 
    4057           0 :     mItemFrame->SetProperty(nsIFrame::FlexItemMainSizeOverride(),
    4058           0 :                             aItem.GetMainSize());
    4059           0 :   }
    4060             : 
    4061           0 :   ~AutoFlexItemMainSizeOverride() {
    4062           0 :     mItemFrame->RemoveProperty(nsIFrame::FlexItemMainSizeOverride());
    4063           0 :   }
    4064             : 
    4065             : private:
    4066             :   nsIFrame* mItemFrame;
    4067             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    4068             : };
    4069             : 
    4070             : void
    4071           0 : nsFlexContainerFrame::CalculatePackingSpace(uint32_t aNumThingsToPack,
    4072             :                                             uint8_t aAlignVal,
    4073             :                                             nscoord* aFirstSubjectOffset,
    4074             :                                             uint32_t* aNumPackingSpacesRemaining,
    4075             :                                             nscoord* aPackingSpaceRemaining)
    4076             : {
    4077             :   MOZ_ASSERT(NS_STYLE_ALIGN_SPACE_BETWEEN == NS_STYLE_JUSTIFY_SPACE_BETWEEN &&
    4078             :              NS_STYLE_ALIGN_SPACE_AROUND == NS_STYLE_JUSTIFY_SPACE_AROUND &&
    4079             :              NS_STYLE_ALIGN_SPACE_EVENLY == NS_STYLE_JUSTIFY_SPACE_EVENLY,
    4080             :              "CalculatePackingSpace assumes that NS_STYLE_ALIGN_SPACE and "
    4081             :              "NS_STYLE_JUSTIFY_SPACE constants are interchangeable");
    4082             : 
    4083           0 :   MOZ_ASSERT(aAlignVal == NS_STYLE_ALIGN_SPACE_BETWEEN ||
    4084             :              aAlignVal == NS_STYLE_ALIGN_SPACE_AROUND ||
    4085             :              aAlignVal == NS_STYLE_ALIGN_SPACE_EVENLY,
    4086             :              "Unexpected alignment value");
    4087             : 
    4088           0 :   MOZ_ASSERT(*aPackingSpaceRemaining >= 0,
    4089             :              "Should not be called with negative packing space");
    4090             : 
    4091           0 :   MOZ_ASSERT(aNumThingsToPack >= 1,
    4092             :              "Should not be called with less than 1 thing to pack");
    4093             : 
    4094             :   // Packing spaces between items:
    4095           0 :   *aNumPackingSpacesRemaining = aNumThingsToPack - 1;
    4096             : 
    4097           0 :   if (aAlignVal == NS_STYLE_ALIGN_SPACE_BETWEEN) {
    4098             :     // No need to reserve space at beginning/end, so we're done.
    4099           0 :     return;
    4100             :   }
    4101             : 
    4102             :   // We need to add 1 or 2 packing spaces, split between beginning/end, for
    4103             :   // space-around / space-evenly:
    4104             :   size_t numPackingSpacesForEdges =
    4105           0 :     aAlignVal == NS_STYLE_JUSTIFY_SPACE_AROUND ? 1 : 2;
    4106             : 
    4107             :   // How big will each "full" packing space be:
    4108           0 :   nscoord packingSpaceSize = *aPackingSpaceRemaining /
    4109           0 :     (*aNumPackingSpacesRemaining + numPackingSpacesForEdges);
    4110             :   // How much packing-space are we allocating to the edges:
    4111           0 :   nscoord totalEdgePackingSpace = numPackingSpacesForEdges * packingSpaceSize;
    4112             : 
    4113             :   // Use half of that edge packing space right now:
    4114           0 :   *aFirstSubjectOffset += totalEdgePackingSpace / 2;
    4115             :   // ...but we need to subtract all of it right away, so that we won't
    4116             :   // hand out any of it to intermediate packing spaces.
    4117           0 :   *aPackingSpaceRemaining -= totalEdgePackingSpace;
    4118             : }
    4119             : 
    4120             : void
    4121           0 : nsFlexContainerFrame::DoFlexLayout(nsPresContext*           aPresContext,
    4122             :                                    ReflowOutput&     aDesiredSize,
    4123             :                                    const ReflowInput& aReflowInput,
    4124             :                                    nsReflowStatus&          aStatus,
    4125             :                                    nscoord aContentBoxMainSize,
    4126             :                                    nscoord aAvailableBSizeForContent,
    4127             :                                    nsTArray<StrutInfo>& aStruts,
    4128             :                                    const FlexboxAxisTracker& aAxisTracker)
    4129             : {
    4130           0 :   aStatus.Reset();
    4131             : 
    4132           0 :   LinkedList<FlexLine> lines;
    4133           0 :   nsTArray<nsIFrame*> placeholderKids;
    4134           0 :   AutoFlexLineListClearer cleanupLines(lines);
    4135             : 
    4136             :   GenerateFlexLines(aPresContext, aReflowInput,
    4137             :                     aContentBoxMainSize,
    4138             :                     aAvailableBSizeForContent,
    4139             :                     aStruts, aAxisTracker,
    4140           0 :                     placeholderKids, lines);
    4141             : 
    4142           0 :   if (lines.getFirst()->IsEmpty() &&
    4143           0 :       !lines.getFirst()->getNext()) {
    4144             :     // We have no flex items, our parent should synthesize a baseline if needed.
    4145           0 :     AddStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE);
    4146             :   } else {
    4147           0 :     RemoveStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE);
    4148             :   }
    4149             : 
    4150             :   aContentBoxMainSize =
    4151             :     ResolveFlexContainerMainSize(aReflowInput, aAxisTracker,
    4152             :                                  aContentBoxMainSize, aAvailableBSizeForContent,
    4153           0 :                                  lines.getFirst(), aStatus);
    4154             : 
    4155           0 :   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
    4156           0 :     line->ResolveFlexibleLengths(aContentBoxMainSize);
    4157             :   }
    4158             : 
    4159             :   // Cross Size Determination - Flexbox spec section 9.4
    4160             :   // ===================================================
    4161             :   // Calculate the hypothetical cross size of each item:
    4162           0 :   nscoord sumLineCrossSizes = 0;
    4163           0 :   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
    4164           0 :     for (FlexItem* item = line->GetFirstItem(); item; item = item->getNext()) {
    4165             :       // The item may already have the correct cross-size; only recalculate
    4166             :       // if the item's main size resolution (flexing) could have influenced it:
    4167           0 :       if (item->CanMainSizeInfluenceCrossSize(aAxisTracker)) {
    4168           0 :         Maybe<AutoFlexItemMainSizeOverride> sizeOverride;
    4169           0 :         if (item->HasIntrinsicRatio()) {
    4170             :           // For flex items with an aspect ratio, we have to impose an override
    4171             :           // for the main-size property *before* we even instantiate the reflow
    4172             :           // state, in order for aspect ratio calculations to produce the right
    4173             :           // cross size in the reflow state. (For other flex items, it's OK
    4174             :           // (and cheaper) to impose our main size *after* the reflow state has
    4175             :           // been constructed, since the main size shouldn't influence anything
    4176             :           // about cross-size measurement until we actually reflow the child.)
    4177           0 :           sizeOverride.emplace(*item);
    4178             :         }
    4179             : 
    4180           0 :         WritingMode wm = item->Frame()->GetWritingMode();
    4181           0 :         LogicalSize availSize = aReflowInput.ComputedSize(wm);
    4182           0 :         availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    4183             :         ReflowInput childReflowInput(aPresContext, aReflowInput,
    4184           0 :                                      item->Frame(), availSize);
    4185           0 :         if (!sizeOverride) {
    4186             :           // Directly override the computed main-size, by tweaking reflow state:
    4187           0 :           if (aAxisTracker.IsMainAxisHorizontal()) {
    4188           0 :             childReflowInput.SetComputedWidth(item->GetMainSize());
    4189             :           } else {
    4190           0 :             childReflowInput.SetComputedHeight(item->GetMainSize());
    4191             :           }
    4192             :         }
    4193             : 
    4194             :         SizeItemInCrossAxis(aPresContext, aAxisTracker,
    4195           0 :                             childReflowInput, *item);
    4196             :       }
    4197             :     }
    4198             :     // Now that we've finished with this line's items, size the line itself:
    4199           0 :     line->ComputeCrossSizeAndBaseline(aAxisTracker);
    4200           0 :     sumLineCrossSizes += line->GetLineCrossSize();
    4201             :   }
    4202             : 
    4203             :   bool isCrossSizeDefinite;
    4204             :   const nscoord contentBoxCrossSize =
    4205             :     ComputeCrossSize(aReflowInput, aAxisTracker, sumLineCrossSizes,
    4206           0 :                      aAvailableBSizeForContent, &isCrossSizeDefinite, aStatus);
    4207             : 
    4208             :   // Set up state for cross-axis alignment, at a high level (outside the
    4209             :   // scope of a particular flex line)
    4210             :   CrossAxisPositionTracker
    4211             :     crossAxisPosnTracker(lines.getFirst(),
    4212             :                          aReflowInput, contentBoxCrossSize,
    4213           0 :                          isCrossSizeDefinite, aAxisTracker);
    4214             : 
    4215             :   // Now that we know the cross size of each line (including
    4216             :   // "align-content:stretch" adjustments, from the CrossAxisPositionTracker
    4217             :   // constructor), we can create struts for any flex items with
    4218             :   // "visibility: collapse" (and restart flex layout).
    4219           0 :   if (aStruts.IsEmpty()) { // (Don't make struts if we already did)
    4220           0 :     BuildStrutInfoFromCollapsedItems(lines.getFirst(), aStruts);
    4221           0 :     if (!aStruts.IsEmpty()) {
    4222             :       // Restart flex layout, using our struts.
    4223           0 :       return;
    4224             :     }
    4225             :   }
    4226             : 
    4227             :   // If the container should derive its baseline from the first FlexLine,
    4228             :   // do that here (while crossAxisPosnTracker is conveniently pointing
    4229             :   // at the cross-start edge of that line, which the line's baseline offset is
    4230             :   // measured from):
    4231             :   nscoord flexContainerAscent;
    4232           0 :   if (!aAxisTracker.AreAxesInternallyReversed()) {
    4233           0 :     nscoord firstLineBaselineOffset = lines.getFirst()->GetFirstBaselineOffset();
    4234           0 :     if (firstLineBaselineOffset == nscoord_MIN) {
    4235             :       // No baseline-aligned items in line. Use sentinel value to prompt us to
    4236             :       // get baseline from the first FlexItem after we've reflowed it.
    4237           0 :       flexContainerAscent = nscoord_MIN;
    4238             :     } else  {
    4239             :       flexContainerAscent =
    4240           0 :         ComputePhysicalAscentFromFlexRelativeAscent(
    4241           0 :           crossAxisPosnTracker.GetPosition() + firstLineBaselineOffset,
    4242           0 :           contentBoxCrossSize, aReflowInput, aAxisTracker);
    4243             :     }
    4244             :   }
    4245             : 
    4246           0 :   const auto justifyContent = IsLegacyBox(aReflowInput.mFrame) ?
    4247           0 :     ConvertLegacyStyleToJustifyContent(StyleXUL()) :
    4248           0 :     aReflowInput.mStylePosition->mJustifyContent;
    4249             : 
    4250           0 :   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
    4251             :     // Main-Axis Alignment - Flexbox spec section 9.5
    4252             :     // ==============================================
    4253           0 :     line->PositionItemsInMainAxis(justifyContent,
    4254             :                                   aContentBoxMainSize,
    4255           0 :                                   aAxisTracker);
    4256             : 
    4257             :     // Cross-Axis Alignment - Flexbox spec section 9.6
    4258             :     // ===============================================
    4259           0 :     line->PositionItemsInCrossAxis(crossAxisPosnTracker.GetPosition(),
    4260           0 :                                    aAxisTracker);
    4261           0 :     crossAxisPosnTracker.TraverseLine(*line);
    4262           0 :     crossAxisPosnTracker.TraversePackingSpace();
    4263             :   }
    4264             : 
    4265             :   // If the container should derive its baseline from the last FlexLine,
    4266             :   // do that here (while crossAxisPosnTracker is conveniently pointing
    4267             :   // at the cross-end edge of that line, which the line's baseline offset is
    4268             :   // measured from):
    4269           0 :   if (aAxisTracker.AreAxesInternallyReversed()) {
    4270           0 :     nscoord lastLineBaselineOffset = lines.getLast()->GetFirstBaselineOffset();
    4271           0 :     if (lastLineBaselineOffset == nscoord_MIN) {
    4272             :       // No baseline-aligned items in line. Use sentinel value to prompt us to
    4273             :       // get baseline from the last FlexItem after we've reflowed it.
    4274           0 :       flexContainerAscent = nscoord_MIN;
    4275             :     } else {
    4276             :       flexContainerAscent =
    4277           0 :         ComputePhysicalAscentFromFlexRelativeAscent(
    4278           0 :           crossAxisPosnTracker.GetPosition() - lastLineBaselineOffset,
    4279           0 :           contentBoxCrossSize, aReflowInput, aAxisTracker);
    4280             :     }
    4281             :   }
    4282             : 
    4283             :   // Before giving each child a final reflow, calculate the origin of the
    4284             :   // flex container's content box (with respect to its border-box), so that
    4285             :   // we can compute our flex item's final positions.
    4286           0 :   WritingMode flexWM = aReflowInput.GetWritingMode();
    4287           0 :   LogicalMargin containerBP = aReflowInput.ComputedLogicalBorderPadding();
    4288             : 
    4289             :   // Unconditionally skip block-end border & padding for now, regardless of
    4290             :   // writing-mode/GetLogicalSkipSides.  We add it lower down, after we've
    4291             :   // established baseline and decided whether bottom border-padding fits (if
    4292             :   // we're fragmented).
    4293           0 :   const nscoord blockEndContainerBP = containerBP.BEnd(flexWM);
    4294             :   const LogicalSides skipSides =
    4295           0 :     GetLogicalSkipSides(&aReflowInput) | LogicalSides(eLogicalSideBitsBEnd);
    4296           0 :   containerBP.ApplySkipSides(skipSides);
    4297             : 
    4298             :   const LogicalPoint containerContentBoxOrigin(flexWM,
    4299           0 :                                                containerBP.IStart(flexWM),
    4300           0 :                                                containerBP.BStart(flexWM));
    4301             : 
    4302             :   // Determine flex container's border-box size (used in positioning children):
    4303             :   LogicalSize logSize =
    4304             :     aAxisTracker.LogicalSizeFromFlexRelativeSizes(aContentBoxMainSize,
    4305           0 :                                                   contentBoxCrossSize);
    4306           0 :   logSize += aReflowInput.ComputedLogicalBorderPadding().Size(flexWM);
    4307           0 :   nsSize containerSize = logSize.GetPhysicalSize(flexWM);
    4308             : 
    4309             :   // If the flex container has no baseline-aligned items, it will use this item
    4310             :   // (the first item, discounting any under-the-hood reversing that we've done)
    4311             :   // to determine its baseline:
    4312             :   const FlexItem* const firstItem =
    4313           0 :     aAxisTracker.AreAxesInternallyReversed()
    4314           0 :     ? lines.getLast()->GetLastItem()
    4315           0 :     : lines.getFirst()->GetFirstItem();
    4316             : 
    4317             :   // FINAL REFLOW: Give each child frame another chance to reflow, now that
    4318             :   // we know its final size and position.
    4319           0 :   for (const FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
    4320           0 :     for (const FlexItem* item = line->GetFirstItem(); item;
    4321           0 :          item = item->getNext()) {
    4322             :       LogicalPoint framePos = aAxisTracker.LogicalPointFromFlexRelativePoint(
    4323             :                                item->GetMainPosition(),
    4324             :                                item->GetCrossPosition(),
    4325             :                                aContentBoxMainSize,
    4326           0 :                                contentBoxCrossSize);
    4327             :       // Adjust framePos to be relative to the container's border-box
    4328             :       // (i.e. its frame rect), instead of the container's content-box:
    4329           0 :       framePos += containerContentBoxOrigin;
    4330             : 
    4331             :       // (Intentionally snapshotting this before ApplyRelativePositioning, to
    4332             :       // maybe use for setting the flex container's baseline.)
    4333           0 :       const nscoord itemNormalBPos = framePos.B(flexWM);
    4334             : 
    4335             :       // Check if we actually need to reflow the item -- if we already reflowed
    4336             :       // it with the right size, we can just reposition it as-needed.
    4337           0 :       bool itemNeedsReflow = true; // (Start out assuming the worst.)
    4338           0 :       if (item->HadMeasuringReflow()) {
    4339             :         LogicalSize finalFlexItemCBSize =
    4340             :           aAxisTracker.LogicalSizeFromFlexRelativeSizes(item->GetMainSize(),
    4341           0 :                                                         item->GetCrossSize());
    4342             :         // We've already reflowed the child once. Was the size we gave it in
    4343             :         // that reflow the same as its final (post-flexing/stretching) size?
    4344           0 :         if (finalFlexItemCBSize ==
    4345           0 :             LogicalSize(flexWM,
    4346           0 :                         item->Frame()->GetContentRectRelativeToSelf().Size())) {
    4347             :           // Even if our size hasn't changed, some of our descendants might
    4348             :           // care that our bsize is now considered "definite" (whereas it
    4349             :           // wasn't in our previous "measuring" reflow), if they have a
    4350             :           // relative bsize.
    4351           0 :           if (!(item->Frame()->GetStateBits() &
    4352             :                 NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
    4353             :             // Item has the correct size (and its children don't care that
    4354             :             // it's now "definite"). Let's just make sure it's at the right
    4355             :             // position.
    4356           0 :             itemNeedsReflow = false;
    4357             :             MoveFlexItemToFinalPosition(aReflowInput, *item, framePos,
    4358           0 :                                         containerSize);
    4359             :           }
    4360             :         }
    4361             :       }
    4362           0 :       if (itemNeedsReflow) {
    4363             :         ReflowFlexItem(aPresContext, aAxisTracker, aReflowInput,
    4364           0 :                        *item, framePos, containerSize);
    4365             :       }
    4366             : 
    4367             :       // If this is our first item and we haven't established a baseline for
    4368             :       // the container yet (i.e. if we don't have 'align-self: baseline' on any
    4369             :       // children), then use this child's first baseline as the container's
    4370             :       // baseline.
    4371           0 :       if (item == firstItem &&
    4372             :           flexContainerAscent == nscoord_MIN) {
    4373           0 :         flexContainerAscent = itemNormalBPos + item->ResolvedAscent(true);
    4374             :       }
    4375             :     }
    4376             :   }
    4377             : 
    4378           0 :   if (!placeholderKids.IsEmpty()) {
    4379             :     ReflowPlaceholders(aPresContext, aReflowInput,
    4380             :                        placeholderKids, containerContentBoxOrigin,
    4381           0 :                        containerSize);
    4382             :   }
    4383             : 
    4384             :   // Compute flex container's desired size (in its own writing-mode),
    4385             :   // starting w/ content-box size & growing from there:
    4386             :   LogicalSize desiredSizeInFlexWM =
    4387             :     aAxisTracker.LogicalSizeFromFlexRelativeSizes(aContentBoxMainSize,
    4388           0 :                                                   contentBoxCrossSize);
    4389             :   // Add border/padding (w/ skipSides already applied):
    4390           0 :   desiredSizeInFlexWM.ISize(flexWM) += containerBP.IStartEnd(flexWM);
    4391           0 :   desiredSizeInFlexWM.BSize(flexWM) += containerBP.BStartEnd(flexWM);
    4392             : 
    4393           0 :   if (flexContainerAscent == nscoord_MIN) {
    4394             :     // Still don't have our baseline set -- this happens if we have no
    4395             :     // children (or if our children are huge enough that they have nscoord_MIN
    4396             :     // as their baseline... in which case, we'll use the wrong baseline, but no
    4397             :     // big deal)
    4398           0 :     NS_WARNING_ASSERTION(
    4399             :       lines.getFirst()->IsEmpty(),
    4400             :       "Have flex items but didn't get an ascent - that's odd (or there are "
    4401             :       "just gigantic sizes involved)");
    4402             :     // Per spec, synthesize baseline from the flex container's content box
    4403             :     // (i.e. use block-end side of content-box)
    4404             :     // XXXdholbert This only makes sense if parent's writing mode is
    4405             :     // horizontal (& even then, really we should be using the BSize in terms
    4406             :     // of the parent's writing mode, not ours). Clean up in bug 1155322.
    4407           0 :     flexContainerAscent = desiredSizeInFlexWM.BSize(flexWM);
    4408             :   }
    4409             : 
    4410           0 :   if (HasAnyStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE)) {
    4411             :     // This will force our parent to call GetLogicalBaseline, which will
    4412             :     // synthesize a margin-box baseline.
    4413           0 :     aDesiredSize.SetBlockStartAscent(ReflowOutput::ASK_FOR_BASELINE);
    4414             :   } else {
    4415             :     // XXXdholbert flexContainerAscent needs to be in terms of
    4416             :     // our parent's writing-mode here. See bug 1155322.
    4417           0 :     aDesiredSize.SetBlockStartAscent(flexContainerAscent);
    4418             :   }
    4419             : 
    4420             :   // Now: If we're complete, add bottom border/padding to desired height (which
    4421             :   // we skipped via skipSides) -- unless that pushes us over available height,
    4422             :   // in which case we become incomplete (unless we already weren't asking for
    4423             :   // any height, in which case we stay complete to avoid looping forever).
    4424             :   // NOTE: If we're auto-height, we allow our bottom border/padding to push us
    4425             :   // over the available height without requesting a continuation, for
    4426             :   // consistency with the behavior of "display:block" elements.
    4427           0 :   if (aStatus.IsComplete()) {
    4428             :     nscoord desiredBSizeWithBEndBP =
    4429           0 :       desiredSizeInFlexWM.BSize(flexWM) + blockEndContainerBP;
    4430             : 
    4431           0 :     if (aReflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE ||
    4432           0 :         desiredSizeInFlexWM.BSize(flexWM) == 0 ||
    4433           0 :         desiredBSizeWithBEndBP <= aReflowInput.AvailableBSize() ||
    4434           0 :         aReflowInput.ComputedBSize() == NS_INTRINSICSIZE) {
    4435             :       // Update desired height to include block-end border/padding
    4436           0 :       desiredSizeInFlexWM.BSize(flexWM) = desiredBSizeWithBEndBP;
    4437             :     } else {
    4438             :       // We couldn't fit bottom border/padding, so we'll need a continuation.
    4439           0 :       aStatus.SetIncomplete();
    4440             :     }
    4441             :   }
    4442             : 
    4443             :   // Calculate the container baselines so that our parent can baseline-align us.
    4444           0 :   mBaselineFromLastReflow = flexContainerAscent;
    4445           0 :   mLastBaselineFromLastReflow = lines.getLast()->GetLastBaselineOffset();
    4446           0 :   if (mLastBaselineFromLastReflow == nscoord_MIN) {
    4447             :     // XXX we fall back to a mirrored first baseline here for now, but this
    4448             :     // should probably use the last baseline of the last item or something.
    4449           0 :     mLastBaselineFromLastReflow =
    4450           0 :       desiredSizeInFlexWM.BSize(flexWM) - flexContainerAscent;
    4451             :   }
    4452             : 
    4453             :   // Convert flex container's final desired size to parent's WM, for outparam.
    4454           0 :   aDesiredSize.SetSize(flexWM, desiredSizeInFlexWM);
    4455             : 
    4456             :   // Overflow area = union(my overflow area, kids' overflow areas)
    4457           0 :   aDesiredSize.SetOverflowAreasToDesiredBounds();
    4458           0 :   for (nsIFrame* childFrame : mFrames) {
    4459           0 :     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, childFrame);
    4460             :   }
    4461             : 
    4462           0 :   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize,
    4463           0 :                                  aReflowInput, aStatus);
    4464             : 
    4465           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize)
    4466             : }
    4467             : 
    4468             : void
    4469           0 : nsFlexContainerFrame::MoveFlexItemToFinalPosition(
    4470             :   const ReflowInput& aReflowInput,
    4471             :   const FlexItem& aItem,
    4472             :   LogicalPoint& aFramePos,
    4473             :   const nsSize& aContainerSize)
    4474             : {
    4475           0 :   WritingMode outerWM = aReflowInput.GetWritingMode();
    4476             : 
    4477             :   // If item is relpos, look up its offsets (cached from prev reflow)
    4478           0 :   LogicalMargin logicalOffsets(outerWM);
    4479           0 :   if (NS_STYLE_POSITION_RELATIVE == aItem.Frame()->StyleDisplay()->mPosition) {
    4480           0 :     nsMargin* cachedOffsets = aItem.Frame()->GetProperty(nsIFrame::ComputedOffsetProperty());
    4481           0 :     MOZ_ASSERT(cachedOffsets,
    4482             :                "relpos previously-reflowed frame should've cached its offsets");
    4483           0 :     logicalOffsets = LogicalMargin(outerWM, *cachedOffsets);
    4484             :   }
    4485           0 :   ReflowInput::ApplyRelativePositioning(aItem.Frame(), outerWM,
    4486             :                                               logicalOffsets, &aFramePos,
    4487           0 :                                               aContainerSize);
    4488           0 :   aItem.Frame()->SetPosition(outerWM, aFramePos, aContainerSize);
    4489           0 :   PositionFrameView(aItem.Frame());
    4490           0 :   PositionChildViews(aItem.Frame());
    4491           0 : }
    4492             : 
    4493             : void
    4494           0 : nsFlexContainerFrame::ReflowFlexItem(nsPresContext* aPresContext,
    4495             :                                      const FlexboxAxisTracker& aAxisTracker,
    4496             :                                      const ReflowInput& aReflowInput,
    4497             :                                      const FlexItem& aItem,
    4498             :                                      LogicalPoint& aFramePos,
    4499             :                                      const nsSize& aContainerSize)
    4500             : {
    4501           0 :   WritingMode outerWM = aReflowInput.GetWritingMode();
    4502           0 :   WritingMode wm = aItem.Frame()->GetWritingMode();
    4503           0 :   LogicalSize availSize = aReflowInput.ComputedSize(wm);
    4504           0 :   availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
    4505             :   ReflowInput childReflowInput(aPresContext, aReflowInput,
    4506           0 :                                      aItem.Frame(), availSize);
    4507             : 
    4508             :   // Keep track of whether we've overriden the child's computed height
    4509             :   // and/or width, so we can set its resize flags accordingly.
    4510           0 :   bool didOverrideComputedWidth = false;
    4511           0 :   bool didOverrideComputedHeight = false;
    4512             : 
    4513             :   // Override computed main-size
    4514           0 :   if (aAxisTracker.IsMainAxisHorizontal()) {
    4515           0 :     childReflowInput.SetComputedWidth(aItem.GetMainSize());
    4516           0 :     didOverrideComputedWidth = true;
    4517             :   } else {
    4518           0 :     childReflowInput.SetComputedHeight(aItem.GetMainSize());
    4519           0 :     didOverrideComputedHeight = true;
    4520             :   }
    4521             : 
    4522             :   // Override reflow state's computed cross-size if either:
    4523             :   // - the item was stretched (in which case we're imposing a cross size)
    4524             :   // ...or...
    4525             :   // - the item it has an aspect ratio (in which case the cross-size that's
    4526             :   // currently in the reflow state is based on arithmetic involving a stale
    4527             :   // main-size value that we just stomped on above). (Note that we could handle
    4528             :   // this case using an AutoFlexItemMainSizeOverride, as we do elsewhere; but
    4529             :   // given that we *already know* the correct cross size to use here, it's
    4530             :   // cheaper to just directly set it instead of setting a frame property.)
    4531           0 :   if (aItem.IsStretched() ||
    4532           0 :       aItem.HasIntrinsicRatio()) {
    4533           0 :     if (aAxisTracker.IsCrossAxisHorizontal()) {
    4534           0 :       childReflowInput.SetComputedWidth(aItem.GetCrossSize());
    4535           0 :       didOverrideComputedWidth = true;
    4536             :     } else {
    4537           0 :       childReflowInput.SetComputedHeight(aItem.GetCrossSize());
    4538           0 :       didOverrideComputedHeight = true;
    4539             :     }
    4540             :   }
    4541           0 :   if (aItem.IsStretched() && !aAxisTracker.IsCrossAxisHorizontal()) {
    4542             :     // If this item's height is stretched, it's a relative height.
    4543           0 :     aItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
    4544             :   }
    4545             : 
    4546             :   // XXXdholbert Might need to actually set the correct margins in the
    4547             :   // reflow state at some point, so that they can be saved on the frame for
    4548             :   // UsedMarginProperty().  Maybe doesn't matter though...?
    4549             : 
    4550             :   // If we're overriding the computed width or height, *and* we had an
    4551             :   // earlier "measuring" reflow, then this upcoming reflow needs to be
    4552             :   // treated as a resize.
    4553           0 :   if (aItem.HadMeasuringReflow()) {
    4554           0 :     if (didOverrideComputedWidth) {
    4555             :       // (This is somewhat redundant, since the reflow state already
    4556             :       // sets mHResize whenever our computed width has changed since the
    4557             :       // previous reflow. Still, it's nice for symmetry, and it may become
    4558             :       // necessary once we support orthogonal flows.)
    4559           0 :       childReflowInput.SetHResize(true);
    4560             :     }
    4561           0 :     if (didOverrideComputedHeight) {
    4562           0 :       childReflowInput.SetVResize(true);
    4563             :     }
    4564             :   }
    4565             :   // NOTE: Be very careful about doing anything else with childReflowInput
    4566             :   // after this point, because some of its methods (e.g. SetComputedWidth)
    4567             :   // internally call InitResizeFlags and stomp on mVResize & mHResize.
    4568             : 
    4569           0 :   ReflowOutput childDesiredSize(childReflowInput);
    4570           0 :   nsReflowStatus childReflowStatus;
    4571           0 :   ReflowChild(aItem.Frame(), aPresContext,
    4572             :               childDesiredSize, childReflowInput,
    4573             :               outerWM, aFramePos, aContainerSize,
    4574           0 :               0, childReflowStatus);
    4575             : 
    4576             :   // XXXdholbert Once we do pagination / splitting, we'll need to actually
    4577             :   // handle incomplete childReflowStatuses. But for now, we give our kids
    4578             :   // unconstrained available height, which means they should always
    4579             :   // complete.
    4580           0 :   MOZ_ASSERT(childReflowStatus.IsComplete(),
    4581             :              "We gave flex item unconstrained available height, so it "
    4582             :              "should be complete");
    4583             : 
    4584             :   LogicalMargin offsets =
    4585           0 :     childReflowInput.ComputedLogicalOffsets().ConvertTo(outerWM, wm);
    4586           0 :   ReflowInput::ApplyRelativePositioning(aItem.Frame(), outerWM,
    4587             :                                               offsets, &aFramePos,
    4588           0 :                                               aContainerSize);
    4589             : 
    4590           0 :   FinishReflowChild(aItem.Frame(), aPresContext,
    4591             :                     childDesiredSize, &childReflowInput,
    4592           0 :                     outerWM, aFramePos, aContainerSize, 0);
    4593             : 
    4594           0 :   aItem.SetAscent(childDesiredSize.BlockStartAscent());
    4595           0 : }
    4596             : 
    4597             : void
    4598           0 : nsFlexContainerFrame::ReflowPlaceholders(nsPresContext* aPresContext,
    4599             :                                          const ReflowInput& aReflowInput,
    4600             :                                          nsTArray<nsIFrame*>& aPlaceholders,
    4601             :                                          const LogicalPoint& aContentBoxOrigin,
    4602             :                                          const nsSize& aContainerSize)
    4603             : {
    4604           0 :   WritingMode outerWM = aReflowInput.GetWritingMode();
    4605             : 
    4606             :   // As noted in this method's documentation, we'll reflow every entry in
    4607             :   // |aPlaceholders| at the container's content-box origin.
    4608           0 :   for (nsIFrame* placeholder : aPlaceholders) {
    4609           0 :     MOZ_ASSERT(placeholder->IsPlaceholderFrame(),
    4610             :                "placeholders array should only contain placeholder frames");
    4611           0 :     WritingMode wm = placeholder->GetWritingMode();
    4612           0 :     LogicalSize availSize = aReflowInput.ComputedSize(wm);
    4613             :     ReflowInput childReflowInput(aPresContext, aReflowInput,
    4614           0 :                                  placeholder, availSize);
    4615           0 :     ReflowOutput childDesiredSize(childReflowInput);
    4616           0 :     nsReflowStatus childReflowStatus;
    4617           0 :     ReflowChild(placeholder, aPresContext,
    4618             :                 childDesiredSize, childReflowInput,
    4619             :                 outerWM, aContentBoxOrigin, aContainerSize, 0,
    4620           0 :                 childReflowStatus);
    4621             : 
    4622             :     FinishReflowChild(placeholder, aPresContext,
    4623             :                       childDesiredSize, &childReflowInput,
    4624           0 :                       outerWM, aContentBoxOrigin, aContainerSize, 0);
    4625             : 
    4626             :     // Mark the placeholder frame to indicate that it's not actually at the
    4627             :     // element's static position, because we need to apply CSS Alignment after
    4628             :     // we determine the OOF's size:
    4629           0 :     placeholder->AddStateBits(PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN);
    4630             :   }
    4631           0 : }
    4632             : 
    4633             : /* virtual */ nscoord
    4634           0 : nsFlexContainerFrame::GetMinISize(gfxContext* aRenderingContext)
    4635             : {
    4636           0 :   nscoord minISize = 0;
    4637           0 :   DISPLAY_MIN_WIDTH(this, minISize);
    4638             : 
    4639           0 :   RenumberList();
    4640             : 
    4641           0 :   const nsStylePosition* stylePos = StylePosition();
    4642           0 :   const FlexboxAxisTracker axisTracker(this, GetWritingMode());
    4643             : 
    4644           0 :   for (nsIFrame* childFrame : mFrames) {
    4645             :     nscoord childMinISize =
    4646           0 :       nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
    4647           0 :                                            nsLayoutUtils::MIN_ISIZE);
    4648             :     // For a horizontal single-line flex container, the intrinsic min
    4649             :     // isize is the sum of its items' min isizes.
    4650             :     // For a column-oriented flex container, or for a multi-line row-
    4651             :     // oriented flex container, the intrinsic min isize is the max of
    4652             :     // its items' min isizes.
    4653           0 :     if (axisTracker.IsRowOriented() &&
    4654           0 :         NS_STYLE_FLEX_WRAP_NOWRAP == stylePos->mFlexWrap) {
    4655           0 :       minISize += childMinISize;
    4656             :     } else {
    4657           0 :       minISize = std::max(minISize, childMinISize);
    4658             :     }
    4659             :   }
    4660           0 :   return minISize;
    4661             : }
    4662             : 
    4663             : /* virtual */ nscoord
    4664           0 : nsFlexContainerFrame::GetPrefISize(gfxContext* aRenderingContext)
    4665             : {
    4666           0 :   nscoord prefISize = 0;
    4667           0 :   DISPLAY_PREF_WIDTH(this, prefISize);
    4668             : 
    4669           0 :   RenumberList();
    4670             : 
    4671             :   // XXXdholbert Optimization: We could cache our intrinsic widths like
    4672             :   // nsBlockFrame does (and return it early from this function if it's set).
    4673             :   // Whenever anything happens that might change it, set it to
    4674             :   // NS_INTRINSIC_WIDTH_UNKNOWN (like nsBlockFrame::MarkIntrinsicISizesDirty
    4675             :   // does)
    4676           0 :   const FlexboxAxisTracker axisTracker(this, GetWritingMode());
    4677             : 
    4678           0 :   for (nsIFrame* childFrame : mFrames) {
    4679             :     nscoord childPrefISize =
    4680           0 :       nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
    4681           0 :                                            nsLayoutUtils::PREF_ISIZE);
    4682           0 :     if (axisTracker.IsRowOriented()) {
    4683           0 :       prefISize += childPrefISize;
    4684             :     } else {
    4685           0 :       prefISize = std::max(prefISize, childPrefISize);
    4686             :     }
    4687             :   }
    4688           0 :   return prefISize;
    4689             : }

Generated by: LCOV version 1.13