Bug 1176775 part 1 - [css-grid] Implement "Implied Minimum Size of Grid Items" (special min-width/height:auto behavior). r=dholbert

This commit is contained in:
Mats Palmgren 2015-11-03 21:45:33 +01:00
parent 759f29e87f
commit a09faf6998
4 changed files with 129 additions and 39 deletions

View File

@ -4546,10 +4546,15 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
const nsStylePosition* stylePos = aFrame->StylePosition();
uint8_t boxSizing = stylePos->mBoxSizing;
const nsStyleCoord& styleISize =
horizontalAxis ? stylePos->mWidth : stylePos->mHeight;
const nsStyleCoord& styleMinISize =
horizontalAxis ? stylePos->mMinWidth : stylePos->mMinHeight;
const nsStyleCoord& styleISize =
(aFlags & MIN_INTRINSIC_ISIZE) ? styleMinISize :
(horizontalAxis ? stylePos->mWidth : stylePos->mHeight);
MOZ_ASSERT(!(aFlags & MIN_INTRINSIC_ISIZE) ||
styleISize.GetUnit() == eStyleUnit_Auto ||
styleISize.GetUnit() == eStyleUnit_Enumerated,
"should only use MIN_INTRINSIC_ISIZE for intrinsic values");
const nsStyleCoord& styleMaxISize =
horizontalAxis ? stylePos->mMaxWidth : stylePos->mMaxHeight;
@ -4765,9 +4770,9 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
IntrinsicISizeType aType,
uint32_t aFlags)
{
NS_PRECONDITION(aFrame, "null frame");
NS_PRECONDITION(aFrame->GetParent(),
"MinSizeContributionForAxis called on frame not in tree");
MOZ_ASSERT(aFrame);
MOZ_ASSERT(aFrame->IsFlexOrGridItem(),
"only grid/flex items have this behavior currently");
#ifdef DEBUG_INTRINSIC_WIDTH
nsFrame::IndentBy(stderr, gNoiseIndent);
@ -4777,6 +4782,46 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
aWM.IsVertical() ? "vertical" : "horizontal");
#endif
const nsStylePosition* const stylePos = aFrame->StylePosition();
const nsStyleCoord* style = aAxis == eAxisHorizontal ? &stylePos->mMinWidth
: &stylePos->mMinHeight;
nscoord minSize;
nscoord* fixedMinSize = nullptr;
auto minSizeUnit = style->GetUnit();
if (minSizeUnit == eStyleUnit_Auto) {
if (aFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) {
style = aAxis == eAxisHorizontal ? &stylePos->mWidth
: &stylePos->mHeight;
if (GetAbsoluteCoord(*style, minSize)) {
// We have a definite width/height. This is the "specified size" in:
// https://drafts.csswg.org/css-grid/#min-size-auto
fixedMinSize = &minSize;
}
// XXX the "transferred size" piece is missing (bug 1218178)
} else {
// min-[width|height]:auto with overflow != visible computes to zero.
minSize = 0;
fixedMinSize = &minSize;
}
} else if (GetAbsoluteCoord(*style, minSize)) {
fixedMinSize = &minSize;
} else if (minSizeUnit != eStyleUnit_Enumerated) {
MOZ_ASSERT(style->HasPercent());
minSize = 0;
fixedMinSize = &minSize;
}
if (!fixedMinSize) {
// Let the caller deal with the "content size" cases.
#ifdef DEBUG_INTRINSIC_WIDTH
nsFrame::IndentBy(stderr, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stderr);
printf_stderr(" %s min-isize is indefinite.\n",
aType == MIN_ISIZE ? "min" : "pref");
#endif
return NS_UNCONSTRAINEDSIZE;
}
// If aFrame is a container for font size inflation, then shrink
// wrapping inside of it should not apply font size inflation.
AutoMaybeDisableFontInflation an(aFrame);
@ -4788,18 +4833,13 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis,
: aFrame->IntrinsicBSizeOffsets();
nscoord result = 0;
nscoord min = 0;
const nsStylePosition* stylePos = aFrame->StylePosition();
uint8_t boxSizing = stylePos->mBoxSizing;
const nsStyleCoord& style = aAxis == eAxisHorizontal ? stylePos->mMinWidth
: stylePos->mMinHeight;
nscoord minSize;
nscoord* fixedMinSize = nullptr;
if (GetAbsoluteCoord(style, minSize)) {
fixedMinSize = &minSize;
}
result = AddIntrinsicSizeOffset(aRC, aFrame, offsets, aType, boxSizing,
result, min, style, fixedMinSize,
style, fixedMinSize, style, aFlags, aAxis);
const nsStyleCoord& maxISize =
aAxis == eAxisHorizontal ? stylePos->mMaxWidth : stylePos->mMaxHeight;
result = AddIntrinsicSizeOffset(aRC, aFrame, offsets, aType,
stylePos->mBoxSizing,
result, min, *style, fixedMinSize,
*style, nullptr, maxISize, aFlags, aAxis);
#ifdef DEBUG_INTRINSIC_WIDTH
nsFrame::IndentBy(stderr, gNoiseIndent);

