[CSS Grid Layout] Flex tracks sizing alg must handle 0fr values
authorjfernandez@igalia.com <jfernandez@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Sep 2015 12:32:48 +0000 (12:32 +0000)
committerjfernandez@igalia.com <jfernandez@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Sep 2015 12:32:48 +0000 (12:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148944

Reviewed by Darin Adler.

Source/WebCore:

We don't allow 0 as flexible size value, which is not following current
specs; it just states that it must be a positive value. This patch
adds such change in the parser but some additional logic must be added
as well to handle 0 values during the flex tracks sizing algorithm.

The old algorithm didn't take 0 values into account, so there is the risk
of division by zero. Additionally, it was not handling fraction values
in the best way. The last versions of the spec changed this algorithm in
order to handle fraction values so that they don't cause exponential
grow of tracks using values bigger than 1.

This patch implements also such new algorithm, so we can deal not only
with 0 values, but managing fraction values properly.

No new tests, just some additional test cases and some of them rebaselined.

* rendering/RenderGrid.cpp:
(WebCore::normalizedFlexFraction):
(WebCore::RenderGrid::computeUsedBreadthOfGridTracks):
(WebCore::RenderGrid::computeFlexFactorUnitSize): Added.
(WebCore::RenderGrid::findFlexFactorUnitSize): Added.
(WebCore::RenderGrid::GridTrackForNormalization): Deleted.
(WebCore::RenderGrid::computeNormalizedFractionBreadth): Deleted.
* rendering/RenderGrid.h:

LayoutTests:

Allow 0 as flex factor value and implement the new flex track sizing algorithm.

* fast/css-grid-layout/flex-and-minmax-content-resolution-rows.html: Updated some cases.
* fast/css-grid-layout/flex-content-resolution-columns-expected.txt:
* fast/css-grid-layout/flex-content-resolution-columns.html: Added some new cases.
* fast/css-grid-layout/flex-content-resolution-rows-expected.txt:
* fast/css-grid-layout/flex-content-resolution-rows.html: Added some new cases.

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

LayoutTests/ChangeLog
LayoutTests/fast/css-grid-layout/flex-and-minmax-content-resolution-rows.html
LayoutTests/fast/css-grid-layout/flex-content-resolution-columns-expected.txt
LayoutTests/fast/css-grid-layout/flex-content-resolution-columns.html
LayoutTests/fast/css-grid-layout/flex-content-resolution-rows-expected.txt
LayoutTests/fast/css-grid-layout/flex-content-resolution-rows.html
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/RenderGrid.h

index fbd7137..d6c6d75 100644 (file)
@@ -1,3 +1,18 @@
+2015-09-29  Javier Fernandez  <jfernandez@igalia.com>
+
+        [CSS Grid Layout] Flex tracks sizing alg must handle 0fr values
+        https://bugs.webkit.org/show_bug.cgi?id=148944
+
+        Reviewed by Darin Adler.
+
+        Allow 0 as flex factor value and implement the new flex track sizing algorithm.
+
+        * fast/css-grid-layout/flex-and-minmax-content-resolution-rows.html: Updated some cases.
+        * fast/css-grid-layout/flex-content-resolution-columns-expected.txt:
+        * fast/css-grid-layout/flex-content-resolution-columns.html: Added some new cases.
+        * fast/css-grid-layout/flex-content-resolution-rows-expected.txt:
+        * fast/css-grid-layout/flex-content-resolution-rows.html: Added some new cases.
+
 2015-09-16  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         printing does not use minimum page zoom factor
index 69b3fee..f16ebd6 100644 (file)
     </div>
 </div>
 
+<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. -->
 <div style="width: 10px; height: 60px;">
     <div class="grid gridWithIntrinsicSizeBiggerThanFlex" style="height: 100%">
         <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="40">XXXXX XXXXX XXXXX XXXXX</div>
     </div>
 </div>
 
+<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. -->
 <div style="width: 10px; height: 60px;">
     <div class="grid gridWithIntrinsicSizeBiggerThanFlex">
         <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="40">XXXXX XXXXX XXXXX XXXXX</div>
-        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="160"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="80"></div>
     </div>
 </div>
 
index b8350a1..54b5069 100644 (file)
@@ -6,6 +6,10 @@
     -webkit-grid-template-columns: minmax(1fr, 50px);
     -webkit-grid-template-rows: 50px;
 }
