[CSS Grid Layout] Columns set in percentages collapse to auto width

Based on a patch by svillar@igalia.com.

RenderGrid::gridTrackSize() was not checking properly if the grid has or
not an indefinite size.

The condition was including auto which is not indefinite per se. For
example, auto is definite if the containing block is definite.

This patch adds 2 new new methods in RenderBox to determine if the grid
is definite or not.

BUG=407089
TEST=fast/css-grid-layout/percent-track-breadths-regarding-container-size.html

Review URL: https://codereview.chromium.org/906323003

git-svn-id: svn://svn.chromium.org/blink/trunk@189895 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/percent-track-breadths-regarding-container-size-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/percent-track-breadths-regarding-container-size-expected.txt
new file mode 100644
index 0000000..29459ebb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/percent-track-breadths-regarding-container-size-expected.txt
@@ -0,0 +1,50 @@
+This test checks percentage track breadths are resolved properly regarding the container size.
+
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
+XX
+XXXXX
+XXX
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/percent-track-breadths-regarding-container-size.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/percent-track-breadths-regarding-container-size.html
new file mode 100644
index 0000000..2da63d6c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/percent-track-breadths-regarding-container-size.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="resources/grid.css" rel="stylesheet">
+<style>
+.grid {
+    grid-template-columns: 20% 50% 30%;
+    grid-template-rows: 40%;
+}
+
+.fixedSize {
+    width: 400px;
+    height: 400px;
+}
+
+.calculatedSize {
+    width: calc(200px + 20%);
+    height: calc(300px + 10%);
+}
+
+.percentageSize {
+    width: 50%;
+    height: 50%;
+}
+
+.indefiniteSize {
+    width: -webkit-fit-content;
+    height: auto;
+}
+
+.legacyIntrinsicSize {
+    width: intrinsic;
+    height: intrinsic;
+}
+
+.firstRowFirstColumn {
+    color: blue;
+    background-color: cyan;
+}
+
+.firstRowSecondColumn {
+    color: green;
+    background-color: lime;
+}
+
+.firstRowThirdColumn {
+    color: brown;
+    background-color: yellow;
+    grid-column: 3;
+    grid-row: 1;
+}
+</style>
+<script src="../../resources/check-layout.js"></script>
+</head>
+<body onload="checkLayout('.grid');">
+    <p>This test checks percentage track breadths are resolved properly regarding the container size.</p>
+    <div class="unconstrainedContainer">
+        <div class="grid">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="200" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="500" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="300" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="indefiniteSize">
+        <div class="grid">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="unconstrainedContainer">
+        <div class="grid fixedSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="80" data-expected-height="160">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="200" data-expected-height="160">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="120" data-expected-height="160">XXX</div>
+        </div>
+    </div>
+
+    <div class="indefiniteSize">
+        <div class="grid fixedSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="80" data-expected-height="160">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="200" data-expected-height="160">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="120" data-expected-height="160">XXX</div>
+        </div>
+    </div>
+
+    <div class="indefiniteSize">
+        <div class="grid calculatedSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="unconstrainedContainer">
+        <div class="grid calculatedSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="80" data-expected-height="160">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="200" data-expected-height="160">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="120" data-expected-height="160">XXX</div>
+        </div>
+    </div>
+
+    <div class="indefiniteSize">
+        <div class="grid percentageSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="unconstrainedContainer">
+        <div class="grid percentageSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="100" data-expected-height="200">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="250" data-expected-height="200">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="150" data-expected-height="200">XXX</div>
+        </div>
+    </div>
+
+    <div class="indefiniteSize">
+        <div class="grid indefiniteSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="unconstrainedContainer">
+        <div class="grid indefiniteSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="indefiniteSize">
+        <div class="grid legacyIntrinsicSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+    <div class="unconstrainedContainer">
+        <div class="grid legacyIntrinsicSize">
+            <div class="firstRowFirstColumn sizedToGridArea" data-expected-width="20" data-expected-height="10">XX</div>
+            <div class="firstRowSecondColumn sizedToGridArea" data-expected-width="50" data-expected-height="10">XXXXX</div>
+            <div class="firstRowThirdColumn sizedToGridArea" data-expected-width="30" data-expected-height="10">XXX</div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/Source/core/rendering/RenderBox.cpp b/third_party/WebKit/Source/core/rendering/RenderBox.cpp
index b2b42cfa..c5e2eb2 100644
--- a/third_party/WebKit/Source/core/rendering/RenderBox.cpp
+++ b/third_party/WebKit/Source/core/rendering/RenderBox.cpp
@@ -4176,6 +4176,40 @@
     m_overflow->setLayoutOverflow(noOverflowRect());
 }
 
