Bug 1255393 part 4 - [css-grid] Cache min/max-content and min-size contributions better. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Tue, 27 Sep 2016 17:05:41 +0200
changeset 315471 580d291f1771e8122540b24dbfe587539bdda618
parent 315470 622d8de79f0c165e1431c7337ba9bd18064556db
child 315472 35d48b9fededaa5366e2d956af7d88e21d47b99c
push id32628
push usercbook@mozilla.com
push dateWed, 28 Sep 2016 14:56:02 +0000
treeherderautoland@3a5db9f20b43 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1255393
milestone52.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 1255393 part 4 - [css-grid] Cache min/max-content and min-size contributions better. r=dholbert
layout/generic/nsGridContainerFrame.cpp
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -3637,54 +3637,80 @@ ContentContribution(const GridItemInfo& 
              "baseline offset should be non-negative at this point");
   MOZ_ASSERT((aGridItem.mState[aAxis] & ItemState::eIsBaselineAligned) ||
              aGridItem.mBaselineOffset[aAxis] == nscoord(0),
              "baseline offset should be zero when not baseline-aligned");
   size += aGridItem.mBaselineOffset[aAxis];
   return std::max(size, 0);
 }
 
+struct CachedIntrinsicSizes
+{
+  Maybe<nscoord> mMinSize;
+  Maybe<nscoord> mMinContentContribution;
+  Maybe<nscoord> mMaxContentContribution;
+};
+
 static nscoord
 MinContentContribution(const GridItemInfo&    aGridItem,
                        const GridReflowInput& aState,
                        nsRenderingContext*    aRC,
                        WritingMode            aCBWM,
-                       LogicalAxis            aAxis)
+                       LogicalAxis            aAxis,
+                       CachedIntrinsicSizes*  aCache)
 {
-  return ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
-                             nsLayoutUtils::MIN_ISIZE);
+  if (aCache->mMinContentContribution.isSome()) {
+    return aCache->mMinContentContribution.value();
+  }
+  nscoord s = ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
+                                  nsLayoutUtils::MIN_ISIZE);
+  aCache->mMinContentContribution.emplace(s);
+  return s;
 }
 
 static nscoord
 MaxContentContribution(const GridItemInfo&    aGridItem,
                        const GridReflowInput& aState,
                        nsRenderingContext*    aRC,
                        WritingMode            aCBWM,
-                       LogicalAxis            aAxis)
+                       LogicalAxis            aAxis,
+                       CachedIntrinsicSizes*  aCache)
 {
-  return ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
-                             nsLayoutUtils::PREF_ISIZE);
+  if (aCache->mMaxContentContribution.isSome()) {
+    return aCache->mMaxContentContribution.value();
+  }
+  nscoord s = ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
+                                  nsLayoutUtils::PREF_ISIZE);
+  aCache->mMaxContentContribution.emplace(s);
+  return s;
 }
 
 // Computes the min-size contribution for a grid item, as defined at
 // https://drafts.csswg.org/css-grid/#min-size-contributions
 static nscoord
 MinSize(const GridItemInfo&    aGridItem,
         const GridReflowInput& aState,
         nsRenderingContext*    aRC,
         WritingMode            aCBWM,
-        LogicalAxis            aAxis)
+        LogicalAxis            aAxis,
+        CachedIntrinsicSizes*  aCache)
 {
+  if (aCache->mMinSize.isSome()) {
+    return aCache->mMinSize.value();
+  }
   nsIFrame* child = aGridItem.mFrame;
   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
   const nsStylePosition* stylePos = child->StylePosition();
   const nsStyleCoord& sizeStyle =
     axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight;
   if (sizeStyle.GetUnit() != eStyleUnit_Auto) {
-    return MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis);
+    nscoord s =
+      MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache);
+    aCache->mMinSize.emplace(s);
+    return s;
   }
 
   // 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).
@@ -3703,16 +3729,17 @@ MinSize(const GridItemInfo&    aGridItem
       (unit == eStyleUnit_Auto &&
        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(aGridItem, aState, aRC, aCBWM, aAxis,
                                           nsLayoutUtils::MIN_ISIZE,
                                           nsLayoutUtils::MIN_INTRINSIC_ISIZE));
   }
