Bug 1105111 part 3: Add support for 'flex-basis:content' in layout. r=mats
authorDaniel Holbert <dholbert@cs.stanford.edu>
Fri, 30 Mar 2018 16:50:49 -0700
changeset 410911 4df15097883c
parent 410910 46097b1d0225
child 410912 59abb3d013ef
push id62007
push userecoal95@gmail.com
push dateMon, 02 Apr 2018 02:30:59 +0000
treeherderautoland@16eaa1e05dac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs1105111
milestone61.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 1105111 part 3: Add support for 'flex-basis:content' in layout. r=mats BACKGROUND: Early in flex layout, we have to resolve the 'flex-basis' value to produce the "flex base size" (basically, the flex-basis resolved to an absolute length). This resolution happens in two "phases" (which both happen within nsFlexContainer::GenerateFlexItemForChild()): First phase: we try to resolve the flex-basis by creating a ReflowInput for the flex item (which gets us some other things as well). Under the hood, we use the flex-basis when resolving this ReflowInput's main-axis size. The code for this lives in nsFrame::ComputeSize (and in nsFrame::ComputeSizeWithIntrinsicDimensions, via some frame classes' overrides of ComputeSize). Second phase: If the first phase didn't get us a definite size, then that means we have to do reflow to measure the content size & produce a resolved flex base size, which we do via ResolveAutoFlexBasisAndMinSize(). NOTES ON THIS PATCH: To add 'flex-basis:content' support to layout, this patch only needs to modify the first phase discussed above. If it turns out we also have some second-phase work to do (i.e. if we need to do reflow to resolve 'flex-basis:content'), this patch causes that reflow to happen by simply making us use eStyleUnit_Auto in the main axis's nsStyleCoord in the first phase. (And then, if that 'auto' nsStyleCoord really does require reflow, then that first phase will end up producing an unconstrained main-size in the flex item's ReflowInput, which will automatically trigger the second phase.) MozReview-Commit-ID: 2nH4Fh78C81
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -8,16 +8,17 @@
 
 #include "nsContainerFrame.h"
 
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/dom/HTMLSummaryElement.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
+#include "nsFlexContainerFrame.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
 #include "nsPoint.h"
 #include "nsStyleConsts.h"
 #include "nsView.h"
 #include "nsIPresShell.h"
 #include "nsCOMPtr.h"
@@ -841,18 +842,28 @@ nsContainerFrame::ComputeAutoSize(gfxCon
                                   const LogicalSize&  aPadding,
                                   ComputeSizeFlags    aFlags)
 {
   LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
   nscoord availBased = aAvailableISize - aMargin.ISize(aWM) -
                        aBorder.ISize(aWM) - aPadding.ISize(aWM);
   // replaced elements always shrink-wrap
   if ((aFlags & ComputeSizeFlags::eShrinkWrap) || IsFrameOfType(eReplaced)) {
-    // don't bother setting it if the result won't be used
-    if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
+    // Only bother computing our 'auto' ISize if the result will be used.
+    // It'll be used under two scenarios:
+    // - If our ISize property is itself 'auto'.
+    // - If we're using flex-basis in place of our ISize property (i.e. we're a
+    // flex item with our inline axis being the main axis), AND we have
+    // flex-basis:content.
+    const nsStylePosition* pos = StylePosition();
+    if (pos->ISize(aWM).GetUnit() == eStyleUnit_Auto ||
+        (pos->mFlexBasis.GetUnit() == eStyleUnit_Enumerated &&
+         pos->mFlexBasis.GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT &&
+         IsFlexItem() &&
+         nsFlexContainerFrame::IsItemInlineAxisMainAxis(this))) {
       result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
     }
   } else {
     result.ISize(aWM) = availBased;
   }
 
   if (IsTableCaption()) {
     // If we're a container for font size inflation, then shrink
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5669,19 +5669,32 @@ nsFrame::ComputeSize(gfxContext*        
     flexMainAxis = nsFlexContainerFrame::IsItemInlineAxisMainAxis(this) ?
       eLogicalAxisInline : eLogicalAxisBlock;
 
     // NOTE: The logic here should match the similar chunk for determining
     // inlineStyleCoord and blockStyleCoord in
     // nsFrame::ComputeSizeWithIntrinsicDimensions().
     const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
     if (flexBasis->GetUnit() != eStyleUnit_Auto) {
-      // Override whichever styleCoord is in flex container's main axis:
-      (flexMainAxis == eLogicalAxisInline ?
-       inlineStyleCoord : blockStyleCoord) = flexBasis;
+      // Replace our main-axis styleCoord pointer with a different one,
+      // depending on our flex-basis value.
+      auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
+                             ? inlineStyleCoord : blockStyleCoord);
+      if (flexBasis->GetUnit() == eStyleUnit_Enumerated &&
+          flexBasis->GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT) {
+        // We have 'flex-basis: content', which is equivalent to
+        // 'flex-basis:auto; {main-size}: auto'. So, just swap in a dummy
+        // 'auto' value to use for the main size property:
+        static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
+        mainAxisCoord = &autoStyleCoord;
+      } else {
+        // For all other flex-basis values, we just swap in the flex-basis
+        // itself for the main-size property here:
+        mainAxisCoord = flexBasis;
+      }
     }
   }
 
   // Compute inline-axis size
   if (inlineStyleCoord->GetUnit() != eStyleUnit_Auto) {
     result.ISize(aWM) =
       ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
                         boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
@@ -5911,19 +5924,33 @@ nsFrame::ComputeSizeWithIntrinsicDimensi
       // Flex items use their "flex-basis" property in place of their main-size
       // property (e.g. "width") for sizing purposes, *unless* they have
       // "flex-basis:auto", in which case they use their main-size property
       // after all.
       // NOTE: The logic here should match the similar chunk for determining
       // inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize().
       const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
       if (flexBasis->GetUnit() != eStyleUnit_Auto) {
-        // Override whichever styleCoord is in flex container's main axis:
-        (flexMainAxis == eLogicalAxisInline ?
-         inlineStyleCoord : blockStyleCoord) = flexBasis;
+        // Replace our main-axis styleCoord pointer with a different one,
+        // depending on our flex-basis value.
+        auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
+                               ? inlineStyleCoord : blockStyleCoord);
+
+        if (flexBasis->GetUnit() == eStyleUnit_Enumerated &&
+            flexBasis->GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT) {
+          // We have 'flex-basis: content', which is equivalent to
+          // 'flex-basis:auto; {main-size}: auto'. So, just swap in a dummy
+          // 'auto' value to use for the main size property:
+          static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
+          mainAxisCoord = &autoStyleCoord;
+        } else {
+          // For all other flex-basis values, we just swap in the flex-basis
+          // itself for the main-size property here:
+          mainAxisCoord = flexBasis;
+        }
       }
     }
   }
 
   // Handle intrinsic sizes and their interaction with
   // {min-,max-,}{width,height} according to the rules in
   // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths