[CSS Grid Layout] Update track sizes after distributing extra space
authorsvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2015 14:53:34 +0000 (14:53 +0000)
committersvillar@igalia.com <svillar@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2015 14:53:34 +0000 (14:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141422

Reviewed by Antti Koivisto.

Source/WebCore:

Both old and new tracks sizing algorithms instruct us to update
the sizes of the content sized tracks only after distributing the
extra space for all the items in the same span group. So far we
were doing it inside distributeSpaceToTracks(), i.e., once for
every single item. That is wrong because it makes the algorithm
order dependent.

Our old implementation looked something like this (pseudocode):

resolveContentBasedTrackSizingFunctions()
  foreach item
    resolveContentBasedTrackSizingFunctionsForItems() (x4)
      distributeSpaceToTracks()
        updateTrackSizes()

Now it's done this way (pseudocode):

resolveContentBasedTrackSizingFunctions()
  foreach spanGroup
    resolveContentBasedTrackSizingFunctionsForItems() (x4)
      foreach item in spanGroup
        distributeSpaceToTracks()
      updateTrackSizes()

As it can be seen the update of track sizes only happens after
processing all the items of a given span group. In order to
accomplish this a new field was added to GridTrack called
tempIncrease which stores per-track increases while distributing
the extra space among the items in the same span group. That
temporal increase could eventually be used to update the
plannedIncrease which is the one we use to finally set the new
size of the track.

This change makes our implementation closer to the spec, removes
the order dependency and ensures that every track satisfies their
min track sizing functions before starting to consider the max
track sizing functions.

Test: fast/css-grid-layout/grid-update-sizes-after-distributing-all.html

* rendering/RenderGrid.cpp:
(WebCore::GridTrack::plannedSize):
(WebCore::GridTrack::setPlannedSize): New setter.
(WebCore::GridTrack::tempSize): New attribute.
(WebCore::RenderGrid::computeUsedBreadthOfGridTracks):
RenderGrid::distributeSpaceToTracks() no longer updates the track
sizes so we have to do it after the call returns.
(WebCore::RenderGrid::resolveContentBasedTrackSizingFunctions):
Call RenderGrid::resolveContentBasedTrackSizingFunctionsForItems()
passing a span group instead of a single item.
(WebCore::RenderGrid::resolveContentBasedTrackSizingFunctionsForItems):
It now receives a span group instead of a single item. Apart from
that we need an extra function to get the unaltered track size (as
the current one returns the base size whenever the growth limit is
infinity).
(WebCore::RenderGrid::distributeSpaceToTracks): This no longer
updates track sizes but only the track's planned size;
* rendering/RenderGrid.h:

LayoutTests:

* fast/css-grid-layout/grid-content-sized-columns-resolution-expected.txt:
* fast/css-grid-layout/grid-content-sized-columns-resolution.html:
* fast/css-grid-layout/grid-update-sizes-after-distributing-all-expected.txt: Added.
* fast/css-grid-layout/grid-update-sizes-after-distributing-all.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/grid-content-sized-columns-resolution-expected.txt
LayoutTests/fast/css-grid-layout/grid-content-sized-columns-resolution.html
LayoutTests/fast/css-grid-layout/grid-update-sizes-after-distributing-all-expected.txt [new file with mode: 0644]
LayoutTests/fast/css-grid-layout/grid-update-sizes-after-distributing-all.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/RenderGrid.h

index 4ae0146..8381451 100644 (file)
@@ -1,3 +1,15 @@
+2015-02-25  Sergio Villar Senin  <svillar@igalia.com>
+
+        [CSS Grid Layout] Update track sizes after distributing extra space
+        https://bugs.webkit.org/show_bug.cgi?id=141422
+
+        Reviewed by Antti Koivisto.
+
+        * fast/css-grid-layout/grid-content-sized-columns-resolution-expected.txt:
+        * fast/css-grid-layout/grid-content-sized-columns-resolution.html:
+        * fast/css-grid-layout/grid-update-sizes-after-distributing-all-expected.txt: Added.
+        * fast/css-grid-layout/grid-update-sizes-after-distributing-all.html: Added.
+
 2015-04-07  Marcos Chavarría Teijeiro  <chavarria1991@gmail.com>
 
         [GTK] Gardening 7th April
index 7e21d84..5127415 100644 (file)
@@ -39,9 +39,9 @@ PASS window.getComputedStyle(gridAutoMaxContentUnsorted, '').getPropertyValue('-
 PASS window.getComputedStyle(gridMaxContentAndMinContentFixedUnsorted, '').getPropertyValue('-webkit-grid-template-columns') is "50px 40px"
 PASS window.getComputedStyle(gridMaxContentAndMaxContentFixedUnsorted, '').getPropertyValue('-webkit-grid-template-columns') is "40px 70px"
 PASS window.getComputedStyle(gridMinContentFixedAndAutoAboveLimits, '').getPropertyValue('-webkit-grid-template-columns') is "15px 95px"
-PASS window.getComputedStyle(gridMaxContentFixedAndAutoAboveLimits, '').getPropertyValue('-webkit-grid-template-columns') is "65px 85px"
+PASS window.getComputedStyle(gridMaxContentFixedAndAutoAboveLimits, '').getPropertyValue('-webkit-grid-template-columns') is "15px 135px"
 PASS window.getComputedStyle(gridMinContentFixedAndFixedFixedAndAuto, '').getPropertyValue('-webkit-grid-template-columns') is "20px 20px 60px"
-PASS window.getComputedStyle(gridAutoAndFixedFixedAndMaxContentFixed, '').getPropertyValue('-webkit-grid-template-columns') is "70px 20px 60px"
+PASS window.getComputedStyle(gridAutoAndFixedFixedAndMaxContentFixed, '').getPropertyValue('-webkit-grid-template-columns') is "110px 20px 20px"
 PASS window.getComputedStyle(gridMaxContentAndMaxContentFixedAndMaxContent, '').getPropertyValue('-webkit-grid-template-columns') is "70px 20px 50px"
 PASS window.getComputedStyle(gridAutoAndMinContentFixedAndMinContent, '').getPropertyValue('-webkit-grid-template-columns') is "55px 30px 65px"
 PASS successfullyParsed is true
index 4126ea9..f976ae5 100644 (file)
@@ -363,9 +363,9 @@ testGridColumnsValues("gridMaxContentAndMinContentFixedUnsorted", "50px 40px");
 testGridColumnsValues("gridMaxContentAndMaxContentFixedUnsorted", "40px 70px");
 
 testGridColumnsValues("gridMinContentFixedAndAutoAboveLimits", "15px 95px");
-testGridColumnsValues("gridMaxContentFixedAndAutoAboveLimits", "65px 85px");
+testGridColumnsValues("gridMaxContentFixedAndAutoAboveLimits", "15px 135px");
 testGridColumnsValues("gridMinContentFixedAndFixedFixedAndAuto", "20px 20px 60px");
-testGridColumnsValues("gridAutoAndFixedFixedAndMaxContentFixed", "70px 20px 60px");
+testGridColumnsValues("gridAutoAndFixedFixedAndMaxContentFixed", "110px 20px 20px");
 testGridColumnsValues("gridMaxContentAndMaxContentFixedAndMaxContent", "70px 20px 50px");
 testGridColumnsValues("gridAutoAndMinContentFixedAndMinContent", "55px 30px 65px");
 </script>
diff --git a/LayoutTests/fast/css-grid-layout/grid-update-sizes-after-distributing-all-expected.txt b/LayoutTests/fast/css-grid-layout/grid-update-sizes-after-distributing-all-expected.txt
new file mode 100644 (file)
index 0000000..4c245e9
--- /dev/null
@@ -0,0 +1,51 @@
+Check that tracks are updated after distributing the extra space for all the items in the same group span.
+PASS window.getComputedStyle(gridAutoAndMaxContent, '').getPropertyValue('-webkit-grid-template-columns') is "25px 65px"
+PASS window.getComputedStyle(gridFixedMinContentAndFixedMaxContent, '').getPropertyValue('-webkit-grid-template-columns') is "25px 85px"
+PASS window.getComputedStyle(gridMinContentAndMaxContent, '').getPropertyValue('-webkit-grid-template-columns') is "15px 85px"
+PASS window.getComputedStyle(gridMinContentAndFixedAndMaxContent, '').getPropertyValue('-webkit-grid-template-columns') is "15px 20px 105px"
+PASS window.getComputedStyle(gridMaxContentAndFixedAndAuto, '').getPropertyValue('-webkit-grid-template-columns') is "105px 20px 15px"
+PASS window.getComputedStyle(gridRepeatTwoMaxContentAndMinContentTwoOverlapping, '').getPropertyValue('-webkit-grid-template-columns') is "115px 25px 85px 15px"
+PASS window.getComputedStyle(gridRepeatTwoMaxContentAndMinContentThreeOverlapping, '').getPropertyValue('-webkit-grid-template-columns') is "65px 25px 115px 15px"
+PASS window.getComputedStyle(gridRepeatTwoMaxContentAndMinContentTwoAndFourOverlapping, '').getPropertyValue('-webkit-grid-template-columns') is "70px 30px 80px 10px"
+PASS window.getComputedStyle(gridRepeatTwoAutoAndMaxContentTwoOverlapping, '').getPropertyValue('-webkit-grid-template-columns') is "25px 115px 15px 85px"
+PASS window.getComputedStyle(gridRepeatTwoAutoAndMaxContentThreeOverlapping, '').getPropertyValue('-webkit-grid-template-columns') is "20px 115px 25px 75px"
+PASS window.getComputedStyle(gridRepeatTwoAutoAndMaxContentTwoAndFourOverlapping, '').getPropertyValue('-webkit-grid-template-columns') is "30px 70px 10px 80px"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+XXXX XXXX
+XXXXX X
+XXXX XXXX
+XXXXX XXXXX
+XX XX
+XXX XX XXX
+XXXX XXXX
+XXXXX XXX XXXX
+XXXX XXXX
+XXXXX XXX XXXX
+XXXX XXXX
+XX XX
+XXXXX XXX XXXX
+XXX XX XXX
+XXXXX XXX XXXX
+XXX XX XXX
+XXXX XXXX
+XXXX XXXX
+XX XX
+XXXXX XXX XXXX
+XXX XX XXX
+X X X X X
+XXXXXX
+XXXX XXXX
+XX XX
+XXXXX XXX XXXX
+XXX XX XXX
+XXXXX XXX XXXX
+XXX XX XXX
+XXXX XXXX
+XXXX XXXX
+XX XX
+XXXXX XXX XXXX
+XXX XX XXX
+X X X X X
+XXXXXX
diff --git a/LayoutTests/fast/css-grid-layout/grid-update-sizes-after-distributing-all.html b/LayoutTests/fast/css-grid-layout/grid-update-sizes-after-distributing-all.html
new file mode 100644 (file)
index 0000000..985c5fe
--- /dev/null
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<head>
+<link href="resources/grid.css" rel="stylesheet"/>
+<style>
+ .grid { font: 10px/1 Ahem; }
+
+ .gridAutoAndMaxContent {
+    -webkit-grid-template-columns: auto -webkit-max-content;
+ }
+ .gridFixedMinContentAndFixedMaxContent {
+    -webkit-grid-template-columns: minmax(10px, -webkit-min-content) minmax(10px, -webkit-max-content);
+ }
+ .gridMinContentAndMaxContent {
+    -webkit-grid-template-columns: -webkit-min-content -webkit-max-content;
+ }
+
+ .gridMinContentAndFixedAndMaxContent {
+    -webkit-grid-template-columns: -webkit-min-content 20px -webkit-max-content;
+ }
+
+ .gridMaxContentAndFixedAndAuto {
+    -webkit-grid-template-columns: -webkit-max-content 20px auto;
+ }
+
+ .gridRepeatTwoMaxContentAndMinContent {
+    -webkit-grid-template-columns: repeat(2, -webkit-max-content -webkit-min-content);
+ }
+
+ .gridRepeatTwoAutoAndMaxContent {
+    -webkit-grid-template-columns: repeat(2, auto -webkit-max-content);
+ }
+
+ .columns1And2 { -webkit-grid-column: 1 / span 2; }
+ .columns2And3 { -webkit-grid-column: 2 / span 2; }
+ .columns3And4 { -webkit-grid-column: 3 / span 2; }
+ .columns1To3 { -webkit-grid-column: 1 / span 3; }
+ .columns1To4 { -webkit-grid-column: 1 / span 4; }
+</style>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+
+<div class="constrainedContainer">
+    <div class="grid gridAutoAndMaxContent" id="gridAutoAndMaxContent">
+       <div class="columns1And2">XXXX XXXX</div>
+       <div class="columns1And2">XXXXX X</div>
+    </div>
+</div>
+
+<div class="grid gridFixedMinContentAndFixedMaxContent" id="gridFixedMinContentAndFixedMaxContent">
+    <div class="columns1And2">XXXX XXXX</div>
+    <div class="columns1And2">XXXXX XXXXX</div>
+</div>
+
+<div class="grid gridMinContentAndMaxContent" id="gridMinContentAndMaxContent">
+    <div class="columns1And2">XX XX</div>
+    <div class="columns1And2">XXX XX XXX</div>
+</div>
+
+<div class="grid gridMinContentAndFixedAndMaxContent" id="gridMinContentAndFixedAndMaxContent">
+    <div class="columns1To3">XXXX XXXX</div>
+    <div class="columns1To3">XXXXX XXX XXXX</div>
+</div>
+
+<div class="grid gridMaxContentAndFixedAndAuto" id="gridMaxContentAndFixedAndAuto">
+    <div class="columns1To3">XXXX XXXX</div>
+    <div class="columns1To3">XXXXX XXX XXXX</div>
+</div>
+
+<div class="grid gridRepeatTwoMaxContentAndMinContent" id="gridRepeatTwoMaxContentAndMinContentTwoOverlapping">
+    <div class="columns1And2">XXXX XXXX</div>
+    <div class="columns3And4">XX XX</div>
+    <div class="columns1And2">XXXXX XXX XXXX</div>
+    <div class="columns3And4">XXX XX XXX</div>
+</div>
+
+<div class="grid gridRepeatTwoMaxContentAndMinContent" id="gridRepeatTwoMaxContentAndMinContentThreeOverlapping">
+    <div class="columns2And3">XXXXX XXX XXXX</div>
+    <div class="columns3And4">XXX XX XXX</div>
+    <div class="columns1And2">XXXX XXXX</div>
+</div>
+
+<div class="grid gridRepeatTwoMaxContentAndMinContent" id="gridRepeatTwoMaxContentAndMinContentTwoAndFourOverlapping">
+    <div class="columns1To4">XXXX XXXX</div>
+    <div class="columns3And4">XX XX</div>
+    <div class="columns1To4">XXXXX XXX XXXX</div>
+    <div class="columns1And2">XXX XX XXX</div>
+    <div class="columns3And4">X X X X X</div>
+    <div class="columns1And2">XXXXXX</div>
+</div>
+
+<div class="grid gridRepeatTwoAutoAndMaxContent" id="gridRepeatTwoAutoAndMaxContentTwoOverlapping">
+    <div class="columns1And2">XXXX XXXX</div>
+    <div class="columns3And4">XX XX</div>
+    <div class="columns1And2">XXXXX XXX XXXX</div>
+    <div class="columns3And4">XXX XX XXX</div>
+</div>
+
+<div class="grid gridRepeatTwoAutoAndMaxContent" id="gridRepeatTwoAutoAndMaxContentThreeOverlapping">
+    <div class="columns2And3">XXXXX XXX XXXX</div>
+    <div class="columns3And4">XXX XX XXX</div>
+    <div class="columns1And2">XXXX XXXX</div>
+</div>
+
+<div class="grid gridRepeatTwoAutoAndMaxContent" id="gridRepeatTwoAutoAndMaxContentTwoAndFourOverlapping">
+    <div class="columns1To4">XXXX XXXX</div>
+    <div class="columns3And4">XX XX</div>
+    <div class="columns1To4">XXXXX XXX XXXX</div>
+    <div class="columns1And2">XXX XX XXX</div>
+    <div class="columns3And4">X X X X X</div>
+    <div class="columns1And2">XXXXXX</div>
+</div>
+
+<script>
+function testGridColumnsValues(id, computedColumnValue)
+{
+    shouldBeEqualToString("window.getComputedStyle(" + id + ", '').getPropertyValue('-webkit-grid-template-columns')", computedColumnValue);
+}
+
+debug("Check that tracks are updated after distributing the extra space for all the items in the same group span.");
+testGridColumnsValues("gridAutoAndMaxContent", "25px 65px");
+testGridColumnsValues("gridFixedMinContentAndFixedMaxContent", "25px 85px");
+testGridColumnsValues("gridMinContentAndMaxContent", "15px 85px");
+testGridColumnsValues("gridMinContentAndFixedAndMaxContent", "15px 20px 105px");
+testGridColumnsValues("gridMaxContentAndFixedAndAuto", "105px 20px 15px");
+testGridColumnsValues("gridRepeatTwoMaxContentAndMinContentTwoOverlapping", "115px 25px 85px 15px");
+testGridColumnsValues("gridRepeatTwoMaxContentAndMinContentThreeOverlapping", "65px 25px 115px 15px");
+testGridColumnsValues("gridRepeatTwoMaxContentAndMinContentTwoAndFourOverlapping", "70px 30px 80px 10px");
+testGridColumnsValues("gridRepeatTwoAutoAndMaxContentTwoOverlapping", "25px 115px 15px 85px");
+testGridColumnsValues("gridRepeatTwoAutoAndMaxContentThreeOverlapping", "20px 115px 25px 75px");
+testGridColumnsValues("gridRepeatTwoAutoAndMaxContentTwoAndFourOverlapping", "30px 70px 10px 80px");
+</script>
+</body>
index c324574..6356981 100644 (file)
@@ -1,3 +1,69 @@
+2015-02-25  Sergio Villar Senin  <svillar@igalia.com>
+
+        [CSS Grid Layout] Update track sizes after distributing extra space
+        https://bugs.webkit.org/show_bug.cgi?id=141422
+
+        Reviewed by Antti Koivisto.
+
+        Both old and new tracks sizing algorithms instruct us to update
+        the sizes of the content sized tracks only after distributing the
+        extra space for all the items in the same span group. So far we
+        were doing it inside distributeSpaceToTracks(), i.e., once for
+        every single item. That is wrong because it makes the algorithm
+        order dependent.
+
+        Our old implementation looked something like this (pseudocode):
+
+        resolveContentBasedTrackSizingFunctions()
+          foreach item
+            resolveContentBasedTrackSizingFunctionsForItems() (x4)
+              distributeSpaceToTracks()
+                updateTrackSizes()
+
+        Now it's done this way (pseudocode):
+
+        resolveContentBasedTrackSizingFunctions()
+          foreach spanGroup
+            resolveContentBasedTrackSizingFunctionsForItems() (x4)
+              foreach item in spanGroup
+                distributeSpaceToTracks()
+              updateTrackSizes()
+
+        As it can be seen the update of track sizes only happens after
+        processing all the items of a given span group. In order to
+        accomplish this a new field was added to GridTrack called
+        tempIncrease which stores per-track increases while distributing
+        the extra space among the items in the same span group. That
+        temporal increase could eventually be used to update the
+        plannedIncrease which is the one we use to finally set the new
+        size of the track.
+
+        This change makes our implementation closer to the spec, removes
+        the order dependency and ensures that every track satisfies their
+        min track sizing functions before starting to consider the max
+        track sizing functions.
+
+        Test: fast/css-grid-layout/grid-update-sizes-after-distributing-all.html
+
+        * rendering/RenderGrid.cpp:
+        (WebCore::GridTrack::plannedSize):
+        (WebCore::GridTrack::setPlannedSize): New setter.
+        (WebCore::GridTrack::tempSize): New attribute.
+        (WebCore::RenderGrid::computeUsedBreadthOfGridTracks):
+        RenderGrid::distributeSpaceToTracks() no longer updates the track
+        sizes so we have to do it after the call returns.
+        (WebCore::RenderGrid::resolveContentBasedTrackSizingFunctions):
+        Call RenderGrid::resolveContentBasedTrackSizingFunctionsForItems()
+        passing a span group instead of a single item.
+        (WebCore::RenderGrid::resolveContentBasedTrackSizingFunctionsForItems):
+        It now receives a span group instead of a single item. Apart from
+        that we need an extra function to get the unaltered track size (as
+        the current one returns the base size whenever the growth limit is
+        infinity).
+        (WebCore::RenderGrid::distributeSpaceToTracks): This no longer
+        updates track sizes but only the track's planned size;
+        * rendering/RenderGrid.h:
+
 2015-04-06  Chris Dumez  <cdumez@apple.com>
 
         Bing video search result pages are not PageCacheable
index 9c6d131..7c5b7d5 100644 (file)
@@ -79,11 +79,15 @@ public:
         return (m_growthLimit == infinity) ? m_baseSize : m_growthLimit;
     }
 
-    LayoutUnit& plannedSize()
+    const LayoutUnit& plannedSize() const { return m_plannedSize; }
+
+    void setPlannedSize(LayoutUnit plannedSize)
     {
-        return m_plannedSize;
+        m_plannedSize = plannedSize;
     }
 
+    LayoutUnit& tempSize() { return m_tempSize; }
+
 private:
     bool isGrowthLimitBiggerThanBaseSize() const { return growthLimitIsInfinite() || m_growthLimit >= m_baseSize; }
 
@@ -96,6 +100,7 @@ private:
     LayoutUnit m_baseSize { 0 };
     LayoutUnit m_growthLimit { 0 };
     LayoutUnit m_plannedSize { 0 };
+    LayoutUnit m_tempSize { 0 };
 };
 
 struct GridTrackForNormalization {
@@ -362,10 +367,15 @@ void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
     if (!hasUndefinedRemainingSpace) {
         const unsigned tracksSize = tracks.size();
         Vector<GridTrack*> tracksForDistribution(tracksSize);
-        for (unsigned i = 0; i < tracksSize; ++i)
+        for (unsigned i = 0; i < tracksSize; ++i) {
             tracksForDistribution[i] = tracks.data() + i;
+            tracksForDistribution[i]->setPlannedSize(tracksForDistribution[i]->baseSize());
+        }
 
-        distributeSpaceToTracks(tracksForDistribution, nullptr, &GridTrack::baseSize, &GridTrack::setBaseSize, availableLogicalSpace);
+        distributeSpaceToTracks(tracksForDistribution, nullptr, &GridTrack::baseSize, availableLogicalSpace);
+
+        for (auto* track : tracksForDistribution)
+            track->setBaseSize(track->plannedSize());
     } else {
         for (auto& track : tracks)
             track.setBaseSize(track.growthLimit());
@@ -603,6 +613,11 @@ static inline unsigned integerSpanForDirection(const GridCoordinate& coordinate,
     return (direction == ForRows) ? coordinate.rows.integerSpan() : coordinate.columns.integerSpan();
 }
 
+struct GridItemsSpanGroupRange {
+    Vector<GridItemWithSpan>::iterator rangeStart;
+    Vector<GridItemWithSpan>::iterator rangeEnd;
+};
+
 void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirection direction, GridSizingData& sizingData)
 {
     sizingData.itemsSortedByIncreasingSpan.shrink(0);
@@ -623,11 +638,15 @@ void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirectio
     }
     std::sort(sizingData.itemsSortedByIncreasingSpan.begin(), sizingData.itemsSortedByIncreasingSpan.end());
 
-    for (auto& itemWithSpan : sizingData.itemsSortedByIncreasingSpan) {
-        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, itemWithSpan, &GridTrackSize::hasMinOrMaxContentMinTrackBreadth, &RenderGrid::minContentForChild, &GridTrack::baseSize, &GridTrack::setBaseSize, &GridTrackSize::hasMinContentMinTrackBreadthAndMinOrMaxContentMaxTrackBreadth);
-        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, itemWithSpan, &GridTrackSize::hasMaxContentMinTrackBreadth, &RenderGrid::maxContentForChild, &GridTrack::baseSize, &GridTrack::setBaseSize, &GridTrackSize::hasMaxContentMinTrackBreadthAndMaxContentMaxTrackBreadth);
-        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, itemWithSpan, &GridTrackSize::hasMinOrMaxContentMaxTrackBreadth, &RenderGrid::minContentForChild, &GridTrack::growthLimitIfNotInfinite, &GridTrack::setGrowthLimit);
-        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, itemWithSpan, &GridTrackSize::hasMaxContentMaxTrackBreadth, &RenderGrid::maxContentForChild, &GridTrack::growthLimitIfNotInfinite, &GridTrack::setGrowthLimit);
+    auto it = sizingData.itemsSortedByIncreasingSpan.begin();
+    auto end = sizingData.itemsSortedByIncreasingSpan.end();
+    while (it != end) {
+        GridItemsSpanGroupRange spanGroupRange = { it, std::upper_bound(it, end, *it) };
+        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, spanGroupRange, &GridTrackSize::hasMinOrMaxContentMinTrackBreadth, &RenderGrid::minContentForChild, &GridTrack::baseSize, &GridTrack::baseSize, &GridTrack::setBaseSize, &GridTrackSize::hasMinContentMinTrackBreadthAndMinOrMaxContentMaxTrackBreadth);
+        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, spanGroupRange, &GridTrackSize::hasMaxContentMinTrackBreadth, &RenderGrid::maxContentForChild, &GridTrack::baseSize, &GridTrack::baseSize, &GridTrack::setBaseSize, &GridTrackSize::hasMaxContentMinTrackBreadthAndMaxContentMaxTrackBreadth);
+        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, spanGroupRange, &GridTrackSize::hasMinOrMaxContentMaxTrackBreadth, &RenderGrid::minContentForChild, &GridTrack::growthLimit, &GridTrack::growthLimitIfNotInfinite, &GridTrack::setGrowthLimit);
+        resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, spanGroupRange, &GridTrackSize::hasMaxContentMaxTrackBreadth, &RenderGrid::maxContentForChild, &GridTrack::growthLimit, &GridTrack::growthLimitIfNotInfinite, &GridTrack::setGrowthLimit);
+        it = spanGroupRange.rangeEnd;
     }
 
     for (auto trackIndex : sizingData.contentSizedTracksIndex) {
@@ -653,41 +672,51 @@ void RenderGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(Grid
         track.setGrowthLimit(std::max(track.growthLimit(), maxContentForChild(gridItem, direction, columnTracks)));
 }
 
-void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection direction, GridSizingData& sizingData, GridItemWithSpan& gridItemWithSpan, FilterFunction filterFunction, SizingFunction sizingFunction, AccumulatorGetter trackGetter, AccumulatorGrowFunction trackGrowthFunction, FilterFunction growAboveMaxBreadthFilterFunction)
+void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection direction, GridSizingData& sizingData, const GridItemsSpanGroupRange& gridItemsWithSpan, FilterFunction filterFunction, SizingFunction sizingFunction, AccumulatorGetter trackSize, AccumulatorGetter correctedTrackSize, AccumulatorGrowFunction trackGrowthFunction, FilterFunction growAboveMaxBreadthFilterFunction)
 {
-    ASSERT(gridItemWithSpan.span() > 1);
-    const GridCoordinate& coordinate = gridItemWithSpan.coordinate();
-    const GridResolvedPosition initialTrackPosition = (direction == ForColumns) ? coordinate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPosition;
-    const GridResolvedPosition finalTrackPosition = (direction == ForColumns) ? coordinate.columns.resolvedFinalPosition : coordinate.rows.resolvedFinalPosition;
-
-    sizingData.filteredTracks.shrink(0);
-    sizingData.growBeyondGrowthLimitsTracks.shrink(0);
-    for (GridResolvedPosition trackIndex = initialTrackPosition; trackIndex <= finalTrackPosition; ++trackIndex) {
-        const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex.toInt());
-        if (!(trackSize.*filterFunction)())
-            continue;
-
-        GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackIndex.toInt()] : sizingData.rowTracks[trackIndex.toInt()];
-        sizingData.filteredTracks.append(&track);
-
-        if (!growAboveMaxBreadthFilterFunction || (trackSize.*growAboveMaxBreadthFilterFunction)())
-            sizingData.growBeyondGrowthLimitsTracks.append(&track);
+    Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTracks : sizingData.rowTracks;
+    for (const auto& trackIndex : sizingData.contentSizedTracksIndex) {
+        GridTrack& track = tracks[trackIndex];
+        track.setPlannedSize((track.*trackSize)());
     }
 
