Issue #1230 - Part 1: Fix Back-computing percentages for intrinsic sizing in Layout CSS-Grid

List of relevant patches applied:

1398537 part 2 - [css-multicol] Implement percentages for 'column-gap' (Gecko part).

1434478 part 1 - [css-grid] Stop back-computing percentage grid gaps when the percentage basis is indefinite. Treat them as zero sized instead.

1434478 part 2 - Stop back-computing percentage padding/margin when the percentage basis is indefinite. Treat them as zero sized instead.

1434478 part 3 - Remove IntrinsicISizeOffsetData::hPctPadding/hPctMargin members since they are now unused.

1434478 part 4 - Factor out constants like NS_UNCONSTRAINEDSIZE so they can be used in headers without needing nsIFrame.h (idempotent patch).

1434478 part 5 - Create nsLayoutUtils::ResolveToLength for resolving CSS <length-percentage> (idempotent patch).

1434478 part 6 - Propagate a percentage basis to nsIFrame::IntrinsicISizeOffsets for resolving padding/margin.

This is needed only for CSS Grid since in other cases we're only using IntrinsicISizeOffsets in the inline-axis and the percentage basis is always indefinite for *intrinsic sizing*. When calculating the intrinsic size of grid items in the grid container's block axis however, we do have a definite size for the grid area in the inline-axis and it should be used per: https://drafts.csswg.org/css-grid/#algo-overview "2. Next, the track sizing algorithm resolves the sizes of the grid rows, using the grid column sizes calculated in the previous step." (Percentage padding/margin for grid items is always resolved against the grid area's inline-size nowadays.)
This commit is contained in:
Gaming4JC 2019-09-28 23:36:05 -04:00 • committed by Roy Tam
commit e4c397f0d9
16 changed files with 240 additions and 319 deletions

View file

@ -6,6 +6,7 @@
#ifndef nsLayoutUtils_h__
#define nsLayoutUtils_h__
#include "LayoutConstants.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Maybe.h"
@ -154,6 +155,7 @@ public:
typedef mozilla::ScreenMargin ScreenMargin;
typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
typedef mozilla::StyleGeometryBox StyleGeometryBox;
typedef mozilla::LogicalSize LogicalSize;
/**
* Finds previously assigned ViewID for the given content element, if any.
@ -1381,7 +1383,8 @@ public:
* variations if that's what matches aAxis) and its padding, border and margin
* in the corresponding dimension.
* @param aPercentageBasis an optional percentage basis (in aFrame's WM).
* Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes.
* If the basis is indefinite in a given axis, pass a size with
* NS_UNCONSTRAINEDSIZE in that component.
* If you pass Nothing() a percentage basis will be calculated from aFrame's
* ancestors' computed size in the relevant axis, if needed.
* @param aMarginBoxMinSizeClamp make the result fit within this margin-box
@ -1395,14 +1398,13 @@ public:
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
ADD_PERCENTS = 0x08, // apply AddPercents also for MIN_ISIZE
};
static nscoord
IntrinsicForAxis(mozilla::PhysicalAxis aAxis,
nsRenderingContext* aRenderingContext,
nsIFrame* aFrame,
IntrinsicISizeType aType,
const mozilla::Maybe<mozilla::LogicalSize>& aPercentageBasis = mozilla::Nothing(),
const mozilla::Maybe<LogicalSize>& aPercentageBasis = mozilla::Nothing(),
uint32_t aFlags = 0,
nscoord aMarginBoxMinSizeClamp = NS_MAXSIZE);
/**
@ -1427,31 +1429,18 @@ public:
* calculates the result as if the 'min-' computed value is zero.
* Otherwise, return NS_UNCONSTRAINEDSIZE.
*
* @param aPercentageBasis the percentage basis (in aFrame's WM).
* Pass NS_UNCONSTRAINEDSIZE if the basis is indefinite in either/both axes.
* @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,
nsIFrame* aFrame,
IntrinsicISizeType aType,
uint32_t aFlags = 0);
/**
* This function increases an initial intrinsic size, 'aCurrent', according
* to the given 'aPercent', such that the size-increase makes up exactly
* 'aPercent' percent of the returned value. If 'aPercent' or 'aCurrent' are
* less than or equal to zero the original 'aCurrent' value is returned.
* If 'aPercent' is greater than or equal to 1.0 the value nscoord_MAX is
* returned.
*/
static nscoord AddPercents(nscoord aCurrent, float aPercent)
{
if (aPercent > 0.0f && aCurrent > 0) {
return MOZ_UNLIKELY(aPercent >= 1.0f) ? nscoord_MAX
: NSToCoordRound(float(aCurrent) / (1.0f - aPercent));
}
return aCurrent;
}
static nscoord
MinSizeContributionForAxis(mozilla::PhysicalAxis aAxis,
nsRenderingContext* aRC,
nsIFrame* aFrame,
IntrinsicISizeType aType,
const LogicalSize& aPercentageBasis,
uint32_t aFlags = 0);
/*
* Convert nsStyleCoord to nscoord when percentages depend on the
@ -2876,6 +2865,62 @@ public:
static nsRect ComputeGeometryBox(nsIFrame* aFrame,
StyleGeometryBox aGeometryBox);
/**
* Resolve a CSS <length-percentage> value to a definite size.
*/
template<bool clampNegativeResultToZero>
static nscoord ResolveToLength(const nsStyleCoord& aCoord,
nscoord aPercentageBasis)
{
NS_WARNING_ASSERTION(aPercentageBasis >= nscoord(0), "nscoord overflow?");
switch (aCoord.GetUnit()) {
case eStyleUnit_Coord:
MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetCoordValue() >= 0,
"This value should have been rejected by the style system");
return aCoord.GetCoordValue();
case eStyleUnit_Percent:
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
return nscoord(0);
}
MOZ_ASSERT(!clampNegativeResultToZero || aCoord.GetPercentValue() >= 0,
"This value should have been rejected by the style system");
return NSToCoordFloorClamped(aPercentageBasis *
aCoord.GetPercentValue());
case eStyleUnit_Calc: {
nsStyleCoord::Calc* calc = aCoord.GetCalcValue();
nscoord result;
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
result = calc->mLength;
} else {
result = calc->mLength +
NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
}
if (clampNegativeResultToZero && result < 0) {
return nscoord(0);
}
return result;
}
default:
MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
return nscoord(0);
}
}
/**
* Resolve a column-gap/row-gap to a definite size.
* @note This method resolves 'normal' to zero.
* Callers who want different behavior should handle 'normal' on their own.
*/
static nscoord ResolveGapToLength(const nsStyleCoord& aGap,
nscoord aPercentageBasis)
{
if (aGap.GetUnit() == eStyleUnit_Normal) {
return nscoord(0);
}
return ResolveToLength<true>(aGap, aPercentageBasis);
}
private:
static uint32_t sFontSizeInflationEmPerLine;
static uint32_t sFontSizeInflationMinTwips;