+  aCache->mMinSize.emplace(sz);
   return sz;
 }
 
 void
 nsGridContainerFrame::Tracks::CalculateSizes(
   GridReflowInput&            aState,
   nsTArray<GridItemInfo>&     aGridItems,
   const TrackSizingFunctions& aFunctions,
@@ -3769,65 +3796,56 @@ bool
 nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
   GridReflowInput&            aState,
   const TrackSizingFunctions& aFunctions,
   nscoord                     aPercentageBasis,
   SizingConstraint            aConstraint,
   const LineRange&            aRange,
   const GridItemInfo&         aGridItem)
 {
-  Maybe<nscoord> minContentContribution;
-  Maybe<nscoord> maxContentContribution;
+  CachedIntrinsicSizes cache;
   // min sizing
   TrackSize& sz = mSizes[aRange.mStart];
   WritingMode wm = aState.mWM;
   nsRenderingContext* rc = &aState.mRenderingContext;
   if (sz.mState & TrackSize::eAutoMinSizing) {
     nscoord s;
     if (aConstraint == SizingConstraint::eMinContent) {
-      s = MinContentContribution(aGridItem, aState, rc, wm, mAxis);
+      s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     } else if (aConstraint == SizingConstraint::eMaxContent) {
-      s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis);
+      s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     } else {
       MOZ_ASSERT(aConstraint == SizingConstraint::eNoConstraint);
-      s = MinSize(aGridItem, aState, rc, wm, mAxis);
+      s = MinSize(aGridItem, aState, rc, wm, mAxis, &cache);
     }
     sz.mBase = std::max(sz.mBase, s);
   } else if ((sz.mState & TrackSize::eMinContentMinSizing) ||
              (aConstraint == SizingConstraint::eMinContent &&
               (sz.mState & TrackSize::eFlexMinSizing))) {
-    nscoord s = MinContentContribution(aGridItem, aState, rc, wm, mAxis);
-    minContentContribution.emplace(s);
-    sz.mBase = std::max(sz.mBase, minContentContribution.value());
+    auto s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
+    sz.mBase = std::max(sz.mBase, s);
   } else if (sz.mState & TrackSize::eMaxContentMinSizing) {
-    nscoord s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis);
-    maxContentContribution.emplace(s);
-    sz.mBase = std::max(sz.mBase, maxContentContribution.value());
+    auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
+    sz.mBase = std::max(sz.mBase, s);
   }
   // max sizing
   if (sz.mState & TrackSize::eMinContentMaxSizing) {
-    if (minContentContribution.isNothing()) {
-      nscoord s = MinContentContribution(aGridItem, aState, rc, wm, mAxis);
-      minContentContribution.emplace(s);
-    }
+    auto s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
-      sz.mLimit = minContentContribution.value();
+      sz.mLimit = s;
     } else {
-      sz.mLimit = std::max(sz.mLimit, minContentContribution.value());
+      sz.mLimit = std::max(sz.mLimit, s);
     }
   } else if (sz.mState & (TrackSize::eAutoMaxSizing |
                           TrackSize::eMaxContentMaxSizing)) {
-    if (maxContentContribution.isNothing()) {
-      nscoord s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis);
-      maxContentContribution.emplace(s);
-    }
+    auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
-      sz.mLimit = maxContentContribution.value();
+      sz.mLimit = s;
     } else {
-      sz.mLimit = std::max(sz.mLimit, maxContentContribution.value());
+      sz.mLimit = std::max(sz.mLimit, s);
     }
     if (MOZ_UNLIKELY(sz.mState & TrackSize::eFitContent)) {
       // Clamp mLimit to the fit-content() size, for ยง12.5.1.
       auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
       nscoord fitContentClamp =
         nsRuleNode::ComputeCoordPercentCalc(maxCoord, aPercentageBasis);
       sz.mLimit = std::min(sz.mLimit, fitContentClamp);
     }
@@ -4158,31 +4176,32 @@ nsGridContainerFrame::Tracks::ResolveInt
         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;
+        CachedIntrinsicSizes cache;
         nscoord minSize = 0;
         if (state & (flexMin | TrackSize::eIntrinsicMinSizing)) { // for 2.1
-          minSize = MinSize(gridItem, aState, rc, wm, mAxis);
+          minSize = MinSize(gridItem, aState, rc, wm, mAxis, &cache);
         }
         nscoord minContent = 0;
         if (state & (flexMin | TrackSize::eMinOrMaxContentMinSizing | // for 2.2
                      TrackSize::eIntrinsicMaxSizing)) {               // for 2.5
           minContent = MinContentContribution(gridItem, aState,
-                                              rc, wm, mAxis);
+                                              rc, wm, mAxis, &cache);
         }
         nscoord maxContent = 0;
         if (state & (TrackSize::eMaxContentMinSizing |         // for 2.3
                      TrackSize::eAutoOrMaxContentMaxSizing)) { // for 2.6
           maxContent = MaxContentContribution(gridItem, aState,
-                                              rc, wm, mAxis);
+                                              rc, wm, mAxis, &cache);
         }
         step2Items.AppendElement(
           Step2ItemData({span, state, lineRange, minSize,
                          minContent, maxContent, *iter}));
       } else if (state & TrackSize::eFlexMaxSizing) {
         gridItem.mState[mAxis] |= ItemState::eIsFlexing;
       }
     }
@@ -4434,17 +4453,19 @@ nsGridContainerFrame::Tracks::FindUsedFl
   nsRenderingContext* rc = &aState.mRenderingContext;
   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.mState[mAxis] & ItemState::eIsFlexing) {
-      nscoord spaceToFill = MaxContentContribution(item, aState, rc, wm, mAxis);
+      // XXX optimize: bug 1194446
+      nscoord spaceToFill = ContentContribution(item, aState, rc, wm, mAxis,
+                                                nsLayoutUtils::PREF_ISIZE);
       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) {