-    if (sizingData.filteredTracks.isEmpty())
-        return;
+    for (auto it = gridItemsWithSpan.rangeStart; it != gridItemsWithSpan.rangeEnd; ++it) {
+        GridItemWithSpan& gridItemWithSpan = *it;
+        ASSERT(gridItemWithSpan.span() > 1);
+        const GridCoordinate& coordinate = gridItemWithSpan.coordinate();
+        const GridSpan& itemSpan = (direction == ForColumns) ? coordinate.columns : coordinate.rows;
+
+        sizingData.filteredTracks.shrink(0);
+        sizingData.growBeyondGrowthLimitsTracks.shrink(0);
+        LayoutUnit spanningTracksSize;
+        for (auto& trackPosition : itemSpan) {
+            const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.toInt());
+            GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()];
+            spanningTracksSize += (track.*correctedTrackSize)();
+            if (!(trackSize.*filterFunction)())
+                continue;
+
+            sizingData.filteredTracks.append(&track);
+
+            if (!growAboveMaxBreadthFilterFunction || (trackSize.*growAboveMaxBreadthFilterFunction)())
+                sizingData.growBeyondGrowthLimitsTracks.append(&track);
+        }
 
-    LayoutUnit extraSpace = (this->*sizingFunction)(gridItemWithSpan.gridItem(), direction, sizingData.columnTracks);
-    for (GridResolvedPosition trackPositionForSpace = initialTrackPosition; trackPositionForSpace <= finalTrackPosition; ++trackPositionForSpace) {
-        GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[trackPositionForSpace.toInt()] : sizingData.rowTracks[trackPositionForSpace.toInt()];
-        extraSpace -= (track.*trackGetter)();
+        if (sizingData.filteredTracks.isEmpty())
+            continue;
+
+        // Specs mandate to floor extraSpace to 0. Instead we directly avoid the function call in those cases as it will be
+        // a noop in terms of track sizing.
+        LayoutUnit extraSpace = (this->*sizingFunction)(gridItemWithSpan.gridItem(), direction, sizingData.columnTracks) - spanningTracksSize;
+        if (extraSpace > 0) {
+            auto* tracksToGrowBeyondGrowthLimits = sizingData.growBeyondGrowthLimitsTracks.isEmpty() ? &sizingData.filteredTracks : &sizingData.growBeyondGrowthLimitsTracks;
+            distributeSpaceToTracks(sizingData.filteredTracks, tracksToGrowBeyondGrowthLimits, correctedTrackSize, extraSpace);
+        }
     }
 
