[CSS Grid Layout] Simplify the named grid lines resolution algorithm
authorsvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Jun 2014 10:23:59 +0000 (10:23 +0000)
committersvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Jun 2014 10:23:59 +0000 (10:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133543

Reviewed by Darin Adler.

Source/WebCore:
Named grid lines resolution algorithm can be heavily simplified by
inserting the implicit named grid lines generated by each grid
area (<area-name>-{start|end} for rows and columns), into the list
of user defined named grid lines. This way we would only have to
deal with named grid lines and forget about the named grid areas
(as described in the specs
http://dev.w3.org/csswg/css-grid/#grid-placement-slot).

As a nice side effect, we'll get for free the implementation of the
use case described in section 5.2.2 Implicit Named Areas.

Test: fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html

* css/StyleResolver.cpp:
(WebCore::createImplicitNamedGridLinesFromGridArea):
(WebCore::StyleResolver::applyProperty):
* rendering/RenderGrid.cpp:
(WebCore::isStartSide):
(WebCore::gridLinesForSide):
(WebCore::implicitNamedGridLineForSide):
(WebCore::isNonExistentNamedLineOrArea):
(WebCore::RenderGrid::adjustGridPositionsFromStyle):
(WebCore::RenderGrid::resolveNamedGridLinePositionFromStyle):
(WebCore::RenderGrid::resolveGridPositionFromStyle):
(WebCore::RenderGrid::resolveNamedGridLinePositionAgainstOppositePosition):
(WebCore::gridLineDefinedBeforeGridArea): Deleted.
(WebCore::setNamedLinePositionIfDefinedBeforeArea): Deleted.
(WebCore::RenderGrid::adjustNamedGridItemPosition): Deleted.

LayoutTests:
Added a new test that checks that named grid lines and areas are
correctly set after dynamically changing them with JS. It also
verifies that we properly recompute the resolution of named grid
lines/areas when the positioning properties change.

Also appended a new test case to verify that explicitly adding
named lines of the form <foo-start>/<foo-end> effectively creates
implicit named grid areas so that we could use them in grid
placement properties (for example -webkit-grid-column: foo).

No need to add more tests for named grid lines/areas resolution as
we already have a quite good coverage (the feature was already
there, we're simplifying/improving the implementation).

* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set-expected.txt: Added.
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html: Added.
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution-expected.txt:
* fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html:

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

LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution-expected.txt
LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html
Source/WebCore/ChangeLog
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/rendering/RenderGrid.cpp

index b057f02..50a4eb2 100644 (file)
@@ -1,3 +1,29 @@
+2014-06-05  Sergio Villar Senin  <svillar@igalia.com>
+
+        [CSS Grid Layout] Simplify the named grid lines resolution algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=133543
+
+        Reviewed by Darin Adler.
+
+        Added a new test that checks that named grid lines and areas are
+        correctly set after dynamically changing them with JS. It also
+        verifies that we properly recompute the resolution of named grid
+        lines/areas when the positioning properties change.
+
+        Also appended a new test case to verify that explicitly adding
+        named lines of the form <foo-start>/<foo-end> effectively creates
+        implicit named grid areas so that we could use them in grid
+        placement properties (for example -webkit-grid-column: foo).
+
+        No need to add more tests for named grid lines/areas resolution as
+        we already have a quite good coverage (the feature was already
+        there, we're simplifying/improving the implementation).
+
+        * fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set-expected.txt: Added.
+        * fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html: Added.
+        * fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution-expected.txt:
+        * fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html:
+
 2014-06-10  Kiran  <kiran.guduru@samsung.com>
 
         [MediaStream] Add getTracks() support to MediaStream.
diff --git a/LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set-expected.txt b/LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set-expected.txt
new file mode 100644 (file)
index 0000000..84d944b
--- /dev/null
@@ -0,0 +1,37 @@
+This test checks we properly recompute the resolution of named grid lines and named grid areas when we change the grid positioning properties.
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
diff --git a/LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html b/LayoutTests/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html
new file mode 100644 (file)
index 0000000..fa0115a
--- /dev/null
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link href="resources/grid.css" rel="stylesheet">
+<script src="../../resources/check-layout.js"></script>
+<script type="text/javascript">
+
+function testLayout(gridDefinitions, itemsDefinitions)
+{
+    var gridContainer = document.getElementById("gridContainer");
+    var gridElement = document.createElement("div");
+    gridElement.className = "grid";
+
+    for (var key in gridDefinitions) {
+       if (key == "rows")
+           gridElement.style.webkitGridTemplateRows = gridDefinitions[key];
+       else if (key == "columns")
+           gridElement.style.webkitGridTemplateColumns = gridDefinitions[key];
+       else
+           gridElement.style.webkitGridTemplateAreas = gridDefinitions[key];
+    }
+
+    for (var i in itemsDefinitions) {
+       var itemDefinition = itemsDefinitions[i];
+       var gridItem = document.createElement("div");
+       gridItem.className = "sizedToGridArea";
+
+       if (itemDefinition.row)
+           gridItem.style.webkitGridRow = itemDefinition.row;
+       if (itemDefinition.column)
+           gridItem.style.webkitGridColumn = itemDefinition.column;
+
+       gridItem.setAttribute("data-offset-x", itemDefinition.x);
+       gridItem.setAttribute("data-offset-y", itemDefinition.y);
+       gridItem.setAttribute("data-expected-width", itemDefinition.width);
+       gridItem.setAttribute("data-expected-height", itemDefinition.height);
+
+       gridElement.appendChild(gridItem);
+    }
+
+    gridContainer.appendChild(gridElement);
+
+    checkLayout(".grid", document.getElementById("test-output"));
+    gridContainer.removeChild(gridElement);
+}
+
+function updateRowsColumns()
+{
+    var templateAreaOne = '". a a" "c a a" ". . d"';
+    var templateAreaTwo = '". d d" "a d d" ". . c"';
+
+    var columnUniqueNames = '(a) 50px (b b-start) 100px (c -start) 200px (d)';
+    var rowUniqueNames = '(e) 50px (f -end) 100px (g g-start) 200px (h)';
+    var columnNamedLineBeforeArea = '(a-start c-start) 50px (d-start) 100px 200px';
+    var rowNamedLineBeforeArea = '(c-start) 50px (d-start) 100px 200px';
+    var columnRepeatedNames = '(d-start) 50px (d-start) 100px (d-start) 200px';
+    var rowRepeatedNames = '50px (c-end) 100px (c-end) 200px (c-end)';
+    var columnNoNames = '50px 100px 200px';
+    var rowNoNames = '50px 100px 200px';
+
+    // Check grid area resolution.
+    var gridAreasItems = [ { 'column': 'd', 'x': '150', 'y': '0', 'width': '200', 'height': '50' },
+                          { 'column': 'c', 'x': '0', 'y': '0', 'width': '50', 'height': '50' },
+                          { 'column': 'a', 'x': '50', 'y': '0', 'width': '300', 'height': '50' }];
+
+    testLayout({ 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaOne }, gridAreasItems);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnNoNames, 'rows': rowNoNames }, gridAreasItems);
+    testLayout({ 'columns': columnNoNames, 'areas': templateAreaOne, 'rows': rowNoNames }, gridAreasItems);
+
+    var gridAreasItemsTwo = [ { 'column': 'd', 'x': '50', 'y': '0', 'width': '300', 'height': '50' },
+                             { 'column': 'c', 'x': '150', 'y': '0', 'width': '200', 'height': '50' },
+                             { 'column': 'a', 'x': '0', 'y': '0', 'width': '50', 'height': '50' }];
+
+    testLayout({ 'areas': templateAreaTwo, 'areas': templateAreaOne, 'columns': columnNoNames, 'rows': rowNoNames }, gridAreasItems);
+    testLayout({ 'areas': templateAreaOne, 'areas': templateAreaTwo, 'columns': columnNoNames, 'rows': rowNoNames }, gridAreasItemsTwo);
+    testLayout({ 'areas': templateAreaTwo, 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaOne,  }, gridAreasItems);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaTwo,  }, gridAreasItemsTwo);
+    testLayout({ 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaTwo, 'areas': templateAreaOne }, gridAreasItems);
+    testLayout({ 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaOne, 'areas': templateAreaTwo }, gridAreasItemsTwo);
+
+    // Check grid implicit named grid lines resolution.
+    var implicitNamesItems = [{ 'column': 'a-start', 'row': 'd-start', 'x': '50', 'y': '150', 'width': '100', 'height': '200' },
+                             { 'column': 'a-start', 'row': 'd', 'x': '50', 'y': '150', 'width': '100', 'height': '200' },
+                             { 'column': 'd-start', 'row': 'c-start', 'x': '150', 'y': '50', 'width': '200', 'height': '100' }];
+
+    testLayout({ 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaOne }, implicitNamesItems);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnNoNames, 'rows': rowNoNames }, implicitNamesItems);
+    testLayout({ 'columns': columnNoNames, 'areas': templateAreaOne, 'rows': rowNoNames }, implicitNamesItems);
+
+    var implicitNamesItemsTwo = [{ 'column': 'a-start', 'row': 'd-start', 'x': '0', 'y': '0', 'width': '50', 'height': '50' },
+                                { 'column': 'a-start', 'row': 'd', 'x': '0', 'y': '0', 'width': '50', 'height': '150' },
+                                { 'column': 'd-start', 'row': 'c-start', 'x': '50', 'y': '150', 'width': '100', 'height': '200' }];
+
+    testLayout({ 'areas': templateAreaTwo, 'areas': templateAreaOne, 'columns': columnNoNames, 'rows': rowNoNames }, implicitNamesItems);
+    testLayout({ 'areas': templateAreaOne, 'areas': templateAreaTwo, 'columns': columnNoNames, 'rows': rowNoNames }, implicitNamesItemsTwo);
+    testLayout({ 'areas': templateAreaTwo, 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaOne }, implicitNamesItems);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaTwo }, implicitNamesItemsTwo);
+    testLayout({ 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaTwo, 'areas': templateAreaOne }, implicitNamesItems);
+    testLayout({ 'columns': columnNoNames, 'rows': rowNoNames, 'areas': templateAreaOne, 'areas': templateAreaTwo }, implicitNamesItemsTwo);
+
+    // Check resolution when named lines are defined before the grid area.
+    var itemsBeforeArea = [ { 'column': 'd', 'x': '50', 'y': '0', 'width': '300', 'height': '50' },
+                           { 'row': 'c', 'x': '0', 'y': '0', 'width': '50', 'height': '150'},
+                           { 'column': 'd-start', 'x': '50', 'y': '0', 'width': '100', 'height': '50' },
+                           { 'column': 'a-start', 'row': 'd', 'x': '0', 'y': '50', 'width': '50', 'height': '300' } ];
+
+    testLayout({ 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea, 'areas': templateAreaOne }, itemsBeforeArea);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea }, itemsBeforeArea);
+    testLayout({ 'columns': columnNamedLineBeforeArea, 'areas': templateAreaOne, 'rows': rowNamedLineBeforeArea }, itemsBeforeArea);
+
+    var itemsBeforeAreaTwo = [ { 'column': 'd', 'x': '50', 'y': '0', 'width': '300', 'height': '50' },
+                              { 'row': 'c', 'x': '0', 'y': '0', 'width': '50', 'height': '350'},
+                              { 'column': 'd-start', 'x': '50', 'y': '0', 'width': '100', 'height': '50' },
+                              { 'column': 'a-start', 'row': 'd', 'x': '0', 'y': '0', 'width': '50', 'height': '150' } ];
+
+    testLayout({ 'areas': templateAreaTwo, 'areas': templateAreaOne, 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea }, itemsBeforeArea);
+    testLayout({ 'areas': templateAreaOne, 'areas': templateAreaTwo, 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea }, itemsBeforeAreaTwo);
+    testLayout({ 'areas': templateAreaTwo, 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea, 'areas': templateAreaOne }, itemsBeforeArea);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea, 'areas': templateAreaTwo }, itemsBeforeAreaTwo);
+    testLayout({ 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea, 'areas': templateAreaTwo, 'areas': templateAreaOne }, itemsBeforeArea);
+    testLayout({ 'columns': columnNamedLineBeforeArea, 'rows': rowNamedLineBeforeArea, 'areas': templateAreaOne, 'areas': templateAreaTwo }, itemsBeforeAreaTwo);
+
+    // Check resolution when named lines are defined multiple times.
+    var itemsRepeat = [ { 'column': 'd', 'row': 'c', 'x': '0', 'y': '50', 'width': '350', 'height': '100' },
+                       { 'column': 'd-start / d-end', 'row': 'c-start / c-end', 'x': '0', 'y': '50', 'width': '350', 'height': '100'},
+                       { 'column': 'c', 'row': 'd', 'x': '0', 'y': '150', 'width': '50', 'height': '200' } ];
+
+    testLayout({ 'columns': columnRepeatedNames, 'rows': rowRepeatedNames, 'areas': templateAreaOne }, itemsRepeat);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnRepeatedNames, 'rows': rowRepeatedNames }, itemsRepeat);
+    testLayout({ 'columns': columnRepeatedNames, 'areas': templateAreaOne, 'rows': rowRepeatedNames }, itemsRepeat);
+
+    var itemsRepeatTwo = [ { 'column': 'd', 'row': 'c', 'x': '0', 'y': '150', 'width': '350', 'height': '200' },
+                          { 'column': 'd-start / d-end', 'row': 'c-start / c-end', 'x': '0', 'y': '150', 'width': '350', 'height': '200'},
+                          { 'column': 'c', 'row': 'd', 'x': '150', 'y': '0', 'width': '200', 'height': '150' } ];
+
+    testLayout({ 'areas': templateAreaTwo, 'areas': templateAreaOne, 'columns': columnRepeatedNames, 'rows': rowRepeatedNames }, itemsRepeat);
+    testLayout({ 'areas': templateAreaOne, 'areas': templateAreaTwo, 'columns': columnRepeatedNames, 'rows': rowRepeatedNames }, itemsRepeatTwo);
+    testLayout({ 'areas': templateAreaTwo, 'columns': columnRepeatedNames, 'rows': rowRepeatedNames, 'areas': templateAreaOne }, itemsRepeat);
+    testLayout({ 'areas': templateAreaOne, 'columns': columnRepeatedNames, 'rows': rowRepeatedNames, 'areas': templateAreaTwo }, itemsRepeatTwo);
+    testLayout({ 'columns': columnRepeatedNames, 'rows': rowRepeatedNames, 'areas': templateAreaTwo, 'areas': templateAreaOne }, itemsRepeat);
+    testLayout({ 'columns': columnRepeatedNames, 'rows': rowRepeatedNames, 'areas': templateAreaOne, 'areas': templateAreaTwo }, itemsRepeatTwo);
+}
+
+window.addEventListener("load", updateRowsColumns, false);
+</script>
+</head>
+<body>
+<div>This test checks we properly recompute the resolution of named grid lines and named grid areas when we change the grid positioning properties.</div>
+
+<div id="gridContainer" style="position: relative"></div>
+
+<div id="test-output"></div>
+
+</body>
+</html>
index 31ce82a..0b97814 100644 (file)
       -webkit-grid-template-rows: 50px (c-end) 100px (c-end) 200px (c-end);
   }
 
