Index: Source/core/layout/LayoutGrid.cpp |
diff --git a/Source/core/layout/LayoutGrid.cpp b/Source/core/layout/LayoutGrid.cpp |
index ea24f4a816f7685ea38101faee1b3dc171c8f832..5836d68ed8d476df2ecc2de579643af787617e90 100644 |
--- a/Source/core/layout/LayoutGrid.cpp |
+++ b/Source/core/layout/LayoutGrid.cpp |
@@ -236,6 +236,11 @@ public: |
Vector<GridTrack*> filteredTracks; |
Vector<GridItemWithSpan> itemsSortedByIncreasingSpan; |
Vector<GridTrack*> growBeyondGrowthLimitsTracks; |
+ |
+ LayoutUnit rowsPositionOffset; |
+ LayoutUnit rowsDistributionOffset; |
+ LayoutUnit columnsPositionOffset; |
+ LayoutUnit columnsDistributionOffset; |
}; |
struct GridItemsSpanGroupRange { |
@@ -435,6 +440,12 @@ void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi |
return; |
// 3. Grow all Grid tracks in GridTracks from their baseSize up to their growthLimit value until freeSpace is exhausted. |
+ // Any 'auto-sized' (content based) track will be 'stretched' over their MaxBreadth if required |
+ // and there is space available, except if there are flexible track, which will occupy the whole |
+ // available space. |
+ bool needToStretch = flexibleSizedTracksIndex.isEmpty() && !sizingData.contentSizedTracksIndex.isEmpty() |
+ && ((direction == ForColumns && style()->justifyContentDistribution() == ContentDistributionStretch) |
+ || (direction == ForRows && style()->alignContentDistribution() == ContentDistributionStretch)); |
const size_t tracksSize = tracks.size(); |
if (!hasUndefinedRemainingSpace) { |
Vector<GridTrack*> tracksForDistribution(tracksSize); |
@@ -443,7 +454,15 @@ void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi |
tracksForDistribution[i]->m_plannedIncrease = 0; |
} |
- distributeSpaceToTracks(tracksForDistribution, nullptr, &GridTrack::baseSize, sizingData, freeSpace); |
+ Vector<GridTrack*> tracksToStretch(sizingData.contentSizedTracksIndex.size()); |
+ if (needToStretch) { |
+ unsigned i = 0; |
+ for (const auto& trackIndex : sizingData.contentSizedTracksIndex) { |
+ tracksToStretch[i++] = tracks.data() + trackIndex; |
+ } |
+ } |
+ |
+ distributeSpaceToTracks(tracksForDistribution, needToStretch ? &tracksToStretch : nullptr, &GridTrack::baseSize, sizingData, freeSpace); |
for (auto* track : tracksForDistribution) |
track->growBaseSize(track->m_plannedIncrease); |
@@ -1129,13 +1148,12 @@ void LayoutGrid::layoutGridItems() |
computeUsedBreadthOfGridTracks(ForRows, sizingData, availableSpaceForRows); |
ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, sizingData.rowTracks)); |
+ computeContentPositionAndDistributionColumnOffset(availableSpaceForColumns, sizingData); |
+ computeContentPositionAndDistributionRowOffset(availableSpaceForRows, sizingData); |
+ |
populateGridPositions(sizingData); |
m_gridItemsOverflowingGridArea.resize(0); |
- LayoutUnit columnOffset = contentPositionAndDistributionColumnOffset(availableSpaceForColumns, style()->justifyContent(), style()->justifyContentDistribution(), style()->justifyContentOverflowAlignment(), m_columnPositions.size() - 1); |
- LayoutUnit rowOffset = contentPositionAndDistributionRowOffset(availableSpaceForRows, style()->alignContent(), style()->alignContentDistribution(), style()->alignContentOverflowAlignment(), m_rowPositions.size() - 1); |
- LayoutSize contentPositionOffset(columnOffset, rowOffset); |
- |
for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { |
if (child->isOutOfFlowPositioned()) { |
child->containingBlock()->insertPositionedObject(child); |
@@ -1169,7 +1187,7 @@ void LayoutGrid::layoutGridItems() |
ASSERT(coordinate.columns.resolvedInitialPosition.toInt() < sizingData.columnTracks.size()); |
ASSERT(coordinate.rows.resolvedInitialPosition.toInt() < sizingData.rowTracks.size()); |
#endif |
- child->setLogicalLocation(findChildLogicalPosition(*child, contentPositionOffset)); |
+ child->setLogicalLocation(findChildLogicalPosition(*child, sizingData)); |
// Keep track of children overflowing their grid area as we might need to paint them even if the grid-area is |
// not visible |
@@ -1283,9 +1301,16 @@ LayoutUnit LayoutGrid::gridAreaBreadthForChild(const LayoutBox& child, GridTrack |
{ |
const GridCoordinate& coordinate = cachedGridCoordinate(child); |
const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coordinate.rows; |
+ const Vector<LayoutUnit>& trackPositions = (direction == ForColumns) ? m_columnPositions : m_rowPositions; |
+ if (span.resolvedFinalPosition.toInt() < trackPositions.size()) { |
+ LayoutUnit startOftrack = trackPositions[span.resolvedInitialPosition.toInt()]; |
+ LayoutUnit endOfTrack = trackPositions[span.resolvedFinalPosition.toInt()]; |
+ return endOfTrack - startOftrack + tracks[span.resolvedFinalPosition.toInt()].baseSize(); |
+ } |
LayoutUnit gridAreaBreadth = 0; |
for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.end(); ++trackPosition) |
gridAreaBreadth += tracks[trackPosition.toInt()].baseSize(); |
+ |
return gridAreaBreadth; |
} |
@@ -1295,14 +1320,14 @@ void LayoutGrid::populateGridPositions(const GridSizingData& sizingData) |
unsigned numberOfRowTracks = sizingData.rowTracks.size(); |
m_columnPositions.resize(numberOfColumnTracks + 1); |
- m_columnPositions[0] = borderAndPaddingStart(); |
+ m_columnPositions[0] = borderAndPaddingStart() + sizingData.columnsPositionOffset; |
for (unsigned i = 0; i < numberOfColumnTracks; ++i) |
- m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnTracks[i].baseSize(); |
+ m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnsDistributionOffset + sizingData.columnTracks[i].baseSize(); |
m_rowPositions.resize(numberOfRowTracks + 1); |
- m_rowPositions[0] = borderAndPaddingBefore(); |
+ m_rowPositions[0] = borderAndPaddingBefore() + sizingData.rowsPositionOffset; |
for (unsigned i = 0; i < numberOfRowTracks; ++i) |
- m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowTracks[i].baseSize(); |
+ m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowsDistributionOffset + sizingData.rowTracks[i].baseSize(); |
} |
static LayoutUnit computeOverflowAlignmentOffset(OverflowAlignment overflow, LayoutUnit startOfTrack, LayoutUnit endOfTrack, LayoutUnit childBreadth) |
@@ -1664,97 +1689,149 @@ static inline LayoutUnit offsetToEndEdge(bool isLeftToRight, LayoutUnit availabl |
return !isLeftToRight ? LayoutUnit() : availableSpace; |
} |
-LayoutUnit LayoutGrid::contentPositionAndDistributionColumnOffset(LayoutUnit availableFreeSpace, ContentPosition position, ContentDistributionType distribution, OverflowAlignment overflow, unsigned numberOfGridTracks) const |
+ |
+static bool contentDistributionOffset(LayoutUnit availableFreeSpace, ContentPosition& fallbackPosition, ContentDistributionType distribution, unsigned numberOfGridTracks, LayoutUnit& positionOffset, LayoutUnit& distributionOffset) |
{ |
- if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) |
- return 0; |
+ if (distribution != ContentDistributionDefault && fallbackPosition == ContentPositionAuto) |
+ fallbackPosition = resolveContentDistributionFallback(distribution); |
+ |
+ if (availableFreeSpace <= 0) |
+ return false; |
+ |
+ switch (distribution) { |
+ case ContentDistributionSpaceBetween: |
+ if (numberOfGridTracks < 2) |
+ return false; |
+ distributionOffset = availableFreeSpace / (numberOfGridTracks - 1); |
+ positionOffset = 0; |
+ return true; |
+ case ContentDistributionSpaceAround: |
+ if (numberOfGridTracks < 1) |
+ return false; |
+ distributionOffset = availableFreeSpace / numberOfGridTracks; |
+ positionOffset = distributionOffset / 2; |
+ return true; |
+ case ContentDistributionSpaceEvenly: |
+ distributionOffset = availableFreeSpace / (numberOfGridTracks + 1); |
+ positionOffset = distributionOffset; |
+ return true; |
+ case ContentDistributionStretch: |
+ distributionOffset = 0; |
+ positionOffset = 0; |
+ return true; |
+ case ContentDistributionDefault: |
+ distributionOffset = 0; |
+ positionOffset = 0; |
+ return false; |
+ } |
+ |
+ ASSERT_NOT_REACHED(); |
+ return false; |
+} |
+ |
+void LayoutGrid::computeContentPositionAndDistributionColumnOffset(LayoutUnit availableFreeSpace, GridSizingData& sizingData) const |
+{ |
+ ContentPosition position = styleRef().justifyContent(); |
+ ContentDistributionType distribution = styleRef().justifyContentDistribution(); |
+ // If <content-distribution> value can't be applied, 'position' will become the associated |
+ // <content-position> fallback value. |
+ if (contentDistributionOffset(availableFreeSpace, position, distribution, sizingData.columnTracks.size(), sizingData.columnsPositionOffset, sizingData.columnsDistributionOffset)) |
+ return; |
- // FIXME: for the time being, spec states that it will always fallback for Grids, but |
- // discussion is ongoing. |
- if (distribution != ContentDistributionDefault && position == ContentPositionAuto) |
- position = resolveContentDistributionFallback(distribution); |
+ OverflowAlignment overflow = styleRef().justifyContentOverflowAlignment(); |
+ if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) |
+ return; |
switch (position) { |
case ContentPositionLeft: |
- return 0; |
+ sizingData.columnsPositionOffset = 0; |
+ return; |
case ContentPositionRight: |
- return availableFreeSpace; |
+ sizingData.columnsPositionOffset = availableFreeSpace; |
+ return; |
case ContentPositionCenter: |
- return availableFreeSpace / 2; |
+ sizingData.columnsPositionOffset = availableFreeSpace / 2; |
+ return; |
case ContentPositionFlexEnd: |
// Only used in flex layout, for other layout, it's equivalent to 'end'. |
case ContentPositionEnd: |
- return offsetToEndEdge(style()->isLeftToRightDirection(), availableFreeSpace); |
+ sizingData.columnsPositionOffset = offsetToEndEdge(style()->isLeftToRightDirection(), availableFreeSpace); |
+ return; |
case ContentPositionFlexStart: |
// Only used in flex layout, for other layout, it's equivalent to 'start'. |
case ContentPositionStart: |
- return offsetToStartEdge(style()->isLeftToRightDirection(), availableFreeSpace); |
+ sizingData.columnsPositionOffset = offsetToStartEdge(style()->isLeftToRightDirection(), availableFreeSpace); |
+ return; |
case ContentPositionBaseline: |
case ContentPositionLastBaseline: |
// FIXME: Implement the previous values. For now, we always 'start' align. |
// crbug.com/234191 |
- return offsetToStartEdge(style()->isLeftToRightDirection(), availableFreeSpace); |
+ sizingData.columnsPositionOffset = offsetToStartEdge(style()->isLeftToRightDirection(), availableFreeSpace); |
+ return; |
case ContentPositionAuto: |
break; |
} |
ASSERT_NOT_REACHED(); |
- return 0; |
} |
-LayoutUnit LayoutGrid::contentPositionAndDistributionRowOffset(LayoutUnit availableFreeSpace, ContentPosition position, ContentDistributionType distribution, OverflowAlignment overflow, unsigned numberOfGridTracks) const |
+void LayoutGrid::computeContentPositionAndDistributionRowOffset(LayoutUnit availableFreeSpace, GridSizingData& sizingData) const |
{ |
- if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) |
- return 0; |
+ ContentPosition position = styleRef().alignContent(); |
+ ContentDistributionType distribution = styleRef().alignContentDistribution(); |
+ // If <content-distribution> value can't be applied, 'position' will become the associated |
+ // <content-position> fallback value. |
+ if (contentDistributionOffset(availableFreeSpace, position, distribution, sizingData.rowTracks.size(), sizingData.rowsPositionOffset, sizingData.rowsDistributionOffset)) |
+ return; |
- // FIXME: for the time being, spec states that it will always fallback for Grids, but |
- // discussion is ongoing. |
- if (distribution != ContentDistributionDefault && position == ContentPositionAuto) |
- position = resolveContentDistributionFallback(distribution); |
+ OverflowAlignment overflow = styleRef().alignContentOverflowAlignment(); |
+ if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) |
+ return; |
switch (position) { |
case ContentPositionLeft: |
// The align-content's axis is always orthogonal to the inline-axis. |
- return 0; |
+ sizingData.rowsPositionOffset = 0; |
+ return; |
case ContentPositionRight: |
// The align-content's axis is always orthogonal to the inline-axis. |
- return 0; |
+ sizingData.rowsPositionOffset = 0; |
+ return; |
case ContentPositionCenter: |
- return availableFreeSpace / 2; |
+ sizingData.rowsPositionOffset = availableFreeSpace / 2; |
+ return; |
case ContentPositionFlexEnd: |
// Only used in flex layout, for other layout, it's equivalent to 'End'. |
case ContentPositionEnd: |
- return availableFreeSpace; |
+ sizingData.rowsPositionOffset = availableFreeSpace; |
+ return; |
case ContentPositionFlexStart: |
// Only used in flex layout, for other layout, it's equivalent to 'Start'. |
case ContentPositionStart: |
- return 0; |
+ sizingData.rowsPositionOffset = 0; |
+ return; |
case ContentPositionBaseline: |
case ContentPositionLastBaseline: |
// FIXME: Implement the previous values. For now, we always start align. |
// crbug.com/234191 |
- return 0; |
+ sizingData.rowsPositionOffset = 0; |
+ return; |
case ContentPositionAuto: |
break; |
} |
ASSERT_NOT_REACHED(); |
- return 0; |
} |
-LayoutPoint LayoutGrid::findChildLogicalPosition(const LayoutBox& child, LayoutSize contentAlignmentOffset) const |
+LayoutPoint LayoutGrid::findChildLogicalPosition(const LayoutBox& child, GridSizingData& sizingData) const |
{ |
LayoutUnit columnPosition = columnPositionForChild(child); |
// We stored m_columnPositions's data ignoring the direction, hence we might need now |
// to translate positions from RTL to LTR, as it's more convenient for painting. |
if (!style()->isLeftToRightDirection()) |
- columnPosition = (m_columnPositions[m_columnPositions.size() - 1] + borderAndPaddingLogicalLeft()) - columnPosition - child.logicalWidth(); |
- |
- // The Content Alignment offset accounts for the RTL to LTR flip. |
- LayoutPoint childLocation(columnPosition, rowPositionForChild(child)); |
- childLocation.move(contentAlignmentOffset); |
+ columnPosition = (m_columnPositions[m_columnPositions.size() - 1] + borderAndPaddingLogicalLeft() + sizingData.columnsPositionOffset) - columnPosition - sizingData.columnsDistributionOffset - child.logicalWidth(); |
- return childLocation; |
+ return LayoutPoint(columnPosition, rowPositionForChild(child)); |
} |
void LayoutGrid::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) |