-    // Specs mandate to floor extraSpace to 0. Instead we directly avoid the function call in those cases as it will be
-    // a noop in terms of track sizing.
-    if (extraSpace > 0) {
-        auto* tracksToGrowBeyondGrowthLimits = sizingData.growBeyondGrowthLimitsTracks.isEmpty() ? &sizingData.filteredTracks : &sizingData.growBeyondGrowthLimitsTracks;
-        distributeSpaceToTracks(sizingData.filteredTracks, tracksToGrowBeyondGrowthLimits, trackGetter, trackGrowthFunction, extraSpace);
+    for (const auto& trackIndex : sizingData.contentSizedTracksIndex) {
+        GridTrack& track = tracks[trackIndex];
+        (track.*trackGrowthFunction)(track.plannedSize());
     }
 }
 
@@ -704,7 +733,7 @@ static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTr
     return (track1->growthLimit() - track1->baseSize()) < (track2->growthLimit() - track2->baseSize());
 }
 
-void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vector<GridTrack*>* growBeyondGrowthLimitsTracks, AccumulatorGetter trackGetter, AccumulatorGrowFunction trackGrowthFunction, LayoutUnit& availableLogicalSpace)
+void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vector<GridTrack*>* growBeyondGrowthLimitsTracks, AccumulatorGetter trackGetter, LayoutUnit& availableLogicalSpace)
 {
     ASSERT(availableLogicalSpace > 0);
     std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential);