+  .gridImplicitArea {
+      -webkit-grid-template-columns: 50px (z-start) 100px (z-end) 200px;
+      -webkit-grid-template-rows: 50px (z-start) 100px 200px (z-end);
+  }
+
 </style>
 <script src="../../resources/check-layout.js"></script>
 </head>
   </div>
 </div>
 
+<!-- Check that <custom-ident>-{start|end} named lines define implicit named areas -->
+<div style="position: relative">
+  <div class="grid gridAreas gridImplicitArea">
+    <div class="sizedToGridArea" style="-webkit-grid-column: z;" data-offset-x="50" data-offset-y="0" data-expected-width="100" data-expected-height="50"></div>
+    <div class="sizedToGridArea" style="-webkit-grid-row: z;" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="300"></div>
+    <div class="sizedToGridArea" style="-webkit-grid-column-end: z; -webkit-grid-row-start: z;" data-offset-x="50" data-offset-y="50" data-expected-width="100" data-expected-height="100"></div>
+  </div>
+</div>
+
 </body>
 </html>
index b542022..4c1b052 100644 (file)
@@ -1,3 +1,39 @@
+2014-06-05  Sergio Villar Senin  <svillar@igalia.com>
+
+        [CSS Grid Layout] Simplify the named grid lines resolution algorithm
+        https://bugs.webkit.org/show_bug.cgi?id=133543
+
+        Reviewed by Darin Adler.
+
+        Named grid lines resolution algorithm can be heavily simplified by
+        inserting the implicit named grid lines generated by each grid
+        area (<area-name>-{start|end} for rows and columns), into the list
+        of user defined named grid lines. This way we would only have to
+        deal with named grid lines and forget about the named grid areas
+        (as described in the specs
+        http://dev.w3.org/csswg/css-grid/#grid-placement-slot).
+
+        As a nice side effect, we'll get for free the implementation of the
+        use case described in section 5.2.2 Implicit Named Areas.
+
+        Test: fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html
+
+        * css/StyleResolver.cpp:
+        (WebCore::createImplicitNamedGridLinesFromGridArea):
+        (WebCore::StyleResolver::applyProperty):
+        * rendering/RenderGrid.cpp:
+        (WebCore::isStartSide):
+        (WebCore::gridLinesForSide):
+        (WebCore::implicitNamedGridLineForSide):
+        (WebCore::isNonExistentNamedLineOrArea):
+        (WebCore::RenderGrid::adjustGridPositionsFromStyle):
+        (WebCore::RenderGrid::resolveNamedGridLinePositionFromStyle):
+        (WebCore::RenderGrid::resolveGridPositionFromStyle):
+        (WebCore::RenderGrid::resolveNamedGridLinePositionAgainstOppositePosition):
+        (WebCore::gridLineDefinedBeforeGridArea): Deleted.
+        (WebCore::setNamedLinePositionIfDefinedBeforeArea): Deleted.
+        (WebCore::RenderGrid::adjustNamedGridItemPosition): Deleted.
+
 2014-06-10  Kiran  <kiran.guduru@samsung.com>
 
         [MediaStream] Add getTracks() support to MediaStream.
index 943ac66..cc2a707 100644 (file)
@@ -94,6 +94,7 @@
 #include "PseudoElement.h"
 #include "QuotesData.h"
 #include "Rect.h"
+#include "RenderGrid.h"
 #include "RenderRegion.h"
 #include "RenderScrollbar.h"
 #include "RenderScrollbarTheme.h"
@@ -1857,6 +1858,23 @@ bool StyleResolver::useSVGZoomRules()
 }
 
 #if ENABLE(CSS_GRID_LAYOUT)
