Position grid items by row/column index
authortony@chromium.org <tony@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Jul 2012 19:09:57 +0000 (19:09 +0000)
committertony@chromium.org <tony@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Jul 2012 19:09:57 +0000 (19:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=91293

Reviewed by Ojan Vafai.

Source/WebCore:

Do some initial grid positioning. Only handle the simple case where tracks are
fixed values and don't properly size the grid items. This gives us something to
work with and starts implementing the "Grid Track Sizing Algorithm":
http://dev.w3.org/csswg/css3-grid-layout/#grid-track-sizing-algorithm0

Test: fast/css-grid-layout/place-cell-by-index.html

* rendering/RenderGrid.cpp:
(RenderGrid::GridTrack): Data structure for holding the track size. UsedBreadth matches the terminology
used in the spec.
(WebCore::RenderGrid::layoutBlock): Pull in some boiler plate code and put the
grid specific code in layoutGridItems.
(WebCore::RenderGrid::computedUsedBreadthOfGridTracks): Implement part of the grid track sizing algorithm.
(WebCore::RenderGrid::layoutGridItems): Compute the size of grid tracks, layout and position children.
(WebCore::RenderGrid::findChildLogicalPosition): Map track sizes to the actual position of the child.
* rendering/RenderGrid.h:
* rendering/style/RenderStyle.h: Just return a copy of Length rather than a reference to Length. This seems
more consistent with other getters that return a Length.

LayoutTests:

Add a test for grid layout in each writing mode direction.  The height in vertical writing mode is incorrect for now.

* fast/css-grid-layout/containing-block-grids-expected.html: Scope <p> around text only.
* fast/css-grid-layout/containing-block-grids.html: Fix missing closing </div>.
* fast/css-grid-layout/place-cell-by-index-expected.txt: Added.
* fast/css-grid-layout/place-cell-by-index.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/containing-block-grids-expected.html
LayoutTests/fast/css-grid-layout/containing-block-grids.html
LayoutTests/fast/css-grid-layout/place-cell-by-index-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/place-cell-by-index.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/RenderGrid.h
Source/WebCore/rendering/style/RenderStyle.h

index 44f854e9f2cbd8f9cefb9a6a51589be7e58c2689..56723e70b614f80b3f3ef547ab9c98dd6f5da11e 100644 (file)
@@ -1,3 +1,17 @@
+2012-07-16  Tony Chang  <tony@chromium.org>
+
+        Position grid items by row/column index
+        https://bugs.webkit.org/show_bug.cgi?id=91293
+
+        Reviewed by Ojan Vafai.
+
+        Add a test for grid layout in each writing mode direction.  The height in vertical writing mode is incorrect for now.
+
+        * fast/css-grid-layout/containing-block-grids-expected.html: Scope <p> around text only.
+        * fast/css-grid-layout/containing-block-grids.html: Fix missing closing </div>.
+        * fast/css-grid-layout/place-cell-by-index-expected.txt: Added.
+        * fast/css-grid-layout/place-cell-by-index.html: Added.
+
 2012-07-16  Mike West  <mkwst@chromium.org>
 
         Invalid `script-nonce` directives should block script execution.
index 573f2b5ad4f8b295925686be581bf95ea6815cea..a97812a0db06dca2d5927f158bfcedd573bfb829 100644 (file)
@@ -6,8 +6,7 @@
     </style>
 </head>
 <body>
-<p>Grids can act as containing blocks for positioned content.
+<p>Grids can act as containing blocks for positioned content.</p>
 <div style="width: 100px; height: 200px; background-color: green;"></div>
-</p>
 </body>
 </html>
index a6ae771a385e5b67f273050908ade8db12522f4c..8bb4b8abdf79ca53b82a74b3151f585367bc52be 100644 (file)
@@ -12,9 +12,8 @@
     </style>
 </head>
 <body>
-<p>Grids can act as containing blocks for positioned content.
-<div class="relative-positioned-grid" style="display: -webkit-grid"><div style="background-color: green; left: 0; top: 0"></div>
-<div class="relative-positioned-inline-grid" style="display: -webkit-inline-grid"><div style="background-color:green; left: 0; top: 0"></div>
-</p>
+<p>Grids can act as containing blocks for positioned content.</p>
+<div class="relative-positioned-grid" style="display: -webkit-grid"><div style="background-color: green; left: 0; top: 0"></div></div>
+<div class="relative-positioned-inline-grid" style="display: -webkit-inline-grid"><div style="background-color:green; left: 0; top: 0"></div></div>
 </body>
 </html>
diff --git a/LayoutTests/fast/css-grid-layout/place-cell-by-index-expected.txt b/LayoutTests/fast/css-grid-layout/place-cell-by-index-expected.txt
new file mode 100644 (file)
index 0000000..d2cecc8
--- /dev/null
@@ -0,0 +1,22 @@
+Test some simple grid layouts by positioning grid items by index.
+
+PASS
+PASS
+FAIL:
+Expected 110 for height, but got 15. 
+
+<div class="grid" style="-webkit-writing-mode: vertical-rl; margin-bottom: 60px;" data-expected-width="50" data-expected-height="110">
+    <div id="a" data-offset-x="40" data-offset-y="0"></div>
+    <div id="b" data-offset-x="40" data-offset-y="50"></div>
+    <div id="c" data-offset-x="20" data-offset-y="0"></div>
+    <div id="d" data-offset-x="20" data-offset-y="50"></div>
+</div>
+FAIL:
+Expected 110 for height, but got 15. 
+
+<div class="grid" style="-webkit-writing-mode: vertical-lr; margin-bottom: 60px;" data-expected-width="50" data-expected-height="110">
+    <div id="a" data-offset-x="0" data-offset-y="0"></div>
+    <div id="b" data-offset-x="0" data-offset-y="50"></div>
+    <div id="c" data-offset-x="20" data-offset-y="0"></div>
+    <div id="d" data-offset-x="20" data-offset-y="50"></div>
+</div>
diff --git a/LayoutTests/fast/css-grid-layout/place-cell-by-index.html b/LayoutTests/fast/css-grid-layout/place-cell-by-index.html
new file mode 100644 (file)
index 0000000..97b978c
--- /dev/null
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<script>
+if (window.testRunner) {
+    testRunner.overridePreference("WebKitCSSGridLayoutEnabled", 1);
+    testRunner.dumpAsText();
+}
+</script>
+<style>
+.grid {
+    display: -webkit-grid;
+    -webkit-grid-columns: 50px 60px;
+    -webkit-grid-rows: 20px 30px;
+    background-color: grey;
+    max-width: 110px;
+}
+
+#a {
+    background-color: blue;
+    -webkit-grid-column: 1;
+    -webkit-grid-row: 1;
+    width: 10px;
+    height: 15px;
+}
+#b {
+    background-color: green;
+    -webkit-grid-column: 2;
+    -webkit-grid-row: 1;
+    width: 10px;
+    height: 15px;
+}
+#c {
+    background-color: red;
+    -webkit-grid-column: 1;
+    -webkit-grid-row: 2;
+    width: 10px;
+    height: 15px;
+}
+#d {
+    background-color: orange;
+    -webkit-grid-column: 2;
+    -webkit-grid-row: 2;
+    width: 10px;
+    height: 15px;
+}
+</style>
+<script src="../../resources/check-layout.js"></script>
+<body onload="checkLayout('.grid')">
+
+<p>Test some simple grid layouts by positioning grid items by index.</p>
+
+<div style="position: relative">
+<div class="grid" data-expected-width="110" data-expected-height="50">
+    <div id="a" data-offset-x="0" data-offset-y="0"></div>
+    <div id="b" data-offset-x="50" data-offset-y="0"></div>
+    <div id="c" data-offset-x="0" data-offset-y="20"></div>
+    <div id="d" data-offset-x="50" data-offset-y="20"></div>
+</div>
+</div>
+
+<div style="position: relative">
+<div class="grid" style="-webkit-writing-mode: horizontal-bt" data-expected-width="110" data-expected-height="50">
+    <div id="a" data-offset-x="0" data-offset-y="35"></div>
+    <div id="b" data-offset-x="50" data-offset-y="35"></div>
+    <div id="c" data-offset-x="0" data-offset-y="15"></div>
+    <div id="d" data-offset-x="50" data-offset-y="15"></div>
+</div>
+</div>
+
+<div style="position: relative">
+<!-- FIXME: The height of the grid is wrong because we need to implement computePreferredLogicalWidths(). -->
+<div class="grid" style="-webkit-writing-mode: vertical-rl; margin-bottom: 60px;" data-expected-width="50" data-expected-height="110">
+    <div id="a" data-offset-x="40" data-offset-y="0"></div>
+    <div id="b" data-offset-x="40" data-offset-y="50"></div>
+    <div id="c" data-offset-x="20" data-offset-y="0"></div>
+    <div id="d" data-offset-x="20" data-offset-y="50"></div>
+</div>
+</div>
+
+<div style="position: relative">
+<!-- FIXME: The height of the grid is wrong because we need to implement computePreferredLogicalWidths(). -->
+<div class="grid" style="-webkit-writing-mode: vertical-lr; margin-bottom: 60px;" data-expected-width="50" data-expected-height="110">
+    <div id="a" data-offset-x="0" data-offset-y="0"></div>
+    <div id="b" data-offset-x="0" data-offset-y="50"></div>
+    <div id="c" data-offset-x="20" data-offset-y="0"></div>
+    <div id="d" data-offset-x="20" data-offset-y="50"></div>
+</div>
+</div>
+
+</body>
+</html>
index d3089f327773aef477b130807a9f8659d1fbd409..4b2bcab32d8796d829cc89ed0272f2affb5d6424 100644 (file)
@@ -1,3 +1,29 @@
+2012-07-16  Tony Chang  <tony@chromium.org>
+
+        Position grid items by row/column index
+        https://bugs.webkit.org/show_bug.cgi?id=91293
+
+        Reviewed by Ojan Vafai.
+
+        Do some initial grid positioning. Only handle the simple case where tracks are
+        fixed values and don't properly size the grid items. This gives us something to
+        work with and starts implementing the "Grid Track Sizing Algorithm":
+        http://dev.w3.org/csswg/css3-grid-layout/#grid-track-sizing-algorithm0
+
+        Test: fast/css-grid-layout/place-cell-by-index.html
+
+        * rendering/RenderGrid.cpp:
+        (RenderGrid::GridTrack): Data structure for holding the track size. UsedBreadth matches the terminology
+        used in the spec.
+        (WebCore::RenderGrid::layoutBlock): Pull in some boiler plate code and put the
+        grid specific code in layoutGridItems.
+        (WebCore::RenderGrid::computedUsedBreadthOfGridTracks): Implement part of the grid track sizing algorithm.
+        (WebCore::RenderGrid::layoutGridItems): Compute the size of grid tracks, layout and position children.
+        (WebCore::RenderGrid::findChildLogicalPosition): Map track sizes to the actual position of the child.
+        * rendering/RenderGrid.h:
+        * rendering/style/RenderStyle.h: Just return a copy of Length rather than a reference to Length. This seems
+        more consistent with other getters that return a Length.
+
 2012-07-16  Sami Kyostila  <skyostil@chromium.org>
 
         [chromium] Only apply page scale delta to root scroll layer