+.gridZeroFlexContent {
+    -webkit-grid-template-columns: minmax(1fr, 0px);
+    -webkit-grid-template-rows: 50px;
+}
 .gridMaxFlexContent {
     -webkit-grid-template-columns: minmax(30px, 2fr);
     -webkit-grid-template-rows: 50px;
     -webkit-grid-template-columns: minmax(300px, 3fr) minmax(150px, 1fr);
     -webkit-grid-template-rows: 50px;
 }
+.gridRespectBaseSize {
+    -webkit-grid-template-columns: minmax(75px, 1fr) minmax(0px, 2fr);
+    -webkit-grid-template-rows: 50px;
+}
+.gridRespectProportions {
+    -webkit-grid-template-columns: minmax(0px, .25fr) minmax(0px, .5fr) minmax(0px, 2fr);
+    -webkit-grid-template-rows: 50px;
+}
+.gridRespectBaseSizeProportions {
+    -webkit-grid-template-columns: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr);
+    -webkit-grid-template-rows: 50px;
+}
+.gridRespectBaseSizeBeforeProportions {
+    -webkit-grid-template-columns: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr);
+    -webkit-grid-template-rows: 50px;
+}
+.firstRowThirdColumn {
+    background-color: yellow;
+    -webkit-grid-column: 3;
+    -webkit-grid-row: 1;
+}
 </style>
 <script src="../../resources/check-layout.js"></script>
 <body onload="checkLayout('.grid');">
     </div>
 </div>
 
+<div style="width: 100px">
+    <div class="grid gridZeroFlexContent">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="0" data-expected-height="50"></div>
+    </div>
+</div>
+
 <!-- Allow the extra logical space distribution to occur. -->
 <div style="width: 40px; height: 10px">
     <div class="grid gridMinFlexContent">
     </div>
 </div>
 
+<!-- Flex track length must be at least its baseSize. -->
+<div style="width: 100px; height: 10px;">
+    <div class="grid gridRespectBaseSize">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="75" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="25" data-expected-height="50"></div>
+    </div>
+</div>
+
+<!-- Flex track lengths must be proportional to their flex factors.. -->
+<div style="width: 275px; height: 10px;">
+    <div class="grid gridRespectProportions">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="25" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowThirdColumn" data-expected-width="200" data-expected-height="50"></div>
+    </div>
+</div>
+
+<!-- Flex track lengths must be proportional but still respecting their base sizes. -->
+<div style="width: 350px; height: 10px;">
+    <div class="grid gridRespectBaseSizeProportions">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="100" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowThirdColumn" data-expected-width="200" data-expected-height="50"></div>
+    </div>
+</div>
+
+<!-- Not enough space to repsect proportions, because minTrackBreadh it's a harder requirement -->
+<div style="width: 275px; height: 10px;">
+    <div class="grid gridRespectBaseSizeBeforeProportions">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowSecondColumn" data-expected-width="75" data-expected-height="50"></div>
+        <div class="sizedToGridArea firstRowThirdColumn" data-expected-width="150" data-expected-height="50"></div>
+    </div>
+</div>
+
 </body>
 </html>
index e1ca9c6..e1d2559 100644 (file)
@@ -6,6 +6,10 @@
     -webkit-grid-template-columns: 50px;
     -webkit-grid-template-rows: minmax(1fr, 50px);
 }
+.gridZeroFlexContent {
+    -webkit-grid-template-columns: 50px;
+    -webkit-grid-template-rows: minmax(1fr, 0px);
+}
 .gridMaxFlexContent {
     -webkit-grid-template-columns: 50px;
     -webkit-grid-template-rows: minmax(30px, 2fr);
     -webkit-grid-template-columns: 50px;
     -webkit-grid-template-rows: minmax(10px, 0.5fr) minmax(10px, 2fr);
 }
