[CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks
authorjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Jan 2013 02:41:22 +0000 (02:41 +0000)
committerjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Jan 2013 02:41:22 +0000 (02:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104700

Reviewed by Tony Chang.

Source/WebCore:

This change implements parts of the minmax() track sizing algorithm. The chosen subset enables us
to resolve any sizing function that doesn't size based on the content (min-content, max-content).

Tests: fast/css-grid-layout/minmax-fixed-logical-height-only.html
       fast/css-grid-layout/minmax-fixed-logical-width-only.html

* rendering/RenderGrid.cpp:
(WebCore::GridTrack::GridTrack):
Added a new member to hold the maximum track breadth.

(WebCore::RenderGrid::computePreferredLogicalWidths):
(WebCore::RenderGrid::computedUsedBreadthOfGridTracks):
Updated these functions to work on both min and max track breadth. In order to match
the specification, if max track breadth < min track breadth, we ignore the max track breadth.
For computedUsedBreadthOfGridTracks, it also involves calling distributeSpaceToTracks.

(WebCore::RenderGrid::computeUsedBreadthOfLength):
New helper function that compute a single length's size.

(WebCore::sortByGridTrackGrowthPotential):
Ordering function for the sorting the track: it orders the track per increasing potential
growth (defined as the difference between max breadth and the currently used breadth).

(WebCore::RenderGrid::distributeSpaceToTracks):
Added this function that matches the specification's algorithm. Only the relevant bits from
the specification were implemented for now (for example, SubsetOfTracksForGrowthBeyondTrackGrowthConstraint
is always the empty set so it was omitted).

* rendering/RenderGrid.h:
Added the new functions and declared GridTrack as public into the WebCore namespace.

* rendering/style/GridTrackSize.h:
(WebCore::GridTrackSize::minTrackBreadth):
(WebCore::GridTrackSize::maxTrackBreadth):
Removed 2 ASSERTs as the layout algorithm doesn't care if the min / max were
set from a single track breadth or through minmax().

LayoutTests:

* fast/css-grid-layout/minmax-fixed-logical-height-only-expected.txt: Added.
* fast/css-grid-layout/minmax-fixed-logical-height-only.html: Added.
* fast/css-grid-layout/minmax-fixed-logical-width-only-expected.txt: Added.
* fast/css-grid-layout/minmax-fixed-logical-width-only.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@139025 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/minmax-fixed-logical-height-only-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/minmax-fixed-logical-height-only.html [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/minmax-fixed-logical-width-only-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/minmax-fixed-logical-width-only.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/RenderGrid.h
Source/WebCore/rendering/style/GridTrackSize.h

index 19ad353..0417ede 100644 (file)
@@ -1,3 +1,15 @@
+2013-01-07  Julien Chaffraix  <jchaffraix@webkit.org>
+
+        [CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks
+        https://bugs.webkit.org/show_bug.cgi?id=104700
+
+        Reviewed by Tony Chang.
+
+        * fast/css-grid-layout/minmax-fixed-logical-height-only-expected.txt: Added.
+        * fast/css-grid-layout/minmax-fixed-logical-height-only.html: Added.
+        * fast/css-grid-layout/minmax-fixed-logical-width-only-expected.txt: Added.
+        * fast/css-grid-layout/minmax-fixed-logical-width-only.html: Added.
+
 2013-01-07  Xianzhu Wang  <wangxianzhu@chromium.org>
 
         Add a setting to enable composited scrolling for frames
diff --git a/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-height-only-expected.txt b/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-height-only-expected.txt
new file mode 100644 (file)
index 0000000..aca7ed1
--- /dev/null
@@ -0,0 +1,10 @@
+Bug 104700: [CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks
+
+Checks that a grid element with fixed minmax properly compute the logical height in several writing-mode.
+
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
diff --git a/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-height-only.html b/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-height-only.html
new file mode 100644 (file)
index 0000000..5d8575c
--- /dev/null
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<script>
+if (window.testRunner)
+    testRunner.overridePreference("WebKitCSSGridLayoutEnabled", 1);
+</script>
+<style>
+.grid {
+    display: -webkit-grid;
+    background-color: grey;
+    width: 100px;
+    height: 200px;
+}
+
+#grid1 {
+    -webkit-grid-columns: 30px;
+    -webkit-grid-rows: minmax(20px, 80px) 160px;
+}
+
+#grid2 {
+    -webkit-grid-columns: 30px;
+    -webkit-grid-rows: minmax(50%, 120px) minmax(20px, 40%);
+}
+
+#grid3 {
+    -webkit-grid-columns: 30px;
+    /* Overlapping range. */
+    -webkit-grid-rows: minmax(10px, 180px) minmax(30px, 150px);
+}
+
+#grid4 {
+    -webkit-grid-columns: 30px;
+    -webkit-grid-rows: minmax(20px, 80px) 60px;
+    -webkit-writing-mode: vertical-rl;
+}
+
+#grid5 {
+    -webkit-grid-columns: 30px;
+    /* 90% > 80px, 80px should be ignored. */
+    -webkit-grid-rows: minmax(90%, 80px) minmax(10px, 60%);
+    -webkit-writing-mode: vertical-lr;
+}
+
+#grid6 {
+    /* Overlapping range. */
+    -webkit-grid-columns: 30px;
+    -webkit-grid-rows: minmax(10px, 180px) minmax(30px, 150px);
+    -webkit-writing-mode: horizontal-bt;
+}
+
+#a {
+    background-color: blue;
+    -webkit-grid-column: 1;
+    -webkit-grid-row: 1;
+    width: 100%;
+    height: 100%;
+}
+
+#b {
+    background-color: green;
+    -webkit-grid-column: 1;
+    -webkit-grid-row: 2;
+    width: 100%;
+    height: 100%;
+}
+
+</style>
+<script src="../../resources/check-layout.js"></script>
+<body onload="checkLayout('.grid')">
+
+<p><a href="https://webkit.org/b/104700">Bug 104700<a>: [CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks</p>
+<p>Checks that a grid element with fixed minmax properly compute the logical height in several writing-mode.</p>
+
+<div class="grid" id="grid1" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="40" data-expected-width="30"></div>
+    <div id="b" data-expected-height="160" data-expected-width="30"></div>
+</div>
+
+<div class="grid" id="grid2" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="120" data-expected-width="30"></div>
+    <div id="b" data-expected-height="80" data-expected-width="30"></div>
+</div>
+
+<div class="grid" id="grid3" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="90" data-expected-width="30"></div>
+    <div id="b" data-expected-height="110" data-expected-width="30"></div>
+</div>
+
+<div class="grid" id="grid4" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="30" data-expected-width="40"></div>
+    <div id="b" data-expected-height="30" data-expected-width="60"></div>
+</div>
+
+<div class="grid" id="grid5" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="30" data-expected-width="90"></div>
+    <div id="b" data-expected-height="30" data-expected-width="10"></div>
+</div>
+
+<div class="grid" id="grid6" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="90" data-expected-width="30"></div>
+    <div id="b" data-expected-height="110" data-expected-width="30"></div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-width-only-expected.txt b/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-width-only-expected.txt
new file mode 100644 (file)
index 0000000..03e4f6f
--- /dev/null
@@ -0,0 +1,10 @@
+Bug 104700: [CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks
+
+Checks that a grid element with fixed minmax properly compute the logical width in several writing-mode.
+
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
diff --git a/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-width-only.html b/LayoutTests/fast/css-grid-layout/minmax-fixed-logical-width-only.html
new file mode 100644 (file)
index 0000000..94ab9a1
--- /dev/null
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<script>
+if (window.testRunner)
+    testRunner.overridePreference("WebKitCSSGridLayoutEnabled", 1);
+</script>
+<style>
+.grid {
+    display: -webkit-grid;
+    background-color: grey;
+    width: 100px;
+    height: 200px;
+}
+
+#grid1 {
+    -webkit-grid-columns: minmax(20px, 80px) 60px;
+    -webkit-grid-rows: 30px;
+}
+
+#grid2 {
+    /* First minmax more constraining than available logical width. */
+    -webkit-grid-columns: minmax(50%, 60px) minmax(10px, 40%);
+    -webkit-grid-rows: 30px;
+}
+
+#grid3 {
+    /* Overlapping range. */
+    -webkit-grid-columns: minmax(10px, 80px) minmax(20px, 50px);
+    -webkit-grid-rows: 30px;
+}
+
+#grid4 {
+    -webkit-grid-columns: minmax(20px, 80px) 160px;
+    -webkit-grid-rows: 30px;
+    -webkit-writing-mode: vertical-rl;
+}
+
+#grid5 {
+    /* 50% > 80px, 80px should be ignored. */
+    -webkit-grid-columns: minmax(50%, 80px) minmax(10px, 60%);
+    -webkit-grid-rows: 30px;
+    -webkit-writing-mode: vertical-lr;
+}
+
+#grid6 {
+    /* Overlapping range. */
+    -webkit-grid-columns: minmax(10px, 180px) minmax(30px, 150px);
+    -webkit-grid-rows: 30px;
+    -webkit-writing-mode: horizontal-bt;
+}
+
+#a {
+    background-color: blue;
+    -webkit-grid-column: 1;
+    -webkit-grid-row: 1;
+    width: 100%;
+    height: 100%;
+}
+
+#b {
+    background-color: green;
+    -webkit-grid-column: 2;
+    -webkit-grid-row: 1;
+    width: 100%;
+    height: 100%;
+}
+
+</style>
+<script src="../../resources/check-layout.js"></script>
+<body onload="checkLayout('.grid')">
+
+<p><a href="https://webkit.org/b/104700">Bug 104700<a>: [CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks</p>
+<p>Checks that a grid element with fixed minmax properly compute the logical width in several writing-mode.</p>
+
+<div class="grid" id="grid1" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="30" data-expected-width="40"></div>
+    <div id="b" data-expected-height="30" data-expected-width="60"></div>
+</div>
+
+<div class="grid" id="grid2" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="30" data-expected-width="60"></div>
+    <div id="b" data-expected-height="30" data-expected-width="40"></div>
+</div>
+
+<div class="grid" id="grid3" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="30" data-expected-width="50"></div>
+    <div id="b" data-expected-height="30" data-expected-width="50"></div>
+</div>
+
+<div class="grid" id="grid4" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="40" data-expected-width="30"></div>
+    <div id="b" data-expected-height="160" data-expected-width="30"></div>
+</div>
+
+<div class="grid" id="grid5" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="100" data-expected-width="30"></div>
+    <div id="b" data-expected-height="100" data-expected-width="30"></div>
+</div>
+
+<div class="grid" id="grid6" data-expected-width="100" data-expected-height="200">
+    <div id="a" data-expected-height="30" data-expected-width="40"></div>
+    <div id="b" data-expected-height="30" data-expected-width="60"></div>
+</div>
+
+</body>
+</html>
index b34d5ab..9e3f74d 100644 (file)
@@ -1,3 +1,47 @@
+2013-01-07  Julien Chaffraix  <jchaffraix@webkit.org>
+
+        [CSS Grid Layout] Implement grid items sizing for fixed minmax grid tracks
+        https://bugs.webkit.org/show_bug.cgi?id=104700
+
+        Reviewed by Tony Chang.
+
+        This change implements parts of the minmax() track sizing algorithm. The chosen subset enables us
+        to resolve any sizing function that doesn't size based on the content (min-content, max-content).
+
+        Tests: fast/css-grid-layout/minmax-fixed-logical-height-only.html
+               fast/css-grid-layout/minmax-fixed-logical-width-only.html
+
+        * rendering/RenderGrid.cpp:
+        (WebCore::GridTrack::GridTrack):
+        Added a new member to hold the maximum track breadth.
+
+        (WebCore::RenderGrid::computePreferredLogicalWidths):
+        (WebCore::RenderGrid::computedUsedBreadthOfGridTracks):
+        Updated these functions to work on both min and max track breadth. In order to match
+        the specification, if max track breadth < min track breadth, we ignore the max track breadth.
+        For computedUsedBreadthOfGridTracks, it also involves calling distributeSpaceToTracks.
+
+        (WebCore::RenderGrid::computeUsedBreadthOfLength):
+        New helper function that compute a single length's size.
+
+        (WebCore::sortByGridTrackGrowthPotential):
+        Ordering function for the sorting the track: it orders the track per increasing potential
+        growth (defined as the difference between max breadth and the currently used breadth).
+
+        (WebCore::RenderGrid::distributeSpaceToTracks):
+        Added this function that matches the specification's algorithm. Only the relevant bits from
+        the specification were implemented for now (for example, SubsetOfTracksForGrowthBeyondTrackGrowthConstraint
+        is always the empty set so it was omitted).
+
+        * rendering/RenderGrid.h:
+        Added the new functions and declared GridTrack as public into the WebCore namespace.
+
+        * rendering/style/GridTrackSize.h:
+        (WebCore::GridTrackSize::minTrackBreadth):
+        (WebCore::GridTrackSize::maxTrackBreadth):
+        Removed 2 ASSERTs as the layout algorithm doesn't care if the min / max were
+        set from a single track breadth or through minmax().
+
 2013-01-07  Xianzhu Wang  <wangxianzhu@chromium.org>
 
         Add a setting to enable composited scrolling for frames
index 322d3a8..016f530 100644 (file)
 
 namespace WebCore {
 
-class RenderGrid::GridTrack {
+class GridTrack {
 public:
     GridTrack()
         : m_usedBreadth(0)
+        , m_maxBreadth(0)
     {
     }
 
     LayoutUnit m_usedBreadth;
+    LayoutUnit m_maxBreadth;
 };
 
 RenderGrid::RenderGrid(Node* node)
@@ -119,14 +121,21 @@ void RenderGrid::computePreferredLogicalWidths()
     const Vector<GridTrackSize>& trackStyles = style()->gridColumns();
 
     for (size_t i = 0; i < trackStyles.size(); ++i) {
-        Length trackLength = trackStyles[i].length();
-        if (!trackLength.isFixed()) {
+        const Length& minTrackLength = trackStyles[i].minTrackBreadth();
+        const Length& maxTrackLength = trackStyles[i].maxTrackBreadth();
+        // FIXME: Handle only one fixed length properly (e.g minmax(100px, max-content)).
+        if (!minTrackLength.isFixed() || !maxTrackLength.isFixed()) {
             notImplemented();
             continue;
         }
 
-        m_minPreferredLogicalWidth += trackLength.intValue();
-        m_maxPreferredLogicalWidth += trackLength.intValue();
+        LayoutUnit minTrackBreadth = minTrackLength.intValue();
+        LayoutUnit maxTrackBreadth = maxTrackLength.intValue();
+
+        maxTrackBreadth = std::max(maxTrackBreadth, minTrackBreadth);
+
+        m_minPreferredLogicalWidth += minTrackBreadth;
+        m_maxPreferredLogicalWidth += maxTrackBreadth;
     }
 
     // FIXME: We should account for min / max logical width.
@@ -141,25 +150,63 @@ void RenderGrid::computePreferredLogicalWidths()
 void RenderGrid::computedUsedBreadthOfGridTracks(TrackSizingDirection direction, Vector<GridTrack>& tracks)
 {
     const Vector<GridTrackSize>& trackStyles = (direction == ForColumns) ? style()->gridColumns() : style()->gridRows();
+    LayoutUnit availableLogicalSpace = (direction == ForColumns) ? availableLogicalWidth() : availableLogicalHeight(IncludeMarginBorderPadding);
     for (size_t i = 0; i < trackStyles.size(); ++i) {
         GridTrack track;
-        switch (trackStyles[i].type()) {
-        case LengthTrackSizing: {
-            Length trackLength = trackStyles[i].length();
-            // FIXME: We stil need to support calc() here (bug 103761).
-            if (trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage())
-                track.m_usedBreadth = valueForLength(trackLength, direction == ForColumns ? logicalWidth() : computeContentLogicalHeight(MainOrPreferredSize, style()->logicalHeight()), view());
-            else
-                notImplemented();
-
-            break;
-        }
-        case MinMaxTrackSizing:
-            // FIXME: Implement support for minmax track sizing (bug 103311).
-            notImplemented();
-        }
+        const Length& minTrackBreadth = trackStyles[i].minTrackBreadth();
+        const Length& maxTrackBreadth = trackStyles[i].maxTrackBreadth();
+
+        track.m_usedBreadth = computeUsedBreadthOfLength(direction, minTrackBreadth);
+        track.m_maxBreadth = computeUsedBreadthOfLength(direction, maxTrackBreadth);
+
+        track.m_maxBreadth = std::max(track.m_maxBreadth, track.m_usedBreadth);
+
+        availableLogicalSpace -= track.m_usedBreadth;
+
         tracks.append(track);
     }
+
+    // FIXME: Implement content-based sizing (step 2 of the algorithm).
+
+    if (availableLogicalSpace <= 0)
+        return;
+
+    distributeSpaceToTracks(direction, tracks, availableLogicalSpace);
+}
+
+LayoutUnit RenderGrid::computeUsedBreadthOfLength(TrackSizingDirection direction, const Length& trackLength)
+{
+    // FIXME: We still need to support calc() here (bug 103761).
+    if (trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage())
+        return valueForLength(trackLength, direction == ForColumns ? logicalWidth() : computeContentLogicalHeight(MainOrPreferredSize, style()->logicalHeight()), view());
+
+    notImplemented();
+    return 0;
+}
+
+static bool sortByGridTrackGrowthPotential(GridTrack* track1, GridTrack* track2)
+{
+    return (track1->m_maxBreadth - track1->m_usedBreadth) <= (track2->m_maxBreadth - track2->m_usedBreadth);
+}
+
+void RenderGrid::distributeSpaceToTracks(TrackSizingDirection, Vector<GridTrack>& tracks, LayoutUnit availableLogicalSpace)
+{
+    const size_t tracksSize = tracks.size();
+    Vector<GridTrack*> sortedTracks(tracksSize);
+    for (size_t i = 0; i < tracksSize; ++i)
+        sortedTracks[i] = tracks.data() + i;
+
+    std::sort(sortedTracks.begin(), sortedTracks.end(), sortByGridTrackGrowthPotential);
+
+    for (size_t i = 0; i < tracksSize; ++i) {
+        GridTrack& track = *sortedTracks[i];
+        LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksSize - i);
+        LayoutUnit growthShare = std::min(availableLogicalSpaceShare, track.m_maxBreadth - track.m_usedBreadth);
+        track.m_usedBreadth += growthShare;
+        availableLogicalSpace -= growthShare;
+    }
+
+    // FIXME: We don't implement the last 2 steps of the algorithm as we don't implement content based sizing.
 }
 
 void RenderGrid::layoutGridItems()
index be9bbad..8eedfc2 100644 (file)
@@ -30,6 +30,8 @@
 
 namespace WebCore {
 
+class GridTrack;
+
 class RenderGrid : public RenderBlock {
 public:
     RenderGrid(Node*);
@@ -46,9 +48,10 @@ public:
 private:
     virtual bool isRenderGrid() const OVERRIDE { return true; }
 
-    class GridTrack;
     enum TrackSizingDirection { ForColumns, ForRows };
     void computedUsedBreadthOfGridTracks(TrackSizingDirection, Vector<GridTrack>&);
+    LayoutUnit computeUsedBreadthOfLength(TrackSizingDirection, const Length&);
+    void distributeSpaceToTracks(TrackSizingDirection, Vector<GridTrack>&, LayoutUnit availableLogicalSpace);
     void layoutGridItems();
 
     LayoutPoint findChildLogicalPosition(RenderBox*, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks);
index 0b5d8b1..142b2ad 100644 (file)
@@ -66,14 +66,12 @@ public:
 
     const Length& minTrackBreadth() const
     {
-        ASSERT(m_type == MinMaxTrackSizing);
         ASSERT(!m_minTrackBreadth.isUndefined());
         return m_minTrackBreadth;
     }
 
     const Length& maxTrackBreadth() const
     {
-        ASSERT(m_type == MinMaxTrackSizing);
         ASSERT(!m_maxTrackBreadth.isUndefined());
         return m_maxTrackBreadth;
     }