index 883e1710b0102b96be8de24925aaabc783893ad7..b4d2a0c08b4f6072ec605da6c47242be8bdfa2e0 100644 (file)
  */
 
 #include "config.h"
-
 #include "RenderGrid.h"
 
+#include "LayoutRepainter.h"
+#include "NotImplemented.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+
 namespace WebCore {
 
+class RenderGrid::GridTrack {
+public:
+    GridTrack()
+        : m_usedBreadth(0)
+    {
+    }
+
+    LayoutUnit m_usedBreadth;
+};
+
 RenderGrid::RenderGrid(Node* node)
     : RenderBlock(node)
 {
@@ -40,10 +54,129 @@ RenderGrid::~RenderGrid()
 {
 }
 
-void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
+void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
 {
-    // For now just call the base class.
-    RenderBlock::layoutBlock(relayoutChildren, pageLogicalHeight);
+    ASSERT(needsLayout());
+
+    if (!relayoutChildren && simplifiedLayout())
+        return;
+
+    // FIXME: Much of this method is boiler plate that matches RenderBox::layoutBlock and Render*FlexibleBox::layoutBlock.
+    // It would be nice to refactor some of the duplicate code.
+    LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
+    LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
+
+    if (inRenderFlowThread()) {
+        // Regions changing widths can force us to relayout our children.
+        if (logicalWidthChangedInRegions())
+            relayoutChildren = true;
+    }
+    computeInitialRegionRangeForBlock();
+
+    LayoutSize previousSize = size();
+
+    setLogicalHeight(0);
+    computeLogicalWidth();
+
+    m_overflow.clear();
+
+    if (scrollsOverflow()) {
+        if (style()->overflowX() == OSCROLL)
+            layer()->setHasHorizontalScrollbar(true);
+        if (style()->overflowY() == OSCROLL)
+            layer()->setHasVerticalScrollbar(true);
+    }
+
+    layoutGridItems();
+
+    LayoutUnit oldClientAfterEdge = clientLogicalBottom();
+    computeLogicalHeight();
+
+    if (size() != previousSize)
+        relayoutChildren = true;
+
+    layoutPositionedObjects(relayoutChildren || isRoot());
+
+    computeRegionRangeForBlock();
+
+    computeOverflow(oldClientAfterEdge);
+    statePusher.pop();
+
+    updateLayerTransform();
+
+    // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
+    // we overflow or not.
+    if (hasOverflowClip())
+        layer()->updateScrollInfoAfterLayout();
+
+    repainter.repaintAfterLayout();
+
+    setNeedsLayout(false);
+}
+
+void RenderGrid::computedUsedBreadthOfGridTracks(TrackSizingDirection direction, Vector<GridTrack>& tracks)
+{
+    const Vector<Length>& trackStyles = (direction == ForColumns) ? style()->gridColumns() : style()->gridRows();
+    for (size_t i = 0; i < trackStyles.size(); ++i) {
+        GridTrack track;
+        if (trackStyles[i].isFixed())
+            track.m_usedBreadth = trackStyles[i].getFloatValue();
+        else
+            notImplemented();
+
+        tracks.append(track);
+    }
+}
+
+void RenderGrid::layoutGridItems()
+{
+    Vector<GridTrack> columnTracks, rowTracks;
+    computedUsedBreadthOfGridTracks(ForColumns, columnTracks);
+    // FIXME: The logical width of Grid Columns from the prior step is used in
+    // the formatting of Grid items in content-sized Grid Rows to determine
+    // their required height. We will probably need to pass columns through.
+    computedUsedBreadthOfGridTracks(ForRows, rowTracks);
+
+    for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+        LayoutPoint childPosition = findChildLogicalPosition(child, columnTracks, rowTracks);
+        // FIXME: Grid items should stretch to fill their cells. Once we
+        // implement grid-{column,row}-align, we can also shrink to fit. For
+        // now, just size as if we were a regular child.
+        child->layoutIfNeeded();
+
+        // FIXME: Handle border & padding on the grid element.
+        child->setLogicalLocation(childPosition);
+    }
+
+    // FIXME: Handle border & padding on the grid element.
+    for (size_t i = 0; i < rowTracks.size(); ++i)
+        setLogicalHeight(logicalHeight() + rowTracks[i].m_usedBreadth);
+}
+
+LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks)
+{
+    Length column = child->style()->gridItemColumn();
+    Length row = child->style()->gridItemRow();
+
+    // FIXME: What does a non-positive integer mean for a column/row?
+    if (!column.isPositive() || !row.isPositive())
+        return LayoutPoint();
+
+    // FIXME: Handle other values for grid-{row,column} like ranges or line names.
+    if (!column.isFixed() || !row.isFixed())
+        return LayoutPoint();
+
+    size_t columnTrack = static_cast<size_t>(column.intValue()) - 1;
+    size_t rowTrack = static_cast<size_t>(row.intValue()) - 1;
+
+    LayoutPoint offset;
+    for (size_t i = 0; i < columnTrack && i < columnTracks.size(); ++i)
+        offset.setX(offset.x() + columnTracks[i].m_usedBreadth);
+    for (size_t i = 0; i < rowTrack && i < rowTracks.size(); ++i)
+        offset.setY(offset.y() + rowTracks[i].m_usedBreadth);
+
+    // FIXME: Handle margins on the grid item.
+    return offset;
 }
 
 const char* RenderGrid::renderName() const