+.gridRespectBaseSize {
+    -webkit-grid-template-columns: 50px;
+    -webkit-grid-template-rows: minmax(75px, 1fr) minmax(0px, 2fr);
+}
+.gridRespectProportions {
+    -webkit-grid-template-columns: 50px;
+    -webkit-grid-template-rows: minmax(25px, .25fr) minmax(0px, .5fr) minmax(0px, 2fr);
+}
+.gridRespectBaseSizeProportions {
+    -webkit-grid-template-columns: 50px;
+    -webkit-grid-template-rows: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr);
+}
+.gridRespectBaseSizeBeforeProportions {
+    -webkit-grid-template-columns: 50px;
+    -webkit-grid-template-rows: minmax(50px, .25fr) minmax(0px, .5fr) minmax(0px, 1fr);
+}
+.thirdRowFirstColumn {
+    background-color: yellow;
+    -webkit-grid-column: 1;
+    -webkit-grid-row: 3;
+}
 </style>
 <script src="../../resources/check-layout.js"></script>
 <body onload="checkLayout('.grid');">
 </div>
 
 <div style="height: 0px">
+    <div class="grid gridZeroFlexContent">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="0"></div>
+    </div>
+</div>
+
+<div style="height: 0px">
     <div class="grid gridMinFlexContent">
         <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
     </div>
     </div>
 </div>
 
+<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. -->
 <div class="constrainedContainer">
     <div class="grid gridTwoDoubleMaxFlexContent">
         <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div>
-        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="40"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div>
     </div>
 </div>
 
     </div>
 </div>
 
+<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. -->
 <div style="width: 10px; height: 60px">
     <div class="grid gridTwoDoubleMaxFlexContent">
         <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div>
-        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="40"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div>
     </div>
 </div>
 
     </div>
 </div>
 
+<!-- We normalize fraction flex factors to 1, so we don't keep exact proportions with >1 factors. -->
 <div style="width: 10px; height: 120px;">
     <div class="grid gridTwoDoubleMaxFlexContent">
         <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="10"></div>
-        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="40"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="20"></div>
+    </div>
+</div>
+
+<!-- Flex track lengths must be proportional to their flex factors.. -->
+<div style="width: 10px; height: 275px;">
+    <div class="grid gridRespectProportions" style="height: 100%;">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="25"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="200"></div>
+    </div>
+</div>
+
+<div style="width: 10px; height: 275px;">
+    <div class="grid gridRespectProportions">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="25"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="13"></div>
+        <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+    </div>
+</div>
+
+<!-- Flex track lengths must be proportional but still respecting their base sizes. -->
+<div style="width: 10px; height: 350px;">
+    <div class="grid gridRespectBaseSizeProportions" style="height: 100%;">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="100"></div>
+        <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="200"></div>
+    </div>
+</div>
+
+<div style="width: 10px; height: 350px;">
+    <div class="grid gridRespectBaseSizeProportions">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="25"></div>
+        <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+    </div>
+</div>
+
+<!-- Not enough space to repsect proportions, because minTrackBreadh it's a harder requirement -->
+<div style="width: 10px; height: 275px;">
+    <div class="grid gridRespectBaseSizeBeforeProportions" style="height: 100%;">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="75"></div>
+        <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="150"></div>
+    </div>
+</div>
+
+<div style="width: 10px; height: 275px;">
+    <div class="grid gridRespectBaseSizeBeforeProportions">
+        <div class="sizedToGridArea firstRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
+        <div class="sizedToGridArea secondRowFirstColumn" data-expected-width="50" data-expected-height="25"></div>
+        <div class="sizedToGridArea thirdRowFirstColumn" data-expected-width="50" data-expected-height="50"></div>
     </div>
 </div>
 