@@ -716,13 +745,13 @@ void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
         const LayoutUnit& trackBreadth = (track.*trackGetter)();
         bool infiniteGrowthPotential = track.growthLimitIsInfinite();
         LayoutUnit trackGrowthPotential = infiniteGrowthPotential ? track.growthLimit() : track.growthLimit() - trackBreadth;
-        track.plannedSize() = trackBreadth;
+        track.tempSize() = trackBreadth;
         // Let's avoid computing availableLogicalSpaceShare as much as possible as it's a hot spot in performance tests.
         if (trackGrowthPotential > 0 || infiniteGrowthPotential) {
             LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksSize - i);
             LayoutUnit growthShare = infiniteGrowthPotential ? availableLogicalSpaceShare : std::min(availableLogicalSpaceShare, trackGrowthPotential);
             ASSERT_WITH_MESSAGE(growthShare >= 0, "We should never shrink any grid track or else we can't guarantee we abide by our min-sizing function. We can still have 0 as growthShare if the amount of tracks greatly exceeds the availableLogicalSpace.");
-            track.plannedSize() += growthShare;
+            track.tempSize() += growthShare;
             availableLogicalSpace -= growthShare;
         }
     }
@@ -732,13 +761,13 @@ void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
         for (unsigned i = 0; i < tracksGrowingBeyondGrowthLimitsSize; ++i) {
             GridTrack* track = growBeyondGrowthLimitsTracks->at(i);
             LayoutUnit growthShare = availableLogicalSpace / (tracksGrowingBeyondGrowthLimitsSize - i);
-            track->plannedSize() += growthShare;
+            track->tempSize() += growthShare;
             availableLogicalSpace -= growthShare;
         }
     }
 
     for (auto* track : tracks)
