Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(522)

Unified Diff: third_party/WebKit/Source/core/layout/LayoutGrid.cpp

Issue 2287113004: [css-grid] Implement fit-content track size (Closed)
Patch Set: Patch for landing Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/layout/LayoutGrid.cpp
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index c28234db2533348344725a408ec6f857ea4073c5..d1819a40a58015f31237ef510fc72a2dae22e35e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -49,15 +49,16 @@ public:
{
}
- const LayoutUnit& baseSize() const
+ LayoutUnit baseSize() const
{
- ASSERT(isGrowthLimitBiggerThanBaseSize());
+ DCHECK(isGrowthLimitBiggerThanBaseSize());
return m_baseSize;
}
- const LayoutUnit& growthLimit() const
+ LayoutUnit growthLimit() const
{
- ASSERT(isGrowthLimitBiggerThanBaseSize());
+ DCHECK(isGrowthLimitBiggerThanBaseSize());
+ DCHECK(!m_growthLimitCap || m_growthLimitCap.value() >= m_growthLimit || m_baseSize >= m_growthLimitCap.value());
return m_growthLimit;
}
@@ -69,21 +70,13 @@ public:
void setGrowthLimit(LayoutUnit growthLimit)
{
- m_growthLimit = growthLimit;
+ m_growthLimit = growthLimit == infinity ? growthLimit : std::min(growthLimit, m_growthLimitCap.value_or(growthLimit));
ensureGrowthLimitIsBiggerThanBaseSize();
}
- bool growthLimitIsInfinite() const
- {
- return m_growthLimit == infinity;
- }
+ bool infiniteGrowthPotential() const { return growthLimitIsInfinite() || m_infinitelyGrowable; }
- bool infiniteGrowthPotential() const
- {
- return growthLimitIsInfinite() || m_infinitelyGrowable;
- }
-
- const LayoutUnit& plannedSize() const { return m_plannedSize; }
+ LayoutUnit plannedSize() const { return m_plannedSize; }
void setPlannedSize(const LayoutUnit& plannedSize)
{
@@ -91,24 +84,34 @@ public:
m_plannedSize = plannedSize;
}
- const LayoutUnit& sizeDuringDistribution() { return m_sizeDuringDistribution; }
+ LayoutUnit sizeDuringDistribution() const { return m_sizeDuringDistribution; }
void setSizeDuringDistribution(const LayoutUnit& sizeDuringDistribution)
{
- ASSERT(sizeDuringDistribution >= 0);
+ DCHECK_GE(sizeDuringDistribution, 0);
+ DCHECK(growthLimitIsInfinite() || growthLimit() >= sizeDuringDistribution);
m_sizeDuringDistribution = sizeDuringDistribution;
}
void growSizeDuringDistribution(const LayoutUnit& sizeDuringDistribution)
{
- ASSERT(sizeDuringDistribution >= 0);
+ DCHECK_GE(sizeDuringDistribution, 0);
m_sizeDuringDistribution += sizeDuringDistribution;
}
bool infinitelyGrowable() const { return m_infinitelyGrowable; }
void setInfinitelyGrowable(bool infinitelyGrowable) { m_infinitelyGrowable = infinitelyGrowable; }
+ void setGrowthLimitCap(Optional<LayoutUnit> growthLimitCap)
+ {
+ DCHECK(!growthLimitCap || *growthLimitCap >= 0);
+ m_growthLimitCap = growthLimitCap;
+ }
+
+ Optional<LayoutUnit> growthLimitCap() const { return m_growthLimitCap; }
+
private:
+ bool growthLimitIsInfinite() const { return m_growthLimit == infinity; }
bool isGrowthLimitBiggerThanBaseSize() const { return growthLimitIsInfinite() || m_growthLimit >= m_baseSize; }
void ensureGrowthLimitIsBiggerThanBaseSize()
@@ -121,6 +124,7 @@ private:
LayoutUnit m_growthLimit;
LayoutUnit m_plannedSize;
LayoutUnit m_sizeDuringDistribution;
+ Optional<LayoutUnit> m_growthLimitCap;
bool m_infinitelyGrowable;
};
@@ -250,7 +254,10 @@ public:
Vector<GridItemWithSpan> itemsSortedByIncreasingSpan;
Vector<GridTrack*> growBeyondGrowthLimitsTracks;
- LayoutUnit& freeSpaceForDirection(GridTrackSizingDirection direction) { return direction == ForColumns ? freeSpaceForColumns : freeSpaceForRows; }
+ LayoutUnit& freeSpace(GridTrackSizingDirection direction) { return direction == ForColumns ? freeSpaceForColumns : freeSpaceForRows; }
+
+ LayoutUnit availableSpace() const { return m_availableSpace; }
+ void setAvailableSpace(LayoutUnit availableSpace) { m_availableSpace = availableSpace; }
SizingOperation sizingOperation { TrackSizing };
enum SizingState { ColumnSizingFirstIteration, RowSizingFirstIteration, ColumnSizingSecondIteration, RowSizingSecondIteration};
@@ -290,6 +297,9 @@ public:
private:
LayoutUnit freeSpaceForColumns { };
LayoutUnit freeSpaceForRows { };
+ // No need to store one per direction as it will be only used for computations during each axis
+ // track sizing. It's cached here because we need it to compute relative sizes.
+ LayoutUnit m_availableSpace;
};
struct GridItemsSpanGroupRange {
@@ -388,10 +398,11 @@ LayoutUnit LayoutGrid::computeTrackBasedLogicalHeight(const GridSizingData& sizi
return logicalHeight;
}
-void LayoutGrid::computeTrackSizesForDirection(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit freeSpace)
+void LayoutGrid::computeTrackSizesForDirection(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit availableSpace)
{
DCHECK(sizingData.isValidTransition(direction));
- sizingData.freeSpaceForDirection(direction) = freeSpace - guttersSize(direction, 0, direction == ForRows ? gridRowCount() : gridColumnCount());
+ sizingData.setAvailableSpace(availableSpace);
+ sizingData.freeSpace(direction) = availableSpace - guttersSize(direction, 0, direction == ForRows ? gridRowCount() : gridColumnCount());
sizingData.sizingOperation = TrackSizing;
LayoutUnit baseSizes, growthLimits;
@@ -577,7 +588,8 @@ void LayoutGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layo
const_cast<LayoutGrid*>(this)->placeItemsOnGrid(IntrinsicSizeComputation);
GridSizingData sizingData(gridColumnCount(), gridRowCount());
- sizingData.freeSpaceForDirection(ForColumns) = LayoutUnit();
+ sizingData.setAvailableSpace(LayoutUnit());
+ sizingData.freeSpace(ForColumns) = LayoutUnit();
sizingData.sizingOperation = IntrinsicSizeComputation;
computeUsedBreadthOfGridTracks(ForColumns, sizingData, minLogicalWidth, maxLogicalWidth);
@@ -593,7 +605,8 @@ void LayoutGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layo
void LayoutGrid::computeIntrinsicLogicalHeight(GridSizingData& sizingData)
{
ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns, sizingData));
- sizingData.freeSpaceForDirection(ForRows) = LayoutUnit();
+ sizingData.setAvailableSpace(LayoutUnit());
+ sizingData.freeSpace(ForRows) = LayoutUnit();
sizingData.sizingOperation = IntrinsicSizeComputation;
computeUsedBreadthOfGridTracks(ForRows, sizingData, m_minContentHeight, m_maxContentHeight);
@@ -632,29 +645,31 @@ static inline double normalizedFlexFraction(const GridTrack& track, double flexF
void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit& baseSizesWithoutMaximization, LayoutUnit& growthLimitsWithoutMaximization) const
{
- LayoutUnit& freeSpace = sizingData.freeSpaceForDirection(direction);
+ LayoutUnit& freeSpace = sizingData.freeSpace(direction);
const LayoutUnit initialFreeSpace = freeSpace;
Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
Vector<size_t> flexibleSizedTracksIndex;
sizingData.contentSizedTracksIndex.shrink(0);
- LayoutUnit maxSize = std::max(LayoutUnit(), initialFreeSpace);
// Grid gutters were removed from freeSpace by the caller, but we must use them to compute relative (i.e. percentages) sizes.
+ LayoutUnit maxSize = sizingData.availableSpace().clampNegativeToZero();
bool hasDefiniteFreeSpace = sizingData.sizingOperation == TrackSizing;
- if (hasDefiniteFreeSpace)
- maxSize += guttersSize(direction, 0, direction == ForRows ? gridRowCount() : gridColumnCount());
// 1. Initialize per Grid track variables.
for (size_t i = 0; i < tracks.size(); ++i) {
GridTrack& track = tracks[i];
GridTrackSize trackSize = gridTrackSize(direction, i, sizingData.sizingOperation);
- const GridLength& minTrackBreadth = trackSize.minTrackBreadth();
- const GridLength& maxTrackBreadth = trackSize.maxTrackBreadth();
- track.setBaseSize(computeUsedBreadthOfMinLength(minTrackBreadth, maxSize));
- track.setGrowthLimit(computeUsedBreadthOfMaxLength(maxTrackBreadth, track.baseSize(), maxSize));
+ track.setBaseSize(computeUsedBreadthOfMinLength(trackSize, maxSize));
+ track.setGrowthLimit(computeUsedBreadthOfMaxLength(trackSize, track.baseSize(), maxSize));
track.setInfinitelyGrowable(false);
+ if (trackSize.isFitContent()) {
+ GridLength gridLength = trackSize.length();
+ if (!gridLength.hasPercentage() || hasDefiniteFreeSpace)
+ track.setGrowthLimitCap(valueForLength(gridLength.length(), maxSize));
+ }
+
if (trackSize.isContentSized())
sizingData.contentSizedTracksIndex.append(i);
if (trackSize.maxTrackBreadth().isFlex())
@@ -667,10 +682,13 @@ void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
baseSizesWithoutMaximization = growthLimitsWithoutMaximization = LayoutUnit();
- for (const auto& track: tracks) {
+ for (auto& track: tracks) {
ASSERT(!track.infiniteGrowthPotential());
baseSizesWithoutMaximization += track.baseSize();
growthLimitsWithoutMaximization += track.growthLimit();
+ // The growth limit caps must be cleared now in order to properly sort tracks by growth
+ // potential on an eventual "Maximize Tracks".
+ track.setGrowthLimitCap(WTF::nullopt);
}
freeSpace = initialFreeSpace - baseSizesWithoutMaximization;
@@ -737,8 +755,9 @@ void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
}
}
-LayoutUnit LayoutGrid::computeUsedBreadthOfMinLength(const GridLength& gridLength, LayoutUnit maxSize) const
+LayoutUnit LayoutGrid::computeUsedBreadthOfMinLength(const GridTrackSize& trackSize, LayoutUnit maxSize) const
{
+ const GridLength& gridLength = trackSize.minTrackBreadth();
if (gridLength.isFlex())
return LayoutUnit();
@@ -750,8 +769,9 @@ LayoutUnit LayoutGrid::computeUsedBreadthOfMinLength(const GridLength& gridLengt
return LayoutUnit();
}
-LayoutUnit LayoutGrid::computeUsedBreadthOfMaxLength(const GridLength& gridLength, LayoutUnit usedBreadth, LayoutUnit maxSize) const
+LayoutUnit LayoutGrid::computeUsedBreadthOfMaxLength(const GridTrackSize& trackSize, LayoutUnit usedBreadth, LayoutUnit maxSize) const
{
+ const GridLength& gridLength = trackSize.maxTrackBreadth();
if (gridLength.isFlex())
return usedBreadth;
@@ -881,13 +901,14 @@ GridTrackSize LayoutGrid::gridTrackSize(GridTrackSizingDirection direction, size
{
// Collapse empty auto repeat tracks if auto-fit.
if (hasAutoRepeatEmptyTracks(direction) && isEmptyAutoRepeatTrack(direction, translatedIndex))
- return { Length(Fixed), Length(Fixed) };
+ return { Length(Fixed), LengthTrackSizing };
const GridTrackSize& trackSize = rawGridTrackSize(direction, translatedIndex);
+ if (trackSize.isFitContent())
+ return trackSize;
GridLength minTrackBreadth = trackSize.minTrackBreadth();
GridLength maxTrackBreadth = trackSize.maxTrackBreadth();
-
// If the logical width/height of the grid container is indefinite, percentage values are treated as <auto>.
if (minTrackBreadth.hasPercentage() || maxTrackBreadth.hasPercentage()) {
// For the inline axis this only happens when we're computing the intrinsic sizes (AvailableSpaceIndefinite).
@@ -1096,7 +1117,7 @@ void LayoutGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirectio
for (const auto& trackIndex : sizingData.contentSizedTracksIndex) {
GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackIndex] : sizingData.rowTracks[trackIndex];
- if (track.growthLimitIsInfinite())
+ if (track.growthLimit() == infinity)
track.setGrowthLimit(track.baseSize());
}
}
@@ -1113,13 +1134,19 @@ void LayoutGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(Grid
else if (trackSize.hasAutoMinTrackBreadth())
track.setBaseSize(std::max(track.baseSize(), minSizeForChild(gridItem, direction, sizingData)));
- if (trackSize.hasMinContentMaxTrackBreadth())
+ if (trackSize.hasMinContentMaxTrackBreadth()) {
track.setGrowthLimit(std::max(track.growthLimit(), minContentForChild(gridItem, direction, sizingData)));
- else if (trackSize.hasMaxContentOrAutoMaxTrackBreadth())
- track.setGrowthLimit(std::max(track.growthLimit(), maxContentForChild(gridItem, direction, sizingData)));
+ } else if (trackSize.hasMaxContentOrAutoMaxTrackBreadth()) {
+ LayoutUnit growthLimit = maxContentForChild(gridItem, direction, sizingData);
+ if (trackSize.isFitContent()) {
+ DCHECK(trackSize.length().isLength());
+ growthLimit = std::min(growthLimit, valueForLength(trackSize.length().length(), sizingData.availableSpace()));
+ }
+ track.setGrowthLimit(std::max(track.growthLimit(), growthLimit));
+ }
}
-static const LayoutUnit& trackSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase, const GridTrack& track, TrackSizeRestriction restriction)
+static LayoutUnit trackSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase, const GridTrack& track, TrackSizeRestriction restriction)
{
switch (phase) {
case ResolveIntrinsicMinimums:
@@ -1296,17 +1323,34 @@ static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTr
{
// This check ensures that we respect the irreflexivity property of the strict weak ordering required by std::sort
// (forall x: NOT x < x).
- if (track1->infiniteGrowthPotential() && track2->infiniteGrowthPotential())
+ bool track1HasInfiniteGrowthPotentialWithoutCap = track1->infiniteGrowthPotential() && !track1->growthLimitCap();
+ bool track2HasInfiniteGrowthPotentialWithoutCap = track2->infiniteGrowthPotential() && !track2->growthLimitCap();
+
+ if (track1HasInfiniteGrowthPotentialWithoutCap && track2HasInfiniteGrowthPotentialWithoutCap)
return false;
- if (track1->infiniteGrowthPotential() || track2->infiniteGrowthPotential())
- return track2->infiniteGrowthPotential();
+ if (track1HasInfiniteGrowthPotentialWithoutCap || track2HasInfiniteGrowthPotentialWithoutCap)
+ return track2HasInfiniteGrowthPotentialWithoutCap;
+
+ LayoutUnit track1Limit = track1->growthLimitCap().value_or(track1->growthLimit());
+ LayoutUnit track2Limit = track2->growthLimitCap().value_or(track2->growthLimit());
+ return (track1Limit - track1->baseSize()) < (track2Limit - track2->baseSize());
+}
+
+static void clampGrowthShareIfNeeded(TrackSizeComputationPhase phase, const GridTrack& track, LayoutUnit& growthShare)
+{
+ if (phase != ResolveMaxContentMaximums || !track.growthLimitCap())
+ return;
+
+ LayoutUnit distanceToCap = track.growthLimitCap().value() - track.sizeDuringDistribution();
+ if (distanceToCap <= 0)
+ return;
- return (track1->growthLimit() - track1->baseSize()) < (track2->growthLimit() - track2->baseSize());
+ growthShare = std::min(growthShare, distanceToCap);
}
template <TrackSizeComputationPhase phase>
-void LayoutGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vector<GridTrack*>* growBeyondGrowthLimitsTracks, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) const
+void LayoutGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, Vector<GridTrack*>* growBeyondGrowthLimitsTracks, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) const
{
ASSERT(availableLogicalSpace >= 0);
@@ -1322,6 +1366,7 @@ void LayoutGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksSize - i);
const LayoutUnit& trackBreadth = trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity);
LayoutUnit growthShare = track.infiniteGrowthPotential() ? availableLogicalSpaceShare : std::min(availableLogicalSpaceShare, track.growthLimit() - trackBreadth);
+ clampGrowthShareIfNeeded(phase, track, growthShare);
DCHECK_GE(growthShare, 0) << "We must never shrink any grid track or else we can't guarantee we abide by our min-sizing function.";
track.growSizeDuringDistribution(growthShare);
availableLogicalSpace -= growthShare;
@@ -1329,10 +1374,17 @@ void LayoutGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
}
if (availableLogicalSpace > 0 && growBeyondGrowthLimitsTracks) {
+ // We need to sort them because there might be tracks with growth limit caps (like the ones
+ // with fit-content()) which cannot indefinitely grow over the limits.
+ if (phase == ResolveMaxContentMaximums)
+ std::sort(growBeyondGrowthLimitsTracks->begin(), growBeyondGrowthLimitsTracks->end(), sortByGridTrackGrowthPotential);
+
size_t tracksGrowingAboveMaxBreadthSize = growBeyondGrowthLimitsTracks->size();
for (size_t i = 0; i < tracksGrowingAboveMaxBreadthSize; ++i) {
GridTrack* track = growBeyondGrowthLimitsTracks->at(i);
LayoutUnit growthShare = availableLogicalSpace / (tracksGrowingAboveMaxBreadthSize - i);
+ clampGrowthShareIfNeeded(phase, *track, growthShare);
+ DCHECK_GE(growthShare, 0) << "We must never shrink any grid track or else we can't guarantee we abide by our min-sizing function.";
track->growSizeDuringDistribution(growthShare);
availableLogicalSpace -= growthShare;
}
@@ -1346,11 +1398,10 @@ void LayoutGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
bool LayoutGrid::tracksAreWiderThanMinTrackBreadth(GridTrackSizingDirection direction, GridSizingData& sizingData)
{
const Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
- LayoutUnit& maxSize = sizingData.freeSpaceForDirection(direction);
+ LayoutUnit& maxSize = sizingData.freeSpace(direction);
for (size_t i = 0; i < tracks.size(); ++i) {
GridTrackSize trackSize = gridTrackSize(direction, i, sizingData.sizingOperation);
- const GridLength& minTrackBreadth = trackSize.minTrackBreadth();
- if (computeUsedBreadthOfMinLength(minTrackBreadth, maxSize) > tracks[i].baseSize())
+ if (computeUsedBreadthOfMinLength(trackSize, maxSize) > tracks[i].baseSize())
return false;
}
return true;
@@ -1799,7 +1850,7 @@ static const StyleContentAlignmentData& contentAlignmentNormalBehavior()
void LayoutGrid::applyStretchAlignmentToTracksIfNeeded(GridTrackSizingDirection direction, GridSizingData& sizingData)
{
- LayoutUnit& availableSpace = sizingData.freeSpaceForDirection(direction);
+ LayoutUnit& availableSpace = sizingData.freeSpace(direction);
if (availableSpace <= 0
|| (direction == ForColumns && styleRef().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior()) != ContentDistributionStretch)
|| (direction == ForRows && styleRef().resolvedAlignContentDistribution(contentAlignmentNormalBehavior()) != ContentDistributionStretch))
@@ -2084,7 +2135,7 @@ void LayoutGrid::populateGridPositionsForDirection(GridSizingData& sizingData, G
size_t numberOfTracks = tracks.size();
size_t numberOfLines = numberOfTracks + 1;
size_t lastLine = numberOfLines - 1;
- ContentAlignmentData offset = computeContentPositionAndDistributionOffset(direction, sizingData.freeSpaceForDirection(direction), numberOfTracks);
+ ContentAlignmentData offset = computeContentPositionAndDistributionOffset(direction, sizingData.freeSpace(direction), numberOfTracks);
auto& positions = isRowAxis ? m_columnPositions : m_rowPositions;
positions.resize(numberOfLines);
auto borderAndPadding = isRowAxis ? borderAndPaddingLogicalLeft() : borderAndPaddingBefore();
« no previous file with comments | « third_party/WebKit/Source/core/layout/LayoutGrid.h ('k') | third_party/WebKit/Source/core/style/GridTrackSize.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698