[css-grid] repeat() syntax should take a <track-list> argument
authorsvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Jul 2016 11:08:28 +0000 (11:08 +0000)
committersvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Jul 2016 11:08:28 +0000 (11:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=160162

Reviewed by Darin Adler.

Source/WebCore:

The repeat() notation used to allow just 1 <track-size> as second argument. Specs have been
recently modified so that a <track-list> is now supported, meaning that we can pass an
arbitrary number of track sizes and line numbers.

It has been working for some time for repeat() if the first argument was a positive integer,
but it requires some changes for the auto repeat cases (auto-fill and auto-fit).

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::OrderedNamedLinesCollector::OrderedNamedLinesCollector): Store the total number of
auto repeat tracks and the length of a single repetition instead of the number of
repetitions.
(WebCore::OrderedNamedLinesCollector::collectLineNamesForIndex): Do not assume that there is
only 1 repeat track.
(WebCore::valueForGridTrackList):
* css/CSSParser.cpp:
(WebCore::CSSParser::parseGridTrackRepeatFunction): Allow multiple tracks in repeat().
* rendering/RenderGrid.cpp:
(WebCore::RenderGrid::rawGridTrackSize): Renamed repetitions -> autoRepeatTracksCount.
(WebCore::RenderGrid::computeAutoRepeatTracksCount): Use all the repeat tracks to compute
the total track size of a single repetition.
(WebCore::RenderGrid::computeEmptyTracksForAutoRepeat):
* rendering/style/GridPositionsResolver.cpp:
(WebCore::NamedLineCollection::NamedLineCollection): Renamed m_repetitions ->
m_autoRepeatTotalTracks. Added m_autoRepeatTrackListLength (it was always 1 before).
(WebCore::NamedLineCollection::find): Resolve lines inside multiple repeat tracks.
(WebCore::NamedLineCollection::firstPosition): Ditto.
* rendering/style/GridPositionsResolver.h:

LayoutTests:

Added new test cases with multiple tracks inside repeat() notation, both for fixed an
automatic (auto-fill & auto-fit) repetitions.

* fast/css-grid-layout/grid-auto-fill-columns-expected.txt:
* fast/css-grid-layout/grid-auto-fill-columns.html:
* fast/css-grid-layout/grid-auto-fill-rows-expected.txt:
* fast/css-grid-layout/grid-auto-fill-rows.html:
* fast/css-grid-layout/grid-auto-fit-columns-expected.txt:
* fast/css-grid-layout/grid-auto-fit-columns.html:
* fast/css-grid-layout/grid-auto-fit-rows-expected.txt:
* fast/css-grid-layout/grid-auto-fit-rows.html:
* fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt:
* fast/css-grid-layout/grid-element-auto-repeat-get-set.html:
* fast/css-grid-layout/grid-element-repeat-get-set-expected.txt:
* fast/css-grid-layout/grid-element-repeat-get-set.html:

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

19 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/grid-auto-fill-columns-expected.txt
LayoutTests/fast/css-grid-layout/grid-auto-fill-columns.html
LayoutTests/fast/css-grid-layout/grid-auto-fill-rows-expected.txt
LayoutTests/fast/css-grid-layout/grid-auto-fill-rows.html
LayoutTests/fast/css-grid-layout/grid-auto-fit-columns-expected.txt
LayoutTests/fast/css-grid-layout/grid-auto-fit-columns.html
LayoutTests/fast/css-grid-layout/grid-auto-fit-rows-expected.txt
LayoutTests/fast/css-grid-layout/grid-auto-fit-rows.html
LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt
LayoutTests/fast/css-grid-layout/grid-element-auto-repeat-get-set.html
LayoutTests/fast/css-grid-layout/grid-element-repeat-get-set-expected.txt
LayoutTests/fast/css-grid-layout/grid-element-repeat-get-set.html
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSParser.cpp
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/style/GridPositionsResolver.cpp
Source/WebCore/rendering/style/GridPositionsResolver.h

index b45ee80..80ab0e9 100644 (file)
@@ -1,5 +1,28 @@
 2016-07-25  Sergio Villar Senin  <svillar@igalia.com>
 
+        [css-grid] repeat() syntax should take a <track-list> argument
+        https://bugs.webkit.org/show_bug.cgi?id=160162
+
+        Reviewed by Darin Adler.
+
+        Added new test cases with multiple tracks inside repeat() notation, both for fixed an
+        automatic (auto-fill & auto-fit) repetitions.
+
+        * fast/css-grid-layout/grid-auto-fill-columns-expected.txt:
+        * fast/css-grid-layout/grid-auto-fill-columns.html:
+        * fast/css-grid-layout/grid-auto-fill-rows-expected.txt:
+        * fast/css-grid-layout/grid-auto-fill-rows.html:
+        * fast/css-grid-layout/grid-auto-fit-columns-expected.txt:
+        * fast/css-grid-layout/grid-auto-fit-columns.html:
+        * fast/css-grid-layout/grid-auto-fit-rows-expected.txt:
+        * fast/css-grid-layout/grid-auto-fit-rows.html:
+        * fast/css-grid-layout/grid-element-auto-repeat-get-set-expected.txt:
+        * fast/css-grid-layout/grid-element-auto-repeat-get-set.html:
+        * fast/css-grid-layout/grid-element-repeat-get-set-expected.txt:
+        * fast/css-grid-layout/grid-element-repeat-get-set.html:
+
+2016-07-25  Sergio Villar Senin  <svillar@igalia.com>
+
         [css-grid] grid-auto-flow|row should take a <track-size>+
         https://bugs.webkit.org/show_bug.cgi?id=160158
 