View File

@ -1324,10 +1324,13 @@ public:
* variations if that's what matches aAxis) and its padding, border and margin
* in the corresponding dimension.
*/
enum IntrinsicISizeType { MIN_ISIZE, PREF_ISIZE };
enum class IntrinsicISizeType { MIN_ISIZE, PREF_ISIZE };
static const auto MIN_ISIZE = IntrinsicISizeType::MIN_ISIZE;
static const auto PREF_ISIZE = IntrinsicISizeType::PREF_ISIZE;
enum {
IGNORE_PADDING = 0x01,
BAIL_IF_REFLOW_NEEDED = 0x02, // returns NS_INTRINSIC_WIDTH_UNKNOWN if so
MIN_INTRINSIC_ISIZE = 0x04, // use min-width/height instead of width/height
};
static nscoord IntrinsicForAxis(mozilla::PhysicalAxis aAxis,
nsRenderingContext* aRenderingContext,
@ -1343,10 +1346,20 @@ public:
uint32_t aFlags = 0);
/**
* Get the contribution of aFrame for the given physical axis.
* Get the definite size contribution of aFrame for the given physical axis.
* This considers the child's 'min-width' property (or 'min-height' if the
* given axis is vertical), and its padding, border, and margin in the
* corresponding dimension.
* corresponding dimension. If the 'min-' property is 'auto' (and 'overflow'
* is 'visible') and the corresponding 'width'/'height' is definite it returns
* the "specified / transferred size" for:
* https://drafts.csswg.org/css-grid/#min-size-auto
* Note that any percentage in 'width'/'height' makes it count as indefinite.
* If the 'min-' property is 'auto' and 'overflow' is not 'visible', then it
* calculates the result as if the 'min-' computed value is zero.
* Otherwise, return NS_UNCONSTRAINEDSIZE.
*
* @note this behavior is specific to Grid/Flexbox (currently) so aFrame
* should be a grid/flex item.
*/
static nscoord MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis,
nsRenderingContext* aRC,

View File

