Bug 984711 part 5: Add back handling for min-height:auto to nsFlexContainerFrame. r=mats
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 22 Jul 2014 08:24:35 -0700
changeset 195505 24c2f03786ac671248e6497d985a8eb11246901a
parent 195504 fc15aa6922065e4396084fb2d87e4486549a8bf6
child 195506 b2c96bbed41dd1cb1856112eb32628df2b55a47a
push id27184
push userkwierso@gmail.com
push dateWed, 23 Jul 2014 00:39:18 +0000
treeherdermozilla-central@0ad20ad7b70a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs984711, 848539
milestone34.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 984711 part 5: Add back handling for min-height:auto to nsFlexContainerFrame. r=mats This conceptually reverts changeset 7a289f49170f from bug 848539, though the code being modified looks a bit different now.
layout/generic/nsFlexContainerFrame.cpp
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -414,16 +414,32 @@ public:
   nscoord GetMarginBorderPaddingSizeInAxis(AxisOrientationType aAxis) const
   {
     return GetMarginSizeInAxis(aAxis) + GetBorderPaddingSizeInAxis(aAxis);
   }
 
   // Setters
   // =======
 
+  void UpdateMainMinSize(nscoord aNewMinSize)
+  {
+    MOZ_ASSERT(mMainMinSize == 0 ||
+               mFrame->IsThemed(mFrame->StyleDisplay()),
+               "Should only update main min-size for min-height:auto, "
+               "which would initially be resolved as 0 (unless we have an "
+               "additional themed-widget-imposed minimum size)");
+
+    if (aNewMinSize > mMainMinSize) {
+      mMainMinSize = aNewMinSize;
+      // Clamp main-max-size & main-size to be >= new min-size:
+      mMainMaxSize = std::max(mMainMaxSize, aNewMinSize);
+      mMainSize = std::max(mMainSize, aNewMinSize);
+    }
+  }
+
   // This sets our flex base size, and then sets our main size to the
   // resulting "hypothetical main size" (the base size clamped to our
   // main-axis [min,max] sizing constraints).
   void SetFlexBaseSizeAndMainSize(nscoord aNewFlexBaseSize)
   {
     MOZ_ASSERT(!mIsFrozen || mFlexBaseSize == NS_INTRINSICSIZE,
                "flex base size shouldn't change after we're frozen "
                "(unless we're just resolving an intrinsic size)");
@@ -529,20 +545,23 @@ protected:
 
   // Values that we already know in constructor: (and are hence mostly 'const')
   const float mFlexGrow;
   const float mFlexShrink;
 
   const nsMargin mBorderPadding;
   nsMargin mMargin; // non-const because we need to resolve auto margins
 
+  // These are non-const so that we can lazily update them with the item's
+  // intrinsic size (obtained via a "measuring" reflow), when necessary.
+  // (e.g. for "flex-basis:auto;height:auto" & "min-height:auto")
   nscoord mFlexBaseSize;
-
-  const nscoord mMainMinSize;
-  const nscoord mMainMaxSize;
+  nscoord mMainMinSize;
+  nscoord mMainMaxSize;
+
   const nscoord mCrossMinSize;
   const nscoord mCrossMaxSize;
 
   // Values that we compute after constructor:
   nscoord mMainSize;
   nscoord mMainPosn;
   nscoord mCrossSize;
   nscoord mCrossPosn;
@@ -1025,26 +1044,35 @@ nsFlexContainerFrame::
                                   const FlexboxAxisTracker& aAxisTracker)
 {
   if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
     // Nothing to do -- this function is only for measuring flex items
     // in a vertical flex container.
     return;
   }
 