index 90b6f69..4cd138b 100644 (file)
@@ -17,6 +17,7 @@
 .gridAutoRepeatAndFixedAfter { grid-template-columns: repeat(auto-fill, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, -webkit-max-content); }
 .gridAutoRepeatAndFixed { grid-template-columns: [start] repeat(2, 50px [a]) [middle] repeat(auto-fill, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; }
 .gridMultipleNames { grid-template-columns: [start] 20px [foo] 50% repeat(auto-fill, [bar] 20px [start foo]) [foo] 10% [end bar]; }
+.gridMultipleTracks { grid-template-columns: [start] 20px repeat(auto-fill, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; }
 
 .item { background-color: cyan; }
 
     <div class="item" style="grid-column: foo / bar 2"  data-offset-x="40" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div>
 </div>
 
+<div class="grid gridMultipleTracks">
+    <div class="item" style="grid-column: a / 2 c"  data-offset-x="20" data-offset-y="0" data-expected-width="84" data-expected-height="25"></div>
+    <div class="item" style="grid-column: 3 / e; grid-row: 2;"  data-offset-x="52" data-offset-y="25" data-expected-width="72" data-expected-height="25"></div>
+</div>
+
+<div class="grid gridMultipleTracks gap">
+    <div class="item" style="grid-column: a / c"  data-offset-x="40" data-offset-y="0" data-expected-width="32" data-expected-height="25"></div>
+    <div class="item" style="grid-column: 3 / last; grid-row: 2;"  data-offset-x="92" data-offset-y="25" data-expected-width="115" data-expected-height="25"></div>
+</div>
+
 </body>
index d34fde6..319bf57 100644 (file)
@@ -21,6 +21,7 @@
 .gridAutoRepeatAndFixedAfter { grid-template-rows: repeat(auto-fill, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, -webkit-max-content); }
 .gridAutoRepeatAndFixed { grid-template-rows: [start] repeat(2, 50px [a]) [middle] repeat(auto-fill, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; }
 .gridMultipleNames { grid-template-rows: [start] 20px [foo] 50% repeat(auto-fill, [bar] 20px [start foo]) [foo] 10% [end bar]; }
+.gridMultipleTracks { grid-template-rows: [start] 20px repeat(auto-fill, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; }
 
 .item { background-color: cyan; }
 
     <div class="item" style="grid-row: foo / bar 2"  data-offset-y="40" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div>
 </div>
 
+<div class="grid gridMultipleTracks">
+    <div class="item" style="grid-row: a / 2 c"  data-offset-y="20" data-offset-x="0" data-expected-height="84" data-expected-width="25"></div>
+    <div class="item" style="grid-row: 3 / e; grid-column: 2;"  data-offset-y="52" data-offset-x="25" data-expected-height="72" data-expected-width="25"></div>
+</div>
+
+<div class="grid gridMultipleTracks gap">
+    <div class="item" style="grid-row: a / c"  data-offset-y="40" data-offset-x="0" data-expected-height="32" data-expected-width="25"></div>
+    <div class="item" style="grid-row: 3 / last; grid-column: 2;"  data-offset-y="92" data-offset-x="25" data-expected-height="115" data-expected-width="25"></div>
+</div>
+
 </body>
index 560015b..288e971 100644 (file)
 .gridAutoRepeatAndFixedAfter { grid-template-columns: repeat(auto-fit, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, -webkit-max-content); }
 .gridAutoRepeatAndFixed { grid-template-columns: [start] repeat(2, 50px [a]) [middle] repeat(auto-fit, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; }
 .gridMultipleNames { grid-template-columns: [start] 20px [foo] 50% repeat(auto-fit, [bar] 20px [start foo]) [foo] 10% [end bar]; }
+.gridMultipleTracks { grid-template-columns: [start] 20px repeat(auto-fit, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; }
 
 .item { background-color: cyan; }
+.item:nth-child(2n) { background-color: green; }
 
 .gap { grid-column-gap: 20px; }
 
     <div class="item" style="grid-column: foo / bar 2"  data-offset-x="40" data-offset-y="0" data-expected-width="180" data-expected-height="25"></div>
 </div>
 
+<div class="grid gridMultipleTracks">
+    <div class="item" style="grid-column: e / last;"  data-offset-x="52" data-offset-y="0" data-expected-width="148" data-expected-height="25"></div>
+    <div class="item" style="grid-column: start / b;"  data-offset-x="0" data-offset-y="25" data-expected-width="52" data-expected-height="25"></div>
+</div>
+
+<div class="grid gridMultipleTracks gap">
+    <div class="item" style="grid-column: c / -1;"  data-offset-x="40" data-offset-y="0" data-expected-width="160" data-expected-height="25"></div>
+</div>
+
 </body>
index 1d2b003..5847a6f 100644 (file)
 .gridAutoRepeatAndFixedAfter { grid-template-rows: repeat(auto-fit, [first] 30px [last]) [foo] minmax(60px, 80px) [bar] minmax(45px, -webkit-max-content); }
 .gridAutoRepeatAndFixed { grid-template-rows: [start] repeat(2, 50px [a]) [middle] repeat(auto-fit, [autofoo] 15px [autobar]) minmax(5%, 10%) [end]; }
 .gridMultipleNames { grid-template-rows: [start] 20px [foo] 50% repeat(auto-fit, [bar] 20px [start foo]) [foo] 10% [end bar]; }
+.gridMultipleTracks { grid-template-rows: [start] 20px repeat(auto-fit, [a] 2em [b c] 10% [d]) [e] minmax(75px, 1fr) [last]; }
 
 .item { background-color: cyan; }
+.item:nth-child(2n) { background-color: green; }
 
 .gap { grid-row-gap: 20px; }
 
     <div class="item" style="grid-row: foo / bar 2"  data-offset-y="40" data-offset-x="0" data-expected-height="180" data-expected-width="25"></div>
 </div>
 
+<div class="grid gridMultipleTracks">
+    <div class="item" style="grid-row: e / last;"  data-offset-y="52" data-offset-x="0" data-expected-height="148" data-expected-width="25"></div>
+    <div class="item" style="grid-row: start / b;"  data-offset-y="0" data-offset-x="0" data-expected-height="52" data-expected-width="25"></div>
+</div>
+
+<div class="grid gridMultipleTracks gap">
+    <div class="item" style="grid-row: c / -1;"  data-offset-y="40" data-offset-x="0" data-expected-height="160" data-expected-width="25"></div>
+</div>
+
 </body>
index d18ddfd..24559bc 100644 (file)
@@ -24,6 +24,10 @@ PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is
 PASS element.style.gridTemplateColumns is "repeat(auto-fit, [foo bar] 150px)"
 PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "0px [foo bar] 0px [foo bar]"
 PASS element.style.gridTemplateRows is "repeat(auto-fit, 24em [foo bar])"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[start] 200px 100px [end start] 200px 100px [end]"
+PASS element.style.gridTemplateColumns is "repeat(auto-fill, [start] 200px 100px [end])"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "100px [foo a] 20px [b] 60px [c a] 20px [b] 60px [c a] 20px [b] 60px [c a] 20px [b] 60px [c a] 20px [b] 60px [c bar] 30px"
+PASS element.style.gridTemplateRows is "100px [foo] repeat(auto-fill, [a] 2em [b] 10% [c]) [bar] 3em"
 PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[foo bar] 0px [foo bar] 0px"
 PASS element.style.gridTemplateColumns is "repeat(auto-fit, [foo bar] minmax(270px, 1fr))"
 PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "[foo] 0px [bar foo] 0px [bar foo] 0px [bar]"
@@ -40,6 +44,10 @@ PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is
 PASS element.style.gridTemplateColumns is "[a] repeat(auto-fit, [z] 100px [y]) [b] 30px [c] 20px [e]"
 PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "[a b] 30px [c d] 20px [e z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y]"
 PASS element.style.gridTemplateRows is "[a b] 30px [c d] 20px [e] repeat(auto-fit, [z] 100px [y])"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "[start] 0px 0px [end start] 0px 0px [end]"
+PASS element.style.gridTemplateColumns is "repeat(auto-fit, [start] 200px 100px [end])"
+PASS getComputedStyle(element, '').getPropertyValue('grid-template-rows') is "100px [foo a] 0px [b] 0px [c a] 0px [b] 0px [c a] 0px [b] 0px [c a] 0px [b] 0px [c a] 0px [b] 0px [c bar] 30px"
+PASS element.style.gridTemplateRows is "100px [foo] repeat(auto-fit, [a] 2em [b] 10% [c]) [bar] 3em"
 
 Test invalid repeat syntax.
 PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
index 57c4a0c..c66b0db 100644 (file)
@@ -16,10 +16,12 @@ body { font-size: 10px; }
     testGridTemplatesSetJSValues("repeat(auto-fill, minmax(50px, 100px)) repeat(2, 250px)", "repeat(1, 450px) repeat(auto-fill, minmax(-webkit-max-content, 5em) [bar]) repeat(2, [foo] 1em)", "100px 100px 100px 250px 250px", "450px 50px [bar] 50px [bar foo] 10px [foo] 10px", "repeat(auto-fill, minmax(50px, 100px)) 250px 250px", "450px repeat(auto-fill, minmax(-webkit-max-content, 5em) [bar]) [foo] 1em [foo] 1em");
     testGridTemplatesSetJSValues("[start] 10% repeat(auto-fill, [foo bar] 200px) [end]", "75px [prev] repeat(auto-fill, 20em [foo bar]) [next] 15em [last end]", "[start] 80px [foo bar] 200px [foo bar] 200px [foo bar] 200px [end]", "75px [prev] 200px [foo bar next] 150px [last end]");
     testGridTemplatesSetJSValues("repeat(auto-fit, [foo bar] 150px)", "repeat(auto-fit, 24em [foo bar])", "[foo bar] 0px [foo bar] 0px [foo bar] 0px [foo bar] 0px [foo bar] 0px", "0px [foo bar] 0px [foo bar]");
+    testGridTemplatesSetJSValues("repeat(auto-fill, [start] 200px 100px [end])", "100px [foo] repeat(auto-fill, [a] 2em [b] 10% [c]) [bar] 3em", "[start] 200px 100px [end start] 200px 100px [end]", "100px [foo a] 20px [b] 60px [c a] 20px [b] 60px [c a] 20px [b] 60px [c a] 20px [b] 60px [c a] 20px [b] 60px [c bar] 30px");
     testGridTemplatesSetJSValues("repeat(auto-fit, [foo bar] minmax(270px, 1fr))", "repeat(auto-fit, [foo] minmax(20em, -webkit-max-content) [bar])", "[foo bar] 0px [foo bar] 0px", "[foo] 0px [bar foo] 0px [bar foo] 0px [bar]");
     testGridTemplatesSetJSValues("repeat(auto-fit, minmax(300px, -webkit-min-content)) repeat(2, 20px)", "repeat(1, 10%) repeat(auto-fit, minmax(30em, -webkit-max-content) [bar]) repeat(2, [foo] 1em)", "0px 0px 20px 20px", "60px 0px [bar foo] 10px [foo] 10px", "repeat(auto-fit, minmax(300px, -webkit-min-content)) 20px 20px", "10% repeat(auto-fit, minmax(30em, -webkit-max-content) [bar]) [foo] 1em [foo] 1em");
     testGridTemplatesSetJSValues("[a] repeat(auto-fit, [z] 100px [y]) [b] 30px [c d] 20px [e]", "repeat(auto-fit, [z] 100px [y]) [a b] 30px [c d] 20px [e]", "[a z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y b] 30px [c d] 20px [e]", "[z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y a b] 30px [c d] 20px [e]");
     testGridTemplatesSetJSValues("[a] repeat(auto-fit, [z] 100px [y]) repeat(1, [b] 30px [c]) 20px [e]", "[a b] 30px [c d] 20px [e] repeat(auto-fit, [z] 100px [y])", "[a z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y b] 30px [c] 20px [e]", "[a b] 30px [c d] 20px [e z] 0px [y z] 0px [y z] 0px [y z] 0px [y z] 0px [y]", "[a] repeat(auto-fit, [z] 100px [y]) [b] 30px [c] 20px [e]");
+    testGridTemplatesSetJSValues("repeat(auto-fit, [start] 200px 100px [end])", "100px [foo] repeat(auto-fit, [a] 2em [b] 10% [c]) [bar] 3em", "[start] 0px 0px [end start] 0px 0px [end]", "100px [foo a] 0px [b] 0px [c a] 0px [b] 0px [c a] 0px [b] 0px [c a] 0px [b] 0px [c a] 0px [b] 0px [c bar] 30px");
 
     debug("");
     debug("Test invalid repeat syntax.");
@@ -33,14 +35,14 @@ body { font-size: 10px; }
 
     testInvalidSyntax("repeat(auto-fill, 1fr)");
     testInvalidSyntax("repeat(auto-fill, [bar] auto)");
-    testInvalidSyntax("repeat(auto-fill, 20px 10px)");
-    testInvalidSyntax("repeat(auto-fill, 20px [foo bar] 10px)");
+    testInvalidSyntax("repeat(auto-fill, 20px -webkit-min-content)");
+    testInvalidSyntax("repeat(auto-fill, auto [foo bar] 10px)");
     testInvalidSyntax("repeat(auto-fill,)");
     testInvalidSyntax("repeat(auto-fill, [foo])");
     testInvalidSyntax("repeat(auto-fit, 1fr)");
     testInvalidSyntax("repeat(auto-fit, [bar] auto)");
-    testInvalidSyntax("repeat(auto-fit, 20px 10px)");
-    testInvalidSyntax("repeat(auto-fit, 20px [foo bar] 10px)");
+    testInvalidSyntax("repeat(auto-fit, minmax(20px, 30px) auto)");
+    testInvalidSyntax("repeat(auto-fit, -webkit-max-content 2em)");
     testInvalidSyntax("repeat(auto-fit,)");
     testInvalidSyntax("repeat(auto-fit, [foo])");
 
index deb7d26..54dce41 100644 (file)
@@ -26,6 +26,8 @@ PASS window.getComputedStyle(mixRepeatAfterNonRepeat, '').getPropertyValue('grid
 PASS window.getComputedStyle(mixRepeatAfterNonRepeat, '').getPropertyValue('grid-template-rows') is "44px 10px 10px"
 PASS window.getComputedStyle(mixNonRepeatAfterRepeat, '').getPropertyValue('grid-template-columns') is "250px 250px 120px [last]"
 PASS window.getComputedStyle(mixNonRepeatAfterRepeat, '').getPropertyValue('grid-template-rows') is "10px 10px [end] 0px"
+PASS window.getComputedStyle(multipleTrackRepeat, '').getPropertyValue('grid-template-columns') is "[start] 20px [a] 20px 0px [b a] 20px 0px [b] 200px [c] 0px [end]"
+PASS window.getComputedStyle(multipleTrackRepeat, '').getPropertyValue('grid-template-rows') is "0px [a] 0px [b c] 20px [d] 0px [a] 0px [b c] 20px [d] 0px [a] 0px [b c] 20px [d e] 16px"
 
 Test invalid repeat syntax.
 PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
@@ -38,6 +40,8 @@ PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-column
 PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
 PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
 PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
+PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
+PASS window.getComputedStyle(element, '').getPropertyValue('grid-template-columns') is "none"
 PASS successfullyParsed is true
 
 TEST COMPLETE
index fade1f7..54f4147 100644 (file)
     grid-template-rows: repeat(2, 10px) [end] auto;
     grid-template-columns: repeat(2, 250px) 15% [last];
 }
+
+.multipleTrackRepeat {
+    grid-template-rows: repeat(3, -webkit-min-content [a] -webkit-max-content [b c] 20px [d]) [e] 1em;
+    grid-template-columns: [start] 20px repeat(2, [a] minmax(20px, -webkit-min-content) -webkit-max-content [b]) 200px [c] -webkit-min-content [end];
+}
+
 </style>
 <script src="../../resources/js-test-pre.js"></script>
 </head>
     <div class="gridItem"></div>
 </div>
 <div class="grid definite mixNonRepeatAfterRepeat alignContentStart" id="mixNonRepeatAfterRepeat"></div>
+<div class="grid multipleTrackRepeat" id="multipleTrackRepeat"></div>
 
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script>
     testGridTemplatesValues(document.getElementById("leadingNamedGridLineRepeat"), "[start] 250px 250px", "[start] 10px 10px");
     testGridTemplatesValues(document.getElementById("mixRepeatAfterNonRepeat"), "[start] 140px 250px 250px", "44px 10px 10px");
     testGridTemplatesValues(document.getElementById("mixNonRepeatAfterRepeat"), "250px 250px 120px [last]", "10px 10px [end] 0px");
+ testGridTemplatesValues(document.getElementById("multipleTrackRepeat"), "[start] 20px [a] 20px 0px [b a] 20px 0px [b] 200px [c] 0px [end]", "0px [a] 0px [b c] 20px [d] 0px [a] 0px [b c] 20px [d] 0px [a] 0px [b c] 20px [d e] 16px");
 
     debug("");
     debug("Test invalid repeat syntax.");
     testInvalidSyntax("repeat(1, [foo])");
     testInvalidSyntax("repeat(1, )");
     testInvalidSyntax("repeat(1)");
+    testInvalidSyntax("repeat(3, [a] [a] 100px 200px)");
     // Nesting is no allowed.
     testInvalidSyntax("repeat(2, repeat(1, auto))");
+    testInvalidSyntax("repeat(2, [a] 100px 200px repeat(2, 20px))");
 </script>
 <script src="../../resources/js-test-post.js"></script>
 </body>
index dbc3f06..5f3167b 100644 (file)
@@ -1,5 +1,40 @@
 2016-07-25  Sergio Villar Senin  <svillar@igalia.com>
 
+        [css-grid] repeat() syntax should take a <track-list> argument
+        https://bugs.webkit.org/show_bug.cgi?id=160162
+
+        Reviewed by Darin Adler.
+
+        The repeat() notation used to allow just 1 <track-size> as second argument. Specs have been
+        recently modified so that a <track-list> is now supported, meaning that we can pass an
+        arbitrary number of track sizes and line numbers.
+
+        It has been working for some time for repeat() if the first argument was a positive integer,
+        but it requires some changes for the auto repeat cases (auto-fill and auto-fit).
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::OrderedNamedLinesCollector::OrderedNamedLinesCollector): Store the total number of
+        auto repeat tracks and the length of a single repetition instead of the number of
+        repetitions.
+        (WebCore::OrderedNamedLinesCollector::collectLineNamesForIndex): Do not assume that there is
+        only 1 repeat track.
+        (WebCore::valueForGridTrackList):
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseGridTrackRepeatFunction): Allow multiple tracks in repeat().
+        * rendering/RenderGrid.cpp:
+        (WebCore::RenderGrid::rawGridTrackSize): Renamed repetitions -> autoRepeatTracksCount.
+        (WebCore::RenderGrid::computeAutoRepeatTracksCount): Use all the repeat tracks to compute
+        the total track size of a single repetition.
+        (WebCore::RenderGrid::computeEmptyTracksForAutoRepeat):
+        * rendering/style/GridPositionsResolver.cpp:
+        (WebCore::NamedLineCollection::NamedLineCollection): Renamed m_repetitions ->
+        m_autoRepeatTotalTracks. Added m_autoRepeatTrackListLength (it was always 1 before).
+        (WebCore::NamedLineCollection::find): Resolve lines inside multiple repeat tracks.
+        (WebCore::NamedLineCollection::firstPosition): Ditto.
+        * rendering/style/GridPositionsResolver.h:
+
+2016-07-25  Sergio Villar Senin  <svillar@igalia.com>
+
         [css-grid] grid-auto-flow|row should take a <track-size>+
         https://bugs.webkit.org/show_bug.cgi?id=160158
 
index a9f30e3..619d399 100644 (file)
@@ -1036,11 +1036,12 @@ static Ref<CSSValue> specifiedValueForGridTrackSize(const GridTrackSize& trackSi
 class OrderedNamedLinesCollector {
     WTF_MAKE_NONCOPYABLE(OrderedNamedLinesCollector);
 public:
-    OrderedNamedLinesCollector(const RenderStyle& style, bool isRowAxis, unsigned repetitions)
+    OrderedNamedLinesCollector(const RenderStyle& style, bool isRowAxis, unsigned autoRepeatTracksCount)
         : m_orderedNamedGridLines(isRowAxis ? style.orderedNamedGridColumnLines() : style.orderedNamedGridRowLines())
         , m_orderedNamedAutoRepeatGridLines(isRowAxis ? style.autoRepeatOrderedNamedGridColumnLines() : style.autoRepeatOrderedNamedGridRowLines())
         , m_insertionPoint(isRowAxis ? style.gridAutoRepeatColumnsInsertionPoint() : style.gridAutoRepeatRowsInsertionPoint())
-        , m_repetitions(repetitions)
+        , m_autoRepeatTotalTracks(autoRepeatTracksCount)
+        , m_autoRepeatTrackListLength(isRowAxis ? style.gridAutoRepeatColumns().size() : style.gridAutoRepeatRows().size())
     {
     }
 
@@ -1055,7 +1056,8 @@ private:
     const OrderedNamedGridLinesMap& m_orderedNamedGridLines;
     const OrderedNamedGridLinesMap& m_orderedNamedAutoRepeatGridLines;
     unsigned m_insertionPoint;
-    unsigned m_repetitions;
+    unsigned m_autoRepeatTotalTracks;
+    unsigned m_autoRepeatTrackListLength;
 };
 
 void OrderedNamedLinesCollector::appendLines(CSSGridLineNamesValue& lineNamesValue, unsigned index, NamedLinesType type) const
@@ -1078,9 +1080,10 @@ void OrderedNamedLinesCollector::collectLineNamesForIndex(CSSGridLineNamesValue&
         return;
     }
 
-    ASSERT(m_repetitions);
-    if (i > m_insertionPoint + m_repetitions) {
-        appendLines(lineNamesValue, i - (m_repetitions - 1), NamedLines);
+    ASSERT(m_autoRepeatTotalTracks);
+
+    if (i > m_insertionPoint + m_autoRepeatTotalTracks) {
+        appendLines(lineNamesValue, i - (m_autoRepeatTotalTracks - 1), NamedLines);
         return;
     }
 
@@ -1090,14 +1093,16 @@ void OrderedNamedLinesCollector::collectLineNamesForIndex(CSSGridLineNamesValue&
         return;
     }
 
-    if (i == m_insertionPoint + m_repetitions) {
-        appendLines(lineNamesValue, 1, AutoRepeatNamedLines);
+    if (i == m_insertionPoint + m_autoRepeatTotalTracks) {
+        appendLines(lineNamesValue, m_autoRepeatTrackListLength, AutoRepeatNamedLines);
         appendLines(lineNamesValue, m_insertionPoint + 1, NamedLines);
         return;
     }
 
-    appendLines(lineNamesValue, 1, AutoRepeatNamedLines);
-    appendLines(lineNamesValue, 0, AutoRepeatNamedLines);
+    unsigned autoRepeatIndexInFirstRepetition = (i - m_insertionPoint) % m_autoRepeatTrackListLength;
+    if (!autoRepeatIndexInFirstRepetition && i > m_insertionPoint)
+        appendLines(lineNamesValue, m_autoRepeatTrackListLength, AutoRepeatNamedLines);
+    appendLines(lineNamesValue, autoRepeatIndexInFirstRepetition, AutoRepeatNamedLines);
 }
 
 static void addValuesForNamedGridLinesAtIndex(OrderedNamedLinesCollector& collector, unsigned i, CSSValueList& list)
@@ -1141,8 +1146,8 @@ static Ref<CSSValue> valueForGridTrackList(GridTrackSizingDirection direction, R
     if (trackListIsEmpty)
         return CSSValuePool::singleton().createIdentifierValue(CSSValueNone);
 
-    unsigned repetitions = isRenderGrid ? downcast<RenderGrid>(renderer)->autoRepeatCountForDirection(direction) : 0;
-    OrderedNamedLinesCollector collector(style, isRowAxis, repetitions);
+    unsigned autoRepeatTotalTracks = isRenderGrid ? downcast<RenderGrid>(renderer)->autoRepeatCountForDirection(direction) : 0;
+    OrderedNamedLinesCollector collector(style, isRowAxis, autoRepeatTotalTracks);
     auto list = CSSValueList::createSpaceSeparated();
     unsigned insertionIndex;
     if (isRenderGrid) {
index bf3f561..188d224 100644 (file)
@@ -6022,9 +6022,6 @@ bool CSSParser::parseGridTrackRepeatFunction(CSSValueList& list, bool& isAutoRep
 
     unsigned numberOfTracks = 0;
     while (arguments->current()) {
-        if (isAutoRepeat && numberOfTracks)
-            return false;
-
         RefPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
         if (!trackSize)
             return false;
index b838c2c..460bf75 100644 (file)
@@ -877,12 +877,12 @@ const GridTrackSize& RenderGrid::rawGridTrackSize(GridTrackSizingDirection direc
     auto& autoRepeatTrackStyles = isRowAxis ? style().gridAutoRepeatColumns() : style().gridAutoRepeatRows();
     auto& autoTrackStyles = isRowAxis ? style().gridAutoColumns() : style().gridAutoRows();
     unsigned insertionPoint = isRowAxis ? style().gridAutoRepeatColumnsInsertionPoint() : style().gridAutoRepeatRowsInsertionPoint();
-    unsigned repetitions = autoRepeatCountForDirection(direction);
+    unsigned autoRepeatTracksCount = autoRepeatCountForDirection(direction);
 
     // We should not use GridPositionsResolver::explicitGridXXXCount() for this because the
     // explicit grid might be larger than the number of tracks in grid-template-rows|columns (if
     // grid-template-areas is specified for example).
-    unsigned explicitTracksCount = trackStyles.size() + repetitions;
+    unsigned explicitTracksCount = trackStyles.size() + autoRepeatTracksCount;
 
     int untranslatedIndexAsInt = translatedIndex + (isRowAxis ? m_smallestColumnStart : m_smallestRowStart);
     unsigned autoTrackStylesSize = autoTrackStyles.size();
@@ -897,13 +897,15 @@ const GridTrackSize& RenderGrid::rawGridTrackSize(GridTrackSizingDirection direc
     if (untranslatedIndex >= explicitTracksCount)
         return autoTrackStyles[(untranslatedIndex - explicitTracksCount) % autoTrackStylesSize];
 
-    if (!repetitions || untranslatedIndex < insertionPoint)
+    if (!autoRepeatTracksCount || untranslatedIndex < insertionPoint)
         return trackStyles[untranslatedIndex];
 
-    if (untranslatedIndex < (insertionPoint + repetitions))
-        return autoRepeatTrackStyles[0];
+    if (untranslatedIndex < (insertionPoint + autoRepeatTracksCount)) {
+        unsigned autoRepeatLocalIndex = untranslatedIndexAsInt - insertionPoint;
+        return autoRepeatTrackStyles[autoRepeatLocalIndex % autoRepeatTrackStyles.size()];
+    }
 
-    return trackStyles[untranslatedIndex - repetitions];
+    return trackStyles[untranslatedIndex - autoRepeatTracksCount];
 }
 
 GridTrackSize RenderGrid::gridTrackSize(GridTrackSizingDirection direction, unsigned translatedIndex, SizingOperation sizingOperation) const
@@ -1418,15 +1420,11 @@ unsigned RenderGrid::computeAutoRepeatTracksCount(GridTrackSizingDirection direc
 {
     bool isRowAxis = direction == ForColumns;
     const auto& autoRepeatTracks = isRowAxis ? style().gridAutoRepeatColumns() : style().gridAutoRepeatRows();
+    unsigned autoRepeatTrackListLength = autoRepeatTracks.size();
 
-    if (!autoRepeatTracks.size())
+    if (!autoRepeatTrackListLength)
         return 0;
 
-    ASSERT(autoRepeatTracks.size() == 1);
-    auto autoTrackSize = autoRepeatTracks.at(0);
-    ASSERT(autoTrackSize.minTrackBreadth().isLength());
-    ASSERT(!autoTrackSize.minTrackBreadth().isFlex());
-
     Optional<LayoutUnit> availableSize = isRowAxis ? availableLogicalWidth() : computeContentLogicalHeight(MainOrPreferredSize, style().logicalHeight(), Nullopt);
     if (!isRowAxis || containingBlock()) {
         if (!availableSize) {
@@ -1447,21 +1445,27 @@ unsigned RenderGrid::computeAutoRepeatTracksCount(GridTrackSizingDirection direc
     if (!availableSize) {
         const Length& minSize = isRowAxis ? style().logicalMinWidth() : style().logicalMinHeight();
         if (!minSize.isSpecified())
-            return 1;
+            return autoRepeatTrackListLength;
 
         LayoutUnit containingBlockAvailableSize = isRowAxis ? containingBlockLogicalWidthForContent() : containingBlockLogicalHeightForContent(ExcludeMarginBorderPadding);
         availableSize = valueForLength(minSize, containingBlockAvailableSize);
         needsToFulfillMinimumSize = true;
     }
 
-    bool hasDefiniteMaxTrackSizingFunction = autoTrackSize.maxTrackBreadth().isLength() && !autoTrackSize.maxTrackBreadth().isContentSized();
-    const Length trackLength = hasDefiniteMaxTrackSizingFunction ? autoTrackSize.maxTrackBreadth().length() : autoTrackSize.minTrackBreadth().length();
+    LayoutUnit autoRepeatTracksSize;
+    for (auto& autoTrackSize : autoRepeatTracks) {
+        ASSERT(autoTrackSize.minTrackBreadth().isLength());
+        ASSERT(!autoTrackSize.minTrackBreadth().isFlex());
+        bool hasDefiniteMaxTrackSizingFunction = autoTrackSize.maxTrackBreadth().isLength() && !autoTrackSize.maxTrackBreadth().isContentSized();
+        auto trackLength = hasDefiniteMaxTrackSizingFunction ? autoTrackSize.maxTrackBreadth().length() : autoTrackSize.minTrackBreadth().length();
+        autoRepeatTracksSize += valueForLength(trackLength, availableSize.value());
+    }
     // For the purpose of finding the number of auto-repeated tracks, the UA must floor the track size to a UA-specified
     // value to avoid division by zero. It is suggested that this floor be 1px.
-    LayoutUnit autoRepeatTrackSize = std::max<LayoutUnit>(LayoutUnit(1), valueForLength(trackLength, availableSize.value()));
+    autoRepeatTracksSize = std::max<LayoutUnit>(LayoutUnit(1), autoRepeatTracksSize);
 
     // There will be always at least 1 auto-repeat track, so take it already into account when computing the total track size.
-    LayoutUnit tracksSize = autoRepeatTrackSize;
+    LayoutUnit tracksSize = autoRepeatTracksSize;
     auto& trackSizes = isRowAxis ? style().gridColumns() : style().gridRows();
 
     for (const auto& track : trackSizes) {
@@ -1477,9 +1481,9 @@ unsigned RenderGrid::computeAutoRepeatTracksCount(GridTrackSizingDirection direc
 
     LayoutUnit freeSpace = availableSize.value() - tracksSize;
     if (freeSpace <= 0)
-        return 1;
+        return autoRepeatTrackListLength;
 
-    unsigned repetitions = 1 + (freeSpace / (autoRepeatTrackSize + gapSize)).toInt();
+    unsigned repetitions = 1 + (freeSpace / (autoRepeatTracksSize + gapSize)).toInt();
 
     // Provided the grid container does not have a definite size or max-size in the relevant axis,
     // if the min size is definite then the number of repetitions is the largest possible positive
@@ -1487,7 +1491,7 @@ unsigned RenderGrid::computeAutoRepeatTracksCount(GridTrackSizingDirection direc
     if (needsToFulfillMinimumSize)
         ++repetitions;
 
-    return repetitions;
+    return repetitions * autoRepeatTrackListLength;
 }
 
 
@@ -1499,10 +1503,9 @@ std::unique_ptr<RenderGrid::OrderedTrackIndexSet> RenderGrid::computeEmptyTracks
         return nullptr;
 
     std::unique_ptr<OrderedTrackIndexSet> emptyTrackIndexes;
-    size_t insertionPoint = isRowAxis ? style().gridAutoRepeatColumnsInsertionPoint() : style().gridAutoRepeatRowsInsertionPoint();
-    size_t repetitions = autoRepeatCountForDirection(direction);
-    size_t firstAutoRepeatTrack = insertionPoint + std::abs(isRowAxis ? m_smallestColumnStart : m_smallestRowStart);
-    size_t lastAutoRepeatTrack = firstAutoRepeatTrack + repetitions;
+    unsigned insertionPoint = isRowAxis ? style().gridAutoRepeatColumnsInsertionPoint() : style().gridAutoRepeatRowsInsertionPoint();
+    unsigned firstAutoRepeatTrack = insertionPoint + std::abs(isRowAxis ? m_smallestColumnStart : m_smallestRowStart);
+    unsigned lastAutoRepeatTrack = firstAutoRepeatTrack + autoRepeatCountForDirection(direction);
 
     if (m_gridItemArea.isEmpty()) {
         emptyTrackIndexes = std::make_unique<OrderedTrackIndexSet>();
index a490785..e47c921 100644 (file)
@@ -71,7 +71,7 @@ static const String implicitNamedGridLineForSide(const String& lineName, GridPos
 
 NamedLineCollection::NamedLineCollection(const RenderStyle& gridContainerStyle, const String& namedLine, GridTrackSizingDirection direction, unsigned lastLine, unsigned autoRepeatTracksCount)
     : m_lastLine(lastLine)
-    , m_repetitions(autoRepeatTracksCount)
+    , m_autoRepeatTotalTracks(autoRepeatTracksCount)
 {
     bool isRowAxis = direction == ForColumns;
     const NamedGridLinesMap& gridLineNames = isRowAxis ? gridContainerStyle.namedGridColumnLines() : gridContainerStyle.namedGridRowLines();
@@ -84,6 +84,8 @@ NamedLineCollection::NamedLineCollection(const RenderStyle& gridContainerStyle,
     m_autoRepeatNamedLinesIndexes = autoRepeatLinesIterator == autoRepeatGridLineNames.end() ? nullptr : &autoRepeatLinesIterator->value;
 
     m_insertionPoint = isRowAxis ? gridContainerStyle.gridAutoRepeatColumnsInsertionPoint() : gridContainerStyle.gridAutoRepeatRowsInsertionPoint();
+
+    m_autoRepeatTrackListLength = isRowAxis ? gridContainerStyle.gridAutoRepeatColumns().size() : gridContainerStyle.gridAutoRepeatRows().size();
 }
 
 bool NamedLineCollection::isValidNamedLineOrArea(const String& namedLine, const RenderStyle& gridContainerStyle, GridPositionSide side)
@@ -112,22 +114,24 @@ size_t NamedLineCollection::find(unsigned line) const
     if (!m_autoRepeatNamedLinesIndexes || line < m_insertionPoint)
         return m_namedLinesIndexes ? m_namedLinesIndexes->find(line) : notFound;
 
-    if (line <= (m_insertionPoint + m_repetitions)) {
+    if (line <= (m_insertionPoint + m_autoRepeatTotalTracks)) {
         size_t localIndex = line - m_insertionPoint;
 
+        size_t indexInFirstRepetition = localIndex % m_autoRepeatTrackListLength;
+        if (indexInFirstRepetition)
+            return m_autoRepeatNamedLinesIndexes->find(indexInFirstRepetition);
+
         // The line names defined in the last line are also present in the first line of the next
-        // repetition (if any). Same for the line names defined in the first line. Note that there
-        // is only one auto-repeated track allowed by the syntax, that's why it's enough to store
-        // indexes 0 and 1 (before and after the track size).
-        if (localIndex == m_repetitions)
-            return m_autoRepeatNamedLinesIndexes->find(1u);
+        // repetition (if any). Same for the line names defined in the first line.
+        if (localIndex == m_autoRepeatTotalTracks)
+            return m_autoRepeatNamedLinesIndexes->find(m_autoRepeatTrackListLength);
         size_t position = m_autoRepeatNamedLinesIndexes->find(0u);
         if (position != notFound)
             return position;
-        return localIndex ? m_autoRepeatNamedLinesIndexes->find(1u) : notFound;
+        return localIndex ? m_autoRepeatNamedLinesIndexes->find(m_autoRepeatTrackListLength) : notFound;
     }
 
-    return m_namedLinesIndexes ? m_namedLinesIndexes->find(line - (m_repetitions - 1)) : notFound;
+    return m_namedLinesIndexes ? m_namedLinesIndexes->find(line - (m_autoRepeatTotalTracks - 1)) : notFound;
 }
 
 bool NamedLineCollection::contains(unsigned line) const
@@ -143,7 +147,7 @@ unsigned NamedLineCollection::firstPosition() const
 
     if (!m_autoRepeatNamedLinesIndexes) {
         if (!m_insertionPoint || m_insertionPoint < m_namedLinesIndexes->at(firstLine))
-            return m_namedLinesIndexes->at(firstLine) + (m_repetitions ? m_repetitions - 1 : 0);
+            return m_namedLinesIndexes->at(firstLine) + (m_autoRepeatTotalTracks ? m_autoRepeatTotalTracks - 1 : 0);
         return m_namedLinesIndexes->at(firstLine);
     }
 
@@ -151,7 +155,7 @@ unsigned NamedLineCollection::firstPosition() const
         return m_autoRepeatNamedLinesIndexes->at(firstLine) + m_insertionPoint;
 
     if (!m_insertionPoint)
-        return m_autoRepeatNamedLinesIndexes->at(firstLine);
+        return std::min(m_namedLinesIndexes->at(firstLine) + m_autoRepeatTotalTracks, m_autoRepeatNamedLinesIndexes->at(firstLine));
 
     return std::min(m_namedLinesIndexes->at(firstLine), m_autoRepeatNamedLinesIndexes->at(firstLine) + m_insertionPoint);
 }
index 8e7ebdb..c978733 100644 (file)
@@ -66,7 +66,8 @@ private:
 
     unsigned m_insertionPoint;
     unsigned m_lastLine;
-    unsigned m_repetitions;
+    unsigned m_autoRepeatTotalTracks;
+    unsigned m_autoRepeatTrackListLength;
 };
 
 // Class with all the code related to grid items positions resolution.