Bug 1309407 - [css-grid] Apply min/max-sizes after stretching <flex> grid items with an indefinite CB size and re-run the algo with a definite size if the grid size changed. r=dholbert
authorMats Palmgren <mats@mozilla.com>
Wed, 19 Oct 2016 04:20:48 +0200
changeset 318562 682ba994390bd158d90b394d403ac8d2fb85ed74
parent 318561 3b4965bb11c0649ce8e0757c708b6c13d5f1e854
child 318563 dff23ddb74cf190a6d3998a122a68aa0d0c44277
push id20725
push userphilringnalda@gmail.com
push dateThu, 20 Oct 2016 01:36:01 +0000
treeherderfx-team@998ad5a74da8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1309407
milestone52.0a1
Bug 1309407 - [css-grid] Apply min/max-sizes after stretching <flex> grid items with an indefinite CB size and re-run the algo with a definite size if the grid size changed. r=dholbert
layout/generic/nsGridContainerFrame.cpp
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -4647,27 +4647,78 @@ nsGridContainerFrame::Tracks::StretchFle
   for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
     if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
       flexTracks.AppendElement(i);
     }
   }
   if (flexTracks.IsEmpty()) {
     return;
   }
-  float fr = FindUsedFlexFraction(aState, aGridItems, flexTracks,
-                                  aFunctions, aAvailableSize);
-  if (fr != 0.0f) {
-    for (uint32_t i : flexTracks) {
-      float flexFactor = aFunctions.MaxSizingFor(i).GetFlexFractionValue();
-      nscoord flexLength = NSToCoordRound(flexFactor * fr);
-      nscoord& base = mSizes[i].mBase;
-      if (flexLength > base) {
-        base = flexLength;
+  nscoord minSize = 0;
+  nscoord maxSize = NS_UNCONSTRAINEDSIZE;
+  if (aState.mReflowInput) {
+    auto* ri = aState.mReflowInput;
+    minSize = mAxis == eLogicalAxisBlock ? ri->ComputedMinBSize()
+                                         : ri->ComputedMinISize();
+    maxSize = mAxis == eLogicalAxisBlock ? ri->ComputedMaxBSize()
+                                         : ri->ComputedMaxISize();
+  }
+  Maybe<nsTArray<TrackSize>> origSizes;
+  // We iterate twice at most.  The 2nd time if the grid size changed after
+  // applying a min/max-size (can only occur if aAvailableSize is indefinite).
+  while (true) {
+    float fr = FindUsedFlexFraction(aState, aGridItems, flexTracks,
+                                    aFunctions, aAvailableSize);
+    if (fr != 0.0f) {
+      bool applyMinMax = (minSize != 0 || maxSize != NS_UNCONSTRAINEDSIZE) &&
+                         aAvailableSize == NS_UNCONSTRAINEDSIZE;
+      for (uint32_t i : flexTracks) {
+        float flexFactor = aFunctions.MaxSizingFor(i).GetFlexFractionValue();
+        nscoord flexLength = NSToCoordRound(flexFactor * fr);
+        nscoord& base = mSizes[i].mBase;
+        if (flexLength > base) {
+          if (applyMinMax && origSizes.isNothing()) {
+            origSizes.emplace(mSizes);
+          }
+          base = flexLength;
+        }
       }
-    }
+      if (applyMinMax && origSizes.isSome()) {
+        // https://drafts.csswg.org/css-grid/#algo-flex-tracks
+        // "If using this flex fraction would cause the grid to be smaller than
+        // the grid container’s min-width/height (or larger than the grid
+        // container’s max-width/height), then redo this step, treating the free
+        // space as definite [...]"
+        nscoord newSize = 0;
+        for (auto& sz : mSizes) {
+          newSize += sz.mBase;
+        }
+        const auto sumOfGridGaps = SumOfGridGaps();
+        newSize += sumOfGridGaps;
+        if (newSize > maxSize) {
+          aAvailableSize = maxSize;
+        } else if (newSize < minSize) {
+          aAvailableSize = minSize;
+        }
+        if (aAvailableSize != NS_UNCONSTRAINEDSIZE) {
+          // Reset min/max-size to ensure 'applyMinMax' becomes false next time.
+          minSize = 0;
+          maxSize = NS_UNCONSTRAINEDSIZE;
+          aAvailableSize = std::max(0, aAvailableSize - sumOfGridGaps);
+          // Restart with the original track sizes and definite aAvailableSize.
+          mSizes = Move(*origSizes);
+          origSizes.reset();
+          if (aAvailableSize == 0) {
+            break; // zero available size wouldn't change any sizes though...
+          }
+          continue;
+        }
+      }
+    }
+    break;
   }
 }
 
 void
 nsGridContainerFrame::Tracks::AlignJustifyContent(
   const nsStylePosition* aStyle,
   WritingMode            aWM,
   const LogicalSize&     aContainerSize)