-  if (NS_AUTOHEIGHT != aFlexItem.GetFlexBaseSize()) {
+  // Both "flex-basis:auto;height:auto" & "min-height:auto" require that we
+  // resolve our max-content height.
+  bool isMainSizeAuto = (NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
+
+  // 'min-height:auto' is treated as 0 in most code (e.g. in the reflow state),
+  // so we have to actually go the source & check the style struct:
+  bool isMainMinSizeAuto =
+    (eStyleUnit_Auto ==
+     aFlexItem.Frame()->StylePosition()->mMinHeight.GetUnit());
+
+  if (!isMainSizeAuto && !isMainMinSizeAuto) {
     // Nothing to do; this function's only relevant for flex items
     // with a base size of "auto" (or equivalent).
     // XXXdholbert If & when we handle "min-height: min-content" for flex items,
     // we'll want to resolve that in this function, too.
     return;
   }
 
-  // If we get here, we're vertical and our main size ended up being
-  // unconstrained. We need to use our "max-content" height, which is what we
+  // We need to compute our "max-content" height, which is what we
   // get from reflowing into our available width.
   // Note: This has to come *after* we construct the FlexItem, since we
   // invoke at least one convenience method (ResolveStretchedCrossSize) which
   // requires a FlexItem.
 
   // Give the item a special reflow with "mIsFlexContainerMeasuringHeight"
   // set.  This tells it to behave as if it had "height: auto", regardless
   // of what the "height" property is actually set to.
@@ -1068,26 +1096,28 @@ nsFlexContainerFrame::
                                         aAxisTracker);
   }
 
   if (aFlexItem.IsStretched()) {
     childRSForMeasuringHeight.SetComputedWidth(aFlexItem.GetCrossSize());
     childRSForMeasuringHeight.mFlags.mHResize = true;
   }
 
-  // If this item is flexible (vertically), then we assume that the
-  // computed-height we're reflowing with now could be different
+  // If this item is flexible (vertically), or if we're measuring the
+  // 'auto' min-height and our main-size is something else, then we assume
+  // that the computed-height we're reflowing with now could be different
   // from the one we'll use for this flex item's "actual" reflow later on.
   // In that case, we need to be sure the flex item treats this as a
   // vertical resize, even though none of its ancestors are necessarily
   // being vertically resized.
   // (Note: We don't have to do this for width, because InitResizeFlags
   // will always turn on mHResize on when it sees that the computed width
   // is different from current width, and that's all we need.)
-  if (!aFlexItem.IsFrozen()) {  // Are we flexible?
+  if (!aFlexItem.IsFrozen() ||  // Are we flexible?
+      !isMainSizeAuto) { // Are we *only* measuring this for min-height?
     childRSForMeasuringHeight.mFlags.mVResize = true;
   }
 
   nsHTMLReflowMetrics childDesiredSize(childRSForMeasuringHeight);
   nsReflowStatus childReflowStatus;
   const uint32_t flags = NS_FRAME_NO_MOVE_FRAME;
   ReflowChild(aFlexItem.Frame(), aPresContext,
               childDesiredSize, childRSForMeasuringHeight,
@@ -1102,17 +1132,23 @@ nsFlexContainerFrame::
                     0, 0, flags);
 
   // Subtract border/padding in vertical axis, to get _just_
   // the effective computed value of the "height" property.
   nscoord childDesiredHeight = childDesiredSize.Height() -
     childRSForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom();
   childDesiredHeight = std::max(0, childDesiredHeight);
 
-  aFlexItem.SetFlexBaseSizeAndMainSize(childDesiredHeight);
+  if (isMainSizeAuto) {
+    aFlexItem.SetFlexBaseSizeAndMainSize(childDesiredHeight);
+  }
+  if (isMainMinSizeAuto) {
+    aFlexItem.UpdateMainMinSize(childDesiredHeight);
+  }
+
   aFlexItem.SetHadMeasuringReflow();
 }
 
 FlexItem::FlexItem(nsIFrame* aChildFrame,
                    float aFlexGrow, float aFlexShrink, nscoord aFlexBaseSize,
                    nscoord aMainMinSize,  nscoord aMainMaxSize,
                    nscoord aCrossMinSize, nscoord aCrossMaxSize,
                    nsMargin aMargin, nsMargin aBorderPadding,