Bug 1221525 part 1 - [css-grid] Break out the grid item measuring reflow code to a separate function. Also, make the size contribution functions take a GridItemInfo instead of a frame, for use in later parts (idempotent patch). r=dholbert
authorMats Palmgren <mats@mozilla.com>
Thu, 02 Jun 2016 17:46:58 +0200
changeset 300180 1ad5e5ff1669c75e73910fbda77c9c4aae7c66c0
parent 300179 212dd0c9cdbbeca1259be8be73a0e0947261a53c
child 300181 0a36a1082b8f4f0fb15f402b8239646841dd812a
push id77840
push usermpalmgren@mozilla.com
push dateThu, 02 Jun 2016 15:47:09 +0000
treeherdermozilla-inbound@2b4dfcc5160c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1221525
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1221525 part 1 - [css-grid] Break out the grid item measuring reflow code to a separate function. Also, make the size contribution functions take a GridItemInfo instead of a frame, for use in later parts (idempotent patch). r=dholbert
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -625,16 +625,18 @@ struct nsGridContainerFrame::GridItemInf
 
   nsIFrame* const mFrame;
   GridArea mArea;
   bool mIsFlexing[2]; // does the item span a flex track? (LogicalAxis index)
   static_assert(mozilla::eLogicalAxisBlock == 0, "unexpected index value");
   static_assert(mozilla::eLogicalAxisInline == 1, "unexpected index value");
 };
 
+using GridItemInfo = nsGridContainerFrame::GridItemInfo;
+
 /**
  * Utility class to find line names.  It provides an interface to lookup line
  * names with a dynamic number of repeat(auto-fill/fit) tracks taken into
  * account.
  */
 class MOZ_STACK_CLASS nsGridContainerFrame::LineNameMap
 {
 public:
@@ -1020,17 +1022,17 @@ struct nsGridContainerFrame::Tracks
    * non-spanning items" in the spec.  Return true if the track has a <flex>
    * max-sizing function, false otherwise.
    */
   bool ResolveIntrinsicSizeStep1(GridReflowState&            aState,
                                  const TrackSizingFunctions& aFunctions,
                                  nscoord                     aPercentageBasis,
                                  IntrinsicISizeType          aConstraint,
                                  const LineRange&            aRange,
-                                 nsIFrame*                   aGridItem);
+                                 const GridItemInfo&         aGridItem);
   /**
    * Collect the tracks which are growable (matching aSelector) into
    * aGrowableTracks, and return the amount of space that can be used
    * to grow those tracks.  Specifically, we return aAvailableSpace minus
    * the sum of mBase's in aPlan (clamped to 0) for the tracks in aRange,
    * or zero when there are no growable tracks.
    * @note aPlan[*].mBase represents a planned new base or limit.
    */
@@ -3176,123 +3178,137 @@ nsGridContainerFrame::Tracks::Initialize
                          aFunctions.MaxSizingFor(i));
   }
   auto gap = nsRuleNode::ComputeCoordPercentCalc(aGridGap, aContentBoxSize);
   mGridGap = std::max(nscoord(0), gap);
   mContentBoxSize = aContentBoxSize;
 }
 
 /**
+ * Reflow aChild in the given aAvailableSize.
+ */
+static nscoord
+MeasuringReflow(nsIFrame*                aChild,
+                const nsHTMLReflowState* aReflowState,
+                nsRenderingContext*      aRC,
+                const LogicalSize&       aAvailableSize)
+{
+  nsContainerFrame* parent = aChild->GetParent();
+  nsPresContext* pc = aChild->PresContext();
+  Maybe<nsHTMLReflowState> dummyParentState;
+  const nsHTMLReflowState* rs = aReflowState;
+  if (!aReflowState) {
+    MOZ_ASSERT(!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW));
+    dummyParentState.emplace(pc, parent, aRC,
+                             LogicalSize(parent->GetWritingMode(), 0,
+                                         NS_UNCONSTRAINEDSIZE),
+                             nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
+    rs = dummyParentState.ptr();
+  }
+#ifdef DEBUG
+  // This will suppress various CRAZY_SIZE warnings for this reflow.
+  parent->Properties().Set(
+    nsContainerFrame::DebugReflowingWithInfiniteISize(), true);
+#endif
+  nsHTMLReflowState childRS(pc, *rs, aChild, aAvailableSize, nullptr,
+                            nsHTMLReflowState::COMPUTE_SIZE_SHRINK_WRAP |
+                            nsHTMLReflowState::COMPUTE_SIZE_USE_AUTO_BSIZE);
+  nsHTMLReflowMetrics childSize(childRS);
+  nsReflowStatus childStatus;
+  const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW;
+  WritingMode wm = childRS.GetWritingMode();
+  parent->ReflowChild(aChild, pc, childSize, childRS, wm,
+                      LogicalPoint(wm), nsSize(), flags, childStatus);
+  parent->FinishReflowChild(aChild, pc, childSize, &childRS, wm,
+                            LogicalPoint(wm), nsSize(), flags);
+#ifdef DEBUG
+    parent->Properties().Delete(nsContainerFrame::DebugReflowingWithInfiniteISize());
+#endif
+  return childSize.BSize(wm);
+}
+
+/**
  * Return the [min|max]-content contribution of aChild to its parent (i.e.
  * the child's margin-box) in aAxis.
  */
 static nscoord
