[css-grid] Make the grid sizing data persistent through layouts
authorjfernandez@igalia.com <jfernandez@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Jan 2017 18:41:28 +0000 (18:41 +0000)
committerjfernandez@igalia.com <jfernandez@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Jan 2017 18:41:28 +0000 (18:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=166883

Reviewed by Darin Adler and Manuel Rego Casasnovas.

Source/WebCore:

We want to keep the grid sizing data structures through different
layouts. This will allow to optimize some operations, reusing
these data while still valid. Additionally, operations like
determining the baseline position when the grid container is under
an inline formatting context need these data once the grid has
been laid out.

This patch controls the sizing data validity and make the data
structures persistent after layout.

Tests: fast/css-grid-layout/grid-add-item-with-positioned-items.html
       fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html
       fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html
       fast/css-grid-layout/grid-item-change-order-auto-flow.html

* rendering/RenderBox.cpp:
(WebCore::RenderBox::styleDidChange): Evaluate if the style change made the grid data invalid.
(WebCore::RenderBox::updateGridPositionAfterStyleChange): Evaluate if the style change made the grid data invalid.
* rendering/RenderBox.h:
* rendering/RenderGrid.cpp:
(WebCore::RenderGrid::Grid::setNeedsItemsPlacement): The grid must execute the items placement logic before continue processing the layout.
(WebCore::RenderGrid::addChild): Mark the grid data as dirty.
(WebCore::RenderGrid::removeChild): Mark the grid data as dirty.
(WebCore::RenderGrid::styleDidChange): Evaluate grid data validity.
(WebCore::RenderGrid::explicitGridDidResize): Mark the grid data as dirty.
(WebCore::RenderGrid::namedGridLinesDefinitionDidChange): Mark the grid data as dirty.
(WebCore::RenderGrid::layoutBlock): We don't need to clear the grid data anymore.
(WebCore::RenderGrid::dirtyGrid): Clearing the grid data and mark is as needing to execute the items placement logic.
(WebCore::RenderGrid::trackSizesForComputedStyle): Assert we don't need to perform the items placement logic.
(WebCore::RenderGrid::paintChildren): Assert we don't need to perform the items placement logic.
* rendering/RenderGrid.h:
(WebCore::RenderGrid::clear): Deleted.

LayoutTests:

The tests added are now needed to verify we perform correctly the
data validation after certain style changes.

* fast/css-grid-layout/grid-add-item-with-positioned-items-expected.txt: Added.
* fast/css-grid-layout/grid-add-item-with-positioned-items.html: Added.
* fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item-expected.txt: Added.
* fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html: Added.
* fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child-expected.txt: Added.
* fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html: Added.
* fast/css-grid-layout/grid-item-change-order-auto-flow-expected.txt: Added.
* fast/css-grid-layout/grid-item-change-order-auto-flow.html: Added.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/grid-add-item-with-positioned-items-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-add-item-with-positioned-items.html [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-item-change-order-auto-flow-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-item-change-order-auto-flow.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBox.h
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/RenderGrid.h

index 98d51e4..ac439c5 100644 (file)
@@ -1,3 +1,22 @@
+2017-01-12  Javier Fernandez  <jfernandez@igalia.com>
+
+        [css-grid] Make the grid sizing data persistent through layouts
+        https://bugs.webkit.org/show_bug.cgi?id=166883
+
+        Reviewed by Darin Adler and Manuel Rego Casasnovas.
+
+        The tests added are now needed to verify we perform correctly the
+        data validation after certain style changes.
+
+        * fast/css-grid-layout/grid-add-item-with-positioned-items-expected.txt: Added.
+        * fast/css-grid-layout/grid-add-item-with-positioned-items.html: Added.
+        * fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item-expected.txt: Added.
+        * fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html: Added.
+        * fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child-expected.txt: Added.
+        * fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html: Added.
+        * fast/css-grid-layout/grid-item-change-order-auto-flow-expected.txt: Added.
+        * fast/css-grid-layout/grid-item-change-order-auto-flow.html: Added.
+
 2017-01-12  Chris Dumez  <cdumez@apple.com>
 
         [iOS] Implement support for KeyboardEvent.code
diff --git a/LayoutTests/fast/css-grid-layout/grid-add-item-with-positioned-items-expected.txt b/LayoutTests/fast/css-grid-layout/grid-add-item-with-positioned-items-expected.txt
new file mode 100644 (file)
index 0000000..663072a
--- /dev/null
@@ -0,0 +1,3 @@
+This tests checks that adding grid items when some of them are positioned does not crash.
+
+
diff --git a/LayoutTests/fast/css-grid-layout/grid-add-item-with-positioned-items.html b/LayoutTests/fast/css-grid-layout/grid-add-item-with-positioned-items.html
new file mode 100644 (file)
index 0000000..088ac94
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #grid {
+        display: grid;
+        grid-auto-flow: stack;
+    }
+    .absolute {
+        position: absolute;
+    }
+</style>
+<script type="text/javascript">
+    if (window.testRunner)
+        testRunner.dumpAsText();
+</script>
+</head>
+<body>
+    <p>This tests checks that adding grid items when some of them are positioned does not crash.</p>
+    <div id="grid">
+        <div></div>
+        <div class="absolute"></div>
+    </div>
+    <script>
+        var grid = document.getElementById("grid");
+        grid.offsetTop;
+        var newItem1 = document.createElement("div");
+        grid.appendChild(newItem1);
+        var newItem2 = document.createElement("div");
+        newItem2.className = "absolute";
+        grid.appendChild(newItem2);
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item-expected.txt b/LayoutTests/fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item-expected.txt
new file mode 100644 (file)
index 0000000..9545c98
--- /dev/null
@@ -0,0 +1,3 @@
+This test checks that adding a positioned block grid item after an inline grid item (which inserts it inside the existing anonymous block wrapping the inline item) does not crash on debug.
+
+test 
diff --git a/LayoutTests/fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html b/LayoutTests/fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html
new file mode 100644 (file)
index 0000000..62e3074
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #grid {
+        display: grid;
+        grid-auto-flow: stack;
+    }
+    embed {
+        position: absolute;
+    }
+</style>
+<script type="text/javascript">
+    if (window.testRunner)
+        testRunner.dumpAsText();
+</script>
+</head>
+<body>
+    <p>This test checks that adding a positioned block grid item after an inline grid item (which inserts it inside the
+    existing anonymous block wrapping the inline item) does not crash on debug.</p>
+    <div id="grid">
+        test
+    </div>
+    <script>
+        var grid = document.getElementById("grid");
+        grid.offsetTop;
+        var embed = document.createElement("embed");
+        embed.setAttribute("type", "image/png");
+        grid.appendChild(embed);
+    </script>
+</body>
+</html>
diff --git a/LayoutTests/fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child-expected.txt b/LayoutTests/fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child-expected.txt
new file mode 100644 (file)
index 0000000..51b904e
--- /dev/null
@@ -0,0 +1,7 @@
+This test checks that grid-template-{rows|columns} dynamic updates recomputes the positions of automatically placed grid items.
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
diff --git a/LayoutTests/fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html b/LayoutTests/fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html
new file mode 100644 (file)
index 0000000..e9eb8bc
--- /dev/null
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<link href="resources/grid.css" rel="stylesheet">
+<script src="../../resources/check-layout.js"></script>
+<style>
+.grid {
+    grid-auto-flow: row dense;
+    grid-auto-rows: 5px;
+    grid-auto-columns: 5px;
+}
+#firstGridItem {
+    grid-row: auto;
+    grid-column: 1;
+}
+
+#secondGridItem {
+    grid-row: 1;
+    grid-column: auto;
+}
+
+#thirdGridItem {
+    grid-row: auto;
+    grid-column: auto;
+}
+</style>
+<script>
+function testGridDefinitions(gridTemplateRows, gridTemplateColumns, gridTemplateAreas, firstGridItemData, secondGridItemData, thirdGridItemData)
+{
+    var gridElement = document.getElementsByClassName("grid")[0];
+    gridElement.style.gridTemplateRows = gridTemplateRows;
+    gridElement.style.gridTemplateColumns = gridTemplateColumns;
+    gridElement.style.gridTemplateAreas = gridTemplateAreas;
+
+    var firstGridItem = document.getElementById("firstGridItem");
+    firstGridItem.setAttribute("data-expected-width", firstGridItemData.width);
+    firstGridItem.setAttribute("data-expected-height", firstGridItemData.height);
+    firstGridItem.setAttribute("data-offset-x", firstGridItemData.x);
+    firstGridItem.setAttribute("data-offset-y", firstGridItemData.y);
+
+    var secondGridItem = document.getElementById("secondGridItem");
+    secondGridItem.setAttribute("data-expected-width", secondGridItemData.width);
+    secondGridItem.setAttribute("data-expected-height", secondGridItemData.height);
+    secondGridItem.setAttribute("data-offset-x", secondGridItemData.x);
+    secondGridItem.setAttribute("data-offset-y", secondGridItemData.y);
+
+    var thirdGridItem = document.getElementById("thirdGridItem");
+    thirdGridItem.setAttribute("data-expected-width", thirdGridItemData.width);
+    thirdGridItem.setAttribute("data-expected-height", thirdGridItemData.height);
+    thirdGridItem.setAttribute("data-offset-x", thirdGridItemData.x);
+    thirdGridItem.setAttribute("data-offset-y", thirdGridItemData.y);
+
+    checkLayout(".grid");
+}
+
+function testChangingGridDefinitions()
+{
+    testGridDefinitions('10px 20px', '10px', '', { 'width': '10', 'height': '20', 'x': '0', 'y': '10' }, { 'width': '10', 'height': '10', 'x': '0', 'y': '0' }, { 'width': '10', 'height': '5', 'x': '0', 'y': '30' });
+    testGridDefinitions('10px', '10px', '"a"', { 'width': '10', 'height': '5', 'x': '0', 'y': '10' }, { 'width': '10', 'height': '10', 'x': '0', 'y': '0' }, { 'width': '10', 'height': '5', 'x': '0', 'y': '15' });
+    testGridDefinitions('10px', '10px', '"a ."', { 'width': '10', 'height': '5', 'x': '0', 'y': '10' }, { 'width': '10', 'height': '10', 'x': '0', 'y': '0' }, { 'width': '5', 'height': '10', 'x': '10', 'y': '0' });
+    testGridDefinitions('50px', '30px 40px', '', { 'width': '30', 'height': '5', 'x': '0', 'y': '50' }, { 'width': '30', 'height': '50', 'x': '0', 'y': '0' }, { 'width': '40', 'height': '50', 'x': '30', 'y': '0' });
+    testGridDefinitions('50px', '60px', '', { 'width': '60', 'height': '5', 'x': '0', 'y': '50' }, { 'width': '60', 'height': '50', 'x': '0', 'y': '0' }, { 'width': '60', 'height': '5', 'x': '0', 'y': '55' });
+    testGridDefinitions('50px 100px 150px', '60px', '', { 'width': '60', 'height': '100', 'x': '0', 'y': '50' }, { 'width': '60', 'height': '50', 'x': '0', 'y': '0' }, { 'width': '60', 'height': '150', 'x': '0', 'y': '150' });
+}
+
+window.addEventListener("load", testChangingGridDefinitions, false);
+</script>
+<body>
+<div>This test checks that grid-template-{rows|columns} dynamic updates recomputes the positions of automatically placed grid items.</div>
+
+<div style="position: relative">
+    <div class="grid">
+        <div class="sizedToGridArea" id="firstGridItem"></div>
+        <div class="sizedToGridArea" id="secondGridItem"></div>
+        <div class="sizedToGridArea" id="thirdGridItem"></div>
+    </div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/css-grid-layout/grid-item-change-order-auto-flow-expected.txt b/LayoutTests/fast/css-grid-layout/grid-item-change-order-auto-flow-expected.txt
new file mode 100644 (file)
index 0000000..0f089d6
--- /dev/null
@@ -0,0 +1,5 @@
+This test checks that grid items' 'order' dynamic updates recomputes the positions of automatically placed grid items.
+PASS
+PASS
+PASS
+PASS
diff --git a/LayoutTests/fast/css-grid-layout/grid-item-change-order-auto-flow.html b/LayoutTests/fast/css-grid-layout/grid-item-change-order-auto-flow.html
new file mode 100644 (file)
index 0000000..dcd5736
--- /dev/null
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<link href="resources/grid.css" rel="stylesheet">
+<script src="../../resources/check-layout.js"></script>
+<style>
+.grid {
+    grid-auto-flow: row;
+    grid-template-rows: 50px 100px;
+    grid-template-columns: 40px;
+}
+
+#firstGridItem {
+    grid-row: auto;
+    grid-column: 1;
+}
+
+#secondGridItem {
+    grid-row: 1;
+    grid-column: auto;
+}
+
+#thirdGridItem {
+    grid-row: auto;
+    grid-column: auto;
+}
+</style>
+<script>
+function testGridItemsOrder(firstGridItemData, secondGridItemData, thirdGridItemData)
+{
+    var firstGridItem = document.getElementById("firstGridItem");
+    firstGridItem.style.order = firstGridItemData.order;
+    firstGridItem.setAttribute("data-expected-width", firstGridItemData.width);
+    firstGridItem.setAttribute("data-expected-height", firstGridItemData.height);
+    firstGridItem.setAttribute("data-offset-x", firstGridItemData.x);
+    firstGridItem.setAttribute("data-offset-y", firstGridItemData.y);
+
+    var secondGridItem = document.getElementById("secondGridItem");
+    secondGridItem.style.order = secondGridItemData.order;
+    secondGridItem.setAttribute("data-expected-width", secondGridItemData.width);
+    secondGridItem.setAttribute("data-expected-height", secondGridItemData.height);
+    secondGridItem.setAttribute("data-offset-x", secondGridItemData.x);
+    secondGridItem.setAttribute("data-offset-y", secondGridItemData.y);
+
+    var thirdGridItem = document.getElementById("thirdGridItem");
+    thirdGridItem.style.order = thirdGridItemData.order;
+    thirdGridItem.setAttribute("data-expected-width", thirdGridItemData.width);
+    thirdGridItem.setAttribute("data-expected-height", thirdGridItemData.height);
+    thirdGridItem.setAttribute("data-offset-x", thirdGridItemData.x);
+    thirdGridItem.setAttribute("data-offset-y", thirdGridItemData.y);
+
+    checkLayout(".grid");
+}
+
+function testChangingGridItemsOrder()
+{
+    testGridItemsOrder({ 'order': '0', 'width': '40', 'height': '100', 'x': '0', 'y': '50' }, { 'order': '0', 'width': '40', 'height': '50', 'x': '0', 'y': '0' }, { 'order': '0', 'width': '40', 'height': '0', 'x': '0', 'y': '150' });
+    testGridItemsOrder({ 'order': '0', 'width': '40', 'height': '100', 'x': '0', 'y': '50' }, { 'order': '-1', 'width': '40', 'height': '50', 'x': '0', 'y': '0' }, { 'order': '0', 'width': '40', 'height': '0', 'x': '0', 'y': '150' });
+    testGridItemsOrder({ 'order': '1', 'width': '40', 'height': '0', 'x': '0', 'y': '150' }, { 'order': '-1', 'width': '40', 'height': '50', 'x': '0', 'y': '0' }, { 'order': '0', 'width': '40', 'height': '100', 'x': '0', 'y': '50' });
+    testGridItemsOrder({ 'order': '1', 'width': '40', 'height': '100', 'x': '0', 'y': '50' }, { 'order': '-1', 'width': '40', 'height': '50', 'x': '0', 'y': '0' }, { 'order': '10', 'width': '40', 'height': '0', 'x': '0', 'y': '150' });
+}
+
+window.addEventListener("load", testChangingGridItemsOrder, false);
+</script>
+<body>
+<div>This test checks that grid items' 'order' dynamic updates recomputes the positions of automatically placed grid items.</div>
+
+<div style="position: relative">
+    <div class="grid">
+        <div class="sizedToGridArea" id="firstGridItem"></div>
+        <div class="sizedToGridArea" id="secondGridItem"></div>
+        <div class="sizedToGridArea" id="thirdGridItem"></div>
+    </div>
+</div>
+
+</body>
+</html>
index e69dd2e..c54e983 100644 (file)
@@ -1,3 +1,43 @@
+2017-01-12  Javier Fernandez  <jfernandez@igalia.com>
+
+        [css-grid] Make the grid sizing data persistent through layouts
+        https://bugs.webkit.org/show_bug.cgi?id=166883
+
+        Reviewed by Darin Adler and Manuel Rego Casasnovas.
+
+        We want to keep the grid sizing data structures through different
+        layouts. This will allow to optimize some operations, reusing
+        these data while still valid. Additionally, operations like
+        determining the baseline position when the grid container is under
+        an inline formatting context need these data once the grid has
+        been laid out.
+
+        This patch controls the sizing data validity and make the data
+        structures persistent after layout.
+
+        Tests: fast/css-grid-layout/grid-add-item-with-positioned-items.html
+               fast/css-grid-layout/grid-add-positioned-block-item-after-inline-item.html
+               fast/css-grid-layout/grid-container-change-explicit-grid-recompute-child.html
+               fast/css-grid-layout/grid-item-change-order-auto-flow.html
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::styleDidChange): Evaluate if the style change made the grid data invalid.
+        (WebCore::RenderBox::updateGridPositionAfterStyleChange): Evaluate if the style change made the grid data invalid.
+        * rendering/RenderBox.h:
+        * rendering/RenderGrid.cpp:
+        (WebCore::RenderGrid::Grid::setNeedsItemsPlacement): The grid must execute the items placement logic before continue processing the layout.
+        (WebCore::RenderGrid::addChild): Mark the grid data as dirty.
+        (WebCore::RenderGrid::removeChild): Mark the grid data as dirty.
+        (WebCore::RenderGrid::styleDidChange): Evaluate grid data validity.
+        (WebCore::RenderGrid::explicitGridDidResize): Mark the grid data as dirty.
+        (WebCore::RenderGrid::namedGridLinesDefinitionDidChange): Mark the grid data as dirty.
+        (WebCore::RenderGrid::layoutBlock): We don't need to clear the grid data anymore.
+        (WebCore::RenderGrid::dirtyGrid): Clearing the grid data and mark is as needing to execute the items placement logic.
+        (WebCore::RenderGrid::trackSizesForComputedStyle): Assert we don't need to perform the items placement logic.
+        (WebCore::RenderGrid::paintChildren): Assert we don't need to perform the items placement logic.
+        * rendering/RenderGrid.h:
+        (WebCore::RenderGrid::clear): Deleted.
+
 2017-01-12  Chris Dumez  <cdumez@apple.com>
 
         [iOS] Implement support for KeyboardEvent.code