-        (track->*trackGrowthFunction)(track->plannedSize());
+        track->setPlannedSize(std::max(track->plannedSize(), track->tempSize()));
 }
 
 #ifndef NDEBUG
index 7f0688a..e7a7593 100644 (file)
@@ -91,9 +91,10 @@ private:
     typedef const LayoutUnit& (GridTrack::* AccumulatorGetter)() const;
     typedef void (GridTrack::* AccumulatorGrowFunction)(LayoutUnit);
     typedef bool (GridTrackSize::* FilterFunction)() const;
+    typedef struct GridItemsSpanGroupRange GridItemsSpanGroupRange;
     void resolveContentBasedTrackSizingFunctionsForNonSpanningItems(GridTrackSizingDirection, const GridCoordinate&, RenderBox& gridItem, GridTrack&, Vector<GridTrack>& columnTracks);
-    void resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection, GridSizingData&, GridItemWithSpan&, FilterFunction, SizingFunction, AccumulatorGetter, AccumulatorGrowFunction, FilterFunction growAboveMaxBreadthFilterFunction = nullptr);
-    void distributeSpaceToTracks(Vector<GridTrack*>&, const Vector<GridTrack*>* growBeyondGrowthLimitsTracks, AccumulatorGetter, AccumulatorGrowFunction, LayoutUnit& availableLogicalSpace);
+    void resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection, GridSizingData&, const GridItemsSpanGroupRange&, FilterFunction, SizingFunction, AccumulatorGetter trackSize, AccumulatorGetter correctedTrackSize, AccumulatorGrowFunction, FilterFunction growAboveMaxBreadthFilterFunction = nullptr);
+    void distributeSpaceToTracks(Vector<GridTrack*>&, const Vector<GridTrack*>* growBeyondGrowthLimitsTracks, AccumulatorGetter, LayoutUnit& availableLogicalSpace);
 
     double computeNormalizedFractionBreadth(Vector<GridTrack>&, const GridSpan& tracksSpan, GridTrackSizingDirection, LayoutUnit availableLogicalSpace) const;