LCOV - code coverage report
Current view: top level - layout/generic - nsGridContainerFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 3317 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 189 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             : /* This Source Code is subject to the terms of the Mozilla Public License
       4             :  * version 2.0 (the "License"). You can obtain a copy of the License at
       5             :  * http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* rendering object for CSS "display: grid | inline-grid" */
       8             : 
       9             : #include "nsGridContainerFrame.h"
      10             : 
      11             : #include <algorithm> // for std::stable_sort
      12             : #include <functional>
      13             : #include <limits>
      14             : #include "gfxContext.h"
      15             : #include "mozilla/CSSAlignUtils.h"
      16             : #include "mozilla/CSSOrderAwareFrameIterator.h"
      17             : #include "mozilla/dom/GridBinding.h"
      18             : #include "mozilla/Maybe.h"
      19             : #include "mozilla/PodOperations.h" // for PodZero
      20             : #include "mozilla/Poison.h"
      21             : #include "nsAbsoluteContainingBlock.h"
      22             : #include "nsAlgorithm.h" // for clamped()
      23             : #include "nsCSSAnonBoxes.h"
      24             : #include "nsCSSFrameConstructor.h"
      25             : #include "nsDataHashtable.h"
      26             : #include "nsDisplayList.h"
      27             : #include "nsHashKeys.h"
      28             : #include "nsIFrameInlines.h"
      29             : #include "nsPresContext.h"
      30             : #include "nsReadableUtils.h"
      31             : #include "nsRuleNode.h"
      32             : #include "nsStyleContext.h"
      33             : #include "nsTableWrapperFrame.h"
      34             : 
      35             : using namespace mozilla;
      36             : 
      37             : typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
      38             : typedef nsGridContainerFrame::TrackSize TrackSize;
      39             : const uint32_t nsGridContainerFrame::kTranslatedMaxLine =
      40             :   uint32_t(nsStyleGridLine::kMaxLine - nsStyleGridLine::kMinLine);
      41             : const uint32_t nsGridContainerFrame::kAutoLine = kTranslatedMaxLine + 3457U;
      42             : typedef nsTHashtable< nsPtrHashKey<nsIFrame> > FrameHashtable;
      43             : typedef mozilla::CSSAlignUtils::AlignJustifyFlags AlignJustifyFlags;
      44             : typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType;
      45             : 
      46             : // https://drafts.csswg.org/css-sizing/#constraints
      47             : enum class SizingConstraint
      48             : {
      49             :   eMinContent,  // sizing under min-content constraint
      50             :   eMaxContent,  // sizing under max-content constraint
      51             :   eNoConstraint // no constraint, used during Reflow
      52             : };
      53             : 
      54             : static void
      55           0 : ReparentFrame(nsIFrame* aFrame, nsContainerFrame* aOldParent,
      56             :               nsContainerFrame* aNewParent)
      57             : {
      58           0 :   NS_ASSERTION(aOldParent == aFrame->GetParent(),
      59             :                "Parent not consistent with expectations");
      60             : 
      61           0 :   aFrame->SetParent(aNewParent);
      62             : 
      63             :   // When pushing and pulling frames we need to check for whether any
      64             :   // views need to be reparented
      65           0 :   nsContainerFrame::ReparentFrameView(aFrame, aOldParent, aNewParent);
      66           0 : }
      67             : 
      68             : static void
      69           0 : ReparentFrames(nsFrameList& aFrameList, nsContainerFrame* aOldParent,
      70             :                nsContainerFrame* aNewParent)
      71             : {
      72           0 :   for (auto f : aFrameList) {
      73           0 :     ReparentFrame(f, aOldParent, aNewParent);
      74             :   }
      75           0 : }
      76             : 
      77             : static nscoord
      78           0 : ClampToCSSMaxBSize(nscoord aSize, const ReflowInput* aReflowInput)
      79             : {
      80           0 :   auto maxSize = aReflowInput->ComputedMaxBSize();
      81           0 :   if (MOZ_UNLIKELY(maxSize != NS_UNCONSTRAINEDSIZE)) {
      82           0 :     MOZ_ASSERT(aReflowInput->ComputedMinBSize() <= maxSize);
      83           0 :     aSize = std::min(aSize, maxSize);
      84             :   }
      85           0 :   return aSize;
      86             : }
      87             : 
      88             : // Same as above and set aStatus INCOMPLETE if aSize wasn't clamped.
      89             : // (If we clamp aSize it means our size is less than the break point,
      90             : // i.e. we're effectively breaking in our overflow, so we should leave
      91             : // aStatus as is (it will likely be set to OVERFLOW_INCOMPLETE later)).
      92             : static nscoord
      93           0 : ClampToCSSMaxBSize(nscoord aSize, const ReflowInput* aReflowInput,
      94             :                    nsReflowStatus* aStatus)
      95             : {
      96           0 :   auto maxSize = aReflowInput->ComputedMaxBSize();
      97           0 :   if (MOZ_UNLIKELY(maxSize != NS_UNCONSTRAINEDSIZE)) {
      98           0 :     MOZ_ASSERT(aReflowInput->ComputedMinBSize() <= maxSize);
      99           0 :     if (aSize < maxSize) {
     100           0 :       aStatus->SetIncomplete();
     101             :     } else {
     102           0 :       aSize = maxSize;
     103             :     }
     104             :   } else {
     105           0 :     aStatus->SetIncomplete();
     106             :   }
     107           0 :   return aSize;
     108             : }
     109             : 
     110             : static bool
     111           0 : IsPercentOfIndefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
     112             : {
     113           0 :   return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
     114             : }
     115             : 
     116             : static nscoord
     117           0 : ResolveToDefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
     118             : {
     119           0 :   MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
     120           0 :   if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) {
     121           0 :     return nscoord(0);
     122             :   }
     123           0 :   return std::max(nscoord(0),
     124           0 :                   nsRuleNode::ComputeCoordPercentCalc(aCoord, aPercentBasis));
     125             : }
     126             : 
     127             : static bool
     128           0 : GetPercentSizeParts(const nsStyleCoord& aCoord, nscoord* aLength, float* aPercent)
     129             : {
     130           0 :   switch (aCoord.GetUnit()) {
     131             :     case eStyleUnit_Percent:
     132           0 :       *aLength = 0;
     133           0 :       *aPercent = aCoord.GetPercentValue();
     134           0 :       return true;
     135             :     case eStyleUnit_Calc: {
     136           0 :       nsStyleCoord::Calc* calc = aCoord.GetCalcValue();
     137           0 :       *aLength = calc->mLength;
     138           0 :       *aPercent = calc->mPercent;
     139           0 :       return true;
     140             :     }
     141             :     default:
     142           0 :       return false;
     143             :   }
     144             : }
     145             : 
     146             : static void
     147           0 : ResolvePercentSizeParts(const nsStyleCoord& aCoord, nscoord aPercentBasis,
     148             :                         nscoord* aLength, float* aPercent)
     149             : {
     150           0 :   MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
     151           0 :   if (aPercentBasis != NS_UNCONSTRAINEDSIZE) {
     152           0 :     *aLength = std::max(nscoord(0),
     153           0 :                         nsRuleNode::ComputeCoordPercentCalc(aCoord,
     154           0 :                                                             aPercentBasis));
     155           0 :     *aPercent = 0.0f;
     156           0 :     return;
     157             :   }
     158           0 :   if (!GetPercentSizeParts(aCoord, aLength, aPercent)) {
     159           0 :     *aLength = aCoord.ToLength();
     160           0 :     *aPercent = 0.0f;
     161             :   }
     162             : }
     163             : 
     164             : // Synthesize a baseline from a border box.  For an alphabetical baseline
     165             : // this is the end edge of the border box.  For a central baseline it's
     166             : // the center of the border box.
     167             : // https://drafts.csswg.org/css-align-3/#synthesize-baselines
     168             : // For a 'first baseline' the measure is from the border-box start edge and
     169             : // for a 'last baseline' the measure is from the border-box end edge.
     170             : static nscoord
     171           0 : SynthesizeBaselineFromBorderBox(BaselineSharingGroup aGroup,
     172             :                                 WritingMode aWM,
     173             :                                 nscoord aBorderBoxSize)
     174             : {
     175           0 :   if (aGroup == BaselineSharingGroup::eFirst) {
     176           0 :     return aWM.IsAlphabeticalBaseline() ? aBorderBoxSize : aBorderBoxSize / 2;
     177             :   }
     178           0 :   MOZ_ASSERT(aGroup == BaselineSharingGroup::eLast);
     179             :   // Round up for central baseline offset, to be consistent with eFirst.
     180           0 :   return aWM.IsAlphabeticalBaseline() ? 0 :
     181           0 :     (aBorderBoxSize / 2) + (aBorderBoxSize % 2);
     182             : }
     183             : 
     184             : enum class GridLineSide
     185             : {
     186             :   eBeforeGridGap,
     187             :   eAfterGridGap,
     188             : };
     189             : 
     190             : struct nsGridContainerFrame::TrackSize
     191             : {
     192             :   enum StateBits : uint16_t {
     193             :     eAutoMinSizing =              0x1,
     194             :     eMinContentMinSizing =        0x2,
     195             :     eMaxContentMinSizing =        0x4,
     196             :     eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
     197             :     eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
     198             :     // 0x8 is unused, feel free to take it!
     199             :     eAutoMaxSizing =             0x10,
     200             :     eMinContentMaxSizing =       0x20,
     201             :     eMaxContentMaxSizing =       0x40,
     202             :     eAutoOrMaxContentMaxSizing = eAutoMaxSizing | eMaxContentMaxSizing,
     203             :     eIntrinsicMaxSizing = eAutoOrMaxContentMaxSizing | eMinContentMaxSizing,
     204             :     eFlexMaxSizing =             0x80,
     205             :     eFrozen =                   0x100,
     206             :     eSkipGrowUnlimited1 =       0x200,
     207             :     eSkipGrowUnlimited2 =       0x400,
     208             :     eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2,
     209             :     eBreakBefore =              0x800,
     210             :     eFitContent =              0x1000,
     211             :   };
     212             : 
     213             :   StateBits Initialize(nscoord aPercentageBasis,
     214             :                        const nsStyleCoord& aMinCoord,
     215             :                        const nsStyleCoord& aMaxCoord);
     216           0 :   bool IsFrozen() const { return mState & eFrozen; }
     217             : #ifdef DEBUG
     218             :   void Dump() const;
     219             : #endif
     220             : 
     221           0 :   static bool IsMinContent(const nsStyleCoord& aCoord)
     222             :   {
     223           0 :     return aCoord.GetUnit() == eStyleUnit_Enumerated &&
     224           0 :       aCoord.GetEnumValue<StyleGridTrackBreadth>() == StyleGridTrackBreadth::MinContent;
     225             :   }
     226           0 :   static bool IsDefiniteMaxSizing(StateBits aStateBits)
     227             :   {
     228           0 :     return (aStateBits & (eIntrinsicMaxSizing | eFlexMaxSizing)) == 0;
     229             :   }
     230             : 
     231             :   nscoord mBase;
     232             :   nscoord mLimit;
     233             :   nscoord mPosition;  // zero until we apply 'align/justify-content'
     234             :   // mBaselineSubtreeSize is the size of a baseline-aligned subtree within
     235             :   // this track.  One subtree per baseline-sharing group (per track).
     236             :   nscoord mBaselineSubtreeSize[2];
     237             :   StateBits mState;
     238             : };
     239             : 
     240           0 : MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TrackSize::StateBits)
     241             : 
     242             : namespace mozilla {
     243             : template <>
     244             : struct IsPod<nsGridContainerFrame::TrackSize> : TrueType {};
     245             : }
     246             : 
     247             : TrackSize::StateBits
     248           0 : nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
     249             :                                             const nsStyleCoord& aMinCoord,
     250             :                                             const nsStyleCoord& aMaxCoord)
     251             : {
     252           0 :   MOZ_ASSERT(mBase == 0 && mLimit == 0 && mState == 0,
     253             :              "track size data is expected to be initialized to zero");
     254           0 :   auto minSizeUnit = aMinCoord.GetUnit();
     255           0 :   auto maxSizeUnit = aMaxCoord.GetUnit();
     256           0 :   if (minSizeUnit == eStyleUnit_None) {
     257             :     // This track is sized using fit-content(size) (represented in style system
     258             :     // with minCoord=None,maxCoord=size).  In layout, fit-content(size) behaves
     259             :     // as minmax(auto, max-content), with 'size' as an additional upper-bound.
     260           0 :     mState = eFitContent;
     261           0 :     minSizeUnit = eStyleUnit_Auto;
     262           0 :     maxSizeUnit = eStyleUnit_Enumerated; // triggers max-content sizing below
     263             :   }
     264           0 :   if (::IsPercentOfIndefiniteSize(aMinCoord, aPercentageBasis)) {
     265             :     // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-percentage
     266             :     // "If the inline or block size of the grid container is indefinite,
     267             :     //  <percentage> values relative to that size are treated as 'auto'."
     268           0 :     minSizeUnit = eStyleUnit_Auto;
     269             :   }
     270           0 :   if (::IsPercentOfIndefiniteSize(aMaxCoord, aPercentageBasis)) {
     271           0 :     maxSizeUnit = eStyleUnit_Auto;
     272             :   }
     273             :   // http://dev.w3.org/csswg/css-grid/#algo-init
     274           0 :   switch (minSizeUnit) {
     275             :     case eStyleUnit_Auto:
     276           0 :       mState |= eAutoMinSizing;
     277           0 :       break;
     278             :     case eStyleUnit_Enumerated:
     279           0 :       mState |= IsMinContent(aMinCoord) ? eMinContentMinSizing
     280           0 :                                         : eMaxContentMinSizing;
     281           0 :       break;
     282             :     default:
     283           0 :       MOZ_ASSERT(minSizeUnit != eStyleUnit_FlexFraction,
     284             :                  "<flex> min-sizing is invalid as a track size");
     285           0 :       mBase = ::ResolveToDefiniteSize(aMinCoord, aPercentageBasis);
     286             :   }
     287           0 :   switch (maxSizeUnit) {
     288             :     case eStyleUnit_Auto:
     289           0 :       mState |= eAutoMaxSizing;
     290           0 :       mLimit = NS_UNCONSTRAINEDSIZE;
     291           0 :       break;
     292             :     case eStyleUnit_Enumerated:
     293           0 :       mState |= IsMinContent(aMaxCoord) ? eMinContentMaxSizing
     294           0 :                                         : eMaxContentMaxSizing;
     295           0 :       mLimit = NS_UNCONSTRAINEDSIZE;
     296           0 :       break;
     297             :     case eStyleUnit_FlexFraction:
     298           0 :       mState |= eFlexMaxSizing;
     299           0 :       mLimit = mBase;
     300           0 :       break;
     301             :     default:
     302           0 :       mLimit = ::ResolveToDefiniteSize(aMaxCoord, aPercentageBasis);
     303           0 :       if (mLimit < mBase) {
     304           0 :         mLimit = mBase;
     305             :       }
     306             :   }
     307             : 
     308           0 :   mBaselineSubtreeSize[BaselineSharingGroup::eFirst] = nscoord(0);
     309           0 :   mBaselineSubtreeSize[BaselineSharingGroup::eLast] = nscoord(0);
     310           0 :   return mState;
     311             : }
     312             : 
     313             : /**
     314             :  * Is aFrame1 a prev-continuation of aFrame2?
     315             :  */
     316             : static bool
     317           0 : IsPrevContinuationOf(nsIFrame* aFrame1, nsIFrame* aFrame2)
     318             : {
     319           0 :   nsIFrame* prev = aFrame2;
     320           0 :   while ((prev = prev->GetPrevContinuation())) {
     321           0 :     if (prev == aFrame1) {
     322           0 :       return true;
     323             :     }
     324             :   }
     325           0 :   return false;
     326             : }
     327             : 
     328             : /**
     329             :  * Moves all frames from aSrc into aDest such that the resulting aDest
     330             :  * is still sorted in document content order and continuation order.
     331             :  * Precondition: both |aSrc| and |aDest| must be sorted to begin with.
     332             :  * @param aCommonAncestor a hint for nsLayoutUtils::CompareTreePosition
     333             :  */
     334             : static void
     335           0 : MergeSortedFrameLists(nsFrameList& aDest, nsFrameList& aSrc,
     336             :                       nsIContent* aCommonAncestor)
     337             : {
     338           0 :   nsIFrame* dest = aDest.FirstChild();
     339           0 :   for (nsIFrame* src = aSrc.FirstChild(); src; ) {
     340           0 :     if (!dest) {
     341           0 :       aDest.AppendFrames(nullptr, aSrc);
     342           0 :       break;
     343             :     }
     344           0 :     nsIContent* srcContent = src->GetContent();
     345           0 :     nsIContent* destContent = dest->GetContent();
     346             :     int32_t result = nsLayoutUtils::CompareTreePosition(srcContent,
     347             :                                                         destContent,
     348           0 :                                                         aCommonAncestor);
     349           0 :     if (MOZ_UNLIKELY(result == 0)) {
     350             :       // NOTE: we get here when comparing ::before/::after for the same element.
     351           0 :       if (MOZ_UNLIKELY(srcContent->IsGeneratedContentContainerForBefore())) {
     352           0 :         if (MOZ_LIKELY(!destContent->IsGeneratedContentContainerForBefore()) ||
     353           0 :             ::IsPrevContinuationOf(src, dest)) {
     354           0 :           result = -1;
     355             :         }
     356           0 :       } else if (MOZ_UNLIKELY(srcContent->IsGeneratedContentContainerForAfter())) {
     357           0 :         if (MOZ_UNLIKELY(destContent->IsGeneratedContentContainerForAfter()) &&
     358           0 :             ::IsPrevContinuationOf(src, dest)) {
     359           0 :           result = -1;
     360             :         }
     361           0 :       } else if (::IsPrevContinuationOf(src, dest)) {
     362           0 :         result = -1;
     363             :       }
     364             :     }
     365           0 :     if (result < 0) {
     366             :       // src should come before dest
     367           0 :       nsIFrame* next = src->GetNextSibling();
     368           0 :       aSrc.RemoveFrame(src);
     369           0 :       aDest.InsertFrame(nullptr, dest->GetPrevSibling(), src);
     370           0 :       src = next;
     371             :     } else {
     372           0 :       dest = dest->GetNextSibling();
     373             :     }
     374             :   }
     375           0 :   MOZ_ASSERT(aSrc.IsEmpty());
     376           0 : }
     377             : 
     378             : static void
     379           0 : MergeSortedFrameListsFor(nsFrameList& aDest, nsFrameList& aSrc,
     380             :                          nsContainerFrame* aParent)
     381             : {
     382           0 :   MergeSortedFrameLists(aDest, aSrc, aParent->GetContent());
     383           0 : }
     384             : 
     385             : /**
     386             :  * A LineRange can be definite or auto - when it's definite it represents
     387             :  * a consecutive set of tracks between a starting line and an ending line.
     388             :  * Before it's definite it can also represent an auto position with a span,
     389             :  * where mStart == kAutoLine and mEnd is the (non-zero positive) span.
     390             :  * For normal-flow items, the invariant mStart < mEnd holds when both
     391             :  * lines are definite.
     392             :  *
     393             :  * For abs.pos. grid items, mStart and mEnd may both be kAutoLine, meaning
     394             :  * "attach this side to the grid container containing block edge".
     395             :  * Additionally, mStart <= mEnd holds when both are definite (non-kAutoLine),
     396             :  * i.e. the invariant is slightly relaxed compared to normal flow items.
     397             :  */
     398             : struct nsGridContainerFrame::LineRange
     399             : {
     400           0 :  LineRange(int32_t aStart, int32_t aEnd)
     401           0 :    : mUntranslatedStart(aStart), mUntranslatedEnd(aEnd)
     402             :   {
     403             : #ifdef DEBUG
     404           0 :     if (!IsAutoAuto()) {
     405           0 :       if (IsAuto()) {
     406           0 :         MOZ_ASSERT(aEnd >= nsStyleGridLine::kMinLine &&
     407             :                    aEnd <= nsStyleGridLine::kMaxLine, "invalid span");
     408             :       } else {
     409           0 :         MOZ_ASSERT(aStart >= nsStyleGridLine::kMinLine &&
     410             :                    aStart <= nsStyleGridLine::kMaxLine, "invalid start line");
     411           0 :         MOZ_ASSERT(aEnd == int32_t(kAutoLine) ||
     412             :                    (aEnd >= nsStyleGridLine::kMinLine &&
     413             :                     aEnd <= nsStyleGridLine::kMaxLine), "invalid end line");
     414             :       }
     415             :     }
     416             : #endif
     417           0 :   }
     418           0 :   bool IsAutoAuto() const { return mStart == kAutoLine && mEnd == kAutoLine; }
     419           0 :   bool IsAuto() const { return mStart == kAutoLine; }
     420           0 :   bool IsDefinite() const { return mStart != kAutoLine; }
     421           0 :   uint32_t Extent() const
     422             :   {
     423           0 :     MOZ_ASSERT(mEnd != kAutoLine, "Extent is undefined for abs.pos. 'auto'");
     424           0 :     if (IsAuto()) {
     425           0 :       MOZ_ASSERT(mEnd >= 1 && mEnd < uint32_t(nsStyleGridLine::kMaxLine),
     426             :                  "invalid span");
     427           0 :       return mEnd;
     428             :     }
     429           0 :     return mEnd - mStart;
     430             :   }
     431             :   /**
     432             :    * Resolve this auto range to start at aStart, making it definite.
     433             :    * Precondition: this range IsAuto()
     434             :    */
     435           0 :   void ResolveAutoPosition(uint32_t aStart, uint32_t aExplicitGridOffset)
     436             :   {
     437           0 :     MOZ_ASSERT(IsAuto(), "Why call me?");
     438           0 :     mStart = aStart;
     439           0 :     mEnd += aStart;
     440             :     // Clamping to where kMaxLine is in the explicit grid, per
     441             :     // http://dev.w3.org/csswg/css-grid/#overlarge-grids :
     442           0 :     uint32_t translatedMax = aExplicitGridOffset + nsStyleGridLine::kMaxLine;
     443           0 :     if (MOZ_UNLIKELY(mStart >= translatedMax)) {
     444           0 :       mEnd = translatedMax;
     445           0 :       mStart = mEnd - 1;
     446           0 :     } else if (MOZ_UNLIKELY(mEnd > translatedMax)) {
     447           0 :       mEnd = translatedMax;
     448             :     }
     449           0 :   }
     450             :   /**
     451             :    * Translate the lines to account for (empty) removed tracks.  This method
     452             :    * is only for grid items and should only be called after placement.
     453             :    * aNumRemovedTracks contains a count for each line in the grid how many
     454             :    * tracks were removed between the start of the grid and that line.
     455             :    */
     456           0 :   void AdjustForRemovedTracks(const nsTArray<uint32_t>& aNumRemovedTracks)
     457             :   {
     458           0 :     MOZ_ASSERT(mStart != kAutoLine, "invalid resolved line for a grid item");
     459           0 :     MOZ_ASSERT(mEnd != kAutoLine, "invalid resolved line for a grid item");
     460           0 :     uint32_t numRemovedTracks = aNumRemovedTracks[mStart];
     461           0 :     MOZ_ASSERT(numRemovedTracks == aNumRemovedTracks[mEnd],
     462             :                "tracks that a grid item spans can't be removed");
     463           0 :     mStart -= numRemovedTracks;
     464           0 :     mEnd -= numRemovedTracks;
     465           0 :   }
     466             :   /**
     467             :    * Translate the lines to account for (empty) removed tracks.  This method
     468             :    * is only for abs.pos. children and should only be called after placement.
     469             :    * Same as for in-flow items, but we don't touch 'auto' lines here and we
     470             :    * also need to adjust areas that span into the removed tracks.
     471             :    */
     472           0 :   void AdjustAbsPosForRemovedTracks(const nsTArray<uint32_t>& aNumRemovedTracks)
     473             :   {
     474           0 :     if (mStart != nsGridContainerFrame::kAutoLine) {
     475           0 :       mStart -= aNumRemovedTracks[mStart];
     476             :     }
     477           0 :     if (mEnd != nsGridContainerFrame::kAutoLine) {
     478           0 :       MOZ_ASSERT(mStart == nsGridContainerFrame::kAutoLine ||
     479             :                  mEnd > mStart, "invalid line range");
     480           0 :       mEnd -= aNumRemovedTracks[mEnd];
     481             :     }
     482           0 :     if (mStart == mEnd) {
     483           0 :       mEnd = nsGridContainerFrame::kAutoLine;
     484             :     }
     485           0 :   }
     486             :   /**
     487             :    * Return the contribution of this line range for step 2 in
     488             :    * http://dev.w3.org/csswg/css-grid/#auto-placement-algo
     489             :    */
     490           0 :   uint32_t HypotheticalEnd() const { return mEnd; }
     491             :   /**
     492             :    * Given an array of track sizes, return the starting position and length
     493             :    * of the tracks in this line range.
     494             :    */
     495             :   void ToPositionAndLength(const nsTArray<TrackSize>& aTrackSizes,
     496             :                            nscoord* aPos, nscoord* aLength) const;
     497             :   /**
     498             :    * Given an array of track sizes, return the length of the tracks in this
     499             :    * line range.
     500             :    */
     501             :   nscoord ToLength(const nsTArray<TrackSize>& aTrackSizes) const;
     502             :   /**
     503             :    * Given an array of track sizes and a grid origin coordinate, adjust the
     504             :    * abs.pos. containing block along an axis given by aPos and aLength.
     505             :    * aPos and aLength should already be initialized to the grid container
     506             :    * containing block for this axis before calling this method.
     507             :    */
     508             :   void ToPositionAndLengthForAbsPos(const Tracks& aTracks,
     509             :                                     nscoord aGridOrigin,
     510             :                                     nscoord* aPos, nscoord* aLength) const;
     511             : 
     512             :   /**
     513             :    * @note We'll use the signed member while resolving definite positions
     514             :    * to line numbers (1-based), which may become negative for implicit lines
     515             :    * to the top/left of the explicit grid.  PlaceGridItems() then translates
     516             :    * the whole grid to a 0,0 origin and we'll use the unsigned member from
     517             :    * there on.
     518             :    */
     519             :   union {
     520             :     uint32_t mStart;
     521             :     int32_t mUntranslatedStart;
     522             :   };
     523             :   union {
     524             :     uint32_t mEnd;
     525             :     int32_t mUntranslatedEnd;
     526             :   };
     527             : protected:
     528           0 :   LineRange() {}
     529             : };
     530             : 
     531             : /**
     532             :  * Helper class to construct a LineRange from translated lines.
     533             :  * The ctor only accepts translated definite line numbers.
     534             :  */
     535             : struct nsGridContainerFrame::TranslatedLineRange : public LineRange
     536             : {
     537           0 :   TranslatedLineRange(uint32_t aStart, uint32_t aEnd)
     538           0 :   {
     539           0 :     MOZ_ASSERT(aStart < aEnd && aEnd <= kTranslatedMaxLine);
     540           0 :     mStart = aStart;
     541           0 :     mEnd = aEnd;
     542           0 :   }
     543             : };
     544             : 
     545             : /**
     546             :  * A GridArea is the area in the grid for a grid item.
     547             :  * The area is represented by two LineRanges, both of which can be auto
     548             :  * (@see LineRange) in intermediate steps while the item is being placed.
     549             :  * @see PlaceGridItems
     550             :  */
     551             : struct nsGridContainerFrame::GridArea
     552             : {
     553           0 :   GridArea(const LineRange& aCols, const LineRange& aRows)
     554           0 :     : mCols(aCols), mRows(aRows) {}
     555           0 :   bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
     556             :   LineRange mCols;
     557             :   LineRange mRows;
     558             : };
     559             : 
     560             : struct nsGridContainerFrame::GridItemInfo
     561             : {
     562             :   /**
     563             :    * Item state per axis.
     564             :    */
     565             :   enum StateBits : uint8_t {
     566             :     eIsFlexing =              0x1, // does the item span a flex track?
     567             :     eFirstBaseline =          0x2, // participate in 'first baseline' alignment?
     568             :     // ditto 'last baseline', mutually exclusive w. eFirstBaseline
     569             :     eLastBaseline =           0x4,
     570             :     eIsBaselineAligned = eFirstBaseline | eLastBaseline,
     571             :     // One of e[Self|Content]Baseline is set when eIsBaselineAligned is true
     572             :     eSelfBaseline =           0x8, // is it *-self:[last ]baseline alignment?
     573             :     // Ditto *-content:[last ]baseline. Mutually exclusive w. eSelfBaseline.
     574             :     eContentBaseline =       0x10,
     575             :     eAllBaselineBits = eIsBaselineAligned | eSelfBaseline | eContentBaseline,
     576             :     // Should apply Automatic Minimum Size per:
     577             :     // https://drafts.csswg.org/css-grid/#min-size-auto
     578             :     eApplyAutoMinSize =      0x20,
     579             :     // Clamp per https://drafts.csswg.org/css-grid/#min-size-auto
     580             :     eClampMarginBoxMinSize = 0x40,
     581             :   };
     582             : 
     583           0 :   explicit GridItemInfo(nsIFrame* aFrame,
     584             :                         const GridArea& aArea)
     585           0 :     : mFrame(aFrame)
     586           0 :     , mArea(aArea)
     587             :   {
     588           0 :     mState[eLogicalAxisBlock] = StateBits(0);
     589           0 :     mState[eLogicalAxisInline] = StateBits(0);
     590           0 :     mBaselineOffset[eLogicalAxisBlock] = nscoord(0);
     591           0 :     mBaselineOffset[eLogicalAxisInline] = nscoord(0);
     592           0 :   }
     593             : 
     594             :   /**
     595             :    * If the item is [align|justify]-self:[last ]baseline aligned in the given
     596             :    * axis then set aBaselineOffset to the baseline offset and return aAlign.
     597             :    * Otherwise, return a fallback alignment.
     598             :    */
     599           0 :   uint8_t GetSelfBaseline(uint8_t aAlign, LogicalAxis aAxis,
     600             :                           nscoord* aBaselineOffset) const
     601             :   {
     602           0 :     MOZ_ASSERT(aAlign == NS_STYLE_ALIGN_BASELINE ||
     603             :                aAlign == NS_STYLE_ALIGN_LAST_BASELINE);
     604           0 :     if (!(mState[aAxis] & eSelfBaseline)) {
     605             :       return aAlign == NS_STYLE_ALIGN_BASELINE ? NS_STYLE_ALIGN_SELF_START
     606           0 :                                                : NS_STYLE_ALIGN_SELF_END;
     607             :     }
     608           0 :     *aBaselineOffset = mBaselineOffset[aAxis];
     609           0 :     return aAlign;
     610             :   }
     611             : 
     612             :   // Return true if we should apply Automatic Minimum Size to this item.
     613             :   // https://drafts.csswg.org/css-grid/#min-size-auto
     614           0 :   bool ShouldApplyAutoMinSize(WritingMode aContainerWM,
     615             :                               LogicalAxis aContainerAxis,
     616             :                               nscoord aPercentageBasis) const
     617             :   {
     618           0 :     const auto pos = mFrame->StylePosition();
     619           0 :     const auto& size = aContainerAxis == eLogicalAxisInline ?
     620           0 :       pos->ISize(aContainerWM) : pos->BSize(aContainerWM);
     621             :     // NOTE: if we have a definite or 'max-content' size then our automatic
     622             :     // minimum size can't affect our size.  Excluding these simplifies applying
     623             :     // the clamping in the right cases later.
     624           0 :     if (size.GetUnit() == eStyleUnit_Auto ||
     625           0 :         ::IsPercentOfIndefiniteSize(size, aPercentageBasis) || // same as 'auto'
     626           0 :         (size.GetUnit() == eStyleUnit_Enumerated &&
     627           0 :          size.GetIntValue() != NS_STYLE_WIDTH_MAX_CONTENT)) {
     628           0 :       const auto& minSize = aContainerAxis == eLogicalAxisInline ?
     629           0 :         pos->MinISize(aContainerWM) : pos->MinBSize(aContainerWM);
     630           0 :       return minSize.GetUnit() == eStyleUnit_Auto &&
     631           0 :              mFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE;
     632             :     }
     633           0 :     return false;
     634             :   }
     635             : 
     636             : #ifdef DEBUG
     637             :   void Dump() const;
     638             : #endif
     639             : 
     640           0 :   static bool IsStartRowLessThan(const GridItemInfo* a, const GridItemInfo* b)
     641             :   {
     642           0 :     return a->mArea.mRows.mStart < b->mArea.mRows.mStart;
     643             :   }
     644             : 
     645             :   nsIFrame* const mFrame;
     646             :   GridArea mArea;
     647             :   // Offset from the margin edge to the baseline (LogicalAxis index).  It's from
     648             :   // the start edge when eFirstBaseline is set, end edge otherwise. It's mutable
     649             :   // since we update the value fairly late (just before reflowing the item).
     650             :   mutable nscoord mBaselineOffset[2];
     651             :   mutable StateBits mState[2]; // state bits per axis (LogicalAxis index)
     652             :   static_assert(mozilla::eLogicalAxisBlock == 0, "unexpected index value");
     653             :   static_assert(mozilla::eLogicalAxisInline == 1, "unexpected index value");
     654             : };
     655             : 
     656             : using GridItemInfo = nsGridContainerFrame::GridItemInfo;
     657             : using ItemState = GridItemInfo::StateBits;
     658           0 : MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ItemState)
     659             : 
     660             : #ifdef DEBUG
     661             : void
     662           0 : nsGridContainerFrame::GridItemInfo::Dump() const
     663             : {
     664           0 :   auto Dump1 = [this] (const char* aMsg, LogicalAxis aAxis) {
     665           0 :     auto state = mState[aAxis];
     666           0 :     if (!state) {
     667           0 :       return;
     668             :     }
     669           0 :     printf("%s", aMsg);
     670           0 :     if (state & ItemState::eIsFlexing) {
     671           0 :       printf("flexing ");
     672             :     }
     673           0 :     if (state & ItemState::eFirstBaseline) {
     674           0 :       printf("first baseline %s-alignment ",
     675           0 :              (state & ItemState::eSelfBaseline) ? "self" : "content");
     676             :     }
     677           0 :     if (state & ItemState::eLastBaseline) {
     678           0 :       printf("last baseline %s-alignment ",
     679           0 :              (state & ItemState::eSelfBaseline) ? "self" : "content");
     680             :     }
     681           0 :     if (state & ItemState::eIsBaselineAligned) {
     682           0 :       printf("%.2fpx", NSAppUnitsToFloatPixels(mBaselineOffset[aAxis],
     683           0 :                                                AppUnitsPerCSSPixel()));
     684             :     }
     685           0 :     printf("\n");
     686           0 :   };
     687           0 :   printf("grid-row: %d %d\n", mArea.mRows.mStart, mArea.mRows.mEnd);
     688           0 :   Dump1("  grid block-axis: ", eLogicalAxisBlock);
     689           0 :   printf("grid-column: %d %d\n", mArea.mCols.mStart, mArea.mCols.mEnd);
     690           0 :   Dump1("  grid inline-axis: ", eLogicalAxisInline);
     691           0 : }
     692             : #endif
     693             : 
     694             : /**
     695             :  * Utility class to find line names.  It provides an interface to lookup line
     696             :  * names with a dynamic number of repeat(auto-fill/fit) tracks taken into
     697             :  * account.
     698             :  */
     699             : class MOZ_STACK_CLASS nsGridContainerFrame::LineNameMap
     700             : {
     701             : public:
     702             :   /**
     703             :    * Create a LineNameMap.
     704             :    * @param aGridTemplate is the grid-template-rows/columns data for this axis
     705             :    * @param aNumRepeatTracks the number of actual tracks associated with
     706             :    *   a repeat(auto-fill/fit) track (zero or more), or zero if there is no
     707             :    *   specified repeat(auto-fill/fit) track
     708             :    */
     709           0 :   LineNameMap(const nsStyleGridTemplate& aGridTemplate,
     710             :               uint32_t                   aNumRepeatTracks)
     711           0 :     : mLineNameLists(aGridTemplate.mLineNameLists)
     712             :     , mRepeatAutoLineNameListBefore(aGridTemplate.mRepeatAutoLineNameListBefore)
     713             :     , mRepeatAutoLineNameListAfter(aGridTemplate.mRepeatAutoLineNameListAfter)
     714           0 :     , mRepeatAutoStart(aGridTemplate.HasRepeatAuto() ?
     715           0 :                          aGridTemplate.mRepeatAutoIndex : 0)
     716           0 :     , mRepeatAutoEnd(mRepeatAutoStart + aNumRepeatTracks)
     717           0 :     , mRepeatEndDelta(aGridTemplate.HasRepeatAuto() ?
     718           0 :                         int32_t(aNumRepeatTracks) - 1 :
     719             :                         0)
     720           0 :     , mTemplateLinesEnd(mLineNameLists.Length() + mRepeatEndDelta)
     721           0 :     , mHasRepeatAuto(aGridTemplate.HasRepeatAuto())
     722             :   {
     723           0 :     MOZ_ASSERT(mHasRepeatAuto || aNumRepeatTracks == 0);
     724           0 :     MOZ_ASSERT(mRepeatAutoStart <= mLineNameLists.Length());
     725           0 :     MOZ_ASSERT(!mHasRepeatAuto || mLineNameLists.Length() >= 2);
     726           0 :   }
     727             : 
     728             :   /**
     729             :    * Find the aNth occurrence of aName, searching forward if aNth is positive,
     730             :    * and in reverse if aNth is negative (aNth == 0 is invalid), starting from
     731             :    * aFromIndex (not inclusive), and return a 1-based line number.
     732             :    * Also take into account there is an unconditional match at aImplicitLine
     733             :    * unless it's zero.
     734             :    * Return zero if aNth occurrences can't be found.  In that case, aNth has
     735             :    * been decremented with the number of occurrences that were found (if any).
     736             :    *
     737             :    * E.g. to search for "A 2" forward from the start of the grid: aName is "A"
     738             :    * aNth is 2 and aFromIndex is zero.  To search for "A -2", aNth is -2 and
     739             :    * aFromIndex is ExplicitGridEnd + 1 (which is the line "before" the last
     740             :    * line when we're searching in reverse).  For "span A 2", aNth is 2 when
     741             :    * used on a grid-[row|column]-end property and -2 for a *-start property,
     742             :    * and aFromIndex is the line (which we should skip) on the opposite property.
     743             :    */
     744           0 :   uint32_t FindNamedLine(const nsString& aName, int32_t* aNth,
     745             :                          uint32_t aFromIndex, uint32_t aImplicitLine) const
     746             :   {
     747           0 :     MOZ_ASSERT(aNth && *aNth != 0);
     748           0 :     if (*aNth > 0) {
     749           0 :       return FindLine(aName, aNth, aFromIndex, aImplicitLine);
     750             :     }
     751           0 :     int32_t nth = -*aNth;
     752           0 :     int32_t line = RFindLine(aName, &nth, aFromIndex, aImplicitLine);
     753           0 :     *aNth = -nth;
     754           0 :     return line;
     755             :   }
     756             : 
     757             : private:
     758             :   /**
     759             :    * @see FindNamedLine, this function searches forward.
     760             :    */
     761           0 :   uint32_t FindLine(const nsString& aName, int32_t* aNth,
     762             :                     uint32_t aFromIndex, uint32_t aImplicitLine) const
     763             :   {
     764           0 :     MOZ_ASSERT(aNth && *aNth > 0);
     765           0 :     int32_t nth = *aNth;
     766           0 :     const uint32_t end = mTemplateLinesEnd;
     767             :     uint32_t line;
     768           0 :     uint32_t i = aFromIndex;
     769           0 :     for (; i < end; i = line) {
     770           0 :       line = i + 1;
     771           0 :       if (line == aImplicitLine || Contains(i, aName)) {
     772           0 :         if (--nth == 0) {
     773           0 :           return line;
     774             :         }
     775             :       }
     776             :     }
     777           0 :     if (aImplicitLine > i) {
     778             :       // aImplicitLine is after the lines we searched above so it's last.
     779             :       // (grid-template-areas has more tracks than grid-template-[rows|columns])
     780           0 :       if (--nth == 0) {
     781           0 :         return aImplicitLine;
     782             :       }
     783             :     }
     784           0 :     MOZ_ASSERT(nth > 0, "should have returned a valid line above already");
     785           0 :     *aNth = nth;
     786           0 :     return 0;
     787             :   }
     788             : 
     789             :   /**
     790             :    * @see FindNamedLine, this function searches in reverse.
     791             :    */
     792           0 :   uint32_t RFindLine(const nsString& aName, int32_t* aNth,
     793             :                      uint32_t aFromIndex, uint32_t aImplicitLine) const
     794             :   {
     795           0 :     MOZ_ASSERT(aNth && *aNth > 0);
     796           0 :     if (MOZ_UNLIKELY(aFromIndex == 0)) {
     797           0 :       return 0; // There are no named lines beyond the start of the explicit grid.
     798             :     }
     799           0 :     --aFromIndex; // (shift aFromIndex so we can treat it as inclusive)
     800           0 :     int32_t nth = *aNth;
     801             :     // The implicit line may be beyond the explicit grid so we match
     802             :     // this line first if it's within the mTemplateLinesEnd..aFromIndex range.
     803           0 :     const uint32_t end = mTemplateLinesEnd;
     804           0 :     if (aImplicitLine > end && aImplicitLine < aFromIndex) {
     805           0 :       if (--nth == 0) {
     806           0 :         return aImplicitLine;
     807             :       }
     808             :     }
     809           0 :     for (uint32_t i = std::min(aFromIndex, end); i; --i) {
     810           0 :       if (i == aImplicitLine || Contains(i - 1, aName)) {
     811           0 :         if (--nth == 0) {
     812           0 :           return i;
     813             :         }
     814             :       }
     815             :     }
     816           0 :     MOZ_ASSERT(nth > 0, "should have returned a valid line above already");
     817           0 :     *aNth = nth;
     818           0 :     return 0;
     819             :   }
     820             : 
     821             :   // Return true if aName exists at aIndex.
     822           0 :   bool Contains(uint32_t aIndex, const nsString& aName) const
     823             :   {
     824           0 :     if (!mHasRepeatAuto) {
     825           0 :       return mLineNameLists[aIndex].Contains(aName);
     826             :     }
     827           0 :     if (aIndex < mRepeatAutoEnd && aIndex >= mRepeatAutoStart &&
     828           0 :         mRepeatAutoLineNameListBefore.Contains(aName)) {
     829           0 :       return true;
     830             :     }
     831           0 :     if (aIndex <= mRepeatAutoEnd && aIndex > mRepeatAutoStart &&
     832           0 :         mRepeatAutoLineNameListAfter.Contains(aName)) {
     833           0 :       return true;
     834             :     }
     835           0 :     if (aIndex <= mRepeatAutoStart) {
     836           0 :       return mLineNameLists[aIndex].Contains(aName) ||
     837           0 :              (aIndex == mRepeatAutoEnd &&
     838           0 :               mLineNameLists[aIndex + 1].Contains(aName));
     839             :     }
     840           0 :     return aIndex >= mRepeatAutoEnd &&
     841           0 :            mLineNameLists[aIndex - mRepeatEndDelta].Contains(aName);
     842             :   }
     843             : 
     844             :   // Some style data references, for easy access.
     845             :   const nsTArray<nsTArray<nsString>>& mLineNameLists;
     846             :   const nsTArray<nsString>& mRepeatAutoLineNameListBefore;
     847             :   const nsTArray<nsString>& mRepeatAutoLineNameListAfter;
     848             :   // The index of the repeat(auto-fill/fit) track, or zero if there is none.
     849             :   const uint32_t mRepeatAutoStart;
     850             :   // The (hypothetical) index of the last such repeat() track.
     851             :   const uint32_t mRepeatAutoEnd;
     852             :   // The difference between mTemplateLinesEnd and mLineNameLists.Length().
     853             :   const int32_t mRepeatEndDelta;
     854             :   // The end of the line name lists with repeat(auto-fill/fit) tracks accounted
     855             :   // for.  It is equal to mLineNameLists.Length() when a repeat() track
     856             :   // generates one track (making mRepeatEndDelta == 0).
     857             :   const uint32_t mTemplateLinesEnd;
     858             :   // True if there is a specified repeat(auto-fill/fit) track.
     859             :   const bool mHasRepeatAuto;
     860             : };
     861             : 
     862             : /**
     863             :  * Encapsulates CSS track-sizing functions.
     864             :  */
     865           0 : struct nsGridContainerFrame::TrackSizingFunctions
     866             : {
     867           0 :   TrackSizingFunctions(const nsStyleGridTemplate& aGridTemplate,
     868             :                        const nsStyleCoord&        aAutoMinSizing,
     869             :                        const nsStyleCoord&        aAutoMaxSizing)
     870           0 :     : mMinSizingFunctions(aGridTemplate.mMinTrackSizingFunctions)
     871             :     , mMaxSizingFunctions(aGridTemplate.mMaxTrackSizingFunctions)
     872             :     , mAutoMinSizing(aAutoMinSizing)
     873             :     , mAutoMaxSizing(aAutoMaxSizing)
     874             :     , mExplicitGridOffset(0)
     875           0 :     , mRepeatAutoStart(aGridTemplate.HasRepeatAuto() ?
     876           0 :                          aGridTemplate.mRepeatAutoIndex : 0)
     877           0 :     , mRepeatAutoEnd(mRepeatAutoStart)
     878             :     , mRepeatEndDelta(0)
     879           0 :     , mHasRepeatAuto(aGridTemplate.HasRepeatAuto())
     880             :   {
     881           0 :     MOZ_ASSERT(mMinSizingFunctions.Length() == mMaxSizingFunctions.Length());
     882           0 :     MOZ_ASSERT(!mHasRepeatAuto ||
     883             :                (mMinSizingFunctions.Length() >= 1 &&
     884             :                 mRepeatAutoStart < mMinSizingFunctions.Length()));
     885           0 :   }
     886             : 
     887             :   /**
     888             :    * Initialize the number of auto-fill/fit tracks to use and return that.
     889             :    * (zero if no auto-fill/fit track was specified)
     890             :    */
     891           0 :   uint32_t InitRepeatTracks(const nsStyleCoord& aGridGap, nscoord aMinSize,
     892             :                             nscoord aSize, nscoord aMaxSize)
     893             :   {
     894             :     uint32_t repeatTracks =
     895           0 :       CalculateRepeatFillCount(aGridGap, aMinSize, aSize, aMaxSize);
     896           0 :     SetNumRepeatTracks(repeatTracks);
     897             :     // Blank out the removed flags for each of these tracks.
     898           0 :     mRemovedRepeatTracks.SetLength(repeatTracks);
     899           0 :     for (auto& track : mRemovedRepeatTracks) {
     900           0 :       track = false;
     901             :     }
     902           0 :     return repeatTracks;
     903             :   }
     904             : 
     905           0 :   uint32_t CalculateRepeatFillCount(const nsStyleCoord& aGridGap,
     906             :                                     nscoord aMinSize,
     907             :                                     nscoord aSize,
     908             :                                     nscoord aMaxSize) const
     909             :   {
     910           0 :     if (!mHasRepeatAuto) {
     911           0 :       return 0;
     912             :     }
     913             :     // Spec quotes are from https://drafts.csswg.org/css-grid/#repeat-notation
     914           0 :     const uint32_t numTracks = mMinSizingFunctions.Length();
     915           0 :     MOZ_ASSERT(numTracks >= 1, "expected at least the repeat() track");
     916           0 :     nscoord maxFill = aSize != NS_UNCONSTRAINEDSIZE ? aSize : aMaxSize;
     917           0 :     if (maxFill == NS_UNCONSTRAINEDSIZE && aMinSize == 0) {
     918             :       // "Otherwise, the specified track list repeats only once."
     919           0 :       return 1;
     920             :     }
     921           0 :     nscoord repeatTrackSize = 0;
     922             :     // Note that the repeat() track size is included in |sum| in this loop.
     923           0 :     nscoord sum = 0;
     924           0 :     const nscoord percentBasis = aSize;
     925           0 :     for (uint32_t i = 0; i < numTracks; ++i) {
     926             :       // "treating each track as its max track sizing function if that is
     927             :       // definite or as its minimum track sizing function otherwise"
     928             :       // https://drafts.csswg.org/css-grid/#valdef-repeat-auto-fill
     929           0 :       const auto& maxCoord = mMaxSizingFunctions[i];
     930           0 :       const auto* coord = &maxCoord;
     931           0 :       if (!coord->IsCoordPercentCalcUnit()) {
     932           0 :         coord = &mMinSizingFunctions[i];
     933           0 :         if (!coord->IsCoordPercentCalcUnit()) {
     934           0 :           return 1;
     935             :         }
     936             :       }
     937           0 :       nscoord trackSize = ::ResolveToDefiniteSize(*coord, percentBasis);
     938           0 :       if (i == mRepeatAutoStart) {
     939           0 :         if (percentBasis != NS_UNCONSTRAINEDSIZE) {
     940             :           // Use a minimum 1px for the repeat() track-size.
     941           0 :           if (trackSize < AppUnitsPerCSSPixel()) {
     942           0 :             trackSize = AppUnitsPerCSSPixel();
     943             :           }
     944             :         }
     945           0 :         repeatTrackSize = trackSize;
     946             :       }
     947           0 :       sum += trackSize;
     948             :     }
     949             :     nscoord gridGap;
     950           0 :     float percentSum = 0.0f;
     951             :     float gridGapPercent;
     952           0 :     ResolvePercentSizeParts(aGridGap, percentBasis, &gridGap, &gridGapPercent);
     953           0 :     if (numTracks > 1) {
     954             :       // Add grid-gaps for all the tracks including the repeat() track.
     955           0 :       sum += gridGap * (numTracks - 1);
     956           0 :       percentSum = gridGapPercent * (numTracks - 1);
     957             :     }
     958             :     // Calculate the max number of tracks that fits without overflow.
     959           0 :     nscoord available = maxFill != NS_UNCONSTRAINEDSIZE ? maxFill : aMinSize;
     960           0 :     nscoord size = nsLayoutUtils::AddPercents(sum, percentSum);
     961           0 :     if (available - size < 0) {
     962             :       // "if any number of repetitions would overflow, then 1 repetition"
     963           0 :       return 1;
     964             :     }
     965           0 :     uint32_t numRepeatTracks = 1;
     966           0 :     bool exactFit = false;
     967             :     while (true) {
     968           0 :       sum += gridGap + repeatTrackSize;
     969           0 :       percentSum += gridGapPercent;
     970           0 :       nscoord newSize = nsLayoutUtils::AddPercents(sum, percentSum);
     971           0 :       if (newSize <= size) {
     972             :         // Adding more repeat-tracks won't make forward progress.
     973           0 :         return numRepeatTracks;
     974             :       }
     975           0 :       size = newSize;
     976           0 :       nscoord remaining = available - size;
     977           0 :       exactFit = remaining == 0;
     978           0 :       if (remaining >= 0) {
     979           0 :         ++numRepeatTracks;
     980             :       }
     981           0 :       if (remaining <= 0) {
     982           0 :         break;
     983             :       }
     984           0 :     }
     985             : 
     986           0 :     if (!exactFit && maxFill == NS_UNCONSTRAINEDSIZE) {
     987             :       // "Otherwise, if the grid container has a definite min size in
     988             :       // the relevant axis, the number of repetitions is the largest possible
     989             :       // positive integer that fulfills that minimum requirement."
     990           0 :       ++numRepeatTracks; // one more to ensure the grid is at least min-size
     991             :     }
     992             :     // Clamp the number of repeat tracks so that the last line <= kMaxLine.
     993             :     // (note that |numTracks| already includes one repeat() track)
     994           0 :     const uint32_t maxRepeatTracks = nsStyleGridLine::kMaxLine - numTracks;
     995           0 :     return std::min(numRepeatTracks, maxRepeatTracks);
     996             :   }
     997             : 
     998             :   /**
     999             :    * Compute the explicit grid end line number (in a zero-based grid).
    1000             :    * @param aGridTemplateAreasEnd 'grid-template-areas' end line in this axis
    1001             :    */
    1002           0 :   uint32_t ComputeExplicitGridEnd(uint32_t aGridTemplateAreasEnd)
    1003             :   {
    1004           0 :     uint32_t end = NumExplicitTracks() + 1;
    1005           0 :     end = std::max(end, aGridTemplateAreasEnd);
    1006           0 :     end = std::min(end, uint32_t(nsStyleGridLine::kMaxLine));
    1007           0 :     return end;
    1008             :   }
    1009             : 
    1010           0 :   const nsStyleCoord& MinSizingFor(uint32_t aTrackIndex) const
    1011             :   {
    1012           0 :     if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) {
    1013           0 :       return mAutoMinSizing;
    1014             :     }
    1015           0 :     uint32_t index = aTrackIndex - mExplicitGridOffset;
    1016           0 :     if (index >= mRepeatAutoStart) {
    1017           0 :       if (index < mRepeatAutoEnd) {
    1018           0 :         return mMinSizingFunctions[mRepeatAutoStart];
    1019             :       }
    1020           0 :       index -= mRepeatEndDelta;
    1021             :     }
    1022           0 :     return index < mMinSizingFunctions.Length() ?
    1023           0 :       mMinSizingFunctions[index] : mAutoMinSizing;
    1024             :   }
    1025           0 :   const nsStyleCoord& MaxSizingFor(uint32_t aTrackIndex) const
    1026             :   {
    1027           0 :     if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) {
    1028           0 :       return mAutoMaxSizing;
    1029             :     }
    1030           0 :     uint32_t index = aTrackIndex - mExplicitGridOffset;
    1031           0 :     if (index >= mRepeatAutoStart) {
    1032           0 :       if (index < mRepeatAutoEnd) {
    1033           0 :         return mMaxSizingFunctions[mRepeatAutoStart];
    1034             :       }
    1035           0 :       index -= mRepeatEndDelta;
    1036             :     }
    1037           0 :     return index < mMaxSizingFunctions.Length() ?
    1038           0 :       mMaxSizingFunctions[index] : mAutoMaxSizing;
    1039             :   }
    1040           0 :   uint32_t NumExplicitTracks() const
    1041             :   {
    1042           0 :     return mMinSizingFunctions.Length() + mRepeatEndDelta;
    1043             :   }
    1044           0 :   uint32_t NumRepeatTracks() const
    1045             :   {
    1046           0 :     return mRepeatAutoEnd - mRepeatAutoStart;
    1047             :   }
    1048           0 :   void SetNumRepeatTracks(uint32_t aNumRepeatTracks)
    1049             :   {
    1050           0 :     MOZ_ASSERT(mHasRepeatAuto || aNumRepeatTracks == 0);
    1051           0 :     mRepeatAutoEnd = mRepeatAutoStart + aNumRepeatTracks;
    1052           0 :     mRepeatEndDelta = mHasRepeatAuto ?
    1053           0 :                         int32_t(aNumRepeatTracks) - 1 :
    1054             :                         0;
    1055           0 : }
    1056             : 
    1057             :   // Some style data references, for easy access.
    1058             :   const nsTArray<nsStyleCoord>& mMinSizingFunctions;
    1059             :   const nsTArray<nsStyleCoord>& mMaxSizingFunctions;
    1060             :   const nsStyleCoord& mAutoMinSizing;
    1061             :   const nsStyleCoord& mAutoMaxSizing;
    1062             :   // Offset from the start of the implicit grid to the first explicit track.
    1063             :   uint32_t mExplicitGridOffset;
    1064             :   // The index of the repeat(auto-fill/fit) track, or zero if there is none.
    1065             :   const uint32_t mRepeatAutoStart;
    1066             :   // The (hypothetical) index of the last such repeat() track.
    1067             :   uint32_t mRepeatAutoEnd;
    1068             :   // The difference between mExplicitGridEnd and mMinSizingFunctions.Length().
    1069             :   int32_t mRepeatEndDelta;
    1070             :   // True if there is a specified repeat(auto-fill/fit) track.
    1071             :   const bool mHasRepeatAuto;
    1072             :   // True if this track (relative to mRepeatAutoStart) is a removed auto-fit.
    1073             :   nsTArray<bool> mRemovedRepeatTracks;
    1074             : };
    1075             : 
    1076             : /**
    1077             :  * State for the tracks in one dimension.
    1078             :  */
    1079           0 : struct nsGridContainerFrame::Tracks
    1080             : {
    1081           0 :   explicit Tracks(LogicalAxis aAxis)
    1082           0 :     : mStateUnion(TrackSize::StateBits(0))
    1083             :     , mAxis(aAxis)
    1084           0 :     , mCanResolveLineRangeSize(false)
    1085             :   {
    1086           0 :     mBaselineSubtreeAlign[BaselineSharingGroup::eFirst] = NS_STYLE_ALIGN_AUTO;
    1087           0 :     mBaselineSubtreeAlign[BaselineSharingGroup::eLast] = NS_STYLE_ALIGN_AUTO;
    1088           0 :     mBaseline[BaselineSharingGroup::eFirst] = NS_INTRINSIC_WIDTH_UNKNOWN;
    1089           0 :     mBaseline[BaselineSharingGroup::eLast] = NS_INTRINSIC_WIDTH_UNKNOWN;
    1090           0 :   }
    1091             : 
    1092             :   void Initialize(const TrackSizingFunctions& aFunctions,
    1093             :                   const nsStyleCoord&         aGridGap,
    1094             :                   uint32_t                    aNumTracks,
    1095             :                   nscoord                     aContentBoxSize);
    1096             : 
    1097             :   /**
    1098             :    * Return true if aRange spans at least one track with an intrinsic sizing
    1099             :    * function and does not span any tracks with a <flex> max-sizing function.
    1100             :    * @param aRange the span of tracks to check
    1101             :    * @param aState will be set to the union of the state bits of all the spanned
    1102             :    *               tracks, unless a flex track is found - then it only contains
    1103             :    *               the union of the tracks up to and including the flex track.
    1104             :    */
    1105             :   bool HasIntrinsicButNoFlexSizingInRange(const LineRange&      aRange,
    1106             :                                           TrackSize::StateBits* aState) const;
    1107             : 
    1108             :   // Some data we collect for aligning baseline-aligned items.
    1109             :   struct ItemBaselineData
    1110             :   {
    1111             :     uint32_t mBaselineTrack;
    1112             :     nscoord mBaseline;
    1113             :     nscoord mSize;
    1114             :     GridItemInfo* mGridItem;
    1115           0 :     static bool IsBaselineTrackLessThan(const ItemBaselineData& a,
    1116             :                                         const ItemBaselineData& b)
    1117             :     {
    1118           0 :       return a.mBaselineTrack < b.mBaselineTrack;
    1119             :     }
    1120             :   };
    1121             : 
    1122             :   /**
    1123             :    * Calculate baseline offsets for the given set of items.
    1124             :    * Helper for InitialzeItemBaselines.
    1125             :    */
    1126             :   void CalculateItemBaselines(nsTArray<ItemBaselineData>& aBaselineItems,
    1127             :                               BaselineSharingGroup aBaselineGroup);
    1128             : 
    1129             :   /**
    1130             :    * Initialize grid item baseline state and offsets.
    1131             :    */
    1132             :   void InitializeItemBaselines(GridReflowInput&        aState,
    1133             :                                nsTArray<GridItemInfo>& aGridItems);
    1134             : 
    1135             :   /**
    1136             :    * Apply the additional alignment needed to align the baseline-aligned subtree
    1137             :    * the item belongs to within its baseline track.
    1138             :    */
    1139             :   void AlignBaselineSubtree(const GridItemInfo& aGridItem) const;
    1140             : 
    1141             :   /**
    1142             :    * Resolve Intrinsic Track Sizes.
    1143             :    * http://dev.w3.org/csswg/css-grid/#algo-content
    1144             :    */
    1145             :   void ResolveIntrinsicSize(GridReflowInput&            aState,
    1146             :                             nsTArray<GridItemInfo>&     aGridItems,
    1147             :                             const TrackSizingFunctions& aFunctions,
    1148             :                             LineRange GridArea::*       aRange,
    1149             :                             nscoord                     aPercentageBasis,
    1150             :                             SizingConstraint            aConstraint);
    1151             : 
    1152             :   /**
    1153             :    * Helper for ResolveIntrinsicSize.  It implements step 1 "size tracks to fit
    1154             :    * non-spanning items" in the spec.  Return true if the track has a <flex>
    1155             :    * max-sizing function, false otherwise.
    1156             :    */
    1157             :   bool ResolveIntrinsicSizeStep1(GridReflowInput&            aState,
    1158             :                                  const TrackSizingFunctions& aFunctions,
    1159             :                                  nscoord                     aPercentageBasis,
    1160             :                                  SizingConstraint            aConstraint,
    1161             :                                  const LineRange&            aRange,
    1162             :                                  const GridItemInfo&         aGridItem);
    1163             :   /**
    1164             :    * Collect the tracks which are growable (matching aSelector) into
    1165             :    * aGrowableTracks, and return the amount of space that can be used
    1166             :    * to grow those tracks.  Specifically, we return aAvailableSpace minus
    1167             :    * the sum of mBase's (and corresponding grid gaps) in aPlan (clamped to 0)
    1168             :    * for the tracks in aRange, or zero when there are no growable tracks.
    1169             :    * @note aPlan[*].mBase represents a planned new base or limit.
    1170             :    */
    1171           0 :   nscoord CollectGrowable(nscoord                    aAvailableSpace,
    1172             :                           const nsTArray<TrackSize>& aPlan,
    1173             :                           const LineRange&           aRange,
    1174             :                           TrackSize::StateBits       aSelector,
    1175             :                           nsTArray<uint32_t>&        aGrowableTracks) const
    1176             :   {
    1177           0 :     MOZ_ASSERT(aAvailableSpace > 0, "why call me?");
    1178           0 :     nscoord space = aAvailableSpace - mGridGap * (aRange.Extent() - 1);
    1179           0 :     const uint32_t start = aRange.mStart;
    1180           0 :     const uint32_t end = aRange.mEnd;
    1181           0 :     for (uint32_t i = start; i < end; ++i) {
    1182           0 :       const TrackSize& sz = aPlan[i];
    1183           0 :       space -= sz.mBase;
    1184           0 :       if (space <= 0) {
    1185           0 :         return 0;
    1186             :       }
    1187           0 :       if ((sz.mState & aSelector) && !sz.IsFrozen()) {
    1188           0 :         aGrowableTracks.AppendElement(i);
    1189             :       }
    1190             :     }
    1191           0 :     return aGrowableTracks.IsEmpty() ? 0 : space;
    1192             :   }
    1193             : 
    1194           0 :   void SetupGrowthPlan(nsTArray<TrackSize>&      aPlan,
    1195             :                        const nsTArray<uint32_t>& aTracks) const
    1196             :   {
    1197           0 :     for (uint32_t track : aTracks) {
    1198           0 :       aPlan[track] = mSizes[track];
    1199             :     }
    1200           0 :   }
    1201             : 
    1202           0 :   void CopyPlanToBase(const nsTArray<TrackSize>& aPlan,
    1203             :                       const nsTArray<uint32_t>&  aTracks)
    1204             :   {
    1205           0 :     for (uint32_t track : aTracks) {
    1206           0 :       MOZ_ASSERT(mSizes[track].mBase <= aPlan[track].mBase);
    1207           0 :       mSizes[track].mBase = aPlan[track].mBase;
    1208             :     }
    1209           0 :   }
    1210             : 
    1211           0 :   void CopyPlanToLimit(const nsTArray<TrackSize>& aPlan,
    1212             :                        const nsTArray<uint32_t>&  aTracks)
    1213             :   {
    1214           0 :     for (uint32_t track : aTracks) {
    1215           0 :       MOZ_ASSERT(mSizes[track].mLimit == NS_UNCONSTRAINEDSIZE ||
    1216             :                  mSizes[track].mLimit <= aPlan[track].mBase);
    1217           0 :       mSizes[track].mLimit = aPlan[track].mBase;
    1218             :     }
    1219           0 :   }
    1220             : 
    1221             :   using FitContentClamper =
    1222             :     std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
    1223             :   /**
    1224             :    * Grow the planned size for tracks in aGrowableTracks up to their limit
    1225             :    * and then freeze them (all aGrowableTracks must be unfrozen on entry).
    1226             :    * Subtract the space added from aAvailableSpace and return that.
    1227             :    */
    1228           0 :   nscoord GrowTracksToLimit(nscoord                   aAvailableSpace,
    1229             :                             nsTArray<TrackSize>&      aPlan,
    1230             :                             const nsTArray<uint32_t>& aGrowableTracks,
    1231             :                             const FitContentClamper&  aFitContentClamper) const
    1232             :   {
    1233           0 :     MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0);
    1234           0 :     nscoord space = aAvailableSpace;
    1235           0 :     uint32_t numGrowable = aGrowableTracks.Length();
    1236             :     while (true) {
    1237           0 :       nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
    1238           0 :       for (uint32_t track : aGrowableTracks) {
    1239           0 :         TrackSize& sz = aPlan[track];
    1240           0 :         if (sz.IsFrozen()) {
    1241           0 :           continue;
    1242             :         }
    1243           0 :         nscoord newBase = sz.mBase + spacePerTrack;
    1244           0 :         nscoord limit = sz.mLimit;
    1245           0 :         if (MOZ_UNLIKELY((sz.mState & TrackSize::eFitContent) &&
    1246             :                          aFitContentClamper)) {
    1247             :           // Clamp the limit to the fit-content() size, for §12.5.2 step 5/6.
    1248           0 :           aFitContentClamper(track, sz.mBase, &limit);
    1249             :         }
    1250           0 :         if (newBase > limit) {
    1251           0 :           nscoord consumed = limit - sz.mBase;
    1252           0 :           if (consumed > 0) {
    1253           0 :             space -= consumed;
    1254           0 :             sz.mBase = limit;
    1255             :           }
    1256           0 :           sz.mState |= TrackSize::eFrozen;
    1257           0 :           if (--numGrowable == 0) {
    1258           0 :             return space;
    1259             :           }
    1260             :         } else {
    1261           0 :           sz.mBase = newBase;
    1262           0 :           space -= spacePerTrack;
    1263             :         }
    1264           0 :         MOZ_ASSERT(space >= 0);
    1265           0 :         if (space == 0) {
    1266           0 :           return 0;
    1267             :         }
    1268             :       }
    1269           0 :     }
    1270             :     MOZ_ASSERT_UNREACHABLE("we don't exit the loop above except by return");
    1271             :     return 0;
    1272             :   }
    1273             : 
    1274             :   /**
    1275             :    * Helper for GrowSelectedTracksUnlimited.  For the set of tracks (S) that
    1276             :    * match aMinSizingSelector: if a track in S doesn't match aMaxSizingSelector
    1277             :    * then mark it with aSkipFlag.  If all tracks in S were marked then unmark
    1278             :    * them.  Return aNumGrowable minus the number of tracks marked.  It is
    1279             :    * assumed that aPlan have no aSkipFlag set for tracks in aGrowableTracks
    1280             :    * on entry to this method.
    1281             :    */
    1282           0 :    uint32_t MarkExcludedTracks(nsTArray<TrackSize>&      aPlan,
    1283             :                                uint32_t                  aNumGrowable,
    1284             :                                const nsTArray<uint32_t>& aGrowableTracks,
    1285             :                                TrackSize::StateBits      aMinSizingSelector,
    1286             :                                TrackSize::StateBits      aMaxSizingSelector,
    1287             :                                TrackSize::StateBits      aSkipFlag) const
    1288             :   {
    1289           0 :     bool foundOneSelected = false;
    1290           0 :     bool foundOneGrowable = false;
    1291           0 :     uint32_t numGrowable = aNumGrowable;
    1292           0 :     for (uint32_t track : aGrowableTracks) {
    1293           0 :       TrackSize& sz = aPlan[track];
    1294           0 :       const auto state = sz.mState;
    1295           0 :       if (state & aMinSizingSelector) {
    1296           0 :         foundOneSelected = true;
    1297           0 :         if (state & aMaxSizingSelector) {
    1298           0 :           foundOneGrowable = true;
    1299           0 :           continue;
    1300             :         }
    1301           0 :         sz.mState |= aSkipFlag;
    1302           0 :         MOZ_ASSERT(numGrowable != 0);
    1303           0 :         --numGrowable;
    1304             :       }
    1305             :     }
    1306             :     // 12.5 "if there are no such tracks, then all affected tracks"
    1307           0 :     if (foundOneSelected && !foundOneGrowable) {
    1308           0 :       for (uint32_t track : aGrowableTracks) {
    1309           0 :         aPlan[track].mState &= ~aSkipFlag;
    1310             :       }
    1311           0 :       numGrowable = aNumGrowable;
    1312             :     }
    1313           0 :     return numGrowable;
    1314             :   }
    1315             : 
    1316             :   /**
    1317             :    * Increase the planned size for tracks in aGrowableTracks that match
    1318             :    * aSelector (or all tracks if aSelector is zero) beyond their limit.
    1319             :    * This implements the "Distribute space beyond growth limits" step in
    1320             :    * https://drafts.csswg.org/css-grid/#distribute-extra-space
    1321             :    */
    1322           0 :   void GrowSelectedTracksUnlimited(nscoord                   aAvailableSpace,
    1323             :                                    nsTArray<TrackSize>&      aPlan,
    1324             :                                    const nsTArray<uint32_t>& aGrowableTracks,
    1325             :                                    TrackSize::StateBits      aSelector,
    1326             :                                    const FitContentClamper&  aFitContentClamper) const
    1327             :   {
    1328           0 :     MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0);
    1329           0 :     uint32_t numGrowable = aGrowableTracks.Length();
    1330           0 :     if (aSelector) {
    1331           0 :       MOZ_ASSERT(aSelector == (aSelector & TrackSize::eIntrinsicMinSizing) &&
    1332             :                  (aSelector & TrackSize::eMaxContentMinSizing),
    1333             :                  "Should only get here for track sizing steps 2.1 to 2.3");
    1334             :       // Note that eMaxContentMinSizing is always included. We do those first:
    1335             :       numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
    1336             :                                        TrackSize::eMaxContentMinSizing,
    1337             :                                        TrackSize::eMaxContentMaxSizing,
    1338           0 :                                        TrackSize::eSkipGrowUnlimited1);
    1339             :       // Now mark min-content/auto min-sizing tracks if requested.
    1340           0 :       auto minOrAutoSelector = aSelector & ~TrackSize::eMaxContentMinSizing;
    1341           0 :       if (minOrAutoSelector) {
    1342           0 :         numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
    1343             :                                          minOrAutoSelector,
    1344             :                                          TrackSize::eIntrinsicMaxSizing,
    1345           0 :                                          TrackSize::eSkipGrowUnlimited2);
    1346             :       }
    1347             :     }
    1348           0 :     nscoord space = aAvailableSpace;
    1349           0 :     DebugOnly<bool> didClamp = false;
    1350           0 :     while (numGrowable) {
    1351           0 :       nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
    1352           0 :       for (uint32_t track : aGrowableTracks) {
    1353           0 :         TrackSize& sz = aPlan[track];
    1354           0 :         if (sz.mState & TrackSize::eSkipGrowUnlimited) {
    1355           0 :           continue; // an excluded track
    1356             :         }
    1357           0 :         nscoord delta = spacePerTrack;
    1358           0 :         nscoord newBase = sz.mBase + delta;
    1359           0 :         if (MOZ_UNLIKELY((sz.mState & TrackSize::eFitContent) &&
    1360             :                          aFitContentClamper)) {
    1361             :           // Clamp newBase to the fit-content() size, for §12.5.2 step 5/6.
    1362           0 :           if (aFitContentClamper(track, sz.mBase, &newBase)) {
    1363           0 :             didClamp = true;
    1364           0 :             delta = newBase - sz.mBase;
    1365           0 :             MOZ_ASSERT(delta >= 0, "track size shouldn't shrink");
    1366           0 :             sz.mState |= TrackSize::eSkipGrowUnlimited1;
    1367           0 :             --numGrowable;
    1368             :           }
    1369             :         }
    1370           0 :         sz.mBase = newBase;
    1371           0 :         space -= delta;
    1372           0 :         MOZ_ASSERT(space >= 0);
    1373           0 :         if (space == 0) {
    1374           0 :           return;
    1375             :         }
    1376             :       }
    1377             :     }
    1378           0 :     MOZ_ASSERT(didClamp, "we don't exit the loop above except by return, "
    1379             :                          "unless we clamped some track's size");
    1380             :   }
    1381             : 
    1382             :   /**
    1383             :    * Distribute aAvailableSpace to the planned base size for aGrowableTracks
    1384             :    * up to their limits, then distribute the remaining space beyond the limits.
    1385             :    */
    1386           0 :   void DistributeToTrackBases(nscoord              aAvailableSpace,
    1387             :                               nsTArray<TrackSize>& aPlan,
    1388             :                               nsTArray<uint32_t>&  aGrowableTracks,
    1389             :                               TrackSize::StateBits aSelector)
    1390             :   {
    1391           0 :     SetupGrowthPlan(aPlan, aGrowableTracks);
    1392           0 :     nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks, nullptr);
    1393           0 :     if (space > 0) {
    1394           0 :       GrowSelectedTracksUnlimited(space, aPlan, aGrowableTracks, aSelector, nullptr);
    1395             :     }
    1396           0 :     CopyPlanToBase(aPlan, aGrowableTracks);
    1397           0 :   }
    1398             : 
    1399             :   /**
    1400             :    * Distribute aAvailableSpace to the planned limits for aGrowableTracks.
    1401             :    */
    1402           0 :   void DistributeToTrackLimits(nscoord              aAvailableSpace,
    1403             :                                nsTArray<TrackSize>& aPlan,
    1404             :                                nsTArray<uint32_t>&  aGrowableTracks,
    1405             :                                const TrackSizingFunctions& aFunctions,
    1406             :                                nscoord                     aPercentageBasis)
    1407             :   {
    1408             :     auto fitContentClamper = [&aFunctions, aPercentageBasis] (uint32_t aTrack,
    1409             :                                                               nscoord aMinSize,
    1410           0 :                                                               nscoord* aSize) {
    1411             :       nscoord fitContentLimit =
    1412           0 :         ::ResolveToDefiniteSize(aFunctions.MaxSizingFor(aTrack), aPercentageBasis);
    1413           0 :       if (*aSize > fitContentLimit) {
    1414           0 :         *aSize = std::max(aMinSize, fitContentLimit);
    1415           0 :         return true;
    1416             :       }
    1417           0 :       return false;
    1418           0 :     };
    1419           0 :     nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks,
    1420           0 :                                       fitContentClamper);
    1421           0 :     if (space > 0) {
    1422           0 :       GrowSelectedTracksUnlimited(aAvailableSpace, aPlan, aGrowableTracks,
    1423           0 :                                   TrackSize::StateBits(0), fitContentClamper);
    1424             :     }
    1425           0 :     CopyPlanToLimit(aPlan, aGrowableTracks);
    1426           0 :   }
    1427             : 
    1428             :   /**
    1429             :    * Distribute aAvailableSize to the tracks.  This implements 12.6 at:
    1430             :    * http://dev.w3.org/csswg/css-grid/#algo-grow-tracks
    1431             :    */
    1432           0 :   void DistributeFreeSpace(nscoord aAvailableSize)
    1433             :   {
    1434           0 :     const uint32_t numTracks = mSizes.Length();
    1435           0 :     if (MOZ_UNLIKELY(numTracks == 0 || aAvailableSize <= 0)) {
    1436           0 :       return;
    1437             :     }
    1438           0 :     if (aAvailableSize == NS_UNCONSTRAINEDSIZE) {
    1439           0 :       for (TrackSize& sz : mSizes) {
    1440           0 :         sz.mBase = sz.mLimit;
    1441             :       }
    1442             :     } else {
    1443             :       // Compute free space and count growable tracks.
    1444           0 :       nscoord space = aAvailableSize;
    1445           0 :       uint32_t numGrowable = numTracks;
    1446           0 :       for (const TrackSize& sz : mSizes) {
    1447           0 :         space -= sz.mBase;
    1448           0 :         MOZ_ASSERT(sz.mBase <= sz.mLimit);
    1449           0 :         if (sz.mBase == sz.mLimit) {
    1450           0 :           --numGrowable;
    1451             :         }
    1452             :       }
    1453             :       // Distribute the free space evenly to the growable tracks. If not exactly
    1454             :       // divisable the remainder is added to the leading tracks.
    1455           0 :       while (space > 0 && numGrowable) {
    1456             :         nscoord spacePerTrack =
    1457           0 :           std::max<nscoord>(space / numGrowable, 1);
    1458           0 :         for (uint32_t i = 0; i < numTracks && space > 0; ++i) {
    1459           0 :           TrackSize& sz = mSizes[i];
    1460           0 :           if (sz.mBase == sz.mLimit) {
    1461           0 :             continue;
    1462             :           }
    1463           0 :           nscoord newBase = sz.mBase + spacePerTrack;
    1464           0 :           if (newBase >= sz.mLimit) {
    1465           0 :             space -= sz.mLimit - sz.mBase;
    1466           0 :             sz.mBase = sz.mLimit;
    1467           0 :             --numGrowable;
    1468             :           } else {
    1469           0 :             space -= spacePerTrack;
    1470           0 :             sz.mBase = newBase;
    1471             :           }
    1472             :         }
    1473             :       }
    1474             :     }
    1475             :   }
    1476             : 
    1477             :   /**
    1478             :    * Implements "12.7.1. Find the Size of an 'fr'".
    1479             :    * http://dev.w3.org/csswg/css-grid/#algo-find-fr-size
    1480             :    * (The returned value is a 'nscoord' divided by a factor - a floating type
    1481             :    * is used to avoid intermediary rounding errors.)
    1482             :    */
    1483             :   float FindFrUnitSize(const LineRange&            aRange,
    1484             :                        const nsTArray<uint32_t>&   aFlexTracks,
    1485             :                        const TrackSizingFunctions& aFunctions,
    1486             :                        nscoord                     aSpaceToFill) const;
    1487             : 
    1488             :   /**
    1489             :    * Implements the "find the used flex fraction" part of StretchFlexibleTracks.
    1490             :    * (The returned value is a 'nscoord' divided by a factor - a floating type
    1491             :    * is used to avoid intermediary rounding errors.)
    1492             :    */
    1493             :   float FindUsedFlexFraction(GridReflowInput&            aState,
    1494             :                              nsTArray<GridItemInfo>&     aGridItems,
    1495             :                              const nsTArray<uint32_t>&   aFlexTracks,
    1496             :                              const TrackSizingFunctions& aFunctions,
    1497             :                              nscoord                     aAvailableSize) const;
    1498             : 
    1499             :   /**
    1500             :    * Implements "12.7. Stretch Flexible Tracks"
    1501             :    * http://dev.w3.org/csswg/css-grid/#algo-flex-tracks
    1502             :    */
    1503             :   void StretchFlexibleTracks(GridReflowInput&            aState,
    1504             :                              nsTArray<GridItemInfo>&     aGridItems,
    1505             :                              const TrackSizingFunctions& aFunctions,
    1506             :                              nscoord                     aAvailableSize);
    1507             : 
    1508             :   /**
    1509             :    * Implements "12.3. Track Sizing Algorithm"
    1510             :    * http://dev.w3.org/csswg/css-grid/#algo-track-sizing
    1511             :    */
    1512             :   void CalculateSizes(GridReflowInput&            aState,
    1513             :                       nsTArray<GridItemInfo>&     aGridItems,
    1514             :                       const TrackSizingFunctions& aFunctions,
    1515             :                       nscoord                     aContentSize,
    1516             :                       LineRange GridArea::*       aRange,
    1517             :                       SizingConstraint            aConstraint);
    1518             : 
    1519             :   /**
    1520             :    * Apply 'align/justify-content', whichever is relevant for this axis.
    1521             :    * https://drafts.csswg.org/css-align-3/#propdef-align-content
    1522             :    */
    1523             :   void AlignJustifyContent(const nsStylePosition* aStyle,
    1524             :                            WritingMode            aWM,
    1525             :                            const LogicalSize&     aContainerSize);
    1526             : 
    1527             :   /**
    1528             :    * Return the intrinsic size by back-computing percentages as:
    1529             :    * IntrinsicSize = SumOfCoordSizes / (1 - SumOfPercentages).
    1530             :    */
    1531             :   nscoord BackComputedIntrinsicSize(const TrackSizingFunctions& aFunctions,
    1532             :                                     const nsStyleCoord& aGridGap) const;
    1533             : 
    1534           0 :   nscoord GridLineEdge(uint32_t aLine, GridLineSide aSide) const
    1535             :   {
    1536           0 :     if (MOZ_UNLIKELY(mSizes.IsEmpty())) {
    1537             :       // https://drafts.csswg.org/css-grid/#grid-definition
    1538             :       // "... the explicit grid still contains one grid line in each axis."
    1539           0 :       MOZ_ASSERT(aLine == 0, "We should only resolve line 1 in an empty grid");
    1540           0 :       return nscoord(0);
    1541             :     }
    1542           0 :     MOZ_ASSERT(aLine <= mSizes.Length(), "mSizes is too small");
    1543           0 :     if (aSide == GridLineSide::eBeforeGridGap) {
    1544           0 :       if (aLine == 0) {
    1545           0 :         return nscoord(0);
    1546             :       }
    1547           0 :       const TrackSize& sz = mSizes[aLine - 1];
    1548           0 :       return sz.mPosition + sz.mBase;
    1549             :     }
    1550           0 :     if (aLine == mSizes.Length()) {
    1551           0 :       return mContentBoxSize;
    1552             :     }
    1553           0 :     return mSizes[aLine].mPosition;
    1554             :   }
    1555             : 
    1556           0 :   nscoord SumOfGridGaps() const
    1557             :   {
    1558           0 :     auto len = mSizes.Length();
    1559           0 :     return MOZ_LIKELY(len > 1) ? (len - 1) * mGridGap : 0;
    1560             :   }
    1561             : 
    1562             :   /**
    1563             :    * Break before aRow, i.e. set the eBreakBefore flag on aRow and set the grid
    1564             :    * gap before aRow to zero (and shift all rows after it by the removed gap).
    1565             :    */
    1566           0 :   void BreakBeforeRow(uint32_t aRow)
    1567             :   {
    1568           0 :     MOZ_ASSERT(mAxis == eLogicalAxisBlock,
    1569             :                "Should only be fragmenting in the block axis (between rows)");
    1570           0 :     nscoord prevRowEndPos = 0;
    1571           0 :     if (aRow != 0) {
    1572           0 :       auto& prevSz = mSizes[aRow - 1];
    1573           0 :       prevRowEndPos = prevSz.mPosition + prevSz.mBase;
    1574             :     }
    1575           0 :     auto& sz = mSizes[aRow];
    1576           0 :     const nscoord gap = sz.mPosition - prevRowEndPos;
    1577           0 :     sz.mState |= TrackSize::eBreakBefore;
    1578           0 :     if (gap != 0) {
    1579           0 :       for (uint32_t i = aRow, len = mSizes.Length(); i < len; ++i) {
    1580           0 :         mSizes[i].mPosition -= gap;
    1581             :       }
    1582             :     }
    1583           0 :   }
    1584             : 
    1585             :   /**
    1586             :    * Set the size of aRow to aSize and adjust the position of all rows after it.
    1587             :    */
    1588           0 :   void ResizeRow(uint32_t aRow, nscoord aNewSize)
    1589             :   {
    1590           0 :     MOZ_ASSERT(mAxis == eLogicalAxisBlock,
    1591             :                "Should only be fragmenting in the block axis (between rows)");
    1592           0 :     MOZ_ASSERT(aNewSize >= 0);
    1593           0 :     auto& sz = mSizes[aRow];
    1594           0 :     nscoord delta = aNewSize - sz.mBase;
    1595           0 :     NS_WARNING_ASSERTION(delta != nscoord(0), "Useless call to ResizeRow");
    1596           0 :     sz.mBase = aNewSize;
    1597           0 :     const uint32_t numRows = mSizes.Length();
    1598           0 :     for (uint32_t r = aRow + 1; r < numRows; ++r) {
    1599           0 :       mSizes[r].mPosition += delta;
    1600             :     }
    1601           0 :   }
    1602             : 
    1603           0 :   nscoord ResolveSize(const LineRange& aRange) const
    1604             :   {
    1605           0 :     MOZ_ASSERT(mCanResolveLineRangeSize);
    1606           0 :     MOZ_ASSERT(aRange.Extent() > 0, "grid items cover at least one track");
    1607             :     nscoord pos, size;
    1608           0 :     aRange.ToPositionAndLength(mSizes, &pos, &size);
    1609           0 :     return size;
    1610             :   }
    1611             : 
    1612           0 :   nsTArray<nsString> GetExplicitLineNamesAtIndex(
    1613             :     const nsStyleGridTemplate& aGridTemplate,
    1614             :     const TrackSizingFunctions& aFunctions,
    1615             :     uint32_t aIndex)
    1616             :   {
    1617           0 :     nsTArray<nsString> lineNames;
    1618             : 
    1619           0 :     bool hasRepeatAuto = aGridTemplate.HasRepeatAuto();
    1620             :     const nsTArray<nsTArray<nsString>>& lineNameLists(
    1621           0 :       aGridTemplate.mLineNameLists);
    1622             : 
    1623           0 :     if (!hasRepeatAuto) {
    1624           0 :       if (aIndex < lineNameLists.Length()) {
    1625           0 :         lineNames.AppendElements(lineNameLists[aIndex]);
    1626             :       }
    1627             :     } else {
    1628           0 :       const uint32_t repeatTrackCount = aFunctions.NumRepeatTracks();
    1629           0 :       const uint32_t repeatAutoStart = aGridTemplate.mRepeatAutoIndex;
    1630           0 :       const uint32_t repeatAutoEnd = (repeatAutoStart + repeatTrackCount);
    1631           0 :       const int32_t repeatEndDelta = int32_t(repeatTrackCount - 1);
    1632             : 
    1633           0 :       if (aIndex <= repeatAutoStart) {
    1634           0 :         if (aIndex < lineNameLists.Length()) {
    1635           0 :           lineNames.AppendElements(lineNameLists[aIndex]);
    1636             :         }
    1637           0 :         if (aIndex == repeatAutoEnd) {
    1638           0 :           uint32_t i = aIndex + 1;
    1639           0 :           if (i < lineNameLists.Length()) {
    1640           0 :             lineNames.AppendElements(lineNameLists[i]);
    1641             :           }
    1642             :         }
    1643             :       }
    1644           0 :       if (aIndex <= repeatAutoEnd && aIndex > repeatAutoStart) {
    1645           0 :         lineNames.AppendElements(aGridTemplate.mRepeatAutoLineNameListAfter);
    1646             :       }
    1647           0 :       if (aIndex < repeatAutoEnd && aIndex >= repeatAutoStart) {
    1648           0 :         lineNames.AppendElements(aGridTemplate.mRepeatAutoLineNameListBefore);
    1649             :       }
    1650           0 :       if (aIndex >= repeatAutoEnd && aIndex > repeatAutoStart) {
    1651           0 :         uint32_t i = aIndex - repeatEndDelta;
    1652           0 :         if (i < lineNameLists.Length()) {
    1653           0 :           lineNames.AppendElements(lineNameLists[i]);
    1654             :         }
    1655             :       }
    1656             :     }
    1657             : 
    1658           0 :     return lineNames;
    1659             :   }
    1660             : 
    1661             : #ifdef DEBUG
    1662             :   void Dump() const
    1663             :   {
    1664             :     for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
    1665             :       printf("  %d: ", i);
    1666             :       mSizes[i].Dump();
    1667             :       printf("\n");
    1668             :     }
    1669             :   }
    1670             : #endif
    1671             : 
    1672             :   AutoTArray<TrackSize, 32> mSizes;
    1673             :   nscoord mContentBoxSize;
    1674             :   nscoord mGridGap;
    1675             :   // The first(last)-baseline for the first(last) track in this axis.
    1676             :   nscoord mBaseline[2]; // index by BaselineSharingGroup
    1677             :   // The union of the track min/max-sizing state bits in this axis.
    1678             :   TrackSize::StateBits mStateUnion;
    1679             :   LogicalAxis mAxis;
    1680             :   // Used for aligning a baseline-aligned subtree of items.  The only possible
    1681             :   // values are NS_STYLE_ALIGN_{START,END,CENTER,AUTO}.  AUTO means there are
    1682             :   // no baseline-aligned items in any track in that axis.
    1683             :   // There is one alignment value for each BaselineSharingGroup.
    1684             :   uint8_t mBaselineSubtreeAlign[2];
    1685             :   // True if track positions and sizes are final in this axis.
    1686             :   bool mCanResolveLineRangeSize;
    1687             : };
    1688             : 
    1689             : /**
    1690             :  * Grid data shared by all continuations, owned by the first-in-flow.
    1691             :  * The data is initialized from the first-in-flow's GridReflowInput at
    1692             :  * the end of its reflow.  Fragmentation will modify mRows.mSizes -
    1693             :  * the mPosition to remove the row gap at the break boundary, the mState
    1694             :  * by setting the eBreakBefore flag, and mBase is modified when we decide
    1695             :  * to grow a row.  mOriginalRowData is setup by the first-in-flow and
    1696             :  * not modified after that.  It's used for undoing the changes to mRows.
    1697             :  * mCols, mGridItems, mAbsPosItems are used for initializing the grid
    1698             :  * reflow state for continuations, see GridReflowInput::Initialize below.
    1699             :  */
    1700           0 : struct nsGridContainerFrame::SharedGridData
    1701             : {
    1702           0 :   SharedGridData() :
    1703             :     mCols(eLogicalAxisInline),
    1704             :     mRows(eLogicalAxisBlock),
    1705           0 :     mGenerateComputedGridInfo(false) {}
    1706             :   Tracks mCols;
    1707             :   Tracks mRows;
    1708             :   struct RowData {
    1709             :     nscoord mBase; // the original track size
    1710             :     nscoord mGap;  // the original gap before a track
    1711             :   };
    1712             :   nsTArray<RowData> mOriginalRowData;
    1713             :   nsTArray<GridItemInfo> mGridItems;
    1714             :   nsTArray<GridItemInfo> mAbsPosItems;
    1715             :   bool mGenerateComputedGridInfo;
    1716             : 
    1717             :   /**
    1718             :    * Only set on the first-in-flow.  Continuations will Initialize() their
    1719             :    * GridReflowInput from it.
    1720             :    */
    1721           0 :   NS_DECLARE_FRAME_PROPERTY_DELETABLE(Prop, SharedGridData)
    1722             : };
    1723             : 
    1724           0 : struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput
    1725             : {
    1726           0 :   GridReflowInput(nsGridContainerFrame*    aFrame,
    1727             :                   const ReflowInput& aRI)
    1728           0 :     : GridReflowInput(aFrame, *aRI.mRenderingContext, &aRI, aRI.mStylePosition,
    1729           0 :                       aRI.GetWritingMode())
    1730           0 :   {}
    1731           0 :   GridReflowInput(nsGridContainerFrame* aFrame,
    1732             :                   gfxContext&           aRC)
    1733           0 :     : GridReflowInput(aFrame, aRC, nullptr, aFrame->StylePosition(),
    1734           0 :                       aFrame->GetWritingMode())
    1735           0 :   {}
    1736             : 
    1737             :   /**
    1738             :    * Initialize our track sizes and grid item info using the shared
    1739             :    * state from aGridContainerFrame first-in-flow.
    1740             :    */
    1741           0 :   void InitializeForContinuation(nsGridContainerFrame* aGridContainerFrame,
    1742             :                                  nscoord               aConsumedBSize)
    1743             :   {
    1744           0 :     MOZ_ASSERT(aGridContainerFrame->GetPrevInFlow(),
    1745             :                "don't call this on the first-in-flow");
    1746           0 :     MOZ_ASSERT(mGridItems.IsEmpty() && mAbsPosItems.IsEmpty(),
    1747             :                "shouldn't have any item data yet");
    1748             : 
    1749             :     // Get the SharedGridData from the first-in-flow. Also calculate the number
    1750             :     // of fragments before this so that we can figure out our start row below.
    1751           0 :     uint32_t fragment = 0;
    1752           0 :     nsIFrame* firstInFlow = aGridContainerFrame;
    1753           0 :     for (auto pif = aGridContainerFrame->GetPrevInFlow();
    1754           0 :          pif; pif = pif->GetPrevInFlow()) {
    1755           0 :       ++fragment;
    1756           0 :       firstInFlow = pif;
    1757             :     }
    1758           0 :     mSharedGridData = firstInFlow->GetProperty(SharedGridData::Prop());
    1759           0 :     MOZ_ASSERT(mSharedGridData, "first-in-flow must have SharedGridData");
    1760             : 
    1761             :     // Find the start row for this fragment and undo breaks after that row
    1762             :     // since the breaks might be different from the last reflow.
    1763           0 :     auto& rowSizes = mSharedGridData->mRows.mSizes;
    1764           0 :     const uint32_t numRows = rowSizes.Length();
    1765           0 :     mStartRow = numRows;
    1766           0 :     for (uint32_t row = 0, breakCount = 0; row < numRows; ++row) {
    1767           0 :       if (rowSizes[row].mState & TrackSize::eBreakBefore) {
    1768           0 :         if (fragment == ++breakCount) {
    1769           0 :           mStartRow = row;
    1770           0 :           mFragBStart = rowSizes[row].mPosition;
    1771             :           // Restore the original size for |row| and grid gaps / state after it.
    1772           0 :           const auto& origRowData = mSharedGridData->mOriginalRowData;
    1773           0 :           rowSizes[row].mBase = origRowData[row].mBase;
    1774           0 :           nscoord prevEndPos = rowSizes[row].mPosition + rowSizes[row].mBase;
    1775           0 :           while (++row < numRows) {
    1776           0 :             auto& sz = rowSizes[row];
    1777           0 :             const auto& orig = origRowData[row];
    1778           0 :             sz.mPosition = prevEndPos + orig.mGap;
    1779           0 :             sz.mBase = orig.mBase;
    1780           0 :             sz.mState &= ~TrackSize::eBreakBefore;
    1781           0 :             prevEndPos = sz.mPosition + sz.mBase;
    1782             :           }
    1783           0 :           break;
    1784             :         }
    1785             :       }
    1786             :     }
    1787           0 :     if (mStartRow == numRows) {
    1788             :       // All of the grid's rows fit inside of previous grid-container fragments.
    1789           0 :       mFragBStart = aConsumedBSize;
    1790             :     }
    1791             : 
    1792             :     // Copy the shared track state.
    1793             :     // XXX consider temporarily swapping the array elements instead and swapping
    1794             :     // XXX them back after we're done reflowing, for better performance.
    1795             :     // XXX (bug 1252002)
    1796           0 :     mCols = mSharedGridData->mCols;
    1797           0 :     mRows = mSharedGridData->mRows;
    1798             : 
    1799             :     // Copy item data from each child's first-in-flow data in mSharedGridData.
    1800             :     // XXX NOTE: This is O(n^2) in the number of items. (bug 1252186)
    1801           0 :     mIter.Reset();
    1802           0 :     for (; !mIter.AtEnd(); mIter.Next()) {
    1803           0 :       nsIFrame* child = *mIter;
    1804           0 :       nsIFrame* childFirstInFlow = child->FirstInFlow();
    1805           0 :       DebugOnly<size_t> len = mGridItems.Length();
    1806           0 :       for (auto& itemInfo : mSharedGridData->mGridItems) {
    1807           0 :         if (itemInfo.mFrame == childFirstInFlow) {
    1808           0 :           auto item = mGridItems.AppendElement(GridItemInfo(child, itemInfo.mArea));
    1809             :           // Copy the item's baseline data so that the item's last fragment can do
    1810             :           // 'last baseline' alignment if necessary.
    1811           0 :           item->mState[0] |= itemInfo.mState[0] & ItemState::eAllBaselineBits;
    1812           0 :           item->mState[1] |= itemInfo.mState[1] & ItemState::eAllBaselineBits;
    1813           0 :           item->mBaselineOffset[0] = itemInfo.mBaselineOffset[0];
    1814           0 :           item->mBaselineOffset[1] = itemInfo.mBaselineOffset[1];
    1815           0 :           break;
    1816             :         }
    1817             :       }
    1818           0 :       MOZ_ASSERT(mGridItems.Length() == len + 1, "can't find GridItemInfo");
    1819             :     }
    1820             : 
    1821             :     // XXX NOTE: This is O(n^2) in the number of abs.pos. items. (bug 1252186)
    1822             :     nsFrameList absPosChildren(aGridContainerFrame->GetChildList(
    1823           0 :                                  aGridContainerFrame->GetAbsoluteListID()));
    1824           0 :     for (auto f : absPosChildren) {
    1825           0 :       nsIFrame* childFirstInFlow = f->FirstInFlow();
    1826           0 :       DebugOnly<size_t> len = mAbsPosItems.Length();
    1827           0 :       for (auto& itemInfo : mSharedGridData->mAbsPosItems) {
    1828           0 :         if (itemInfo.mFrame == childFirstInFlow) {
    1829           0 :           mAbsPosItems.AppendElement(GridItemInfo(f, itemInfo.mArea));
    1830           0 :           break;
    1831             :         }
    1832             :       }
    1833           0 :       MOZ_ASSERT(mAbsPosItems.Length() == len + 1, "can't find GridItemInfo");
    1834             :     }
    1835             : 
    1836             :     // Copy in the computed grid info state bit
    1837           0 :     if (mSharedGridData->mGenerateComputedGridInfo) {
    1838           0 :       aGridContainerFrame->AddStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES);
    1839             :     }
    1840           0 :   }
    1841             : 
    1842             :   /**
    1843             :    * Calculate our track sizes.  If the given aContentBox block-axis size is
    1844             :    * unconstrained, it is assigned to the resulting intrinsic block-axis size.
    1845             :    */
    1846             :   void CalculateTrackSizes(const Grid&        aGrid,
    1847             :                            LogicalSize&       aContentBox,
    1848             :                            SizingConstraint   aConstraint);
    1849             : 
    1850             :   /**
    1851             :    * Return the percentage basis for a grid item in its writing-mode.
    1852             :    * If aAxis is eLogicalAxisInline then we return NS_UNCONSTRAINEDSIZE in
    1853             :    * both axes since we know all track sizes are indefinite at this point
    1854             :    * (we calculate column sizes before row sizes).  Otherwise, assert that
    1855             :    * column sizes are known and calculate the size for aGridItem.mArea.mCols
    1856             :    * and use NS_UNCONSTRAINEDSIZE in the other axis.
    1857             :    * @param aAxis the axis we're currently calculating track sizes for
    1858             :    */
    1859             :   LogicalSize PercentageBasisFor(LogicalAxis aAxis,
    1860             :                                  const GridItemInfo& aGridItem) const;
    1861             : 
    1862             :   /**
    1863             :    * Return the containing block for a grid item occupying aArea.
    1864             :    */
    1865             :   LogicalRect ContainingBlockFor(const GridArea& aArea) const;
    1866             : 
    1867             :   /**
    1868             :    * Return the containing block for an abs.pos. grid item occupying aArea.
    1869             :    * Any 'auto' lines in the grid area will be aligned with grid container
    1870             :    * containing block on that side.
    1871             :    * @param aGridOrigin the origin of the grid
    1872             :    * @param aGridCB the grid container containing block (its padding area)
    1873             :    */
    1874             :   LogicalRect ContainingBlockForAbsPos(const GridArea&     aArea,
    1875             :                                        const LogicalPoint& aGridOrigin,
    1876             :                                        const LogicalRect&  aGridCB) const;
    1877             : 
    1878             :   CSSOrderAwareFrameIterator mIter;
    1879             :   const nsStylePosition* const mGridStyle;
    1880             :   Tracks mCols;
    1881             :   Tracks mRows;
    1882             :   TrackSizingFunctions mColFunctions;
    1883             :   TrackSizingFunctions mRowFunctions;
    1884             :   /**
    1885             :    * Info about each (normal flow) grid item.
    1886             :    */
    1887             :   nsTArray<GridItemInfo> mGridItems;
    1888             :   /**
    1889             :    * Info about each grid-aligned abs.pos. child.
    1890             :    */
    1891             :   nsTArray<GridItemInfo> mAbsPosItems;
    1892             : 
    1893             :   /**
    1894             :    * @note mReflowInput may be null when using the 2nd ctor above. In this case
    1895             :    * we'll construct a dummy parent reflow state if we need it to calculate
    1896             :    * min/max-content contributions when sizing tracks.
    1897             :    */
    1898             :   const ReflowInput* const mReflowInput;
    1899             :   gfxContext& mRenderingContext;
    1900             :   nsGridContainerFrame* const mFrame;
    1901             :   SharedGridData* mSharedGridData; // [weak] owned by mFrame's first-in-flow.
    1902             :   /** Computed border+padding with mSkipSides applied. */
    1903             :   LogicalMargin mBorderPadding;
    1904             :   /**
    1905             :    * BStart of this fragment in "grid space" (i.e. the concatenation of content
    1906             :    * areas of all fragments).  Equal to mRows.mSizes[mStartRow].mPosition,
    1907             :    * or, if this fragment starts after the last row, the ConsumedBSize().
    1908             :    */
    1909             :   nscoord mFragBStart;
    1910             :   /** The start row for this fragment. */
    1911             :   uint32_t mStartRow;
    1912             :   /**
    1913             :    * The start row for the next fragment, if any.  If mNextFragmentStartRow ==
    1914             :    * mStartRow then there are no rows in this fragment.
    1915             :    */
    1916             :   uint32_t mNextFragmentStartRow;
    1917             :   /** Our tentative ApplySkipSides bits. */
    1918             :   LogicalSides mSkipSides;
    1919             :   const WritingMode mWM;
    1920             :   /** Initialized lazily, when we find the fragmentainer. */
    1921             :   bool mInFragmentainer;
    1922             : 
    1923             : private:
    1924           0 :   GridReflowInput(nsGridContainerFrame*    aFrame,
    1925             :                   gfxContext&              aRenderingContext,
    1926             :                   const ReflowInput* aReflowInput,
    1927             :                   const nsStylePosition*   aGridStyle,
    1928             :                   const WritingMode&       aWM)
    1929           0 :     : mIter(aFrame, kPrincipalList)
    1930             :     , mGridStyle(aGridStyle)
    1931             :     , mCols(eLogicalAxisInline)
    1932             :     , mRows(eLogicalAxisBlock)
    1933           0 :     , mColFunctions(mGridStyle->mGridTemplateColumns,
    1934           0 :                     mGridStyle->mGridAutoColumnsMin,
    1935           0 :                     mGridStyle->mGridAutoColumnsMax)
    1936           0 :     , mRowFunctions(mGridStyle->mGridTemplateRows,
    1937           0 :                     mGridStyle->mGridAutoRowsMin,
    1938           0 :                     mGridStyle->mGridAutoRowsMax)
    1939             :     , mReflowInput(aReflowInput)
    1940             :     , mRenderingContext(aRenderingContext)
    1941             :     , mFrame(aFrame)
    1942             :     , mSharedGridData(nullptr)
    1943             :     , mBorderPadding(aWM)
    1944             :     , mFragBStart(0)
    1945             :     , mStartRow(0)
    1946             :     , mNextFragmentStartRow(0)
    1947             :     , mWM(aWM)
    1948           0 :     , mInFragmentainer(false)
    1949             :   {
    1950           0 :     MOZ_ASSERT(!aReflowInput || aReflowInput->mFrame == mFrame);
    1951           0 :     if (aReflowInput) {
    1952           0 :       mBorderPadding = aReflowInput->ComputedLogicalBorderPadding();
    1953           0 :       mSkipSides = aFrame->PreReflowBlockLevelLogicalSkipSides();
    1954           0 :       mBorderPadding.ApplySkipSides(mSkipSides);
    1955             :     }
    1956           0 :   }
    1957             : };
    1958             : 
    1959             : using GridReflowInput = nsGridContainerFrame::GridReflowInput;
    1960             : 
    1961             : /**
    1962             :  * The Grid implements grid item placement and the state of the grid -
    1963             :  * the size of the explicit/implicit grid, which cells are occupied etc.
    1964             :  */
    1965           0 : struct MOZ_STACK_CLASS nsGridContainerFrame::Grid
    1966             : {
    1967             :   /**
    1968             :    * Place all child frames into the grid and expand the (implicit) grid as
    1969             :    * needed.  The allocated GridAreas are stored in the GridAreaProperty
    1970             :    * frame property on the child frame.
    1971             :    * @param aComputedMinSize the container's min-size - used to determine
    1972             :    *   the number of repeat(auto-fill/fit) tracks.
    1973             :    * @param aComputedSize the container's size - used to determine
    1974             :    *   the number of repeat(auto-fill/fit) tracks.
    1975             :    * @param aComputedMaxSize the container's max-size - used to determine
    1976             :    *   the number of repeat(auto-fill/fit) tracks.
    1977             :    */
    1978             :   void PlaceGridItems(GridReflowInput& aState,
    1979             :                       const LogicalSize& aComputedMinSize,
    1980             :                       const LogicalSize& aComputedSize,
    1981             :                       const LogicalSize& aComputedMaxSize);
    1982             : 
    1983             :   /**
    1984             :    * As above but for an abs.pos. child.  Any 'auto' lines will be represented
    1985             :    * by kAutoLine in the LineRange result.
    1986             :    * @param aGridStart the first line in the final, but untranslated grid
    1987             :    * @param aGridEnd the last line in the final, but untranslated grid
    1988             :    */
    1989             :   LineRange ResolveAbsPosLineRange(const nsStyleGridLine& aStart,
    1990             :                                    const nsStyleGridLine& aEnd,
    1991             :                                    const LineNameMap& aNameMap,
    1992             :                                    uint32_t GridNamedArea::* aAreaStart,
    1993             :                                    uint32_t GridNamedArea::* aAreaEnd,
    1994             :                                    uint32_t aExplicitGridEnd,
    1995             :                                    int32_t aGridStart,
    1996             :                                    int32_t aGridEnd,
    1997             :                                    const nsStylePosition* aStyle);
    1998             : 
    1999             :   /**
    2000             :    * Return a GridArea for abs.pos. item with non-auto lines placed at
    2001             :    * a definite line (1-based) with placement errors resolved.  One or both
    2002             :    * positions may still be 'auto'.
    2003             :    * @param aChild the abs.pos. grid item to place
    2004             :    * @param aStyle the StylePosition() for the grid container
    2005             :    */
    2006             :   GridArea PlaceAbsPos(nsIFrame* aChild,
    2007             :                        const LineNameMap& aColLineNameMap,
    2008             :                        const LineNameMap& aRowLineNameMap,
    2009             :                        const nsStylePosition* aStyle);
    2010             : 
    2011             :   /**
    2012             :    * Find the first column in row aLockedRow starting at aStartCol where aArea
    2013             :    * could be placed without overlapping other items.  The returned column may
    2014             :    * cause aArea to overflow the current implicit grid bounds if placed there.
    2015             :    */
    2016             :   uint32_t FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
    2017             :                        const GridArea* aArea) const;
    2018             : 
    2019             :   /**
    2020             :    * Place aArea in the first column (in row aArea->mRows.mStart) starting at
    2021             :    * aStartCol without overlapping other items.  The resulting aArea may
    2022             :    * overflow the current implicit grid bounds.
    2023             :    * Pre-condition: aArea->mRows.IsDefinite() is true.
    2024             :    * Post-condition: aArea->IsDefinite() is true.
    2025             :    */
    2026             :   void PlaceAutoCol(uint32_t aStartCol, GridArea* aArea) const;
    2027             : 
    2028             :   /**
    2029             :    * Find the first row in column aLockedCol starting at aStartRow where aArea
    2030             :    * could be placed without overlapping other items.  The returned row may
    2031             :    * cause aArea to overflow the current implicit grid bounds if placed there.
    2032             :    */
    2033             :   uint32_t FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
    2034             :                        const GridArea* aArea) const;
    2035             : 
    2036             :   /**
    2037             :    * Place aArea in the first row (in column aArea->mCols.mStart) starting at
    2038             :    * aStartRow without overlapping other items. The resulting aArea may
    2039             :    * overflow the current implicit grid bounds.
    2040             :    * Pre-condition: aArea->mCols.IsDefinite() is true.
    2041             :    * Post-condition: aArea->IsDefinite() is true.
    2042             :    */
    2043             :   void PlaceAutoRow(uint32_t aStartRow, GridArea* aArea) const;
    2044             : 
    2045             :   /**
    2046             :    * Place aArea in the first column starting at aStartCol,aStartRow without
    2047             :    * causing it to overlap other items or overflow mGridColEnd.
    2048             :    * If there's no such column in aStartRow, continue in position 1,aStartRow+1.
    2049             :    * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
    2050             :    * Post-condition: aArea->IsDefinite() is true.
    2051             :    */
    2052             :   void PlaceAutoAutoInRowOrder(uint32_t aStartCol,
    2053             :                                uint32_t aStartRow,
    2054             :                                GridArea* aArea) const;
    2055             : 
    2056             :   /**
    2057             :    * Place aArea in the first row starting at aStartCol,aStartRow without
    2058             :    * causing it to overlap other items or overflow mGridRowEnd.
    2059             :    * If there's no such row in aStartCol, continue in position aStartCol+1,1.
    2060             :    * Pre-condition: aArea->mCols.IsAuto() && aArea->mRows.IsAuto() is true.
    2061             :    * Post-condition: aArea->IsDefinite() is true.
    2062             :    */
    2063             :   void PlaceAutoAutoInColOrder(uint32_t aStartCol,
    2064             :                                uint32_t aStartRow,
    2065             :                                GridArea* aArea) const;
    2066             : 
    2067             :   /**
    2068             :    * Return aLine if it's inside the aMin..aMax range (inclusive),
    2069             :    * otherwise return kAutoLine.
    2070             :    */
    2071             :   static int32_t
    2072           0 :   AutoIfOutside(int32_t aLine, int32_t aMin, int32_t aMax)
    2073             :   {
    2074           0 :     MOZ_ASSERT(aMin <= aMax);
    2075           0 :     if (aLine < aMin || aLine > aMax) {
    2076           0 :       return kAutoLine;
    2077             :     }
    2078           0 :     return aLine;
    2079             :   }
    2080             : 
    2081             :   /**
    2082             :    * Inflate the implicit grid to include aArea.
    2083             :    * @param aArea may be definite or auto
    2084             :    */
    2085           0 :   void InflateGridFor(const GridArea& aArea)
    2086             :   {
    2087           0 :     mGridColEnd = std::max(mGridColEnd, aArea.mCols.HypotheticalEnd());
    2088           0 :     mGridRowEnd = std::max(mGridRowEnd, aArea.mRows.HypotheticalEnd());
    2089           0 :     MOZ_ASSERT(mGridColEnd <= kTranslatedMaxLine &&
    2090             :                mGridRowEnd <= kTranslatedMaxLine);
    2091           0 :   }
    2092             : 
    2093             :   enum LineRangeSide {
    2094             :     eLineRangeSideStart, eLineRangeSideEnd
    2095             :   };
    2096             :   /**
    2097             :    * Return a line number for (non-auto) aLine, per:
    2098             :    * http://dev.w3.org/csswg/css-grid/#line-placement
    2099             :    * @param aLine style data for the line (must be non-auto)
    2100             :    * @param aNth a number of lines to find from aFromIndex, negative if the
    2101             :    *             search should be in reverse order.  In the case aLine has
    2102             :    *             a specified line name, it's permitted to pass in zero which
    2103             :    *             will be treated as one.
    2104             :    * @param aFromIndex the zero-based index to start counting from
    2105             :    * @param aLineNameList the explicit named lines
    2106             :    * @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
    2107             :    * @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
    2108             :    * @param aExplicitGridEnd the last line in the explicit grid
    2109             :    * @param aEdge indicates whether we are resolving a start or end line
    2110             :    * @param aStyle the StylePosition() for the grid container
    2111             :    * @return a definite line (1-based), clamped to the kMinLine..kMaxLine range
    2112             :    */
    2113             :   int32_t ResolveLine(const nsStyleGridLine& aLine,
    2114             :                       int32_t aNth,
    2115             :                       uint32_t aFromIndex,
    2116             :                       const LineNameMap& aNameMap,
    2117             :                       uint32_t GridNamedArea::* aAreaStart,
    2118             :                       uint32_t GridNamedArea::* aAreaEnd,
    2119             :                       uint32_t aExplicitGridEnd,
    2120             :                       LineRangeSide aSide,
    2121             :                       const nsStylePosition* aStyle);
    2122             : 
    2123             :   /**
    2124             :    * Helper method for ResolveLineRange.
    2125             :    * @see ResolveLineRange
    2126             :    * @return a pair (start,end) of lines
    2127             :    */
    2128             :   typedef std::pair<int32_t, int32_t> LinePair;
    2129             :   LinePair ResolveLineRangeHelper(const nsStyleGridLine& aStart,
    2130             :                                   const nsStyleGridLine& aEnd,
    2131             :                                   const LineNameMap& aNameMap,
    2132             :                                   uint32_t GridNamedArea::* aAreaStart,
    2133             :                                   uint32_t GridNamedArea::* aAreaEnd,
    2134             :                                   uint32_t aExplicitGridEnd,
    2135             :                                   const nsStylePosition* aStyle);
    2136             : 
    2137             :   /**
    2138             :    * Return a LineRange based on the given style data. Non-auto lines
    2139             :    * are resolved to a definite line number (1-based) per:
    2140             :    * http://dev.w3.org/csswg/css-grid/#line-placement
    2141             :    * with placement errors corrected per:
    2142             :    * http://dev.w3.org/csswg/css-grid/#grid-placement-errors
    2143             :    * @param aStyle the StylePosition() for the grid container
    2144             :    * @param aStart style data for the start line
    2145             :    * @param aEnd style data for the end line
    2146             :    * @param aLineNameList the explicit named lines
    2147             :    * @param aAreaStart a pointer to GridNamedArea::mColumnStart/mRowStart
    2148             :    * @param aAreaEnd a pointer to GridNamedArea::mColumnEnd/mRowEnd
    2149             :    * @param aExplicitGridEnd the last line in the explicit grid
    2150             :    * @param aStyle the StylePosition() for the grid container
    2151             :    */
    2152             :   LineRange ResolveLineRange(const nsStyleGridLine& aStart,
    2153             :                              const nsStyleGridLine& aEnd,
    2154             :                              const LineNameMap& aNameMap,
    2155             :                              uint32_t GridNamedArea::* aAreaStart,
    2156             :                              uint32_t GridNamedArea::* aAreaEnd,
    2157             :                              uint32_t aExplicitGridEnd,
    2158             :                              const nsStylePosition* aStyle);
    2159             : 
    2160             :   /**
    2161             :    * Return a GridArea with non-auto lines placed at a definite line (1-based)
    2162             :    * with placement errors resolved.  One or both positions may still
    2163             :    * be 'auto'.
    2164             :    * @param aChild the grid item
    2165             :    * @param aStyle the StylePosition() for the grid container
    2166             :    */
    2167             :   GridArea PlaceDefinite(nsIFrame*              aChild,
    2168             :                          const LineNameMap&     aColLineNameMap,
    2169             :                          const LineNameMap&     aRowLineNameMap,
    2170             :                          const nsStylePosition* aStyle);
    2171             : 
    2172           0 :   bool HasImplicitNamedArea(const nsString& aName) const
    2173             :   {
    2174           0 :     return mAreas && mAreas->Contains(aName);
    2175             :   }
    2176             : 
    2177             :   /**
    2178             :    * A convenience method to lookup a name in 'grid-template-areas'.
    2179             :    * @param aStyle the StylePosition() for the grid container
    2180             :    * @return null if not found
    2181             :    */
    2182             :   static const css::GridNamedArea*
    2183           0 :   FindNamedArea(const nsAString& aName, const nsStylePosition* aStyle)
    2184             :   {
    2185           0 :     if (!aStyle->mGridTemplateAreas) {
    2186           0 :       return nullptr;
    2187             :     }
    2188             :     const nsTArray<css::GridNamedArea>& areas =
    2189           0 :       aStyle->mGridTemplateAreas->mNamedAreas;
    2190           0 :     size_t len = areas.Length();
    2191           0 :     for (size_t i = 0; i < len; ++i) {
    2192           0 :       const css::GridNamedArea& area = areas[i];
    2193           0 :       if (area.mName == aName) {
    2194           0 :         return &area;
    2195             :       }
    2196             :     }
    2197           0 :     return nullptr;
    2198             :   }
    2199             : 
    2200             :   // Return true if aString ends in aSuffix and has at least one character before
    2201             :   // the suffix. Assign aIndex to where the suffix starts.
    2202             :   static bool
    2203           0 :   IsNameWithSuffix(const nsString& aString, const nsString& aSuffix,
    2204             :                    uint32_t* aIndex)
    2205             :   {
    2206           0 :     if (StringEndsWith(aString, aSuffix)) {
    2207           0 :       *aIndex = aString.Length() - aSuffix.Length();
    2208           0 :       return *aIndex != 0;
    2209             :     }
    2210           0 :     return false;
    2211             :   }
    2212             : 
    2213             :   static bool
    2214           0 :   IsNameWithEndSuffix(const nsString& aString, uint32_t* aIndex)
    2215             :   {
    2216           0 :     return IsNameWithSuffix(aString, NS_LITERAL_STRING("-end"), aIndex);
    2217             :   }
    2218             : 
    2219             :   static bool
    2220           0 :   IsNameWithStartSuffix(const nsString& aString, uint32_t* aIndex)
    2221             :   {
    2222           0 :     return IsNameWithSuffix(aString, NS_LITERAL_STRING("-start"), aIndex);
    2223             :   }
    2224             : 
    2225             :   /**
    2226             :    * A CellMap holds state for each cell in the grid.
    2227             :    * It's row major.  It's sparse in the sense that it only has enough rows to
    2228             :    * cover the last row that has a grid item.  Each row only has enough entries
    2229             :    * to cover columns that are occupied *on that row*, i.e. it's not a full
    2230             :    * matrix covering the entire implicit grid.  An absent Cell means that it's
    2231             :    * unoccupied by any grid item.
    2232             :    */
    2233           0 :   struct CellMap {
    2234             :     struct Cell {
    2235           0 :       Cell() : mIsOccupied(false) {}
    2236             :       bool mIsOccupied : 1;
    2237             :     };
    2238             : 
    2239           0 :     void Fill(const GridArea& aGridArea)
    2240             :     {
    2241           0 :       MOZ_ASSERT(aGridArea.IsDefinite());
    2242           0 :       MOZ_ASSERT(aGridArea.mRows.mStart < aGridArea.mRows.mEnd);
    2243           0 :       MOZ_ASSERT(aGridArea.mCols.mStart < aGridArea.mCols.mEnd);
    2244           0 :       const auto numRows = aGridArea.mRows.mEnd;
    2245           0 :       const auto numCols = aGridArea.mCols.mEnd;
    2246           0 :       mCells.EnsureLengthAtLeast(numRows);
    2247           0 :       for (auto i = aGridArea.mRows.mStart; i < numRows; ++i) {
    2248           0 :         nsTArray<Cell>& cellsInRow = mCells[i];
    2249           0 :         cellsInRow.EnsureLengthAtLeast(numCols);
    2250           0 :         for (auto j = aGridArea.mCols.mStart; j < numCols; ++j) {
    2251           0 :           cellsInRow[j].mIsOccupied = true;
    2252             :         }
    2253             :       }
    2254           0 :     }
    2255             : 
    2256           0 :     uint32_t IsEmptyCol(uint32_t aCol) const
    2257             :     {
    2258           0 :       for (auto& row : mCells) {
    2259           0 :         if (aCol < row.Length() && row[aCol].mIsOccupied) {
    2260           0 :           return false;
    2261             :         }
    2262             :       }
    2263           0 :       return true;
    2264             :     }
    2265           0 :     uint32_t IsEmptyRow(uint32_t aRow) const
    2266             :     {
    2267           0 :       if (aRow >= mCells.Length()) {
    2268           0 :         return true;
    2269             :       }
    2270           0 :       for (const Cell& cell : mCells[aRow]) {
    2271           0 :         if (cell.mIsOccupied) {
    2272           0 :           return false;
    2273             :         }
    2274             :       }
    2275           0 :       return true;
    2276             :     }
    2277             : #ifdef DEBUG
    2278             :     void Dump() const
    2279             :     {
    2280             :       const size_t numRows = mCells.Length();
    2281             :       for (size_t i = 0; i < numRows; ++i) {
    2282             :         const nsTArray<Cell>& cellsInRow = mCells[i];
    2283             :         const size_t numCols = cellsInRow.Length();
    2284             :         printf("%lu:\t", (unsigned long)i + 1);
    2285             :         for (size_t j = 0; j < numCols; ++j) {
    2286             :           printf(cellsInRow[j].mIsOccupied ? "X " : ". ");
    2287             :         }
    2288             :         printf("\n");
    2289             :       }
    2290             :     }
    2291             : #endif
    2292             : 
    2293             :     nsTArray<nsTArray<Cell>> mCells;
    2294             :   };
    2295             : 
    2296             :   /**
    2297             :    * State for each cell in the grid.
    2298             :    */
    2299             :   CellMap mCellMap;
    2300             :   /**
    2301             :    * @see HasImplicitNamedArea.
    2302             :    */
    2303             :   ImplicitNamedAreas* mAreas;
    2304             :   /**
    2305             :    * The last column grid line (1-based) in the explicit grid.
    2306             :    * (i.e. the number of explicit columns + 1)
    2307             :    */
    2308             :   uint32_t mExplicitGridColEnd;
    2309             :   /**
    2310             :    * The last row grid line (1-based) in the explicit grid.
    2311             :    * (i.e. the number of explicit rows + 1)
    2312             :    */
    2313             :   uint32_t mExplicitGridRowEnd;
    2314             :   // Same for the implicit grid, except these become zero-based after
    2315             :   // resolving definite lines.
    2316             :   uint32_t mGridColEnd;
    2317             :   uint32_t mGridRowEnd;
    2318             : 
    2319             :   /**
    2320             :    * Offsets from the start of the implicit grid to the start of the translated
    2321             :    * explicit grid.  They are zero if there are no implicit lines before 1,1.
    2322             :    * e.g. "grid-column: span 3 / 1" makes mExplicitGridOffsetCol = 3 and the
    2323             :    * corresponding GridArea::mCols will be 0 / 3 in the zero-based translated
    2324             :    * grid.
    2325             :    */
    2326             :   uint32_t mExplicitGridOffsetCol;
    2327             :   uint32_t mExplicitGridOffsetRow;
    2328             : };
    2329             : 
    2330             : void
    2331           0 : nsGridContainerFrame::GridReflowInput::CalculateTrackSizes(
    2332             :   const Grid&        aGrid,
    2333             :   LogicalSize&       aContentBox,
    2334             :   SizingConstraint   aConstraint)
    2335             : {
    2336           0 :   mCols.Initialize(mColFunctions, mGridStyle->mGridColumnGap,
    2337           0 :                    aGrid.mGridColEnd, aContentBox.ISize(mWM));
    2338           0 :   mRows.Initialize(mRowFunctions, mGridStyle->mGridRowGap,
    2339           0 :                    aGrid.mGridRowEnd, aContentBox.BSize(mWM));
    2340             : 
    2341           0 :   mCols.CalculateSizes(*this, mGridItems, mColFunctions,
    2342           0 :                        aContentBox.ISize(mWM), &GridArea::mCols,
    2343           0 :                        aConstraint);
    2344           0 :   mCols.AlignJustifyContent(mGridStyle, mWM, aContentBox);
    2345             :   // Column positions and sizes are now final.
    2346           0 :   mCols.mCanResolveLineRangeSize = true;
    2347             : 
    2348           0 :   mRows.CalculateSizes(*this, mGridItems, mRowFunctions,
    2349           0 :                        aContentBox.BSize(mWM), &GridArea::mRows,
    2350           0 :                        aConstraint);
    2351           0 :   if (aContentBox.BSize(mWM) == NS_AUTOHEIGHT) {
    2352           0 :     aContentBox.BSize(mWM) =
    2353           0 :       mRows.BackComputedIntrinsicSize(mRowFunctions, mGridStyle->mGridRowGap);
    2354           0 :     mRows.mGridGap =
    2355           0 :       ::ResolveToDefiniteSize(mGridStyle->mGridRowGap, aContentBox.BSize(mWM));
    2356             :   }
    2357           0 : }
    2358             : 
    2359             : /**
    2360             :  * (XXX share this utility function with nsFlexContainerFrame at some point)
    2361             :  *
    2362             :  * Helper for BuildDisplayList, to implement this special-case for grid
    2363             :  * items from the spec:
    2364             :  *   The painting order of grid items is exactly the same as inline blocks,
    2365             :  *   except that [...] 'z-index' values other than 'auto' create a stacking
    2366             :  *   context even if 'position' is 'static'.
    2367             :  * http://dev.w3.org/csswg/css-grid/#z-order
    2368             :  */
    2369             : static uint32_t
    2370           0 : GetDisplayFlagsForGridItem(nsIFrame* aFrame)
    2371             : {
    2372           0 :   const nsStylePosition* pos = aFrame->StylePosition();
    2373           0 :   if (pos->mZIndex.GetUnit() == eStyleUnit_Integer) {
    2374           0 :     return nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT;
    2375             :   }
    2376           0 :   return nsIFrame::DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT;
    2377             : }
    2378             : 
    2379             : // Align an item's margin box in its aAxis inside aCBSize.
    2380             : static void
    2381           0 : AlignJustifySelf(uint8_t aAlignment, LogicalAxis aAxis,
    2382             :                  AlignJustifyFlags aFlags,
    2383             :                  nscoord aBaselineAdjust, nscoord aCBSize,
    2384             :                  const ReflowInput& aRI, const LogicalSize& aChildSize,
    2385             :                  LogicalPoint* aPos)
    2386             : {
    2387           0 :   MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_AUTO, "unexpected 'auto' "
    2388             :              "computed value for normal flow grid item");
    2389             : 
    2390             :   // NOTE: this is the resulting frame offset (border box).
    2391             :   nscoord offset =
    2392           0 :     CSSAlignUtils::AlignJustifySelf(aAlignment, aAxis, aFlags,
    2393             :                                     aBaselineAdjust, aCBSize,
    2394           0 :                                     aRI, aChildSize);
    2395             : 
    2396             :   // Set the position (aPos) for the requested alignment.
    2397           0 :   if (offset != 0) {
    2398           0 :     WritingMode wm = aRI.GetWritingMode();
    2399           0 :     nscoord& pos = aAxis == eLogicalAxisBlock ? aPos->B(wm) : aPos->I(wm);
    2400           0 :     pos += MOZ_LIKELY(aFlags & AlignJustifyFlags::eSameSide) ? offset : -offset;
    2401             :   }
    2402           0 : }
    2403             : 
    2404             : static void
    2405           0 : AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
    2406             :           uint8_t aAlignSelf, nscoord aCBSize, const WritingMode aCBWM,
    2407             :           const ReflowInput& aRI, const LogicalSize& aSize,
    2408             :           LogicalPoint* aPos)
    2409             : {
    2410           0 :   auto alignSelf = aAlignSelf;
    2411             : 
    2412           0 :   AlignJustifyFlags flags = AlignJustifyFlags::eNoFlags;
    2413           0 :   if (alignSelf & NS_STYLE_ALIGN_SAFE) {
    2414           0 :     flags |= AlignJustifyFlags::eOverflowSafe;
    2415             :   }
    2416           0 :   alignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS;
    2417             : 
    2418           0 :   WritingMode childWM = aRI.GetWritingMode();
    2419           0 :   if (aCBWM.ParallelAxisStartsOnSameSide(eLogicalAxisBlock, childWM)) {
    2420           0 :     flags |= AlignJustifyFlags::eSameSide;
    2421             :   }
    2422             : 
    2423             :   // Grid's 'align-self' axis is never parallel to the container's inline axis.
    2424           0 :   if (alignSelf == NS_STYLE_ALIGN_LEFT || alignSelf == NS_STYLE_ALIGN_RIGHT) {
    2425           0 :     alignSelf = NS_STYLE_ALIGN_START;
    2426             :   }
    2427           0 :   if (MOZ_LIKELY(alignSelf == NS_STYLE_ALIGN_NORMAL)) {
    2428           0 :     alignSelf = NS_STYLE_ALIGN_STRETCH;
    2429             :   }
    2430             : 
    2431           0 :   nscoord baselineAdjust = 0;
    2432           0 :   if (alignSelf == NS_STYLE_ALIGN_BASELINE ||
    2433             :       alignSelf == NS_STYLE_ALIGN_LAST_BASELINE) {
    2434           0 :     alignSelf = aGridItem.GetSelfBaseline(alignSelf, eLogicalAxisBlock,
    2435           0 :                                           &baselineAdjust);
    2436             :   }
    2437             : 
    2438           0 :   bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
    2439           0 :   LogicalAxis axis = isOrthogonal ? eLogicalAxisInline : eLogicalAxisBlock;
    2440           0 :   AlignJustifySelf(alignSelf, axis, flags, baselineAdjust,
    2441           0 :                    aCBSize, aRI, aSize, aPos);
    2442           0 : }
    2443             : 
    2444             : static void
    2445           0 : JustifySelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
    2446             :             uint8_t aJustifySelf, nscoord aCBSize, const WritingMode aCBWM,
    2447             :             const ReflowInput& aRI, const LogicalSize& aSize,
    2448             :             LogicalPoint* aPos)
    2449             : {
    2450           0 :   auto justifySelf = aJustifySelf;
    2451             : 
    2452           0 :   AlignJustifyFlags flags = AlignJustifyFlags::eNoFlags;
    2453           0 :   if (justifySelf & NS_STYLE_JUSTIFY_SAFE) {
    2454           0 :     flags |= AlignJustifyFlags::eOverflowSafe;
    2455             :   }
    2456           0 :   justifySelf &= ~NS_STYLE_JUSTIFY_FLAG_BITS;
    2457             : 
    2458           0 :   WritingMode childWM = aRI.GetWritingMode();
    2459           0 :   if (aCBWM.ParallelAxisStartsOnSameSide(eLogicalAxisInline, childWM)) {
    2460           0 :     flags |= AlignJustifyFlags::eSameSide;
    2461             :   }
    2462             : 
    2463           0 :   if (MOZ_LIKELY(justifySelf == NS_STYLE_ALIGN_NORMAL)) {
    2464           0 :     justifySelf = NS_STYLE_ALIGN_STRETCH;
    2465             :   }
    2466             : 
    2467           0 :   nscoord baselineAdjust = 0;
    2468             :   // Grid's 'justify-self' axis is always parallel to the container's inline
    2469             :   // axis, so justify-self:left|right always applies.
    2470           0 :   switch (justifySelf) {
    2471             :     case NS_STYLE_JUSTIFY_LEFT:
    2472           0 :       justifySelf = aCBWM.IsBidiLTR() ? NS_STYLE_JUSTIFY_START
    2473           0 :                                       : NS_STYLE_JUSTIFY_END;
    2474           0 :       break;
    2475             :     case NS_STYLE_JUSTIFY_RIGHT:
    2476           0 :       justifySelf = aCBWM.IsBidiLTR() ? NS_STYLE_JUSTIFY_END
    2477           0 :                                       : NS_STYLE_JUSTIFY_START;
    2478           0 :       break;
    2479             :     case NS_STYLE_JUSTIFY_BASELINE:
    2480             :     case NS_STYLE_JUSTIFY_LAST_BASELINE:
    2481           0 :       justifySelf = aGridItem.GetSelfBaseline(justifySelf, eLogicalAxisInline,
    2482           0 :                                               &baselineAdjust);
    2483           0 :       break;
    2484             :   }
    2485             : 
    2486           0 :   bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
    2487           0 :   LogicalAxis axis = isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline;
    2488           0 :   AlignJustifySelf(justifySelf, axis, flags, baselineAdjust,
    2489           0 :                    aCBSize, aRI, aSize, aPos);
    2490           0 : }
    2491             : 
    2492             : static uint16_t
    2493           0 : GetAlignJustifyValue(uint16_t aAlignment, const WritingMode aWM,
    2494             :                      const bool aIsAlign, bool* aOverflowSafe)
    2495             : {
    2496           0 :   *aOverflowSafe = aAlignment & NS_STYLE_ALIGN_SAFE;
    2497           0 :   aAlignment &= (NS_STYLE_ALIGN_ALL_BITS & ~NS_STYLE_ALIGN_FLAG_BITS);
    2498             : 
    2499             :   // Map some alignment values to 'start' / 'end'.
    2500           0 :   switch (aAlignment) {
    2501             :     case NS_STYLE_ALIGN_LEFT:
    2502             :     case NS_STYLE_ALIGN_RIGHT: {
    2503           0 :       if (aIsAlign) {
    2504             :         // Grid's 'align-content' axis is never parallel to the inline axis.
    2505           0 :         return NS_STYLE_ALIGN_START;
    2506             :       }
    2507           0 :       bool isStart = aWM.IsBidiLTR() == (aAlignment == NS_STYLE_ALIGN_LEFT);
    2508           0 :       return isStart ? NS_STYLE_ALIGN_START : NS_STYLE_ALIGN_END;
    2509             :     }
    2510             :     case NS_STYLE_ALIGN_FLEX_START: // same as 'start' for Grid
    2511           0 :       return NS_STYLE_ALIGN_START;
    2512             :     case NS_STYLE_ALIGN_FLEX_END: // same as 'end' for Grid
    2513           0 :       return NS_STYLE_ALIGN_END;
    2514             :   }
    2515           0 :   return aAlignment;
    2516             : }
    2517             : 
    2518             : static uint16_t
    2519           0 : GetAlignJustifyFallbackIfAny(uint16_t aAlignment, const WritingMode aWM,
    2520             :                              const bool aIsAlign, bool* aOverflowSafe)
    2521             : {
    2522           0 :   uint16_t fallback = aAlignment >> NS_STYLE_ALIGN_ALL_SHIFT;
    2523           0 :   if (fallback) {
    2524           0 :     return GetAlignJustifyValue(fallback, aWM, aIsAlign, aOverflowSafe);
    2525             :   }
    2526             :   // https://drafts.csswg.org/css-align-3/#fallback-alignment
    2527           0 :   switch (aAlignment) {
    2528             :     case NS_STYLE_ALIGN_STRETCH:
    2529             :     case NS_STYLE_ALIGN_SPACE_BETWEEN:
    2530           0 :       return NS_STYLE_ALIGN_START;
    2531             :     case NS_STYLE_ALIGN_SPACE_AROUND:
    2532             :     case NS_STYLE_ALIGN_SPACE_EVENLY:
    2533           0 :       return NS_STYLE_ALIGN_CENTER;
    2534             :   }
    2535           0 :   return 0;
    2536             : }
    2537             : 
    2538             : //----------------------------------------------------------------------
    2539             : 
    2540             : // Frame class boilerplate
    2541             : // =======================
    2542             : 
    2543           0 : NS_QUERYFRAME_HEAD(nsGridContainerFrame)
    2544           0 :   NS_QUERYFRAME_ENTRY(nsGridContainerFrame)
    2545           0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    2546             : 
    2547           0 : NS_IMPL_FRAMEARENA_HELPERS(nsGridContainerFrame)
    2548             : 
    2549             : nsContainerFrame*
    2550           0 : NS_NewGridContainerFrame(nsIPresShell* aPresShell,
    2551             :                          nsStyleContext* aContext)
    2552             : {
    2553           0 :   return new (aPresShell) nsGridContainerFrame(aContext);
    2554             : }
    2555             : 
    2556             : 
    2557             : //----------------------------------------------------------------------
    2558             : 
    2559             : // nsGridContainerFrame Method Implementations
    2560             : // ===========================================
    2561             : 
    2562             : /*static*/ const nsRect&
    2563           0 : nsGridContainerFrame::GridItemCB(nsIFrame* aChild)
    2564             : {
    2565           0 :   MOZ_ASSERT((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
    2566             :              aChild->IsAbsolutelyPositioned());
    2567           0 :   nsRect* cb = aChild->GetProperty(GridItemContainingBlockRect());
    2568           0 :   MOZ_ASSERT(cb, "this method must only be called on grid items, and the grid "
    2569             :                  "container should've reflowed this item by now and set up cb");
    2570           0 :   return *cb;
    2571             : }
    2572             : 
    2573             : void
    2574           0 : nsGridContainerFrame::AddImplicitNamedAreas(
    2575             :   const nsTArray<nsTArray<nsString>>& aLineNameLists)
    2576             : {
    2577             :   // http://dev.w3.org/csswg/css-grid/#implicit-named-areas
    2578             :   // Note: recording these names for fast lookup later is just an optimization.
    2579             :   const uint32_t len =
    2580           0 :     std::min(aLineNameLists.Length(), size_t(nsStyleGridLine::kMaxLine));
    2581           0 :   nsTHashtable<nsStringHashKey> currentStarts;
    2582           0 :   ImplicitNamedAreas* areas = GetImplicitNamedAreas();
    2583           0 :   for (uint32_t i = 0; i < len; ++i) {
    2584           0 :     for (const nsString& name : aLineNameLists[i]) {
    2585             :       uint32_t indexOfSuffix;
    2586           0 :       if (Grid::IsNameWithStartSuffix(name, &indexOfSuffix) ||
    2587           0 :           Grid::IsNameWithEndSuffix(name, &indexOfSuffix)) {
    2588             :         // Extract the name that was found earlier.
    2589           0 :         nsDependentSubstring areaName(name, 0, indexOfSuffix);
    2590             : 
    2591             :         // Lazily create the ImplicitNamedAreas.
    2592           0 :         if (!areas) {
    2593           0 :           areas = new ImplicitNamedAreas;
    2594           0 :           SetProperty(ImplicitNamedAreasProperty(), areas);
    2595             :         }
    2596             : 
    2597           0 :         mozilla::css::GridNamedArea area;
    2598           0 :         if (!areas->Get(areaName, &area)) {
    2599             :           // Not found, so prep the newly-seen area with a name and empty
    2600             :           // boundary information, which will get filled in later.
    2601           0 :           area.mName = areaName;
    2602           0 :           area.mRowStart = 0;
    2603           0 :           area.mRowEnd = 0;
    2604           0 :           area.mColumnStart = 0;
    2605           0 :           area.mColumnEnd = 0;
    2606             : 
    2607           0 :           areas->Put(areaName, area);
    2608             :         }
    2609             :       }
    2610             :     }
    2611             :   }
    2612           0 : }
    2613             : 
    2614             : void
    2615           0 : nsGridContainerFrame::InitImplicitNamedAreas(const nsStylePosition* aStyle)
    2616             : {
    2617           0 :   ImplicitNamedAreas* areas = GetImplicitNamedAreas();
    2618           0 :   if (areas) {
    2619             :     // Clear it, but reuse the hashtable itself for now.  We'll remove it
    2620             :     // below if it isn't needed anymore.
    2621           0 :     areas->Clear();
    2622             :   }
    2623           0 :   AddImplicitNamedAreas(aStyle->mGridTemplateColumns.mLineNameLists);
    2624           0 :   AddImplicitNamedAreas(aStyle->mGridTemplateRows.mLineNameLists);
    2625           0 :   if (areas && areas->Count() == 0) {
    2626           0 :     DeleteProperty(ImplicitNamedAreasProperty());
    2627             :   }
    2628           0 : }
    2629             : 
    2630             : int32_t
    2631           0 : nsGridContainerFrame::Grid::ResolveLine(const nsStyleGridLine& aLine,
    2632             :                                         int32_t aNth,
    2633             :                                         uint32_t aFromIndex,
    2634             :                                         const LineNameMap& aNameMap,
    2635             :                                         uint32_t GridNamedArea::* aAreaStart,
    2636             :                                         uint32_t GridNamedArea::* aAreaEnd,
    2637             :                                         uint32_t aExplicitGridEnd,
    2638             :                                         LineRangeSide aSide,
    2639             :                                         const nsStylePosition* aStyle)
    2640             : {
    2641           0 :   MOZ_ASSERT(!aLine.IsAuto());
    2642           0 :   int32_t line = 0;
    2643           0 :   if (aLine.mLineName.IsEmpty()) {
    2644           0 :     MOZ_ASSERT(aNth != 0, "css-grid 9.2: <integer> must not be zero.");
    2645           0 :     line = int32_t(aFromIndex) + aNth;
    2646             :   } else {
    2647           0 :     if (aNth == 0) {
    2648             :       // <integer> was omitted; treat it as 1.
    2649           0 :       aNth = 1;
    2650             :     }
    2651           0 :     bool isNameOnly = !aLine.mHasSpan && aLine.mInteger == 0;
    2652           0 :     if (isNameOnly) {
    2653           0 :       const GridNamedArea* area = FindNamedArea(aLine.mLineName, aStyle);
    2654           0 :       if (area || HasImplicitNamedArea(aLine.mLineName)) {
    2655             :         // The given name is a named area - look for explicit lines named
    2656             :         // <name>-start/-end depending on which side we're resolving.
    2657             :         // http://dev.w3.org/csswg/css-grid/#grid-placement-slot
    2658           0 :         uint32_t implicitLine = 0;
    2659           0 :         nsAutoString lineName(aLine.mLineName);
    2660           0 :         if (aSide == eLineRangeSideStart) {
    2661           0 :           lineName.AppendLiteral("-start");
    2662           0 :           implicitLine = area ? area->*aAreaStart : 0;
    2663             :         } else {
    2664           0 :           lineName.AppendLiteral("-end");
    2665           0 :           implicitLine = area ? area->*aAreaEnd : 0;
    2666             :         }
    2667           0 :         line = aNameMap.FindNamedLine(lineName, &aNth, aFromIndex,
    2668             :                                       implicitLine);
    2669             :       }
    2670             :     }
    2671             : 
    2672           0 :     if (line == 0) {
    2673             :       // If mLineName ends in -start/-end, try the prefix as a named area.
    2674           0 :       uint32_t implicitLine = 0;
    2675             :       uint32_t index;
    2676           0 :       auto GridNamedArea::* areaEdge = aAreaStart;
    2677           0 :       bool found = IsNameWithStartSuffix(aLine.mLineName, &index);
    2678           0 :       if (!found) {
    2679           0 :         found = IsNameWithEndSuffix(aLine.mLineName, &index);
    2680           0 :         areaEdge = aAreaEnd;
    2681             :       }
    2682           0 :       if (found) {
    2683             :         const GridNamedArea* area =
    2684           0 :           FindNamedArea(nsDependentSubstring(aLine.mLineName, 0, index),
    2685           0 :                         aStyle);
    2686           0 :         if (area) {
    2687           0 :           implicitLine = area->*areaEdge;
    2688             :         }
    2689             :       }
    2690           0 :       line = aNameMap.FindNamedLine(aLine.mLineName, &aNth, aFromIndex,
    2691             :                                     implicitLine);
    2692             :     }
    2693             : 
    2694           0 :     if (line == 0) {
    2695           0 :       MOZ_ASSERT(aNth != 0, "we found all N named lines but 'line' is zero!");
    2696             :       int32_t edgeLine;
    2697           0 :       if (aLine.mHasSpan) {
    2698             :         // http://dev.w3.org/csswg/css-grid/#grid-placement-span-int
    2699             :         // 'span <custom-ident> N'
    2700           0 :         edgeLine = aSide == eLineRangeSideStart ? 1 : aExplicitGridEnd;
    2701             :       } else {
    2702             :         // http://dev.w3.org/csswg/css-grid/#grid-placement-int
    2703             :         // '<custom-ident> N'
    2704           0 :         edgeLine = aNth < 0 ? 1 : aExplicitGridEnd;
    2705             :       }
    2706             :       // "If not enough lines with that name exist, all lines in the implicit
    2707             :       // grid are assumed to have that name..."
    2708           0 :       line = edgeLine + aNth;
    2709             :     }
    2710             :   }
    2711           0 :   return clamped(line, nsStyleGridLine::kMinLine, nsStyleGridLine::kMaxLine);
    2712             : }
    2713             : 
    2714             : nsGridContainerFrame::Grid::LinePair
    2715           0 : nsGridContainerFrame::Grid::ResolveLineRangeHelper(
    2716             :   const nsStyleGridLine& aStart,
    2717             :   const nsStyleGridLine& aEnd,
    2718             :   const LineNameMap& aNameMap,
    2719             :   uint32_t GridNamedArea::* aAreaStart,
    2720             :   uint32_t GridNamedArea::* aAreaEnd,
    2721             :   uint32_t aExplicitGridEnd,
    2722             :   const nsStylePosition* aStyle)
    2723             : {
    2724             :   MOZ_ASSERT(int32_t(nsGridContainerFrame::kAutoLine) > nsStyleGridLine::kMaxLine);
    2725             : 
    2726           0 :   if (aStart.mHasSpan) {
    2727           0 :     if (aEnd.mHasSpan || aEnd.IsAuto()) {
    2728             :       // http://dev.w3.org/csswg/css-grid/#grid-placement-errors
    2729           0 :       if (aStart.mLineName.IsEmpty()) {
    2730             :         // span <integer> / span *
    2731             :         // span <integer> / auto
    2732           0 :         return LinePair(kAutoLine, aStart.mInteger);
    2733             :       }
    2734             :       // span <custom-ident> / span *
    2735             :       // span <custom-ident> / auto
    2736           0 :       return LinePair(kAutoLine, 1); // XXX subgrid explicit size instead of 1?
    2737             :     }
    2738             : 
    2739           0 :     uint32_t from = aEnd.mInteger < 0 ? aExplicitGridEnd + 1: 0;
    2740           0 :     auto end = ResolveLine(aEnd, aEnd.mInteger, from, aNameMap, aAreaStart,
    2741             :                            aAreaEnd, aExplicitGridEnd, eLineRangeSideEnd,
    2742           0 :                            aStyle);
    2743           0 :     int32_t span = aStart.mInteger == 0 ? 1 : aStart.mInteger;
    2744           0 :     if (end <= 1) {
    2745             :       // The end is at or before the first explicit line, thus all lines before
    2746             :       // it match <custom-ident> since they're implicit.
    2747           0 :       int32_t start = std::max(end - span, nsStyleGridLine::kMinLine);
    2748           0 :       return LinePair(start, end);
    2749             :     }
    2750           0 :     auto start = ResolveLine(aStart, -span, end, aNameMap, aAreaStart,
    2751             :                              aAreaEnd, aExplicitGridEnd, eLineRangeSideStart,
    2752           0 :                              aStyle);
    2753           0 :     return LinePair(start, end);
    2754             :   }
    2755             : 
    2756           0 :   int32_t start = kAutoLine;
    2757           0 :   if (aStart.IsAuto()) {
    2758           0 :     if (aEnd.IsAuto()) {
    2759             :       // auto / auto
    2760           0 :       return LinePair(start, 1); // XXX subgrid explicit size instead of 1?
    2761             :     }
    2762           0 :     if (aEnd.mHasSpan) {
    2763           0 :       if (aEnd.mLineName.IsEmpty()) {
    2764             :         // auto / span <integer>
    2765           0 :         MOZ_ASSERT(aEnd.mInteger != 0);
    2766           0 :         return LinePair(start, aEnd.mInteger);
    2767             :       }
    2768             :       // http://dev.w3.org/csswg/css-grid/#grid-placement-errors
    2769             :       // auto / span <custom-ident>
    2770           0 :       return LinePair(start, 1); // XXX subgrid explicit size instead of 1?
    2771             :     }
    2772             :   } else {
    2773           0 :     uint32_t from = aStart.mInteger < 0 ? aExplicitGridEnd + 1: 0;
    2774           0 :     start = ResolveLine(aStart, aStart.mInteger, from, aNameMap,
    2775             :                         aAreaStart, aAreaEnd, aExplicitGridEnd,
    2776             :                         eLineRangeSideStart, aStyle);
    2777           0 :     if (aEnd.IsAuto()) {
    2778             :       // A "definite line / auto" should resolve the auto to 'span 1'.
    2779             :       // The error handling in ResolveLineRange will make that happen and also
    2780             :       // clamp the end line correctly if we return "start / start".
    2781           0 :       return LinePair(start, start);
    2782             :     }
    2783             :   }
    2784             : 
    2785             :   uint32_t from;
    2786           0 :   int32_t nth = aEnd.mInteger == 0 ? 1 : aEnd.mInteger;
    2787           0 :   if (aEnd.mHasSpan) {
    2788           0 :     if (MOZ_UNLIKELY(start < 0)) {
    2789           0 :       if (aEnd.mLineName.IsEmpty()) {
    2790           0 :         return LinePair(start, start + nth);
    2791             :       }
    2792           0 :       from = 0;
    2793             :     } else {
    2794           0 :       if (start >= int32_t(aExplicitGridEnd)) {
    2795             :         // The start is at or after the last explicit line, thus all lines
    2796             :         // after it match <custom-ident> since they're implicit.
    2797           0 :         return LinePair(start, std::min(start + nth, nsStyleGridLine::kMaxLine));
    2798             :       }
    2799           0 :       from = start;
    2800             :     }
    2801             :   } else {
    2802           0 :     from = aEnd.mInteger < 0 ? aExplicitGridEnd + 1: 0;
    2803             :   }
    2804           0 :   auto end = ResolveLine(aEnd, nth, from, aNameMap, aAreaStart,
    2805           0 :                          aAreaEnd, aExplicitGridEnd, eLineRangeSideEnd, aStyle);
    2806           0 :   if (start == int32_t(kAutoLine)) {
    2807             :     // auto / definite line
    2808           0 :     start = std::max(nsStyleGridLine::kMinLine, end - 1);
    2809             :   }
    2810           0 :   return LinePair(start, end);
    2811             : }
    2812             : 
    2813             : nsGridContainerFrame::LineRange
    2814           0 : nsGridContainerFrame::Grid::ResolveLineRange(
    2815             :   const nsStyleGridLine& aStart,
    2816             :   const nsStyleGridLine& aEnd,
    2817             :   const LineNameMap& aNameMap,
    2818             :   uint32_t GridNamedArea::* aAreaStart,
    2819             :   uint32_t GridNamedArea::* aAreaEnd,
    2820             :   uint32_t aExplicitGridEnd,
    2821             :   const nsStylePosition* aStyle)
    2822             : {
    2823             :   LinePair r = ResolveLineRangeHelper(aStart, aEnd, aNameMap, aAreaStart,
    2824           0 :                                       aAreaEnd, aExplicitGridEnd, aStyle);
    2825           0 :   MOZ_ASSERT(r.second != int32_t(kAutoLine));
    2826             : 
    2827           0 :   if (r.first == int32_t(kAutoLine)) {
    2828             :     // r.second is a span, clamp it to kMaxLine - 1 so that the returned
    2829             :     // range has a HypotheticalEnd <= kMaxLine.
    2830             :     // http://dev.w3.org/csswg/css-grid/#overlarge-grids
    2831           0 :     r.second = std::min(r.second, nsStyleGridLine::kMaxLine - 1);
    2832             :   } else {
    2833             :     // http://dev.w3.org/csswg/css-grid/#grid-placement-errors
    2834           0 :     if (r.first > r.second) {
    2835           0 :       Swap(r.first, r.second);
    2836           0 :     } else if (r.first == r.second) {
    2837           0 :       if (MOZ_UNLIKELY(r.first == nsStyleGridLine::kMaxLine)) {
    2838           0 :         r.first = nsStyleGridLine::kMaxLine - 1;
    2839             :       }
    2840           0 :       r.second = r.first + 1; // XXX subgrid explicit size instead of 1?
    2841             :     }
    2842             :   }
    2843           0 :   return LineRange(r.first, r.second);
    2844             : }
    2845             : 
    2846             : nsGridContainerFrame::GridArea
    2847           0 : nsGridContainerFrame::Grid::PlaceDefinite(nsIFrame* aChild,
    2848             :                                           const LineNameMap& aColLineNameMap,
    2849             :                                           const LineNameMap& aRowLineNameMap,
    2850             :                                           const nsStylePosition* aStyle)
    2851             : {
    2852           0 :   const nsStylePosition* itemStyle = aChild->StylePosition();
    2853           0 :   return GridArea(
    2854           0 :     ResolveLineRange(itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
    2855             :                      aColLineNameMap,
    2856             :                      &GridNamedArea::mColumnStart, &GridNamedArea::mColumnEnd,
    2857           0 :                      mExplicitGridColEnd, aStyle),
    2858           0 :     ResolveLineRange(itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
    2859             :                      aRowLineNameMap,
    2860             :                      &GridNamedArea::mRowStart, &GridNamedArea::mRowEnd,
    2861           0 :                      mExplicitGridRowEnd, aStyle));
    2862             : }
    2863             : 
    2864             : nsGridContainerFrame::LineRange
    2865           0 : nsGridContainerFrame::Grid::ResolveAbsPosLineRange(
    2866             :   const nsStyleGridLine& aStart,
    2867             :   const nsStyleGridLine& aEnd,
    2868             :   const LineNameMap& aNameMap,
    2869             :   uint32_t GridNamedArea::* aAreaStart,
    2870             :   uint32_t GridNamedArea::* aAreaEnd,
    2871             :   uint32_t aExplicitGridEnd,
    2872             :   int32_t aGridStart,
    2873             :   int32_t aGridEnd,
    2874             :   const nsStylePosition* aStyle)
    2875             : {
    2876           0 :   if (aStart.IsAuto()) {
    2877           0 :     if (aEnd.IsAuto()) {
    2878           0 :       return LineRange(kAutoLine, kAutoLine);
    2879             :     }
    2880           0 :     uint32_t from = aEnd.mInteger < 0 ? aExplicitGridEnd + 1: 0;
    2881             :     int32_t end =
    2882           0 :       ResolveLine(aEnd, aEnd.mInteger, from, aNameMap, aAreaStart,
    2883           0 :                   aAreaEnd, aExplicitGridEnd, eLineRangeSideEnd, aStyle);
    2884           0 :     if (aEnd.mHasSpan) {
    2885           0 :       ++end;
    2886             :     }
    2887             :     // A line outside the existing grid is treated as 'auto' for abs.pos (10.1).
    2888           0 :     end = AutoIfOutside(end, aGridStart, aGridEnd);
    2889           0 :     return LineRange(kAutoLine, end);
    2890             :   }
    2891             : 
    2892           0 :   if (aEnd.IsAuto()) {
    2893           0 :     uint32_t from = aStart.mInteger < 0 ? aExplicitGridEnd + 1: 0;
    2894             :     int32_t start =
    2895           0 :       ResolveLine(aStart, aStart.mInteger, from, aNameMap, aAreaStart,
    2896           0 :                   aAreaEnd, aExplicitGridEnd, eLineRangeSideStart, aStyle);
    2897           0 :     if (aStart.mHasSpan) {
    2898           0 :       start = std::max(aGridEnd - start, aGridStart);
    2899             :     }
    2900           0 :     start = AutoIfOutside(start, aGridStart, aGridEnd);
    2901           0 :     return LineRange(start, kAutoLine);
    2902             :   }
    2903             : 
    2904             :   LineRange r = ResolveLineRange(aStart, aEnd, aNameMap, aAreaStart,
    2905           0 :                                  aAreaEnd, aExplicitGridEnd, aStyle);
    2906           0 :   if (r.IsAuto()) {
    2907           0 :     MOZ_ASSERT(aStart.mHasSpan && aEnd.mHasSpan, "span / span is the only case "
    2908             :                "leading to IsAuto here -- we dealt with the other cases above");
    2909             :     // The second span was ignored per 9.2.1.  For abs.pos., 10.1 says that this
    2910             :     // case should result in "auto / auto" unlike normal flow grid items.
    2911           0 :     return LineRange(kAutoLine, kAutoLine);
    2912             :   }
    2913             : 
    2914           0 :   return LineRange(AutoIfOutside(r.mUntranslatedStart, aGridStart, aGridEnd),
    2915           0 :                    AutoIfOutside(r.mUntranslatedEnd, aGridStart, aGridEnd));
    2916             : }
    2917             : 
    2918             : nsGridContainerFrame::GridArea
    2919           0 : nsGridContainerFrame::Grid::PlaceAbsPos(nsIFrame* aChild,
    2920             :                                         const LineNameMap& aColLineNameMap,
    2921             :                                         const LineNameMap& aRowLineNameMap,
    2922             :                                         const nsStylePosition* aStyle)
    2923             : {
    2924           0 :   const nsStylePosition* itemStyle = aChild->StylePosition();
    2925           0 :   int32_t gridColStart = 1 - mExplicitGridOffsetCol;
    2926           0 :   int32_t gridRowStart = 1 - mExplicitGridOffsetRow;
    2927           0 :   return GridArea(
    2928           0 :     ResolveAbsPosLineRange(itemStyle->mGridColumnStart,
    2929             :                            itemStyle->mGridColumnEnd,
    2930             :                            aColLineNameMap,
    2931             :                            &GridNamedArea::mColumnStart,
    2932             :                            &GridNamedArea::mColumnEnd,
    2933           0 :                            mExplicitGridColEnd, gridColStart, mGridColEnd,
    2934           0 :                            aStyle),
    2935           0 :     ResolveAbsPosLineRange(itemStyle->mGridRowStart,
    2936             :                            itemStyle->mGridRowEnd,
    2937             :                            aRowLineNameMap,
    2938             :                            &GridNamedArea::mRowStart,
    2939             :                            &GridNamedArea::mRowEnd,
    2940           0 :                            mExplicitGridRowEnd, gridRowStart, mGridRowEnd,
    2941           0 :                            aStyle));
    2942             : }
    2943             : 
    2944             : uint32_t
    2945           0 : nsGridContainerFrame::Grid::FindAutoCol(uint32_t aStartCol, uint32_t aLockedRow,
    2946             :                                         const GridArea* aArea) const
    2947             : {
    2948           0 :   const uint32_t extent = aArea->mCols.Extent();
    2949           0 :   const uint32_t iStart = aLockedRow;
    2950           0 :   const uint32_t iEnd = iStart + aArea->mRows.Extent();
    2951           0 :   uint32_t candidate = aStartCol;
    2952           0 :   for (uint32_t i = iStart; i < iEnd; ) {
    2953           0 :     if (i >= mCellMap.mCells.Length()) {
    2954           0 :       break;
    2955             :     }
    2956           0 :     const nsTArray<CellMap::Cell>& cellsInRow = mCellMap.mCells[i];
    2957           0 :     const uint32_t len = cellsInRow.Length();
    2958           0 :     const uint32_t lastCandidate = candidate;
    2959             :     // Find the first gap in the current row that's at least 'extent' wide.
    2960             :     // ('gap' tracks how wide the current column gap is.)
    2961           0 :     for (uint32_t j = candidate, gap = 0; j < len && gap < extent; ++j) {
    2962           0 :       if (!cellsInRow[j].mIsOccupied) {
    2963           0 :         ++gap;
    2964           0 :         continue;
    2965             :       }
    2966           0 :       candidate = j + 1;
    2967           0 :       gap = 0;
    2968             :     }
    2969           0 :     if (lastCandidate < candidate && i != iStart) {
    2970             :       // Couldn't fit 'extent' tracks at 'lastCandidate' here so we must
    2971             :       // restart from the beginning with the new 'candidate'.
    2972           0 :       i = iStart;
    2973             :     } else {
    2974           0 :       ++i;
    2975             :     }
    2976             :   }
    2977           0 :   return candidate;
    2978             : }
    2979             : 
    2980             : void
    2981           0 : nsGridContainerFrame::Grid::PlaceAutoCol(uint32_t aStartCol,
    2982             :                                          GridArea* aArea) const
    2983             : {
    2984           0 :   MOZ_ASSERT(aArea->mRows.IsDefinite() && aArea->mCols.IsAuto());
    2985           0 :   uint32_t col = FindAutoCol(aStartCol, aArea->mRows.mStart, aArea);
    2986           0 :   aArea->mCols.ResolveAutoPosition(col, mExplicitGridOffsetCol);
    2987           0 :   MOZ_ASSERT(aArea->IsDefinite());
    2988           0 : }
    2989             : 
    2990             : uint32_t
    2991           0 : nsGridContainerFrame::Grid::FindAutoRow(uint32_t aLockedCol, uint32_t aStartRow,
    2992             :                                         const GridArea* aArea) const
    2993             : {
    2994           0 :   const uint32_t extent = aArea->mRows.Extent();
    2995           0 :   const uint32_t jStart = aLockedCol;
    2996           0 :   const uint32_t jEnd = jStart + aArea->mCols.Extent();
    2997           0 :   const uint32_t iEnd = mCellMap.mCells.Length();
    2998           0 :   uint32_t candidate = aStartRow;
    2999             :   // Find the first gap in the rows that's at least 'extent' tall.
    3000             :   // ('gap' tracks how tall the current row gap is.)
    3001           0 :   for (uint32_t i = candidate, gap = 0; i < iEnd && gap < extent; ++i) {
    3002           0 :     ++gap; // tentative, but we may reset it below if a column is occupied
    3003           0 :     const nsTArray<CellMap::Cell>& cellsInRow = mCellMap.mCells[i];
    3004           0 :     const uint32_t clampedJEnd = std::min<uint32_t>(jEnd, cellsInRow.Length());
    3005             :     // Check if the current row is unoccupied from jStart to jEnd.
    3006           0 :     for (uint32_t j = jStart; j < clampedJEnd; ++j) {
    3007           0 :       if (cellsInRow[j].mIsOccupied) {
    3008             :         // Couldn't fit 'extent' rows at 'candidate' here; we hit something
    3009             :         // at row 'i'.  So, try the row after 'i' as our next candidate.
    3010           0 :         candidate = i + 1;
    3011           0 :         gap = 0;
    3012           0 :         break;
    3013             :       }
    3014             :     }
    3015             :   }
    3016           0 :   return candidate;
    3017             : }
    3018             : 
    3019             : void
    3020           0 : nsGridContainerFrame::Grid::PlaceAutoRow(uint32_t aStartRow,
    3021             :                                          GridArea* aArea) const
    3022             : {
    3023           0 :   MOZ_ASSERT(aArea->mCols.IsDefinite() && aArea->mRows.IsAuto());
    3024           0 :   uint32_t row = FindAutoRow(aArea->mCols.mStart, aStartRow, aArea);
    3025           0 :   aArea->mRows.ResolveAutoPosition(row, mExplicitGridOffsetRow);
    3026           0 :   MOZ_ASSERT(aArea->IsDefinite());
    3027           0 : }
    3028             : 
    3029             : void
    3030           0 : nsGridContainerFrame::Grid::PlaceAutoAutoInRowOrder(uint32_t aStartCol,
    3031             :                                                     uint32_t aStartRow,
    3032             :                                                     GridArea* aArea) const
    3033             : {
    3034           0 :   MOZ_ASSERT(aArea->mCols.IsAuto() && aArea->mRows.IsAuto());
    3035           0 :   const uint32_t colExtent = aArea->mCols.Extent();
    3036           0 :   const uint32_t gridRowEnd = mGridRowEnd;
    3037           0 :   const uint32_t gridColEnd = mGridColEnd;
    3038           0 :   uint32_t col = aStartCol;
    3039           0 :   uint32_t row = aStartRow;
    3040           0 :   for (; row < gridRowEnd; ++row) {
    3041           0 :     col = FindAutoCol(col, row, aArea);
    3042           0 :     if (col + colExtent <= gridColEnd) {
    3043           0 :       break;
    3044             :     }
    3045           0 :     col = 0;
    3046             :   }
    3047           0 :   MOZ_ASSERT(row < gridRowEnd || col == 0,
    3048             :              "expected column 0 for placing in a new row");
    3049           0 :   aArea->mCols.ResolveAutoPosition(col, mExplicitGridOffsetCol);
    3050           0 :   aArea->mRows.ResolveAutoPosition(row, mExplicitGridOffsetRow);
    3051           0 :   MOZ_ASSERT(aArea->IsDefinite());
    3052           0 : }
    3053             : 
    3054             : void
    3055           0 : nsGridContainerFrame::Grid::PlaceAutoAutoInColOrder(uint32_t aStartCol,
    3056             :                                                     uint32_t aStartRow,
    3057             :                                                     GridArea* aArea) const
    3058             : {
    3059           0 :   MOZ_ASSERT(aArea->mCols.IsAuto() && aArea->mRows.IsAuto());
    3060           0 :   const uint32_t rowExtent = aArea->mRows.Extent();
    3061           0 :   const uint32_t gridRowEnd = mGridRowEnd;
    3062           0 :   const uint32_t gridColEnd = mGridColEnd;
    3063           0 :   uint32_t col = aStartCol;
    3064           0 :   uint32_t row = aStartRow;
    3065           0 :   for (; col < gridColEnd; ++col) {
    3066           0 :     row = FindAutoRow(col, row, aArea);
    3067           0 :     if (row + rowExtent <= gridRowEnd) {
    3068           0 :       break;
    3069             :     }
    3070           0 :     row = 0;
    3071             :   }
    3072           0 :   MOZ_ASSERT(col < gridColEnd || row == 0,
    3073             :              "expected row 0 for placing in a new column");
    3074           0 :   aArea->mCols.ResolveAutoPosition(col, mExplicitGridOffsetCol);
    3075           0 :   aArea->mRows.ResolveAutoPosition(row, mExplicitGridOffsetRow);
    3076           0 :   MOZ_ASSERT(aArea->IsDefinite());
    3077           0 : }
    3078             : 
    3079             : void
    3080           0 : nsGridContainerFrame::Grid::PlaceGridItems(GridReflowInput& aState,
    3081             :                                            const LogicalSize& aComputedMinSize,
    3082             :                                            const LogicalSize& aComputedSize,
    3083             :                                            const LogicalSize& aComputedMaxSize)
    3084             : {
    3085           0 :   mAreas = aState.mFrame->GetImplicitNamedAreas();
    3086           0 :   const nsStylePosition* const gridStyle = aState.mGridStyle;
    3087           0 :   MOZ_ASSERT(mCellMap.mCells.IsEmpty(), "unexpected entries in cell map");
    3088             : 
    3089             :   // http://dev.w3.org/csswg/css-grid/#grid-definition
    3090             :   // Initialize the end lines of the Explicit Grid (mExplicitGridCol[Row]End).
    3091             :   // This is determined by the larger of the number of rows/columns defined
    3092             :   // by 'grid-template-areas' and the 'grid-template-rows'/'-columns', plus one.
    3093             :   // Also initialize the Implicit Grid (mGridCol[Row]End) to the same values.
    3094             :   // Note that this is for a grid with a 1,1 origin.  We'll change that
    3095             :   // to a 0,0 based grid after placing definite lines.
    3096           0 :   auto areas = gridStyle->mGridTemplateAreas.get();
    3097           0 :   uint32_t numRepeatCols = aState.mColFunctions.InitRepeatTracks(
    3098             :                              gridStyle->mGridColumnGap,
    3099             :                              aComputedMinSize.ISize(aState.mWM),
    3100             :                              aComputedSize.ISize(aState.mWM),
    3101           0 :                              aComputedMaxSize.ISize(aState.mWM));
    3102           0 :   mGridColEnd = mExplicitGridColEnd =
    3103           0 :     aState.mColFunctions.ComputeExplicitGridEnd(areas ? areas->mNColumns + 1 : 1);
    3104           0 :   LineNameMap colLineNameMap(gridStyle->mGridTemplateColumns, numRepeatCols);
    3105             : 
    3106           0 :   uint32_t numRepeatRows = aState.mRowFunctions.InitRepeatTracks(
    3107             :                              gridStyle->mGridRowGap,
    3108             :                              aComputedMinSize.BSize(aState.mWM),
    3109             :                              aComputedSize.BSize(aState.mWM),
    3110           0 :                              aComputedMaxSize.BSize(aState.mWM));
    3111           0 :   mGridRowEnd = mExplicitGridRowEnd =
    3112           0 :     aState.mRowFunctions.ComputeExplicitGridEnd(areas ? areas->NRows() + 1 : 1);
    3113           0 :   LineNameMap rowLineNameMap(gridStyle->mGridTemplateRows, numRepeatRows);
    3114             : 
    3115             :   // http://dev.w3.org/csswg/css-grid/#line-placement
    3116             :   // Resolve definite positions per spec chap 9.2.
    3117           0 :   int32_t minCol = 1;
    3118           0 :   int32_t minRow = 1;
    3119           0 :   aState.mGridItems.ClearAndRetainStorage();
    3120           0 :   aState.mIter.Reset();
    3121           0 :   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
    3122           0 :     nsIFrame* child = *aState.mIter;
    3123             :     GridItemInfo* info =
    3124           0 :         aState.mGridItems.AppendElement(GridItemInfo(child,
    3125           0 :                                           PlaceDefinite(child,
    3126             :                                                         colLineNameMap,
    3127             :                                                         rowLineNameMap,
    3128           0 :                                                         gridStyle)));
    3129           0 :     MOZ_ASSERT(aState.mIter.ItemIndex() == aState.mGridItems.Length() - 1,
    3130             :                "ItemIndex() is broken");
    3131           0 :     GridArea& area = info->mArea;
    3132           0 :     if (area.mCols.IsDefinite()) {
    3133           0 :       minCol = std::min(minCol, area.mCols.mUntranslatedStart);
    3134             :     }
    3135           0 :     if (area.mRows.IsDefinite()) {
    3136           0 :       minRow = std::min(minRow, area.mRows.mUntranslatedStart);
    3137             :     }
    3138             :   }
    3139             : 
    3140             :   // Translate the whole grid so that the top-/left-most area is at 0,0.
    3141           0 :   mExplicitGridOffsetCol = 1 - minCol; // minCol/Row is always <= 1, see above
    3142           0 :   mExplicitGridOffsetRow = 1 - minRow;
    3143           0 :   aState.mColFunctions.mExplicitGridOffset = mExplicitGridOffsetCol;
    3144           0 :   aState.mRowFunctions.mExplicitGridOffset = mExplicitGridOffsetRow;
    3145           0 :   const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
    3146           0 :   const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
    3147           0 :   mGridColEnd += offsetToColZero;
    3148           0 :   mGridRowEnd += offsetToRowZero;
    3149           0 :   aState.mIter.Reset();
    3150           0 :   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
    3151           0 :     GridArea& area = aState.mGridItems[aState.mIter.ItemIndex()].mArea;
    3152           0 :     if (area.mCols.IsDefinite()) {
    3153           0 :       area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
    3154           0 :       area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
    3155             :     }
    3156           0 :     if (area.mRows.IsDefinite()) {
    3157           0 :       area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
    3158           0 :       area.mRows.mEnd = area.mRows.mUntranslatedEnd + offsetToRowZero;
    3159             :     }
    3160           0 :     if (area.IsDefinite()) {
    3161           0 :       mCellMap.Fill(area);
    3162           0 :       InflateGridFor(area);
    3163             :     }
    3164             :   }
    3165             : 
    3166             :   // http://dev.w3.org/csswg/css-grid/#auto-placement-algo
    3167             :   // Step 1, place 'auto' items that have one definite position -
    3168             :   // definite row (column) for grid-auto-flow:row (column).
    3169           0 :   auto flowStyle = gridStyle->mGridAutoFlow;
    3170           0 :   const bool isRowOrder = (flowStyle & NS_STYLE_GRID_AUTO_FLOW_ROW);
    3171           0 :   const bool isSparse = !(flowStyle & NS_STYLE_GRID_AUTO_FLOW_DENSE);
    3172             :   // We need 1 cursor per row (or column) if placement is sparse.
    3173             :   {
    3174           0 :     Maybe<nsDataHashtable<nsUint32HashKey, uint32_t>> cursors;
    3175           0 :     if (isSparse) {
    3176           0 :       cursors.emplace();
    3177             :     }
    3178             :     auto placeAutoMinorFunc = isRowOrder ? &Grid::PlaceAutoCol
    3179           0 :                                          : &Grid::PlaceAutoRow;
    3180           0 :     aState.mIter.Reset();
    3181           0 :     for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
    3182           0 :       GridArea& area = aState.mGridItems[aState.mIter.ItemIndex()].mArea;
    3183           0 :       LineRange& major = isRowOrder ? area.mRows : area.mCols;
    3184           0 :       LineRange& minor = isRowOrder ? area.mCols : area.mRows;
    3185           0 :       if (major.IsDefinite() && minor.IsAuto()) {
    3186             :         // Items with 'auto' in the minor dimension only.
    3187           0 :         uint32_t cursor = 0;
    3188           0 :         if (isSparse) {
    3189           0 :           cursors->Get(major.mStart, &cursor);
    3190             :         }
    3191           0 :         (this->*placeAutoMinorFunc)(cursor, &area);
    3192           0 :         mCellMap.Fill(area);
    3193           0 :         if (isSparse) {
    3194           0 :           cursors->Put(major.mStart, minor.mEnd);
    3195             :         }
    3196             :       }
    3197           0 :       InflateGridFor(area);  // Step 2, inflating for auto items too
    3198             :     }
    3199             :   }
    3200             : 
    3201             :   // XXX NOTE possible spec issue.
    3202             :   // XXX It's unclear if the remaining major-dimension auto and
    3203             :   // XXX auto in both dimensions should use the same cursor or not,
    3204             :   // XXX https://www.w3.org/Bugs/Public/show_bug.cgi?id=16044
    3205             :   // XXX seems to indicate it shouldn't.
    3206             :   // XXX http://dev.w3.org/csswg/css-grid/#auto-placement-cursor
    3207             :   // XXX now says it should (but didn't in earlier versions)
    3208             : 
    3209             :   // Step 3, place the remaining grid items
    3210           0 :   uint32_t cursorMajor = 0; // for 'dense' these two cursors will stay at 0,0
    3211           0 :   uint32_t cursorMinor = 0;
    3212             :   auto placeAutoMajorFunc = isRowOrder ? &Grid::PlaceAutoRow
    3213           0 :                                        : &Grid::PlaceAutoCol;
    3214           0 :   aState.mIter.Reset();
    3215           0 :   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
    3216           0 :     GridArea& area = aState.mGridItems[aState.mIter.ItemIndex()].mArea;
    3217           0 :     MOZ_ASSERT(*aState.mIter == aState.mGridItems[aState.mIter.ItemIndex()].mFrame,
    3218             :                "iterator out of sync with aState.mGridItems");
    3219           0 :     LineRange& major = isRowOrder ? area.mRows : area.mCols;
    3220           0 :     LineRange& minor = isRowOrder ? area.mCols : area.mRows;
    3221           0 :     if (major.IsAuto()) {
    3222           0 :       if (minor.IsDefinite()) {
    3223             :         // Items with 'auto' in the major dimension only.
    3224           0 :         if (isSparse) {
    3225           0 :           if (minor.mStart < cursorMinor) {
    3226           0 :             ++cursorMajor;
    3227             :           }
    3228           0 :           cursorMinor = minor.mStart;
    3229             :         }
    3230           0 :         (this->*placeAutoMajorFunc)(cursorMajor, &area);
    3231           0 :         if (isSparse) {
    3232           0 :           cursorMajor = major.mStart;
    3233             :         }
    3234             :       } else {
    3235             :         // Items with 'auto' in both dimensions.
    3236           0 :         if (isRowOrder) {
    3237           0 :           PlaceAutoAutoInRowOrder(cursorMinor, cursorMajor, &area);
    3238             :         } else {
    3239           0 :           PlaceAutoAutoInColOrder(cursorMajor, cursorMinor, &area);
    3240             :         }
    3241           0 :         if (isSparse) {
    3242           0 :           cursorMajor = major.mStart;
    3243           0 :           cursorMinor = minor.mEnd;
    3244             : #ifdef DEBUG
    3245           0 :           uint32_t gridMajorEnd = isRowOrder ? mGridRowEnd : mGridColEnd;
    3246           0 :           uint32_t gridMinorEnd = isRowOrder ? mGridColEnd : mGridRowEnd;
    3247           0 :           MOZ_ASSERT(cursorMajor <= gridMajorEnd,
    3248             :                      "we shouldn't need to place items further than 1 track "
    3249             :                      "past the current end of the grid, in major dimension");
    3250           0 :           MOZ_ASSERT(cursorMinor <= gridMinorEnd,
    3251             :                      "we shouldn't add implicit minor tracks for auto/auto");
    3252             : #endif
    3253             :         }
    3254             :       }
    3255           0 :       mCellMap.Fill(area);
    3256           0 :       InflateGridFor(area);
    3257             :     }
    3258             :   }
    3259             : 
    3260           0 :   if (aState.mFrame->IsAbsoluteContainer()) {
    3261             :     // 9.4 Absolutely-positioned Grid Items
    3262             :     // http://dev.w3.org/csswg/css-grid/#abspos-items
    3263             :     // We only resolve definite lines here; we'll align auto positions to the
    3264             :     // grid container later during reflow.
    3265           0 :     nsFrameList children(aState.mFrame->GetChildList(
    3266           0 :                            aState.mFrame->GetAbsoluteListID()));
    3267           0 :     const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
    3268           0 :     const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
    3269             :     // Untranslate the grid again temporarily while resolving abs.pos. lines.
    3270           0 :     AutoRestore<uint32_t> save1(mGridColEnd);
    3271           0 :     AutoRestore<uint32_t> save2(mGridRowEnd);
    3272           0 :     mGridColEnd -= offsetToColZero;
    3273           0 :     mGridRowEnd -= offsetToRowZero;
    3274           0 :     aState.mAbsPosItems.ClearAndRetainStorage();
    3275           0 :     size_t i = 0;
    3276           0 :     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next(), ++i) {
    3277           0 :       nsIFrame* child = e.get();
    3278             :       GridItemInfo* info =
    3279           0 :           aState.mAbsPosItems.AppendElement(GridItemInfo(child,
    3280           0 :                                               PlaceAbsPos(child,
    3281             :                                                           colLineNameMap,
    3282             :                                                           rowLineNameMap,
    3283           0 :                                                           gridStyle)));
    3284           0 :       GridArea& area = info->mArea;
    3285           0 :       if (area.mCols.mUntranslatedStart != int32_t(kAutoLine)) {
    3286           0 :         area.mCols.mStart = area.mCols.mUntranslatedStart + offsetToColZero;
    3287             :       }
    3288           0 :       if (area.mCols.mUntranslatedEnd != int32_t(kAutoLine)) {
    3289           0 :         area.mCols.mEnd = area.mCols.mUntranslatedEnd + offsetToColZero;
    3290             :       }
    3291           0 :       if (area.mRows.mUntranslatedStart != int32_t(kAutoLine)) {
    3292           0 :         area.mRows.mStart = area.mRows.mUntranslatedStart + offsetToRowZero;
    3293             :       }
    3294           0 :       if (area.mRows.mUntranslatedEnd != int32_t(kAutoLine)) {
    3295           0 :         area.mRows.mEnd = area.mRows.mUntranslatedEnd + offsetToRowZero;
    3296             :       }
    3297             :     }
    3298             :   }
    3299             : 
    3300             :   // Count empty 'auto-fit' tracks in the repeat() range.
    3301             :   // |colAdjust| will have a count for each line in the grid of how many
    3302             :   // tracks were empty between the start of the grid and that line.
    3303           0 :   Maybe<nsTArray<uint32_t>> colAdjust;
    3304           0 :   uint32_t numEmptyCols = 0;
    3305           0 :   if (aState.mColFunctions.mHasRepeatAuto &&
    3306           0 :       !gridStyle->mGridTemplateColumns.mIsAutoFill &&
    3307           0 :       aState.mColFunctions.NumRepeatTracks() > 0) {
    3308           0 :     for (uint32_t col = aState.mColFunctions.mRepeatAutoStart,
    3309           0 :            endRepeat = aState.mColFunctions.mRepeatAutoEnd,
    3310           0 :            numColLines = mGridColEnd + 1;
    3311           0 :          col < numColLines; ++col) {
    3312           0 :       if (numEmptyCols) {
    3313           0 :         (*colAdjust)[col] = numEmptyCols;
    3314             :       }
    3315           0 :       if (col < endRepeat && mCellMap.IsEmptyCol(col)) {
    3316           0 :         ++numEmptyCols;
    3317           0 :         if (colAdjust.isNothing()) {
    3318           0 :           colAdjust.emplace(numColLines);
    3319           0 :           colAdjust->SetLength(numColLines);
    3320           0 :           PodZero(colAdjust->Elements(), colAdjust->Length());
    3321             :         }
    3322             : 
    3323           0 :         uint32_t repeatIndex = col - aState.mColFunctions.mRepeatAutoStart;
    3324           0 :         MOZ_ASSERT(aState.mColFunctions.mRemovedRepeatTracks.Length() >
    3325             :                    repeatIndex);
    3326           0 :         aState.mColFunctions.mRemovedRepeatTracks[repeatIndex] = true;
    3327             :       }
    3328             :     }
    3329             :   }
    3330           0 :   Maybe<nsTArray<uint32_t>> rowAdjust;
    3331           0 :   uint32_t numEmptyRows = 0;
    3332           0 :   if (aState.mRowFunctions.mHasRepeatAuto &&
    3333           0 :       !gridStyle->mGridTemplateRows.mIsAutoFill &&
    3334           0 :       aState.mRowFunctions.NumRepeatTracks() > 0) {
    3335           0 :     for (uint32_t row = aState.mRowFunctions.mRepeatAutoStart,
    3336           0 :            endRepeat = aState.mRowFunctions.mRepeatAutoEnd,
    3337           0 :            numRowLines = mGridRowEnd + 1;
    3338           0 :          row < numRowLines; ++row) {
    3339           0 :       if (numEmptyRows) {
    3340           0 :         (*rowAdjust)[row] = numEmptyRows;
    3341             :       }
    3342           0 :       if (row < endRepeat && mCellMap.IsEmptyRow(row)) {
    3343           0 :         ++numEmptyRows;
    3344           0 :         if (rowAdjust.isNothing()) {
    3345           0 :           rowAdjust.emplace(numRowLines);
    3346           0 :           rowAdjust->SetLength(numRowLines);
    3347           0 :           PodZero(rowAdjust->Elements(), rowAdjust->Length());
    3348             :         }
    3349             : 
    3350           0 :         uint32_t repeatIndex = row - aState.mRowFunctions.mRepeatAutoStart;
    3351           0 :         MOZ_ASSERT(aState.mRowFunctions.mRemovedRepeatTracks.Length() >
    3352             :                    repeatIndex);
    3353           0 :         aState.mRowFunctions.mRemovedRepeatTracks[repeatIndex] = true;
    3354             :       }
    3355             :     }
    3356             :   }
    3357             :   // Remove the empty 'auto-fit' tracks we found above, if any.
    3358           0 :   if (numEmptyCols || numEmptyRows) {
    3359             :     // Adjust the line numbers in the grid areas.
    3360           0 :     for (auto& item : aState.mGridItems) {
    3361           0 :       GridArea& area = item.mArea;
    3362           0 :       if (numEmptyCols) {
    3363           0 :         area.mCols.AdjustForRemovedTracks(*colAdjust);
    3364             :       }
    3365           0 :       if (numEmptyRows) {
    3366           0 :         area.mRows.AdjustForRemovedTracks(*rowAdjust);
    3367             :       }
    3368             :     }
    3369           0 :     for (auto& item : aState.mAbsPosItems) {
    3370           0 :       GridArea& area = item.mArea;
    3371           0 :       if (numEmptyCols) {
    3372           0 :         area.mCols.AdjustAbsPosForRemovedTracks(*colAdjust);
    3373             :       }
    3374           0 :       if (numEmptyRows) {
    3375           0 :         area.mRows.AdjustAbsPosForRemovedTracks(*rowAdjust);
    3376             :       }
    3377             :     }
    3378             :     // Adjust the grid size.
    3379           0 :     mGridColEnd -= numEmptyCols;
    3380           0 :     mExplicitGridColEnd -= numEmptyCols;
    3381           0 :     mGridRowEnd -= numEmptyRows;
    3382           0 :     mExplicitGridRowEnd -= numEmptyRows;
    3383             :     // Adjust the track mapping to unmap the removed tracks.
    3384           0 :     auto colRepeatCount = aState.mColFunctions.NumRepeatTracks();
    3385           0 :     aState.mColFunctions.SetNumRepeatTracks(colRepeatCount - numEmptyCols);
    3386           0 :     auto rowRepeatCount = aState.mRowFunctions.NumRepeatTracks();
    3387           0 :     aState.mRowFunctions.SetNumRepeatTracks(rowRepeatCount - numEmptyRows);
    3388             :   }
    3389             : 
    3390             :   // Update the line boundaries of the implicit grid areas, if needed.
    3391           0 :   if (mAreas &&
    3392           0 :       aState.mFrame->HasAnyStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES)) {
    3393           0 :     for (auto iter = mAreas->Iter(); !iter.Done(); iter.Next()) {
    3394           0 :       auto& areaInfo = iter.Data();
    3395             : 
    3396             :       // Resolve the lines for the area. We use the name of the area as the
    3397             :       // name of the lines, knowing that the line placement algorithm will
    3398             :       // add the -start and -end suffixes as appropriate for layout.
    3399           0 :       nsStyleGridLine lineStartAndEnd;
    3400           0 :       lineStartAndEnd.mLineName = areaInfo.mName;
    3401             : 
    3402             :       LineRange columnLines = ResolveLineRange(
    3403             :         lineStartAndEnd, lineStartAndEnd,
    3404             :         colLineNameMap,
    3405             :         &GridNamedArea::mColumnStart, &GridNamedArea::mColumnEnd,
    3406           0 :         mExplicitGridColEnd, gridStyle);
    3407             : 
    3408             :       LineRange rowLines = ResolveLineRange(
    3409             :         lineStartAndEnd, lineStartAndEnd,
    3410             :         rowLineNameMap,
    3411             :         &GridNamedArea::mRowStart, &GridNamedArea::mRowEnd,
    3412           0 :         mExplicitGridRowEnd, gridStyle);
    3413             : 
    3414             :       // Put the resolved line indices back into the area structure.
    3415           0 :       areaInfo.mColumnStart = columnLines.mStart + mExplicitGridOffsetCol;
    3416           0 :       areaInfo.mColumnEnd = columnLines.mEnd + mExplicitGridOffsetCol;
    3417           0 :       areaInfo.mRowStart = rowLines.mStart + mExplicitGridOffsetRow;
    3418           0 :       areaInfo.mRowEnd = rowLines.mEnd + mExplicitGridOffsetRow;
    3419             :     }
    3420             :   }
    3421           0 : }
    3422             : 
    3423             : void
    3424           0 : nsGridContainerFrame::Tracks::Initialize(
    3425             :   const TrackSizingFunctions& aFunctions,
    3426             :   const nsStyleCoord&         aGridGap,
    3427             :   uint32_t                    aNumTracks,
    3428             :   nscoord                     aContentBoxSize)
    3429             : {
    3430           0 :   MOZ_ASSERT(aNumTracks >= aFunctions.mExplicitGridOffset +
    3431             :                              aFunctions.NumExplicitTracks());
    3432           0 :   mSizes.SetLength(aNumTracks);
    3433           0 :   PodZero(mSizes.Elements(), mSizes.Length());
    3434           0 :   for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
    3435           0 :     mStateUnion |= mSizes[i].Initialize(aContentBoxSize,
    3436             :                                         aFunctions.MinSizingFor(i),
    3437           0 :                                         aFunctions.MaxSizingFor(i));
    3438             :   }
    3439           0 :   mGridGap = ::ResolveToDefiniteSize(aGridGap, aContentBoxSize);
    3440           0 :   mContentBoxSize = aContentBoxSize;
    3441           0 : }
    3442             : 
    3443             : /**
    3444             :  * Reflow aChild in the given aAvailableSize.
    3445             :  */
    3446             : static nscoord
    3447           0 : MeasuringReflow(nsIFrame*           aChild,
    3448             :                 const ReflowInput*  aReflowInput,
    3449             :                 gfxContext*         aRC,
    3450             :                 const LogicalSize&  aAvailableSize,
    3451             :                 const LogicalSize&  aCBSize,
    3452             :                 nscoord             aIMinSizeClamp = NS_MAXSIZE,
    3453             :                 nscoord             aBMinSizeClamp = NS_MAXSIZE)
    3454             : {
    3455           0 :   nsContainerFrame* parent = aChild->GetParent();
    3456           0 :   nsPresContext* pc = aChild->PresContext();
    3457           0 :   Maybe<ReflowInput> dummyParentState;
    3458           0 :   const ReflowInput* rs = aReflowInput;
    3459           0 :   if (!aReflowInput) {
    3460           0 :     MOZ_ASSERT(!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW));
    3461           0 :     dummyParentState.emplace(pc, parent, aRC,
    3462           0 :                              LogicalSize(parent->GetWritingMode(), 0,
    3463             :                                          NS_UNCONSTRAINEDSIZE),
    3464           0 :                              ReflowInput::DUMMY_PARENT_REFLOW_STATE);
    3465           0 :     rs = dummyParentState.ptr();
    3466             :   }
    3467             : #ifdef DEBUG
    3468             :   // This will suppress various CRAZY_SIZE warnings for this reflow.
    3469           0 :   parent->SetProperty(
    3470           0 :     nsContainerFrame::DebugReflowingWithInfiniteISize(), true);
    3471             : #endif
    3472           0 :   auto wm = aChild->GetWritingMode();
    3473           0 :   uint32_t riFlags = ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE;
    3474           0 :   if (aAvailableSize.ISize(wm) == INFINITE_ISIZE_COORD) {
    3475           0 :     riFlags |= ReflowInput::COMPUTE_SIZE_SHRINK_WRAP;
    3476             :   }
    3477           0 :   if (aIMinSizeClamp != NS_MAXSIZE) {
    3478           0 :     riFlags |= ReflowInput::I_CLAMP_MARGIN_BOX_MIN_SIZE;
    3479             :   }
    3480           0 :   if (aBMinSizeClamp != NS_MAXSIZE) {
    3481           0 :     riFlags |= ReflowInput::B_CLAMP_MARGIN_BOX_MIN_SIZE;
    3482           0 :     aChild->SetProperty(nsIFrame::BClampMarginBoxMinSizeProperty(),
    3483           0 :                              aBMinSizeClamp);
    3484             :   } else {
    3485           0 :     aChild->DeleteProperty(nsIFrame::BClampMarginBoxMinSizeProperty());
    3486             :   }
    3487           0 :   ReflowInput childRI(pc, *rs, aChild, aAvailableSize, &aCBSize, riFlags);
    3488             : 
    3489             :   // Because we pass ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE, and the
    3490             :   // previous reflow of the child might not have, set the child's
    3491             :   // block-resize flag to true.
    3492             :   // FIXME (perf): It would be faster to do this only if the previous
    3493             :   // reflow of the child was not a measuring reflow, and only if the
    3494             :   // child does some of the things that are affected by
    3495             :   // ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE.
    3496           0 :   childRI.SetBResize(true);
    3497             : 
    3498           0 :   ReflowOutput childSize(childRI);
    3499           0 :   nsReflowStatus childStatus;
    3500           0 :   const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW;
    3501           0 :   parent->ReflowChild(aChild, pc, childSize, childRI, wm,
    3502           0 :                       LogicalPoint(wm), nsSize(), flags, childStatus);
    3503             :   parent->FinishReflowChild(aChild, pc, childSize, &childRI, wm,
    3504           0 :                             LogicalPoint(wm), nsSize(), flags);
    3505             : #ifdef DEBUG
    3506           0 :     parent->DeleteProperty(nsContainerFrame::DebugReflowingWithInfiniteISize());
    3507             : #endif
    3508           0 :   return childSize.BSize(wm);
    3509             : }
    3510             : 
    3511             : /**
    3512             :  * Return the [min|max]-content contribution of aChild to its parent (i.e.
    3513             :  * the child's margin-box) in aAxis.
    3514             :  */
    3515             : static nscoord
    3516           0 : ContentContribution(const GridItemInfo&       aGridItem,
    3517             :                     const GridReflowInput&    aState,
    3518             :                     gfxContext*               aRC,
    3519             :                     WritingMode               aCBWM,
    3520             :                     LogicalAxis               aAxis,
    3521             :                     const Maybe<LogicalSize>& aPercentageBasis,
    3522             :                     IntrinsicISizeType        aConstraint,
    3523             :                     nscoord                   aMinSizeClamp = NS_MAXSIZE,
    3524             :                     uint32_t                  aFlags = 0)
    3525             : {
    3526           0 :   nsIFrame* child = aGridItem.mFrame;
    3527           0 :   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
    3528           0 :   nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, child, aConstraint,
    3529             :                    aPercentageBasis,
    3530             :                    aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED |
    3531             :                             nsLayoutUtils::ADD_PERCENTS,
    3532           0 :                    aMinSizeClamp);
    3533           0 :   if (size == NS_INTRINSIC_WIDTH_UNKNOWN) {
    3534             :     // We need to reflow the child to find its BSize contribution.
    3535             :     // XXX this will give mostly correct results for now (until bug 1174569).
    3536           0 :     nscoord availISize = INFINITE_ISIZE_COORD;
    3537           0 :     nscoord availBSize = NS_UNCONSTRAINEDSIZE;
    3538           0 :     auto childWM = child->GetWritingMode();
    3539           0 :     const bool isOrthogonal = childWM.IsOrthogonalTo(aCBWM);
    3540             :     // The next two variables are MinSizeClamp values in the child's axes.
    3541           0 :     nscoord iMinSizeClamp = NS_MAXSIZE;
    3542           0 :     nscoord bMinSizeClamp = NS_MAXSIZE;
    3543           0 :     LogicalSize cbSize(childWM, 0, 0);
    3544           0 :     if (aState.mCols.mCanResolveLineRangeSize) {
    3545           0 :       nscoord sz = aState.mCols.ResolveSize(aGridItem.mArea.mCols);
    3546           0 :       if (isOrthogonal) {
    3547           0 :         availBSize = sz;
    3548           0 :         cbSize.BSize(childWM) = sz;
    3549           0 :         if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
    3550           0 :           bMinSizeClamp = sz;
    3551             :         }
    3552             :       } else {
    3553           0 :         availISize = sz;
    3554           0 :         cbSize.ISize(childWM) = sz;
    3555           0 :         if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
    3556           0 :           iMinSizeClamp = sz;
    3557             :         }
    3558             :       }
    3559             :     }
    3560           0 :     if (isOrthogonal == (aAxis == eLogicalAxisInline)) {
    3561           0 :       bMinSizeClamp = aMinSizeClamp;
    3562             :     } else {
    3563           0 :       iMinSizeClamp = aMinSizeClamp;
    3564             :     }
    3565           0 :     LogicalSize availableSize(childWM, availISize, availBSize);
    3566           0 :     size = ::MeasuringReflow(child, aState.mReflowInput, aRC, availableSize,
    3567             :                              cbSize, iMinSizeClamp, bMinSizeClamp);
    3568           0 :     nsIFrame::IntrinsicISizeOffsetData offsets = child->IntrinsicBSizeOffsets();
    3569           0 :     size += offsets.hMargin;
    3570           0 :     auto percent = offsets.hPctMargin;
    3571           0 :     if (availBSize == NS_UNCONSTRAINEDSIZE) {
    3572             :       // We always want to add in percent padding too, unless we already did so
    3573             :       // using a resolved column size above.
    3574           0 :       percent += offsets.hPctPadding;
    3575             :     }
    3576           0 :     size = nsLayoutUtils::AddPercents(size, percent);
    3577           0 :     nscoord overflow = size - aMinSizeClamp;
    3578           0 :     if (MOZ_UNLIKELY(overflow > 0)) {
    3579           0 :       nscoord contentSize = child->ContentBSize(childWM);
    3580           0 :       nscoord newContentSize = std::max(nscoord(0), contentSize - overflow);
    3581             :       // XXXmats deal with percentages better, see bug 1300369 comment 27.
    3582           0 :       size -= contentSize - newContentSize;
    3583             :     }
    3584             :   }
    3585           0 :   MOZ_ASSERT(aGridItem.mBaselineOffset[aAxis] >= 0,
    3586             :              "baseline offset should be non-negative at this point");
    3587           0 :   MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||
    3588             :              aGridItem.mBaselineOffset[aAxis] == nscoord(0),
    3589             :              "baseline offset should be zero when not baseline-aligned");
    3590           0 :   size += aGridItem.mBaselineOffset[aAxis];
    3591           0 :   return std::max(size, 0);
    3592             : }
    3593             : 
    3594           0 : struct CachedIntrinsicSizes
    3595             : {
    3596             :   Maybe<nscoord> mMinSize;
    3597             :   Maybe<nscoord> mMinContentContribution;
    3598             :   Maybe<nscoord> mMaxContentContribution;
    3599             : 
    3600             :   // The item's percentage basis for intrinsic sizing purposes.
    3601             :   Maybe<LogicalSize> mPercentageBasis;
    3602             : 
    3603             :   // "if the grid item spans only grid tracks that have a fixed max track
    3604             :   // sizing function, its automatic minimum size in that dimension is
    3605             :   // further clamped to less than or equal to the size necessary to fit its
    3606             :   // margin box within the resulting grid area (flooring at zero)"
    3607             :   // https://drafts.csswg.org/css-grid/#min-size-auto
    3608             :   // This is the clamp value to use for that:
    3609             :   nscoord mMinSizeClamp = NS_MAXSIZE;
    3610             : };
    3611             : 
    3612             : static nscoord
    3613           0 : MinContentContribution(const GridItemInfo&    aGridItem,
    3614             :                        const GridReflowInput& aState,
    3615             :                        gfxContext*            aRC,
    3616             :                        WritingMode            aCBWM,
    3617             :                        LogicalAxis            aAxis,
    3618             :                        CachedIntrinsicSizes*  aCache)
    3619             : {
    3620           0 :   if (aCache->mMinContentContribution.isSome()) {
    3621           0 :     return aCache->mMinContentContribution.value();
    3622             :   }
    3623           0 :   if (aCache->mPercentageBasis.isNothing()) {
    3624           0 :     aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem));
    3625             :   }
    3626           0 :   nscoord s = ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
    3627             :                                   aCache->mPercentageBasis,
    3628             :                                   nsLayoutUtils::MIN_ISIZE,
    3629           0 :                                   aCache->mMinSizeClamp);
    3630           0 :   aCache->mMinContentContribution.emplace(s);
    3631           0 :   return s;
    3632             : }
    3633             : 
    3634             : static nscoord
    3635           0 : MaxContentContribution(const GridItemInfo&    aGridItem,
    3636             :                        const GridReflowInput& aState,
    3637             :                        gfxContext*            aRC,
    3638             :                        WritingMode            aCBWM,
    3639             :                        LogicalAxis            aAxis,
    3640             :                        CachedIntrinsicSizes*  aCache)
    3641             : {
    3642           0 :   if (aCache->mMaxContentContribution.isSome()) {
    3643           0 :     return aCache->mMaxContentContribution.value();
    3644             :   }
    3645           0 :   if (aCache->mPercentageBasis.isNothing()) {
    3646           0 :     aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem));
    3647             :   }
    3648           0 :   nscoord s = ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
    3649             :                                   aCache->mPercentageBasis,
    3650             :                                   nsLayoutUtils::PREF_ISIZE,
    3651           0 :                                   aCache->mMinSizeClamp);
    3652           0 :   aCache->mMaxContentContribution.emplace(s);
    3653           0 :   return s;
    3654             : }
    3655             : 
    3656             : // Computes the min-size contribution for a grid item, as defined at
    3657             : // https://drafts.csswg.org/css-grid/#min-size-contributions
    3658             : static nscoord
    3659           0 : MinSize(const GridItemInfo&    aGridItem,
    3660             :         const GridReflowInput& aState,
    3661             :         gfxContext*            aRC,
    3662             :         WritingMode            aCBWM,
    3663             :         LogicalAxis            aAxis,
    3664             :         CachedIntrinsicSizes*  aCache)
    3665             : {
    3666           0 :   if (aCache->mMinSize.isSome()) {
    3667           0 :     return aCache->mMinSize.value();
    3668             :   }
    3669           0 :   nsIFrame* child = aGridItem.mFrame;
    3670           0 :   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
    3671           0 :   const nsStylePosition* stylePos = child->StylePosition();
    3672             :   const nsStyleCoord& sizeStyle =
    3673           0 :     axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight;
    3674           0 :   if (sizeStyle.GetUnit() != eStyleUnit_Auto) {
    3675             :     nscoord s =
    3676           0 :       MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache);
    3677           0 :     aCache->mMinSize.emplace(s);
    3678           0 :     return s;
    3679             :   }
    3680             : 
    3681             :   // https://drafts.csswg.org/css-grid/#min-size-auto
    3682             :   // This calculates the min-content contribution from either a definite
    3683             :   // min-width (or min-height depending on aAxis), or the "specified /
    3684             :   // transferred size" for min-width:auto if overflow == visible (as min-width:0
    3685             :   // otherwise), or NS_UNCONSTRAINEDSIZE for other min-width intrinsic values
    3686             :   // (which results in always taking the "content size" part below).
    3687           0 :   MOZ_ASSERT(aGridItem.mBaselineOffset[aAxis] >= 0,
    3688             :              "baseline offset should be non-negative at this point");
    3689           0 :   MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||
    3690             :              aGridItem.mBaselineOffset[aAxis] == nscoord(0),
    3691             :              "baseline offset should be zero when not baseline-aligned");
    3692           0 :   nscoord sz = aGridItem.mBaselineOffset[aAxis] +
    3693           0 :     nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, child,
    3694           0 :                                               nsLayoutUtils::MIN_ISIZE);
    3695             :   const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth
    3696           0 :                                                       : stylePos->mMinHeight;
    3697           0 :   auto unit = style.GetUnit();
    3698           0 :   if (unit == eStyleUnit_Enumerated ||
    3699           0 :       (unit == eStyleUnit_Auto &&
    3700           0 :        child->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) {
    3701             :     // Now calculate the "content size" part and return whichever is smaller.
    3702           0 :     MOZ_ASSERT(unit != eStyleUnit_Enumerated || sz == NS_UNCONSTRAINEDSIZE);
    3703           0 :     if (aCache->mPercentageBasis.isNothing()) {
    3704           0 :       aCache->mPercentageBasis.emplace(aState.PercentageBasisFor(aAxis, aGridItem));
    3705             :     }
    3706           0 :     sz = std::min(sz, ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
    3707             :                                           aCache->mPercentageBasis,
    3708             :                                           nsLayoutUtils::MIN_ISIZE,
    3709             :                                           aCache->mMinSizeClamp,
    3710           0 :                                           nsLayoutUtils::MIN_INTRINSIC_ISIZE));
    3711             :   }
    3712           0 :   aCache->mMinSize.emplace(sz);
    3713           0 :   return sz;
    3714             : }
    3715             : 
    3716             : void
    3717           0 : nsGridContainerFrame::Tracks::CalculateSizes(
    3718             :   GridReflowInput&            aState,
    3719             :   nsTArray<GridItemInfo>&     aGridItems,
    3720             :   const TrackSizingFunctions& aFunctions,
    3721             :   nscoord                     aContentBoxSize,
    3722             :   LineRange GridArea::*       aRange,
    3723             :   SizingConstraint            aConstraint)
    3724             : {
    3725           0 :   nscoord percentageBasis = aContentBoxSize;
    3726           0 :   if (percentageBasis == NS_UNCONSTRAINEDSIZE) {
    3727           0 :     percentageBasis = 0;
    3728             :   }
    3729           0 :   InitializeItemBaselines(aState, aGridItems);
    3730             :   ResolveIntrinsicSize(aState, aGridItems, aFunctions, aRange, percentageBasis,
    3731           0 :                        aConstraint);
    3732           0 :   if (aConstraint != SizingConstraint::eMinContent) {
    3733           0 :     nscoord freeSpace = aContentBoxSize;
    3734           0 :     if (freeSpace != NS_UNCONSTRAINEDSIZE) {
    3735           0 :       freeSpace -= SumOfGridGaps();
    3736             :     }
    3737           0 :     DistributeFreeSpace(freeSpace);
    3738           0 :     StretchFlexibleTracks(aState, aGridItems, aFunctions, freeSpace);
    3739             :   }
    3740           0 : }
    3741             : 
    3742             : bool
    3743           0 : nsGridContainerFrame::Tracks::HasIntrinsicButNoFlexSizingInRange(
    3744             :   const LineRange&      aRange,
    3745             :   TrackSize::StateBits* aState) const
    3746             : {
    3747           0 :   MOZ_ASSERT(!aRange.IsAuto(), "must have a definite range");
    3748           0 :   const uint32_t start = aRange.mStart;
    3749           0 :   const uint32_t end = aRange.mEnd;
    3750             :   const TrackSize::StateBits selector =
    3751           0 :     TrackSize::eIntrinsicMinSizing | TrackSize::eIntrinsicMaxSizing;
    3752           0 :   bool foundIntrinsic = false;
    3753           0 :   for (uint32_t i = start; i < end; ++i) {
    3754           0 :     TrackSize::StateBits state = mSizes[i].mState;
    3755           0 :     *aState |= state;
    3756           0 :     if (state & TrackSize::eFlexMaxSizing) {
    3757           0 :       return false;
    3758             :     }
    3759           0 :     if (state & selector) {
    3760           0 :       foundIntrinsic = true;
    3761             :     }
    3762             :   }
    3763           0 :   return foundIntrinsic;
    3764             : }
    3765             : 
    3766             : bool
    3767           0 : nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
    3768             :   GridReflowInput&            aState,
    3769             :   const TrackSizingFunctions& aFunctions,
    3770             :   nscoord                     aPercentageBasis,
    3771             :   SizingConstraint            aConstraint,
    3772             :   const LineRange&            aRange,
    3773             :   const GridItemInfo&         aGridItem)
    3774             : {
    3775           0 :   CachedIntrinsicSizes cache;
    3776           0 :   TrackSize& sz = mSizes[aRange.mStart];
    3777           0 :   WritingMode wm = aState.mWM;
    3778             :   // Calculate data for "Automatic Minimum Size" clamping, if needed.
    3779           0 :   bool needed = ((sz.mState & TrackSize::eIntrinsicMinSizing) ||
    3780           0 :                  aConstraint == SizingConstraint::eNoConstraint) &&
    3781           0 :                 (aGridItem.mState[mAxis] & ItemState::eApplyAutoMinSize);
    3782           0 :   if (needed && TrackSize::IsDefiniteMaxSizing(sz.mState)) {
    3783           0 :     if (sz.mState & TrackSize::eIntrinsicMinSizing) {
    3784           0 :       auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
    3785           0 :       cache.mMinSizeClamp =
    3786           0 :         nsRuleNode::ComputeCoordPercentCalc(maxCoord, aPercentageBasis);
    3787             :     }
    3788           0 :     aGridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
    3789             :   }
    3790             :   // min sizing
    3791           0 :   gfxContext* rc = &aState.mRenderingContext;
    3792           0 :   if (sz.mState & TrackSize::eAutoMinSizing) {
    3793             :     nscoord s;
    3794           0 :     if (aConstraint == SizingConstraint::eMinContent) {
    3795           0 :       s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
    3796           0 :     } else if (aConstraint == SizingConstraint::eMaxContent) {
    3797           0 :       s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
    3798             :     } else {
    3799           0 :       MOZ_ASSERT(aConstraint == SizingConstraint::eNoConstraint);
    3800           0 :       s = MinSize(aGridItem, aState, rc, wm, mAxis, &cache);
    3801             :     }
    3802           0 :     sz.mBase = std::max(sz.mBase, s);
    3803           0 :   } else if (sz.mState & TrackSize::eMinContentMinSizing) {
    3804           0 :     auto s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
    3805           0 :     sz.mBase = std::max(sz.mBase, s);
    3806           0 :   } else if (sz.mState & TrackSize::eMaxContentMinSizing) {
    3807           0 :     auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
    3808           0 :     sz.mBase = std::max(sz.mBase, s);
    3809             :   }
    3810             :   // max sizing
    3811           0 :   if (sz.mState & TrackSize::eMinContentMaxSizing) {
    3812           0 :     auto s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
    3813           0 :     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
    3814           0 :       sz.mLimit = s;
    3815             :     } else {
    3816           0 :       sz.mLimit = std::max(sz.mLimit, s);
    3817             :     }
    3818           0 :   } else if (sz.mState & (TrackSize::eAutoMaxSizing |
    3819           0 :                           TrackSize::eMaxContentMaxSizing)) {
    3820           0 :     auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
    3821           0 :     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
    3822           0 :       sz.mLimit = s;
    3823             :     } else {
    3824           0 :       sz.mLimit = std::max(sz.mLimit, s);
    3825             :     }
    3826           0 :     if (MOZ_UNLIKELY(sz.mState & TrackSize::eFitContent)) {
    3827             :       // Clamp mLimit to the fit-content() size, for §12.5.1.
    3828           0 :       auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
    3829             :       nscoord fitContentClamp =
    3830           0 :         nsRuleNode::ComputeCoordPercentCalc(maxCoord, aPercentageBasis);
    3831           0 :       sz.mLimit = std::min(sz.mLimit, fitContentClamp);
    3832             :     }
    3833             :   }
    3834           0 :   if (sz.mLimit < sz.mBase) {
    3835           0 :     sz.mLimit = sz.mBase;
    3836             :   }
    3837           0 :   return sz.mState & TrackSize::eFlexMaxSizing;
    3838             : }
    3839             : 
    3840             : void
    3841           0 : nsGridContainerFrame::Tracks::CalculateItemBaselines(
    3842             :   nsTArray<ItemBaselineData>& aBaselineItems,
    3843             :   BaselineSharingGroup aBaselineGroup)
    3844             : {
    3845           0 :   if (aBaselineItems.IsEmpty()) {
    3846           0 :     return;
    3847             :   }
    3848             : 
    3849             :   // Sort the collected items on their baseline track.
    3850           0 :   std::sort(aBaselineItems.begin(), aBaselineItems.end(),
    3851           0 :             ItemBaselineData::IsBaselineTrackLessThan);
    3852             : 
    3853           0 :   MOZ_ASSERT(mSizes.Length() > 0, "having an item implies at least one track");
    3854           0 :   const uint32_t lastTrack = mSizes.Length() - 1;
    3855           0 :   nscoord maxBaseline = 0;
    3856           0 :   nscoord maxDescent = 0;
    3857           0 :   uint32_t currentTrack = kAutoLine; // guaranteed to not match any item
    3858           0 :   uint32_t trackStartIndex = 0;
    3859           0 :   for (uint32_t i = 0, len = aBaselineItems.Length(); true ; ++i) {
    3860             :     // Find the maximum baseline and descent in the current track.
    3861           0 :     if (i != len) {
    3862           0 :       const ItemBaselineData& item = aBaselineItems[i];
    3863           0 :       if (currentTrack == item.mBaselineTrack) {
    3864           0 :         maxBaseline = std::max(maxBaseline, item.mBaseline);
    3865           0 :         maxDescent = std::max(maxDescent, item.mSize - item.mBaseline);
    3866           0 :         continue;
    3867             :       }
    3868             :     }
    3869             :     // Iterate the current track again and update the baseline offsets making
    3870             :     // all items baseline-aligned within this group in this track.
    3871           0 :     for (uint32_t j = trackStartIndex; j < i; ++j) {
    3872           0 :       const ItemBaselineData& item = aBaselineItems[j];
    3873           0 :       item.mGridItem->mBaselineOffset[mAxis] = maxBaseline - item.mBaseline;
    3874           0 :       MOZ_ASSERT(item.mGridItem->mBaselineOffset[mAxis] >= 0);
    3875             :     }
    3876           0 :     if (i != 0) {
    3877             :       // Store the size of this baseline-aligned subtree.
    3878           0 :       mSizes[currentTrack].mBaselineSubtreeSize[aBaselineGroup] =
    3879           0 :         maxBaseline + maxDescent;
    3880             :       // Record the first(last) baseline for the first(last) track.
    3881           0 :       if (currentTrack == 0 && aBaselineGroup == BaselineSharingGroup::eFirst) {
    3882           0 :         mBaseline[aBaselineGroup] = maxBaseline;
    3883             :       }
    3884           0 :       if (currentTrack == lastTrack &&
    3885             :           aBaselineGroup == BaselineSharingGroup::eLast) {
    3886           0 :         mBaseline[aBaselineGroup] = maxBaseline;
    3887             :       }
    3888             :     }
    3889           0 :     if (i == len) {
    3890           0 :       break;
    3891             :     }
    3892             :     // Initialize data for the next track with baseline-aligned items.
    3893           0 :     const ItemBaselineData& item = aBaselineItems[i];
    3894           0 :     currentTrack = item.mBaselineTrack;
    3895           0 :     trackStartIndex = i;
    3896           0 :     maxBaseline = item.mBaseline;
    3897           0 :     maxDescent = item.mSize - item.mBaseline;
    3898           0 :   }
    3899             : }
    3900             : 
    3901             : void
    3902           0 : nsGridContainerFrame::Tracks::InitializeItemBaselines(
    3903             :   GridReflowInput&        aState,
    3904             :   nsTArray<GridItemInfo>& aGridItems)
    3905             : {
    3906             : 
    3907           0 :   nsTArray<ItemBaselineData> firstBaselineItems;
    3908           0 :   nsTArray<ItemBaselineData> lastBaselineItems;
    3909           0 :   WritingMode wm = aState.mWM;
    3910           0 :   nsStyleContext* containerSC = aState.mFrame->StyleContext();
    3911           0 :   CSSOrderAwareFrameIterator& iter = aState.mIter;
    3912           0 :   iter.Reset();
    3913           0 :   for (; !iter.AtEnd(); iter.Next()) {
    3914           0 :     nsIFrame* child = *iter;
    3915           0 :     GridItemInfo& gridItem = aGridItems[iter.ItemIndex()];
    3916           0 :     uint32_t baselineTrack = kAutoLine;
    3917           0 :     auto state = ItemState(0);
    3918           0 :     auto childWM = child->GetWritingMode();
    3919           0 :     const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
    3920           0 :     const bool isInlineAxis = mAxis == eLogicalAxisInline; // i.e. columns
    3921             :     // XXX update the line below to include orthogonal grid/table boxes
    3922             :     // XXX since they have baselines in both dimensions. And flexbox with
    3923             :     // XXX reversed main/cross axis?
    3924           0 :     const bool itemHasBaselineParallelToTrack = isInlineAxis == isOrthogonal;
    3925           0 :     if (itemHasBaselineParallelToTrack) {
    3926             :       // [align|justify]-self:[last ]baseline.
    3927           0 :       auto selfAlignment = isOrthogonal ?
    3928           0 :         child->StylePosition()->UsedJustifySelf(containerSC) :
    3929           0 :         child->StylePosition()->UsedAlignSelf(containerSC);
    3930           0 :       selfAlignment &= ~NS_STYLE_ALIGN_FLAG_BITS;
    3931           0 :       if (selfAlignment == NS_STYLE_ALIGN_BASELINE) {
    3932           0 :         state |= ItemState::eFirstBaseline | ItemState::eSelfBaseline;
    3933           0 :         const GridArea& area = gridItem.mArea;
    3934           0 :         baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
    3935           0 :       } else if (selfAlignment == NS_STYLE_ALIGN_LAST_BASELINE) {
    3936           0 :         state |= ItemState::eLastBaseline | ItemState::eSelfBaseline;
    3937           0 :         const GridArea& area = gridItem.mArea;
    3938           0 :         baselineTrack = (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
    3939             :       }
    3940             : 
    3941             :       // [align|justify]-content:[last ]baseline.
    3942             :       // https://drafts.csswg.org/css-align-3/#baseline-align-content
    3943             :       // "[...] and its computed 'align-self' or 'justify-self' (whichever
    3944             :       // affects its block axis) is 'stretch' or 'self-start' ('self-end').
    3945             :       // For this purpose, the 'start', 'end', 'flex-start', and 'flex-end'
    3946             :       // values of 'align-self' are treated as either 'self-start' or
    3947             :       // 'self-end', whichever they end up equivalent to.
    3948           0 :       auto alignContent = child->StylePosition()->mAlignContent;
    3949           0 :       alignContent &= ~NS_STYLE_ALIGN_FLAG_BITS;
    3950           0 :       if (alignContent == NS_STYLE_ALIGN_BASELINE ||
    3951             :           alignContent == NS_STYLE_ALIGN_LAST_BASELINE) {
    3952           0 :         const auto selfAlignEdge = alignContent == NS_STYLE_ALIGN_BASELINE ?
    3953           0 :           NS_STYLE_ALIGN_SELF_START : NS_STYLE_ALIGN_SELF_END;
    3954           0 :         bool validCombo = selfAlignment == NS_STYLE_ALIGN_NORMAL ||
    3955           0 :                           selfAlignment == NS_STYLE_ALIGN_STRETCH ||
    3956           0 :                           selfAlignment == selfAlignEdge;
    3957           0 :         if (!validCombo) {
    3958             :           // We're doing alignment in the axis that's orthogonal to mAxis here.
    3959           0 :           LogicalAxis alignAxis = GetOrthogonalAxis(mAxis);
    3960             :           // |sameSide| is true if the container's start side in this axis is
    3961             :           // the same as the child's start side, in the child's parallel axis.
    3962           0 :           bool sameSide = wm.ParallelAxisStartsOnSameSide(alignAxis, childWM);
    3963           0 :           switch (selfAlignment) {
    3964             :             case NS_STYLE_ALIGN_LEFT:
    3965           0 :               selfAlignment = !isInlineAxis || wm.IsBidiLTR() ? NS_STYLE_ALIGN_START
    3966           0 :                                                               : NS_STYLE_ALIGN_END;
    3967           0 :               break;
    3968             :             case NS_STYLE_ALIGN_RIGHT:
    3969           0 :               selfAlignment = isInlineAxis && wm.IsBidiLTR() ? NS_STYLE_ALIGN_END
    3970           0 :                                                              : NS_STYLE_ALIGN_START;
    3971           0 :               break;
    3972             :           }
    3973           0 :           switch (selfAlignment) {
    3974             :             case NS_STYLE_ALIGN_START:
    3975             :             case NS_STYLE_ALIGN_FLEX_START:
    3976           0 :               validCombo = sameSide ==
    3977           0 :                            (alignContent == NS_STYLE_ALIGN_BASELINE);
    3978           0 :               break;
    3979             :             case NS_STYLE_ALIGN_END:
    3980             :             case NS_STYLE_ALIGN_FLEX_END:
    3981           0 :               validCombo = sameSide ==
    3982           0 :                            (alignContent == NS_STYLE_ALIGN_LAST_BASELINE);
    3983           0 :               break;
    3984             :           }
    3985             :         }
    3986           0 :         if (validCombo) {
    3987           0 :           const GridArea& area = gridItem.mArea;
    3988           0 :           if (alignContent == NS_STYLE_ALIGN_BASELINE) {
    3989           0 :             state |= ItemState::eFirstBaseline | ItemState::eContentBaseline;
    3990           0 :             baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
    3991           0 :           } else if (alignContent == NS_STYLE_ALIGN_LAST_BASELINE) {
    3992           0 :             state |= ItemState::eLastBaseline | ItemState::eContentBaseline;
    3993           0 :             baselineTrack = (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
    3994             :           }
    3995             :         }
    3996             :       }
    3997             :     }
    3998             : 
    3999           0 :     if (state & ItemState::eIsBaselineAligned) {
    4000             :       // XXX available size issue
    4001           0 :       LogicalSize avail(childWM, INFINITE_ISIZE_COORD, NS_UNCONSTRAINEDSIZE);
    4002           0 :       auto* rc = &aState.mRenderingContext;
    4003             :       // XXX figure out if we can avoid/merge this reflow with the main reflow.
    4004             :       // XXX (after bug 1174569 is sorted out)
    4005             :       //
    4006             :       // XXX How should we handle percentage padding here? (bug 1330866)
    4007             :       // XXX (see ::ContentContribution and how it deals with percentages)
    4008             :       // XXX What if the true baseline after line-breaking differs from this
    4009             :       // XXX hypothetical baseline based on an infinite inline size?
    4010             :       // XXX Maybe we should just call ::ContentContribution here instead?
    4011             :       // XXX For now we just pass a zero-sized CB:
    4012           0 :       LogicalSize cbSize(childWM, 0, 0);
    4013           0 :       ::MeasuringReflow(child, aState.mReflowInput, rc, avail, cbSize);
    4014             :       nscoord baseline;
    4015           0 :       nsGridContainerFrame* grid = do_QueryFrame(child);
    4016           0 :       if (state & ItemState::eFirstBaseline) {
    4017           0 :         if (grid) {
    4018           0 :           if (isOrthogonal == isInlineAxis) {
    4019           0 :             grid->GetBBaseline(BaselineSharingGroup::eFirst, &baseline);
    4020             :           } else {
    4021           0 :             grid->GetIBaseline(BaselineSharingGroup::eFirst, &baseline);
    4022             :           }
    4023             :         }
    4024           0 :         if (grid ||
    4025           0 :             nsLayoutUtils::GetFirstLineBaseline(wm, child, &baseline)) {
    4026           0 :           NS_ASSERTION(baseline != NS_INTRINSIC_WIDTH_UNKNOWN,
    4027             :                        "about to use an unknown baseline");
    4028           0 :           auto frameSize = isInlineAxis ? child->ISize(wm) : child->BSize(wm);
    4029           0 :           auto m = child->GetLogicalUsedMargin(wm);
    4030           0 :           baseline += isInlineAxis ? m.IStart(wm) : m.BStart(wm);
    4031           0 :           auto alignSize = frameSize + (isInlineAxis ? m.IStartEnd(wm)
    4032           0 :                                                      : m.BStartEnd(wm));
    4033           0 :           firstBaselineItems.AppendElement(ItemBaselineData(
    4034           0 :             { baselineTrack, baseline, alignSize, &gridItem }));
    4035             :         } else {
    4036           0 :           state &= ~ItemState::eAllBaselineBits;
    4037             :         }
    4038             :       } else {
    4039           0 :         if (grid) {
    4040           0 :           if (isOrthogonal == isInlineAxis) {
    4041           0 :             grid->GetBBaseline(BaselineSharingGroup::eLast, &baseline);
    4042             :           } else {
    4043           0 :             grid->GetIBaseline(BaselineSharingGroup::eLast, &baseline);
    4044             :           }
    4045             :         }
    4046           0 :         if (grid ||
    4047           0 :             nsLayoutUtils::GetLastLineBaseline(wm, child, &baseline)) {
    4048           0 :           NS_ASSERTION(baseline != NS_INTRINSIC_WIDTH_UNKNOWN,
    4049             :                        "about to use an unknown baseline");
    4050           0 :           auto frameSize = isInlineAxis ? child->ISize(wm) : child->BSize(wm);
    4051           0 :           auto m = child->GetLogicalUsedMargin(wm);
    4052           0 :           if (!grid) {
    4053             :             // Convert to distance from border-box end.
    4054           0 :             baseline = frameSize - baseline;
    4055             :           }
    4056           0 :           auto descent = baseline + (isInlineAxis ? m.IEnd(wm) : m.BEnd(wm));
    4057           0 :           auto alignSize = frameSize + (isInlineAxis ? m.IStartEnd(wm)
    4058           0 :                                                      : m.BStartEnd(wm));
    4059           0 :           lastBaselineItems.AppendElement(ItemBaselineData(
    4060           0 :             { baselineTrack, descent, alignSize, &gridItem }));
    4061             :         } else {
    4062           0 :           state &= ~ItemState::eAllBaselineBits;
    4063             :         }
    4064             :       }
    4065             :     }
    4066           0 :     MOZ_ASSERT((state &
    4067             :                 (ItemState::eFirstBaseline | ItemState::eLastBaseline)) !=
    4068             :                (ItemState::eFirstBaseline | ItemState::eLastBaseline),
    4069             :                "first/last baseline bits are mutually exclusive");
    4070           0 :     MOZ_ASSERT((state &
    4071             :                 (ItemState::eSelfBaseline | ItemState::eContentBaseline)) !=
    4072             :                (ItemState::eSelfBaseline | ItemState::eContentBaseline),
    4073             :                "*-self and *-content baseline bits are mutually exclusive");
    4074           0 :     MOZ_ASSERT(!(state &
    4075             :                  (ItemState::eFirstBaseline | ItemState::eLastBaseline)) ==
    4076             :                !(state &
    4077             :                  (ItemState::eSelfBaseline | ItemState::eContentBaseline)),
    4078             :                "first/last bit requires self/content bit and vice versa");
    4079           0 :     gridItem.mState[mAxis] = state;
    4080           0 :     gridItem.mBaselineOffset[mAxis] = nscoord(0);
    4081             :   }
    4082             : 
    4083           0 :   if (firstBaselineItems.IsEmpty() && lastBaselineItems.IsEmpty()) {
    4084           0 :     return;
    4085             :   }
    4086             : 
    4087             :   // TODO: CSS Align spec issue - how to align a baseline subtree in a track?
    4088             :   // https://lists.w3.org/Archives/Public/www-style/2016May/0141.html
    4089           0 :   mBaselineSubtreeAlign[BaselineSharingGroup::eFirst] = NS_STYLE_ALIGN_START;
    4090           0 :   mBaselineSubtreeAlign[BaselineSharingGroup::eLast] = NS_STYLE_ALIGN_END;
    4091             : 
    4092           0 :   CalculateItemBaselines(firstBaselineItems, BaselineSharingGroup::eFirst);
    4093           0 :   CalculateItemBaselines(lastBaselineItems, BaselineSharingGroup::eLast);
    4094             : }
    4095             : 
    4096             : void
    4097           0 : nsGridContainerFrame::Tracks::AlignBaselineSubtree(
    4098             :   const GridItemInfo& aGridItem) const
    4099             : {
    4100           0 :   auto state = aGridItem.mState[mAxis];
    4101           0 :   if (!(state & ItemState::eIsBaselineAligned)) {
    4102           0 :     return;
    4103             :   }
    4104           0 :   const GridArea& area = aGridItem.mArea;
    4105             :   int32_t baselineTrack;
    4106           0 :   const bool isFirstBaseline = state & ItemState::eFirstBaseline;
    4107           0 :   if (isFirstBaseline) {
    4108           0 :     baselineTrack = mAxis == eLogicalAxisBlock ? area.mRows.mStart
    4109           0 :                                                : area.mCols.mStart;
    4110             :   } else {
    4111           0 :     baselineTrack = (mAxis == eLogicalAxisBlock ? area.mRows.mEnd
    4112           0 :                                                 : area.mCols.mEnd) - 1;
    4113             :   }
    4114           0 :   const TrackSize& sz = mSizes[baselineTrack];
    4115           0 :   auto baselineGroup = isFirstBaseline ? BaselineSharingGroup::eFirst
    4116           0 :                                        : BaselineSharingGroup::eLast;
    4117           0 :   nscoord delta = sz.mBase - sz.mBaselineSubtreeSize[baselineGroup];
    4118           0 :   const auto subtreeAlign = mBaselineSubtreeAlign[baselineGroup];
    4119           0 :   switch (subtreeAlign) {
    4120             :     case NS_STYLE_ALIGN_START:
    4121           0 :       if (state & ItemState::eLastBaseline) {
    4122           0 :         aGridItem.mBaselineOffset[mAxis] += delta;
    4123             :       }
    4124           0 :       break;
    4125             :     case NS_STYLE_ALIGN_END:
    4126           0 :       if (isFirstBaseline) {
    4127           0 :         aGridItem.mBaselineOffset[mAxis] += delta;
    4128             :       }
    4129           0 :       break;
    4130             :     case NS_STYLE_ALIGN_CENTER:
    4131           0 :       aGridItem.mBaselineOffset[mAxis] += delta / 2;
    4132           0 :       break;
    4133             :     default:
    4134           0 :       MOZ_ASSERT_UNREACHABLE("unexpected baseline subtree alignment");
    4135             :   }
    4136             : }
    4137             : 
    4138             : void
    4139           0 : nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
    4140             :   GridReflowInput&            aState,
    4141             :   nsTArray<GridItemInfo>&     aGridItems,
    4142             :   const TrackSizingFunctions& aFunctions,
    4143             :   LineRange GridArea::*       aRange,
    4144             :   nscoord                     aPercentageBasis,
    4145             :   SizingConstraint            aConstraint)
    4146             : {
    4147             :   // Some data we collect on each item for Step 2 of the algorithm below.
    4148             :   struct Step2ItemData
    4149             :   {
    4150             :     uint32_t mSpan;
    4151             :     TrackSize::StateBits mState;
    4152             :     LineRange mLineRange;
    4153             :     nscoord mMinSize;
    4154             :     nscoord mMinContentContribution;
    4155             :     nscoord mMaxContentContribution;
    4156             :     nsIFrame* mFrame;
    4157           0 :     static bool IsSpanLessThan(const Step2ItemData& a, const Step2ItemData& b)
    4158             :     {
    4159           0 :       return a.mSpan < b.mSpan;
    4160             :     }
    4161             :   };
    4162             : 
    4163             :   // Resolve Intrinsic Track Sizes
    4164             :   // http://dev.w3.org/csswg/css-grid/#algo-content
    4165             :   // We're also setting eIsFlexing on the item state here to speed up
    4166             :   // FindUsedFlexFraction later.
    4167           0 :   AutoTArray<TrackSize::StateBits, 16> stateBitsPerSpan;
    4168           0 :   nsTArray<Step2ItemData> step2Items;
    4169           0 :   CSSOrderAwareFrameIterator& iter = aState.mIter;
    4170           0 :   gfxContext* rc = &aState.mRenderingContext;
    4171           0 :   WritingMode wm = aState.mWM;
    4172           0 :   uint32_t maxSpan = 0; // max span of the step2Items items
    4173             :   // Setup track selector for step 2.2:
    4174             :   const auto contentBasedMinSelector =
    4175           0 :     aConstraint == SizingConstraint::eMinContent ?
    4176           0 :     TrackSize::eIntrinsicMinSizing : TrackSize::eMinOrMaxContentMinSizing;
    4177             :   // Setup track selector for step 2.3:
    4178             :   const auto maxContentMinSelector =
    4179           0 :     aConstraint == SizingConstraint::eMaxContent ?
    4180           0 :     (TrackSize::eMaxContentMinSizing | TrackSize::eAutoMinSizing) :
    4181           0 :     TrackSize::eMaxContentMinSizing;
    4182           0 :   iter.Reset();
    4183           0 :   for (; !iter.AtEnd(); iter.Next()) {
    4184           0 :     auto& gridItem = aGridItems[iter.ItemIndex()];
    4185             : 
    4186             :     // Check if we need to apply "Automatic Minimum Size" and cache it.
    4187           0 :     MOZ_ASSERT(!(gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize),
    4188             :                "Why is eApplyAutoMinSize set already?");
    4189           0 :     if (gridItem.ShouldApplyAutoMinSize(wm, mAxis, aPercentageBasis)) {
    4190           0 :       gridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize;
    4191             :     }
    4192             : 
    4193           0 :     const GridArea& area = gridItem.mArea;
    4194           0 :     const LineRange& lineRange = area.*aRange;
    4195           0 :     uint32_t span = lineRange.Extent();
    4196           0 :     if (span == 1) {
    4197             :       // Step 1. Size tracks to fit non-spanning items.
    4198           0 :       if (ResolveIntrinsicSizeStep1(aState, aFunctions, aPercentageBasis,
    4199             :                                     aConstraint, lineRange, gridItem)) {
    4200           0 :         gridItem.mState[mAxis] |= ItemState::eIsFlexing;
    4201             :       }
    4202             :     } else {
    4203           0 :       TrackSize::StateBits state = TrackSize::StateBits(0);
    4204           0 :       if (HasIntrinsicButNoFlexSizingInRange(lineRange, &state)) {
    4205             :         // Collect data for Step 2.
    4206           0 :         maxSpan = std::max(maxSpan, span);
    4207           0 :         if (span >= stateBitsPerSpan.Length()) {
    4208           0 :           uint32_t len = 2 * span;
    4209           0 :           stateBitsPerSpan.SetCapacity(len);
    4210           0 :           for (uint32_t i = stateBitsPerSpan.Length(); i < len; ++i) {
    4211           0 :             stateBitsPerSpan.AppendElement(TrackSize::StateBits(0));
    4212             :           }
    4213             :         }
    4214           0 :         stateBitsPerSpan[span] |= state;
    4215           0 :         CachedIntrinsicSizes cache;
    4216             :         // Calculate data for "Automatic Minimum Size" clamping, if needed.
    4217           0 :         bool needed = ((state & TrackSize::eIntrinsicMinSizing) ||
    4218           0 :                        aConstraint == SizingConstraint::eNoConstraint) &&
    4219           0 :                       (gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize);
    4220           0 :         if (needed && TrackSize::IsDefiniteMaxSizing(state)) {
    4221           0 :           nscoord minSizeClamp = 0;
    4222           0 :           for (auto i = lineRange.mStart, end = lineRange.mEnd; i < end; ++i) {
    4223           0 :             auto maxCoord = aFunctions.MaxSizingFor(i);
    4224           0 :             minSizeClamp +=
    4225           0 :               nsRuleNode::ComputeCoordPercentCalc(maxCoord, aPercentageBasis);
    4226             :           }
    4227           0 :           minSizeClamp += mGridGap * (span - 1);
    4228           0 :           cache.mMinSizeClamp = minSizeClamp;
    4229           0 :           gridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
    4230             :         }
    4231             :         // Collect the various grid item size contributions we need.
    4232           0 :         nscoord minSize = 0;
    4233           0 :         if (state & (TrackSize::eIntrinsicMinSizing |   // for 2.1
    4234             :                      TrackSize::eIntrinsicMaxSizing)) { // for 2.5
    4235           0 :           minSize = MinSize(gridItem, aState, rc, wm, mAxis, &cache);
    4236             :         }
    4237           0 :         nscoord minContent = 0;
    4238           0 :         if (state & contentBasedMinSelector) { // for 2.2
    4239           0 :           minContent = MinContentContribution(gridItem, aState,
    4240           0 :                                               rc, wm, mAxis, &cache);
    4241             :         }
    4242           0 :         nscoord maxContent = 0;
    4243           0 :         if (state & (maxContentMinSelector |                   // for 2.3
    4244           0 :                      TrackSize::eAutoOrMaxContentMaxSizing)) { // for 2.6
    4245           0 :           maxContent = MaxContentContribution(gridItem, aState,
    4246           0 :                                               rc, wm, mAxis, &cache);
    4247             :         }
    4248             :         step2Items.AppendElement(
    4249           0 :           Step2ItemData({span, state, lineRange, minSize,
    4250           0 :                          minContent, maxContent, *iter}));
    4251             :       } else {
    4252           0 :         if (state & TrackSize::eFlexMaxSizing) {
    4253           0 :           gridItem.mState[mAxis] |= ItemState::eIsFlexing;
    4254           0 :         } else if (aConstraint == SizingConstraint::eNoConstraint &&
    4255           0 :                    TrackSize::IsDefiniteMaxSizing(state) &&
    4256           0 :                    (gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize)) {
    4257           0 :           gridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
    4258             :         }
    4259             :       }
    4260             :     }
    4261           0 :     MOZ_ASSERT(!(gridItem.mState[mAxis] & ItemState::eClampMarginBoxMinSize) ||
    4262             :                (gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize),
    4263             :                "clamping only applies to Automatic Minimum Size");
    4264             :   }
    4265             : 
    4266             :   // Step 2.
    4267           0 :   if (maxSpan) {
    4268             :     // Sort the collected items on span length, shortest first.
    4269           0 :     std::stable_sort(step2Items.begin(), step2Items.end(),
    4270           0 :                      Step2ItemData::IsSpanLessThan);
    4271             : 
    4272           0 :     nsTArray<uint32_t> tracks(maxSpan);
    4273           0 :     nsTArray<TrackSize> plan(mSizes.Length());
    4274           0 :     plan.SetLength(mSizes.Length());
    4275           0 :     for (uint32_t i = 0, len = step2Items.Length(); i < len; ) {
    4276             :       // Start / end index for items of the same span length:
    4277           0 :       const uint32_t spanGroupStartIndex = i;
    4278           0 :       uint32_t spanGroupEndIndex = len;
    4279           0 :       const uint32_t span = step2Items[i].mSpan;
    4280           0 :       for (++i; i < len; ++i) {
    4281           0 :         if (step2Items[i].mSpan != span) {
    4282           0 :           spanGroupEndIndex = i;
    4283           0 :           break;
    4284             :         }
    4285             :       }
    4286             : 
    4287           0 :       bool updatedBase = false; // Did we update any mBase in step 2.1 - 2.3?
    4288           0 :       TrackSize::StateBits selector(TrackSize::eIntrinsicMinSizing);
    4289           0 :       if (stateBitsPerSpan[span] & selector) {
    4290             :         // Step 2.1 MinSize to intrinsic min-sizing.
    4291           0 :         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
    4292           0 :           Step2ItemData& item = step2Items[i];
    4293           0 :           if (!(item.mState & selector)) {
    4294           0 :             continue;
    4295             :           }
    4296           0 :           nscoord space = item.mMinSize;
    4297           0 :           if (space <= 0) {
    4298           0 :             continue;
    4299             :           }
    4300           0 :           tracks.ClearAndRetainStorage();
    4301           0 :           space = CollectGrowable(space, mSizes, item.mLineRange, selector,
    4302           0 :                                   tracks);
    4303           0 :           if (space > 0) {
    4304           0 :             DistributeToTrackBases(space, plan, tracks, selector);
    4305           0 :             updatedBase = true;
    4306             :           }
    4307             :         }
    4308             :       }
    4309             : 
    4310           0 :       selector = contentBasedMinSelector;
    4311           0 :       if (stateBitsPerSpan[span] & selector) {
    4312             :         // Step 2.2 MinContentContribution to min-/max-content (and 'auto' when
    4313             :         // sizing under a min-content constraint) min-sizing.
    4314           0 :         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
    4315           0 :           Step2ItemData& item = step2Items[i];
    4316           0 :           if (!(item.mState & selector)) {
    4317           0 :             continue;
    4318             :           }
    4319           0 :           nscoord space = item.mMinContentContribution;
    4320           0 :           if (space <= 0) {
    4321           0 :             continue;
    4322             :           }
    4323           0 :           tracks.ClearAndRetainStorage();
    4324           0 :           space = CollectGrowable(space, mSizes, item.mLineRange, selector,
    4325           0 :                                   tracks);
    4326           0 :           if (space > 0) {
    4327           0 :             DistributeToTrackBases(space, plan, tracks, selector);
    4328           0 :             updatedBase = true;
    4329             :           }
    4330             :         }
    4331             :       }
    4332             : 
    4333           0 :       selector = maxContentMinSelector;
    4334           0 :       if (stateBitsPerSpan[span] & selector) {
    4335             :         // Step 2.3 MaxContentContribution to max-content (and 'auto' when
    4336             :         // sizing under a max-content constraint) min-sizing.
    4337           0 :         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
    4338           0 :           Step2ItemData& item = step2Items[i];
    4339           0 :           if (!(item.mState & selector)) {
    4340           0 :             continue;
    4341             :           }
    4342           0 :           nscoord space = item.mMaxContentContribution;
    4343           0 :           if (space <= 0) {
    4344           0 :             continue;
    4345             :           }
    4346           0 :           tracks.ClearAndRetainStorage();
    4347           0 :           space = CollectGrowable(space, mSizes, item.mLineRange, selector,
    4348           0 :                                   tracks);
    4349           0 :           if (space > 0) {
    4350           0 :             DistributeToTrackBases(space, plan, tracks, selector);
    4351           0 :             updatedBase = true;
    4352             :           }
    4353             :         }
    4354             :       }
    4355             : 
    4356           0 :       if (updatedBase) {
    4357             :         // Step 2.4
    4358           0 :         for (TrackSize& sz : mSizes) {
    4359           0 :           if (sz.mBase > sz.mLimit) {
    4360           0 :             sz.mLimit = sz.mBase;
    4361             :           }
    4362             :         }
    4363             :       }
    4364           0 :       if (stateBitsPerSpan[span] & TrackSize::eIntrinsicMaxSizing) {
    4365           0 :         plan = mSizes;
    4366           0 :         for (TrackSize& sz : plan) {
    4367           0 :           if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
    4368             :             // use mBase as the planned limit
    4369             :           } else {
    4370           0 :             sz.mBase = sz.mLimit;
    4371             :           }
    4372             :         }
    4373             : 
    4374             :         // Step 2.5 MinSize to intrinsic max-sizing.
    4375           0 :         for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
    4376           0 :           Step2ItemData& item = step2Items[i];
    4377           0 :           if (!(item.mState & TrackSize::eIntrinsicMaxSizing)) {
    4378           0 :             continue;
    4379             :           }
    4380           0 :           nscoord space = item.mMinSize;
    4381           0 :           if (space <= 0) {
    4382           0 :             continue;
    4383             :           }
    4384           0 :           tracks.ClearAndRetainStorage();
    4385           0 :           space = CollectGrowable(space, plan, item.mLineRange,
    4386             :                                   TrackSize::eIntrinsicMaxSizing,
    4387           0 :                                   tracks);
    4388           0 :           if (space > 0) {
    4389             :             DistributeToTrackLimits(space, plan, tracks, aFunctions,
    4390           0 :                                     aPercentageBasis);
    4391             :           }
    4392             :         }
    4393           0 :         for (size_t j = 0, len = mSizes.Length(); j < len; ++j) {
    4394           0 :           TrackSize& sz = plan[j];
    4395           0 :           sz.mState &= ~(TrackSize::eFrozen | TrackSize::eSkipGrowUnlimited);
    4396           0 :           if (sz.mLimit != NS_UNCONSTRAINEDSIZE) {
    4397           0 :             sz.mLimit = sz.mBase;  // collect the results from 2.5
    4398             :           }
    4399             :         }
    4400             : 
    4401           0 :         if (stateBitsPerSpan[span] & TrackSize::eAutoOrMaxContentMaxSizing) {
    4402             :           // Step 2.6 MaxContentContribution to max-content max-sizing.
    4403           0 :           for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
    4404           0 :             Step2ItemData& item = step2Items[i];
    4405           0 :             if (!(item.mState & TrackSize::eAutoOrMaxContentMaxSizing)) {
    4406           0 :               continue;
    4407             :             }
    4408           0 :             nscoord space = item.mMaxContentContribution;
    4409           0 :             if (space <= 0) {
    4410           0 :               continue;
    4411             :             }
    4412           0 :             tracks.ClearAndRetainStorage();
    4413           0 :             space = CollectGrowable(space, plan, item.mLineRange,
    4414             :                                     TrackSize::eAutoOrMaxContentMaxSizing,
    4415           0 :                                     tracks);
    4416           0 :             if (space > 0) {
    4417             :               DistributeToTrackLimits(space, plan, tracks, aFunctions,
    4418           0 :                                       aPercentageBasis);
    4419             :             }
    4420             :           }
    4421             :         }
    4422             :       }
    4423             :     }
    4424             :   }
    4425             : 
    4426             :   // Step 3.
    4427           0 :   for (TrackSize& sz : mSizes) {
    4428           0 :     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
    4429           0 :       sz.mLimit = sz.mBase;
    4430             :     }
    4431             :   }
    4432           0 : }
    4433             : 
    4434             : float
    4435           0 : nsGridContainerFrame::Tracks::FindFrUnitSize(
    4436             :   const LineRange&            aRange,
    4437             :   const nsTArray<uint32_t>&   aFlexTracks,
    4438             :   const TrackSizingFunctions& aFunctions,
    4439             :   nscoord                     aSpaceToFill) const
    4440             : {
    4441           0 :   MOZ_ASSERT(aSpaceToFill > 0 && !aFlexTracks.IsEmpty());
    4442           0 :   float flexFactorSum = 0.0f;
    4443           0 :   nscoord leftOverSpace = aSpaceToFill;
    4444           0 :   for (uint32_t i = aRange.mStart, end = aRange.mEnd; i < end; ++i) {
    4445           0 :     const TrackSize& sz = mSizes[i];
    4446           0 :     if (sz.mState & TrackSize::eFlexMaxSizing) {
    4447           0 :       flexFactorSum += aFunctions.MaxSizingFor(i).GetFlexFractionValue();
    4448             :     } else {
    4449           0 :       leftOverSpace -= sz.mBase;
    4450           0 :       if (leftOverSpace <= 0) {
    4451           0 :         return 0.0f;
    4452             :       }
    4453             :     }
    4454             :   }
    4455             :   bool restart;
    4456             :   float hypotheticalFrSize;
    4457           0 :   nsTArray<uint32_t> flexTracks(aFlexTracks);
    4458           0 :   uint32_t numFlexTracks = flexTracks.Length();
    4459           0 :   do {
    4460           0 :     restart = false;
    4461           0 :     hypotheticalFrSize = leftOverSpace / std::max(flexFactorSum, 1.0f);
    4462           0 :     for (uint32_t i = 0, len = flexTracks.Length(); i < len; ++i) {
    4463           0 :       uint32_t track = flexTracks[i];
    4464           0 :       if (track == kAutoLine) {
    4465           0 :         continue; // Track marked as inflexible in a prev. iter of this loop.
    4466             :       }
    4467           0 :       float flexFactor = aFunctions.MaxSizingFor(track).GetFlexFractionValue();
    4468           0 :       const nscoord base = mSizes[track].mBase;
    4469           0 :       if (flexFactor * hypotheticalFrSize < base) {
    4470             :         // 12.7.1.4: Treat this track as inflexible.
    4471           0 :         flexTracks[i] = kAutoLine;
    4472           0 :         flexFactorSum -= flexFactor;
    4473           0 :         leftOverSpace -= base;
    4474           0 :         --numFlexTracks;
    4475           0 :         if (numFlexTracks == 0 || leftOverSpace <= 0) {
    4476           0 :           return 0.0f;
    4477             :         }
    4478           0 :         restart = true;
    4479             :         // break; XXX (bug 1176621 comment 16) measure which is more common
    4480             :       }
    4481             :     }
    4482             :   } while (restart);
    4483           0 :   return hypotheticalFrSize;
    4484             : }
    4485             : 
    4486             : float
    4487           0 : nsGridContainerFrame::Tracks::FindUsedFlexFraction(
    4488             :   GridReflowInput&            aState,
    4489             :   nsTArray<GridItemInfo>&     aGridItems,
    4490             :   const nsTArray<uint32_t>&   aFlexTracks,
    4491             :   const TrackSizingFunctions& aFunctions,
    4492             :   nscoord                     aAvailableSize) const
    4493             : {
    4494           0 :   if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
    4495             :     // Use all of the grid tracks and a 'space to fill' of the available space.
    4496           0 :     const TranslatedLineRange range(0, mSizes.Length());
    4497           0 :     return FindFrUnitSize(range, aFlexTracks, aFunctions, aAvailableSize);
    4498             :   }
    4499             : 
    4500             :   // The used flex fraction is the maximum of:
    4501             :   // ... each flexible track's base size divided by its flex factor (which is
    4502             :   // floored at 1).
    4503           0 :   float fr = 0.0f;
    4504           0 :   for (uint32_t track : aFlexTracks) {
    4505           0 :     float flexFactor = aFunctions.MaxSizingFor(track).GetFlexFractionValue();
    4506             :     float possiblyDividedBaseSize = (flexFactor > 1.0f)
    4507           0 :       ? mSizes[track].mBase / flexFactor
    4508           0 :       : mSizes[track].mBase;
    4509           0 :     fr = std::max(fr, possiblyDividedBaseSize);
    4510             :   }
    4511           0 :   WritingMode wm = aState.mWM;
    4512           0 :   gfxContext* rc = &aState.mRenderingContext;
    4513           0 :   CSSOrderAwareFrameIterator& iter = aState.mIter;
    4514           0 :   iter.Reset();
    4515             :   // ... the result of 'finding the size of an fr' for each item that spans
    4516             :   // a flex track with its max-content contribution as 'space to fill'
    4517           0 :   for (; !iter.AtEnd(); iter.Next()) {
    4518           0 :     const GridItemInfo& item = aGridItems[iter.ItemIndex()];
    4519           0 :     if (item.mState[mAxis] & ItemState::eIsFlexing) {
    4520             :       // XXX optimize: bug 1194446
    4521           0 :       auto pb = Some(aState.PercentageBasisFor(mAxis, item));
    4522           0 :       nscoord spaceToFill = ContentContribution(item, aState, rc, wm, mAxis, pb,
    4523           0 :                                                 nsLayoutUtils::PREF_ISIZE);
    4524           0 :       if (spaceToFill <= 0) {
    4525           0 :         continue;
    4526             :       }
    4527             :       // ... and all its spanned tracks as input.
    4528             :       const LineRange& range =
    4529           0 :         mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
    4530           0 :       nsTArray<uint32_t> itemFlexTracks;
    4531           0 :       for (uint32_t i = range.mStart, end = range.mEnd; i < end; ++i) {
    4532           0 :         if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
    4533           0 :           itemFlexTracks.AppendElement(i);
    4534             :         }
    4535             :       }
    4536             :       float itemFr =
    4537           0 :         FindFrUnitSize(range, itemFlexTracks, aFunctions, spaceToFill);
    4538           0 :       fr = std::max(fr, itemFr);
    4539             :     }
    4540             :   }
    4541           0 :   return fr;
    4542             : }
    4543             : 
    4544             : void
    4545           0 : nsGridContainerFrame::Tracks::StretchFlexibleTracks(
    4546             :   GridReflowInput&            aState,
    4547             :   nsTArray<GridItemInfo>&     aGridItems,
    4548             :   const TrackSizingFunctions& aFunctions,
    4549             :   nscoord                     aAvailableSize)
    4550             : {
    4551           0 :   if (aAvailableSize <= 0) {
    4552           0 :     return;
    4553             :   }
    4554           0 :   nsTArray<uint32_t> flexTracks(mSizes.Length());
    4555           0 :   for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
    4556           0 :     if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
    4557           0 :       flexTracks.AppendElement(i);
    4558             :     }
    4559             :   }
    4560           0 :   if (flexTracks.IsEmpty()) {
    4561           0 :     return;
    4562             :   }
    4563           0 :   nscoord minSize = 0;
    4564           0 :   nscoord maxSize = NS_UNCONSTRAINEDSIZE;
    4565           0 :   if (aState.mReflowInput) {
    4566           0 :     auto* ri = aState.mReflowInput;
    4567           0 :     minSize = mAxis == eLogicalAxisBlock ? ri->ComputedMinBSize()
    4568             :                                          : ri->ComputedMinISize();
    4569           0 :     maxSize = mAxis == eLogicalAxisBlock ? ri->ComputedMaxBSize()
    4570             :                                          : ri->ComputedMaxISize();
    4571             :   }
    4572           0 :   Maybe<nsTArray<TrackSize>> origSizes;
    4573           0 :   bool applyMinMax = (minSize != 0 || maxSize != NS_UNCONSTRAINEDSIZE) &&
    4574           0 :                      aAvailableSize == NS_UNCONSTRAINEDSIZE;
    4575             :   // We iterate twice at most.  The 2nd time if the grid size changed after
    4576             :   // applying a min/max-size (can only occur if aAvailableSize is indefinite).
    4577             :   while (true) {
    4578             :     float fr = FindUsedFlexFraction(aState, aGridItems, flexTracks,
    4579           0 :                                     aFunctions, aAvailableSize);
    4580           0 :     if (fr != 0.0f) {
    4581           0 :       for (uint32_t i : flexTracks) {
    4582           0 :         float flexFactor = aFunctions.MaxSizingFor(i).GetFlexFractionValue();
    4583           0 :         nscoord flexLength = NSToCoordRound(flexFactor * fr);
    4584           0 :         nscoord& base = mSizes[i].mBase;
    4585           0 :         if (flexLength > base) {
    4586           0 :           if (applyMinMax && origSizes.isNothing()) {
    4587           0 :             origSizes.emplace(mSizes);
    4588             :           }
    4589           0 :           base = flexLength;
    4590             :         }
    4591             :       }
    4592             :     }
    4593           0 :     if (applyMinMax) {
    4594           0 :       applyMinMax = false;
    4595             :       // https://drafts.csswg.org/css-grid/#algo-flex-tracks
    4596             :       // "If using this flex fraction would cause the grid to be smaller than
    4597             :       // the grid container’s min-width/height (or larger than the grid
    4598             :       // container’s max-width/height), then redo this step, treating the free
    4599             :       // space as definite [...]"
    4600           0 :       nscoord newSize = 0;
    4601           0 :       for (auto& sz : mSizes) {
    4602           0 :         newSize += sz.mBase;
    4603             :       }
    4604           0 :       const auto sumOfGridGaps = SumOfGridGaps();
    4605           0 :       newSize += sumOfGridGaps;
    4606           0 :       if (newSize > maxSize) {
    4607           0 :         aAvailableSize = maxSize;
    4608           0 :       } else if (newSize < minSize) {
    4609           0 :         aAvailableSize = minSize;
    4610             :       }
    4611           0 :       if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
    4612           0 :         aAvailableSize = std::max(0, aAvailableSize - sumOfGridGaps);
    4613             :         // Restart with the original track sizes and definite aAvailableSize.
    4614           0 :         if (origSizes.isSome()) {
    4615           0 :           mSizes = Move(*origSizes);
    4616           0 :           origSizes.reset();
    4617             :         } // else, no mSizes[].mBase were changed above so it's still correct
    4618           0 :         if (aAvailableSize == 0) {
    4619           0 :           break; // zero available size wouldn't change any sizes though...
    4620             :         }
    4621           0 :         continue;
    4622             :       }
    4623             :     }
    4624           0 :     break;
    4625           0 :   }
    4626             : }
    4627             : 
    4628             : void
    4629           0 : nsGridContainerFrame::Tracks::AlignJustifyContent(
    4630             :   const nsStylePosition* aStyle,
    4631             :   WritingMode            aWM,
    4632             :   const LogicalSize&     aContainerSize)
    4633             : {
    4634           0 :   if (mSizes.IsEmpty()) {
    4635           0 :     return;
    4636             :   }
    4637             : 
    4638           0 :   const bool isAlign = mAxis == eLogicalAxisBlock;
    4639           0 :   auto valueAndFallback = isAlign ? aStyle->mAlignContent :
    4640           0 :                                     aStyle->mJustifyContent;
    4641             :   bool overflowSafe;
    4642           0 :   auto alignment = ::GetAlignJustifyValue(valueAndFallback, aWM, isAlign,
    4643           0 :                                           &overflowSafe);
    4644           0 :   if (alignment == NS_STYLE_ALIGN_NORMAL) {
    4645           0 :     MOZ_ASSERT(valueAndFallback == NS_STYLE_ALIGN_NORMAL,
    4646             :                "*-content:normal cannot be specified with explicit fallback");
    4647           0 :     alignment = NS_STYLE_ALIGN_STRETCH;
    4648           0 :     valueAndFallback = alignment; // we may need a fallback for 'stretch' below
    4649             :   }
    4650             : 
    4651             :   // Compute the free space and count auto-sized tracks.
    4652           0 :   size_t numAutoTracks = 0;
    4653             :   nscoord space;
    4654           0 :   if (alignment != NS_STYLE_ALIGN_START) {
    4655           0 :     nscoord trackSizeSum = 0;
    4656           0 :     for (const TrackSize& sz : mSizes) {
    4657           0 :       trackSizeSum += sz.mBase;
    4658           0 :       if (sz.mState & TrackSize::eAutoMaxSizing) {
    4659           0 :         ++numAutoTracks;
    4660             :       }
    4661             :     }
    4662           0 :     nscoord cbSize = isAlign ? aContainerSize.BSize(aWM)
    4663           0 :                              : aContainerSize.ISize(aWM);
    4664           0 :     space = cbSize - trackSizeSum - SumOfGridGaps();
    4665             :     // Use the fallback value instead when applicable.
    4666           0 :     if (space < 0 ||
    4667           0 :         (alignment == NS_STYLE_ALIGN_SPACE_BETWEEN && mSizes.Length() == 1)) {
    4668           0 :       auto fallback = ::GetAlignJustifyFallbackIfAny(valueAndFallback, aWM,
    4669           0 :                                                      isAlign, &overflowSafe);
    4670           0 :       if (fallback) {
    4671           0 :         alignment = fallback;
    4672             :       }
    4673             :     }
    4674           0 :     if (space == 0 || (space < 0 && overflowSafe)) {
    4675             :       // XXX check that this makes sense also for [last ]baseline (bug 1151204).
    4676           0 :       alignment = NS_STYLE_ALIGN_START;
    4677             :     }
    4678             :   }
    4679             : 
    4680             :   // Optimize the cases where we just need to set each track's position.
    4681           0 :   nscoord pos = 0;
    4682           0 :   bool distribute = true;
    4683           0 :   switch (alignment) {
    4684             :     case NS_STYLE_ALIGN_BASELINE:
    4685             :     case NS_STYLE_ALIGN_LAST_BASELINE:
    4686           0 :       NS_WARNING("NYI: 'first/last baseline' (bug 1151204)"); // XXX
    4687             :       MOZ_FALLTHROUGH;
    4688             :     case NS_STYLE_ALIGN_START:
    4689           0 :       distribute = false;
    4690           0 :       break;
    4691             :     case NS_STYLE_ALIGN_END:
    4692           0 :       pos = space;
    4693           0 :       distribute = false;
    4694           0 :       break;
    4695             :     case NS_STYLE_ALIGN_CENTER:
    4696           0 :       pos = space / 2;
    4697           0 :       distribute = false;
    4698           0 :       break;
    4699             :     case NS_STYLE_ALIGN_STRETCH:
    4700           0 :       distribute = numAutoTracks != 0;
    4701           0 :       break;
    4702             :   }
    4703           0 :   if (!distribute) {
    4704           0 :     for (TrackSize& sz : mSizes) {
    4705           0 :       sz.mPosition = pos;
    4706           0 :       pos += sz.mBase + mGridGap;
    4707             :     }
    4708           0 :     return;
    4709             :   }
    4710             : 
    4711             :   // Distribute free space to/between tracks and set their position.
    4712           0 :   MOZ_ASSERT(space > 0, "should've handled that on the fallback path above");
    4713             :   nscoord between, roundingError;
    4714           0 :   switch (alignment) {
    4715             :     case NS_STYLE_ALIGN_STRETCH: {
    4716           0 :       MOZ_ASSERT(numAutoTracks > 0, "we handled numAutoTracks == 0 above");
    4717             :       nscoord spacePerTrack;
    4718           0 :       roundingError = NSCoordDivRem(space, numAutoTracks, &spacePerTrack);
    4719           0 :       for (TrackSize& sz : mSizes) {
    4720           0 :         sz.mPosition = pos;
    4721           0 :         if (!(sz.mState & TrackSize::eAutoMaxSizing)) {
    4722           0 :           pos += sz.mBase + mGridGap;
    4723           0 :           continue;
    4724             :         }
    4725           0 :         nscoord stretch = spacePerTrack;
    4726           0 :         if (roundingError) {
    4727           0 :           roundingError -= 1;
    4728           0 :           stretch += 1;
    4729             :         }
    4730           0 :         nscoord newBase = sz.mBase + stretch;
    4731           0 :         sz.mBase = newBase;
    4732           0 :         pos += newBase + mGridGap;
    4733             :       }
    4734           0 :       MOZ_ASSERT(!roundingError, "we didn't distribute all rounding error?");
    4735           0 :       return;
    4736             :     }
    4737             :     case NS_STYLE_ALIGN_SPACE_BETWEEN:
    4738           0 :       MOZ_ASSERT(mSizes.Length() > 1, "should've used a fallback above");
    4739           0 :       roundingError = NSCoordDivRem(space, mSizes.Length() - 1, &between);
    4740           0 :       break;
    4741             :     case NS_STYLE_ALIGN_SPACE_AROUND:
    4742           0 :       roundingError = NSCoordDivRem(space, mSizes.Length(), &between);
    4743           0 :       pos = between / 2;
    4744           0 :       break;
    4745             :     case NS_STYLE_ALIGN_SPACE_EVENLY:
    4746           0 :       roundingError = NSCoordDivRem(space, mSizes.Length() + 1, &between);
    4747           0 :       pos = between;
    4748           0 :       break;
    4749             :     default:
    4750           0 :       MOZ_ASSERT_UNREACHABLE("unknown align-/justify-content value");
    4751             :       between = 0; // just to avoid a compiler warning
    4752             :       roundingError = 0; // just to avoid a compiler warning
    4753             :   }
    4754           0 :   between += mGridGap;
    4755           0 :   for (TrackSize& sz : mSizes) {
    4756           0 :     sz.mPosition = pos;
    4757           0 :     nscoord spacing = between;
    4758           0 :     if (roundingError) {
    4759           0 :       roundingError -= 1;
    4760           0 :       spacing += 1;
    4761             :     }
    4762           0 :     pos += sz.mBase + spacing;
    4763             :   }
    4764           0 :   MOZ_ASSERT(!roundingError, "we didn't distribute all rounding error?");
    4765             : }
    4766             : 
    4767             : nscoord
    4768           0 : nsGridContainerFrame::Tracks::BackComputedIntrinsicSize(
    4769             :   const TrackSizingFunctions& aFunctions,
    4770             :   const nsStyleCoord& aGridGap) const
    4771             : {
    4772             :   // Sum up the current sizes (where percentage tracks were treated as 'auto')
    4773             :   // in 'size'.
    4774           0 :   nscoord size = 0;
    4775           0 :   for (size_t i = 0, len = mSizes.Length(); i < len; ++i) {
    4776           0 :     size += mSizes[i].mBase;
    4777             :   }
    4778             : 
    4779             :   // Add grid-gap contributions to 'size' and calculate a 'percent' sum.
    4780           0 :   float percent = 0.0f;
    4781           0 :   size_t numTracks = mSizes.Length();
    4782           0 :   if (numTracks > 1) {
    4783           0 :     const size_t gridGapCount = numTracks - 1;
    4784             :     nscoord gridGapLength;
    4785             :     float gridGapPercent;
    4786           0 :     if (::GetPercentSizeParts(aGridGap, &gridGapLength, &gridGapPercent)) {
    4787           0 :       percent = gridGapCount * gridGapPercent;
    4788             :     } else {
    4789           0 :       gridGapLength = aGridGap.ToLength();
    4790             :     }
    4791           0 :     size += gridGapCount * gridGapLength;
    4792             :   }
    4793             : 
    4794           0 :   return std::max(0, nsLayoutUtils::AddPercents(size, percent));
    4795             : }
    4796             : 
    4797             : void
    4798           0 : nsGridContainerFrame::LineRange::ToPositionAndLength(
    4799             :   const nsTArray<TrackSize>& aTrackSizes, nscoord* aPos, nscoord* aLength) const
    4800             : {
    4801           0 :   MOZ_ASSERT(mStart != kAutoLine && mEnd != kAutoLine,
    4802             :              "expected a definite LineRange");
    4803           0 :   MOZ_ASSERT(mStart < mEnd);
    4804           0 :   nscoord startPos = aTrackSizes[mStart].mPosition;
    4805           0 :   const TrackSize& sz = aTrackSizes[mEnd - 1];
    4806           0 :   *aPos = startPos;
    4807           0 :   *aLength = (sz.mPosition + sz.mBase) - startPos;
    4808           0 : }
    4809             : 
    4810             : nscoord
    4811           0 : nsGridContainerFrame::LineRange::ToLength(
    4812             :   const nsTArray<TrackSize>& aTrackSizes) const
    4813             : {
    4814           0 :   MOZ_ASSERT(mStart != kAutoLine && mEnd != kAutoLine,
    4815             :              "expected a definite LineRange");
    4816           0 :   MOZ_ASSERT(mStart < mEnd);
    4817           0 :   nscoord startPos = aTrackSizes[mStart].mPosition;
    4818           0 :   const TrackSize& sz = aTrackSizes[mEnd - 1];
    4819           0 :   return (sz.mPosition + sz.mBase) - startPos;
    4820             : }
    4821             : 
    4822             : void
    4823           0 : nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos(
    4824             :   const Tracks& aTracks, nscoord aGridOrigin,
    4825             :   nscoord* aPos, nscoord* aLength) const
    4826             : {
    4827             :   // kAutoLine for abspos children contributes the corresponding edge
    4828             :   // of the grid container's padding-box.
    4829           0 :   if (mEnd == kAutoLine) {
    4830           0 :     if (mStart == kAutoLine) {
    4831             :       // done
    4832             :     } else {
    4833           0 :       const nscoord endPos = *aPos + *aLength;
    4834           0 :       auto side = mStart == aTracks.mSizes.Length() ? GridLineSide::eBeforeGridGap
    4835           0 :                                                     : GridLineSide::eAfterGridGap;
    4836           0 :       nscoord startPos = aTracks.GridLineEdge(mStart, side);
    4837           0 :       *aPos = aGridOrigin + startPos;
    4838           0 :       *aLength = std::max(endPos - *aPos, 0);
    4839             :     }
    4840             :   } else {
    4841           0 :     if (mStart == kAutoLine) {
    4842           0 :       auto side = mEnd == 0 ? GridLineSide::eAfterGridGap
    4843           0 :                             : GridLineSide::eBeforeGridGap;
    4844           0 :       nscoord endPos = aTracks.GridLineEdge(mEnd, side);
    4845           0 :       *aLength = std::max(aGridOrigin + endPos, 0);
    4846             :     } else {
    4847             :       nscoord pos;
    4848           0 :       ToPositionAndLength(aTracks.mSizes, &pos, aLength);
    4849           0 :       *aPos = aGridOrigin + pos;
    4850             :     }
    4851             :   }
    4852           0 : }
    4853             : 
    4854             : LogicalSize
    4855           0 : nsGridContainerFrame::GridReflowInput::PercentageBasisFor(
    4856             :   LogicalAxis aAxis,
    4857             :   const GridItemInfo& aGridItem) const
    4858             : {
    4859           0 :   auto wm = aGridItem.mFrame->GetWritingMode();
    4860           0 :   if (aAxis == eLogicalAxisInline) {
    4861           0 :     return LogicalSize(wm, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    4862             :   }
    4863             :   // Note: for now, we only resolve transferred percentages to row sizing.
    4864             :   // We may need to adjust these assertions once we implement bug 1300366.
    4865           0 :   MOZ_ASSERT(mCols.mCanResolveLineRangeSize);
    4866           0 :   MOZ_ASSERT(!mRows.mCanResolveLineRangeSize);
    4867           0 :   nscoord colSize = aGridItem.mArea.mCols.ToLength(mCols.mSizes);
    4868           0 :   nscoord rowSize = NS_UNCONSTRAINEDSIZE;
    4869           0 :   return !wm.IsOrthogonalTo(mWM) ?
    4870           0 :     LogicalSize(wm, colSize, rowSize) : LogicalSize(wm, rowSize, colSize);
    4871             : }
    4872             : 
    4873             : LogicalRect
    4874           0 : nsGridContainerFrame::GridReflowInput::ContainingBlockFor(const GridArea& aArea) const
    4875             : {
    4876             :   nscoord i, b, iSize, bSize;
    4877           0 :   MOZ_ASSERT(aArea.mCols.Extent() > 0, "grid items cover at least one track");
    4878           0 :   MOZ_ASSERT(aArea.mRows.Extent() > 0, "grid items cover at least one track");
    4879           0 :   aArea.mCols.ToPositionAndLength(mCols.mSizes, &i, &iSize);
    4880           0 :   aArea.mRows.ToPositionAndLength(mRows.mSizes, &b, &bSize);
    4881           0 :   return LogicalRect(mWM, i, b, iSize, bSize);
    4882             : }
    4883             : 
    4884             : LogicalRect
    4885           0 : nsGridContainerFrame::GridReflowInput::ContainingBlockForAbsPos(
    4886             :   const GridArea&     aArea,
    4887             :   const LogicalPoint& aGridOrigin,
    4888             :   const LogicalRect&  aGridCB) const
    4889             : {
    4890           0 :   nscoord i = aGridCB.IStart(mWM);
    4891           0 :   nscoord b = aGridCB.BStart(mWM);
    4892           0 :   nscoord iSize = aGridCB.ISize(mWM);
    4893           0 :   nscoord bSize = aGridCB.BSize(mWM);
    4894           0 :   aArea.mCols.ToPositionAndLengthForAbsPos(mCols, aGridOrigin.I(mWM),
    4895           0 :                                            &i, &iSize);
    4896           0 :   aArea.mRows.ToPositionAndLengthForAbsPos(mRows, aGridOrigin.B(mWM),
    4897           0 :                                            &b, &bSize);
    4898           0 :   return LogicalRect(mWM, i, b, iSize, bSize);
    4899             : }
    4900             : 
    4901             : /**
    4902             :  * Return a Fragmentainer object if we have a fragmentainer frame in our
    4903             :  * ancestor chain of containing block (CB) reflow states.  We'll only
    4904             :  * continue traversing the ancestor chain as long as the CBs have
    4905             :  * the same writing-mode and have overflow:visible.
    4906             :  */
    4907             : Maybe<nsGridContainerFrame::Fragmentainer>
    4908           0 : nsGridContainerFrame::GetNearestFragmentainer(const GridReflowInput& aState) const
    4909             : {
    4910           0 :   Maybe<nsGridContainerFrame::Fragmentainer> data;
    4911           0 :   const ReflowInput* gridRI = aState.mReflowInput;
    4912           0 :   if (gridRI->AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
    4913           0 :     return data;
    4914             :   }
    4915           0 :   WritingMode wm = aState.mWM;
    4916           0 :   const ReflowInput* cbRI = gridRI->mCBReflowInput;
    4917           0 :   for ( ; cbRI; cbRI = cbRI->mCBReflowInput) {
    4918           0 :     nsIScrollableFrame* sf = do_QueryFrame(cbRI->mFrame);
    4919           0 :     if (sf) {
    4920           0 :       break;
    4921             :     }
    4922           0 :     if (wm.IsOrthogonalTo(cbRI->GetWritingMode())) {
    4923           0 :       break;
    4924             :     }
    4925           0 :     LayoutFrameType frameType = cbRI->mFrame->Type();
    4926           0 :     if ((frameType == LayoutFrameType::Canvas &&
    4927           0 :          PresContext()->IsPaginated()) ||
    4928             :         frameType == LayoutFrameType::ColumnSet) {
    4929           0 :       data.emplace();
    4930           0 :       data->mIsTopOfPage = gridRI->mFlags.mIsTopOfPage;
    4931           0 :       data->mToFragmentainerEnd = aState.mFragBStart +
    4932           0 :         gridRI->AvailableBSize() - aState.mBorderPadding.BStart(wm);
    4933           0 :       const auto numRows = aState.mRows.mSizes.Length();
    4934           0 :       data->mCanBreakAtStart =
    4935           0 :         numRows > 0 && aState.mRows.mSizes[0].mPosition > 0;
    4936           0 :       nscoord bSize = gridRI->ComputedBSize();
    4937           0 :       data->mIsAutoBSize = bSize == NS_AUTOHEIGHT;
    4938           0 :       if (data->mIsAutoBSize) {
    4939           0 :         bSize = gridRI->ComputedMinBSize();
    4940             :       } else {
    4941           0 :         bSize = NS_CSS_MINMAX(bSize,
    4942             :                               gridRI->ComputedMinBSize(),
    4943           0 :                               gridRI->ComputedMaxBSize());
    4944             :       }
    4945             :       nscoord gridEnd =
    4946           0 :         aState.mRows.GridLineEdge(numRows, GridLineSide::eBeforeGridGap);
    4947           0 :       data->mCanBreakAtEnd = bSize > gridEnd &&
    4948           0 :                              bSize > aState.mFragBStart;
    4949           0 :       break;
    4950             :     }
    4951             :   }
    4952           0 :   return data;
    4953             : }
    4954             : 
    4955             : void
    4956           0 : nsGridContainerFrame::ReflowInFlowChild(nsIFrame*              aChild,
    4957             :                                         const GridItemInfo*    aGridItemInfo,
    4958             :                                         nsSize                 aContainerSize,
    4959             :                                         const Maybe<nscoord>&  aStretchBSize,
    4960             :                                         const Fragmentainer*   aFragmentainer,
    4961             :                                         const GridReflowInput& aState,
    4962             :                                         const LogicalRect&     aContentArea,
    4963             :                                         ReflowOutput&   aDesiredSize,
    4964             :                                         nsReflowStatus&        aStatus)
    4965             : {
    4966           0 :   nsPresContext* pc = PresContext();
    4967           0 :   nsStyleContext* containerSC = StyleContext();
    4968           0 :   WritingMode wm = aState.mReflowInput->GetWritingMode();
    4969           0 :   LogicalMargin pad(aState.mReflowInput->ComputedLogicalPadding());
    4970           0 :   const LogicalPoint padStart(wm, pad.IStart(wm), pad.BStart(wm));
    4971           0 :   const bool isGridItem = !!aGridItemInfo;
    4972           0 :   MOZ_ASSERT(isGridItem == !aChild->IsPlaceholderFrame());
    4973           0 :   LogicalRect cb(wm);
    4974           0 :   WritingMode childWM = aChild->GetWritingMode();
    4975           0 :   bool isConstrainedBSize = false;
    4976             :   nscoord toFragmentainerEnd;
    4977             :   // The part of the child's grid area that's in previous container fragments.
    4978           0 :   nscoord consumedGridAreaBSize = 0;
    4979           0 :   const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
    4980           0 :   if (MOZ_LIKELY(isGridItem)) {
    4981           0 :     MOZ_ASSERT(aGridItemInfo->mFrame == aChild);
    4982           0 :     const GridArea& area = aGridItemInfo->mArea;
    4983           0 :     MOZ_ASSERT(area.IsDefinite());
    4984           0 :     cb = aState.ContainingBlockFor(area);
    4985           0 :     isConstrainedBSize = aFragmentainer && !wm.IsOrthogonalTo(childWM);
    4986           0 :     if (isConstrainedBSize) {
    4987             :       // |gridAreaBOffset| is the offset of the child's grid area in this
    4988             :       // container fragment (if negative, that distance is the child CB size
    4989             :       // consumed in previous container fragments).  Note that cb.BStart
    4990             :       // (initially) and aState.mFragBStart are in "global" grid coordinates
    4991             :       // (like all track positions).
    4992           0 :       nscoord gridAreaBOffset = cb.BStart(wm) - aState.mFragBStart;
    4993           0 :       consumedGridAreaBSize = std::max(0, -gridAreaBOffset);
    4994           0 :       cb.BStart(wm) = std::max(0, gridAreaBOffset);
    4995           0 :       toFragmentainerEnd = aFragmentainer->mToFragmentainerEnd -
    4996           0 :         aState.mFragBStart - cb.BStart(wm);
    4997           0 :       toFragmentainerEnd = std::max(toFragmentainerEnd, 0);
    4998             :     }
    4999           0 :     cb += aContentArea.Origin(wm);
    5000           0 :     aState.mRows.AlignBaselineSubtree(*aGridItemInfo);
    5001           0 :     aState.mCols.AlignBaselineSubtree(*aGridItemInfo);
    5002             :     // Setup [align|justify]-content:[last ]baseline related frame properties.
    5003             :     // These are added to the padding in SizeComputationInput::InitOffsets.
    5004             :     // (a negative value signals the value is for 'last baseline' and should be
    5005             :     //  added to the (logical) end padding)
    5006             :     typedef const FramePropertyDescriptor<SmallValueHolder<nscoord>>* Prop;
    5007             :     auto SetProp = [aGridItemInfo, aChild] (LogicalAxis aGridAxis,
    5008           0 :                                             Prop aProp) {
    5009           0 :       auto state = aGridItemInfo->mState[aGridAxis];
    5010           0 :       auto baselineAdjust = (state & ItemState::eContentBaseline) ?
    5011           0 :              aGridItemInfo->mBaselineOffset[aGridAxis] : nscoord(0);
    5012           0 :       if (baselineAdjust < nscoord(0)) {
    5013             :         // This happens when the subtree overflows its track.
    5014             :         // XXX spec issue? it's unclear how to handle this.
    5015           0 :         baselineAdjust = nscoord(0);
    5016           0 :       } else if (baselineAdjust > nscoord(0) &&
    5017           0 :                  (state & ItemState::eLastBaseline)) {
    5018           0 :         baselineAdjust = -baselineAdjust;
    5019             :       }
    5020           0 :       if (baselineAdjust != nscoord(0)) {
    5021           0 :         aChild->SetProperty(aProp, baselineAdjust);
    5022             :       } else {
    5023           0 :         aChild->DeleteProperty(aProp);
    5024             :       }
    5025           0 :     };
    5026           0 :     SetProp(eLogicalAxisBlock, isOrthogonal ? IBaselinePadProperty() :
    5027           0 :                                               BBaselinePadProperty());
    5028           0 :     SetProp(eLogicalAxisInline, isOrthogonal ? BBaselinePadProperty() :
    5029           0 :                                                IBaselinePadProperty());
    5030             :   } else {
    5031             :     // By convention, for frames that perform CSS Box Alignment, we position
    5032             :     // placeholder children at the start corner of their alignment container,
    5033             :     // and in this case that's usually the grid's padding box.
    5034             :     // ("Usually" - the exception is when the grid *also* forms the
    5035             :     // abs.pos. containing block. In that case, the alignment container isn't
    5036             :     // the padding box -- it's some grid area instead.  But that case doesn't
    5037             :     // require any special handling here, because we handle it later using a
    5038             :     // special flag (STATIC_POS_IS_CB_ORIGIN) which will make us ignore the
    5039             :     // placeholder's position entirely.)
    5040           0 :     cb = aContentArea - padStart;
    5041           0 :     aChild->AddStateBits(PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN);
    5042             :   }
    5043             : 
    5044           0 :   LogicalSize reflowSize(cb.Size(wm));
    5045           0 :   if (isConstrainedBSize) {
    5046           0 :     reflowSize.BSize(wm) = toFragmentainerEnd;
    5047             :   }
    5048           0 :   LogicalSize childCBSize = reflowSize.ConvertTo(childWM, wm);
    5049             : 
    5050             :   // Setup the ClampMarginBoxMinSize reflow flags and property, if needed.
    5051           0 :   uint32_t flags = 0;
    5052           0 :   if (aGridItemInfo) {
    5053           0 :     auto childIAxis = isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline;
    5054           0 :     if (aGridItemInfo->mState[childIAxis] & ItemState::eClampMarginBoxMinSize) {
    5055           0 :       flags |= ReflowInput::I_CLAMP_MARGIN_BOX_MIN_SIZE;
    5056             :     }
    5057           0 :     auto childBAxis = GetOrthogonalAxis(childIAxis);
    5058           0 :     if (aGridItemInfo->mState[childBAxis] & ItemState::eClampMarginBoxMinSize) {
    5059           0 :       flags |= ReflowInput::B_CLAMP_MARGIN_BOX_MIN_SIZE;
    5060           0 :       aChild->SetProperty(BClampMarginBoxMinSizeProperty(),
    5061           0 :                           childCBSize.BSize(childWM));
    5062             :     } else {
    5063           0 :       aChild->DeleteProperty(BClampMarginBoxMinSizeProperty());
    5064             :     }
    5065           0 :     if ((aGridItemInfo->mState[childIAxis] & ItemState::eApplyAutoMinSize)) {
    5066           0 :       flags |= ReflowInput::I_APPLY_AUTO_MIN_SIZE;
    5067             :     }
    5068             :   }
    5069             : 
    5070           0 :   if (!isConstrainedBSize) {
    5071           0 :     childCBSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE;
    5072             :   }
    5073           0 :   LogicalSize percentBasis(cb.Size(wm).ConvertTo(childWM, wm));
    5074           0 :   ReflowInput childRI(pc, *aState.mReflowInput, aChild, childCBSize,
    5075           0 :                       &percentBasis, flags);
    5076           0 :   childRI.mFlags.mIsTopOfPage = aFragmentainer ? aFragmentainer->mIsTopOfPage : false;
    5077             : 
    5078             :   // Because we pass ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE, and the
    5079             :   // previous reflow of the child might not have, set the child's
    5080             :   // block-resize flag to true.
    5081             :   // FIXME (perf): It would be faster to do this only if the previous
    5082             :   // reflow of the child was a measuring reflow, and only if the child
    5083             :   // does some of the things that are affected by
    5084             :   // ReflowInput::COMPUTE_SIZE_USE_AUTO_BSIZE.
    5085           0 :   childRI.SetBResize(true);
    5086             : 
    5087             :   // A table-wrapper needs to propagate the CB size we give it to its
    5088             :   // inner table frame later.  @see nsTableWrapperFrame::InitChildReflowInput.
    5089           0 :   if (aChild->IsTableWrapperFrame()) {
    5090             :     LogicalSize* cb =
    5091           0 :       aChild->GetProperty(nsTableWrapperFrame::GridItemCBSizeProperty());
    5092           0 :     if (!cb) {
    5093           0 :       cb = new LogicalSize(childWM);
    5094           0 :       aChild->SetProperty(nsTableWrapperFrame::GridItemCBSizeProperty(), cb);
    5095             :     }
    5096           0 :     *cb = percentBasis;
    5097             :   }
    5098             : 
    5099             :   // If the child is stretching in its block axis, and we might be fragmenting
    5100             :   // it in that axis, then setup a frame property to tell
    5101             :   // nsBlockFrame::ComputeFinalSize the size.
    5102           0 :   if (isConstrainedBSize && !wm.IsOrthogonalTo(childWM)) {
    5103           0 :     bool stretch = false;
    5104           0 :     if (!childRI.mStyleMargin->HasBlockAxisAuto(childWM) &&
    5105           0 :         childRI.mStylePosition->BSize(childWM).GetUnit() == eStyleUnit_Auto) {
    5106             :       auto blockAxisAlignment =
    5107           0 :         childRI.mStylePosition->UsedAlignSelf(StyleContext());
    5108           0 :       if (blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
    5109             :           blockAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
    5110           0 :         stretch = true;
    5111             :       }
    5112             :     }
    5113           0 :     if (stretch) {
    5114           0 :       aChild->SetProperty(FragStretchBSizeProperty(), *aStretchBSize);
    5115             :     } else {
    5116           0 :       aChild->DeleteProperty(FragStretchBSizeProperty());
    5117             :     }
    5118             :   }
    5119             : 
    5120             :   // We need the width of the child before we can correctly convert
    5121             :   // the writing-mode of its origin, so we reflow at (0, 0) using a dummy
    5122             :   // aContainerSize, and then pass the correct position to FinishReflowChild.
    5123           0 :   ReflowOutput childSize(childRI);
    5124           0 :   const nsSize dummyContainerSize;
    5125           0 :   ReflowChild(aChild, pc, childSize, childRI, childWM, LogicalPoint(childWM),
    5126           0 :               dummyContainerSize, 0, aStatus);
    5127             :   LogicalPoint childPos =
    5128           0 :     cb.Origin(wm).ConvertTo(childWM, wm,
    5129           0 :                             aContainerSize - childSize.PhysicalSize());
    5130             :   // Apply align/justify-self and reflow again if that affects the size.
    5131           0 :   if (MOZ_LIKELY(isGridItem)) {
    5132           0 :     LogicalSize size = childSize.Size(childWM); // from the ReflowChild()
    5133           0 :     if (aStatus.IsComplete()) {
    5134           0 :       auto align = childRI.mStylePosition->UsedAlignSelf(containerSC);
    5135           0 :       auto state = aGridItemInfo->mState[eLogicalAxisBlock];
    5136           0 :       if (state & ItemState::eContentBaseline) {
    5137           0 :         align = (state & ItemState::eFirstBaseline) ? NS_STYLE_ALIGN_SELF_START
    5138           0 :                                                     : NS_STYLE_ALIGN_SELF_END;
    5139             :       }
    5140           0 :       nscoord cbsz = cb.BSize(wm) - consumedGridAreaBSize;
    5141           0 :       AlignSelf(*aGridItemInfo, align, cbsz, wm, childRI, size, &childPos);
    5142             :     }
    5143           0 :     auto justify = childRI.mStylePosition->UsedJustifySelf(containerSC);
    5144           0 :     auto state = aGridItemInfo->mState[eLogicalAxisInline];
    5145           0 :     if (state & ItemState::eContentBaseline) {
    5146           0 :       justify = (state & ItemState::eFirstBaseline) ? NS_STYLE_JUSTIFY_SELF_START
    5147           0 :                                                     : NS_STYLE_JUSTIFY_SELF_END;
    5148             :     }
    5149           0 :     nscoord cbsz = cb.ISize(wm);
    5150           0 :     JustifySelf(*aGridItemInfo, justify, cbsz, wm, childRI, size, &childPos);
    5151             :   } // else, nsAbsoluteContainingBlock.cpp will handle align/justify-self.
    5152             : 
    5153           0 :   childRI.ApplyRelativePositioning(&childPos, aContainerSize);
    5154             :   FinishReflowChild(aChild, pc, childSize, &childRI, childWM, childPos,
    5155           0 :                     aContainerSize, 0);
    5156           0 :   ConsiderChildOverflow(aDesiredSize.mOverflowAreas, aChild);
    5157           0 : }
    5158             : 
    5159             : nscoord
    5160           0 : nsGridContainerFrame::ReflowInFragmentainer(GridReflowInput&     aState,
    5161             :                                             const LogicalRect&   aContentArea,
    5162             :                                             ReflowOutput& aDesiredSize,
    5163             :                                             nsReflowStatus&      aStatus,
    5164             :                                             Fragmentainer&       aFragmentainer,
    5165             :                                             const nsSize&        aContainerSize)
    5166             : {
    5167           0 :   MOZ_ASSERT(aStatus.IsEmpty());
    5168           0 :   MOZ_ASSERT(aState.mReflowInput);
    5169             : 
    5170             :   // Collect our grid items and sort them in row order.  Collect placeholders
    5171             :   // and put them in a separate array.
    5172           0 :   nsTArray<const GridItemInfo*> sortedItems(aState.mGridItems.Length());
    5173           0 :   nsTArray<nsIFrame*> placeholders(aState.mAbsPosItems.Length());
    5174           0 :   aState.mIter.Reset(CSSOrderAwareFrameIterator::eIncludeAll);
    5175           0 :   for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
    5176           0 :     nsIFrame* child = *aState.mIter;
    5177           0 :     if (!child->IsPlaceholderFrame()) {
    5178           0 :       const GridItemInfo* info = &aState.mGridItems[aState.mIter.ItemIndex()];
    5179           0 :       sortedItems.AppendElement(info);
    5180             :     } else {
    5181           0 :       placeholders.AppendElement(child);
    5182             :     }
    5183             :   }
    5184             :   // NOTE: no need to use stable_sort here, there are no dependencies on
    5185             :   // having content order between items on the same row in the code below.
    5186           0 :   std::sort(sortedItems.begin(), sortedItems.end(),
    5187           0 :             GridItemInfo::IsStartRowLessThan);
    5188             : 
    5189             :   // Reflow our placeholder children; they must all be complete.
    5190           0 :   for (auto child : placeholders) {
    5191           0 :     nsReflowStatus childStatus;
    5192           0 :     ReflowInFlowChild(child, nullptr, aContainerSize, Nothing(), &aFragmentainer,
    5193           0 :                       aState, aContentArea, aDesiredSize, childStatus);
    5194           0 :     MOZ_ASSERT(childStatus.IsComplete(),
    5195             :                "nsPlaceholderFrame should never need to be fragmented");
    5196             :   }
    5197             : 
    5198             :   // The available size for children - we'll set this to the edge of the last
    5199             :   // row in most cases below, but for now use the full size.
    5200           0 :   nscoord childAvailableSize = aFragmentainer.mToFragmentainerEnd;
    5201           0 :   const uint32_t startRow = aState.mStartRow;
    5202           0 :   const uint32_t numRows = aState.mRows.mSizes.Length();
    5203           0 :   bool isBDBClone = aState.mReflowInput->mStyleBorder->mBoxDecorationBreak ==
    5204           0 :                       StyleBoxDecorationBreak::Clone;
    5205           0 :   nscoord bpBEnd = aState.mBorderPadding.BEnd(aState.mWM);
    5206             : 
    5207             :   // Set |endRow| to the first row that doesn't fit.
    5208           0 :   uint32_t endRow = numRows;
    5209           0 :   for (uint32_t row = startRow; row < numRows; ++row) {
    5210           0 :     auto& sz = aState.mRows.mSizes[row];
    5211           0 :     const nscoord bEnd = sz.mPosition + sz.mBase;
    5212           0 :     nscoord remainingAvailableSize = childAvailableSize - bEnd;
    5213           0 :     if (remainingAvailableSize < 0 ||
    5214           0 :         (isBDBClone && remainingAvailableSize < bpBEnd)) {
    5215           0 :       endRow = row;
    5216           0 :       break;
    5217             :     }
    5218             :   }
    5219             : 
    5220             :   // Check for forced breaks on the items.
    5221           0 :   const bool isTopOfPage = aFragmentainer.mIsTopOfPage;
    5222           0 :   bool isForcedBreak = false;
    5223           0 :   const bool avoidBreakInside = ShouldAvoidBreakInside(*aState.mReflowInput);
    5224           0 :   for (const GridItemInfo* info : sortedItems) {
    5225           0 :     uint32_t itemStartRow = info->mArea.mRows.mStart;
    5226           0 :     if (itemStartRow == endRow) {
    5227           0 :       break;
    5228             :     }
    5229           0 :     auto disp = info->mFrame->StyleDisplay();
    5230           0 :     if (disp->mBreakBefore) {
    5231             :       // Propagate break-before on the first row to the container unless we're
    5232             :       // already at top-of-page.
    5233           0 :       if ((itemStartRow == 0 && !isTopOfPage) || avoidBreakInside) {
    5234           0 :         aStatus.SetInlineLineBreakBeforeAndReset();
    5235           0 :         return aState.mFragBStart;
    5236             :       }
    5237           0 :       if ((itemStartRow > startRow ||
    5238           0 :            (itemStartRow == startRow && !isTopOfPage)) &&
    5239             :           itemStartRow < endRow) {
    5240           0 :         endRow = itemStartRow;
    5241           0 :         isForcedBreak = true;
    5242             :         // reset any BREAK_AFTER we found on an earlier item
    5243           0 :         aStatus.Reset();
    5244           0 :         break;  // we're done since the items are sorted in row order
    5245             :       }
    5246             :     }
    5247           0 :     uint32_t itemEndRow = info->mArea.mRows.mEnd;
    5248           0 :     if (disp->mBreakAfter) {
    5249           0 :       if (itemEndRow != numRows) {
    5250           0 :         if (itemEndRow > startRow && itemEndRow < endRow) {
    5251           0 :           endRow = itemEndRow;
    5252           0 :           isForcedBreak = true;
    5253             :           // No "break;" here since later items with break-after may have
    5254             :           // a shorter span.
    5255             :         }
    5256             :       } else {
    5257             :         // Propagate break-after on the last row to the container, we may still
    5258             :         // find a break-before on this row though (and reset aStatus).
    5259           0 :         aStatus.SetInlineLineBreakAfter(); // tentative
    5260             :       }
    5261             :     }
    5262             :   }
    5263             : 
    5264             :   // Consume at least one row in each fragment until we have consumed them all.
    5265             :   // Except for the first row if there's a break opportunity before it.
    5266           0 :   if (startRow == endRow && startRow != numRows &&
    5267           0 :       (startRow != 0 || !aFragmentainer.mCanBreakAtStart)) {
    5268           0 :     ++endRow;
    5269             :   }
    5270             : 
    5271             :   // Honor break-inside:avoid if we can't fit all rows.
    5272           0 :   if (avoidBreakInside && endRow < numRows) {
    5273           0 :     aStatus.SetInlineLineBreakBeforeAndReset();
    5274           0 :     return aState.mFragBStart;
    5275             :   }
    5276             : 
    5277             :   // Calculate the block-size including this fragment.
    5278             :   nscoord bEndRow =
    5279           0 :     aState.mRows.GridLineEdge(endRow, GridLineSide::eBeforeGridGap);
    5280             :   nscoord bSize;
    5281           0 :   if (aFragmentainer.mIsAutoBSize) {
    5282             :     // We only apply min-bsize once all rows are complete (when bsize is auto).
    5283           0 :     if (endRow < numRows) {
    5284           0 :       bSize = bEndRow;
    5285           0 :       auto clampedBSize = ClampToCSSMaxBSize(bSize, aState.mReflowInput);
    5286           0 :       if (MOZ_UNLIKELY(clampedBSize != bSize)) {
    5287             :         // We apply max-bsize in all fragments though.
    5288           0 :         bSize = clampedBSize;
    5289           0 :       } else if (!isBDBClone) {
    5290             :         // The max-bsize won't make this fragment COMPLETE, so the block-end
    5291             :         // border will be in a later fragment.
    5292           0 :         bpBEnd = 0;
    5293             :       }
    5294             :     } else {
    5295           0 :       bSize = NS_CSS_MINMAX(bEndRow,
    5296           0 :                             aState.mReflowInput->ComputedMinBSize(),
    5297           0 :                             aState.mReflowInput->ComputedMaxBSize());
    5298             :     }
    5299             :   } else {
    5300           0 :     bSize = NS_CSS_MINMAX(aState.mReflowInput->ComputedBSize(),
    5301           0 :                           aState.mReflowInput->ComputedMinBSize(),
    5302           0 :                           aState.mReflowInput->ComputedMaxBSize());
    5303             :   }
    5304             : 
    5305             :   // Check for overflow and set aStatus INCOMPLETE if so.
    5306           0 :   bool overflow = bSize + bpBEnd > childAvailableSize;
    5307           0 :   if (overflow) {
    5308           0 :     if (avoidBreakInside) {
    5309           0 :       aStatus.SetInlineLineBreakBeforeAndReset();
    5310           0 :       return aState.mFragBStart;
    5311             :     }
    5312           0 :     bool breakAfterLastRow = endRow == numRows && aFragmentainer.mCanBreakAtEnd;
    5313           0 :     if (breakAfterLastRow) {
    5314           0 :       MOZ_ASSERT(bEndRow < bSize, "bogus aFragmentainer.mCanBreakAtEnd");
    5315           0 :       nscoord availableSize = childAvailableSize;
    5316           0 :       if (isBDBClone) {
    5317           0 :         availableSize -= bpBEnd;
    5318             :       }
    5319             :       // Pretend we have at least 1px available size, otherwise we'll never make
    5320             :       // progress in consuming our bSize.
    5321           0 :       availableSize = std::max(availableSize,
    5322           0 :                                aState.mFragBStart + AppUnitsPerCSSPixel());
    5323             :       // Fill the fragmentainer, but not more than our desired block-size and
    5324             :       // at least to the size of the last row (even if that overflows).
    5325           0 :       nscoord newBSize = std::min(bSize, availableSize);
    5326           0 :       newBSize = std::max(newBSize, bEndRow);
    5327             :       // If it's just the border+padding that is overflowing and we have
    5328             :       // box-decoration-break:clone then we are technically COMPLETE.  There's
    5329             :       // no point in creating another zero-bsize fragment in this case.
    5330           0 :       if (newBSize < bSize || !isBDBClone) {
    5331           0 :         aStatus.SetIncomplete();
    5332             :       }
    5333           0 :       bSize = newBSize;
    5334           0 :     } else if (bSize <= bEndRow && startRow + 1 < endRow) {
    5335           0 :       if (endRow == numRows) {
    5336             :         // We have more than one row in this fragment, so we can break before
    5337             :         // the last row instead.
    5338           0 :         --endRow;
    5339           0 :         bEndRow = aState.mRows.GridLineEdge(endRow, GridLineSide::eBeforeGridGap);
    5340           0 :         bSize = bEndRow;
    5341           0 :         if (aFragmentainer.mIsAutoBSize) {
    5342           0 :           bSize = ClampToCSSMaxBSize(bSize, aState.mReflowInput);
    5343             :         }
    5344             :       }
    5345           0 :       aStatus.SetIncomplete();
    5346           0 :     } else if (endRow < numRows) {
    5347           0 :       bSize = ClampToCSSMaxBSize(bEndRow, aState.mReflowInput, &aStatus);
    5348             :     } // else - no break opportunities.
    5349             :   } else {
    5350             :     // Even though our block-size fits we need to honor forced breaks, or if
    5351             :     // a row doesn't fit in an auto-sized container (unless it's constrained
    5352             :     // by a max-bsize which make us overflow-incomplete).
    5353           0 :     if (endRow < numRows && (isForcedBreak ||
    5354           0 :                              (aFragmentainer.mIsAutoBSize && bEndRow == bSize))) {
    5355           0 :       bSize = ClampToCSSMaxBSize(bEndRow, aState.mReflowInput, &aStatus);
    5356             :     }
    5357             :   }
    5358             : 
    5359             :   // If we can't fit all rows then we're at least overflow-incomplete.
    5360           0 :   if (endRow < numRows) {
    5361           0 :     childAvailableSize = bEndRow;
    5362           0 :     if (aStatus.IsComplete()) {
    5363           0 :       aStatus.SetOverflowIncomplete();
    5364           0 :       aStatus.SetNextInFlowNeedsReflow();
    5365             :     }
    5366             :   } else {
    5367             :     // Children always have the full size of the rows in this fragment.
    5368           0 :     childAvailableSize = std::max(childAvailableSize, bEndRow);
    5369             :   }
    5370             : 
    5371           0 :   return ReflowRowsInFragmentainer(aState, aContentArea, aDesiredSize, aStatus,
    5372             :                                    aFragmentainer, aContainerSize, sortedItems,
    5373           0 :                                    startRow, endRow, bSize, childAvailableSize);
    5374             : }
    5375             : 
    5376             : nscoord
    5377           0 : nsGridContainerFrame::ReflowRowsInFragmentainer(
    5378             :   GridReflowInput&                     aState,
    5379             :   const LogicalRect&                   aContentArea,
    5380             :   ReflowOutput&                 aDesiredSize,
    5381             :   nsReflowStatus&                      aStatus,
    5382             :   Fragmentainer&                       aFragmentainer,
    5383             :   const nsSize&                        aContainerSize,
    5384             :   const nsTArray<const GridItemInfo*>& aSortedItems,
    5385             :   uint32_t                             aStartRow,
    5386             :   uint32_t                             aEndRow,
    5387             :   nscoord                              aBSize,
    5388             :   nscoord                              aAvailableSize)
    5389             : {
    5390           0 :   FrameHashtable pushedItems;
    5391           0 :   FrameHashtable incompleteItems;
    5392           0 :   FrameHashtable overflowIncompleteItems;
    5393           0 :   bool isBDBClone = aState.mReflowInput->mStyleBorder->mBoxDecorationBreak ==
    5394           0 :                       StyleBoxDecorationBreak::Clone;
    5395           0 :   bool didGrowRow = false;
    5396             :   // As we walk across rows, we track whether the current row is at the top
    5397             :   // of its grid-fragment, to help decide whether we can break before it. When
    5398             :   // this function starts, our row is at the top of the current fragment if:
    5399             :   //  - we're starting with a nonzero row (i.e. we're a continuation)
    5400             :   // OR:
    5401             :   //  - we're starting with the first row, & we're not allowed to break before
    5402             :   //    it (which makes it effectively at the top of its grid-fragment).
    5403           0 :   bool isRowTopOfPage = aStartRow != 0 || !aFragmentainer.mCanBreakAtStart;
    5404           0 :   const bool isStartRowTopOfPage = isRowTopOfPage;
    5405             :   // Save our full available size for later.
    5406           0 :   const nscoord gridAvailableSize = aFragmentainer.mToFragmentainerEnd;
    5407             :   // Propagate the constrained size to our children.
    5408           0 :   aFragmentainer.mToFragmentainerEnd = aAvailableSize;
    5409             :   // Reflow the items in row order up to |aEndRow| and push items after that.
    5410           0 :   uint32_t row = 0;
    5411             :   // |i| is intentionally signed, so we can set it to -1 to restart the loop.
    5412           0 :   for (int32_t i = 0, len = aSortedItems.Length(); i < len; ++i) {
    5413           0 :     const GridItemInfo* const info = aSortedItems[i];
    5414           0 :     nsIFrame* child = info->mFrame;
    5415           0 :     row = info->mArea.mRows.mStart;
    5416           0 :     MOZ_ASSERT(child->GetPrevInFlow() ? row < aStartRow : row >= aStartRow,
    5417             :                "unexpected child start row");
    5418           0 :     if (row >= aEndRow) {
    5419           0 :       pushedItems.PutEntry(child);
    5420           0 :       continue;
    5421             :     }
    5422             : 
    5423           0 :     bool rowCanGrow = false;
    5424           0 :     nscoord maxRowSize = 0;
    5425           0 :     if (row >= aStartRow) {
    5426           0 :       if (row > aStartRow) {
    5427           0 :         isRowTopOfPage = false;
    5428             :       }
    5429             :       // Can we grow this row?  Only consider span=1 items per spec...
    5430           0 :       rowCanGrow = !didGrowRow && info->mArea.mRows.Extent() == 1;
    5431           0 :       if (rowCanGrow) {
    5432           0 :         auto& sz = aState.mRows.mSizes[row];
    5433             :         // and only min-/max-content rows or flex rows in an auto-sized container
    5434           0 :         rowCanGrow = (sz.mState & TrackSize::eMinOrMaxContentMinSizing) ||
    5435           0 :                      ((sz.mState & TrackSize::eFlexMaxSizing) &&
    5436           0 :                       aFragmentainer.mIsAutoBSize);
    5437           0 :         if (rowCanGrow) {
    5438           0 :           if (isBDBClone) {
    5439           0 :             maxRowSize = gridAvailableSize -
    5440           0 :                          aState.mBorderPadding.BEnd(aState.mWM);
    5441             :           } else {
    5442           0 :             maxRowSize = gridAvailableSize;
    5443             :           }
    5444           0 :           maxRowSize -= sz.mPosition;
    5445             :           // ...and only if there is space for it to grow.
    5446           0 :           rowCanGrow = maxRowSize > sz.mBase;
    5447             :         }
    5448             :       }
    5449             :     }
    5450             : 
    5451             :     // aFragmentainer.mIsTopOfPage is propagated to the child reflow state.
    5452             :     // When it's false the child can request BREAK_BEFORE.  We intentionally
    5453             :     // set it to false when the row is growable (as determined in CSS Grid
    5454             :     // Fragmentation) and there is a non-zero space between it and the
    5455             :     // fragmentainer end (that can be used to grow it).  If the child reports
    5456             :     // a forced break in this case, we grow this row to fill the fragment and
    5457             :     // restart the loop.  We also restart the loop with |aEndRow = row|
    5458             :     // (but without growing any row) for a BREAK_BEFORE child if it spans
    5459             :     // beyond the last row in this fragment.  This is to avoid fragmenting it.
    5460             :     // We only restart the loop once.
    5461           0 :     aFragmentainer.mIsTopOfPage = isRowTopOfPage && !rowCanGrow;
    5462           0 :     nsReflowStatus childStatus;
    5463             :     // Pass along how much to stretch this fragment, in case it's needed.
    5464             :     nscoord bSize =
    5465           0 :       aState.mRows.GridLineEdge(std::min(aEndRow, info->mArea.mRows.mEnd),
    5466           0 :                                 GridLineSide::eBeforeGridGap) -
    5467           0 :       aState.mRows.GridLineEdge(std::max(aStartRow, row),
    5468           0 :                                 GridLineSide::eAfterGridGap);
    5469           0 :     ReflowInFlowChild(child, info, aContainerSize, Some(bSize), &aFragmentainer,
    5470           0 :                       aState, aContentArea, aDesiredSize, childStatus);
    5471           0 :     MOZ_ASSERT(childStatus.IsInlineBreakBefore() ||
    5472             :                !childStatus.IsFullyComplete() ||
    5473             :                !child->GetNextInFlow(),
    5474             :                "fully-complete reflow should destroy any NIFs");
    5475             : 
    5476           0 :     if (childStatus.IsInlineBreakBefore()) {
    5477           0 :       MOZ_ASSERT(!child->GetPrevInFlow(),
    5478             :                  "continuations should never report BREAK_BEFORE status");
    5479           0 :       MOZ_ASSERT(!aFragmentainer.mIsTopOfPage,
    5480             :                  "got IsInlineBreakBefore() at top of page");
    5481           0 :       if (!didGrowRow) {
    5482           0 :         if (rowCanGrow) {
    5483             :           // Grow this row and restart with the next row as |aEndRow|.
    5484           0 :           aState.mRows.ResizeRow(row, maxRowSize);
    5485           0 :           if (aState.mSharedGridData) {
    5486           0 :             aState.mSharedGridData->mRows.ResizeRow(row, maxRowSize);
    5487             :           }
    5488           0 :           didGrowRow = true;
    5489           0 :           aEndRow = row + 1;  // growing this row makes the next one not fit
    5490           0 :           i = -1;  // i == 0 after the next loop increment
    5491           0 :           isRowTopOfPage = isStartRowTopOfPage;
    5492           0 :           overflowIncompleteItems.Clear();
    5493           0 :           incompleteItems.Clear();
    5494             :           nscoord bEndRow =
    5495           0 :             aState.mRows.GridLineEdge(aEndRow, GridLineSide::eBeforeGridGap);
    5496           0 :           aFragmentainer.mToFragmentainerEnd = bEndRow;
    5497           0 :           if (aFragmentainer.mIsAutoBSize) {
    5498           0 :             aBSize = ClampToCSSMaxBSize(bEndRow, aState.mReflowInput, &aStatus);
    5499           0 :           } else if (aStatus.IsIncomplete()) {
    5500           0 :             aBSize = NS_CSS_MINMAX(aState.mReflowInput->ComputedBSize(),
    5501           0 :                                    aState.mReflowInput->ComputedMinBSize(),
    5502           0 :                                    aState.mReflowInput->ComputedMaxBSize());
    5503           0 :             aBSize = std::min(bEndRow, aBSize);
    5504             :           }
    5505           0 :           continue;
    5506             :         }
    5507             : 
    5508           0 :         if (!isRowTopOfPage) {
    5509             :           // We can break before this row - restart with it as the new end row.
    5510           0 :           aEndRow = row;
    5511           0 :           aBSize = aState.mRows.GridLineEdge(aEndRow, GridLineSide::eBeforeGridGap);
    5512           0 :           i = -1;  // i == 0 after the next loop increment
    5513           0 :           isRowTopOfPage = isStartRowTopOfPage;
    5514           0 :           overflowIncompleteItems.Clear();
    5515           0 :           incompleteItems.Clear();
    5516           0 :           aStatus.SetIncomplete();
    5517           0 :           continue;
    5518             :         }
    5519           0 :         NS_ERROR("got BREAK_BEFORE at top-of-page");
    5520           0 :         childStatus.Reset();
    5521             :       } else {
    5522           0 :         NS_ERROR("got BREAK_BEFORE again after growing the row?");
    5523           0 :         childStatus.SetIncomplete();
    5524             :       }
    5525           0 :     } else if (childStatus.IsInlineBreakAfter()) {
    5526           0 :       MOZ_ASSERT_UNREACHABLE("unexpected child reflow status");
    5527             :     }
    5528             : 
    5529           0 :     if (childStatus.IsIncomplete()) {
    5530           0 :       incompleteItems.PutEntry(child);
    5531           0 :     } else if (!childStatus.IsFullyComplete()) {
    5532           0 :       overflowIncompleteItems.PutEntry(child);
    5533             :     }
    5534             :   }
    5535             : 
    5536             :   // Record a break before |aEndRow|.
    5537           0 :   aState.mNextFragmentStartRow = aEndRow;
    5538           0 :   if (aEndRow < aState.mRows.mSizes.Length()) {
    5539           0 :     aState.mRows.BreakBeforeRow(aEndRow);
    5540           0 :     if (aState.mSharedGridData) {
    5541           0 :       aState.mSharedGridData->mRows.BreakBeforeRow(aEndRow);
    5542             :     }
    5543             :   }
    5544             : 
    5545           0 :   if (!pushedItems.IsEmpty() ||
    5546           0 :       !incompleteItems.IsEmpty() ||
    5547           0 :       !overflowIncompleteItems.IsEmpty()) {
    5548           0 :     if (aStatus.IsComplete()) {
    5549           0 :       aStatus.SetOverflowIncomplete();
    5550           0 :       aStatus.SetNextInFlowNeedsReflow();
    5551             :     }
    5552             :     // Iterate the children in normal document order and append them (or a NIF)
    5553             :     // to one of the following frame lists according to their status.
    5554           0 :     nsFrameList pushedList;
    5555           0 :     nsFrameList incompleteList;
    5556           0 :     nsFrameList overflowIncompleteList;
    5557           0 :     auto* pc = PresContext();
    5558           0 :     auto* fc = pc->PresShell()->FrameConstructor();
    5559           0 :     for (nsIFrame* child = GetChildList(kPrincipalList).FirstChild(); child; ) {
    5560           0 :       MOZ_ASSERT((pushedItems.Contains(child) ? 1 : 0) +
    5561             :                  (incompleteItems.Contains(child) ? 1 : 0) +
    5562             :                  (overflowIncompleteItems.Contains(child) ? 1 : 0) <= 1,
    5563             :                  "child should only be in one of these sets");
    5564             :       // Save the next-sibling so we can continue the loop if |child| is moved.
    5565           0 :       nsIFrame* next = child->GetNextSibling();
    5566           0 :       if (pushedItems.Contains(child)) {
    5567           0 :         MOZ_ASSERT(child->GetParent() == this);
    5568           0 :         StealFrame(child);
    5569           0 :         pushedList.AppendFrame(nullptr, child);
    5570           0 :       } else if (incompleteItems.Contains(child)) {
    5571           0 :         nsIFrame* childNIF = child->GetNextInFlow();
    5572           0 :         if (!childNIF) {
    5573           0 :           childNIF = fc->CreateContinuingFrame(pc, child, this);
    5574           0 :           incompleteList.AppendFrame(nullptr, childNIF);
    5575             :         } else {
    5576           0 :           auto parent = static_cast<nsGridContainerFrame*>(childNIF->GetParent());
    5577           0 :           MOZ_ASSERT(parent != this || !mFrames.ContainsFrame(childNIF),
    5578             :                      "child's NIF shouldn't be in the same principal list");
    5579             :           // If child's existing NIF is an overflow container, convert it to an
    5580             :           // actual NIF, since now |child| has non-overflow stuff to give it.
    5581             :           // Or, if it's further away then our next-in-flow, then pull it up.
    5582           0 :           if ((childNIF->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ||
    5583           0 :               (parent != this && parent != GetNextInFlow())) {
    5584           0 :             parent->StealFrame(childNIF);
    5585           0 :             childNIF->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
    5586           0 :             if (parent == this) {
    5587           0 :               incompleteList.AppendFrame(nullptr, childNIF);
    5588             :             } else {
    5589             :               // If childNIF already lives on the next grid fragment, then we
    5590             :               // don't need to reparent it, since we know it's destined to end
    5591             :               // up there anyway.  Just move it to its parent's overflow list.
    5592           0 :               if (parent == GetNextInFlow()) {
    5593           0 :                 nsFrameList toMove(childNIF, childNIF);
    5594           0 :                 parent->MergeSortedOverflow(toMove);
    5595             :               } else {
    5596           0 :                 ReparentFrame(childNIF, parent, this);
    5597           0 :                 incompleteList.AppendFrame(nullptr, childNIF);
    5598             :               }
    5599             :             }
    5600             :           }
    5601             :         }
    5602           0 :       } else if (overflowIncompleteItems.Contains(child)) {
    5603           0 :         nsIFrame* childNIF = child->GetNextInFlow();
    5604           0 :         if (!childNIF) {
    5605           0 :           childNIF = fc->CreateContinuingFrame(pc, child, this);
    5606           0 :           childNIF->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
    5607           0 :           overflowIncompleteList.AppendFrame(nullptr, childNIF);
    5608             :         } else {
    5609           0 :           DebugOnly<nsGridContainerFrame*> lastParent = this;
    5610           0 :           auto nif = static_cast<nsGridContainerFrame*>(GetNextInFlow());
    5611             :           // If child has any non-overflow-container NIFs, convert them to
    5612             :           // overflow containers, since that's all |child| needs now.
    5613           0 :           while (childNIF &&
    5614           0 :                  !childNIF->HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER)) {
    5615           0 :             auto parent = static_cast<nsGridContainerFrame*>(childNIF->GetParent());
    5616           0 :             parent->StealFrame(childNIF);
    5617           0 :             childNIF->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
    5618           0 :             if (parent == this) {
    5619           0 :               overflowIncompleteList.AppendFrame(nullptr, childNIF);
    5620             :             } else {
    5621           0 :               if (!nif || parent == nif) {
    5622           0 :                 nsFrameList toMove(childNIF, childNIF);
    5623           0 :                 parent->MergeSortedExcessOverflowContainers(toMove);
    5624             :               } else {
    5625           0 :                 ReparentFrame(childNIF, parent, nif);
    5626           0 :                 nsFrameList toMove(childNIF, childNIF);
    5627           0 :                 nif->MergeSortedExcessOverflowContainers(toMove);
    5628             :               }
    5629             :               // We only need to reparent the first childNIF (or not at all if
    5630             :               // its parent is our NIF).
    5631           0 :               nif = nullptr;
    5632             :             }
    5633           0 :             lastParent = parent;
    5634           0 :             childNIF = childNIF->GetNextInFlow();
    5635             :           }
    5636             :         }
    5637             :       }
    5638           0 :       child = next;
    5639             :     }
    5640             : 
    5641             :     // Merge the results into our respective overflow child lists.
    5642           0 :     if (!pushedList.IsEmpty()) {
    5643           0 :       MergeSortedOverflow(pushedList);
    5644           0 :       AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
    5645             :       // NOTE since we messed with our child list here, we intentionally
    5646             :       // make aState.mIter invalid to avoid any use of it after this point.
    5647           0 :       aState.mIter.Invalidate();
    5648             :     }
    5649           0 :     if (!incompleteList.IsEmpty()) {
    5650           0 :       MergeSortedOverflow(incompleteList);
    5651             :       // NOTE since we messed with our child list here, we intentionally
    5652             :       // make aState.mIter invalid to avoid any use of it after this point.
    5653           0 :       aState.mIter.Invalidate();
    5654             :     }
    5655           0 :     if (!overflowIncompleteList.IsEmpty()) {
    5656           0 :       MergeSortedExcessOverflowContainers(overflowIncompleteList);
    5657             :     }
    5658             :   }
    5659           0 :   return aBSize;
    5660             : }
    5661             : 
    5662             : nscoord
    5663           0 : nsGridContainerFrame::ReflowChildren(GridReflowInput&     aState,
    5664             :                                      const LogicalRect&   aContentArea,
    5665             :                                      ReflowOutput& aDesiredSize,
    5666             :                                      nsReflowStatus&      aStatus)
    5667             : {
    5668           0 :   MOZ_ASSERT(aState.mReflowInput);
    5669             : 
    5670           0 :   aStatus.Reset();
    5671           0 :   nsOverflowAreas ocBounds;
    5672           0 :   nsReflowStatus ocStatus;
    5673           0 :   if (GetPrevInFlow()) {
    5674           0 :     ReflowOverflowContainerChildren(PresContext(), *aState.mReflowInput,
    5675             :                                     ocBounds, 0, ocStatus,
    5676           0 :                                     MergeSortedFrameListsFor);
    5677             :   }
    5678             : 
    5679           0 :   WritingMode wm = aState.mReflowInput->GetWritingMode();
    5680             :   const nsSize containerSize =
    5681           0 :     (aContentArea.Size(wm) + aState.mBorderPadding.Size(wm)).GetPhysicalSize(wm);
    5682             : 
    5683           0 :   nscoord bSize = aContentArea.BSize(wm);
    5684           0 :   Maybe<Fragmentainer> fragmentainer = GetNearestFragmentainer(aState);
    5685           0 :   if (MOZ_UNLIKELY(fragmentainer.isSome())) {
    5686           0 :     aState.mInFragmentainer = true;
    5687           0 :     bSize = ReflowInFragmentainer(aState, aContentArea, aDesiredSize, aStatus,
    5688           0 :                                   *fragmentainer, containerSize);
    5689             :   } else {
    5690           0 :     aState.mIter.Reset(CSSOrderAwareFrameIterator::eIncludeAll);
    5691           0 :     for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
    5692           0 :       nsIFrame* child = *aState.mIter;
    5693           0 :       const GridItemInfo* info = nullptr;
    5694           0 :       if (!child->IsPlaceholderFrame()) {
    5695           0 :         info = &aState.mGridItems[aState.mIter.ItemIndex()];
    5696             :       }
    5697           0 :       ReflowInFlowChild(*aState.mIter, info, containerSize, Nothing(), nullptr,
    5698           0 :                         aState, aContentArea, aDesiredSize, aStatus);
    5699           0 :       MOZ_ASSERT(aStatus.IsComplete(), "child should be complete "
    5700             :                  "in unconstrained reflow");
    5701             :     }
    5702             :   }
    5703             : 
    5704             :   // Merge overflow container bounds and status.
    5705           0 :   aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
    5706           0 :   aStatus.MergeCompletionStatusFrom(ocStatus);
    5707             : 
    5708           0 :   if (IsAbsoluteContainer()) {
    5709           0 :     nsFrameList children(GetChildList(GetAbsoluteListID()));
    5710           0 :     if (!children.IsEmpty()) {
    5711             :       // 'gridOrigin' is the origin of the grid (the start of the first track),
    5712             :       // with respect to the grid container's padding-box (CB).
    5713           0 :       LogicalMargin pad(aState.mReflowInput->ComputedLogicalPadding());
    5714           0 :       const LogicalPoint gridOrigin(wm, pad.IStart(wm), pad.BStart(wm));
    5715             :       const LogicalRect gridCB(wm, 0, 0,
    5716           0 :                                aContentArea.ISize(wm) + pad.IStartEnd(wm),
    5717           0 :                                bSize + pad.BStartEnd(wm));
    5718           0 :       const nsSize gridCBPhysicalSize = gridCB.Size(wm).GetPhysicalSize(wm);
    5719           0 :       size_t i = 0;
    5720           0 :       for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next(), ++i) {
    5721           0 :         nsIFrame* child = e.get();
    5722           0 :         MOZ_ASSERT(i < aState.mAbsPosItems.Length());
    5723           0 :         MOZ_ASSERT(aState.mAbsPosItems[i].mFrame == child);
    5724           0 :         GridArea& area = aState.mAbsPosItems[i].mArea;
    5725             :         LogicalRect itemCB =
    5726           0 :           aState.ContainingBlockForAbsPos(area, gridOrigin, gridCB);
    5727             :         // nsAbsoluteContainingBlock::Reflow uses physical coordinates.
    5728           0 :         nsRect* cb = child->GetProperty(GridItemContainingBlockRect());
    5729           0 :         if (!cb) {
    5730           0 :           cb = new nsRect;
    5731           0 :           child->SetProperty(GridItemContainingBlockRect(), cb);
    5732             :         }
    5733           0 :         *cb = itemCB.GetPhysicalRect(wm, gridCBPhysicalSize);
    5734             :       }
    5735             :       // We pass a dummy rect as CB because each child has its own CB rect.
    5736             :       // The eIsGridContainerCB flag tells nsAbsoluteContainingBlock::Reflow to
    5737             :       // use those instead.
    5738           0 :       nsRect dummyRect;
    5739             :       AbsPosReflowFlags flags =
    5740           0 :         AbsPosReflowFlags::eCBWidthAndHeightChanged; // XXX could be optimized
    5741           0 :       flags |= AbsPosReflowFlags::eConstrainHeight;
    5742           0 :       flags |= AbsPosReflowFlags::eIsGridContainerCB;
    5743           0 :       GetAbsoluteContainingBlock()->Reflow(this, PresContext(),
    5744           0 :                                            *aState.mReflowInput,
    5745             :                                            aStatus, dummyRect, flags,
    5746           0 :                                            &aDesiredSize.mOverflowAreas);
    5747             :     }
    5748             :   }
    5749           0 :   return bSize;
    5750             : }
    5751             : 
    5752             : void
    5753           0 : nsGridContainerFrame::Reflow(nsPresContext*           aPresContext,
    5754             :                              ReflowOutput&     aDesiredSize,
    5755             :                              const ReflowInput& aReflowInput,
    5756             :                              nsReflowStatus&          aStatus)
    5757             : {
    5758           0 :   MarkInReflow();
    5759           0 :   DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame");
    5760           0 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
    5761             : 
    5762           0 :   if (IsFrameTreeTooDeep(aReflowInput, aDesiredSize, aStatus)) {
    5763           0 :     return;
    5764             :   }
    5765             : 
    5766             :   // First we gather child frames we should include in our reflow,
    5767             :   // i.e. overflowed children from our prev-in-flow, and pushed first-in-flow
    5768             :   // children (that might now fit). It's important to note that these children
    5769             :   // can be in arbitrary order vis-a-vis the current children in our lists.
    5770             :   // E.g. grid items in the document order: A, B, C may be placed in the rows
    5771             :   // 3, 2, 1.  Assume each row goes in a separate grid container fragment,
    5772             :   // and we reflow the second fragment.  Now if C (in fragment 1) overflows,
    5773             :   // we can't just prepend it to our mFrames like we usually do because that
    5774             :   // would violate the document order invariant that other code depends on.
    5775             :   // Similarly if we pull up child A (from fragment 3) we can't just append
    5776             :   // that for the same reason.  Instead, we must sort these children into
    5777             :   // our child lists.  (The sorting is trivial given that both lists are
    5778             :   // already fully sorted individually - it's just a merge.)
    5779             :   //
    5780             :   // The invariants that we maintain are that each grid container child list
    5781             :   // is sorted in the normal document order at all times, but that children
    5782             :   // in different grid container continuations may be in arbitrary order.
    5783             : 
    5784           0 :   auto prevInFlow = static_cast<nsGridContainerFrame*>(GetPrevInFlow());
    5785             :   // Merge overflow frames from our prev-in-flow into our principal child list.
    5786           0 :   if (prevInFlow) {
    5787             :     AutoFrameListPtr overflow(aPresContext,
    5788           0 :                               prevInFlow->StealOverflowFrames());
    5789           0 :     if (overflow) {
    5790           0 :       ReparentFrames(*overflow, prevInFlow, this);
    5791           0 :       ::MergeSortedFrameLists(mFrames, *overflow, GetContent());
    5792             : 
    5793             :       // Move trailing next-in-flows into our overflow list.
    5794           0 :       nsFrameList continuations;
    5795           0 :       for (nsIFrame* f = mFrames.FirstChild(); f; ) {
    5796           0 :         nsIFrame* next = f->GetNextSibling();
    5797           0 :         nsIFrame* pif = f->GetPrevInFlow();
    5798           0 :         if (pif && pif->GetParent() == this) {
    5799           0 :           mFrames.RemoveFrame(f);
    5800           0 :           continuations.AppendFrame(nullptr, f);
    5801             :         }
    5802           0 :         f = next;
    5803             :       }
    5804           0 :       MergeSortedOverflow(continuations);
    5805             : 
    5806             :       // Move trailing OC next-in-flows into our excess overflow containers list.
    5807             :       nsFrameList* overflowContainers =
    5808           0 :         GetPropTableFrames(OverflowContainersProperty());
    5809           0 :       if (overflowContainers) {
    5810           0 :         nsFrameList moveToEOC;
    5811           0 :         for (nsIFrame* f = overflowContainers->FirstChild(); f; ) {
    5812           0 :           nsIFrame* next = f->GetNextSibling();
    5813           0 :           nsIFrame* pif = f->GetPrevInFlow();
    5814           0 :           if (pif && pif->GetParent() == this) {
    5815           0 :             overflowContainers->RemoveFrame(f);
    5816           0 :             moveToEOC.AppendFrame(nullptr, f);
    5817             :           }
    5818           0 :           f = next;
    5819             :         }
    5820           0 :         if (overflowContainers->IsEmpty()) {
    5821           0 :           DeleteProperty(OverflowContainersProperty());
    5822             :         }
    5823           0 :         MergeSortedExcessOverflowContainers(moveToEOC);
    5824             :       }
    5825             :     }
    5826             :   }
    5827             : 
    5828             :   // Merge our own overflow frames into our principal child list,
    5829             :   // except those that are a next-in-flow for one of our items.
    5830           0 :   DebugOnly<bool> foundOwnPushedChild = false;
    5831             :   {
    5832           0 :     nsFrameList* ourOverflow = GetOverflowFrames();
    5833           0 :     if (ourOverflow) {
    5834           0 :       nsFrameList items;
    5835           0 :       for (nsIFrame* f = ourOverflow->FirstChild(); f; ) {
    5836           0 :         nsIFrame* next = f->GetNextSibling();
    5837           0 :         nsIFrame* pif = f->GetPrevInFlow();
    5838           0 :         if (!pif || pif->GetParent() != this) {
    5839           0 :           MOZ_ASSERT(f->GetParent() == this);
    5840           0 :           ourOverflow->RemoveFrame(f);
    5841           0 :           items.AppendFrame(nullptr, f);
    5842           0 :           if (!pif) {
    5843           0 :             foundOwnPushedChild = true;
    5844             :           }
    5845             :         }
    5846           0 :         f = next;
    5847             :       }
    5848           0 :       ::MergeSortedFrameLists(mFrames, items, GetContent());
    5849           0 :       if (ourOverflow->IsEmpty()) {
    5850           0 :         DestroyOverflowList();
    5851             :       }
    5852             :     }
    5853             :   }
    5854             : 
    5855             :   // Pull up any first-in-flow children we might have pushed.
    5856           0 :   if (HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS)) {
    5857           0 :     RemoveStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
    5858           0 :     nsFrameList items;
    5859           0 :     auto nif = static_cast<nsGridContainerFrame*>(GetNextInFlow());
    5860           0 :     auto firstNIF = nif;
    5861           0 :     DebugOnly<bool> nifNeedPushedItem = false;
    5862           0 :     while (nif) {
    5863           0 :       nsFrameList nifItems;
    5864           0 :       for (nsIFrame* nifChild = nif->GetChildList(kPrincipalList).FirstChild();
    5865           0 :            nifChild; ) {
    5866           0 :         nsIFrame* next = nifChild->GetNextSibling();
    5867           0 :         if (!nifChild->GetPrevInFlow()) {
    5868           0 :           nif->StealFrame(nifChild);
    5869           0 :           ReparentFrame(nifChild, nif, this);
    5870           0 :           nifItems.AppendFrame(nullptr, nifChild);
    5871           0 :           nifNeedPushedItem = false;
    5872             :         }
    5873           0 :         nifChild = next;
    5874             :       }
    5875           0 :       ::MergeSortedFrameLists(items, nifItems, GetContent());
    5876             : 
    5877           0 :       if (!nif->HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS)) {
    5878           0 :         MOZ_ASSERT(!nifNeedPushedItem || mDidPushItemsBitMayLie,
    5879             :                    "NS_STATE_GRID_DID_PUSH_ITEMS lied");
    5880           0 :         break;
    5881             :       }
    5882           0 :       nifNeedPushedItem = true;
    5883             : 
    5884           0 :       for (nsIFrame* nifChild = nif->GetChildList(kOverflowList).FirstChild();
    5885           0 :            nifChild; ) {
    5886           0 :         nsIFrame* next = nifChild->GetNextSibling();
    5887           0 :         if (!nifChild->GetPrevInFlow()) {
    5888           0 :           nif->StealFrame(nifChild);
    5889           0 :           ReparentFrame(nifChild, nif, this);
    5890           0 :           nifItems.AppendFrame(nullptr, nifChild);
    5891           0 :           nifNeedPushedItem = false;
    5892             :         }
    5893           0 :         nifChild = next;
    5894             :       }
    5895           0 :       ::MergeSortedFrameLists(items, nifItems, GetContent());
    5896             : 
    5897           0 :       nif->RemoveStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
    5898           0 :       nif = static_cast<nsGridContainerFrame*>(nif->GetNextInFlow());
    5899           0 :       MOZ_ASSERT(nif || !nifNeedPushedItem || mDidPushItemsBitMayLie,
    5900             :                  "NS_STATE_GRID_DID_PUSH_ITEMS lied");
    5901             :     }
    5902             : 
    5903           0 :     if (!items.IsEmpty()) {
    5904             :       // Pull up the first next-in-flow of the pulled up items too, unless its
    5905             :       // parent is our nif (to avoid leaving a hole there).
    5906           0 :       nsFrameList childNIFs;
    5907           0 :       nsFrameList childOCNIFs;
    5908           0 :       for (auto child : items) {
    5909           0 :         auto childNIF = child->GetNextInFlow();
    5910           0 :         if (childNIF && childNIF->GetParent() != firstNIF) {
    5911           0 :           auto parent = childNIF->GetParent();
    5912           0 :           parent->StealFrame(childNIF);
    5913           0 :           ReparentFrame(childNIF, parent, firstNIF);
    5914           0 :           if ((childNIF->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
    5915           0 :             childOCNIFs.AppendFrame(nullptr, childNIF);
    5916             :           } else {
    5917           0 :             childNIFs.AppendFrame(nullptr, childNIF);
    5918             :           }
    5919             :         }
    5920             :       }
    5921             :       // Merge items' NIFs into our NIF's respective overflow child lists.
    5922           0 :       firstNIF->MergeSortedOverflow(childNIFs);
    5923           0 :       firstNIF->MergeSortedExcessOverflowContainers(childOCNIFs);
    5924             :     }
    5925             : 
    5926           0 :     MOZ_ASSERT(foundOwnPushedChild || !items.IsEmpty() || mDidPushItemsBitMayLie,
    5927             :                "NS_STATE_GRID_DID_PUSH_ITEMS lied");
    5928           0 :     ::MergeSortedFrameLists(mFrames, items, GetContent());
    5929             :   }
    5930             : 
    5931           0 :   RenumberList();
    5932             : 
    5933             : #ifdef DEBUG
    5934           0 :   mDidPushItemsBitMayLie = false;
    5935           0 :   SanityCheckGridItemsBeforeReflow();
    5936             : #endif // DEBUG
    5937             : 
    5938           0 :   mBaseline[0][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
    5939           0 :   mBaseline[0][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
    5940           0 :   mBaseline[1][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
    5941           0 :   mBaseline[1][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
    5942             : 
    5943           0 :   const nsStylePosition* stylePos = aReflowInput.mStylePosition;
    5944           0 :   if (!prevInFlow) {
    5945           0 :     InitImplicitNamedAreas(stylePos);
    5946             :   }
    5947           0 :   GridReflowInput gridReflowInput(this, aReflowInput);
    5948           0 :   if (gridReflowInput.mIter.ItemsAreAlreadyInOrder()) {
    5949           0 :     AddStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
    5950             :   } else {
    5951           0 :     RemoveStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER);
    5952             :   }
    5953           0 :   if (gridReflowInput.mIter.AtEnd()) {
    5954             :     // We have no grid items, our parent should synthesize a baseline if needed.
    5955           0 :     AddStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE);
    5956             :   } else {
    5957           0 :     RemoveStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE);
    5958             :   }
    5959           0 :   const nscoord computedBSize = aReflowInput.ComputedBSize();
    5960           0 :   const nscoord computedISize = aReflowInput.ComputedISize();
    5961           0 :   const WritingMode& wm = gridReflowInput.mWM;
    5962           0 :   LogicalSize computedSize(wm, computedISize, computedBSize);
    5963             : 
    5964           0 :   nscoord consumedBSize = 0;
    5965             :   nscoord bSize;
    5966           0 :   if (!prevInFlow) {
    5967           0 :     Grid grid;
    5968           0 :     grid.PlaceGridItems(gridReflowInput, aReflowInput.ComputedMinSize(),
    5969           0 :                         computedSize, aReflowInput.ComputedMaxSize());
    5970             : 
    5971             :     gridReflowInput.CalculateTrackSizes(grid, computedSize,
    5972           0 :                                         SizingConstraint::eNoConstraint);
    5973           0 :     bSize = computedSize.BSize(wm);
    5974             :   } else {
    5975           0 :     consumedBSize = ConsumedBSize(wm);
    5976           0 :     gridReflowInput.InitializeForContinuation(this, consumedBSize);
    5977           0 :     const uint32_t numRows = gridReflowInput.mRows.mSizes.Length();
    5978             :     bSize = gridReflowInput.mRows.GridLineEdge(numRows,
    5979           0 :                                                GridLineSide::eAfterGridGap);
    5980             :   }
    5981           0 :   if (computedBSize == NS_AUTOHEIGHT) {
    5982           0 :     bSize = NS_CSS_MINMAX(bSize,
    5983             :                           aReflowInput.ComputedMinBSize(),
    5984           0 :                           aReflowInput.ComputedMaxBSize());
    5985             :   } else {
    5986           0 :     bSize = computedBSize;
    5987             :   }
    5988           0 :   bSize = std::max(bSize - consumedBSize, 0);
    5989           0 :   auto& bp = gridReflowInput.mBorderPadding;
    5990           0 :   LogicalRect contentArea(wm, bp.IStart(wm), bp.BStart(wm),
    5991           0 :                           computedISize, bSize);
    5992             : 
    5993           0 :   if (!prevInFlow) {
    5994             :     // Apply 'align/justify-content' to the grid.
    5995             :     // CalculateTrackSizes did the columns.
    5996           0 :     gridReflowInput.mRows.AlignJustifyContent(stylePos, wm, contentArea.Size(wm));
    5997             :   }
    5998             : 
    5999           0 :   bSize = ReflowChildren(gridReflowInput, contentArea, aDesiredSize, aStatus);
    6000           0 :   bSize = std::max(bSize - consumedBSize, 0);
    6001             : 
    6002             :   // Skip our block-end border if we're INCOMPLETE.
    6003           0 :   if (!aStatus.IsComplete() &&
    6004           0 :       !gridReflowInput.mSkipSides.BEnd() &&
    6005           0 :       StyleBorder()->mBoxDecorationBreak !=
    6006             :         StyleBoxDecorationBreak::Clone) {
    6007           0 :     bp.BEnd(wm) = nscoord(0);
    6008             :   }
    6009             : 
    6010           0 :   LogicalSize desiredSize(wm, computedISize + bp.IStartEnd(wm),
    6011           0 :                               bSize         + bp.BStartEnd(wm));
    6012           0 :   aDesiredSize.SetSize(wm, desiredSize);
    6013           0 :   nsRect frameRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height());
    6014           0 :   aDesiredSize.mOverflowAreas.UnionAllWith(frameRect);
    6015             : 
    6016             :   // Convert INCOMPLETE -> OVERFLOW_INCOMPLETE and zero bsize if we're an OC.
    6017           0 :   if (HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER)) {
    6018           0 :     if (!aStatus.IsComplete()) {
    6019           0 :       aStatus.SetOverflowIncomplete();
    6020           0 :       aStatus.SetNextInFlowNeedsReflow();
    6021             :     }
    6022           0 :     bSize = 0;
    6023           0 :     desiredSize.BSize(wm) = bSize + bp.BStartEnd(wm);
    6024           0 :     aDesiredSize.SetSize(wm, desiredSize);
    6025             :   }
    6026             : 
    6027           0 :   if (!gridReflowInput.mInFragmentainer) {
    6028           0 :     MOZ_ASSERT(gridReflowInput.mIter.IsValid());
    6029           0 :     auto sz = frameRect.Size();
    6030           0 :     CalculateBaselines(BaselineSet::eBoth, &gridReflowInput.mIter,
    6031             :                        &gridReflowInput.mGridItems, gridReflowInput.mCols,
    6032           0 :                        0, gridReflowInput.mCols.mSizes.Length(),
    6033           0 :                        wm, sz, bp.IStart(wm),
    6034           0 :                        bp.IEnd(wm), desiredSize.ISize(wm));
    6035           0 :     CalculateBaselines(BaselineSet::eBoth, &gridReflowInput.mIter,
    6036             :                        &gridReflowInput.mGridItems, gridReflowInput.mRows,
    6037           0 :                        0, gridReflowInput.mRows.mSizes.Length(),
    6038           0 :                        wm, sz, bp.BStart(wm),
    6039           0 :                        bp.BEnd(wm), desiredSize.BSize(wm));
    6040             :   } else {
    6041             :     // Only compute 'first baseline' if this fragment contains the first track.
    6042             :     // XXXmats maybe remove this condition? bug 1306499
    6043           0 :     BaselineSet baselines = BaselineSet::eNone;
    6044           0 :     if (gridReflowInput.mStartRow == 0 &&
    6045           0 :         gridReflowInput.mStartRow != gridReflowInput.mNextFragmentStartRow) {
    6046           0 :       baselines = BaselineSet::eFirst;
    6047             :     }
    6048             :     // Only compute 'last baseline' if this fragment contains the last track.
    6049             :     // XXXmats maybe remove this condition? bug 1306499
    6050           0 :     uint32_t len = gridReflowInput.mRows.mSizes.Length();
    6051           0 :     if (gridReflowInput.mStartRow != len &&
    6052           0 :         gridReflowInput.mNextFragmentStartRow == len) {
    6053           0 :       baselines = BaselineSet(baselines | BaselineSet::eLast);
    6054             :     }
    6055           0 :     Maybe<CSSOrderAwareFrameIterator> iter;
    6056           0 :     Maybe<nsTArray<GridItemInfo>> gridItems;
    6057           0 :     if (baselines != BaselineSet::eNone) {
    6058             :       // We need to create a new iterator and GridItemInfo array because we
    6059             :       // might have pushed some children at this point.
    6060             :       // Even if the gridReflowInput iterator is invalid we can reuse its
    6061             :       // state about order to optimize initialization of the new iterator.
    6062             :       // An ordered child list can't become unordered by pushing frames.
    6063             :       // An unordered list can become ordered in a number of cases, but we
    6064             :       // ignore that here and guess that the child list is still unordered.
    6065             :       // XXX this is O(n^2) in the number of items in this fragment: bug 1306705
    6066             :       using Filter = CSSOrderAwareFrameIterator::ChildFilter;
    6067             :       using Order = CSSOrderAwareFrameIterator::OrderState;
    6068           0 :       bool ordered = gridReflowInput.mIter.ItemsAreAlreadyInOrder();
    6069           0 :       auto orderState = ordered ? Order::eKnownOrdered : Order::eKnownUnordered;
    6070           0 :       iter.emplace(this, kPrincipalList, Filter::eSkipPlaceholders, orderState);
    6071           0 :       gridItems.emplace();
    6072           0 :       for (; !iter->AtEnd(); iter->Next()) {
    6073           0 :         auto child = **iter;
    6074           0 :         for (const auto& info : gridReflowInput.mGridItems) {
    6075           0 :           if (info.mFrame == child) {
    6076           0 :             gridItems->AppendElement(info);
    6077             :           }
    6078             :         }
    6079             :       }
    6080             :     }
    6081           0 :     auto sz = frameRect.Size();
    6082           0 :     CalculateBaselines(baselines, iter.ptrOr(nullptr), gridItems.ptrOr(nullptr),
    6083             :                        gridReflowInput.mCols, 0,
    6084           0 :                        gridReflowInput.mCols.mSizes.Length(), wm, sz,
    6085           0 :                        bp.IStart(wm), bp.IEnd(wm), desiredSize.ISize(wm));
    6086           0 :     CalculateBaselines(baselines, iter.ptrOr(nullptr), gridItems.ptrOr(nullptr),
    6087             :                        gridReflowInput.mRows, gridReflowInput.mStartRow,
    6088             :                        gridReflowInput.mNextFragmentStartRow, wm, sz,
    6089           0 :                        bp.BStart(wm), bp.BEnd(wm), desiredSize.BSize(wm));
    6090             :   }
    6091             : 
    6092           0 :   if (HasAnyStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES)) {
    6093             :     // This state bit will never be cleared, since reflow can be called
    6094             :     // multiple times in fragmented grids, and it's challenging to scope
    6095             :     // the bit to only that sequence of calls. This is relatively harmless
    6096             :     // since this bit is only set by accessing a ChromeOnly property, and
    6097             :     // therefore can't unduly slow down normal web browsing.
    6098             : 
    6099             :     // Now that we know column and row sizes and positions, set
    6100             :     // the ComputedGridTrackInfo and related properties
    6101             : 
    6102           0 :     uint32_t colTrackCount = gridReflowInput.mCols.mSizes.Length();
    6103           0 :     nsTArray<nscoord> colTrackPositions(colTrackCount);
    6104           0 :     nsTArray<nscoord> colTrackSizes(colTrackCount);
    6105           0 :     nsTArray<uint32_t> colTrackStates(colTrackCount);
    6106             :     nsTArray<bool> colRemovedRepeatTracks(
    6107           0 :       gridReflowInput.mColFunctions.mRemovedRepeatTracks);
    6108           0 :     uint32_t col = 0;
    6109           0 :     for (const TrackSize& sz : gridReflowInput.mCols.mSizes) {
    6110           0 :       colTrackPositions.AppendElement(sz.mPosition);
    6111           0 :       colTrackSizes.AppendElement(sz.mBase);
    6112           0 :       bool isRepeat = ((col >= gridReflowInput.mColFunctions.mRepeatAutoStart) &&
    6113           0 :                        (col < gridReflowInput.mColFunctions.mRepeatAutoEnd));
    6114             :       colTrackStates.AppendElement(
    6115           0 :           isRepeat ?
    6116             :           (uint32_t)mozilla::dom::GridTrackState::Repeat :
    6117             :           (uint32_t)mozilla::dom::GridTrackState::Static
    6118           0 :       );
    6119             : 
    6120           0 :       col++;
    6121             :     }
    6122             :     ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
    6123             :       gridReflowInput.mColFunctions.mExplicitGridOffset,
    6124           0 :       gridReflowInput.mColFunctions.NumExplicitTracks(),
    6125             :       0,
    6126             :       col,
    6127             :       Move(colTrackPositions),
    6128             :       Move(colTrackSizes),
    6129             :       Move(colTrackStates),
    6130             :       Move(colRemovedRepeatTracks),
    6131           0 :       gridReflowInput.mColFunctions.mRepeatAutoStart);
    6132           0 :     SetProperty(GridColTrackInfo(), colInfo);
    6133             : 
    6134           0 :     uint32_t rowTrackCount = gridReflowInput.mRows.mSizes.Length();
    6135           0 :     nsTArray<nscoord> rowTrackPositions(rowTrackCount);
    6136           0 :     nsTArray<nscoord> rowTrackSizes(rowTrackCount);
    6137           0 :     nsTArray<uint32_t> rowTrackStates(rowTrackCount);
    6138             :     nsTArray<bool> rowRemovedRepeatTracks(
    6139           0 :       gridReflowInput.mRowFunctions.mRemovedRepeatTracks);
    6140           0 :     uint32_t row = 0;
    6141           0 :     for (const TrackSize& sz : gridReflowInput.mRows.mSizes) {
    6142           0 :       rowTrackPositions.AppendElement(sz.mPosition);
    6143           0 :       rowTrackSizes.AppendElement(sz.mBase);
    6144           0 :       bool isRepeat = ((row >= gridReflowInput.mRowFunctions.mRepeatAutoStart) &&
    6145           0 :                        (row < gridReflowInput.mRowFunctions.mRepeatAutoEnd));
    6146             :       rowTrackStates.AppendElement(
    6147           0 :         isRepeat ?
    6148             :         (uint32_t)mozilla::dom::GridTrackState::Repeat :
    6149             :         (uint32_t)mozilla::dom::GridTrackState::Static
    6150           0 :       );
    6151             : 
    6152           0 :       row++;
    6153             :     }
    6154             :     // Row info has to accomodate fragmentation of the grid, which may happen in
    6155             :     // later calls to Reflow. For now, presume that no more fragmentation will
    6156             :     // occur.
    6157             :     ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo(
    6158             :       gridReflowInput.mRowFunctions.mExplicitGridOffset,
    6159           0 :       gridReflowInput.mRowFunctions.NumExplicitTracks(),
    6160             :       gridReflowInput.mStartRow,
    6161             :       row,
    6162             :       Move(rowTrackPositions),
    6163             :       Move(rowTrackSizes),
    6164             :       Move(rowTrackStates),
    6165             :       Move(rowRemovedRepeatTracks),
    6166           0 :       gridReflowInput.mRowFunctions.mRepeatAutoStart);
    6167           0 :     SetProperty(GridRowTrackInfo(), rowInfo);
    6168             : 
    6169           0 :     if (prevInFlow) {
    6170             :       // This frame is fragmenting rows from a previous frame, so patch up
    6171             :       // the prior GridRowTrackInfo with a new end row.
    6172             : 
    6173             :       // FIXME: This can be streamlined and/or removed when bug 1151204 lands.
    6174             : 
    6175             :       ComputedGridTrackInfo* priorRowInfo =
    6176           0 :         prevInFlow->GetProperty(GridRowTrackInfo());
    6177             : 
    6178             :       // Adjust track positions based on the first track in this fragment.
    6179           0 :       if (priorRowInfo->mPositions.Length() >
    6180           0 :           priorRowInfo->mStartFragmentTrack) {
    6181             :         nscoord delta =
    6182           0 :           priorRowInfo->mPositions[priorRowInfo->mStartFragmentTrack];
    6183           0 :         for (nscoord& pos : priorRowInfo->mPositions) {
    6184           0 :           pos -= delta;
    6185             :         }
    6186             :       }
    6187             : 
    6188             :       ComputedGridTrackInfo* revisedPriorRowInfo = new ComputedGridTrackInfo(
    6189             :         priorRowInfo->mNumLeadingImplicitTracks,
    6190             :         priorRowInfo->mNumExplicitTracks,
    6191             :         priorRowInfo->mStartFragmentTrack,
    6192             :         gridReflowInput.mStartRow,
    6193           0 :         Move(priorRowInfo->mPositions),
    6194           0 :         Move(priorRowInfo->mSizes),
    6195           0 :         Move(priorRowInfo->mStates),
    6196           0 :         Move(priorRowInfo->mRemovedRepeatTracks),
    6197           0 :         priorRowInfo->mRepeatFirstTrack);
    6198           0 :       prevInFlow->SetProperty(GridRowTrackInfo(), revisedPriorRowInfo);
    6199             :     }
    6200             : 
    6201             :     // Generate the line info properties. We need to provide the number of
    6202             :     // repeat tracks produced in the reflow. Only explicit names are assigned
    6203             :     // to lines here; the mozilla::dom::GridLines class will later extract
    6204             :     // implicit names from grid areas and assign them to the appropriate lines.
    6205             : 
    6206             :     // Generate column lines first.
    6207           0 :     uint32_t capacity = gridReflowInput.mCols.mSizes.Length();
    6208             :     const nsStyleGridTemplate& gridColTemplate =
    6209           0 :       gridReflowInput.mGridStyle->mGridTemplateColumns;
    6210           0 :     nsTArray<nsTArray<nsString>> columnLineNames(capacity);
    6211           0 :     for (col = 0; col <= gridReflowInput.mCols.mSizes.Length(); col++) {
    6212             :       // Offset col by the explicit grid offset, to get the original names.
    6213             :       nsTArray<nsString> explicitNames =
    6214             :         gridReflowInput.mCols.GetExplicitLineNamesAtIndex(
    6215             :           gridColTemplate,
    6216             :           gridReflowInput.mColFunctions,
    6217           0 :           col - gridReflowInput.mColFunctions.mExplicitGridOffset);
    6218             : 
    6219           0 :       columnLineNames.AppendElement(explicitNames);
    6220             :     }
    6221             :     ComputedGridLineInfo* columnLineInfo = new ComputedGridLineInfo(
    6222             :       Move(columnLineNames),
    6223             :       gridColTemplate.mRepeatAutoLineNameListBefore,
    6224           0 :       gridColTemplate.mRepeatAutoLineNameListAfter);
    6225           0 :     SetProperty(GridColumnLineInfo(), columnLineInfo);
    6226             : 
    6227             :     // Generate row lines next.
    6228           0 :     capacity = gridReflowInput.mRows.mSizes.Length();
    6229             :     const nsStyleGridTemplate& gridRowTemplate =
    6230           0 :       gridReflowInput.mGridStyle->mGridTemplateRows;
    6231           0 :     nsTArray<nsTArray<nsString>> rowLineNames(capacity);
    6232           0 :     for (row = 0; row <= gridReflowInput.mRows.mSizes.Length(); row++) {
    6233             :       // Offset row by the explicit grid offset, to get the original names.
    6234             :       nsTArray<nsString> explicitNames =
    6235             :         gridReflowInput.mRows.GetExplicitLineNamesAtIndex(
    6236             :           gridRowTemplate,
    6237             :           gridReflowInput.mRowFunctions,
    6238           0 :           row - gridReflowInput.mRowFunctions.mExplicitGridOffset);
    6239             : 
    6240           0 :       rowLineNames.AppendElement(explicitNames);
    6241             :     }
    6242             :     ComputedGridLineInfo* rowLineInfo = new ComputedGridLineInfo(
    6243             :       Move(rowLineNames),
    6244             :       gridRowTemplate.mRepeatAutoLineNameListBefore,
    6245           0 :       gridRowTemplate.mRepeatAutoLineNameListAfter);
    6246           0 :     SetProperty(GridRowLineInfo(), rowLineInfo);
    6247             : 
    6248             :     // Generate area info for explicit areas. Implicit areas are handled
    6249             :     // elsewhere.
    6250           0 :     if (gridReflowInput.mGridStyle->mGridTemplateAreas) {
    6251             :       nsTArray<css::GridNamedArea>* areas = new nsTArray<css::GridNamedArea>(
    6252           0 :           gridReflowInput.mGridStyle->mGridTemplateAreas->mNamedAreas);
    6253           0 :       SetProperty(ExplicitNamedAreasProperty(), areas);
    6254             :     } else {
    6255           0 :       DeleteProperty(ExplicitNamedAreasProperty());
    6256             :     }
    6257             :   }
    6258             : 
    6259           0 :   if (!prevInFlow) {
    6260           0 :     SharedGridData* sharedGridData = GetProperty(SharedGridData::Prop());
    6261           0 :     if (!aStatus.IsFullyComplete()) {
    6262           0 :       if (!sharedGridData) {
    6263           0 :         sharedGridData = new SharedGridData;
    6264           0 :         SetProperty(SharedGridData::Prop(), sharedGridData);
    6265             :       }
    6266           0 :       sharedGridData->mCols.mSizes.Clear();
    6267           0 :       sharedGridData->mCols.mSizes.SwapElements(gridReflowInput.mCols.mSizes);
    6268           0 :       sharedGridData->mCols.mContentBoxSize = gridReflowInput.mCols.mContentBoxSize;
    6269           0 :       sharedGridData->mCols.mBaselineSubtreeAlign[0] =
    6270           0 :         gridReflowInput.mCols.mBaselineSubtreeAlign[0];
    6271           0 :       sharedGridData->mCols.mBaselineSubtreeAlign[1] =
    6272           0 :         gridReflowInput.mCols.mBaselineSubtreeAlign[1];
    6273           0 :       sharedGridData->mRows.mSizes.Clear();
    6274           0 :       sharedGridData->mRows.mSizes.SwapElements(gridReflowInput.mRows.mSizes);
    6275             :       // Save the original row grid sizes and gaps so we can restore them later
    6276             :       // in GridReflowInput::Initialize for the continuations.
    6277           0 :       auto& origRowData = sharedGridData->mOriginalRowData;
    6278           0 :       origRowData.ClearAndRetainStorage();
    6279           0 :       origRowData.SetCapacity(sharedGridData->mRows.mSizes.Length());
    6280           0 :       nscoord prevTrackEnd = 0;
    6281           0 :       for (auto& sz : sharedGridData->mRows.mSizes) {
    6282           0 :         SharedGridData::RowData data = {sz.mBase, sz.mPosition - prevTrackEnd};
    6283           0 :         origRowData.AppendElement(data);
    6284           0 :         prevTrackEnd = sz.mPosition + sz.mBase;
    6285             :       }
    6286           0 :       sharedGridData->mRows.mContentBoxSize = gridReflowInput.mRows.mContentBoxSize;
    6287           0 :       sharedGridData->mRows.mBaselineSubtreeAlign[0] =
    6288           0 :         gridReflowInput.mRows.mBaselineSubtreeAlign[0];
    6289           0 :       sharedGridData->mRows.mBaselineSubtreeAlign[1] =
    6290           0 :         gridReflowInput.mRows.mBaselineSubtreeAlign[1];
    6291           0 :       sharedGridData->mGridItems.Clear();
    6292           0 :       sharedGridData->mGridItems.SwapElements(gridReflowInput.mGridItems);
    6293           0 :       sharedGridData->mAbsPosItems.Clear();
    6294           0 :       sharedGridData->mAbsPosItems.SwapElements(gridReflowInput.mAbsPosItems);
    6295             : 
    6296           0 :       sharedGridData->mGenerateComputedGridInfo =
    6297           0 :           HasAnyStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES);
    6298           0 :     } else if (sharedGridData && !GetNextInFlow()) {
    6299           0 :       DeleteProperty(SharedGridData::Prop());
    6300             :     }
    6301             :   }
    6302             : 
    6303           0 :   FinishAndStoreOverflow(&aDesiredSize);
    6304           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
    6305             : }
    6306             : 
    6307             : nscoord
    6308           0 : nsGridContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
    6309             :                                      IntrinsicISizeType  aType)
    6310             : {
    6311           0 :   RenumberList();
    6312             : 
    6313             :   // Calculate the sum of column sizes under intrinsic sizing.
    6314             :   // http://dev.w3.org/csswg/css-grid/#intrinsic-sizes
    6315           0 :   GridReflowInput state(this, *aRenderingContext);
    6316           0 :   InitImplicitNamedAreas(state.mGridStyle); // XXX optimize
    6317             : 
    6318             :   auto GetDefiniteSizes = [] (const nsStyleCoord& aMinCoord,
    6319             :                               const nsStyleCoord& aSizeCoord,
    6320             :                               const nsStyleCoord& aMaxCoord,
    6321             :                               nscoord* aMin,
    6322             :                               nscoord* aSize,
    6323           0 :                               nscoord* aMax) {
    6324           0 :     if (aMinCoord.ConvertsToLength()) {
    6325           0 :       *aMin = aMinCoord.ToLength();
    6326             :     }
    6327           0 :     if (aMaxCoord.ConvertsToLength()) {
    6328           0 :       *aMax = std::max(*aMin, aMaxCoord.ToLength());
    6329             :     }
    6330           0 :     if (aSizeCoord.ConvertsToLength()) {
    6331           0 :       *aSize = Clamp(aSizeCoord.ToLength(), *aMin, *aMax);
    6332             :     }
    6333           0 :   };
    6334             :   // The min/sz/max sizes are the input to the "repeat-to-fill" algorithm:
    6335             :   // https://drafts.csswg.org/css-grid/#auto-repeat
    6336             :   // They're only used for auto-repeat so we skip computing them otherwise.
    6337           0 :   LogicalSize min(state.mWM, 0, 0);
    6338           0 :   LogicalSize sz(state.mWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    6339           0 :   LogicalSize max(state.mWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    6340           0 :   if (state.mColFunctions.mHasRepeatAuto) {
    6341           0 :     GetDefiniteSizes(state.mGridStyle->MinISize(state.mWM),
    6342           0 :                      state.mGridStyle->ISize(state.mWM),
    6343           0 :                      state.mGridStyle->MaxISize(state.mWM),
    6344           0 :                      &min.ISize(state.mWM),
    6345           0 :                      &sz.ISize(state.mWM),
    6346           0 :                      &max.ISize(state.mWM));
    6347             :   }
    6348           0 :   if (state.mRowFunctions.mHasRepeatAuto &&
    6349           0 :       !(state.mGridStyle->mGridAutoFlow & NS_STYLE_GRID_AUTO_FLOW_ROW)) {
    6350             :     // Only 'grid-auto-flow:column' can create new implicit columns, so that's
    6351             :     // the only case where our block-size can affect the number of columns.
    6352           0 :     GetDefiniteSizes(state.mGridStyle->MinBSize(state.mWM),
    6353           0 :                      state.mGridStyle->BSize(state.mWM),
    6354           0 :                      state.mGridStyle->MaxBSize(state.mWM),
    6355           0 :                      &min.BSize(state.mWM),
    6356           0 :                      &sz.BSize(state.mWM),
    6357           0 :                      &max.BSize(state.mWM));
    6358             :   }
    6359             : 
    6360           0 :   Grid grid;
    6361           0 :   grid.PlaceGridItems(state, min, sz, max);  // XXX optimize
    6362           0 :   if (grid.mGridColEnd == 0) {
    6363           0 :     return 0;
    6364             :   }
    6365           0 :   state.mCols.Initialize(state.mColFunctions, state.mGridStyle->mGridColumnGap,
    6366           0 :                          grid.mGridColEnd, NS_UNCONSTRAINEDSIZE);
    6367           0 :   auto constraint = aType == nsLayoutUtils::MIN_ISIZE ?
    6368           0 :     SizingConstraint::eMinContent : SizingConstraint::eMaxContent;
    6369             :   state.mCols.CalculateSizes(state, state.mGridItems, state.mColFunctions,
    6370             :                              NS_UNCONSTRAINEDSIZE, &GridArea::mCols,
    6371           0 :                              constraint);
    6372           0 :   return state.mCols.BackComputedIntrinsicSize(state.mColFunctions,
    6373           0 :                                                state.mGridStyle->mGridColumnGap);
    6374             : }
    6375             : 
    6376             : nscoord
    6377           0 : nsGridContainerFrame::GetMinISize(gfxContext* aRC)
    6378             : {
    6379           0 :   DISPLAY_MIN_WIDTH(this, mCachedMinISize);
    6380           0 :   if (mCachedMinISize == NS_INTRINSIC_WIDTH_UNKNOWN) {
    6381           0 :     mCachedMinISize = IntrinsicISize(aRC, nsLayoutUtils::MIN_ISIZE);
    6382             :   }
    6383           0 :   return mCachedMinISize;
    6384             : }
    6385             : 
    6386             : nscoord
    6387           0 : nsGridContainerFrame::GetPrefISize(gfxContext* aRC)
    6388             : {
    6389           0 :   DISPLAY_PREF_WIDTH(this, mCachedPrefISize);
    6390           0 :   if (mCachedPrefISize == NS_INTRINSIC_WIDTH_UNKNOWN) {
    6391           0 :     mCachedPrefISize = IntrinsicISize(aRC, nsLayoutUtils::PREF_ISIZE);
    6392             :   }
    6393           0 :   return mCachedPrefISize;
    6394             : }
    6395             : 
    6396             : void
    6397           0 : nsGridContainerFrame::MarkIntrinsicISizesDirty()
    6398             : {
    6399           0 :   mCachedMinISize = NS_INTRINSIC_WIDTH_UNKNOWN;
    6400           0 :   mCachedPrefISize = NS_INTRINSIC_WIDTH_UNKNOWN;
    6401           0 :   mBaseline[0][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
    6402           0 :   mBaseline[0][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
    6403           0 :   mBaseline[1][0] = NS_INTRINSIC_WIDTH_UNKNOWN;
    6404           0 :   mBaseline[1][1] = NS_INTRINSIC_WIDTH_UNKNOWN;
    6405           0 :   nsContainerFrame::MarkIntrinsicISizesDirty();
    6406           0 : }
    6407             : 
    6408             : void
    6409           0 : nsGridContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    6410             :                                        const nsRect&           aDirtyRect,
    6411             :                                        const nsDisplayListSet& aLists)
    6412             : {
    6413           0 :   DisplayBorderBackgroundOutline(aBuilder, aLists);
    6414           0 :   if (GetPrevInFlow()) {
    6415           0 :     DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
    6416             :   }
    6417             : 
    6418             :   // Our children are all grid-level boxes, which behave the same as
    6419             :   // inline-blocks in painting, so their borders/backgrounds all go on
    6420             :   // the BlockBorderBackgrounds list.
    6421             :   typedef CSSOrderAwareFrameIterator::OrderState OrderState;
    6422           0 :   OrderState order = HasAnyStateBits(NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
    6423           0 :                        ? OrderState::eKnownOrdered
    6424           0 :                        : OrderState::eKnownUnordered;
    6425             :   CSSOrderAwareFrameIterator iter(this, kPrincipalList,
    6426           0 :                                   CSSOrderAwareFrameIterator::eIncludeAll, order);
    6427           0 :   for (; !iter.AtEnd(); iter.Next()) {
    6428           0 :     nsIFrame* child = *iter;
    6429           0 :     BuildDisplayListForChild(aBuilder, child, aDirtyRect, aLists,
    6430           0 :                              ::GetDisplayFlagsForGridItem(child));
    6431             :   }
    6432           0 : }
    6433             : 
    6434             : bool
    6435           0 : nsGridContainerFrame::DrainSelfOverflowList()
    6436             : {
    6437             :   // Unlike nsContainerFrame::DrainSelfOverflowList we need to merge these lists
    6438             :   // so that the resulting mFrames is in document content order.
    6439             :   // NOTE: nsContainerFrame::AppendFrames/InsertFrames calls this method.
    6440           0 :   AutoFrameListPtr overflowFrames(PresContext(), StealOverflowFrames());
    6441           0 :   if (overflowFrames) {
    6442           0 :     ::MergeSortedFrameLists(mFrames, *overflowFrames, GetContent());
    6443           0 :     return true;
    6444             :   }
    6445           0 :   return false;
    6446             : }
    6447             : 
    6448             : void
    6449           0 : nsGridContainerFrame::AppendFrames(ChildListID aListID, nsFrameList& aFrameList)
    6450             : {
    6451           0 :   NoteNewChildren(aListID, aFrameList);
    6452           0 :   nsContainerFrame::AppendFrames(aListID, aFrameList);
    6453           0 : }
    6454             : 
    6455             : void
    6456           0 : nsGridContainerFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
    6457             :                                    nsFrameList& aFrameList)
    6458             : {
    6459           0 :   NoteNewChildren(aListID, aFrameList);
    6460           0 :   nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
    6461           0 : }
    6462             : 
    6463             : void
    6464           0 : nsGridContainerFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame)
    6465             : {
    6466             : #ifdef DEBUG
    6467             :   ChildListIDs supportedLists =
    6468           0 :     kAbsoluteList | kFixedList | kPrincipalList | kNoReflowPrincipalList;
    6469           0 :   MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
    6470             : 
    6471             :   // Note that kPrincipalList doesn't mean aOldFrame must be on that list.
    6472             :   // It can also be on kOverflowList, in which case it might be a pushed
    6473             :   // item, and if it's the only pushed item our DID_PUSH_ITEMS bit will lie.
    6474           0 :   if (aListID == kPrincipalList && !aOldFrame->GetPrevInFlow()) {
    6475             :     // Since the bit may lie, set the mDidPushItemsBitMayLie value to true for
    6476             :     // ourself and for all our contiguous previous-in-flow nsGridContainerFrames.
    6477           0 :     nsGridContainerFrame* frameThatMayLie = this;
    6478           0 :     do {
    6479           0 :       frameThatMayLie->mDidPushItemsBitMayLie = true;
    6480             :       frameThatMayLie = static_cast<nsGridContainerFrame*>(
    6481           0 :         frameThatMayLie->GetPrevInFlow());
    6482           0 :     } while (frameThatMayLie);
    6483             :   }
    6484             : #endif
    6485             : 
    6486           0 :   nsContainerFrame::RemoveFrame(aListID, aOldFrame);
    6487           0 : }
    6488             : 
    6489             : uint16_t
    6490           0 : nsGridContainerFrame::CSSAlignmentForAbsPosChild(const ReflowInput& aChildRI,
    6491             :                                                  LogicalAxis aLogicalAxis) const
    6492             : {
    6493           0 :   MOZ_ASSERT(aChildRI.mFrame->IsAbsolutelyPositioned(),
    6494             :              "This method should only be called for abspos children");
    6495             : 
    6496           0 :   uint16_t alignment = (aLogicalAxis == eLogicalAxisInline) ?
    6497           0 :     aChildRI.mStylePosition->UsedJustifySelf(StyleContext()) :
    6498           0 :     aChildRI.mStylePosition->UsedAlignSelf(StyleContext());
    6499             : 
    6500             :   // XXX strip off <overflow-position> bits until we implement it
    6501             :   // (bug 1311892)
    6502           0 :   alignment &= ~NS_STYLE_ALIGN_FLAG_BITS;
    6503             : 
    6504           0 :   if (alignment == NS_STYLE_ALIGN_NORMAL) {
    6505             :     // "the 'normal' keyword behaves as 'start' on replaced
    6506             :     // absolutely-positioned boxes, and behaves as 'stretch' on all other
    6507             :     // absolutely-positioned boxes."
    6508             :     // https://drafts.csswg.org/css-align/#align-abspos
    6509             :     // https://drafts.csswg.org/css-align/#justify-abspos
    6510           0 :     alignment = aChildRI.mFrame->IsFrameOfType(nsIFrame::eReplaced) ?
    6511           0 :       NS_STYLE_ALIGN_START : NS_STYLE_ALIGN_STRETCH;
    6512           0 :   } else if (alignment == NS_STYLE_ALIGN_FLEX_START) {
    6513           0 :     alignment = NS_STYLE_ALIGN_START;
    6514           0 :   } else if (alignment == NS_STYLE_ALIGN_FLEX_END) {
    6515           0 :     alignment = NS_STYLE_ALIGN_END;
    6516           0 :   } else if (alignment == NS_STYLE_ALIGN_LEFT ||
    6517             :              alignment == NS_STYLE_ALIGN_RIGHT) {
    6518           0 :     if (aLogicalAxis == eLogicalAxisInline) {
    6519           0 :       const bool isLeft = (alignment == NS_STYLE_ALIGN_LEFT);
    6520           0 :       WritingMode wm = GetWritingMode();
    6521           0 :       alignment = (isLeft == wm.IsBidiLTR()) ? NS_STYLE_ALIGN_START
    6522           0 :                                              : NS_STYLE_ALIGN_END;
    6523             :     } else {
    6524           0 :       alignment = NS_STYLE_ALIGN_START;
    6525           0 :     }
    6526           0 :   } else if (alignment == NS_STYLE_ALIGN_BASELINE) {
    6527           0 :     alignment = NS_STYLE_ALIGN_START;
    6528           0 :   } else if (alignment == NS_STYLE_ALIGN_LAST_BASELINE) {
    6529           0 :     alignment = NS_STYLE_ALIGN_END;
    6530             :   }
    6531             : 
    6532           0 :   return alignment;
    6533             : }
    6534             : 
    6535             : nscoord
    6536           0 : nsGridContainerFrame::SynthesizeBaseline(
    6537             :   const FindItemInGridOrderResult& aGridOrderItem,
    6538             :   LogicalAxis          aAxis,
    6539             :   BaselineSharingGroup aGroup,
    6540             :   const nsSize&        aCBPhysicalSize,
    6541             :   nscoord              aCBSize,
    6542             :   WritingMode          aCBWM)
    6543             : {
    6544           0 :   if (MOZ_UNLIKELY(!aGridOrderItem.mItem)) {
    6545             :     // No item in this fragment - synthesize a baseline from our border-box.
    6546           0 :     return ::SynthesizeBaselineFromBorderBox(aGroup, aCBWM, aCBSize);
    6547             :   }
    6548             :   auto GetBBaseline = [] (BaselineSharingGroup aGroup, WritingMode aWM,
    6549           0 :                           const nsIFrame* aFrame, nscoord* aBaseline) {
    6550           0 :     return aGroup == BaselineSharingGroup::eFirst ?
    6551             :       nsLayoutUtils::GetFirstLineBaseline(aWM, aFrame, aBaseline) :
    6552             :       nsLayoutUtils::GetLastLineBaseline(aWM, aFrame, aBaseline);
    6553           0 :   };
    6554           0 :   nsIFrame* child = aGridOrderItem.mItem->mFrame;
    6555           0 :   nsGridContainerFrame* grid = do_QueryFrame(child);
    6556           0 :   auto childWM = child->GetWritingMode();
    6557           0 :   bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
    6558             :   nscoord baseline;
    6559             :   nscoord start;
    6560             :   nscoord size;
    6561           0 :   if (aAxis == eLogicalAxisBlock) {
    6562           0 :     start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).B(aCBWM);
    6563           0 :     size = child->BSize(aCBWM);
    6564           0 :     if (grid && aGridOrderItem.mIsInEdgeTrack) {
    6565             :       isOrthogonal ? grid->GetIBaseline(aGroup, &baseline) :
    6566           0 :                      grid->GetBBaseline(aGroup, &baseline);
    6567           0 :     } else if (!isOrthogonal && aGridOrderItem.mIsInEdgeTrack) {
    6568           0 :       baseline = child->BaselineBOffset(childWM, aGroup, AlignmentContext::eGrid);
    6569             :     } else {
    6570           0 :       baseline = ::SynthesizeBaselineFromBorderBox(aGroup, childWM, size);
    6571             :     }
    6572             :   } else {
    6573           0 :     start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).I(aCBWM);
    6574           0 :     size = child->ISize(aCBWM);
    6575           0 :     if (grid && aGridOrderItem.mIsInEdgeTrack) {
    6576             :       isOrthogonal ? grid->GetBBaseline(aGroup, &baseline) :
    6577           0 :                      grid->GetIBaseline(aGroup, &baseline);
    6578           0 :     } else if (isOrthogonal && aGridOrderItem.mIsInEdgeTrack &&
    6579           0 :                GetBBaseline(aGroup, childWM, child, &baseline)) {
    6580           0 :       if (aGroup == BaselineSharingGroup::eLast) {
    6581           0 :         baseline = size - baseline; // convert to distance from border-box end
    6582             :       }
    6583             :     } else {
    6584           0 :       baseline = ::SynthesizeBaselineFromBorderBox(aGroup, childWM, size);
    6585             :     }
    6586             :   }
    6587           0 :   return aGroup == BaselineSharingGroup::eFirst ? start + baseline :
    6588           0 :     aCBSize - start - size + baseline;
    6589             : }
    6590             : 
    6591             : void
    6592           0 : nsGridContainerFrame::CalculateBaselines(
    6593             :   BaselineSet                   aBaselineSet,
    6594             :   CSSOrderAwareFrameIterator*   aIter,
    6595             :   const nsTArray<GridItemInfo>* aGridItems,
    6596             :   const Tracks&    aTracks,
    6597             :   uint32_t         aFragmentStartTrack,
    6598             :   uint32_t         aFirstExcludedTrack,
    6599             :   WritingMode      aWM,
    6600             :   const nsSize&    aCBPhysicalSize,
    6601             :   nscoord          aCBBorderPaddingStart,
    6602             :   nscoord          aCBBorderPaddingEnd,
    6603             :   nscoord          aCBSize)
    6604             : {
    6605           0 :   const auto axis = aTracks.mAxis;
    6606           0 :   auto firstBaseline = aTracks.mBaseline[BaselineSharingGroup::eFirst];
    6607           0 :   if (!(aBaselineSet & BaselineSet::eFirst)) {
    6608           0 :     mBaseline[axis][BaselineSharingGroup::eFirst] =
    6609           0 :       ::SynthesizeBaselineFromBorderBox(BaselineSharingGroup::eFirst, aWM,
    6610             :                                         aCBSize);
    6611           0 :   } else if (firstBaseline == NS_INTRINSIC_WIDTH_UNKNOWN) {
    6612             :     FindItemInGridOrderResult gridOrderFirstItem =
    6613             :       FindFirstItemInGridOrder(*aIter, *aGridItems,
    6614             :         axis == eLogicalAxisBlock ? &GridArea::mRows : &GridArea::mCols,
    6615             :         axis == eLogicalAxisBlock ? &GridArea::mCols : &GridArea::mRows,
    6616           0 :         aFragmentStartTrack);
    6617           0 :     mBaseline[axis][BaselineSharingGroup::eFirst] =
    6618           0 :       SynthesizeBaseline(gridOrderFirstItem,
    6619             :                          axis,
    6620             :                          BaselineSharingGroup::eFirst,
    6621             :                          aCBPhysicalSize,
    6622             :                          aCBSize,
    6623             :                          aWM);
    6624             :   } else {
    6625             :     // We have a 'first baseline' group in the start track in this fragment.
    6626             :     // Convert it from track to grid container border-box coordinates.
    6627           0 :     MOZ_ASSERT(!aGridItems->IsEmpty());
    6628           0 :     nscoord gapBeforeStartTrack = aFragmentStartTrack == 0 ?
    6629             :       aTracks.GridLineEdge(aFragmentStartTrack, GridLineSide::eAfterGridGap) :
    6630           0 :       nscoord(0); // no content gap at start of fragment
    6631           0 :     mBaseline[axis][BaselineSharingGroup::eFirst] =
    6632           0 :       aCBBorderPaddingStart + gapBeforeStartTrack + firstBaseline;
    6633             :   }
    6634             : 
    6635           0 :   auto lastBaseline = aTracks.mBaseline[BaselineSharingGroup::eLast];
    6636           0 :   if (!(aBaselineSet & BaselineSet::eLast)) {
    6637           0 :     mBaseline[axis][BaselineSharingGroup::eLast] =
    6638           0 :       ::SynthesizeBaselineFromBorderBox(BaselineSharingGroup::eLast, aWM,
    6639             :                                         aCBSize);
    6640           0 :   } else if (lastBaseline == NS_INTRINSIC_WIDTH_UNKNOWN) {
    6641             :     // For finding items for the 'last baseline' we need to create a reverse
    6642             :     // iterator ('aIter' is the forward iterator from the GridReflowInput).
    6643             :     using Iter = ReverseCSSOrderAwareFrameIterator;
    6644           0 :     auto orderState = aIter->ItemsAreAlreadyInOrder() ?
    6645           0 :       Iter::OrderState::eKnownOrdered : Iter::OrderState::eKnownUnordered;
    6646             :     Iter iter(this, kPrincipalList, Iter::ChildFilter::eSkipPlaceholders,
    6647           0 :               orderState);
    6648           0 :     iter.SetItemCount(aGridItems->Length());
    6649             :     FindItemInGridOrderResult gridOrderLastItem =
    6650             :       FindLastItemInGridOrder(iter, *aGridItems,
    6651             :         axis == eLogicalAxisBlock ? &GridArea::mRows : &GridArea::mCols,
    6652             :         axis == eLogicalAxisBlock ? &GridArea::mCols : &GridArea::mRows,
    6653           0 :         aFragmentStartTrack, aFirstExcludedTrack);
    6654           0 :     mBaseline[axis][BaselineSharingGroup::eLast] =
    6655           0 :       SynthesizeBaseline(gridOrderLastItem,
    6656             :                          axis,
    6657             :                          BaselineSharingGroup::eLast,
    6658             :                          aCBPhysicalSize,
    6659             :                          aCBSize,
    6660             :                          aWM);
    6661             :   } else {
    6662             :     // We have a 'last baseline' group in the end track in this fragment.
    6663             :     // Convert it from track to grid container border-box coordinates.
    6664           0 :     MOZ_ASSERT(!aGridItems->IsEmpty());
    6665           0 :     auto borderBoxStartToEndOfEndTrack = aCBBorderPaddingStart +
    6666           0 :       aTracks.GridLineEdge(aFirstExcludedTrack, GridLineSide::eBeforeGridGap) -
    6667           0 :       aTracks.GridLineEdge(aFragmentStartTrack, GridLineSide::eBeforeGridGap);
    6668           0 :     mBaseline[axis][BaselineSharingGroup::eLast] =
    6669           0 :       (aCBSize - borderBoxStartToEndOfEndTrack) + lastBaseline;
    6670             :   }
    6671           0 : }
    6672             : 
    6673             : #ifdef DEBUG_FRAME_DUMP
    6674             : nsresult
    6675           0 : nsGridContainerFrame::GetFrameName(nsAString& aResult) const
    6676             : {
    6677           0 :   return MakeFrameName(NS_LITERAL_STRING("GridContainer"), aResult);
    6678             : }
    6679             : #endif
    6680             : 
    6681             : void
    6682           0 : nsGridContainerFrame::NoteNewChildren(ChildListID aListID,
    6683             :                                       const nsFrameList& aFrameList)
    6684             : {
    6685             : #ifdef DEBUG
    6686             :   ChildListIDs supportedLists =
    6687           0 :     kAbsoluteList | kFixedList | kPrincipalList | kNoReflowPrincipalList;
    6688           0 :   MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
    6689             : #endif
    6690             : 
    6691           0 :   nsIPresShell* shell = PresContext()->PresShell();
    6692           0 :   for (auto pif = GetPrevInFlow(); pif; pif = pif->GetPrevInFlow()) {
    6693           0 :     if (aListID == kPrincipalList) {
    6694           0 :       pif->AddStateBits(NS_STATE_GRID_DID_PUSH_ITEMS);
    6695             :     }
    6696           0 :     shell->FrameNeedsReflow(pif, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
    6697             :   }
    6698           0 : }
    6699             : 
    6700             : void
    6701           0 : nsGridContainerFrame::MergeSortedOverflow(nsFrameList& aList)
    6702             : {
    6703           0 :   if (aList.IsEmpty()) {
    6704           0 :     return;
    6705             :   }
    6706           0 :   MOZ_ASSERT(!aList.FirstChild()->HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER),
    6707             :              "this is the wrong list to put this child frame");
    6708           0 :   MOZ_ASSERT(aList.FirstChild()->GetParent() == this);
    6709           0 :   nsFrameList* overflow = GetOverflowFrames();
    6710           0 :   if (overflow) {
    6711           0 :     ::MergeSortedFrameLists(*overflow, aList, GetContent());
    6712             :   } else {
    6713           0 :     SetOverflowFrames(aList);
    6714             :   }
    6715             : }
    6716             : 
    6717             : void
    6718           0 : nsGridContainerFrame::MergeSortedExcessOverflowContainers(nsFrameList& aList)
    6719             : {
    6720           0 :   if (aList.IsEmpty()) {
    6721           0 :     return;
    6722             :   }
    6723           0 :   MOZ_ASSERT(aList.FirstChild()->HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER),
    6724             :              "this is the wrong list to put this child frame");
    6725           0 :   MOZ_ASSERT(aList.FirstChild()->GetParent() == this);
    6726           0 :   nsFrameList* eoc = GetPropTableFrames(ExcessOverflowContainersProperty());
    6727           0 :   if (eoc) {
    6728           0 :     ::MergeSortedFrameLists(*eoc, aList, GetContent());
    6729             :   } else {
    6730           0 :     SetPropTableFrames(new (PresContext()->PresShell()) nsFrameList(aList),
    6731           0 :                        ExcessOverflowContainersProperty());
    6732             :   }
    6733             : }
    6734             : 
    6735             : /* static */ nsGridContainerFrame::FindItemInGridOrderResult
    6736           0 : nsGridContainerFrame::FindFirstItemInGridOrder(
    6737             :   CSSOrderAwareFrameIterator& aIter,
    6738             :   const nsTArray<GridItemInfo>& aGridItems,
    6739             :   LineRange GridArea::* aMajor,
    6740             :   LineRange GridArea::* aMinor,
    6741             :   uint32_t aFragmentStartTrack)
    6742             : {
    6743           0 :   FindItemInGridOrderResult result = { nullptr, false };
    6744           0 :   uint32_t minMajor = kTranslatedMaxLine + 1;
    6745           0 :   uint32_t minMinor = kTranslatedMaxLine + 1;
    6746           0 :   aIter.Reset();
    6747           0 :   for (; !aIter.AtEnd(); aIter.Next()) {
    6748           0 :     const GridItemInfo& item = aGridItems[aIter.ItemIndex()];
    6749           0 :     if ((item.mArea.*aMajor).mEnd <= aFragmentStartTrack) {
    6750           0 :       continue; // item doesn't span any track in this fragment
    6751             :     }
    6752           0 :     uint32_t major = (item.mArea.*aMajor).mStart;
    6753           0 :     uint32_t minor = (item.mArea.*aMinor).mStart;
    6754           0 :     if (major < minMajor || (major == minMajor && minor < minMinor)) {
    6755           0 :       minMajor = major;
    6756           0 :       minMinor = minor;
    6757           0 :       result.mItem = &item;
    6758           0 :       result.mIsInEdgeTrack = major == 0U;
    6759             :     }
    6760             :   }
    6761           0 :   return result;
    6762             : }
    6763             : 
    6764             : /* static */ nsGridContainerFrame::FindItemInGridOrderResult
    6765           0 : nsGridContainerFrame::FindLastItemInGridOrder(
    6766             :   ReverseCSSOrderAwareFrameIterator& aIter,
    6767             :   const nsTArray<GridItemInfo>& aGridItems,
    6768             :   LineRange GridArea::* aMajor,
    6769             :   LineRange GridArea::* aMinor,
    6770             :   uint32_t aFragmentStartTrack,
    6771             :   uint32_t aFirstExcludedTrack)
    6772             : {
    6773           0 :   FindItemInGridOrderResult result = { nullptr, false };
    6774           0 :   int32_t maxMajor = -1;
    6775           0 :   int32_t maxMinor = -1;
    6776           0 :   aIter.Reset();
    6777           0 :   int32_t lastMajorTrack = int32_t(aFirstExcludedTrack) - 1;
    6778           0 :   for (; !aIter.AtEnd(); aIter.Next()) {
    6779           0 :     const GridItemInfo& item = aGridItems[aIter.ItemIndex()];
    6780             :     // Subtract 1 from the end line to get the item's last track index.
    6781           0 :     int32_t major = (item.mArea.*aMajor).mEnd - 1;
    6782             :     // Currently, this method is only called with aFirstExcludedTrack ==
    6783             :     // the first track in the next fragment, so we take the opportunity
    6784             :     // to assert this item really belongs to this fragment.
    6785           0 :     MOZ_ASSERT((item.mArea.*aMajor).mStart < aFirstExcludedTrack,
    6786             :                "found an item that belongs to some later fragment");
    6787           0 :     if (major < int32_t(aFragmentStartTrack)) {
    6788           0 :       continue; // item doesn't span any track in this fragment
    6789             :     }
    6790           0 :     int32_t minor = (item.mArea.*aMinor).mEnd - 1;
    6791           0 :     MOZ_ASSERT(minor >= 0 && major >= 0, "grid item must have span >= 1");
    6792           0 :     if (major > maxMajor || (major == maxMajor && minor > maxMinor)) {
    6793           0 :       maxMajor = major;
    6794           0 :       maxMinor = minor;
    6795           0 :       result.mItem = &item;
    6796           0 :       result.mIsInEdgeTrack = major == lastMajorTrack;
    6797             :     }
    6798             :   }
    6799           0 :   return result;
    6800             : }
    6801             : 
    6802             : #ifdef DEBUG
    6803             : void
    6804           0 : nsGridContainerFrame::SetInitialChildList(ChildListID  aListID,
    6805             :                                           nsFrameList& aChildList)
    6806             : {
    6807           0 :   ChildListIDs supportedLists = kAbsoluteList | kFixedList | kPrincipalList;
    6808           0 :   MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
    6809             : 
    6810           0 :   return nsContainerFrame::SetInitialChildList(aListID, aChildList);
    6811             : }
    6812             : 
    6813             : void
    6814           0 : nsGridContainerFrame::SanityCheckGridItemsBeforeReflow() const
    6815             : {
    6816           0 :   ChildListIDs absLists = kAbsoluteList | kFixedList |
    6817           0 :     kOverflowContainersList | kExcessOverflowContainersList;
    6818           0 :   ChildListIDs itemLists = kPrincipalList | kOverflowList;
    6819           0 :   for (const nsIFrame* f = this; f; f = f->GetNextInFlow()) {
    6820           0 :     MOZ_ASSERT(!f->HasAnyStateBits(NS_STATE_GRID_DID_PUSH_ITEMS),
    6821             :                "At start of reflow, we should've pulled items back from all "
    6822             :                "NIFs and cleared NS_STATE_GRID_DID_PUSH_ITEMS in the process");
    6823           0 :     for (nsIFrame::ChildListIterator childLists(f);
    6824           0 :          !childLists.IsDone(); childLists.Next()) {
    6825           0 :       if (!itemLists.Contains(childLists.CurrentID())) {
    6826           0 :         MOZ_ASSERT(absLists.Contains(childLists.CurrentID()),
    6827             :                    "unexpected non-empty child list");
    6828           0 :         continue;
    6829             :       }
    6830           0 :       for (auto child : childLists.CurrentList()) {
    6831           0 :         MOZ_ASSERT(f == this || child->GetPrevInFlow(),
    6832             :                    "all pushed items must be pulled up before reflow");
    6833             :       }
    6834             :     }
    6835             :   }
    6836             :   // If we have a prev-in-flow, each of its children's next-in-flow
    6837             :   // should be one of our children or be null.
    6838           0 :   const auto pif = static_cast<nsGridContainerFrame*>(GetPrevInFlow());
    6839           0 :   if (pif) {
    6840             :     const nsFrameList* oc =
    6841           0 :       GetPropTableFrames(OverflowContainersProperty());
    6842             :     const nsFrameList* eoc =
    6843           0 :       GetPropTableFrames(ExcessOverflowContainersProperty());
    6844             :     const nsFrameList* pifEOC =
    6845           0 :       pif->GetPropTableFrames(ExcessOverflowContainersProperty());
    6846           0 :     for (const nsIFrame* child : pif->GetChildList(kPrincipalList)) {
    6847           0 :       const nsIFrame* childNIF = child->GetNextInFlow();
    6848           0 :       MOZ_ASSERT(!childNIF || mFrames.ContainsFrame(childNIF) ||
    6849             :                  (pifEOC && pifEOC->ContainsFrame(childNIF)) ||
    6850             :                  (oc && oc->ContainsFrame(childNIF)) ||
    6851             :                  (eoc && eoc->ContainsFrame(childNIF)));
    6852             :     }
    6853             :   }
    6854           0 : }
    6855             : 
    6856             : void
    6857           0 : nsGridContainerFrame::TrackSize::Dump() const
    6858             : {
    6859           0 :   printf("mPosition=%d mBase=%d mLimit=%d", mPosition, mBase, mLimit);
    6860             : 
    6861           0 :   printf(" min:");
    6862           0 :   if (mState & eAutoMinSizing) {
    6863           0 :     printf("auto ");
    6864           0 :   } else if (mState & eMinContentMinSizing) {
    6865           0 :     printf("min-content ");
    6866           0 :   } else if (mState & eMaxContentMinSizing) {
    6867           0 :     printf("max-content ");
    6868             :   }
    6869             : 
    6870           0 :   printf(" max:");
    6871           0 :   if (mState & eAutoMaxSizing) {
    6872           0 :     printf("auto ");
    6873           0 :   } else if (mState & eMinContentMaxSizing) {
    6874           0 :     printf("min-content ");
    6875           0 :   } else if (mState & eMaxContentMaxSizing) {
    6876           0 :     printf("max-content ");
    6877           0 :   } else if (mState & eFlexMaxSizing) {
    6878           0 :     printf("flex ");
    6879             :   }
    6880             : 
    6881           0 :   if (mState & eFrozen) {
    6882           0 :     printf("frozen ");
    6883             :   }
    6884           0 :   if (mState & eBreakBefore) {
    6885           0 :     printf("break-before ");
    6886             :   }
    6887           0 : }
    6888             : 
    6889             : #endif // DEBUG
    6890             : 
    6891             : nsGridContainerFrame*
    6892           0 : nsGridContainerFrame::GetGridFrameWithComputedInfo(nsIFrame* aFrame)
    6893             : {
    6894             :   // Prepare a lambda function that we may need to call multiple times.
    6895           0 :   auto GetGridContainerFrame = [](nsIFrame *aFrame) {
    6896             :     // Return the aFrame's content insertion frame, iff it is
    6897             :     // a grid container.
    6898           0 :     nsGridContainerFrame* gridFrame = nullptr;
    6899             : 
    6900           0 :     if (aFrame) {
    6901           0 :       nsIFrame* contentFrame = aFrame->GetContentInsertionFrame();
    6902           0 :       if (contentFrame && (contentFrame->IsGridContainerFrame())) {
    6903           0 :         gridFrame = static_cast<nsGridContainerFrame*>(contentFrame);
    6904             :       }
    6905             :     }
    6906           0 :     return gridFrame;
    6907             :   };
    6908             : 
    6909           0 :   nsGridContainerFrame* gridFrame = GetGridContainerFrame(aFrame);
    6910           0 :   if (gridFrame) {
    6911             :     // if any of our properties are missing, generate them
    6912           0 :     bool reflowNeeded = (!gridFrame->HasProperty(GridColTrackInfo()) ||
    6913           0 :                          !gridFrame->HasProperty(GridRowTrackInfo()) ||
    6914           0 :                          !gridFrame->HasProperty(GridColumnLineInfo()) ||
    6915           0 :                          !gridFrame->HasProperty(GridRowLineInfo()));
    6916             : 
    6917           0 :     if (reflowNeeded) {
    6918             :       // Trigger a reflow that generates additional grid property data.
    6919           0 :       nsIPresShell* shell = gridFrame->PresContext()->PresShell();
    6920           0 :       gridFrame->AddStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES);
    6921             :       shell->FrameNeedsReflow(gridFrame,
    6922             :                               nsIPresShell::eResize,
    6923           0 :                               NS_FRAME_IS_DIRTY);
    6924           0 :       shell->FlushPendingNotifications(FlushType::Layout);
    6925             : 
    6926             :       // Since the reflow may have side effects, get the grid frame again.
    6927           0 :       gridFrame = GetGridContainerFrame(aFrame);
    6928             : 
    6929             :       // Assert the grid properties are present
    6930           0 :       MOZ_ASSERT(!gridFrame ||
    6931             :                   gridFrame->HasProperty(GridColTrackInfo()));
    6932           0 :       MOZ_ASSERT(!gridFrame ||
    6933             :                   gridFrame->HasProperty(GridRowTrackInfo()));
    6934           0 :       MOZ_ASSERT(!gridFrame ||
    6935             :                   gridFrame->HasProperty(GridColumnLineInfo()));
    6936           0 :       MOZ_ASSERT(!gridFrame ||
    6937             :                   gridFrame->HasProperty(GridRowLineInfo()));
    6938             :     }
    6939             :   }
    6940             : 
    6941           0 :   return gridFrame;
    6942             : }

Generated by: LCOV version 1.13