index b4a7ba0..3433ec5 100644 (file)
 #include <math.h>
 #include <wtf/StackStats.h>
 
+#if ENABLE(CSS_GRID_LAYOUT)
+#include "RenderGrid.h"
+#endif
+
 #if PLATFORM(IOS)
 #include "Settings.h"
 #endif
@@ -450,6 +454,9 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
 
     if ((oldStyle && oldStyle->shapeOutside()) || style().shapeOutside())
         updateShapeOutsideInfoAfterStyleChange(style(), oldStyle);
+#if ENABLE(CSS_GRID_LAYOUT)
+    updateGridPositionAfterStyleChange(style(), oldStyle);
+#endif
 }
 
 void RenderBox::willBeRemovedFromTree()
@@ -462,6 +469,34 @@ void RenderBox::willBeRemovedFromTree()
     RenderBoxModelObject::willBeRemovedFromTree();
 }
     
+#if ENABLE(CSS_GRID_LAYOUT)
+
+void RenderBox::updateGridPositionAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
+{
+    if (!oldStyle || !is<RenderGrid>(parent()))
+        return;
+
+    if (oldStyle->gridItemColumnStart() == style.gridItemColumnStart()
+        && oldStyle->gridItemColumnEnd() == style.gridItemColumnEnd()
+        && oldStyle->gridItemRowStart() == style.gridItemRowStart()
+        && oldStyle->gridItemRowEnd() == style.gridItemRowEnd()
+        && oldStyle->order() == style.order()
+        && oldStyle->hasOutOfFlowPosition() == style.hasOutOfFlowPosition())
+        return;
+
+    // Positioned items don't participate on the layout of the grid,
+    // so we don't need to mark the grid as dirty if they change positions.
+    if (oldStyle->hasOutOfFlowPosition() && style.hasOutOfFlowPosition())
+        return;
+
+    // It should be possible to not dirty the grid in some cases (like moving an
+    // explicitly placed grid item).
+    // For now, it's more simple to just always recompute the grid.
+    downcast<RenderGrid>(*parent()).dirtyGrid();
+}
+
+#endif
+
 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
 {
     const ShapeValue* shapeOutside = style.shapeOutside();
index d0fa7b2..4f5549d 100644 (file)
@@ -654,6 +654,7 @@ private:
     void updateShapeOutsideInfoAfterStyleChange(const RenderStyle&, const RenderStyle* oldStyle);
 
 #if ENABLE(CSS_GRID_LAYOUT)
+    void updateGridPositionAfterStyleChange(const RenderStyle&, const RenderStyle* oldStyle);
     bool isGridItem() const { return parent() && parent()->isRenderGrid(); }
 #endif
 
index 33bff0e..13fca78 100644 (file)
@@ -152,23 +152,20 @@ void RenderGrid::Grid::setNeedsItemsPlacement(bool needsItemsPlacement)
 {
     m_needsItemsPlacement = needsItemsPlacement;
 
-    if (needsItemsPlacement)
-        clear();
-}
+    if (!needsItemsPlacement) {
+        m_grid.shrinkToFit();
+        return;
+    }
 
-void RenderGrid::Grid::clear()
-{
     m_grid.resize(0);
     m_gridItemArea.clear();
     m_hasAnyOrthogonalGridItem = false;
     m_smallestRowStart = 0;
     m_smallestColumnStart = 0;
-    // FIXME: clear these once m_grid survives layout. We cannot clear them now because they're
-    // needed after layout.
-    // m_autoRepeatEmptyColumns = nullptr;
-    // m_autoRepeatEmptyRows = nullptr;
-    // m_autoRepeatColumns = 0;
-    // m_autoRepeatRows = 0;
+    m_autoRepeatEmptyColumns = nullptr;
+    m_autoRepeatEmptyRows = nullptr;
+    m_autoRepeatColumns = 0;
+    m_autoRepeatRows = 0;
 }
 
 class GridTrack {
@@ -491,6 +488,24 @@ static inline bool selfAlignmentChangedFromStretchInColumnAxis(const RenderStyle
         && childStyle.resolvedAlignSelf(newStyle, selfAlignmentNormalBehavior).position() != ItemPositionStretch;
 }
 
+void RenderGrid::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+    RenderBlock::addChild(newChild, beforeChild);
+
+    // The grid needs to be recomputed as it might contain auto-placed items that
+    // will change their position.
+    dirtyGrid();
+}
+
+void RenderGrid::removeChild(RenderObject& child)
+{
+    RenderBlock::removeChild(child);
+
+    // The grid needs to be recomputed as it might contain auto-placed items that
+    // will change their position.
+    dirtyGrid();
+}
+
 void RenderGrid::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
 {
     RenderBlock::styleDidChange(diff, oldStyle);
@@ -512,6 +527,26 @@ void RenderGrid::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
             }
         }
     }
