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

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

Issue 1220043002: [CSS Grid Layout] Removing Content Alignment logic from track sizing alg (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 6 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
« Source/core/layout/LayoutGrid.h ('K') | « Source/core/layout/LayoutGrid.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/layout/LayoutGrid.cpp
diff --git a/Source/core/layout/LayoutGrid.cpp b/Source/core/layout/LayoutGrid.cpp
index bbc127fec4d4b4a5055d2b86284633e04ea4c9ea..b4571bc54143abecd92beaa0d21788cf79d95f17 100644
--- a/Source/core/layout/LayoutGrid.cpp
+++ b/Source/core/layout/LayoutGrid.cpp
@@ -119,6 +119,17 @@ private:
LayoutUnit m_growthLimit;
};
+struct ContentAlignmentData {
+ ContentAlignmentData(LayoutUnit position, LayoutUnit distribution)
+ : positionOffset(position)
+ , distributionOffset(distribution)
+ {
+ }
+
+ LayoutUnit positionOffset;
+ LayoutUnit distributionOffset;
svillar 2015/07/01 16:22:55 missing "m_"
jfernandez 2015/07/02 10:04:22 I've been told that when fields are accessible dir
svillar 2015/07/07 18:32:54 The idea in general is not to allow public accesso
jfernandez 2015/07/07 21:18:34 Yeah, but when using structs it's all assumed as p
+};
+
struct GridTrackForNormalization {
GridTrackForNormalization(const GridTrack& track, double flex)
: m_track(&track)
@@ -232,9 +243,30 @@ public:
GridSizingData(size_t gridColumnCount, size_t gridRowCount)
: columnTracks(gridColumnCount)
, rowTracks(gridRowCount)
+ , columnTracksPositionsCacheIsValid(false)
+ , rowTracksPositionsCacheIsValid(false)
{
}
+ bool tracksPositionsCacheIsValid(GridTrackSizingDirection direction) const
+ {
+ return direction == ForColumns ? columnTracksPositionsCacheIsValid : rowTracksPositionsCacheIsValid;
+ }
+
+ void setTracksPositionsCacheValidity(GridTrackSizingDirection direction, bool isValid)
+ {
+ if (direction == ForColumns)
+ columnTracksPositionsCacheIsValid = isValid;
+ else
+ rowTracksPositionsCacheIsValid = isValid;
+ }
+
+ void setTracksPositionsCacheValidity(bool isValid)
+ {
+ columnTracksPositionsCacheIsValid = isValid;
+ rowTracksPositionsCacheIsValid = isValid;
svillar 2015/07/01 16:22:55 Can be a single line. Also it's called just once s
jfernandez 2015/07/02 10:04:21 Well, we might be overprotecting our code. The rea
svillar 2015/07/02 11:19:28 You didn't understand me, I was not talking about
jfernandez 2015/07/02 13:48:52 Done.
+ }
+
Vector<GridTrack> columnTracks;
Vector<GridTrack> rowTracks;
Vector<size_t> contentSizedTracksIndex;
@@ -244,10 +276,9 @@ public:
Vector<GridItemWithSpan> itemsSortedByIncreasingSpan;
Vector<GridTrack*> growBeyondGrowthLimitsTracks;
- LayoutUnit rowsPositionOffset;
- LayoutUnit rowsDistributionOffset;
- LayoutUnit columnsPositionOffset;
- LayoutUnit columnsDistributionOffset;
+ // Performance optimization: caching grid area size based on tracks positions.
+ bool columnTracksPositionsCacheIsValid;
+ bool rowTracksPositionsCacheIsValid;
};
struct GridItemsSpanGroupRange {
@@ -407,6 +438,7 @@ void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
Vector<size_t> flexibleSizedTracksIndex;
sizingData.contentSizedTracksIndex.shrink(0);
+ sizingData.setTracksPositionsCacheValidity(direction, false);
// 1. Initialize per Grid track variables.
for (size_t i = 0; i < tracks.size(); ++i) {
@@ -1233,6 +1265,40 @@ void LayoutGrid::dirtyGrid()
m_gridIsDirty = true;
}
+void LayoutGrid::applyStretchAlignmentToTracksIfNeeded(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit availableSpace)
+{
+ if (availableSpace <= 0
+ || (direction == ForColumns && styleRef().justifyContentDistribution() != ContentDistributionStretch)
+ || (direction == ForRows && styleRef().alignContentDistribution() != ContentDistributionStretch))
+ return;
+
+ // We consider auto-sized tracks as content-sized (min-content, max-content, auto).
+ Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
+ Vector<unsigned> autoSizedTracksIndex;
+ for (unsigned i = 0; i < tracks.size(); ++i) {
+ const GridTrackSize& trackSize = gridTrackSize(direction, i);
+ // If there is some flexible-sized track, they should have exhausted available space during sizing algorithm.
+ ASSERT(!trackSize.maxTrackBreadth().isFlex());
svillar 2015/07/07 18:32:54 I don't get this ASSERT. If the max function is fl
jfernandez 2015/07/07 21:18:34 We shouldn't reach this point if there are flex tr
+ if (trackSize.isContentSized())
+ autoSizedTracksIndex.append(i);
svillar 2015/07/01 16:22:55 Sizing data already has the indexes of the content
jfernandez 2015/07/02 10:04:22 The reason is that SizingData structure uses the c
+ }
+
+ unsigned numberOfAutoSizedTracks = autoSizedTracksIndex.size();
+ if (numberOfAutoSizedTracks < 1)
+ return;
+
+ // We are changing track sizes, so positions cache must be invalidated.
+ sizingData.setTracksPositionsCacheValidity(direction, false);
+
+ LayoutUnit sizeToIncrease = availableSpace / numberOfAutoSizedTracks;
+ for (const auto& trackIndex : autoSizedTracksIndex) {
+ GridTrack* track = tracks.data() + trackIndex;
+ // FIXME: Respecting the constraints imposed by max-height/max-width.
svillar 2015/07/01 16:22:55 Not sure what you mean here. Which max-height/max-
jfernandez 2015/07/02 10:04:22 Well, Alignment spec states that stretching should
svillar 2015/07/02 11:19:28 The min and max in tracks are the min and max trac
jfernandez 2015/07/02 13:48:52 Stretching can be applied only for 'auto-sized" al
+ LayoutUnit baseSize = track->baseSize() + sizeToIncrease;
+ track->setBaseSize(baseSize);
+ }
+}
+
void LayoutGrid::layoutGridItems()
{
placeItemsOnGrid();
@@ -1245,10 +1311,10 @@ void LayoutGrid::layoutGridItems()
computeUsedBreadthOfGridTracks(ForRows, sizingData, availableSpaceForRows);
ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, sizingData.rowTracks));
- computeContentPositionAndDistributionColumnOffset(availableSpaceForColumns, sizingData);
- computeContentPositionAndDistributionRowOffset(availableSpaceForRows, sizingData);
+ applyStretchAlignmentToTracksIfNeeded(ForColumns, sizingData, availableSpaceForColumns);
+ applyStretchAlignmentToTracksIfNeeded(ForRows, sizingData, availableSpaceForRows);
- populateGridPositions(sizingData);
+ populateGridPositions(sizingData, availableSpaceForColumns, availableSpaceForRows);
m_gridItemsOverflowingGridArea.resize(0);
for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
@@ -1262,8 +1328,8 @@ void LayoutGrid::layoutGridItems()
LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOverrideContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogicalWidth() : LayoutUnit();
LayoutUnit oldOverrideContainingBlockContentLogicalHeight = child->hasOverrideContainingBlockLogicalHeight() ? child->overrideContainingBlockContentLogicalHeight() : LayoutUnit();
- LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForChild(*child, ForColumns, sizingData.columnTracks);
- LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadthForChild(*child, ForRows, sizingData.rowTracks);
+ LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForChild(*child, ForColumns, sizingData);
+ LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadthForChild(*child, ForRows, sizingData);
SubtreeLayoutScope layoutScope(*child);
if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingBlockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != overrideContainingBlockContentLogicalHeight && child->hasRelativeLogicalHeight()))
@@ -1398,33 +1464,46 @@ 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;
}
-void LayoutGrid::populateGridPositions(const GridSizingData& sizingData)
+LayoutUnit LayoutGrid::gridAreaBreadthForChild(const LayoutBox& child, GridTrackSizingDirection direction, const GridSizingData& sizingData) const
+{
+ ASSERT(sizingData.tracksPositionsCacheIsValid(direction));
+ // We need the cached value when available because Content Distribution alignment properties
+ // may have some influence in the final grid area breadth.
+ const Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
+ const GridCoordinate& coordinate = cachedGridCoordinate(child);
+ const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coordinate.rows;
+ const Vector<LayoutUnit>& trackPositions = (direction == ForColumns) ? m_columnPositions : m_rowPositions;
+ LayoutUnit startOftrack = trackPositions[span.resolvedInitialPosition.toInt()];
+ LayoutUnit endOfTrack = trackPositions[span.resolvedFinalPosition.toInt()];
+ return endOfTrack - startOftrack + tracks[span.resolvedFinalPosition.toInt()].baseSize();
+}
+
+void LayoutGrid::populateGridPositions(GridSizingData& sizingData, LayoutUnit availableSpaceForColumns, LayoutUnit availableSpaceForRows)
{
unsigned numberOfColumnTracks = sizingData.columnTracks.size();
unsigned numberOfRowTracks = sizingData.rowTracks.size();
+ ContentAlignmentData columnOffset = computeContentPositionAndDistributionColumnOffset(availableSpaceForColumns, numberOfColumnTracks);
m_columnPositions.resize(numberOfColumnTracks + 1);
- m_columnPositions[0] = borderAndPaddingStart() + sizingData.columnsPositionOffset;
- for (unsigned i = 0; i < numberOfColumnTracks; ++i)
- m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnsDistributionOffset + sizingData.columnTracks[i].baseSize();
+ m_columnPositions[0] = borderAndPaddingStart() + columnOffset.positionOffset;
+ for (unsigned i = 0; i < numberOfColumnTracks - 1; ++i)
+ m_columnPositions[i + 1] = m_columnPositions[i] + columnOffset.distributionOffset + sizingData.columnTracks[i].baseSize();
+ m_columnPositions[numberOfColumnTracks] = m_columnPositions[numberOfColumnTracks - 1] + sizingData.columnTracks[numberOfColumnTracks - 1].baseSize();
svillar 2015/07/01 16:22:55 Why this change in the loop?
jfernandez 2015/07/02 10:04:22 Well, since I had to change this function because
svillar 2015/07/02 11:19:28 I think this likely deserves a separate patch + te
jfernandez 2015/07/02 13:48:52 I can do a new patch for this, not sure about the
+ ContentAlignmentData rowOffset = computeContentPositionAndDistributionRowOffset(availableSpaceForRows, numberOfRowTracks);
m_rowPositions.resize(numberOfRowTracks + 1);
- m_rowPositions[0] = borderAndPaddingBefore() + sizingData.rowsPositionOffset;
- for (unsigned i = 0; i < numberOfRowTracks; ++i)
- m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowsDistributionOffset + sizingData.rowTracks[i].baseSize();
+ m_rowPositions[0] = borderAndPaddingBefore() + rowOffset.positionOffset;
+ for (unsigned i = 0; i < numberOfRowTracks - 1; ++i)
+ m_rowPositions[i + 1] = m_rowPositions[i] + rowOffset.distributionOffset + sizingData.rowTracks[i].baseSize();
+ m_rowPositions[numberOfRowTracks] = m_rowPositions[numberOfRowTracks - 1] + sizingData.rowTracks[numberOfRowTracks - 1].baseSize();
svillar 2015/07/01 16:22:55 Why this change in the loop?
jfernandez 2015/07/02 10:04:21 Same as above comment.
+
+ sizingData.setTracksPositionsCacheValidity(true);
}
static LayoutUnit computeOverflowAlignmentOffset(OverflowAlignment overflow, LayoutUnit trackBreadth, LayoutUnit childBreadth)
@@ -1712,137 +1791,120 @@ static inline LayoutUnit offsetToEndEdge(bool isLeftToRight, LayoutUnit availabl
}
-static bool contentDistributionOffset(LayoutUnit availableFreeSpace, ContentPosition& fallbackPosition, ContentDistributionType distribution, unsigned numberOfGridTracks, LayoutUnit& positionOffset, LayoutUnit& distributionOffset)
+static PassOwnPtr<ContentAlignmentData> contentDistributionOffset(LayoutUnit availableFreeSpace, ContentPosition& fallbackPosition, ContentDistributionType distribution, unsigned numberOfGridTracks)
{
if (distribution != ContentDistributionDefault && fallbackPosition == ContentPositionAuto)
fallbackPosition = resolveContentDistributionFallback(distribution);
if (availableFreeSpace <= 0)
- return false;
+ return nullptr;
+ LayoutUnit distributionOffset;
switch (distribution) {
case ContentDistributionSpaceBetween:
if (numberOfGridTracks < 2)
- return false;
- distributionOffset = availableFreeSpace / (numberOfGridTracks - 1);
- positionOffset = 0;
- return true;
+ return nullptr;
+ return adoptPtr(new ContentAlignmentData(0, availableFreeSpace / (numberOfGridTracks - 1)));
case ContentDistributionSpaceAround:
if (numberOfGridTracks < 1)
- return false;
+ return nullptr;
distributionOffset = availableFreeSpace / numberOfGridTracks;
- positionOffset = distributionOffset / 2;
- return true;
+ return adoptPtr(new ContentAlignmentData(distributionOffset / 2, distributionOffset));
case ContentDistributionSpaceEvenly:
distributionOffset = availableFreeSpace / (numberOfGridTracks + 1);
- positionOffset = distributionOffset;
- return true;
+ return adoptPtr(new ContentAlignmentData(distributionOffset, distributionOffset));
case ContentDistributionStretch:
- distributionOffset = 0;
- positionOffset = 0;
- return true;
+ return adoptPtr(new ContentAlignmentData(0, 0));
case ContentDistributionDefault:
- distributionOffset = 0;
- positionOffset = 0;
- return false;
+ return nullptr;
}
ASSERT_NOT_REACHED();
- return false;
+ return nullptr;
}
svillar 2015/07/01 16:22:55 Why are you allocating all those objects in the st
jfernandez 2015/07/02 10:04:22 Yes, that was my first idea. The issue is that I n
svillar 2015/07/02 11:19:28 You mean is not enough with returning false but yo
jfernandez 2015/07/02 13:48:52 Well, the function returns now data structure, ins
-void LayoutGrid::computeContentPositionAndDistributionColumnOffset(LayoutUnit availableFreeSpace, GridSizingData& sizingData) const
+ContentAlignmentData LayoutGrid::computeContentPositionAndDistributionColumnOffset(LayoutUnit availableFreeSpace, unsigned numberOfGridTracks) const
{
ContentPosition position = styleRef().justifyContentPosition();
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;
+ OwnPtr<ContentAlignmentData> contentAlignment = contentDistributionOffset(availableFreeSpace, position, distribution, numberOfGridTracks);
+ if (contentAlignment)
+ return *contentAlignment;
- OverflowAlignment overflow = styleRef().justifyContentOverflowAlignment();
- if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0)
- return;
+ if (availableFreeSpace <= 0 && styleRef().justifyContentOverflowAlignment() == OverflowAlignmentSafe)
+ return {0, 0};
switch (position) {
case ContentPositionLeft:
- sizingData.columnsPositionOffset = 0;
- return;
+ return {0, 0};
case ContentPositionRight:
- sizingData.columnsPositionOffset = availableFreeSpace;
- return;
+ return {availableFreeSpace, 0};
case ContentPositionCenter:
- sizingData.columnsPositionOffset = availableFreeSpace / 2;
- return;
+ return {availableFreeSpace / 2, 0};
case ContentPositionFlexEnd:
// Only used in flex layout, for other layout, it's equivalent to 'end'.
case ContentPositionEnd:
- sizingData.columnsPositionOffset = offsetToEndEdge(style()->isLeftToRightDirection(), availableFreeSpace);
- return;
+ return {offsetToEndEdge(styleRef().isLeftToRightDirection(), availableFreeSpace), 0};
case ContentPositionFlexStart:
// Only used in flex layout, for other layout, it's equivalent to 'start'.
case ContentPositionStart:
- sizingData.columnsPositionOffset = offsetToStartEdge(style()->isLeftToRightDirection(), availableFreeSpace);
- return;
+ return {offsetToStartEdge(styleRef().isLeftToRightDirection(), availableFreeSpace), 0};
case ContentPositionBaseline:
case ContentPositionLastBaseline:
// FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
// crbug.com/234191
- sizingData.columnsPositionOffset = offsetToStartEdge(style()->isLeftToRightDirection(), availableFreeSpace);
- return;
+ return {offsetToStartEdge(styleRef().isLeftToRightDirection(), availableFreeSpace), 0};
case ContentPositionAuto:
break;
}
ASSERT_NOT_REACHED();
+ return {0, 0};
}
-void LayoutGrid::computeContentPositionAndDistributionRowOffset(LayoutUnit availableFreeSpace, GridSizingData& sizingData) const
+ContentAlignmentData LayoutGrid::computeContentPositionAndDistributionRowOffset(LayoutUnit availableFreeSpace, unsigned numberOfGridTracks) const
{
ContentPosition position = styleRef().alignContentPosition();
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;
+ OwnPtr<ContentAlignmentData> contentAlignment = contentDistributionOffset(availableFreeSpace, position, distribution, numberOfGridTracks);
+ if (contentAlignment)
+ return *contentAlignment;
- OverflowAlignment overflow = styleRef().alignContentOverflowAlignment();
- if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0)
- return;
+ if (availableFreeSpace <= 0 && styleRef().alignContentOverflowAlignment() == OverflowAlignmentSafe)
+ return {0, 0};
switch (position) {
case ContentPositionLeft:
// The align-content's axis is always orthogonal to the inline-axis.
- sizingData.rowsPositionOffset = 0;
- return;
+ return {0, 0};
case ContentPositionRight:
// The align-content's axis is always orthogonal to the inline-axis.
- sizingData.rowsPositionOffset = 0;
- return;
+ return {0, 0};
case ContentPositionCenter:
- sizingData.rowsPositionOffset = availableFreeSpace / 2;
- return;
+ return {availableFreeSpace / 2, 0};
case ContentPositionFlexEnd:
// Only used in flex layout, for other layout, it's equivalent to 'End'.
case ContentPositionEnd:
- sizingData.rowsPositionOffset = availableFreeSpace;
- return;
+ return {availableFreeSpace, 0};
case ContentPositionFlexStart:
// Only used in flex layout, for other layout, it's equivalent to 'Start'.
case ContentPositionStart:
- sizingData.rowsPositionOffset = 0;
- return;
+ return {0, 0};
case ContentPositionBaseline:
case ContentPositionLastBaseline:
// FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
// crbug.com/234191
- sizingData.rowsPositionOffset = 0;
- return;
+ return {0, 0};
case ContentPositionAuto:
break;
}
ASSERT_NOT_REACHED();
+ return {0, 0};
}
LayoutPoint LayoutGrid::findChildLogicalPosition(const LayoutBox& child, GridSizingData& sizingData) const
@@ -1850,8 +1912,11 @@ LayoutPoint LayoutGrid::findChildLogicalPosition(const LayoutBox& child, GridSiz
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() + sizingData.columnsPositionOffset) - columnPosition - sizingData.columnsDistributionOffset - child.logicalWidth();
+ if (!style()->isLeftToRightDirection()) {
+ LayoutUnit rightEdgePosition = m_columnPositions[m_columnPositions.size() - 1] + borderAndPaddingLogicalLeft();
+ LayoutUnit leftEdgePosition = m_columnPositions[0] - borderAndPaddingStart();
+ columnPosition = rightEdgePosition + leftEdgePosition - columnPosition - child.logicalWidth();
+ }
svillar 2015/07/01 16:22:55 Not sure that I understand this, perhaps it's beca
jfernandez 2015/07/02 10:04:22 Are the names changes enough to make the code unde
return LayoutPoint(columnPosition, rowPositionForChild(child));
}
« Source/core/layout/LayoutGrid.h ('K') | « Source/core/layout/LayoutGrid.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698