index de8fa67..c10bbf5 100644 (file)
@@ -1,3 +1,35 @@
+2015-09-29  Javier Fernandez  <jfernandez@igalia.com>
+
+        [CSS Grid Layout] Flex tracks sizing alg must handle 0fr values
+        https://bugs.webkit.org/show_bug.cgi?id=148944
+
+        Reviewed by Darin Adler.
+
+        We don't allow 0 as flexible size value, which is not following current
+        specs; it just states that it must be a positive value. This patch
+        adds such change in the parser but some additional logic must be added
+        as well to handle 0 values during the flex tracks sizing algorithm.
+
+        The old algorithm didn't take 0 values into account, so there is the risk
+        of division by zero. Additionally, it was not handling fraction values
+        in the best way. The last versions of the spec changed this algorithm in
+        order to handle fraction values so that they don't cause exponential
+        grow of tracks using values bigger than 1.
+
+        This patch implements also such new algorithm, so we can deal not only
+        with 0 values, but managing fraction values properly.
+
+        No new tests, just some additional test cases and some of them rebaselined.
+
+        * rendering/RenderGrid.cpp:
+        (WebCore::normalizedFlexFraction):
+        (WebCore::RenderGrid::computeUsedBreadthOfGridTracks):
+        (WebCore::RenderGrid::computeFlexFactorUnitSize): Added.
+        (WebCore::RenderGrid::findFlexFactorUnitSize): Added.
+        (WebCore::RenderGrid::GridTrackForNormalization): Deleted.
+        (WebCore::RenderGrid::computeNormalizedFractionBreadth): Deleted.
+        * rendering/RenderGrid.h:
+
 2015-09-29  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         Fix the broken !ENABLE(STREAM_API) build
index 07d99fd..1ed1fce 100644 (file)
@@ -116,19 +116,6 @@ private:
     bool m_infinitelyGrowable { false };
 };
 
-struct GridTrackForNormalization {
-    GridTrackForNormalization(const GridTrack& track, double flex)
-        : m_track(&track)
-        , m_flex(flex)
-        , m_normalizedFlexValue(track.baseSize() / flex)
-    {
-    }
-
-    const GridTrack* m_track;
-    double m_flex;
-    LayoutUnit m_normalizedFlexValue;
-};
-
 class RenderGrid::GridIterator {
     WTF_MAKE_NONCOPYABLE(GridIterator);
 public:
@@ -369,6 +356,11 @@ bool RenderGrid::gridElementIsShrinkToFit()
     return isFloatingOrOutOfFlowPositioned();
 }
 
+static inline double normalizedFlexFraction(const GridTrack& track, double flexFactor)
+{
+    return track.baseSize() / std::max<double>(1, flexFactor);
+}
+
 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace)
 {
     const LayoutUnit initialAvailableLogicalSpace = availableLogicalSpace;
@@ -429,14 +421,12 @@ void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
         return;
 
     // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction.
-    double normalizedFractionBreadth = 0;
+    double flexFraction = 0;
     if (!hasUndefinedRemainingSpace)
-        normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, GridSpan(0, tracks.size() - 1), direction, initialAvailableLogicalSpace);
+        flexFraction = findFlexFactorUnitSize(tracks, GridSpan(0, tracks.size() - 1), direction, initialAvailableLogicalSpace);
     else {
-        for (auto trackIndex : flexibleSizedTracksIndex) {
-            const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex);
-            normalizedFractionBreadth = std::max(normalizedFractionBreadth, tracks[trackIndex].baseSize() / trackSize.maxTrackBreadth().flex());
-        }
+        for (const auto& trackIndex : flexibleSizedTracksIndex)
+            flexFraction = std::max(flexFraction, normalizedFlexFraction(tracks[trackIndex], gridTrackSize(direction, trackIndex).maxTrackBreadth().flex()));
 
         for (unsigned i = 0; i < flexibleSizedTracksIndex.size(); ++i) {
             GridIterator iterator(m_grid, direction, flexibleSizedTracksIndex[i]);
@@ -448,8 +438,7 @@ void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
                 if (i > 0 && span.resolvedInitialPosition.toInt() <= flexibleSizedTracksIndex[i - 1])
                     continue;
 
-                double itemNormalizedFlexBreadth = computeNormalizedFractionBreadth(tracks, span, direction, maxContentForChild(*gridItem, direction, sizingData.columnTracks));
-                normalizedFractionBreadth = std::max(normalizedFractionBreadth, itemNormalizedFlexBreadth);
+                flexFraction = std::max(flexFraction, findFlexFactorUnitSize(tracks, span, direction, maxContentForChild(*gridItem, direction, sizingData.columnTracks)));
             }
         }
     }