+static void createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
+{
+    for (auto& area : namedGridAreas) {
+        GridSpan areaSpan = direction == ForRows ? area.value.rows : area.value.columns;
+        {
+            auto& startVector = namedGridLines.add(area.key + "-start", Vector<size_t>()).iterator->value;
+            startVector.append(areaSpan.initialPositionIndex);
+            std::sort(startVector.begin(), startVector.end());
+        }
+        {
+            auto& endVector = namedGridLines.add(area.key + "-end", Vector<size_t>()).iterator->value;
+            endVector.append(areaSpan.finalPositionIndex + 1);
+            std::sort(endVector.begin(), endVector.end());
+        }
+    }
+}
+
 static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, const StyleResolver::State& state, GridLength& workingLength)
 {
     if (primitiveValue->getValueID() == CSSValueWebkitMinContent) {
@@ -2663,6 +2681,10 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
         OrderedNamedGridLinesMap orderedNamedGridLines;
         if (!createGridTrackList(value, trackSizes, namedGridLines, orderedNamedGridLines, state))
             return;
+        const NamedGridAreaMap& namedGridAreas = state.style()->namedGridArea();
+        if (!namedGridAreas.isEmpty())
+            createImplicitNamedGridLinesFromGridArea(namedGridAreas, namedGridLines, ForColumns);
+
         state.style()->setGridColumns(trackSizes);
         state.style()->setNamedGridColumnLines(namedGridLines);
         state.style()->setOrderedNamedGridColumnLines(orderedNamedGridLines);
@@ -2686,6 +2708,10 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
         OrderedNamedGridLinesMap orderedNamedGridLines;
         if (!createGridTrackList(value, trackSizes, namedGridLines, orderedNamedGridLines, state))
             return;
+        const NamedGridAreaMap& namedGridAreas = state.style()->namedGridArea();
+        if (!namedGridAreas.isEmpty())
+            createImplicitNamedGridLinesFromGridArea(namedGridAreas, namedGridLines, ForRows);
+
         state.style()->setGridRows(trackSizes);
         state.style()->setNamedGridRowLines(namedGridLines);
         state.style()->setOrderedNamedGridRowLines(orderedNamedGridLines);
@@ -2744,10 +2770,19 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
             return;
         }
 
-        CSSGridTemplateAreasValue* gridTemplateValue = toCSSGridTemplateAreasValue(value);
-        state.style()->setNamedGridArea(gridTemplateValue->gridAreaMap());
-        state.style()->setNamedGridAreaRowCount(gridTemplateValue->rowCount());
-        state.style()->setNamedGridAreaColumnCount(gridTemplateValue->columnCount());
+        CSSGridTemplateAreasValue* gridTemplateAreasValue = toCSSGridTemplateAreasValue(value);
+        const NamedGridAreaMap& newNamedGridAreas = gridTemplateAreasValue->gridAreaMap();
+
+        NamedGridLinesMap namedGridColumnLines = state.style()->namedGridColumnLines();
+        NamedGridLinesMap namedGridRowLines = state.style()->namedGridRowLines();
+        createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridColumnLines, ForColumns);
+        createImplicitNamedGridLinesFromGridArea(newNamedGridAreas, namedGridRowLines, ForRows);
+        state.style()->setNamedGridColumnLines(namedGridColumnLines);
+        state.style()->setNamedGridRowLines(namedGridRowLines);
+
+        state.style()->setNamedGridArea(gridTemplateAreasValue->gridAreaMap());
+        state.style()->setNamedGridAreaRowCount(gridTemplateAreasValue->rowCount());
+        state.style()->setNamedGridAreaColumnCount(gridTemplateAreasValue->columnCount());
         return;
     }
 #endif /* ENABLE(CSS_GRID_LAYOUT) */