+bool RenderBox::logicalWidthIsResolvableFromBlock(const RenderBlock* containingBlock)
+{
+    const RenderBlock* cb = containingBlock;
+    while (!cb->isRenderView() && !cb->isOutOfFlowPositioned() && (cb->style()->logicalWidth().isAuto() || cb->isAnonymousBlock()))
+        cb = cb->containingBlock();
+    // Doesn't anonymousBlocks have all of them cb->style()->logicalWidth().isAuto()
+
+    if (cb->style()->logicalWidth().isFixed())
+        return true;
+    if (cb->isRenderView())
+        return true;
+    if (cb->isOutOfFlowPositioned())
+        return true;
+    if (cb->style()->logicalWidth().isPercent())
+        return logicalWidthIsResolvableFromBlock(cb->containingBlock());
+
+    return false;
+}
+
+bool RenderBox::hasDefiniteLogicalWidth() const
+{
+    const Length& logicalWidth = style()->logicalWidth();
+    if (logicalWidth.isIntrinsic() || logicalWidth.isLegacyIntrinsic())
+        return false;
+    if (logicalWidth.isFixed())
+        return true;
+    // The size of the containing block of an absolutely positioned element is always definite with respect to that
+    // element (http://dev.w3.org/csswg/css-sizing-3/#definite).
+    if (isOutOfFlowPositioned())
+        return true;
+
+    return RenderBox::logicalWidthIsResolvableFromBlock(containingBlock());
+}
+
 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
 {
     return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned());
@@ -4225,6 +4259,21 @@
     return false;
 }
 
+bool RenderBox::hasDefiniteLogicalHeight() const
+{
+    const Length& logicalHeight = style()->logicalHeight();
+    if (logicalHeight.isIntrinsicOrAuto())
+        return false;
+    if (logicalHeight.isFixed())
+        return true;
+    // The size of the containing block of an absolutely positioned element is always definite with respect to that
+    // element (http://dev.w3.org/csswg/css-sizing-3/#definite).
+    if (isOutOfFlowPositioned())
+        return true;
+
+    return percentageLogicalHeightIsResolvable(this);
+}
+
 bool RenderBox::hasUnsplittableScrollingOverflow() const
 {
     // We will paginate as long as we don't scroll overflow in the pagination direction.
diff --git a/third_party/WebKit/Source/core/rendering/RenderBox.h b/third_party/WebKit/Source/core/rendering/RenderBox.h
index 001a96b..0a254ed 100644
--- a/third_party/WebKit/Source/core/rendering/RenderBox.h
+++ b/third_party/WebKit/Source/core/rendering/RenderBox.h
@@ -455,7 +455,10 @@
     virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred  = ComputeActual) const;
     virtual LayoutUnit computeReplacedLogicalHeight() const;
 
+    static bool logicalWidthIsResolvableFromBlock(const RenderBlock* containingBlock);
+    bool hasDefiniteLogicalWidth() const;
     static bool percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool outOfFlowPositioned);
+    bool hasDefiniteLogicalHeight() const;
     LayoutUnit computePercentageLogicalHeight(const Length& height) const;
 
     // Block flows subclass availableWidth/Height to handle multi column layout (shrinking the width/height available to children when laying out.)
diff --git a/third_party/WebKit/Source/core/rendering/RenderGrid.cpp b/third_party/WebKit/Source/core/rendering/RenderGrid.cpp
index dfba456..8dda784 100644
--- a/third_party/WebKit/Source/core/rendering/RenderGrid.cpp
+++ b/third_party/WebKit/Source/core/rendering/RenderGrid.cpp
@@ -590,6 +590,11 @@
     return availableLogicalSpaceIgnoringFractionTracks / accumulatedFractions;
 }
 
+bool RenderGrid::hasDefiniteLogicalSize(GridTrackSizingDirection direction) const
+{
+    return (direction == ForRows) ? hasDefiniteLogicalHeight() : hasDefiniteLogicalWidth();
+}
+
 GridTrackSize RenderGrid::gridTrackSize(GridTrackSizingDirection direction, size_t i) const
 {
     bool isForColumns = direction == ForColumns;
@@ -598,10 +603,7 @@
 
     // If the logical width/height of the grid container is indefinite, percentage values are treated as <auto> (or in
     // the case of minmax() as min-content for the first position and max-content for the second).
-    Length logicalSize = isForColumns ? style()->logicalWidth() : style()->logicalHeight();
-    // FIXME: isIntrinsicOrAuto() does not fulfil the 'indefinite size' description as it does not include <percentage>
-    // of indefinite sizes. This is a broather issue as Length does not have the required context to support it.
-    if (logicalSize.isIntrinsicOrAuto()) {
+    if (!hasDefiniteLogicalSize(direction)) {
         const GridLength& oldMinTrackBreadth = trackSize.minTrackBreadth();
         const GridLength& oldMaxTrackBreadth = trackSize.maxTrackBreadth();
         return GridTrackSize(oldMinTrackBreadth.isPercentage() ? Length(MinContent) : oldMinTrackBreadth, oldMaxTrackBreadth.isPercentage() ? Length(MaxContent) : oldMaxTrackBreadth);
diff --git a/third_party/WebKit/Source/core/rendering/RenderGrid.h b/third_party/WebKit/Source/core/rendering/RenderGrid.h
index 59cdfe9..49620a1 100644
--- a/third_party/WebKit/Source/core/rendering/RenderGrid.h
+++ b/third_party/WebKit/Source/core/rendering/RenderGrid.h
@@ -160,6 +160,8 @@
         return m_grid.size();
     }
 
+    bool hasDefiniteLogicalSize(GridTrackSizingDirection) const;
+
     typedef Vector<Vector<GridCell> > GridRepresentation;
     GridRepresentation m_grid;
     bool m_gridIsDirty;