@ -4300,6 +4300,9 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const LogicalSize& aPadding,
ComputeSizeFlags aFlags)
{
MOZ_ASSERT(GetIntrinsicRatio() == nsSize(0,0),
"Please override this method and call "
"nsLayoutUtils::ComputeSizeWithIntrinsicDimensions instead.");
LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
aCBSize, aAvailableISize,
aMargin, aBorder, aPadding,
@ -4321,9 +4324,12 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
bool isFlexItem = IsFlexItem();
nsIAtom* parentFrameType = GetParent() ? GetParent()->GetType() : nullptr;
bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame &&
!(GetStateBits() & NS_FRAME_OUT_OF_FLOW));
bool isFlexItem = (parentFrameType == nsGkAtoms::flexContainerFrame &&
!(GetStateBits() & NS_FRAME_OUT_OF_FLOW));
bool isInlineFlexItem = false;
if (isFlexItem) {
// Flex items use their "flex-basis" property in place of their main-size
// property (e.g. "width") for sizing purposes, *unless* they have
@ -4365,14 +4371,14 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
*inlineStyleCoord);
}
const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
// Flex items ignore their min & max sizing properties in their
// flex container's main-axis. (Those properties get applied later in
// the flexbox algorithm.)
const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
nscoord maxISize = NS_UNCONSTRAINEDSIZE;
if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
!(isFlexItem && isInlineFlexItem)) {
nscoord maxISize =
maxISize =
nsLayoutUtils::ComputeISizeValue(aRenderingContext, this,
aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
maxISizeCoord);
@ -4380,7 +4386,6 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
}
const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
nscoord minISize;
if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
!(isFlexItem && isInlineFlexItem)) {
@ -4388,6 +4393,13 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
nsLayoutUtils::ComputeISizeValue(aRenderingContext, this,
aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
minISizeCoord);
} else if (MOZ_UNLIKELY(isGridItem)) {
// This implements "Implied Minimum Size of Grid Items".
// https://drafts.csswg.org/css-grid/#min-size-auto
minISize = std::min(maxISize, GetMinISize(aRenderingContext));
if (inlineStyleCoord->IsCoordPercentCalcUnit()) {
minISize = std::min(minISize, result.ISize(aWM));
}
} else {
// Treat "min-width: auto" as 0.
// NOTE: Technically, "auto" is supposed to behave like "min-content" on

View File

@ -1938,15 +1938,6 @@ nsGridContainerFrame::Tracks::Initialize(
}
}
static nscoord
MinSize(nsIFrame* aChild, nsRenderingContext* aRC, WritingMode aCBWM,
LogicalAxis aAxis, nsLayoutUtils::IntrinsicISizeType aConstraint)
{
PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
return nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, aChild,
aConstraint);
}
/**
* Return the [min|max]-content contribution of aChild to its parent (i.e.
* the child's margin-box) in aAxis.
@ -1957,11 +1948,12 @@ ContentContribution(nsIFrame* aChild,
nsRenderingContext* aRC,
WritingMode aCBWM,
LogicalAxis aAxis,
nsLayoutUtils::IntrinsicISizeType aConstraint)
nsLayoutUtils::IntrinsicISizeType aConstraint,
uint32_t aFlags = 0)
{
PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, aChild, aConstraint,
nsLayoutUtils::BAIL_IF_REFLOW_NEEDED);
aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED);
if (size == NS_INTRINSIC_WIDTH_UNKNOWN) {
// We need to reflow the child to find its BSize contribution.
WritingMode wm = aChild->GetWritingMode();
@ -2025,6 +2017,39 @@ MaxContentContribution(nsIFrame* aChild,
nsLayoutUtils::PREF_ISIZE);
}
static nscoord
MinSize(nsIFrame* aChild,
const nsHTMLReflowState* aRS,
nsRenderingContext* aRC,
WritingMode aCBWM,
LogicalAxis aAxis)
{
PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
const nsStylePosition* stylePos = aChild->StylePosition();
const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth
: stylePos->mMinHeight;
// 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).
nscoord sz =
nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, aChild,
nsLayoutUtils::MIN_ISIZE);
auto unit = style.GetUnit();
if (unit == eStyleUnit_Enumerated ||
(unit == eStyleUnit_Auto &&
aChild->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(aChild, aRS, aRC, aCBWM, aAxis,
nsLayoutUtils::MIN_ISIZE,
nsLayoutUtils::MIN_INTRINSIC_ISIZE));
}
return sz;
}
void
nsGridContainerFrame::Tracks::CalculateSizes(
GridReflowState& aState,
@ -2112,7 +2137,7 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
const nsHTMLReflowState* rs = aState.mReflowState;
nsRenderingContext* rc = &aState.mRenderingContext;
if (sz.mState & TrackSize::eAutoMinSizing) {
nscoord s = MinSize(aGridItem, rc, wm, mAxis, aConstraint);
nscoord s = MinSize(aGridItem, rs, rc, wm, mAxis);
sz.mBase = std::max(sz.mBase, s);
} else if ((sz.mState & TrackSize::eMinContentMinSizing) ||
(aConstraint == nsLayoutUtils::MIN_ISIZE &&
@ -2217,7 +2242,7 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
stateBitsPerSpan[span] |= state;
nscoord minSize = 0;
if (state & (flexMin | TrackSize::eIntrinsicMinSizing)) { // for 2.1
minSize = MinSize(child, rc, wm, mAxis, aConstraint);
minSize = MinSize(child, aState.mReflowState, rc, wm, mAxis);
}
nscoord minContent = 0;
if (state & (flexMin | TrackSize::eMinOrMaxContentMinSizing | // for 2.2