index 21bc28e..421e950 100644 (file)
@@ -476,6 +476,11 @@ static inline bool isColumnSide(GridPositionSide side)
     return side == ColumnStartSide || side == ColumnEndSide;
 }
 
+static inline bool isStartSide(GridPositionSide side)
+{
+    return side == ColumnStartSide || side == RowStartSide;
+}
+
 size_t RenderGrid::explicitGridSizeForSide(GridPositionSide side) const
 {
     return isColumnSide(side) ? explicitGridColumnCount() : explicitGridRowCount();
@@ -858,69 +863,20 @@ GridSpan RenderGrid::resolveGridPositionsFromAutoPlacementPosition(const RenderB
     return GridSpan(initialPosition, initialPosition);
 }
 
-static inline bool gridLineDefinedBeforeGridArea(size_t namedGridLineFirstDefinition, const GridCoordinate& gridAreaCoordinates, GridPositionSide side)
+static inline const NamedGridLinesMap& gridLinesForSide(const RenderStyle& style, GridPositionSide side)
 {
-    switch (side) {
-    case ColumnStartSide:
-        return namedGridLineFirstDefinition < gridAreaCoordinates.columns.initialPositionIndex;
-    case ColumnEndSide:
-        return namedGridLineFirstDefinition < gridAreaCoordinates.columns.finalPositionIndex;
-    case RowStartSide:
-        return namedGridLineFirstDefinition < gridAreaCoordinates.rows.initialPositionIndex;
-    case RowEndSide:
-        return namedGridLineFirstDefinition < gridAreaCoordinates.rows.finalPositionIndex;
-    }
-    ASSERT_NOT_REACHED();
-    return false;
+    return isColumnSide(side) ? style.namedGridColumnLines() : style.namedGridRowLines();
 }
 
-static void setNamedLinePositionIfDefinedBeforeArea(GridPosition& position, const NamedGridLinesMap& namedLinesMap, const String& lineName, const GridCoordinate& gridAreaCoordinate, GridPositionSide side)
+static inline const String implicitNamedGridLineForSide(const String& lineName, GridPositionSide side)
 {
-    auto linesIterator = namedLinesMap.find(lineName);
-    if (linesIterator == namedLinesMap.end())
-        return;
-
-    size_t namedGridLineFirstDefinition = GridPosition::adjustGridPositionForSide(linesIterator->value[0], side);
-    if (gridLineDefinedBeforeGridArea(namedGridLineFirstDefinition, gridAreaCoordinate, side))
-        position.setExplicitPosition(1, lineName);
+    return lineName + (isStartSide(side) ? "-start" : "-end");
 }
 
-void RenderGrid::adjustNamedGridItemPosition(GridPosition& position, GridPositionSide side) const
+static bool isNonExistentNamedLineOrArea(const String& lineName, const RenderStyle& style, GridPositionSide side)
 {
-    // The StyleBuilder always treats <custom-ident> as a named grid area. We must decide here if they are going to be
-    // resolved to either a grid area or a grid line.
-    ASSERT(position.isNamedGridArea());
-    const NamedGridAreaMap& gridAreaMap = style().namedGridArea();
-    const NamedGridLinesMap& namedLinesMap = isColumnSide(side) ? style().namedGridColumnLines() : style().namedGridRowLines();
-
-    String namedGridAreaOrGridLine = position.namedGridLine();
-    bool isStartSide = side == ColumnStartSide || side == RowStartSide;
-
-    auto areaIterator = gridAreaMap.find(namedGridAreaOrGridLine);
-    if (areaIterator != gridAreaMap.end()) {
-        String gridLineName = namedGridAreaOrGridLine + (isStartSide ? "-start" : "-end");
-        setNamedLinePositionIfDefinedBeforeArea(position, namedLinesMap, gridLineName, areaIterator->value, side);
-        return;
-    }
-
-    bool hasStartSuffix = namedGridAreaOrGridLine.endsWith("-start");
-    bool hasEndSuffix = namedGridAreaOrGridLine.endsWith("-end");
-    if ((hasStartSuffix && isStartSide) || (hasEndSuffix && !isStartSide)) {
-        size_t suffixLength = hasStartSuffix ? strlen("-start") : strlen("-end");
-        String gridAreaName = namedGridAreaOrGridLine.substring(0, namedGridAreaOrGridLine.length() - suffixLength);
-
-        auto areaIterator = gridAreaMap.find(gridAreaName);
-        if (areaIterator != gridAreaMap.end()) {
-            position.setNamedGridArea(gridAreaName);
-            setNamedLinePositionIfDefinedBeforeArea(position, namedLinesMap, namedGridAreaOrGridLine, areaIterator->value, side);
-            return;
-        }
-    }
-
-    if (namedLinesMap.contains(namedGridAreaOrGridLine))
-        position.setExplicitPosition(1, namedGridAreaOrGridLine);
-    else
-        position.setAutoPosition();
+    const NamedGridLinesMap& gridLineNames = gridLinesForSide(style, side);
+    return !gridLineNames.contains(implicitNamedGridLineForSide(lineName, side)) && !gridLineNames.contains(lineName);
 }
 
 void RenderGrid::adjustGridPositionsFromStyle(GridPosition& initialPosition, GridPosition& finalPosition, GridPositionSide initialPositionSide, GridPositionSide finalPositionSide) const
@@ -932,11 +888,14 @@ void RenderGrid::adjustGridPositionsFromStyle(GridPosition& initialPosition, Gri
     if (initialPosition.isSpan() && finalPosition.isSpan())
         finalPosition.setAutoPosition();
 
-    if (initialPosition.isNamedGridArea())
-        adjustNamedGridItemPosition(initialPosition, initialPositionSide);
+    // Try to early detect the case of non existing named grid lines. This way we could assume later that
+    // RenderGrid::resolveGrisPositionFromStyle() won't require the autoplacement to run, i.e., it'll always return a
+    // valid resolved position.
+    if (initialPosition.isNamedGridArea() && isNonExistentNamedLineOrArea(initialPosition.namedGridLine(), style(), initialPositionSide))
+        initialPosition.setAutoPosition();
 
-    if (finalPosition.isNamedGridArea())
-        adjustNamedGridItemPosition(finalPosition, finalPositionSide);
+    if (finalPosition.isNamedGridArea() && isNonExistentNamedLineOrArea(finalPosition.namedGridLine(), style(), finalPositionSide))
+        finalPosition.setAutoPosition();
 }
 
 std::unique_ptr<GridSpan> RenderGrid::resolveGridPositionsFromStyle(const RenderBox* gridItem, GridTrackSizingDirection direction) const
@@ -982,7 +941,7 @@ size_t RenderGrid::resolveNamedGridLinePositionFromStyle(const GridPosition& pos
 {
     ASSERT(!position.namedGridLine().isNull());
 
-    const NamedGridLinesMap& gridLinesNames = isColumnSide(side) ? style().namedGridColumnLines() : style().namedGridRowLines();
+    const NamedGridLinesMap& gridLinesNames = gridLinesForSide(style(), side);
     NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
     if (it == gridLinesNames.end()) {
         if (position.isPositive())
@@ -1023,20 +982,26 @@ size_t RenderGrid::resolveGridPositionFromStyle(const GridPosition& position, Gr
     }
     case NamedGridAreaPosition:
     {
-        NamedGridAreaMap::const_iterator it = style().namedGridArea().find(position.namedGridLine());
-        // Unknown grid area should have been computed to 'auto' by now.
-        ASSERT(it != style().namedGridArea().end());
-        const GridCoordinate& gridAreaCoordinate = it->value;
-        switch (side) {
-        case ColumnStartSide:
-            return gridAreaCoordinate.columns.initialPositionIndex;
-        case ColumnEndSide:
-            return gridAreaCoordinate.columns.finalPositionIndex;
-        case RowStartSide:
-            return gridAreaCoordinate.rows.initialPositionIndex;
-        case RowEndSide:
-            return gridAreaCoordinate.rows.finalPositionIndex;
-        }
+        // First attempt to match the grid area's edge to a named grid area: if there is a named line with the name
+        // ''<custom-ident>-start (for grid-*-start) / <custom-ident>-end'' (for grid-*-end), contributes the first such
+        // line to the grid item's placement.
+        String namedGridLine = position.namedGridLine();
+        ASSERT(!isNonExistentNamedLineOrArea(namedGridLine, style(), side));
+
+        const NamedGridLinesMap& gridLineNames = gridLinesForSide(style(), side);
+        auto implicitLine = gridLineNames.find(implicitNamedGridLineForSide(namedGridLine, side));
+        if (implicitLine != gridLineNames.end())
+            return GridPosition::adjustGridPositionForSide(implicitLine->value[0], side);
+
+        // Otherwise, if there is a named line with the specified name, contributes the first such line to the grid
+        // item's placement.
+        auto explicitLine = gridLineNames.find(namedGridLine);
+        if (explicitLine != gridLineNames.end())
+            return GridPosition::adjustGridPositionForSide(explicitLine->value[0], side);
+
+        // If none of the above works specs mandate us to treat it as auto BUT we should have detected it before calling
+        // this function in resolveGridPositionsFromStyle(). We should be covered anyway by the ASSERT at the beginning
+        // of this case block.
         ASSERT_NOT_REACHED();
         return 0;
     }
@@ -1066,7 +1031,7 @@ std::unique_ptr<GridSpan> RenderGrid::resolveGridPositionAgainstOppositePosition
     // 'span 1' is contained inside a single grid track regardless of the direction.
     // That's why the CSS span value is one more than the offset we apply.
     size_t positionOffset = position.spanPosition() - 1;
-    if (side == ColumnStartSide || side == RowStartSide) {
+    if (isStartSide(side)) {
         size_t initialResolvedPosition = std::max<int>(0, resolvedOppositePosition - positionOffset);
         return std::make_unique<GridSpan>(initialResolvedPosition, resolvedOppositePosition);
     }
@@ -1081,7 +1046,7 @@ std::unique_ptr<GridSpan> RenderGrid::resolveNamedGridLinePositionAgainstOpposit
     // Negative positions are not allowed per the specification and should have been handled during parsing.
     ASSERT(position.spanPosition() > 0);
 
-    const NamedGridLinesMap& gridLinesNames = isColumnSide(side) ? style().namedGridColumnLines() : style().namedGridRowLines();
+    const NamedGridLinesMap& gridLinesNames = gridLinesForSide(style(), side);
     NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
 
     // If there is no named grid line of that name, we resolve the position to 'auto' (which is equivalent to 'span 1' in this case).
@@ -1089,7 +1054,7 @@ std::unique_ptr<GridSpan> RenderGrid::resolveNamedGridLinePositionAgainstOpposit
     if (it == gridLinesNames.end())
         return std::make_unique<GridSpan>(resolvedOppositePosition, resolvedOppositePosition);
 
-    if (side == RowStartSide || side == ColumnStartSide)
+    if (isStartSide(side))
         return resolveRowStartColumnStartNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, it->value);
 
     return resolveRowEndColumnEndNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, it->value);