@@ -457,7 +446,7 @@ void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
     for (auto trackIndex : flexibleSizedTracksIndex) {
         const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex);
         GridTrack& track = tracks[trackIndex];
-        LayoutUnit baseSize = std::max<LayoutUnit>(track.baseSize(), normalizedFractionBreadth * trackSize.maxTrackBreadth().flex());
+        LayoutUnit baseSize = std::max<LayoutUnit>(track.baseSize(), flexFraction * trackSize.maxTrackBreadth().flex());
         track.setBaseSize(baseSize);
         availableLogicalSpace -= baseSize;
     }
@@ -500,57 +489,56 @@ LayoutUnit RenderGrid::computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirect
     return valueForLength(trackLength, computeContentLogicalHeight(MainOrPreferredSize, style().logicalHeight(), Nullopt).valueOr(0));
 }
 
-double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, const GridSpan& tracksSpan, GridTrackSizingDirection direction, LayoutUnit spaceToFill) const
+double RenderGrid::computeFlexFactorUnitSize(const Vector<GridTrack>& tracks, GridTrackSizingDirection direction, double flexFactorSum, LayoutUnit leftOverSpace, const Vector<size_t, 8>& flexibleTracksIndexes, std::unique_ptr<TrackIndexSet> tracksToTreatAsInflexible) const
 {
-    LayoutUnit allocatedSpace;
-    Vector<GridTrackForNormalization> tracksForNormalization;
-    for (auto& position : tracksSpan) {
-        GridTrack& track = tracks[position.toInt()];
-        allocatedSpace += track.baseSize();
+    // We want to avoid the effect of flex factors sum below 1 making the factor unit size to grow exponentially.
+    double hypotheticalFactorUnitSize = leftOverSpace / std::max<double>(1, flexFactorSum);
 
-        const GridTrackSize& trackSize = gridTrackSize(direction, position.toInt());
-        if (!trackSize.maxTrackBreadth().isFlex())
+    // product of the hypothetical "flex factor unit" and any flexible track's "flex factor" must be grater than such track's "base size".
+    bool validFlexFactorUnit = true;
+    for (auto index : flexibleTracksIndexes) {
+        if (tracksToTreatAsInflexible && tracksToTreatAsInflexible->contains(index))
             continue;
-
-        tracksForNormalization.append(GridTrackForNormalization(track, trackSize.maxTrackBreadth().flex()));
+        LayoutUnit baseSize = tracks[index].baseSize();
+        double flexFactor = gridTrackSize(direction, index).maxTrackBreadth().flex();
+        // treating all such tracks as inflexible.
+        if (baseSize > hypotheticalFactorUnitSize * flexFactor) {
+            leftOverSpace -= baseSize;
+            flexFactorSum -= flexFactor;
+            if (!tracksToTreatAsInflexible)
+                tracksToTreatAsInflexible = std::unique_ptr<TrackIndexSet>(new TrackIndexSet());
+            tracksToTreatAsInflexible->add(index);
+            validFlexFactorUnit = false;
+        }
     }
+    if (!validFlexFactorUnit)
+        return computeFlexFactorUnitSize(tracks, direction, flexFactorSum, leftOverSpace, flexibleTracksIndexes, WTF::move(tracksToTreatAsInflexible));
+    return hypotheticalFactorUnitSize;
+}
 
-    // The function is not called if we don't have <flex> grid tracks
-    ASSERT(!tracksForNormalization.isEmpty());
-
-    std::sort(tracksForNormalization.begin(), tracksForNormalization.end(),
-              [](const GridTrackForNormalization& track1, const GridTrackForNormalization& track2) {
-                  return track1.m_normalizedFlexValue < track2.m_normalizedFlexValue;
-              });
-
-    // These values work together: as we walk over our grid tracks, we increase fractionValueBasedOnGridItemsRatio
-    // to match a grid track's usedBreadth to <flex> ratio until the total fractions sized grid tracks wouldn't
-    // fit into availableLogicalSpaceIgnoringFractionTracks.
-    double accumulatedFractions = 0;
-    LayoutUnit fractionValueBasedOnGridItemsRatio = 0;
-    LayoutUnit availableLogicalSpaceIgnoringFractionTracks = spaceToFill - allocatedSpace;
-
-    for (auto& track : tracksForNormalization) {
-        if (track.m_normalizedFlexValue > fractionValueBasedOnGridItemsRatio) {
-            // If the normalized flex value (we ordered |tracksForNormalization| by increasing normalized flex value)
-            // will make us overflow our container, then stop. We have the previous step's ratio is the best fit.
-            if (track.m_normalizedFlexValue * accumulatedFractions > availableLogicalSpaceIgnoringFractionTracks)
-                break;
-
-            fractionValueBasedOnGridItemsRatio = track.m_normalizedFlexValue;
-        }
+double RenderGrid::findFlexFactorUnitSize(const Vector<GridTrack>& tracks, const GridSpan& tracksSpan, GridTrackSizingDirection direction, LayoutUnit leftOverSpace) const
+{
+    if (leftOverSpace <= 0)
+        return 0;
 
-        accumulatedFractions += track.m_flex;
-        // This item was processed so we re-add its used breadth to the available space to accurately count the remaining space.
-        availableLogicalSpaceIgnoringFractionTracks += track.m_track->baseSize();
+    double flexFactorSum = 0;
+    Vector<size_t, 8> flexibleTracksIndexes;
+    for (const auto& resolvedPosition : tracksSpan) {
+        size_t trackIndex = resolvedPosition.toInt();
+        GridTrackSize trackSize = gridTrackSize(direction, trackIndex);
+        if (!trackSize.maxTrackBreadth().isFlex())
+            leftOverSpace -= tracks[trackIndex].baseSize();
+        else {
+            double flexFactor = trackSize.maxTrackBreadth().flex();
+            flexibleTracksIndexes.append(trackIndex);
+            flexFactorSum += flexFactor;
+        }
     }
 
-    // Let flex factor sum be the sum of the flex factors of the flexible tracks. If this value
-    // is less than 1, set it to 1 instead.
-    if (accumulatedFractions < 1)
-        return availableLogicalSpaceIgnoringFractionTracks;
+    // The function is not called if we don't have <flex> grid tracks
+    ASSERT(!flexibleTracksIndexes.isEmpty());
 
-    return availableLogicalSpaceIgnoringFractionTracks / accumulatedFractions;
+    return computeFlexFactorUnitSize(tracks, direction, flexFactorSum, leftOverSpace, flexibleTracksIndexes);
 }
 
 bool RenderGrid::hasDefiniteLogicalSize(GridTrackSizingDirection direction) const
index ee71fde..48c7352 100644 (file)
@@ -113,7 +113,9 @@ private:
     template <TrackSizeComputationPhase> void resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection, GridSizingData&, const GridItemsSpanGroupRange&);
     template <TrackSizeComputationPhase> void distributeSpaceToTracks(Vector<GridTrack*>&, const Vector<GridTrack*>* growBeyondGrowthLimitsTracks, LayoutUnit& availableLogicalSpace);
 
-    double computeNormalizedFractionBreadth(Vector<GridTrack>&, const GridSpan& tracksSpan, GridTrackSizingDirection, LayoutUnit availableLogicalSpace) const;
+    typedef HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> TrackIndexSet;
+    double computeFlexFactorUnitSize(const Vector<GridTrack>&, GridTrackSizingDirection, double flexFactorSum, LayoutUnit leftOverSpace, const Vector<size_t, 8>& flexibleTracksIndexes, std::unique_ptr<TrackIndexSet> tracksToTreatAsInflexible = nullptr) const;
+    double findFlexFactorUnitSize(const Vector<GridTrack>&, const GridSpan&, GridTrackSizingDirection, LayoutUnit spaceToFill) const;
 
     GridTrackSize gridTrackSize(GridTrackSizingDirection, unsigned) const;