Skip to content

Commit 846cf28

Browse files
add gaps in intrinsic space distribution and some performance improvements
1 parent b85fafb commit 846cf28

File tree

1 file changed

+55
-44
lines changed

1 file changed

+55
-44
lines changed

yoga/algorithm/grid/TrackSizing.h

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
#include <yoga/algorithm/grid/GridLayout.h>
1010
#include <yoga/numeric/Comparison.h>
1111
#include <yoga/style/StyleSizeLength.h>
12-
#include <set>
12+
#include <unordered_set>
1313

1414
namespace facebook::yoga {
1515

16+
// Used in distributeSpaceToTracksBaseSize and distributeSpaceToTracksGrowthLimit
1617
enum SpaceDistributionPhase {
1718
AccommodateMinimumContribution,
1819
AccommodateMaxContentContribution,
@@ -145,11 +146,10 @@ struct TrackSizing {
145146
if (includesFlexibleTrack(spannedTracks)) {
146147
continue;
147148
}
148-
int32_t span = dimension == Dimension::Width ? (item.columnEnd - item.columnStart) : (item.rowEnd - item.rowStart);
149+
size_t span = dimension == Dimension::Width ? (item.columnEnd - item.columnStart) : (item.rowEnd - item.rowStart);
149150
itemsGroupedByIncreasingSpan[span].push_back({item, spannedTracks});
150151
}
151152

152-
// auto sizingMode = dimension == Dimension::Width ? widthSizingMode : heightSizingMode;
153153
auto containerSize = dimension == Dimension::Width ? containerInnerWidth : containerInnerHeight;
154154
auto sizingMode = dimension == Dimension::Width ? widthSizingMode : heightSizingMode;
155155

@@ -181,10 +181,10 @@ struct TrackSizing {
181181
}
182182

183183
// 2. For content-based minimums
184-
// Unimplemented
185-
184+
// TODO: Implement when we support min-content
185+
186186
// 3. For max-content minimums
187-
// Unimplemented
187+
// TODO: Implement when we support max-content
188188

189189
// 4. If at this point any track’s growth limit is now less than its base size, increase its growth limit to match its base size.
190190
for (auto& track: spannedTracks) {
@@ -233,12 +233,12 @@ struct TrackSizing {
233233
auto minimumContribution = sizingMode == SizingMode::MaxContent ? getLimitedMinimumContentContribution(item, dimension) : getMinimumContribution(item, dimension);
234234
distributeSpaceToFlexibleTracks(dimension, intrinsicMinimumSizingFunctionTracks, spannedTracks, minimumContribution, SpaceDistributionPhase::AccommodateMinimumContribution);
235235
}
236-
// 2, 3, 4, 5, 6 Unimplemented
236+
// 2, 3, 4, 5, 6 does not seem to be needed since max-sizing function is flexible kind and we do not support min-content, max-content yet
237237
}
238238
};
239239

240240
// https://www.w3.org/TR/css-grid-1/#extra-space
241-
// Handles for distributing space to track's base size
241+
// Distribute space to tracks' where affected size is base size
242242
void distributeSpaceToTracksBaseSize(
243243
Dimension dimension,
244244
std::vector<GridTrackSize*>& affectedTracks,
@@ -257,12 +257,18 @@ struct TrackSizing {
257257

258258
// 2.1 Find the space to distribute
259259
float totalSpannedTracksSize = 0.0f;
260-
for (auto& track: spannedTracks) {
261-
totalSpannedTracksSize += track->baseSize;
260+
auto gap = node->style().computeGapForDimension(dimension, containerSize);
261+
for (size_t i = 0; i < spannedTracks.size(); i++) {
262+
totalSpannedTracksSize += spannedTracks[i]->baseSize;
263+
// gaps are treated as tracks of fixed size. Item can span over gaps.
264+
if (i < spannedTracks.size() - 1) {
265+
totalSpannedTracksSize += gap;
266+
}
262267
}
263268
float spaceToDistribute = std::max(0.0f, sizeContribution - totalSpannedTracksSize);
264-
std::set<GridTrackSize*> frozenTracks;
265-
269+
std::unordered_set<GridTrackSize*> frozenTracks;
270+
frozenTracks.reserve(affectedTracks.size());
271+
266272
// 2.2. Distribute space up to limits
267273
while (frozenTracks.size() < affectedTracks.size() && spaceToDistribute > 0.0f && !yoga::inexactEquals(spaceToDistribute, 0.0f)) {
268274
auto unfrozenTrackCount = affectedTracks.size() - frozenTracks.size();
@@ -289,7 +295,7 @@ struct TrackSizing {
289295
}
290296

291297
// 2.3. Distribute space to non-affected tracks:
292-
// Currently, browsers do not implement this step.
298+
// Currently, browsers do not implement this step. So we avoid it to match with browsers
293299
// https://github.com/w3c/csswg-drafts/issues/3648
294300

295301
// 2.4. Distribute space beyond limits
@@ -316,14 +322,10 @@ struct TrackSizing {
316322
}
317323
}
318324

319-
frozenTracks.clear();
320-
while (spaceToDistribute > 0.0f && !yoga::inexactEquals(spaceToDistribute, 0.0f) && tracksToGrowBeyondLimits.size() > 0) {
321-
auto unfrozenTrackCount = tracksToGrowBeyondLimits.size() - frozenTracks.size();
325+
auto unfrozenTrackCount = tracksToGrowBeyondLimits.size();
326+
while (spaceToDistribute > 0.0f && !yoga::inexactEquals(spaceToDistribute, 0.0f) && unfrozenTrackCount > 0) {
322327
auto distributionPerTrack = spaceToDistribute / unfrozenTrackCount;
323328
for (auto& track: tracksToGrowBeyondLimits) {
324-
if (frozenTracks.contains(track)) {
325-
continue;
326-
}
327329
itemIncurredIncrease[track] += distributionPerTrack;
328330
spaceToDistribute -= distributionPerTrack;
329331
}
@@ -343,6 +345,8 @@ struct TrackSizing {
343345
}
344346
}
345347

348+
// https://www.w3.org/TR/css-grid-1/#extra-space
349+
// Distribute space to tracks' where affected size is growth limit
346350
void distributeSpaceToTracksGrowthLimit(
347351
Dimension dimension,
348352
std::vector<GridTrackSize*>& affectedTracks,
@@ -361,23 +365,25 @@ struct TrackSizing {
361365

362366
// 2.1 Find the space to distribute
363367
float totalSpannedTracksSize = 0.0f;
364-
for (auto& track: spannedTracks) {
365-
totalSpannedTracksSize += track->growthLimit == INFINITY ? track->baseSize : track->growthLimit;
368+
auto gap = node->style().computeGapForDimension(dimension, containerSize);
369+
for (size_t i = 0; i < spannedTracks.size(); i++) {
370+
totalSpannedTracksSize += spannedTracks[i]->growthLimit == INFINITY ? spannedTracks[i]->baseSize : spannedTracks[i]->growthLimit;
371+
if (i < spannedTracks.size() - 1) {
372+
// gaps are treated as tracks of fixed size. Item can span over gaps.
373+
totalSpannedTracksSize += gap;
374+
}
366375
}
367376
float spaceToDistribute = std::max(0.0f, sizeContribution - totalSpannedTracksSize);
368-
std::set<GridTrackSize*> frozenTracks;
369-
370-
// Freeze tracks that are not infinitely growable before distribution
371-
// Per spec: "If the affected size was a growth limit and the track is not marked infinitely growable,
372-
// then each item-incurred increase will be zero."
377+
std::unordered_set<GridTrackSize*> frozenTracks;
378+
frozenTracks.reserve(affectedTracks.size());
373379

374380
// 2.2. Distribute space up to limits
375381
while (frozenTracks.size() < affectedTracks.size() && spaceToDistribute > 0.0f && !yoga::inexactEquals(spaceToDistribute, 0.0f)) {
376382
auto unfrozenTrackCount = affectedTracks.size() - frozenTracks.size();
377383
auto distributionPerTrack = spaceToDistribute / unfrozenTrackCount;
378384

379385
for (auto& track: affectedTracks) {
380-
if (frozenTracks.find(track) != frozenTracks.end()) {
386+
if (frozenTracks.contains(track)) {
381387
continue;
382388
}
383389
auto limit = INFINITY;
@@ -417,15 +423,11 @@ struct TrackSizing {
417423
tracksToGrowBeyondLimits.push_back(track);
418424
}
419425
}
420-
frozenTracks.clear();
426+
421427
while (spaceToDistribute > 0.0f && !yoga::inexactEquals(spaceToDistribute, 0.0f) && tracksToGrowBeyondLimits.size() > 0) {
422-
// TODO: handle fit-content check here
423428
auto unfrozenTrackCount = tracksToGrowBeyondLimits.size() - frozenTracks.size();
424429
auto distributionPerTrack = spaceToDistribute / unfrozenTrackCount;
425430
for (auto& track: tracksToGrowBeyondLimits) {
426-
if (frozenTracks.find(track) != frozenTracks.end()) {
427-
continue;
428-
}
429431
itemIncurredIncrease[track] += distributionPerTrack;
430432
spaceToDistribute -= distributionPerTrack;
431433
}
@@ -449,17 +451,25 @@ struct TrackSizing {
449451
}
450452
}
451453
}
452-
454+
// https://www.w3.org/TR/css-grid-1/#extra-space
455+
// We keep affected size as base size because growth limit distribution step does not apply to flexible max sizing functions.
456+
// Also there is no use of limit here since growth limit is INFINITY for flexible tracks
453457
void distributeSpaceToFlexibleTracks(
454458
Dimension dimension,
455459
std::vector<GridTrackSize*>& affectedTracks,
456460
const std::vector<GridTrackSize*>& spannedTracks,
457461
float sizeContribution,
458462
SpaceDistributionPhase sizeContributionPhase
459463
) {
464+
auto containerSize = dimension == Dimension::Width ? containerInnerWidth : containerInnerHeight;
460465
float totalSpannedTracksSize = 0.0f;
461-
for (auto& track: spannedTracks) {
462-
totalSpannedTracksSize += track->baseSize;
466+
auto gap = node->style().computeGapForDimension(dimension, containerSize);
467+
for (size_t i = 0; i < spannedTracks.size(); i++) {
468+
totalSpannedTracksSize += spannedTracks[i]->baseSize;
469+
if (i < spannedTracks.size() - 1) {
470+
// gaps are treated as tracks of fixed size. Item can span over gaps.
471+
totalSpannedTracksSize += gap;
472+
}
463473
}
464474

465475
float sumOfFlexFactors = 0.0f;
@@ -513,10 +523,11 @@ struct TrackSizing {
513523
freeSpace = INFINITY;
514524
}
515525

516-
// If the free space is positive, distribute it equally to the base sizes of all tracks,
526+
// If the free space is positive, distribute it equally to the base sizes of all tracks,
517527
// freezing tracks as they reach their growth limits (and continuing to grow the unfrozen tracks as needed).
518528
if (freeSpace > 0.0f && !yoga::inexactEquals(freeSpace, 0.0f)) {
519-
std::set<GridTrackSize*> frozenTracks;
529+
std::unordered_set<GridTrackSize*> frozenTracks;
530+
frozenTracks.reserve(tracks.size());
520531
auto extraSpace = freeSpace;
521532

522533
while (frozenTracks.size() < tracks.size() && extraSpace > 0.0f && !yoga::inexactEquals(extraSpace, 0.0f)) {
@@ -595,8 +606,8 @@ struct TrackSizing {
595606
trackPointers.push_back(&track);
596607
}
597608

598-
std::function<float(const std::vector<GridTrackSize*>&, float, std::set<GridTrackSize*>)> findFrSize;
599-
findFrSize = [&](const std::vector<GridTrackSize*>& tracks, float spaceToFill, std::set<GridTrackSize*> inflexibleTracks) -> float {
609+
std::function<float(const std::vector<GridTrackSize*>&, float, std::unordered_set<GridTrackSize*>)> findFrSize;
610+
findFrSize = [&](const std::vector<GridTrackSize*>& tracks, float spaceToFill, std::unordered_set<GridTrackSize*> inflexibleTracks) -> float {
600611
auto leftoverSpace = spaceToFill;
601612
auto flexFactorSum = 0.0f;
602613
std::vector<GridTrackSize*> flexibleTracks;
@@ -625,7 +636,7 @@ struct TrackSizing {
625636
// Let the hypothetical fr size be the leftover space divided by the flex factor sum.
626637
auto hypotheticalFrSize = leftoverSpace / flexFactorSum;
627638
// If the product of the hypothetical fr size and a flexible track's flex factor is less than the track's base size
628-
std::set<GridTrackSize*> _inflexibleTracks;
639+
std::unordered_set<GridTrackSize*> _inflexibleTracks;
629640
for (auto& track : flexibleTracks) {
630641
if (track->maxSizingFunction.isStretch() && track->maxSizingFunction.value().isDefined()) {
631642
float flexFactor = track->maxSizingFunction.value().unwrap();
@@ -662,7 +673,7 @@ struct TrackSizing {
662673
// Otherwise, if the free space is a definite length:
663674
// The used flex fraction is the result of finding the size of an fr using all of the grid tracks and a space to fill of the available grid space.
664675
else if (freeSpace != YGUndefined) {
665-
usedFlexFraction = findFrSize(trackPointers, containerSize, std::set<GridTrackSize*>());
676+
usedFlexFraction = findFrSize(trackPointers, containerSize, std::unordered_set<GridTrackSize*>());
666677
}
667678
// Otherwise, if the free space is an indefinite length:
668679
// The used flex fraction is the maximum of:
@@ -689,7 +700,7 @@ struct TrackSizing {
689700
spannedTrackPointers.push_back(track);
690701
}
691702
auto itemMaxContentContribution = getMaxContentContribution(item, dimension);
692-
usedFlexFraction = std::max(usedFlexFraction, findFrSize(spannedTrackPointers, itemMaxContentContribution, std::set<GridTrackSize*>()));
703+
usedFlexFraction = std::max(usedFlexFraction, findFrSize(spannedTrackPointers, itemMaxContentContribution, std::unordered_set<GridTrackSize*>()));
693704
}
694705
}
695706

@@ -729,7 +740,7 @@ struct TrackSizing {
729740
if (yoga::isDefined(minContainerSize)) {
730741
if (newTotalSize < minContainerSize) {
731742
// Redo with min constraint
732-
usedFlexFraction = findFrSize(trackPointers, minContainerSize, std::set<GridTrackSize*>());
743+
usedFlexFraction = findFrSize(trackPointers, minContainerSize, std::unordered_set<GridTrackSize*>());
733744
}
734745
}
735746

@@ -747,7 +758,7 @@ struct TrackSizing {
747758
if (yoga::isDefined(maxContainerSize)) {
748759
if (newTotalSize > maxContainerSize) {
749760
// Redo with max constraint
750-
usedFlexFraction = findFrSize(trackPointers, maxContainerSize, std::set<GridTrackSize*>());
761+
usedFlexFraction = findFrSize(trackPointers, maxContainerSize, std::unordered_set<GridTrackSize*>());
751762
}
752763
}
753764

0 commit comments

Comments
 (0)