index 28498fe432d6471de414ae99215dc593580a1453..829bf8862442be9ea13f416c8dc1aa27bcbc9177 100644 (file)
@@ -40,6 +40,14 @@ public:
     virtual void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) OVERRIDE;
 
     virtual bool avoidsFloats() const OVERRIDE { return true; }
+
+private:
+    class GridTrack;
+    enum TrackSizingDirection { ForColumns, ForRows };
+    void computedUsedBreadthOfGridTracks(TrackSizingDirection, Vector<GridTrack>&);
+    void layoutGridItems();
+
+    LayoutPoint findChildLogicalPosition(RenderBox*, const Vector<GridTrack>& columnTracks, const Vector<GridTrack>& rowTracks);
 };
 
 } // namespace WebCore
index a984ff6c088907649fd29c710124151203766aaa..8eb49f7d80f7b94209f75de906f3b3c104b7c01e 100644 (file)
@@ -814,8 +814,8 @@ public:
     const Vector<Length>& gridColumns() const { return rareNonInheritedData->m_grid->m_gridColumns; }
     const Vector<Length>& gridRows() const { return rareNonInheritedData->m_grid->m_gridRows; }
 
-    const Length& gridItemColumn() const { return rareNonInheritedData->m_gridItem->m_gridColumn; }
-    const Length& gridItemRow() const { return rareNonInheritedData->m_gridItem->m_gridRow; }
+    Length gridItemColumn() const { return rareNonInheritedData->m_gridItem->m_gridColumn; }
+    Length gridItemRow() const { return rareNonInheritedData->m_gridItem->m_gridRow; }
 
     const ShadowData* boxShadow() const { return rareNonInheritedData->m_boxShadow.get(); }
     void getBoxShadowExtent(LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const { getShadowExtent(boxShadow(), top, right, bottom, left); }