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
--- 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
@@ -5668,19 +5668,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,
@@ -5910,19 +5923,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