-ContentContribution(nsIFrame*                         aChild,
+ContentContribution(const GridItemInfo&               aGridItem,
                     const nsHTMLReflowState*          aReflowState,
                     nsRenderingContext*               aRC,
                     WritingMode                       aCBWM,
                     LogicalAxis                       aAxis,
                     nsLayoutUtils::IntrinsicISizeType aConstraint,
                     uint32_t                          aFlags = 0)
 {
+  nsIFrame* child = aGridItem.mFrame;
   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
-  nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, aChild, aConstraint,
+  nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, child, aConstraint,
                    aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED);
   if (size == NS_INTRINSIC_WIDTH_UNKNOWN) {
     // We need to reflow the child to find its BSize contribution.
-    WritingMode wm = aChild->GetWritingMode();
-    nsContainerFrame* parent = aChild->GetParent();
-    nsPresContext* pc = aChild->PresContext();
-    Maybe<nsHTMLReflowState> dummyParentState;
-    const nsHTMLReflowState* rs = aReflowState;
-    if (!aReflowState) {
-      MOZ_ASSERT(!parent->HasAnyStateBits(NS_FRAME_IN_REFLOW));
-      dummyParentState.emplace(pc, parent, aRC,
-                               LogicalSize(parent->GetWritingMode(), 0,
-                                           NS_UNCONSTRAINEDSIZE),
-                               nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);
-      rs = dummyParentState.ptr();
-    }
-#ifdef DEBUG
-    // This will suppress various CRAZY_SIZE warnings for this reflow.
-    parent->Properties().Set(
-      nsContainerFrame::DebugReflowingWithInfiniteISize(), true);
-#endif
     // XXX this will give mostly correct results for now (until bug 1174569).
-    LogicalSize availableSize(wm, INFINITE_ISIZE_COORD, NS_UNCONSTRAINEDSIZE);
-    nsHTMLReflowState childRS(pc, *rs, aChild, availableSize, nullptr,
-                              nsHTMLReflowState::COMPUTE_SIZE_SHRINK_WRAP |
-                              nsHTMLReflowState::COMPUTE_SIZE_USE_AUTO_BSIZE);
-    nsHTMLReflowMetrics childSize(childRS);
-    nsReflowStatus childStatus;
-    const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW;
-    parent->ReflowChild(aChild, pc, childSize, childRS, wm,
-                        LogicalPoint(wm), nsSize(), flags, childStatus);
-    parent->FinishReflowChild(aChild, pc, childSize, &childRS, wm,
-                              LogicalPoint(wm), nsSize(), flags);
-    size = childSize.BSize(wm);
-    nsIFrame::IntrinsicISizeOffsetData offsets = aChild->IntrinsicBSizeOffsets();
+    LogicalSize availableSize(child->GetWritingMode(), INFINITE_ISIZE_COORD, NS_UNCONSTRAINEDSIZE);
+    size = ::MeasuringReflow(child, aReflowState, aRC, availableSize);
+    nsIFrame::IntrinsicISizeOffsetData offsets = child->IntrinsicBSizeOffsets();
     size += offsets.hMargin;
     size = nsLayoutUtils::AddPercents(aConstraint, size, offsets.hPctMargin);
-#ifdef DEBUG
-    parent->Properties().Delete(nsContainerFrame::DebugReflowingWithInfiniteISize());
-#endif
   }
   return std::max(size, 0);
 }
 
 static nscoord
-MinContentContribution(nsIFrame*                aChild,
+MinContentContribution(const GridItemInfo&      aGridItem,
                        const nsHTMLReflowState* aRS,
                        nsRenderingContext*      aRC,
                        WritingMode              aCBWM,
                        LogicalAxis              aAxis)
 {
-  return ContentContribution(aChild, aRS, aRC, aCBWM, aAxis,
+  return ContentContribution(aGridItem, aRS, aRC, aCBWM, aAxis,
                              nsLayoutUtils::MIN_ISIZE);
 }
 
 static nscoord
-MaxContentContribution(nsIFrame*                aChild,
+MaxContentContribution(const GridItemInfo&      aGridItem,
                        const nsHTMLReflowState* aRS,
                        nsRenderingContext*      aRC,
                        WritingMode              aCBWM,
                        LogicalAxis              aAxis)
 {
-  return ContentContribution(aChild, aRS, aRC, aCBWM, aAxis,
+  return ContentContribution(aGridItem, aRS, aRC, aCBWM, aAxis,
                              nsLayoutUtils::PREF_ISIZE);
 }
 
 static nscoord
-MinSize(nsIFrame*                aChild,
+MinSize(const GridItemInfo&      aGridItem,
         const nsHTMLReflowState* aRS,
         nsRenderingContext*      aRC,
         WritingMode              aCBWM,
         LogicalAxis              aAxis)
 {
+  nsIFrame* child = aGridItem.mFrame;
   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
-  const nsStylePosition* stylePos = aChild->StylePosition();
+  const nsStylePosition* stylePos = child->StylePosition();
   const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth
                                                       : stylePos->mMinHeight;
   // https://drafts.csswg.org/css-grid/#min-size-auto
   // This calculates the min-content contribution from either a definite
   // min-width (or min-height depending on aAxis), or the "specified /
   // transferred size" for min-width:auto if overflow == visible (as min-width:0
   // otherwise), or NS_UNCONSTRAINEDSIZE for other min-width intrinsic values
   // (which results in always taking the "content size" part below).
   nscoord sz =
-    nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, aChild,
+    nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, child,
                                               nsLayoutUtils::MIN_ISIZE);
   auto unit = style.GetUnit();
   if (unit == eStyleUnit_Enumerated ||
       (unit == eStyleUnit_Auto &&
-       aChild->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) {
+       child->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) {
     // Now calculate the "content size" part and return whichever is smaller.
     MOZ_ASSERT(unit != eStyleUnit_Enumerated || sz == NS_UNCONSTRAINEDSIZE);
-    sz = std::min(sz, ContentContribution(aChild, aRS, aRC, aCBWM, aAxis,
+    sz = std::min(sz, ContentContribution(aGridItem, aRS, aRC, aCBWM, aAxis,
                                           nsLayoutUtils::MIN_ISIZE,
                                           nsLayoutUtils::MIN_INTRINSIC_ISIZE));
   }
   return sz;
 }
 
 void
 nsGridContainerFrame::Tracks::CalculateSizes(
@@ -3349,17 +3365,17 @@ nsGridContainerFrame::Tracks::HasIntrins
 
 bool
 nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
   GridReflowState&            aState,
   const TrackSizingFunctions& aFunctions,
   nscoord                     aPercentageBasis,
   IntrinsicISizeType          aConstraint,
   const LineRange&            aRange,
-  nsIFrame*                   aGridItem)
+  const GridItemInfo&         aGridItem)
 {
   Maybe<nscoord> minContentContribution;
   Maybe<nscoord> maxContentContribution;
   // min sizing
   TrackSize& sz = mSizes[aRange.mStart];
   WritingMode wm = aState.mWM;
   const nsHTMLReflowState* rs = aState.mReflowState;
   nsRenderingContext* rc = &aState.mRenderingContext;
@@ -3441,57 +3457,57 @@ nsGridContainerFrame::Tracks::ResolveInt
   nsRenderingContext* rc = &aState.mRenderingContext;
   WritingMode wm = aState.mWM;
   uint32_t maxSpan = 0; // max span of the step2Items items
   const TrackSize::StateBits flexMin =
     aConstraint == nsLayoutUtils::MIN_ISIZE ? TrackSize::eFlexMinSizing
                                             : TrackSize::StateBits(0);
   iter.Reset();
   for (; !iter.AtEnd(); iter.Next()) {
-    nsIFrame* child = *iter;
-    const GridArea& area = aGridItems[iter.GridItemIndex()].mArea;
+    auto& gridItem = aGridItems[iter.GridItemIndex()];
+    const GridArea& area = gridItem.mArea;
     const LineRange& lineRange = area.*aRange;
     uint32_t span = lineRange.Extent();
     if (span == 1) {
       // Step 1. Size tracks to fit non-spanning items.
-      aGridItems[iter.GridItemIndex()].mIsFlexing[mAxis] =
+      gridItem.mIsFlexing[mAxis] =
         ResolveIntrinsicSizeStep1(aState, aFunctions, aPercentageBasis,
-                                  aConstraint, lineRange, child);
+                                  aConstraint, lineRange, gridItem);
     } else {
       TrackSize::StateBits state = TrackSize::StateBits(0);
       if (HasIntrinsicButNoFlexSizingInRange(lineRange, aConstraint, &state)) {
         // Collect data for Step 2.
         maxSpan = std::max(maxSpan, span);
         if (span >= stateBitsPerSpan.Length()) {
           uint32_t len = 2 * span;
           stateBitsPerSpan.SetCapacity(len);
           for (uint32_t i = stateBitsPerSpan.Length(); i < len; ++i) {
             stateBitsPerSpan.AppendElement(TrackSize::StateBits(0));
           }
         }
         stateBitsPerSpan[span] |= state;
         nscoord minSize = 0;
         if (state & (flexMin | TrackSize::eIntrinsicMinSizing)) { // for 2.1
-          minSize = MinSize(child, aState.mReflowState, rc, wm, mAxis);
+          minSize = MinSize(gridItem, aState.mReflowState, rc, wm, mAxis);
         }
         nscoord minContent = 0;
         if (state & (flexMin | TrackSize::eMinOrMaxContentMinSizing | // for 2.2
                      TrackSize::eIntrinsicMaxSizing)) {               // for 2.5
-          minContent = MinContentContribution(child, aState.mReflowState,
+          minContent = MinContentContribution(gridItem, aState.mReflowState,
                                               rc, wm, mAxis);
         }
         nscoord maxContent = 0;
         if (state & (TrackSize::eMaxContentMinSizing |         // for 2.3
                      TrackSize::eAutoOrMaxContentMaxSizing)) { // for 2.6
-          maxContent = MaxContentContribution(child, aState.mReflowState,
+          maxContent = MaxContentContribution(gridItem, aState.mReflowState,
                                               rc, wm, mAxis);
         }
         step2Items.AppendElement(
           Step2ItemData({span, state, lineRange, minSize,
-                         minContent, maxContent, child}));
+                         minContent, maxContent, *iter}));
       } else {
         aGridItems[iter.GridItemIndex()].mIsFlexing[mAxis] =
           !!(state & TrackSize::eFlexMaxSizing);
       }
     }
   }
 
   // Step 2.
@@ -3739,17 +3755,17 @@ nsGridContainerFrame::Tracks::FindUsedFl
   const nsHTMLReflowState* rs = aState.mReflowState;
   GridItemCSSOrderIterator& iter = aState.mIter;
   iter.Reset();
   // ... the result of 'finding the size of an fr' for each item that spans
   // a flex track with its max-content contribution as 'space to fill'
   for (; !iter.AtEnd(); iter.Next()) {
     const GridItemInfo& item = aGridItems[iter.GridItemIndex()];
     if (item.mIsFlexing[mAxis]) {
-      nscoord spaceToFill = MaxContentContribution(*iter, rs, rc, wm, mAxis);
+      nscoord spaceToFill = MaxContentContribution(item, rs, rc, wm, mAxis);
       if (spaceToFill <= 0) {
         continue;
       }
       // ... and all its spanned tracks as input.
       const LineRange& range =
         mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
       nsTArray<uint32_t> itemFlexTracks;
       for (uint32_t i = range.mStart, end = range.mEnd; i < end; ++i) {
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -101,31 +101,31 @@ public:
 
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowTrackInfo, ComputedGridTrackInfo)
   const ComputedGridTrackInfo* GetComputedTemplateRows()
   {
     return Properties().Get(GridRowTrackInfo());
   }
 
   struct TrackSize;
+  struct GridItemInfo;
 protected:
   static const uint32_t kAutoLine;
   // The maximum line number, in the zero-based translated grid.
   static const uint32_t kTranslatedMaxLine;
   typedef mozilla::LogicalPoint LogicalPoint;
   typedef mozilla::LogicalRect LogicalRect;
   typedef mozilla::LogicalSize LogicalSize;
   typedef mozilla::WritingMode WritingMode;
   typedef mozilla::css::GridNamedArea GridNamedArea;
   typedef mozilla::layout::AutoFrameListPtr AutoFrameListPtr;
   typedef nsLayoutUtils::IntrinsicISizeType IntrinsicISizeType;
   struct Grid;
   struct GridArea;
   class GridItemCSSOrderIterator;
-  struct GridItemInfo;
   struct GridReflowState;
   class LineNameMap;
   struct LineRange;
   struct SharedGridData;
   struct TrackSizingFunctions;
   struct Tracks;
   struct TranslatedLineRange;
   friend nsContainerFrame* NS_NewGridContainerFrame(nsIPresShell* aPresShell,