 Chromium Code Reviews
 Chromium Code Reviews Issue 815833005:
  [css-grid] Handle min-content/max-content with orthogonal flows  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master
    
  
    Issue 815833005:
  [css-grid] Handle min-content/max-content with orthogonal flows  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master| 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 559ff539950feba2497a8a70f9deafaf72a786b3..25183d3f099a07a386920b5d5c01ed574d4be4e4 100644 | 
| --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp | 
| +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp | 
| @@ -249,7 +249,46 @@ public: | 
| enum SizingOperation { TrackSizing, IntrinsicSizeComputation }; | 
| SizingOperation sizingOperation { TrackSizing }; | 
| - | 
| + enum SizingState { ColumnSizingFirstIteration, RowSizingFirstIteration, ColumnSizingSecondIteration, RowSizingSecondIteration}; | 
| + SizingState sizingState { ColumnSizingFirstIteration }; | 
| + void stateTransition() | 
| 
svillar
2016/06/02 14:39:40
Nit: what about nextState() ?
 
jfernandez
2016/06/02 21:39:25
Done.
 | 
| + { | 
| + switch (sizingState) { | 
| + case ColumnSizingFirstIteration: | 
| + sizingState = RowSizingFirstIteration; | 
| + return; | 
| + case RowSizingFirstIteration: | 
| + sizingState = ColumnSizingSecondIteration; | 
| + return; | 
| + case ColumnSizingSecondIteration: | 
| + sizingState = RowSizingSecondIteration; | 
| + return; | 
| + case RowSizingSecondIteration: | 
| + sizingState = ColumnSizingFirstIteration; | 
| + return; | 
| + } | 
| + NOTREACHED(); | 
| + sizingState = ColumnSizingFirstIteration; | 
| + } | 
| +#if DCHECK_IS_ON() | 
| + bool isValidTransitionForDirection(GridTrackSizingDirection direction) | 
| + { | 
| + switch (sizingState) { | 
| + case ColumnSizingFirstIteration: | 
| + return direction == ForColumns ? true : false; | 
| + case RowSizingFirstIteration: | 
| + return direction == ForRows ? true : false; | 
| + case ColumnSizingSecondIteration: | 
| + if (direction == ForRows) | 
| + sizingState = RowSizingFirstIteration; | 
| + return true; | 
| + case RowSizingSecondIteration: | 
| + return direction == ForRows ? true : false; | 
| + } | 
| + NOTREACHED(); | 
| + return false; | 
| + } | 
| +#endif | 
| private: | 
| LayoutUnit freeSpaceForColumns { }; | 
| LayoutUnit freeSpaceForRows { }; | 
| @@ -337,12 +376,32 @@ LayoutUnit LayoutGrid::computeTrackBasedLogicalHeight(const GridSizingData& sizi | 
| void LayoutGrid::computeTrackSizesForDirection(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit freeSpace) | 
| { | 
| ASSERT(freeSpace >= 0); | 
| + DCHECK(sizingData.isValidTransitionForDirection(direction)); | 
| sizingData.freeSpaceForDirection(direction) = freeSpace - guttersSize(direction, direction == ForRows ? gridRowCount() : gridColumnCount()); | 
| sizingData.sizingOperation = GridSizingData::TrackSizing; | 
| LayoutUnit baseSizes, growthLimits; | 
| computeUsedBreadthOfGridTracks(direction, sizingData, baseSizes, growthLimits, AvailableSpaceDefinite); | 
| ASSERT(tracksAreWiderThanMinTrackBreadth(direction, sizingData)); | 
| + sizingData.stateTransition(); | 
| +} | 
| + | 
| +void LayoutGrid::repeatTracksSizingIfNeeded(GridSizingData& sizingData, LayoutUnit availableSpaceForColumns, LayoutUnit availableSpaceForRows) | 
| +{ | 
| + DCHECK(sizingData.sizingState > GridSizingData::RowSizingFirstIteration); | 
| + | 
| + // In orthogonal flow cases column track's size is determined by using the computed | 
| + // row track's size, which it was estimated during the first cycle of the sizing | 
| + // algorithm. Hence we need to repeat computeUsedBreadthOfGridTracks for both, | 
| + // columns and rows, to determine the final values. | 
| + // TODO (lajava): orthogonal flows is just one of the cases which may require | 
| + // a new cycle of the sizing algorithm; there may be more. In addition, not all the | 
| + // cases with orthogonal flows require this extra cycle; we need a more specific | 
| + // condition to detect whether child's min-content contribution has changed or not. | 
| + if (m_hasAnyOrthogonalChild) { | 
| + computeTrackSizesForDirection(ForColumns, sizingData, availableSpaceForColumns); | 
| + computeTrackSizesForDirection(ForRows, sizingData, availableSpaceForRows); | 
| + } | 
| 
svillar
2016/06/02 14:39:40
I think we don't need this, see my comment bellow.
 
jfernandez
2016/06/02 21:39:25
I disagree, I think the function adds value, see m
 | 
| } | 
| void LayoutGrid::layoutBlock(bool relayoutChildren) | 
| @@ -375,7 +434,8 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) | 
| // properly resolves intrinsic sizes. We cannot do the same for heights though because many code | 
| // paths inside updateLogicalHeight() require a previous call to setLogicalHeight() to resolve | 
| // heights properly (like for positioned items for example). | 
| - computeTrackSizesForDirection(ForColumns, sizingData, availableLogicalWidth()); | 
| + LayoutUnit availableSpaceForColumns = availableLogicalWidth(); | 
| + computeTrackSizesForDirection(ForColumns, sizingData, availableSpaceForColumns); | 
| // 2- Next, the track sizing algorithm resolves the sizes of the grid rows, using the | 
| // grid column sizes calculated in the previous step. | 
| @@ -390,8 +450,14 @@ void LayoutGrid::layoutBlock(bool relayoutChildren) | 
| // The above call might have changed the grid's logical height depending on min|max height restrictions. | 
| // Update the sizes of the rows whose size depends on the logical height (also on definite|indefinite sizes). | 
| + LayoutUnit availableSpaceForRows = contentLogicalHeight(); | 
| if (logicalHeightWasIndefinite) | 
| - computeTrackSizesForDirection(ForRows, sizingData, contentLogicalHeight()); | 
| + computeTrackSizesForDirection(ForRows, sizingData, availableSpaceForRows); | 
| + | 
| + // 3- If the min-content contribution of any grid items have changed based on the row | 
| + // sizes calculated in step 2, steps 1 and 2 are repeated with the new min-content | 
| + // contribution (once only). | 
| + repeatTracksSizingIfNeeded(sizingData, availableSpaceForColumns, availableSpaceForRows); | 
| // Grid container should have the minimum height of a line if it's editable. That doesn't affect track sizing though. | 
| if (hasLineIfEmpty()) | 
| @@ -674,7 +740,7 @@ bool LayoutGrid::hasDefiniteLogicalSize(GridTrackSizingDirection direction) cons | 
| static bool hasOverrideContainingBlockContentSizeForChild(const LayoutBox& child, GridTrackSizingDirection direction) | 
| { | 
| - return direction == ForColumns ? child.hasOverrideContainingBlockLogicalWidth() : child.overrideContainingBlockContentLogicalHeight(); | 
| + return direction == ForColumns ? child.hasOverrideContainingBlockLogicalWidth() : child.hasOverrideContainingBlockLogicalHeight(); | 
| } | 
| static LayoutUnit overrideContainingBlockContentSizeForChild(const LayoutBox& child, GridTrackSizingDirection direction) | 
| @@ -784,9 +850,6 @@ GridTrackSizingDirection LayoutGrid::flowAwareDirectionForChild(const LayoutBox& | 
| LayoutUnit LayoutGrid::minSizeForChild(LayoutBox& child, GridTrackSizingDirection direction, GridSizingData& sizingData) | 
| { | 
| - // TODO(svillar): Properly support orthogonal writing mode. | 
| - if (isOrthogonalChild(child)) | 
| - return LayoutUnit(); | 
| GridTrackSizingDirection childInlineDirection = flowAwareDirectionForChild(child, ForColumns); | 
| bool isRowAxis = direction == childInlineDirection; | 
| const Length& childSize = isRowAxis ? child.styleRef().logicalWidth() : child.styleRef().logicalHeight(); | 
| @@ -818,9 +881,6 @@ bool LayoutGrid::updateOverrideContainingBlockContentSizeForChild(LayoutBox& chi | 
| LayoutUnit LayoutGrid::minContentForChild(LayoutBox& child, GridTrackSizingDirection direction, GridSizingData& sizingData) | 
| { | 
| - // FIXME: Properly support orthogonal writing mode. | 
| - if (isOrthogonalChild(child)) | 
| - return LayoutUnit(); | 
| GridTrackSizingDirection childInlineDirection = flowAwareDirectionForChild(child, ForColumns); | 
| if (direction == childInlineDirection) { | 
| // If |child| has a relative logical width, we shouldn't let it override its intrinsic width, which is | 
| @@ -841,8 +901,6 @@ LayoutUnit LayoutGrid::minContentForChild(LayoutBox& child, GridTrackSizingDirec | 
| LayoutUnit LayoutGrid::maxContentForChild(LayoutBox& child, GridTrackSizingDirection direction, GridSizingData& sizingData) | 
| { | 
| - if (isOrthogonalChild(child)) | 
| - return LayoutUnit(); | 
| GridTrackSizingDirection childInlineDirection = flowAwareDirectionForChild(child, ForColumns); | 
| if (direction == childInlineDirection) { | 
| // If |child| has a relative logical width, we shouldn't let it override its intrinsic width, which is | 
| @@ -1307,10 +1365,13 @@ void LayoutGrid::placeItemsOnGrid() | 
| Vector<LayoutBox*> autoMajorAxisAutoGridItems; | 
| Vector<LayoutBox*> specifiedMajorAxisAutoGridItems; | 
| + m_hasAnyOrthogonalChild = false; | 
| for (LayoutBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { | 
| if (child->isOutOfFlowPositioned()) | 
| continue; | 
| + m_hasAnyOrthogonalChild = m_hasAnyOrthogonalChild || isOrthogonalChild(*child); | 
| 
svillar
2016/06/02 14:39:40
That is not enough. Note that you could dynamicall
 
jfernandez
2016/06/02 21:39:25
I see, I'll change how I identify orthogonality.
 | 
| + | 
| GridArea area = cachedGridArea(*child); | 
| if (!area.rows.isIndefinite()) | 
| area.rows.translate(abs(m_smallestRowStart)); | 
| @@ -1593,7 +1654,7 @@ void LayoutGrid::layoutGridItems(GridSizingData& sizingData) | 
| LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadthForChildIncludingAlignmentOffsets(*child, ForRows, sizingData); | 
| SubtreeLayoutScope layoutScope(*child); | 
| - if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingBlockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != overrideContainingBlockContentLogicalHeight && child->hasRelativeLogicalHeight())) | 
| + if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingBlockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != overrideContainingBlockContentLogicalHeight && (child->hasRelativeLogicalHeight() || isOrthogonalChild(*child)))) | 
| layoutScope.setNeedsLayout(child, LayoutInvalidationReason::GridChanged); | 
| child->setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockContentLogicalWidth); | 
| @@ -1763,8 +1824,34 @@ GridSpan LayoutGrid::cachedGridSpan(const LayoutBox& gridItem, GridTrackSizingDi | 
| return direction == ForColumns ? area.columns : area.rows; | 
| } | 
| +LayoutUnit LayoutGrid::assumedRowsSizeForOrthogonalChild(const LayoutBox& child) const | 
| +{ | 
| + DCHECK(isOrthogonalChild(child)); | 
| + const GridSpan& span = cachedGridSpan(child, ForRows); | 
| + LayoutUnit gridAreaSize; | 
| + bool gridAreaIsIndefinite = false; | 
| + LayoutUnit containingBlockAvailableSize = containingBlockLogicalHeightForContent(ExcludeMarginBorderPadding); | 
| + for (auto trackPosition : span) { | 
| + const GridLength& maxTrackSize = gridTrackSize(ForRows, trackPosition).maxTrackBreadth(); | 
| + if (maxTrackSize.isContentSized() || maxTrackSize.isFlex()) | 
| 
svillar
2016/06/02 14:39:40
I think this is still not correct for percentages
 
jfernandez
2016/06/02 21:39:25
I don't understand what you mean; as far as I know
 
svillar
2016/06/10 08:08:35
Yes you're right, sorry for the noise.
 | 
| + gridAreaIsIndefinite = true; | 
| + else | 
| + gridAreaSize += valueForLength(maxTrackSize.length(), containingBlockAvailableSize); | 
| + } | 
| + | 
| + gridAreaSize += guttersSize(ForRows, span.integerSpan()); | 
| + | 
| + return gridAreaIsIndefinite ? std::max(child.maxPreferredLogicalWidth(), gridAreaSize) : gridAreaSize; | 
| +} | 
| + | 
| LayoutUnit LayoutGrid::gridAreaBreadthForChild(const LayoutBox& child, GridTrackSizingDirection direction, const GridSizingData& sizingData) const | 
| { | 
| + // To determine the column track's size based on an orthogonal grid item we need it's logical height, which | 
| + // may depend on the row track's size. It's possible that the row tracks sizing logic has not been performed yet, | 
| + // so we will need to do an estimation. | 
| + if (direction == ForRows && sizingData.sizingState == GridSizingData::ColumnSizingFirstIteration) | 
| + return assumedRowsSizeForOrthogonalChild(child); | 
| 
svillar
2016/06/02 14:39:40
So assumedRowsSizeForOrthogonalChild() has an asse
 
jfernandez
2016/06/02 21:39:25
If we are determining column track's size in the F
 
svillar
2016/06/10 08:08:35
OK. In any case as we depend on the value of an st
 
jfernandez
2016/06/21 21:50:03
Done.
 | 
| + | 
| const Vector<GridTrack>& tracks = direction == ForColumns ? sizingData.columnTracks : sizingData.rowTracks; | 
| const GridSpan& span = cachedGridSpan(child, direction); | 
| LayoutUnit gridAreaBreadth; | 
| @@ -2232,13 +2319,19 @@ LayoutUnit LayoutGrid::translateRTLCoordinate(LayoutUnit coordinate) const | 
| LayoutPoint LayoutGrid::findChildLogicalPosition(const LayoutBox& child, GridSizingData& sizingData) const | 
| { | 
| + LayoutUnit columnAxisOffset = columnAxisOffsetForChild(child, sizingData); | 
| LayoutUnit rowAxisOffset = rowAxisOffsetForChild(child, sizingData); | 
| // We stored m_columnPosition'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()) | 
| rowAxisOffset = translateRTLCoordinate(rowAxisOffset) - child.logicalWidth(); | 
| - return LayoutPoint(rowAxisOffset, columnAxisOffsetForChild(child, sizingData)); | 
| + // "In the positioning phase [...] calculations are performed according to the writing mode | 
| + // of the containing block of the box establishing the orthogonal flow." However, the | 
| + // resulting LayoutPoint will be used in 'setLogicalPosition' in order to set the child's | 
| + // logical position, which will only take into account the child's writing-mode. | 
| + LayoutPoint childLocation(rowAxisOffset, columnAxisOffset); | 
| + return isOrthogonalChild(child) ? childLocation.transposedPoint() : childLocation; | 
| } | 
| void LayoutGrid::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const |