+
+    if (explicitGridDidResize(*oldStyle) || namedGridLinesDefinitionDidChange(*oldStyle) || oldStyle->gridAutoFlow() != style().gridAutoFlow()
+        || (style().gridAutoRepeatColumns().size() || style().gridAutoRepeatRows().size()))
+        dirtyGrid();
+}
+
+bool RenderGrid::explicitGridDidResize(const RenderStyle& oldStyle) const
+{
+    return oldStyle.gridColumns().size() != style().gridColumns().size()
+        || oldStyle.gridRows().size() != style().gridRows().size()
+        || oldStyle.namedGridAreaColumnCount() != style().namedGridAreaColumnCount()
+        || oldStyle.namedGridAreaRowCount() != style().namedGridAreaRowCount()
+        || oldStyle.gridAutoRepeatColumns().size() != style().gridAutoRepeatColumns().size()
+        || oldStyle.gridAutoRepeatRows().size() != style().gridAutoRepeatRows().size();
+}
+
+bool RenderGrid::namedGridLinesDefinitionDidChange(const RenderStyle& oldStyle) const
+{
+    return oldStyle.namedGridRowLines() != style().namedGridRowLines()
+        || oldStyle.namedGridColumnLines() != style().namedGridColumnLines();
 }
 
 LayoutUnit RenderGrid::computeTrackBasedLogicalHeight(const GridSizingData& sizingData) const
