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)); |
} |