@@ -651,8 +686,6 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
 
     layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
 
-    clearGrid();
-
     computeOverflow(oldClientAfterEdge);
     statePusher.pop();
 
@@ -1953,8 +1986,11 @@ GridTrackSizingDirection RenderGrid::autoPlacementMinorAxisDirection() const
     return style().isGridAutoFlowDirectionColumn() ? ForRows : ForColumns;
 }
 
-void RenderGrid::clearGrid()
+void RenderGrid::dirtyGrid()
 {
+    if (m_grid.needsItemsPlacement())
+        return;
+
     m_grid.setNeedsItemsPlacement(true);
 }
 
@@ -1969,8 +2005,7 @@ Vector<LayoutUnit> RenderGrid::trackSizesForComputedStyle(GridTrackSizingDirecti
     if (numPositions < 2)
         return tracks;
 
-    // FIXME: enable the ASSERT once m_grid is persistent.
-    // ASSERT(!m_grid.needsItemsPlacement());
+    ASSERT(!m_grid.needsItemsPlacement());
     bool hasCollapsedTracks = m_grid.hasAutoRepeatEmptyTracks(direction);
     LayoutUnit gap = !hasCollapsedTracks ? gridGapForDirection(direction) : LayoutUnit();
     tracks.reserveCapacity(numPositions - 1);
@@ -2803,8 +2838,7 @@ unsigned RenderGrid::numTracks(GridTrackSizingDirection direction, const Grid& g
 
 void RenderGrid::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& forChild, bool usePrintRect)
 {
-    // FIXME: enable the ASSERT once m_grid is persistent.
-    // ASSERT(!m_grid.needsItemsPlacement());
+    ASSERT(!m_grid.needsItemsPlacement());
     for (RenderBox* child = m_grid.orderIterator().first(); child; child = m_grid.orderIterator().next())
         paintChild(*child, paintInfo, paintOffset, forChild, usePrintRect, PaintAsInlineBlock);
 }
index f39d50a..4313a6e 100644 (file)
@@ -65,6 +65,7 @@ public:
     bool avoidsFloats() const override { return true; }
     bool canDropAnonymousBlockChild() const override { return false; }
 
+    void dirtyGrid();
     Vector<LayoutUnit> trackSizesForComputedStyle(GridTrackSizingDirection) const;
 
     const Vector<LayoutUnit>& columnPositions() const { return m_columnPositions; }
@@ -77,6 +78,12 @@ private:
     bool isRenderGrid() const override { return true; }
     void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override;
 
+    void addChild(RenderObject* newChild, RenderObject* beforeChild) final;
+    void removeChild(RenderObject&) final;
+
+    bool explicitGridDidResize(const RenderStyle&) const;
+    bool namedGridLinesDefinitionDidChange(const RenderStyle&) const;
+
     std::optional<LayoutUnit> computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, std::optional<LayoutUnit> intrinsicContentHeight, LayoutUnit borderAndPadding) const override;
 
     class Grid;
@@ -117,7 +124,6 @@ private:
 
     void layoutGridItems(GridSizingData&);
     void populateGridPositionsForDirection(GridSizingData&, GridTrackSizingDirection);
-    void clearGrid();
 
     static bool shouldProcessTrackForTrackSizeComputationPhase(TrackSizeComputationPhase, const GridTrackSize&);
     static bool trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(TrackSizeComputationPhase, const GridTrackSize&);
@@ -241,8 +247,6 @@ private:
     private:
         friend class GridIterator;
 
-        void clear();
-
         OrderIterator m_orderIterator;
 
         int m_smallestColumnStart { 0 };